summaryrefslogtreecommitdiffstats
path: root/media/base
diff options
context:
space:
mode:
authorqinmin@chromium.org <qinmin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-05-31 03:48:40 +0000
committerqinmin@chromium.org <qinmin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-05-31 03:48:40 +0000
commitfd7dead1ecd0218e8e7170dbe385058eec95cba1 (patch)
tree75556b5302e1eeb8a53c22fa6c93a871392ad436 /media/base
parent063121b87ad753de81230b5c320009529eecb15e (diff)
downloadchromium_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.java5
-rw-r--r--media/base/android/media_codec_bridge.cc148
-rw-r--r--media/base/android/media_codec_bridge.h4
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 {