本代码主要是配合自己搭建的网络服务器,在做视频采集时通过在发送本地拍摄10张图片。并依次的轮流刷新这10张图片。已达到动态的视频效果。其这段代码的主要功能是拍摄10张图片并保存于本地。框架是基于linux下的V4L2框架的。
#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include
#include
#include
#include
#include
#define BUFFER_COUNT 4
#define CLEAR(x) memset (&(x), 0, sizeof (x))
FILE *file_fd; const char *file_name[] ={"1.jpg", "2.jpg", "3.jpg", "4.jpg",
"5.jpg","6.jpg", "7.jpg", "8.jpg", "9.jpg", "10.jpg"};
int file_index =0;
typedef struct VideoBuffer
{
void *start;
size_t length;
}VideoBuffer;
typedef __u64 v4l2_std_id;
static void errno_exit(
const char *
s)
{ fprintf(stderr, "%s error %d, %s\n" , s, errno,
strerror(errno)); exit(EXIT_FAILURE); }
int main(int argc, char* argv[])
{
int cameraFd,ret,numBufs;
cameraFd = open("/dev/video0", O_RDWR, 0);
//设备节点由具体设备改变/dev/xxxxx 非阻塞方式打开
printf("The cameraFd is %d \n",cameraFd);
struct v4l2_capability cap;
ret = ioctl(cameraFd, VIDIOC_QUERYCAP, &cap);
//VIDIOC_QUERYCAP:查询驱动功能
if (ret < 0)
{
printf("VIDIOC_QUERYCAP failed
(%d)\n", ret);
return ret;
} struct v4l2_format fmt;
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.width = 320; //640
fmt.fmt.pix.height = 240; //480
fmt.fmt.pix.pixelformat =
V4L2_PIX_FMT_MJPEG;
fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
ret = ioctl(cameraFd, VIDIOC_S_FMT,
&fmt);
if (ret < 0) //VIDIOC_S_FMT:设置当前驱动的频捕获格式
{
printf("VIDIOC_S_FMT failed
(%d)\n", ret);
return ret;
}
struct v4l2_requestbuffers reqbuf; reqbuf.count =
BUFFER_COUNT;
reqbuf.type =
V4L2_BUF_TYPE_VIDEO_CAPTURE;
reqbuf.memory =
V4L2_MEMORY_MMAP;
printf("The requestbuffers size is %d
\n",sizeof(reqbuf));
if (ioctl(cameraFd, VIDIOC_REQBUFS, &reqbuf) == -1)
{
printf("Rquestbuffers
fail..\n");
return ret;
}
VideoBuffer* buffers = calloc(
reqbuf.count, sizeof(*buffers) );//在内存中分配4个Buffer
struct
v4l2_buffer buf;
printf("\n");
printf("The buffers addres = 0x%x\n", (unsigned
int )&buf);
printf("The
buf.length = %d \n", buf.length);
printf("\n");
for (numBufs = 0; numBufs < reqbuf.count;
numBufs++)
{
buf.type =
V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory =
V4L2_MEMORY_MMAP;
buf.index =
numBufs; //索引分配的buffers个数在以后的运算中有用
// 读取缓存
ret = ioctl(cameraFd,
VIDIOC_QUERYBUF, &buf);
if (ret < 0)
{
printf("VIDIOC_REQBUFS
fail ..\n");
return
ret;
}
buffers[numBufs].start = (char
*)mmap(0, buf.length, PROT_READ | PROT_WRITE,
MAP_SHARED,cameraFd,
buf.m.offset);
printf("The buf.length = %d \n", buf.length);
if (buffers[numBufs].start == MAP_FAILED)
{
return
-1;
}
// 放入缓存队列
ret = ioctl(cameraFd,
VIDIOC_QBUF, &buf);
if(ret < 0)
{
printf("VIDIOC_QBUF failed (%d)\n",ret);
return
ret;
}
printf("buffers[%d].start =
0x%x, length=%d\n", numBufs, (unsigned int)buffers[numBufs].start,
sizeof(buffers[numBufs]));
printf("The buf.index = %d
\n",buf.index);
}
//获取数据到文件
enum v4l2_buf_type type =
V4L2_BUF_TYPE_VIDEO_CAPTURE;
ret = ioctl(cameraFd, VIDIOC_STREAMON,
&type);
if(ret < 0)
{
printf("VIDIOC_STREAMON failed
(%d)\n", ret);
return 0;
}
int num = 0;
char pic_buf[100*1024] ={'0'};
while(1)
{
int r,read_ret;;
// CLEAR (buf);
buf.type =
V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory =
V4L2_MEMORY_MMAP; do r =
ioctl(cameraFd, VIDIOC_DQBUF, &buf); while (-1 == r
&& EINTR == errno); if ((ret ==
ioctl(cameraFd, VIDIOC_DQBUF, &buf)) < 0)
{ switch (errno)
{ case EAGAIN: return 0; case EIO: default
: printf("VIDIOC_DQBUF
failed (%d)\n", ret); } } assert(buf.index <
numBufs); if(file_index == 10)
{
file_index
= 0;
printf("you
got 10 pic file_index = %d \n", file_index);
}
FILE *fp = fopen(file_name[file_index++], "wb");
fputc('#' , stdout);
if(buf.length > 0)
{
fputc('#' ,
stdout);
fwrite(buffers[buf.index].start,
1, buf.length/6, fp);
}
fflush(stdout);
fclose(fp);
ret = ioctl(cameraFd, VIDIOC_QBUF, &buf);
if (ret < 0)
{
printf("VIDIOC_QBUF
failed (%d)\n", ret);
return
ret;
}
} // 释放内存 清空buffer区
for (numBufs=0; numBufs< reqbuf.count;
numBufs++)
{
munmap(buffers[numBufs].start,
buffers[numBufs].length);
}
close(cameraFd);
printf("The camera is close \n");
return 0;
}