背景与定位
Rockchip 平台上有两套多媒体 API:MPP 和 Rockit。两者不是替代关系,而是分层关系——Rockit 在上层,MPP 在底层。
MPP(Media Process Platform) 2015 年开源,只做一件事:视频编解码硬件加速。API 简单,代码在 GitHub 上。
Rockit 2021 年随 RK356X/RK3588 推出,闭源,覆盖完整多媒体管线:采集、缩放、编解码、显示、音频、ISP,模块之间支持零拷贝绑定。编解码部分底层仍然调用 MPP。
简单说:只做编解码用 MPP,要做完整视频系统用 Rockit。
API 设计思路
MPP:一个上下文搞定编解码
MPP 的核心抽象是一个 MppCtx,配上函数指针操作:
MppCtx ctx;
MppApi *mpi;
mpp_create(&ctx, &mpi);
mpp_init(ctx, MPP_CTX_ENC, MPP_VIDEO_H264);
// 同步模式
mpi->encode(ctx, input_frame, &output_packet);
// 异步模式
mpi->encode_put_frame(ctx, frame);
mpi->encode_get_packet(ctx, &packet);
// 高级:Task 模型,适合多线程
mpi->poll(ctx, MPP_PORT_INPUT, MPP_POLL_NON_BLOCK);
mpi->dequeue(ctx, MPP_PORT_OUTPUT, &task);
mpi->enqueue(ctx, MPP_PORT_INPUT, task);
mpp_destroy(ctx);编码和解码用同一套 API,通过 MPP_CTX_ENC/DEC 区分。它不关心数据从哪来、到哪去——你给它帧,它给你码流,仅此而已。
Rockit:模块化管线
Rockit 把系统拆成独立模块(VI/VPSS/VENC/VO 等),每个模块有独立的通道管理:
RK_MPI_SYS_Init();
// 创建编码通道
VENC_CHN_ATTR_S attr = {0};
attr.stVencAttr.enType = RK_VIDEO_ID_AVC;
RK_MPI_VENC_CreateChn(0, &attr);
RK_MPI_VENC_StartRecvFrame(0, NULL);
// 方式一:绑定模式(零拷贝,推荐)
MPP_CHN_S src = {RK_ID_VI, 0, 0};
MPP_CHN_S dst = {RK_ID_VENC, 0, 0};
RK_MPI_SYS_Bind(&src, &dst);
// 绑定后 VI 的帧自动流入 VENC
// 方式二:手动模式(需要中间处理时用)
VIDEO_FRAME_INFO_S frame;
RK_MPI_VI_GetChnFrame(0, 0, &frame, -1);
// ... 应用处理 ...
RK_MPI_VENC_SendFrame(0, &frame, -1);
RK_MPI_VI_ReleaseChnFrame(0, 0, &frame);
// 清理
RK_MPI_SYS_UnBind(&src, &dst);
RK_MPI_VENC_StopRecvFrame(0);
RK_MPI_VENC_DestroyChn(0);
RK_MPI_SYS_Exit();关键区别:Rockit 的模块可以绑定,数据在内核层零拷贝流转,应用层不用搬内存。
功能覆盖
| 功能 | MPP | Rockit |
|---|---|---|
| H.264/H.265/JPEG/VP8/VP9/AV1 编解码 | ✅ | ✅ |
| 视频输入 (VI) | — | ✅ |
| 视频输出 (VO) | — | ✅ |
| 视频处理缩放 (VPSS) | — | ✅ |
| 图形叠加 (VGS/RGN) | — | ✅ |
| 2D 加速 (TDE) | — | ✅ |
| 音频输入输出/编解码 | — | ✅ |
| 智能分析 (IVS) | — | ✅ |
| 畸变校正 (GDC) | — | ✅ |
| 视频拼接 (AVS) | — | ✅ |
| 模块绑定 (Bind) | — | ✅ |
| ISP 图像质量 (配合 RKAIQ) | — | ✅ |
MPP 只管编解码,其余全是 Rockit 独占。
内存管理
两者都用物理连续内存(DMA 需要),但管理方式不同:
// MPP:MppBuffer
MppBuffer buf;
mpp_buffer_get(group, &buf, size);
void *ptr = mpp_buffer_get_ptr(buf); // 只有虚拟地址
mpp_buffer_put(buf);
// Rockit:MB_BLK(三地址互转)
MB_BLK blk;
RK_MPI_SYS_MmzAlloc(&blk, NULL, NULL, size);
void *vir = RK_MPI_MB_Handle2VirAddr(blk); // 虚拟地址
RK_U64 phy = RK_MPI_MB_Handle2PhysAddr(blk); // 物理地址
RK_S32 fd = RK_MPI_MB_Handle2Fd(blk); // DMA-BUF fd
RK_MPI_SYS_MmzFlushCache(blk, RK_FALSE);
RK_MPI_SYS_MmzFree(blk);Rockit 的 MB_BLK 同时暴露虚拟地址、物理地址和 DMA-BUF fd,方便与其他子系统(如 NPU 推理)共享内存。MPP 不直接暴露物理地址和 fd,跨模块协作受限。
模块绑定机制
这是 Rockit 相比 MPP 最大的架构优势:
IPC 典型管线:
┌─────┐ ┌──────┐ ┌──────┐ ┌─────┐
│ VI │───→│ VPSS │───→│ VENC │ │ VO │
│采集 │ │缩放 │ │编码 │ │显示 │
└─────┘ └──────┘ └──────┘ └─────┘
│ ↑
└─────────── Bind ───────────────┘
NVR 典型管线:
┌──────┐ ┌──────┐ ┌─────┐
│ VDEC │───→│ VPSS │───→│ VO │
│解码 │ │缩放 │ │显示 │
└──────┘ └──────┘ └─────┘绑定模式下,数据从 VI 到 VENC 完全在内核层流转,应用零拷贝。手动模式下,应用可以在 VPSS 后插入自定义处理(如 AI 推理前处理)。
MPP 没有绑定概念。用 MPP 时,数据搬运全靠应用层:V4L2 取帧 → memcpy/DMABUF → MPP 编码 → 取码流 → 写文件/推流。
架构层次
┌──────────────────────────────────────────┐
│ 应用层 (CamHal / NVR / IPC) │
├──────────────────┬───────────────────────┤
│ Rockit (librockit.so) │ RKAIQ (ISP) │
│ VI / VPSS / VENC / VO │ 3A/HDR/IQ │
│ ┌────────────────────┐ │ │
│ │ SYS (Bind/MB/MMZ) │ │ │
│ └────────┬───────────┘ │ │
├──────────┼─────────────┴─────────────────┤
│ MPP (librockchip_mpp.so) │
│ H.264/H.265/JPEG/VP8/VP9/AV1 硬件编解码 │
├──────────────────────────────────────────┤
│ Linux Kernel: V4L2 / ISP / VPU / RGA │
├──────────────────────────────────────────┤
│ RK3588: MIPI CSI / ISP / VPU / RGA / HDMI│
└──────────────────────────────────────────┘注意:VI 和 VO 直接走内核驱动,不经过 MPP。VPSS 和 VGS 直接操作硬件引擎,也不经过 MPP。只有编解码走 MPP。
数据结构对比
编码输入帧:
// MPP: MppFrame
// 包含 buffer、宽高、步长、格式、PTS/DTS、meta 等
// 通过 mpp_buffer_get_ptr() 获取数据
// Rockit: VIDEO_FRAME_INFO_S
// 包含 VIDEO_FRAME_S(宽高、格式、物理/虚拟地址、步长、PTS)
// + MB_BLK 句柄(可转物理地址和 fd)
// 统一帧结构贯穿所有模块编码输出码流:
// MPP: MppPacket — 单个包,data + length + pts + flag
// Rockit: VENC_STREAM_S — 包数组,每个包有 DataType(SPS/PPS/SEI/SLICE)Rockit 的码流结构区分了 SPS/PPS/SEI 和 Slice,方便提取参数集或拼 RTMP/RTSP 包。
编译链接
# MPP
target_include_directories(myapp PRIVATE /path/to/mpp/inc)
target_link_libraries(myapp rockchip_mpp)
# Rockit
target_include_directories(myapp PRIVATE
/path/to/rockit/usr/include
/path/to/rockit/usr/include/rkaiq # ISP(需要时)
)
target_link_libraries(myapp rockit)// MPP
#include "rk_mpi.h"
// Rockit
#include "rk_mpi_sys.h"
#include "rk_mpi_vi.h"
#include "rk_mpi_venc.h"选型建议
| 场景 | 推荐 | 理由 |
|---|---|---|
| 文件转码 | MPP | 轻量,无多余依赖 |
| 摄像头采集 + 编码(IPC) | Rockit | VI→VENC 绑定,零拷贝 |
| 多路 NVR | Rockit | 多模块协同,4/8/16 路 |
| 解码 + 显示 | Rockit | VDEC→VO 绑定 |
| 视频会议 | Rockit | 双管线:编码 + 显示并行 |
| AI 推理前处理 | Rockit | VPSS 缩放 + DMA-BUF 共享 |
| 鱼眼畸变校正 | Rockit | GDC 模块 |
| 跨平台编解码库 | MPP | 开源,易集成 |
迁移映射
从 MPP 迁到 Rockit,编码侧的核心映射:
| MPP | Rockit | 说明 |
|---|---|---|
mpp_create + mpp_init(ENC) | RK_MPI_VENC_CreateChn | 创建编码实例 |
mpi->encode_put_frame | RK_MPI_VENC_SendFrame | 送帧 |
mpi->encode_get_packet | RK_MPI_VENC_GetStream | 取码流 |
mpp_buffer_get_ptr | RK_MPI_MB_Handle2VirAddr | 取数据地址 |
mpp_destroy | RK_MPI_VENC_DestroyChn | 销毁实例 |
如果当前项目只用 MPP 做编解码且运行正常,没必要迁移。需要扩展到完整管线时再切 Rockit。