diff options
author | qinmin@chromium.org <qinmin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-05-31 03:48:40 +0000 |
---|---|---|
committer | qinmin@chromium.org <qinmin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-05-31 03:48:40 +0000 |
commit | fd7dead1ecd0218e8e7170dbe385058eec95cba1 (patch) | |
tree | 75556b5302e1eeb8a53c22fa6c93a871392ad436 /media/base | |
parent | 063121b87ad753de81230b5c320009529eecb15e (diff) | |
download | chromium_src-fd7dead1ecd0218e8e7170dbe385058eec95cba1.zip chromium_src-fd7dead1ecd0218e8e7170dbe385058eec95cba1.tar.gz chromium_src-fd7dead1ecd0218e8e7170dbe385058eec95cba1.tar.bz2 |
Add AAC codec specific data for MSE on android
For AAC/ADTS, MediaCodec needs csd in order to work properly.
Passing the csd data from the stream parser using the extra_data field.
BUG=233420
Review URL: https://chromiumcodereview.appspot.com/16114009
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@203330 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media/base')
-rw-r--r-- | media/base/android/java/src/org/chromium/media/MediaCodecBridge.java | 5 | ||||
-rw-r--r-- | media/base/android/media_codec_bridge.cc | 148 | ||||
-rw-r--r-- | media/base/android/media_codec_bridge.h | 4 |
3 files changed, 113 insertions, 44 deletions
diff --git a/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java b/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java index 399ae27..ac3a3bf 100644 --- a/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java +++ b/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java @@ -193,6 +193,11 @@ class MediaCodecBridge { } @CalledByNative + private static void setFrameHasADTSHeader(MediaFormat format) { + format.setInteger(MediaFormat.KEY_IS_ADTS, 1); + } + + @CalledByNative private void configureAudio(MediaFormat format, MediaCrypto crypto, int flags, boolean playAudio) { mMediaCodec.configure(format, null, crypto, flags); diff --git a/media/base/android/media_codec_bridge.cc b/media/base/android/media_codec_bridge.cc index 2587fc4..d64528d 100644 --- a/media/base/android/media_codec_bridge.cc +++ b/media/base/android/media_codec_bridge.cc @@ -15,8 +15,8 @@ #include "base/logging.h" #include "base/safe_numerics.h" #include "base/stringprintf.h" - #include "jni/MediaCodecBridge_jni.h" +#include "media/base/bit_reader.h" using base::android::AttachCurrentThread; using base::android::ConvertUTF8ToJavaString; @@ -83,6 +83,7 @@ MediaCodecBridge::~MediaCodecBridge() { void MediaCodecBridge::StartInternal() { JNIEnv* env = AttachCurrentThread(); Java_MediaCodecBridge_start(env, j_media_codec_.obj()); + GetOutputBuffers(); } void MediaCodecBridge::Reset() { @@ -193,57 +194,116 @@ bool AudioCodecBridge::Start( env, j_mime.obj(), sample_rate, channel_count)); DCHECK(!j_format.is_null()); - if (extra_data_size > 0) { - DCHECK_EQ(kCodecVorbis, codec); - if (extra_data[0] != 2) { - LOG(ERROR) << "Invalid number of headers before the codec header: " - << extra_data[0]; - return false; - } + if (!ConfigureMediaFormat(j_format.obj(), codec, extra_data, extra_data_size)) + return false; + + Java_MediaCodecBridge_configureAudio( + env, media_codec(), j_format.obj(), NULL, 0, play_audio); + StartInternal(); + return true; +} + +bool AudioCodecBridge::ConfigureMediaFormat( + jobject j_format, const AudioCodec codec, const uint8* extra_data, + size_t extra_data_size) { + if (extra_data_size == 0) + return true; + + JNIEnv* env = AttachCurrentThread(); + switch(codec) { + case kCodecVorbis: + { + if (extra_data[0] != 2) { + LOG(ERROR) << "Invalid number of vorbis headers before the codec " + << "header: " << extra_data[0]; + return false; + } - size_t header_length[2]; - // |total_length| keeps track of the total number of bytes before the last - // header. - size_t total_length = 1; - const uint8* current_pos = extra_data; - // Calculate the length of the first 2 headers. - for (int i = 0; i < 2; ++i) { - header_length[i] = 0; - while (total_length < extra_data_size) { - size_t size = *(++current_pos); - total_length += 1 + size; - if (total_length > 0x80000000) { - LOG(ERROR) << "Header size too large"; + size_t header_length[2]; + // |total_length| keeps track of the total number of bytes before the last + // header. + size_t total_length = 1; + const uint8* current_pos = extra_data; + // Calculate the length of the first 2 headers. + for (int i = 0; i < 2; ++i) { + header_length[i] = 0; + while (total_length < extra_data_size) { + size_t size = *(++current_pos); + total_length += 1 + size; + if (total_length > 0x80000000) { + LOG(ERROR) << "Vorbis header size too large"; + return false; + } + header_length[i] += size; + if (size < 0xFF) + break; + } + if (total_length >= extra_data_size) { + LOG(ERROR) << "Invalid vorbis header size in the extra data"; return false; } - header_length[i] += size; - if (size < 0xFF) - break; } - if (total_length >= extra_data_size) { - LOG(ERROR) << "Invalid header size in the extra data"; + current_pos++; + // The first header is identification header. + jobject identification_header = env->NewDirectByteBuffer( + const_cast<uint8*>(current_pos), header_length[0]); + Java_MediaCodecBridge_setCodecSpecificData( + env, j_format, 0, identification_header); + // The last header is codec header. + jobject codec_header = env->NewDirectByteBuffer( + const_cast<uint8*>(extra_data + total_length), + extra_data_size - total_length); + Java_MediaCodecBridge_setCodecSpecificData( + env, j_format, 1, codec_header); + env->DeleteLocalRef(codec_header); + env->DeleteLocalRef(identification_header); + break; + } + case kCodecAAC: + { + media::BitReader reader(extra_data, extra_data_size); + + // The following code is copied from aac.cc + // TODO(qinmin): refactor the code in aac.cc to make it more reusable. + uint8 profile = 0; + uint8 frequency_index = 0; + uint8 channel_config = 0; + if (!reader.ReadBits(5, &profile) || + !reader.ReadBits(4, &frequency_index)) { + LOG(ERROR) << "Unable to parse AAC header"; + return false; + } + if (0xf == frequency_index && !reader.SkipBits(24)) { + LOG(ERROR) << "Unable to parse AAC header"; return false; } + if (!reader.ReadBits(4, &channel_config)) { + LOG(ERROR) << "Unable to parse AAC header"; + return false; + } + + if (profile < 1 || profile > 4 || frequency_index == 0xf || + channel_config > 7) { + LOG(ERROR) << "Invalid AAC header"; + return false; + } + uint8 csd[2]; + csd[0] = profile << 3 | frequency_index >> 1; + csd[1] = (frequency_index & 0x01) << 7 | channel_config << 3; + jobject header = env->NewDirectByteBuffer(csd, 2); + Java_MediaCodecBridge_setCodecSpecificData( + env, j_format, 0, header); + // TODO(qinmin): pass an extra variable to this function to determine + // whether we need to call this. + Java_MediaCodecBridge_setFrameHasADTSHeader(env, j_format); + env->DeleteLocalRef(header); + break; } - current_pos++; - // The first header is identification header. - jobject identification_header = env->NewDirectByteBuffer( - const_cast<uint8*>(current_pos), header_length[0]); - Java_MediaCodecBridge_setCodecSpecificData( - env, j_format.obj(), 0, identification_header); - // The last header is codec header. - jobject codec_header = env->NewDirectByteBuffer( - const_cast<uint8*>(extra_data + total_length), - extra_data_size - total_length); - Java_MediaCodecBridge_setCodecSpecificData( - env, j_format.obj(), 1, codec_header); - env->DeleteLocalRef(codec_header); - env->DeleteLocalRef(identification_header); + default: + LOG(ERROR) << "Invalid header encountered for codec: " + << AudioCodecToMimeType(codec); + return false; } - - Java_MediaCodecBridge_configureAudio( - env, media_codec(), j_format.obj(), NULL, 0, play_audio); - StartInternal(); return true; } diff --git a/media/base/android/media_codec_bridge.h b/media/base/android/media_codec_bridge.h index b8a30a8..74e2d67 100644 --- a/media/base/android/media_codec_bridge.h +++ b/media/base/android/media_codec_bridge.h @@ -121,6 +121,10 @@ class AudioCodecBridge : public MediaCodecBridge { private: explicit AudioCodecBridge(const char* mime); + + // Configure the java MediaFormat object with the extra codec data passed in. + bool ConfigureMediaFormat(jobject j_format, const AudioCodec codec, + const uint8* extra_data, size_t extra_data_size); }; class VideoCodecBridge : public MediaCodecBridge { |