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

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

本篇项目地址,名字是媒体解码MediaCodec,MediaExtractor,求star

这次要用到新的东西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);

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

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

参考文章:

转载于:https://blog.51cto.com/13591594/2068426

你可能感兴趣的文章
用微信玩转你的品牌-布乔
查看>>
2014年大数据发展趋势预测及其解读
查看>>
我的友情链接
查看>>
田传钊:旅游行业成功案例
查看>>
我的友情链接
查看>>
Linux进程与性能监控
查看>>
思想:CoreMVC为什么只有一个文件(5)
查看>>
OsiriX Graphic User Interface
查看>>
spark ml的回归分析
查看>>
对webservice的一些简单理解
查看>>
深入理解spring注解@PropertySource的实现原理
查看>>
关于滨野纯的访谈
查看>>
前线解释多线程《一》
查看>>
WordPress禁止全英文的垃圾评论内容的方案
查看>>
mydumper安装和使用
查看>>
微信小程序开发之分包
查看>>
使用 Exception 写出优雅的代码
查看>>
如何重置本地开发环境的MYSQL密码
查看>>
Solutions Log (2014-06)
查看>>
搭建 JAVA Web 开发环境(CentOS 6.8 64 位)
查看>>