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 #include <string> |
| 9 | 9 |
| 10 #include "base/android/build_info.h" | 10 #include "base/android/build_info.h" |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 34 kBufferFlagEndOfStream = 4, // BUFFER_FLAG_END_OF_STREAM | 34 kBufferFlagEndOfStream = 4, // BUFFER_FLAG_END_OF_STREAM |
| 35 kConfigureFlagEncode = 1, // CONFIGURE_FLAG_ENCODE | 35 kConfigureFlagEncode = 1, // CONFIGURE_FLAG_ENCODE |
| 36 }; | 36 }; |
| 37 | 37 |
| 38 static const std::string AudioCodecToAndroidMimeType(const AudioCodec& codec) { | 38 static const std::string AudioCodecToAndroidMimeType(const AudioCodec& codec) { |
| 39 switch (codec) { | 39 switch (codec) { |
| 40 case kCodecMP3: | 40 case kCodecMP3: |
| 41 return "audio/mpeg"; | 41 return "audio/mpeg"; |
| 42 case kCodecVorbis: | 42 case kCodecVorbis: |
| 43 return "audio/vorbis"; | 43 return "audio/vorbis"; |
| 44 case kCodecOpus: | |
| 45 return "audio/opus"; | |
| 44 case kCodecAAC: | 46 case kCodecAAC: |
| 45 return "audio/mp4a-latm"; | 47 return "audio/mp4a-latm"; |
| 46 default: | 48 default: |
| 47 return std::string(); | 49 return std::string(); |
| 48 } | 50 } |
| 49 } | 51 } |
| 50 | 52 |
| 51 static const std::string VideoCodecToAndroidMimeType(const VideoCodec& codec) { | 53 static const std::string VideoCodecToAndroidMimeType(const VideoCodec& codec) { |
| 52 switch (codec) { | 54 switch (codec) { |
| 53 case kCodecH264: | 55 case kCodecH264: |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 66 if (codec == "avc1") | 68 if (codec == "avc1") |
| 67 return "video/avc"; | 69 return "video/avc"; |
| 68 if (codec == "mp4a") | 70 if (codec == "mp4a") |
| 69 return "audio/mp4a-latm"; | 71 return "audio/mp4a-latm"; |
| 70 if (codec == "vp8" || codec == "vp8.0") | 72 if (codec == "vp8" || codec == "vp8.0") |
| 71 return "video/x-vnd.on2.vp8"; | 73 return "video/x-vnd.on2.vp8"; |
| 72 if (codec == "vp9" || codec == "vp9.0") | 74 if (codec == "vp9" || codec == "vp9.0") |
| 73 return "video/x-vnd.on2.vp9"; | 75 return "video/x-vnd.on2.vp9"; |
| 74 if (codec == "vorbis") | 76 if (codec == "vorbis") |
| 75 return "audio/vorbis"; | 77 return "audio/vorbis"; |
| 78 if (codec == "opus") | |
| 79 return "audio/opus"; | |
| 76 return std::string(); | 80 return std::string(); |
| 77 } | 81 } |
| 78 | 82 |
| 79 // TODO(qinmin): using a map to help all the conversions in this class. | 83 // TODO(qinmin): using a map to help all the conversions in this class. |
| 80 static const std::string AndroidMimeTypeToCodecType(const std::string& mime) { | 84 static const std::string AndroidMimeTypeToCodecType(const std::string& mime) { |
| 81 if (mime == "video/mp4v-es") | 85 if (mime == "video/mp4v-es") |
| 82 return "mp4v"; | 86 return "mp4v"; |
| 83 if (mime == "video/avc") | 87 if (mime == "video/avc") |
| 84 return "avc1"; | 88 return "avc1"; |
| 85 if (mime == "video/x-vnd.on2.vp8") | 89 if (mime == "video/x-vnd.on2.vp8") |
| 86 return "vp8"; | 90 return "vp8"; |
| 87 if (mime == "video/x-vnd.on2.vp9") | 91 if (mime == "video/x-vnd.on2.vp9") |
| 88 return "vp9"; | 92 return "vp9"; |
| 89 if (mime == "audio/mp4a-latm") | 93 if (mime == "audio/mp4a-latm") |
| 90 return "mp4a"; | 94 return "mp4a"; |
| 91 if (mime == "audio/mpeg") | 95 if (mime == "audio/mpeg") |
| 92 return "mp3"; | 96 return "mp3"; |
| 93 if (mime == "audio/vorbis") | 97 if (mime == "audio/vorbis") |
| 94 return "vorbis"; | 98 return "vorbis"; |
| 99 if (mime == "audio/opus") | |
| 100 return "opus"; | |
| 95 return std::string(); | 101 return std::string(); |
| 96 } | 102 } |
| 97 | 103 |
| 98 static ScopedJavaLocalRef<jintArray> | 104 static ScopedJavaLocalRef<jintArray> |
| 99 ToJavaIntArray(JNIEnv* env, scoped_ptr<jint[]> native_array, int size) { | 105 ToJavaIntArray(JNIEnv* env, scoped_ptr<jint[]> native_array, int size) { |
| 100 ScopedJavaLocalRef<jintArray> j_array(env, env->NewIntArray(size)); | 106 ScopedJavaLocalRef<jintArray> j_array(env, env->NewIntArray(size)); |
| 101 env->SetIntArrayRegion(j_array.obj(), 0, size, native_array.get()); | 107 env->SetIntArrayRegion(j_array.obj(), 0, size, native_array.get()); |
| 102 return j_array; | 108 return j_array; |
| 103 } | 109 } |
| 104 | 110 |
| (...skipping 403 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 508 AudioCodecBridge::AudioCodecBridge(const std::string& mime) | 514 AudioCodecBridge::AudioCodecBridge(const std::string& mime) |
| 509 // Audio codec doesn't care about security level and there is no need for | 515 // Audio codec doesn't care about security level and there is no need for |
| 510 // audio encoding yet. | 516 // audio encoding yet. |
| 511 : MediaCodecBridge(mime, false, MEDIA_CODEC_DECODER) {} | 517 : MediaCodecBridge(mime, false, MEDIA_CODEC_DECODER) {} |
| 512 | 518 |
| 513 bool AudioCodecBridge::Start(const AudioCodec& codec, | 519 bool AudioCodecBridge::Start(const AudioCodec& codec, |
| 514 int sample_rate, | 520 int sample_rate, |
| 515 int channel_count, | 521 int channel_count, |
| 516 const uint8* extra_data, | 522 const uint8* extra_data, |
| 517 size_t extra_data_size, | 523 size_t extra_data_size, |
| 524 int64 codec_delay_ns, | |
| 525 int64 seek_preroll_ns, | |
| 518 bool play_audio, | 526 bool play_audio, |
| 519 jobject media_crypto) { | 527 jobject media_crypto) { |
| 520 JNIEnv* env = AttachCurrentThread(); | 528 JNIEnv* env = AttachCurrentThread(); |
| 521 | 529 |
| 522 if (!media_codec()) | 530 if (!media_codec()) |
| 523 return false; | 531 return false; |
| 524 | 532 |
| 525 std::string codec_string = AudioCodecToAndroidMimeType(codec); | 533 std::string codec_string = AudioCodecToAndroidMimeType(codec); |
| 526 if (codec_string.empty()) | 534 if (codec_string.empty()) |
| 527 return false; | 535 return false; |
| 528 | 536 |
| 529 ScopedJavaLocalRef<jstring> j_mime = | 537 ScopedJavaLocalRef<jstring> j_mime = |
| 530 ConvertUTF8ToJavaString(env, codec_string); | 538 ConvertUTF8ToJavaString(env, codec_string); |
| 531 ScopedJavaLocalRef<jobject> j_format(Java_MediaCodecBridge_createAudioFormat( | 539 ScopedJavaLocalRef<jobject> j_format(Java_MediaCodecBridge_createAudioFormat( |
| 532 env, j_mime.obj(), sample_rate, channel_count)); | 540 env, j_mime.obj(), sample_rate, channel_count)); |
| 533 DCHECK(!j_format.is_null()); | 541 DCHECK(!j_format.is_null()); |
| 534 | 542 |
| 535 if (!ConfigureMediaFormat(j_format.obj(), codec, extra_data, extra_data_size)) | 543 if (!ConfigureMediaFormat(j_format.obj(), codec, extra_data, extra_data_size, |
| 544 codec_delay_ns, seek_preroll_ns)) { | |
| 536 return false; | 545 return false; |
| 546 } | |
| 537 | 547 |
| 538 if (!Java_MediaCodecBridge_configureAudio( | 548 if (!Java_MediaCodecBridge_configureAudio( |
| 539 env, media_codec(), j_format.obj(), media_crypto, 0, play_audio)) { | 549 env, media_codec(), j_format.obj(), media_crypto, 0, play_audio)) { |
| 540 return false; | 550 return false; |
| 541 } | 551 } |
| 542 | 552 |
| 543 return StartInternal(); | 553 return StartInternal(); |
| 544 } | 554 } |
| 545 | 555 |
| 546 bool AudioCodecBridge::ConfigureMediaFormat(jobject j_format, | 556 bool AudioCodecBridge::ConfigureMediaFormat(jobject j_format, |
| 547 const AudioCodec& codec, | 557 const AudioCodec& codec, |
| 548 const uint8* extra_data, | 558 const uint8* extra_data, |
| 549 size_t extra_data_size) { | 559 size_t extra_data_size, |
| 560 int64 codec_delay_ns, | |
| 561 int64 seek_preroll_ns) { | |
| 550 if (extra_data_size == 0) | 562 if (extra_data_size == 0) |
| 551 return true; | 563 return true; |
| 552 | 564 |
| 553 JNIEnv* env = AttachCurrentThread(); | 565 JNIEnv* env = AttachCurrentThread(); |
| 554 switch (codec) { | 566 switch (codec) { |
| 555 case kCodecVorbis: { | 567 case kCodecVorbis: { |
| 556 if (extra_data[0] != 2) { | 568 if (extra_data[0] != 2) { |
| 557 LOG(ERROR) << "Invalid number of vorbis headers before the codec " | 569 LOG(ERROR) << "Invalid number of vorbis headers before the codec " |
| 558 << "header: " << extra_data[0]; | 570 << "header: " << extra_data[0]; |
| 559 return false; | 571 return false; |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 631 ScopedJavaLocalRef<jbyteArray> byte_array = | 643 ScopedJavaLocalRef<jbyteArray> byte_array = |
| 632 base::android::ToJavaByteArray(env, csd, kCsdLength); | 644 base::android::ToJavaByteArray(env, csd, kCsdLength); |
| 633 Java_MediaCodecBridge_setCodecSpecificData( | 645 Java_MediaCodecBridge_setCodecSpecificData( |
| 634 env, j_format, 0, byte_array.obj()); | 646 env, j_format, 0, byte_array.obj()); |
| 635 | 647 |
| 636 // TODO(qinmin): pass an extra variable to this function to determine | 648 // TODO(qinmin): pass an extra variable to this function to determine |
| 637 // whether we need to call this. | 649 // whether we need to call this. |
| 638 Java_MediaCodecBridge_setFrameHasADTSHeader(env, j_format); | 650 Java_MediaCodecBridge_setFrameHasADTSHeader(env, j_format); |
| 639 break; | 651 break; |
| 640 } | 652 } |
| 653 case kCodecOpus: { | |
| 654 if (codec_delay_ns < 0 || seek_preroll_ns < 0) { | |
| 655 LOG(ERROR) << "Invalid Opus Header"; | |
| 656 return false; | |
| 657 } | |
| 658 | |
| 659 // csd0 - Opus Header | |
| 660 ScopedJavaLocalRef<jbyteArray> csd0 = base::android::ToJavaByteArray( | |
| 661 env, extra_data, extra_data_size); | |
|
Tom Finegan
2015/01/22 02:35:14
I'd wrap after the =, assuming it fits.. And even
vignesh
2015/01/22 21:29:50
Done.
| |
| 662 Java_MediaCodecBridge_setCodecSpecificData(env, j_format, 0, csd0.obj()); | |
| 663 | |
| 664 // csd1 - Codec Delay | |
| 665 ScopedJavaLocalRef<jbyteArray> csd1 = base::android::ToJavaByteArray( | |
| 666 env, reinterpret_cast<const uint8*>(&codec_delay_ns), | |
| 667 sizeof(int64_t)); | |
| 668 Java_MediaCodecBridge_setCodecSpecificData(env, j_format, 1, csd1.obj()); | |
| 669 | |
| 670 // csd2 - Seek Preroll | |
| 671 ScopedJavaLocalRef<jbyteArray> csd2 = base::android::ToJavaByteArray( | |
| 672 env, reinterpret_cast<const uint8*>(&seek_preroll_ns), | |
| 673 sizeof(int64_t)); | |
| 674 Java_MediaCodecBridge_setCodecSpecificData(env, j_format, 2, csd1.obj()); | |
| 675 break; | |
| 676 } | |
| 641 default: | 677 default: |
| 642 LOG(ERROR) << "Invalid header encountered for codec: " | 678 LOG(ERROR) << "Invalid header encountered for codec: " |
| 643 << AudioCodecToAndroidMimeType(codec); | 679 << AudioCodecToAndroidMimeType(codec); |
| 644 return false; | 680 return false; |
| 645 } | 681 } |
| 646 return true; | 682 return true; |
| 647 } | 683 } |
| 648 | 684 |
| 649 int64 AudioCodecBridge::PlayOutputBuffer(int index, size_t size) { | 685 int64 AudioCodecBridge::PlayOutputBuffer(int index, size_t size) { |
| 650 DCHECK_LE(0, index); | 686 DCHECK_LE(0, index); |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 790 JNIEnv* env = AttachCurrentThread(); | 826 JNIEnv* env = AttachCurrentThread(); |
| 791 return Java_MediaCodecBridge_isAdaptivePlaybackSupported( | 827 return Java_MediaCodecBridge_isAdaptivePlaybackSupported( |
| 792 env, media_codec(), width, height); | 828 env, media_codec(), width, height); |
| 793 } | 829 } |
| 794 | 830 |
| 795 bool MediaCodecBridge::RegisterMediaCodecBridge(JNIEnv* env) { | 831 bool MediaCodecBridge::RegisterMediaCodecBridge(JNIEnv* env) { |
| 796 return RegisterNativesImpl(env); | 832 return RegisterNativesImpl(env); |
| 797 } | 833 } |
| 798 | 834 |
| 799 } // namespace media | 835 } // namespace media |
| OLD | NEW |