瑞芯微RV1126开发笔记
目录
一. 嵌入式音视频概述
1.1 常见的嵌入式音视频芯片
1.2 瑞芯微 RV1126芯片的硬件介绍
二. 瑞芯微RV1126开发笔记
2.1 RV1126编译环境的搭建
2.1.1 RV1126的SDK结构框图
2.1.2 UBuntu整体编译RV1126的SDK环境&固件烧写
2.1.3 交叉编译
工具链所处目录
2.2 YUV原理讲解
2.2.1 YUV的优势
2.2.2 YUV的采样格式
2.2.3 YUV的存储格式
三.RV1126视频输入模块VI讲解
3.1 什么是VI模块
3.2 VI模块初始化API
3.2.1 RK_MPI_VI_SetChnAttr
3.2.2 RK_MPI_VI_EnableChn
3.3 多线程获取VI模块的YUV数据
3.3.1 Rv1126 VI模块采集摄像头YUV数据流程
一. 嵌入式音视频概述
1.1 常见的嵌入式音视频芯片
瑞芯微 RV1126 / RK3399 / RK3568、海思 Hi3519AV100 / Hi3559AV00、英伟达 TX1 / TX2等等
1.2 瑞芯微 RV1126芯片的硬件介绍
瑞芯微 RV1126芯片主要运用在人工智能、人脸识别、智能监控等场景。支持4k 30帧、H264 / H265视频编解码功能,该硬件编解码效率远高于软件视频编解码,并支持ISP2.0、HDR、麦克风阵列等最新技术,支持3个摄像头同时输入。
二. 瑞芯微RV1126开发笔记
2.1 RV1126编译环境的搭建
2.1.1 RV1126的SDK结构框图
app: app目录主要包含了IPC的一些demo
buildroot: 这是一个构建系统,用于编译整个项目。
device: 内核配置的选项
IMAGE: 空文件夹
prebuilts: RV1126交叉编译工具链
u-boot:嵌入式系统的引导加载程序
docs: 相关的技术文档
external: RV1126的相关例程,这个文件夹中的内容是很重要的
kernel: RV1126烧写的内核
tools: RV1126的工具,包括烧录工具、升级工具等等。
2.1.2 UBuntu整体编译RV1126的SDK环境&固件烧写
参照产品手册进行整体编译,最终会生成该update.img镜像。
烧写时必须要保证设备在MSAKROM模式下。
步骤一:然后打开瑞芯微的开发工具,进行热拔插会显示发现一个ADB设备
步骤二:点击切换按键,等待一分钟,会显示发现一个LOADER设备
步骤三:点击高级功能,选择进入Maskrom,会显示发现一个MASKROM设备
步骤四:点击升级固件,点击固件,选择固件的位置。然后点击升级即可完成固件的烧录。
2.1.3 交叉编译
工具链所处目录
/opt/rv1126_rv1109_linux_sdk_v1.8.0_20210224/prebuilts/gcc/linux-x86/arm/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf/bin/
使用这俩个进行开发。arm-linux-gnueabihf-g++,arm-linux-gnueabihf-gcc
2.2 YUV原理讲解
YUV是一种常见的视频像素格式。Y分量是亮度分量,也就是灰阶值。U分量和V分量是色度分量,用于色彩和饱和度,U分量是蓝色与亮度的差值,V分量是红色与亮度的差值。换而言之,一部电视如果只有Y分量就是黑白画面,只有U分量就只有蓝色画面。
2.2.1 YUV的优势
YUV和RGB是目前最流行的俩套视频像素格式,但是在视频编解码和网络传输过程中一般采用YUV格式,这是由于YUV在网络传输时只需要占用很少的带宽,大大节约了存储空间,提高传输效率。
2.2.2 YUV的采样格式
现在流行的有YUV444, YUV422, YUV420
———————————————————————————————————————————
YUV444:YUV444 的采样比例为 4:4:4。在 YUV444 格式中,每个像素都有完整的亮度(Y 分量)和色度(U 和 V 分量)。Y、U、V 三个分量的分辨率都是 w × h,与原始图像的宽度和高度一致。
- 第一个 "4":表示每 4 个水平像素中有 4 个亮度(Y)样本。
- 第二个 "4":表示每 4 个水平像素中有 4 个 U 色度样本。
- 第三个 "4":表示每 4 个水平像素中有 4 个 V 色度样本。
当使用YUV444去采样一个大小为1920*1080的图像时,得到的大小为(1920*1080*8+1920*1080*8+1920*1080*8)/8/1024/1024=5.94M
大小和RGB采样差不多,不利于网络传输,在实际开发中一般不使用。
———————————————————————————————————————————
YUV422:YUV422 的采样比例为 4:2:2。
当使用YUV422去采样一个大小为1920*1080的图像时,得到的大小为(1920*1080*8+1920*1080*4+1920*1080*4)/8/1024/1024=3.96M
———————————————————————————————————————————
YUV420:YUV420 的采样比例为 4:2:0。
这一行采用4个Y分量,2个U分量,0个V分量。而下一行采用4个Y分量,2个V分量,0个U分量。
当使用YUV420去采样一个大小为1920*1080的图像时,得到的大小为(1920*1080*8+1920*1080*2+1920*1080*2)/8/1024/1024=2.97M
2.2.3 YUV的存储格式
YUV 数据有三种存储格式:Planar,Semi-Planar 和 Packed。
Planar:YUV 三个分量分开存放
Semi-Planar:Y 分量单独存放,UV 分量交错存放
Packed:三个分量全部交错存放
针对不同的存储方式,实际开发中有了多种YUV格式。
三.RV1126视频输入模块VI讲解
RV1126的VI模块的底层采用V4L2来处理。
3.1 什么是VI模块
VI模块的主要功能是从摄像头或其他图像传感器sensor中接收原始数据(通常是 YUV、RAW 等格式)。
3.2 VI模块初始化API
3.2.1 RK_MPI_VI_SetChnAttr
功能:设置VI通道属性
ViPipe:管道号,管道号和传感器(sensor)的数量是对应的,VI 管道号默认从 0 开始分配。设系统中配置了双目摄像头:camera0
对应 pipe0
(VI 管道号 0)camera1
对应 pipe1
(VI 管道号 1)。
ViChn:通道号,一个管道号里面,有多个通道能用。通常来说 Vi 通道号和管道号的数值是相同 的。每个Camera的Vipipe最多对应8个通道数(ViChn),MAX_CHN的值是8。
3.2.2 RK_MPI_VI_EnableChn
功能:使能VI通道
3.3 多线程获取VI模块的YUV数据
3.3.1 Rv1126 VI模块采集摄像头YUV数据流程
- 初始化VI模块:VI模块的初始化实际上就是对VI_CHN_ATTR_S的参数进行设置、然后调用RK_MPI_VI_SetChnAttr设置VI模块并使能RK_MPI_VI_EnableChn
- 启动VI模块:设置完上面的VI模块后,就要开启VI模块的工作,使用的API是RK_MPI_VI_StartStream。
- 使用多线程的方式去采集:开启一个线程去采集每一帧VI模块的数据,使用的API是RK_MPI_SYS_GetMediaBuffer,这个API的具体作用是获取指定通道中的数据,具体的定义如下:
#include <assert.h>
#include <fcntl.h>
#include <getopt.h>
#include <pthread.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include "rkmedia_api.h"#define CAMERA_PATH "rkispp_scale0" //摄像头设备路径
#define PIPE_ID 0 //管道号
#define CHN_ID 0 //通道号static bool quit = false;void handle_quit_signal(int sig){printf("vi_program quit....\n");quit = true;
}void * get_camera_vi_thread(void * args){MEDIA_BUFFER mb = NULL;FILE * nv12_file = fopen("test_camera.nv12", "w+");while (!quit){mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_VI, CHN_ID, -1);if(!mb){printf("get Vi mb break....\n");break;}fwrite(RK_MPI_MB_GetPtr(mb), 1, RK_MPI_MB_GetSize(mb), nv12_file);RK_MPI_MB_ReleaseBuffer(mb);}
}int main(int argc, char *argv[])
{signal(SIGINT, handle_quit_signal); //捕捉到Ctrl+C信号时,执行退出函数int ret;VI_CHN_ATTR_S vi_chn_attr;vi_chn_attr.pcVideoNode = CAMERA_PATH; // 指定摄像头设备路径vi_chn_attr.u32Width = 1920;vi_chn_attr.u32Height = 1080;vi_chn_attr.enPixFmt = IMAGE_TYPE_NV12; // 设置YUV格式为 NV12vi_chn_attr.u32BufCnt = 3; // 设置缓冲区数量为 3vi_chn_attr.enBufType = VI_CHN_BUF_TYPE_MMAP; // 设置缓冲区类型为内存映射vi_chn_attr.enWorkMode = VI_WORK_MODE_NORMAL; // 设置工作模式为普通类型//初始化VI模块ret = RK_MPI_VI_SetChnAttr(PIPE_ID, CHN_ID, &vi_chn_attr);if(ret){printf("Create VI Failed...\n");return -1;}else{printf("Create VI Success...\n");}//使能VI模块ret = RK_MPI_VI_EnableChn(PIPE_ID, CHN_ID);if(ret){printf("Enable VI Failed...\n");return -1;}else{printf("Enable VI Success...\n");}//启动VI模块ret = RK_MPI_VI_StartStream(PIPE_ID, CHN_ID);if(ret){printf("RK_MPI_VI_StartStream Failed...\n");return -1;}else{printf("RK_MPI_VI_StartStream Success...\n");}pthread_t pid;pthread_create(&pid, NULL, get_camera_vi_thread, NULL);while (!quit){sleep(1);}RK_MPI_VI_DisableChn(0, 0);return 0;
}
需进入ffmpeg的bin目录下播放,命令如下:
ffplay -f rawvideo -pix_fmt nv12 -video_size 1920x1080 test_camera.nv12