From 5bd9d5cd173a93631136a66eeafbbccef54c3d69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 30 Sep 2008 16:22:04 +0000 Subject: [PATCH] gst/flacparse/gstbaseparse.c: Approximate the average bitrate, duration and size if possible and add a default conver... Original commit message from CVS: * gst/flacparse/gstbaseparse.c: (gst_base_parse_class_init), (gst_base_parse_init), (gst_base_parse_push_buffer), (gst_base_parse_update_upstream_durations), (gst_base_parse_chain), (gst_base_parse_loop), (gst_base_parse_activate), (gst_base_parse_convert), (gst_base_parse_query): Approximate the average bitrate, duration and size if possible and add a default conversion function which uses this for time<->byte conversions. * gst/flacparse/gstflacparse.c: (gst_flac_parse_get_frame_size): Fix parsing if upstream gives -1 as duration. --- ChangeLog | 14 ++ gst/flacparse/gstbaseparse.c | 255 +++++++++++++++++++++++++---------- gst/flacparse/gstflacparse.c | 13 +- 3 files changed, 205 insertions(+), 77 deletions(-) diff --git a/ChangeLog b/ChangeLog index d13eb08f57..2322dc5c1a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +2008-09-30 Sebastian Dröge + + * gst/flacparse/gstbaseparse.c: (gst_base_parse_class_init), + (gst_base_parse_init), (gst_base_parse_push_buffer), + (gst_base_parse_update_upstream_durations), (gst_base_parse_chain), + (gst_base_parse_loop), (gst_base_parse_activate), + (gst_base_parse_convert), (gst_base_parse_query): + Approximate the average bitrate, duration and size if possible + and add a default conversion function which uses this for + time<->byte conversions. + + * gst/flacparse/gstflacparse.c: (gst_flac_parse_get_frame_size): + Fix parsing if upstream gives -1 as duration. + 2008-09-30 Wim Taymans * gst/rtpmanager/rtpsession.c: (on_new_ssrc), (on_ssrc_collision), diff --git a/gst/flacparse/gstbaseparse.c b/gst/flacparse/gstbaseparse.c index dd990ab341..2886cded3c 100644 --- a/gst/flacparse/gstbaseparse.c +++ b/gst/flacparse/gstbaseparse.c @@ -163,7 +163,6 @@ * - In push mode provide a queue of adapter-"queued" buffers for upstream * buffer metadata * - Handle upstream timestamps - * - Bitrate tracking => inaccurate seeking, inaccurate duration calculation * - Let subclass decide if frames outside the segment should be dropped */ @@ -211,8 +210,12 @@ struct _GstBaseParsePrivate GstAdapter *adapter; - guint64 bitrate_sum; + guint64 upstream_size; + guint64 upstream_duration; + guint64 avg_bitrate; + guint64 estimated_size; + guint64 estimated_duration; }; struct _GstBaseParseClassPrivate @@ -271,12 +274,6 @@ static const GstQueryType *gst_base_parse_get_querytypes (GstPad * pad); static GstFlowReturn gst_base_parse_chain (GstPad * pad, GstBuffer * buffer); static void gst_base_parse_loop (GstPad * pad); -static gboolean gst_base_parse_check_frame (GstBaseParse * parse, - GstBuffer * buffer, guint * framesize, gint * skipsize); - -static gboolean gst_base_parse_parse_frame (GstBaseParse * parse, - GstBuffer * buffer); - static gboolean gst_base_parse_sink_eventfunc (GstBaseParse * parse, GstEvent * event); @@ -285,6 +282,10 @@ static gboolean gst_base_parse_src_eventfunc (GstBaseParse * parse, static gboolean gst_base_parse_is_seekable (GstBaseParse * parse); +static gboolean +gst_base_parse_convert (GstBaseParse * parse, GstFormat src_format, + gint64 src_value, GstFormat dest_format, gint64 * dest_value); + static void gst_base_parse_drain (GstBaseParse * parse); static void @@ -351,11 +352,12 @@ gst_base_parse_class_init (GstBaseParseClass * klass) gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_base_parse_finalize); /* Default handlers */ - klass->check_valid_frame = gst_base_parse_check_frame; - klass->parse_frame = gst_base_parse_parse_frame; + klass->check_valid_frame = NULL; + klass->parse_frame = NULL; klass->event = gst_base_parse_sink_eventfunc; klass->src_event = gst_base_parse_src_eventfunc; klass->is_seekable = gst_base_parse_is_seekable; + klass->convert = gst_base_parse_convert; } static void @@ -411,50 +413,14 @@ gst_base_parse_init (GstBaseParse * parse, GstBaseParseClass * bclass) parse->priv->discont = FALSE; parse->priv->flushing = FALSE; parse->priv->offset = 0; + parse->priv->avg_bitrate = 0; + parse->priv->upstream_duration = -1; + parse->priv->upstream_size = -1; + parse->priv->estimated_size = -1; + parse->priv->estimated_duration = -1; GST_DEBUG_OBJECT (parse, "init ok"); } - - -/** - * gst_base_parse_check_frame: - * @parse: #GstBaseParse. - * @buffer: GstBuffer. - * @framesize: This will be set to tell the found frame size in bytes. - * @skipsize: Output parameter that tells how much data needs to be skipped - * in order to find the following frame header. - * - * Default callback for check_valid_frame. - * - * Returns: Always TRUE. - */ -static gboolean -gst_base_parse_check_frame (GstBaseParse * parse, - GstBuffer * buffer, guint * framesize, gint * skipsize) -{ - *framesize = GST_BUFFER_SIZE (buffer); - *skipsize = 0; - return TRUE; -} - - -/** - * gst_base_parse_parse_frame: - * @parse: #GstBaseParse. - * @buffer: #GstBuffer. - * - * Default callback for parse_frame. - */ -static gboolean -gst_base_parse_parse_frame (GstBaseParse * parse, GstBuffer * buffer) -{ - /* FIXME: Could we even _try_ to do something clever here? */ - GST_BUFFER_TIMESTAMP (buffer) = GST_CLOCK_TIME_NONE; - GST_BUFFER_DURATION (buffer) = GST_CLOCK_TIME_NONE; - return TRUE; -} - - /** * gst_base_parse_bytepos_to_time: * @parse: #GstBaseParse. @@ -797,6 +763,42 @@ gst_base_parse_push_buffer (GstBaseParse * parse, GstBuffer * buffer) if (ret == GST_FLOW_OK && last_stop != GST_CLOCK_TIME_NONE) gst_segment_set_last_stop (&parse->segment, GST_FORMAT_TIME, last_stop); + if (parse->priv->upstream_size && (!parse->priv->upstream_duration + && parse->priv->duration == -1)) { + parse->priv->avg_bitrate = + gst_util_uint64_scale (parse->priv->offset, 8, + parse->segment.last_stop); + GST_DEBUG_OBJECT (parse, "Approximate average bitrate: %" G_GUINT64_FORMAT, + parse->priv->avg_bitrate); + parse->priv->estimated_duration = + gst_util_uint64_scale (parse->priv->avg_bitrate, + parse->priv->upstream_size, 8); + GST_DEBUG_OBJECT (parse, "Estimated duration: %" GST_TIME_FORMAT, + parse->priv->estimated_duration); + } else if (!parse->priv->upstream_size && parse->priv->upstream_duration) { + parse->priv->avg_bitrate = + gst_util_uint64_scale (parse->priv->offset, 8, + parse->segment.last_stop); + GST_DEBUG_OBJECT (parse, "Approximate average bitrate: %" G_GUINT64_FORMAT, + parse->priv->avg_bitrate); + parse->priv->estimated_size = + gst_util_uint64_scale (parse->priv->upstream_duration, + parse->priv->avg_bitrate, 8); + GST_DEBUG_OBJECT (parse, "Estimated size: %" G_GUINT64_FORMAT, + parse->priv->estimated_size); + } else if (!parse->priv->upstream_size && parse->priv->duration != -1) { + parse->priv->avg_bitrate = + gst_util_uint64_scale (parse->priv->offset, 8, + parse->segment.last_stop); + GST_DEBUG_OBJECT (parse, "Approximate average bitrate: %" G_GUINT64_FORMAT, + parse->priv->avg_bitrate); + parse->priv->estimated_size = + gst_util_uint64_scale (parse->priv->duration, parse->priv->avg_bitrate, + 8); + GST_DEBUG_OBJECT (parse, "Estimated size: %" G_GUINT64_FORMAT, + parse->priv->estimated_size); + } + return ret; } @@ -870,6 +872,58 @@ gst_base_parse_drain (GstBaseParse * parse) } } +static void +gst_base_parse_update_upstream_durations (GstBaseParse * parse) +{ + /* Get/update upstream size and duration if possible */ + if (parse->priv->upstream_duration == -1 || + (parse->priv->upstream_duration > 0 && + parse->segment.last_stop > parse->priv->upstream_duration)) { + GstFormat fmt = GST_FORMAT_TIME; + gint64 duration; + + if (gst_pad_query_peer_duration (parse->sinkpad, &fmt, &duration) && + fmt == GST_FORMAT_TIME && duration != -1) { + parse->priv->upstream_duration = duration; + GST_DEBUG_OBJECT (parse, "Upstream duration: %" GST_TIME_FORMAT, + parse->priv->upstream_duration); + } else { + GST_DEBUG_OBJECT (parse, "Failed to get upstream duration"); + parse->priv->upstream_duration = 0; + } + } + + if (parse->priv->upstream_size == -1 || + (parse->priv->upstream_size > 0 + && parse->priv->offset > parse->priv->upstream_size)) { + GstFormat fmt = GST_FORMAT_BYTES; + gint64 duration; + + if (gst_pad_query_peer_duration (parse->sinkpad, &fmt, &duration) && + fmt == GST_FORMAT_BYTES && duration != -1) { + parse->priv->upstream_size = duration; + GST_DEBUG_OBJECT (parse, "Upstream size: %" G_GUINT64_FORMAT " bytes", + parse->priv->upstream_size); + } else { + GST_DEBUG_OBJECT (parse, "Failed to get upstream size in bytes"); + parse->priv->upstream_size = 0; + } + } + + if (parse->priv->upstream_size && parse->priv->upstream_duration) { + parse->priv->avg_bitrate = + gst_util_uint64_scale (parse->priv->upstream_duration, 8, + parse->priv->upstream_size); + GST_DEBUG_OBJECT (parse, "Approximate average bitrate: %" G_GUINT64_FORMAT, + parse->priv->avg_bitrate); + } else if (parse->priv->upstream_size && parse->priv->duration != -1) { + parse->priv->avg_bitrate = + gst_util_uint64_scale (parse->priv->duration, 8, + parse->priv->upstream_size); + GST_DEBUG_OBJECT (parse, "Approximate average bitrate: %" G_GUINT64_FORMAT, + parse->priv->avg_bitrate); + } +} /** * gst_base_parse_chain: @@ -901,6 +955,8 @@ gst_base_parse_chain (GstPad * pad, GstBuffer * buffer) parse->priv->offset = parse->priv->pending_offset; } + gst_base_parse_update_upstream_durations (parse); + if (buffer) { GST_LOG_OBJECT (parse, "buffer size: %d, offset = %lld", GST_BUFFER_SIZE (buffer), GST_BUFFER_OFFSET (buffer)); @@ -1091,6 +1147,8 @@ gst_base_parse_loop (GstPad * pad) parse = GST_BASE_PARSE (gst_pad_get_parent (pad)); klass = GST_BASE_PARSE_GET_CLASS (parse); + gst_base_parse_update_upstream_durations (parse); + /* TODO: Check if we reach segment stop limit */ while (TRUE) { @@ -1237,6 +1295,11 @@ gst_base_parse_activate (GstBaseParse * parse, gboolean active) parse->priv->discont = FALSE; parse->priv->flushing = FALSE; parse->priv->offset = 0; + parse->priv->avg_bitrate = 0; + parse->priv->upstream_duration = -1; + parse->priv->upstream_size = -1; + parse->priv->estimated_size = -1; + parse->priv->estimated_duration = -1; if (parse->pending_segment) gst_event_unref (parse->pending_segment); @@ -1339,6 +1402,39 @@ gst_base_parse_sink_activate_pull (GstPad * sinkpad, gboolean active) return result; } +static gboolean +gst_base_parse_convert (GstBaseParse * parse, GstFormat src_format, + gint64 src_value, GstFormat dest_format, gint64 * dest_value) +{ + gboolean res = FALSE; + + if (G_UNLIKELY (src_format == dest_format)) { + *dest_value = src_value; + return TRUE; + } + + if (src_value == -1) { + *dest_value = -1; + return TRUE; + } + + /* TODO: Use seek table for accurate conversions */ + if (parse->priv->avg_bitrate && src_format == GST_FORMAT_BYTES + && dest_format == GST_FORMAT_TIME) { + *dest_value = + gst_util_uint64_scale (src_value, 8, parse->priv->avg_bitrate); + res = TRUE; + } else if (parse->priv->avg_bitrate && src_format == GST_FORMAT_TIME + && dest_format == GST_FORMAT_BYTES) { + *dest_value = + gst_util_uint64_scale (src_value, parse->priv->avg_bitrate, 8); + res = TRUE; + } else { + res = FALSE; + } + + return res; +} /** * gst_base_parse_set_duration: @@ -1431,12 +1527,6 @@ gst_base_parse_query (GstPad * pad, GstQuery * query) parse = GST_BASE_PARSE (GST_PAD_PARENT (pad)); klass = GST_BASE_PARSE_GET_CLASS (parse); - /* If subclass doesn't provide conversion function we can't reply - to the query either */ - if (!klass->convert) { - return FALSE; - } - switch (GST_QUERY_TYPE (query)) { case GST_QUERY_POSITION: { @@ -1466,7 +1556,7 @@ gst_base_parse_query (GstPad * pad, GstQuery * query) if (res) gst_query_set_position (query, format, dest_value); else - res = gst_pad_query_default (pad, query); + res = gst_pad_peer_query (parse->sinkpad, query); break; } @@ -1481,24 +1571,45 @@ gst_base_parse_query (GstPad * pad, GstQuery * query) g_mutex_lock (parse->parse_lock); - if (format == GST_FORMAT_BYTES) { - res = gst_pad_query_peer_duration (parse->sinkpad, &format, - &dest_value); - } else if (parse->priv->duration != -1 && - format == parse->priv->duration_fmt) { - dest_value = parse->priv->duration; - res = TRUE; - } else if (parse->priv->duration != -1) { - res = klass->convert (parse, parse->priv->duration_fmt, - parse->priv->duration, format, &dest_value); + switch (format) { + case GST_FORMAT_BYTES: + if (parse->priv->upstream_duration != -1 && + parse->priv->upstream_duration) { + dest_value = parse->priv->upstream_duration; + res = TRUE; + } else if (parse->priv->estimated_duration != -1 && + parse->priv->estimated_duration) { + dest_value = parse->priv->estimated_duration; + res = TRUE; + } + break; + case GST_FORMAT_TIME: + if (parse->priv->duration != -1 && + format == parse->priv->duration_fmt) { + dest_value = parse->priv->duration; + res = TRUE; + } else if (parse->priv->duration != -1) { + res = klass->convert (parse, parse->priv->duration_fmt, + parse->priv->duration, format, &dest_value); + } else if (parse->priv->upstream_duration != -1 && + parse->priv->upstream_duration > 0) { + dest_value = parse->priv->upstream_duration; + res = TRUE; + } else if (parse->priv->estimated_duration != -1 && + parse->priv->estimated_duration > 0) { + dest_value = parse->priv->estimated_duration; + res = TRUE; + } + break; + default: + break; } - g_mutex_unlock (parse->parse_lock); if (res) gst_query_set_duration (query, format, dest_value); else - res = gst_pad_query_default (pad, query); + res = gst_pad_peer_query (parse->sinkpad, query); break; } case GST_QUERY_SEEKING: @@ -1544,11 +1655,13 @@ gst_base_parse_query (GstPad * pad, GstQuery * query) if (res) { gst_query_set_convert (query, src_format, src_value, dest_format, dest_value); + } else { + res = gst_pad_peer_query (parse->sinkpad, query); } break; } default: - res = gst_pad_query_default (pad, query); + res = gst_pad_peer_query (parse->sinkpad, query); break; } return res; diff --git a/gst/flacparse/gstflacparse.c b/gst/flacparse/gstflacparse.c index f25e34b9bc..871082b1ba 100644 --- a/gst/flacparse/gstflacparse.c +++ b/gst/flacparse/gstflacparse.c @@ -597,7 +597,7 @@ need_more_data: if (upstream_len != -1 || (gst_pad_query_peer_duration (GST_BASE_PARSE_SINK_PAD (GST_BASE_PARSE (flacparse)), &fmt, &upstream_len) - && fmt == GST_FORMAT_BYTES)) { + && fmt == GST_FORMAT_BYTES && upstream_len != -1)) { flacparse->upstream_length = upstream_len; upstream_len -= GST_BUFFER_OFFSET (buffer); @@ -635,16 +635,17 @@ need_streaminfo: return -2; } -error: - { - GST_WARNING_OBJECT (flacparse, "Invalid frame"); - return -1; - } eos: { GST_WARNING_OBJECT (flacparse, "EOS"); return -1; } + +error: + { + GST_WARNING_OBJECT (flacparse, "Invalid frame"); + return -1; + } } static gboolean