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) |
wolenetz
2015/01/22 22:06:22
Might it ever be valid to configure opus with 0 ex
vignesh
2015/01/22 22:48:42
Opus always need extra data from the headers. I ha
wolenetz
2015/01/22 23:01:06
Acknowledged.
| |
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; |
560 } | 572 } |
(...skipping 70 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) { | |
wolenetz
2015/01/22 22:06:22
nit: default DemuxerConfig initializer values for
vignesh
2015/01/22 22:48:42
Done.
| |
655 LOG(ERROR) << "Invalid Opus Header"; | |
656 return false; | |
657 } | |
658 | |
659 // csd0 - Opus Header | |
660 ScopedJavaLocalRef<jbyteArray> csd0 = | |
661 base::android::ToJavaByteArray(env, extra_data, extra_data_size); | |
662 Java_MediaCodecBridge_setCodecSpecificData(env, j_format, 0, csd0.obj()); | |
663 | |
664 // csd1 - Codec Delay | |
665 ScopedJavaLocalRef<jbyteArray> csd1 = | |
666 base::android::ToJavaByteArray( | |
667 env, reinterpret_cast<const uint8*>(&codec_delay_ns), | |
668 sizeof(int64_t)); | |
669 Java_MediaCodecBridge_setCodecSpecificData(env, j_format, 1, csd1.obj()); | |
670 | |
671 // csd2 - Seek Preroll | |
672 ScopedJavaLocalRef<jbyteArray> csd2 = | |
673 base::android::ToJavaByteArray( | |
674 env, reinterpret_cast<const uint8*>(&seek_preroll_ns), | |
675 sizeof(int64_t)); | |
676 Java_MediaCodecBridge_setCodecSpecificData(env, j_format, 2, csd1.obj()); | |
wolenetz
2015/01/22 22:06:22
hmm. this looks wrong. should it instead be sendin
vignesh
2015/01/22 22:48:42
Whoops.
Any idea how i can add a test for this? S
wolenetz
2015/01/22 23:01:06
I guess you could add a mediasourceplayertest that
| |
677 break; | |
678 } | |
641 default: | 679 default: |
642 LOG(ERROR) << "Invalid header encountered for codec: " | 680 LOG(ERROR) << "Invalid header encountered for codec: " |
643 << AudioCodecToAndroidMimeType(codec); | 681 << AudioCodecToAndroidMimeType(codec); |
644 return false; | 682 return false; |
645 } | 683 } |
646 return true; | 684 return true; |
647 } | 685 } |
648 | 686 |
649 int64 AudioCodecBridge::PlayOutputBuffer(int index, size_t size) { | 687 int64 AudioCodecBridge::PlayOutputBuffer(int index, size_t size) { |
650 DCHECK_LE(0, index); | 688 DCHECK_LE(0, index); |
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
790 JNIEnv* env = AttachCurrentThread(); | 828 JNIEnv* env = AttachCurrentThread(); |
791 return Java_MediaCodecBridge_isAdaptivePlaybackSupported( | 829 return Java_MediaCodecBridge_isAdaptivePlaybackSupported( |
792 env, media_codec(), width, height); | 830 env, media_codec(), width, height); |
793 } | 831 } |
794 | 832 |
795 bool MediaCodecBridge::RegisterMediaCodecBridge(JNIEnv* env) { | 833 bool MediaCodecBridge::RegisterMediaCodecBridge(JNIEnv* env) { |
796 return RegisterNativesImpl(env); | 834 return RegisterNativesImpl(env); |
797 } | 835 } |
798 | 836 |
799 } // namespace media | 837 } // namespace media |
OLD | NEW |