| 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 413 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 518 AudioCodecBridge::AudioCodecBridge(const std::string& mime) | 524 AudioCodecBridge::AudioCodecBridge(const std::string& mime) |
| 519 // Audio codec doesn't care about security level and there is no need for | 525 // Audio codec doesn't care about security level and there is no need for |
| 520 // audio encoding yet. | 526 // audio encoding yet. |
| 521 : MediaCodecBridge(mime, false, MEDIA_CODEC_DECODER) {} | 527 : MediaCodecBridge(mime, false, MEDIA_CODEC_DECODER) {} |
| 522 | 528 |
| 523 bool AudioCodecBridge::Start(const AudioCodec& codec, | 529 bool AudioCodecBridge::Start(const AudioCodec& codec, |
| 524 int sample_rate, | 530 int sample_rate, |
| 525 int channel_count, | 531 int channel_count, |
| 526 const uint8* extra_data, | 532 const uint8* extra_data, |
| 527 size_t extra_data_size, | 533 size_t extra_data_size, |
| 534 int64 codec_delay_ns, |
| 535 int64 seek_preroll_ns, |
| 528 bool play_audio, | 536 bool play_audio, |
| 529 jobject media_crypto) { | 537 jobject media_crypto) { |
| 530 JNIEnv* env = AttachCurrentThread(); | 538 JNIEnv* env = AttachCurrentThread(); |
| 531 | 539 |
| 532 if (!media_codec()) | 540 if (!media_codec()) |
| 533 return false; | 541 return false; |
| 534 | 542 |
| 535 std::string codec_string = AudioCodecToAndroidMimeType(codec); | 543 std::string codec_string = AudioCodecToAndroidMimeType(codec); |
| 536 if (codec_string.empty()) | 544 if (codec_string.empty()) |
| 537 return false; | 545 return false; |
| 538 | 546 |
| 539 ScopedJavaLocalRef<jstring> j_mime = | 547 ScopedJavaLocalRef<jstring> j_mime = |
| 540 ConvertUTF8ToJavaString(env, codec_string); | 548 ConvertUTF8ToJavaString(env, codec_string); |
| 541 ScopedJavaLocalRef<jobject> j_format(Java_MediaCodecBridge_createAudioFormat( | 549 ScopedJavaLocalRef<jobject> j_format(Java_MediaCodecBridge_createAudioFormat( |
| 542 env, j_mime.obj(), sample_rate, channel_count)); | 550 env, j_mime.obj(), sample_rate, channel_count)); |
| 543 DCHECK(!j_format.is_null()); | 551 DCHECK(!j_format.is_null()); |
| 544 | 552 |
| 545 if (!ConfigureMediaFormat(j_format.obj(), codec, extra_data, extra_data_size)) | 553 if (!ConfigureMediaFormat(j_format.obj(), codec, extra_data, extra_data_size, |
| 554 codec_delay_ns, seek_preroll_ns)) { |
| 546 return false; | 555 return false; |
| 556 } |
| 547 | 557 |
| 548 if (!Java_MediaCodecBridge_configureAudio( | 558 if (!Java_MediaCodecBridge_configureAudio( |
| 549 env, media_codec(), j_format.obj(), media_crypto, 0, play_audio)) { | 559 env, media_codec(), j_format.obj(), media_crypto, 0, play_audio)) { |
| 550 return false; | 560 return false; |
| 551 } | 561 } |
| 552 | 562 |
| 553 return StartInternal(); | 563 return StartInternal(); |
| 554 } | 564 } |
| 555 | 565 |
| 556 bool AudioCodecBridge::ConfigureMediaFormat(jobject j_format, | 566 bool AudioCodecBridge::ConfigureMediaFormat(jobject j_format, |
| 557 const AudioCodec& codec, | 567 const AudioCodec& codec, |
| 558 const uint8* extra_data, | 568 const uint8* extra_data, |
| 559 size_t extra_data_size) { | 569 size_t extra_data_size, |
| 560 if (extra_data_size == 0) | 570 int64 codec_delay_ns, |
| 571 int64 seek_preroll_ns) { |
| 572 if (extra_data_size == 0 && codec != kCodecOpus) |
| 561 return true; | 573 return true; |
| 562 | 574 |
| 563 JNIEnv* env = AttachCurrentThread(); | 575 JNIEnv* env = AttachCurrentThread(); |
| 564 switch (codec) { | 576 switch (codec) { |
| 565 case kCodecVorbis: { | 577 case kCodecVorbis: { |
| 566 if (extra_data[0] != 2) { | 578 if (extra_data[0] != 2) { |
| 567 LOG(ERROR) << "Invalid number of vorbis headers before the codec " | 579 LOG(ERROR) << "Invalid number of vorbis headers before the codec " |
| 568 << "header: " << extra_data[0]; | 580 << "header: " << extra_data[0]; |
| 569 return false; | 581 return false; |
| 570 } | 582 } |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 641 ScopedJavaLocalRef<jbyteArray> byte_array = | 653 ScopedJavaLocalRef<jbyteArray> byte_array = |
| 642 base::android::ToJavaByteArray(env, csd, kCsdLength); | 654 base::android::ToJavaByteArray(env, csd, kCsdLength); |
| 643 Java_MediaCodecBridge_setCodecSpecificData( | 655 Java_MediaCodecBridge_setCodecSpecificData( |
| 644 env, j_format, 0, byte_array.obj()); | 656 env, j_format, 0, byte_array.obj()); |
| 645 | 657 |
| 646 // TODO(qinmin): pass an extra variable to this function to determine | 658 // TODO(qinmin): pass an extra variable to this function to determine |
| 647 // whether we need to call this. | 659 // whether we need to call this. |
| 648 Java_MediaCodecBridge_setFrameHasADTSHeader(env, j_format); | 660 Java_MediaCodecBridge_setFrameHasADTSHeader(env, j_format); |
| 649 break; | 661 break; |
| 650 } | 662 } |
| 663 case kCodecOpus: { |
| 664 if (!extra_data || extra_data_size == 0 || |
| 665 codec_delay_ns < 0 || seek_preroll_ns < 0) { |
| 666 LOG(ERROR) << "Invalid Opus Header"; |
| 667 return false; |
| 668 } |
| 669 |
| 670 // csd0 - Opus Header |
| 671 ScopedJavaLocalRef<jbyteArray> csd0 = |
| 672 base::android::ToJavaByteArray(env, extra_data, extra_data_size); |
| 673 Java_MediaCodecBridge_setCodecSpecificData(env, j_format, 0, csd0.obj()); |
| 674 |
| 675 // csd1 - Codec Delay |
| 676 ScopedJavaLocalRef<jbyteArray> csd1 = |
| 677 base::android::ToJavaByteArray( |
| 678 env, reinterpret_cast<const uint8*>(&codec_delay_ns), |
| 679 sizeof(int64_t)); |
| 680 Java_MediaCodecBridge_setCodecSpecificData(env, j_format, 1, csd1.obj()); |
| 681 |
| 682 // csd2 - Seek Preroll |
| 683 ScopedJavaLocalRef<jbyteArray> csd2 = |
| 684 base::android::ToJavaByteArray( |
| 685 env, reinterpret_cast<const uint8*>(&seek_preroll_ns), |
| 686 sizeof(int64_t)); |
| 687 Java_MediaCodecBridge_setCodecSpecificData(env, j_format, 2, csd2.obj()); |
| 688 break; |
| 689 } |
| 651 default: | 690 default: |
| 652 LOG(ERROR) << "Invalid header encountered for codec: " | 691 LOG(ERROR) << "Invalid header encountered for codec: " |
| 653 << AudioCodecToAndroidMimeType(codec); | 692 << AudioCodecToAndroidMimeType(codec); |
| 654 return false; | 693 return false; |
| 655 } | 694 } |
| 656 return true; | 695 return true; |
| 657 } | 696 } |
| 658 | 697 |
| 659 int64 AudioCodecBridge::PlayOutputBuffer(int index, size_t size) { | 698 int64 AudioCodecBridge::PlayOutputBuffer(int index, size_t size) { |
| 660 DCHECK_LE(0, index); | 699 DCHECK_LE(0, index); |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 800 JNIEnv* env = AttachCurrentThread(); | 839 JNIEnv* env = AttachCurrentThread(); |
| 801 return Java_MediaCodecBridge_isAdaptivePlaybackSupported( | 840 return Java_MediaCodecBridge_isAdaptivePlaybackSupported( |
| 802 env, media_codec(), width, height); | 841 env, media_codec(), width, height); |
| 803 } | 842 } |
| 804 | 843 |
| 805 bool MediaCodecBridge::RegisterMediaCodecBridge(JNIEnv* env) { | 844 bool MediaCodecBridge::RegisterMediaCodecBridge(JNIEnv* env) { |
| 806 return RegisterNativesImpl(env); | 845 return RegisterNativesImpl(env); |
| 807 } | 846 } |
| 808 | 847 |
| 809 } // namespace media | 848 } // namespace media |
| OLD | NEW |