1a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// found in the LICENSE file.
490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)package org.chromium.media;
690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)import android.media.AudioFormat;
890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)import android.media.AudioManager;
990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)import android.media.AudioTrack;
1090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)import android.media.MediaCodec;
1158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)import android.media.MediaCodecInfo;
1258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)import android.media.MediaCodecList;
1390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)import android.media.MediaCrypto;
1490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)import android.media.MediaFormat;
15f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import android.os.Build;
16a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)import android.os.Bundle;
1790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)import android.util.Log;
18f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import android.view.Surface;
1990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
20a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)import org.chromium.base.CalledByNative;
21a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)import org.chromium.base.JNINamespace;
22a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
2390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)import java.nio.ByteBuffer;
2458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)import java.util.ArrayList;
2558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)import java.util.HashMap;
2658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)import java.util.Map;
2790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
2890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)/**
2990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) * A wrapper of the MediaCodec class to facilitate exception capturing and
3090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) * audio rendering.
3190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) */
3290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)@JNINamespace("media")
3390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)class MediaCodecBridge {
3490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    private static final String TAG = "MediaCodecBridge";
3590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
36868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // Error code for MediaCodecBridge. Keep this value in sync with
3758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // MediaCodecStatus in media_codec_bridge.h.
3858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    private static final int MEDIA_CODEC_OK = 0;
3958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    private static final int MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER = 1;
4058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    private static final int MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER = 2;
4158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    private static final int MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED = 3;
4258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    private static final int MEDIA_CODEC_OUTPUT_FORMAT_CHANGED = 4;
4358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    private static final int MEDIA_CODEC_INPUT_END_OF_STREAM = 5;
4458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    private static final int MEDIA_CODEC_OUTPUT_END_OF_STREAM = 6;
4558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    private static final int MEDIA_CODEC_NO_KEY = 7;
4658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    private static final int MEDIA_CODEC_STOPPED = 8;
4758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    private static final int MEDIA_CODEC_ERROR = 9;
48868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
49a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // Codec direction.  Keep this in sync with media_codec_bridge.h.
50a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    private static final int MEDIA_CODEC_DECODER = 0;
51a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    private static final int MEDIA_CODEC_ENCODER = 1;
52a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
53f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    // Max adaptive playback size to be supplied to the decoder.
54f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    private static final int MAX_ADAPTIVE_PLAYBACK_WIDTH = 1920;
55f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    private static final int MAX_ADAPTIVE_PLAYBACK_HEIGHT = 1080;
56f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
57ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    // After a flush(), dequeueOutputBuffer() can often produce empty presentation timestamps
58ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    // for several frames. As a result, the player may find that the time does not increase
59ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    // after decoding a frame. To detect this, we check whether the presentation timestamp from
60ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    // dequeueOutputBuffer() is larger than input_timestamp - MAX_PRESENTATION_TIMESTAMP_SHIFT_US
61ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    // after a flush. And we set the presentation timestamp from dequeueOutputBuffer() to be
62ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    // non-decreasing for the remaining frames.
63ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    private static final long MAX_PRESENTATION_TIMESTAMP_SHIFT_US = 100000;
64ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
6590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    private ByteBuffer[] mInputBuffers;
6690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    private ByteBuffer[] mOutputBuffers;
6790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
6890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    private MediaCodec mMediaCodec;
6990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    private AudioTrack mAudioTrack;
70ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    private boolean mFlushed;
71ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    private long mLastPresentationTimeUs;
72f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    private String mMime;
73f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    private boolean mAdaptivePlaybackSupported;
7490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
7558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    private static class DequeueInputResult {
7658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        private final int mStatus;
7758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        private final int mIndex;
7858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
7958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        private DequeueInputResult(int status, int index) {
8058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            mStatus = status;
8158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            mIndex = index;
8258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        }
8358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
8458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        @CalledByNative("DequeueInputResult")
8558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        private int status() { return mStatus; }
8658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
8758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        @CalledByNative("DequeueInputResult")
8858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        private int index() { return mIndex; }
8958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    }
9058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
9158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    /**
9258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)     * This class represents supported android codec information.
9358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)     */
9458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    private static class CodecInfo {
951e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        private final String mCodecType;  // e.g. "video/x-vnd.on2.vp8".
961e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        private final String mCodecName;  // e.g. "OMX.google.vp8.decoder".
97a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        private final int mDirection;
9858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
99a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        private CodecInfo(String codecType, String codecName,
100a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                          int direction) {
10158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            mCodecType = codecType;
1021e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)            mCodecName = codecName;
103a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            mDirection = direction;
10458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        }
10558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
10658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        @CalledByNative("CodecInfo")
10758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        private String codecType() { return mCodecType; }
10858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
10958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        @CalledByNative("CodecInfo")
1101e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        private String codecName() { return mCodecName; }
111a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
112a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        @CalledByNative("CodecInfo")
113a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        private int direction() { return mDirection; }
11458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    }
11558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
11690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    private static class DequeueOutputResult {
11758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        private final int mStatus;
11890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        private final int mIndex;
11990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        private final int mFlags;
12090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        private final int mOffset;
12190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        private final long mPresentationTimeMicroseconds;
12290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        private final int mNumBytes;
12390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
12458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        private DequeueOutputResult(int status, int index, int flags, int offset,
125868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                long presentationTimeMicroseconds, int numBytes) {
12658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            mStatus = status;
12790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            mIndex = index;
12890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            mFlags = flags;
12990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            mOffset = offset;
13090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            mPresentationTimeMicroseconds = presentationTimeMicroseconds;
13190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            mNumBytes = numBytes;
13290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        }
13390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
13490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        @CalledByNative("DequeueOutputResult")
13558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        private int status() { return mStatus; }
13658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
13758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        @CalledByNative("DequeueOutputResult")
13890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        private int index() { return mIndex; }
13990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
14090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        @CalledByNative("DequeueOutputResult")
14190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        private int flags() { return mFlags; }
14290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
14390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        @CalledByNative("DequeueOutputResult")
14490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        private int offset() { return mOffset; }
14590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
14690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        @CalledByNative("DequeueOutputResult")
14790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        private long presentationTimeMicroseconds() { return mPresentationTimeMicroseconds; }
14890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
14990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        @CalledByNative("DequeueOutputResult")
15090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        private int numBytes() { return mNumBytes; }
15190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
15290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
15358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    /**
15458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)     * Get a list of supported android codec mimes.
15558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)     */
1561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    @SuppressWarnings("deprecation")
15758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    @CalledByNative
15858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    private static CodecInfo[] getCodecsInfo() {
159a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        // Return the first (highest-priority) codec for each MIME type.
160a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        Map<String, CodecInfo> encoderInfoMap = new HashMap<String, CodecInfo>();
161a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        Map<String, CodecInfo> decoderInfoMap = new HashMap<String, CodecInfo>();
16258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        int count = MediaCodecList.getCodecCount();
16358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        for (int i = 0; i < count; ++i) {
16458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            MediaCodecInfo info = MediaCodecList.getCodecInfoAt(i);
165a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            int direction =
166a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                info.isEncoder() ? MEDIA_CODEC_ENCODER : MEDIA_CODEC_DECODER;
16758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            String codecString = info.getName();
168f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            String[] supportedTypes = info.getSupportedTypes();
16958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            for (int j = 0; j < supportedTypes.length; ++j) {
170a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                Map<String, CodecInfo> map = info.isEncoder() ? encoderInfoMap : decoderInfoMap;
171a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                if (!map.containsKey(supportedTypes[j])) {
172a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                    map.put(supportedTypes[j], new CodecInfo(
173a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                        supportedTypes[j], codecString, direction));
17458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                }
17558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            }
17658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        }
177a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        ArrayList<CodecInfo> codecInfos = new ArrayList<CodecInfo>(
178a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            decoderInfoMap.size() + encoderInfoMap.size());
179a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        codecInfos.addAll(encoderInfoMap.values());
180a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        codecInfos.addAll(decoderInfoMap.values());
181a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        return codecInfos.toArray(new CodecInfo[codecInfos.size()]);
18258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    }
18358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
1841675a649fd7a8b3cb80ffddae2dc181f122353c5Ben Murdoch    /**
1851675a649fd7a8b3cb80ffddae2dc181f122353c5Ben Murdoch     * Get a name of default android codec.
1861675a649fd7a8b3cb80ffddae2dc181f122353c5Ben Murdoch     */
1871675a649fd7a8b3cb80ffddae2dc181f122353c5Ben Murdoch    @SuppressWarnings("deprecation")
1881675a649fd7a8b3cb80ffddae2dc181f122353c5Ben Murdoch    @CalledByNative
1891675a649fd7a8b3cb80ffddae2dc181f122353c5Ben Murdoch    private static String getDefaultCodecName(String mime, int direction) {
1901675a649fd7a8b3cb80ffddae2dc181f122353c5Ben Murdoch        String codecName = "";
1911675a649fd7a8b3cb80ffddae2dc181f122353c5Ben Murdoch        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
1921675a649fd7a8b3cb80ffddae2dc181f122353c5Ben Murdoch            try {
1931675a649fd7a8b3cb80ffddae2dc181f122353c5Ben Murdoch                MediaCodec mediaCodec = null;
1941675a649fd7a8b3cb80ffddae2dc181f122353c5Ben Murdoch                if (direction == MEDIA_CODEC_ENCODER) {
1951675a649fd7a8b3cb80ffddae2dc181f122353c5Ben Murdoch                    mediaCodec = MediaCodec.createEncoderByType(mime);
1961675a649fd7a8b3cb80ffddae2dc181f122353c5Ben Murdoch                } else {
1971675a649fd7a8b3cb80ffddae2dc181f122353c5Ben Murdoch                    mediaCodec = MediaCodec.createDecoderByType(mime);
1981675a649fd7a8b3cb80ffddae2dc181f122353c5Ben Murdoch                }
1991675a649fd7a8b3cb80ffddae2dc181f122353c5Ben Murdoch                codecName = mediaCodec.getName();
2001675a649fd7a8b3cb80ffddae2dc181f122353c5Ben Murdoch                mediaCodec.release();
2011675a649fd7a8b3cb80ffddae2dc181f122353c5Ben Murdoch            } catch (Exception e) {
2021675a649fd7a8b3cb80ffddae2dc181f122353c5Ben Murdoch                Log.w(TAG, "getDefaultCodecName: Failed to create MediaCodec: " +
2031675a649fd7a8b3cb80ffddae2dc181f122353c5Ben Murdoch                        mime + ", direction: " + direction, e);
2041675a649fd7a8b3cb80ffddae2dc181f122353c5Ben Murdoch            }
2051675a649fd7a8b3cb80ffddae2dc181f122353c5Ben Murdoch        }
2061675a649fd7a8b3cb80ffddae2dc181f122353c5Ben Murdoch        return codecName;
2071675a649fd7a8b3cb80ffddae2dc181f122353c5Ben Murdoch    }
2081675a649fd7a8b3cb80ffddae2dc181f122353c5Ben Murdoch
2091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    @SuppressWarnings("deprecation")
210f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    private static String getDecoderNameForMime(String mime) {
21158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        int count = MediaCodecList.getCodecCount();
21258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        for (int i = 0; i < count; ++i) {
21358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            MediaCodecInfo info = MediaCodecList.getCodecInfoAt(i);
21458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            if (info.isEncoder()) {
21558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                continue;
21658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            }
21758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
21858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            String[] supportedTypes = info.getSupportedTypes();
21958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            for (int j = 0; j < supportedTypes.length; ++j) {
22058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                if (supportedTypes[j].equalsIgnoreCase(mime)) {
221f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                    return info.getName();
22258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                }
22358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            }
22458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        }
22558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
22658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        return null;
22758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    }
22858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
229f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    private MediaCodecBridge(
230f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)            MediaCodec mediaCodec, String mime, boolean adaptivePlaybackSupported) {
231a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        assert mediaCodec != null;
23258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        mMediaCodec = mediaCodec;
233f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        mMime = mime;
234ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        mLastPresentationTimeUs = 0;
235ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        mFlushed = true;
236f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        mAdaptivePlaybackSupported = adaptivePlaybackSupported;
23790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
23890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
23990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    @CalledByNative
240a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    private static MediaCodecBridge create(String mime, boolean isSecure, int direction) {
241f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        // Creation of ".secure" codecs sometimes crash instead of throwing exceptions
242f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        // on pre-JBMR2 devices.
243f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        if (isSecure && Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
244f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            return null;
245f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        }
24658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        MediaCodec mediaCodec = null;
247f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        boolean adaptivePlaybackSupported = false;
2483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        try {
24958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            // |isSecure| only applies to video decoders.
250a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            if (mime.startsWith("video") && isSecure && direction == MEDIA_CODEC_DECODER) {
251f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                String decoderName = getDecoderNameForMime(mime);
252f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                if (decoderName == null) {
253f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                    return null;
254f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                }
255f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
256f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                    // To work around an issue that we cannot get the codec info from the secure
257f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                    // decoder, create an insecure decoder first so that we can query its codec
258f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                    // info. http://b/15587335.
259f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                    MediaCodec insecureCodec = MediaCodec.createByCodecName(decoderName);
260f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                    adaptivePlaybackSupported = codecSupportsAdaptivePlayback(insecureCodec, mime);
261f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                    insecureCodec.release();
262f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                }
263f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                mediaCodec = MediaCodec.createByCodecName(decoderName + ".secure");
26458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            } else {
265a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                if (direction == MEDIA_CODEC_ENCODER) {
266a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                    mediaCodec = MediaCodec.createEncoderByType(mime);
267a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                } else {
268a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                    mediaCodec = MediaCodec.createDecoderByType(mime);
269f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                    adaptivePlaybackSupported = codecSupportsAdaptivePlayback(mediaCodec, mime);
270a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                }
27158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            }
27258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        } catch (Exception e) {
27358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            Log.e(TAG, "Failed to create MediaCodec: " +  mime + ", isSecure: "
274a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                    + isSecure + ", direction: " + direction, e);
27558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        }
27658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
27758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        if (mediaCodec == null) {
27858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            return null;
2793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        }
280f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        return new MediaCodecBridge(mediaCodec, mime, adaptivePlaybackSupported);
28190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
28290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
28390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    @CalledByNative
28490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    private void release() {
285c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        try {
286c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch            mMediaCodec.release();
287f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        } catch (IllegalStateException e) {
288c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch            // The MediaCodec is stuck in a wrong state, possibly due to losing
289c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch            // the surface.
290c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch            Log.e(TAG, "Cannot release media codec", e);
291c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        }
292a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        mMediaCodec = null;
29390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        if (mAudioTrack != null) {
29490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            mAudioTrack.release();
29590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        }
29690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
29790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
2981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    @SuppressWarnings("deprecation")
29990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    @CalledByNative
3004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    private boolean start() {
3014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        try {
3024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)            mMediaCodec.start();
3034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)            mInputBuffers = mMediaCodec.getInputBuffers();
3044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        } catch (IllegalStateException e) {
305a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            Log.e(TAG, "Cannot start the media codec", e);
3064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)            return false;
3074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        }
3084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        return true;
30990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
31090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
31190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    @CalledByNative
31258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    private DequeueInputResult dequeueInputBuffer(long timeoutUs) {
31358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        int status = MEDIA_CODEC_ERROR;
31458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        int index = -1;
315868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        try {
316a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            int indexOrStatus = mMediaCodec.dequeueInputBuffer(timeoutUs);
317a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            if (indexOrStatus >= 0) { // index!
31858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                status = MEDIA_CODEC_OK;
319a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                index = indexOrStatus;
320a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            } else if (indexOrStatus == MediaCodec.INFO_TRY_AGAIN_LATER) {
32158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                Log.e(TAG, "dequeueInputBuffer: MediaCodec.INFO_TRY_AGAIN_LATER");
32258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                status = MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER;
32358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            } else {
324a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                Log.e(TAG, "Unexpected index_or_status: " + indexOrStatus);
325a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                assert false;
32658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            }
327a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        } catch (Exception e) {
328a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            Log.e(TAG, "Failed to dequeue input buffer", e);
329868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        }
33058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        return new DequeueInputResult(status, index);
33190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
33290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
33390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    @CalledByNative
33458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    private int flush() {
33558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        try {
33658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            mFlushed = true;
33758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            if (mAudioTrack != null) {
3380529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                // Need to call pause() here, or otherwise flush() is a no-op.
3390529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                mAudioTrack.pause();
34058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                mAudioTrack.flush();
34158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            }
34258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            mMediaCodec.flush();
343a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        } catch (IllegalStateException e) {
344a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            Log.e(TAG, "Failed to flush MediaCodec", e);
34558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            return MEDIA_CODEC_ERROR;
34690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        }
34758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        return MEDIA_CODEC_OK;
34890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
34990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
35090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    @CalledByNative
35190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    private void stop() {
35290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        mMediaCodec.stop();
35390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        if (mAudioTrack != null) {
35490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            mAudioTrack.pause();
35590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        }
35690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
35790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
35890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    @CalledByNative
35990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    private int getOutputHeight() {
36090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        return mMediaCodec.getOutputFormat().getInteger(MediaFormat.KEY_HEIGHT);
36190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
36290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
36390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    @CalledByNative
36490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    private int getOutputWidth() {
36590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        return mMediaCodec.getOutputFormat().getInteger(MediaFormat.KEY_WIDTH);
36690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
36790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
36890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    @CalledByNative
36990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    private ByteBuffer getInputBuffer(int index) {
37090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        return mInputBuffers[index];
37190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
37290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
37390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    @CalledByNative
37490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    private ByteBuffer getOutputBuffer(int index) {
37590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        return mOutputBuffers[index];
37690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
37790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
37890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    @CalledByNative
379a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    private int getInputBuffersCount() {
380a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        return mInputBuffers.length;
381a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    }
382a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
383a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    @CalledByNative
384a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    private int getOutputBuffersCount() {
385a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        return mOutputBuffers != null ? mOutputBuffers.length : -1;
386a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    }
387a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
388a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    @CalledByNative
389a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    private int getOutputBuffersCapacity() {
390a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        return mOutputBuffers != null ? mOutputBuffers[0].capacity() : -1;
391a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    }
392a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
3931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    @SuppressWarnings("deprecation")
394a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    @CalledByNative
395a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    private boolean getOutputBuffers() {
396a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        try {
397a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            mOutputBuffers = mMediaCodec.getOutputBuffers();
398a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        } catch (IllegalStateException e) {
399a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            Log.e(TAG, "Cannot get output buffers", e);
400a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            return false;
401a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        }
402a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        return true;
403a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    }
404a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
405a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    @CalledByNative
40658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    private int queueInputBuffer(
40790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            int index, int offset, int size, long presentationTimeUs, int flags) {
408ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        resetLastPresentationTimeIfNeeded(presentationTimeUs);
409eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        try {
410eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch            mMediaCodec.queueInputBuffer(index, offset, size, presentationTimeUs, flags);
411a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        } catch (Exception e) {
412a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            Log.e(TAG, "Failed to queue input buffer", e);
41358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            return MEDIA_CODEC_ERROR;
414eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        }
41558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        return MEDIA_CODEC_OK;
416eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    }
417eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
418eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    @CalledByNative
419a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    private void setVideoBitrate(int bps) {
420a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        Bundle b = new Bundle();
421a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        b.putInt(MediaCodec.PARAMETER_KEY_VIDEO_BITRATE, bps);
422a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        mMediaCodec.setParameters(b);
423a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    }
424a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
425a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    @CalledByNative
426a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    private void requestKeyFrameSoon() {
427a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        Bundle b = new Bundle();
428a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        b.putInt(MediaCodec.PARAMETER_KEY_REQUEST_SYNC_FRAME, 0);
429a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        mMediaCodec.setParameters(b);
430a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    }
431a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
432a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    @CalledByNative
43358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    private int queueSecureInputBuffer(
434eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch            int index, int offset, byte[] iv, byte[] keyId, int[] numBytesOfClearData,
435eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch            int[] numBytesOfEncryptedData, int numSubSamples, long presentationTimeUs) {
436ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        resetLastPresentationTimeIfNeeded(presentationTimeUs);
437eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        try {
438eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch            MediaCodec.CryptoInfo cryptoInfo = new MediaCodec.CryptoInfo();
439eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch            cryptoInfo.set(numSubSamples, numBytesOfClearData, numBytesOfEncryptedData,
440eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                    keyId, iv, MediaCodec.CRYPTO_MODE_AES_CTR);
441eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch            mMediaCodec.queueSecureInputBuffer(index, offset, cryptoInfo, presentationTimeUs, 0);
44258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        } catch (MediaCodec.CryptoException e) {
443a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            Log.e(TAG, "Failed to queue secure input buffer", e);
444f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            if (e.getErrorCode() == MediaCodec.CryptoException.ERROR_NO_KEY) {
445f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                Log.e(TAG, "MediaCodec.CryptoException.ERROR_NO_KEY");
44658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                return MEDIA_CODEC_NO_KEY;
44758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            }
448f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            Log.e(TAG, "MediaCodec.CryptoException with error code " + e.getErrorCode());
44958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            return MEDIA_CODEC_ERROR;
450a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        } catch (IllegalStateException e) {
451a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            Log.e(TAG, "Failed to queue secure input buffer", e);
45258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            return MEDIA_CODEC_ERROR;
453eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        }
45458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        return MEDIA_CODEC_OK;
45590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
45690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
45790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    @CalledByNative
45890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    private void releaseOutputBuffer(int index, boolean render) {
459effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        try {
460effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch            mMediaCodec.releaseOutputBuffer(index, render);
461f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        } catch (IllegalStateException e) {
462effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch            // TODO(qinmin): May need to report the error to the caller. crbug.com/356498.
463effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch            Log.e(TAG, "Failed to release output buffer", e);
464effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        }
46590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
46690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
4671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    @SuppressWarnings("deprecation")
46890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    @CalledByNative
46990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    private DequeueOutputResult dequeueOutputBuffer(long timeoutUs) {
47090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
47158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        int status = MEDIA_CODEC_ERROR;
47258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        int index = -1;
473868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        try {
474a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            int indexOrStatus = mMediaCodec.dequeueOutputBuffer(info, timeoutUs);
475ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch            if (info.presentationTimeUs < mLastPresentationTimeUs) {
476ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                // TODO(qinmin): return a special code through DequeueOutputResult
477ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                // to notify the native code the the frame has a wrong presentation
478ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                // timestamp and should be skipped.
479ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                info.presentationTimeUs = mLastPresentationTimeUs;
480ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch            }
481ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch            mLastPresentationTimeUs = info.presentationTimeUs;
48258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
483a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            if (indexOrStatus >= 0) { // index!
48458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                status = MEDIA_CODEC_OK;
485a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                index = indexOrStatus;
486a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            } else if (indexOrStatus == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
48758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                status = MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED;
488a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            } else if (indexOrStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
48958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                status = MEDIA_CODEC_OUTPUT_FORMAT_CHANGED;
490a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            } else if (indexOrStatus == MediaCodec.INFO_TRY_AGAIN_LATER) {
49158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                status = MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER;
49258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            } else {
493a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                Log.e(TAG, "Unexpected index_or_status: " + indexOrStatus);
494a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                assert false;
49558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            }
4967d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        } catch (IllegalStateException e) {
497a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            Log.e(TAG, "Failed to dequeue output buffer", e);
498868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        }
49958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
50090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        return new DequeueOutputResult(
50158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                status, index, info.flags, info.offset, info.presentationTimeUs, info.size);
50290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
50390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
50490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    @CalledByNative
5057d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    private boolean configureVideo(MediaFormat format, Surface surface, MediaCrypto crypto,
50690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            int flags) {
5077d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        try {
508f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)            if (mAdaptivePlaybackSupported) {
509f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                format.setInteger(MediaFormat.KEY_MAX_WIDTH, MAX_ADAPTIVE_PLAYBACK_WIDTH);
510f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                format.setInteger(MediaFormat.KEY_MAX_HEIGHT, MAX_ADAPTIVE_PLAYBACK_HEIGHT);
511f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)            }
5127d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)            mMediaCodec.configure(format, surface, crypto, flags);
5137d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)            return true;
5147d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        } catch (IllegalStateException e) {
515a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            Log.e(TAG, "Cannot configure the video codec", e);
5167d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        }
5177d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        return false;
51890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
51990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
52090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    @CalledByNative
521a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    private static MediaFormat createAudioFormat(String mime, int sampleRate, int channelCount) {
522a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        return MediaFormat.createAudioFormat(mime, sampleRate, channelCount);
52390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
52490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
52590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    @CalledByNative
526a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    private static MediaFormat createVideoDecoderFormat(String mime, int width, int height) {
52790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        return MediaFormat.createVideoFormat(mime, width, height);
52890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
52990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
53090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    @CalledByNative
531a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    private static MediaFormat createVideoEncoderFormat(String mime, int width, int height,
532a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            int bitRate, int frameRate, int iFrameInterval, int colorFormat) {
533a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        MediaFormat format = MediaFormat.createVideoFormat(mime, width, height);
534a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        format.setInteger(MediaFormat.KEY_BIT_RATE, bitRate);
535a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        format.setInteger(MediaFormat.KEY_FRAME_RATE, frameRate);
536a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, iFrameInterval);
537a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        format.setInteger(MediaFormat.KEY_COLOR_FORMAT, colorFormat);
538a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        return format;
539a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    }
540a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
541a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    @CalledByNative
542f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    private boolean isAdaptivePlaybackSupported(int width, int height) {
543f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        if (!mAdaptivePlaybackSupported)
544f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)            return false;
545f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        return width <= MAX_ADAPTIVE_PLAYBACK_WIDTH && height <= MAX_ADAPTIVE_PLAYBACK_HEIGHT;
546f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    }
547f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
548f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    private static boolean codecSupportsAdaptivePlayback(MediaCodec mediaCodec, String mime) {
549f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT || mediaCodec == null) {
550f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)            return false;
551f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        }
552f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        try {
553f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)            MediaCodecInfo info = mediaCodec.getCodecInfo();
554f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)            if (info.isEncoder()) {
555f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                return false;
556f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)            }
557f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)            MediaCodecInfo.CodecCapabilities capabilities = info.getCapabilitiesForType(mime);
558f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)            return (capabilities != null) && capabilities.isFeatureSupported(
559f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                    MediaCodecInfo.CodecCapabilities.FEATURE_AdaptivePlayback);
560f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        } catch (IllegalArgumentException e) {
561f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)              Log.e(TAG, "Cannot retrieve codec information", e);
562f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        }
563f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        return false;
564f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    }
565f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
566f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    @CalledByNative
567d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    private static void setCodecSpecificData(MediaFormat format, int index, byte[] bytes) {
56890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        String name = null;
56990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        if (index == 0) {
57090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            name = "csd-0";
57190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        } else if (index == 1) {
57290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            name = "csd-1";
57390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        }
57490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        if (name != null) {
575d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)            format.setByteBuffer(name, ByteBuffer.wrap(bytes));
57690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        }
57790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
57890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
57990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    @CalledByNative
580868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    private static void setFrameHasADTSHeader(MediaFormat format) {
581868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        format.setInteger(MediaFormat.KEY_IS_ADTS, 1);
582868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    }
583868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
584868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    @CalledByNative
5857d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    private boolean configureAudio(MediaFormat format, MediaCrypto crypto, int flags,
58690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            boolean playAudio) {
5877d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        try {
5887d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)            mMediaCodec.configure(format, null, crypto, flags);
5897d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)            if (playAudio) {
5907d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                int sampleRate = format.getInteger(MediaFormat.KEY_SAMPLE_RATE);
5917d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                int channelCount = format.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
5925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                int channelConfig = getAudioFormat(channelCount);
593eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                // Using 16bit PCM for output. Keep this value in sync with
594eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                // kBytesPerAudioOutputSample in media_codec_bridge.cc.
5957d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                int minBufferSize = AudioTrack.getMinBufferSize(sampleRate, channelConfig,
5967d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                        AudioFormat.ENCODING_PCM_16BIT);
5977d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate, channelConfig,
5987d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                        AudioFormat.ENCODING_PCM_16BIT, minBufferSize, AudioTrack.MODE_STREAM);
5995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                if (mAudioTrack.getState() == AudioTrack.STATE_UNINITIALIZED) {
6005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    mAudioTrack = null;
6015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    return false;
6025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                }
6037d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)            }
6047d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)            return true;
6057d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        } catch (IllegalStateException e) {
606a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            Log.e(TAG, "Cannot configure the audio codec", e);
60790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        }
6087d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        return false;
60990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
61090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
6110529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    /**
6120529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch     *  Play the audio buffer that is passed in.
6130529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch     *
6140529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch     *  @param buf Audio buffer to be rendered.
6150529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch     *  @return The number of frames that have already been consumed by the
6160529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch     *  hardware. This number resets to 0 after each flush call.
6170529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch     */
61890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    @CalledByNative
6190529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    private long playOutputBuffer(byte[] buf) {
6200529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        if (mAudioTrack == null) {
6210529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch            return 0;
6220529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        }
6230529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
6240529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        if (AudioTrack.PLAYSTATE_PLAYING != mAudioTrack.getPlayState()) {
6250529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch            mAudioTrack.play();
6260529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        }
6270529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        int size = mAudioTrack.write(buf, 0, buf.length);
6280529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        if (buf.length != size) {
6290529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch            Log.i(TAG, "Failed to send all data to audio output, expected size: " +
6300529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                    buf.length + ", actual size: " + size);
63190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        }
6320529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        // TODO(qinmin): Returning the head position allows us to estimate
6330529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        // the current presentation time in native code. However, it is
6340529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        // better to use AudioTrack.getCurrentTimestamp() to get the last
6350529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        // known time when a frame is played. However, we will need to
6360529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        // convert the java nano time to C++ timestamp.
6370529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        // If the stream runs too long, getPlaybackHeadPosition() could
6380529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        // overflow. AudioTimestampHelper in MediaSourcePlayer has the same
6390529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        // issue. See http://crbug.com/358801.
6400529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        return mAudioTrack.getPlaybackHeadPosition();
64190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
642ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
6431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    @SuppressWarnings("deprecation")
644a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    @CalledByNative
645a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    private void setVolume(double volume) {
646a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        if (mAudioTrack != null) {
647a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)            mAudioTrack.setStereoVolume((float) volume, (float) volume);
648a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        }
649a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    }
650a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
651ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    private void resetLastPresentationTimeIfNeeded(long presentationTimeUs) {
652ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        if (mFlushed) {
653ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch            mLastPresentationTimeUs =
654ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                    Math.max(presentationTimeUs - MAX_PRESENTATION_TIMESTAMP_SHIFT_US, 0);
655ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch            mFlushed = false;
656ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        }
657ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    }
6585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    private int getAudioFormat(int channelCount) {
6605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        switch (channelCount) {
6615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            case 1:
6625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                return AudioFormat.CHANNEL_OUT_MONO;
6635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            case 2:
6645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                return AudioFormat.CHANNEL_OUT_STEREO;
6655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            case 4:
6665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                return AudioFormat.CHANNEL_OUT_QUAD;
6675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            case 6:
6685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                return AudioFormat.CHANNEL_OUT_5POINT1;
6695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            case 8:
6705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                return AudioFormat.CHANNEL_OUT_7POINT1;
6715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            default:
6725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                return AudioFormat.CHANNEL_OUT_DEFAULT;
6735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        }
6745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
67590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
676