Skip to content

Instantly share code, notes, and snippets.

@JavaDeveloper
Created October 1, 2012 15:21
Show Gist options
  • Save JavaDeveloper/3812450 to your computer and use it in GitHub Desktop.
Save JavaDeveloper/3812450 to your computer and use it in GitHub Desktop.
import java.nio.ByteBuffer;
import android.media.MediaCodec;
import android.media.MediaExtractor;
import android.media.MediaFormat;
import android.util.Log;
import android.view.Surface;
public abstract class AbstractTrackDecoder extends Thread {
private static final String TAG = AbstractTrackDecoder.class.getSimpleName();
protected final long TIMEOUT_US = 5000;
protected boolean hasInputData = true;
protected boolean hasOutputData = true;
protected MediaExtractor extractor;
protected MediaFormat format;
protected String mime;
protected int trackNum;
protected MediaCodec codec;
protected ByteBuffer[] inputBuffers;
protected ByteBuffer[] outputBuffers;
protected MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
/**
* Index of the current buffer(decoded data), which is the first in the
* buffers queue.
*/
protected int outputBufferIndex = -1;
protected AbstractTrackDecoder(String path, String prefix, Surface surface) {
this.extractor = new MediaExtractor();
this.extractor.setDataSource(path);
initializeCodec(extractor, prefix, surface);
}
private void initializeCodec(MediaExtractor extractor, String prefix, Surface surface) {
int trackCount = extractor.getTrackCount();
for (int i = 0; i < trackCount; i++) {
format = extractor.getTrackFormat(i);
mime = format.getString(MediaFormat.KEY_MIME);
if (mime.startsWith(prefix)) {
trackNum = i;
codec = MediaCodec.createDecoderByType(mime);
codec.configure(format, surface, null /* crypto */, 0 /* flags */);
codec.start();
inputBuffers = codec.getInputBuffers();
outputBuffers = codec.getOutputBuffers();
Log.d(TAG, "Found: " + mime);
break;
}
}
}
public boolean isHasRawData() {
return hasInputData;
}
public boolean isHasDecodedData() {
return hasOutputData;
}
public void cleanup() {
if (codec == null) {
return;
}
codec.stop();
codec.release();
codec = null;
}
public void dequeueInput() throws InterruptedException {
int inputBufferIndex = codec.dequeueInputBuffer(TIMEOUT_US);
if (inputBufferIndex >= 0) {
ByteBuffer dst = inputBuffers[inputBufferIndex];
extractor.selectTrack(trackNum);
int sampleSize = extractor.readSampleData(dst, 0 /* offset */);
if (sampleSize >= 0) {
long pts = extractor.getSampleTime();
codec.queueInputBuffer(inputBufferIndex, 0 /* offset */, sampleSize, pts, 0);
extractor.advance();
} else {
codec.queueInputBuffer(inputBufferIndex, 0 /* offset */, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
hasInputData = false;
Log.d(TAG, "Raw data EOS.");
}
} else {
// no buffer is available
synchronized (this) {
wait();
}
}
}
public void dequeueOutput() {
outputBufferIndex = codec.dequeueOutputBuffer(bufferInfo, TIMEOUT_US);
if (outputBufferIndex >= 0) {
if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
Log.d(TAG, "Decoded data EOS.");
hasOutputData = false;
}
}
}
public void systemTime(long us) {
if (bufferInfo.presentationTimeUs / 1000 <= us) {
processDecodedData();
dequeueOutput();
synchronized (this) {
notify();
}
}
}
protected abstract void processDecodedData();
@Override
public void run() {
while (true) {
if (hasInputData) {
try {
dequeueInput();
} catch (Exception e) {
Log.e(TAG, "reading data", e);
break;
}
}
if (!hasOutputData) {
break;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment