Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "media/base/android/media_codec_bridge.h" | 5 #include "media/base/android/media_codec_bridge.h" |
| 6 | 6 |
| 7 #include <jni.h> | 7 #include <jni.h> |
| 8 #include <string> | |
| 8 | 9 |
| 9 #include "base/android/build_info.h" | 10 #include "base/android/build_info.h" |
| 10 #include "base/android/jni_android.h" | 11 #include "base/android/jni_android.h" |
| 11 #include "base/android/jni_array.h" | 12 #include "base/android/jni_array.h" |
| 12 #include "base/android/jni_string.h" | 13 #include "base/android/jni_string.h" |
| 13 #include "base/basictypes.h" | 14 #include "base/basictypes.h" |
| 14 #include "base/lazy_instance.h" | 15 #include "base/lazy_instance.h" |
| 15 #include "base/logging.h" | 16 #include "base/logging.h" |
| 16 #include "base/safe_numerics.h" | 17 #include "base/safe_numerics.h" |
| 17 #include "base/strings/stringprintf.h" | 18 #include "base/strings/stringprintf.h" |
| 18 #include "jni/MediaCodecBridge_jni.h" | 19 #include "jni/MediaCodecBridge_jni.h" |
| 19 #include "media/base/bit_reader.h" | 20 #include "media/base/bit_reader.h" |
| 20 #include "media/base/decrypt_config.h" | 21 #include "media/base/decrypt_config.h" |
| 21 | 22 |
| 22 using base::android::AttachCurrentThread; | 23 using base::android::AttachCurrentThread; |
| 23 using base::android::ConvertUTF8ToJavaString; | 24 using base::android::ConvertUTF8ToJavaString; |
| 24 using base::android::ScopedJavaLocalRef; | 25 using base::android::ScopedJavaLocalRef; |
| 25 | 26 |
| 26 namespace media { | 27 namespace media { |
| 27 | 28 |
| 28 enum { kBufferFlagEndOfStream = 4 }; | 29 enum { kBufferFlagEndOfStream = 4 }; |
| 29 | 30 |
| 30 static const char* AudioCodecToMimeType(const AudioCodec codec) { | 31 static const std::string AudioCodecToMimeType(const AudioCodec codec) { |
| 31 switch (codec) { | 32 switch (codec) { |
| 32 case kCodecMP3: | 33 case kCodecMP3: |
| 33 return "audio/mpeg"; | 34 return "audio/mpeg"; |
| 34 case kCodecVorbis: | 35 case kCodecVorbis: |
| 35 return "audio/vorbis"; | 36 return "audio/vorbis"; |
| 36 case kCodecAAC: | 37 case kCodecAAC: |
| 37 return "audio/mp4a-latm"; | 38 return "audio/mp4a-latm"; |
| 38 default: | 39 default: |
| 39 return NULL; | 40 return ""; |
|
ddorwin
2013/08/28 02:28:50
std::string()
xhwang
2013/08/28 18:19:15
Done.
| |
| 40 } | 41 } |
| 41 } | 42 } |
| 42 | 43 |
| 43 static const char* VideoCodecToMimeType(const VideoCodec codec) { | 44 static const std::string VideoCodecToMimeType(const VideoCodec codec) { |
| 44 switch (codec) { | 45 switch (codec) { |
| 45 case kCodecH264: | 46 case kCodecH264: |
| 46 return "video/avc"; | 47 return "video/avc"; |
| 47 case kCodecVP8: | 48 case kCodecVP8: |
| 48 return "video/x-vnd.on2.vp8"; | 49 return "video/x-vnd.on2.vp8"; |
| 49 default: | 50 default: |
| 50 return NULL; | 51 return ""; |
| 51 } | 52 } |
| 52 } | 53 } |
| 53 | 54 |
| 54 static ScopedJavaLocalRef<jintArray> ToJavaIntArray( | 55 static ScopedJavaLocalRef<jintArray> ToJavaIntArray( |
| 55 JNIEnv* env, scoped_ptr<jint[]> native_array, int size) { | 56 JNIEnv* env, scoped_ptr<jint[]> native_array, int size) { |
| 56 ScopedJavaLocalRef<jintArray> j_array(env, env->NewIntArray(size)); | 57 ScopedJavaLocalRef<jintArray> j_array(env, env->NewIntArray(size)); |
| 57 env->SetIntArrayRegion(j_array.obj(), 0, size, native_array.get()); | 58 env->SetIntArrayRegion(j_array.obj(), 0, size, native_array.get()); |
| 58 return j_array; | 59 return j_array; |
| 59 } | 60 } |
| 60 | 61 |
| 61 // static | 62 // static |
| 62 const base::TimeDelta MediaCodecBridge::kTimeOutInfinity = | 63 const base::TimeDelta MediaCodecBridge::kTimeOutInfinity = |
| 63 base::TimeDelta::FromMicroseconds(-1); | 64 base::TimeDelta::FromMicroseconds(-1); |
| 64 | 65 |
| 65 // static | 66 // static |
| 66 const base::TimeDelta MediaCodecBridge::kTimeOutNoWait = | 67 const base::TimeDelta MediaCodecBridge::kTimeOutNoWait = |
| 67 base::TimeDelta::FromMicroseconds(0); | 68 base::TimeDelta::FromMicroseconds(0); |
| 68 | 69 |
| 69 // static | 70 // static |
| 70 bool MediaCodecBridge::IsAvailable() { | 71 bool MediaCodecBridge::IsAvailable() { |
| 71 // MediaCodec is only available on JB and greater. | 72 // MediaCodec is only available on JB and greater. |
| 72 return base::android::BuildInfo::GetInstance()->sdk_int() >= 16; | 73 return base::android::BuildInfo::GetInstance()->sdk_int() >= 16; |
| 73 } | 74 } |
| 74 | 75 |
| 75 MediaCodecBridge::MediaCodecBridge(const char* mime) { | 76 // static |
| 77 bool MediaCodecBridge::IsDecoderSupported(const std::string& mime, | |
| 78 bool secure) { | |
| 79 JNIEnv* env = AttachCurrentThread(); | |
| 80 ScopedJavaLocalRef<jstring> j_mime = ConvertUTF8ToJavaString(env, mime); | |
| 81 return !Java_MediaCodecBridge_create(env, j_mime.obj(), secure).is_null(); | |
| 82 } | |
| 83 | |
| 84 // TODO(xhwang): Support creating secure MediaCodecBridge. | |
| 85 MediaCodecBridge::MediaCodecBridge(const std::string& mime) { | |
| 76 JNIEnv* env = AttachCurrentThread(); | 86 JNIEnv* env = AttachCurrentThread(); |
| 77 CHECK(env); | 87 CHECK(env); |
| 78 DCHECK(mime); | |
| 79 | 88 |
| 80 ScopedJavaLocalRef<jstring> j_type = ConvertUTF8ToJavaString(env, mime); | 89 DCHECK(!mime.empty()); |
| 81 j_media_codec_.Reset(Java_MediaCodecBridge_create( | 90 ScopedJavaLocalRef<jstring> j_mime = ConvertUTF8ToJavaString(env, mime); |
| 82 env, j_type.obj())); | 91 j_media_codec_.Reset(Java_MediaCodecBridge_create(env, j_mime.obj(), false)); |
| 83 } | 92 } |
| 84 | 93 |
| 85 MediaCodecBridge::~MediaCodecBridge() { | 94 MediaCodecBridge::~MediaCodecBridge() { |
| 86 JNIEnv* env = AttachCurrentThread(); | 95 JNIEnv* env = AttachCurrentThread(); |
| 87 CHECK(env); | 96 CHECK(env); |
| 88 if (j_media_codec_.obj()) | 97 if (j_media_codec_.obj()) |
| 89 Java_MediaCodecBridge_release(env, j_media_codec_.obj()); | 98 Java_MediaCodecBridge_release(env, j_media_codec_.obj()); |
| 90 } | 99 } |
| 91 | 100 |
| 92 void MediaCodecBridge::StartInternal() { | 101 void MediaCodecBridge::StartInternal() { |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 220 int size_to_copy = (buffer_capacity < size) ? buffer_capacity : size; | 229 int size_to_copy = (buffer_capacity < size) ? buffer_capacity : size; |
| 221 // TODO(qinmin): Handling the case that not all the data can be copied. | 230 // TODO(qinmin): Handling the case that not all the data can be copied. |
| 222 DCHECK(size_to_copy == size) << | 231 DCHECK(size_to_copy == size) << |
| 223 "Failed to fill all the data into the input buffer. Size to fill: " | 232 "Failed to fill all the data into the input buffer. Size to fill: " |
| 224 << size << ". Size filled: " << size_to_copy; | 233 << size << ". Size filled: " << size_to_copy; |
| 225 if (size_to_copy > 0) | 234 if (size_to_copy > 0) |
| 226 memcpy(direct_buffer, data, size_to_copy); | 235 memcpy(direct_buffer, data, size_to_copy); |
| 227 return size_to_copy; | 236 return size_to_copy; |
| 228 } | 237 } |
| 229 | 238 |
| 230 AudioCodecBridge::AudioCodecBridge(const char* mime) | 239 AudioCodecBridge::AudioCodecBridge(const std::string& mime) |
| 231 : MediaCodecBridge(mime) { | 240 : MediaCodecBridge(mime) { |
| 232 } | 241 } |
| 233 | 242 |
| 234 bool AudioCodecBridge::Start( | 243 bool AudioCodecBridge::Start( |
| 235 const AudioCodec codec, int sample_rate, int channel_count, | 244 const AudioCodec codec, int sample_rate, int channel_count, |
| 236 const uint8* extra_data, size_t extra_data_size, bool play_audio, | 245 const uint8* extra_data, size_t extra_data_size, bool play_audio, |
| 237 jobject media_crypto) { | 246 jobject media_crypto) { |
| 238 JNIEnv* env = AttachCurrentThread(); | 247 JNIEnv* env = AttachCurrentThread(); |
| 239 DCHECK(AudioCodecToMimeType(codec)); | |
| 240 | 248 |
| 241 if (!media_codec()) | 249 if (!media_codec()) |
| 242 return false; | 250 return false; |
| 243 | 251 |
| 252 std::string codec_string = AudioCodecToMimeType(codec); | |
| 253 DCHECK(!codec_string.empty()); | |
|
ddorwin
2013/08/28 02:28:50
Who calls Start()? Are we sure invalid types won't
xhwang
2013/08/28 18:19:15
Good point. It comes from renderer. So we could hi
| |
| 244 ScopedJavaLocalRef<jstring> j_mime = | 254 ScopedJavaLocalRef<jstring> j_mime = |
| 245 ConvertUTF8ToJavaString(env, AudioCodecToMimeType(codec)); | 255 ConvertUTF8ToJavaString(env, codec_string); |
| 246 ScopedJavaLocalRef<jobject> j_format( | 256 ScopedJavaLocalRef<jobject> j_format( |
| 247 Java_MediaCodecBridge_createAudioFormat( | 257 Java_MediaCodecBridge_createAudioFormat( |
| 248 env, j_mime.obj(), sample_rate, channel_count)); | 258 env, j_mime.obj(), sample_rate, channel_count)); |
| 249 DCHECK(!j_format.is_null()); | 259 DCHECK(!j_format.is_null()); |
| 250 | 260 |
| 251 if (!ConfigureMediaFormat(j_format.obj(), codec, extra_data, extra_data_size)) | 261 if (!ConfigureMediaFormat(j_format.obj(), codec, extra_data, extra_data_size)) |
| 252 return false; | 262 return false; |
| 253 | 263 |
| 254 if (!Java_MediaCodecBridge_configureAudio( | 264 if (!Java_MediaCodecBridge_configureAudio( |
| 255 env, media_codec(), j_format.obj(), media_crypto, 0, play_audio)) { | 265 env, media_codec(), j_format.obj(), media_crypto, 0, play_audio)) { |
| 256 return false; | 266 return false; |
| 257 } | 267 } |
| 268 | |
| 258 StartInternal(); | 269 StartInternal(); |
| 259 return true; | 270 return true; |
| 260 } | 271 } |
| 261 | 272 |
| 262 bool AudioCodecBridge::ConfigureMediaFormat( | 273 bool AudioCodecBridge::ConfigureMediaFormat( |
| 263 jobject j_format, const AudioCodec codec, const uint8* extra_data, | 274 jobject j_format, const AudioCodec codec, const uint8* extra_data, |
| 264 size_t extra_data_size) { | 275 size_t extra_data_size) { |
| 265 if (extra_data_size == 0) | 276 if (extra_data_size == 0) |
| 266 return true; | 277 return true; |
| 267 | 278 |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 375 base::android::ToJavaByteArray(env, buffer, numBytes); | 386 base::android::ToJavaByteArray(env, buffer, numBytes); |
| 376 Java_MediaCodecBridge_playOutputBuffer( | 387 Java_MediaCodecBridge_playOutputBuffer( |
| 377 env, media_codec(), byte_array.obj()); | 388 env, media_codec(), byte_array.obj()); |
| 378 } | 389 } |
| 379 | 390 |
| 380 void AudioCodecBridge::SetVolume(double volume) { | 391 void AudioCodecBridge::SetVolume(double volume) { |
| 381 JNIEnv* env = AttachCurrentThread(); | 392 JNIEnv* env = AttachCurrentThread(); |
| 382 Java_MediaCodecBridge_setVolume(env, media_codec(), volume); | 393 Java_MediaCodecBridge_setVolume(env, media_codec(), volume); |
| 383 } | 394 } |
| 384 | 395 |
| 385 VideoCodecBridge::VideoCodecBridge(const char* mime) | 396 VideoCodecBridge::VideoCodecBridge(const std::string& mime) |
| 386 : MediaCodecBridge(mime) { | 397 : MediaCodecBridge(mime) { |
| 387 } | 398 } |
| 388 | 399 |
| 389 bool VideoCodecBridge::Start( | 400 bool VideoCodecBridge::Start( |
| 390 const VideoCodec codec, const gfx::Size& size, jobject surface, | 401 const VideoCodec codec, const gfx::Size& size, jobject surface, |
| 391 jobject media_crypto) { | 402 jobject media_crypto) { |
| 392 JNIEnv* env = AttachCurrentThread(); | 403 JNIEnv* env = AttachCurrentThread(); |
| 393 DCHECK(VideoCodecToMimeType(codec)); | |
| 394 | 404 |
| 395 if (!media_codec()) | 405 if (!media_codec()) |
| 396 return false; | 406 return false; |
| 397 | 407 |
| 408 std::string codec_string = VideoCodecToMimeType(codec); | |
| 409 DCHECK(!codec_string.empty()); | |
| 398 ScopedJavaLocalRef<jstring> j_mime = | 410 ScopedJavaLocalRef<jstring> j_mime = |
| 399 ConvertUTF8ToJavaString(env, VideoCodecToMimeType(codec)); | 411 ConvertUTF8ToJavaString(env, codec_string); |
| 400 ScopedJavaLocalRef<jobject> j_format( | 412 ScopedJavaLocalRef<jobject> j_format( |
| 401 Java_MediaCodecBridge_createVideoFormat( | 413 Java_MediaCodecBridge_createVideoFormat( |
| 402 env, j_mime.obj(), size.width(), size.height())); | 414 env, j_mime.obj(), size.width(), size.height())); |
| 403 DCHECK(!j_format.is_null()); | 415 DCHECK(!j_format.is_null()); |
| 404 if (!Java_MediaCodecBridge_configureVideo( | 416 if (!Java_MediaCodecBridge_configureVideo( |
| 405 env, media_codec(), j_format.obj(), surface, media_crypto, 0)) { | 417 env, media_codec(), j_format.obj(), surface, media_crypto, 0)) { |
| 406 return false; | 418 return false; |
| 407 } | 419 } |
| 408 StartInternal(); | 420 StartInternal(); |
| 409 return true; | 421 return true; |
| 410 } | 422 } |
| 411 | 423 |
| 412 AudioCodecBridge* AudioCodecBridge::Create(const AudioCodec codec) { | 424 AudioCodecBridge* AudioCodecBridge::Create(const AudioCodec codec) { |
| 413 const char* mime = AudioCodecToMimeType(codec); | 425 const std::string mime = AudioCodecToMimeType(codec); |
| 414 return mime ? new AudioCodecBridge(mime) : NULL; | 426 return mime.empty() ? NULL: new AudioCodecBridge(mime); |
|
ddorwin
2013/08/28 02:28:50
space before ':'
below too
xhwang
2013/08/28 18:19:15
Done.
| |
| 415 } | 427 } |
| 416 | 428 |
| 417 VideoCodecBridge* VideoCodecBridge::Create(const VideoCodec codec) { | 429 VideoCodecBridge* VideoCodecBridge::Create(const VideoCodec codec) { |
| 418 const char* mime = VideoCodecToMimeType(codec); | 430 const std::string mime = VideoCodecToMimeType(codec); |
| 419 return mime ? new VideoCodecBridge(mime) : NULL; | 431 return mime.empty() ? NULL: new VideoCodecBridge(mime); |
| 420 } | 432 } |
| 421 | 433 |
| 422 bool MediaCodecBridge::RegisterMediaCodecBridge(JNIEnv* env) { | 434 bool MediaCodecBridge::RegisterMediaCodecBridge(JNIEnv* env) { |
| 423 return RegisterNativesImpl(env); | 435 return RegisterNativesImpl(env); |
| 424 } | 436 } |
| 425 | 437 |
| 426 } // namespace media | 438 } // namespace media |
| OLD | NEW |