From: Wim Taymans Date: Sun, 26 Nov 2006 16:39:41 +0000 (+0000) Subject: ext/theora/theoradec.c: Implement reverse playback. X-Git-Tag: 1.19.3~511^2~11466 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=0a5978dfaf6de28e26f9535c9f067d18a1b3c573;p=platform%2Fupstream%2Fgstreamer.git ext/theora/theoradec.c: Implement reverse playback. Original commit message from CVS: * ext/theora/theoradec.c: (gst_theora_dec_reset), (theora_dec_push_forward), (theora_dec_push_reverse), (theora_handle_data_packet), (theora_dec_decode_buffer), (theora_dec_flush_decode), (theora_dec_chain_reverse), (theora_dec_chain_forward), (theora_dec_chain): Implement reverse playback. * ext/vorbis/vorbisdec.c: (gst_vorbis_dec_reset), (vorbis_dec_decode_buffer), (vorbis_dec_flush_decode), (vorbis_dec_chain_forward): Clear buffers used for reverse playback in _reset. No need to set the eos flag, we clip samples using the segment. --- diff --git a/ChangeLog b/ChangeLog index b871fa6..761f66c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +2006-11-26 Wim Taymans + + * ext/theora/theoradec.c: (gst_theora_dec_reset), + (theora_dec_push_forward), (theora_dec_push_reverse), + (theora_handle_data_packet), (theora_dec_decode_buffer), + (theora_dec_flush_decode), (theora_dec_chain_reverse), + (theora_dec_chain_forward), (theora_dec_chain): + Implement reverse playback. + + * ext/vorbis/vorbisdec.c: (gst_vorbis_dec_reset), + (vorbis_dec_decode_buffer), (vorbis_dec_flush_decode), + (vorbis_dec_chain_forward): + Clear buffers used for reverse playback in _reset. + No need to set the eos flag, we clip samples using the segment. + 2006-11-24 Wim Taymans * ext/ogg/gstoggdemux.c: (gst_ogg_page_copy), (gst_ogg_page_free), diff --git a/ext/theora/theoradec.c b/ext/theora/theoradec.c index 72f6913..88bd299 100644 --- a/ext/theora/theoradec.c +++ b/ext/theora/theoradec.c @@ -171,8 +171,6 @@ gst_theora_dec_init (GstTheoraDec * dec, GstTheoraDecClass * g_class) static void gst_theora_dec_reset (GstTheoraDec * dec) { - GList *walk; - dec->need_keyframe = TRUE; dec->last_timestamp = -1; dec->granulepos = -1; @@ -185,11 +183,15 @@ gst_theora_dec_reset (GstTheoraDec * dec) dec->earliest_time = -1; GST_OBJECT_UNLOCK (dec); - for (walk = dec->queued; walk; walk = g_list_next (walk)) { - gst_buffer_unref (GST_BUFFER_CAST (walk->data)); - } + g_list_foreach (dec->queued, (GFunc) gst_mini_object_unref, NULL); g_list_free (dec->queued); dec->queued = NULL; + g_list_foreach (dec->gather, (GFunc) gst_mini_object_unref, NULL); + g_list_free (dec->gather); + dec->gather = NULL; + g_list_foreach (dec->decode, (GFunc) gst_mini_object_unref, NULL); + g_list_free (dec->decode); + dec->decode = NULL; } static int @@ -902,7 +904,7 @@ beach: /* FIXME, this needs to be moved to the demuxer */ static GstFlowReturn -theora_dec_push (GstTheoraDec * dec, GstBuffer * buf) +theora_dec_push_forward (GstTheoraDec * dec, GstBuffer * buf) { GstFlowReturn result = GST_FLOW_OK; GstClockTime outtime = GST_BUFFER_TIMESTAMP (buf); @@ -952,6 +954,15 @@ theora_dec_push (GstTheoraDec * dec, GstBuffer * buf) else gst_buffer_unref (buf); } + return result; +} + +static GstFlowReturn +theora_dec_push_reverse (GstTheoraDec * dec, GstBuffer * buf) +{ + GstFlowReturn result = GST_FLOW_OK; + + dec->queued = g_list_prepend (dec->queued, buf); return result; } @@ -1091,7 +1102,10 @@ theora_handle_data_packet (GstTheoraDec * dec, ogg_packet * packet, dec->info.fps_numerator); GST_BUFFER_TIMESTAMP (out) = outtime; - result = theora_dec_push (dec, out); + if (dec->segment.rate >= 0.0) + result = theora_dec_push_forward (dec, out); + else + result = theora_dec_push_reverse (dec, out); return result; @@ -1143,20 +1157,11 @@ no_buffer: } static GstFlowReturn -theora_dec_chain_forward (GstTheoraDec * dec, gboolean discont, GstBuffer * buf) +theora_dec_decode_buffer (GstTheoraDec * dec, GstBuffer * buf) { ogg_packet packet; GstFlowReturn result = GST_FLOW_OK; - /* resync on DISCONT */ - if (G_UNLIKELY (discont)) { - GST_DEBUG_OBJECT (dec, "received DISCONT buffer"); - dec->need_keyframe = TRUE; - dec->last_timestamp = -1; - dec->granulepos = -1; - dec->discont = TRUE; - } - /* make ogg_packet out of the buffer */ packet.packet = GST_BUFFER_DATA (buf); packet.bytes = GST_BUFFER_SIZE (buf); @@ -1199,8 +1204,6 @@ done: /* interpolate granule pos */ dec->granulepos = _inc_granulepos (dec, dec->granulepos); - gst_buffer_unref (buf); - return result; } @@ -1297,7 +1300,13 @@ theora_dec_flush_decode (GstTheoraDec * dec) while (dec->decode) { GstBuffer *buf = GST_BUFFER_CAST (dec->decode->data); - /* FIXME, decode buffer, prepend to output queue */ + GST_DEBUG_OBJECT (dec, "decoding buffer %p, ts %" GST_TIME_FORMAT, + buf, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf))); + + /* decode buffer, prepend to output queue */ + res = theora_dec_decode_buffer (dec, buf); + + /* don't need it anymore now */ gst_buffer_unref (buf); dec->decode = g_list_delete_link (dec->decode, dec->decode); @@ -1320,31 +1329,49 @@ theora_dec_chain_reverse (GstTheoraDec * dec, gboolean discont, GstBuffer * buf) GstFlowReturn res = GST_FLOW_OK; /* if we have a discont, move buffers to the decode list */ - if (discont) { + if (G_UNLIKELY (discont)) { + GST_DEBUG_OBJECT (dec, "received discont,gathering buffers"); while (dec->gather) { - GstBuffer *buf; + GstBuffer *gbuf; guint8 *data; - buf = GST_BUFFER_CAST (dec->gather->data); + gbuf = GST_BUFFER_CAST (dec->gather->data); /* remove from the gather list */ dec->gather = g_list_delete_link (dec->gather, dec->gather); /* copy to decode queue */ - dec->decode = g_list_prepend (dec->decode, buf); + dec->decode = g_list_prepend (dec->decode, gbuf); /* if we copied a keyframe, flush and decode the decode queue */ - data = GST_BUFFER_DATA (buf); - if ((data[0] & 0x40) == 0) + data = GST_BUFFER_DATA (gbuf); + if ((data[0] & 0x40) == 0) { + GST_DEBUG_OBJECT (dec, "copied keyframe"); res = theora_dec_flush_decode (dec); + } } } /* add buffer to gather queue */ + GST_DEBUG_OBJECT (dec, "gathering buffer %p, size %u", buf, + GST_BUFFER_SIZE (buf)); dec->gather = g_list_prepend (dec->gather, buf); return res; } static GstFlowReturn +theora_dec_chain_forward (GstTheoraDec * dec, gboolean discont, + GstBuffer * buffer) +{ + GstFlowReturn result; + + result = theora_dec_decode_buffer (dec, buffer); + + gst_buffer_unref (buffer); + + return result; +} + +static GstFlowReturn theora_dec_chain (GstPad * pad, GstBuffer * buf) { GstTheoraDec *dec; @@ -1356,6 +1383,15 @@ theora_dec_chain (GstPad * pad, GstBuffer * buf) /* peel of DISCONT flag */ discont = GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT); + /* resync on DISCONT */ + if (G_UNLIKELY (discont)) { + GST_DEBUG_OBJECT (dec, "received DISCONT buffer"); + dec->need_keyframe = TRUE; + dec->last_timestamp = -1; + dec->granulepos = -1; + dec->discont = TRUE; + } + if (dec->segment.rate > 0.0) res = theora_dec_chain_forward (dec, discont, buf); else diff --git a/ext/vorbis/vorbisdec.c b/ext/vorbis/vorbisdec.c index 1fd5b63..678bd47 100644 --- a/ext/vorbis/vorbisdec.c +++ b/ext/vorbis/vorbisdec.c @@ -189,23 +189,22 @@ vorbis_dec_finalize (GObject * object) static void gst_vorbis_dec_reset (GstVorbisDec * dec) { - GList *walk; - dec->cur_timestamp = GST_CLOCK_TIME_NONE; dec->prev_timestamp = GST_CLOCK_TIME_NONE; dec->granulepos = -1; dec->discont = TRUE; gst_segment_init (&dec->segment, GST_FORMAT_TIME); - for (walk = dec->queued; walk; walk = g_list_next (walk)) { - gst_buffer_unref (GST_BUFFER_CAST (walk->data)); - } + g_list_foreach (dec->queued, (GFunc) gst_mini_object_unref, NULL); g_list_free (dec->queued); dec->queued = NULL; - - for (walk = dec->pendingevents; walk; walk = g_list_next (walk)) { - gst_event_unref (GST_EVENT_CAST (walk->data)); - } + g_list_foreach (dec->gather, (GFunc) gst_mini_object_unref, NULL); + g_list_free (dec->gather); + dec->gather = NULL; + g_list_foreach (dec->decode, (GFunc) gst_mini_object_unref, NULL); + g_list_free (dec->decode); + dec->decode = NULL; + g_list_foreach (dec->pendingevents, (GFunc) gst_mini_object_unref, NULL); g_list_free (dec->pendingevents); dec->pendingevents = NULL; @@ -1071,7 +1070,7 @@ wrong_samples: } static GstFlowReturn -vorbis_dec_decode_buffer (GstVorbisDec * vd, GstBuffer * buffer, gboolean eos) +vorbis_dec_decode_buffer (GstVorbisDec * vd, GstBuffer * buffer) { ogg_packet packet; GstFlowReturn result = GST_FLOW_OK; @@ -1105,7 +1104,7 @@ vorbis_dec_decode_buffer (GstVorbisDec * vd, GstBuffer * buffer, gboolean eos) * Yes there is, keep one packet at all times and only push out when * you receive a new one. Implement this. */ - packet.e_o_s = (eos ? 1 : 0); + packet.e_o_s = 0; if (G_UNLIKELY (packet.bytes < 1)) goto wrong_size; @@ -1220,7 +1219,7 @@ vorbis_dec_flush_decode (GstVorbisDec * dec) next = g_list_next (walk); /* decode buffer, prepend to output queue */ - res = vorbis_dec_decode_buffer (dec, buf, next == NULL); + res = vorbis_dec_decode_buffer (dec, buf); /* if we generated output, we can discard the buffer, else we * keep it in the queue */ @@ -1282,7 +1281,6 @@ vorbis_dec_flush_decode (GstVorbisDec * dec) } else { GST_DEBUG_OBJECT (dec, "we don't have a granulepos yet, delayed push"); } - return res; } @@ -1321,7 +1319,7 @@ vorbis_dec_chain_forward (GstVorbisDec * vd, gboolean discont, { GstFlowReturn result; - result = vorbis_dec_decode_buffer (vd, buffer, FALSE); + result = vorbis_dec_decode_buffer (vd, buffer); gst_buffer_unref (buffer);