+2006-11-26 Wim Taymans <wim@fluendo.com>
+
+ * 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 <wim@fluendo.com>
* ext/ogg/gstoggdemux.c: (gst_ogg_page_copy), (gst_ogg_page_free),
static void
gst_theora_dec_reset (GstTheoraDec * dec)
{
- GList *walk;
-
dec->need_keyframe = TRUE;
dec->last_timestamp = -1;
dec->granulepos = -1;
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
/* 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);
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;
}
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;
}
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);
/* interpolate granule pos */
dec->granulepos = _inc_granulepos (dec, dec->granulepos);
- gst_buffer_unref (buf);
-
return result;
}
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);
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)
{
/* 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
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;
}
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;
* 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;
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 */
} else {
GST_DEBUG_OBJECT (dec, "we don't have a granulepos yet, delayed push");
}
-
return res;
}
{
GstFlowReturn result;
- result = vorbis_dec_decode_buffer (vd, buffer, FALSE);
+ result = vorbis_dec_decode_buffer (vd, buffer);
gst_buffer_unref (buffer);