mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-04 05:22:30 +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>
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -757,6 +756,48 @@ gst_faad_srcconnect (GstPad * pad, const GstCaps * caps)
|
|||
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
|
||||
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 %"
|
||||
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
|
||||
|
@ -803,14 +844,14 @@ gst_faad_src_event (GstPad * pad, GstEvent * event)
|
|||
case GST_EVENT_SEEK:{
|
||||
/* try upstream first, there might be a demuxer */
|
||||
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);
|
||||
}
|
||||
gst_event_unref (event);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
res = gst_pad_event_default (pad, event);
|
||||
res = gst_pad_push_event (faad->sinkpad, event);
|
||||
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));
|
||||
|
||||
/* FIXME: we should probably handle FLUSH */
|
||||
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:
|
||||
gst_faad_drain (faad);
|
||||
if (faad->tempbuf != NULL) {
|
||||
gst_buffer_unref (faad->tempbuf);
|
||||
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,
|
||||
&end, &base);
|
||||
|
||||
if (fmt == GST_FORMAT_TIME) {
|
||||
GST_DEBUG ("Got NEWSEGMENT event in GST_FORMAT_TIME, passing on (%"
|
||||
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);
|
||||
|
||||
/* drain queued buffers before we activate the new segment */
|
||||
gst_faad_drain (faad);
|
||||
|
||||
event = gst_event_new_new_segment (is_update, rate,
|
||||
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));
|
||||
|
||||
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);
|
||||
faad->bytes_in += GST_BUFFER_SIZE (buffer);
|
||||
GST_OBJECT_UNLOCK (faad);
|
||||
|
@ -1264,47 +1327,11 @@ gst_faad_chain (GstPad * pad, GstBuffer * buffer)
|
|||
input_size - skip_bytes);
|
||||
|
||||
if (info.error > 0) {
|
||||
guint32 rate;
|
||||
guint8 ch;
|
||||
|
||||
GST_DEBUG_OBJECT (faad, "decoding error: %s",
|
||||
GST_WARNING_OBJECT (faad, "decoding error: %s",
|
||||
faacDecGetErrorMessage (info.error));
|
||||
|
||||
/* mark discont for the next buffer */
|
||||
faad->discont = TRUE;
|
||||
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)
|
||||
|
@ -1378,7 +1405,20 @@ gst_faad_chain (GstPad * pad, GstBuffer * buffer)
|
|||
"pushing buffer, off=%" G_GUINT64_FORMAT ", ts=%" GST_TIME_FORMAT,
|
||||
GST_BUFFER_OFFSET (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)
|
||||
goto out;
|
||||
}
|
||||
|
@ -1421,13 +1461,6 @@ init2_failed:
|
|||
ret = GST_FLOW_ERROR;
|
||||
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
|
||||
|
@ -1498,13 +1531,14 @@ gst_faad_change_state (GstElement * element, GstStateChange transition)
|
|||
faad->bytes_in = 0;
|
||||
faad->sum_dur_out = 0;
|
||||
faad->error_count = 0;
|
||||
break;
|
||||
case GST_STATE_CHANGE_READY_TO_NULL:
|
||||
gst_faad_close_decoder (faad);
|
||||
if (faad->tempbuf) {
|
||||
gst_buffer_unref (faad->tempbuf);
|
||||
faad->tempbuf = NULL;
|
||||
}
|
||||
clear_queued (faad);
|
||||
break;
|
||||
case GST_STATE_CHANGE_READY_TO_NULL:
|
||||
gst_faad_close_decoder (faad);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
|
@ -68,9 +68,16 @@ typedef struct _GstFaad {
|
|||
guint64 bytes_in; /* bytes received */
|
||||
guint64 sum_dur_out; /* sum of durations of decoded buffers we sent out */
|
||||
gint error_count;
|
||||
gboolean discont;
|
||||
|
||||
/* segment handling */
|
||||
GstSegment * segment;
|
||||
|
||||
/* list of raw output buffers for reverse playback */
|
||||
GList *queued;
|
||||
/* gather/decode queues for reverse playback */
|
||||
GList *gather;
|
||||
GList *decode;
|
||||
} GstFaad;
|
||||
|
||||
typedef struct _GstFaadClass {
|
||||
|
|
Loading…
Reference in a new issue