| 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 |