ext/faad/gstfaad.c: Handle 'framed' field in caps; Port syncing for raw streams from 0.8 branch (for AAC+ radio strea...

Original commit message from CVS:
* ext/faad/gstfaad.c: (gst_faad_setcaps),
(gst_faad_chanpos_to_gst), (gst_faad_sync), (gst_faad_chain):
Handle 'framed' field in caps; Port syncing for raw streams
from 0.8 branch (for AAC+ radio streams) (#328722).
This commit is contained in:
Tim-Philipp Müller 2006-01-27 12:47:12 +00:00
parent 607d32dd1f
commit b0ebf7d661
2 changed files with 109 additions and 15 deletions

View file

@ -1,3 +1,10 @@
2006-01-27 Tim-Philipp Müller <tim at centricular dot net>
* ext/faad/gstfaad.c: (gst_faad_setcaps),
(gst_faad_chanpos_to_gst), (gst_faad_sync), (gst_faad_chain):
Handle 'framed' field in caps; Port syncing for raw streams
from 0.8 branch (for AAC+ radio streams) (#328722).
2006-01-27 Jan Schmidt <thaytan@mad.scientist.com>
* ext/sdl/sdlvideosink.c: (gst_sdlvideosink_supported),

View file

@ -248,6 +248,9 @@ gst_faad_setcaps (GstPad * pad, GstCaps * caps)
gst_buffer_unref (faad->tempbuf);
faad->tempbuf = NULL;
}
} else if ((value = gst_structure_get_value (str, "framed")) &&
g_value_get_boolean (value) == TRUE) {
faad->packetised = TRUE;
} else {
faad->init = FALSE;
}
@ -356,15 +359,25 @@ gst_faad_chanpos_to_gst (guchar * fpos, guint num)
}
}
if (unknown_channel) {
if (num == 2) {
GST_DEBUG ("FAAD reports unknown 2 channel mapping. Forcing to stereo");
pos[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
pos[1] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
} else {
GST_WARNING ("Unsupported FAAD channel position 0x%x encountered",
fpos[n]);
g_free (pos);
return NULL;
switch (num) {
case 1:{
GST_DEBUG ("FAAD reports unknown 1 channel mapping. Forcing to mono");
pos[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_MONO;
break;
}
case 2:{
GST_DEBUG ("FAAD reports unknown 2 channel mapping. Forcing to stereo");
pos[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
pos[1] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
break;
}
default:{
GST_WARNING ("Unsupported FAAD channel position 0x%x encountered",
fpos[n]);
g_free (pos);
pos = NULL;
break;
}
}
}
@ -760,6 +773,68 @@ gst_faad_update_caps (GstFaad * faad, faacDecFrameInfo * info,
return TRUE;
}
/*
* Find syncpoint in ADTS/ADIF stream. Doesn't work for raw,
* packetized streams. Be careful when calling.
* Returns FALSE on no-sync, fills offset/length if one/two
* syncpoints are found, only returns TRUE when it finds two
* subsequent syncpoints (similar to mp3 typefinding in
* gst/typefind/) for ADTS because 12 bits isn't very reliable.
*/
static gboolean
gst_faad_sync (GstBuffer * buf, guint * off)
{
guint8 *data = GST_BUFFER_DATA (buf);
guint size = GST_BUFFER_SIZE (buf), n;
gint snc;
GST_DEBUG ("Finding syncpoint");
/* 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++) {
snc = GST_READ_UINT16_BE (&data[n]);
if ((snc & 0xfff6) == 0xfff0) {
/* we have an ADTS syncpoint. Parse length and find
* next syncpoint. */
guint len;
GST_DEBUG ("Found one ADTS syncpoint at offset 0x%x, tracing next...", n);
if (size - n < 5) {
GST_DEBUG ("Not enough data to parse ADTS header");
return FALSE;
}
*off = n;
len = ((data[n + 3] & 0x03) << 11) |
(data[n + 4] << 3) | ((data[n + 5] & 0xe0) >> 5);
if (n + len + 2 >= size) {
GST_DEBUG ("Next frame is not within reach");
return FALSE;
}
snc = GST_READ_UINT16_BE (&data[n + len]);
if ((snc & 0xfff6) == 0xfff0) {
GST_DEBUG ("Found ADTS syncpoint at offset 0x%x (framelen %u)", n, len);
return TRUE;
}
GST_DEBUG ("No next frame found... (should be at 0x%x)", n + len);
} else if (!memcmp (&data[n], "ADIF", 4)) {
/* we have an ADIF syncpoint. 4 bytes is enough. */
*off = n;
GST_DEBUG ("Found ADIF syncpoint at offset 0x%x", n);
return TRUE;
}
}
GST_DEBUG ("Found no syncpoint");
return FALSE;
}
static GstFlowReturn
gst_faad_chain (GstPad * pad, GstBuffer * buffer)
{
@ -773,6 +848,7 @@ gst_faad_chain (GstPad * pad, GstBuffer * buffer)
faacDecFrameInfo info;
void *out;
gboolean run_loop = TRUE;
guint sync_off;
faad = GST_FAAD (gst_pad_get_parent (pad));
@ -794,22 +870,32 @@ gst_faad_chain (GstPad * pad, GstBuffer * buffer)
faad->tempbuf = NULL;
}
input_data = GST_BUFFER_DATA (buffer);
input_size = GST_BUFFER_SIZE (buffer);
if (!faad->packetised) {
if (!gst_faad_sync (buffer, &sync_off)) {
goto next;
} else {
input_data += sync_off;
input_size -= sync_off;
}
}
/* init if not already done during capsnego */
if (!faad->init) {
guint32 samplerate;
guchar channels;
glong init_res;
init_res = faacDecInit (faad->handle,
GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer), &samplerate,
&channels);
init_res = faacDecInit (faad->handle, input_data, input_size,
&samplerate, &channels);
if (init_res < 0) {
GST_ELEMENT_ERROR (faad, STREAM, DECODE, (NULL),
("Failed to init decoder from stream"));
gst_object_unref (faad);
return GST_FLOW_UNEXPECTED;
}
skip_bytes = init_res;
skip_bytes = 0; /* init_res; */
faad->init = TRUE;
/* make sure we create new caps below */
@ -818,9 +904,8 @@ gst_faad_chain (GstPad * pad, GstBuffer * buffer)
}
/* decode cycle */
input_data = GST_BUFFER_DATA (buffer);
input_size = GST_BUFFER_SIZE (buffer);
info.bytesconsumed = input_size - skip_bytes;
info.error = 0;
if (!faad->packetised) {
/* We must check that ourselves for raw stream */
@ -909,6 +994,8 @@ 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)) {