把一个音视频文件的视频部分抽取出来播放

本文详细介绍如何使用Android的MediaCodec和MediaExtractor进行视频文件的解码与播放。通过具体示例代码展示了创建SurfaceView,利用MediaExtractor从视频文件中提取视频流,并使用MediaCodec进行解码的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

知识结构

MediaCodec: Android中直播视频技术探究之—基础知识大纲介绍MediaCodec文档翻译
详细介绍了MediaCodec的用法;在这里我们只使用MediaCodec的解码的功能;
mMediaCodec.configure(mMediaFormat, mSurface, null, 0);我们把SurfaceView.getSurface()传给它,就能把视频在SurfaceView上播放;

MediaExtractor: 实现把一个音频文件的视频抽取出来这里已经详细介绍了MediaExtractor的用处,这里不再累述;

步骤

1、创建一个SurfaceView

mSurfaceView = (SurfaceView) this.findViewById(R.id.mSurfaceView);
mSurfaceView.getHolder().addCallback(this);

2、在SurfaceView的Surface创建成功后开启一个线程执行MediaExtractor抽取视频,在MediaCodec进行解码;

public void surfaceCreated(SurfaceHolder holder) {

    }
    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
            int height) {
        mSurfaceHolder = holder;
        if(null == mPlayerThread){
            mPlayerThread = new Thread(new PlayerRunnable(mSurfaceHolder.getSurface()));
            mPlayerThread.start();
        }
    }
    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        if(null != mPlayerThread){
            mPlayerThread.interrupt();
        }
    }

3、最重要的:MediaExtractor与MediaCodec的组合

private class PlayerRunnable implements Runnable{
        private MediaExtractor mMediaExtractor;
        private MediaCodec mMediaCodec;
        private Surface mSurface ;

        public PlayerRunnable(Surface surface) {
            this.mSurface = surface;
        }

        @Override
        public void run() {
            try {
                mMediaExtractor = new MediaExtractor();

                String filePath = new File(Environment.getExternalStorageDirectory(), "/input.mp4").getPath();
                mMediaExtractor.setDataSource(filePath);

                int trackCount = mMediaExtractor.getTrackCount();
                for(int i=0; i<trackCount; i++){
                    MediaFormat mMediaFormat = mMediaExtractor.getTrackFormat(i);
                    String mime = mMediaFormat.getString(MediaFormat.KEY_MIME);
                    if(mime.startsWith("video/")){
                        mMediaExtractor.selectTrack(i);
                        mMediaCodec = MediaCodec.createDecoderByType(mime);
                        mMediaCodec.configure(mMediaFormat, mSurface, null, 0);
                        break;
                    }
                }

                if(null == mMediaCodec){
                    Log.d("MainActivity","dont't find mediaformat info;");
                    return ;
                }
                mMediaCodec.start();

                ByteBuffer[] inputBuffers = mMediaCodec.getInputBuffers();
                ByteBuffer[] outputBuffers = mMediaCodec.getOutputBuffers();
                boolean isEOS = false;
                BufferInfo info = new BufferInfo();
                long startMs = System.currentTimeMillis();

                while(!Thread.interrupted()){
                    if(!isEOS){
                        int inputBufferIndex = mMediaCodec.dequeueInputBuffer(10000);
                        if(inputBufferIndex >= 0){
                            ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
                            int readSampleSize = mMediaExtractor.readSampleData(inputBuffer, 0);
                            if(readSampleSize < 0){
                                //此时表明Video数据我们已经抽取完毕
                                mMediaCodec.queueInputBuffer(inputBufferIndex, 0, 0, 0,         MediaCodec.BUFFER_FLAG_END_OF_STREAM);
                                isEOS = true;
                            } else {
                                mMediaCodec.queueInputBuffer(inputBufferIndex, 0, readSampleSize, mMediaExtractor.getSampleTime(), 0);
                                mMediaExtractor.advance();
                            }
                        }
                    }

                    int outputBufferIndex = mMediaCodec.dequeueOutputBuffer(info, 10000);
                    switch (outputBufferIndex) {
                    case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED:
                        outputBuffers = mMediaCodec.getOutputBuffers();
                        break;
                    case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED:
                        Log.d("MainActivity", "New format " + mMediaCodec.getOutputFormat());
                        break;
                    case MediaCodec.INFO_TRY_AGAIN_LATER:
                        Log.d("MainActivity", "dequeueOutputBuffer timed out!");
                        break;

                    default:
                        ByteBuffer outputBuffer = outputBuffers[outputBufferIndex];
                        while (info.presentationTimeUs / 1000 > System.currentTimeMillis() - startMs) {
                            try {
                                Thread.sleep(10);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                                break;
                            }
                        }
                        mMediaCodec.releaseOutputBuffer(outputBufferIndex, true);
                        break;
                    }

                }
                mMediaCodec.stop();
                mMediaCodec.release();
                mMediaExtractor.release();

            } catch (Exception e) {
                e.printStackTrace();
            }
        } 
    }

总结

上面的代码主要是练习这几天学习的MediaCodec、MediaExtractor;只有多次练习,我们才能熟练使用;

Demo实例下载:DecodeVideoFileDemo

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值