一、MediaCodec 硬编
本质
MediaCodec 是 Android 提供的硬件编解码 API,直接调用底层硬件编码器(高通 Venus、三星 Exynos、联发平台等),绕过 CPU 软编码,功耗低 5-10 倍。它采用 input/output 双队列模型:你往 input buffer 喂原始 YUV 帧,从 output buffer 取编码后的 H.264/H.265 NAL 单元。
两种工作模式
异步模式是 Google 官方推荐的方式,避免了同步模式中 dequeueOutputBuffer 轮询的 CPU 开销和超时问题。
核心流程
plaintext
createEncoderByType("video/avc")
→ configure(MediaFormat) // 设置码率、帧率、IDR间隔、颜色格式
→ start()
→ 循环:
dequeueInputBuffer() → 获取输入buffer索引
queueInputBuffer() → 填入YUV数据 + pts时间戳
dequeueOutputBuffer() → 获取输出buffer索引 + BufferInfo
取出编码后H.264数据 → 判断NAL类型(SPS/PPS/IDR/P帧)
releaseOutputBuffer() → 释放输出buffer
→ stop() / release()
关键参数说明
KEY_MIME:
"video/avc"(H.264) 或"video/hevc"(H.265)KEY_COLOR_FORMAT:最坑的参数。不同芯片支持的格式不同,
COLOR_FormatSurface(API 21+) 最省心,直接用 Surface 输入免去了 YUV 格式适配。如果手动喂 YUV,通常用COLOR_FormatYUV420SemiPlanar(NV12) 或COLOR_FormatYUV420Planar(I420),但必须查询getCodecInfo().getCapabilitiesForType()确认支持KEY_I_FRAME_INTERVAL:IDR 间隔,单位秒,直播设 2-4 秒
KEY_BIT_RATE:码率,直播 1080p 建议 2-4Mbps,720p 建议 1-2Mbps
KEY_FRAME_RATE:帧率,通常 30,低端机可降 24
常见踩坑
SPS/PPS 提取:MediaCodec 输出的第一个 buffer 通常包含 SPS+PPS(
BufferInfo.flags == BUFFER_FLAG_CODEC_CONFIG),必须单独保存并在每个 IDR 帧前发送,否则播放端花屏NAL 单元拆分:MediaCodec 输出的是完整帧(可能含多个 NAL),RTMP 封装时需要按 Annex-B 格式(
00 00 00 01起始码)拆分处理时间戳必须严格递增:
presentationTimeUs单位是微秒,如果时间戳回退或不连续,编码器可能丢帧或输出异常颜色格式兼容性:高通/三星/MTK 平台对 YUV 格式支持不一致,Surface 输入是最安全的方案
低端机 dequeue 超时:同步模式下
dequeueOutputBuffer超时设 10ms,避免长时间阻塞;异步模式无此问题
二、RTMP 推流
RTMP 协议本质
RTMP (Real-Time Messaging Protocol) 是 Adobe 设计的流媒体协议,基于 TCP 长连接。直播推流的标准流程是:
plaintext
TCP 握手 → RTMP 握手 (C0/C1 → S0/S1/S2 → C2)
→ Connect 命令 (App连接)
→ CreateStream
→ Publish 命令 (声明推流)
→ 发送 FLV 音视频数据 (AVC/HEVC Sequence Header + 媒体数据)
FLV 封装
RTMP 不直接传 H.264 裸流,需要封装成 FLV tag:
关键技术点:H.264 NAL 需要转成 AVCC 格式(4 字节长度前缀),而非 Annex-B 格式(起始码 00 00 00 01)。这是 MediaCodec 输出到 RTMP 封装之间需要做的格式转换。
开源库对比
三、主流开源推流框架
1. RootEncoder(原 rtmp-rtsp-stream-client-java)
目前 Android 端最活跃的开源推流框架,支持 RTMP/RTSP/SRT 协议。
优势:
纯 Java/Kotlin 实现,无需 NDK 编译
内置 MediaCodec 硬编封装,自动处理 SPS/PPS 和 NAL 格式转换
支持 Camera2 API + OpenGL ES 美颜滤镜链
活跃维护,社区支持好
典型架构:Camera2 采集 → Surface → MediaCodec 硬编 → H.264 NAL → FLV 封装 → librtmp TCP 发送
2. FFmpeg + libx264 / MediaCodec
FFmpeg 是全能方案,支持通过 h264_mediacodec 直接调用 Android 硬件编码器。
bash
# 典型推流命令
ffmpeg -f android_camera -i 0:0 \
-c:v h264_mediacodec -b:v 2M -s 1080x720 \
-c:a aac -b:a 128k \
-f flv rtmp://server/live/streamkey
优势:协议支持全面(RTMP/SRT/RTSP/WebRTC),滤镜生态丰富
劣势:库体积大(10-30MB),启动慢,内存占用高
3. SRS (Simple Realtime Server)
服务端方案,不仅是 RTMP 接收方,还支持转码、转协议(RTMP → HLS/WebRTC)、集群推流。生产环境部署最常用的开源流媒体服务器。
4. WebRTC
严格来说不是 RTMP 方案,但它是低延迟直播的趋势。WebRTC 用 SRTP over UDP,延迟可控制在 300ms 以内,而 RTMP 通常 1-3 秒。如果对延迟要求极高,可以 RTMP 推流 → SRS 转 WebRTC 播放。
四、MediaCodec + RTMP 的典型集成架构
生产环境典型架构如下:
plaintext
Camera2 采集 (YUV)
→ OpenGL ES 渲染 (美颜/滤镜/水印)
→ EGL Surface → MediaCodec 硬编 (H.264 NAL)
→ NAL 格式转换 (Annex-B → AVCC)
→ FLV Muxer (拼装 Sequence Header + 媒体Tag)
→ RTMP 协议层 (Chunk 封装 + TCP 发送)
→ CDN / SRS 服务器
其中几个关键衔接点:
Surface 输入:Camera2 → MediaCodec 用 Surface 直连,GPU 零拷贝,避免 YUV 格式兼容问题
SPS/PPS 拦截:MediaCodec 输出的第一个 codec-config buffer 需要解析出 SPS/PPS,拼成 AVC Sequence Header 发给 RTMP
音视频同步:音频用 AAC 编码器(MediaCodec
audio/mp4a-latm),音频和视频的 FLV tag 必须按 DTS 排序发送,时间戳差值控制在 ±50ms 内重连机制:TCP 断开后自动重连,重连后重新发送 Sequence Header(SPS/PPS/AAC Config),确保播放端能正确初始化解码器
这套架构在 RootEncoder 和各大厂自研 SDK(腾讯云 LiteAV、阿里云推流 SDK、字节火山引擎)中都有类似的实现路径。
MediaCodec硬编与RTMP推流管线图
