赞
踩
在上一个的文章Android 音视频编解码(一) – MediaCodec 初探 中,已经对 MediaCodec 有个感性的认知,这一章,来学习 MediaCodec 的解码功能。
本章效果如下:
为了更好的理解 MediaCodec 的工作原理和工作步骤,首先先使用同步解码的方式去解码本地视频。
首先,我们先要准备一个视频,比如 MP4 格式的,它其实已经被编码过的,我们可以通过 MediaCodec 来获取该视频的 MediaFormat 信息,如果你对 MediaExtractor 不熟悉,可以通过 Android 音视频开发(五) – 使用 MediaExtractor 分离音视频,并使用 MediaMuxer合成新视频(音视频同步) 来学习;
定义一个 MyExtractor ,里面实现 MediaExtractor 用来专门解析视频,拿到视频数据:
- public MyExtractor(String path) {
- try {
- mediaExtractor = new MediaExtractor();
- // 设置数据源
- mediaExtractor.setDataSource(path);
- } catch (IOException e) {
- e.printStackTrace();
- }
- //拿到所有的轨道
- int count = mediaExtractor.getTrackCount();
- for (int i = 0; i < count; i++) {
- //根据下标拿到 MediaFormat
- MediaFormat format = mediaExtractor.getTrackFormat(i);
- //拿到 mime 类型
- String mime = format.getString(MediaFormat.KEY_MIME);
- //拿到视频轨
- if (mime.startsWith("video")) {
- videoTrackId = i;
- videoFormat = format;
- } else if (mime.startsWith("audio")) {
- //拿到音频轨
- audioTrackId = i;
- audioFormat = format;
- }
-
- }
- }
-
-
- public void selectTrack(int trackId){
- mediaExtractor.selectTrack(trackId);
- }
-
- /**
- * 读取一帧的数据
- *
- * @param buffer
- * @return
- */
- public int readBuffer(ByteBuffer buffer) {
- //先清空数据
- buffer.clear();
- //选择要解析的轨道
- // mediaExtractor.selectTrack(video ? videoTrackId : audioTrackId);
- //读取当前帧的数据
- int buffercount = mediaExtractor.readSampleData(buffer, 0);
- if (buffercount < 0) {
- return -1;
- }
- //记录当前时间戳
- curSampleTime = mediaExtractor.getSampleTime();
- //记录当前帧的标志位
- curSampleFlags = mediaExtractor.getSampleFlags();
- //进入下一帧
- mediaExtractor.advance();
- return buffercount;
- }

首先,先通过 selectTrack 来指定是解析视频还是音频,接着使用 readBuffer 这个方法,该方法使用 mediaExtractor.readSampleData(buffer, 0); 去拿到当前视频的 buffer,并通过 mediaExtractor.advance() 拿到下一帧的数据。
上一章说到 MediaCodec 的解码是基于以下两张图的:
MediaCodec 工作图
MediaCodec状态图
如果你对这两张图的流程不熟悉,请阅读 Android 音视频编解码(一) – MediaCodec 初探 。
为了方便后续的音频解码,这里我们定义一个基类,用来解析视频和音频,由于是同步解析视频,我们应该在线程中去解析,所以继承 Runnable:
- /**
- * 解码基类,用于解码音视频
- */
- abstract class BaseDecode implements Runnable {
- final static int VIDEO = 1;
- final static int AUDIO = 2;
- //等待时间
- final static int TIME_US = 1000;
- MediaFormat mediaFormat;
- MediaCodec mediaCodec;
- MyExtractor extractor;
-
- private boolean isDone;
- public BaseDecode() {
- try {
- //获取 MediaExtractor
- extractor = new MyExtractor(Constants.VIDEO_PATH);
- //判断是音频还是视频
- int type = decodeType();
- //拿到音频或视频的 MediaFormat
- mediaFormat = (type == VIDEO ? extractor.getVideoFormat() : extractor.getAudioFormat());
- String mime = mediaFormat.getString(MediaFormat.KEY_MIME);
- //选择要解析的轨道
- extractor.selectTrack(type == VIDEO ? extractor.getVideoTrackId() : extractor.getAudioTr

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。