diff options
Diffstat (limited to 'ext/faad')
-rw-r--r-- | ext/faad/gstfaad.c | 144 | ||||
-rw-r--r-- | ext/faad/gstfaad.h | 7 |
2 files changed, 96 insertions, 55 deletions
diff --git a/ext/faad/gstfaad.c b/ext/faad/gstfaad.c index a65550d3..178ff642 100644 --- a/ext/faad/gstfaad.c +++ b/ext/faad/gstfaad.c @@ -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; diff --git a/ext/faad/gstfaad.h b/ext/faad/gstfaad.h index 7c20a01f..fd989b6b 100644 --- a/ext/faad/gstfaad.h +++ b/ext/faad/gstfaad.h @@ -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 { |