summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
authorqinmin@chromium.org <qinmin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-05-07 06:24:48 +0000
committerqinmin@chromium.org <qinmin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-05-07 06:24:48 +0000
commit9ab892fba317eafae180f2418d5f3bebd639f2f9 (patch)
tree639c93c045c4a6b85301a69eae903f3970c4bb28 /media
parent8020c930dc95dbe04920a12daf6eb21e5d7a4f20 (diff)
downloadchromium_src-9ab892fba317eafae180f2418d5f3bebd639f2f9.zip
chromium_src-9ab892fba317eafae180f2418d5f3bebd639f2f9.tar.gz
chromium_src-9ab892fba317eafae180f2418d5f3bebd639f2f9.tar.bz2
Allow extra codec data to be passed to AudioCodecBridge
Android MediaCodec needs vorbis codec data to work properly. Passing the extra codec data from ChunkDemuxer should fix the problem. BUG=233420 Review URL: https://chromiumcodereview.appspot.com/14957003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@198650 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media')
-rw-r--r--media/base/android/demuxer_stream_player_params.h4
-rw-r--r--media/base/android/media_codec_bridge.cc60
-rw-r--r--media/base/android/media_codec_bridge.h7
-rw-r--r--media/base/android/media_codec_bridge_unittest.cc31
4 files changed, 94 insertions, 8 deletions
diff --git a/media/base/android/demuxer_stream_player_params.h b/media/base/android/demuxer_stream_player_params.h
index face665..585af2b 100644
--- a/media/base/android/demuxer_stream_player_params.h
+++ b/media/base/android/demuxer_stream_player_params.h
@@ -25,10 +25,12 @@ struct MEDIA_EXPORT MediaPlayerHostMsg_DemuxerReady_Params {
int audio_channels;
int audio_sampling_rate;
bool is_audio_encrypted;
+ std::vector<uint8> audio_extra_data;
VideoCodec video_codec;
gfx::Size video_size;
bool is_video_encrypted;
+ std::vector<uint8> video_extra_data;
int duration_ms;
std::string key_system;
@@ -42,7 +44,7 @@ struct MEDIA_EXPORT MediaPlayerHostMsg_ReadFromDemuxerAck_Params {
DemuxerStream::Status status;
bool end_of_stream;
// TODO(ycheo): Use the shared memory to transfer the block data.
- std::vector<unsigned char> data;
+ std::vector<uint8> data;
base::TimeDelta timestamp;
std::vector<char> key_id;
std::vector<char> iv;
diff --git a/media/base/android/media_codec_bridge.cc b/media/base/android/media_codec_bridge.cc
index e466654..bd4c274 100644
--- a/media/base/android/media_codec_bridge.cc
+++ b/media/base/android/media_codec_bridge.cc
@@ -281,8 +281,9 @@ AudioCodecBridge::AudioCodecBridge(const AudioCodec codec)
: MediaCodecBridge(AudioCodecToMimeType(codec)) {
}
-void AudioCodecBridge::Start(
- const AudioCodec codec, int sample_rate, int channel_count) {
+bool AudioCodecBridge::Start(
+ const AudioCodec codec, int sample_rate, int channel_count,
+ const uint8* extra_data, size_t extra_data_size) {
JNIEnv* env = AttachCurrentThread();
DCHECK(AudioCodecToMimeType(codec));
@@ -292,16 +293,68 @@ void AudioCodecBridge::Start(
JNI_MediaFormat::Java_MediaFormat_createAudioFormat(
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;
+ }
+
+ 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";
+ 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";
+ return false;
+ }
+ }
+ current_pos++;
+ // The first header is identification header.
+ jobject identification_header = env->NewDirectByteBuffer(
+ const_cast<uint8*>(current_pos), header_length[0]);
+ ScopedJavaLocalRef<jstring> j_csd_0 = ConvertUTF8ToJavaString(env, "csd-0");
+ JNI_MediaFormat::Java_MediaFormat_setByteBuffer(
+ env, j_format.obj(), j_csd_0.obj(), 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);
+ ScopedJavaLocalRef<jstring> j_csd_1 = ConvertUTF8ToJavaString(env, "csd-1");
+ JNI_MediaFormat::Java_MediaFormat_setByteBuffer(
+ env, j_format.obj(), j_csd_1.obj(), codec_header);
+ env->DeleteLocalRef(codec_header);
+ env->DeleteLocalRef(identification_header);
+ }
+
JNI_MediaCodec::Java_MediaCodec_configure(
env, media_codec(), j_format.obj(), NULL, NULL, 0);
StartInternal();
+ return true;
}
VideoCodecBridge::VideoCodecBridge(const VideoCodec codec)
: MediaCodecBridge(VideoCodecToMimeType(codec)) {
}
-void VideoCodecBridge::Start(
+bool VideoCodecBridge::Start(
const VideoCodec codec, const gfx::Size& size, jobject surface) {
JNIEnv* env = AttachCurrentThread();
DCHECK(VideoCodecToMimeType(codec));
@@ -315,6 +368,7 @@ void VideoCodecBridge::Start(
JNI_MediaCodec::Java_MediaCodec_configure(
env, media_codec(), j_format.obj(), surface, NULL, 0);
StartInternal();
+ return true;
}
} // namespace media
diff --git a/media/base/android/media_codec_bridge.h b/media/base/android/media_codec_bridge.h
index c291f82..b1f779e 100644
--- a/media/base/android/media_codec_bridge.h
+++ b/media/base/android/media_codec_bridge.h
@@ -117,8 +117,8 @@ class AudioCodecBridge : public MediaCodecBridge {
explicit AudioCodecBridge(const AudioCodec codec);
// Start the audio codec bridge.
- void Start(
- const AudioCodec codec, int sample_rate, int channel_count);
+ bool Start(const AudioCodec codec, int sample_rate, int channel_count,
+ const uint8* extra_data, size_t extra_data_size);
};
class VideoCodecBridge : public MediaCodecBridge {
@@ -126,7 +126,8 @@ class VideoCodecBridge : public MediaCodecBridge {
explicit VideoCodecBridge(const VideoCodec codec);
// Start the video codec bridge.
- void Start(
+ // TODO(qinmin): Pass codec specific data if available.
+ bool Start(
const VideoCodec codec, const gfx::Size& size, jobject surface);
};
diff --git a/media/base/android/media_codec_bridge_unittest.cc b/media/base/android/media_codec_bridge_unittest.cc
index d77041c..acf421e 100644
--- a/media/base/android/media_codec_bridge_unittest.cc
+++ b/media/base/android/media_codec_bridge_unittest.cc
@@ -107,7 +107,7 @@ TEST(MediaCodecBridgeTest, DoNormal) {
scoped_ptr<media::AudioCodecBridge> media_codec;
media_codec.reset(new AudioCodecBridge(kCodecMP3));
- media_codec->Start(kCodecMP3, 44100, 2);
+ media_codec->Start(kCodecMP3, 44100, 2, NULL, 0);
ASSERT_GT(media_codec->GetOutputBuffers(), 0);
@@ -159,4 +159,33 @@ TEST(MediaCodecBridgeTest, DoNormal) {
ASSERT_EQ(input_pts, kPresentationTimeBase + 2);
}
+TEST(MediaCodecBridgeTest, InvalidVorbisHeader) {
+ if (!MediaCodecBridge::IsAvailable())
+ return;
+
+ scoped_ptr<media::AudioCodecBridge> media_codec;
+ media_codec.reset(new AudioCodecBridge(kCodecVorbis));
+
+ // The first byte of the header is not 0x02.
+ uint8 invalid_first_byte[] = { 0x00, 0xff, 0xff, 0xff, 0xff };
+ EXPECT_FALSE(media_codec->Start(
+ kCodecVorbis, 44100, 2, invalid_first_byte, sizeof(invalid_first_byte)));
+
+ // Size of the header does not match with the data we passed in.
+ uint8 invalid_size[] = { 0x02, 0x01, 0xff, 0x01, 0xff };
+ EXPECT_FALSE(media_codec->Start(
+ kCodecVorbis, 44100, 2, invalid_size, sizeof(invalid_size)));
+
+ // Size of the header is too large.
+ size_t large_size = 8 * 1024 * 1024 + 2;
+ uint8* very_large_header = new uint8[large_size];
+ very_large_header[0] = 0x02;
+ for (size_t i = 1; i < large_size - 1; ++i)
+ very_large_header[i] = 0xff;
+ very_large_header[large_size - 1] = 0xfe;
+ EXPECT_FALSE(media_codec->Start(
+ kCodecVorbis, 44100, 2, very_large_header, 0x80000000));
+ delete[] very_large_header;
+}
+
} // namespace media