mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-30 13:41:48 +00:00
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.
This commit is contained in:
parent
b8583561da
commit
0a5978dfaf
3 changed files with 89 additions and 40 deletions
15
ChangeLog
15
ChangeLog
|
@ -1,3 +1,18 @@
|
||||||
|
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>
|
2006-11-24 Wim Taymans <wim@fluendo.com>
|
||||||
|
|
||||||
* ext/ogg/gstoggdemux.c: (gst_ogg_page_copy), (gst_ogg_page_free),
|
* ext/ogg/gstoggdemux.c: (gst_ogg_page_copy), (gst_ogg_page_free),
|
||||||
|
|
|
@ -171,8 +171,6 @@ gst_theora_dec_init (GstTheoraDec * dec, GstTheoraDecClass * g_class)
|
||||||
static void
|
static void
|
||||||
gst_theora_dec_reset (GstTheoraDec * dec)
|
gst_theora_dec_reset (GstTheoraDec * dec)
|
||||||
{
|
{
|
||||||
GList *walk;
|
|
||||||
|
|
||||||
dec->need_keyframe = TRUE;
|
dec->need_keyframe = TRUE;
|
||||||
dec->last_timestamp = -1;
|
dec->last_timestamp = -1;
|
||||||
dec->granulepos = -1;
|
dec->granulepos = -1;
|
||||||
|
@ -185,11 +183,15 @@ gst_theora_dec_reset (GstTheoraDec * dec)
|
||||||
dec->earliest_time = -1;
|
dec->earliest_time = -1;
|
||||||
GST_OBJECT_UNLOCK (dec);
|
GST_OBJECT_UNLOCK (dec);
|
||||||
|
|
||||||
for (walk = dec->queued; walk; walk = g_list_next (walk)) {
|
g_list_foreach (dec->queued, (GFunc) gst_mini_object_unref, NULL);
|
||||||
gst_buffer_unref (GST_BUFFER_CAST (walk->data));
|
|
||||||
}
|
|
||||||
g_list_free (dec->queued);
|
g_list_free (dec->queued);
|
||||||
dec->queued = NULL;
|
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
|
static int
|
||||||
|
@ -902,7 +904,7 @@ beach:
|
||||||
|
|
||||||
/* FIXME, this needs to be moved to the demuxer */
|
/* FIXME, this needs to be moved to the demuxer */
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
theora_dec_push (GstTheoraDec * dec, GstBuffer * buf)
|
theora_dec_push_forward (GstTheoraDec * dec, GstBuffer * buf)
|
||||||
{
|
{
|
||||||
GstFlowReturn result = GST_FLOW_OK;
|
GstFlowReturn result = GST_FLOW_OK;
|
||||||
GstClockTime outtime = GST_BUFFER_TIMESTAMP (buf);
|
GstClockTime outtime = GST_BUFFER_TIMESTAMP (buf);
|
||||||
|
@ -952,6 +954,15 @@ theora_dec_push (GstTheoraDec * dec, GstBuffer * buf)
|
||||||
else
|
else
|
||||||
gst_buffer_unref (buf);
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -1091,7 +1102,10 @@ theora_handle_data_packet (GstTheoraDec * dec, ogg_packet * packet,
|
||||||
dec->info.fps_numerator);
|
dec->info.fps_numerator);
|
||||||
GST_BUFFER_TIMESTAMP (out) = outtime;
|
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;
|
return result;
|
||||||
|
|
||||||
|
@ -1143,20 +1157,11 @@ no_buffer:
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
theora_dec_chain_forward (GstTheoraDec * dec, gboolean discont, GstBuffer * buf)
|
theora_dec_decode_buffer (GstTheoraDec * dec, GstBuffer * buf)
|
||||||
{
|
{
|
||||||
ogg_packet packet;
|
ogg_packet packet;
|
||||||
GstFlowReturn result = GST_FLOW_OK;
|
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 */
|
/* make ogg_packet out of the buffer */
|
||||||
packet.packet = GST_BUFFER_DATA (buf);
|
packet.packet = GST_BUFFER_DATA (buf);
|
||||||
packet.bytes = GST_BUFFER_SIZE (buf);
|
packet.bytes = GST_BUFFER_SIZE (buf);
|
||||||
|
@ -1199,8 +1204,6 @@ done:
|
||||||
/* interpolate granule pos */
|
/* interpolate granule pos */
|
||||||
dec->granulepos = _inc_granulepos (dec, dec->granulepos);
|
dec->granulepos = _inc_granulepos (dec, dec->granulepos);
|
||||||
|
|
||||||
gst_buffer_unref (buf);
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1297,7 +1300,13 @@ theora_dec_flush_decode (GstTheoraDec * dec)
|
||||||
while (dec->decode) {
|
while (dec->decode) {
|
||||||
GstBuffer *buf = GST_BUFFER_CAST (dec->decode->data);
|
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);
|
gst_buffer_unref (buf);
|
||||||
|
|
||||||
dec->decode = g_list_delete_link (dec->decode, dec->decode);
|
dec->decode = g_list_delete_link (dec->decode, dec->decode);
|
||||||
|
@ -1320,30 +1329,48 @@ theora_dec_chain_reverse (GstTheoraDec * dec, gboolean discont, GstBuffer * buf)
|
||||||
GstFlowReturn res = GST_FLOW_OK;
|
GstFlowReturn res = GST_FLOW_OK;
|
||||||
|
|
||||||
/* if we have a discont, move buffers to the decode list */
|
/* 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) {
|
while (dec->gather) {
|
||||||
GstBuffer *buf;
|
GstBuffer *gbuf;
|
||||||
guint8 *data;
|
guint8 *data;
|
||||||
|
|
||||||
buf = GST_BUFFER_CAST (dec->gather->data);
|
gbuf = GST_BUFFER_CAST (dec->gather->data);
|
||||||
/* remove from the gather list */
|
/* remove from the gather list */
|
||||||
dec->gather = g_list_delete_link (dec->gather, dec->gather);
|
dec->gather = g_list_delete_link (dec->gather, dec->gather);
|
||||||
/* copy to decode queue */
|
/* 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 */
|
/* if we copied a keyframe, flush and decode the decode queue */
|
||||||
data = GST_BUFFER_DATA (buf);
|
data = GST_BUFFER_DATA (gbuf);
|
||||||
if ((data[0] & 0x40) == 0)
|
if ((data[0] & 0x40) == 0) {
|
||||||
|
GST_DEBUG_OBJECT (dec, "copied keyframe");
|
||||||
res = theora_dec_flush_decode (dec);
|
res = theora_dec_flush_decode (dec);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* add buffer to gather queue */
|
/* 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);
|
dec->gather = g_list_prepend (dec->gather, buf);
|
||||||
|
|
||||||
return res;
|
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
|
static GstFlowReturn
|
||||||
theora_dec_chain (GstPad * pad, GstBuffer * buf)
|
theora_dec_chain (GstPad * pad, GstBuffer * buf)
|
||||||
{
|
{
|
||||||
|
@ -1356,6 +1383,15 @@ theora_dec_chain (GstPad * pad, GstBuffer * buf)
|
||||||
/* peel of DISCONT flag */
|
/* peel of DISCONT flag */
|
||||||
discont = GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT);
|
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)
|
if (dec->segment.rate > 0.0)
|
||||||
res = theora_dec_chain_forward (dec, discont, buf);
|
res = theora_dec_chain_forward (dec, discont, buf);
|
||||||
else
|
else
|
||||||
|
|
|
@ -189,23 +189,22 @@ vorbis_dec_finalize (GObject * object)
|
||||||
static void
|
static void
|
||||||
gst_vorbis_dec_reset (GstVorbisDec * dec)
|
gst_vorbis_dec_reset (GstVorbisDec * dec)
|
||||||
{
|
{
|
||||||
GList *walk;
|
|
||||||
|
|
||||||
dec->cur_timestamp = GST_CLOCK_TIME_NONE;
|
dec->cur_timestamp = GST_CLOCK_TIME_NONE;
|
||||||
dec->prev_timestamp = GST_CLOCK_TIME_NONE;
|
dec->prev_timestamp = GST_CLOCK_TIME_NONE;
|
||||||
dec->granulepos = -1;
|
dec->granulepos = -1;
|
||||||
dec->discont = TRUE;
|
dec->discont = TRUE;
|
||||||
gst_segment_init (&dec->segment, GST_FORMAT_TIME);
|
gst_segment_init (&dec->segment, GST_FORMAT_TIME);
|
||||||
|
|
||||||
for (walk = dec->queued; walk; walk = g_list_next (walk)) {
|
g_list_foreach (dec->queued, (GFunc) gst_mini_object_unref, NULL);
|
||||||
gst_buffer_unref (GST_BUFFER_CAST (walk->data));
|
|
||||||
}
|
|
||||||
g_list_free (dec->queued);
|
g_list_free (dec->queued);
|
||||||
dec->queued = NULL;
|
dec->queued = NULL;
|
||||||
|
g_list_foreach (dec->gather, (GFunc) gst_mini_object_unref, NULL);
|
||||||
for (walk = dec->pendingevents; walk; walk = g_list_next (walk)) {
|
g_list_free (dec->gather);
|
||||||
gst_event_unref (GST_EVENT_CAST (walk->data));
|
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);
|
g_list_free (dec->pendingevents);
|
||||||
dec->pendingevents = NULL;
|
dec->pendingevents = NULL;
|
||||||
|
|
||||||
|
@ -1071,7 +1070,7 @@ wrong_samples:
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
vorbis_dec_decode_buffer (GstVorbisDec * vd, GstBuffer * buffer, gboolean eos)
|
vorbis_dec_decode_buffer (GstVorbisDec * vd, GstBuffer * buffer)
|
||||||
{
|
{
|
||||||
ogg_packet packet;
|
ogg_packet packet;
|
||||||
GstFlowReturn result = GST_FLOW_OK;
|
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
|
* Yes there is, keep one packet at all times and only push out when
|
||||||
* you receive a new one. Implement this.
|
* 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))
|
if (G_UNLIKELY (packet.bytes < 1))
|
||||||
goto wrong_size;
|
goto wrong_size;
|
||||||
|
@ -1220,7 +1219,7 @@ vorbis_dec_flush_decode (GstVorbisDec * dec)
|
||||||
next = g_list_next (walk);
|
next = g_list_next (walk);
|
||||||
|
|
||||||
/* decode buffer, prepend to output queue */
|
/* 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
|
/* if we generated output, we can discard the buffer, else we
|
||||||
* keep it in the queue */
|
* keep it in the queue */
|
||||||
|
@ -1282,7 +1281,6 @@ vorbis_dec_flush_decode (GstVorbisDec * dec)
|
||||||
} else {
|
} else {
|
||||||
GST_DEBUG_OBJECT (dec, "we don't have a granulepos yet, delayed push");
|
GST_DEBUG_OBJECT (dec, "we don't have a granulepos yet, delayed push");
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1321,7 +1319,7 @@ vorbis_dec_chain_forward (GstVorbisDec * vd, gboolean discont,
|
||||||
{
|
{
|
||||||
GstFlowReturn result;
|
GstFlowReturn result;
|
||||||
|
|
||||||
result = vorbis_dec_decode_buffer (vd, buffer, FALSE);
|
result = vorbis_dec_decode_buffer (vd, buffer);
|
||||||
|
|
||||||
gst_buffer_unref (buffer);
|
gst_buffer_unref (buffer);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue