ffmpeg: port to new API

This commit is contained in:
Wim Taymans 2011-06-02 16:23:19 +02:00
parent 8860e5c6c9
commit dad7da7ca6
9 changed files with 83 additions and 115 deletions

View file

@ -541,11 +541,12 @@ gst_ffmpegdec_src_event (GstPad * pad, GstEvent * event)
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_QOS:
{
GstQOSType type;
gdouble proportion;
GstClockTimeDiff diff;
GstClockTime timestamp;
gst_event_parse_qos (event, &proportion, &diff, &timestamp);
gst_event_parse_qos (event, &type, &proportion, &diff, &timestamp);
/* update our QoS values */
gst_ffmpegdec_update_qos (ffmpegdec, proportion, timestamp + diff);
@ -920,12 +921,9 @@ alloc_output_buffer (GstFFMpegDec * ffmpegdec, GstBuffer ** outbuf,
* fsize contains the size of the palette, so the overall size
* is bigger than ffmpegcolorspace's unit size, which will
* prompt GstBaseTransform to complain endlessly ... */
*outbuf = new_aligned_buffer (fsize, GST_PAD_CAPS (ffmpegdec->srcpad));
*outbuf = new_aligned_buffer (fsize);
ret = GST_FLOW_OK;
}
/* set caps, we do this here because the buffer is still writable here and we
* are sure to be negotiated */
gst_buffer_set_caps (*outbuf, GST_PAD_CAPS (ffmpegdec->srcpad));
return ret;
@ -1488,7 +1486,7 @@ clip_video_buffer (GstFFMpegDec * dec, GstBuffer * buf, GstClockTime in_ts,
GstClockTime in_dur)
{
gboolean res = TRUE;
gint64 cstart, cstop;
guint64 cstart, cstop;
GstClockTime stop;
GST_LOG_OBJECT (dec,
@ -2048,7 +2046,8 @@ clip_audio_buffer (GstFFMpegDec * dec, GstBuffer * buf, GstClockTime in_ts,
GstClockTime in_dur)
{
GstClockTime stop;
gint64 diff, ctime, cstop;
gint64 diff;
guint64 ctime, cstop;
gboolean res = TRUE;
gsize size, offset;
@ -2134,9 +2133,7 @@ gst_ffmpegdec_audio_frame (GstFFMpegDec * ffmpegdec,
dec_info->offset, GST_TIME_ARGS (dec_info->timestamp),
GST_TIME_ARGS (dec_info->duration), GST_TIME_ARGS (ffmpegdec->next_out));
*outbuf =
new_aligned_buffer (AVCODEC_MAX_AUDIO_FRAME_SIZE,
GST_PAD_CAPS (ffmpegdec->srcpad));
*outbuf = new_aligned_buffer (AVCODEC_MAX_AUDIO_FRAME_SIZE);
odata = gst_buffer_map (*outbuf, NULL, NULL, GST_MAP_WRITE);
@ -2194,7 +2191,6 @@ gst_ffmpegdec_audio_frame (GstFFMpegDec * ffmpegdec,
GST_BUFFER_TIMESTAMP (*outbuf) = out_timestamp;
GST_BUFFER_DURATION (*outbuf) = out_duration;
GST_BUFFER_OFFSET (*outbuf) = out_offset;
gst_buffer_set_caps (*outbuf, GST_PAD_CAPS (ffmpegdec->srcpad));
/* the next timestamp we'll use when interpolating */
ffmpegdec->next_out = out_timestamp + out_duration;
@ -2430,17 +2426,13 @@ gst_ffmpegdec_sink_event (GstPad * pad, GstEvent * event)
clear_queued (ffmpegdec);
break;
}
case GST_EVENT_NEWSEGMENT:
case GST_EVENT_SEGMENT:
{
gboolean update;
GstFormat fmt;
gint64 start, stop, time;
gdouble rate, arate;
GstSegment segment;
gst_event_parse_new_segment_full (event, &update, &rate, &arate, &fmt,
&start, &stop, &time);
gst_event_copy_segment (event, &segment);
switch (fmt) {
switch (segment.format) {
case GST_FORMAT_TIME:
/* fine, our native segment format */
break;
@ -2457,23 +2449,25 @@ gst_ffmpegdec_sink_event (GstPad * pad, GstEvent * event)
GST_DEBUG_OBJECT (ffmpegdec, "bitrate: %d", bit_rate);
/* convert values to TIME */
if (start != -1)
start = gst_util_uint64_scale_int (start, GST_SECOND, bit_rate);
if (stop != -1)
stop = gst_util_uint64_scale_int (stop, GST_SECOND, bit_rate);
if (time != -1)
time = gst_util_uint64_scale_int (time, GST_SECOND, bit_rate);
if (segment.start != -1)
segment.start =
gst_util_uint64_scale_int (segment.start, GST_SECOND, bit_rate);
if (segment.stop != -1)
segment.stop =
gst_util_uint64_scale_int (segment.stop, GST_SECOND, bit_rate);
if (segment.time != -1)
segment.time =
gst_util_uint64_scale_int (segment.time, GST_SECOND, bit_rate);
/* unref old event */
gst_event_unref (event);
/* create new converted time segment */
fmt = GST_FORMAT_TIME;
segment.format = GST_FORMAT_TIME;
/* FIXME, bitrate is not good enough too find a good stop, let's
* hope start and time were 0... meh. */
stop = -1;
event = gst_event_new_new_segment (update, rate, fmt,
start, stop, time);
segment.stop = -1;
event = gst_event_new_segment (&segment);
break;
}
default:
@ -2486,13 +2480,11 @@ gst_ffmpegdec_sink_event (GstPad * pad, GstEvent * event)
if (ffmpegdec->context->codec)
gst_ffmpegdec_drain (ffmpegdec);
GST_DEBUG_OBJECT (ffmpegdec,
"NEWSEGMENT in time start %" GST_TIME_FORMAT " -- stop %"
GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (stop));
GST_DEBUG_OBJECT (ffmpegdec, "SEGMENT in time %" GST_SEGMENT_FORMAT,
&segment);
/* and store the values */
gst_segment_set_newsegment_full (&ffmpegdec->segment, update,
rate, arate, fmt, start, stop, time);
gst_segment_copy_into (&segment, &ffmpegdec->segment);
break;
}
default:

View file

@ -170,7 +170,6 @@ gst_ffmpegdeinterlace_chain (GstPad * pad, GstBuffer * inbuf)
gsize from_size, to_size;
outbuf = gst_buffer_new_and_alloc (deinterlace->to_size);
gst_buffer_set_caps (outbuf, GST_PAD_CAPS (deinterlace->srcpad));
from_data = gst_buffer_map (inbuf, &from_size, NULL, GST_MAP_READ);
gst_ffmpeg_avpicture_fill (&deinterlace->from_frame, from_data,

View file

@ -89,7 +89,6 @@ struct _GstFFMpegDemux
/* segment stuff */
GstSegment segment;
gboolean running;
/* cached seek in READY */
GstEvent *seek_event;
@ -451,7 +450,7 @@ gst_ffmpegdemux_do_seek (GstFFMpegDemux * demux, GstSegment * segment)
/* get the stream for seeking */
stream = demux->context->streams[index];
/* initial seek position */
target = segment->last_stop;
target = segment->position;
/* convert target to ffmpeg time */
fftarget = gst_ffmpeg_time_gst_to_ff (target, stream->time_base);
@ -494,7 +493,7 @@ gst_ffmpegdemux_do_seek (GstFFMpegDemux * demux, GstSegment * segment)
GST_DEBUG_OBJECT (demux, "seek success, returned %d", seekret);
segment->last_stop = target;
segment->position = target;
segment->time = target;
segment->start = target;
@ -578,13 +577,13 @@ gst_ffmpegdemux_perform_seek (GstFFMpegDemux * demux, GstEvent * event)
/* now configure the seek segment */
if (event) {
gst_segment_set_seek (&seeksegment, rate, format, flags,
gst_segment_do_seek (&seeksegment, rate, format, flags,
cur_type, cur, stop_type, stop, &update);
}
GST_DEBUG_OBJECT (demux, "segment configured from %" G_GINT64_FORMAT
" to %" G_GINT64_FORMAT ", position %" G_GINT64_FORMAT,
seeksegment.start, seeksegment.stop, seeksegment.last_stop);
seeksegment.start, seeksegment.stop, seeksegment.position);
/* make the sinkpad available for data passing since we might need
* it when doing the seek */
@ -595,7 +594,7 @@ gst_ffmpegdemux_perform_seek (GstFFMpegDemux * demux, GstEvent * event)
gst_pad_push_event (demux->sinkpad, gst_event_new_flush_stop ());
}
/* do the seek, segment.last_stop contains new position. */
/* do the seek, segment.position contains new position. */
res = gst_ffmpegdemux_do_seek (demux, &seeksegment);
/* and prepare to continue streaming */
@ -609,18 +608,6 @@ gst_ffmpegdemux_perform_seek (GstFFMpegDemux * demux, GstEvent * event)
if (demux->streams[n])
demux->streams[n]->last_flow = GST_FLOW_OK;
}
} else if (res && demux->running) {
/* we are running the current segment and doing a non-flushing seek,
* close the segment first based on the last_stop. */
GST_DEBUG_OBJECT (demux, "closing running segment %" G_GINT64_FORMAT
" to %" G_GINT64_FORMAT, demux->segment.start,
demux->segment.last_stop);
gst_ffmpegdemux_push_event (demux,
gst_event_new_new_segment (TRUE,
demux->segment.rate, demux->segment.format,
demux->segment.start, demux->segment.last_stop,
demux->segment.time));
}
/* if successfull seek, we update our real segment and push
* out the new segment. */
@ -630,18 +617,14 @@ gst_ffmpegdemux_perform_seek (GstFFMpegDemux * demux, GstEvent * event)
if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
gst_element_post_message (GST_ELEMENT (demux),
gst_message_new_segment_start (GST_OBJECT (demux),
demux->segment.format, demux->segment.last_stop));
demux->segment.format, demux->segment.position));
}
/* now send the newsegment */
/* now send the newsegment, FIXME, do this from the streaming thread */
GST_DEBUG_OBJECT (demux, "Sending newsegment from %" G_GINT64_FORMAT
" to %" G_GINT64_FORMAT, demux->segment.last_stop, demux->segment.stop);
" to %" G_GINT64_FORMAT, demux->segment.position, demux->segment.stop);
gst_ffmpegdemux_push_event (demux,
gst_event_new_new_segment (FALSE,
demux->segment.rate, demux->segment.format,
demux->segment.last_stop, demux->segment.stop,
demux->segment.time));
gst_ffmpegdemux_push_event (demux, gst_event_new_segment (&demux->segment));
}
/* Mark discont on all srcpads and remove eos */
@ -649,7 +632,6 @@ gst_ffmpegdemux_perform_seek (GstFFMpegDemux * demux, GstEvent * event)
/* and restart the task in case it got paused explicitely or by
* the FLUSH_START event we pushed out. */
demux->running = TRUE;
gst_pad_start_task (demux->sinkpad, (GstTaskFunction) gst_ffmpegdemux_loop,
demux->sinkpad);
@ -1208,7 +1190,7 @@ gst_ffmpegdemux_open (GstFFMpegDemux * demux)
GST_TIME_ARGS (demux->duration));
/* store duration in the segment as well */
gst_segment_set_duration (&demux->segment, GST_FORMAT_TIME, demux->duration);
demux->segment.duration = demux->duration;
GST_OBJECT_LOCK (demux);
demux->opened = TRUE;
@ -1222,16 +1204,12 @@ gst_ffmpegdemux_open (GstFFMpegDemux * demux)
gst_ffmpegdemux_perform_seek (demux, event);
gst_event_unref (event);
} else {
gst_ffmpegdemux_push_event (demux,
gst_event_new_new_segment (FALSE,
demux->segment.rate, demux->segment.format,
demux->segment.start, demux->segment.stop, demux->segment.time));
gst_ffmpegdemux_push_event (demux, gst_event_new_segment (&demux->segment));
}
while (cached_events) {
event = cached_events->data;
GST_INFO_OBJECT (demux, "pushing cached %s event: %" GST_PTR_FORMAT,
GST_EVENT_TYPE_NAME (event), event->structure);
GST_INFO_OBJECT (demux, "pushing cached event: %" GST_PTR_FORMAT, event);
gst_ffmpegdemux_push_event (demux, event);
cached_events = g_list_delete_link (cached_events, cached_events);
}
@ -1416,7 +1394,6 @@ gst_ffmpegdemux_loop (GstFFMpegDemux * demux)
outsize = pkt.size;
outbuf = gst_buffer_new_and_alloc (outsize);
gst_buffer_set_caps (outbuf, GST_PAD_CAPS (srcpad));
if ((ret = gst_ffmpegdemux_aggregated_flow (demux)) != GST_FLOW_OK)
goto no_buffer;
@ -1494,7 +1471,6 @@ pause:
{
GST_LOG_OBJECT (demux, "pausing task, reason %d (%s)", ret,
gst_flow_get_name (ret));
demux->running = FALSE;
if (demux->seekable)
gst_pad_pause_task (demux->sinkpad);
else {
@ -1588,8 +1564,7 @@ gst_ffmpegdemux_sink_event (GstPad * sinkpad, GstEvent * event)
demux = (GstFFMpegDemux *) (GST_PAD_PARENT (sinkpad));
ffpipe = &(demux->ffpipe);
GST_LOG_OBJECT (demux, "%s event: %" GST_PTR_FORMAT,
GST_EVENT_TYPE_NAME (event), event->structure);
GST_LOG_OBJECT (demux, "event: %" GST_PTR_FORMAT, event);
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_FLUSH_START:
@ -1621,7 +1596,6 @@ gst_ffmpegdemux_sink_event (GstPad * sinkpad, GstEvent * event)
ffpipe->srcresult = GST_FLOW_OK;
/* loop may have decided to end itself as a result of flush WRONG_STATE */
gst_task_start (demux->task);
demux->running = TRUE;
demux->flushing = FALSE;
GST_LOG_OBJECT (demux, "loop started");
GST_FFMPEG_PIPE_MUTEX_UNLOCK (ffpipe);
@ -1724,20 +1698,29 @@ ignore:
static gboolean
gst_ffmpegdemux_sink_activate (GstPad * sinkpad)
{
GstFFMpegDemux *demux;
gboolean res;
GstQuery *query;
gboolean pull_mode;
demux = (GstFFMpegDemux *) (gst_pad_get_parent (sinkpad));
query = gst_query_new_scheduling ();
res = FALSE;
if (gst_pad_check_pull_range (sinkpad))
res = gst_pad_activate_pull (sinkpad, TRUE);
else {
res = gst_pad_activate_push (sinkpad, TRUE);
if (!gst_pad_peer_query (sinkpad, query)) {
gst_query_unref (query);
goto activate_push;
}
gst_query_parse_scheduling (query, &pull_mode, NULL, NULL, NULL, NULL, NULL);
if (!pull_mode)
goto activate_push;
GST_DEBUG_OBJECT (sinkpad, "activating pull");
return gst_pad_activate_pull (sinkpad, TRUE);
activate_push:
{
GST_DEBUG_OBJECT (sinkpad, "activating push");
return gst_pad_activate_push (sinkpad, TRUE);
}
gst_object_unref (demux);
return res;
}
/* push mode:
@ -1761,7 +1744,6 @@ gst_ffmpegdemux_sink_activate_push (GstPad * sinkpad, gboolean active)
demux->ffpipe.eos = FALSE;
demux->ffpipe.srcresult = GST_FLOW_OK;
demux->ffpipe.needed = 0;
demux->running = TRUE;
demux->seekable = FALSE;
res = gst_task_start (demux->task);
} else {
@ -1780,7 +1762,6 @@ gst_ffmpegdemux_sink_activate_push (GstPad * sinkpad, gboolean active)
g_static_rec_mutex_lock (demux->task_lock);
g_static_rec_mutex_unlock (demux->task_lock);
res = gst_task_join (demux->task);
demux->running = FALSE;
demux->seekable = FALSE;
}
@ -1804,12 +1785,10 @@ gst_ffmpegdemux_sink_activate_pull (GstPad * sinkpad, gboolean active)
demux = (GstFFMpegDemux *) (gst_pad_get_parent (sinkpad));
if (active) {
demux->running = TRUE;
demux->seekable = TRUE;
res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_ffmpegdemux_loop,
demux);
} else {
demux->running = FALSE;
res = gst_pad_stop_task (sinkpad);
demux->seekable = FALSE;
}

View file

@ -97,7 +97,7 @@ static void gst_ffmpegenc_init (GstFFMpegEnc * ffmpegenc);
static void gst_ffmpegenc_finalize (GObject * object);
static gboolean gst_ffmpegenc_setcaps (GstPad * pad, GstCaps * caps);
static GstCaps *gst_ffmpegenc_getcaps (GstPad * pad);
static GstCaps *gst_ffmpegenc_getcaps (GstPad * pad, GstCaps * filter);
static GstFlowReturn gst_ffmpegenc_chain_video (GstPad * pad,
GstBuffer * buffer);
static GstFlowReturn gst_ffmpegenc_chain_audio (GstPad * pad,
@ -318,7 +318,7 @@ gst_ffmpegenc_get_possible_sizes (GstFFMpegEnc * ffmpegenc, GstPad * pad,
GstCaps *intersect = NULL;
guint i;
othercaps = gst_pad_peer_get_caps (ffmpegenc->srcpad);
othercaps = gst_pad_peer_get_caps (ffmpegenc->srcpad, NULL);
if (!othercaps)
return gst_caps_copy (caps);
@ -371,7 +371,7 @@ gst_ffmpegenc_get_possible_sizes (GstFFMpegEnc * ffmpegenc, GstPad * pad,
static GstCaps *
gst_ffmpegenc_getcaps (GstPad * pad)
gst_ffmpegenc_getcaps (GstPad * pad, GstCaps * filter)
{
GstFFMpegEnc *ffmpegenc = (GstFFMpegEnc *) GST_PAD_PARENT (pad);
GstFFMpegEncClass *oclass =
@ -526,9 +526,6 @@ gst_ffmpegenc_setcaps (GstPad * pad, GstCaps * caps)
if (ffmpegenc->opened) {
gst_ffmpeg_avcodec_close (ffmpegenc->context);
ffmpegenc->opened = FALSE;
/* fixed src caps;
* so clear src caps for proper (re-)negotiation */
gst_pad_set_caps (ffmpegenc->srcpad, NULL);
}
/* set defaults */
@ -829,7 +826,6 @@ gst_ffmpegenc_chain_video (GstPad * pad, GstBuffer * inbuf)
GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
} else
GST_WARNING_OBJECT (ffmpegenc, "codec did not provide keyframe info");
gst_buffer_set_caps (outbuf, GST_PAD_CAPS (ffmpegenc->srcpad));
gst_buffer_unref (inbuf);
@ -884,7 +880,6 @@ gst_ffmpegenc_encode_audio (GstFFMpegEnc * ffmpegenc, guint8 * audio_in,
GST_BUFFER_DURATION (outbuf) = duration;
if (discont)
GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
gst_buffer_set_caps (outbuf, GST_PAD_CAPS (ffmpegenc->srcpad));
GST_LOG_OBJECT (ffmpegenc, "pushing size %d, timestamp %" GST_TIME_FORMAT,
res, GST_TIME_ARGS (timestamp));
@ -1109,7 +1104,6 @@ gst_ffmpegenc_flush_buffers (GstFFMpegEnc * ffmpegenc, gboolean send)
if (!ffmpegenc->context->coded_frame->key_frame)
GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
gst_buffer_set_caps (outbuf, GST_PAD_CAPS (ffmpegenc->srcpad));
gst_buffer_unref (inbuf);

View file

@ -113,7 +113,7 @@ static void gst_ffmpegmux_finalize (GObject * object);
static gboolean gst_ffmpegmux_setcaps (GstPad * pad, GstCaps * caps);
static GstPad *gst_ffmpegmux_request_new_pad (GstElement * element,
GstPadTemplate * templ, const gchar * name);
GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
static GstFlowReturn gst_ffmpegmux_collected (GstCollectPads * pads,
gpointer user_data);
@ -404,7 +404,7 @@ gst_ffmpegmux_finalize (GObject * object)
static GstPad *
gst_ffmpegmux_request_new_pad (GstElement * element,
GstPadTemplate * templ, const gchar * name)
GstPadTemplate * templ, const gchar * name, const GstCaps * caps)
{
GstFFMpegMux *ffmpegmux = (GstFFMpegMux *) element;
GstElementClass *klass = GST_ELEMENT_GET_CLASS (element);

View file

@ -166,7 +166,6 @@ gst_ffmpegdata_write (URLContext * h, const unsigned char *buf, int size)
/* create buffer and push data further */
outbuf = gst_buffer_new_and_alloc (size);
gst_buffer_set_caps (outbuf, GST_PAD_CAPS (info->pad));
gst_buffer_fill (outbuf, 0, buf, size);
@ -181,7 +180,7 @@ static int64_t
gst_ffmpegdata_seek (URLContext * h, int64_t pos, int whence)
{
GstProtocolInfo *info;
guint64 newpos = 0;
guint64 newpos = 0, oldpos;
GST_DEBUG ("Seeking to %" G_GINT64_FORMAT ", whence=%d",
(gint64) pos, whence);
@ -227,26 +226,33 @@ gst_ffmpegdata_seek (URLContext * h, int64_t pos, int whence)
break;
case URL_WRONLY:
{
GstSegment segment;
oldpos = info->offset;
/* srcpad */
switch (whence) {
case SEEK_SET:
{
info->offset = (guint64) pos;
gst_pad_push_event (info->pad, gst_event_new_new_segment
(TRUE, 1.0, GST_FORMAT_BYTES, info->offset,
GST_CLOCK_TIME_NONE, info->offset));
break;
}
case SEEK_CUR:
info->offset += pos;
gst_pad_push_event (info->pad, gst_event_new_new_segment
(TRUE, 1.0, GST_FORMAT_BYTES, info->offset,
GST_CLOCK_TIME_NONE, info->offset));
break;
default:
break;
}
newpos = info->offset;
}
if (newpos != oldpos) {
gst_segment_init (&segment, GST_FORMAT_BYTES);
segment.start = newpos;
segment.time = newpos;
gst_pad_push_event (info->pad, gst_event_new_segment (&segment));
}
break;
}
default:
g_assert (0);
break;

View file

@ -430,15 +430,13 @@ gst_ffmpeg_avpicture_fill (AVPicture * picture,
* for any processing. */
GstBuffer *
new_aligned_buffer (gint size, GstCaps * caps)
new_aligned_buffer (gint size)
{
GstBuffer *buf;
buf = gst_buffer_new ();
gst_buffer_take_memory (buf,
gst_memory_new_wrapped (0, av_malloc (size), av_free, size, 0, size));
if (caps)
gst_buffer_set_caps (buf, caps);
return buf;
}

View file

@ -88,6 +88,6 @@ gint
av_smp_format_depth(enum SampleFormat smp_fmt);
GstBuffer *
new_aligned_buffer (gint size, GstCaps * caps);
new_aligned_buffer (gint size);
#endif /* __GST_FFMPEG_UTILS_H__ */

View file

@ -172,7 +172,7 @@ static void gst_ffmpegscale_get_property (GObject * object, guint prop_id,
static gboolean gst_ffmpegscale_stop (GstBaseTransform * trans);
static GstCaps *gst_ffmpegscale_transform_caps (GstBaseTransform * trans,
GstPadDirection direction, GstCaps * caps);
GstPadDirection direction, GstCaps * caps, GstCaps * filter);
static void gst_ffmpegscale_fixate_caps (GstBaseTransform * trans,
GstPadDirection direction, GstCaps * caps, GstCaps * othercaps);
static gboolean gst_ffmpegscale_get_unit_size (GstBaseTransform * trans,
@ -307,7 +307,7 @@ gst_ffmpegscale_caps_remove_format_info (GstCaps * caps)
static GstCaps *
gst_ffmpegscale_transform_caps (GstBaseTransform * trans,
GstPadDirection direction, GstCaps * caps)
GstPadDirection direction, GstCaps * caps, GstCaps * filter)
{
GstCaps *ret;
GstStructure *structure;