Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(205)

Side by Side Diff: media/base/android/java/src/org/chromium/media/MediaCodecBridge.java

Issue 2283493003: Delete browser MSE implementation. (Closed)
Patch Set: Actually delete MSP. Cleanse references. Remove AudioTrack usage. Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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.annotation.TargetApi; 7 import android.annotation.TargetApi;
8 import android.media.AudioFormat; 8 import android.media.AudioFormat;
9 import android.media.AudioManager;
10 import android.media.AudioTrack;
11 import android.media.MediaCodec; 9 import android.media.MediaCodec;
12 import android.media.MediaCrypto; 10 import android.media.MediaCrypto;
13 import android.media.MediaFormat; 11 import android.media.MediaFormat;
14 import android.os.Build; 12 import android.os.Build;
15 import android.os.Bundle; 13 import android.os.Bundle;
16 import android.view.Surface; 14 import android.view.Surface;
17 15
18 import org.chromium.base.Log; 16 import org.chromium.base.Log;
19 import org.chromium.base.annotations.CalledByNative; 17 import org.chromium.base.annotations.CalledByNative;
20 import org.chromium.base.annotations.JNINamespace; 18 import org.chromium.base.annotations.JNINamespace;
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
58 // TODO(qinmin): Use MediaFormat constants when part of the public API. 56 // TODO(qinmin): Use MediaFormat constants when part of the public API.
59 private static final String KEY_CROP_LEFT = "crop-left"; 57 private static final String KEY_CROP_LEFT = "crop-left";
60 private static final String KEY_CROP_RIGHT = "crop-right"; 58 private static final String KEY_CROP_RIGHT = "crop-right";
61 private static final String KEY_CROP_BOTTOM = "crop-bottom"; 59 private static final String KEY_CROP_BOTTOM = "crop-bottom";
62 private static final String KEY_CROP_TOP = "crop-top"; 60 private static final String KEY_CROP_TOP = "crop-top";
63 61
64 private ByteBuffer[] mInputBuffers; 62 private ByteBuffer[] mInputBuffers;
65 private ByteBuffer[] mOutputBuffers; 63 private ByteBuffer[] mOutputBuffers;
66 64
67 private MediaCodec mMediaCodec; 65 private MediaCodec mMediaCodec;
68 private AudioTrack mAudioTrack;
69 private byte[] mPendingAudioBuffer;
70 private boolean mFlushed; 66 private boolean mFlushed;
71 private long mLastPresentationTimeUs; 67 private long mLastPresentationTimeUs;
72 private String mMime; 68 private String mMime;
73 private boolean mAdaptivePlaybackSupported; 69 private boolean mAdaptivePlaybackSupported;
74 70
75 @MainDex 71 @MainDex
76 private static class DequeueInputResult { 72 private static class DequeueInputResult {
77 private final int mStatus; 73 private final int mStatus;
78 private final int mIndex; 74 private final int mIndex;
79 75
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after
187 @CalledByNative("GetOutputFormatResult") 183 @CalledByNative("GetOutputFormatResult")
188 private int channelCount() { 184 private int channelCount() {
189 return mFormat.getInteger(MediaFormat.KEY_CHANNEL_COUNT); 185 return mFormat.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
190 } 186 }
191 } 187 }
192 188
193 private MediaCodecBridge( 189 private MediaCodecBridge(
194 MediaCodec mediaCodec, String mime, boolean adaptivePlaybackSupporte d) { 190 MediaCodec mediaCodec, String mime, boolean adaptivePlaybackSupporte d) {
195 assert mediaCodec != null; 191 assert mediaCodec != null;
196 mMediaCodec = mediaCodec; 192 mMediaCodec = mediaCodec;
197 mPendingAudioBuffer = null;
198 mMime = mime; 193 mMime = mime;
199 mLastPresentationTimeUs = 0; 194 mLastPresentationTimeUs = 0;
200 mFlushed = true; 195 mFlushed = true;
201 mAdaptivePlaybackSupported = adaptivePlaybackSupported; 196 mAdaptivePlaybackSupported = adaptivePlaybackSupported;
202 } 197 }
203 198
204 @CalledByNative 199 @CalledByNative
205 private static MediaCodecBridge create( 200 private static MediaCodecBridge create(
206 String mime, boolean isSecure, int direction, boolean requireSoftwar eCodec) { 201 String mime, boolean isSecure, int direction, boolean requireSoftwar eCodec) {
207 MediaCodecUtil.CodecCreationInfo info = new MediaCodecUtil.CodecCreation Info(); 202 MediaCodecUtil.CodecCreationInfo info = new MediaCodecUtil.CodecCreation Info();
(...skipping 23 matching lines...) Expand all
231 codecName = mMediaCodec.getName(); 226 codecName = mMediaCodec.getName();
232 } 227 }
233 Log.w(TAG, "calling MediaCodec.release() on " + codecName); 228 Log.w(TAG, "calling MediaCodec.release() on " + codecName);
234 mMediaCodec.release(); 229 mMediaCodec.release();
235 } catch (IllegalStateException e) { 230 } catch (IllegalStateException e) {
236 // The MediaCodec is stuck in a wrong state, possibly due to losing 231 // The MediaCodec is stuck in a wrong state, possibly due to losing
237 // the surface. 232 // the surface.
238 Log.e(TAG, "Cannot release media codec", e); 233 Log.e(TAG, "Cannot release media codec", e);
239 } 234 }
240 mMediaCodec = null; 235 mMediaCodec = null;
241 if (mAudioTrack != null) {
242 mAudioTrack.release();
243 }
244 mPendingAudioBuffer = null;
245 } 236 }
246 237
247 @SuppressWarnings("deprecation") 238 @SuppressWarnings("deprecation")
248 @CalledByNative 239 @CalledByNative
249 private boolean start() { 240 private boolean start() {
250 try { 241 try {
251 mMediaCodec.start(); 242 mMediaCodec.start();
252 if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) { 243 if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
253 mInputBuffers = mMediaCodec.getInputBuffers(); 244 mInputBuffers = mMediaCodec.getInputBuffers();
254 mOutputBuffers = mMediaCodec.getOutputBuffers(); 245 mOutputBuffers = mMediaCodec.getOutputBuffers();
(...skipping 26 matching lines...) Expand all
281 } catch (Exception e) { 272 } catch (Exception e) {
282 Log.e(TAG, "Failed to dequeue input buffer", e); 273 Log.e(TAG, "Failed to dequeue input buffer", e);
283 } 274 }
284 return new DequeueInputResult(status, index); 275 return new DequeueInputResult(status, index);
285 } 276 }
286 277
287 @CalledByNative 278 @CalledByNative
288 private int flush() { 279 private int flush() {
289 try { 280 try {
290 mFlushed = true; 281 mFlushed = true;
291 if (mAudioTrack != null) {
292 // Need to call pause() here, or otherwise flush() is a no-op.
293 mAudioTrack.pause();
294 mAudioTrack.flush();
295 mPendingAudioBuffer = null;
296 }
297 mMediaCodec.flush(); 282 mMediaCodec.flush();
298 } catch (IllegalStateException e) { 283 } catch (IllegalStateException e) {
299 Log.e(TAG, "Failed to flush MediaCodec", e); 284 Log.e(TAG, "Failed to flush MediaCodec", e);
300 return MEDIA_CODEC_ERROR; 285 return MEDIA_CODEC_ERROR;
301 } 286 }
302 return MEDIA_CODEC_OK; 287 return MEDIA_CODEC_OK;
303 } 288 }
304 289
305 @CalledByNative 290 @CalledByNative
306 private void stop() { 291 private void stop() {
307 mMediaCodec.stop(); 292 mMediaCodec.stop();
308 if (mAudioTrack != null) {
309 mAudioTrack.pause();
310 }
311 } 293 }
312 294
313 @TargetApi(Build.VERSION_CODES.KITKAT) 295 @TargetApi(Build.VERSION_CODES.KITKAT)
314 @CalledByNative 296 @CalledByNative
315 private String getName() { 297 private String getName() {
316 return mMediaCodec.getName(); 298 return mMediaCodec.getName();
317 } 299 }
318 300
319 @CalledByNative 301 @CalledByNative
320 private GetOutputFormatResult getOutputFormat() { 302 private GetOutputFormatResult getOutputFormat() {
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after
440 if (indexOrStatus >= 0) { // index! 422 if (indexOrStatus >= 0) { // index!
441 status = MEDIA_CODEC_OK; 423 status = MEDIA_CODEC_OK;
442 index = indexOrStatus; 424 index = indexOrStatus;
443 } else if (indexOrStatus == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) { 425 } else if (indexOrStatus == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
444 assert Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT; 426 assert Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT;
445 mOutputBuffers = mMediaCodec.getOutputBuffers(); 427 mOutputBuffers = mMediaCodec.getOutputBuffers();
446 status = MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED; 428 status = MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED;
447 } else if (indexOrStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { 429 } else if (indexOrStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
448 status = MEDIA_CODEC_OUTPUT_FORMAT_CHANGED; 430 status = MEDIA_CODEC_OUTPUT_FORMAT_CHANGED;
449 MediaFormat newFormat = mMediaCodec.getOutputFormat(); 431 MediaFormat newFormat = mMediaCodec.getOutputFormat();
450 if (mAudioTrack != null && newFormat.containsKey(MediaFormat.KEY _SAMPLE_RATE)) {
451 int newSampleRate = newFormat.getInteger(MediaFormat.KEY_SAM PLE_RATE);
452 if (mAudioTrack.setPlaybackRate(newSampleRate) != AudioTrack .SUCCESS) {
453 status = MEDIA_CODEC_ERROR;
454 }
455 }
456 } else if (indexOrStatus == MediaCodec.INFO_TRY_AGAIN_LATER) { 432 } else if (indexOrStatus == MediaCodec.INFO_TRY_AGAIN_LATER) {
457 status = MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER; 433 status = MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER;
458 } else { 434 } else {
459 Log.e(TAG, "Unexpected index_or_status: " + indexOrStatus); 435 Log.e(TAG, "Unexpected index_or_status: " + indexOrStatus);
460 assert false; 436 assert false;
461 } 437 }
462 } catch (IllegalStateException e) { 438 } catch (IllegalStateException e) {
463 status = MEDIA_CODEC_ERROR; 439 status = MEDIA_CODEC_ERROR;
464 Log.e(TAG, "Failed to dequeue output buffer", e); 440 Log.e(TAG, "Failed to dequeue output buffer", e);
465 } 441 }
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after
603 format.setByteBuffer(name, ByteBuffer.wrap(bytes)); 579 format.setByteBuffer(name, ByteBuffer.wrap(bytes));
604 } 580 }
605 } 581 }
606 582
607 @CalledByNative 583 @CalledByNative
608 private static void setFrameHasADTSHeader(MediaFormat format) { 584 private static void setFrameHasADTSHeader(MediaFormat format) {
609 format.setInteger(MediaFormat.KEY_IS_ADTS, 1); 585 format.setInteger(MediaFormat.KEY_IS_ADTS, 1);
610 } 586 }
611 587
612 @CalledByNative 588 @CalledByNative
613 private boolean configureAudio( 589 private boolean configureAudio(MediaFormat format, MediaCrypto crypto, int f lags) {
614 MediaFormat format, MediaCrypto crypto, int flags, boolean playAudio ) {
615 try { 590 try {
616 mMediaCodec.configure(format, null, crypto, flags); 591 mMediaCodec.configure(format, null, crypto, flags);
617 if (playAudio) {
618 int sampleRate = format.getInteger(MediaFormat.KEY_SAMPLE_RATE);
619 int channelCount = format.getInteger(MediaFormat.KEY_CHANNEL_COU NT);
620 if (!createAudioTrack(sampleRate, channelCount)) return false;
621 }
622 return true; 592 return true;
623 } catch (IllegalArgumentException e) { 593 } catch (IllegalArgumentException e) {
624 Log.e(TAG, "Cannot configure the audio codec", e); 594 Log.e(TAG, "Cannot configure the audio codec", e);
625 } catch (IllegalStateException e) { 595 } catch (IllegalStateException e) {
626 Log.e(TAG, "Cannot configure the audio codec", e); 596 Log.e(TAG, "Cannot configure the audio codec", e);
627 } catch (MediaCodec.CryptoException e) { 597 } catch (MediaCodec.CryptoException e) {
628 Log.e(TAG, "Cannot configure the audio codec: DRM error", e); 598 Log.e(TAG, "Cannot configure the audio codec: DRM error", e);
629 } catch (Exception e) { 599 } catch (Exception e) {
630 Log.e(TAG, "Cannot configure the audio codec", e); 600 Log.e(TAG, "Cannot configure the audio codec", e);
631 } 601 }
632 return false; 602 return false;
633 } 603 }
634 604
635 @CalledByNative
636 private boolean createAudioTrack(int sampleRate, int channelCount) {
637 Log.v(TAG, "createAudioTrack: sampleRate:" + sampleRate + " channelCount :" + channelCount);
638
639 int channelConfig = getAudioFormat(channelCount);
640
641 // Using 16bit PCM for output. Keep this value in sync with
642 // kBytesPerAudioOutputSample in media_codec_bridge.cc.
643 int minBufferSize = AudioTrack.getMinBufferSize(
644 sampleRate, channelConfig, AudioFormat.ENCODING_PCM_16BIT);
645
646 // Set buffer size to be at least 1.5 times the minimum buffer size
647 // (see http://crbug.com/589269).
648 // TODO(timav, qinmin): For MediaSourcePlayer, we starts both audio and
649 // video decoder once we got valid presentation timestamp from the decod er
650 // (prerolling_==false). However, this doesn't guarantee that audiotrack
651 // starts outputing samples, especially with a larger buffersize.
652 // The best solution will be having a large buffer size in AudioTrack, a nd
653 // sync audio/video start when audiotrack starts output samples
654 // (head position starts progressing).
655 int minBufferSizeInFrames = minBufferSize / PCM16_BYTES_PER_SAMPLE / cha nnelCount;
656 int bufferSize =
657 (int) (1.5 * minBufferSizeInFrames) * PCM16_BYTES_PER_SAMPLE * c hannelCount;
658
659 if (mAudioTrack != null) mAudioTrack.release();
660
661 mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate, chan nelConfig,
662 AudioFormat.ENCODING_PCM_16BIT, bufferSize, AudioTrack.MODE_STRE AM);
663 if (mAudioTrack.getState() == AudioTrack.STATE_UNINITIALIZED) {
664 Log.e(TAG, "Cannot create AudioTrack");
665 mAudioTrack = null;
666 return false;
667 }
668 return true;
669 }
670
671 /**
672 * Play the audio buffer that is passed in.
673 *
674 * @param buf Audio buffer to be rendered.
675 * @param postpone If true, save audio buffer for playback with the next
676 * audio buffer. Must be followed by playOutputBuffer() without postpone,
677 * flush() or release().
678 * @return The number of frames that have already been consumed by the
679 * hardware. This number resets to 0 after each flush call.
680 */
681 @CalledByNative
682 private long playOutputBuffer(byte[] buf, boolean postpone) {
683 if (mAudioTrack == null) {
684 return 0;
685 }
686
687 if (postpone) {
688 assert mPendingAudioBuffer == null;
689 mPendingAudioBuffer = buf;
690 return 0;
691 }
692
693 if (AudioTrack.PLAYSTATE_PLAYING != mAudioTrack.getPlayState()) {
694 mAudioTrack.play();
695 }
696
697 int size = 0;
698 if (mPendingAudioBuffer != null) {
699 size = mAudioTrack.write(mPendingAudioBuffer, 0, mPendingAudioBuffer .length);
700 if (mPendingAudioBuffer.length != size) {
701 Log.i(TAG, "Failed to send all data to audio output, expected si ze: "
702 + mPendingAudioBuffer.length + ", actual size: " + size);
703 }
704 mPendingAudioBuffer = null;
705 }
706
707 size = mAudioTrack.write(buf, 0, buf.length);
708 if (buf.length != size) {
709 Log.i(TAG, "Failed to send all data to audio output, expected size: "
710 + buf.length + ", actual size: " + size);
711 }
712 // TODO(qinmin): Returning the head position allows us to estimate
713 // the current presentation time in native code. However, it is
714 // better to use AudioTrack.getCurrentTimestamp() to get the last
715 // known time when a frame is played. However, we will need to
716 // convert the java nano time to C++ timestamp.
717 // If the stream runs too long, getPlaybackHeadPosition() could
718 // overflow. AudioTimestampHelper in MediaSourcePlayer has the same
719 // issue. See http://crbug.com/358801.
720
721 // The method AudioTrack.getPlaybackHeadPosition() returns int that shou ld be
722 // interpreted as unsigned 32 bit value. Convert the return value of
723 // getPlaybackHeadPosition() into unsigned int using the long mask.
724 return 0xFFFFFFFFL & mAudioTrack.getPlaybackHeadPosition();
725 }
726
727 @SuppressWarnings("deprecation")
728 @CalledByNative
729 private void setVolume(double volume) {
730 if (mAudioTrack != null) {
731 mAudioTrack.setStereoVolume((float) volume, (float) volume);
732 }
733 }
734
735 private void resetLastPresentationTimeIfNeeded(long presentationTimeUs) { 605 private void resetLastPresentationTimeIfNeeded(long presentationTimeUs) {
736 if (mFlushed) { 606 if (mFlushed) {
737 mLastPresentationTimeUs = 607 mLastPresentationTimeUs =
738 Math.max(presentationTimeUs - MAX_PRESENTATION_TIMESTAMP_SHI FT_US, 0); 608 Math.max(presentationTimeUs - MAX_PRESENTATION_TIMESTAMP_SHI FT_US, 0);
739 mFlushed = false; 609 mFlushed = false;
740 } 610 }
741 } 611 }
742 612
743 @SuppressWarnings("deprecation") 613 @SuppressWarnings("deprecation")
744 private int getAudioFormat(int channelCount) { 614 private int getAudioFormat(int channelCount) {
(...skipping 10 matching lines...) Expand all
755 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 625 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
756 return AudioFormat.CHANNEL_OUT_7POINT1_SURROUND; 626 return AudioFormat.CHANNEL_OUT_7POINT1_SURROUND;
757 } else { 627 } else {
758 return AudioFormat.CHANNEL_OUT_7POINT1; 628 return AudioFormat.CHANNEL_OUT_7POINT1;
759 } 629 }
760 default: 630 default:
761 return AudioFormat.CHANNEL_OUT_DEFAULT; 631 return AudioFormat.CHANNEL_OUT_DEFAULT;
762 } 632 }
763 } 633 }
764 } 634 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698