From 56b6088c46809b85e10ed4f081c6d25579ec4efb Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Tue, 3 Feb 2004 16:15:16 +0000 Subject: [PATCH] ext/ogg/gstoggdemux.c: handle chain parsing correctly in the multichain case Original commit message from CVS: 2004-02-03 Benjamin Otte * ext/ogg/gstoggdemux.c: (gst_ogg_demux_chain): handle chain parsing correctly in the multichain case * ext/theora/theoradec.c: (gst_theora_dec_init), (_theora_ilog), (theora_dec_from_granulepos), (theora_dec_to_granulepos), (theora_dec_src_query), (theora_dec_src_event), (theora_dec_event), (theora_dec_chain): handle events and queries correctly --- ChangeLog | 10 ++++ ext/ogg/gstoggdemux.c | 18 +++---- ext/theora/theoradec.c | 124 ++++++++++++++++++++++++++++++++++++++++++------- 3 files changed, 128 insertions(+), 24 deletions(-) diff --git a/ChangeLog b/ChangeLog index f8bc155..abc6604 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2004-02-03 Benjamin Otte + + * ext/ogg/gstoggdemux.c: (gst_ogg_demux_chain): + handle chain parsing correctly in the multichain case + * ext/theora/theoradec.c: (gst_theora_dec_init), (_theora_ilog), + (theora_dec_from_granulepos), (theora_dec_to_granulepos), + (theora_dec_src_query), (theora_dec_src_event), (theora_dec_event), + (theora_dec_chain): + handle events and queries correctly + 2004-02-03 David I. Lehn * .cvsignore: diff --git a/ext/ogg/gstoggdemux.c b/ext/ogg/gstoggdemux.c index 7743f0d..d8e4349 100644 --- a/ext/ogg/gstoggdemux.c +++ b/ext/ogg/gstoggdemux.c @@ -508,6 +508,16 @@ gst_ogg_demux_chain (GstPad *pad, GstData *buffer) * we only have the END_OFFSET */ break; case 0: + if (ogg->state == GST_OGG_STATE_SETUP) { + guint64 length; + GstFormat format = GST_FORMAT_BYTES; + if (!gst_pad_query (GST_PAD_PEER (ogg->sinkpad), GST_QUERY_TOTAL, &format, &length)) + length = 0; + if (length <= offset_end) { + gst_ogg_start_playing (ogg); + goto out; + } + } break; case 1: GST_LOG_OBJECT (ogg, "processing ogg page (serial %d, packet %ld, granule pos %llu", @@ -515,8 +525,6 @@ gst_ogg_demux_chain (GstPad *pad, GstData *buffer) switch (ogg->state) { case GST_OGG_STATE_SETUP: if (ogg_page_eos (&page)) { - guint64 length; - GstFormat format = GST_FORMAT_BYTES; GstOggPad *cur = gst_ogg_pad_get_in_current_chain (ogg, ogg_page_serialno (&page)); GST_FLAG_SET (ogg, GST_OGG_FLAG_EOS); if (!cur) { @@ -525,12 +533,6 @@ gst_ogg_demux_chain (GstPad *pad, GstData *buffer) cur->pages = ogg_page_pageno (&page); cur->length = ogg_page_granulepos (&page); } - if (!gst_pad_query (GST_PAD_PEER (ogg->sinkpad), GST_QUERY_TOTAL, &format, &length)) - length = 0; - if (length >= offset_end) { - gst_ogg_start_playing (ogg); - goto out; - } } else { if (GST_FLAG_IS_SET (ogg, GST_OGG_FLAG_EOS) && ogg_page_bos (&page)) { gst_ogg_add_chain (ogg); diff --git a/ext/theora/theoradec.c b/ext/theora/theoradec.c index 1174503..857193b 100644 --- a/ext/theora/theoradec.c +++ b/ext/theora/theoradec.c @@ -98,6 +98,10 @@ static GstElementStateReturn theora_dec_change_state (GstElement * element); static gboolean theora_dec_src_event (GstPad * pad, GstEvent * event); +static gboolean theora_dec_src_query (GstPad * pad, + GstQueryType query, + GstFormat * format, + gint64 * value); static void @@ -132,11 +136,53 @@ gst_theora_dec_init (GstTheoraDec *dec) gst_static_pad_template_get (&theora_dec_src_factory), "src"); gst_pad_use_explicit_caps (dec->srcpad); gst_pad_set_event_function (dec->srcpad, theora_dec_src_event); + gst_pad_set_query_function (dec->srcpad, theora_dec_src_query); gst_element_add_pad (GST_ELEMENT (dec), dec->srcpad); GST_FLAG_SET (dec, GST_ELEMENT_EVENT_AWARE); } -#if 0 + +/* FIXME: copy from libtheora, theora should somehow make this available for seeking */ +static int +_theora_ilog(unsigned int v){ + int ret=0; + while(v){ + ret++; + v>>=1; + } + return(ret); +} + +static gboolean +theora_dec_from_granulepos (GstTheoraDec *dec, GstFormat format, guint64 from, guint64 *to) +{ + guint64 framecount; + guint ilog = _theora_ilog (dec->info.keyframe_frequency_force); + + if (dec->packetno < 1) return FALSE; + + /* granulepos is last ilog bits for counting pframes since last iframe and + * bits in front of that for the framenumber of the last iframe. */ + framecount = from >> ilog; + framecount += from - (framecount << ilog); + + switch (format) { + case GST_FORMAT_TIME: + *to = framecount = from * GST_SECOND * dec->info.fps_denominator / dec->info.fps_numerator; + break; + case GST_FORMAT_DEFAULT: + *to = framecount; + break; + case GST_FORMAT_BYTES: + *to = framecount * dec->info.height * dec->info.width * 12 / 8; + break; + default: + return FALSE; + } + return TRUE; +} + +/* FIXME: we can only seek to keyframes... */ static gboolean theora_dec_to_granulepos (GstTheoraDec *dec, GstFormat format, guint64 from, guint64 *to) { @@ -146,19 +192,39 @@ theora_dec_to_granulepos (GstTheoraDec *dec, GstFormat format, guint64 from, gui switch (format) { case GST_FORMAT_TIME: - framecount = from * dec->vi.rate / GST_SECOND; - return TRUE; + framecount = from * dec->info.fps_numerator / (GST_SECOND * dec->info.fps_denominator); + break; case GST_FORMAT_DEFAULT: framecount = from; - return TRUE; + break; case GST_FORMAT_BYTES: - framecount = from / sizeof (float) / dec->vi.channels; - return TRUE; + framecount = from * 8 / (dec->info.height * dec->info.width * 12); + break; default: return FALSE; } + *to = framecount << _theora_ilog (dec->info.keyframe_frequency_force - 1); + return TRUE; } -#endif + +static gboolean +theora_dec_src_query (GstPad *pad, GstQueryType query, GstFormat *format, gint64 *value) +{ + gint64 granulepos; + GstTheoraDec *dec = GST_THEORA_DEC (gst_pad_get_parent (pad)); + GstFormat my_format = GST_FORMAT_DEFAULT; + + if (!gst_pad_query (GST_PAD_PEER (dec->sinkpad), query, &my_format, &granulepos)) + return FALSE; + + if (!theora_dec_from_granulepos (dec, *format, granulepos, value)) + return FALSE; + + GST_LOG_OBJECT (dec, "query %u: peer returned granulepos: %llu - we return %llu (format %u)\n", + query, granulepos, *value, *format); + return TRUE; +} + static gboolean theora_dec_src_event (GstPad *pad, GstEvent *event) { @@ -169,7 +235,6 @@ theora_dec_src_event (GstPad *pad, GstEvent *event) switch (GST_EVENT_TYPE (event)) { case GST_EVENT_SEEK: { -#if 0 guint64 value; res = theora_dec_to_granulepos (dec, GST_EVENT_SEEK_FORMAT (event), @@ -180,10 +245,7 @@ theora_dec_src_event (GstPad *pad, GstEvent *event) value); res = gst_pad_send_event (GST_PAD_PEER (dec->sinkpad), real_seek); } -#else gst_event_unref (event); - res = FALSE; -#endif break; } default: @@ -197,7 +259,7 @@ theora_dec_src_event (GstPad *pad, GstEvent *event) static void theora_dec_event (GstTheoraDec *dec, GstEvent *event) { - guint64 value; + guint64 value, time, bytes; GST_LOG_OBJECT (dec, "handling event"); switch (GST_EVENT_TYPE (event)) { @@ -209,7 +271,24 @@ theora_dec_event (GstTheoraDec *dec, GstEvent *event) GST_WARNING_OBJECT (dec, "discont event didn't include offset, we might set it wrong now"); } - dec->packetno = 3; + if (dec->packetno < 3) { + if (dec->granulepos != 0) + GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL), ("can't handle discont before parsing first 3 packets")); + dec->packetno = 0; + gst_pad_push (dec->srcpad, GST_DATA (gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME, (guint64) 0, + GST_FORMAT_DEFAULT, (guint64) 0, GST_FORMAT_BYTES, (guint64) 0, 0))); + } else { + dec->packetno = 3; + /* if one of them works, all of them work */ + if (theora_dec_from_granulepos (dec, GST_FORMAT_TIME, dec->granulepos, &time) && + theora_dec_from_granulepos (dec, GST_FORMAT_DEFAULT, dec->granulepos, &value) && + theora_dec_from_granulepos (dec, GST_FORMAT_BYTES, dec->granulepos, &bytes)) { + gst_pad_push (dec->srcpad, GST_DATA (gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME, time, + GST_FORMAT_DEFAULT, value, GST_FORMAT_BYTES, bytes, 0))); + } else { + GST_ERROR_OBJECT (dec, "failed to parse data for DISCONT event, not sending any"); + } + } break; default: break; @@ -236,8 +315,8 @@ theora_dec_chain (GstPad *pad, GstData *data) packet.bytes = GST_BUFFER_SIZE (buf); packet.granulepos = GST_BUFFER_OFFSET_END (buf); packet.packetno = dec->packetno ++; - if (packet.packetno == 0) - packet.b_o_s = 1; + packet.b_o_s = (packet.packetno == 0) ? 1 : 0; + packet.e_o_s = 0; /* switch depending on packet type */ if (packet.packet[0] & 0x80) { /* header packet */ @@ -272,7 +351,6 @@ theora_dec_chain (GstPad *pad, GstData *data) "width", G_TYPE_INT, dec->info.width, "height", G_TYPE_INT, dec->info.height, NULL); - g_print ("%s\n", gst_caps_to_string (caps)); gst_pad_set_explicit_caps (dec->srcpad, caps); gst_caps_free (caps); } @@ -282,6 +360,13 @@ theora_dec_chain (GstPad *pad, GstData *data) guint8 *y, *v, *u; guint i; /* normal data packet */ +#if 0 + { + GTimeVal tv; + guint64 time; + g_get_current_time (&tv); + time = GST_TIMEVAL_TO_TIME (tv); +#endif if (theora_decode_packetin (&dec->state, &packet)) { GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE, (NULL), ("theora decoder did not read data packet")); @@ -312,6 +397,13 @@ theora_dec_chain (GstPad *pad, GstData *data) GST_BUFFER_OFFSET_END (out) = dec->packetno - 3; GST_BUFFER_DURATION (out) = GST_SECOND * ((gdouble) dec->info.fps_denominator) / dec->info.fps_numerator; GST_BUFFER_TIMESTAMP (out) = GST_BUFFER_OFFSET (out) * GST_BUFFER_DURATION (out); +#if 0 + g_get_current_time (&tv); + time = GST_TIMEVAL_TO_TIME (tv) - time; + if (time > 10000000) + g_print ("w00t, you're sl0000w!! - %llu\n", time); + } +#endif gst_pad_push (dec->srcpad, GST_DATA (out)); } gst_data_unref (data); -- 2.7.4