1. 程式人生 > >把一個音視訊檔案的視訊部分抽取出來播放

把一個音視訊檔案的視訊部分抽取出來播放

知識結構

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;只有多次練習,我們才能熟練使用;