Send seek event to baseparse when aacparse seek failed in push mode
[platform/upstream/gst-plugins-good.git] / gst / audioparsers / gstaacparse.c
index 982d242..cd15f01 100644 (file)
@@ -68,19 +68,29 @@ 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, 7, 8, 0, 8, 0
 };
@@ -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);
 }
 
 
@@ -145,6 +186,13 @@ 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
 }
 
 
@@ -215,6 +263,19 @@ 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 (allowed && !gst_caps_can_intersect (src_caps, allowed)) {
     GST_DEBUG_OBJECT (GST_BASE_PARSE (aacparse)->srcpad,
@@ -237,6 +298,7 @@ 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,
@@ -253,6 +315,9 @@ gst_aac_parse_set_src_caps (GstAacParse * aacparse, GstCaps * sink_caps)
   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);
 
   res = gst_pad_set_caps (GST_BASE_PARSE (aacparse)->srcpad, src_caps);
@@ -298,26 +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;
-
-      gst_buffer_map (buf, &map, GST_MAP_READ);
-
-      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;
+      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);
+
       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, "
@@ -328,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;
 }
 
@@ -474,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;
@@ -517,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;
 }
 
@@ -582,21 +695,23 @@ gst_aac_parse_read_loas_config (GstAacParse * aacparse, const guint8 * data,
     return FALSE;
   if (u8) {
     GST_LOG_OBJECT (aacparse, "Frame uses previous config");
-    if (!aacparse->sample_rate || !aacparse->channels) {
+    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
@@ -607,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;
     }
@@ -635,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;
           }
@@ -724,7 +839,8 @@ gst_aac_parse_check_loas_frame (GstAacParse * aacparse,
 
   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
@@ -753,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;
@@ -1169,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);
@@ -1295,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;
 
@@ -1336,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) {
@@ -1403,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;
@@ -1432,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;
 }
 
@@ -1579,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 */