aacparse: Fix caps change handling
[platform/upstream/gstreamer.git] / gst / audioparsers / gstaacparse.c
index 21b8c8c..2b54a53 100644 (file)
@@ -21,6 +21,7 @@
 
 /**
  * SECTION:element-aacparse
+ * @title: aacparse
  * @short_description: AAC parser
  * @see_also: #GstAmrParse
  *
  * be determined either. However, ADTS format AAC clips can be seeked, and parser
  * can also estimate playback position and clip duration.
  *
- * <refsect2>
- * <title>Example launch line</title>
+ * ## Example launch line
  * |[
  * gst-launch-1.0 filesrc location=abc.aac ! aacparse ! faad ! audioresample ! audioconvert ! alsasink
  * ]|
- * </refsect2>
+ *
  */
 
 #ifdef HAVE_CONFIG_H
@@ -68,6 +68,7 @@ GST_DEBUG_CATEGORY_STATIC (aacparse_debug);
 #define ADIF_MAX_SIZE 40        /* Should be enough */
 #define ADTS_MAX_SIZE 10        /* Should be enough */
 #define LOAS_MAX_SIZE 3         /* Should be enough */
+#define RAW_MAX_SIZE  1         /* Correct framing is required */
 
 #define ADTS_HEADERS_LENGTH 7UL /* Total byte-length of fixed and variable
                                    headers prepended during raw to ADTS
@@ -100,6 +101,11 @@ static GstFlowReturn gst_aac_parse_pre_push_frame (GstBaseParse * parse,
 static gboolean gst_aac_parse_src_event (GstBaseParse * parse,
     GstEvent * event);
 
+static gboolean gst_aac_parse_read_audio_specific_config (GstAacParse *
+    aacparse, GstBitReader * br, gint * object_type, gint * sample_rate,
+    gint * channels, gint * frame_samples);
+
+
 #define gst_aac_parse_parent_class parent_class
 G_DEFINE_TYPE (GstAacParse, gst_aac_parse, GST_TYPE_BASE_PARSE);
 
@@ -167,7 +173,7 @@ static gboolean
 gst_aac_parse_set_src_caps (GstAacParse * aacparse, GstCaps * sink_caps)
 {
   GstStructure *s;
-  GstCaps *src_caps = NULL, *allowed;
+  GstCaps *src_caps = NULL, *peercaps;
   gboolean res = FALSE;
   const gchar *stream_format;
   guint8 codec_data[2];
@@ -220,8 +226,8 @@ gst_aac_parse_set_src_caps (GstAacParse * aacparse, GstCaps * sink_caps)
   if (stream_format)
     gst_structure_set (s, "stream-format", G_TYPE_STRING, stream_format, NULL);
 
-  allowed = gst_pad_get_allowed_caps (GST_BASE_PARSE (aacparse)->srcpad);
-  if (allowed && !gst_caps_can_intersect (src_caps, allowed)) {
+  peercaps = gst_pad_peer_query_caps (GST_BASE_PARSE_SRC_PAD (aacparse), NULL);
+  if (peercaps && !gst_caps_can_intersect (src_caps, peercaps)) {
     GST_DEBUG_OBJECT (GST_BASE_PARSE (aacparse)->srcpad,
         "Caps can not intersect");
     if (aacparse->header_type == DSPAAC_HEADER_ADTS) {
@@ -229,7 +235,7 @@ gst_aac_parse_set_src_caps (GstAacParse * aacparse, GstCaps * sink_caps)
           "Input is ADTS, trying raw");
       gst_caps_set_simple (src_caps, "stream-format", G_TYPE_STRING, "raw",
           NULL);
-      if (gst_caps_can_intersect (src_caps, allowed)) {
+      if (gst_caps_can_intersect (src_caps, peercaps)) {
         GstBuffer *codec_data_buffer;
 
         GST_DEBUG_OBJECT (GST_BASE_PARSE (aacparse)->srcpad,
@@ -242,21 +248,22 @@ gst_aac_parse_set_src_caps (GstAacParse * aacparse, GstCaps * sink_caps)
         gst_buffer_fill (codec_data_buffer, 0, codec_data, 2);
         gst_caps_set_simple (src_caps, "codec_data", GST_TYPE_BUFFER,
             codec_data_buffer, NULL);
+        gst_buffer_unref (codec_data_buffer);
       }
     } else if (aacparse->header_type == DSPAAC_HEADER_NONE) {
       GST_DEBUG_OBJECT (GST_BASE_PARSE (aacparse)->srcpad,
           "Input is raw, trying ADTS");
       gst_caps_set_simple (src_caps, "stream-format", G_TYPE_STRING, "adts",
           NULL);
-      if (gst_caps_can_intersect (src_caps, allowed)) {
+      if (gst_caps_can_intersect (src_caps, peercaps)) {
         GST_DEBUG_OBJECT (GST_BASE_PARSE (aacparse)->srcpad,
             "Caps can intersect, we will prepend ADTS headers");
         aacparse->output_header_type = DSPAAC_HEADER_ADTS;
       }
     }
   }
-  if (allowed)
-    gst_caps_unref (allowed);
+  if (peercaps)
+    gst_caps_unref (peercaps);
 
   aacparse->last_parsed_channels = 0;
   aacparse->last_parsed_sample_rate = 0;
@@ -308,25 +315,17 @@ gst_aac_parse_sink_setcaps (GstBaseParse * parse, GstCaps * caps)
 
     if (buf && gst_buffer_get_size (buf) >= 2) {
       GstMapInfo map;
-      guint sr_idx;
+      GstBitReader br;
 
       if (!gst_buffer_map (buf, &map, GST_MAP_READ))
         return FALSE;
+      gst_bit_reader_init (&br, map.data, map.size);
+      gst_aac_parse_read_audio_specific_config (aacparse, &br,
+          &aacparse->object_type, &aacparse->sample_rate, &aacparse->channels,
+          &aacparse->frame_samples);
 
-      sr_idx = ((map.data[0] & 0x07) << 1) | ((map.data[1] & 0x80) >> 7);
-      aacparse->object_type = (map.data[0] & 0xf8) >> 3;
-      aacparse->sample_rate =
-          gst_codec_utils_aac_get_sample_rate_from_index (sr_idx);
-      aacparse->channels = (map.data[1] & 0x78) >> 3;
-      if (aacparse->channels == 7)
-        aacparse->channels = 8;
-      else if (aacparse->channels == 11)
-        aacparse->channels = 7;
-      else if (aacparse->channels == 12 || aacparse->channels == 14)
-        aacparse->channels = 8;
       aacparse->header_type = DSPAAC_HEADER_NONE;
       aacparse->mpegversion = 4;
-      aacparse->frame_samples = (map.data[1] & 4) ? 960 : 1024;
       gst_buffer_unmap (buf, &map);
 
       GST_DEBUG ("codec_data: object_type=%d, sample_rate=%d, channels=%d, "
@@ -337,6 +336,9 @@ gst_aac_parse_sink_setcaps (GstBaseParse * parse, GstCaps * caps)
       gst_aac_parse_set_src_caps (aacparse, caps);
       if (aacparse->header_type == aacparse->output_header_type)
         gst_base_parse_set_passthrough (parse, TRUE);
+
+      /* input is already correctly framed */
+      gst_base_parse_set_min_frame_size (parse, RAW_MAX_SIZE);
     } else {
       return FALSE;
     }
@@ -540,8 +542,9 @@ gst_aac_parse_get_audio_sample_rate (GstAacParse * aacparse, GstBitReader * br,
 
 /* See table 1.13 in ISO/IEC 14496-3 */
 static gboolean
-gst_aac_parse_read_loas_audio_specific_config (GstAacParse * aacparse,
-    GstBitReader * br, gint * sample_rate, gint * channels, guint32 * bits)
+gst_aac_parse_read_audio_specific_config (GstAacParse * aacparse,
+    GstBitReader * br, gint * object_type, gint * sample_rate, gint * channels,
+    gint * frame_samples)
 {
   guint8 audio_object_type;
   guint8 G_GNUC_UNUSED extension_audio_object_type;
@@ -550,6 +553,8 @@ gst_aac_parse_read_loas_audio_specific_config (GstAacParse * aacparse,
 
   if (!gst_aac_parse_get_audio_object_type (aacparse, br, &audio_object_type))
     return FALSE;
+  if (object_type)
+    *object_type = audio_object_type;
 
   if (!gst_aac_parse_get_audio_sample_rate (aacparse, br, sample_rate))
     return FALSE;
@@ -573,7 +578,8 @@ gst_aac_parse_read_loas_audio_specific_config (GstAacParse * aacparse,
     }
 
     GST_LOG_OBJECT (aacparse,
-        "Audio object type 5 or 29, so rereading sampling rate...");
+        "Audio object type 5 or 29, so rereading sampling rate (was %d)...",
+        *sample_rate);
     if (!gst_aac_parse_get_audio_sample_rate (aacparse, br, sample_rate))
       return FALSE;
 
@@ -595,15 +601,23 @@ gst_aac_parse_read_loas_audio_specific_config (GstAacParse * aacparse,
     extension_audio_object_type = 0;
   }
 
-  GST_INFO_OBJECT (aacparse, "Found LOAS config: %d Hz, %d channels",
+  GST_INFO_OBJECT (aacparse, "Parsed AudioSpecificConfig: %d Hz, %d channels",
       *sample_rate, *channels);
 
+  if (frame_samples && audio_object_type == 23) {
+    guint8 frame_flag;
+    /* Read the Decoder Configuration (GASpecificConfig) if present */
+    /* We only care about the first bit to know what the number of samples
+     * in a frame is */
+    if (!gst_bit_reader_get_bits_uint8 (br, &frame_flag, 1))
+      return FALSE;
+    *frame_samples = frame_flag ? 960 : 1024;
+  }
+
   /* There's LOTS of stuff next, but we ignore it for now as we have
      what we want (sample rate and number of channels */
   GST_DEBUG_OBJECT (aacparse,
       "Need more code to parse humongous LOAS data, currently ignored");
-  if (bits)
-    *bits = 0;
   aacparse->last_parsed_channels = *channels;
   return TRUE;
 }
@@ -687,17 +701,16 @@ gst_aac_parse_read_loas_config (GstAacParse * aacparse, const guint8 * data,
         }
         if (!use_same_config) {
           if (v == 0) {
-            if (!gst_aac_parse_read_loas_audio_specific_config (aacparse, &br,
+            if (!gst_aac_parse_read_audio_specific_config (aacparse, &br, NULL,
                     sample_rate, channels, NULL))
               return FALSE;
           } else {
-            guint32 bits, asc_len;
+            guint32 asc_len;
             if (!gst_aac_parse_latm_get_value (aacparse, &br, &asc_len))
               return FALSE;
-            if (!gst_aac_parse_read_loas_audio_specific_config (aacparse, &br,
-                    sample_rate, channels, &bits))
+            if (!gst_aac_parse_read_audio_specific_config (aacparse, &br, NULL,
+                    sample_rate, channels, NULL))
               return FALSE;
-            asc_len -= bits;
             if (!gst_bit_reader_skip (&br, asc_len))
               return FALSE;
           }
@@ -1224,7 +1237,7 @@ gst_aac_parse_prepend_adts_headers (GstAacParse * aacparse,
   adts_headers[0] = 0xFFU;
   adts_headers[1] = 0xF0U | (id << 3) | 0x1U;
   adts_headers[2] = (profile << 6) | (sampling_frequency_index << 2) | 0x2U |
-      (channel_configuration & 0x4U);
+      ((channel_configuration & 0x4U) >> 2);
   adts_headers[3] = ((channel_configuration & 0x3U) << 6) | 0x30U |
       (guint8) (frame_size >> 11);
   adts_headers[4] = (guint8) ((frame_size >> 3) & 0x00FF);
@@ -1467,6 +1480,8 @@ gst_aac_parse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
         gst_buffer_get_size (frame->out_buffer) - header_size);
   }
 
+  frame->flags |= GST_BASE_PARSE_FRAME_FLAG_CLIP;
+
   return GST_FLOW_OK;
 }
 
@@ -1491,6 +1506,12 @@ gst_aac_parse_start (GstBaseParse * parse)
   aacparse->sent_codec_tag = FALSE;
   aacparse->last_parsed_channels = 0;
   aacparse->last_parsed_sample_rate = 0;
+  aacparse->object_type = 0;
+  aacparse->bitrate = 0;
+  aacparse->header_type = DSPAAC_HEADER_NOT_PARSED;
+  aacparse->output_header_type = DSPAAC_HEADER_NOT_PARSED;
+  aacparse->channels = 0;
+  aacparse->sample_rate = 0;
   return TRUE;
 }