mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-06-05 06:58:56 +00:00
ext/faad/gstfaad.*: Add basic reverse playback support.
Original commit message from CVS: * ext/faad/gstfaad.c: (gst_faad_dispose), (clear_queued), (flush_queued), (gst_faad_drain), (gst_faad_do_raw_seek), (gst_faad_src_event), (gst_faad_sink_event), (gst_faad_chain), (gst_faad_change_state): * ext/faad/gstfaad.h: Add basic reverse playback support. Clear decoder state after disconts. Remove some unused code. Mark output buffers with a discont after a decoding error.
This commit is contained in:
parent
d0d99f937b
commit
eea50a9a85
3 changed files with 108 additions and 55 deletions
12
ChangeLog
12
ChangeLog
|
@ -1,3 +1,15 @@
|
||||||
|
2008-06-02 Wim Taymans <wim.taymans@collabora.co.uk>
|
||||||
|
|
||||||
|
* ext/faad/gstfaad.c: (gst_faad_dispose), (clear_queued),
|
||||||
|
(flush_queued), (gst_faad_drain), (gst_faad_do_raw_seek),
|
||||||
|
(gst_faad_src_event), (gst_faad_sink_event), (gst_faad_chain),
|
||||||
|
(gst_faad_change_state):
|
||||||
|
* ext/faad/gstfaad.h:
|
||||||
|
Add basic reverse playback support.
|
||||||
|
Clear decoder state after disconts.
|
||||||
|
Remove some unused code.
|
||||||
|
Mark output buffers with a discont after a decoding error.
|
||||||
|
|
||||||
2008-06-02 Sebastian Dröge <slomo@circular-chaos.org>
|
2008-06-02 Sebastian Dröge <slomo@circular-chaos.org>
|
||||||
|
|
||||||
Patch by: Sjoerd Simons <sjoerd at luon dot net>
|
Patch by: Sjoerd Simons <sjoerd at luon dot net>
|
||||||
|
|
|
@ -246,7 +246,6 @@ gst_faad_dispose (GObject * object)
|
||||||
}
|
}
|
||||||
|
|
||||||
G_OBJECT_CLASS (parent_class)->dispose (object);
|
G_OBJECT_CLASS (parent_class)->dispose (object);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -757,6 +756,48 @@ gst_faad_srcconnect (GstPad * pad, const GstCaps * caps)
|
||||||
return GST_PAD_LINK_REFUSED;
|
return GST_PAD_LINK_REFUSED;
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
|
static void
|
||||||
|
clear_queued (GstFaad * faad)
|
||||||
|
{
|
||||||
|
g_list_foreach (faad->queued, (GFunc) gst_mini_object_unref, NULL);
|
||||||
|
g_list_free (faad->queued);
|
||||||
|
faad->queued = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GstFlowReturn
|
||||||
|
flush_queued (GstFaad * faad)
|
||||||
|
{
|
||||||
|
GstFlowReturn ret = GST_FLOW_OK;
|
||||||
|
|
||||||
|
while (faad->queued) {
|
||||||
|
GstBuffer *buf = GST_BUFFER_CAST (faad->queued->data);
|
||||||
|
|
||||||
|
GST_LOG_OBJECT (faad, "pushing buffer %p, timestamp %"
|
||||||
|
GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT, buf,
|
||||||
|
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
|
||||||
|
GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
|
||||||
|
|
||||||
|
/* iterate ouput queue an push downstream */
|
||||||
|
ret = gst_pad_push (faad->srcpad, buf);
|
||||||
|
|
||||||
|
faad->queued = g_list_delete_link (faad->queued, faad->queued);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GstFlowReturn
|
||||||
|
gst_faad_drain (GstFaad * faad)
|
||||||
|
{
|
||||||
|
GstFlowReturn ret = GST_FLOW_OK;
|
||||||
|
|
||||||
|
if (faad->segment->rate < 0.0) {
|
||||||
|
/* if we have some queued frames for reverse playback, flush
|
||||||
|
* them now */
|
||||||
|
ret = flush_queued (faad);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_faad_do_raw_seek (GstFaad * faad, GstEvent * event)
|
gst_faad_do_raw_seek (GstFaad * faad, GstEvent * event)
|
||||||
{
|
{
|
||||||
|
@ -786,7 +827,7 @@ gst_faad_do_raw_seek (GstFaad * faad, GstEvent * event)
|
||||||
GST_DEBUG_OBJECT (faad, "seeking to %" GST_TIME_FORMAT " at byte offset %"
|
GST_DEBUG_OBJECT (faad, "seeking to %" GST_TIME_FORMAT " at byte offset %"
|
||||||
G_GINT64_FORMAT, GST_TIME_ARGS (start_time), start);
|
G_GINT64_FORMAT, GST_TIME_ARGS (start_time), start);
|
||||||
|
|
||||||
return gst_pad_send_event (GST_PAD_PEER (faad->sinkpad), event);
|
return gst_pad_push_event (faad->sinkpad, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
|
@ -803,14 +844,14 @@ gst_faad_src_event (GstPad * pad, GstEvent * event)
|
||||||
case GST_EVENT_SEEK:{
|
case GST_EVENT_SEEK:{
|
||||||
/* try upstream first, there might be a demuxer */
|
/* try upstream first, there might be a demuxer */
|
||||||
gst_event_ref (event);
|
gst_event_ref (event);
|
||||||
if (!(res = gst_pad_event_default (pad, event))) {
|
if (!(res = gst_pad_push_event (faad->sinkpad, event))) {
|
||||||
res = gst_faad_do_raw_seek (faad, event);
|
res = gst_faad_do_raw_seek (faad, event);
|
||||||
}
|
}
|
||||||
gst_event_unref (event);
|
gst_event_unref (event);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
res = gst_pad_event_default (pad, event);
|
res = gst_pad_push_event (faad->sinkpad, event);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -828,9 +869,17 @@ gst_faad_sink_event (GstPad * pad, GstEvent * event)
|
||||||
|
|
||||||
GST_LOG_OBJECT (faad, "Handling %s event", GST_EVENT_TYPE_NAME (event));
|
GST_LOG_OBJECT (faad, "Handling %s event", GST_EVENT_TYPE_NAME (event));
|
||||||
|
|
||||||
/* FIXME: we should probably handle FLUSH */
|
|
||||||
switch (GST_EVENT_TYPE (event)) {
|
switch (GST_EVENT_TYPE (event)) {
|
||||||
|
case GST_EVENT_FLUSH_STOP:
|
||||||
|
if (faad->tempbuf != NULL) {
|
||||||
|
gst_buffer_unref (faad->tempbuf);
|
||||||
|
faad->tempbuf = NULL;
|
||||||
|
}
|
||||||
|
clear_queued (faad);
|
||||||
|
res = gst_pad_push_event (faad->srcpad, event);
|
||||||
|
break;
|
||||||
case GST_EVENT_EOS:
|
case GST_EVENT_EOS:
|
||||||
|
gst_faad_drain (faad);
|
||||||
if (faad->tempbuf != NULL) {
|
if (faad->tempbuf != NULL) {
|
||||||
gst_buffer_unref (faad->tempbuf);
|
gst_buffer_unref (faad->tempbuf);
|
||||||
faad->tempbuf = NULL;
|
faad->tempbuf = NULL;
|
||||||
|
@ -846,6 +895,7 @@ gst_faad_sink_event (GstPad * pad, GstEvent * event)
|
||||||
|
|
||||||
gst_event_parse_new_segment (event, &is_update, &rate, &fmt, &start,
|
gst_event_parse_new_segment (event, &is_update, &rate, &fmt, &start,
|
||||||
&end, &base);
|
&end, &base);
|
||||||
|
|
||||||
if (fmt == GST_FORMAT_TIME) {
|
if (fmt == GST_FORMAT_TIME) {
|
||||||
GST_DEBUG ("Got NEWSEGMENT event in GST_FORMAT_TIME, passing on (%"
|
GST_DEBUG ("Got NEWSEGMENT event in GST_FORMAT_TIME, passing on (%"
|
||||||
GST_TIME_FORMAT " - %" GST_TIME_FORMAT ")", GST_TIME_ARGS (start),
|
GST_TIME_FORMAT " - %" GST_TIME_FORMAT ")", GST_TIME_ARGS (start),
|
||||||
|
@ -871,6 +921,9 @@ gst_faad_sink_event (GstPad * pad, GstEvent * event)
|
||||||
}
|
}
|
||||||
gst_event_unref (event);
|
gst_event_unref (event);
|
||||||
|
|
||||||
|
/* drain queued buffers before we activate the new segment */
|
||||||
|
gst_faad_drain (faad);
|
||||||
|
|
||||||
event = gst_event_new_new_segment (is_update, rate,
|
event = gst_event_new_new_segment (is_update, rate,
|
||||||
GST_FORMAT_TIME, new_start, new_end, new_start);
|
GST_FORMAT_TIME, new_start, new_end, new_start);
|
||||||
|
|
||||||
|
@ -1173,6 +1226,16 @@ gst_faad_chain (GstPad * pad, GstBuffer * buffer)
|
||||||
|
|
||||||
faad = GST_FAAD (gst_pad_get_parent (pad));
|
faad = GST_FAAD (gst_pad_get_parent (pad));
|
||||||
|
|
||||||
|
if (GST_BUFFER_IS_DISCONT (buffer)) {
|
||||||
|
gst_faad_drain (faad);
|
||||||
|
faacDecPostSeekReset (faad->handle, 0);
|
||||||
|
if (faad->tempbuf != NULL) {
|
||||||
|
gst_buffer_unref (faad->tempbuf);
|
||||||
|
faad->tempbuf = NULL;
|
||||||
|
}
|
||||||
|
faad->discont = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
GST_OBJECT_LOCK (faad);
|
GST_OBJECT_LOCK (faad);
|
||||||
faad->bytes_in += GST_BUFFER_SIZE (buffer);
|
faad->bytes_in += GST_BUFFER_SIZE (buffer);
|
||||||
GST_OBJECT_UNLOCK (faad);
|
GST_OBJECT_UNLOCK (faad);
|
||||||
|
@ -1264,47 +1327,11 @@ gst_faad_chain (GstPad * pad, GstBuffer * buffer)
|
||||||
input_size - skip_bytes);
|
input_size - skip_bytes);
|
||||||
|
|
||||||
if (info.error > 0) {
|
if (info.error > 0) {
|
||||||
guint32 rate;
|
GST_WARNING_OBJECT (faad, "decoding error: %s",
|
||||||
guint8 ch;
|
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (faad, "decoding error: %s",
|
|
||||||
faacDecGetErrorMessage (info.error));
|
faacDecGetErrorMessage (info.error));
|
||||||
|
/* mark discont for the next buffer */
|
||||||
|
faad->discont = TRUE;
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (!faad->packetised)
|
|
||||||
goto decode_error;
|
|
||||||
|
|
||||||
/* decode error? try again using faacDecInit2
|
|
||||||
* fabricated private codec data from sink caps */
|
|
||||||
gst_faad_close_decoder (faad);
|
|
||||||
if (!gst_faad_open_decoder (faad))
|
|
||||||
goto init2_failed;
|
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (faad, "decoding error, reopening with faacDecInit2()");
|
|
||||||
if ((gint8) faacDecInit2 (faad->handle, faad->fake_codec_data, 2,
|
|
||||||
&rate, &ch) < 0) {
|
|
||||||
goto init2_failed;
|
|
||||||
}
|
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (faad, "faacDecInit2(): rate=%d,channels=%d", rate, ch);
|
|
||||||
|
|
||||||
/* let's try again */
|
|
||||||
info.error = 0;
|
|
||||||
out = faacDecDecode (faad->handle, &info, input_data + skip_bytes,
|
|
||||||
input_size - skip_bytes);
|
|
||||||
|
|
||||||
if (info.error) {
|
|
||||||
faad->error_count++;
|
|
||||||
if (faad->error_count >= MAX_DECODE_ERRORS)
|
|
||||||
goto decode_error;
|
|
||||||
GST_DEBUG_OBJECT (faad,
|
|
||||||
"Failed to decode buffer: %s, count = %d, trying to resync",
|
|
||||||
faacDecGetErrorMessage (info.error), faad->error_count);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
faad->error_count = 0; /* all fine, reset error counter */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info.bytesconsumed > input_size)
|
if (info.bytesconsumed > input_size)
|
||||||
|
@ -1378,7 +1405,20 @@ gst_faad_chain (GstPad * pad, GstBuffer * buffer)
|
||||||
"pushing buffer, off=%" G_GUINT64_FORMAT ", ts=%" GST_TIME_FORMAT,
|
"pushing buffer, off=%" G_GUINT64_FORMAT ", ts=%" GST_TIME_FORMAT,
|
||||||
GST_BUFFER_OFFSET (outbuf),
|
GST_BUFFER_OFFSET (outbuf),
|
||||||
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)));
|
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)));
|
||||||
ret = gst_pad_push (faad->srcpad, outbuf);
|
|
||||||
|
if (faad->discont) {
|
||||||
|
GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
|
||||||
|
faad->discont = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (faad->segment->rate > 0.0) {
|
||||||
|
ret = gst_pad_push (faad->srcpad, outbuf);
|
||||||
|
} else {
|
||||||
|
/* reverse playback, queue frame till later when we get a discont. */
|
||||||
|
GST_DEBUG_OBJECT (faad, "queued frame");
|
||||||
|
faad->queued = g_list_prepend (faad->queued, outbuf);
|
||||||
|
ret = GST_FLOW_OK;
|
||||||
|
}
|
||||||
if (ret != GST_FLOW_OK)
|
if (ret != GST_FLOW_OK)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -1421,13 +1461,6 @@ init2_failed:
|
||||||
ret = GST_FLOW_ERROR;
|
ret = GST_FLOW_ERROR;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
decode_error:
|
|
||||||
{
|
|
||||||
GST_ELEMENT_ERROR (faad, STREAM, DECODE, (NULL),
|
|
||||||
("Failed to decode buffer: %s", faacDecGetErrorMessage (info.error)));
|
|
||||||
ret = GST_FLOW_ERROR;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
|
@ -1498,13 +1531,14 @@ gst_faad_change_state (GstElement * element, GstStateChange transition)
|
||||||
faad->bytes_in = 0;
|
faad->bytes_in = 0;
|
||||||
faad->sum_dur_out = 0;
|
faad->sum_dur_out = 0;
|
||||||
faad->error_count = 0;
|
faad->error_count = 0;
|
||||||
break;
|
|
||||||
case GST_STATE_CHANGE_READY_TO_NULL:
|
|
||||||
gst_faad_close_decoder (faad);
|
|
||||||
if (faad->tempbuf) {
|
if (faad->tempbuf) {
|
||||||
gst_buffer_unref (faad->tempbuf);
|
gst_buffer_unref (faad->tempbuf);
|
||||||
faad->tempbuf = NULL;
|
faad->tempbuf = NULL;
|
||||||
}
|
}
|
||||||
|
clear_queued (faad);
|
||||||
|
break;
|
||||||
|
case GST_STATE_CHANGE_READY_TO_NULL:
|
||||||
|
gst_faad_close_decoder (faad);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -68,9 +68,16 @@ typedef struct _GstFaad {
|
||||||
guint64 bytes_in; /* bytes received */
|
guint64 bytes_in; /* bytes received */
|
||||||
guint64 sum_dur_out; /* sum of durations of decoded buffers we sent out */
|
guint64 sum_dur_out; /* sum of durations of decoded buffers we sent out */
|
||||||
gint error_count;
|
gint error_count;
|
||||||
|
gboolean discont;
|
||||||
|
|
||||||
/* segment handling */
|
/* segment handling */
|
||||||
GstSegment * segment;
|
GstSegment * segment;
|
||||||
|
|
||||||
|
/* list of raw output buffers for reverse playback */
|
||||||
|
GList *queued;
|
||||||
|
/* gather/decode queues for reverse playback */
|
||||||
|
GList *gather;
|
||||||
|
GList *decode;
|
||||||
} GstFaad;
|
} GstFaad;
|
||||||
|
|
||||||
typedef struct _GstFaadClass {
|
typedef struct _GstFaadClass {
|
||||||
|
|
Loading…
Reference in a new issue