【Android 多媒体应用】使用MediaCodec解码使用SurfaceView显示视频
1.MainActivity.java
import android.app.Activity; import android.os.Bundle; import android.os.Environment; import android.view.SurfaceHolder; import android.view.SurfaceView; /** * MediaCodec SurfaceHolder Example * @author taehwan * */ public class MainActivity extends Activity implements SurfaceHolder.Callback { private VideoDecoderThread mVideoDecoder; private static final String FILE_PATH = Environment.getExternalStorageDirectory() + "/TopGirl.mp4"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); SurfaceView surfaceView = new SurfaceView(this); surfaceView.getHolder().addCallback(this); setContentView(surfaceView); mVideoDecoder = new VideoDecoderThread(); } @Override public void surfaceCreated(SurfaceHolder holder) { } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { if (mVideoDecoder != null) { if (mVideoDecoder.init(holder.getSurface(), FILE_PATH)) { mVideoDecoder.start(); } else { mVideoDecoder = null; } } } @Override public void surfaceDestroyed(SurfaceHolder holder) { if (mVideoDecoder != null) { mVideoDecoder.close(); } } }
2.VideoDecoderThread.java
import java.io.IOException; import java.nio.ByteBuffer; import android.media.MediaCodec; import android.media.MediaCodec.BufferInfo; import android.media.MediaExtractor; import android.media.MediaFormat; import android.util.Log; import android.view.Surface; public class VideoDecoderThread extends Thread { private static final String VIDEO = "video/"; private static final String TAG = "VideoDecoder"; private MediaExtractor mExtractor; private MediaCodec mDecoder; private boolean eosReceived; public boolean init(Surface surface, String filePath) { eosReceived = false; try { mExtractor = new MediaExtractor(); mExtractor.setDataSource(filePath); //分离出音轨和视轨 Log.d(TAG, "getTrackCount: " + mExtractor.getTrackCount() ); for (int i = 0; i < mExtractor.getTrackCount(); i++) { MediaFormat format = mExtractor.getTrackFormat(i); String mime = format.getString(MediaFormat.KEY_MIME); if (mime.startsWith(VIDEO)) { mExtractor.selectTrack(i); mDecoder = MediaCodec.createDecoderByType(mime); try { Log.d(TAG, "format : " + format); mDecoder.configure(format, surface, null, 0 /* Decoder */); } catch (IllegalStateException e) { Log.e(TAG, "codec '" + mime + "' failed configuration. " + e); return false; } mDecoder.start(); break; } } } catch (IOException e) { e.printStackTrace(); } return true; } @Override public void run() { BufferInfo info = new BufferInfo(); ByteBuffer[] inputBuffers = mDecoder.getInputBuffers(); mDecoder.getOutputBuffers(); boolean isInput = true; boolean first = false; long startWhen = 0; while (!eosReceived) { if (isInput) { int inputIndex = mDecoder.dequeueInputBuffer(10000); if (inputIndex >= 0) { // fill inputBuffers[inputBufferIndex] with valid data ByteBuffer inputBuffer = inputBuffers[inputIndex]; int sampleSize = mExtractor.readSampleData(inputBuffer, 0); if (mExtractor.advance() && sampleSize > 0) { mDecoder.queueInputBuffer(inputIndex, 0, sampleSize, mExtractor.getSampleTime(), 0); } else { Log.d(TAG, "InputBuffer BUFFER_FLAG_END_OF_STREAM"); mDecoder.queueInputBuffer(inputIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM); isInput = false; } } } int outIndex = mDecoder.dequeueOutputBuffer(info, 10000); switch (outIndex) { case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED: Log.d(TAG, "INFO_OUTPUT_BUFFERS_CHANGED"); mDecoder.getOutputBuffers(); break; case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED: Log.d(TAG, "INFO_OUTPUT_FORMAT_CHANGED format : " + mDecoder.getOutputFormat()); break; case MediaCodec.INFO_TRY_AGAIN_LATER: // Log.d(TAG, "INFO_TRY_AGAIN_LATER"); break; default: if (!first) { startWhen = System.currentTimeMillis(); first = true; } try { long sleepTime = (info.presentationTimeUs / 1000) - (System.currentTimeMillis() - startWhen); //Log.d(TAG, "info.presentationTimeUs : " + (info.presentationTimeUs / 1000) + " playTime: " + (System.currentTimeMillis() - startWhen) + " sleepTime : " + sleepTime); if (sleepTime > 0) Thread.sleep(sleepTime); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } mDecoder.releaseOutputBuffer(outIndex, true /* Surface init */); break; } // All decoded frames have been rendered, we can stop playing now if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) { Log.d(TAG, "OutputBuffer BUFFER_FLAG_END_OF_STREAM"); break; } } mDecoder.stop(); mDecoder.release(); mExtractor.release(); } public void close() { eosReceived = true; } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步