Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(193)

Unified Diff: media/filters/ffmpeg_aac_bitstream_converter.cc

Issue 691233002: Added aac bitstream converter (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Figured it out Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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..bc29f1f8845ecedb9ff540c892b69a56d9655b2b
--- /dev/null
+++ b/media/filters/ffmpeg_aac_bitstream_converter.cc
@@ -0,0 +1,217 @@
+// 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 {
+
+namespace {
+
+// Creates an ADTS header and stores in |hdr|
+// Assumes |hdr| points to an array of length |kAdtsHeaderSize|
+// Returns false if parameter values are for an unsupported configuration.
+bool 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, uint8* hdr) {
+ DCHECK_EQ(codec, CODEC_ID_AAC);
+
+ memset(reinterpret_cast<void *>(hdr), 0,
+ FFmpegAACBitstreamConverter::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;
+}
+
+}
+
+FFmpegAACBitstreamConverter::FFmpegAACBitstreamConverter(
+ AVCodecContext* stream_codec_context)
+ : stream_codec_context_(stream_codec_context),
+ header_generated_(false) {
+ CHECK(stream_codec_context_);
+}
+
+FFmpegAACBitstreamConverter::~FFmpegAACBitstreamConverter() {
+}
+
+bool FFmpegAACBitstreamConverter::ConvertPacket(AVPacket* packet) {
+ if (packet == NULL || !packet->data) {
+ return false;
+ }
+
+ 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
+ hdr_);
+ }
+
+ // 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;
+}
+
+} // namespace media

Powered by Google App Engine
This is Rietveld 408576698