MediaCodec 解码视频文件

首先初始化解码器: 其中包括视频解码器 和 音频解码器

  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            extractor = new MediaExtractor();
            audioExtractor = new MediaExtractor();
            try {
                extractor.setDataSource(path);


                audioExtractor.setDataSource(path);
                for (int i = 0; i < extractor.getTrackCount(); i++) {
                    MediaFormat format = extractor.getTrackFormat(i);
                    String mime = format.getString(MediaFormat.KEY_MIME);
                    Log.i(TAG, "mime: " + mime);
                    if (mime.startsWith("video/")) {
                        extractor.selectTrack(i);
                        decoder = MediaCodec.createDecoderByType(mime);
                        decoder.configure(format, surfaceHolder.getSurface(), null, 0);
                        //format.setInteger(MediaFormat.KEY_FRAME_RATE, 30);//帧率
                        //format.setInteger(MediaFormat.KEY_BIT_RATE, 17648);//设置比特率
                        decoder.start();
                        Log.i(TAG, "createDecoder mime: " + mime);
                        //break;
                    } else if (mime.startsWith("audio/")) {
                        audioExtractor.selectTrack(i);
                        audioDecoder = MediaCodec.createDecoderByType(mime);
                        //采样率
                        format.setInteger(MediaFormat.KEY_SAMPLE_RATE, 8000);
                        //声道个数
                        format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1);
                        //比特率
                        format.setInteger(MediaFormat.KEY_BIT_RATE, 0);
                        format.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC);
                        //ByteBuffer key(暂时不了解该参数的含义,但必须设置)
                        audioDecoder.configure(format, null, null, 0);
                        audioDecoder.start();
                    }
                }

                if (audioDecoder!=null){

                    audio = new AudioDecodecPlay();
                    audio.start();
                }
                if (decoder != null) {
                    DecodecPlay play = new DecodecPlay();
                    play.start();
                    Log.i(TAG, "initDecoder: 找不到解码器");
                    return false;
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            Log.i(TAG, "initDecoder: failed");
            return false;
        }

初始化解码器就可以开始解码了:
视频解码线程

 private class DecodecPlay extends Thread {

        @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
        @Override
        public void run() {
            ByteBuffer[] inputBuffers = decoder.getInputBuffers();
            ByteBuffer[] outputBuffers = decoder.getOutputBuffers();
            MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
            boolean first = false;
            long startMs=0;
            boolean isEndOfStream = false;
            while (!Thread.interrupted()) {
                if (!isEndOfStream) {
                    int dequeueIndex = decoder.dequeueInputBuffer(1000);
                    Log.i(TAG, "dequeueIndex: " + dequeueIndex);
                    if (dequeueIndex > 0) {

                        ByteBuffer inputBuffer = inputBuffers[dequeueIndex];
                        int sampleSize = extractor.readSampleData(inputBuffer, 0);

                        if (sampleSize<0){
                            Log.e(TAG, "input buffer end of stream");
                            decoder.queueInputBuffer(dequeueIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
                            isEndOfStream = true;
                        }else {
                            Log.i(TAG, "time: "+extractor.getSampleTime());
                            decoder.queueInputBuffer(dequeueIndex, 0, sampleSize, extractor.getSampleTime(), 0);
                            extractor.advance();
                        }
                    }

                }

                int outputIndex = decoder.dequeueOutputBuffer(info, 10000);
                switch (outputIndex){
                    case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED:
                        Log.i(TAG, "--缓冲区已经更改");
                        outputBuffers = decoder.getOutputBuffers();
                        break;
                    case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED:
                        Log.i(TAG, "--格式以及更改-----> "+decoder.getOutputFormat().getString(MediaFormat.KEY_MIME));
                        break;
                    case MediaCodec.INFO_TRY_AGAIN_LATER:
                        Log.i(TAG, "dequeueOutputBuffer  indicates that the call timed out.");
                        break;
                    default:
                        Log.i(TAG, "run: outputIndex01"+outputIndex);
                        if (!first){
                            startMs = System.currentTimeMillis();
                            first=true;
                        }
                        Log.i(TAG, "info.presentationTimeUs: "+info.presentationTimeUs/1000+"::::"+(System.currentTimeMillis() - startMs));
                        long sleepTime = (info.presentationTimeUs / 1000) - (System.currentTimeMillis() - startMs);
                        if (sleepTime>0){
                            try {
                                sleep(sleepTime);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }

                        decoder.releaseOutputBuffer(outputIndex, true);
                        break;
                }

                if((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0){
                    Log.d(TAG, "Output buffer BUFFER_FLAG_END_OF_STREAM");
                    finish();
                    break;
                }


            }

            decoder.stop();
            decoder.release();
            extractor.release();

        }
    }

音频解码线程:

  private class AudioDecodecPlay extends Thread {

        @TargetApi(Build.VERSION_CODES.LOLLIPOP)
        @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
        @Override
        public void run() {
           boolean first=false;
            ByteBuffer[] inputBuffers = audioDecoder.getInputBuffers();
            ByteBuffer[] outputBuffers = audioDecoder.getOutputBuffers();
            MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
            boolean isEndOfStream = false;
            long startMs = 0;
            while (!Thread.interrupted()) {
                if (!isEndOfStream) {
                    int dequeueIndex = audioDecoder.dequeueInputBuffer(1000);
                    Log.i(TAG, "dequeueIndex: " + dequeueIndex);
                    if (dequeueIndex > 0) {

                        ByteBuffer inputBuffer = inputBuffers[dequeueIndex];
                        int sampleSize = audioExtractor.readSampleData(inputBuffer, 0);
                        if (sampleSize<0){
                            Log.e(TAG, "input buffer end of stream");
                            audioDecoder.queueInputBuffer(dequeueIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
                            isEndOfStream = true;
                        }else {
                            audioDecoder.queueInputBuffer(dequeueIndex, 0, sampleSize, audioExtractor.getSampleTime(), 0);
                            audioExtractor.advance();
                        }
                    }

                }

                int outputIndex = audioDecoder.dequeueOutputBuffer(info, 10000);
                switch (outputIndex){
                    case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED:
                        Log.i(TAG, "--缓冲区已经更改");
                        outputBuffers = audioDecoder.getOutputBuffers();
                        break;
                    case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED:
                        Log.i(TAG, "--格式以及更改-----> "+decoder.getOutputFormat().getString(MediaFormat.KEY_MIME));
                        break;
                    case MediaCodec.INFO_TRY_AGAIN_LATER:
                        Log.i(TAG, "dequeueOutputBuffer  indicates that the call timed out.");
                        break;
                    default:
                        Log.i(TAG, "run: outputIndex02"+outputIndex);
                        if (!first){
                            startMs = System.currentTimeMillis();
                            first=true;
                        }
                        Log.i(TAG, "info.presentationTimeUs: "+info.presentationTimeUs/1000+"::::"+(System.currentTimeMillis() - startMs));
                        long sleepTime = (info.presentationTimeUs / 1000) - (System.currentTimeMillis() - startMs);
                        if (sleepTime>0){
                            try {
                                sleep(sleepTime);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                        ByteBuffer buffer = outputBuffers[outputIndex];
                        byte[] data = new byte[buffer.remaining()];
                        buffer.get(data);
                        mPlayer.write(data,0,data.length);
                        audioDecoder.releaseOutputBuffer(outputIndex, false);
                        break;
                }

                if((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0){
                    Log.d(TAG, "Output buffer BUFFER_FLAG_END_OF_STREAM");
                    break;
                }


            }

            audioDecoder.stop();
            audioDecoder.release();
            audioExtractor.release();
        }
    }

关键代码就这么多!!!
解码后的音频可以使用AudioTrack播放

  mPlayer = new AudioTrack(AudioManager.STREAM_MUSIC,
                sampleRateInHz, channelConfig, audioFormat,2880,
                AudioTrack.MODE_STREAM);
        mPlayer.play();
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值