Created
January 15, 2016 08:30
-
-
Save waveacme/4e783c5b687c4aedd33b to your computer and use it in GitHub Desktop.
MediaCodec decode h264 example
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//from https://github.com/vecio/MediaCodecDemo | |
package io.vec.demo.mediacodec; | |
import java.nio.ByteBuffer; | |
import android.app.Activity; | |
import android.media.MediaCodec; | |
import android.media.MediaCodec.BufferInfo; | |
import android.media.MediaExtractor; | |
import android.media.MediaFormat; | |
import android.os.Bundle; | |
import android.os.Environment; | |
import android.util.Log; | |
import android.view.Surface; | |
import android.view.SurfaceHolder; | |
import android.view.SurfaceView; | |
public class DecodeActivity extends Activity implements SurfaceHolder.Callback { | |
private static final String SAMPLE = Environment.getExternalStorageDirectory() + "/video.mp4"; | |
private PlayerThread mPlayer = null; | |
@Override | |
protected void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
SurfaceView sv = new SurfaceView(this); | |
sv.getHolder().addCallback(this); | |
setContentView(sv); | |
} | |
protected void onDestroy() { | |
super.onDestroy(); | |
} | |
@Override | |
public void surfaceCreated(SurfaceHolder holder) { | |
} | |
@Override | |
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { | |
if (mPlayer == null) { | |
mPlayer = new PlayerThread(holder.getSurface()); | |
mPlayer.start(); | |
} | |
} | |
@Override | |
public void surfaceDestroyed(SurfaceHolder holder) { | |
if (mPlayer != null) { | |
mPlayer.interrupt(); | |
} | |
} | |
private class PlayerThread extends Thread { | |
private MediaExtractor extractor; | |
private MediaCodec decoder; | |
private Surface surface; | |
public PlayerThread(Surface surface) { | |
this.surface = surface; | |
} | |
@Override | |
public void run() { | |
extractor = new MediaExtractor(); | |
extractor.setDataSource(SAMPLE); | |
for (int i = 0; i < extractor.getTrackCount(); i++) { | |
MediaFormat format = extractor.getTrackFormat(i); | |
String mime = format.getString(MediaFormat.KEY_MIME); | |
if (mime.startsWith("video/")) { | |
extractor.selectTrack(i); | |
decoder = MediaCodec.createDecoderByType(mime); | |
decoder.configure(format, surface, null, 0); | |
break; | |
} | |
} | |
if (decoder == null) { | |
Log.e("DecodeActivity", "Can't find video info!"); | |
return; | |
} | |
decoder.start(); | |
ByteBuffer[] inputBuffers = decoder.getInputBuffers(); | |
ByteBuffer[] outputBuffers = decoder.getOutputBuffers(); | |
BufferInfo info = new BufferInfo(); | |
boolean isEOS = false; | |
long startMs = System.currentTimeMillis(); | |
while (!Thread.interrupted()) { | |
if (!isEOS) { | |
int inIndex = decoder.dequeueInputBuffer(10000); | |
if (inIndex >= 0) { | |
ByteBuffer buffer = inputBuffers[inIndex]; | |
int sampleSize = extractor.readSampleData(buffer, 0); | |
if (sampleSize < 0) { | |
// We shouldn't stop the playback at this point, just pass the EOS | |
// flag to decoder, we will get it again from the | |
// dequeueOutputBuffer | |
Log.d("DecodeActivity", "InputBuffer BUFFER_FLAG_END_OF_STREAM"); | |
decoder.queueInputBuffer(inIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM); | |
isEOS = true; | |
} else { | |
decoder.queueInputBuffer(inIndex, 0, sampleSize, extractor.getSampleTime(), 0); | |
extractor.advance(); | |
} | |
} | |
} | |
int outIndex = decoder.dequeueOutputBuffer(info, 10000); | |
switch (outIndex) { | |
case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED: | |
Log.d("DecodeActivity", "INFO_OUTPUT_BUFFERS_CHANGED"); | |
outputBuffers = decoder.getOutputBuffers(); | |
break; | |
case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED: | |
Log.d("DecodeActivity", "New format " + decoder.getOutputFormat()); | |
break; | |
case MediaCodec.INFO_TRY_AGAIN_LATER: | |
Log.d("DecodeActivity", "dequeueOutputBuffer timed out!"); | |
break; | |
default: | |
ByteBuffer buffer = outputBuffers[outIndex]; | |
Log.v("DecodeActivity", "We can't use this buffer but render it due to the API limit, " + buffer); | |
// We use a very simple clock to keep the video FPS, or the video | |
// playback will be too fast | |
while (info.presentationTimeUs / 1000 > System.currentTimeMillis() - startMs) { | |
try { | |
sleep(10); | |
} catch (InterruptedException e) { | |
e.printStackTrace(); | |
break; | |
} | |
} | |
decoder.releaseOutputBuffer(outIndex, true); | |
break; | |
} | |
// All decoded frames have been rendered, we can stop playing now | |
if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) { | |
Log.d("DecodeActivity", "OutputBuffer BUFFER_FLAG_END_OF_STREAM"); | |
break; | |
} | |
} | |
decoder.stop(); | |
decoder.release(); | |
extractor.release(); | |
} | |
} | |
} |
If I have a byte[] with some frames, what should I do?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
It is decoding the mp4 file when I tried decoding H264 file it was not able to read the H264 encoded file.