OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 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 package org.chromium.media; | 5 package org.chromium.media; |
6 | 6 |
7 import android.media.AudioFormat; | 7 import android.media.AudioFormat; |
8 import android.media.AudioManager; | 8 import android.media.AudioManager; |
9 import android.media.AudioTrack; | 9 import android.media.AudioTrack; |
10 import android.media.MediaCodec; | 10 import android.media.MediaCodec; |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
70 | 70 |
71 private ByteBuffer[] mInputBuffers; | 71 private ByteBuffer[] mInputBuffers; |
72 private ByteBuffer[] mOutputBuffers; | 72 private ByteBuffer[] mOutputBuffers; |
73 | 73 |
74 private MediaCodec mMediaCodec; | 74 private MediaCodec mMediaCodec; |
75 private AudioTrack mAudioTrack; | 75 private AudioTrack mAudioTrack; |
76 private boolean mFlushed; | 76 private boolean mFlushed; |
77 private long mLastPresentationTimeUs; | 77 private long mLastPresentationTimeUs; |
78 private String mMime; | 78 private String mMime; |
79 private boolean mAdaptivePlaybackSupported; | 79 private boolean mAdaptivePlaybackSupported; |
80 private int mSampleRate; | |
81 | 80 |
82 private static class DequeueInputResult { | 81 private static class DequeueInputResult { |
83 private final int mStatus; | 82 private final int mStatus; |
84 private final int mIndex; | 83 private final int mIndex; |
85 | 84 |
86 private DequeueInputResult(int status, int index) { | 85 private DequeueInputResult(int status, int index) { |
87 mStatus = status; | 86 mStatus = status; |
88 mIndex = index; | 87 mIndex = index; |
89 } | 88 } |
90 | 89 |
(...skipping 351 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
442 | 441 |
443 @CalledByNative | 442 @CalledByNative |
444 private int getOutputWidth() { | 443 private int getOutputWidth() { |
445 MediaFormat format = mMediaCodec.getOutputFormat(); | 444 MediaFormat format = mMediaCodec.getOutputFormat(); |
446 return outputFormatHasCropValues(format) | 445 return outputFormatHasCropValues(format) |
447 ? format.getInteger(KEY_CROP_RIGHT) - format.getInteger(KEY_CROP
_LEFT) + 1 | 446 ? format.getInteger(KEY_CROP_RIGHT) - format.getInteger(KEY_CROP
_LEFT) + 1 |
448 : format.getInteger(MediaFormat.KEY_WIDTH); | 447 : format.getInteger(MediaFormat.KEY_WIDTH); |
449 } | 448 } |
450 | 449 |
451 @CalledByNative | 450 @CalledByNative |
| 451 private int getOutputSamplingRate() { |
| 452 MediaFormat format = mMediaCodec.getOutputFormat(); |
| 453 return format.getInteger(MediaFormat.KEY_SAMPLE_RATE); |
| 454 } |
| 455 |
| 456 @CalledByNative |
452 private ByteBuffer getInputBuffer(int index) { | 457 private ByteBuffer getInputBuffer(int index) { |
453 if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) { | 458 if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) { |
454 return mMediaCodec.getInputBuffer(index); | 459 return mMediaCodec.getInputBuffer(index); |
455 } | 460 } |
456 return mInputBuffers[index]; | 461 return mInputBuffers[index]; |
457 } | 462 } |
458 | 463 |
459 @CalledByNative | 464 @CalledByNative |
460 private ByteBuffer getOutputBuffer(int index) { | 465 private ByteBuffer getOutputBuffer(int index) { |
461 if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) { | 466 if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) { |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
562 status = MEDIA_CODEC_OK; | 567 status = MEDIA_CODEC_OK; |
563 index = indexOrStatus; | 568 index = indexOrStatus; |
564 } else if (indexOrStatus == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED)
{ | 569 } else if (indexOrStatus == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED)
{ |
565 mOutputBuffers = mMediaCodec.getOutputBuffers(); | 570 mOutputBuffers = mMediaCodec.getOutputBuffers(); |
566 status = MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED; | 571 status = MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED; |
567 } else if (indexOrStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { | 572 } else if (indexOrStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { |
568 status = MEDIA_CODEC_OUTPUT_FORMAT_CHANGED; | 573 status = MEDIA_CODEC_OUTPUT_FORMAT_CHANGED; |
569 MediaFormat newFormat = mMediaCodec.getOutputFormat(); | 574 MediaFormat newFormat = mMediaCodec.getOutputFormat(); |
570 if (mAudioTrack != null && newFormat.containsKey(MediaFormat.KEY
_SAMPLE_RATE)) { | 575 if (mAudioTrack != null && newFormat.containsKey(MediaFormat.KEY
_SAMPLE_RATE)) { |
571 int newSampleRate = newFormat.getInteger(MediaFormat.KEY_SAM
PLE_RATE); | 576 int newSampleRate = newFormat.getInteger(MediaFormat.KEY_SAM
PLE_RATE); |
572 if (newSampleRate != mSampleRate && !reconfigureAudioTrack(n
ewFormat)) { | 577 if (mAudioTrack.setPlaybackRate(newSampleRate) != AudioTrack
.SUCCESS) { |
573 status = MEDIA_CODEC_ERROR; | 578 status = MEDIA_CODEC_ERROR; |
574 } | 579 } |
575 } | 580 } |
576 } else if (indexOrStatus == MediaCodec.INFO_TRY_AGAIN_LATER) { | 581 } else if (indexOrStatus == MediaCodec.INFO_TRY_AGAIN_LATER) { |
577 status = MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER; | 582 status = MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER; |
578 } else { | 583 } else { |
579 Log.e(TAG, "Unexpected index_or_status: " + indexOrStatus); | 584 Log.e(TAG, "Unexpected index_or_status: " + indexOrStatus); |
580 assert false; | 585 assert false; |
581 } | 586 } |
582 } catch (IllegalStateException e) { | 587 } catch (IllegalStateException e) { |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
665 @CalledByNative | 670 @CalledByNative |
666 private static void setFrameHasADTSHeader(MediaFormat format) { | 671 private static void setFrameHasADTSHeader(MediaFormat format) { |
667 format.setInteger(MediaFormat.KEY_IS_ADTS, 1); | 672 format.setInteger(MediaFormat.KEY_IS_ADTS, 1); |
668 } | 673 } |
669 | 674 |
670 @CalledByNative | 675 @CalledByNative |
671 private boolean configureAudio(MediaFormat format, MediaCrypto crypto, int f
lags, | 676 private boolean configureAudio(MediaFormat format, MediaCrypto crypto, int f
lags, |
672 boolean playAudio) { | 677 boolean playAudio) { |
673 try { | 678 try { |
674 mMediaCodec.configure(format, null, crypto, flags); | 679 mMediaCodec.configure(format, null, crypto, flags); |
675 if (playAudio && !reconfigureAudioTrack(format)) { | 680 if (playAudio) { |
676 return false; | 681 int sampleRate = format.getInteger(MediaFormat.KEY_SAMPLE_RATE); |
| 682 int channelCount = format.getInteger(MediaFormat.KEY_CHANNEL_COU
NT); |
| 683 int channelConfig = getAudioFormat(channelCount); |
| 684 // Using 16bit PCM for output. Keep this value in sync with |
| 685 // kBytesPerAudioOutputSample in media_codec_bridge.cc. |
| 686 int minBufferSize = AudioTrack.getMinBufferSize(sampleRate, chan
nelConfig, |
| 687 AudioFormat.ENCODING_PCM_16BIT); |
| 688 mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRa
te, channelConfig, |
| 689 AudioFormat.ENCODING_PCM_16BIT, minBufferSize, AudioTrac
k.MODE_STREAM); |
| 690 if (mAudioTrack.getState() == AudioTrack.STATE_UNINITIALIZED) { |
| 691 mAudioTrack = null; |
| 692 return false; |
| 693 } |
677 } | 694 } |
678 return true; | 695 return true; |
679 } catch (IllegalStateException e) { | 696 } catch (IllegalStateException e) { |
680 Log.e(TAG, "Cannot configure the audio codec", e); | 697 Log.e(TAG, "Cannot configure the audio codec", e); |
681 } | 698 } |
682 return false; | 699 return false; |
683 } | 700 } |
684 | 701 |
685 /** | 702 /** |
686 * Resets the AudioTrack instance, configured according to the given format. | |
687 * If a previous AudioTrack instance already exists, release it. | |
688 * | |
689 * @param format The format from which to get sample rate and channel count. | |
690 * @return Whether or not creating the AudioTrack succeeded. | |
691 */ | |
692 private boolean reconfigureAudioTrack(MediaFormat format) { | |
693 if (mAudioTrack != null) { | |
694 mAudioTrack.release(); | |
695 } | |
696 | |
697 mSampleRate = format.getInteger(MediaFormat.KEY_SAMPLE_RATE); | |
698 int channelCount = format.getInteger(MediaFormat.KEY_CHANNEL_COUNT); | |
699 int channelConfig = getAudioFormat(channelCount); | |
700 // Using 16bit PCM for output. Keep this value in sync with | |
701 // kBytesPerAudioOutputSample in media_codec_bridge.cc. | |
702 int minBufferSize = AudioTrack.getMinBufferSize(mSampleRate, channelConf
ig, | |
703 AudioFormat.ENCODING_PCM_16BIT); | |
704 mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, mSampleRate, cha
nnelConfig, | |
705 AudioFormat.ENCODING_PCM_16BIT, minBufferSize, AudioTrack.MODE_S
TREAM); | |
706 if (mAudioTrack.getState() == AudioTrack.STATE_UNINITIALIZED) { | |
707 mAudioTrack = null; | |
708 Log.e(TAG, "Failed to initialize AudioTrack"); | |
709 return false; | |
710 } | |
711 return true; | |
712 } | |
713 | |
714 /** | |
715 * Play the audio buffer that is passed in. | 703 * Play the audio buffer that is passed in. |
716 * | 704 * |
717 * @param buf Audio buffer to be rendered. | 705 * @param buf Audio buffer to be rendered. |
718 * @return The number of frames that have already been consumed by the | 706 * @return The number of frames that have already been consumed by the |
719 * hardware. This number resets to 0 after each flush call. | 707 * hardware. This number resets to 0 after each flush call. |
720 */ | 708 */ |
721 @CalledByNative | 709 @CalledByNative |
722 private long playOutputBuffer(byte[] buf) { | 710 private long playOutputBuffer(byte[] buf) { |
723 if (mAudioTrack == null) { | 711 if (mAudioTrack == null) { |
724 return 0; | 712 return 0; |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
769 return AudioFormat.CHANNEL_OUT_QUAD; | 757 return AudioFormat.CHANNEL_OUT_QUAD; |
770 case 6: | 758 case 6: |
771 return AudioFormat.CHANNEL_OUT_5POINT1; | 759 return AudioFormat.CHANNEL_OUT_5POINT1; |
772 case 8: | 760 case 8: |
773 return AudioFormat.CHANNEL_OUT_7POINT1; | 761 return AudioFormat.CHANNEL_OUT_7POINT1; |
774 default: | 762 default: |
775 return AudioFormat.CHANNEL_OUT_DEFAULT; | 763 return AudioFormat.CHANNEL_OUT_DEFAULT; |
776 } | 764 } |
777 } | 765 } |
778 } | 766 } |
OLD | NEW |