Administrator
发布于 2026-08-08 / 17 阅读
0
0

说下对开源框架的了解:MediaCodec 硬编,RTMP 推流

一、MediaCodec 硬编

本质

MediaCodec 是 Android 提供的硬件编解码 API,直接调用底层硬件编码器(高通 Venus、三星 Exynos、联发平台等),绕过 CPU 软编码,功耗低 5-10 倍。它采用 input/output 双队列模型:你往 input buffer 喂原始 YUV 帧,从 output buffer 取编码后的 H.264/H.265 NAL 单元。

两种工作模式

模式

API 版本

特点

适用场景

同步模式

API 16+

dequeueInputBuffer / dequeueOutputBuffer 轮询,阻塞等待

简单场景,旧设备兼容

异步模式

API 23+ (Android 6.0)

回调驱动 setCallback,不阻塞线程

生产环境推荐,性能更好

异步模式是 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

常见踩坑

  1. SPS/PPS 提取:MediaCodec 输出的第一个 buffer 通常包含 SPS+PPS(BufferInfo.flags == BUFFER_FLAG_CODEC_CONFIG),必须单独保存并在每个 IDR 帧前发送,否则播放端花屏

  2. NAL 单元拆分:MediaCodec 输出的是完整帧(可能含多个 NAL),RTMP 封装时需要按 Annex-B 格式(00 00 00 01 起始码)拆分处理

  3. 时间戳必须严格递增:presentationTimeUs 单位是微秒,如果时间戳回退或不连续,编码器可能丢帧或输出异常

  4. 颜色格式兼容性:高通/三星/MTK 平台对 YUV 格式支持不一致,Surface 输入是最安全的方案

  5. 低端机 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:

Tag 类型

内容

说明

Script (0x12)

onMetaData

视频元信息(分辨率、码率、时长等)

Video (0x09)

AVC Sequence Header

SPS + PPS,首帧发送

Video (0x09)

AVC NALU

实际视频帧,区分 IDR(关键帧)和 P 帧

Audio (0x08)

AAC Sequence Header

AudioSpecificConfig

Audio (0x08)

AAC Raw

实际音频帧

关键技术点:H.264 NAL 需要转成 AVCC 格式(4 字节长度前缀),而非 Annex-B 格式(起始码 00 00 00 01)。这是 MediaCodec 输出到 RTMP 封装之间需要做的格式转换。

开源库对比

库

语言

特点

适用场景

librtmp / rtmpdump

C

最经典的 RTMP 实现,轻量但已停止维护

早期方案,兼容性好

yasea

Java

纯 Java RTMP 推流,集成 MediaCodec

快速原型,适合学习

RootEncoder (rtmp-rtsp-stream-client-java 继任)

Java

支持 RTMP/RTSP/SRT,活跃维护

Android 推流首选

srs (Simple Realtime Server)​

C++

RTMP 服务器 + 推拉流,生态完整

服务端方案

FFmpeg

C

全能选手,支持 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推流管线图


评论