Index: gstfaad.c
===================================================================
RCS file: /cvs/gstreamer/gst-plugins-bad/ext/faad/gstfaad.c,v
retrieving revision 1.49
diff -u -p -r1.49 gstfaad.c
--- gstfaad.c	6 Apr 2006 11:35:21 -0000	1.49
+++ gstfaad.c	21 Apr 2006 11:40:25 -0000
@@ -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_cha
     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 */
 
@@ -227,6 +230,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 +271,8 @@ gst_faad_setcaps (GstPad * pad, GstCaps 
   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;
@@ -257,6 +289,8 @@ gst_faad_setcaps (GstPad * pad, GstCaps 
     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 +309,25 @@ gst_faad_setcaps (GstPad * pad, GstCaps 
     faad->init = FALSE;
   }
 
+  faad->fake_codec_data[0] = 0;
+  faad->fake_codec_data[1] = 0;
+
+  if (faad->packetised && !faad->init) {
+    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_DEBUG_OBJECT (faad, "created fake codec data");
+    }
+  }
+
   faad->need_channel_setup = TRUE;
 
   if (!faad->packetised)
@@ -1079,7 +1132,7 @@ gst_faad_chain (GstPad * pad, GstBuffer 
       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 +1156,16 @@ gst_faad_chain (GstPad * pad, GstBuffer 
 
   /* 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 +1196,35 @@ gst_faad_chain (GstPad * pad, GstBuffer 
 
     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 +1258,7 @@ gst_faad_chain (GstPad * pad, GstBuffer 
       }
 
       /* 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 +1281,7 @@ gst_faad_chain (GstPad * pad, GstBuffer 
         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 +1313,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 +1380,9 @@ gst_faad_change_state (GstElement * elem
 
   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 +1404,7 @@ gst_faad_change_state (GstElement * elem
       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;
Index: gstfaad.h
===================================================================
RCS file: /cvs/gstreamer/gst-plugins-bad/ext/faad/gstfaad.h,v
retrieving revision 1.8
diff -u -p -r1.8 gstfaad.h
--- gstfaad.h	20 Oct 2005 15:08:14 -0000	1.8
+++ gstfaad.h	21 Apr 2006 11:40:25 -0000
@@ -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 */
