V4L2拍照程序
由于毕设中⽤到了摄像头拍照功能,然后⽹上查了⼀下,最后⾃⼰稍微修改,以当前时间保存为.jpeg格式的图⽚,最后稍微添加了⾃⼰的⼀些⼩理解,与⼤家分享⼀下。
-----------------------------------------------------------------------------------------------------------------------------------
⽤的摄像头是ZC301P,已经加载进内核,输出格式是JPEG,⼤⼩是640*480,所以后⾯的图⽚⼤⼩计算的时候是640*480*3。
cam.c:
#include <fcntl.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <linux/videodev2.h>
#include <time.h>
#include <stdio.h>
#include <string.h>
int main(){
//add by liuzj
time_t t;
struct tm *tmp;
t = time(NULL);
tmp = localtime(&t);
char buffer1[30];
char path[30];
/end
int fd = open("/dev/video0",O_RDWR);
printf("lzj------->>>fd is %d\n",fd);
//
struct v4l2_capability cap;
ioctl(fd,VIDIOC_QUERYCAP,&cap);
printf("lzj---------->>>>>Driver Name:%s\nCard Name:%s\nBus info:%s\n",cap.driver,cap.card,cap.bus_info);
//
struct v4l2_fmtdesc fmtdesc;
fmtdesc.index = 0;
while(ioctl(fd,VIDIOC_ENUM_FMT,&fmtdesc) != -1){
printf("lzj-------->>>>>fmtdesc.description is %s\n",fmtdesc.description);
fmtdesc.index ++;
}
//
struct v4l2_format fmt;
ioctl(fd,VIDIOC_G_FMT,&fmt);
printf("lzj----------->>>>>fmt.fmt.width is %d\nfmt.fmt.pix.height is %d\nfmt.lorspace is %d\n",fmt.fmt.pix.width,fmt.fmt.pix.height,fmt.lorspace);  //
struct v4l2_requestbuffers req;
< = V4L2_MEMORY_MMAP;
ioctl(fd,VIDIOC_REQBUFS,&req);
struct buffer
{
void *start;
unsigned int length;
}*buffers;
buffers = (struct buffer*)calloc (unt, sizeof(*buffers));
unsigned int n_buffers = 0;
for(n_buffers = 0; n_buffers < unt; ++n_buffers)
{
struct v4l2_buffer buf;
memset(&buf,0,sizeof(buf));
memset(&buf,0,sizeof(buf));
< = V4L2_MEMORY_MMAP;
buf.index = n_buffers;
if(ioctl(fd,VIDIOC_QUERYBUF,&buf) == -1)
{
printf("lzj---------_>>>>>>error\n");
close(fd);
exit(-1);
}
buffers[n_buffers].length = buf.length;
buffers[n_buffers].start = mmap(NULL,buf.length,PROT_READ|PROT_WRITE,MAP_SHARED,ffset);    if(MAP_FAILED == buffers[n_buffers].start)
{
printf("lzj--------__>>>>>error 2\n");
close(fd);
exit(-1);
mmap格式怎么打开
}
}
unsigned int i;
enum v4l2_buf_type type;
for(i = 0; i < 4; i++)
{
struct v4l2_buffer buf;
< = V4L2_MEMORY_MMAP;
buf.index = i;
ioctl(fd,VIDIOC_QBUF,&buf);
}
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ioctl(fd,VIDIOC_STREAMON,&type);
struct v4l2_buffer buf;
< = V4L2_MEMORY_MMAP;
ioctl(fd,VIDIOC_DQBUF,&buf);
//add by liuzj
strftime(buffer1, sizeof(buffer1), "%Y-%m-%d_%H-%M.jpeg", tmp);
snprintf(path,sizeof(path),"/data/%s",buffer1); //modify by liuzj
int fdyuyv = open(path,O_WRONLY|O_CREAT,00700);
printf("\nlzj--------->>>>fdyuyv is %d\n",fdyuyv);
int resultyuyv = write(fdyuyv,buffers[buf.index].start,640*480*3);
printf("lzj--------->>>resultyuyv is %d\n",resultyuyv);
close(fdyuyv);
close(fd);
return 0;
}
交叉编译好了之后,可以移到开发板上直接运⾏。
/apps >: pic
lzj------->>>fd is 3
lzj---------->>>>>Driver Name:zc3xx
Card Name:PC Camera
Bus info:usb-s3c24xx-1.1
lzj-------->>>>>fmtdesc.description is JPEG
lzj----------->>>>>fmt.fmt.width is 640
fmt.fmt.pix.height is 480
fmt.lorspace is 7
lzj--------->>>>fdyuyv is 4
lzj--------->>>resultyuyv is 118784
会打印出我摄像头⽀持的格式和采集的相关参数,然后进⼊我存放的⽬录下去寻我的图⽚,再利⽤tftp命令来将其传到电脑上查看。
/apps >: cd /data/
/data >: ls
2016-05-09 12-47.jpeg
/date >: tftp -pr 2016-05-09 12-47.jpeg 10.228.26.4
最后贴上我的⼀点⼩注释
1.打开摄像头
int fd = open("/dev/video0",O_RDWR);
2.捕获摄像头能⼒及属性
ioctl(fd,VIDIOC_QUERYCAP,&cap);
3.查看当前摄像头⽀持的视频格式
ioctl(fd,VIDIOC_ENUM_FMT,&fmtdesc)
4.查看视频帧格式
ioctl(fd,VIDIOC_G_FMT,&fmt);//读取当前驱动的捕捉格式
5.向驱动申请缓冲帧
ioctl(fd,VIDIOC_REQBUFS,&req);//向驱动申请缓冲帧
< = V4L2_MEMORY_MMAP;//设置使⽤mmap来访问内存
6.申请物理内存并进⾏内存映射
将申请到的帧缓冲映射到⽤户空间,这样就可以直接操作采集到的帧了,⽽不必去复制。将申请到的帧缓冲全部⼊队列,以便存放采集到的数据,利⽤mmap进⾏映射    struct buffer
{
void *start;
unsigned int length;
}*buffers;
buffers = (struct buffer*)calloc (unt, sizeof(*buffers));
for(n_buffers = 0; n_buffers < unt; ++n_buffers)
{
struct v4l2_buffer buf;
memset(&buf,0,sizeof(buf));
< = V4L2_MEMORY_MMAP;
buf.index = n_buffers;
if(ioctl(fd,VIDIOC_QUERYBUF,&buf) == -1)
{
{
printf("lzj---------_>>>>>>error\n");
close(fd);
exit(-1);
}
buffers[n_buffers].length = buf.length;
buffers[n_buffers].start = mmap(NULL,buf.length,PROT_READ|PROT_WRITE,MAP_SHARED,ffset);    if(MAP_FAILED == buffers[n_buffers].start)
{
printf("lzj--------__>>>>>error 2\n");
7.开始视频传输
for(i = 0; i < 4; i++)
{
struct v4l2_buffer buf;
< = V4L2_MEMORY_MMAP;
buf.index = i;
ioctl(fd,VIDIOC_QBUF,&buf);
}//将4个缓冲区放⼊输⼊队列中去,VIDIOC_QBUF为其控制命令。
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ioctl(fd,VIDIOC_STREAMON,&type);//开始进⾏视频采集
8.采集图像
从视频缓冲区的输出队列中取得⼀个已经保存有⼀帧视频数据的视频缓冲区。
struct v4l2_buffer buf;
< = V4L2_MEMORY_MMAP;
ioctl(fd,VIDIOC_DQBUF,&buf);
//从视频的缓冲区中取得⼀个缓冲区数据到buf中去,VIDIOC_DQBUF为其控制命令。
9.将采集到的图⽚以当前时间保存下来
strftime(buffer1, sizeof(buffer1), "%Y-%m-%d_%H-%M.jpeg", tmp);
snprintf(path,sizeof(path),"/data/%s",buffer1);
int fdyuyv = open(path,O_WRONLY|O_CREAT,00700);
int resultyuyv = write(fdyuyv,buffers[buf.index].start,640*480*3);
close(fdyuyv);
close(fd);

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。