diff options
author | qinmin@chromium.org <qinmin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-05-07 06:24:48 +0000 |
---|---|---|
committer | qinmin@chromium.org <qinmin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-05-07 06:24:48 +0000 |
commit | 9ab892fba317eafae180f2418d5f3bebd639f2f9 (patch) | |
tree | 639c93c045c4a6b85301a69eae903f3970c4bb28 /media | |
parent | 8020c930dc95dbe04920a12daf6eb21e5d7a4f20 (diff) | |
download | chromium_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.h | 4 | ||||
-rw-r--r-- | media/base/android/media_codec_bridge.cc | 60 | ||||
-rw-r--r-- | media/base/android/media_codec_bridge.h | 7 | ||||
-rw-r--r-- | media/base/android/media_codec_bridge_unittest.cc | 31 |
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 |