这章文档节各位学员就可以对RV1126的采集VI摄像头模块的流程有更深刻的了解。后面需要源代码的可以私信我或在评论区扣1
1.RV1126 VI模块采集摄像头YUV数据的流程
RV1126多线程采集VI模块的数据,一般分为三个步骤:分别是初始化VI模块、启动VI模块开启采集、开启多线程采集VI数据并保存到本地。
1.1初始化VI模块:
VI模块的初始化实际上就是对VI_CHN_ATTR_S的参数进行设置、然后调用RK_MPI_VI_SetChnAttr设置VI模块并使能RK_MPI_VI_EnableChn
1.2启动VI模块:
设置完上面的VI模块后,就要开启VI模块的工作,使用的API是RK_MPI_VI_StartStream。
1.3使用多线程的方式去采集:
开启一个线程去采集每一帧VI模块的数据,使用的API是RK_MPI_SYS_GetMediaBuffer,这个API的具体作用是获取指定通道中的数据,具体的定义如下:
enModID:模块号ID,模块号指的是目前使用的是哪个模块如:VI模块(RK_ID_VI)、VENC模块(RK_ID_VENC)
s32ChnID:通道号ID,这里的通道号跟初始化通道的ID号一致。
S32MilliSec:默认是-1,阻塞状态。
注意:RK_MPI_SYS_GetMediaBuffer获取的数据是一个整体的数据,换言之这个数据包含了缓冲区指针和缓冲区大小。如下图:
拿到整体数据后,我们就要对整体数据进行分割操作。所谓的分割操作,就是要获取整体数据里面的缓冲区指针和缓冲区大小。那具体的我们来看看下面的API是怎么获取到它的具体数据。
缓冲区指针的获取:
RK_MPI_MB_GetPtr就是获取每一帧的具体指针,也就是我们每一帧数据。
缓冲区长度的获取
RK_MPI_MB_GetSize就是获取每一帧数据的长度。
获取完具体的缓冲区数据和缓冲区大小之后,就开始写入文件。写入文件的操作就是fwrite就可以写入。
好的,上述流程已经梳理完毕,开始主代码实战,不懂可以看我写的注释
#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);
//vi模块的初始化
int ret;
VI_CHN_ATTR_S vi_chn_attr;
vi_chn_attr.pcVideoNode = CAMERA_PATH;// 视频设备路径(如 "/dev/video0"
vi_chn_attr.u32Width = 1920;// 视频宽度(1920像素)
vi_chn_attr.u32Height = 1080; 视频高度(1920像素)
vi_chn_attr.enPixFmt = IMAGE_TYPE_NV12;// 像素格式(NV12是YUV格式的一种)420
vi_chn_attr.u32BufCnt = 3;// 缓冲区数量(用于双缓冲/三缓冲)
vi_chn_attr.enBufType = VI_CHN_BUF_TYPE_MMAP;// 缓冲区类型(内存映射)
vi_chn_attr.enWorkMode = VI_WORK_MODE_NORMAL;// 工作模式(正常模式)
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");
}
//启用视频通道
ret = RK_MPI_VI_EnableChn(PIPE_ID, CHN_ID);
if(ret)
{
printf("Enable VI Failed...\n");
return -1;
}
else
{
printf("Enable VI Success...\n");
}
//启动视频流,此时摄像头开始采集数据
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;
}
好的,这就是简单的多线程VI数据采集,看不懂的可以私信我。