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.
This commit is contained in:
Sebastian Dröge 2008-09-30 16:22:04 +00:00
parent aaee1a3d42
commit 5bd9d5cd17
3 changed files with 205 additions and 77 deletions

View file

@ -1,3 +1,17 @@
2008-09-30 Sebastian Dröge <sebastian.droege@collabora.co.uk>
* 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 <wim.taymans@collabora.co.uk>
* gst/rtpmanager/rtpsession.c: (on_new_ssrc), (on_ssrc_collision),

View file

@ -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;

View file

@ -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