Android音视频深入三MP4解码播放视频(附源码下载)-创新互联

本篇项目地址,名字是媒体解码MediaCodec,MediaExtractor,求star
https://github.com/979451341/Audio-and-video-learning-materials

目前创新互联公司已为上千的企业提供了网站建设、域名、虚拟空间、绵阳服务器托管、企业网站设计、镇宁网站维护等服务,公司将坚持客户导向、应用为本的策略,正道将秉承"和谐、参与、激情"的文化,与客户和合作伙伴齐心协力一起成长,共同发展。

这次要用到新的东西SurfaceView、MediaCodec、MediaExtractor、MediaFormat

1.文字说明

SurfaceView:一个View,用来显示视频的,使用的时候代码都比较简单就不多说了

MediaCodec:访问底层媒体编码,能够完成媒体编码和解码
编码是将源对象内容按照一种标准转换为一种标准格式内容。
解码是和编码对应的,它使用和编码相同的标准将编码内容还原为最初的对象内容。

MediaExtractor:负责将指定类型的媒体文件从文件中找到轨道,并填充到MediaCodec的缓冲区中

MediaFormat:封装描述媒体数据格式的信息,无论是音频还是视频。媒体数据的格式被指定为字符串/值对。所有格式通用的键,所有未标记为可选的键都是必需的:
名称 值类型 描述
KEY_MIME 串 格式的类型。
KEY_MAX_INPUT_SIZE 整数 可选,输入数据缓冲区的大大小
KEY_BIT_RATE 整数 仅编码器,所需比特率(以比特/秒为单位)

2.视频播放顺序

(1)开启两个线程分别处理MP4的音频和视频

我先说一下视频的处理

使用MediaExtractor提取资源,选择频道

 MediaExtractor videoExtractor = new MediaExtractor();
        MediaCodec videoCodec = null;
        try {
            videoExtractor.setDataSource(filePath);
        } catch (IOException e) {
            e.printStackTrace();
        }
        int videoTrackIndex;
        //获取视频所在轨道
        videoTrackIndex = getMediaTrackIndex(videoExtractor, "video/");

videoExtractor.selectTrack(videoTrackIndex);

设置解码配置,并给MediaCodec配置,而且将SurfaceView于MediaCodec相关联,设置为在这个SurfaceView上显示

MediaFormat mediaFormat = videoExtractor.getTrackFormat(videoTrackIndex);
            int width = mediaFormat.getInteger(MediaFormat.KEY_WIDTH);
            int height = mediaFormat.getInteger(MediaFormat.KEY_HEIGHT);
            float time = mediaFormat.getLong(MediaFormat.KEY_DURATION) / 1000000;
            callBack.videoAspect(width, height, time);
            videoExtractor.selectTrack(videoTrackIndex);
            try {
                videoCodec = MediaCodec.createDecoderByType(mediaFormat.getString(MediaFormat.KEY_MIME));
                videoCodec.configure(mediaFormat, surface, null, 0);
            } catch (IOException e) {
                e.printStackTrace();
            }

循环从MediaExtractor取数据放入MediaCodec,同时MediaCodec返回数据,表示视频播放状态,然后对应转台做不同的处理,

 while (!Thread.interrupted()) {
            if (!isPlaying) {
                continue;
            }
            //将资源传递到×××
            if (!isVideoEOS) {
                isVideoEOS = putBufferToCoder(videoExtractor, videoCodec, inputBuffers);
            }
            int outputBufferIndex = videoCodec.dequeueOutputBuffer(videoBufferInfo, TIMEOUT_US);
            switch (outputBufferIndex) {
                case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED:
                    Log.v(TAG, "format changed");
                    break;
                case MediaCodec.INFO_TRY_AGAIN_LATER:
                    Log.v(TAG, "超时");
                    break;
                case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED:
                    //outputBuffers = videoCodec.getOutputBuffers();
                    Log.v(TAG, "output buffers changed");
                    break;
                default:
                    //直接渲染到Surface时使用不到outputBuffer
                    //ByteBuffer outputBuffer = outputBuffers[outputBufferIndex];
                    //延时操作
                    //如果缓冲区里的可展示时间>当前视频播放的进度,就休眠一下
                    sleepRender(videoBufferInfo, startMs);
                    //渲染
                    videoCodec.releaseOutputBuffer(outputBufferIndex, true);
                    break;
            }

            if ((videoBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
                Log.v(TAG, "buffer stream end");
                break;
            }
        }//end while

然后是音频,很相似
MediaExtractor获取资源,选择频道,得到MediaFormat,获取一些参数来配置AudioTrack,然后就不说了,上一篇博客说了如何播放音频,

 MediaExtractor audioExtractor = new MediaExtractor();
        try {
            audioExtractor.setDataSource(filePath);
        } catch (IOException e) {
            e.printStackTrace();
        }

           MediaFormat mediaFormat = audioExtractor.getTrackFormat(i);
            String mime = mediaFormat.getString(MediaFormat.KEY_MIME);
            if (mime.startsWith("audio/")) {
                audioExtractor.selectTrack(i);

                int audioChannels = mediaFormat.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
                int audioSampleRate = mediaFormat.getInteger(MediaFormat.KEY_SAMPLE_RATE);
                int minBufferSize = AudioTrack.getMinBufferSize(audioSampleRate,
                        (audioChannels == 1 ? AudioFormat.CHANNEL_OUT_MONO : AudioFormat.CHANNEL_OUT_STEREO),
                        AudioFormat.ENCODING_PCM_16BIT);
                int maxInputSize = mediaFormat.getInteger(MediaFormat.KEY_MAX_INPUT_SIZE);

                    audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
                        audioSampleRate,
                        (audioChannels == 1 ? AudioFormat.CHANNEL_OUT_MONO : AudioFormat.CHANNEL_OUT_STEREO),
                        AudioFormat.ENCODING_PCM_16BIT,
                        audioInputBufferSize,
                        AudioTrack.MODE_STREAM);

其实这做的不太好,因为音频和视频没有做协调,之前可能不同步

完整代码下载地址在文章头部

参考文章:
http://blog.csdn.net/qq_36467463/article/details/77990089
https://www.cnblogs.com/jiy-for-you/p/7282033.html
https://www.jianshu.com/p/6df2ab17651a

另外有需要云服务器可以了解下创新互联scvps.cn,海内外云服务器15元起步,三天无理由+7*72小时售后在线,公司持有idc许可证,提供“云服务器、裸金属服务器、高防服务器、香港服务器、美国服务器、虚拟主机、免备案服务器”等云主机租用服务以及企业上云的综合解决方案,具有“安全稳定、简单易用、服务可用性高、性价比高”等特点与优势,专为企业上云打造定制,能够满足用户丰富、多元化的应用场景需求。


新闻标题:Android音视频深入三MP4解码播放视频(附源码下载)-创新互联
网站链接:http://hbruida.cn/article/csohgd.html