Camera|4.瑞芯微平台MIPI摄像头应用程序编写

原创 一口Linux 2023-02-14 11:50
点击左上方蓝色“一口Linux”,选择“设为星标


第一时间看干货文章 

【干货】嵌入式驱动工程师学习路线
【干货】一个适合初学者的Linux物联网综合项目
【干货】Linux嵌入式知识点-思维导图-免费获取



 1

Camera | 1.Camera基础知识

Camera | 2.MIPI、CSI基础

Camera | 3.瑞芯微平台MIPI摄像头常用调试命令

前面3篇我们讲解了camera的基础概念,MIPI协议,CSI2,常用命令等,本文带领大家入门,如何用c语言编写应用程序来操作摄像头。

Linux下摄像头驱动都是基于v4l2架构,要基于该架构编写摄像头的应用程序,必须先要搞清楚什么是v4l2。

1. 什么是v4l2

vl42是video for Linux 2的缩写,是一套Linux内核视频设备的驱动框架,该驱动框架为应用层提供一套统一的操作接口(一系列的ioctl)

https://linuxtv.org/downloads/legacy/video4linux/API/V4L2_API/

官网有一个简单的用于抓图的程序capture.c。

本文后面基于该实例编写一个最简单的抓图程序。

v4l2接口

V4L2 :video for linux 2 ,是 linux ⾥⼀套标准的视频驱动,让应⽤层可以像访问普通⽂件⼀样对**/dev/videoX** 节点进⾏ open 、 read 、 ioctl 等操作。

V4L2在设计时,是要支持很多广泛的设备的,它们之中只有一部分在本质上是真正的视频设备,可以支持多种设备,它可以有以下几种接口:

1. video capture interface(捕获):视频采集接口,这种接口应用于摄像头,v4l2在最初设计的时候就是应用于这种功能

2. video output interface(输出):视频输出接口,将静止图像或图像序列编码为模拟视频信号,通过此接口,应用程序可以控制编码过程并将图像从用户空间移动到驱动程序

3. video overlay interface(预览):视频直接传输接口,可以将采集到的视频数据直接传输到显示设备,不需要cpu参与,这种方式的显示图像的效率比其他方式高得多

本文主要讲解如何使用capture功能。

2. 截取图象的3种方法

1)用mmap(内存映射)方式截取视频

mmap( )系统调用使得进程之间通过映射同一个普通文件实现共享内存。普通文件被映射到进程地址空间后,进程可以向访问普通内存一样对文件进行访问,不必再调用read(),write()等操作。

两个不同进程A、B共享内存的意思是,同一块物理内存被映射到进程A、B各自的进程地址空间。进程A可以即时看到进程B对共享内存中数据的更新,反之亦然

采用共享内存通信的一个显而易见的好处是效率高,因为进程可以直接读写内存,而不需要任何数据的拷贝

*(1)设置picture的属性 *(2) 初始化video_mbuf,以得到所映射的buffer的信息

ioctl(vd->fd, VIDIOCGMBUF, &(vd->mbuf))

*(3)可以修改video_mmap和帧状态的当前设置

 Eg. vd->mmap.format = VIDEO_PALETTE_RGB24
 vd->framestat[0] = vd->framestat[1] = 0; vd->frame = 0;

*(4)将mmap与video_mbuf绑定

voidmmap void * addr , size_t len , int prot , int flags , int fd , off_t offset )
len //映射到调用进程地址空间的字节数,它从被映射文件开头offset个字节开始算起
Prot //指定共享内存的访问权限 PROT_READ(可读), PROT_WRITE (可写), PROT_EXEC (可执行)
flags // MAP_SHARED MAP_PRIVATE中必选一个 // MAP_ FIXED不推荐使用addr //共内存享的起始地址,一般设0,表示由系统分配
Mmap( ) 返回值是系统实际分配的起始地址
if((vd->map = (unsigned char*)mmap(0, vd->mbuf.size, PROT_READ|PROT_WRITE, MAP_SHARED, vd->fd, 0)) < 0)
{
 perror("v4l_mmap mmap:");
 return -1;
}

*(5)Mmap方式下真正做视频截取的 VIDIOCMCAPTURE

ioctl(vd->fd, VIDIOCMCAPTURE, &(vd->mmap)) ;
若调用成功,开始一帧的截取,是非阻塞的,
是否截取完毕留给VIDIOCSYNC来判断

*(6)调用VIDIOCSYNC等待一帧截取结束

if(ioctl(vd->fd, VIDIOCSYNC, &frame) < 0)
{
 perror("v4l_sync:VIDIOCSYNC");
 return -1;
}

若成功,表明一帧截取已完成。可以开始做下一次 VIDIOCMCAPTURE

frame是当前截取的帧的序号。

关于双缓冲:

video_bmuf bmuf.frames = 2;
一帧被处理时可以采集另一帧
int frame; //当前采集的是哪一帧
int framestat[2]; //帧的状态 没开始采集|等待采集结束
帧的地址由vd->map + vd->mbuf.offsets[vd->frame]得到
采集工作结束后调用munmap取消绑定
munmap(vd->map, vd->mbuf.size)

2)视频截取的第二种方法:直接读设备

关于缓冲大小,图象等的属性须由使用者事先设置

int read (要访问的文件描述符;指向要读写的信息的指针;应该读写的字符数);
 返回值为实际读写的字符数

实例:

int len ;
unsigned char *vd->map= (unsigned char *) malloc(vd->capability.maxwidth*vd->capability.maxheight );
len = read(vd->fd,vd->map, vd->capability.maxwidth*vd->capability.maxheight*3 );

3)用户指针

3. v4l2 设备操作说明

对设备的大多数操作都是应用层通过调用ioctl实现的, 不同的命令需要操作不同的文件设备节点, 具体的需要根据拓扑结构来决定操作那个字符设备。

以下是瑞芯微rk3568平台的摄像头拓扑图,移植了ov13850摄像头。

在这里插入图片描述
  1. 其中摄像头对应的此设备为: /dev/v4l-subdev3
  2. 应用层要配置通用配置、或者获取图像,需要操作设备 /dev/video0
  3. 有一些摄像头专用的命令,我们可以操作 /dev/v4l-subdev3

ov13850摄像头驱动中注册了一些命令对应的回调函数:

这些回调函数都注册到了V4L2架构中,我们可以通过字符设备 /dev/videox,、/dev/v4l-subdevx 直接或者间接访问到这些回调函数。

V4L2定义了一些通用的命令,操作字符设备 /dev/videox即可调用,命令具体定义如下:

kernel\drivers\media\v4l2-core\v4l2-ioctl.c

可以通过数组名+命令对应的数值方式访问对应的回调函数。 该数组定义如下:

struct v4l2_ioctl_info {
 unsigned int ioctl;
 u32 flags;
 const char * const name;
 int (*func)(const struct v4l2_ioctl_ops *ops, struct file *file,
      void *fh, void *p);
 void (*debug)(const void *arg, bool write_only);
};

字符设备**/dev/v4l-subdevx**支持的命令如下:

@kernel\drivers\media\v4l2-core\v4l2-subdev.c

static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{
  ……
 switch (cmd) {
 case VIDIOC_QUERYCTRL:
  ……
 case VIDIOC_QUERY_EXT_CTRL:
  ……
 case VIDIOC_QUERYMENU:
  ……
 case VIDIOC_G_CTRL:
  ……
 case VIDIOC_S_CTRL:
  ……
 case VIDIOC_G_EXT_CTRLS:
  ……
 case VIDIOC_S_EXT_CTRLS:
  ……
 case VIDIOC_TRY_EXT_CTRLS:
  ……
 case VIDIOC_DQEVENT:
  ……
 case VIDIOC_SUBSCRIBE_EVENT:
  return v4l2_subdev_call(sd, core, subscribe_event, vfh, arg);
 case VIDIOC_UNSUBSCRIBE_EVENT:
  return v4l2_subdev_call(sd, core, unsubscribe_event, vfh, arg);
#ifdef CONFIG_VIDEO_ADV_DEBUG
 case VIDIOC_DBG_G_REGISTER:
  ……
 case VIDIOC_DBG_S_REGISTER:
  ……
 case VIDIOC_DBG_G_CHIP_INFO:
  ……
#endif
 case VIDIOC_LOG_STATUS: {
  ……
#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
 case VIDIOC_SUBDEV_G_FMT: {
  ……
 case VIDIOC_SUBDEV_S_FMT: {
  ……
 case VIDIOC_SUBDEV_G_CROP: {
  ……
 }
 case VIDIOC_SUBDEV_S_CROP: {
  ……
 }
 case VIDIOC_SUBDEV_ENUM_MBUS_CODE: {
  ……
 }
 case VIDIOC_SUBDEV_ENUM_FRAME_SIZE: {
  ……
 }
 case VIDIOC_SUBDEV_G_FRAME_INTERVAL: {
  ……
 }
 case VIDIOC_SUBDEV_S_FRAME_INTERVAL: {
  ……
 }
 case VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL: {
  ……
 }
 case VIDIOC_SUBDEV_G_SELECTION: {
  ……
 }
 case VIDIOC_SUBDEV_S_SELECTION: {
  ……
 }
 case VIDIOC_G_EDID: {
  ……
 }
 case VIDIOC_S_EDID: {
  ……
 }
 case VIDIOC_SUBDEV_DV_TIMINGS_CAP: {
  ……
 }
 case VIDIOC_SUBDEV_ENUM_DV_TIMINGS: {
  ……
 }
 case VIDIOC_SUBDEV_QUERY_DV_TIMINGS:
  return v4l2_subdev_call(sd, video, query_dv_timings, arg);
 case VIDIOC_SUBDEV_G_DV_TIMINGS:
  return v4l2_subdev_call(sd, video, g_dv_timings, arg);
 case VIDIOC_SUBDEV_S_DV_TIMINGS:
  return v4l2_subdev_call(sd, video, s_dv_timings, arg);
 case VIDIOC_G_INPUT:
  return v4l2_subdev_call(sd, video, g_input_status, arg);
 case VIDIOC_SUBDEV_G_STD:
  return v4l2_subdev_call(sd, video, g_std, arg);
 case VIDIOC_SUBDEV_S_STD: {
  v4l2_std_id *std = arg;
  return v4l2_subdev_call(sd, video, s_std, *std);
 }
 case VIDIOC_SUBDEV_ENUMSTD: {
  ……
 }
 case VIDIOC_SUBDEV_QUERYSTD:
  ……
 }
 return 0;
}

这其中有一些命令是和字符设备 /dev/videox 的命令重复的,

比如:VIDIOC_S_CTRL,

VIDIOC_SUBDEV_ 开头的则是subdev私有的。

关于这些命令和回调函数,后续会再深入讲解,对于应用程序开发,

我们首先搞清楚设备的拓扑结构,然后需要知道我们要执行的命令功能以及对应的是哪一个设备节点即可。

4. ioctl命令说明

参见结构体见

 /usr/include/linux/videodev2.h

1)Querying Capabilities

查询设备的功能

由于V4L2涵盖了各种各样的设备,因此并非API的所有方面都适用于所有类型的设备,在使用v4l2设备时,必须调用此API,获得设备支持的功能(capture、output、overlay…)

ID描述
VIDIOC_QUERYCAP查询设备功能
struct v4l2_capability
{

 u8 driver[16]; // 驱动名字
 u8 card[32]; // 设备名字
 u8 bus_info[32]; // 设备在系统中的位置
 u32 version; // 驱动版本号
 u32 capabilities; // 设备支持的操作
 u32 reserved[4]; // 保留字段
};

capabilities 常用值:

V4L2_CAP_VIDEO_CAPTURE // 是否支持图像获取

2)Application Priority

应用优先级

当多个应用程序共享设备时,可能需要为它们分配不同的优先级。视频录制应用程序可以例如阻止其他应用程序改变视频控制或切换当前的电视频道。

另一个目标是允许在后台工作的低优先级应用程序,这些应用程序可以被用户控制的应用程序抢占,并在以后自动重新获得对设备的控制

ID描述
VIDIOC_G_PRIORITY获取优先级
VIDIOC_S_PRIORITY设置优先级

3)Device Inputs and Outputs

输入和输出设备

ID描述
VIDIOC_ENUMINPUT枚举视频输入设备
VIDIOC_G_INPUT获取当前的视频输入设备
VIDIOC_S_INPUT设置视频输入设备
VIDIOC_ENUMOUTPUT枚举视频输出设备
VIDIOC_G_OUTPUT获取当前视频输出设备
VIDIOC_S_OUTPUT设置视频输出设备
VIDIOC_ENUMAUDIO枚举音频输入设备
VIDIOC_G_AUDIO获取当前音频输入设备
VIDIOC_S_AUDIO设置音频输入设备
VIDIOC_ENUMAUDOUT枚举音频输出设备
VIDIOC_G_OUTPUT获取音频输出设备
VIDIOC_S_AUDOUT设置音频输出设备

VIDIOC_G_INPUT 和 VIDIOC_S_INPUT 用来查询和选则当前的 input,一个 video 设备 节点可能对应多个视频源,比如 saf7113 可以最多支持四路 cvbs 输入,如果上层想在四 个cvbs视频输入间切换,那么就要调用 ioctl(fd, VIDIOC_S_INPUT, &input) 来切换。

VIDIOC_G_INPUT and VIDIOC_G_OUTPUT 返回当前的 video input和output的index.

struct v4l2_input {
 __u32 index; /* Which input */
 __u8 name[32]; /* Label */
 __u32 type; /* Type of input */
 __u32 audioset; /* Associated audios (bitfield) */
 __u32 tuner; /* Associated tuner */
 v4l2_std_id std;
 __u32 status;
 __u32 reserved[4];
};

我们可以通过VIDIOC_ENUMINPUT and VIDIOC_ENUMOUTPUT 分别列举一个input或者 output的信息,我们使用一个v4l2_input结构体来存放查询结果,这个结构体中有一个 index域用来指定你索要查询的是第几个input/ouput,如果你所查询的这个input是当前正 在使用的,那么在v4l2_input还会包含一些当前的状态信息,如果所 查询的input/output 不存在,那么回返回EINVAL错误,所以,我们通过循环查找,直到返回错误来遍历所有的 input/output. VIDIOC_G_INPUT and VIDIOC_G_OUTPUT 返回当前的video input和output 的index.

4) Video Standards

视频标准

ID描述
VIDIOC_ENUMSTD枚举设备支持的所有标准
VIDIOC_G_STD获取当前正在使用的标准
VIDIOC_S_STD设置视频标准
VIDIOC_QUERYSTD有的设备支持自动侦测输入源的视频标准,此ioctl获取检测到的标准
typedef u64 v4l2_std_id;
 struct v4l2_standard {
 u32 index;
 v4l2_std_id id;
 u8 name[24];
 struct v4l2_fract frameperiod; /* Frames, not fields */
 u32 framelines;
 u32 reserved[4];
};

当然世界上现在有多个视频标准,如NTSC和PAL,他们又细分为好多种,那么我们的设 备输入/输出究竟支持什么样的标准呢?我们的当前在使用的输入和输出正在使用的是哪 个标准呢?我们怎么设置我们的某个输入输出使用的标准呢?这都是有方法的。

查询我们的输入支持什么标准,首先就得找到当前的这个输入的index,然后查出它的 属性,在其属性里面可以得到该输入所支持的标准,将它所支持的各个标准与所有的标准 的信息进行比较,就可以获知所支持的各个标准的属性。一个输入所支持的标准应该是一 个集合,而这个集合是用bit与的方式用一个64位数字表示。因此我们所查到的是一个数字。

5) Camera Control Reference

控制属性

ID描述
VIDIOC_QUERYCTRL查询指定的control详细信息
VIDIOC_QUERYMENU查询menu
VIDIOC_G_CTRL获取设备指定control的当前信息
VIDIOC_S_CTRL设置设备指定的control

6) Image Format

图像格式

图像由多种格式YUV和RGB还有压缩格式等等,其中每种格式又分有多种格式,比如RGB:RGB565、RGB888…

所以在使用设备时,需要对格式进行设置

ID描述
VIDIOC_ENUM_FMT枚举设备支持的图像格式
VIDIOC_G_FMT获取当前设备的图像格式
VIDIOC_S_FMT设置图像格式
VIDIOC_TRY_FMT测试设备是否支持此格式

查询并显示所有支持的格式:VIDIOC_ENUM_FMT

struct v4l2_fmtdesc
{

 u32 index; // 要查询的格式序号,应用程序设置
 enum v4l2_buf_type type; // 帧类型,应用程序设置
 u32 flags; // 是否为压缩格式
 u8 description[32]; // 格式名称
 u32 pixelformat; // 格式
 u32 reserved[4]; // 保留
};

查看或设置当前格式: VIDIOC_G_FMT, VIDIOC_S_FMT

struct v4l2_format
{

 enum v4l2_buf_type type; // 帧类型,应用程序设置
 union fmt
 {
  struct v4l2_pix_format pix; // 视频设备使用 
  struct v4l2_window win; 
  struct v4l2_vbi_format vbi; 
  struct v4l2_sliced_vbi_format sliced; 
  u8 raw_data[200]; 
 };
};

struct v4l2_pix_format
{

 u32 width; // 帧宽,单位像素 
 u32 height; // 帧高,单位像素 
 u32 pixelformat; // 帧格式 
 enum v4l2_field field; 
 u32 bytesperline; 
 u32 sizeimage; 
 enum v4l2_colorspace colorspace; 
 u32 priv;
};

7) Cropping, composing and scaling

图像裁剪、插入与缩放

ID描述
VIDIOC_CROPCAP获取图像裁剪缩放能力
VIDIOC_G_CROP获取当前的裁剪矩阵
VIDIOC_S_CROP设置裁剪矩阵

Cropping 和 scaling 主要指的是图像的取景范围及图片的比例缩放的支持。Crop 就 是把得到的数据作一定的裁剪和伸缩,裁剪可以只取样我们可以得到的图像大小的一部分, 剪裁的主要参数是位置、长度、宽度。而 scale 的设置是通过 VIDIOC_G_FMT 和 VIDIOC_S_FMT 来获得和设置当前的 image 的长度,宽度来实现的。 看下图:

我们可以假设 bounds 是 sensor 最大能捕捉到的图像范围,而 defrect 是设备默认 的最大取样范围,这个可以通过 VIDIOC_CROPCAP 的 ioctl 来获得设备的 crap 相关的属 性 v4l2_cropcap,其中的 bounds 就是这个 bounds,其实就是上限。每个设备都有个默 认的取样范围,就是 defrect,就是 default rect 的意思,它比 bounds 要小一些。这 个范围也是通过 VIDIOC_CROPCAP 的 ioctl 来获得的 v4l2_cropcap 结构中的 defrect 来表示的,我们可以通过 VIDIOC_G_CROP 和 VIDIOC_S_CROP 来获取和设置设备当前的 crop 设置。

设置设备捕捉能力的参数

struct v4l2_cropcap
{

 enum v4l2_buf_type type; // 数据流的类型,应用程序设置
 struct v4l2_rect bounds; // 这是 camera 的镜头能捕捉到的窗口大小的局限
 struct v4l2_rect defrect; // 定义默认窗口大小,包括起点位置及长,宽的大小,大小以像素为单位
 struct v4l2_fract pixelaspect; // 定义了图片的宽高比
};

设置窗口取景参数 VIDIOC_G_CROP 和 VIDIOC_S_CROP

struct v4l2_crop
{

 enum v4l2_buf_type type;// 应用程序设置
 struct v4l2_rect c;
}

8)  buf Input/Output

数据的输入和输出

内核中使用缓存队列对图像数据进行管理,用户空间获取图像数据有两种方式,一种是通过read、write方式读取内核空间的缓存,一种是将内核空间的缓存映射到用户空间,即streaming。在操作v4l2设备时,通过VIDIOC_QUERYCAP获取设备支持哪种方式。 streaming就是在内核空间中维护一个缓存队列,然后将内存映射到用户空间,应用读取图像数据就是一个不断地出队列和入队列的过程,如下图所示

ID描述
VIDIOC_REQBUFS申请缓存
VIDIOC_QUERYBUF获取缓存信息
VIDIOC_QBUF将缓存放入队列中
VIDIOC_DQBUF将缓存从队列中取出

1. 向设备申请缓冲区 VIDIOC_REQBUFS

struct v4l2_requestbuffers
{

 u32 count; // 缓冲区内缓冲帧的数目
 enum v4l2_buf_type type; // 缓冲帧数据格式
 enum v4l2_memory memory; // 区别是内存映射还是用户指针方式
 u32 reserved[2];
};
enum v4l2_memoy
{
 V4L2_MEMORY_MMAP, V4L2_MEMORY_USERPTR
};

获取缓冲帧的地址,长度:VIDIOC_QUERYBUF

struct v4l2_buffer
{

 u32 index; //buffer 序号
 enum v4l2_buf_type type; //buffer 类型
 u32 byteused; //buffer 中已使用的字节数
 u32 flags; // 区分是MMAP 还是USERPTR 
 enum v4l2_field field; 
 struct timeval timestamp; // 获取第一个字节时的系统时间 
 struct v4l2_timecode timecode; 
 u32 sequence; // 队列中的序号 
 enum v4l2_memory memory; //IO 方式,被应用程序设置 
 union m 
 { 
  u32 offset; // 缓冲帧地址,只对MMAP 有效 
  unsigned long userptr; 
 }; 
 u32 length; // 缓冲帧长度 
 u32 input; 
 u32 reserved;
};

2. 内存映射MMAP 及定义一个结构体来映射每个缓冲帧。相关结构体:

struct buffer
{

 void* start;
 unsigned int length;
}*buffers;

相关函数:

#include 

void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset)
参数:
addr 映射起始地址,一般为NULL ,让内核自动选择
length 被映射内存块的长度
prot 标志映射后能否被读写,其值为PROT_EXEC,PROT_READ,PROT_WRITE, PROT_NONE
flags 确定此内存映射能否被其他进程共享,MAP_SHARED,MAP_PRIVATE
fd,offset, 确定被映射的内存地址 返回成功映射后的地址,不成功返回MAP_FAILED ((void*)-1)

3.将所有的缓存放入队列

struct v4l2_buffer v4l2_buffer;

for(i = 0; i < nr_bufs; i++)
{
 memset(&v4l2_buffer, 0sizeof(struct v4l2_buffer));
 v4l2_buffer.index = i; //想要放入队列的缓存
 v4l2_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 v4l2_buffer.memory = V4L2_MEMORY_MMAP; 

    ret = ioctl(fd, VIDIOC_QBUF, &v4l2_buffer);
    if(ret < 0)
    {
        printf("Unable to queue buffer.\n");
        return -1;
    }
}

9)启动 或 停止数据流

VIDIOC_STREAMON, VIDIOC_STREAMOFF

type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ioctl (fd, VIDIOC_STREAMON, &type);

5. v4l2设备抓帧程序编写

v4l2设备的命令比较多,其实常用的并不是很多,下面通过一个实例来详细讲解,如何操作v4l2设备。

1)设备配置

本例,将常用的摄像头配置参数等装成结构体:

struct v4l2_dev
{

    int fd;   //videoO对应的设备描述符
    int sub_fd; 
    const char *path; //字符设备 /dev/videoO
    const char *name; //摄像头名称
    const char *subdev_path;//字符设备 /dev/v4l-subdev3
    const char *out_type; //输出图像格式
    enum v4l2_buf_type buf_type;//缓存类型
    int format; //像素格式
    int width;  //图像宽度
    int height; //图像高度
    unsigned int req_count; //缓存数量
    enum v4l2_memory memory_type; //读取图像的方法,DMA还是MMAP
    struct buffer *buffers; //缓冲区
    unsigned long int timestamp;//时长度
    int data_len;//图像数据长度
    unsigned char *out_data;//图像数据
};

本例填写的摄像头ov13850的配置信息如下:

struct v4l2_dev ov13850 = {
    .fd = -1,
    .sub_fd = -1,
    .path = "/dev/video0",
    .name = "ov13850",
    .subdev_path = "/dev/v4l-subdev3",
    .out_type = "nv12",
    .buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
    .format = V4L2_PIX_FMT_NV12,
    .width = 800,
    .height = 600,
    .req_count = 4,
    .memory_type = V4L2_MEMORY_MMAP,
    .buffers = NULL,
    .timestamp = 0,
    .data_len = 0,
    .out_data = NULL,
};

2)v4l2设备一般操作流程(抓帧)

v4l2设备一般操作流程如下图所示:

各功能对应的ioctrl命令如下:

测试程序一口君已经上传到gitee:

https://gitee.com/yikoulinux/v4l2-app

git clone git@gitee.com:yikoulinux/v4l2-app.git

欢迎各位老铁star。

3)程序执行log

以下是在瑞芯微rk3568实际测试的log。

rk3568_r:/ # /data/capture                                       
/data/capture                                                    
Open /dev/video0 succeed - 3                                     
                                                                 
Open /dev/v4l-subdev3 succeed                                    
                                                                 
------- VIDIOC_QUERYCAP ----                                     
  driver: rkisp_v5                                               
  card: rkisp_mainpath                                           
  bus_info: platform:rkisp-vir0                                  
  version: 1.8.0                                                 
  capabilities: 84201000                                         
        Video Capture Mplane                                     
        Streaming                                                
                                                                 
VIDIOC_S_FMT succeed!                                            
width 800, height 600, size 720000, bytesperline 0, format NV12  
                                                                 
VIDIOC_REQBUFS succeed!                                          
                                                                 
Memory map succeed!                                              
                                                                 
VIDIOC_QBUF succeed!                                             
                                                                 
VIDIOC_STREAMON succeed!                                         
                                                                 
image: sequence = 0, timestamp = 1115378780                      
image: sequence = 1, timestamp = 1115511890                      
image: sequence = 2, timestamp = 1115645004                      
image: sequence = 3, timestamp = 1115778130                      
image: sequence = 4, timestamp = 1115911257                      
image: sequence = 5, timestamp = 1116044365                      
image: sequence = 6, timestamp = 1116177498                      
image: sequence = 7, timestamp = 1116310610                      
image: sequence = 8, timestamp = 1116443739                      
image: sequence = 9, timestamp = 1116576844                      
Save one frame to /data/ov13850.nv12 succeed!                    
                                                                 
VIDIOC_STREAMOFF succeed!                                        

文中各种mipi技术文档,后台回复关键字:mipi

掌握了这些命令,我们就可以调试摄像头了。

后面还会继续更新几篇Camera文章,

建议大家订阅本专题!

也可以后台留言,加一口君好友yikoupeng,

拉你进高质量技术交流群。

end


一口Linux 


关注,回复【1024】海量Linux资料赠送

精彩文章合集


文章推荐

【专辑】ARM
【专辑】粉丝问答
专辑linux入门
专辑计算机网络
专辑Linux驱动
【干货】嵌入式驱动工程师学习路线
【干货】Linux嵌入式所有知识点-思维导图

一口Linux 写点代码,写点人生!
评论
  • 物联网(IoT)的快速发展彻底改变了从智能家居到工业自动化等各个行业。由于物联网系统需要高效、可靠且紧凑的组件来处理众多传感器、执行器和通信设备,国产固态继电器(SSR)已成为满足中国这些需求的关键解决方案。本文探讨了国产SSR如何满足物联网应用的需求,重点介绍了它们的优势、技术能力以及在现实场景中的应用。了解物联网中的固态继电器固态继电器是一种电子开关设备,它使用半导体而不是机械触点来控制负载。与传统的机械继电器不同,固态继电器具有以下优势:快速切换:确保精确快速的响应,这对于实时物联网系统至
    克里雅半导体科技 2025-01-03 16:11 81浏览
  • 光耦合器,也称为光隔离器,是一种利用光在两个隔离电路之间传输电信号的组件。在医疗领域,确保患者安全和设备可靠性至关重要。在众多有助于医疗设备安全性和效率的组件中,光耦合器起着至关重要的作用。这些紧凑型设备经常被忽视,但对于隔离高压和防止敏感医疗设备中的电气危害却是必不可少的。本文深入探讨了光耦合器的功能、其在医疗应用中的重要性以及其实际使用示例。什么是光耦合器?它通常由以下部分组成:LED(发光二极管):将电信号转换为光。光电探测器(例如光电晶体管):检测光并将其转换回电信号。这种布置确保输入和
    腾恩科技-彭工 2025-01-03 16:27 77浏览
  • 前言近年来,随着汽车工业的快速发展,尤其是新能源汽车与智能汽车领域的崛起,汽车安全标准和认证要求日益严格,应用范围愈加广泛。ISO 26262和ISO 21448作为两个重要的汽车安全标准,它们在“系统安全”中扮演的角色各自不同,但又有一定交集。在智能网联汽车的高级辅助驾驶系统(ADAS)应用中,理解这两个标准的区别及其相互关系,对于保障车辆的安全性至关重要。ISO 26262:汽车功能安全的基石如图2.1所示,ISO 26262对“功能安全”的定义解释为:不存在由于电子/电气系统失效引起的危害
    广电计量 2025-01-02 17:18 146浏览
  • Matter加持:新世代串流装置如何改变智能家居体验?随着现在智能家庭快速成长,串流装置(Streaming Device,以下简称Streaming Device)除了提供更卓越的影音体验,越来越多厂商开始推出支持Matter标准的串流产品,使其能作为智能家庭中枢,连结多种智能家电。消费者可以透过Matter的功能执行多样化功能,例如:开关灯、控制窗帘、对讲机开门,以及操作所有支持Matter的智能家电。此外,再搭配语音遥控器与语音助理,打造出一个更加智能、便捷的居家生活。支持Matter协议
    百佳泰测试实验室 2025-01-03 10:29 60浏览
  • 影像质量应用于多个不同领域,无论是在娱乐、医疗或工业应用中,高质量的影像都是决策的关键基础。清晰的影像不仅能提升观看体验,还能保证关键细节的准确传达,例如:在医学影像中,它对诊断结果有着直接的影响!不仅如此,影像质量还影响了:▶ 压缩技术▶ 存储需求▶ 传输效率随着技术进步,影像质量的标准不断提高,对于研究与开发领域,理解并提升影像质量已成为不可忽视的重要课题。在图像处理的过程中,硬件与软件除了各自扮演着不可或缺的基础角色,有效地协作能够确保图像处理过程既高效又具有优异的质量。软硬件各扮演了什么
    百佳泰测试实验室 2025-01-03 10:39 55浏览
  • 【工程师故事】+半年的经历依然忧伤,带着焦虑和绝望  对于一个企业来说,赚钱才是第一位的,对于一个人来说,赚钱也是第一位的。因为企业要活下去,因为个人也要活下去。企业打不了倒闭。个人还是要吃饭的。企业倒闭了,打不了从头再来。个人失业了,面对的不仅是房贷车贷和教育,还有找工作的焦虑。企业说,一个公司倒闭了,说明不了什么,这是正常的一个现象。个人说,一个中年男人失业了,面对的压力太大了,焦虑会摧毁你的一切。企业说,是个公司倒闭了,也不是什么大的问题,只不过是这些公司经营有问题吧。
    curton 2025-01-02 23:08 173浏览
  • 在快速发展的能源领域,发电厂是发电的支柱,效率和安全性至关重要。在这种背景下,国产数字隔离器已成为现代化和优化发电厂运营的重要组成部分。本文探讨了这些设备在提高性能方面的重要性,同时展示了中国在生产可靠且具有成本效益的数字隔离器方面的进步。什么是数字隔离器?数字隔离器充当屏障,在电气上将系统的不同部分隔离开来,同时允许无缝数据传输。在发电厂中,它们保护敏感的控制电路免受高压尖峰的影响,确保准确的信号处理,并在恶劣条件下保持系统完整性。中国国产数字隔离器经历了重大创新,在许多方面达到甚至超过了全球
    克里雅半导体科技 2025-01-03 16:10 48浏览
  • 本文继续介绍Linux系统查看硬件配置及常用调试命令,方便开发者快速了解开发板硬件信息及进行相关调试。触觉智能RK3562开发板演示,搭载4核A53处理器,主频高达2.0GHz;内置独立1Tops算力NPU,可应用于物联网网关、平板电脑、智能家居、教育电子、工业显示与控制等行业。查看系统版本信息查看操作系统版本信息root@ido:/# cat /etc/*releaseDISTRIB_ID=UbuntuDISTRIB_RELEASE=20.04DISTRIB_CODENAME=focalDIS
    Industio_触觉智能 2025-01-03 11:37 65浏览
  • 自动化已成为现代制造业的基石,而驱动隔离器作为关键组件,在提升效率、精度和可靠性方面起到了不可或缺的作用。随着工业技术不断革新,驱动隔离器正助力自动化生产设备适应新兴趋势,并推动行业未来的发展。本文将探讨自动化的核心趋势及驱动隔离器在其中的重要角色。自动化领域的新兴趋势智能工厂的崛起智能工厂已成为自动化生产的新标杆。通过结合物联网(IoT)、人工智能(AI)和机器学习(ML),智能工厂实现了实时监控和动态决策。驱动隔离器在其中至关重要,它确保了传感器、执行器和控制单元之间的信号完整性,同时提供高
    腾恩科技-彭工 2025-01-03 16:28 87浏览
  • 车身域是指负责管理和控制汽车车身相关功能的一个功能域,在汽车域控系统中起着至关重要的作用。它涵盖了车门、车窗、车灯、雨刮器等各种与车身相关的功能模块。与汽车电子电气架构升级相一致,车身域发展亦可以划分为三个阶段,功能集成愈加丰富:第一阶段为分布式架构:对应BCM车身控制模块,包含灯光、雨刮、门窗等传统车身控制功能。第二阶段为域集中架构:对应BDC/CEM域控制器,在BCM基础上集成网关、PEPS等。第三阶段为SOA理念下的中央集中架构:VIU/ZCU区域控制器,在BDC/CEM基础上集成VCU、
    北汇信息 2025-01-03 16:01 76浏览
  • 国际标准IPC 标准:IPC-A-600:规定了印刷电路板制造过程中的质量要求和验收标准,涵盖材料、外观、尺寸、焊接、表面处理等方面。IPC-2221/2222:IPC-2221 提供了用于设计印刷电路板的一般原则和要求,IPC-2222 则针对高可靠性电子产品的设计提供了进一步的指导。IPC-6012:详细定义了刚性基板和柔性基板的要求,包括材料、工艺、尺寸、层次结构、特征等。IPC-4101:定义了印刷电路板的基板材料的物理和电气特性。IPC-7351:提供了元件封装的设计规范,包括封装尺寸
    Jeffreyzhang123 2025-01-02 16:50 155浏览
  • 在测试XTS时会遇到修改产品属性、SElinux权限、等一些内容,修改源码再编译很费时。今天为大家介绍一个便捷的方法,让OpenHarmony通过挂载镜像来修改镜像内容!触觉智能Purple Pi OH鸿蒙开发板演示。搭载了瑞芯微RK3566四核处理器,树莓派卡片电脑设计,支持开源鸿蒙OpenHarmony3.2-5.0系统,适合鸿蒙开发入门学习。挂载镜像首先,将要修改内容的镜像传入虚拟机当中,并创建一个要挂载镜像的文件夹,如下图:之后通过挂载命令将system.img镜像挂载到sys
    Industio_触觉智能 2025-01-03 11:39 57浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦