From: Vincent Penquerc'h Date: Mon, 15 Jul 2013 16:11:45 +0000 (+0100) Subject: aacparse: allow conversion from ADTS to raw AAC X-Git-Tag: 1.1.3~50 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=91d4abceaada3dfd313d27152f51c7055d1f6ad0;p=platform%2Fupstream%2Fgst-plugins-good.git aacparse: allow conversion from ADTS to raw AAC Some muxers (eg, qtmux) only support raw AAC, so this allows linking an encoder that outputs ADTS only to those muxers. The conversion is simple (omit the first 7 or 9 bytes of the frame), but has to be done in pre_push instead of handle_frame as 1.0 does not seem to allow skipping bytes there as 0.10 used to. Other conversions are not supported (yet). --- diff --git a/gst/audioparsers/Makefile.am b/gst/audioparsers/Makefile.am index 1263c93..b2b2a4d 100644 --- a/gst/audioparsers/Makefile.am +++ b/gst/audioparsers/Makefile.am @@ -8,6 +8,7 @@ libgstaudioparsers_la_SOURCES = \ libgstaudioparsers_la_CFLAGS = \ $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) libgstaudioparsers_la_LIBADD = \ + -lgstpbutils-$(GST_API_VERSION) \ $(GST_PLUGINS_BASE_LIBS) -lgsttag-$(GST_API_VERSION) \ -lgstaudio-$(GST_API_VERSION) \ $(GST_BASE_LIBS) $(GST_LIBS) diff --git a/gst/audioparsers/gstaacparse.c b/gst/audioparsers/gstaacparse.c index 8291917..784a2fa 100644 --- a/gst/audioparsers/gstaacparse.c +++ b/gst/audioparsers/gstaacparse.c @@ -45,6 +45,7 @@ #include #include +#include #include "gstaacparse.h" @@ -91,22 +92,11 @@ static GstCaps *gst_aac_parse_sink_getcaps (GstBaseParse * parse, 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); G_DEFINE_TYPE (GstAacParse, gst_aac_parse, GST_TYPE_BASE_PARSE); -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_class_init: * @klass: #GstAacParseClass. @@ -135,6 +125,8 @@ gst_aac_parse_class_init (GstAacParseClass * klass) 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->handle_frame = GST_DEBUG_FUNCPTR (gst_aac_parse_handle_frame); + parse_class->pre_push_frame = + GST_DEBUG_FUNCPTR (gst_aac_parse_pre_push_frame); } @@ -165,9 +157,11 @@ static gboolean gst_aac_parse_set_src_caps (GstAacParse * aacparse, GstCaps * sink_caps) { GstStructure *s; - GstCaps *src_caps = NULL; + GstCaps *src_caps = NULL, *allowed; gboolean res = FALSE; const gchar *stream_format; + GstBuffer *codec_data; + guint16 codec_data_data; GST_DEBUG_OBJECT (aacparse, "sink caps: %" GST_PTR_FORMAT, sink_caps); if (sink_caps) @@ -178,6 +172,7 @@ gst_aac_parse_set_src_caps (GstAacParse * aacparse, GstCaps * sink_caps) gst_caps_set_simple (src_caps, "framed", G_TYPE_BOOLEAN, TRUE, "mpegversion", G_TYPE_INT, aacparse->mpegversion, NULL); + aacparse->output_header_type = aacparse->header_type; switch (aacparse->header_type) { case DSPAAC_HEADER_NONE: stream_format = "raw"; @@ -203,11 +198,55 @@ gst_aac_parse_set_src_caps (GstAacParse * aacparse, GstCaps * sink_caps) if (stream_format) gst_structure_set (s, "stream-format", G_TYPE_STRING, stream_format, NULL); + allowed = gst_pad_get_allowed_caps (GST_BASE_PARSE (aacparse)->srcpad); + if (!gst_caps_can_intersect (src_caps, allowed)) { + GST_DEBUG_OBJECT (GST_BASE_PARSE (aacparse)->srcpad, + "Caps can not intersect"); + if (aacparse->header_type == DSPAAC_HEADER_ADTS) { + GST_DEBUG_OBJECT (GST_BASE_PARSE (aacparse)->srcpad, + "Input is ADTS, trying raw"); + gst_caps_set_simple (src_caps, "stream-format", G_TYPE_STRING, "raw", + NULL); + if (gst_caps_can_intersect (src_caps, allowed)) { + GstMapInfo map; + int idx; + + idx = + gst_codec_utils_aac_get_index_from_sample_rate + (aacparse->sample_rate); + if (idx < 0) + goto not_a_known_rate; + + GST_DEBUG_OBJECT (GST_BASE_PARSE (aacparse)->srcpad, + "Caps can intersect, we will drop the ADTS layer"); + aacparse->output_header_type = DSPAAC_HEADER_NONE; + + /* The codec_data data is according to AudioSpecificConfig, + ISO/IEC 14496-3, 1.6.2.1 */ + codec_data = gst_buffer_new_and_alloc (2); + gst_buffer_map (codec_data, &map, GST_MAP_WRITE); + codec_data_data = + (aacparse->object_type << 11) | + (idx << 7) | (aacparse->channels << 3); + GST_WRITE_UINT16_BE (map.data, codec_data_data); + gst_buffer_unmap (codec_data, &map); + gst_caps_set_simple (src_caps, "codec_data", GST_TYPE_BUFFER, + codec_data, NULL); + } + } + } + gst_caps_unref (allowed); + 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; + +not_a_known_rate: + gst_caps_unref (allowed); + gst_caps_unref (src_caps); + return FALSE; } @@ -250,7 +289,8 @@ gst_aac_parse_sink_setcaps (GstBaseParse * parse, GstCaps * caps) sr_idx = ((map.data[0] & 0x07) << 1) | ((map.data[1] & 0x80) >> 7); aacparse->object_type = (map.data[0] & 0xf8) >> 3; - aacparse->sample_rate = gst_aac_parse_get_sample_rate_from_index (sr_idx); + aacparse->sample_rate = + gst_codec_utils_aac_get_sample_rate_from_index (sr_idx); aacparse->channels = (map.data[1] & 0x78) >> 3; aacparse->header_type = DSPAAC_HEADER_NONE; aacparse->mpegversion = 4; @@ -669,7 +709,7 @@ gst_aac_parse_parse_adts_header (GstAacParse * aacparse, const guint8 * data, if (rate) { gint sr_idx = (data[2] & 0x3c) >> 2; - *rate = gst_aac_parse_get_sample_rate_from_index (sr_idx); + *rate = gst_codec_utils_aac_get_sample_rate_from_index (sr_idx); } if (channels) *channels = ((data[2] & 0x01) << 2) | ((data[3] & 0xc0) >> 6); @@ -860,7 +900,8 @@ gst_aac_parse_detect_stream (GstAacParse * aacparse, /* 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); + aacparse->sample_rate = + gst_codec_utils_aac_get_sample_rate_from_index (sr_idx); /* baseparse is not given any fps, * so it will give up on timestamps, seeking, etc */ @@ -1056,6 +1097,26 @@ exit: return GST_FLOW_OK; } +static GstFlowReturn +gst_aac_parse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame) +{ + GstAacParse *aacparse = GST_AAC_PARSE (parse); + + /* As a special case, we can remove the ADTS framing and output raw AAC. */ + if (aacparse->header_type == DSPAAC_HEADER_ADTS + && aacparse->output_header_type == DSPAAC_HEADER_NONE) { + guint header_size; + GstMapInfo map; + gst_buffer_map (frame->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); + } + + return GST_FLOW_OK; +} + /** * gst_aac_parse_start: diff --git a/gst/audioparsers/gstaacparse.h b/gst/audioparsers/gstaacparse.h index 8eca9aa..51a2ed1 100644 --- a/gst/audioparsers/gstaacparse.h +++ b/gst/audioparsers/gstaacparse.h @@ -80,6 +80,7 @@ struct _GstAacParse { gint frame_samples; GstAacHeaderType header_type; + GstAacHeaderType output_header_type; }; /**