| Index: media/filters/ffmpeg_aac_bitstream_converter.cc
|
| diff --git a/media/filters/ffmpeg_aac_bitstream_converter.cc b/media/filters/ffmpeg_aac_bitstream_converter.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..020bc29deadcfe32f7df9022c81753df8cb7426c
|
| --- /dev/null
|
| +++ b/media/filters/ffmpeg_aac_bitstream_converter.cc
|
| @@ -0,0 +1,205 @@
|
| +// Copyright 2014 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "media/filters/ffmpeg_aac_bitstream_converter.h"
|
| +
|
| +#include "base/logging.h"
|
| +#include "media/ffmpeg/ffmpeg_common.h"
|
| +
|
| +namespace media {
|
| +
|
| +FFmpegAACBitstreamConverter::FFmpegAACBitstreamConverter(
|
| + AVCodecContext* stream_codec_context)
|
| + : stream_codec_context_(stream_codec_context) {
|
| + CHECK(stream_codec_context_);
|
| + header_generated_ = false;
|
| +}
|
| +
|
| +FFmpegAACBitstreamConverter::~FFmpegAACBitstreamConverter() {
|
| +}
|
| +
|
| +bool FFmpegAACBitstreamConverter::ConvertPacket(AVPacket* packet) {
|
| + int header_plus_packet_size =
|
| + packet->size + kAdtsHeaderSize;
|
| + if (!header_generated_) {
|
| + if (!stream_codec_context_->extradata) {
|
| + DLOG(ERROR) << "extradata is null";
|
| + return false;
|
| + }
|
| + if (stream_codec_context_->extradata_size < 2) {
|
| + DLOG(ERROR) << "extradata too small to contain MP4A header";
|
| + return false;
|
| + }
|
| + int sample_rate_index =
|
| + ((stream_codec_context_->extradata[0] & 0x07) << 1) |
|
| + ((stream_codec_context_->extradata[1] & 0x80) >> 7);
|
| + if (sample_rate_index > 12) {
|
| + sample_rate_index = 4;
|
| + }
|
| + header_generated_ = GenerateAdtsHeader(stream_codec_context_->codec_id,
|
| + 0, // layer
|
| + stream_codec_context_->profile,
|
| + sample_rate_index,
|
| + 0, // private stream
|
| + stream_codec_context_->channels,
|
| + 0, // originality
|
| + 0, // home
|
| + 0, // copyrighted_stream
|
| + 0, // copyright start
|
| + header_plus_packet_size,
|
| + 0x7FF, // buffer fullness
|
| + 0); // one frame per packet
|
| + }
|
| +
|
| + // Inform caller if the header generation failed.
|
| + if (!header_generated_)
|
| + return false;
|
| +
|
| + // Allocate new packet for the output.
|
| + AVPacket dest_packet;
|
| + if (av_new_packet(&dest_packet, header_plus_packet_size) != 0)
|
| + return false; // Memory allocation failure.
|
| +
|
| + memcpy(dest_packet.data, hdr_, kAdtsHeaderSize);
|
| + memcpy(reinterpret_cast<void*>(dest_packet.data + kAdtsHeaderSize),
|
| + reinterpret_cast<void*>(packet->data), packet->size);
|
| +
|
| + // This is a bit tricky: since the interface does not allow us to replace
|
| + // the pointer of the old packet with a new one, we will initially copy the
|
| + // metadata from old packet to new bigger packet.
|
| + av_packet_copy_props(&dest_packet, packet);
|
| +
|
| + // Release the old packet.
|
| + av_free_packet(packet);
|
| + *packet = dest_packet; // Finally, replace the values in the input packet.
|
| +
|
| + return true;
|
| +}
|
| +
|
| +bool FFmpegAACBitstreamConverter::GenerateAdtsHeader(
|
| + int codec, int layer, int audio_profile, int sample_rate_index,
|
| + int private_stream, int channel_configuration, int originality, int home,
|
| + int copyrighted_stream, int copyright_start, int frame_length,
|
| + int buffer_fullness, int number_of_frames_minus_one) {
|
| + DCHECK_EQ(codec, CODEC_ID_AAC);
|
| +
|
| + memset(reinterpret_cast<void *>(hdr_), 0,
|
| + kAdtsHeaderSize);
|
| + // Ref: http://wiki.multimedia.cx/index.php?title=ADTS
|
| + // ADTS header structure is the following
|
| + // AAAAAAAA AAAABCCD EEFFFFGH HHIJKLMM MMMMMMMM MMMOOOOO OOOOOOPP
|
| + //
|
| + // A Syncword 0xFFF, all bits must be 1
|
| + // B MPEG Version: 0 for MPEG-4, 1 for MPEG-2
|
| + // C Layer: always 0
|
| + // D Protection absent: Set to 1 if no CRC and 0 if there is CRC.
|
| + // E Profile: the MPEG-4 Audio Object Type minus 1.
|
| + // F MPEG-4 Sampling Frequency Index (15 is forbidden)
|
| + // G Private stream:
|
| + // H MPEG-4 Channel Configuration
|
| + // I Originality
|
| + // J Home
|
| + // K Copyrighted Stream
|
| + // L Copyright start
|
| + // M Frame length. This must include the ADTS header length.
|
| + // O Buffer fullness
|
| + // P Number of AAC frames in ADTS frame minus 1.
|
| + // For maximum compatibility always use 1 AAC frame per ADTS frame.
|
| +
|
| + // Syncword
|
| + hdr_[0] = 0xFF;
|
| + hdr_[1] = 0xF0;
|
| +
|
| + // Layer is always 0. No further action required.
|
| +
|
| + // Protection absent (no CRC) is always 1.
|
| + hdr_[1] |= 1;
|
| +
|
| + switch (audio_profile) {
|
| + case FF_PROFILE_AAC_MAIN:
|
| + break;
|
| + case FF_PROFILE_AAC_LOW:
|
| + hdr_[2] |= (1 << 6);
|
| + break;
|
| + case FF_PROFILE_AAC_SSR:
|
| + hdr_[2] |= (2 << 6);
|
| + break;
|
| + case FF_PROFILE_AAC_LTP:
|
| + hdr_[2] |= (3 << 6);
|
| + break;
|
| + }
|
| +
|
| + hdr_[2] |= ((sample_rate_index & 0xf) << 2);
|
| +
|
| + if (private_stream)
|
| + hdr_[2] |= (1 << 1);
|
| +
|
| + switch (channel_configuration) {
|
| + case 1:
|
| + // front-center
|
| + hdr_[3] |= (1 << 6);
|
| + break;
|
| + case 2:
|
| + // front-left, front-right
|
| + hdr_[3] |= (2 << 6);
|
| + break;
|
| + case 3:
|
| + // front-center, front-left, front-right
|
| + hdr_[3] |= (3 << 6);
|
| + break;
|
| + case 4:
|
| + // front-center, front-left, front-right, back-center
|
| + hdr_[2] |= 1;
|
| + break;
|
| + case 5:
|
| + // front-center, front-left, front-right, back-left, back-right
|
| + hdr_[2] |= 1;
|
| + hdr_[3] |= (1 << 6);
|
| + break;
|
| + case 6:
|
| + // front-center, front-left, front-right, back-left, back-right,
|
| + // LFE-channel
|
| + hdr_[2] |= 1;
|
| + hdr_[3] |= (2 << 6);
|
| + break;
|
| + case 7:
|
| + // front-center, front-left, front-right, side-left, side-right,
|
| + // back-left, back-right, LFE-channel
|
| + hdr_[2] |= 1;
|
| + hdr_[3] |= (3 << 6);
|
| + break;
|
| + default:
|
| + DLOG(ERROR) << "[" << __FUNCTION__ << "] "
|
| + << "unsupported number of audio channels:"
|
| + << channel_configuration;
|
| + return false;
|
| + }
|
| +
|
| + if (originality)
|
| + hdr_[3] |= (1 << 5);
|
| +
|
| + if (home)
|
| + hdr_[3] |= (1 << 4);
|
| +
|
| + if (copyrighted_stream)
|
| + hdr_[3] |= (1 << 3);
|
| +
|
| + if (copyright_start)
|
| + hdr_[3] |= (1 << 2);
|
| +
|
| + // frame length
|
| + hdr_[3] |= (frame_length >> 11) & 0x03;
|
| + hdr_[4] = (frame_length >> 3) & 0xFF;
|
| + hdr_[5] |= (frame_length & 7) << 5;
|
| +
|
| + // buffer fullness
|
| + hdr_[5] |= (buffer_fullness >> 6) & 0x1F;
|
| + hdr_[6] |= (buffer_fullness & 0x3F) << 2;
|
| +
|
| + hdr_[6] |= number_of_frames_minus_one & 0x3;
|
| +
|
| + return true;
|
| +}
|
| +
|
| +} // namespace media
|
|
|