V4L2驱动的移植与应用(三)

摘要:
capture.c程序中的process_image函数:capture.c程序主要是用来演示怎样使用v4l2接口,并没有对采集到的视频帧数据做任何实际的处理,仅仅用process_image函数表示了处理图像的代码位置。考虑到程序中对buffer的定义structbuffer{void*start;size_tlength};如果将buffer.length作为第2个参数传递到修改后的process_image函数中,这样做是不正确的。process_image需要的第二个参数应该是每帧图像的大小,仔细阅读代码后会发现,buffer.length并不一定就等于图像帧的大小。

三、V4L2的demo

capture.c是官方示例程序。

capture.c 程序中的 process_image 函数:

capture.c 程序主要是用来演示怎样使用 v4l2 接口,并没有对采集到的视频帧数据做任何实际的处理,仅仅用 process_image 函数表示了处理图像的代码位置。

process_image 函数只有一个参数,就是存储视频帧的内存的地址指针,但是在真正的应用中,通常还需要知道该指针指向的数据的大小。

因此可以修改函数,改成 void process_image ( const void * p, int len ) ,但是每次调用 process_image 的时候,第 2 个参数该传递什么值?

考虑到程序中对 buffer 的定义

struct buffer {

void * start;

size_t length};

如果将 buffer.length 作为第 2 个参数传递到修改后的 process_image 函数中,这样做是不正确的。 process_image 需要的第二个参数应该是每帧图像的大小,仔细阅读代码后会发现, buffer.length 并不一定就等于图像帧的大小。 (buffer 的大小,还需要考虑其他的一些因素,比如内存对齐等 )。

capture.c只是一个示例程序,仅仅是演示怎样使用v4l2中最基本的接口。尤其是在main函数中的那几个函数调用,表明了在使用v4l2时的最基本的一个流程,包括 open_device,init_device,start_capturing,mainloop,stop_capturing,uninit_device,close_device。在写程序的时候,可以充分的利用这几个基本模块,把他们分散在不同的代码位置上,灵活的调用,有兴趣的可以看一下gstreamer中v4l2src的源代码或者其他的大型程序的相关部分。

总之一句话,capture.c仅仅是一个演示程序,不要局限于它的代码结构,要灵活的使用。

下面是capture.c的源代码:

#include<stdio.h>

#include<stdlib.h>

#include<string.h>

#include<assert.h>

#include<getopt.h>/*getopt_long()*/

#include<fcntl.h>/*low-leveli/o*/

#include<unistd.h>

#include<errno.h>

#include<malloc.h>

#include<sys/stat.h>

#include<sys/types.h>

#include<sys/time.h>

#include<sys/mman.h>

#include<sys/ioctl.h>

#include<asm/types.h>/*forvideodev2.h*/

#include<linux/videodev2.h>

#defineCLEAR(x)memset(&(x),0,sizeof(x))

typedefenum{

IO_METHOD_READ,IO_METHOD_MMAP,IO_METHOD_USERPTR,

}io_method;

structbuffer{

void*start;

size_tlength;//buffer'slengthisdifferentfromcap_image_size

};

staticchar*dev_name=NULL;

staticio_methodio=IO_METHOD_MMAP;//IO_METHOD_READ;//IO_METHOD_MMAP;

staticintfd=-1;

structbuffer*buffers=NULL;

staticunsignedintn_buffers=0;

staticFILE*outf=0;

staticunsignedintcap_image_size=0;//tokeeptherealimagesize!!

//////////////////////////////////////////

staticvoiderrno_exit(constchar*s){

fprintf(stderr,"%serror%d,%s/n",s,errno,strerror(errno));

exit(EXIT_FAILURE);

}

staticintxioctl(intfd,intrequest,void*arg){

intr;

do

r=ioctl(fd,request,arg);

while(-1==r&&EINTR==errno);

returnr;

}

staticvoidprocess_image(constvoid*p,intlen){

//staticchar[115200]Outbuff;

fputc('.',stdout);

if(len>0){

fputc('.',stdout);

fwrite(p,1,len,outf);

}

fflush(stdout);

}

staticintread_frame(void){

structv4l2_bufferbuf;

unsignedinti;

switch(io){

caseIO_METHOD_READ:

if(-1==read(fd,buffers[0].start,buffers[0].length)){

switch(errno){

caseEAGAIN:

return0;

caseEIO:

/*CouldignoreEIO,seespec.*/

/*fallthrough*/

default:

errno_exit("read");

}

}

//printf("length=%d/r",buffers[0].length);

//process_image(buffers[0].start,buffers[0].length);

printf("image_size=%d,/tIO_METHOD_READbuffer.length=%d/r",

cap_image_size,buffers[0].length);

process_image(buffers[0].start,cap_image_size);

break;

caseIO_METHOD_MMAP:

CLEAR(buf);

buf.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;

buf.memory=V4L2_MEMORY_MMAP;

if(-1==xioctl(fd,VIDIOC_DQBUF,&buf)){

switch(errno){

caseEAGAIN:

return0;

caseEIO:

/*CouldignoreEIO,seespec.*/

/*fallthrough*/

default:

errno_exit("VIDIOC_DQBUF");

}

}

assert(buf.index<n_buffers);

//printf("length=%d/r",buffers[buf.index].length);

//process_image(buffers[buf.index].start,buffers[buf.index].length);

printf("image_size=%d,/tIO_METHOD_MMAPbuffer.length=%d/r",

cap_image_size,buffers[0].length);

process_image(buffers[0].start,cap_image_size);

if(-1==xioctl(fd,VIDIOC_QBUF,&buf))

errno_exit("VIDIOC_QBUF");

break;

caseIO_METHOD_USERPTR:

CLEAR(buf);

buf.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;

buf.memory=V4L2_MEMORY_USERPTR;

if(-1==xioctl(fd,VIDIOC_DQBUF,&buf)){

switch(errno){

caseEAGAIN:

return0;

caseEIO:

/*CouldignoreEIO,seespec.*/

/*fallthrough*/

default:

errno_exit("VIDIOC_DQBUF");

}

}

for(i=0;i<n_buffers;++i)

if(buf.m.userptr==(unsignedlong)buffers[i].start&&buf.length

==buffers[i].length)

break;

assert(i<n_buffers);

//printf("length=%d/r",buffers[i].length);

//process_image((void*)buf.m.userptr,buffers[i].length);

printf("image_size=%d,/tIO_METHOD_USERPTRbuffer.length=%d/r",

cap_image_size,buffers[0].length);

process_image(buffers[0].start,cap_image_size);

if(-1==xioctl(fd,VIDIOC_QBUF,&buf))

errno_exit("VIDIOC_QBUF");

break;

}

return1;

}

staticvoidmainloop(void){

unsignedintcount;

count=100;

while(count-->0){

for(;;){

fd_setfds;

structtimevaltv;

intr;

FD_ZERO(&fds);

FD_SET(fd,&fds);

/*Timeout.*/

tv.tv_sec=2;

tv.tv_usec=0;

r=select(fd+1,&fds,NULL,NULL,&tv);

if(-1==r){

if(EINTR==errno)

continue;

errno_exit("select");

}

if(0==r){

fprintf(stderr,"selecttimeout/n");

exit(EXIT_FAILURE);

}

if(read_frame())

break;

/*EAGAIN-continueselectloop.*/

}

}

}

staticvoidstop_capturing(void){

enumv4l2_buf_typetype;

switch(io){

caseIO_METHOD_READ:

/*Nothingtodo.*/

break;

caseIO_METHOD_MMAP:

caseIO_METHOD_USERPTR:

type=V4L2_BUF_TYPE_VIDEO_CAPTURE;

if(-1==xioctl(fd,VIDIOC_STREAMOFF,&type))

errno_exit("VIDIOC_STREAMOFF");

break;

}

}

staticvoidstart_capturing(void){

unsignedinti;

enumv4l2_buf_typetype;

switch(io){

caseIO_METHOD_READ:

/*Nothingtodo.*/

break;

caseIO_METHOD_MMAP:

for(i=0;i<n_buffers;++i){

structv4l2_bufferbuf;

CLEAR(buf);

buf.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;

buf.memory=V4L2_MEMORY_MMAP;

buf.index=i;

if(-1==xioctl(fd,VIDIOC_QBUF,&buf))

errno_exit("VIDIOC_QBUF");

}

type=V4L2_BUF_TYPE_VIDEO_CAPTURE;

if(-1==xioctl(fd,VIDIOC_STREAMON,&type))

errno_exit("VIDIOC_STREAMON");

break;

caseIO_METHOD_USERPTR:

for(i=0;i<n_buffers;++i){

structv4l2_bufferbuf;

CLEAR(buf);

buf.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;

buf.memory=V4L2_MEMORY_USERPTR;

buf.index=i;

buf.m.userptr=(unsignedlong)buffers[i].start;

buf.length=buffers[i].length;

if(-1==xioctl(fd,VIDIOC_QBUF,&buf))

errno_exit("VIDIOC_QBUF");

}

type=V4L2_BUF_TYPE_VIDEO_CAPTURE;

if(-1==xioctl(fd,VIDIOC_STREAMON,&type))

errno_exit("VIDIOC_STREAMON");

break;

}

}

staticvoiduninit_device(void){

unsignedinti;

switch(io){

caseIO_METHOD_READ:

free(buffers[0].start);

break;

caseIO_METHOD_MMAP:

for(i=0;i<n_buffers;++i)

if(-1==munmap(buffers[i].start,buffers[i].length))

errno_exit("munmap");

break;

caseIO_METHOD_USERPTR:

for(i=0;i<n_buffers;++i)

free(buffers[i].start);

break;

}

free(buffers);

}

staticvoidinit_read(unsignedintbuffer_size){

buffers=calloc(1,sizeof(*buffers));

if(!buffers){

fprintf(stderr,"Outofmemory/n");

exit(EXIT_FAILURE);

}

buffers[0].length=buffer_size;

buffers[0].start=malloc(buffer_size);

if(!buffers[0].start){

fprintf(stderr,"Outofmemory/n");

exit(EXIT_FAILURE);

}

}

staticvoidinit_mmap(void){

structv4l2_requestbuffersreq;

CLEAR(req);

req.count=4;

req.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;

req.memory=V4L2_MEMORY_MMAP;

if(-1==xioctl(fd,VIDIOC_REQBUFS,&req)){

if(EINVAL==errno){

fprintf(stderr,"%sdoesnotsupport"

"memorymapping/n",dev_name);

exit(EXIT_FAILURE);

}else{

errno_exit("VIDIOC_REQBUFS");

}

}

if(req.count<2){

fprintf(stderr,"Insufficientbuffermemoryon%s/n",dev_name);

exit(EXIT_FAILURE);

}

buffers=calloc(req.count,sizeof(*buffers));

if(!buffers){

fprintf(stderr,"Outofmemory/n");

exit(EXIT_FAILURE);

}

for(n_buffers=0;n_buffers<req.count;++n_buffers){

structv4l2_bufferbuf;

CLEAR(buf);

buf.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;

buf.memory=V4L2_MEMORY_MMAP;

buf.index=n_buffers;

if(-1==xioctl(fd,VIDIOC_QUERYBUF,&buf))

errno_exit("VIDIOC_QUERYBUF");

buffers[n_buffers].length=buf.length;

buffers[n_buffers].start=mmap(NULL/*startanywhere*/,buf.length,

PROT_READ|PROT_WRITE/*required*/,

MAP_SHARED/*recommended*/,fd,buf.m.offset);

if(MAP_FAILED==buffers[n_buffers].start)

errno_exit("mmap");

}

}

staticvoidinit_userp(unsignedintbuffer_size){

structv4l2_requestbuffersreq;

unsignedintpage_size;

page_size=getpagesize();

buffer_size=(buffer_size+page_size-1)&~(page_size-1);

CLEAR(req);

req.count=4;

req.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;

req.memory=V4L2_MEMORY_USERPTR;

if(-1==xioctl(fd,VIDIOC_REQBUFS,&req)){

if(EINVAL==errno){

fprintf(stderr,"%sdoesnotsupport"

"userpointeri/o/n",dev_name);

exit(EXIT_FAILURE);

}else{

errno_exit("VIDIOC_REQBUFS");

}

}

buffers=calloc(4,sizeof(*buffers));

if(!buffers){

fprintf(stderr,"Outofmemory/n");

exit(EXIT_FAILURE);

}

for(n_buffers=0;n_buffers<4;++n_buffers){

buffers[n_buffers].length=buffer_size;

buffers[n_buffers].start=memalign(/*boundary*/page_size,

buffer_size);

if(!buffers[n_buffers].start){

fprintf(stderr,"Outofmemory/n");

exit(EXIT_FAILURE);

}

}

}

staticvoidinit_device(void){

structv4l2_capabilitycap;

structv4l2_cropcapcropcap;

structv4l2_cropcrop;

structv4l2_formatfmt;

unsignedintmin;

if(-1==xioctl(fd,VIDIOC_QUERYCAP,&cap)){

if(EINVAL==errno){

fprintf(stderr,"%sisnoV4L2device/n",dev_name);

exit(EXIT_FAILURE);

}else{

errno_exit("VIDIOC_QUERYCAP");

}

}

if(!(cap.capabilities&V4L2_CAP_VIDEO_CAPTURE)){

fprintf(stderr,"%sisnovideocapturedevice/n",dev_name);

exit(EXIT_FAILURE);

}

switch(io){

caseIO_METHOD_READ:

if(!(cap.capabilities&V4L2_CAP_READWRITE)){

fprintf(stderr,"%sdoesnotsupportreadi/o/n",dev_name);

exit(EXIT_FAILURE);

}

break;

caseIO_METHOD_MMAP:

caseIO_METHOD_USERPTR:

if(!(cap.capabilities&V4L2_CAP_STREAMING)){

fprintf(stderr,"%sdoesnotsupportstreamingi/o/n",dev_name);

exit(EXIT_FAILURE);

}

break;

}

//////notallcapturesupportcrop!!!!!!!

/*Selectvideoinput,videostandardandtunehere.*/

printf("-#-#-#-#-#-#-#-#-#-#-#-#-#-/n");

CLEAR(cropcap);

cropcap.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;

if(0==xioctl(fd,VIDIOC_CROPCAP,&cropcap)){

crop.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;

#ifndefCROP_BY_JACK

crop.c=cropcap.defrect;/*resettodefault*/

#else

crop.c.left=cropcap.defrect.left;

crop.c.top=cropcap.defrect.top;

crop.c.width=352;

crop.c.height=288;

#endif

printf("----->hasabilitytocrop!!/n");

printf("cropcap.defrect=(%d,%d,%d,%d)/n",cropcap.defrect.left,

cropcap.defrect.top,cropcap.defrect.width,

cropcap.defrect.height);

if(-1==xioctl(fd,VIDIOC_S_CROP,&crop)){

switch(errno){

caseEINVAL:

/*Croppingnotsupported.*/

break;

default:

/*Errorsignored.*/

break;

}

printf("-----!!butcropto(%d,%d,%d,%d)Failed!!/n",

crop.c.left,crop.c.top,crop.c.width,crop.c.height);

}else{

printf("----->sussesscropto(%d,%d,%d,%d)/n",crop.c.left,

crop.c.top,crop.c.width,crop.c.height);

}

}else{

/*Errorsignored.*/

printf("!!hasnoabilitytocrop!!/n");

}

printf("-#-#-#-#-#-#-#-#-#-#-#-#-#-/n");

printf("/n");

////////////cropfinished!

//////////settheformat

CLEAR(fmt);

fmt.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;

fmt.fmt.pix.width=640;

fmt.fmt.pix.height=480;

//V4L2_PIX_FMT_YVU420,V4L2_PIX_FMT_YUV420—Planarformatswith1/2horizontalandverticalchromaresolution,alsoknownasYUV4:2:0

//V4L2_PIX_FMT_YUYV—Packedformatwith1/2horizontalchromaresolution,alsoknownasYUV4:2:2

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

fmt.fmt.pix.field=V4L2_FIELD_INTERLACED;

{

printf("-#-#-#-#-#-#-#-#-#-#-#-#-#-/n");

printf("=====willsetfmtto(%d,%d)--",fmt.fmt.pix.width,

fmt.fmt.pix.height);

if(fmt.fmt.pix.pixelformat==V4L2_PIX_FMT_YUYV){

printf("V4L2_PIX_FMT_YUYV/n");

}elseif(fmt.fmt.pix.pixelformat==V4L2_PIX_FMT_YUV420){

printf("V4L2_PIX_FMT_YUV420/n");

}elseif(fmt.fmt.pix.pixelformat==V4L2_PIX_FMT_NV12){

printf("V4L2_PIX_FMT_NV12/n");

}

}

if(-1==xioctl(fd,VIDIOC_S_FMT,&fmt))

errno_exit("VIDIOC_S_FMT");

{

printf("=====aftersetfmt/n");

printf("fmt.fmt.pix.width=%d/n",fmt.fmt.pix.width);

printf("fmt.fmt.pix.height=%d/n",fmt.fmt.pix.height);

printf("fmt.fmt.pix.sizeimage=%d/n",fmt.fmt.pix.sizeimage);

cap_image_size=fmt.fmt.pix.sizeimage;

printf("fmt.fmt.pix.bytesperline=%d/n",fmt.fmt.pix.bytesperline);

printf("-#-#-#-#-#-#-#-#-#-#-#-#-#-/n");

printf("/n");

}

cap_image_size=fmt.fmt.pix.sizeimage;

/*NoteVIDIOC_S_FMTmaychangewidthandheight.*/

printf("-#-#-#-#-#-#-#-#-#-#-#-#-#-/n");

/*Buggydriverparanoia.*/

min=fmt.fmt.pix.width*2;

if(fmt.fmt.pix.bytesperline<min)

fmt.fmt.pix.bytesperline=min;

min=fmt.fmt.pix.bytesperline*fmt.fmt.pix.height;

if(fmt.fmt.pix.sizeimage<min)

fmt.fmt.pix.sizeimage=min;

printf("AfterBuggydriverparanoia/n");

printf(">>fmt.fmt.pix.sizeimage=%d/n",fmt.fmt.pix.sizeimage);

printf(">>fmt.fmt.pix.bytesperline=%d/n",fmt.fmt.pix.bytesperline);

printf("-#-#-#-#-#-#-#-#-#-#-#-#-#-/n");

printf("/n");

switch(io){

caseIO_METHOD_READ:

init_read(fmt.fmt.pix.sizeimage);

break;

caseIO_METHOD_MMAP:

init_mmap();

break;

caseIO_METHOD_USERPTR:

init_userp(fmt.fmt.pix.sizeimage);

break;

}

}

staticvoidclose_device(void){

if(-1==close(fd))

errno_exit("close");

fd=-1;

}

staticvoidopen_device(void){

structstatst;

if(-1==stat(dev_name,&st)){

fprintf(stderr,"Cannotidentify'%s':%d,%s/n",dev_name,errno,

strerror(errno));

exit(EXIT_FAILURE);

}

if(!S_ISCHR(st.st_mode)){

fprintf(stderr,"%sisnodevice/n",dev_name);

exit(EXIT_FAILURE);

}

fd=open(dev_name,O_RDWR/*required*/|O_NONBLOCK,0);

if(-1==fd){

fprintf(stderr,"Cannotopen'%s':%d,%s/n",dev_name,errno,

strerror(errno));

exit(EXIT_FAILURE);

}

}

staticvoidusage(FILE*fp,intargc,char**argv){

fprintf(fp,"Usage:%s[options]/n/n"

"Options:/n"

"-d|--devicenameVideodevicename[/dev/video0]/n"

"-h|--helpPrintthismessage/n"

"-m|--mmapUsememorymappedbuffers/n"

"-r|--readUseread()calls/n"

"-u|--userpUseapplicationallocatedbuffers/n"

"",argv[0]);

}

staticconstcharshort_options[]="d:hmru";

staticconststructoptionlong_options[]={{"device",required_argument,

NULL,'d'},{"help",no_argument,NULL,'h'},{"mmap",no_argument,

NULL,'m'},{"read",no_argument,NULL,'r'},{"userp",

no_argument,NULL,'u'},{0,0,0,0}};

intmain(intargc,char**argv){

dev_name="/dev/video0";

outf=fopen("out.yuv","wb");

for(;;){

intindex;

intc;

c=getopt_long(argc,argv,short_options,long_options,&index);

if(-1==c)

break;

switch(c){

case0:/*getopt_long()flag*/

break;

case'd':

dev_name=optarg;

break;

case'h':

usage(stdout,argc,argv);

exit(EXIT_SUCCESS);

case'm':

io=IO_METHOD_MMAP;

break;

case'r':

io=IO_METHOD_READ;

break;

case'u':

io=IO_METHOD_USERPTR;

break;

default:

usage(stderr,argc,argv);

exit(EXIT_FAILURE);

}

}

open_device();

init_device();

start_capturing();

mainloop();

printf("/n");

stop_capturing();

fclose(outf);

uninit_device();

close_device();

exit(EXIT_SUCCESS);

return0;

}

免责声明:文章转载自《V4L2驱动的移植与应用(三)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇SqlServer临时表iOS开发-Runloop详解(简书)下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Linux网络编程——进程池实现过程详解(2)

进程池功能升级: send_recv_syn同步机制 自定义设置函数recvCycle,确保双方收发机制正常 客户端中显示下载进度 time/slice两种方法 设置异常情况 客户端在下载中突然断开,原先的服务端会一直死循环打印 服务器突然断开,客户端全部死循环 服务器断开后,再次执行同一端口会出现异常 服务器要升级,通知客户端有序退出 如果业务...

Linux 主分区_扩展分区_逻辑分区

目录:   1、MBR分区介绍   2、创建主分区   3、创建扩展分区   4、创建逻辑分区   1、MBR分区介绍   1.1 分区规定:   每个磁盘设备最多4个主分区,或者3个主分区+1个扩展分区,是因为MBR(主引导记录)的分区表(主分区表)只能存放4个分区 (GPT分区没有这个限制)。   扩展分区只能有一个。   逻辑分区可以有多个。   可...

Android学习——移植tr069程序到Android平台

原创作品,转载请注明出处,严禁非法转载。如有错误,请留言! email:40879506@qq.com 声明:本系列涉及的开源程序代码学习和研究,严禁用于商业目的。 如有任何问题,欢迎和我交流。(企鹅号:408797506)  淘宝店:https://shop484606081.taobao.com 本篇用到的代码下载路径:http://download....

测usb读写

dd if=/dev/sda of=/dev/null bs=1M count=1000每次测完 清一下 memory cacheecho 3 > /proc/sys/vm/drop_caches不然会继续从cache 读数据 / # dd if=/dev/sda of=/dev/null bs=1M count=10001000+0 records...

在linux中使用ramdisk文件系统 天高地厚

一 什么是RamDisk Ram:内存,Disk:磁盘,在Linux中可以将一部分内存当作分区来使用,称之为RamDisk。对于一些经常被访问、并且不会被更改的文件,可以将它们通过RamDisk放在内存中,能够明显地提高系统性能。RamDisk工作于虚拟文件系统(VFS)层,不能格式化,但可以创建多个RamDisk。虽然现在硬盘价钱越来越便宜,但对于一些...

docker占满linux磁盘根目录的解决办法

一、磁盘根目录被占满 [test@localhost docker]$ df -lh Filesystem Size Used Avail Use%Mounted on /dev/mapper/centos-root 50G 50G 0G 100% / devtmpfs 7.7...