diff options
Diffstat (limited to 'mobile/gst/audioparsers/gstaacparse.c')
-rw-r--r-- | mobile/gst/audioparsers/gstaacparse.c | 925 |
1 files changed, 0 insertions, 925 deletions
diff --git a/mobile/gst/audioparsers/gstaacparse.c b/mobile/gst/audioparsers/gstaacparse.c deleted file mode 100644 index b1dca6c..0000000 --- a/mobile/gst/audioparsers/gstaacparse.c +++ /dev/null @@ -1,925 +0,0 @@ -/* GStreamer AAC parser plugin - * Copyright (C) 2008 Nokia Corporation. All rights reserved. - * - * Contact: Stefan Kost <stefan.kost@nokia.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -/** - * SECTION:element-aacparse - * @short_description: AAC parser - * @see_also: #GstAmrParse - * - * This is an AAC parser which handles both ADIF and ADTS stream formats. - * - * As ADIF format is not framed, it is not seekable and stream duration cannot - * be determined either. However, ADTS format AAC clips can be seeked, and parser - * can also estimate playback position and clip duration. - * - * <refsect2> - * <title>Example launch line</title> - * |[ - * gst-launch filesrc location=abc.aac ! aacparse ! faad ! audioresample ! audioconvert ! alsasink - * ]| - * </refsect2> - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <string.h> - -#include "gstaacparse.h" - - -static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("audio/mpeg, " - "framed = (boolean) true, " "mpegversion = (int) { 2, 4 }, " - "stream-format = (string) { raw, adts, adif };")); - -static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("audio/mpeg, mpegversion = (int) { 2, 4 };")); - -GST_DEBUG_CATEGORY_STATIC (aacparse_debug); -#define GST_CAT_DEFAULT aacparse_debug - - -#define ADIF_MAX_SIZE 40 /* Should be enough */ -#define ADTS_MAX_SIZE 10 /* Should be enough */ - -#ifdef GST_EXT_AACPARSER_MODIFICATION /* to get more accurate duration */ -#define AAC_MAX_ESTIMATE_DURATION_BUF (1024 * 1024) /* use first 1 Mbyte */ -#define AAC_SAMPLE_PER_FRAME 1024 -#endif - -#define AAC_FRAME_DURATION(parse) (GST_SECOND/parse->frames_per_sec) - -static gboolean gst_aac_parse_start (GstBaseParse * parse); -static gboolean gst_aac_parse_stop (GstBaseParse * parse); - -static gboolean gst_aac_parse_sink_setcaps (GstBaseParse * parse, - GstCaps * caps); -static GstCaps *gst_aac_parse_sink_getcaps (GstBaseParse * parse); - -static gboolean gst_aac_parse_check_valid_frame (GstBaseParse * parse, - GstBaseParseFrame * frame, guint * size, gint * skipsize); - -static GstFlowReturn gst_aac_parse_parse_frame (GstBaseParse * parse, - GstBaseParseFrame * frame); - -#define _do_init(bla) \ - GST_DEBUG_CATEGORY_INIT (aacparse_debug, "aacparse", 0, \ - "AAC audio stream parser"); - -GST_BOILERPLATE_FULL (GstAacParse, gst_aac_parse, GstBaseParse, - GST_TYPE_BASE_PARSE, _do_init); - -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; -} - -/** - * gst_aac_parse_base_init: - * @klass: #GstElementClass. - * - */ -static void -gst_aac_parse_base_init (gpointer klass) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (klass); - - 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_details_simple (element_class, - "AAC audio stream parser", "Codec/Parser/Audio", - "Advanced Audio Coding parser", "Stefan Kost <stefan.kost@nokia.com>"); -} - - -/** - * gst_aac_parse_class_init: - * @klass: #GstAacParseClass. - * - */ -static void -gst_aac_parse_class_init (GstAacParseClass * klass) -{ - GstBaseParseClass *parse_class = GST_BASE_PARSE_CLASS (klass); - - parse_class->start = GST_DEBUG_FUNCPTR (gst_aac_parse_start); - parse_class->stop = GST_DEBUG_FUNCPTR (gst_aac_parse_stop); - parse_class->set_sink_caps = GST_DEBUG_FUNCPTR (gst_aac_parse_sink_setcaps); - parse_class->get_sink_caps = GST_DEBUG_FUNCPTR (gst_aac_parse_sink_getcaps); - parse_class->parse_frame = GST_DEBUG_FUNCPTR (gst_aac_parse_parse_frame); - parse_class->check_valid_frame = - GST_DEBUG_FUNCPTR (gst_aac_parse_check_valid_frame); -} - - -/** - * gst_aac_parse_init: - * @aacparse: #GstAacParse. - * @klass: #GstAacParseClass. - * - */ -static void -gst_aac_parse_init (GstAacParse * aacparse, GstAacParseClass * klass) -{ - GST_DEBUG ("initialized"); -#ifdef GST_EXT_AACPARSER_MODIFICATION /* to get more correct duration */ - aacparse->first_frame = TRUE; -#endif -} - - -/** - * gst_aac_parse_set_src_caps: - * @aacparse: #GstAacParse. - * @sink_caps: (proposed) caps of sink pad - * - * Set source pad caps according to current knowledge about the - * audio stream. - * - * Returns: TRUE if caps were successfully set. - */ -static gboolean -gst_aac_parse_set_src_caps (GstAacParse * aacparse, GstCaps * sink_caps) -{ - GstStructure *s; - GstCaps *src_caps = NULL; - gboolean res = FALSE; - const gchar *stream_format; - - GST_DEBUG_OBJECT (aacparse, "sink caps: %" GST_PTR_FORMAT, sink_caps); - if (sink_caps) - src_caps = gst_caps_copy (sink_caps); - else - src_caps = gst_caps_new_simple ("audio/mpeg", NULL); - - gst_caps_set_simple (src_caps, "framed", G_TYPE_BOOLEAN, TRUE, - "mpegversion", G_TYPE_INT, aacparse->mpegversion, NULL); - - switch (aacparse->header_type) { - case DSPAAC_HEADER_NONE: - stream_format = "raw"; - break; - case DSPAAC_HEADER_ADTS: - stream_format = "adts"; - break; - case DSPAAC_HEADER_ADIF: - stream_format = "adif"; - break; - default: - stream_format = NULL; - } - - 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); - if (aacparse->channels > 0) - gst_structure_set (s, "channels", G_TYPE_INT, aacparse->channels, NULL); - if (stream_format) - gst_structure_set (s, "stream-format", G_TYPE_STRING, stream_format, NULL); - - GST_DEBUG_OBJECT (aacparse, "setting src caps: %" GST_PTR_FORMAT, src_caps); - - res = gst_pad_set_caps (GST_BASE_PARSE (aacparse)->srcpad, src_caps); - gst_caps_unref (src_caps); - return res; -} - - -/** - * gst_aac_parse_sink_setcaps: - * @sinkpad: GstPad - * @caps: GstCaps - * - * Implementation of "set_sink_caps" vmethod in #GstBaseParse class. - * - * Returns: TRUE on success. - */ -static gboolean -gst_aac_parse_sink_setcaps (GstBaseParse * parse, GstCaps * caps) -{ - GstAacParse *aacparse; - GstStructure *structure; - gchar *caps_str; - const GValue *value; - - aacparse = GST_AAC_PARSE (parse); - structure = gst_caps_get_structure (caps, 0); - caps_str = gst_caps_to_string (caps); - - GST_DEBUG_OBJECT (aacparse, "setcaps: %s", caps_str); - g_free (caps_str); - - /* This is needed at least in case of RTP - * Parses the codec_data information to get ObjectType, - * number of channels and samplerate */ - value = gst_structure_get_value (structure, "codec_data"); - if (value) { - GstBuffer *buf = gst_value_get_buffer (value); - - if (buf) { - const guint8 *buffer = GST_BUFFER_DATA (buf); - guint sr_idx; - - sr_idx = ((buffer[0] & 0x07) << 1) | ((buffer[1] & 0x80) >> 7); - aacparse->object_type = (buffer[0] & 0xf8) >> 3; - aacparse->sample_rate = gst_aac_parse_get_sample_rate_from_index (sr_idx); - aacparse->channels = (buffer[1] & 0x78) >> 3; - aacparse->header_type = DSPAAC_HEADER_NONE; - aacparse->mpegversion = 4; - aacparse->frame_samples = (buffer[1] & 4) ? 960 : 1024; - - GST_DEBUG ("codec_data: object_type=%d, sample_rate=%d, channels=%d, " - "samples=%d", aacparse->object_type, aacparse->sample_rate, - aacparse->channels, aacparse->frame_samples); - - /* arrange for metadata and get out of the way */ - gst_aac_parse_set_src_caps (aacparse, caps); - gst_base_parse_set_passthrough (parse, TRUE); - } else - return FALSE; - - /* caps info overrides */ - gst_structure_get_int (structure, "rate", &aacparse->sample_rate); - gst_structure_get_int (structure, "channels", &aacparse->channels); - } else { - gst_base_parse_set_passthrough (parse, FALSE); - } - - return TRUE; -} - - -/** - * gst_aac_parse_adts_get_frame_len: - * @data: block of data containing an ADTS header. - * - * This function calculates ADTS frame length from the given header. - * - * Returns: size of the ADTS frame. - */ -static inline guint -gst_aac_parse_adts_get_frame_len (const guint8 * data) -{ - return ((data[3] & 0x03) << 11) | (data[4] << 3) | ((data[5] & 0xe0) >> 5); -} - - -/** - * gst_aac_parse_check_adts_frame: - * @aacparse: #GstAacParse. - * @data: Data to be checked. - * @avail: Amount of data passed. - * @framesize: If valid ADTS frame was found, this will be set to tell the - * found frame size in bytes. - * @needed_data: If frame was not found, this may be set to tell how much - * more data is needed in the next round to detect the frame - * reliably. This may happen when a frame header candidate - * is found but it cannot be guaranteed to be the header without - * peeking the following data. - * - * Check if the given data contains contains ADTS frame. The algorithm - * will examine ADTS frame header and calculate the frame size. Also, another - * consecutive ADTS frame header need to be present after the found frame. - * Otherwise the data is not considered as a valid ADTS frame. However, this - * "extra check" is omitted when EOS has been received. In this case it is - * enough when data[0] contains a valid ADTS header. - * - * This function may set the #needed_data to indicate that a possible frame - * candidate has been found, but more data (#needed_data bytes) is needed to - * be absolutely sure. When this situation occurs, FALSE will be returned. - * - * When a valid frame is detected, this function will use - * gst_base_parse_set_min_frame_size() function from #GstBaseParse class - * to set the needed bytes for next frame.This way next data chunk is already - * of correct size. - * - * Returns: TRUE if the given data contains a valid ADTS header. - */ -static gboolean -gst_aac_parse_check_adts_frame (GstAacParse * aacparse, - const guint8 * data, const guint avail, gboolean drain, - guint * framesize, guint * needed_data) -{ - if (G_UNLIKELY (avail < 2)) - return FALSE; - - if ((data[0] == 0xff) && ((data[1] & 0xf6) == 0xf0)) { - *framesize = gst_aac_parse_adts_get_frame_len (data); - - /* 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 - to get the correct sync, and this avoids losing two frames when - a single bit corruption happens. */ - if (drain || !GST_BASE_PARSE_LOST_SYNC (aacparse)) { - return TRUE; - } - - if (*framesize + ADTS_MAX_SIZE > avail) { - /* We have found a possible frame header candidate, but can't be - sure since we don't have enough data to check the next frame */ - GST_DEBUG ("NEED MORE DATA: we need %d, available %d", - *framesize + ADTS_MAX_SIZE, avail); - *needed_data = *framesize + ADTS_MAX_SIZE; - gst_base_parse_set_min_frame_size (GST_BASE_PARSE (aacparse), - *framesize + ADTS_MAX_SIZE); - return FALSE; - } - - if ((data[*framesize] == 0xff) && ((data[*framesize + 1] & 0xf6) == 0xf0)) { - guint nextlen = gst_aac_parse_adts_get_frame_len (data + (*framesize)); - - GST_LOG ("ADTS frame found, len: %d bytes", *framesize); - gst_base_parse_set_min_frame_size (GST_BASE_PARSE (aacparse), - nextlen + ADTS_MAX_SIZE); - return TRUE; - } - } - return FALSE; -} - -/* caller ensure sufficient data */ -static inline void -gst_aac_parse_parse_adts_header (GstAacParse * aacparse, const guint8 * data, - gint * rate, gint * channels, gint * object, gint * version) -{ - - if (rate) { - gint sr_idx = (data[2] & 0x3c) >> 2; - - *rate = gst_aac_parse_get_sample_rate_from_index (sr_idx); - } - if (channels) - *channels = ((data[2] & 0x01) << 2) | ((data[3] & 0xc0) >> 6); - - if (version) - *version = (data[1] & 0x08) ? 2 : 4; - if (object) - *object = (data[2] & 0xc0) >> 6; -} - -/** - * gst_aac_parse_detect_stream: - * @aacparse: #GstAacParse. - * @data: A block of data that needs to be examined for stream characteristics. - * @avail: Size of the given datablock. - * @framesize: If valid stream was found, this will be set to tell the - * first frame size in bytes. - * @skipsize: If valid stream was found, this will be set to tell the first - * audio frame position within the given data. - * - * Examines the given piece of data and try to detect the format of it. It - * checks for "ADIF" header (in the beginning of the clip) and ADTS frame - * header. If the stream is detected, TRUE will be returned and #framesize - * is set to indicate the found frame size. Additionally, #skipsize might - * be set to indicate the number of bytes that need to be skipped, a.k.a. the - * position of the frame inside given data chunk. - * - * Returns: TRUE on success. - */ -static gboolean -gst_aac_parse_detect_stream (GstAacParse * aacparse, - const guint8 * data, const guint avail, gboolean drain, - guint * framesize, gint * skipsize) -{ - gboolean found = FALSE; - guint need_data = 0; - guint i = 0; - - GST_DEBUG_OBJECT (aacparse, "Parsing header data"); - - /* FIXME: No need to check for ADIF if we are not in the beginning of the - stream */ - - /* Can we even parse the header? */ - if (avail < ADTS_MAX_SIZE) - return FALSE; - - for (i = 0; i < avail - 4; i++) { - if (((data[i] == 0xff) && ((data[i + 1] & 0xf6) == 0xf0)) || - strncmp ((char *) data + i, "ADIF", 4) == 0) { - found = TRUE; - - if (i) { - /* Trick: tell the parent class that we didn't find the frame yet, - but make it skip 'i' amount of bytes. Next time we arrive - here we have full frame in the beginning of the data. */ - *skipsize = i; - return FALSE; - } - break; - } - } - if (!found) { - if (i) - *skipsize = i; - return FALSE; - } - - if (gst_aac_parse_check_adts_frame (aacparse, data, avail, drain, - framesize, &need_data)) { - gint rate, channels; - - GST_INFO ("ADTS ID: %d, framesize: %d", (data[1] & 0x08) >> 3, *framesize); - - aacparse->header_type = DSPAAC_HEADER_ADTS; - gst_aac_parse_parse_adts_header (aacparse, data, &rate, &channels, - &aacparse->object_type, &aacparse->mpegversion); - - gst_base_parse_set_frame_rate (GST_BASE_PARSE (aacparse), rate, - aacparse->frame_samples, 2, 2); - - GST_DEBUG ("ADTS: samplerate %d, channels %d, objtype %d, version %d", - rate, channels, aacparse->object_type, aacparse->mpegversion); - - gst_base_parse_set_syncable (GST_BASE_PARSE (aacparse), TRUE); - - return TRUE; - } else if (need_data) { - /* This tells the parent class not to skip any data */ - *skipsize = 0; - return FALSE; - } - - if (avail < ADIF_MAX_SIZE) - return FALSE; - - if (memcmp (data + i, "ADIF", 4) == 0) { - const guint8 *adif; - int skip_size = 0; - int bitstream_type; - int sr_idx; - - aacparse->header_type = DSPAAC_HEADER_ADIF; - aacparse->mpegversion = 4; - - /* Skip the "ADIF" bytes */ - adif = data + i + 4; - - /* copyright string */ - if (adif[0] & 0x80) - skip_size += 9; /* skip 9 bytes */ - - bitstream_type = adif[0 + skip_size] & 0x10; - aacparse->bitrate = - ((unsigned int) (adif[0 + skip_size] & 0x0f) << 19) | - ((unsigned int) adif[1 + skip_size] << 11) | - ((unsigned int) adif[2 + skip_size] << 3) | - ((unsigned int) adif[3 + skip_size] & 0xe0); - - /* CBR */ - if (bitstream_type == 0) { -#if 0 - /* Buffer fullness parsing. Currently not needed... */ - guint num_elems = 0; - guint fullness = 0; - - num_elems = (adif[3 + skip_size] & 0x1e); - GST_INFO ("ADIF num_config_elems: %d", num_elems); - - fullness = ((unsigned int) (adif[3 + skip_size] & 0x01) << 19) | - ((unsigned int) adif[4 + skip_size] << 11) | - ((unsigned int) adif[5 + skip_size] << 3) | - ((unsigned int) (adif[6 + skip_size] & 0xe0) >> 5); - - GST_INFO ("ADIF buffer fullness: %d", fullness); -#endif - aacparse->object_type = ((adif[6 + skip_size] & 0x01) << 1) | - ((adif[7 + skip_size] & 0x80) >> 7); - sr_idx = (adif[7 + skip_size] & 0x78) >> 3; - } - /* VBR */ - else { - aacparse->object_type = (adif[4 + skip_size] & 0x18) >> 3; - sr_idx = ((adif[4 + skip_size] & 0x07) << 1) | - ((adif[5 + skip_size] & 0x80) >> 7); - } - - /* FIXME: This gives totally wrong results. Duration calculation cannot - be based on this */ - aacparse->sample_rate = gst_aac_parse_get_sample_rate_from_index (sr_idx); - - /* baseparse is not given any fps, - * so it will give up on timestamps, seeking, etc */ - - /* FIXME: Can we assume this? */ - aacparse->channels = 2; - - GST_INFO ("ADIF: br=%d, samplerate=%d, objtype=%d", - aacparse->bitrate, aacparse->sample_rate, aacparse->object_type); - - gst_base_parse_set_min_frame_size (GST_BASE_PARSE (aacparse), 512); - - /* arrange for metadata and get out of the way */ - gst_aac_parse_set_src_caps (aacparse, - GST_PAD_CAPS (GST_BASE_PARSE_SINK_PAD (aacparse))); - - /* not syncable, not easily seekable (unless we push data from start */ - gst_base_parse_set_syncable (GST_BASE_PARSE_CAST (aacparse), FALSE); - gst_base_parse_set_passthrough (GST_BASE_PARSE_CAST (aacparse), TRUE); - gst_base_parse_set_average_bitrate (GST_BASE_PARSE_CAST (aacparse), 0); - - *framesize = avail; - return TRUE; - } - - /* This should never happen */ - return FALSE; -} - - -/** - * gst_aac_parse_check_valid_frame: - * @parse: #GstBaseParse. - * @buffer: #GstBuffer. - * @framesize: If the buffer contains a valid frame, its size will be put here - * @skipsize: How much data parent class should skip in order to find the - * frame header. - * - * Implementation of "check_valid_frame" vmethod in #GstBaseParse class. - * - * Returns: TRUE if buffer contains a valid frame. - */ -static gboolean -gst_aac_parse_check_valid_frame (GstBaseParse * parse, - GstBaseParseFrame * frame, guint * framesize, gint * skipsize) -{ - const guint8 *data; - GstAacParse *aacparse; - gboolean ret = FALSE; - gboolean lost_sync; - GstBuffer *buffer; - - aacparse = GST_AAC_PARSE (parse); - buffer = frame->buffer; - data = GST_BUFFER_DATA (buffer); - - lost_sync = GST_BASE_PARSE_LOST_SYNC (parse); - - if (aacparse->header_type == DSPAAC_HEADER_ADIF || - aacparse->header_type == DSPAAC_HEADER_NONE) { - /* There is nothing to parse */ - *framesize = GST_BUFFER_SIZE (buffer); - ret = TRUE; - - } else if (aacparse->header_type == DSPAAC_HEADER_NOT_PARSED || lost_sync) { - - ret = gst_aac_parse_detect_stream (aacparse, data, GST_BUFFER_SIZE (buffer), - GST_BASE_PARSE_DRAINING (parse), framesize, skipsize); - - } else if (aacparse->header_type == DSPAAC_HEADER_ADTS) { - guint needed_data = 1024; - - ret = gst_aac_parse_check_adts_frame (aacparse, data, - GST_BUFFER_SIZE (buffer), GST_BASE_PARSE_DRAINING (parse), - framesize, &needed_data); - - if (!ret) { - GST_DEBUG ("buffer didn't contain valid frame"); - gst_base_parse_set_min_frame_size (GST_BASE_PARSE (aacparse), - needed_data); - } - - } else { - GST_DEBUG ("buffer didn't contain valid frame"); - gst_base_parse_set_min_frame_size (GST_BASE_PARSE (aacparse), - ADTS_MAX_SIZE); - } - - return ret; -} - - -#ifdef GST_EXT_AACPARSER_MODIFICATION /* to get more correct duration */ -/** - * 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)) { - return 0; - } - - /* 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; - GstClockTime estimated_duration = GST_CLOCK_TIME_NONE; - GstBuffer *buffer = NULL; - guint8 *buf = NULL; - gint i = 0; - GstActivateMode pad_mode = GST_ACTIVATE_NONE; - GstAacParse *aacparse; - - aacparse = GST_AAC_PARSE (parse); - GST_LOG_OBJECT (aacparse, "gst_aac_parse_estimate_duration enter"); - -#ifdef GST_EXT_BASEPARSER_MODIFICATION /* check baseparse define these fuction */ - gst_base_parse_get_pad_mode(parse, &pad_mode); - if (pad_mode != GST_ACTIVATE_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); -#else - GST_WARNING_OBJECT (aacparse, "baseparser does not define get private param functions"); - return FALSE; -#endif - - 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; - } - - buf = GST_BUFFER_DATA(buffer); - - for (i = 0; i < pull_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); - channel = (buf[i+2] & 0x1) << 2 | (buf[i+3] >> 6); - - GST_INFO_OBJECT (aacparse, "found sync. aac sample_rate=%d, channel=%d", sample_rate, channel); - - /* count number of frames */ - while (offset < pull_size) { - if ((frame_size = get_aac_parse_get_adts_frame_length(buf, i + offset)) == 0) { - GST_ERROR_OBJECT (aacparse, "framesize error at offset %"G_GINT64_FORMAT, offset); - break; - } - offset += frame_size; - num_frames++; - } /* while */ - - /* if we can got full file, we can calculate the accurate duration */ - if (pull_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)); - gst_base_parse_set_duration (parse, GST_FORMAT_TIME, calculated_duration, 0); /* 0 means disable estimate */ - - } 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_unref (buffer); - return TRUE; -} -#endif - - -/** - * gst_aac_parse_parse_frame: - * @parse: #GstBaseParse. - * @buffer: #GstBuffer. - * - * Implementation of "parse_frame" vmethod in #GstBaseParse class. - * - * Also determines frame overhead. - * ADTS streams have a 7 byte header in each frame. MP4 and ADIF streams don't have - * a per-frame header. - * - * We're making a couple of simplifying assumptions: - * - * 1. We count Program Configuration Elements rather than searching for them - * in the streams to discount them - the overhead is negligible. - * - * 2. We ignore CRC. This has a worst-case impact of (num_raw_blocks + 1)*16 - * bits, which should still not be significant enough to warrant the - * additional parsing through the headers - * - * Returns: GST_FLOW_OK if frame was successfully parsed and can be pushed - * forward. Otherwise appropriate error is returned. - */ -static GstFlowReturn -gst_aac_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame) -{ - GstAacParse *aacparse; - GstBuffer *buffer; - GstFlowReturn ret = GST_FLOW_OK; - gint rate, channels; - - aacparse = GST_AAC_PARSE (parse); - buffer = frame->buffer; - - if (G_UNLIKELY (aacparse->header_type != DSPAAC_HEADER_ADTS)) - return ret; - - /* see above */ - frame->overhead = 7; - - gst_aac_parse_parse_adts_header (aacparse, GST_BUFFER_DATA (buffer), - &rate, &channels, NULL, NULL); - GST_LOG_OBJECT (aacparse, "rate: %d, chans: %d", rate, channels); - - if (G_UNLIKELY (rate != aacparse->sample_rate - || channels != aacparse->channels)) { - aacparse->sample_rate = rate; - aacparse->channels = channels; - - if (!gst_aac_parse_set_src_caps (aacparse, - GST_PAD_CAPS (GST_BASE_PARSE (aacparse)->sinkpad))) { - /* If linking fails, we need to return appropriate error */ - ret = GST_FLOW_NOT_LINKED; - } - - gst_base_parse_set_frame_rate (GST_BASE_PARSE (aacparse), - aacparse->sample_rate, aacparse->frame_samples, 2, 2); - } - -#ifdef GST_EXT_AACPARSER_MODIFICATION /* to get more correct duration */ - 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"); - } - } -#endif - - return ret; -} - - -/** - * gst_aac_parse_start: - * @parse: #GstBaseParse. - * - * Implementation of "start" vmethod in #GstBaseParse class. - * - * Returns: TRUE if startup succeeded. - */ -static gboolean -gst_aac_parse_start (GstBaseParse * parse) -{ - GstAacParse *aacparse; - - aacparse = GST_AAC_PARSE (parse); - GST_DEBUG ("start"); - aacparse->frame_samples = 1024; - gst_base_parse_set_min_frame_size (GST_BASE_PARSE (aacparse), ADTS_MAX_SIZE); - return TRUE; -} - - -/** - * gst_aac_parse_stop: - * @parse: #GstBaseParse. - * - * Implementation of "stop" vmethod in #GstBaseParse class. - * - * Returns: TRUE is stopping succeeded. - */ -static gboolean -gst_aac_parse_stop (GstBaseParse * parse) -{ - GST_DEBUG ("stop"); - return TRUE; -} - -static GstCaps * -gst_aac_parse_sink_getcaps (GstBaseParse * parse) -{ - GstCaps *peercaps; - GstCaps *res; - - peercaps = gst_pad_get_allowed_caps (GST_BASE_PARSE_SRC_PAD (parse)); - if (peercaps) { - guint i, n; - - /* Remove the framed field */ - peercaps = gst_caps_make_writable (peercaps); - n = gst_caps_get_size (peercaps); - for (i = 0; i < n; i++) { - GstStructure *s = gst_caps_get_structure (peercaps, i); - - gst_structure_remove_field (s, "framed"); - } - - res = - gst_caps_intersect_full (peercaps, - gst_pad_get_pad_template_caps (GST_BASE_PARSE_SRC_PAD (parse)), - GST_CAPS_INTERSECT_FIRST); - gst_caps_unref (peercaps); - } else { - res = - gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_PARSE_SINK_PAD - (parse))); - } - - return res; -} |