From aa64df8ffd3a21ed3131ceecab637d8b1ce7dde0 Mon Sep 17 00:00:00 2001 From: Andy Wingo Date: Fri, 5 May 2006 16:34:15 +0000 Subject: [PATCH] ext/theora/theoraparse.c (gst_theora_parse_init) ext/vorbis/vorbisparse.c (gst_vorbis_parse_init) Original commit message from CVS: 2006-05-05 Andy Wingo * ext/theora/theoraparse.c (gst_theora_parse_init) (theora_parse_src_convert, theora_parse_src_query): * ext/vorbis/vorbisparse.c (gst_vorbis_parse_init) (vorbis_parse_convert, vorbis_parse_src_query): Add convert and query functions on the source pads of the theora and vorbis parse elements. Fixes position querying when doing a remux. --- ChangeLog | 9 +++ ext/theora/theoraparse.c | 168 +++++++++++++++++++++++++++++++++++++++ ext/vorbis/vorbisparse.c | 154 +++++++++++++++++++++++++++++++++++ 3 files changed, 331 insertions(+) diff --git a/ChangeLog b/ChangeLog index 61809b6f48..67d74ae9f8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2006-05-05 Andy Wingo + + * ext/theora/theoraparse.c (gst_theora_parse_init) + (theora_parse_src_convert, theora_parse_src_query): + * ext/vorbis/vorbisparse.c (gst_vorbis_parse_init) + (vorbis_parse_convert, vorbis_parse_src_query): Add convert and + query functions on the source pads of the theora and vorbis parse + elements. Fixes position querying when doing a remux. + 2006-05-05 Michael Smith * ext/theora/theoraparse.c: (parse_granulepos), diff --git a/ext/theora/theoraparse.c b/ext/theora/theoraparse.c index ec15145920..52cb96bf91 100644 --- a/ext/theora/theoraparse.c +++ b/ext/theora/theoraparse.c @@ -92,6 +92,7 @@ static GstFlowReturn theora_parse_chain (GstPad * pad, GstBuffer * buffer); static GstStateChangeReturn theora_parse_change_state (GstElement * element, GstStateChange transition); static gboolean theora_parse_sink_event (GstPad * pad, GstEvent * event); +static gboolean theora_parse_src_query (GstPad * pad, GstQuery * query); static void gst_theora_parse_base_init (gpointer g_class) @@ -124,6 +125,7 @@ gst_theora_parse_init (GstTheoraParse * parse, GstTheoraParseClass * g_class) parse->srcpad = gst_pad_new_from_static_template (&theora_parse_src_factory, "src"); + gst_pad_set_query_function (parse->srcpad, theora_parse_src_query); gst_element_add_pad (GST_ELEMENT (parse), parse->srcpad); } @@ -449,6 +451,172 @@ theora_parse_sink_event (GstPad * pad, GstEvent * event) return ret; } +static gboolean +theora_parse_src_convert (GstPad * pad, + GstFormat src_format, gint64 src_value, + GstFormat * dest_format, gint64 * dest_value) +{ + gboolean res = TRUE; + GstTheoraParse *parse; + guint64 scale = 1; + + if (src_format == *dest_format) { + *dest_value = src_value; + return TRUE; + } + + parse = GST_THEORA_PARSE (gst_pad_get_parent (pad)); + + /* we need the info part before we can done something */ + if (!parse->streamheader_received) + goto no_header; + + switch (src_format) { + case GST_FORMAT_BYTES: + switch (*dest_format) { + case GST_FORMAT_DEFAULT: + *dest_value = gst_util_uint64_scale_int (src_value, 2, + parse->info.height * parse->info.width * 3); + break; + case GST_FORMAT_TIME: + /* seems like a rather silly conversion, implement me if you like */ + default: + res = FALSE; + } + break; + case GST_FORMAT_TIME: + switch (*dest_format) { + case GST_FORMAT_BYTES: + scale = 3 * (parse->info.width * parse->info.height) / 2; + case GST_FORMAT_DEFAULT: + *dest_value = scale * gst_util_uint64_scale (src_value, + parse->info.fps_numerator, + parse->info.fps_denominator * GST_SECOND); + break; + default: + GST_DEBUG_OBJECT (parse, "cannot convert to format %s", + gst_format_get_name (*dest_format)); + res = FALSE; + } + break; + case GST_FORMAT_DEFAULT: + switch (*dest_format) { + case GST_FORMAT_TIME: + *dest_value = gst_util_uint64_scale (src_value, + GST_SECOND * parse->info.fps_denominator, + parse->info.fps_numerator); + break; + case GST_FORMAT_BYTES: + *dest_value = gst_util_uint64_scale_int (src_value, + 3 * parse->info.width * parse->info.height, 2); + break; + default: + res = FALSE; + } + break; + default: + res = FALSE; + } +done: + gst_object_unref (parse); + return res; + + /* ERRORS */ +no_header: + { + GST_DEBUG_OBJECT (parse, "no header yet, cannot convert"); + res = FALSE; + goto done; + } +} + +static gboolean +theora_parse_src_query (GstPad * pad, GstQuery * query) +{ + GstTheoraParse *parse; + + gboolean res = FALSE; + + parse = GST_THEORA_PARSE (gst_pad_get_parent (pad)); + + switch (GST_QUERY_TYPE (query)) { + case GST_QUERY_POSITION: + { + gint64 frame, value; + GstFormat my_format, format; + gint64 time; + + frame = parse->prev_frame; + + GST_LOG_OBJECT (parse, + "query %p: we have current frame: %lld", query, frame); + + /* parse format */ + gst_query_parse_position (query, &format, NULL); + + /* and convert to the final format in two steps with time as the + * intermediate step */ + my_format = GST_FORMAT_TIME; + if (!(res = + theora_parse_src_convert (parse->sinkpad, GST_FORMAT_DEFAULT, + frame, &my_format, &time))) + goto error; + + /* fixme: handle segments + time = (time - parse->segment.start) + parse->segment.time; + */ + + GST_LOG_OBJECT (parse, + "query %p: our time: %" GST_TIME_FORMAT " (conv to %s)", + query, GST_TIME_ARGS (time), gst_format_get_name (format)); + + if (!(res = + theora_parse_src_convert (pad, my_format, time, &format, &value))) + goto error; + + gst_query_set_position (query, format, value); + + GST_LOG_OBJECT (parse, + "query %p: we return %lld (format %u)", query, value, format); + + break; + } + case GST_QUERY_DURATION: + /* forward to peer for total */ + if (!(res = gst_pad_query (GST_PAD_PEER (parse->sinkpad), query))) + goto error; + break; + case GST_QUERY_CONVERT: + { + GstFormat src_fmt, dest_fmt; + gint64 src_val, dest_val; + + gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val); + if (!(res = + theora_parse_src_convert (pad, src_fmt, src_val, &dest_fmt, + &dest_val))) + goto error; + + gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val); + break; + } + default: + res = gst_pad_query_default (pad, query); + break; + } +done: + gst_object_unref (parse); + + return res; + + /* ERRORS */ +error: + { + GST_DEBUG_OBJECT (parse, "query failed"); + goto done; + } +} + static GstStateChangeReturn theora_parse_change_state (GstElement * element, GstStateChange transition) { diff --git a/ext/vorbis/vorbisparse.c b/ext/vorbis/vorbisparse.c index 026ecd650e..b655bcef82 100644 --- a/ext/vorbis/vorbisparse.c +++ b/ext/vorbis/vorbisparse.c @@ -107,6 +107,10 @@ static GstFlowReturn vorbis_parse_chain (GstPad * pad, GstBuffer * buffer); static GstStateChangeReturn vorbis_parse_change_state (GstElement * element, GstStateChange transition); static gboolean vorbis_parse_sink_event (GstPad * pad, GstEvent * event); +static gboolean vorbis_parse_src_query (GstPad * pad, GstQuery * query); +static gboolean vorbis_parse_convert (GstPad * pad, + GstFormat src_format, gint64 src_value, + GstFormat * dest_format, gint64 * dest_value); static void gst_vorbis_parse_base_init (gpointer g_class) @@ -139,6 +143,7 @@ gst_vorbis_parse_init (GstVorbisParse * parse, GstVorbisParseClass * g_class) parse->srcpad = gst_pad_new_from_static_template (&vorbis_parse_src_factory, "src"); + gst_pad_set_query_function (parse->srcpad, vorbis_parse_src_query); gst_element_add_pad (GST_ELEMENT (parse), parse->srcpad); } @@ -428,6 +433,155 @@ vorbis_parse_sink_event (GstPad * pad, GstEvent * event) return ret; } +static gboolean +vorbis_parse_convert (GstPad * pad, + GstFormat src_format, gint64 src_value, + GstFormat * dest_format, gint64 * dest_value) +{ + gboolean res = TRUE; + GstVorbisParse *parse; + guint64 scale = 1; + + parse = GST_VORBIS_PARSE (GST_PAD_PARENT (pad)); + + /* fixme: assumes atomic access to lots of instance variables modified from + * the streaming thread, including 64-bit variables */ + + if (parse->packetno < 4) + return FALSE; + + if (src_format == *dest_format) { + *dest_value = src_value; + return TRUE; + } + + if (parse->sinkpad == pad && + (src_format == GST_FORMAT_BYTES || *dest_format == GST_FORMAT_BYTES)) + return FALSE; + + switch (src_format) { + case GST_FORMAT_TIME: + switch (*dest_format) { + case GST_FORMAT_BYTES: + scale = sizeof (float) * parse->vi.channels; + case GST_FORMAT_DEFAULT: + *dest_value = + scale * gst_util_uint64_scale_int (src_value, parse->vi.rate, + GST_SECOND); + break; + default: + res = FALSE; + } + break; + case GST_FORMAT_DEFAULT: + switch (*dest_format) { + case GST_FORMAT_BYTES: + *dest_value = src_value * sizeof (float) * parse->vi.channels; + break; + case GST_FORMAT_TIME: + *dest_value = + gst_util_uint64_scale_int (src_value, GST_SECOND, parse->vi.rate); + break; + default: + res = FALSE; + } + break; + case GST_FORMAT_BYTES: + switch (*dest_format) { + case GST_FORMAT_DEFAULT: + *dest_value = src_value / (sizeof (float) * parse->vi.channels); + break; + case GST_FORMAT_TIME: + *dest_value = gst_util_uint64_scale_int (src_value, GST_SECOND, + parse->vi.rate * sizeof (float) * parse->vi.channels); + break; + default: + res = FALSE; + } + break; + default: + res = FALSE; + } + + return res; +} + +static gboolean +vorbis_parse_src_query (GstPad * pad, GstQuery * query) +{ + gint64 granulepos; + GstVorbisParse *parse; + gboolean res = FALSE; + + parse = GST_VORBIS_PARSE (GST_PAD_PARENT (pad)); + + switch (GST_QUERY_TYPE (query)) { + case GST_QUERY_POSITION: + { + GstFormat format; + gint64 value; + + granulepos = parse->prev_granulepos; + + gst_query_parse_position (query, &format, NULL); + + /* and convert to the final format */ + if (!(res = + vorbis_parse_convert (pad, GST_FORMAT_DEFAULT, granulepos, + &format, &value))) + goto error; + + /* fixme: support segments + value = (value - parse->segment_start) + parse->segment_time; + */ + + gst_query_set_position (query, format, value); + + GST_LOG_OBJECT (parse, + "query %u: peer returned granulepos: %llu - we return %llu (format %u)", + query, granulepos, value, format); + + break; + } + case GST_QUERY_DURATION: + { + /* fixme: not threadsafe */ + /* query peer for total length */ + if (!gst_pad_is_linked (parse->sinkpad)) { + GST_WARNING_OBJECT (parse, "sink pad %" GST_PTR_FORMAT " is not linked", + parse->sinkpad); + goto error; + } + if (!(res = gst_pad_query (GST_PAD_PEER (parse->sinkpad), query))) + goto error; + break; + } + case GST_QUERY_CONVERT: + { + GstFormat src_fmt, dest_fmt; + gint64 src_val, dest_val; + + gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val); + if (!(res = + vorbis_parse_convert (pad, src_fmt, src_val, &dest_fmt, + &dest_val))) + goto error; + gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val); + break; + } + default: + res = gst_pad_query_default (pad, query); + break; + } + return res; + +error: + { + GST_WARNING_OBJECT (parse, "error handling query"); + return res; + } +} + static GstStateChangeReturn vorbis_parse_change_state (GstElement * element, GstStateChange transition) {