ext/faad/gstfaad.*: If we run into a decoding error, try re-opening the decoder with faacDecInit2() using fake codec ...

Original commit message from CVS:
* ext/faad/gstfaad.c: (gst_faad_init), (aac_rate_idx),
(gst_faad_setcaps), (gst_faad_chain), (gst_faad_open_decoder),
(gst_faad_close_decoder), (gst_faad_change_state):
* ext/faad/gstfaad.h:
If we run into a decoding error, try re-opening the decoder
with faacDecInit2() using fake codec data created from the
data the demuxer gave us. Should fix a whole bunch of
GStreamer-faad problems incl. 'channel coupling not
implemented', 'maximum number of scalefactor bands exceeded'
etc. (#173007, #332892).
This commit is contained in:
Tim-Philipp Müller 2006-04-28 11:04:12 +00:00
parent bf3fd4f95d
commit 2d4c661169
3 changed files with 173 additions and 92 deletions

View file

@ -1,3 +1,16 @@
2006-04-28 Tim-Philipp Müller <tim at centricular dot net>
* ext/faad/gstfaad.c: (gst_faad_init), (aac_rate_idx),
(gst_faad_setcaps), (gst_faad_chain), (gst_faad_open_decoder),
(gst_faad_close_decoder), (gst_faad_change_state):
* ext/faad/gstfaad.h:
If we run into a decoding error, try re-opening the decoder
with faacDecInit2() using fake codec data created from the
data the demuxer gave us. Should fix a whole bunch of
GStreamer-faad problems incl. 'channel coupling not
implemented', 'maximum number of scalefactor bands exceeded'
etc. (#173007, #332892).
2006-04-26 Stefan Kost <ensonic@users.sf.net>
* ext/amrwb/gstamrwbdec.c:

View file

@ -1,5 +1,6 @@
/* GStreamer FAAD (Free AAC Decoder) plugin
* Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
* Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@ -121,6 +122,8 @@ static GstStateChangeReturn gst_faad_change_state (GstElement * element,
GstStateChange transition);
static gboolean gst_faad_src_convert (GstFaad * faad, GstFormat src_format,
gint64 src_val, GstFormat dest_format, gint64 * dest_val);
static gboolean gst_faad_open_decoder (GstFaad * faad);
static void gst_faad_close_decoder (GstFaad * faad);
static GstElementClass *parent_class; /* NULL */
@ -190,9 +193,7 @@ gst_faad_init (GstFaad * faad)
faad->sum_dur_out = 0;
faad->packetised = FALSE;
faad->sinkpad =
gst_pad_new_from_template (gst_static_pad_template_get (&sink_template),
"sink");
faad->sinkpad = gst_pad_new_from_static_template (&sink_template, "sink");
gst_element_add_pad (GST_ELEMENT (faad), faad->sinkpad);
gst_pad_set_event_function (faad->sinkpad,
GST_DEBUG_FUNCPTR (gst_faad_sink_event));
@ -201,9 +202,7 @@ gst_faad_init (GstFaad * faad)
gst_pad_set_chain_function (faad->sinkpad,
GST_DEBUG_FUNCPTR (gst_faad_chain));
faad->srcpad =
gst_pad_new_from_template (gst_static_pad_template_get (&src_template),
"src");
faad->srcpad = gst_pad_new_from_static_template (&src_template, "src");
gst_pad_use_fixed_caps (faad->srcpad);
gst_pad_set_getcaps_function (faad->srcpad,
GST_DEBUG_FUNCPTR (gst_faad_srcgetcaps));
@ -227,6 +226,35 @@ gst_faad_send_tags (GstFaad * faad)
gst_element_found_tags (GST_ELEMENT (faad), tags);
}
static gint
aac_rate_idx (gint rate)
{
if (92017 <= rate)
return 0;
else if (75132 <= rate)
return 1;
else if (55426 <= rate)
return 2;
else if (46009 <= rate)
return 3;
else if (37566 <= rate)
return 4;
else if (27713 <= rate)
return 5;
else if (23004 <= rate)
return 6;
else if (18783 <= rate)
return 7;
else if (13856 <= rate)
return 8;
else if (11502 <= rate)
return 9;
else if (9391 <= rate)
return 10;
else
return 11;
}
static gboolean
gst_faad_setcaps (GstPad * pad, GstCaps * caps)
{
@ -239,8 +267,8 @@ gst_faad_setcaps (GstPad * pad, GstCaps * caps)
faad->packetised = FALSE;
if ((value = gst_structure_get_value (str, "codec_data"))) {
guint samplerate;
guchar channels;
guint32 samplerate;
guint8 channels;
/* We have codec data, means packetised stream */
faad->packetised = TRUE;
@ -253,10 +281,9 @@ gst_faad_setcaps (GstPad * pad, GstCaps * caps)
GST_DEBUG ("faacDecInit2() failed");
return FALSE;
}
#if 0
faad->samplerate = samplerate;
faad->channels = channels;
#endif
GST_DEBUG_OBJECT (faad, "channels=%u, rate=%u", channels, samplerate);
/* not updating these here, so they are updated in the
* chain function, and new caps are created etc. */
faad->samplerate = 0;
@ -275,6 +302,25 @@ gst_faad_setcaps (GstPad * pad, GstCaps * caps)
faad->init = FALSE;
}
faad->fake_codec_data[0] = 0;
faad->fake_codec_data[1] = 0;
if (faad->packetised) {
gint rate, channels;
if (gst_structure_get_int (str, "rate", &rate) &&
gst_structure_get_int (str, "channels", &channels)) {
gint rate_idx, profile;
profile = 3; /* 0=MAIN, 1=LC, 2=SSR, 3=? */
rate_idx = aac_rate_idx (rate);
faad->fake_codec_data[0] = ((profile + 1) << 3) | ((rate_idx & 0xE) >> 1);
faad->fake_codec_data[1] = ((rate_idx & 0x1) << 7) | (channels << 3);
GST_LOG_OBJECT (faad, "created fake codec data (%u,%u)", rate, channels);
}
}
faad->need_channel_setup = TRUE;
if (!faad->packetised)
@ -407,51 +453,6 @@ gst_faad_chanpos_to_gst (guchar * fpos, guint num)
return pos;
}
/*
static GstPadLinkReturn
gst_faad_sinkconnect (GstPad * pad, const GstCaps * caps)
{
GstFaad *faad = GST_FAAD (gst_pad_get_parent (pad));
GstStructure *str = gst_caps_get_structure (caps, 0);
const GValue *value;
GstBuffer *buf;
// Assume raw stream
faad->packetised = FALSE;
if ((value = gst_structure_get_value (str, "codec_data"))) {
gulong samplerate;
guchar channels;
// We have codec data, means packetised stream
faad->packetised = TRUE;
buf = g_value_get_boxed (value);
// someone forgot that char can be unsigned when writing the API
if ((gint8) faacDecInit2 (faad->handle, GST_BUFFER_DATA (buf),
GST_BUFFER_SIZE (buf), &samplerate, &channels) < 0)
return GST_PAD_LINK_REFUSED;
//faad->samplerate = samplerate;
//faad->channels = channels;
faad->init = TRUE;
if (faad->tempbuf) {
gst_buffer_unref (faad->tempbuf);
faad->tempbuf = NULL;
}
} else {
faad->init = FALSE;
}
faad->need_channel_setup = TRUE;
// if there's no decoderspecificdata, it's all fine. We cannot know
// * much more at this point...
return GST_PAD_LINK_OK;
}
*/
static GstCaps *
gst_faad_srcgetcaps (GstPad * pad)
{
@ -1079,7 +1080,7 @@ gst_faad_chain (GstPad * pad, GstBuffer * buffer)
faad->next_ts = GST_BUFFER_TIMESTAMP (buffer);
faad->prev_ts = GST_BUFFER_TIMESTAMP (buffer);
}
GST_DEBUG ("Timestamp on incoming buffer: %" GST_TIME_FORMAT
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));
@ -1103,19 +1104,16 @@ gst_faad_chain (GstPad * pad, GstBuffer * buffer)
/* init if not already done during capsnego */
if (!faad->init) {
guint32 samplerate;
guchar channels;
glong init_res;
guint32 rate;
guint8 ch;
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 = 0; /* init_res; */
GST_DEBUG_OBJECT (faad, "initialising ...");
if (faacDecInit (faad->handle, input_data, input_size, &rate, &ch) < 0)
goto init_failed;
GST_DEBUG_OBJECT (faad, "faacDecInit() ok: rate=%u,channels=%u", rate, ch);
skip_bytes = 0;
faad->init = TRUE;
/* make sure we create new caps below */
@ -1146,11 +1144,35 @@ gst_faad_chain (GstPad * pad, GstBuffer * buffer)
out = faacDecDecode (faad->handle, &info, input_data + skip_bytes,
input_size - skip_bytes);
if (info.error) {
GST_ELEMENT_ERROR (faad, STREAM, DECODE, (NULL),
("Failed to decode buffer: %s", faacDecGetErrorMessage (info.error)));
ret = GST_FLOW_ERROR;
goto out;
guint32 rate;
guint8 ch;
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)
goto decode_error;
}
if (info.bytesconsumed > input_size)
@ -1184,7 +1206,7 @@ gst_faad_chain (GstPad * pad, GstBuffer * buffer)
}
/* play decoded data */
if (info.samples > 0 && GST_PAD_PEER (faad->srcpad)) {
if (info.samples > 0) {
guint bufsize = info.samples * faad->bps;
guint num_samples = info.samples / faad->channels;
@ -1207,7 +1229,7 @@ gst_faad_chain (GstPad * pad, GstBuffer * buffer)
faad->sum_dur_out += GST_BUFFER_DURATION (outbuf);
GST_OBJECT_UNLOCK (faad);
GST_DEBUG ("pushing buffer, off=%" G_GUINT64_FORMAT ", ts=%"
GST_LOG_OBJECT (faad, "pushing buffer, off=%" G_GUINT64_FORMAT ", ts=%"
GST_TIME_FORMAT, GST_BUFFER_OFFSET (outbuf),
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)));
if ((ret = gst_pad_push (faad->srcpad, outbuf)) != GST_FLOW_OK &&
@ -1239,6 +1261,63 @@ out:
gst_object_unref (faad);
return ret;
/* ERRORS */
init_failed:
{
GST_ELEMENT_ERROR (faad, STREAM, DECODE, (NULL),
("Failed to init decoder from stream"));
ret = GST_FLOW_ERROR;
goto out;
}
init2_failed:
{
GST_ELEMENT_ERROR (faad, STREAM, DECODE, (NULL),
("%s() failed", (faad->handle) ? "faacDecInit2" : "faacDecOpen"));
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
gst_faad_open_decoder (GstFaad * faad)
{
faacDecConfiguration *conf;
faad->handle = faacDecOpen ();
if (faad->handle == NULL) {
GST_WARNING_OBJECT (faad, "faacDecOpen() failed");
return FALSE;
}
conf = faacDecGetCurrentConfiguration (faad->handle);
conf->defObjectType = LC;
/* conf->dontUpSampleImplicitSBR = 1; */
conf->outputFormat = FAAD_FMT_16BIT;
if (faacDecSetConfiguration (faad->handle, conf) == 0) {
GST_WARNING_OBJECT (faad, "faacDecSetConfiguration() failed");
return FALSE;
}
return TRUE;
}
static void
gst_faad_close_decoder (GstFaad * faad)
{
faacDecClose (faad->handle);
faad->handle = NULL;
}
static GstStateChangeReturn
@ -1249,21 +1328,9 @@ gst_faad_change_state (GstElement * element, GstStateChange transition)
switch (transition) {
case GST_STATE_CHANGE_NULL_TO_READY:
{
if (!(faad->handle = faacDecOpen ()))
if (!gst_faad_open_decoder (faad))
return GST_STATE_CHANGE_FAILURE;
else {
faacDecConfiguration *conf;
conf = faacDecGetCurrentConfiguration (faad->handle);
conf->defObjectType = LC;
/* conf->dontUpSampleImplicitSBR = 1; */
conf->outputFormat = FAAD_FMT_16BIT;
if (faacDecSetConfiguration (faad->handle, conf) == 0)
return GST_STATE_CHANGE_FAILURE;
}
break;
}
default:
break;
}
@ -1285,8 +1352,7 @@ gst_faad_change_state (GstElement * element, GstStateChange transition)
faad->sum_dur_out = 0;
break;
case GST_STATE_CHANGE_READY_TO_NULL:
faacDecClose (faad->handle);
faad->handle = NULL;
gst_faad_close_decoder (faad);
if (faad->tempbuf) {
gst_buffer_unref (faad->tempbuf);
faad->tempbuf = NULL;

View file

@ -33,7 +33,7 @@ G_BEGIN_DECLS
(G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_FAAD, GstFaadClass))
#define GST_IS_FAAD(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_FAAD))
#define GST_IS_FAAD_CLASS(obj) \
#define GST_IS_FAAD_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_FAAD))
typedef struct _GstFaad {
@ -46,6 +46,8 @@ typedef struct _GstFaad {
guint channels; /* number of channels of the last frame */
guint bps; /* bytes per sample */
guint8 fake_codec_data[2];
GstBuffer *tempbuf; /* used to keep input leftovers */
/* FAAD object */