ext/libvisual/visual.c: Small cleanups.

Original commit message from CVS:
* ext/libvisual/visual.c: (gst_visual_get_type),
(gst_visual_src_setcaps), (gst_vis_src_negotiate),
(gst_visual_chain):
Small cleanups.
* ext/theora/gsttheoradec.h:
* ext/theora/theoradec.c: (gst_theora_dec_init),
(gst_theora_dec_reset), (_theora_granule_time),
(theora_dec_src_convert), (theora_dec_sink_convert),
(theora_dec_src_query), (theora_dec_src_event),
(theora_dec_sink_event), (theora_handle_comment_packet),
(theora_handle_header_packet), (theora_dec_push),
(theora_handle_data_packet), (theora_dec_chain),
(theora_dec_change_state):
Add simple QoS.
This commit is contained in:
Wim Taymans 2006-03-09 17:58:00 +00:00
parent ba3d2db624
commit 808d7edd02
4 changed files with 201 additions and 87 deletions

View file

@ -1,3 +1,21 @@
2006-03-09 Wim Taymans <wim@fluendo.com>
* ext/libvisual/visual.c: (gst_visual_get_type),
(gst_visual_src_setcaps), (gst_vis_src_negotiate),
(gst_visual_chain):
Small cleanups.
* ext/theora/gsttheoradec.h:
* ext/theora/theoradec.c: (gst_theora_dec_init),
(gst_theora_dec_reset), (_theora_granule_time),
(theora_dec_src_convert), (theora_dec_sink_convert),
(theora_dec_src_query), (theora_dec_src_event),
(theora_dec_sink_event), (theora_handle_comment_packet),
(theora_handle_header_packet), (theora_dec_push),
(theora_handle_data_packet), (theora_dec_chain),
(theora_dec_change_state):
Add simple QoS.
2006-03-09 Wim Taymans <wim@fluendo.com>
* ext/gnomevfs/gstgnomevfssrc.c: (audiocast_init),

View file

@ -134,7 +134,7 @@ gst_visual_get_type (void)
{
static GType type = 0;
if (!type) {
if (G_UNLIKELY (type == 0)) {
static const GTypeInfo info = {
sizeof (GstVisualClass),
NULL,
@ -337,8 +337,10 @@ gst_visual_src_setcaps (GstPad * pad, GstCaps * caps)
gst_object_unref (visual);
return TRUE;
/* ERRORS */
error:
{
GST_DEBUG_OBJECT (visual, "error parsing caps");
gst_object_unref (visual);
return FALSE;
}
@ -397,6 +399,7 @@ gst_vis_src_negotiate (GstVisual * visual)
return TRUE;
/* ERRORS */
no_format:
{
GST_ELEMENT_ERROR (visual, STREAM, FORMAT, (NULL),
@ -535,7 +538,7 @@ gst_visual_chain (GstPad * pad, GstBuffer * buffer)
if (visual->next_ts != -1) {
GST_OBJECT_LOCK (visual);
/* check for QoS, don't compute buffers that are known to be latea */
/* check for QoS, don't compute buffers that are known to be late */
need_skip = visual->earliest_time != -1 &&
visual->next_ts <= visual->earliest_time;
GST_OBJECT_UNLOCK (visual);

View file

@ -53,9 +53,11 @@ struct _GstTheoraDec
{
GstElement element;
/* Pads */
GstPad *sinkpad;
GstPad *srcpad;
/* theora decoder state */
theora_state state;
theora_info info;
theora_comment comment;
@ -65,7 +67,7 @@ struct _GstTheoraDec
guint64 granule_shift;
GstClockTime last_timestamp;
guint64 frame_nr;
guint64 frame_nr; /* unused */
gboolean need_keyframe;
gint width, height;
gint offset_x, offset_y;
@ -74,10 +76,12 @@ struct _GstTheoraDec
GList *queued;
gdouble segment_rate;
gint64 segment_start;
gint64 segment_stop;
gint64 segment_time;
/* segment info */ /* with STREAM_LOCK */
GstSegment segment;
/* QoS stuff */ /* with LOCK*/
gboolean proportion;
GstClockTime earliest_time;
};
struct _GstTheoraDecClass

View file

@ -103,7 +103,6 @@ static gboolean theora_dec_sink_convert (GstPad * pad,
GstFormat src_format, gint64 src_value,
GstFormat * dest_format, gint64 * dest_value);
static gboolean theora_dec_sink_query (GstPad * pad, GstQuery * query);
static GstCaps *theora_dec_src_getcaps (GstPad * pad);
#if 0
static const GstFormat *theora_get_formats (GstPad * pad);
@ -157,10 +156,10 @@ gst_theora_dec_init (GstTheoraDec * dec, GstTheoraDecClass * g_class)
dec->srcpad =
gst_pad_new_from_static_template (&theora_dec_src_factory, "src");
gst_pad_set_getcaps_function (dec->srcpad, theora_dec_src_getcaps);
gst_pad_set_event_function (dec->srcpad, theora_dec_src_event);
gst_pad_set_query_type_function (dec->srcpad, theora_get_query_types);
gst_pad_set_query_function (dec->srcpad, theora_dec_src_query);
gst_pad_use_fixed_caps (dec->srcpad);
gst_element_add_pad (GST_ELEMENT (dec), dec->srcpad);
@ -168,6 +167,20 @@ gst_theora_dec_init (GstTheoraDec * dec, GstTheoraDecClass * g_class)
dec->queued = NULL;
}
static void
gst_theora_dec_reset (GstTheoraDec * dec)
{
dec->need_keyframe = TRUE;
dec->last_timestamp = -1;
dec->granulepos = -1;
gst_segment_init (&dec->segment, GST_FORMAT_TIME);
GST_OBJECT_LOCK (dec);
dec->proportion = 1.0;
dec->earliest_time = -1;
GST_OBJECT_UNLOCK (dec);
}
/* FIXME: copy from libtheora, theora should somehow make this available for seeking */
static int
_theora_ilog (unsigned int v)
@ -207,9 +220,11 @@ _theora_granule_time (GstTheoraDec * dec, gint64 granulepos)
{
gint framecount;
/* invalid granule results in invalid time */
if (granulepos == -1)
return -1;
/* get framecount */
framecount = _theora_granule_frame (dec, granulepos);
return gst_util_uint64_scale_int (framecount * GST_SECOND,
@ -283,17 +298,17 @@ theora_dec_src_convert (GstPad * pad,
GstTheoraDec *dec;
guint64 scale = 1;
dec = GST_THEORA_DEC (GST_PAD_PARENT (pad));
/* we need the info part before we can done something */
if (!dec->have_header)
return FALSE;
if (src_format == *dest_format) {
*dest_value = src_value;
return TRUE;
}
dec = GST_THEORA_DEC (gst_pad_get_parent (pad));
/* we need the info part before we can done something */
if (!dec->have_header)
goto no_header;
switch (src_format) {
case GST_FORMAT_BYTES:
switch (*dest_format) {
@ -326,8 +341,8 @@ theora_dec_src_convert (GstPad * pad,
GST_SECOND * dec->info.fps_denominator, dec->info.fps_numerator);
break;
case GST_FORMAT_BYTES:
*dest_value =
src_value * 3 * (dec->info.width * dec->info.height) / 2;
*dest_value = gst_util_uint64_scale_int (src_value,
3 * dec->info.width * dec->info.height, 2);
break;
default:
res = FALSE;
@ -336,8 +351,17 @@ theora_dec_src_convert (GstPad * pad,
default:
res = FALSE;
}
done:
gst_object_unref (dec);
return res;
/* ERRORS */
no_header:
{
GST_DEBUG_OBJECT (dec, "no header yet, cannot convert");
res = FALSE;
goto done;
}
}
static gboolean
@ -348,20 +372,19 @@ theora_dec_sink_convert (GstPad * pad,
gboolean res = TRUE;
GstTheoraDec *dec;
dec = GST_THEORA_DEC (GST_PAD_PARENT (pad));
/* we need the info part before we can done something */
if (!dec->have_header)
return FALSE;
if (src_format == *dest_format) {
*dest_value = src_value;
return TRUE;
}
dec = GST_THEORA_DEC (gst_pad_get_parent (pad));
/* we need the info part before we can done something */
if (!dec->have_header)
goto no_header;
switch (src_format) {
case GST_FORMAT_DEFAULT:
{
switch (*dest_format) {
case GST_FORMAT_TIME:
*dest_value = _theora_granule_time (dec, src_value);
@ -370,9 +393,7 @@ theora_dec_sink_convert (GstPad * pad,
res = FALSE;
}
break;
}
case GST_FORMAT_TIME:
{
switch (*dest_format) {
case GST_FORMAT_DEFAULT:
{
@ -394,20 +415,31 @@ theora_dec_sink_convert (GstPad * pad,
break;
}
break;
}
default:
res = FALSE;
}
done:
gst_object_unref (dec);
return res;
/* ERRORS */
no_header:
{
GST_DEBUG_OBJECT (dec, "no header yet, cannot convert");
res = FALSE;
goto done;
}
}
static gboolean
theora_dec_src_query (GstPad * pad, GstQuery * query)
{
GstTheoraDec *dec = GST_THEORA_DEC (GST_PAD_PARENT (pad));
GstTheoraDec *dec;
gboolean res = FALSE;
dec = GST_THEORA_DEC (gst_pad_get_parent (pad));
switch (GST_QUERY_TYPE (query)) {
case GST_QUERY_POSITION:
{
@ -432,7 +464,7 @@ theora_dec_src_query (GstPad * pad, GstQuery * query)
granulepos, &my_format, &time)))
goto error;
time = (time - dec->segment_start) + dec->segment_time;
time = (time - dec->segment.start) + dec->segment.time;
GST_LOG_OBJECT (dec,
"query %p: our time: %" GST_TIME_FORMAT, query, GST_TIME_ARGS (time));
@ -471,11 +503,17 @@ theora_dec_src_query (GstPad * pad, GstQuery * query)
res = gst_pad_query_default (pad, query);
break;
}
done:
gst_object_unref (dec);
return res;
/* ERRORS */
error:
GST_DEBUG ("query failed");
return res;
{
GST_DEBUG_OBJECT (dec, "query failed");
goto done;
}
}
static gboolean
@ -513,10 +551,11 @@ theora_dec_src_event (GstPad * pad, GstEvent * event)
gboolean res = TRUE;
GstTheoraDec *dec;
dec = GST_THEORA_DEC (GST_PAD_PARENT (pad));
dec = GST_THEORA_DEC (gst_pad_get_parent (pad));
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_SEEK:{
case GST_EVENT_SEEK:
{
GstFormat format, tformat;
gdouble rate;
GstEvent *real_seek;
@ -536,9 +575,9 @@ theora_dec_src_event (GstPad * pad, GstEvent * event)
*/
tformat = GST_FORMAT_TIME;
if (!(res = theora_dec_src_convert (pad, format, cur, &tformat, &tcur)))
goto error;
goto convert_error;
if (!(res = theora_dec_src_convert (pad, format, stop, &tformat, &tstop)))
goto error;
goto convert_error;
/* then seek with time on the peer */
real_seek = gst_event_new_seek (rate, GST_FORMAT_TIME,
@ -549,30 +588,41 @@ theora_dec_src_event (GstPad * pad, GstEvent * event)
gst_event_unref (event);
break;
}
case GST_EVENT_QOS:
{
gdouble proportion;
GstClockTimeDiff diff;
GstClockTime timestamp;
gst_event_parse_qos (event, &proportion, &diff, &timestamp);
/* we cannot randomly skip frame decoding since we don't have
* B frames. we can however use the timestamp and diff to not
* push late frames. */
GST_OBJECT_LOCK (dec);
dec->proportion = proportion;
dec->earliest_time = timestamp + diff;
GST_OBJECT_UNLOCK (dec);
res = gst_pad_event_default (pad, event);
break;
}
default:
res = gst_pad_event_default (pad, event);
break;
}
done:
gst_object_unref (dec);
return res;
error:
gst_event_unref (event);
return res;
}
static GstCaps *
theora_dec_src_getcaps (GstPad * pad)
{
GstCaps *caps;
GST_OBJECT_LOCK (pad);
if (!(caps = GST_PAD_CAPS (pad)))
caps = (GstCaps *) gst_pad_get_pad_template_caps (pad);
caps = gst_caps_ref (caps);
GST_OBJECT_UNLOCK (pad);
return caps;
/* ERRORS */
convert_error:
{
GST_DEBUG_OBJECT (dec, "could not convert format");
gst_event_unref (event);
goto done;
}
}
static gboolean
@ -585,17 +635,25 @@ theora_dec_sink_event (GstPad * pad, GstEvent * event)
GST_LOG_OBJECT (dec, "handling event");
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_FLUSH_START:
ret = gst_pad_push_event (dec->srcpad, event);
break;
case GST_EVENT_FLUSH_STOP:
gst_theora_dec_reset (dec);
ret = gst_pad_push_event (dec->srcpad, event);
break;
case GST_EVENT_EOS:
ret = gst_pad_push_event (dec->srcpad, event);
break;
case GST_EVENT_NEWSEGMENT:
{
gboolean update;
GstFormat format;
gdouble rate;
gint64 start, stop, time;
gst_event_parse_new_segment (event, NULL, &rate, &format, &start, &stop,
&time);
gst_event_parse_new_segment (event, &update, &rate, &format, &start,
&stop, &time);
/* we need TIME and a positive rate */
if (format != GST_FORMAT_TIME)
@ -604,15 +662,11 @@ theora_dec_sink_event (GstPad * pad, GstEvent * event)
if (rate <= 0.0)
goto newseg_wrong_rate;
/* now copy over the values */
dec->segment_rate = rate;
dec->segment_start = start;
dec->segment_stop = stop;
dec->segment_time = time;
/* now configure the values */
gst_segment_set_newsegment (&dec->segment, update,
rate, format, start, stop, time);
dec->need_keyframe = TRUE;
dec->granulepos = -1;
dec->last_timestamp = -1;
/* and forward */
ret = gst_pad_push_event (dec->srcpad, event);
break;
}
@ -628,12 +682,12 @@ done:
/* ERRORS */
newseg_wrong_format:
{
GST_DEBUG ("received non TIME newsegment");
GST_DEBUG_OBJECT (dec, "received non TIME newsegment");
goto done;
}
newseg_wrong_rate:
{
GST_DEBUG ("negative rates not supported yet");
GST_DEBUG_OBJECT (dec, "negative rates not supported yet");
goto done;
}
}
@ -649,7 +703,7 @@ theora_handle_comment_packet (GstTheoraDec * dec, ogg_packet * packet)
GstBuffer *buf;
GstTagList *list;
GST_DEBUG ("parsing comment packet");
GST_DEBUG_OBJECT (dec, "parsing comment packet");
buf = gst_buffer_new_and_alloc (packet->bytes);
memcpy (GST_BUFFER_DATA (buf), packet->packet, packet->bytes);
@ -757,7 +811,7 @@ theora_handle_header_packet (GstTheoraDec * dec, ogg_packet * packet)
{
GstFlowReturn res;
GST_DEBUG ("parsing header packet");
GST_DEBUG_OBJECT (dec, "parsing header packet");
if (theora_decode_header (&dec->info, &dec->comment, packet))
goto header_read_error;
@ -788,6 +842,7 @@ header_read_error:
}
}
/* FIXME, this needs to be moved to the demuxer */
static GstFlowReturn
theora_dec_push (GstTheoraDec * dec, GstBuffer * buf)
{
@ -811,12 +866,12 @@ theora_dec_push (GstTheoraDec * dec, GstBuffer * buf)
GstBuffer *buffer = GST_BUFFER (walk->data);
GstClockTime time;
time = outtime - ((size * GST_SECOND * dec->info.fps_denominator)
/ dec->info.fps_numerator);
time = outtime - gst_util_uint64_scale_int (size * GST_SECOND,
dec->info.fps_denominator, dec->info.fps_numerator);
GST_DEBUG_OBJECT (dec, "patch buffer %lld %lld", size, time);
GST_BUFFER_TIMESTAMP (buffer) = time;
/* ignore the result */
/* ignore the result.. */
gst_pad_push (dec->srcpad, buffer);
size--;
}
@ -856,16 +911,33 @@ theora_handle_data_packet (GstTheoraDec * dec, ogg_packet * packet,
goto dropping;
}
/* this does the decoding */
if (theora_decode_packetin (&dec->state, packet))
goto could_not_read;
if (theora_decode_YUVout (&dec->state, &yuv) < 0)
goto decode_error;
if (outtime != -1) {
gboolean need_skip;
GST_OBJECT_LOCK (dec);
/* check for QoS, don't perform the last steps of getting and
* pushing the buffers that are known to be late. */
/* FIXME, we can also entirely skip decoding if the next valid buffer is
* known to be after a keyframe (using the granule_shift) */
need_skip = dec->earliest_time != -1 && outtime <= dec->earliest_time;
GST_OBJECT_UNLOCK (dec);
if (need_skip)
goto dropping_qos;
}
/* this does postprocessing and set up the decoded frame
* pointers in our yuv variable */
if (theora_decode_YUVout (&dec->state, &yuv) < 0)
goto no_yuv;
if ((yuv.y_width != dec->info.width) || (yuv.y_height != dec->info.height))
goto wrong_dimensions;
width = dec->width;
height = dec->height;
cwidth = width / 2;
@ -898,6 +970,7 @@ theora_handle_data_packet (GstTheoraDec * dec, ogg_packet * packet,
guchar *dest_y, *src_y;
guchar *dest_u, *src_u;
guchar *dest_v, *src_v;
guint offset;
dest_y = GST_BUFFER_DATA (out);
dest_u = dest_y + stride_y * height;
@ -912,8 +985,10 @@ theora_handle_data_packet (GstTheoraDec * dec, ogg_packet * packet,
src_y += yuv.y_stride;
}
src_u = yuv.u + dec->offset_x / 2 + dec->offset_y / 2 * yuv.uv_stride;
src_v = yuv.v + dec->offset_x / 2 + dec->offset_y / 2 * yuv.uv_stride;
offset = dec->offset_x / 2 + dec->offset_y / 2 * yuv.uv_stride;
src_u = yuv.u + offset;
src_v = yuv.v + offset;
for (i = 0; i < cheight; i++) {
memcpy (dest_u, src_u, cwidth);
@ -926,6 +1001,7 @@ theora_handle_data_packet (GstTheoraDec * dec, ogg_packet * packet,
}
}
/* FIXME, frame_nr not correct */
GST_BUFFER_OFFSET (out) = dec->frame_nr;
dec->frame_nr++;
GST_BUFFER_OFFSET_END (out) = dec->frame_nr;
@ -950,13 +1026,19 @@ dropping:
GST_WARNING_OBJECT (dec, "dropping frame because we need a keyframe");
return GST_FLOW_OK;
}
could_not_read:
dropping_qos:
{
GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
(NULL), ("theora decoder did not read data packet"));
return GST_FLOW_ERROR;
dec->frame_nr++;
GST_WARNING_OBJECT (dec, "dropping frame because of QoS");
return GST_FLOW_OK;
}
decode_error:
{
GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
(NULL), ("theora decoder did not decode data packet"));
return GST_FLOW_ERROR;
}
no_yuv:
{
GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
(NULL), ("couldn't read out YUV image"));
@ -964,12 +1046,14 @@ decode_error:
}
wrong_dimensions:
{
GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, FORMAT,
(NULL), ("dimensions of image do not match header"));
return GST_FLOW_ERROR;
}
no_buffer:
{
GST_DEBUG_OBJECT (dec, "could not get buffer, reason: %s",
gst_flow_get_name (result));
return result;
}
}
@ -983,12 +1067,20 @@ theora_dec_chain (GstPad * pad, GstBuffer * buf)
dec = GST_THEORA_DEC (gst_pad_get_parent (pad));
/* resync on DISCONT */
if (G_UNLIKELY (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT))) {
dec->need_keyframe = TRUE;
dec->last_timestamp = -1;
dec->granulepos = -1;
}
/* make ogg_packet out of the buffer */
packet.packet = GST_BUFFER_DATA (buf);
packet.bytes = GST_BUFFER_SIZE (buf);
packet.granulepos = GST_BUFFER_OFFSET_END (buf);
packet.packetno = 0; /* we don't really care */
packet.b_o_s = dec->have_header ? 0 : 1;
/* EOS does not matter for the decoder */
packet.e_o_s = 0;
if (dec->have_header) {
@ -1017,6 +1109,7 @@ theora_dec_chain (GstPad * pad, GstBuffer * buf)
}
done:
/* interpollate granule pos */
dec->granulepos = _inc_granulepos (dec, dec->granulepos);
gst_object_unref (dec);
@ -1040,9 +1133,7 @@ theora_dec_change_state (GstElement * element, GstStateChange transition)
theora_info_init (&dec->info);
theora_comment_init (&dec->comment);
dec->have_header = FALSE;
dec->need_keyframe = TRUE;
dec->last_timestamp = -1;
dec->granulepos = -1;
gst_theora_dec_reset (dec);
break;
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
break;
@ -1059,8 +1150,6 @@ theora_dec_change_state (GstElement * element, GstStateChange transition)
theora_clear (&dec->state);
theora_comment_clear (&dec->comment);
theora_info_clear (&dec->info);
dec->have_header = FALSE;
dec->granulepos = -1;
break;
case GST_STATE_CHANGE_READY_TO_NULL:
break;