Android音视频开发之MediaCodec的使用教程

 更新时间:2022年04月29日 10:48:02   作者:JulyYu  
在Android开发中提供了实现音视频编解码工具MediaCodec,针对对应音视频解码类型通过该类创建对应解码器就能实现对数据进行解码操作。本文通过示例详细讲解了MediaCodec的使用,需要的可以参考一下

前言

获取到音视频轨道(编解码格式),知道设备支持哪些编解码器,下一步就是创建编解码器去实现数据流的编解码过程了。在Android开发中提供了实现音视频编解码工具MediaCodec,针对对应音视频解码类型通过该类创建对应解码器就能实现对数据进行解码操作。

MediaCodec

MediaCodec所支持的数据类型:压缩的音视频数据、原始音频数据和原始视频数据。 首先show代码,紧接着之前MediaExtactor提取资源,MediaCodecList遍历支持格式,确认设置支持该资源格式后通过MediaCodec创建解码器(这里是做视频解码播放)。

// 加载资源
extractor.setDataSource(path);
// 获取视频轨道
int trackIndex = getTrackIndex(extractor,"video/");
// 获取视频轨道参数
MediaFormatInfo mediaFormatInfo = MediaFormatInfo.buildUpVideoMediaFormatInfo(extractor.getTrackFormat(trackIndex));
// 选取上述的视频轨道
extractor.selectTrack(trackIndex);
MediaCodecInfo mediaCodecInfo = CodecInfoInstance.getInstance().selectDeCodec(mediaFormatInfo.getMime());
// 判断设备是否支持该视频解码,创建视频编码器
if(mediaCodecInfo != null){
    mediaCodec = MediaCodec.createDecoderByType(mediaFormatInfo.getMime());
    mediaCodec.configure(mediaFormatInfo.getMediaFormat(),surface,null,0);
}

编解码流程

  • MediaCodec的功能其实很简单通过一个数据缓冲去,将数据填充到输入缓冲区给到Codec
  • Codec通过异步方式处理输入缓冲区数据将处理好数据填充到输出缓冲区
  • 客户端从输出缓冲区获取到处理好的数据去消费,最后把缓冲区返还给Codec

部分代码实现

  • dequeueInputBuffer:从输入流队列取数据进行编码操作
  • getInputBuffers: 获取需要编码数据的输入队列 返回ByteBuffer数组
  • queueInoutBuffer: 输入流入队列
  • dequeueOutputBuffer: 从输入队列中取出编码操作结果数据
  • getOutPutBuffer: 获取编解码之后数据输出队列 返回一个ByterBuffer数组
  • releaseOutPutBuffer: 处理完成释放ByterBuffer数组
while (!isEnd && !isInterrupted()){
    if (!mIsEOS) {
        mIsEOS = dequeueInputBuffers();
    }
    isEnd = dequeueOutputBuffers();
}

//输入缓冲区
private boolean dequeueInputBuffers() {
    boolean isMediaEOS = false;
    //  等待编码器输入缓冲区数据出队
    int inputBufferId = mediaCodec.dequeueInputBuffer(TIMEOUT_US);
    if (inputBufferId >= 0) {
        // 获取缓存区数据
        ByteBuffer inputBuffer = mediaCodec.getInputBuffer(inputBufferId);
        // 读取数据 返回值sampleSize大于0表示还有数据,否则表示结束
        int sampleSize = extractor.readSampleData(inputBuffer, 0);
        if (sampleSize < 0) {
            // 数据末尾 必须再次调用queueInputBuffer使用BUFFER_FLAG_END_OF_STREAM标识符输入到编码器
            mediaCodec.queueInputBuffer(inputBufferId, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
            isMediaEOS = true;
            MediaLogUtils.printI(TAG + "end of stream");
        } else {
            // 输入缓冲区数据入队
            mediaCodec.queueInputBuffer(inputBufferId, 0, sampleSize, extractor.getSampleTime(), 0);
            extractor.advance();
        }
    }
    return isMediaEOS;
}

//输出缓冲区
private synchronized boolean dequeueOutputBuffers() {
    MediaCodec.BufferInfo outBufferInfo = new MediaCodec.BufferInfo();
    //输出缓冲区
    int outputBufferId = mediaCodec.dequeueOutputBuffer(outBufferInfo, TIMEOUT_US);
    switch (outputBufferId) {
        case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED:
            MediaLogUtils.printI(TAG+"INFO_OUTPUT_FORMAT_CHANGED");
            break;
        case MediaCodec.INFO_TRY_AGAIN_LATER:
            MediaLogUtils.printI(TAG+ "INFO_TRY_AGAIN_LATER");
            break;
        case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED:
            MediaLogUtils.printI(TAG+ "INFO_OUTPUT_BUFFERS_CHANGED");
            break;
        default:
            // 延迟解码
            decodeDelay(outBufferInfo, mStartMs);
            // 释放输出缓冲区数据 render为true渲染到surface上
            mediaCodec.releaseOutputBuffer(outputBufferId, true);
            break;
    }
    // 结尾
    if ((outBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
        MediaLogUtils.printI(TAG+"buffer stream end");
        return true;
    }
    return false;
}

生命周期

MediaCodec生命周期分为三种状态:StoppedExecutingReleased

  • Stopped具有三种子状态:Uninitialized、Configured、Error
  • Executing具有三种子状态:Flushed、Running、End-of-Stream

Stopped

Uninitialized: UninitializedMediaCodec创建后初始状态。可通过reset()复位到Uninitialized

Configured: MediaCodec通过configure方法设置配置(编解码器类型等)进入到Configured状态。

Error: MediaCodec发生异常情况下会进入Error状态。

Executing

Flush:MediaCodec调用start方法后进入FlushedMediaCodec就具备所有缓存能力。若可以在Executing,调用flush()回到Flushed状态。

Running: 当第一次InputBuffer输入缓存被移除队列,MediaCodec就会进入到Running状态。

End-of-Stream:将end-of-stream标记输入InputBuffer队列,MediaCodec就会进入到 End-of-Stream状态,MediaCodec就不再接收InputBuffer,但不影响输出队列OutBuffer产出直到end-of-stream标记输出为止(输入和输出中间是有一定处理时间)。

接口简介

createDecoderByType/createEncoderByType,创建解码器/编码器对象

createByCodecName,根据编解码器名称创建

configure,配置编解码器配置

start,配置完成后需要执行start完成配置

dequeueInputBuffer, 输入队列取数据编码操作

queueInputBuffer,输入入队列

dequeueOutputBuffer,从输出队列取出编码操作后的数据

releaseOutputBuffer,释放输出队列释放ByteBuffer数据

getInputBuffers,获取需要编码数据输入流队列,返回ByteBuffer数组

getOutputBuffers,获取编解码后数据输出流队列,返回ByteBuffer数组

flush,清空输入和输出端口

stop,终止decode/encode会话

release,释放编解码器资源

参考文章

到此这篇关于Android音视频开发之MediaCodec的使用教程的文章就介绍到这了,更多相关Android MediaCodec内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Flutter 中检测常用的命令详解

    Flutter 中检测常用的命令详解

    这篇文章主要介绍了Flutter 中检测常用的命令详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-08-08
  • Android ScrollView实现横向和竖向拖动回弹效果

    Android ScrollView实现横向和竖向拖动回弹效果

    这篇文章主要为大家详细介绍了Android ScrollView实现横向和竖向拖动回弹效果,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-09-09
  • Android 自定义TextView实现滑动解锁高亮文字

    Android 自定义TextView实现滑动解锁高亮文字

    这篇文章主要介绍了Android 自定义TextView实现滑动解锁高亮文字的相关资料,需要的朋友可以参考下
    2018-03-03
  • Android关于获取时间的记录(小结)

    Android关于获取时间的记录(小结)

    这篇文章主要介绍了Android关于获取时间的记录(小结),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-04-04
  • Android开关控件Switch的使用案例

    Android开关控件Switch的使用案例

    今天小编就为大家分享一篇关于Android开关控件Switch的使用案例,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-03-03
  • kotlin的函数forEach示例详解

    kotlin的函数forEach示例详解

    在 Kotlin 中,forEach 是一个高阶函数,用于遍历集合中的每个元素并对其执行指定的操作,它的核心特点是 简洁、函数式,适用于需要遍历集合且无需返回值的场景,这篇文章主要介绍了kotlin的函数forEach示例详解,需要的朋友可以参考下
    2025-03-03
  • Android项目开发 教你实现Periscope点赞效果

    Android项目开发 教你实现Periscope点赞效果

    这篇文章主要为大家分享了Android项目开发,一步一步教你实现Periscope点赞效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2015-12-12
  • Android ViewDragHelper使用介绍

    Android ViewDragHelper使用介绍

    ViewDragHelper是support.v4下提供的用于处理拖拽滑动的辅助类。接下来通过本文给大家介绍Android ViewDragHelper使用,感兴趣的朋友一起看看吧
    2017-08-08
  • 浅析Android TextView常用属性

    浅析Android TextView常用属性

    TextView是用来显示文本的组件。这篇文章给大家详细介绍了Android TextView常用属性 ,需要的朋友参考下
    2018-04-04
  • Android实战APP启动速度优化

    Android实战APP启动速度优化

    本篇文章给大家通过实战总结了Android开发APP启动速度优化的方法以及需要注意的地方,有需要的朋友可以参考下。
    2018-05-05

最新评论