如何将mediacodec解码后的数据显示出来,代码如何实现
时间: 2024-02-19 16:01:25 浏览: 108
以下是一个简单的Android代码示例,演示如何将MediaCodec解码后的视频数据显示出来:
```
import android.media.MediaCodec;
import android.media.MediaExtractor;
import android.media.MediaFormat;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import androidx.appcompat.app.AppCompatActivity;
import java.io.IOException;
import java.nio.ByteBuffer;
public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback {
private SurfaceView mSurfaceView;
private SurfaceHolder mSurfaceHolder;
private MediaExtractor mMediaExtractor;
private MediaCodec mMediaCodec;
private ByteBuffer[] mInputBuffers;
private ByteBuffer[] mOutputBuffers;
private MediaFormat mMediaFormat;
private int mVideoTrackIndex;
private boolean mIsEOS;
private boolean mIsStarted;
private boolean mIsSurfaceCreated;
private DecoderHandler mHandler;
private static final int MSG_DECODER_START = 0;
private static final int MSG_DECODER_STOP = 1;
private static final int MSG_DECODER_RELEASE = 2;
private static final int MSG_DECODER_DECODE = 3;
private static final int TIMEOUT_USEC = 10000;
private class DecoderHandler extends Handler {
public DecoderHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_DECODER_START:
startDecoder();
break;
case MSG_DECODER_STOP:
stopDecoder();
break;
case MSG_DECODER_RELEASE:
releaseDecoder();
break;
case MSG_DECODER_DECODE:
decodeFrame();
break;
}
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mSurfaceView = findViewById(R.id.surface_view);
mSurfaceHolder = mSurfaceView.getHolder();
mSurfaceHolder.addCallback(this);
mMediaExtractor = new MediaExtractor();
try {
mMediaExtractor.setDataSource("path/to/video/file");
} catch (IOException e) {
e.printStackTrace();
}
int trackCount = mMediaExtractor.getTrackCount();
for (int i = 0; i < trackCount; i++) {
MediaFormat format = mMediaExtractor.getTrackFormat(i);
String mime = format.getString(MediaFormat.KEY_MIME);
if (mime.startsWith("video/")) {
mVideoTrackIndex = i;
mMediaFormat = format;
break;
}
}
mHandler = new DecoderHandler(Looper.getMainLooper());
}
private void startDecoder() {
mMediaCodec = MediaCodec.createDecoderByType(mMediaFormat.getString(MediaFormat.KEY_MIME));
mMediaCodec.configure(mMediaFormat, mSurfaceHolder.getSurface(), null, 0);
mMediaCodec.start();
mInputBuffers = mMediaCodec.getInputBuffers();
mOutputBuffers = mMediaCodec.getOutputBuffers();
mIsEOS = false;
mIsStarted = true;
}
private void stopDecoder() {
mIsStarted = false;
mMediaCodec.stop();
}
private void releaseDecoder() {
mIsSurfaceCreated = false;
mMediaCodec.release();
mMediaExtractor.release();
}
private void decodeFrame() {
if (!mIsStarted) {
return;
}
if (!mIsEOS) {
int inputBufferIndex = mMediaCodec.dequeueInputBuffer(TIMEOUT_USEC);
if (inputBufferIndex >= 0) {
ByteBuffer inputBuffer = mInputBuffers[inputBufferIndex];
int sampleSize = mMediaExtractor.readSampleData(inputBuffer, 0);
if (sampleSize < 0) {
mMediaCodec.queueInputBuffer(inputBufferIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
mIsEOS = true;
} else {
mMediaCodec.queueInputBuffer(inputBufferIndex, 0, sampleSize, mMediaExtractor.getSampleTime(), 0);
mMediaExtractor.advance();
}
}
}
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
int outputBufferIndex = mMediaCodec.dequeueOutputBuffer(bufferInfo, TIMEOUT_USEC);
switch (outputBufferIndex) {
case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED:
mOutputBuffers = mMediaCodec.getOutputBuffers();
break;
case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED:
break;
case MediaCodec.INFO_TRY_AGAIN_LATER:
break;
default:
if (mIsSurfaceCreated) {
mMediaCodec.releaseOutputBuffer(outputBufferIndex, true);
}
break;
}
if (mIsStarted) {
mHandler.sendEmptyMessage(MSG_DECODER_DECODE);
}
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
mIsSurfaceCreated = true;
mHandler.sendEmptyMessage(MSG_DECODER_START);
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
mIsSurfaceCreated = false;
mHandler.sendEmptyMessage(MSG_DECODER_STOP);
mHandler.sendEmptyMessage(MSG_DECODER_RELEASE);
}
}
```
以上代码中,我们创建了一个SurfaceView用于显示视频画面,使用MediaExtractor从视频文件中提取音视频数据,选择需要解码的视频轨道,创建MediaCodec对象,并将其配置为解码器,将Surface对象作为MediaCodec的输出Surface。在循环中,我们从MediaExtractor中读取音视频数据,将其提交给MediaCodec进行解码,并从MediaCodec中获取解码后的数据,将解码后的视频数据渲染到SurfaceView上。我们还使用了Handler来进行解码器的控制和视频数据的解码。需要注意的是,由于解码和渲染是异步进行的,我们需要使用Handler来驱动解码器的工作,保证视频能够正常播放。
阅读全文