Send seek event to baseparse when aacparse seek failed in push mode
[platform/upstream/gst-plugins-good.git] / gst / audioparsers / gstaacparse.c
index 82bdc50..cd15f01 100644 (file)
@@ -68,21 +68,31 @@ 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
                                    conversion */
 
+#ifdef TIZEN_FEATURE_AACPARSE_MODIFICATION      /* to get more accurate duration */
+#define AAC_MAX_ESTIMATE_DURATION_BUF (1024 * 1024)     /* use first 1 Mbyte */
+#define AAC_SAMPLE_PER_FRAME 1024
+
+#define AAC_MAX_PULL_RANGE_BUF  (1 * 1024 * 1024)       /* 1 MByte */
+#define AAC_LARGE_FILE_SIZE     (2 * 1024 * 1024)       /* 2 MByte */
+#define gst_aac_parse_parent_class parent_class
+#endif
+
 #define AAC_FRAME_DURATION(parse) (GST_SECOND/parse->frames_per_sec)
 
-static const gint loas_sample_rate_table[32] = {
+static const gint loas_sample_rate_table[16] = {
   96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
   16000, 12000, 11025, 8000, 7350, 0, 0, 0
 };
 
-static const gint loas_channels_table[32] = {
+static const gint loas_channels_table[16] = {
   0, 1, 2, 3, 4, 5, 6, 8,
-  0, 0, 0, 0, 0, 0, 0, 0
+  0, 0, 0, 7, 8, 0, 8, 0
 };
 
 static gboolean gst_aac_parse_start (GstBaseParse * parse);
@@ -97,9 +107,41 @@ static GstFlowReturn gst_aac_parse_handle_frame (GstBaseParse * parse,
     GstBaseParseFrame * frame, gint * skipsize);
 static GstFlowReturn gst_aac_parse_pre_push_frame (GstBaseParse * parse,
     GstBaseParseFrame * frame);
+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);
+
+#ifdef TIZEN_FEATURE_AACPARSE_MODIFICATION
+static guint gst_aac_parse_adts_get_fast_frame_len (const guint8 * data);
+/* make full aac(adts) index table when seek */
+static gboolean gst_aac_parse_adts_src_eventfunc (GstBaseParse * parse,
+    GstEvent * event);
+int get_aac_parse_get_adts_frame_length (const unsigned char *data,
+    gint64 offset);
+static gboolean gst_aac_parse_estimate_duration (GstBaseParse * parse);
+static void gst_aac_parse_check_byte_seekability (GstBaseParse * parse);
+#endif
 
+#define gst_aac_parse_parent_class parent_class
 G_DEFINE_TYPE (GstAacParse, gst_aac_parse, GST_TYPE_BASE_PARSE);
 
+#ifdef TIZEN_FEATURE_AACPARSE_MODIFICATION
+static inline gint
+gst_aac_parse_get_sample_rate_from_index (guint sr_idx)
+{
+  static const guint aac_sample_rates[] = { 96000, 88200, 64000, 48000, 44100,
+    32000, 24000, 22050, 16000, 12000, 11025, 8000
+  };
+
+  if (sr_idx < G_N_ELEMENTS (aac_sample_rates))
+    return aac_sample_rates[sr_idx];
+  GST_WARNING ("Invalid sample rate index %u", sr_idx);
+  return 0;
+}
+#endif
 /**
  * gst_aac_parse_class_init:
  * @klass: #GstAacParseClass.
@@ -114,10 +156,8 @@ gst_aac_parse_class_init (GstAacParseClass * klass)
   GST_DEBUG_CATEGORY_INIT (aacparse_debug, "aacparse", 0,
       "AAC audio stream parser");
 
-  gst_element_class_add_pad_template (element_class,
-      gst_static_pad_template_get (&sink_template));
-  gst_element_class_add_pad_template (element_class,
-      gst_static_pad_template_get (&src_template));
+  gst_element_class_add_static_pad_template (element_class, &sink_template);
+  gst_element_class_add_static_pad_template (element_class, &src_template);
 
   gst_element_class_set_static_metadata (element_class,
       "AAC audio stream parser", "Codec/Parser/Audio",
@@ -130,6 +170,7 @@ gst_aac_parse_class_init (GstAacParseClass * klass)
   parse_class->handle_frame = GST_DEBUG_FUNCPTR (gst_aac_parse_handle_frame);
   parse_class->pre_push_frame =
       GST_DEBUG_FUNCPTR (gst_aac_parse_pre_push_frame);
+  parse_class->src_event = GST_DEBUG_FUNCPTR (gst_aac_parse_src_event);
 }
 
 
@@ -144,6 +185,14 @@ gst_aac_parse_init (GstAacParse * aacparse)
 {
   GST_DEBUG ("initialized");
   GST_PAD_SET_ACCEPT_INTERSECT (GST_BASE_PARSE_SINK_PAD (aacparse));
+  GST_PAD_SET_ACCEPT_TEMPLATE (GST_BASE_PARSE_SINK_PAD (aacparse));
+
+  aacparse->last_parsed_sample_rate = 0;
+  aacparse->last_parsed_channels = 0;
+#ifdef TIZEN_FEATURE_AACPARSE_MODIFICATION
+  /* to get more correct duration */
+  aacparse->first_frame = TRUE;
+#endif
 }
 
 
@@ -164,8 +213,9 @@ gst_aac_parse_set_src_caps (GstAacParse * aacparse, GstCaps * sink_caps)
   GstCaps *src_caps = NULL, *allowed;
   gboolean res = FALSE;
   const gchar *stream_format;
-  GstBuffer *codec_data;
+  guint8 codec_data[2];
   guint16 codec_data_data;
+  gint sample_rate_idx;
 
   GST_DEBUG_OBJECT (aacparse, "sink caps: %" GST_PTR_FORMAT, sink_caps);
   if (sink_caps)
@@ -194,6 +244,17 @@ gst_aac_parse_set_src_caps (GstAacParse * aacparse, GstCaps * sink_caps)
       stream_format = NULL;
   }
 
+  /* Generate codec data to be able to set profile/level on the caps */
+  sample_rate_idx =
+      gst_codec_utils_aac_get_index_from_sample_rate (aacparse->sample_rate);
+  if (sample_rate_idx < 0)
+    goto not_a_known_rate;
+  codec_data_data =
+      (aacparse->object_type << 11) |
+      (sample_rate_idx << 7) | (aacparse->channels << 3);
+  GST_WRITE_UINT16_BE (codec_data, codec_data_data);
+  gst_codec_utils_aac_caps_set_level_and_profile (src_caps, codec_data, 2);
+
   s = gst_caps_get_structure (src_caps, 0);
   if (aacparse->sample_rate > 0)
     gst_structure_set (s, "rate", G_TYPE_INT, aacparse->sample_rate, NULL);
@@ -202,8 +263,21 @@ 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);
 
+#ifdef TIZEN_FEATURE_AACPARSE_MODIFICATION
+  if (!gst_structure_get_value (s, "codec_data")) {
+    GstBuffer *codec_data_buffer;
+    GST_WARNING("Insert codec_data to src_caps");
+    /* The codec_data data is according to AudioSpecificConfig,
+       ISO/IEC 14496-3, 1.6.2.1 */
+    codec_data_buffer = gst_buffer_new_and_alloc (2);
+    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);
+  }
+#endif
+
   allowed = gst_pad_get_allowed_caps (GST_BASE_PARSE (aacparse)->srcpad);
-  if (!gst_caps_can_intersect (src_caps, allowed)) {
+  if (allowed && !gst_caps_can_intersect (src_caps, allowed)) {
     GST_DEBUG_OBJECT (GST_BASE_PARSE (aacparse)->srcpad,
         "Caps can not intersect");
     if (aacparse->header_type == DSPAAC_HEADER_ADTS) {
@@ -212,14 +286,7 @@ gst_aac_parse_set_src_caps (GstAacParse * aacparse, GstCaps * sink_caps)
       gst_caps_set_simple (src_caps, "stream-format", G_TYPE_STRING, "raw",
           NULL);
       if (gst_caps_can_intersect (src_caps, allowed)) {
-        GstMapInfo map;
-        int idx;
-
-        idx =
-            gst_codec_utils_aac_get_index_from_sample_rate
-            (aacparse->sample_rate);
-        if (idx < 0)
-          goto not_a_known_rate;
+        GstBuffer *codec_data_buffer;
 
         GST_DEBUG_OBJECT (GST_BASE_PARSE (aacparse)->srcpad,
             "Caps can intersect, we will drop the ADTS layer");
@@ -227,15 +294,11 @@ gst_aac_parse_set_src_caps (GstAacParse * aacparse, GstCaps * sink_caps)
 
         /* The codec_data data is according to AudioSpecificConfig,
            ISO/IEC 14496-3, 1.6.2.1 */
-        codec_data = gst_buffer_new_and_alloc (2);
-        gst_buffer_map (codec_data, &map, GST_MAP_WRITE);
-        codec_data_data =
-            (aacparse->object_type << 11) |
-            (idx << 7) | (aacparse->channels << 3);
-        GST_WRITE_UINT16_BE (map.data, codec_data_data);
-        gst_buffer_unmap (codec_data, &map);
+        codec_data_buffer = gst_buffer_new_and_alloc (2);
+        gst_buffer_fill (codec_data_buffer, 0, codec_data, 2);
         gst_caps_set_simple (src_caps, "codec_data", GST_TYPE_BUFFER,
-            codec_data, NULL);
+            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,
@@ -249,7 +312,11 @@ gst_aac_parse_set_src_caps (GstAacParse * aacparse, GstCaps * sink_caps)
       }
     }
   }
-  gst_caps_unref (allowed);
+  if (allowed)
+    gst_caps_unref (allowed);
+
+  aacparse->last_parsed_channels = 0;
+  aacparse->last_parsed_sample_rate = 0;
 
   GST_DEBUG_OBJECT (aacparse, "setting src caps: %" GST_PTR_FORMAT, src_caps);
 
@@ -258,7 +325,8 @@ gst_aac_parse_set_src_caps (GstAacParse * aacparse, GstCaps * sink_caps)
   return res;
 
 not_a_known_rate:
-  gst_caps_unref (allowed);
+  GST_ERROR_OBJECT (aacparse, "Not a known sample rate: %d",
+      aacparse->sample_rate);
   gst_caps_unref (src_caps);
   return FALSE;
 }
@@ -295,20 +363,19 @@ gst_aac_parse_sink_setcaps (GstBaseParse * parse, GstCaps * caps)
   if (value) {
     GstBuffer *buf = gst_value_get_buffer (value);
 
-    if (buf) {
+    if (buf && gst_buffer_get_size (buf) >= 2) {
       GstMapInfo map;
-      guint sr_idx;
+      GstBitReader br;
 
-      gst_buffer_map (buf, &map, GST_MAP_READ);
+      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;
       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, "
@@ -319,19 +386,30 @@ 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);
-    } else
+
+      /* input is already correctly framed */
+      gst_base_parse_set_min_frame_size (parse, RAW_MAX_SIZE);
+    } else {
       return FALSE;
+    }
 
     /* caps info overrides */
     gst_structure_get_int (structure, "rate", &aacparse->sample_rate);
     gst_structure_get_int (structure, "channels", &aacparse->channels);
   } else {
-    aacparse->sample_rate = 0;
-    aacparse->channels = 0;
-    aacparse->header_type = DSPAAC_HEADER_NOT_PARSED;
-    gst_base_parse_set_passthrough (parse, FALSE);
-  }
+    const gchar *stream_format =
+        gst_structure_get_string (structure, "stream-format");
 
+    if (g_strcmp0 (stream_format, "raw") == 0) {
+      GST_ERROR_OBJECT (parse, "Need codec_data for raw AAC");
+      return FALSE;
+    } else {
+      aacparse->sample_rate = 0;
+      aacparse->channels = 0;
+      aacparse->header_type = DSPAAC_HEADER_NOT_PARSED;
+      gst_base_parse_set_passthrough (parse, FALSE);
+    }
+  }
   return TRUE;
 }
 
@@ -387,14 +465,43 @@ gst_aac_parse_check_adts_frame (GstAacParse * aacparse,
     const guint8 * data, const guint avail, gboolean drain,
     guint * framesize, guint * needed_data)
 {
+  guint crc_size;
+
   *needed_data = 0;
 
-  if (G_UNLIKELY (avail < 2))
+  /* Absolute minimum to perform the ADTS syncword,
+     layer and sampling frequency tests */
+  if (G_UNLIKELY (avail < 3)) {
+    *needed_data = 3;
     return FALSE;
+  }
 
+  /* Syncword and layer tests */
   if ((data[0] == 0xff) && ((data[1] & 0xf6) == 0xf0)) {
+
+    /* Sampling frequency test */
+    if (G_UNLIKELY ((data[2] & 0x3C) >> 2 == 15))
+      return FALSE;
+
+    /* This looks like an ADTS frame header but
+       we need at least 6 bytes to proceed */
+    if (G_UNLIKELY (avail < 6)) {
+      *needed_data = 6;
+      return FALSE;
+    }
+
     *framesize = gst_aac_parse_adts_get_frame_len (data);
 
+    /* If frame has CRC, it needs 2 bytes
+       for it at the end of the header */
+    crc_size = (data[1] & 0x01) ? 0 : 2;
+
+    /* CRC size test */
+    if (*framesize < 7 + crc_size) {
+      *needed_data = 7 + crc_size;
+      return FALSE;
+    }
+
     /* In EOS mode this is enough. No need to examine the data further.
        We also relax the check when we have sync, on the assumption that
        if we're not looking at random data, we have a much higher chance
@@ -436,7 +543,7 @@ gst_aac_parse_latm_get_value (GstAacParse * aacparse, GstBitReader * br,
   *value = 0;
   if (!gst_bit_reader_get_bits_uint8 (br, &bytes, 2))
     return FALSE;
-  for (i = 0; i < bytes; ++i) {
+  for (i = 0; i <= bytes; ++i) {
     *value <<= 8;
     if (!gst_bit_reader_get_bits_uint8 (br, &byte, 8))
       return FALSE;
@@ -479,45 +586,89 @@ gst_aac_parse_get_audio_sample_rate (GstAacParse * aacparse, GstBitReader * br,
     if (!*sample_rate)
       return FALSE;
   }
+  aacparse->last_parsed_sample_rate = *sample_rate;
   return TRUE;
 }
 
 /* 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, channel_configuration;
+  guint8 audio_object_type;
+  guint8 G_GNUC_UNUSED extension_audio_object_type;
+  guint8 channel_configuration, extension_channel_configuration;
+  gboolean G_GNUC_UNUSED sbr = FALSE, ps = FALSE;
 
   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;
 
   if (!gst_bit_reader_get_bits_uint8 (br, &channel_configuration, 4))
     return FALSE;
-  GST_LOG_OBJECT (aacparse, "channel_configuration: %d", channel_configuration);
   *channels = loas_channels_table[channel_configuration];
+  GST_LOG_OBJECT (aacparse, "channel_configuration: %d", channel_configuration);
   if (!*channels)
     return FALSE;
 
-  if (audio_object_type == 5) {
+  if (audio_object_type == 5 || audio_object_type == 29) {
+    extension_audio_object_type = 5;
+    sbr = TRUE;
+    if (audio_object_type == 29) {
+      ps = TRUE;
+      /* Parametric stereo. If we have a one-channel configuration, we can
+       * override it to stereo */
+      if (*channels == 1)
+        *channels = 2;
+    }
+
     GST_LOG_OBJECT (aacparse,
-        "Audio object type 5, 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;
+
+    if (!gst_aac_parse_get_audio_object_type (aacparse, br, &audio_object_type))
+      return FALSE;
+
+    if (audio_object_type == 22) {
+      /* extension channel configuration */
+      if (!gst_bit_reader_get_bits_uint8 (br, &extension_channel_configuration,
+              4))
+        return FALSE;
+      GST_LOG_OBJECT (aacparse, "extension channel_configuration: %d",
+          extension_channel_configuration);
+      *channels = loas_channels_table[extension_channel_configuration];
+      if (!*channels)
+        return FALSE;
+    }
+  } else {
+    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;
 }
 
@@ -543,20 +694,24 @@ gst_aac_parse_read_loas_config (GstAacParse * aacparse, const guint8 * data,
   if (!gst_bit_reader_get_bits_uint8 (&br, &u8, 1))
     return FALSE;
   if (u8) {
-    GST_DEBUG_OBJECT (aacparse, "Frame uses previous config");
-    if (!aacparse->sample_rate || !aacparse->channels) {
-      GST_WARNING_OBJECT (aacparse, "No previous config to use");
+    GST_LOG_OBJECT (aacparse, "Frame uses previous config");
+    if (!aacparse->last_parsed_sample_rate || !aacparse->last_parsed_channels) {
+      GST_DEBUG_OBJECT (aacparse,
+          "No previous config to use. We'll look for more data.");
+      return FALSE;
     }
-    *sample_rate = aacparse->sample_rate;
-    *channels = aacparse->channels;
+    *sample_rate = aacparse->last_parsed_sample_rate;
+    *channels = aacparse->last_parsed_channels;
     return TRUE;
   }
 
   GST_DEBUG_OBJECT (aacparse, "Frame contains new config");
 
+  /* audioMuxVersion */
   if (!gst_bit_reader_get_bits_uint8 (&br, &v, 1))
     return FALSE;
   if (v) {
+    /* audioMuxVersionA */
     if (!gst_bit_reader_get_bits_uint8 (&br, &vA, 1))
       return FALSE;
   } else
@@ -567,6 +722,7 @@ gst_aac_parse_read_loas_config (GstAacParse * aacparse, const guint8 * data,
     guint8 same_time, subframes, num_program, prog;
     if (v == 1) {
       guint32 value;
+      /* taraBufferFullness */
       if (!gst_aac_parse_latm_get_value (aacparse, &br, &value))
         return FALSE;
     }
@@ -595,17 +751,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;
           }
@@ -615,6 +770,7 @@ gst_aac_parse_read_loas_config (GstAacParse * aacparse, const guint8 * data,
     GST_LOG_OBJECT (aacparse, "More data ignored");
   } else {
     GST_WARNING_OBJECT (aacparse, "Spec says \"TBD\"...");
+    return FALSE;
   }
   return TRUE;
 }
@@ -676,12 +832,15 @@ gst_aac_parse_check_loas_frame (GstAacParse * aacparse,
   *needed_data = 0;
 
   /* 3 byte header */
-  if (G_UNLIKELY (avail < 3))
+  if (G_UNLIKELY (avail < 3)) {
+    *needed_data = 3;
     return FALSE;
+  }
 
   if ((data[0] == 0x56) && ((data[1] & 0xe0) == 0xe0)) {
     *framesize = gst_aac_parse_loas_get_frame_len (data);
-    GST_DEBUG_OBJECT (aacparse, "Found %u byte LOAS frame", *framesize);
+    GST_DEBUG_OBJECT (aacparse, "Found possible %u byte LOAS frame",
+        *framesize);
 
     /* In EOS mode this is enough. No need to examine the data further.
        We also relax the check when we have sync, on the assumption that
@@ -710,6 +869,8 @@ gst_aac_parse_check_loas_frame (GstAacParse * aacparse,
       gst_base_parse_set_min_frame_size (GST_BASE_PARSE (aacparse),
           nextlen + LOAS_MAX_SIZE);
       return TRUE;
+    } else {
+      GST_DEBUG_OBJECT (aacparse, "That was a false positive");
     }
   }
   return FALSE;
@@ -726,8 +887,11 @@ gst_aac_parse_parse_adts_header (GstAacParse * aacparse, const guint8 * data,
 
     *rate = gst_codec_utils_aac_get_sample_rate_from_index (sr_idx);
   }
-  if (channels)
+  if (channels) {
     *channels = ((data[2] & 0x01) << 2) | ((data[3] & 0xc0) >> 6);
+    if (*channels == 7)
+      *channels = 8;
+  }
 
   if (version)
     *version = (data[1] & 0x08) ? 2 : 4;
@@ -776,7 +940,7 @@ gst_aac_parse_detect_stream (GstAacParse * aacparse,
 
   for (i = 0; i < avail - 4; i++) {
     if (((data[i] == 0xff) && ((data[i + 1] & 0xf6) == 0xf0)) ||
-        ((data[0] == 0x56) && ((data[1] & 0xe0) == 0xe0)) ||
+        ((data[i] == 0x56) && ((data[i + 1] & 0xe0) == 0xe0)) ||
         strncmp ((char *) data + i, "ADIF", 4) == 0) {
       GST_DEBUG_OBJECT (aacparse, "Found signature at offset %u", i);
       found = TRUE;
@@ -825,7 +989,7 @@ gst_aac_parse_detect_stream (GstAacParse * aacparse,
 
   if (gst_aac_parse_check_loas_frame (aacparse, data, avail, drain,
           framesize, &need_data_loas)) {
-    gint rate, channels;
+    gint rate = 0, channels = 0;
 
     GST_INFO ("LOAS, framesize: %d", *framesize);
 
@@ -833,7 +997,9 @@ gst_aac_parse_detect_stream (GstAacParse * aacparse,
 
     if (!gst_aac_parse_read_loas_config (aacparse, data, avail, &rate,
             &channels, &aacparse->mpegversion)) {
-      GST_WARNING_OBJECT (aacparse, "Error reading LOAS config");
+      /* This is pretty normal when skipping data at the start of
+       * random stream (MPEG-TS capture for example) */
+      GST_LOG_OBJECT (aacparse, "Error reading LOAS config");
       return FALSE;
     }
 
@@ -841,10 +1007,10 @@ gst_aac_parse_detect_stream (GstAacParse * aacparse,
       gst_base_parse_set_frame_rate (GST_BASE_PARSE (aacparse), rate,
           aacparse->frame_samples, 2, 2);
 
+      /* Don't store the sample rate and channels yet -
+       * this is just format detection. */
       GST_DEBUG ("LOAS: samplerate %d, channels %d, objtype %d, version %d",
           rate, channels, aacparse->object_type, aacparse->mpegversion);
-      aacparse->sample_rate = rate;
-      aacparse->channels = channels;
     }
 
     gst_base_parse_set_syncable (GST_BASE_PARSE (aacparse), TRUE);
@@ -968,6 +1134,10 @@ gst_aac_parse_get_audio_profile_object_type (GstAacParse * aacparse)
   guint8 ret;
 
   srccaps = gst_pad_get_current_caps (GST_BASE_PARSE_SRC_PAD (aacparse));
+  if (G_UNLIKELY (srccaps == NULL)) {
+    return G_MAXUINT8;
+  }
+
   srcstruct = gst_caps_get_structure (srccaps, 0);
   profile = gst_structure_get_string (srcstruct, "profile");
   if (G_UNLIKELY (profile == NULL)) {
@@ -1013,6 +1183,10 @@ gst_aac_parse_get_audio_channel_configuration (gint num_channels)
     return (guint8) 7U;
   else
     return G_MAXUINT8;
+
+  /* FIXME: Add support for configurations 11, 12 and 14 from
+   * ISO/IEC 14496-3:2009/PDAM 4 based on the actual channel layout
+   */
 }
 
 /**
@@ -1113,7 +1287,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);
@@ -1121,7 +1295,7 @@ gst_aac_parse_prepend_adts_headers (GstAacParse * aacparse,
   adts_headers[6] = 0xFCU;
 
   mem = gst_memory_new_wrapped (0, adts_headers, ADTS_HEADERS_LENGTH, 0,
-      ADTS_HEADERS_LENGTH, NULL, NULL);
+      ADTS_HEADERS_LENGTH, adts_headers, g_free);
   gst_buffer_prepend_memory (frame->out_buffer, mem);
 
   return TRUE;
@@ -1161,7 +1335,7 @@ gst_aac_parse_handle_frame (GstBaseParse * parse,
   gboolean lost_sync;
   GstBuffer *buffer;
   guint framesize;
-  gint rate, channels;
+  gint rate = 0, channels = 0;
 
   aacparse = GST_AAC_PARSE (parse);
   buffer = frame->buffer;
@@ -1188,8 +1362,9 @@ gst_aac_parse_handle_frame (GstBaseParse * parse,
     ret = gst_aac_parse_check_adts_frame (aacparse, map.data, map.size,
         GST_BASE_PARSE_DRAINING (parse), &framesize, &needed_data);
 
-    if (!ret) {
+    if (!ret && needed_data) {
       GST_DEBUG ("buffer didn't contain valid frame");
+      *skipsize = 0;
       gst_base_parse_set_min_frame_size (GST_BASE_PARSE (aacparse),
           needed_data);
     }
@@ -1200,8 +1375,9 @@ gst_aac_parse_handle_frame (GstBaseParse * parse,
     ret = gst_aac_parse_check_loas_frame (aacparse, map.data,
         map.size, GST_BASE_PARSE_DRAINING (parse), &framesize, &needed_data);
 
-    if (!ret) {
+    if (!ret && needed_data) {
       GST_DEBUG ("buffer didn't contain valid frame");
+      *skipsize = 0;
       gst_base_parse_set_min_frame_size (GST_BASE_PARSE (aacparse),
           needed_data);
     }
@@ -1237,6 +1413,19 @@ gst_aac_parse_handle_frame (GstBaseParse * parse,
       gst_base_parse_set_frame_rate (GST_BASE_PARSE (aacparse),
           aacparse->sample_rate, aacparse->frame_samples, 2, 2);
     }
+#ifdef TIZEN_FEATURE_AACPARSE_MODIFICATION
+    if (aacparse->first_frame == TRUE) {
+      gboolean ret = FALSE;
+      aacparse->first_frame = FALSE;
+
+      ret = gst_aac_parse_estimate_duration (parse);
+      if (!ret) {
+        GST_WARNING_OBJECT (aacparse, "can not estimate total duration");
+        ret = GST_FLOW_NOT_SUPPORTED;
+      }
+      gst_aac_parse_check_byte_seekability (parse);
+    }
+#endif
   } else if (aacparse->header_type == DSPAAC_HEADER_LOAS) {
     gboolean setcaps = FALSE;
 
@@ -1244,9 +1433,18 @@ gst_aac_parse_handle_frame (GstBaseParse * parse,
     frame->overhead = 3;
 
     if (!gst_aac_parse_read_loas_config (aacparse, map.data, map.size, &rate,
-            &channels, NULL)) {
-      GST_WARNING_OBJECT (aacparse, "Error reading LOAS config");
-    } else if (G_UNLIKELY (rate != aacparse->sample_rate
+            &channels, NULL) || !rate || !channels) {
+      /* This is pretty normal when skipping data at the start of
+       * random stream (MPEG-TS capture for example) */
+      GST_DEBUG_OBJECT (aacparse, "Error reading LOAS config. Skipping.");
+      /* Since we don't fully parse the LOAS config, we don't know for sure
+       * how much to skip. Just skip 1 to end up to the next marker and
+       * resume parsing from there */
+      *skipsize = 1;
+      goto exit;
+    }
+
+    if (G_UNLIKELY (rate != aacparse->sample_rate
             || channels != aacparse->channels)) {
       aacparse->sample_rate = rate;
       aacparse->channels = channels;
@@ -1269,6 +1467,19 @@ gst_aac_parse_handle_frame (GstBaseParse * parse,
           aacparse->sample_rate, aacparse->frame_samples, 2, 2);
     }
   }
+#ifdef TIZEN_FEATURE_AACPARSE_MODIFICATION
+  else if (aacparse->header_type == DSPAAC_HEADER_ADIF) {
+    /* to get more correct duration */
+    float estimated_duration = 0;
+    gint64 total_file_size;
+    gst_base_parse_get_upstream_size (parse, &total_file_size);
+    estimated_duration =
+        ((total_file_size * 8) / (float) (aacparse->bitrate * 1000)) *
+        GST_SECOND;
+    gst_base_parse_set_duration (parse, GST_FORMAT_TIME,
+        estimated_duration * 1000, 0);
+  }
+#endif
 
   if (aacparse->header_type == DSPAAC_HEADER_NONE
       && aacparse->output_header_type == DSPAAC_HEADER_ADTS) {
@@ -1307,16 +1518,25 @@ gst_aac_parse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
     GstTagList *taglist;
     GstCaps *caps;
 
-    taglist = gst_tag_list_new_empty ();
-
     /* codec tag */
     caps = gst_pad_get_current_caps (GST_BASE_PARSE_SRC_PAD (parse));
+    if (caps == NULL) {
+      if (GST_PAD_IS_FLUSHING (GST_BASE_PARSE_SRC_PAD (parse))) {
+        GST_INFO_OBJECT (parse, "Src pad is flushing");
+        return GST_FLOW_FLUSHING;
+      } else {
+        GST_INFO_OBJECT (parse, "Src pad is not negotiated!");
+        return GST_FLOW_NOT_NEGOTIATED;
+      }
+    }
+
+    taglist = gst_tag_list_new_empty ();
     gst_pb_utils_add_codec_description_to_tag_list (taglist,
         GST_TAG_AUDIO_CODEC, caps);
     gst_caps_unref (caps);
 
-    gst_pad_push_event (GST_BASE_PARSE_SRC_PAD (aacparse),
-        gst_event_new_tag (taglist));
+    gst_base_parse_merge_tags (parse, taglist, GST_TAG_MERGE_REPLACE);
+    gst_tag_list_unref (taglist);
 
     /* also signals the end of first-frame processing */
     aacparse->sent_codec_tag = TRUE;
@@ -1327,11 +1547,13 @@ gst_aac_parse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
       && aacparse->output_header_type == DSPAAC_HEADER_NONE) {
     guint header_size;
     GstMapInfo map;
-    gst_buffer_map (frame->buffer, &map, GST_MAP_READ);
+    frame->out_buffer = gst_buffer_make_writable (frame->buffer);
+    frame->buffer = NULL;
+    gst_buffer_map (frame->out_buffer, &map, GST_MAP_READ);
     header_size = (map.data[1] & 1) ? 7 : 9;    /* optional CRC */
-    gst_buffer_unmap (frame->buffer, &map);
-    gst_buffer_resize (frame->buffer, header_size,
-        gst_buffer_get_size (frame->buffer) - header_size);
+    gst_buffer_unmap (frame->out_buffer, &map);
+    gst_buffer_resize (frame->out_buffer, header_size,
+        gst_buffer_get_size (frame->out_buffer) - header_size);
   }
 
   return GST_FLOW_OK;
@@ -1356,6 +1578,14 @@ gst_aac_parse_start (GstBaseParse * parse)
   aacparse->frame_samples = 1024;
   gst_base_parse_set_min_frame_size (GST_BASE_PARSE (aacparse), ADTS_MAX_SIZE);
   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;
 }
 
@@ -1388,6 +1618,79 @@ remove_fields (GstCaps * caps)
   }
 }
 
+static void
+add_conversion_fields (GstCaps * caps)
+{
+  guint i, n;
+
+  n = gst_caps_get_size (caps);
+  for (i = 0; i < n; i++) {
+    GstStructure *s = gst_caps_get_structure (caps, i);
+
+    if (gst_structure_has_field (s, "stream-format")) {
+      const GValue *v = gst_structure_get_value (s, "stream-format");
+
+      if (G_VALUE_HOLDS_STRING (v)) {
+        const gchar *str = g_value_get_string (v);
+
+        if (strcmp (str, "adts") == 0 || strcmp (str, "raw") == 0) {
+          GValue va = G_VALUE_INIT;
+          GValue vs = G_VALUE_INIT;
+
+          g_value_init (&va, GST_TYPE_LIST);
+          g_value_init (&vs, G_TYPE_STRING);
+          g_value_set_string (&vs, "adts");
+          gst_value_list_append_value (&va, &vs);
+          g_value_set_string (&vs, "raw");
+          gst_value_list_append_value (&va, &vs);
+          gst_structure_set_value (s, "stream-format", &va);
+          g_value_unset (&va);
+          g_value_unset (&vs);
+        }
+      } else if (GST_VALUE_HOLDS_LIST (v)) {
+        gboolean contains_raw = FALSE;
+        gboolean contains_adts = FALSE;
+        guint m = gst_value_list_get_size (v), j;
+
+        for (j = 0; j < m; j++) {
+          const GValue *ve = gst_value_list_get_value (v, j);
+          const gchar *str;
+
+          if (G_VALUE_HOLDS_STRING (ve) && (str = g_value_get_string (ve))) {
+            if (strcmp (str, "adts") == 0)
+              contains_adts = TRUE;
+            else if (strcmp (str, "raw") == 0)
+              contains_raw = TRUE;
+          }
+        }
+
+        if (contains_adts || contains_raw) {
+          GValue va = G_VALUE_INIT;
+          GValue vs = G_VALUE_INIT;
+
+          g_value_init (&va, GST_TYPE_LIST);
+          g_value_init (&vs, G_TYPE_STRING);
+          g_value_copy (v, &va);
+
+          if (!contains_raw) {
+            g_value_set_string (&vs, "raw");
+            gst_value_list_append_value (&va, &vs);
+          }
+          if (!contains_adts) {
+            g_value_set_string (&vs, "adts");
+            gst_value_list_append_value (&va, &vs);
+          }
+
+          gst_structure_set_value (s, "stream-format", &va);
+
+          g_value_unset (&vs);
+          g_value_unset (&va);
+        }
+      }
+    }
+  }
+}
+
 static GstCaps *
 gst_aac_parse_sink_getcaps (GstBaseParse * parse, GstCaps * filter)
 {
@@ -1400,6 +1703,7 @@ gst_aac_parse_sink_getcaps (GstBaseParse * parse, GstCaps * filter)
     GstCaps *fcopy = gst_caps_copy (filter);
     /* Remove the fields we convert */
     remove_fields (fcopy);
+    add_conversion_fields (fcopy);
     peercaps = gst_pad_peer_query_caps (GST_BASE_PARSE_SRC_PAD (parse), fcopy);
     gst_caps_unref (fcopy);
   } else
@@ -1409,6 +1713,7 @@ gst_aac_parse_sink_getcaps (GstBaseParse * parse, GstCaps * filter)
     peercaps = gst_caps_make_writable (peercaps);
     /* Remove the fields we convert */
     remove_fields (peercaps);
+    add_conversion_fields (peercaps);
 
     res = gst_caps_intersect_full (peercaps, templ, GST_CAPS_INTERSECT_FIRST);
     gst_caps_unref (peercaps);
@@ -1428,3 +1733,629 @@ gst_aac_parse_sink_getcaps (GstBaseParse * parse, GstCaps * filter)
 
   return res;
 }
+
+static gboolean
+gst_aac_parse_src_event (GstBaseParse * parse, GstEvent * event)
+{
+  GstAacParse *aacparse = GST_AAC_PARSE (parse);
+
+  if (GST_EVENT_TYPE (event) == GST_EVENT_FLUSH_STOP) {
+    aacparse->last_parsed_channels = 0;
+    aacparse->last_parsed_sample_rate = 0;
+  }
+#ifdef TIZEN_FEATURE_AACPARSE_MODIFICATION
+  GST_DEBUG ("Entering gst_aac_parse_src_event header type = %d",
+      aacparse->header_type);
+  if (aacparse->header_type == DSPAAC_HEADER_ADTS)
+    return gst_aac_parse_adts_src_eventfunc (parse, event);
+#endif
+  return GST_BASE_PARSE_CLASS (parent_class)->src_event (parse, event);
+
+}
+
+#ifdef TIZEN_FEATURE_AACPARSE_MODIFICATION
+/**
+ * get_aac_parse_get_adts_framelength:
+ * @data: #GstBufferData.
+ * @offset: #GstBufferData offset
+ *
+ * Implementation to get adts framelength by using first some frame.
+ *
+ * Returns: frame size
+ */
+int
+get_aac_parse_get_adts_frame_length (const unsigned char *data, gint64 offset)
+{
+  const gint adts_header_length_no_crc = 7;
+  const gint adts_header_length_with_crc = 9;
+  gint frame_size = 0;
+  gint protection_absent;
+  gint head_size;
+
+  /* check of syncword */
+  if ((data[offset + 0] != 0xff) || ((data[offset + 1] & 0xf6) != 0xf0)) {
+    GST_ERROR ("check sync word is fail\n");
+    return -1;
+  }
+
+  /* check of protection absent */
+  protection_absent = (data[offset + 1] & 0x01);
+
+  /*check of frame length */
+  frame_size =
+      (data[offset + 3] & 0x3) << 11 | data[offset + 4] << 3 | data[offset +
+      5] >> 5;
+
+  /* check of header size */
+  /* protectionAbsent is 0 if there is CRC */
+  head_size =
+      protection_absent ? adts_header_length_no_crc :
+      adts_header_length_with_crc;
+  if (head_size > frame_size) {
+    GST_ERROR ("return frame length as 0 (frameSize %u < headSize %u)",
+        frame_size, head_size);
+    return 0;
+  }
+
+  return frame_size;
+}
+
+/**
+ * gst_aac_parse_estimate_duration:
+ * @parse: #GstBaseParse.
+ *
+ * Implementation to get estimated total duration by using first some frame.
+ *
+ * Returns: TRUE if we can get estimated total duraion
+ */
+static gboolean
+gst_aac_parse_estimate_duration (GstBaseParse * parse)
+{
+  gboolean ret = FALSE;
+  GstFlowReturn res = GST_FLOW_OK;
+  gint64 pull_size = 0, file_size = 0, offset = 0, num_frames = 0, duration = 0;
+  guint sample_rate_index = 0, sample_rate = 0, channel = 0;
+  guint frame_size = 0, frame_duration_us = 0, estimated_bitrate = 0;
+  guint lost_sync_count = 0;
+  GstClockTime estimated_duration = GST_CLOCK_TIME_NONE;
+  GstBuffer *buffer = NULL;
+  guint8 *buf = NULL;
+  gint i = 0;
+  GstPadMode pad_mode = GST_PAD_MODE_NONE;
+  GstAacParse *aacparse;
+  gint64 buffer_size = 0;
+  GstMapInfo map;
+
+  aacparse = GST_AAC_PARSE (parse);
+  GST_LOG_OBJECT (aacparse, "gst_aac_parse_estimate_duration enter");
+
+  /* check baseparse define these fuction */
+  gst_base_parse_get_pad_mode (parse, &pad_mode);
+  if (pad_mode != GST_PAD_MODE_PULL) {
+    GST_INFO_OBJECT (aacparse,
+        "aac parser is not pull mode. can not estimate duration");
+    return FALSE;
+  }
+
+  gst_base_parse_get_upstream_size (parse, &file_size);
+
+  if (file_size < ADIF_MAX_SIZE) {
+    GST_ERROR_OBJECT (aacparse, "file size is too short");
+    return FALSE;
+  }
+
+  pull_size = MIN (file_size, AAC_MAX_ESTIMATE_DURATION_BUF);
+
+  res = gst_pad_pull_range (parse->sinkpad, 0, pull_size, &buffer);
+  if (res != GST_FLOW_OK) {
+    GST_ERROR_OBJECT (aacparse, "gst_pad_pull_range failed!");
+    return FALSE;
+  }
+
+  gst_buffer_map (buffer, &map, GST_MAP_READ);
+  buf = map.data;
+  buffer_size = map.size;
+  if (buffer_size != pull_size) {
+    GST_ERROR_OBJECT (aacparse,
+        "We got different buffer_size(%" G_GINT64_FORMAT ") with pull_size(%"
+        G_GINT64_FORMAT ").", buffer_size, pull_size);
+  }
+
+  /* MODIFICATION : add defence codes for real buffer_size is different with pull_size */
+  for (i = 0; i < buffer_size; i++) {
+    if ((buf[i] == 0xff) && ((buf[i + 1] & 0xf6) == 0xf0)) {    /* aac sync word */
+      //guint profile = (buf[i+2] >> 6) & 0x3;
+      sample_rate_index = (buf[i + 2] >> 2) & 0xf;
+      sample_rate =
+          gst_aac_parse_get_sample_rate_from_index (sample_rate_index);
+      if (sample_rate == 0) {
+        GST_WARNING_OBJECT (aacparse, "Invalid sample rate index (0)");
+        goto EXIT;
+      }
+      channel = (buf[i + 2] & 0x1) << 2 | (buf[i + 3] >> 6);
+
+      GST_INFO_OBJECT (aacparse, "found sync. aac fs=%d, ch=%d", sample_rate,
+          channel);
+
+      /* count number of frames */
+      /* MODIFICATION : add defence codes for real buffer_size is different with pull_size */
+      //while (offset < pull_size) {
+      while (offset < buffer_size) {
+        frame_size = get_aac_parse_get_adts_frame_length (buf, i + offset);
+        if (frame_size == 0) {
+          GST_ERROR_OBJECT (aacparse,
+              "framesize error at offset %" G_GINT64_FORMAT, offset);
+          break;
+        } else if (frame_size == -1) {
+          offset++;
+          lost_sync_count++;    //  lost sync count limmitation 2K Bytes
+          if (lost_sync_count > (1024 * 2)) {
+            GST_WARNING_OBJECT (aacparse,
+                "lost_sync_count is larger than 2048");
+            goto EXIT;
+          }
+        } else {
+          offset += frame_size;
+          num_frames++;
+          lost_sync_count = 0;
+        }
+      }                         /* while */
+
+      /* if we can got full file, we can calculate the accurate duration */
+      /* MODIFICATION : add defence codes for real buffer_size is different with pull_size */
+      //if (pull_size == file_size) {
+      if (buffer_size == file_size) {
+        gfloat duration_for_one_frame = 0;
+        GstClockTime calculated_duration = GST_CLOCK_TIME_NONE;
+
+        GST_INFO_OBJECT (aacparse,
+            "we got total file (%" G_GINT64_FORMAT
+            " bytes). do not estimate but make Accurate total duration.",
+            pull_size);
+
+        duration_for_one_frame =
+            (gfloat) AAC_SAMPLE_PER_FRAME / (gfloat) sample_rate;
+        calculated_duration =
+            num_frames * duration_for_one_frame * 1000 * 1000 * 1000;
+
+        GST_INFO_OBJECT (aacparse, "duration_for_one_frame %f ms",
+            duration_for_one_frame);
+        GST_INFO_OBJECT (aacparse, "calculated duration = %" GST_TIME_FORMAT,
+            GST_TIME_ARGS (calculated_duration));
+        /* 0 means disable estimate */
+        gst_base_parse_set_duration (parse, GST_FORMAT_TIME,
+            calculated_duration, 0);
+
+      } else {
+        GST_INFO_OBJECT (aacparse,
+            "we got %" G_GUINT64_FORMAT " bytes in total file (%"
+            G_GINT64_FORMAT "). can not make accurate duration but Estimate.",
+            pull_size, file_size);
+        frame_duration_us =
+            (1024 * 1000000ll + (sample_rate - 1)) / sample_rate;
+        duration = num_frames * frame_duration_us;
+
+        if (duration == 0) {
+          GST_WARNING_OBJECT (aacparse, "Invalid duration");
+          goto EXIT;
+        }
+        estimated_bitrate =
+            (gint) ((gfloat) (offset * 8) / (gfloat) (duration / 1000));
+
+        if (estimated_bitrate == 0) {
+          GST_WARNING_OBJECT (aacparse, "Invalid estimated_bitrate");
+          goto EXIT;
+        }
+        estimated_duration =
+            (GstClockTime) ((file_size * 8) / (estimated_bitrate * 1000)) *
+            GST_SECOND;
+
+        GST_INFO_OBJECT (aacparse, "number of frame = %" G_GINT64_FORMAT,
+            num_frames);
+        GST_INFO_OBJECT (aacparse, "duration = %" G_GINT64_FORMAT,
+            duration / 1000000);
+        GST_INFO_OBJECT (aacparse, "byte = %" G_GINT64_FORMAT, offset);
+        GST_INFO_OBJECT (aacparse, "estimated bitrate = %d bps",
+            estimated_bitrate);
+        GST_INFO_OBJECT (aacparse, "estimated duration = %" GST_TIME_FORMAT,
+            GST_TIME_ARGS (estimated_duration));
+
+        gst_base_parse_set_average_bitrate (parse, estimated_bitrate * 1000);
+        /* set update_interval as duration(sec)/2 */
+        gst_base_parse_set_duration (parse, GST_FORMAT_TIME, estimated_duration,
+            (gint) (duration / 2));
+      }
+
+      break;
+    }
+  }
+  ret = TRUE;
+
+EXIT:
+  gst_buffer_unmap (buffer, &map);
+  gst_buffer_unref (buffer);
+  return ret;
+}
+
+
+/* perform seek in push based mode:
+   find BYTE position to move to based on time and delegate to upstream
+*/
+static gboolean
+gst_aac_audio_parse_do_push_seek (GstBaseParse * parse,
+    GstPad * pad, GstEvent * event)
+{
+  GstAacParse *aacparse = GST_AAC_PARSE (parse);
+  gdouble rate;
+  GstFormat format;
+  GstSeekFlags flags;
+  GstSeekType cur_type, stop_type;
+  gint64 cur, stop;
+  gboolean res;
+  gint64 byte_cur;
+  gint64 esimate_byte;
+  gint32 frame_dur;
+  gint64 upstream_total_bytes = 0;
+  GstFormat fmt = GST_FORMAT_BYTES;
+
+  GST_INFO_OBJECT (parse, "doing aac push-based seek");
+
+  gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
+      &stop_type, &stop);
+
+  /* FIXME, always play to the end */
+  stop = -1;
+
+  /* only forward streaming and seeking is possible */
+  if (rate <= 0)
+    goto unsupported_seek;
+
+  if (cur == 0) {
+    /* handle rewind only */
+    cur_type = GST_SEEK_TYPE_SET;
+    byte_cur = 0;
+    stop_type = GST_SEEK_TYPE_NONE;
+    stop = -1;
+    flags |= GST_SEEK_FLAG_FLUSH;
+  } else {
+    /* handle normal seek */
+    cur_type = GST_SEEK_TYPE_SET;
+    stop_type = GST_SEEK_TYPE_NONE;
+    stop = -1;
+    flags |= GST_SEEK_FLAG_FLUSH;
+
+    esimate_byte = (cur / (1000 * 1000)) * aacparse->frame_byte;
+    if (aacparse->sample_rate > 0)
+      frame_dur = (aacparse->spf * 1000) / aacparse->sample_rate;
+    else
+      goto unsupported_seek;
+    if (frame_dur > 0)
+      byte_cur = esimate_byte / (frame_dur);
+    else
+      goto unsupported_seek;
+
+    GST_INFO_OBJECT (parse, "frame_byte(%d) spf(%d)  rate (%d) ",
+        aacparse->frame_byte, aacparse->spf, aacparse->sample_rate);
+    GST_INFO_OBJECT (parse,
+        "seek cur (%" G_GINT64_FORMAT ") = (%" GST_TIME_FORMAT ") ", cur,
+        GST_TIME_ARGS (cur));
+    GST_INFO_OBJECT (parse,
+        "esimate_byte(%" G_GINT64_FORMAT ")  esimate_byte (%d)", esimate_byte,
+        frame_dur);
+  }
+
+  /* obtain real upstream total bytes */
+  if (!gst_pad_peer_query_duration (parse->sinkpad, fmt, &upstream_total_bytes))
+    upstream_total_bytes = 0;
+  GST_INFO_OBJECT (aacparse,
+      "gst_pad_query_peer_duration -upstream_total_bytes (%" G_GUINT64_FORMAT
+      ")", upstream_total_bytes);
+  aacparse->file_size = upstream_total_bytes;
+
+  if ((byte_cur == -1) || (byte_cur > aacparse->file_size)) {
+    GST_INFO_OBJECT (parse,
+        "[WEB-ERROR] seek cur (%" G_GINT64_FORMAT ") > file_size (%"
+        G_GINT64_FORMAT ") ", cur, aacparse->file_size);
+    goto abort_seek;
+  }
+
+  GST_INFO_OBJECT (parse,
+      "Pushing BYTE seek rate %g, " "start %" G_GINT64_FORMAT ", stop %"
+      G_GINT64_FORMAT, rate, byte_cur, stop);
+
+  if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
+    GST_INFO_OBJECT (parse,
+        "Requested seek time: %" GST_TIME_FORMAT ", calculated seek offset: %"
+        G_GUINT64_FORMAT, GST_TIME_ARGS (cur), byte_cur);
+  }
+
+  /* BYTE seek event */
+  event =
+      gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
+      stop_type, stop);
+  res = gst_pad_push_event (parse->sinkpad, event);
+
+  return res;
+
+  /* ERRORS */
+
+abort_seek:
+  {
+    GST_DEBUG_OBJECT (parse,
+        "could not determine byte position to seek to, " "seek aborted.");
+    return FALSE;
+  }
+
+unsupported_seek:
+  {
+    GST_DEBUG_OBJECT (parse, "unsupported seek, seek aborted.");
+    return FALSE;
+  }
+}
+
+
+static guint
+gst_aac_parse_adts_get_fast_frame_len (const guint8 * data)
+{
+  int length;
+  if ((data[0] == 0xff) && ((data[1] & 0xf6) == 0xf0)) {
+    length =
+        ((data[3] & 0x03) << 11) | (data[4] << 3) | ((data[5] & 0xe0) >> 5);
+  } else {
+    length = 0;
+  }
+  return length;
+}
+
+/**
+ * gst_aac_parse_adts_src_eventfunc:
+ * @parse: #GstBaseParse. #event
+ *
+ * before baseparse handles seek event, make full amr index table.
+ *
+ * Returns: TRUE on success.
+ */
+static gboolean
+gst_aac_parse_adts_src_eventfunc (GstBaseParse * parse, GstEvent * event)
+{
+  gboolean handled = FALSE;
+  GstAacParse *aacparse = GST_AAC_PARSE (parse);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_SEEK:
+    {
+      GstFlowReturn res = GST_FLOW_OK;
+      gint64 base_offset = 0, cur = 0;
+      gint32 frame_count = 1;   /* do not add first frame because it is already in index table */
+      gint64 second_count = 0;  /* initial 1 second */
+      gint64 total_file_size = 0, start_offset = 0;
+      GstClockTime current_ts = GST_CLOCK_TIME_NONE;
+      GstPadMode pad_mode = GST_PAD_MODE_NONE;
+
+      /* check baseparse define these fuction */
+      gst_base_parse_get_pad_mode (parse, &pad_mode);
+      if (pad_mode != GST_PAD_MODE_PULL) {
+        gboolean ret = FALSE;
+        GstPad *srcpad = parse->srcpad;
+        GST_INFO_OBJECT (aacparse, "aac parser is PUSH MODE.");
+        /* check NULL */
+        if (aacparse->byte_seekable) {
+          ret = gst_aac_audio_parse_do_push_seek (parse, srcpad, event);
+          if (!ret) {
+            GST_INFO_OBJECT (aacparse, "PUSH mode seek() failed, Trying base seek()");
+            goto aac_seek_null_exit;
+          }
+          return ret;
+        }
+        GST_INFO_OBJECT (aacparse, "not support byte seek");
+        goto aac_seek_null_exit;
+      }
+
+      gst_base_parse_get_upstream_size (parse, &total_file_size);
+      gst_base_parse_get_index_last_offset (parse, &start_offset);
+      gst_base_parse_get_index_last_ts (parse, &current_ts);
+
+      if (total_file_size > AAC_LARGE_FILE_SIZE) {
+        gst_base_parse_set_seek_mode (parse, 0);
+        GST_INFO_OBJECT (aacparse, "larger than big size (2MB).");
+        goto aac_seek_null_exit;
+      }
+
+      GST_DEBUG ("gst_aac_parse_adts_src_eventfunc GST_EVENT_SEEK enter");
+
+      if (total_file_size == 0 || start_offset >= total_file_size) {
+        GST_ERROR ("last index offset %" G_GINT64_FORMAT
+            " is larger than file size %" G_GINT64_FORMAT, start_offset,
+            total_file_size);
+        break;
+      }
+
+      gst_event_parse_seek (event, NULL, NULL, NULL, NULL, &cur, NULL, NULL);
+      if (cur <= current_ts) {
+        GST_INFO ("seek to %" GST_TIME_FORMAT " within index table %"
+            GST_TIME_FORMAT ". do not make index table", GST_TIME_ARGS (cur),
+            GST_TIME_ARGS (current_ts));
+        break;
+      } else {
+        GST_INFO ("seek to %" GST_TIME_FORMAT " without index table %"
+            GST_TIME_FORMAT ". make index table", GST_TIME_ARGS (cur),
+            GST_TIME_ARGS (current_ts));
+      }
+
+      GST_INFO ("make AAC(ADTS) Index Table. file_size  = %" G_GINT64_FORMAT
+          " last idx offset=%" G_GINT64_FORMAT ", last idx ts=%"
+          GST_TIME_FORMAT, total_file_size, start_offset,
+          GST_TIME_ARGS (current_ts));
+
+      base_offset = start_offset;       /* set base by start offset */
+      second_count = current_ts + GST_SECOND;   /* 1sec */
+
+      /************************************/
+      /* STEP 0: Setting parse information */
+      /************************************/
+      aacparse->spf = aacparse->frame_samples;
+      aacparse->frame_duration = (aacparse->spf * 1000 * 100) / aacparse->sample_rate;  /* duration per frame (msec) */
+      aacparse->frame_per_sec = (aacparse->sample_rate) / aacparse->spf;        /* frames per second (ea) */
+
+      /************************************/
+      /* STEP 1: MAX_PULL_RANGE_BUF cycle */
+      /************************************/
+      while (total_file_size - base_offset >= AAC_MAX_PULL_RANGE_BUF) {
+        gint64 offset = 0;
+        GstBuffer *buffer = NULL;
+        guint8 *buf = NULL;
+        GstMapInfo map;
+        GST_INFO ("gst_pad_pull_range %d bytes (from %" G_GINT64_FORMAT
+            ") use max size", AAC_MAX_PULL_RANGE_BUF, base_offset);
+        res =
+            gst_pad_pull_range (parse->sinkpad, base_offset,
+            base_offset + AAC_MAX_PULL_RANGE_BUF, &buffer);
+        if (res != GST_FLOW_OK) {
+          GST_ERROR ("gst_pad_pull_range failed!");
+          break;
+        }
+
+        gst_buffer_map (buffer, &map, GST_MAP_READ);
+        buf = map.data;
+        if (buf == NULL) {
+          gst_buffer_unmap (buffer, &map);
+          GST_WARNING ("buffer is NULL in make aac seek table's STEP1");
+          gst_buffer_unref (buffer);
+          goto aac_seek_null_exit;
+        }
+
+        while (offset <= AAC_MAX_PULL_RANGE_BUF) {
+          gint frame_size = 0;
+
+          /* make sure the values in the frame header look sane */
+          frame_size = gst_aac_parse_adts_get_fast_frame_len (buf);
+
+          if ((frame_size > 0)
+              && (frame_size < (AAC_MAX_PULL_RANGE_BUF - offset))) {
+            if (current_ts > second_count) {    /* 1 sec == xx frames. we make idx per sec */
+              gst_base_parse_add_index_entry (parse, base_offset + offset, current_ts, TRUE, TRUE);     /* force */
+              GST_DEBUG ("Adding  index ts=%" GST_TIME_FORMAT " offset %"
+                  G_GINT64_FORMAT, GST_TIME_ARGS (current_ts),
+                  base_offset + offset);
+              second_count += GST_SECOND;       /* 1sec */
+            }
+
+            current_ts += (aacparse->frame_duration * GST_MSECOND) / 100;       /* each frame is (frame_duration) ms */
+            offset += frame_size;
+            buf += frame_size;
+            frame_count++;
+          } else if (frame_size >= (AAC_MAX_PULL_RANGE_BUF - offset)) {
+            GST_DEBUG ("we need refill buffer");
+            break;
+          } else {
+            GST_WARNING ("we lost sync");
+            buf++;
+            offset++;
+          }
+        }                       /* while */
+
+        base_offset = base_offset + offset;
+
+        gst_buffer_unmap (buffer, &map);
+        gst_buffer_unref (buffer);
+      }                         /* end MAX buffer cycle */
+
+      /*******************************/
+      /* STEP 2: Remain Buffer cycle */
+      /*******************************/
+      if (total_file_size - base_offset > 0) {
+        gint64 offset = 0;
+        GstBuffer *buffer = NULL;
+        guint8 *buf = NULL;
+        GstMapInfo map;
+
+        GST_INFO ("gst_pad_pull_range %" G_GINT64_FORMAT " bytes (from %"
+            G_GINT64_FORMAT ") use remain_buf size",
+            total_file_size - base_offset, base_offset);
+        res =
+            gst_pad_pull_range (parse->sinkpad, base_offset, total_file_size,
+            &buffer);
+        if (res != GST_FLOW_OK) {
+          GST_ERROR ("gst_pad_pull_range failed!");
+          break;
+        }
+
+        gst_buffer_map (buffer, &map, GST_MAP_READ);
+        buf = map.data;
+        if (buf == NULL) {
+          gst_buffer_unmap (buffer, &map);
+          GST_WARNING ("buffer is NULL in make aac seek table's STEP2");
+          gst_buffer_unref (buffer);
+          goto aac_seek_null_exit;
+        }
+
+        while (base_offset + offset < total_file_size) {
+          gint frame_size = 0;
+
+          /* make sure the values in the frame header look sane */
+          frame_size = gst_aac_parse_adts_get_fast_frame_len (buf);
+
+          if ((frame_size > 0)
+              && (frame_size <= (total_file_size - (base_offset + offset)))) {
+            if (current_ts > second_count) {    /* 1 sec == xx frames. we make idx per sec */
+              gst_base_parse_add_index_entry (parse, base_offset + offset, current_ts, TRUE, TRUE);     /* force */
+              GST_DEBUG ("Adding  index ts=%" GST_TIME_FORMAT " offset %"
+                  G_GINT64_FORMAT, GST_TIME_ARGS (current_ts),
+                  base_offset + offset);
+              second_count += GST_SECOND;       /* 1sec */
+            }
+
+            current_ts += (aacparse->frame_duration * GST_MSECOND) / 100;       /* each frame is (frame_duration) ms */
+            offset += frame_size;
+            buf += frame_size;
+            frame_count++;
+          } else if (frame_size == 0) {
+            GST_DEBUG ("Frame size is 0 so, Decoding end..");
+            break;
+          } else {
+            GST_WARNING ("we lost sync");
+            buf++;
+            offset++;
+          }
+        }                       /* while */
+
+        gst_buffer_unmap (buffer, &map);
+        gst_buffer_unref (buffer);
+      }
+      /* end remain_buf buffer cycle */
+      GST_DEBUG ("gst_aac_parse_adts_src_eventfunc GST_EVENT_SEEK leave");
+    }
+      break;
+
+    default:
+      break;
+  }
+
+aac_seek_null_exit:
+
+  /* call baseparse src_event function to handle event */
+  handled = GST_BASE_PARSE_CLASS (parent_class)->src_event (parse, event);
+  return handled;
+}
+
+static void
+gst_aac_parse_check_byte_seekability (GstBaseParse * parse)
+{
+  GstQuery *query;
+  gboolean seekable = FALSE;
+  GstAacParse *aacparse = GST_AAC_PARSE (parse);
+  GST_LOG_OBJECT (aacparse, "gst_aac_parse_check_byte_seekability enter");
+
+  query = gst_query_new_seeking (GST_FORMAT_BYTES);
+  if (gst_pad_peer_query (parse->sinkpad, query))
+    gst_query_parse_seeking (query, NULL, &seekable, NULL, NULL);
+  else
+    GST_DEBUG_OBJECT (aacparse, "seeking query failed");
+
+  gst_query_unref (query);
+
+  GST_INFO_OBJECT (aacparse, "byte seekable: %d", seekable);
+
+  aacparse->byte_seekable = seekable;
+}
+#endif /* TIZEN_FEATURE_AACPARSE_MODIFICATION */