MPP
MPP (Multimedia Processing Platform,多媒体处理平台)开发指南。
1. 概述
1.1 编写目的
主要介绍 SpacemiT 的多媒体相关的框架层次结构 ,开放 API 接口等,方便开发者快速上手或者二次开发。
1.2 适用范围
适用于 SpacemiT 的 K1 系列 SOC。
1.3 相关人员
- 应用开发工程师
- 多媒体中间件开发及维护工程师
1.4 文档结构
该文档首先介绍了多媒体整体框架结构及其简要说明,然后分别对 MPP 模块,VPU 模块,JPU 模块,ISP/CPP/MIPI-CSI 模块等进行详细的说明。
2 多媒体整体框架
2.1 框架层次图及说明
从框架结构上看分 4 层,从上到下依次为:
- APP层:包括第三方 APP 和自研 APP,第三方 APP 基本上是通过 GStreamer 和 FFmpeg 等开源框架来实现视频的编解码,例如 Bianbu 默认集成的 mpv 播放器,还有我们常用的 Video(totem)等,自研 APP 目前主要是我们提供的对接 API 的参考 demo 或者 test。
- mpv:Bianbu 桌面系统默认本地播放器,对接了 K1 硬件解码器,支持 H.264/HEVC/VP8/VP9/MPEG-4/MPEG-2/MJPEG 等多种格式的硬件解码,最高支持到 4K60 视频的播放。
- totem:Ubuntu 桌面系统默认本地播放器,对接了 K1 硬件解码器,支持 H.264/HEVC/VP8/VP9/MPEG-4/MPEG-2/MJPEG 等多种格式的硬件解码,目前最高支持到 4K30 视频的播放。
- cheese:Bianbu/Ubuntu 桌面系统默认的 camera 应用,支持预览,拍照,录像等功能,目前已经对接了 K1 的硬件编解码器,实现 1080P30 流畅预览录像。
- chromium:Bianbu 桌面系统默认浏览器,对接了 K1 的硬件解码器,支持 H.264/HEVC 等多种格式的硬件解码,最高支持到 4K30 视频的播放。
- kodi:开发者和发烧友常用的开源播放器,对接了 K1 的硬件解码器,H.264/HEVC/VP8/VP9 等多种格式的硬件解码,最高支持 4K60 视频的播放。
- v2d-test:V2D 模块的测试程序,也可以作为参考 demo,V2D 模块主要是进行非压缩图像的格式转换,旋转,缩放等操作。
- mvx-player:VPU 模块的测试程序,也可以作为参考 demo,通过命令行进行视频的编解码操作,输出以文件的形式保存。
- jpu-test:JPU 模块的测试程序,也可以作为参考 demo,通过命令行进行视频的编解码操作,输出以文件的形式保存,JPU 模块主要进行 JPEG 图像的编解码操作。
- camera-test:CAMERA 通路的测试程序,也可以作为参考 demo,通过命令行进行图像的采集,该测试程序主要是针对 K1 的 CPP-ISP-MIPICSI 模块提 供的 API,不包括 USB camera,USB camera 请使用 v4l-utils 等开源标准测试程序。
- 开源多媒体框架层(FRAMEWORK):常见的就是 GStreamer,FFmpeg,GStreamer 和 FFmpeg 是完整的多媒体解决方案,全面包含了 muxer/demuxer/decoder/encoder/display 的各种实现,是可以直接使用的开源框架。这一层,我们实现了多个插件通过 MPP 把硬件编解码库对接上。
- FFmpeg:FFmpeg 对接了 K1 的硬件编解码器,支持 H.264/HEVC/VP8/VP9/MPEG-4/MPEG-2/MJPEG 等多种格式的硬件解码,最高支持到 4K60 视频的播放,同时支持 AV_PIX_FMT_DRM_PRIME 和 AV_PIX_FMT_NV12 的输出像素格式,支持 H.264/H.265/VP8/VP9/MJPEG 等多种格式的硬件编码,最高支持到 4K30 的编码。
- Gstreamer:Gstreamer 对接了 K1 的硬件编解码器,支持 H.264/HEVC/VP8/VP9/MPEG-4/MPEG-2/MJPEG 等多种格式的硬件解码,最高支持到 4K30 视频的播放,支持 H.264/H.265/VP8/VP9/MJPEG 等多种格式的硬件编码,最高支持到 1080P60 的编码。
- Openmax IL:编解码适配中
- MPP:对上提供统一多媒体 API,对下动态加载不同平台的编解码库插件来调用编解码库。
- Driver & Library:IP 厂商提供的驱动和 API 动态库。
2.2 概念术语
- VPU:(Video Processing Unit,视频处理单元)具有视频编解码功能的硬件,能够提高编解码效率并减少 CPU 负荷,K1 的 VPU 基于标准 V4L2 框架实现,支持 H.264/HEVC/VP8/VP9/MJPEG/MPEG4 等格式的解码和 H.264/HEVC/VP8/VP9/MJPEG 等格式的编码。
- V2D:K1 提供的图像处理硬件模块,支持图像格式转换,缩放,裁剪等功能。
- JPU:(Jpeg Processing Unit)进行 Jpeg 图像编解码的硬件,能够提高 Jpeg 的编解码效率并减少 CPU 负荷。
- ISP:图像处理模块,用于处理传感器输出的图像信号,经过一系列数字图像处理算法达到预期的图像效果。
- CPP:图像后处理模块,用于离线处理 ISP 输出的 NV12 数据,金字塔式多层分时处理,主要功能包括:镜头畸变矫正、空域和时域降噪、频域降噪、边沿增强等。
- RVV:基于 RISC-V 核心指令集架构的一种向量扩展。向量扩展的目的是在指令级别实现对数据的并行操作,以加速计算过程,类似 ARM 的 neon。
- MPP:(Multimedia Processing Platform)多媒体处理平台。
- Gstreamer:一个开源的多媒体框架,用于构建流媒体应用程序和处理音频/视频数据。它提供了一套库和工具,可以用来创建、处理和播放各种多媒体流,包括音频、视频、流媒体等。gstreamer 支持多种编解码器和格式,可以在不同平台上运行,是一个灵活且功能强大的多媒体处理框架。
- FFmpeg:开源的跨平台音视频处理工具,它可以用来录制、转换和流式传输音视频内容,以及进行音视频编辑和处理。它支持多种音视频格式和编解码器,可以在不同的操作系统上运行,包括 Windows、Mac 和 Linux。FFmpeg 是一个功能强大且灵活的工具,被广泛应用于多媒体处理领域。
- V4L2:Video for Linux 2 的缩写,是一个用于 Linux 系统的视频采集和输出设备的驱动程序接口。它提供了一种统一的方式来访问视频设备,包括摄像头、视频采集卡和其他视频输入/输出设备。V4L2 接口允许用 户程序通过统一的 API 来控制和使用视频设备,从而实现视频的采集、处理和显示。这使得在 Linux 系统上开发视频应用程序变得更加简单和灵活。
- ALSA:Advanced Linux Sound Architecture(高级 Linux 音频架构)的缩写,是 Linux 系统上用于处理音频和音频设备的软件架构。它提供了一个统一的音频接口,使得应用程序可以与音频硬件进行通信,支持多种音频设备和音频格式,并提供了低延迟和高质量的音频处理功能。ALSA 还提供了一组工具和库,用于配置和管理音频设备,以及编写音频应用程序。ALSA 已经成为 Linux 系统上主流的音频架构,被广泛应用于各种 Linux 发行版中。
3 MPP
3.1 模块介绍
3.1.1 背景介绍
MPP(Multimedia Processing Platform,多媒体处理平台)属于自研操作系统 Bianbu,其目的是封装多平台硬件编解码的使用差异,提供统一的 API 供开发者使用。
3.1.2 概念术语
- MPP(Multimedia Processing Platform):多媒体处理平台。
- MPI(Multimedia Processing Interface):多媒体处理平台提供给 上层的 API 调用。
- MPP AL: 抽象层,对不同 IP,不同 SOC,不同方案的多媒体接口进行抽象。
- Packet:数据包,主要表示经过压缩后的数据,即解码前或者编码后的数据,如 H.264/H.265 的视频流。
- Frame:数据帧,主要表示未经压缩的数据,即解码后或者编码前的数据,如 YUV420 的图像。
3.1.3 模块功能
目前 MPP 主要包含下面几个部分:
- VDEC: 视频解码子模块及开放 API,主要用于各种数据流 packet 的解码。
- VENC: 视频编码子模块及开放 API,主要用于 RGB/YUV 数据帧 frame 的编码。
- G2D: 2D 图形处理加速子模块及开放 API,主要进行数据帧 frame 的格式转换,缩放,旋转,裁剪等操作。
- BIND 系统:支持多模块动态绑定。
- AL(Abstract Layer): 支持多平台。
- VI: 视频输入子模块及开放 API,目前仅支持文件输入及标准 V4L2 输入。
- VO: 视频输出子模块及开放 API,目前仅支持文件输出及 SDL2 视频输出。
未包含部分:
- AI/AO: 音频的输入输出,走标准的 pipewire->alsa-lib->alsa driver。
- AENC/ADEC: 纯软件实现,Gstreamer/FFmpeg 等开源框架都有全面支持,暂不支持。
3.1.4 配置说明
3.1.4.1 调试配置
- MPP_PRINT_BUFFER:环境变量,默认 0,配置成 1 后能够实时打印 buffer 状态。
- MPP_SAVE_OUTPUT_BUFFER:环境变量,默认 0,配置成 1 后能够保存解码后的 YUV buffer,YUV buffer 较大,会导致播放卡顿并且保存文件会占用较大空间,请注意。
- MPP_SAVE_OUTPUT_BUFFER_PATH:环境变量,用于配置输出 YUV 的文件路径,默认/home/bianbu/output.yuv,MPP_SAVE_OUTPUT_BUFFER 开启后才生效。
- MPP_FRINT_UNFREE_PACKET:环境变量,默认 0,配置成 1 后能够实时打印 packet 的申请释放情况
- MPP_FRINT_UNFREE_FRAME:环境变量,默认 0,配置成 1 后能够实时打印 frame 的申请释放情况
- MPP_FRINT_UNFREE_DMABUF:环境变量,默认 0,配置成 1 后能够实时打印 dmabuf 的申请释放情况
使用示例:
#需要实时打印buffer状态
export MPP_PRINT_BUFFER=1
#需要保存解码后的YUV数据到/mnt/a.yuv
export MPP_SAVE_OUTPUT_BUFFER=1
export MPP_SAVE_OUTPUT_BUFFER_PATH=/mnt/a.yuv
3.1.4.2 参数配置
暂未提供配置参数
3.1.5 源码
3.1.5.1 源码位置
MPP 的源码位置位于:
bianbu-linux/package-src/mpp
3.1.5.2 源码编译
bianbu-linux 方案中默认已经开启了编译,如果需要修改代码后需要重新编译,执行:
make mpp-rebuild
3.1.5.3 源码结构
MPP 的源码结构及简要说明如下(源码结构做了精简):
|-- al ;AL(Abstract Layer)层代码,对接各平台功能模块或者驱动
| |-- CMakeLists.txt
| |-- include
| | |-- al_interface_base.h ;AL层接口基类
| | |-- al_interface_dec.h ;AL层解码接口基类,继承于base
| | |-- al_interface_enc.h ;AL层编码接口基类,继承于base
| | |-- al_interface_g2d.h ;AL层图像转换接口基类,继承于base
| | |-- al_interface_vi.h ;AL层视频输入接口基类,继承于base
| | `-- al_interface_vo.h ;AL层视频输出接口基类,继承于base
| |-- vcodec ;对接多平台的编解码模块或者驱动
| | |-- chipmedia ;对接chipmedia IP的编解码器
| | | |-- CMakeLists.txt
| | | `-- starfive ;对接starfive的编解码器API(暂未实现)
| | | |-- sfdec_plugin.c
| | | `-- sfenc_plugin.c
| | |-- CMakeLists.txt
| | |-- debug ;虚拟解码插件,输出简单纯色图,用于debug
| | | |-- CMakeLists.txt
| | | `-- fake_dec_plugin.c
| | |-- ffmpeg ;对接ffmpeg软件编解码,用于debug
| | | |-- CMakeLists.txt
| | | |-- ffmpegdec.c
| | | |-- ffmpegenc.c
| | | `-- ffmpegswscale.c
| | |-- k1
| | | |-- CMakeLists.txt
| | | `-- jpu ;对接K1的Jpu编解码(暂未实现)
| | | |-- include
| | | |-- jpudec.c
| | | `-- jpuenc.c
| | |-- openh264 ;对接openh264软件编解码库,用于debug
| | | |-- CMakeLists.txt
| | | |-- include
| | | | `-- wels
| | | | |-- codec_api.h
| | | | |-- codec_app_def.h
| | | | |-- codec_def.h
| | | | `-- codec_ver.h
| | | |-- openh264dec.cpp
| | | |-- openh264enc.cpp
| | | `-- README.md
| | |-- openmax ;对接openmax
| | | |-- CMakeLists.txt
| | | |-- include
| | | | |-- khronos
| | | | | |-- OMX_Audio.h
| | | | | |-- OMX_ComponentExt.h
| | | | | |-- OMX_Component.h
| | | | | |-- OMX_ContentPipe.h
| | | | | |-- OMX_CoreExt.h
| | | | | |-- OMX_Core.h
| | | | | |-- OMX_ImageExt.h
| | | | | |-- OMX_Image.h
| | | | | |-- OMX_IndexExt.h
| | | | | |-- OMX_Index.h
| | | | | |-- OMX_IVCommon.h
| | | | | |-- OMX_Other.h
| | | | | |-- OMX_Types.h
| | | | | |-- OMX_VideoExt.h
| | | | | `-- OMX_Video.h
| | | | |-- sfomxil_find_dec_library.h
| | | | `-- sfomxil_find_enc_library.h
| | | `-- starfive ;对接starfive的openmaxIL层视频编解码
| | | |-- sfomxil_dec_plugin.c
| | | `-- sfomxil_enc_plugin.c
| | |-- v4l2 ;对接V4L2编解码
| | | |-- CMakeLists.txt
| | | |-- linlonv5v7 ;对接linlonv5v7编解码(K1)
| | | | |-- include
| | | | | |-- linlonv5v7_buffer.h
| | | | | |-- linlonv5v7_codec.h
| | | | | |-- linlonv5v7_constant.h
| | | | | |-- linlonv5v7_port.h
| | | | | `-- mvx-v4l2-controls.h
| | | | |-- linlonv5v7_buffer.c
| | | | |-- linlonv5v7_codec.c
| | | | |-- linlonv5v7_dec.c
| | | | |-- linlonv5v7_enc.c
| | | | `-- linlonv5v7_port.c
| | | `-- standard
| | | |-- v4l2dec.c
| | | `-- v4l2enc.c
| | `-- verisilicon ;对接verisilicon编解码(未实现)
| | |-- CMakeLists.txt
| | `-- vc8000.c
| |-- vi ;对接多平台视频输入模块或者驱动
| | |-- CMakeLists.txt
| | |-- file ;视频通过File输入
| | | |-- include
| | | | |-- defaultparse.h
| | | | |-- h264parse.h
| | | | |-- h265parse.h
| | | | |-- mjpegparse.h
| | | | `-- parse.h
| | | |-- parse
| | | | |-- defaultparse.c
| | | | |-- h264parse.c
| | | | |-- h265parse.c
| | | | |-- mjpegparse.c
| | | | `-- parse.c
| | | `-- vi_file.c
| | |-- k1 ;视频通过K1的ISP输入,暂未实现
| | | `-- cam
| | | |-- include
| | | `-- vi_k1_cam.c
| | `-- v4l2 ;视频通过标准V4L2输入
| | |-- include
| | `-- vi_v4l2.c
| |-- vo ;对接多平台视频输出模块或者驱动
| | |-- CMakeLists.txt
| | |-- file ;视频输出到File
| | | `-- vo_file.c
| | `-- sdl2 ;视频通过SDL2输出
| | |-- include
| | | |-- begin_code.h
| | | |-- close_code.h
| | | |-- SDL_assert.h
| | | |-- SDL_atomic.h
| | | `-- SDL_vulkan.h
| | `-- vo_sdl2.c
| `-- vps ;对接多平台视频处理模块或者驱动
| |-- CMakeLists.txt
| `-- k1
| |-- CMakeLists.txt
| `-- v2d ;对接K1的v2d模块,实现基本框架
| |-- include
| | |-- asr_v2d_api.h
| | `-- asr_v2d_type.h
| `-- v2d.c
|-- cmake ;查找系统模块
| `-- modules
| |-- Findlibavcodec.cmake
| |-- Findlibopenh264.cmake
| |-- Findlibsfdec.cmake
| |-- Findlibsfenc.cmake
| `-- Findlibsf-omx-il.cmake
|-- CMakeLists.txt
|-- compile_install_completely.sh
|-- debian ;deb包构建目录
| |-- bianbu.conf
| |-- changelog
| |-- compat
| |-- control
| |-- copyright
| |-- install
| |-- README.Debian
| |-- rules
| |-- source
| | `-- format
| |-- usr
| | `-- lib
| | `-- udev
| | `-- rules.d
| | `-- 99-video.rules
| `-- watch
|-- doc ;一些文档
| |-- C_naming_conventions.md
| `-- MPP Module Design Document V0.1.pdf
|-- do_test.sh
|-- format.sh
|-- include ;API头文件
| |-- data.h ;MppData数据基类
| |-- dataqueue.h ;数据队列管理API
| |-- dmabufwrapper.h ;dmabuf管理API
| |-- frame.h ;frame帧管理API
| |-- g2d.h ;图像处理API
| |-- packet.h ;packet包管理API
| |-- para.h ;参数结构体
| |-- processflow.h
| |-- ringbuffer.h ;环形buffer管理API
| |-- sys.h ;SYS相关API
| |-- vdec.h ;视频解码API
| `-- venc.h ;视频解码API
| |-- vi.h ;视频输入API
| `-- vo.h ;视频输出API
|-- LICENSE
|-- mpi ;API接口实现
| |-- CMakeLists.txt
| |-- g2d.c
| |-- include
| | `-- module.h
| |-- module.c
| |-- sys.c
| |-- vdec.c
| |-- venc.c
| |-- vi.c
| `-- vo.c
|-- mpp.cppcheck
|-- pack_to_tar_gz.sh
|-- pkgconfig
| `-- spacemit_mpp.pc.cmake
|-- remove_space_end_of_line.sh
|-- test ;测试程序,测试脚本,测试文件等
| |-- CMakeLists.txt
| |-- g2d_test.c
| |-- include
| | |-- argument.h
| | |-- const.h
| | |-- defaultparse.h
| | |-- h264parse.h
| | |-- h265parse.h
| | |-- mjpegparse.h
| | `-- parse.h
| |-- parse
| | |-- defaultparse.c
| | |-- h264parse.c
| | |-- h265parse.c
| | |-- mjpegparse.c
| | `-- parse.c
| |-- test_script
| | |-- cases
| | | `-- vdec.csv
| | |-- streams
| | `-- vdec_test.sh
| |-- test_sys_vdec_venc_one_frame.c
| |-- test_sys_vdec_venc_vdec_one_frame.c
| |-- test_sys_venc_vdec_one_frame.c
| |-- vi_file_vdec_venc_sync_userptr_vo_file_test.c
| |-- vi_file_vdec_vo_test.c
| |-- vi_file_venc_sync_userptr_vo_file_test.c
| `-- vi_v4l2_vo_test.c
|-- thirdparty
| |-- ffmpeg_compile_install.md
| `-- openh264_compile_install.md
`-- utils ;utils
|-- CMakeLists.txt
|-- dataqueue.c ;数据队列实现
|-- dmabufwrapper.c ;dmabuf管理实现
|-- env.c
|-- frame.c ;frame管理实现
|-- include
| |-- env.h
| |-- log.h
| |-- resolution_utils.h
| |-- type.h
| `-- v4l2_utils.h
|-- log.c
|-- os
| |-- include
| | |-- os_env.h
| | `-- os_log.h
| `-- linux
| |-- os_env.c
| `-- os_log.c
|-- packet.c ;packet管理实现
|-- resolution_utils.c
|-- ringbuffer.c
|-- utils.c
`-- v4l2_utils.c
3.2 MPP 框架结构图
从框架结构上,主要分 2 层,如下:
- MPI:接口层,主要包含对上层的 API 及其实现
- MPP AL:抽象层,屏蔽不同平台和硬件的差异
从功能上来看,分为:
- MPI:接口层
- MPP AL:抽象层
- TESTS:测试程序,测试用例及测试流
- UTILS:工具包,基础功能实现,包括 PACKET/FRAME 管理,日志输出,环境变量读写等
- SYS:主要实现动态加载插件和 BIND 系统