深入浅出安卓MediaCodec

深入浅出安卓MediaCodec

一、MediaCodec是啥?

MediaCodec就像视频工厂的生产线

  • 原材料:原始视频/音频数据(H.264、AAC等)
  • 生产线:编码(打包)或解码(拆包)
  • 产品:处理后的数据(如MP4文件或播放画面)

二、核心概念大白话

1. 编解码器类型

类型 作用 例子
视频编码 把摄像头数据压缩成H.264 录像保存
视频解码 把H.264解压成可播放画面 视频播放
音频编码 把麦克风数据转成AAC 录音
音频解码 把AAC还原成声音波形 音乐播放

2. 数据处理流程

graph LR A[输入数据] --> B[MediaCodec] B --> C{编码/解码} C --> D[输出数据]

三、MediaCodec工作五步走

第一步:创建编解码器

java 复制代码
// 创建H.264解码器
MediaCodec decoder = MediaCodec.createDecoderByType("video/avc");

// 创建AAC编码器
MediaCodec encoder = MediaCodec.createEncoderByType("audio/mp4a-latm");

第二步:配置参数

java 复制代码
// 视频解码配置(以H.264为例)
MediaFormat format = MediaFormat.createVideoFormat("video/avc", width, height);
format.setInteger(MediaFormat.KEY_COLOR_FORMAT, 
    MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);
format.setInteger(MediaFormat.KEY_BIT_RATE, bitRate);
format.setInteger(MediaFormat.KEY_FRAME_RATE, frameRate);
format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, iFrameInterval);

decoder.configure(format, surface, null, 0); // surface用于渲染

第三步:启动生产线

java 复制代码
decoder.start();
encoder.start();

**第四步:喂数据 & 取结果

java 复制代码
// 输入数据(生产者)
ByteBuffer[] inputBuffers = decoder.getInputBuffers();
int inputIndex = decoder.dequeueInputBuffer(timeout);
if (inputIndex >= 0) {
    ByteBuffer buffer = inputBuffers[inputIndex];
    buffer.put(rawData); // 填入原始数据
    decoder.queueInputBuffer(inputIndex, 0, rawData.length, timestamp, 0);
}

// 获取结果(消费者)
ByteBuffer[] outputBuffers = decoder.getOutputBuffers();
MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
int outputIndex = decoder.dequeueOutputBuffer(info, timeout);
if (outputIndex >= 0) {
    ByteBuffer buffer = outputBuffers[outputIndex];
    // 处理解码后的数据...
    decoder.releaseOutputBuffer(outputIndex, true); // true表示渲染到surface
}

第五步:收尾工作

java 复制代码
decoder.stop();
decoder.release(); // 必须释放!

四、关键技巧

1. 异步模式(推荐)

java 复制代码
// 设置回调
decoder.setCallback(new MediaCodec.Callback() {
    @Override
    void onInputBufferAvailable(MediaCodec mc, int index) {
        // 填充数据...
    }
    
    @Override
    void onOutputBufferAvailable(...) {
        // 获取解码数据...
    }
});

2. Surface直接输入/输出

java 复制代码
// 从Camera直接输入
Surface inputSurface = encoder.createInputSurface();
camera.setPreviewSurface(inputSurface);

// 直接输出到SurfaceView
Surface outputSurface = surfaceView.getHolder().getSurface();
decoder.configure(format, outputSurface, null, 0);

3. 码率控制模式

java 复制代码
format.setInteger(MediaFormat.KEY_BITRATE_MODE, 
    MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_VBR); // 可变码率

五、避坑指南

1. 常见崩溃原因

  • 未释放资源:每次create后必须release
  • 格式不匹配:输入数据必须符合配置格式
  • 线程阻塞:同步模式下别在主线程操作

2. 兼容性问题

java 复制代码
// 检查设备支持的编解码器
MediaCodecList list = new MediaCodecList(MediaCodecList.ALL_CODECS);
MediaCodecInfo[] infos = list.getCodecInfos();
for (MediaCodecInfo info : infos) {
    if (info.isEncoder()) { // 是否是编码器
        String[] types = info.getSupportedTypes();
        // ...
    }
}

3. 性能优化

  • 使用硬件加速 :优先选择OMX.qcom/OMX.exynos开头的编解码器
  • 批处理帧:减少频繁调用queue/dequeue
  • 合理设置Buffer大小:根据分辨率调整

六、实战案例

案例:手机直播推流

  1. 视频流
    • Camera → Surface → MediaCodec(H.264编码) → RTMP打包
  2. 音频流
    • AudioRecord → MediaCodec(AAC编码) → RTMP打包
  3. 合并
    • MediaMuxer合成音视频流

七、MediaCodec高级玩法

  • 视频编辑:解码→处理(滤镜/裁剪)→编码
  • 屏幕录制MediaProjection + VirtualDisplay
  • 硬解播放器 :替代MediaPlayer实现自定义渲染

八、终极口诀

"创建配置要记牢,输入输出两条道

同步异步看场景,Surface直通效率高

格式匹配很重要,用完释放不泄漏

硬编硬解真给力,音视频处理离不了"

掌握MediaCodec,你就能玩转安卓音视频处理的"核心引擎"! 🎬🔊

相关推荐
suki_lynn2 小时前
Facebook 引流脚本:功能、风险与合规使用指南
android·云计算
帅锅锅0072 小时前
Android 源码学习之init进程
android·架构·操作系统
聆风吟º2 小时前
【Spring Boot 报错已解决】Spring Boot开发避坑指南:Hibernate实体类主键配置详解与异常修复
android·spring boot·hibernate
APP出海3 小时前
Google政策大更新:涉及金融(个人贷款),社交约会与游戏(未成年人相关),健康等所有类别App
android·游戏·金融·产品运营·产品经理
全栈软件开发4 小时前
音频在线剪切助手网页版源码
android·音视频
2501_915909064 小时前
Flutter 应用怎么加固,多工具组合的工程化实战(Flutter 加固/Dart 混淆/IPA 成品加固/Ipa Guard + CI)
android·flutter·ios·ci/cd·小程序·uni-app·iphone
qq_717410015 小时前
添加快速点击设置-关于设备-版本号弹出仿android13彩蛋
android
KdanMin5 小时前
Android MediaCodec 硬编解码实战:从Camera预览到H264流与回环渲染
android·开发语言
峰哥的Android进阶之路5 小时前
Android常见的内存性能优化场景解决方案
android·性能优化