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 |