1 // Copyright 2014 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "media/filters/ffmpeg_aac_bitstream_converter.h"
7 #include "base/logging.h"
8 #include "media/ffmpeg/ffmpeg_common.h"
14 // Creates an ADTS header and stores in |hdr|
15 // Assumes |hdr| points to an array of length |kAdtsHeaderSize|
16 // Returns false if parameter values are for an unsupported configuration.
17 bool GenerateAdtsHeader(int codec,
20 int sample_rate_index,
22 int channel_configuration,
25 int copyrighted_stream,
29 int number_of_frames_minus_one,
31 DCHECK_EQ(codec, AV_CODEC_ID_AAC);
33 memset(reinterpret_cast<void *>(hdr), 0,
34 FFmpegAACBitstreamConverter::kAdtsHeaderSize);
35 // Ref: http://wiki.multimedia.cx/index.php?title=ADTS
36 // ADTS header structure is the following
37 // AAAAAAAA AAAABCCD EEFFFFGH HHIJKLMM MMMMMMMM MMMOOOOO OOOOOOPP
39 // A Syncword 0xFFF, all bits must be 1
40 // B MPEG Version: 0 for MPEG-4, 1 for MPEG-2
42 // D Protection absent: Set to 1 if no CRC and 0 if there is CRC.
43 // E Profile: the MPEG-4 Audio Object Type minus 1.
44 // F MPEG-4 Sampling Frequency Index (15 is forbidden)
46 // H MPEG-4 Channel Configuration
49 // K Copyrighted Stream
51 // M Frame length. This must include the ADTS header length.
53 // P Number of AAC frames in ADTS frame minus 1.
54 // For maximum compatibility always use 1 AAC frame per ADTS frame.
60 // Layer is always 0. No further action required.
62 // Protection absent (no CRC) is always 1.
65 switch (audio_profile) {
66 case FF_PROFILE_AAC_MAIN:
68 case FF_PROFILE_AAC_HE:
69 case FF_PROFILE_AAC_HE_V2:
70 case FF_PROFILE_AAC_LOW:
73 case FF_PROFILE_AAC_SSR:
76 case FF_PROFILE_AAC_LTP:
80 DLOG(ERROR) << "[" << __func__ << "] "
81 << "unsupported audio profile:" << audio_profile;
85 hdr[2] |= ((sample_rate_index & 0xf) << 2);
90 switch (channel_configuration) {
96 // front-left, front-right
100 // front-center, front-left, front-right
104 // front-center, front-left, front-right, back-center
108 // front-center, front-left, front-right, back-left, back-right
113 // front-center, front-left, front-right, back-left, back-right,
119 // front-center, front-left, front-right, side-left, side-right,
120 // back-left, back-right, LFE-channel
125 DLOG(ERROR) << "[" << __func__ << "] "
126 << "unsupported number of audio channels:"
127 << channel_configuration;
137 if (copyrighted_stream)
144 hdr[3] |= (frame_length >> 11) & 0x03;
145 hdr[4] = (frame_length >> 3) & 0xFF;
146 hdr[5] |= (frame_length & 7) << 5;
149 hdr[5] |= (buffer_fullness >> 6) & 0x1F;
150 hdr[6] |= (buffer_fullness & 0x3F) << 2;
152 hdr[6] |= number_of_frames_minus_one & 0x3;
159 FFmpegAACBitstreamConverter::FFmpegAACBitstreamConverter(
160 AVCodecParameters* stream_codec_parameters)
161 : stream_codec_parameters_(stream_codec_parameters),
162 header_generated_(false),
165 sample_rate_index_(),
166 channel_configuration_(),
168 CHECK(stream_codec_parameters_);
171 FFmpegAACBitstreamConverter::~FFmpegAACBitstreamConverter() = default;
173 bool FFmpegAACBitstreamConverter::ConvertPacket(AVPacket* packet) {
174 if (packet == NULL || !packet->data) {
178 int header_plus_packet_size =
179 packet->size + kAdtsHeaderSize;
180 if (!stream_codec_parameters_->extradata) {
181 DLOG(ERROR) << "extradata is null";
184 if (stream_codec_parameters_->extradata_size < 2) {
185 DLOG(ERROR) << "extradata too small to contain MP4A header";
188 int sample_rate_index =
189 ((stream_codec_parameters_->extradata[0] & 0x07) << 1) |
190 ((stream_codec_parameters_->extradata[1] & 0x80) >> 7);
191 if (sample_rate_index > 12) {
192 sample_rate_index = 4;
195 if (!header_generated_ || codec_ != stream_codec_parameters_->codec_id ||
196 audio_profile_ != stream_codec_parameters_->profile ||
197 sample_rate_index_ != sample_rate_index ||
198 channel_configuration_ !=
199 stream_codec_parameters_->ch_layout.nb_channels ||
200 frame_length_ != header_plus_packet_size) {
202 GenerateAdtsHeader(stream_codec_parameters_->codec_id,
204 stream_codec_parameters_->profile, sample_rate_index,
206 stream_codec_parameters_->ch_layout.nb_channels,
209 0, // copyrighted_stream
210 0, // copyright_ start
211 header_plus_packet_size,
212 0x7FF, // buffer fullness
213 0, // one frame per packet
215 codec_ = stream_codec_parameters_->codec_id;
216 audio_profile_ = stream_codec_parameters_->profile;
217 sample_rate_index_ = sample_rate_index;
218 channel_configuration_ = stream_codec_parameters_->ch_layout.nb_channels;
219 frame_length_ = header_plus_packet_size;
222 // Inform caller if the header generation failed.
223 if (!header_generated_)
226 // Allocate new packet for the output.
227 AVPacket dest_packet;
228 if (av_new_packet(&dest_packet, header_plus_packet_size) != 0)
229 return false; // Memory allocation failure.
231 memcpy(dest_packet.data, hdr_, kAdtsHeaderSize);
232 memcpy(reinterpret_cast<void*>(dest_packet.data + kAdtsHeaderSize),
233 reinterpret_cast<void*>(packet->data), packet->size);
235 // This is a bit tricky: since the interface does not allow us to replace
236 // the pointer of the old packet with a new one, we will initially copy the
237 // metadata from old packet to new bigger packet.
238 av_packet_copy_props(&dest_packet, packet);
240 // Release the old packet.
241 av_packet_unref(packet);
243 // Finally, replace the values in the input packet.
244 memcpy(packet, &dest_packet, sizeof(*packet));