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 std::string(); |
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 std::string(); |
51 } | 52 } |
52 } | 53 } |
53 | 54 |
55 static const std::string CodecTypeToMimeType(const std::string& codec) { | |
ddorwin
2013/08/30 16:59:15
What do you think of using the same type for this
| |
56 // TODO(xhwang): Shall we handle more detailed strings like "mp4a.40.2"? | |
57 if (codec == "avc1") | |
58 return "video/avc"; | |
59 if (codec == "mp4a") | |
60 return "audio/mp4a-latm"; | |
61 if (codec == "vp8" || codec == "vp8.0") | |
62 return "video/x-vnd.on2.vp8"; | |
63 if (codec == "vorbis") | |
64 return "audio/vorbis"; | |
65 return std::string(); | |
66 } | |
67 | |
54 static ScopedJavaLocalRef<jintArray> ToJavaIntArray( | 68 static ScopedJavaLocalRef<jintArray> ToJavaIntArray( |
55 JNIEnv* env, scoped_ptr<jint[]> native_array, int size) { | 69 JNIEnv* env, scoped_ptr<jint[]> native_array, int size) { |
56 ScopedJavaLocalRef<jintArray> j_array(env, env->NewIntArray(size)); | 70 ScopedJavaLocalRef<jintArray> j_array(env, env->NewIntArray(size)); |
57 env->SetIntArrayRegion(j_array.obj(), 0, size, native_array.get()); | 71 env->SetIntArrayRegion(j_array.obj(), 0, size, native_array.get()); |
58 return j_array; | 72 return j_array; |
59 } | 73 } |
60 | 74 |
61 // static | 75 // static |
62 const base::TimeDelta MediaCodecBridge::kTimeOutInfinity = | 76 const base::TimeDelta MediaCodecBridge::kTimeOutInfinity = |
63 base::TimeDelta::FromMicroseconds(-1); | 77 base::TimeDelta::FromMicroseconds(-1); |
64 | 78 |
65 // static | 79 // static |
66 const base::TimeDelta MediaCodecBridge::kTimeOutNoWait = | 80 const base::TimeDelta MediaCodecBridge::kTimeOutNoWait = |
67 base::TimeDelta::FromMicroseconds(0); | 81 base::TimeDelta::FromMicroseconds(0); |
68 | 82 |
69 // static | 83 // static |
70 bool MediaCodecBridge::IsAvailable() { | 84 bool MediaCodecBridge::IsAvailable() { |
71 // MediaCodec is only available on JB and greater. | 85 // MediaCodec is only available on JB and greater. |
72 return base::android::BuildInfo::GetInstance()->sdk_int() >= 16; | 86 return base::android::BuildInfo::GetInstance()->sdk_int() >= 16; |
73 } | 87 } |
74 | 88 |
75 MediaCodecBridge::MediaCodecBridge(const char* mime) { | 89 // static |
90 bool MediaCodecBridge::CanDecode(const std::string& codec, bool is_secure) { | |
91 JNIEnv* env = AttachCurrentThread(); | |
92 std::string mime = CodecTypeToMimeType(codec); | |
93 if (mime.empty()) | |
94 return false; | |
95 ScopedJavaLocalRef<jstring> j_mime = ConvertUTF8ToJavaString(env, mime); | |
96 return !Java_MediaCodecBridge_create(env, j_mime.obj(), is_secure).is_null(); | |
97 } | |
98 | |
99 // TODO(xhwang): Support creating secure MediaCodecBridge. | |
100 MediaCodecBridge::MediaCodecBridge(const std::string& mime) { | |
76 JNIEnv* env = AttachCurrentThread(); | 101 JNIEnv* env = AttachCurrentThread(); |
77 CHECK(env); | 102 CHECK(env); |
78 DCHECK(mime); | |
79 | 103 |
80 ScopedJavaLocalRef<jstring> j_type = ConvertUTF8ToJavaString(env, mime); | 104 DCHECK(!mime.empty()); |
81 j_media_codec_.Reset(Java_MediaCodecBridge_create( | 105 ScopedJavaLocalRef<jstring> j_mime = ConvertUTF8ToJavaString(env, mime); |
82 env, j_type.obj())); | 106 j_media_codec_.Reset(Java_MediaCodecBridge_create(env, j_mime.obj(), false)); |
83 } | 107 } |
84 | 108 |
85 MediaCodecBridge::~MediaCodecBridge() { | 109 MediaCodecBridge::~MediaCodecBridge() { |
86 JNIEnv* env = AttachCurrentThread(); | 110 JNIEnv* env = AttachCurrentThread(); |
87 CHECK(env); | 111 CHECK(env); |
88 if (j_media_codec_.obj()) | 112 if (j_media_codec_.obj()) |
89 Java_MediaCodecBridge_release(env, j_media_codec_.obj()); | 113 Java_MediaCodecBridge_release(env, j_media_codec_.obj()); |
90 } | 114 } |
91 | 115 |
92 void MediaCodecBridge::StartInternal() { | 116 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; | 244 int size_to_copy = (buffer_capacity < size) ? buffer_capacity : size; |
221 // TODO(qinmin): Handling the case that not all the data can be copied. | 245 // TODO(qinmin): Handling the case that not all the data can be copied. |
222 DCHECK(size_to_copy == size) << | 246 DCHECK(size_to_copy == size) << |
223 "Failed to fill all the data into the input buffer. Size to fill: " | 247 "Failed to fill all the data into the input buffer. Size to fill: " |
224 << size << ". Size filled: " << size_to_copy; | 248 << size << ". Size filled: " << size_to_copy; |
225 if (size_to_copy > 0) | 249 if (size_to_copy > 0) |
226 memcpy(direct_buffer, data, size_to_copy); | 250 memcpy(direct_buffer, data, size_to_copy); |
227 return size_to_copy; | 251 return size_to_copy; |
228 } | 252 } |
229 | 253 |
230 AudioCodecBridge::AudioCodecBridge(const char* mime) | 254 AudioCodecBridge::AudioCodecBridge(const std::string& mime) |
231 : MediaCodecBridge(mime) { | 255 : MediaCodecBridge(mime) { |
232 } | 256 } |
233 | 257 |
234 bool AudioCodecBridge::Start( | 258 bool AudioCodecBridge::Start( |
235 const AudioCodec codec, int sample_rate, int channel_count, | 259 const AudioCodec codec, int sample_rate, int channel_count, |
236 const uint8* extra_data, size_t extra_data_size, bool play_audio, | 260 const uint8* extra_data, size_t extra_data_size, bool play_audio, |
237 jobject media_crypto) { | 261 jobject media_crypto) { |
238 JNIEnv* env = AttachCurrentThread(); | 262 JNIEnv* env = AttachCurrentThread(); |
239 DCHECK(AudioCodecToMimeType(codec)); | |
240 | 263 |
241 if (!media_codec()) | 264 if (!media_codec()) |
242 return false; | 265 return false; |
243 | 266 |
267 std::string codec_string = AudioCodecToMimeType(codec); | |
268 if (codec_string.empty()) | |
269 return false; | |
270 | |
244 ScopedJavaLocalRef<jstring> j_mime = | 271 ScopedJavaLocalRef<jstring> j_mime = |
245 ConvertUTF8ToJavaString(env, AudioCodecToMimeType(codec)); | 272 ConvertUTF8ToJavaString(env, codec_string); |
246 ScopedJavaLocalRef<jobject> j_format( | 273 ScopedJavaLocalRef<jobject> j_format( |
247 Java_MediaCodecBridge_createAudioFormat( | 274 Java_MediaCodecBridge_createAudioFormat( |
248 env, j_mime.obj(), sample_rate, channel_count)); | 275 env, j_mime.obj(), sample_rate, channel_count)); |
249 DCHECK(!j_format.is_null()); | 276 DCHECK(!j_format.is_null()); |
250 | 277 |
251 if (!ConfigureMediaFormat(j_format.obj(), codec, extra_data, extra_data_size)) | 278 if (!ConfigureMediaFormat(j_format.obj(), codec, extra_data, extra_data_size)) |
252 return false; | 279 return false; |
253 | 280 |
254 if (!Java_MediaCodecBridge_configureAudio( | 281 if (!Java_MediaCodecBridge_configureAudio( |
255 env, media_codec(), j_format.obj(), media_crypto, 0, play_audio)) { | 282 env, media_codec(), j_format.obj(), media_crypto, 0, play_audio)) { |
256 return false; | 283 return false; |
257 } | 284 } |
285 | |
258 StartInternal(); | 286 StartInternal(); |
259 return true; | 287 return true; |
260 } | 288 } |
261 | 289 |
262 bool AudioCodecBridge::ConfigureMediaFormat( | 290 bool AudioCodecBridge::ConfigureMediaFormat( |
263 jobject j_format, const AudioCodec codec, const uint8* extra_data, | 291 jobject j_format, const AudioCodec codec, const uint8* extra_data, |
264 size_t extra_data_size) { | 292 size_t extra_data_size) { |
265 if (extra_data_size == 0) | 293 if (extra_data_size == 0) |
266 return true; | 294 return true; |
267 | 295 |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
375 base::android::ToJavaByteArray(env, buffer, numBytes); | 403 base::android::ToJavaByteArray(env, buffer, numBytes); |
376 Java_MediaCodecBridge_playOutputBuffer( | 404 Java_MediaCodecBridge_playOutputBuffer( |
377 env, media_codec(), byte_array.obj()); | 405 env, media_codec(), byte_array.obj()); |
378 } | 406 } |
379 | 407 |
380 void AudioCodecBridge::SetVolume(double volume) { | 408 void AudioCodecBridge::SetVolume(double volume) { |
381 JNIEnv* env = AttachCurrentThread(); | 409 JNIEnv* env = AttachCurrentThread(); |
382 Java_MediaCodecBridge_setVolume(env, media_codec(), volume); | 410 Java_MediaCodecBridge_setVolume(env, media_codec(), volume); |
383 } | 411 } |
384 | 412 |
385 VideoCodecBridge::VideoCodecBridge(const char* mime) | 413 VideoCodecBridge::VideoCodecBridge(const std::string& mime) |
386 : MediaCodecBridge(mime) { | 414 : MediaCodecBridge(mime) { |
387 } | 415 } |
388 | 416 |
389 bool VideoCodecBridge::Start( | 417 bool VideoCodecBridge::Start( |
390 const VideoCodec codec, const gfx::Size& size, jobject surface, | 418 const VideoCodec codec, const gfx::Size& size, jobject surface, |
391 jobject media_crypto) { | 419 jobject media_crypto) { |
392 JNIEnv* env = AttachCurrentThread(); | 420 JNIEnv* env = AttachCurrentThread(); |
393 DCHECK(VideoCodecToMimeType(codec)); | |
394 | 421 |
395 if (!media_codec()) | 422 if (!media_codec()) |
396 return false; | 423 return false; |
397 | 424 |
425 std::string codec_string = VideoCodecToMimeType(codec); | |
426 if (codec_string.empty()) | |
427 return false; | |
428 | |
398 ScopedJavaLocalRef<jstring> j_mime = | 429 ScopedJavaLocalRef<jstring> j_mime = |
399 ConvertUTF8ToJavaString(env, VideoCodecToMimeType(codec)); | 430 ConvertUTF8ToJavaString(env, codec_string); |
400 ScopedJavaLocalRef<jobject> j_format( | 431 ScopedJavaLocalRef<jobject> j_format( |
401 Java_MediaCodecBridge_createVideoFormat( | 432 Java_MediaCodecBridge_createVideoFormat( |
402 env, j_mime.obj(), size.width(), size.height())); | 433 env, j_mime.obj(), size.width(), size.height())); |
403 DCHECK(!j_format.is_null()); | 434 DCHECK(!j_format.is_null()); |
404 if (!Java_MediaCodecBridge_configureVideo( | 435 if (!Java_MediaCodecBridge_configureVideo( |
405 env, media_codec(), j_format.obj(), surface, media_crypto, 0)) { | 436 env, media_codec(), j_format.obj(), surface, media_crypto, 0)) { |
406 return false; | 437 return false; |
407 } | 438 } |
408 StartInternal(); | 439 StartInternal(); |
409 return true; | 440 return true; |
410 } | 441 } |
411 | 442 |
412 AudioCodecBridge* AudioCodecBridge::Create(const AudioCodec codec) { | 443 AudioCodecBridge* AudioCodecBridge::Create(const AudioCodec codec) { |
413 const char* mime = AudioCodecToMimeType(codec); | 444 const std::string mime = AudioCodecToMimeType(codec); |
414 return mime ? new AudioCodecBridge(mime) : NULL; | 445 return mime.empty() ? NULL : new AudioCodecBridge(mime); |
415 } | 446 } |
416 | 447 |
417 VideoCodecBridge* VideoCodecBridge::Create(const VideoCodec codec) { | 448 VideoCodecBridge* VideoCodecBridge::Create(const VideoCodec codec) { |
418 const char* mime = VideoCodecToMimeType(codec); | 449 const std::string mime = VideoCodecToMimeType(codec); |
419 return mime ? new VideoCodecBridge(mime) : NULL; | 450 return mime.empty() ? NULL : new VideoCodecBridge(mime); |
420 } | 451 } |
421 | 452 |
422 bool MediaCodecBridge::RegisterMediaCodecBridge(JNIEnv* env) { | 453 bool MediaCodecBridge::RegisterMediaCodecBridge(JNIEnv* env) { |
423 return RegisterNativesImpl(env); | 454 return RegisterNativesImpl(env); |
424 } | 455 } |
425 | 456 |
426 } // namespace media | 457 } // namespace media |
OLD | NEW |