summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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
-rw-r--r--media/mp4/aac.cc3
-rw-r--r--media/mp4/aac.h12
-rw-r--r--media/mp4/mp4_stream_parser.cc12
6 files changed, 136 insertions, 48 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 {
diff --git a/media/mp4/aac.cc b/media/mp4/aac.cc
index f92dd2f..6604c50 100644
--- a/media/mp4/aac.cc
+++ b/media/mp4/aac.cc
@@ -53,6 +53,9 @@ AAC::~AAC() {
}
bool AAC::Parse(const std::vector<uint8>& data) {
+#if defined(OS_ANDROID)
+ codec_specific_data_ = data;
+#endif
if (data.empty())
return false;
diff --git a/media/mp4/aac.h b/media/mp4/aac.h
index 2d4b6f4..1a546b7 100644
--- a/media/mp4/aac.h
+++ b/media/mp4/aac.h
@@ -52,6 +52,13 @@ class MEDIA_EXPORT AAC {
// unchanged.
bool ConvertEsdsToADTS(std::vector<uint8>* buffer) const;
+#if defined(OS_ANDROID)
+ // Returns the codec specific data needed by android MediaCodec.
+ std::vector<uint8> codec_specific_data() const {
+ return codec_specific_data_;
+ }
+#endif
+
// Size in bytes of the ADTS header added by ConvertEsdsToADTS().
static const size_t kADTSHeaderSize = 7;
@@ -66,6 +73,11 @@ class MEDIA_EXPORT AAC {
uint8 frequency_index_;
uint8 channel_config_;
+#if defined(OS_ANDROID)
+ // The codec specific data needed by the android MediaCodec.
+ std::vector<uint8> codec_specific_data_;
+#endif
+
// The following variables store audio configuration information that
// can be used by Chromium. They are based on the AAC specific
// configuration but can be overridden by extensions in elementary
diff --git a/media/mp4/mp4_stream_parser.cc b/media/mp4/mp4_stream_parser.cc
index 77fa2b8..9f808ea 100644
--- a/media/mp4/mp4_stream_parser.cc
+++ b/media/mp4/mp4_stream_parser.cc
@@ -222,12 +222,16 @@ bool MP4StreamParser::ParseMoov(BoxReader* reader) {
AudioCodec codec = kUnknownAudioCodec;
ChannelLayout channel_layout = CHANNEL_LAYOUT_NONE;
int sample_per_second = 0;
+ std::vector<uint8> extra_data;
// Check if it is MPEG4 AAC defined in ISO 14496 Part 3 or
// supported MPEG2 AAC varients.
if (ESDescriptor::IsAAC(audio_type)) {
codec = kCodecAAC;
channel_layout = aac.GetChannelLayout(has_sbr_);
sample_per_second = aac.GetOutputSamplesPerSecond(has_sbr_);
+#if defined(OS_ANDROID)
+ extra_data = aac.codec_specific_data();
+#endif
} else if (audio_type == kEAC3) {
codec = kCodecEAC3;
channel_layout = GuessChannelLayout(entry.channelcount);
@@ -252,10 +256,10 @@ bool MP4StreamParser::ParseMoov(BoxReader* reader) {
is_audio_track_encrypted_ = entry.sinf.info.track_encryption.is_encrypted;
DVLOG(1) << "is_audio_track_encrypted_: " << is_audio_track_encrypted_;
- audio_config.Initialize(codec, sample_format,
- channel_layout,
- sample_per_second,
- NULL, 0, is_audio_track_encrypted_, false);
+ audio_config.Initialize(
+ codec, sample_format, channel_layout, sample_per_second,
+ extra_data.size() ? &extra_data[0] : NULL, extra_data.size(),
+ is_audio_track_encrypted_, false);
has_audio_ = true;
audio_track_id_ = track->header.track_id;
}