Linux下实现视频读取(二)---camera参数设定

Camera的可设置项极多,V4L2 支持了不少。但Sam之前对这些设置的用法和涵义都是在看videodev2.h中边看边理解,感觉非常生涩。直到写这篇blog时,才发现v4l2有专门的SPEC来说明:

http://www.linuxtv.org/downloads/legacy/video4linux/API/V4L2_API/spec-single/v4l2.html

但也基本没有时间仔细看了。先把自己看头文件看出的一些东西记录在这里吧。以实际设置过程为顺序谈谈V4L2 设置。

1. 查询V4L2 功能集:VIDIOC_QUERYCAP

struct v4l2_capability cap;

int rel = 0;

ioctl(Handle, VIDIOC_QUERYCAP, &cap);

使用ioctl VIDIOC_QUERYCAP 来查询当前driver是否合乎规范。因为V4L2要求所有driver 和Device都支持这个Ioctl。所以,可以通过这个ioctl是否成功来判断当前设备和dirver 是否支持V4L2规范。当然,这样同时还能够得到设备足够的能力信息。

struct v4l2_capability

{

__u8 driver[16];   //驱动名。

__u8 card[32];     // Device名

__u8 bus_info[32];  //在Bus系统中存放位置

__u32 version;      //driver 版本

__u32 capabilities;  //能力集

__u32 reserved[4];

};

能力集中包含:

V4L2_CAP_VIDEO_CAPTURE 0x00000001     The device supports the Video    Capture interface.

V4L2_CAP_VIDEO_OUTPUT   0x00000002     The device supports the Video    Output interface.

V4L2_CAP_VIDEO_OVERLAY 0x00000004     The device supports the Video    Overlay interface.

A video overlay device typically stores captured images directly in the video memory   of a graphics card,with hardware clipping and scaling.

V4L2_CAP_VBI_CAPTURE     0x00000010 The device supports the Raw  VBI Capture interface, providing Teletext and Closed Caption   data.

V4L2_CAP_VBI_OUTPUT     0x00000020      The device supports the Raw  VBI Output interface.

V4L2_CAP_SLICED_VBI_CAPTURE  0x00000040 The device supports the Sliced VBI Capture interface.

V4L2_CAP_SLICED_VBI_OUTPUT   0x00000080 The device supports the Sliced VBI Output interface.

V4L2_CAP_RDS_CAPTURE    0x00000100          [to be defined]

#define V4L2_CAP_TUNER 0x00010000

#define V4L2_CAP_AUDIO 0x00020000

#define V4L2_CAP_RADIO 0x00040000

#define V4L2_CAP_READWRITE 0x01000000

#define V4L2_CAP_ASYNCIO 0x02000000

#define V4L2_CAP_STREAMING 0x04000000

看起来很熟悉吧,其实就是Driver里面的Type。

__u8 driver[16]; driver名,通常为:uvcvideo

__u8 card[32];  设备名:厂商会填写。

__u8 bus_info[32];  bus,通常为:usb-hiusb-ehci-2.4

__u32 version;

__u32 capabilities;  通常为:V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING

__u32 reserved[4];

2. 枚举设备所支持的image format:  VIDIOC_ENUM_FMT

struct v4l2_fmtdesc fmtdesc;

fmtdesc.index = 0;

fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

ret = ioctl(Handle, VIDIOC_ENUM_FMT, &fmtdesc);

使用ioctl VIDIOC_ENUM_FMT 依次询问,type为:V4L2_BUF_TYPE_VIDEO_CAPTURE。 index从0开始,依次增加,直到返回. Driver会填充结构体struct v4l2_fmtdesc的其它内容,如果index超出范围,则返回-1。

struct v4l2_fmtdesc

{

__u32 index;                  // 需要填充,从0开始,依次上升。

enum v4l2_buf_type type;      //Camera,则填写V4L2_BUF_TYPE_VIDEO_CAPTURE

__u32 flags;                  // 如果压缩的,则Driver 填写:V4L2_FMT_FLAG_COMPRESSED,否则为0

__u8 description[32];         // image format的描述,如:YUV 4:2:2 (YUYV)

__u32 pixelformat;        //所支持的格式。如:V4L2_PIX_FMT_UYVY

__u32 reserved[4];

};

这样,则知道当前硬件支持什么样的image format. 下一步,则可以设置image 了。当然,设置之前,还可以读取当前缺省设置。

3. 得到和设置Image Format: VIDIOC_G_FMT, VIDIOC_S_FMT:

3.1: 得到当前Image Format:

struct v4l2_format Format;

memset(&Format, 0, sizeof(struct v4l2_format));

Format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

ioctl(Handle, VIDIOC_G_FMT, &Format);

利用ioctl VIDIOC_G_FMT. 得到当前设置。

因为Camera为CAPTURE设备,所以需要设置type为: V4L2_BUF_TYPE_VIDEO_CAPTURE

然后Driver会填充其它内容。

struct v4l2_format

{

enum v4l2_buf_type type;   // Camera,则用户必须填写:V4L2_BUF_TYPE_VIDEO_CAPTURE

union

{

struct v4l2_pix_format pix;    // used by video capture and output devices

struct v4l2_window win;

struct v4l2_vbi_format vbi;

struct v4l2_sliced_vbi_format sliced;

__u8 raw_data[200];

} fmt;

};

因为是Camera, 所以采用pix. 现在分析如下:

struct v4l2_pix_format

{

__u32 width;    //Image width in pixels.

__u32 height;   // Image Height in pixels.

__u32 pixelformat;  // Image格式,最常见的有:V4L2_PIX_FMT_YYUV

enum v4l2_field field; //是否逐行扫描,是否隔行扫描. Sam通常采用V4L2_FIELD_NONE,逐行放置数据 (注1)

__u32 bytesperline; //每行的byte数

__u32 sizeimage;     //总共的byte数,bytesperline * height

enum v4l2_colorspace colorspace;  //This information supplements the pixelformat and must be set by the driver

__u32 priv;

};

3.2:设置Image Format:VIDIOC_S_FMT

之前通过VIDIOC_ENUM_FMT已经知道Device支持什么Format。所以就不用猜测了,直接设置吧。

设置Image  Format ,利用 iocto VIDIOC_S_FMT.

需要APPLICATION填写的Struct项目有:

struct v4l2_format Format;

Format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

Format.fmt.pix.width =  Width;

Format.fmt.pix.height = Height;

Format.fmt.pix.pixelformat= pixelformat;//V4L2_PIX_FMT_YUYV;

Format.fmt.pix.field = field;

io_rel = ioctl(Handle, VIDIOC_S_FMT, &Format);

SamInfo:之前设置了Image Format,是指每一帧的数据格式,但Stream的行为呢,也需要设置,这就是下面所说的Stream 设置了。它就包含帧数设置和修改。

4. 得到和设置Stream信息:VIDIOC_G_PARM, VIDIOC_S_PARM

Stream信息,主要是设置帧数。

4.1:得到Stream信息:

struct v4l2_streamparm Stream_Parm;

memset(&Stream_Parm, 0, sizeof(struct v4l2_streamparm));

Stream_Parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

io_rel = ioctl(Handle, VIDIOC_G_PARM, &Stream_Parm);

用户只需要填充type为V4L2_BUF_TYPE_VIDEO_CAPTURE。 Driver就会把结构体中其它部分填充好。

struct v4l2_streamparm

{

enum v4l2_buf_type type;

union

{

struct v4l2_captureparm capture;

struct v4l2_outputparm output;

__u8 raw_data[200];

} parm;

};

因为是Camera, 所以使用capture. 它是 struct v4l2_captureparm

struct v4l2_captureparm

{

__u32 capability;    //是否可以被timeperframe控制帧数。可以则:V4L2_CAP_TIMEPERFRAME

__u32 capturemode;   //是否为高清模式。如果是:

则设置为:V4L2_MODE_HIGHQUALITY。 高清模式会牺牲其它信息。通常设置为0。

struct v4l2_fract timeperframe;  //帧数。

__u32 extendedmode;  //定制的。如果不支持,设置为0

__u32 readbuffers;

__u32 reserved[4];

};

struct v4l2_fract timeperframe;  //帧数。

struct v4l2_fract {

__u32 numerator;  // 分子。例:1

__u32 denominator; //分母。 例:30

};

4.2:设置帧数:

struct v4l2_streamparm Stream_Parm;

memset(&Stream_Parm, 0, sizeof(struct v4l2_streamparm));

Stream_Parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

Stream_Parm.parm.capture.timeperframe.denominator =Denominator;;

Stream_Parm.parm.capture.timeperframe.numerator = Numerator;

io_rel = ioctl(Handle, VIDIOC_S_PARM, &Stream_Parm);

请注意,哪怕ioctl返回0。也有可能没设置成功。所以需要再次Get。

当然,哪怕Get发现设置成功。真正抓帧也可能没那么高。

5. 利用VIDIOC_G_CTRL得到一些设置:

一些具体的设置,如曝光模式(Exposure Type),曝光值(Exposure),增益(Gain),白平衡(WHITE_BALANCE),亮度(BRIGHTNESS),饱和度(SATURATION),对比度(CONTRAST)等信息。可以通过VIDIOC_G_CTRL得到当前值。

用法:APP 填写结构体中的id. 通过调用VIDIOC_G_CTRL,driver 会填写结构体中value项。

struct v4l2_control ctrl;

struct v4l2_control

{

__u32 id;

__s32 value;

};

以曝光模式,曝光,和增益为例;

曝光模式:

struct v4l2_control ctrl;

ctrl.id = V4L2_CID_EXPOSURE_AUTO;

ret = ioctl(Handle, VIDIOC_G_CTRL, &ctrl);

ctrl.value 则由Driver填写。告知当前曝光模式。

有以下几个选择:

enum  v4l2_exposure_auto_type {

V4L2_EXPOSURE_AUTO = 0,

V4L2_EXPOSURE_MANUAL = 1,

V4L2_EXPOSURE_SHUTTER_PRIORITY = 2,

V4L2_EXPOSURE_APERTURE_PRIORITY = 3

};

曝光:

struct v4l2_control ctrl;

ctrl.id = V4L2_CID_EXPOSURE_ABSOLUTE;

ret = ioctl(Handle, VIDIOC_G_CTRL, &ctrl);

同样,driver填写ctrl.value. 内容为曝光值。

增益:

struct v4l2_control ctrl;

ctrl.id = V4L2_CID_GAIN;

ret = ioctl(Handle, VIDIOC_G_CTRL, &ctrl);

同样,driver填写ctrl.value. 内容为增益。

6. 利用VIDIOC_QUERYCTRL 得到设置具体信息:

在很多情况下,我们并不知道如何设置一些信息,例如,曝光应该设置为多少?Driver能够接受的范围是多少?最大,最小值是多少?步长是多少?缺省值为多少?

可以通过VIDIOC_QUERYCTRL得到。

咱们还是以增益为例:

struct v4l2_queryctrl  Setting;

Setting.id = V4L2_CID_GAIN;

ret = ioctl(Handle, VIDIOC_QUERYCTRL, &Setting);

Driver就会填写结构体中所有信息。

struct v4l2_queryctrl

{

__u32 id;  //用户设置。指定查找的是哪个ID。

enum v4l2_ctrl_type type;

__u8 name[32];  //ID对应的名字。

__s32 minimum;

__s32 maximum;

__s32 step;   //步长

__s32 default_value;

__u32 flags;

__u32 reserved[2];

};

这样,就知道设置什么值是合法的了。那么,下一步就是设置了。

7. 利用VIDIOC_S_CTRL来设置:

很简单,设置id和value.调用ioctl就好。

还是以增益为例:

struct v4l2_control ctrl;

ctrl.id = V4L2_CID_GAIN;

ctrl.value = Gain;

ret = ioctl(Handle, VIDIOC_S_CTRL, &ctrl);

有时候,硬件设置很奇怪,可以设置某个信息,却无法得到如何设置的信息。例如:HD-500可以设置增益。却无法得到该如何设置。

8. 利用扩展Ctrl设置:

焦距(FOUCE);

注1:enum v4l2_field field; 详解:

9.设定分辨率:

struct v4l2_control control;

memset(&control, 0, sizeof(control));

control.id = V4L2_CID_AUTO_WHITE_BALANCE;

control.value = 1;

if (ioctl(fd, VIDIOC_S_CTRL, &control) < 0)

{

printf("Couldn‘t set auto white balance!\n");

//return -1;

}

memset(&control, 0, sizeof(control));

control.id = V4L2_CID_EXPOSURE_AUTO;

control.value = 1;

if (ioctl(fd, VIDIOC_S_CTRL, &control) < 0)

{

printf("Couldn‘t set auto exposure!\n");

//return -1;

}

memset(&control, 0, sizeof(control));

control.id = V4L2_CID_HFLIP;

control.value = 1;

if (ioctl(fd, VIDIOC_S_CTRL, &control) < 0)

{

printf("Couldn‘t set h flip!\n");

//return -1;

}

memset(&control, 0, sizeof(control));

control.id = V4L2_CID_VFLIP;

control.value = 1;

if (ioctl(fd, VIDIOC_S_CTRL, &control) < 0)

{

printf("Couldn‘t set v flip!\n");

//return -1;

}

时间: 2024-10-11 08:45:04

Linux下实现视频读取(二)---camera参数设定的相关文章

Linux下实现视频读取

V4L(video4linux是一些视频系统,视频软件.音频软件的基础,经常时候在需要采集图像的场合,如视频监控,webcam,可视电话,经常使用在embedded linux中是linux嵌入式开发中经常使用的系统接口.它是linux内核提供给用户空间的编程接口,各种的视频和音频设备开发相应的驱动程序后,就可以通过v4l提供的系统API来控制视频和音频设备,也就是说v4l分为两层,底层为音视频设备在内核中的驱动,上层为系统提供的API,而对于我们来说需要的就是使用这些系统API. V4L2是V

Linux下实现视频读取(三)---Buffer的准备和数据读取

前面主要介绍的是:V4L2 的一些设置接口,如亮度,饱和度,曝光时间,帧数,增益,白平衡等.今天看看V4L2 得到数据的几个关键ioctl,Buffer的申请和数据的抓取. 1. 初始化 Memory Mapping 或 User Pointer I/O. int ioctl(int fd, int requestbuf, struct v4l2_requestbuffers * argp); 参数一:open()所产生的句柄. 参数二:VIDIOC_REQBUFS 参数三:in/out结构体.

Linux下的视频字幕编辑

一.Linux下的字幕编辑软件 常用的有subtitleeditor, gnome-subtitles, gaupol 1.gnome-subtitles:不支持多字幕文件批量处理2.gaupol:全英文界面3.subtitleeditor:功能和gnome-subtitles.gaupol差不多,但支持批量处理,界面中文 二.常见视频和字幕不同步原因 网上下载的字幕和视频由于有时来源不一样,造成字幕和音频不同步.常见不同步的原因一般有两个:1.视频桢率(FPS)和字幕桢率(FPS)不一致:例如

嵌入式Linux下MP4视频录制库MP4V2移植和简介

*************************************************************************************************************************** 作者:EasyWave                                                                             时间:2014.10.31 类别:Linux应用-MP4视频录制库MP4V2

嵌入式Linux下MP4视频录制库MP4V2移植和简单介绍

*************************************************************************************************************************** 作者:EasyWave                                                                             时间:2014.10.31 类别:Linux应用-MP4视频录制库MP4V2

一个关于编码的实验(C#写的记事本文档,在Linux下用C++读取)

第一步:用C#用各种类型的编码生成txt文档 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.IO; namespace WordTest {     class Program     {         static void Main(string[] args)         {

Linux下NDK编译FFMPEG包含neon参数

FFMPEG编译成Android库已经有很多案例了,编译优化neon的也很多,以下是我通过实践成功的案例,这里主要讲编译的配置文件,其他设置可结合Linux下使用NDK编译FFMPEG(libstagefright)进行配置. config_android.sh NDK=/opt/android/android-ndk-r9 PLATFORM=$NDK/platforms/android-14/arch-arm/ PREBUILT=$NDK/toolchains/arm-linux-androi

Linux下安装 Posgresql 并设置基本参数

在Linux下安装Postgresql有二进制格式安装和源码安装两种安装方式,这里用的是二进制格式安装.各个版本的Linux都内置了Postgresql,所以可直接通过命令行安装便可.本文用的是Centos6.5. 安装Postgresql # 安装postgresql服务器 yum install postgresql-server #依赖包是否安装 Y/N Y #第三方贡献包 yum install postgresql-contrib #依赖包是否安装 Y/N Y 安装成功后,数据库状态

【归纳总结】Unix/linux下的进程管理(二):创建进程的函数及其应用、对比

创建进程的函数fork().vfork()和execl() 本次内容主要介绍Unix/linux下2个创建进程的函数fork和vfork以及它们的差别. 1.fork函数 (1)函数的格式 #include <unistd.h> pid_t fork(void); 函数功能: 主要用于以复制正在运行进程的方式来创建新的进程,其中新进程叫做子进程,正在运行的进程叫做父进程. 返回值: 函数调用成功时,父进程返回子进程的PID,子进程返回0,函数调用出错时,父进程返回-1,子进程没有被创建. 注意