要从Android MediaCodec的解码输出缓冲区中获取位图,可以使用以下代码示例:
import android.graphics.Bitmap;
import android.media.Image;
import android.media.MediaCodec;
import android.media.MediaCodec.BufferInfo;
import android.media.MediaFormat;
import android.media.MediaExtractor;
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import java.io.IOException;
import java.nio.ByteBuffer;
public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback {
private static final String TAG = "MainActivity";
private static final String VIDEO_PATH = Environment.getExternalStorageDirectory() + "/video.mp4";
private SurfaceView mSurfaceView;
private Surface mSurface;
private MediaExtractor mExtractor;
private MediaCodec mDecoder;
private BufferInfo mBufferInfo;
private ByteBuffer[] mInputBuffers;
private ByteBuffer[] mOutputBuffers;
private int mInputBufferIndex;
private int mOutputBufferIndex;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mSurfaceView = findViewById(R.id.surface_view);
mSurfaceView.getHolder().addCallback(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
releaseDecoder();
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
mSurface = holder.getSurface();
initDecoder();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
releaseDecoder();
}
private void initDecoder() {
try {
mExtractor = new MediaExtractor();
mExtractor.setDataSource(VIDEO_PATH);
int trackIndex = selectTrack(mExtractor);
if (trackIndex < 0) {
Log.e(TAG, "No video track found in " + VIDEO_PATH);
return;
}
mExtractor.selectTrack(trackIndex);
MediaFormat format = mExtractor.getTrackFormat(trackIndex);
String mime = format.getString(MediaFormat.KEY_MIME);
mDecoder = MediaCodec.createDecoderByType(mime);
mDecoder.configure(format, mSurface, null, 0);
mDecoder.start();
mBufferInfo = new BufferInfo();
mInputBuffers = mDecoder.getInputBuffers();
mOutputBuffers = mDecoder.getOutputBuffers();
} catch (IOException e) {
e.printStackTrace();
}
}
private int selectTrack(MediaExtractor extractor) {
int numTracks = extractor.getTrackCount();
for (int i = 0; i < numTracks; i++) {
MediaFormat format = extractor.getTrackFormat(i);
String mime = format.getString(MediaFormat.KEY_MIME);
if (mime.startsWith("video/")) {
return i;
}
}
return -1;
}
private void releaseDecoder() {
if (mDecoder != null) {
mDecoder.stop();
mDecoder.release();
mDecoder = null;
}
if (mExtractor != null) {
mExtractor.release();
mExtractor = null;
}
}
private Bitmap getBitmapFromBuffer(ByteBuffer buffer, int width, int height) {
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
buffer.rewind();
bitmap.copyPixelsFromBuffer(buffer);
return bitmap;
}
private void decodeFrame() {
mInputBufferIndex = mDecoder.dequeueInputBuffer(-1);
if (mInputBufferIndex >= 0) {
ByteBuffer inputBuffer = mInputBuffers[mInputBufferIndex];
int sampleSize = mExtractor.readSampleData(inputBuffer, 0);
long presentationTimeUs = mExtractor.getSampleTime();
mDecoder.queueInputBuffer(mInputBufferIndex, 0, sampleSize, presentationTimeUs, 0);
mExtractor.advance();
}
mOutputBufferIndex = mDecoder.dequeueOutputBuffer(mBufferInfo, -1);
if (mOutputBufferIndex >= 0) {
if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
mDecoder.releaseOutputBuffer(mOutputBufferIndex, false);
} else {
Image image = mDecoder.getOutputImage(mOutputBufferIndex);
if (image != null) {
int width = image.getWidth();
int height = image.getHeight();
Image.Plane[] planes = image.getPlanes();
ByteBuffer buffer = planes[0].getBuffer();
Bitmap bitmap = getBitmapFromBuffer(buffer, width, height);
// 使用位图进行进一步处理