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