mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-23 18:21:04 +00:00
removing icle for v4l2
Original commit message from CVS: removing icle for v4l2
This commit is contained in:
parent
5369e91a3a
commit
9cb48e49d4
2 changed files with 1 additions and 526 deletions
|
@ -1,18 +1,3 @@
|
||||||
if USE_GST_V4L2
|
|
||||||
|
|
||||||
GST_V4L2_TESTS = v4l2src-test
|
|
||||||
|
|
||||||
v4l2src_test_SOURCES = v4l2src-test.c
|
|
||||||
v4l2src_test_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS)
|
|
||||||
v4l2src_test_LDADD = $(GST_PLUGINS_BASE_LIBS)
|
|
||||||
|
|
||||||
v4l2src_test_LDFLAGS = $(GST_PLUGIN_LDFLAGS) -lgstinterfaces-$(GST_MAJORMINOR)
|
|
||||||
|
|
||||||
else
|
|
||||||
GST_V4L2_TESTS =
|
|
||||||
endif
|
|
||||||
|
|
||||||
|
|
||||||
if USE_SOUNDTOUCH
|
if USE_SOUNDTOUCH
|
||||||
|
|
||||||
GST_SOUNDTOUCH_TESTS = pitch-test
|
GST_SOUNDTOUCH_TESTS = pitch-test
|
||||||
|
@ -26,4 +11,4 @@ else
|
||||||
GST_SOUNDTOUCH_TESTS =
|
GST_SOUNDTOUCH_TESTS =
|
||||||
endif
|
endif
|
||||||
|
|
||||||
noinst_PROGRAMS = $(GST_V4L2_TESTS) $(GST_SOUNDTOUCH_TESTS)
|
noinst_PROGRAMS = $(GST_SOUNDTOUCH_TESTS)
|
||||||
|
|
|
@ -1,510 +0,0 @@
|
||||||
/* GStreamer
|
|
||||||
*
|
|
||||||
* Copyright (C) 2006 Edgard Lima <edgard dot lima at indt dot org dot br>
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Library General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Library General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Library General Public
|
|
||||||
* License along with this library; if not, write to the
|
|
||||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
||||||
* Boston, MA 02111-1307, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <getopt.h>
|
|
||||||
|
|
||||||
#include <gst/gst.h>
|
|
||||||
#include <gst/interfaces/tuner.h>
|
|
||||||
#include <gst/interfaces/colorbalance.h>
|
|
||||||
#include <gst/interfaces/videoorientation.h>
|
|
||||||
|
|
||||||
GstElement *pipeline, *source, *sink;
|
|
||||||
GMainLoop *loop;
|
|
||||||
volatile int exit_read = 0;
|
|
||||||
|
|
||||||
void
|
|
||||||
print_options ()
|
|
||||||
{
|
|
||||||
printf ("\nf - to change the fequency\n");
|
|
||||||
printf ("i - to change the input\n");
|
|
||||||
printf ("n - to change the norm\n");
|
|
||||||
printf ("c - list color balance\n");
|
|
||||||
printf ("v - change video orientarion\n");
|
|
||||||
printf ("e - to exit\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
run_options (char opt)
|
|
||||||
{
|
|
||||||
switch (opt) {
|
|
||||||
case 'f':
|
|
||||||
{
|
|
||||||
GstTuner *tuner = GST_TUNER (source);
|
|
||||||
GstTunerChannel *channel;
|
|
||||||
guint freq;
|
|
||||||
|
|
||||||
channel = gst_tuner_get_channel (tuner);
|
|
||||||
|
|
||||||
freq = gst_tuner_get_frequency (tuner, channel);
|
|
||||||
|
|
||||||
printf ("\ntype the new frequency (current = %lu) (-1 to cancel): ",
|
|
||||||
freq);
|
|
||||||
scanf ("%u", &freq);
|
|
||||||
if (freq != -1)
|
|
||||||
gst_tuner_set_frequency (tuner, channel, freq);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'n':
|
|
||||||
{
|
|
||||||
GstTuner *tuner = GST_TUNER (source);
|
|
||||||
const GList *item, *list;
|
|
||||||
const GstTunerNorm *current_norm;
|
|
||||||
GstTunerNorm *norm = NULL;
|
|
||||||
gint index, next_norm;
|
|
||||||
|
|
||||||
|
|
||||||
list = gst_tuner_list_norms (tuner);
|
|
||||||
|
|
||||||
current_norm = gst_tuner_get_norm (tuner);
|
|
||||||
|
|
||||||
printf ("\nlist of norms:\n");
|
|
||||||
for (item = list, index = 0; item != NULL; item = item->next, ++index) {
|
|
||||||
norm = item->data;
|
|
||||||
if (current_norm == norm) {
|
|
||||||
printf (" * %u - %s\n", index, norm->label);
|
|
||||||
} else {
|
|
||||||
printf (" %u - %s\n", index, norm->label);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
printf ("\ntype the number of norm you want (-1 to cancel): ");
|
|
||||||
scanf ("%d", &next_norm);
|
|
||||||
if (next_norm < 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (index <= next_norm) {
|
|
||||||
printf ("Norm %d not available\n", next_norm);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
for (item = list, index = 0; item != NULL && index <= next_norm;
|
|
||||||
item = item->next, ++index) {
|
|
||||||
norm = item->data;
|
|
||||||
}
|
|
||||||
if (norm)
|
|
||||||
gst_tuner_set_norm (tuner, norm);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'i':
|
|
||||||
{
|
|
||||||
GstTuner *tuner = GST_TUNER (source);
|
|
||||||
const GList *item, *list;
|
|
||||||
const GstTunerChannel *current_channel;
|
|
||||||
GstTunerChannel *channel = NULL;
|
|
||||||
gint index, next_channel;
|
|
||||||
|
|
||||||
|
|
||||||
list = gst_tuner_list_channels (tuner);
|
|
||||||
|
|
||||||
current_channel = gst_tuner_get_channel (tuner);
|
|
||||||
|
|
||||||
printf ("\nlist of inputs:\n");
|
|
||||||
for (item = list, index = 0; item != NULL; item = item->next, ++index) {
|
|
||||||
channel = item->data;
|
|
||||||
if (current_channel == channel) {
|
|
||||||
printf (" * %u - %s\n", index, channel->label);
|
|
||||||
} else {
|
|
||||||
printf (" %u - %s\n", index, channel->label);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
printf ("\ntype the number of input you want (-1 to cancel): ");
|
|
||||||
scanf ("%d", &next_channel);
|
|
||||||
if (next_channel < 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (index <= next_channel) {
|
|
||||||
printf ("Input %d not available\n", next_channel);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
for (item = list, index = 0; item != NULL && index <= next_channel;
|
|
||||||
item = item->next, ++index) {
|
|
||||||
channel = item->data;
|
|
||||||
}
|
|
||||||
if (channel)
|
|
||||||
gst_tuner_set_channel (tuner, channel);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'e':
|
|
||||||
gst_element_set_state (pipeline, GST_STATE_NULL);
|
|
||||||
g_main_loop_quit (loop);
|
|
||||||
printf ("Bye\n");
|
|
||||||
g_thread_exit (0);
|
|
||||||
break;
|
|
||||||
case 'c':
|
|
||||||
{
|
|
||||||
GstColorBalance *balance = GST_COLOR_BALANCE (source);
|
|
||||||
const GList *controls;
|
|
||||||
GstColorBalanceChannel *channel;
|
|
||||||
const GList *item;
|
|
||||||
gint index, new_value;
|
|
||||||
|
|
||||||
controls = gst_color_balance_list_channels (balance);
|
|
||||||
|
|
||||||
printf ("\n");
|
|
||||||
|
|
||||||
if (controls == NULL) {
|
|
||||||
printf ("There is no list of colorbalance controls\n");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (controls) {
|
|
||||||
printf ("list of controls:\n");
|
|
||||||
for (item = controls, index = 0; item != NULL;
|
|
||||||
item = item->next, ++index) {
|
|
||||||
channel = item->data;
|
|
||||||
printf (" %u - %s (%d - %d) = %d\n", index, channel->label,
|
|
||||||
channel->min_value, channel->max_value,
|
|
||||||
gst_color_balance_get_value (balance, channel));
|
|
||||||
}
|
|
||||||
printf ("\ntype the number of color control you want (-1 to cancel): ");
|
|
||||||
scanf ("%d", &new_value);
|
|
||||||
if (new_value == -1)
|
|
||||||
break;
|
|
||||||
for (item = controls, index = 0; item != NULL && index <= new_value;
|
|
||||||
item = item->next, ++index) {
|
|
||||||
channel = item->data;
|
|
||||||
}
|
|
||||||
printf (" %u - %s (%d - %d) = %d, type the new value: ", index - 1,
|
|
||||||
channel->label, channel->min_value, channel->max_value,
|
|
||||||
gst_color_balance_get_value (balance, channel));
|
|
||||||
scanf ("%d", &new_value);
|
|
||||||
if (new_value == -1)
|
|
||||||
break;
|
|
||||||
gst_color_balance_set_value (balance, channel, new_value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case 'v':
|
|
||||||
{
|
|
||||||
GstVideoOrientation *vidorient = GST_VIDEO_ORIENTATION (source);
|
|
||||||
gboolean flip = FALSE;
|
|
||||||
gint center = 0;
|
|
||||||
|
|
||||||
printf ("\n");
|
|
||||||
|
|
||||||
if (gst_video_orientation_get_hflip (vidorient, &flip)) {
|
|
||||||
gint new_value;
|
|
||||||
|
|
||||||
printf ("Horizontal flip is %s\n", flip ? "on" : "off");
|
|
||||||
printf ("\ntype 1 to toggle (-1 to cancel): ");
|
|
||||||
scanf ("%d", &new_value);
|
|
||||||
if (new_value == 1) {
|
|
||||||
flip = !flip;
|
|
||||||
if (gst_video_orientation_set_hflip (vidorient, flip)) {
|
|
||||||
gst_video_orientation_get_hflip (vidorient, &flip);
|
|
||||||
printf ("Now horizontal flip is %s\n", flip ? "on" : "off");
|
|
||||||
} else {
|
|
||||||
printf ("Error toggling horizontal flip\n");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
printf ("Horizontal flip control not available\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gst_video_orientation_get_vflip (vidorient, &flip)) {
|
|
||||||
gint new_value;
|
|
||||||
|
|
||||||
printf ("\nVertical flip is %s\n", flip ? "on" : "off");
|
|
||||||
printf ("\ntype 1 to toggle (-1 to cancel): ");
|
|
||||||
scanf ("%d", &new_value);
|
|
||||||
if (new_value == 1) {
|
|
||||||
flip = !flip;
|
|
||||||
if (gst_video_orientation_set_vflip (vidorient, flip)) {
|
|
||||||
gst_video_orientation_get_vflip (vidorient, &flip);
|
|
||||||
printf ("Now vertical flip is %s\n", flip ? "on" : "off");
|
|
||||||
} else {
|
|
||||||
printf ("Error toggling vertical flip\n");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
printf ("Vertical flip control not available\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gst_video_orientation_get_hcenter (vidorient, ¢er)) {
|
|
||||||
printf ("Horizontal center is %d\n", center);
|
|
||||||
printf ("\ntype the new horizontal center value (-1 to cancel): ");
|
|
||||||
scanf ("%d", ¢er);
|
|
||||||
if (center != -1) {
|
|
||||||
if (gst_video_orientation_set_hcenter (vidorient, center)) {
|
|
||||||
gst_video_orientation_get_hcenter (vidorient, ¢er);
|
|
||||||
printf ("Now horizontal center is %d\n", center);
|
|
||||||
} else {
|
|
||||||
printf ("Error setting horizontal center\n");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
printf ("Horizontal center control not available\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gst_video_orientation_get_vcenter (vidorient, ¢er)) {
|
|
||||||
printf ("Vertical center is %d\n", center);
|
|
||||||
printf ("\ntype the new vertical center value (-1 to cancel): ");
|
|
||||||
scanf ("%d", ¢er);
|
|
||||||
if (center != -1) {
|
|
||||||
if (gst_video_orientation_set_vcenter (vidorient, center)) {
|
|
||||||
gst_video_orientation_get_vcenter (vidorient, ¢er);
|
|
||||||
printf ("Now vertical center is %d\n", center);
|
|
||||||
} else {
|
|
||||||
printf ("Error setting vertical center\n");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
printf ("Vertical center control not available\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if (opt != 10)
|
|
||||||
printf ("error: invalid option %c", opt);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
done:
|
|
||||||
|
|
||||||
return;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
gpointer
|
|
||||||
read_user (gpointer data)
|
|
||||||
{
|
|
||||||
|
|
||||||
char opt;
|
|
||||||
|
|
||||||
while (!exit_read) {
|
|
||||||
|
|
||||||
print_options ();
|
|
||||||
|
|
||||||
do {
|
|
||||||
opt = getchar ();
|
|
||||||
if (exit_read) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} while (opt == '\n');
|
|
||||||
|
|
||||||
run_options (opt);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
my_bus_callback (GstBus * bus, GstMessage * message, gpointer data)
|
|
||||||
{
|
|
||||||
|
|
||||||
switch (GST_MESSAGE_TYPE (message)) {
|
|
||||||
case GST_MESSAGE_ERROR:{
|
|
||||||
GError *err;
|
|
||||||
gchar *debug;
|
|
||||||
gchar *str;
|
|
||||||
|
|
||||||
gst_message_parse_error (message, &err, &debug);
|
|
||||||
str = gst_element_get_name (message->src);
|
|
||||||
g_print ("%s error: %s\n", str, err->message);
|
|
||||||
g_free (str);
|
|
||||||
g_print ("Debug: %s\n", debug);
|
|
||||||
|
|
||||||
g_error_free (err);
|
|
||||||
g_free (debug);
|
|
||||||
|
|
||||||
printf ("presse <ENTER> key to exit\n");
|
|
||||||
exit_read = 1;
|
|
||||||
g_main_loop_quit (loop);
|
|
||||||
break;
|
|
||||||
case GST_MESSAGE_EOS:
|
|
||||||
/* end-of-stream */
|
|
||||||
printf ("presse any key to exit\n");
|
|
||||||
exit_read = 1;
|
|
||||||
g_main_loop_quit (loop);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
main (int argc, char *argv[])
|
|
||||||
{
|
|
||||||
|
|
||||||
GThread *input_thread;
|
|
||||||
gint numbuffers = -1;
|
|
||||||
gchar device[128] = { '\0' };
|
|
||||||
gchar input[128] = { '\0' };
|
|
||||||
gulong frequency = 0;
|
|
||||||
GstBus *bus;
|
|
||||||
|
|
||||||
/* see for input option */
|
|
||||||
|
|
||||||
int c;
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
static char long_options_desc[][64] = {
|
|
||||||
{"Number of buffers to output before sending EOS"},
|
|
||||||
{"Device location. Common in /dev/video0"},
|
|
||||||
{"input/output (channel) to switch to"},
|
|
||||||
{"frequency to tune to (in Hz)"},
|
|
||||||
{0, 0, 0, 0}
|
|
||||||
};
|
|
||||||
static struct option long_options[] = {
|
|
||||||
{"numbuffers", 1, 0, 'n'},
|
|
||||||
{"device", 1, 0, 'd'},
|
|
||||||
{"input", 1, 0, 'i'},
|
|
||||||
{"frequency", 1, 0, 'f'},
|
|
||||||
{0, 0, 0, 0}
|
|
||||||
};
|
|
||||||
/* getopt_long stores the option index here. */
|
|
||||||
int option_index = 0;
|
|
||||||
|
|
||||||
c = getopt_long (argc, argv, "n:d:i:f:h", long_options, &option_index);
|
|
||||||
|
|
||||||
/* Detect the end of the options. */
|
|
||||||
if (c == -1) {
|
|
||||||
printf ("tip: use -h to see help message.\n");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (c) {
|
|
||||||
case 0:
|
|
||||||
/* If this option set a flag, do nothing else now. */
|
|
||||||
if (long_options[option_index].flag != 0)
|
|
||||||
break;
|
|
||||||
printf ("option %s", long_options[option_index].name);
|
|
||||||
if (optarg)
|
|
||||||
printf (" with arg %s", optarg);
|
|
||||||
printf ("\n");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'n':
|
|
||||||
numbuffers = atoi (optarg);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'd':
|
|
||||||
strncpy (device, optarg, sizeof (device) / sizeof (device[0]));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'i':
|
|
||||||
strncpy (input, optarg, sizeof (input) / sizeof (input[0]));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'f':
|
|
||||||
frequency = atol (optarg);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'h':
|
|
||||||
printf ("Usage: v4l2src-test [OPTION]...\n");
|
|
||||||
for (c = 0; long_options[c].name; ++c) {
|
|
||||||
printf ("-%c, --%s\r\t\t\t\t%s\n", long_options[c].val,
|
|
||||||
long_options[c].name, long_options_desc[c]);
|
|
||||||
}
|
|
||||||
exit (0);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '?':
|
|
||||||
/* getopt_long already printed an error message. */
|
|
||||||
printf ("Use -h to see help message.\n");
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
abort ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Print any remaining command line arguments (not options). */
|
|
||||||
if (optind < argc) {
|
|
||||||
printf ("Use -h to see help message.\n" "non-option ARGV-elements: ");
|
|
||||||
while (optind < argc)
|
|
||||||
printf ("%s ", argv[optind++]);
|
|
||||||
putchar ('\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
/* init */
|
|
||||||
gst_init (&argc, &argv);
|
|
||||||
|
|
||||||
/* create elements */
|
|
||||||
if (!(pipeline = gst_pipeline_new ("my_pipeline"))) {
|
|
||||||
fprintf (stderr, "error: gst_pipeline_new return NULL");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(source = gst_element_factory_make ("v4l2src", NULL))) {
|
|
||||||
fprintf (stderr,
|
|
||||||
"error: gst_element_factory_make (\"v4l2src\", NULL) return NULL");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(sink = gst_element_factory_make ("xvimagesink", NULL))) {
|
|
||||||
fprintf (stderr,
|
|
||||||
"error: gst_element_factory_make (\"xvimagesink\", NULL) return NULL");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (numbuffers > -1) {
|
|
||||||
g_object_set (source, "num-buffers", numbuffers, NULL);
|
|
||||||
}
|
|
||||||
if (device[0]) {
|
|
||||||
g_object_set (source, "device", device, NULL);
|
|
||||||
}
|
|
||||||
if (input[0]) {
|
|
||||||
g_object_set (source, "input", input, NULL);
|
|
||||||
}
|
|
||||||
if (frequency) {
|
|
||||||
g_object_set (source, "frequency", frequency, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* you would normally check that the elements were created properly */
|
|
||||||
bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
|
|
||||||
gst_bus_add_watch (bus, my_bus_callback, NULL);
|
|
||||||
|
|
||||||
/* put together a pipeline */
|
|
||||||
gst_bin_add_many (GST_BIN (pipeline), source, sink, NULL);
|
|
||||||
gst_element_link_pads (source, "src", sink, "sink");
|
|
||||||
|
|
||||||
/* start the pipeline */
|
|
||||||
gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);
|
|
||||||
loop = g_main_loop_new (NULL, FALSE);
|
|
||||||
|
|
||||||
if (!(input_thread = g_thread_create (read_user, source, TRUE, NULL))) {
|
|
||||||
fprintf (stderr, "error: g_thread_create return NULL");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_main_loop_run (loop);
|
|
||||||
g_thread_join (input_thread);
|
|
||||||
|
|
||||||
gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL);
|
|
||||||
|
|
||||||
gst_object_unref (bus);
|
|
||||||
gst_object_unref (pipeline);
|
|
||||||
|
|
||||||
gst_deinit ();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
}
|
|
Loading…
Reference in a new issue