faad: use adapter rather than temporary buffer

This commit is contained in:
Mark Nauwelaerts 2010-02-10 21:12:07 +01:00
parent cca1fad250
commit 159fe8a1a0
2 changed files with 70 additions and 75 deletions

View file

@ -135,6 +135,7 @@ static void gst_faad_base_init (GstFaadClass * klass);
static void gst_faad_class_init (GstFaadClass * klass); static void gst_faad_class_init (GstFaadClass * klass);
static void gst_faad_init (GstFaad * faad); static void gst_faad_init (GstFaad * faad);
static void gst_faad_reset (GstFaad * faad); static void gst_faad_reset (GstFaad * faad);
static void gst_faad_finalize (GObject * object);
static void clear_queued (GstFaad * faad); static void clear_queued (GstFaad * faad);
@ -196,9 +197,12 @@ static void
gst_faad_class_init (GstFaadClass * klass) gst_faad_class_init (GstFaadClass * klass)
{ {
GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass); GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
parent_class = g_type_class_peek_parent (klass); parent_class = g_type_class_peek_parent (klass);
gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_faad_finalize);
gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_faad_change_state); gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_faad_change_state);
} }
@ -222,6 +226,8 @@ gst_faad_init (GstFaad * faad)
GST_DEBUG_FUNCPTR (gst_faad_src_event)); GST_DEBUG_FUNCPTR (gst_faad_src_event));
gst_element_add_pad (GST_ELEMENT (faad), faad->srcpad); gst_element_add_pad (GST_ELEMENT (faad), faad->srcpad);
faad->adapter = gst_adapter_new ();
gst_faad_reset (faad); gst_faad_reset (faad);
} }
@ -240,13 +246,20 @@ gst_faad_reset (GstFaad * faad)
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;
if (faad->tempbuf) { gst_adapter_clear (faad->adapter);
gst_buffer_unref (faad->tempbuf);
faad->tempbuf = NULL;
}
clear_queued (faad); clear_queued (faad);
} }
static void
gst_faad_finalize (GObject * object)
{
GstFaad *faad = GST_FAAD (object);
g_object_unref (faad->adapter);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void static void
gst_faad_send_tags (GstFaad * faad) gst_faad_send_tags (GstFaad * faad)
{ {
@ -348,10 +361,7 @@ gst_faad_setcaps (GstPad * pad, GstCaps * caps)
faad->init = TRUE; faad->init = TRUE;
if (faad->tempbuf) { gst_adapter_clear (faad->adapter);
gst_buffer_unref (faad->tempbuf);
faad->tempbuf = NULL;
}
} else if ((value = gst_structure_get_value (str, "framed")) && } else if ((value = gst_structure_get_value (str, "framed")) &&
g_value_get_boolean (value) == TRUE) { g_value_get_boolean (value) == TRUE) {
faad->packetised = TRUE; faad->packetised = TRUE;
@ -604,19 +614,13 @@ gst_faad_sink_event (GstPad * pad, GstEvent * event)
switch (GST_EVENT_TYPE (event)) { switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_FLUSH_STOP: case GST_EVENT_FLUSH_STOP:
if (faad->tempbuf != NULL) { gst_adapter_clear (faad->adapter);
gst_buffer_unref (faad->tempbuf);
faad->tempbuf = NULL;
}
clear_queued (faad); clear_queued (faad);
res = gst_pad_push_event (faad->srcpad, event); res = gst_pad_push_event (faad->srcpad, event);
break; break;
case GST_EVENT_EOS: case GST_EVENT_EOS:
gst_faad_drain (faad); gst_faad_drain (faad);
if (faad->tempbuf != NULL) { gst_adapter_clear (faad->adapter);
gst_buffer_unref (faad->tempbuf);
faad->tempbuf = NULL;
}
res = gst_pad_push_event (faad->srcpad, event); res = gst_pad_push_event (faad->srcpad, event);
break; break;
case GST_EVENT_NEWSEGMENT: case GST_EVENT_NEWSEGMENT:
@ -888,20 +892,18 @@ gst_faad_update_caps (GstFaad * faad, faacDecFrameInfo * info)
* gst/typefind/) for ADTS because 12 bits isn't very reliable. * gst/typefind/) for ADTS because 12 bits isn't very reliable.
*/ */
static gboolean static gboolean
gst_faad_sync (GstFaad * faad, GstBuffer * buf, guint * off) gst_faad_sync (GstFaad * faad, guint8 * data, guint size, guint * off)
{ {
guint8 *data = GST_BUFFER_DATA (buf); guint n = 0;
guint size = GST_BUFFER_SIZE (buf), n;
gint snc; gint snc;
gboolean ret = FALSE;
GST_LOG_OBJECT (faad, "Finding syncpoint"); GST_LOG_OBJECT (faad, "Finding syncpoint");
/* check for too small a buffer */ /* check for too small a buffer */
if (size < 3) if (size < 3)
return FALSE; goto exit;
/* FIXME: for no-sync, we go over the same data for every new buffer.
* We should save the information somewhere. */
for (n = 0; n < size - 3; n++) { for (n = 0; n < size - 3; n++) {
snc = GST_READ_UINT16_BE (&data[n]); snc = GST_READ_UINT16_BE (&data[n]);
if ((snc & 0xfff6) == 0xfff0) { if ((snc & 0xfff6) == 0xfff0) {
@ -914,37 +916,41 @@ gst_faad_sync (GstFaad * faad, GstBuffer * buf, guint * off)
if (size - n < 5) { if (size - n < 5) {
GST_LOG_OBJECT (faad, "Not enough data to parse ADTS header"); GST_LOG_OBJECT (faad, "Not enough data to parse ADTS header");
return FALSE; break;
} }
*off = n;
len = ((data[n + 3] & 0x03) << 11) | len = ((data[n + 3] & 0x03) << 11) |
(data[n + 4] << 3) | ((data[n + 5] & 0xe0) >> 5); (data[n + 4] << 3) | ((data[n + 5] & 0xe0) >> 5);
if (n + len + 2 >= size) { if (n + len + 2 >= size) {
GST_LOG_OBJECT (faad, "Next frame is not within reach"); GST_LOG_OBJECT (faad, "Next frame is not within reach");
return FALSE; break;
} }
snc = GST_READ_UINT16_BE (&data[n + len]); snc = GST_READ_UINT16_BE (&data[n + len]);
if ((snc & 0xfff6) == 0xfff0) { if ((snc & 0xfff6) == 0xfff0) {
GST_LOG_OBJECT (faad, GST_LOG_OBJECT (faad,
"Found ADTS syncpoint at offset 0x%x (framelen %u)", n, len); "Found ADTS syncpoint at offset 0x%x (framelen %u)", n, len);
return TRUE; ret = TRUE;
break;
} }
GST_LOG_OBJECT (faad, "No next frame found... (should be at 0x%x)", GST_LOG_OBJECT (faad, "No next frame found... (should be at 0x%x)",
n + len); n + len);
} else if (!memcmp (&data[n], "ADIF", 4)) { } else if (!memcmp (&data[n], "ADIF", 4)) {
/* we have an ADIF syncpoint. 4 bytes is enough. */ /* we have an ADIF syncpoint. 4 bytes is enough. */
*off = n;
GST_LOG_OBJECT (faad, "Found ADIF syncpoint at offset 0x%x", n); GST_LOG_OBJECT (faad, "Found ADIF syncpoint at offset 0x%x", n);
return TRUE; ret = TRUE;
break;
} }
} }
exit:
*off = n;
if (!ret)
GST_LOG_OBJECT (faad, "Found no syncpoint"); GST_LOG_OBJECT (faad, "Found no syncpoint");
return FALSE; return ret;
} }
static gboolean static gboolean
@ -970,7 +976,7 @@ gst_faad_chain (GstPad * pad, GstBuffer * buffer)
{ {
GstFlowReturn ret = GST_FLOW_OK; GstFlowReturn ret = GST_FLOW_OK;
guint input_size; guint input_size;
guint skip_bytes = 0; guint available;
guchar *input_data; guchar *input_data;
GstFaad *faad; GstFaad *faad;
GstBuffer *outbuf; GstBuffer *outbuf;
@ -978,16 +984,19 @@ gst_faad_chain (GstPad * pad, GstBuffer * buffer)
void *out; void *out;
gboolean run_loop = TRUE; gboolean run_loop = TRUE;
guint sync_off; guint sync_off;
GstClockTime ts;
faad = GST_FAAD (gst_pad_get_parent (pad)); faad = GST_FAAD (gst_pad_get_parent (pad));
GST_LOG_OBJECT (faad, "buffer of size %d with ts: %" GST_TIME_FORMAT
", duration %" GST_TIME_FORMAT, GST_BUFFER_SIZE (buffer),
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)));
if (GST_BUFFER_IS_DISCONT (buffer)) { if (GST_BUFFER_IS_DISCONT (buffer)) {
gst_faad_drain (faad); gst_faad_drain (faad);
faacDecPostSeekReset (faad->handle, 0); faacDecPostSeekReset (faad->handle, 0);
if (faad->tempbuf != NULL) { gst_adapter_clear (faad->adapter);
gst_buffer_unref (faad->tempbuf);
faad->tempbuf = NULL;
}
faad->discont = TRUE; faad->discont = TRUE;
} }
@ -995,30 +1004,25 @@ gst_faad_chain (GstPad * pad, GstBuffer * buffer)
faad->bytes_in += GST_BUFFER_SIZE (buffer); faad->bytes_in += GST_BUFFER_SIZE (buffer);
GST_OBJECT_UNLOCK (faad); GST_OBJECT_UNLOCK (faad);
if (GST_BUFFER_TIMESTAMP (buffer) != GST_CLOCK_TIME_NONE) { gst_adapter_push (faad->adapter, buffer);
/* some demuxers send multiple buffers in a row buffer = NULL;
* with the same timestamp (e.g. matroskademux) */
if (GST_BUFFER_TIMESTAMP (buffer) != faad->prev_ts) {
faad->next_ts = GST_BUFFER_TIMESTAMP (buffer);
faad->prev_ts = GST_BUFFER_TIMESTAMP (buffer);
}
GST_LOG_OBJECT (faad, "Timestamp on incoming buffer: %" GST_TIME_FORMAT
", next_ts: %" GST_TIME_FORMAT,
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
GST_TIME_ARGS (faad->next_ts));
}
/* buffer + remaining data */
if (faad->tempbuf) {
buffer = gst_buffer_join (faad->tempbuf, buffer);
faad->tempbuf = NULL;
}
input_data = GST_BUFFER_DATA (buffer); ts = gst_adapter_prev_timestamp (faad->adapter, NULL);
input_size = GST_BUFFER_SIZE (buffer); if (GST_CLOCK_TIME_IS_VALID (ts) && (ts != faad->prev_ts))
faad->prev_ts = faad->next_ts = ts;
available = gst_adapter_available (faad->adapter);
input_size = available;
if (G_UNLIKELY (!available))
goto out;
input_data = (guchar *) gst_adapter_peek (faad->adapter, available);
if (!faad->packetised) { if (!faad->packetised) {
if (!gst_faad_sync (faad, buffer, &sync_off)) { if (!gst_faad_sync (faad, input_data, input_size, &sync_off)) {
goto next; input_size -= sync_off;
goto out;
} else { } else {
input_data += sync_off; input_data += sync_off;
input_size -= sync_off; input_size -= sync_off;
@ -1053,7 +1057,6 @@ gst_faad_chain (GstPad * pad, GstBuffer * buffer)
(guint32) rate, ch); (guint32) rate, ch);
} }
skip_bytes = 0;
faad->init = TRUE; faad->init = TRUE;
/* make sure we create new caps below */ /* make sure we create new caps below */
@ -1063,7 +1066,7 @@ gst_faad_chain (GstPad * pad, GstBuffer * buffer)
} }
/* decode cycle */ /* decode cycle */
info.bytesconsumed = input_size - skip_bytes; info.bytesconsumed = input_size;
info.error = 0; info.error = 0;
if (!faad->packetised) { if (!faad->packetised) {
@ -1082,14 +1085,15 @@ gst_faad_chain (GstPad * pad, GstBuffer * buffer)
} }
} }
out = faacDecDecode (faad->handle, &info, input_data + skip_bytes, out = faacDecDecode (faad->handle, &info, input_data, input_size);
input_size - skip_bytes);
if (info.error > 0) { if (info.error > 0) {
GST_WARNING_OBJECT (faad, "decoding error: %s", GST_WARNING_OBJECT (faad, "decoding error: %s",
faacDecGetErrorMessage (info.error)); faacDecGetErrorMessage (info.error));
/* mark discont for the next buffer */ /* mark discont for the next buffer */
faad->discont = TRUE; faad->discont = TRUE;
/* flush a bit, arranges for resync next time */
input_size--;
goto out; goto out;
} }
@ -1160,22 +1164,12 @@ gst_faad_chain (GstPad * pad, GstBuffer * buffer)
} }
} }
next:
/* Keep the leftovers in raw stream */
if (input_size > 0 && !faad->packetised) {
if (input_size < GST_BUFFER_SIZE (buffer)) {
faad->tempbuf = gst_buffer_create_sub (buffer,
GST_BUFFER_SIZE (buffer) - input_size, input_size);
} else {
faad->tempbuf = buffer;
gst_buffer_ref (buffer);
}
}
out: out:
/* in raw case: (pretend) all consumed */
if (faad->packetised)
input_size = 0;
gst_adapter_flush (faad->adapter, available - input_size);
gst_buffer_unref (buffer);
gst_object_unref (faad); gst_object_unref (faad);
return ret; return ret;

View file

@ -21,6 +21,7 @@
#define __GST_FAAD_H__ #define __GST_FAAD_H__
#include <gst/gst.h> #include <gst/gst.h>
#include <gst/base/gstadapter.h>
#ifdef FAAD_IS_NEAAC #ifdef FAAD_IS_NEAAC
#include <neaacdec.h> #include <neaacdec.h>
#else #else
@ -53,7 +54,7 @@ typedef struct _GstFaad {
guint8 fake_codec_data[2]; guint8 fake_codec_data[2];
GstBuffer *tempbuf; /* used to keep input leftovers */ GstAdapter *adapter;
/* FAAD object */ /* FAAD object */
faacDecHandle handle; faacDecHandle handle;