From 9887254cc27fd5546b36fc8de954b0184ddc6add Mon Sep 17 00:00:00 2001 From: Gilbok Lee Date: Mon, 28 Dec 2015 17:38:17 +0900 Subject: [PATCH] aacparse: Fixed aac(adts) seek speed slow issue Sync with tizen 2.4 fixed code (http://165.213.149.170/gerrit/#/c/71933) Change-Id: Ia42f4501928f01d30a02db9a280082511a333282 Signed-off-by: Gilbok Lee --- gst/audioparsers/gstaacparse.c | 601 ++++++++++++++++++++++++++++++++++++++++ gst/audioparsers/gstaacparse.h | 14 + packaging/gst-plugins-good.spec | 3 +- 3 files changed, 617 insertions(+), 1 deletion(-) diff --git a/gst/audioparsers/gstaacparse.c b/gst/audioparsers/gstaacparse.c index cd75b7f..d4d1764 100644 --- a/gst/audioparsers/gstaacparse.c +++ b/gst/audioparsers/gstaacparse.c @@ -73,6 +73,15 @@ GST_DEBUG_CATEGORY_STATIC (aacparse_debug); headers prepended during raw to ADTS conversion */ +#ifdef GST_EXT_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] = { @@ -98,8 +107,34 @@ static GstFlowReturn gst_aac_parse_handle_frame (GstBaseParse * parse, static GstFlowReturn gst_aac_parse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame); +#ifdef GST_EXT_AACPARSE_MODIFICATION +static guint gst_aac_parse_adts_get_fast_frame_len (const guint8 * data); +static gboolean gst_aac_parse_src_eventfunc(GstBaseParse * parse, + GstEvent * event); +/* 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); +#endif + G_DEFINE_TYPE (GstAacParse, gst_aac_parse, GST_TYPE_BASE_PARSE); +#ifdef GST_EXT_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. @@ -130,6 +165,10 @@ 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); +#ifdef GST_EXT_AACPARSE_MODIFICATION + /* make full aac(adts) index table when seek */ + parse_class->src_event = GST_DEBUG_FUNCPTR (gst_aac_parse_src_eventfunc); +#endif } @@ -145,6 +184,10 @@ 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)); +#ifdef GST_EXT_AACPARSE_MODIFICATION + /* to get more correct duration */ + aacparse->first_frame = TRUE; +#endif } @@ -1291,6 +1334,18 @@ 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 GST_EXT_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; + } + } +#endif } else if (aacparse->header_type == DSPAAC_HEADER_LOAS) { gboolean setcaps = FALSE; @@ -1329,6 +1384,18 @@ gst_aac_parse_handle_frame (GstBaseParse * parse, aacparse->sample_rate, aacparse->frame_samples, 2, 2); } } +#ifdef GST_EXT_AACPARSE_MODIFICATION + else if(aacparse->header_type == DSPAAC_HEADER_ADIF) + { + /* to get more correct duration */ + int file_size = 0; + 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) { @@ -1563,3 +1630,537 @@ gst_aac_parse_sink_getcaps (GstBaseParse * parse, GstCaps * filter) return res; } + +#ifdef GST_EXT_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) +{ + GstFlowReturn res = GST_FLOW_OK; + gint64 pull_size = 0, file_size = 0, offset = 0, num_frames=0, duration=0; + guint profile = 0, 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; + + 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; + } + + GstMapInfo map; + 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(%d) with pull_size(%d).", + 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 */ + 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_buffer_unmap(buffer, &map); + GST_WARNING_OBJECT (aacparse, "Invalid sample rate index (0)"); + return FALSE; + } + 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_buffer_unmap(buffer, &map); + return FALSE; + } + } 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 (%d 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 %d 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; + + estimated_bitrate = (gint)((gfloat)(offset * 8) / (gfloat)(duration / 1000)); + 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; + } + } + + gst_buffer_unmap(buffer, &map); + gst_buffer_unref (buffer); + return TRUE; +} + + +/* 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; + 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; +} + +static gboolean +gst_aac_parse_src_eventfunc(GstBaseParse * parse, GstEvent * event) +{ + gboolean handled = FALSE; + GstAacParse *aacparse; + aacparse = GST_AAC_PARSE(parse); + + GST_DEBUG("Entering gst_aac_parse_src_eventfunc header type = %d", aacparse->header_type); + if(aacparse->header_type == DSPAAC_HEADER_ADTS) + return gst_aac_parse_adts_src_eventfunc (parse, event); + else + goto aac_seek_null_exit; +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; +} + +/** + * 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; + aacparse = GST_AAC_PARSE (parse); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_SEEK: + { + GstFlowReturn res = GST_FLOW_OK; + gint64 base_offset = 0, sync_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; + gboolean large_file_flag = FALSE; + + /* check baseparse define these fuction */ + gst_base_parse_get_pad_mode(parse, &pad_mode); + if (pad_mode != GST_PAD_MODE_PULL) { + gboolean ret = FALSE; + GST_INFO_OBJECT (aacparse, "aac parser is PUSH MODE."); + GstPad* srcpad = parse->srcpad; + /* check NULL */ + ret = gst_aac_audio_parse_do_push_seek(parse, srcpad, event); + gst_object_unref(srcpad); + return ret; + } + 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, ¤t_ts); + + if (total_file_size > AAC_LARGE_FILE_SIZE ) { + large_file_flag = TRUE; + 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 %d is larger than file size %d", 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; + + 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; + } + + GstMapInfo map; + 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; + guint32 header; + + /* 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; + + 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; + } + + GstMapInfo map; + 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; + guint32 header; + + /* 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; +} +#endif //end of #ifdef GST_EXT_AACPARSE_MODIFICATION \ No newline at end of file diff --git a/gst/audioparsers/gstaacparse.h b/gst/audioparsers/gstaacparse.h index 1bb7dca..50b6438 100644 --- a/gst/audioparsers/gstaacparse.h +++ b/gst/audioparsers/gstaacparse.h @@ -79,6 +79,20 @@ struct _GstAacParse { gint mpegversion; gint frame_samples; +#ifdef GST_EXT_AACPARSE_MODIFICATION + gboolean first_frame; /* estimate duration once at the first time */ + guint hdr_bitrate; /* estimated bitrate (bps) */ + guint spf; /* samples per frame = frame_samples */ + guint frame_duration; /* duration per frame (msec) */ + guint frame_per_sec; /* frames per second (ea) */ + guint bitstream_type; /* bitstream type - constant or variable */ + guint adif_header_length; + guint num_program_config_elements; + guint read_bytes; + gint64 file_size; + guint frame_byte; +#endif + GstAacHeaderType header_type; GstAacHeaderType output_header_type; diff --git a/packaging/gst-plugins-good.spec b/packaging/gst-plugins-good.spec index c5ac00d..0f3180a 100644 --- a/packaging/gst-plugins-good.spec +++ b/packaging/gst-plugins-good.spec @@ -75,7 +75,8 @@ export V=1 NOCONFIGURE=1 ./autogen.sh export CFLAGS+=" -DGST_EXT_V4L2SRC_MODIFIED\ -DGST_EXT_WAVPARSE_MODIFICATION\ - -DGST_EXT_MP3PARSE_MODIFICATION" + -DGST_EXT_MP3PARSE_MODIFICATION\ + -DGST_EXT_AACPARSE_MODIFICATION" %configure\ %if ! 0%{?ENABLE_AALIB} --disable-aalib\ -- 2.7.4