| Index: media/base/android/java/src/org/chromium/media/MediaCodecBridge.java
|
| diff --git a/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java b/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java
|
| index 42f1241380c04c4635acb4886f5e60c9ad3ba85d..7025a1de6f19aa14461866e6d101bcf69827908f 100644
|
| --- a/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java
|
| +++ b/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java
|
| @@ -27,12 +27,20 @@ import org.chromium.base.JNINamespace;
|
| */
|
| @JNINamespace("media")
|
| class MediaCodecBridge {
|
| -
|
| private static final String TAG = "MediaCodecBridge";
|
|
|
| // Error code for MediaCodecBridge. Keep this value in sync with
|
| - // INFO_MEDIA_CODEC_ERROR in media_codec_bridge.h.
|
| - private static final int MEDIA_CODEC_ERROR = -1000;
|
| + // MediaCodecStatus in media_codec_bridge.h.
|
| + private static final int MEDIA_CODEC_OK = 0;
|
| + private static final int MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER = 1;
|
| + private static final int MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER = 2;
|
| + private static final int MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED = 3;
|
| + private static final int MEDIA_CODEC_OUTPUT_FORMAT_CHANGED = 4;
|
| + private static final int MEDIA_CODEC_INPUT_END_OF_STREAM = 5;
|
| + private static final int MEDIA_CODEC_OUTPUT_END_OF_STREAM = 6;
|
| + private static final int MEDIA_CODEC_NO_KEY = 7;
|
| + private static final int MEDIA_CODEC_STOPPED = 8;
|
| + private static final int MEDIA_CODEC_ERROR = 9;
|
|
|
| // After a flush(), dequeueOutputBuffer() can often produce empty presentation timestamps
|
| // for several frames. As a result, the player may find that the time does not increase
|
| @@ -50,15 +58,33 @@ class MediaCodecBridge {
|
| private boolean mFlushed;
|
| private long mLastPresentationTimeUs;
|
|
|
| + private static class DequeueInputResult {
|
| + private final int mStatus;
|
| + private final int mIndex;
|
| +
|
| + private DequeueInputResult(int status, int index) {
|
| + mStatus = status;
|
| + mIndex = index;
|
| + }
|
| +
|
| + @CalledByNative("DequeueInputResult")
|
| + private int status() { return mStatus; }
|
| +
|
| + @CalledByNative("DequeueInputResult")
|
| + private int index() { return mIndex; }
|
| + }
|
| +
|
| private static class DequeueOutputResult {
|
| + private final int mStatus;
|
| private final int mIndex;
|
| private final int mFlags;
|
| private final int mOffset;
|
| private final long mPresentationTimeMicroseconds;
|
| private final int mNumBytes;
|
|
|
| - private DequeueOutputResult(int index, int flags, int offset,
|
| + private DequeueOutputResult(int status, int index, int flags, int offset,
|
| long presentationTimeMicroseconds, int numBytes) {
|
| + mStatus = status;
|
| mIndex = index;
|
| mFlags = flags;
|
| mOffset = offset;
|
| @@ -67,6 +93,9 @@ class MediaCodecBridge {
|
| }
|
|
|
| @CalledByNative("DequeueOutputResult")
|
| + private int status() { return mStatus; }
|
| +
|
| + @CalledByNative("DequeueOutputResult")
|
| private int index() { return mIndex; }
|
|
|
| @CalledByNative("DequeueOutputResult")
|
| @@ -143,13 +172,24 @@ class MediaCodecBridge {
|
| }
|
|
|
| @CalledByNative
|
| - private int dequeueInputBuffer(long timeoutUs) {
|
| + private DequeueInputResult dequeueInputBuffer(long timeoutUs) {
|
| + int status = MEDIA_CODEC_ERROR;
|
| + int index = -1;
|
| try {
|
| - return mMediaCodec.dequeueInputBuffer(timeoutUs);
|
| + int index_or_status = mMediaCodec.dequeueInputBuffer(timeoutUs);
|
| + if (index_or_status >= 0) { // index!
|
| + status = MEDIA_CODEC_OK;
|
| + index = index_or_status;
|
| + } else if (index_or_status == MediaCodec.INFO_TRY_AGAIN_LATER) {
|
| + Log.e(TAG, "dequeueInputBuffer: MediaCodec.INFO_TRY_AGAIN_LATER");
|
| + status = MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER;
|
| + } else {
|
| + assert(false);
|
| + }
|
| } catch(Exception e) {
|
| - Log.e(TAG, "Cannot dequeue Input buffer " + e.toString());
|
| + Log.e(TAG, "Failed to dequeue input buffer: " + e.toString());
|
| }
|
| - return MEDIA_CODEC_ERROR;
|
| + return new DequeueInputResult(status, index);
|
| }
|
|
|
| @CalledByNative
|
| @@ -190,18 +230,20 @@ class MediaCodecBridge {
|
| }
|
|
|
| @CalledByNative
|
| - private void queueInputBuffer(
|
| + private int queueInputBuffer(
|
| int index, int offset, int size, long presentationTimeUs, int flags) {
|
| resetLastPresentationTimeIfNeeded(presentationTimeUs);
|
| try {
|
| mMediaCodec.queueInputBuffer(index, offset, size, presentationTimeUs, flags);
|
| - } catch(IllegalStateException e) {
|
| - Log.e(TAG, "Failed to queue input buffer " + e.toString());
|
| + } catch(Exception e) {
|
| + Log.e(TAG, "Failed to queue input buffer: " + e.toString());
|
| + return MEDIA_CODEC_ERROR;
|
| }
|
| + return MEDIA_CODEC_OK;
|
| }
|
|
|
| @CalledByNative
|
| - private void queueSecureInputBuffer(
|
| + private int queueSecureInputBuffer(
|
| int index, int offset, byte[] iv, byte[] keyId, int[] numBytesOfClearData,
|
| int[] numBytesOfEncryptedData, int numSubSamples, long presentationTimeUs) {
|
| resetLastPresentationTimeIfNeeded(presentationTimeUs);
|
| @@ -210,9 +252,19 @@ class MediaCodecBridge {
|
| cryptoInfo.set(numSubSamples, numBytesOfClearData, numBytesOfEncryptedData,
|
| keyId, iv, MediaCodec.CRYPTO_MODE_AES_CTR);
|
| mMediaCodec.queueSecureInputBuffer(index, offset, cryptoInfo, presentationTimeUs, 0);
|
| + } catch (MediaCodec.CryptoException e) {
|
| + Log.e(TAG, "Failed to queue secure input buffer: " + e.toString());
|
| + // TODO(xhwang): Replace hard coded value with constant/enum.
|
| + if (e.getErrorCode() == 1) {
|
| + Log.e(TAG, "No key available.");
|
| + return MEDIA_CODEC_NO_KEY;
|
| + }
|
| + return MEDIA_CODEC_ERROR;
|
| } catch(IllegalStateException e) {
|
| - Log.e(TAG, "Failed to queue secure input buffer " + e.toString());
|
| + Log.e(TAG, "Failed to queue secure input buffer: " + e.toString());
|
| + return MEDIA_CODEC_ERROR;
|
| }
|
| + return MEDIA_CODEC_OK;
|
| }
|
|
|
| @CalledByNative
|
| @@ -228,9 +280,10 @@ class MediaCodecBridge {
|
| @CalledByNative
|
| private DequeueOutputResult dequeueOutputBuffer(long timeoutUs) {
|
| MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
|
| - int index = MEDIA_CODEC_ERROR;
|
| + int status = MEDIA_CODEC_ERROR;
|
| + int index = -1;
|
| try {
|
| - index = mMediaCodec.dequeueOutputBuffer(info, timeoutUs);
|
| + int index_or_status = mMediaCodec.dequeueOutputBuffer(info, timeoutUs);
|
| if (info.presentationTimeUs < mLastPresentationTimeUs) {
|
| // TODO(qinmin): return a special code through DequeueOutputResult
|
| // to notify the native code the the frame has a wrong presentation
|
| @@ -238,11 +291,25 @@ class MediaCodecBridge {
|
| info.presentationTimeUs = mLastPresentationTimeUs;
|
| }
|
| mLastPresentationTimeUs = info.presentationTimeUs;
|
| +
|
| + if (index_or_status >= 0) { // index!
|
| + status = MEDIA_CODEC_OK;
|
| + index = index_or_status;
|
| + } else if (index_or_status == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
|
| + status = MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED;
|
| + } else if (index_or_status == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
|
| + status = MEDIA_CODEC_OUTPUT_FORMAT_CHANGED;
|
| + } else if (index_or_status == MediaCodec.INFO_TRY_AGAIN_LATER) {
|
| + status = MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER;
|
| + } else {
|
| + assert(false);
|
| + }
|
| } catch (IllegalStateException e) {
|
| - Log.e(TAG, "Cannot dequeue output buffer " + e.toString());
|
| + Log.e(TAG, "Failed to dequeue output buffer: " + e.toString());
|
| }
|
| +
|
| return new DequeueOutputResult(
|
| - index, info.flags, info.offset, info.presentationTimeUs, info.size);
|
| + status, index, info.flags, info.offset, info.presentationTimeUs, info.size);
|
| }
|
|
|
| @CalledByNative
|
|
|