博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android 音视频深入 三 MP4解码播放视频 (附源码下载)
阅读量:7095 次
发布时间:2019-06-28

本文共 5264 字,大约阅读时间需要 17 分钟。

本篇项目地址,名字是媒体解码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

 

转载于:https://www.cnblogs.com/jianpanwuzhe/p/8409062.html

你可能感兴趣的文章
初识Web
查看>>
技本功丨技能get,React的优雅升级!
查看>>
102. Binary Tree Level Order Traversal
查看>>
1048 数字加密 (20 分)java
查看>>
vue源码分析系列之响应式数据(一)
查看>>
微信直接下载APP的解决方案
查看>>
2019年第一份DApp调查报告出炉
查看>>
实现一个平行四边形
查看>>
PAT A1122
查看>>
PHP面试常考内容之面向对象(3)
查看>>
React16性能改善的原理一
查看>>
PHP 实现归并排序算法
查看>>
K3s初探:Rancher架构师带你尝鲜史上最轻量Kubernetes发行版
查看>>
UI2Code智能生成Flutter代码--整体设计篇
查看>>
ESLint简介
查看>>
vscode插件列表及配置信息
查看>>
时序数据库连载系列: 时序数据库一哥InfluxDB之存储机制解析
查看>>
java分页算法
查看>>
spring-boot List转Page
查看>>
区块链技术的基本特点都有哪些?
查看>>