1227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks/*
2227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Copyright (C) 2012 The Android Open Source Project
3227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks *
4227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Licensed under the Apache License, Version 2.0 (the "License");
5227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * you may not use this file except in compliance with the License.
6227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * You may obtain a copy of the License at
7227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks *
8227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks *      http://www.apache.org/licenses/LICENSE-2.0
9227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks *
10227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Unless required by applicable law or agreed to in writing, software
11227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * distributed under the License is distributed on an "AS IS" BASIS,
12227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * See the License for the specific language governing permissions and
14227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * limitations under the License.
15227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */
16227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
17227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendrickspackage androidx.media.filterfw.decoder;
18227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
19227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.annotation.TargetApi;
20227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.media.MediaCodec;
21227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.media.MediaCodec.BufferInfo;
22227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.media.MediaExtractor;
23227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.media.MediaFormat;
24227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.util.Log;
25227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
26227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport java.nio.ByteBuffer;
27227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
28227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks@TargetApi(16)
29227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksabstract class TrackDecoder {
30227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
31227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    interface Listener {
32227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        void onDecodedOutputAvailable(TrackDecoder decoder);
33227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
34227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        void onEndOfStream(TrackDecoder decoder);
35227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
36227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
37227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private static final String LOG_TAG = "TrackDecoder";
38227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
39227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private static final long TIMEOUT_US = 50; // Timeout for en-queueing and de-queueing buffers.
40227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
41227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private static final int NO_INPUT_BUFFER = -1;
42227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
43227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private final int mTrackIndex;
44227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private final MediaFormat mMediaFormat;
45227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private final Listener mListener;
46227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
47227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private MediaCodec mMediaCodec;
48227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private MediaFormat mOutputFormat;
49227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
50227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private ByteBuffer[] mCodecInputBuffers;
51227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private ByteBuffer[] mCodecOutputBuffers;
52227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
53227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private boolean mShouldEnqueueEndOfStream;
54227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
55227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
56227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return a configured {@link MediaCodec}.
57227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
58227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    protected abstract MediaCodec initMediaCodec(MediaFormat format);
59227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
60227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
61227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Called when decoded output is available. The implementer is responsible for releasing the
62227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * assigned buffer.
63227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
64227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return {@code true} if any further decoding should be attempted at the moment.
65227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
66227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    protected abstract boolean onDataAvailable(
67227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            MediaCodec codec, ByteBuffer[] buffers, int bufferIndex, BufferInfo info);
68227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
69227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    protected TrackDecoder(int trackIndex, MediaFormat mediaFormat, Listener listener) {
70227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mTrackIndex = trackIndex;
71227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
72227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (mediaFormat == null) {
73227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            throw new NullPointerException("mediaFormat cannot be null");
74227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
75227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mMediaFormat = mediaFormat;
76227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
77227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (listener == null) {
78227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            throw new NullPointerException("listener cannot be null");
79227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
80227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mListener = listener;
81227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
82227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
83227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public void init() {
84227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mMediaCodec = initMediaCodec(mMediaFormat);
85227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mMediaCodec.start();
86227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mCodecInputBuffers = mMediaCodec.getInputBuffers();
87227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mCodecOutputBuffers = mMediaCodec.getOutputBuffers();
88227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
89227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
90227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public void signalEndOfInput() {
91227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mShouldEnqueueEndOfStream = true;
92227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        tryEnqueueEndOfStream();
93227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
94227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
95227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public void release() {
96227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (mMediaCodec != null) {
97227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mMediaCodec.stop();
98227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mMediaCodec.release();
99227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
100227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
101227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
102227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    protected MediaCodec getMediaCodec() {
103227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return mMediaCodec;
104227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
105227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
106227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    protected void notifyListener() {
107227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mListener.onDecodedOutputAvailable(this);
108227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
109227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
110227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public boolean feedInput(MediaExtractor mediaExtractor) {
111227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        long presentationTimeUs = 0;
112227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
113227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        int inputBufferIndex = mMediaCodec.dequeueInputBuffer(TIMEOUT_US);
114227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (inputBufferIndex != NO_INPUT_BUFFER) {
115227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            ByteBuffer destinationBuffer = mCodecInputBuffers[inputBufferIndex];
116227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            int sampleSize = mediaExtractor.readSampleData(destinationBuffer, 0);
117227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            // We don't expect to get a sample without any data, so this should never happen.
118227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (sampleSize < 0) {
119227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                Log.w(LOG_TAG, "Media extractor had sample but no data.");
120227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
121227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                // Signal the end of the track immediately anyway, using the buffer.
122227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                mMediaCodec.queueInputBuffer(
123227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        inputBufferIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
124227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                return false;
125227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
126227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
127227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            presentationTimeUs = mediaExtractor.getSampleTime();
128227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mMediaCodec.queueInputBuffer(
129227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    inputBufferIndex,
130227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    0,
131227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    sampleSize,
132227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    presentationTimeUs,
133227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    0);
134227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
135227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            return mediaExtractor.advance()
136227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    && mediaExtractor.getSampleTrackIndex() == mTrackIndex;
137227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
138227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return false;
139227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
140227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
141227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private void tryEnqueueEndOfStream() {
142227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        int inputBufferIndex = mMediaCodec.dequeueInputBuffer(TIMEOUT_US);
143227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        // We will always eventually have an input buffer, because we keep trying until the last
144227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        // decoded frame is output.
145227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        // The EoS does not need to be signaled if the application stops decoding.
146227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (inputBufferIndex != NO_INPUT_BUFFER) {
147227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mMediaCodec.queueInputBuffer(
148227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    inputBufferIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
149227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mShouldEnqueueEndOfStream = false;
150227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
151227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
152227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
153227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public boolean drainOutputBuffer() {
154227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        BufferInfo outputInfo = new BufferInfo();
155227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        int outputBufferIndex = mMediaCodec.dequeueOutputBuffer(outputInfo, TIMEOUT_US);
156227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
157227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if ((outputInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
158227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mListener.onEndOfStream(this);
159227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            return false;
160227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
161227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (mShouldEnqueueEndOfStream) {
162227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            tryEnqueueEndOfStream();
163227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
164227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (outputBufferIndex >= 0) {
165227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            return onDataAvailable(
166227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    mMediaCodec, mCodecOutputBuffers, outputBufferIndex, outputInfo);
167227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        } else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
168227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mCodecOutputBuffers = mMediaCodec.getOutputBuffers();
169227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            return true;
170227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        } else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
171227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mOutputFormat = mMediaCodec.getOutputFormat();
172227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            Log.d(LOG_TAG, "Output format has changed to " + mOutputFormat);
173227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            return true;
174227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
175227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return false;
176227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
177227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
178227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks}
179