16ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko/*
26ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko * Copyright (C) 2017 The Android Open Source Project
36ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko *
46ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko * Licensed under the Apache License, Version 2.0 (the "License");
56ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko * you may not use this file except in compliance with the License.
66ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko * You may obtain a copy of the License at
76ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko *
86ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko *      http://www.apache.org/licenses/LICENSE-2.0
96ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko *
106ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko * Unless required by applicable law or agreed to in writing, software
116ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko * distributed under the License is distributed on an "AS IS" BASIS,
126ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko * See the License for the specific language governing permissions and
146ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko * limitations under the License.
156ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko */
166ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko
176ebde20b03db4c0d57f67acaac11832b610b966bNick Chalkopackage com.android.tv.tuner.exoplayer.audio;
186ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko
196ebde20b03db4c0d57f67acaac11832b610b966bNick Chalkoimport android.media.MediaCodec;
206ebde20b03db4c0d57f67acaac11832b610b966bNick Chalkoimport android.util.Log;
216ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko
226ebde20b03db4c0d57f67acaac11832b610b966bNick Chalkoimport com.google.android.exoplayer.CodecCounters;
236ebde20b03db4c0d57f67acaac11832b610b966bNick Chalkoimport com.google.android.exoplayer.DecoderInfo;
246ebde20b03db4c0d57f67acaac11832b610b966bNick Chalkoimport com.google.android.exoplayer.ExoPlaybackException;
256ebde20b03db4c0d57f67acaac11832b610b966bNick Chalkoimport com.google.android.exoplayer.MediaCodecSelector;
266ebde20b03db4c0d57f67acaac11832b610b966bNick Chalkoimport com.google.android.exoplayer.MediaCodecUtil;
276ebde20b03db4c0d57f67acaac11832b610b966bNick Chalkoimport com.google.android.exoplayer.MediaFormat;
286ebde20b03db4c0d57f67acaac11832b610b966bNick Chalkoimport com.google.android.exoplayer.SampleHolder;
296ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko
306ebde20b03db4c0d57f67acaac11832b610b966bNick Chalkoimport java.nio.ByteBuffer;
316ebde20b03db4c0d57f67acaac11832b610b966bNick Chalkoimport java.util.ArrayList;
326ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko
336ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko/** A decoder to use MediaCodec for decoding audio stream. */
346ebde20b03db4c0d57f67acaac11832b610b966bNick Chalkopublic class MediaCodecAudioDecoder extends AudioDecoder {
356ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    private static final String TAG = "MediaCodecAudioDecoder";
366ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko
376ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    public static final int INDEX_INVALID = -1;
386ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko
396ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    private final CodecCounters mCodecCounters;
406ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    private final MediaCodecSelector mSelector;
416ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko
426ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    private MediaCodec mCodec;
436ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    private MediaCodec.BufferInfo mOutputBufferInfo;
446ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    private ByteBuffer mMediaCodecOutputBuffer;
456ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    private ArrayList<Long> mDecodeOnlyPresentationTimestamps;
466ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    private boolean mWaitingForFirstSyncFrame;
476ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    private boolean mIsNewIndex;
486ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    private int mInputIndex;
496ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    private int mOutputIndex;
506ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko
516ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    /** Creates a MediaCodec based audio decoder. */
526ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    public MediaCodecAudioDecoder(MediaCodecSelector selector) {
536ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        mSelector = selector;
546ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        mOutputBufferInfo = new MediaCodec.BufferInfo();
556ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        mCodecCounters = new CodecCounters();
566ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        mDecodeOnlyPresentationTimestamps = new ArrayList<>();
576ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    }
586ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko
596ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    /** Returns {@code true} if there is decoder for {@code mimeType}. */
606ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    public static boolean supportMimeType(MediaCodecSelector selector, String mimeType) {
616ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        if (selector == null) {
626ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            return false;
636ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        }
646ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        return getDecoderInfo(selector, mimeType) != null;
656ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    }
666ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko
676ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    private static DecoderInfo getDecoderInfo(MediaCodecSelector selector, String mimeType) {
686ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        try {
696ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            return selector.getDecoderInfo(mimeType, false);
706ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        } catch (MediaCodecUtil.DecoderQueryException e) {
716ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            Log.e(TAG, "Select decoder error:" + e);
726ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            return null;
736ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        }
746ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    }
756ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko
766ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    private boolean shouldInitCodec(MediaFormat format) {
776ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        return format != null && mCodec == null;
786ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    }
796ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko
806ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    @Override
816ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    public void maybeInitDecoder(MediaFormat format) throws ExoPlaybackException {
826ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        if (!shouldInitCodec(format)) {
836ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            return;
846ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        }
856ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko
866ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        String mimeType = format.mimeType;
876ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        DecoderInfo decoderInfo = getDecoderInfo(mSelector, mimeType);
886ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        if (decoderInfo == null) {
896ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            Log.i(TAG, "There is not decoder found for " + mimeType);
906ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            return;
916ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        }
926ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko
936ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        String codecName = decoderInfo.name;
946ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        try {
956ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            mCodec = MediaCodec.createByCodecName(codecName);
966ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            mCodec.configure(format.getFrameworkMediaFormatV16(), null, null, 0);
976ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            mCodec.start();
986ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        } catch (Exception e) {
996ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            Log.e(TAG, "Failed when configure or start codec:" + e);
1006ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            throw new ExoPlaybackException(e);
1016ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        }
1026ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        mInputIndex = INDEX_INVALID;
1036ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        mOutputIndex = INDEX_INVALID;
1046ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        mWaitingForFirstSyncFrame = true;
1056ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        mCodecCounters.codecInitCount++;
1066ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    }
1076ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko
1086ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    @Override
1096ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    public void resetDecoderState(String mimeType) {
1106ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        if (mCodec == null) {
1116ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            return;
1126ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        }
1136ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        mInputIndex = INDEX_INVALID;
1146ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        mOutputIndex = INDEX_INVALID;
1156ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        mDecodeOnlyPresentationTimestamps.clear();
1166ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        mCodec.flush();
1176ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        mWaitingForFirstSyncFrame = true;
1186ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    }
1196ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko
1206ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    @Override
1216ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    public void release() {
1226ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        if (mCodec != null) {
1236ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            mDecodeOnlyPresentationTimestamps.clear();
1246ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            mInputIndex = INDEX_INVALID;
1256ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            mOutputIndex = INDEX_INVALID;
1266ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            mCodecCounters.codecReleaseCount++;
1276ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            try {
1286ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko                mCodec.stop();
1296ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            } finally {
1306ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko                try {
1316ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko                    mCodec.release();
1326ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko                } finally {
1336ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko                    mCodec = null;
1346ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko                }
1356ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            }
1366ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        }
1376ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    }
1386ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko
1396ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    /** Returns the index of input buffer which is ready for using. */
1406ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    public int getInputIndex() {
1416ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        return mInputIndex;
1426ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    }
1436ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko
1446ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    @Override
1456ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    public ByteBuffer getInputBuffer() {
1466ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        if (mInputIndex < 0) {
1476ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            mInputIndex = mCodec.dequeueInputBuffer(0);
1486ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            if (mInputIndex < 0) {
1496ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko                return null;
1506ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            }
1516ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            return mCodec.getInputBuffer(mInputIndex);
1526ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        }
1536ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        return mCodec.getInputBuffer(mInputIndex);
1546ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    }
1556ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko
1566ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    @Override
1576ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    public void decode(SampleHolder sampleHolder) {
1586ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        if (mWaitingForFirstSyncFrame) {
1596ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            if (!sampleHolder.isSyncFrame()) {
1606ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko                sampleHolder.clearData();
1616ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko                return;
1626ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            }
1636ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            mWaitingForFirstSyncFrame = false;
1646ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        }
1656ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        long presentationTimeUs = sampleHolder.timeUs;
1666ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        if (sampleHolder.isDecodeOnly()) {
1676ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            mDecodeOnlyPresentationTimestamps.add(presentationTimeUs);
1686ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        }
1696ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        mCodec.queueInputBuffer(mInputIndex, 0, sampleHolder.data.limit(), presentationTimeUs, 0);
1706ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        mInputIndex = INDEX_INVALID;
1716ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        mCodecCounters.inputBufferCount++;
1726ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    }
1736ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko
1746ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    private int getDecodeOnlyIndex(long presentationTimeUs) {
1756ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        final int size = mDecodeOnlyPresentationTimestamps.size();
1766ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        for (int i = 0; i < size; i++) {
1776ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            if (mDecodeOnlyPresentationTimestamps.get(i).longValue() == presentationTimeUs) {
1786ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko                return i;
1796ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            }
1806ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        }
1816ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        return INDEX_INVALID;
1826ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    }
1836ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko
1846ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    /** Returns the index of output buffer which is ready for using. */
1856ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    public int getOutputIndex() {
1866ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        if (mOutputIndex < 0) {
1876ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            mOutputIndex = mCodec.dequeueOutputBuffer(mOutputBufferInfo, 0);
1886ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            mIsNewIndex = true;
1896ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        } else {
1906ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            mIsNewIndex = false;
1916ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        }
1926ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        return mOutputIndex;
1936ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    }
1946ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko
1956ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    @Override
1966ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    public android.media.MediaFormat getOutputFormat() {
1976ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        return mCodec.getOutputFormat();
1986ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    }
1996ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko
2006ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    /** Returns {@code true} if the output is only for decoding but not for rendering. */
2016ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    public boolean maybeDecodeOnlyIndex() {
2026ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        int decodeOnlyIndex = getDecodeOnlyIndex(mOutputBufferInfo.presentationTimeUs);
2036ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        if (decodeOnlyIndex != INDEX_INVALID) {
2046ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            mCodec.releaseOutputBuffer(mOutputIndex, false);
2056ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            mCodecCounters.skippedOutputBufferCount++;
2066ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            mDecodeOnlyPresentationTimestamps.remove(decodeOnlyIndex);
2076ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            mOutputIndex = INDEX_INVALID;
2086ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            return true;
2096ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        }
2106ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        return false;
2116ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    }
2126ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko
2136ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    @Override
2146ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    public ByteBuffer getDecodedSample() {
2156ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        if (maybeDecodeOnlyIndex() || mOutputIndex < 0) {
2166ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            return null;
2176ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        }
2186ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        if (mIsNewIndex) {
2196ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            mMediaCodecOutputBuffer = mCodec.getOutputBuffer(mOutputIndex);
2206ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        }
2216ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        return mMediaCodecOutputBuffer;
2226ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    }
2236ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko
2246ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    @Override
2256ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    public long getDecodedTimeUs() {
2266ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        return mOutputBufferInfo.presentationTimeUs;
2276ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    }
2286ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko
2296ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    /** Releases the output buffer after rendering. */
2306ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    public void releaseOutputBuffer() {
2316ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        mCodecCounters.renderedOutputBufferCount++;
2326ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        mCodec.releaseOutputBuffer(mOutputIndex, false);
2336ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        mOutputIndex = INDEX_INVALID;
2346ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    }
2356ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko}
236