Android 音视频编解码 MediaCodec

MediaCodec 简介

Android中的MediaCodec是一个用于音视频编解码功能的API,使用它可以实现对音视频数据进行压缩、解压缩、编辑和转换。以下是MediaCodec的主要功能:

  1. 支持多种流媒体格式:包括H.264、AAC、VP8等等。

  2. 可以用于实时处理:通过显卡硬解实现低延迟的录制与播放。

  3. 高效:采用底层编码编解码, 能体现高效率和性能,特别适合在高机器配置下处理模式。

  4. 强大的 APIs:支持一系列 API,例如 Android 5.0 以上的 setCallback() 或新的异步方式做双向通信任务,MediaCodec 提供了更多操作控制。

MediaCodec 使用步骤

  1. 配置:创建 MediaCodec 实例并选择所需的输入/输出流格式。

  2. 输入数据:将编码数据送入解码器进行处理。获取输入缓冲区后,您需要填充其数据(例如从文件中读取),然后通过调用 queueInputBuffer() 将缓冲区提交给 MediaCodec 进行处理。

  3. 输出数据:MediaCodec 解码器处理数据后,在输出缓冲区产生所需的 PCM 视频数组或音频信号数组。可以访问输出缓冲区以获取已解码的数据(Ouput buffer)。MediaCodec 回传数据帧描述释放这一信息。

  4. 释放资源:使用完 MediaCodec 后必须销毁它。如果有任何未达到 EOS 并且不再需要的输入或输出缓存区,则必须停止播放并释放所有资源以避免泄漏。

## MediaCodec 常用方法

  1. MediaCodec.createDecoderByType(String mimeType):创建解码器

  2. MediaFormat MediaExtractor.getTrackFormat(int index): 获取媒体文件流的格式。此格式通常包含编解码标准及相关参数等。

  3. ByteBuffer[] MediaCodec.getInputBuffers(): 获取输入缓冲区。

  4. ByteBuffer[] MediaCodec.getOutputBuffers(): 获取输出缓冲区。

  5. int MediaCodec.dequeueInputBuffer(long timeoutUs): 请求一个空闲的解码器输入缓冲区,其中timeoutUs表示请求最大等待时间(微秒)。

  6. void MediaCodec.queueInputBuffer(int index, int offset, int size, long presentationTimeUs, int flags): 添加输入数据到指定的缓冲区及其时间戳信息。

  7. int MediaCodec.dequeueOutputBuffer(BufferInfo info, long timeoutUs): 等待并返回输出缓冲区索引。BufferInfo包含了解码器相关信息和属性,例如已解码数据大小、 PTS、DTS等。

  8. void MediaCodec.releaseOutputBuffer(int index, boolean render): 释放输出缓冲区以便进行下一次解析操作。

  9. void MediaCodec.flush(): 清空所有未处理输入/输出缓冲区,并将解码器重置持状态到初始状态。

  10. void MediaCodec.stop(): 结束并停止正在运行的MediaCodec。

  11. void MediaCodec.release(): 释放资源。

MediaCodec 示例

以下是一个 MediaCodec 实例的简单示例代码,该示例代码从文件 M file 中读取 AAC 音频流并将其解码到 PCM 缓冲区中:

// 创建MediaExtractor来获取已编码的音频数据
MediaExtractor extractor = new MediaExtractor();
extractor.setDataSource(M_FILE);
int audioTrackIndex = selectTrack(extractor, MIME_TYPE_AUDIO);
extractor.selectTrack(audioTrackIndex);

MediaFormat inputFormat = extractor.getTrackFormat(audioTrackIndex);
String mimeType = inputFormat.getString(MediaFormat.KEY_MIME);
long durationUs = inputFormat.getLong(MediaFormat.KEY_DURATION);

// 创建解码器并配置为解码音频
MediaCodec codec = MediaCodec.createDecoderByType(mimeType);
codec.configure(inputFormat, null, null, 0);
codec.start();

// 获取解码器的输入和输出缓冲区
ByteBuffer[] codecInputBuffers = codec.getInputBuffers();
ByteBuffer[] codecOutputBuffers = codec.getOutputBuffers();

// 循环读取音频数据并且解码
try {
    
    
    boolean decodeDone = false;
    while (!decodeDone) {
    
    
        int inputBufferIndex = codec.dequeueInputBuffer(-1);
        if (inputBufferIndex >= 0) {
    
    
            // 将从文件中读取的音频编码数据放入到解码器的输入缓存区中
            ByteBuffer inputBuffer = codecInputBuffers[inputBufferIndex];
            int sampleSize = extractor.readSampleData(inputBuffer, 0);
            if (sampleSize < 0) {
    
    
                codec.queueInputBuffer(inputBufferIndex, 0, 0, 0L, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
                decodeDone = true;
            } else {
    
    
                long presentationTimeUs = extractor.getSampleTime();
                codec.queueInputBuffer(inputBufferIndex, 0, sampleSize, presentationTimeUs, 0);
                extractor.advance();
            }
        }

        //将解码后的PCM音频数据保存在byte数组decodingFrame中。
        MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
        int outputBufferIndex = codec.dequeueOutputBuffer(info, TIMEOUT_US);
        if (outputBufferIndex >= 0) {
    
    
            ByteBuffer outputBuffer = codecOutputBuffers[outputBufferIndex];
            byte[] decodingFrame = new byte[info.size];
            outputBuffer.get(decodingFrame);
            outputBuffer.clear();
            codec.releaseOutputBuffer(outputBufferIndex, false);
        } 
    }

} finally {
    
    

    // 释放一些资源   
    codec.stop();
    codec.release();
    extractor.release();
}

需要注意的是,以上示例代码只能供参考使用,实际使用时需要根据具体情况进行修改和优化。

ffmpeg 和 MediaCodec对比

ffmpeg 和 MediaCodec 都是用于音视频处理的工具,它们有一些共同之处,但也存在很多不同点。

ffmpeg 是一个跨平台的开源集成工具包,可用于解码、编码、转换和播放各种音视频格式。ffmpeg 提供了广泛的功能,可以在命令行中使用,也可以作为库在其他项目中使用,适用于多种操作系统和语言。它支持各种音视频编解码器、滤镜、容器格式等,并且提供了非常灵活的配置选项。

MediaCodec 是 Android 平台上的 API,用于对视频和音频进行硬件加速编解码,以提高性能并减少功耗。MediaCodec 可以与 OpenGL ES 结合使用,使开发者能够通过硬件加速将每个视频帧直接传输到 GPU 上,从而更快地渲染图像。另外,MediaCodec 还提供了基于 Surface 对象的编解码接口,这意味着应用程序可以直接访问硬件,并在屏幕上渲染视频帧。但是,MediaCodec 只是针对 Android 平台的编解码 API,无法在其他平台上使用,而且其功能相对 ffmpeg 较为有限。

总的来说,ffmpeg 提供了比较全面的视频处理功能,并且可以适用于各种操作系统和平台,而 MediaCodec 则主要是针对 Android 平台的硬件加速编解码 API。使用哪个工具取决于你的需求和平台限制。

猜你喜欢

转载自blog.csdn.net/weixin_44008788/article/details/130291003