mirror of
https://e.coding.net/weidongshan/linux/doc_and_source_for_drivers.git
synced 2025-12-04 05:41:13 +08:00
发布:04_V4L2应用程序开发_获取数据,05_V4L2应用程序开发_调试,06_V4L2应用程序开发_控制亮度
This commit is contained in:
@@ -441,11 +441,31 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
### 3.2 获取数据
|
### 3.2 获取数据
|
||||||
|
|
||||||
|
根据《1.2 完整的使用流程》来编写程序,步骤如下:
|
||||||
|
|
||||||
|
* 打开设备
|
||||||
|
* ioctl VIDIOC_QUERYCAP:Query Capbility,查询能力
|
||||||
|
* 枚举格式、设置格式
|
||||||
|
* ioctl VIDIOC_REQBUFS:申请buffer
|
||||||
|
* ioctl VIDIOC_QUERYBUF和mmap:查询buffer信息、映射
|
||||||
|
* ioctl VIDIOC_QBUF:把buffer放入"空闲链表"
|
||||||
|
* ioctl VIDIOC_STREAMON:启动摄像头
|
||||||
|
* 这里是一个循环:使用poll/select监测buffer,然后从"完成链表"中取出buffer,处理后再放入"空闲链表"
|
||||||
|
* poll/select
|
||||||
|
* ioctl VIDIOC_DQBUF:从"完成链表"中取出buffer
|
||||||
|
* 处理:前面使用mmap映射了每个buffer的地址,把这个buffer的数据存为文件
|
||||||
|
* ioclt VIDIOC_QBUF:把buffer放入"空闲链表"
|
||||||
|
* ioctl VIDIOC_STREAMOFF:停止摄像头
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 3.3 控制亮度
|
### 3.3 控制亮度
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
BIN
IMX6ULL/doc_pic/13_V4L2/pic/19_get_data.png
Normal file
BIN
IMX6ULL/doc_pic/13_V4L2/pic/19_get_data.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.5 KiB |
BIN
IMX6ULL/doc_pic/13_V4L2/pic/20_brightness.png
Normal file
BIN
IMX6ULL/doc_pic/13_V4L2/pic/20_brightness.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.5 KiB |
@@ -46,7 +46,7 @@ sensor---串行器---GSML---->解串器---->soc(mipi接口)这一条路也
|
|||||||
|
|
||||||
## 3. 学习笔记
|
## 3. 学习笔记
|
||||||
|
|
||||||
|
好文:https://zhuanlan.zhihu.com/p/613018868
|
||||||
|
|
||||||
Linux V4L2子系统分析(一): https://blog.csdn.net/u011037593/article/details/115415136
|
Linux V4L2子系统分析(一): https://blog.csdn.net/u011037593/article/details/115415136
|
||||||
|
|
||||||
|
|||||||
237
IMX6ULL/source/13_V4L2/04_video_get_data/video_test.c
Normal file
237
IMX6ULL/source/13_V4L2/04_video_get_data/video_test.c
Normal file
@@ -0,0 +1,237 @@
|
|||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <linux/types.h> /* for videodev2.h */
|
||||||
|
#include <linux/videodev2.h>
|
||||||
|
#include <poll.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
|
||||||
|
/* ./video_test </dev/video0> */
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
struct v4l2_fmtdesc fmtdesc;
|
||||||
|
struct v4l2_frmsizeenum fsenum;
|
||||||
|
int fmt_index = 0;
|
||||||
|
int frame_index = 0;
|
||||||
|
int i;
|
||||||
|
void *bufs[32];
|
||||||
|
int buf_cnt;
|
||||||
|
int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
|
struct pollfd fds[1];
|
||||||
|
char filename[32];
|
||||||
|
int file_cnt = 0;
|
||||||
|
|
||||||
|
if (argc != 2)
|
||||||
|
{
|
||||||
|
printf("Usage: %s </dev/videoX>, print format detail for video device\n", argv[0]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* open */
|
||||||
|
fd = open(argv[1], O_RDWR);
|
||||||
|
if (fd < 0)
|
||||||
|
{
|
||||||
|
printf("can not open %s\n", argv[1]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 查询能力 */
|
||||||
|
struct v4l2_capability cap;
|
||||||
|
memset(&cap, 0, sizeof(struct v4l2_capability));
|
||||||
|
|
||||||
|
if (0 == ioctl(fd, VIDIOC_QUERYCAP, &cap))
|
||||||
|
{
|
||||||
|
if((cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0) {
|
||||||
|
fprintf(stderr, "Error opening device %s: video capture not supported.\n",
|
||||||
|
argv[1]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!(cap.capabilities & V4L2_CAP_STREAMING)) {
|
||||||
|
fprintf(stderr, "%s does not support streaming i/o\n", argv[1]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("can not get capability\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
/* 枚举格式 */
|
||||||
|
fmtdesc.index = fmt_index; // 比如从0开始
|
||||||
|
fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; // 指定type为"捕获"
|
||||||
|
if (0 != ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc))
|
||||||
|
break;
|
||||||
|
|
||||||
|
frame_index = 0;
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
/* 枚举这种格式所支持的帧大小 */
|
||||||
|
memset(&fsenum, 0, sizeof(struct v4l2_frmsizeenum));
|
||||||
|
fsenum.pixel_format = fmtdesc.pixelformat;
|
||||||
|
fsenum.index = frame_index;
|
||||||
|
|
||||||
|
if (ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &fsenum) == 0)
|
||||||
|
{
|
||||||
|
printf("format %s,%d, framesize %d: %d x %d\n", fmtdesc.description, fmtdesc.pixelformat, frame_index, fsenum.discrete.width, fsenum.discrete.height);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
frame_index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt_index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* 设置格式 */
|
||||||
|
struct v4l2_format fmt;
|
||||||
|
memset(&fmt, 0, sizeof(struct v4l2_format));
|
||||||
|
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
|
fmt.fmt.pix.width = 1024;
|
||||||
|
fmt.fmt.pix.height = 768;
|
||||||
|
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;
|
||||||
|
fmt.fmt.pix.field = V4L2_FIELD_ANY;
|
||||||
|
if (0 == ioctl(fd, VIDIOC_S_FMT, &fmt))
|
||||||
|
{
|
||||||
|
printf("set format ok: %d x %d\n", fmt.fmt.pix.width, fmt.fmt.pix.height);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("can not set format\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 申请buffer
|
||||||
|
*/
|
||||||
|
struct v4l2_requestbuffers rb;
|
||||||
|
memset(&rb, 0, sizeof(struct v4l2_requestbuffers));
|
||||||
|
rb.count = 32;
|
||||||
|
rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
|
rb.memory = V4L2_MEMORY_MMAP;
|
||||||
|
|
||||||
|
if (0 == ioctl(fd, VIDIOC_REQBUFS, &rb))
|
||||||
|
{
|
||||||
|
/* 申请成功后, mmap这些buffer */
|
||||||
|
buf_cnt = rb.count;
|
||||||
|
for(i = 0; i < rb.count; i++) {
|
||||||
|
struct v4l2_buffer buf;
|
||||||
|
memset(&buf, 0, sizeof(struct v4l2_buffer));
|
||||||
|
buf.index = i;
|
||||||
|
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
|
buf.memory = V4L2_MEMORY_MMAP;
|
||||||
|
if (0 == ioctl(fd, VIDIOC_QUERYBUF, &buf))
|
||||||
|
{
|
||||||
|
/* mmap */
|
||||||
|
bufs[i] = mmap(0 /* start anywhere */ ,
|
||||||
|
buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd,
|
||||||
|
buf.m.offset);
|
||||||
|
if(bufs[i] == MAP_FAILED) {
|
||||||
|
perror("Unable to map buffer");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("can not query buffer\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("map %d buffers ok\n", buf_cnt);
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("can not request buffers\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 把所有buffer放入"空闲链表" */
|
||||||
|
for(i = 0; i < buf_cnt; ++i) {
|
||||||
|
struct v4l2_buffer buf;
|
||||||
|
memset(&buf, 0, sizeof(struct v4l2_buffer));
|
||||||
|
buf.index = i;
|
||||||
|
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
|
buf.memory = V4L2_MEMORY_MMAP;
|
||||||
|
if (0 != ioctl(fd, VIDIOC_QBUF, &buf))
|
||||||
|
{
|
||||||
|
perror("Unable to queue buffer");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("queue buffers ok\n");
|
||||||
|
|
||||||
|
/* 启动摄像头 */
|
||||||
|
if (0 != ioctl(fd, VIDIOC_STREAMON, &type))
|
||||||
|
{
|
||||||
|
perror("Unable to start capture");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
printf("start capture ok\n");
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
/* poll */
|
||||||
|
memset(fds, 0, sizeof(fds));
|
||||||
|
fds[0].fd = fd;
|
||||||
|
fds[0].events = POLLIN;
|
||||||
|
if (1 == poll(fds, 1, -1))
|
||||||
|
{
|
||||||
|
/* 把buffer取出队列 */
|
||||||
|
struct v4l2_buffer buf;
|
||||||
|
memset(&buf, 0, sizeof(struct v4l2_buffer));
|
||||||
|
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
|
buf.memory = V4L2_MEMORY_MMAP;
|
||||||
|
|
||||||
|
if (0 != ioctl(fd, VIDIOC_DQBUF, &buf))
|
||||||
|
{
|
||||||
|
perror("Unable to dequeue buffer");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 把buffer的数据存为文件 */
|
||||||
|
sprintf(filename, "video_raw_data_%04d.jpg", file_cnt++);
|
||||||
|
int fd_file = open(filename, O_RDWR | O_CREAT, 0666);
|
||||||
|
if (fd_file < 0)
|
||||||
|
{
|
||||||
|
printf("can not create file : %s\n", filename);
|
||||||
|
}
|
||||||
|
printf("capture to %s\n", filename);
|
||||||
|
write(fd_file, bufs[buf.index], buf.bytesused);
|
||||||
|
close(fd_file);
|
||||||
|
|
||||||
|
/* 把buffer放入队列 */
|
||||||
|
if (0 != ioctl(fd, VIDIOC_QBUF, &buf))
|
||||||
|
{
|
||||||
|
perror("Unable to queue buffer");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 != ioctl(fd, VIDIOC_STREAMOFF, &type))
|
||||||
|
{
|
||||||
|
perror("Unable to stop capture");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
printf("stop capture ok\n");
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
289
IMX6ULL/source/13_V4L2/05_video_brightness/video_test.c
Normal file
289
IMX6ULL/source/13_V4L2/05_video_brightness/video_test.c
Normal file
@@ -0,0 +1,289 @@
|
|||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <linux/types.h> /* for videodev2.h */
|
||||||
|
#include <linux/videodev2.h>
|
||||||
|
#include <poll.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
/* ./video_test </dev/video0> */
|
||||||
|
|
||||||
|
static void *thread_brightness_control (void *args)
|
||||||
|
{
|
||||||
|
int fd = (int)args;
|
||||||
|
|
||||||
|
unsigned char c;
|
||||||
|
int brightness;
|
||||||
|
int delta;
|
||||||
|
|
||||||
|
struct v4l2_queryctrl qctrl;
|
||||||
|
memset(&qctrl, 0, sizeof(qctrl));
|
||||||
|
qctrl.id = V4L2_CID_BRIGHTNESS; // V4L2_CID_BASE+0;
|
||||||
|
if (0 != ioctl(fd, VIDIOC_QUERYCTRL, &qctrl))
|
||||||
|
{
|
||||||
|
printf("can not query brightness\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("brightness min = %d, max = %d\n", qctrl.minimum, qctrl.maximum);
|
||||||
|
delta = (qctrl.maximum - qctrl.minimum) / 10;
|
||||||
|
|
||||||
|
struct v4l2_control ctl;
|
||||||
|
ctl.id = V4L2_CID_BRIGHTNESS; // V4L2_CID_BASE+0;
|
||||||
|
ioctl(fd, VIDIOC_G_CTRL, &ctl);
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
c = getchar();
|
||||||
|
if (c == 'u' || c == 'U')
|
||||||
|
{
|
||||||
|
ctl.value += delta;
|
||||||
|
}
|
||||||
|
else if (c == 'd' || c == 'D')
|
||||||
|
{
|
||||||
|
ctl.value -= delta;
|
||||||
|
}
|
||||||
|
if (ctl.value > qctrl.maximum)
|
||||||
|
ctl.value = qctrl.maximum;
|
||||||
|
if (ctl.value < qctrl.minimum)
|
||||||
|
ctl.value = qctrl.minimum;
|
||||||
|
|
||||||
|
ioctl(fd, VIDIOC_S_CTRL, &ctl);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
struct v4l2_fmtdesc fmtdesc;
|
||||||
|
struct v4l2_frmsizeenum fsenum;
|
||||||
|
int fmt_index = 0;
|
||||||
|
int frame_index = 0;
|
||||||
|
int i;
|
||||||
|
void *bufs[32];
|
||||||
|
int buf_cnt;
|
||||||
|
int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
|
struct pollfd fds[1];
|
||||||
|
char filename[32];
|
||||||
|
int file_cnt = 0;
|
||||||
|
|
||||||
|
if (argc != 2)
|
||||||
|
{
|
||||||
|
printf("Usage: %s </dev/videoX>, print format detail for video device\n", argv[0]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* open */
|
||||||
|
fd = open(argv[1], O_RDWR);
|
||||||
|
if (fd < 0)
|
||||||
|
{
|
||||||
|
printf("can not open %s\n", argv[1]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 查询能力 */
|
||||||
|
struct v4l2_capability cap;
|
||||||
|
memset(&cap, 0, sizeof(struct v4l2_capability));
|
||||||
|
|
||||||
|
if (0 == ioctl(fd, VIDIOC_QUERYCAP, &cap))
|
||||||
|
{
|
||||||
|
if((cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0) {
|
||||||
|
fprintf(stderr, "Error opening device %s: video capture not supported.\n",
|
||||||
|
argv[1]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!(cap.capabilities & V4L2_CAP_STREAMING)) {
|
||||||
|
fprintf(stderr, "%s does not support streaming i/o\n", argv[1]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("can not get capability\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
/* 枚举格式 */
|
||||||
|
fmtdesc.index = fmt_index; // 比如从0开始
|
||||||
|
fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; // 指定type为"捕获"
|
||||||
|
if (0 != ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc))
|
||||||
|
break;
|
||||||
|
|
||||||
|
frame_index = 0;
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
/* 枚举这种格式所支持的帧大小 */
|
||||||
|
memset(&fsenum, 0, sizeof(struct v4l2_frmsizeenum));
|
||||||
|
fsenum.pixel_format = fmtdesc.pixelformat;
|
||||||
|
fsenum.index = frame_index;
|
||||||
|
|
||||||
|
if (ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &fsenum) == 0)
|
||||||
|
{
|
||||||
|
printf("format %s,%d, framesize %d: %d x %d\n", fmtdesc.description, fmtdesc.pixelformat, frame_index, fsenum.discrete.width, fsenum.discrete.height);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
frame_index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt_index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* 设置格式 */
|
||||||
|
struct v4l2_format fmt;
|
||||||
|
memset(&fmt, 0, sizeof(struct v4l2_format));
|
||||||
|
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
|
fmt.fmt.pix.width = 1024;
|
||||||
|
fmt.fmt.pix.height = 768;
|
||||||
|
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;
|
||||||
|
fmt.fmt.pix.field = V4L2_FIELD_ANY;
|
||||||
|
if (0 == ioctl(fd, VIDIOC_S_FMT, &fmt))
|
||||||
|
{
|
||||||
|
printf("set format ok: %d x %d\n", fmt.fmt.pix.width, fmt.fmt.pix.height);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("can not set format\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 申请buffer
|
||||||
|
*/
|
||||||
|
struct v4l2_requestbuffers rb;
|
||||||
|
memset(&rb, 0, sizeof(struct v4l2_requestbuffers));
|
||||||
|
rb.count = 32;
|
||||||
|
rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
|
rb.memory = V4L2_MEMORY_MMAP;
|
||||||
|
|
||||||
|
if (0 == ioctl(fd, VIDIOC_REQBUFS, &rb))
|
||||||
|
{
|
||||||
|
/* 申请成功后, mmap这些buffer */
|
||||||
|
buf_cnt = rb.count;
|
||||||
|
for(i = 0; i < rb.count; i++) {
|
||||||
|
struct v4l2_buffer buf;
|
||||||
|
memset(&buf, 0, sizeof(struct v4l2_buffer));
|
||||||
|
buf.index = i;
|
||||||
|
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
|
buf.memory = V4L2_MEMORY_MMAP;
|
||||||
|
if (0 == ioctl(fd, VIDIOC_QUERYBUF, &buf))
|
||||||
|
{
|
||||||
|
/* mmap */
|
||||||
|
bufs[i] = mmap(0 /* start anywhere */ ,
|
||||||
|
buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd,
|
||||||
|
buf.m.offset);
|
||||||
|
if(bufs[i] == MAP_FAILED) {
|
||||||
|
perror("Unable to map buffer");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("can not query buffer\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("map %d buffers ok\n", buf_cnt);
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("can not request buffers\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 把所有buffer放入"空闲链表" */
|
||||||
|
for(i = 0; i < buf_cnt; ++i) {
|
||||||
|
struct v4l2_buffer buf;
|
||||||
|
memset(&buf, 0, sizeof(struct v4l2_buffer));
|
||||||
|
buf.index = i;
|
||||||
|
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
|
buf.memory = V4L2_MEMORY_MMAP;
|
||||||
|
if (0 != ioctl(fd, VIDIOC_QBUF, &buf))
|
||||||
|
{
|
||||||
|
perror("Unable to queue buffer");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("queue buffers ok\n");
|
||||||
|
|
||||||
|
/* 启动摄像头 */
|
||||||
|
if (0 != ioctl(fd, VIDIOC_STREAMON, &type))
|
||||||
|
{
|
||||||
|
perror("Unable to start capture");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
printf("start capture ok\n");
|
||||||
|
|
||||||
|
|
||||||
|
/* 创建线程用来控制亮度 */
|
||||||
|
pthread_t thread;
|
||||||
|
pthread_create(&thread, NULL, thread_brightness_control, (void *)fd);
|
||||||
|
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
/* poll */
|
||||||
|
memset(fds, 0, sizeof(fds));
|
||||||
|
fds[0].fd = fd;
|
||||||
|
fds[0].events = POLLIN;
|
||||||
|
if (1 == poll(fds, 1, -1))
|
||||||
|
{
|
||||||
|
/* 把buffer取出队列 */
|
||||||
|
struct v4l2_buffer buf;
|
||||||
|
memset(&buf, 0, sizeof(struct v4l2_buffer));
|
||||||
|
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
|
buf.memory = V4L2_MEMORY_MMAP;
|
||||||
|
|
||||||
|
if (0 != ioctl(fd, VIDIOC_DQBUF, &buf))
|
||||||
|
{
|
||||||
|
perror("Unable to dequeue buffer");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 把buffer的数据存为文件 */
|
||||||
|
sprintf(filename, "video_raw_data_%04d.jpg", file_cnt++);
|
||||||
|
int fd_file = open(filename, O_RDWR | O_CREAT, 0666);
|
||||||
|
if (fd_file < 0)
|
||||||
|
{
|
||||||
|
printf("can not create file : %s\n", filename);
|
||||||
|
}
|
||||||
|
printf("capture to %s\n", filename);
|
||||||
|
write(fd_file, bufs[buf.index], buf.bytesused);
|
||||||
|
close(fd_file);
|
||||||
|
|
||||||
|
/* 把buffer放入队列 */
|
||||||
|
if (0 != ioctl(fd, VIDIOC_QBUF, &buf))
|
||||||
|
{
|
||||||
|
perror("Unable to queue buffer");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 != ioctl(fd, VIDIOC_STREAMOFF, &type))
|
||||||
|
{
|
||||||
|
perror("Unable to stop capture");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
printf("stop capture ok\n");
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -784,6 +784,9 @@ git clone https://e.coding.net/weidongshan/linux/doc_and_source_for_drivers.git
|
|||||||
|
|
||||||
```shell
|
```shell
|
||||||
03_V4L2应用程序开发_列出帧细节
|
03_V4L2应用程序开发_列出帧细节
|
||||||
|
04_V4L2应用程序开发_获取数据
|
||||||
|
05_V4L2应用程序开发_调试
|
||||||
|
06_V4L2应用程序开发_控制亮度
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -441,11 +441,31 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
### 3.2 获取数据
|
### 3.2 获取数据
|
||||||
|
|
||||||
|
根据《1.2 完整的使用流程》来编写程序,步骤如下:
|
||||||
|
|
||||||
|
* 打开设备
|
||||||
|
* ioctl VIDIOC_QUERYCAP:Query Capbility,查询能力
|
||||||
|
* 枚举格式、设置格式
|
||||||
|
* ioctl VIDIOC_REQBUFS:申请buffer
|
||||||
|
* ioctl VIDIOC_QUERYBUF和mmap:查询buffer信息、映射
|
||||||
|
* ioctl VIDIOC_QBUF:把buffer放入"空闲链表"
|
||||||
|
* ioctl VIDIOC_STREAMON:启动摄像头
|
||||||
|
* 这里是一个循环:使用poll/select监测buffer,然后从"完成链表"中取出buffer,处理后再放入"空闲链表"
|
||||||
|
* poll/select
|
||||||
|
* ioctl VIDIOC_DQBUF:从"完成链表"中取出buffer
|
||||||
|
* 处理:前面使用mmap映射了每个buffer的地址,把这个buffer的数据存为文件
|
||||||
|
* ioclt VIDIOC_QBUF:把buffer放入"空闲链表"
|
||||||
|
* ioctl VIDIOC_STREAMOFF:停止摄像头
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 3.3 控制亮度
|
### 3.3 控制亮度
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
BIN
STM32MP157/doc_pic/13_V4L2/pic/19_get_data.png
Normal file
BIN
STM32MP157/doc_pic/13_V4L2/pic/19_get_data.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.5 KiB |
BIN
STM32MP157/doc_pic/13_V4L2/pic/20_brightness.png
Normal file
BIN
STM32MP157/doc_pic/13_V4L2/pic/20_brightness.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.5 KiB |
@@ -46,7 +46,7 @@ sensor---串行器---GSML---->解串器---->soc(mipi接口)这一条路也
|
|||||||
|
|
||||||
## 3. 学习笔记
|
## 3. 学习笔记
|
||||||
|
|
||||||
|
好文:https://zhuanlan.zhihu.com/p/613018868
|
||||||
|
|
||||||
Linux V4L2子系统分析(一): https://blog.csdn.net/u011037593/article/details/115415136
|
Linux V4L2子系统分析(一): https://blog.csdn.net/u011037593/article/details/115415136
|
||||||
|
|
||||||
|
|||||||
237
STM32MP157/source/A7/13_V4L2/04_video_get_data/video_test.c
Normal file
237
STM32MP157/source/A7/13_V4L2/04_video_get_data/video_test.c
Normal file
@@ -0,0 +1,237 @@
|
|||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <linux/types.h> /* for videodev2.h */
|
||||||
|
#include <linux/videodev2.h>
|
||||||
|
#include <poll.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
|
||||||
|
/* ./video_test </dev/video0> */
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
struct v4l2_fmtdesc fmtdesc;
|
||||||
|
struct v4l2_frmsizeenum fsenum;
|
||||||
|
int fmt_index = 0;
|
||||||
|
int frame_index = 0;
|
||||||
|
int i;
|
||||||
|
void *bufs[32];
|
||||||
|
int buf_cnt;
|
||||||
|
int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
|
struct pollfd fds[1];
|
||||||
|
char filename[32];
|
||||||
|
int file_cnt = 0;
|
||||||
|
|
||||||
|
if (argc != 2)
|
||||||
|
{
|
||||||
|
printf("Usage: %s </dev/videoX>, print format detail for video device\n", argv[0]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* open */
|
||||||
|
fd = open(argv[1], O_RDWR);
|
||||||
|
if (fd < 0)
|
||||||
|
{
|
||||||
|
printf("can not open %s\n", argv[1]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 查询能力 */
|
||||||
|
struct v4l2_capability cap;
|
||||||
|
memset(&cap, 0, sizeof(struct v4l2_capability));
|
||||||
|
|
||||||
|
if (0 == ioctl(fd, VIDIOC_QUERYCAP, &cap))
|
||||||
|
{
|
||||||
|
if((cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0) {
|
||||||
|
fprintf(stderr, "Error opening device %s: video capture not supported.\n",
|
||||||
|
argv[1]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!(cap.capabilities & V4L2_CAP_STREAMING)) {
|
||||||
|
fprintf(stderr, "%s does not support streaming i/o\n", argv[1]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("can not get capability\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
/* 枚举格式 */
|
||||||
|
fmtdesc.index = fmt_index; // 比如从0开始
|
||||||
|
fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; // 指定type为"捕获"
|
||||||
|
if (0 != ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc))
|
||||||
|
break;
|
||||||
|
|
||||||
|
frame_index = 0;
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
/* 枚举这种格式所支持的帧大小 */
|
||||||
|
memset(&fsenum, 0, sizeof(struct v4l2_frmsizeenum));
|
||||||
|
fsenum.pixel_format = fmtdesc.pixelformat;
|
||||||
|
fsenum.index = frame_index;
|
||||||
|
|
||||||
|
if (ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &fsenum) == 0)
|
||||||
|
{
|
||||||
|
printf("format %s,%d, framesize %d: %d x %d\n", fmtdesc.description, fmtdesc.pixelformat, frame_index, fsenum.discrete.width, fsenum.discrete.height);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
frame_index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt_index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* 设置格式 */
|
||||||
|
struct v4l2_format fmt;
|
||||||
|
memset(&fmt, 0, sizeof(struct v4l2_format));
|
||||||
|
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
|
fmt.fmt.pix.width = 1024;
|
||||||
|
fmt.fmt.pix.height = 768;
|
||||||
|
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;
|
||||||
|
fmt.fmt.pix.field = V4L2_FIELD_ANY;
|
||||||
|
if (0 == ioctl(fd, VIDIOC_S_FMT, &fmt))
|
||||||
|
{
|
||||||
|
printf("set format ok: %d x %d\n", fmt.fmt.pix.width, fmt.fmt.pix.height);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("can not set format\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 申请buffer
|
||||||
|
*/
|
||||||
|
struct v4l2_requestbuffers rb;
|
||||||
|
memset(&rb, 0, sizeof(struct v4l2_requestbuffers));
|
||||||
|
rb.count = 32;
|
||||||
|
rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
|
rb.memory = V4L2_MEMORY_MMAP;
|
||||||
|
|
||||||
|
if (0 == ioctl(fd, VIDIOC_REQBUFS, &rb))
|
||||||
|
{
|
||||||
|
/* 申请成功后, mmap这些buffer */
|
||||||
|
buf_cnt = rb.count;
|
||||||
|
for(i = 0; i < rb.count; i++) {
|
||||||
|
struct v4l2_buffer buf;
|
||||||
|
memset(&buf, 0, sizeof(struct v4l2_buffer));
|
||||||
|
buf.index = i;
|
||||||
|
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
|
buf.memory = V4L2_MEMORY_MMAP;
|
||||||
|
if (0 == ioctl(fd, VIDIOC_QUERYBUF, &buf))
|
||||||
|
{
|
||||||
|
/* mmap */
|
||||||
|
bufs[i] = mmap(0 /* start anywhere */ ,
|
||||||
|
buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd,
|
||||||
|
buf.m.offset);
|
||||||
|
if(bufs[i] == MAP_FAILED) {
|
||||||
|
perror("Unable to map buffer");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("can not query buffer\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("map %d buffers ok\n", buf_cnt);
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("can not request buffers\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 把所有buffer放入"空闲链表" */
|
||||||
|
for(i = 0; i < buf_cnt; ++i) {
|
||||||
|
struct v4l2_buffer buf;
|
||||||
|
memset(&buf, 0, sizeof(struct v4l2_buffer));
|
||||||
|
buf.index = i;
|
||||||
|
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
|
buf.memory = V4L2_MEMORY_MMAP;
|
||||||
|
if (0 != ioctl(fd, VIDIOC_QBUF, &buf))
|
||||||
|
{
|
||||||
|
perror("Unable to queue buffer");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("queue buffers ok\n");
|
||||||
|
|
||||||
|
/* 启动摄像头 */
|
||||||
|
if (0 != ioctl(fd, VIDIOC_STREAMON, &type))
|
||||||
|
{
|
||||||
|
perror("Unable to start capture");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
printf("start capture ok\n");
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
/* poll */
|
||||||
|
memset(fds, 0, sizeof(fds));
|
||||||
|
fds[0].fd = fd;
|
||||||
|
fds[0].events = POLLIN;
|
||||||
|
if (1 == poll(fds, 1, -1))
|
||||||
|
{
|
||||||
|
/* 把buffer取出队列 */
|
||||||
|
struct v4l2_buffer buf;
|
||||||
|
memset(&buf, 0, sizeof(struct v4l2_buffer));
|
||||||
|
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
|
buf.memory = V4L2_MEMORY_MMAP;
|
||||||
|
|
||||||
|
if (0 != ioctl(fd, VIDIOC_DQBUF, &buf))
|
||||||
|
{
|
||||||
|
perror("Unable to dequeue buffer");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 把buffer的数据存为文件 */
|
||||||
|
sprintf(filename, "video_raw_data_%04d.jpg", file_cnt++);
|
||||||
|
int fd_file = open(filename, O_RDWR | O_CREAT, 0666);
|
||||||
|
if (fd_file < 0)
|
||||||
|
{
|
||||||
|
printf("can not create file : %s\n", filename);
|
||||||
|
}
|
||||||
|
printf("capture to %s\n", filename);
|
||||||
|
write(fd_file, bufs[buf.index], buf.bytesused);
|
||||||
|
close(fd_file);
|
||||||
|
|
||||||
|
/* 把buffer放入队列 */
|
||||||
|
if (0 != ioctl(fd, VIDIOC_QBUF, &buf))
|
||||||
|
{
|
||||||
|
perror("Unable to queue buffer");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 != ioctl(fd, VIDIOC_STREAMOFF, &type))
|
||||||
|
{
|
||||||
|
perror("Unable to stop capture");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
printf("stop capture ok\n");
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
289
STM32MP157/source/A7/13_V4L2/05_video_brightness/video_test.c
Normal file
289
STM32MP157/source/A7/13_V4L2/05_video_brightness/video_test.c
Normal file
@@ -0,0 +1,289 @@
|
|||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <linux/types.h> /* for videodev2.h */
|
||||||
|
#include <linux/videodev2.h>
|
||||||
|
#include <poll.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
/* ./video_test </dev/video0> */
|
||||||
|
|
||||||
|
static void *thread_brightness_control (void *args)
|
||||||
|
{
|
||||||
|
int fd = (int)args;
|
||||||
|
|
||||||
|
unsigned char c;
|
||||||
|
int brightness;
|
||||||
|
int delta;
|
||||||
|
|
||||||
|
struct v4l2_queryctrl qctrl;
|
||||||
|
memset(&qctrl, 0, sizeof(qctrl));
|
||||||
|
qctrl.id = V4L2_CID_BRIGHTNESS; // V4L2_CID_BASE+0;
|
||||||
|
if (0 != ioctl(fd, VIDIOC_QUERYCTRL, &qctrl))
|
||||||
|
{
|
||||||
|
printf("can not query brightness\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("brightness min = %d, max = %d\n", qctrl.minimum, qctrl.maximum);
|
||||||
|
delta = (qctrl.maximum - qctrl.minimum) / 10;
|
||||||
|
|
||||||
|
struct v4l2_control ctl;
|
||||||
|
ctl.id = V4L2_CID_BRIGHTNESS; // V4L2_CID_BASE+0;
|
||||||
|
ioctl(fd, VIDIOC_G_CTRL, &ctl);
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
c = getchar();
|
||||||
|
if (c == 'u' || c == 'U')
|
||||||
|
{
|
||||||
|
ctl.value += delta;
|
||||||
|
}
|
||||||
|
else if (c == 'd' || c == 'D')
|
||||||
|
{
|
||||||
|
ctl.value -= delta;
|
||||||
|
}
|
||||||
|
if (ctl.value > qctrl.maximum)
|
||||||
|
ctl.value = qctrl.maximum;
|
||||||
|
if (ctl.value < qctrl.minimum)
|
||||||
|
ctl.value = qctrl.minimum;
|
||||||
|
|
||||||
|
ioctl(fd, VIDIOC_S_CTRL, &ctl);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
struct v4l2_fmtdesc fmtdesc;
|
||||||
|
struct v4l2_frmsizeenum fsenum;
|
||||||
|
int fmt_index = 0;
|
||||||
|
int frame_index = 0;
|
||||||
|
int i;
|
||||||
|
void *bufs[32];
|
||||||
|
int buf_cnt;
|
||||||
|
int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
|
struct pollfd fds[1];
|
||||||
|
char filename[32];
|
||||||
|
int file_cnt = 0;
|
||||||
|
|
||||||
|
if (argc != 2)
|
||||||
|
{
|
||||||
|
printf("Usage: %s </dev/videoX>, print format detail for video device\n", argv[0]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* open */
|
||||||
|
fd = open(argv[1], O_RDWR);
|
||||||
|
if (fd < 0)
|
||||||
|
{
|
||||||
|
printf("can not open %s\n", argv[1]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 查询能力 */
|
||||||
|
struct v4l2_capability cap;
|
||||||
|
memset(&cap, 0, sizeof(struct v4l2_capability));
|
||||||
|
|
||||||
|
if (0 == ioctl(fd, VIDIOC_QUERYCAP, &cap))
|
||||||
|
{
|
||||||
|
if((cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0) {
|
||||||
|
fprintf(stderr, "Error opening device %s: video capture not supported.\n",
|
||||||
|
argv[1]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!(cap.capabilities & V4L2_CAP_STREAMING)) {
|
||||||
|
fprintf(stderr, "%s does not support streaming i/o\n", argv[1]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("can not get capability\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
/* 枚举格式 */
|
||||||
|
fmtdesc.index = fmt_index; // 比如从0开始
|
||||||
|
fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; // 指定type为"捕获"
|
||||||
|
if (0 != ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc))
|
||||||
|
break;
|
||||||
|
|
||||||
|
frame_index = 0;
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
/* 枚举这种格式所支持的帧大小 */
|
||||||
|
memset(&fsenum, 0, sizeof(struct v4l2_frmsizeenum));
|
||||||
|
fsenum.pixel_format = fmtdesc.pixelformat;
|
||||||
|
fsenum.index = frame_index;
|
||||||
|
|
||||||
|
if (ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &fsenum) == 0)
|
||||||
|
{
|
||||||
|
printf("format %s,%d, framesize %d: %d x %d\n", fmtdesc.description, fmtdesc.pixelformat, frame_index, fsenum.discrete.width, fsenum.discrete.height);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
frame_index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt_index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* 设置格式 */
|
||||||
|
struct v4l2_format fmt;
|
||||||
|
memset(&fmt, 0, sizeof(struct v4l2_format));
|
||||||
|
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
|
fmt.fmt.pix.width = 1024;
|
||||||
|
fmt.fmt.pix.height = 768;
|
||||||
|
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;
|
||||||
|
fmt.fmt.pix.field = V4L2_FIELD_ANY;
|
||||||
|
if (0 == ioctl(fd, VIDIOC_S_FMT, &fmt))
|
||||||
|
{
|
||||||
|
printf("set format ok: %d x %d\n", fmt.fmt.pix.width, fmt.fmt.pix.height);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("can not set format\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 申请buffer
|
||||||
|
*/
|
||||||
|
struct v4l2_requestbuffers rb;
|
||||||
|
memset(&rb, 0, sizeof(struct v4l2_requestbuffers));
|
||||||
|
rb.count = 32;
|
||||||
|
rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
|
rb.memory = V4L2_MEMORY_MMAP;
|
||||||
|
|
||||||
|
if (0 == ioctl(fd, VIDIOC_REQBUFS, &rb))
|
||||||
|
{
|
||||||
|
/* 申请成功后, mmap这些buffer */
|
||||||
|
buf_cnt = rb.count;
|
||||||
|
for(i = 0; i < rb.count; i++) {
|
||||||
|
struct v4l2_buffer buf;
|
||||||
|
memset(&buf, 0, sizeof(struct v4l2_buffer));
|
||||||
|
buf.index = i;
|
||||||
|
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
|
buf.memory = V4L2_MEMORY_MMAP;
|
||||||
|
if (0 == ioctl(fd, VIDIOC_QUERYBUF, &buf))
|
||||||
|
{
|
||||||
|
/* mmap */
|
||||||
|
bufs[i] = mmap(0 /* start anywhere */ ,
|
||||||
|
buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd,
|
||||||
|
buf.m.offset);
|
||||||
|
if(bufs[i] == MAP_FAILED) {
|
||||||
|
perror("Unable to map buffer");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("can not query buffer\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("map %d buffers ok\n", buf_cnt);
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("can not request buffers\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 把所有buffer放入"空闲链表" */
|
||||||
|
for(i = 0; i < buf_cnt; ++i) {
|
||||||
|
struct v4l2_buffer buf;
|
||||||
|
memset(&buf, 0, sizeof(struct v4l2_buffer));
|
||||||
|
buf.index = i;
|
||||||
|
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
|
buf.memory = V4L2_MEMORY_MMAP;
|
||||||
|
if (0 != ioctl(fd, VIDIOC_QBUF, &buf))
|
||||||
|
{
|
||||||
|
perror("Unable to queue buffer");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("queue buffers ok\n");
|
||||||
|
|
||||||
|
/* 启动摄像头 */
|
||||||
|
if (0 != ioctl(fd, VIDIOC_STREAMON, &type))
|
||||||
|
{
|
||||||
|
perror("Unable to start capture");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
printf("start capture ok\n");
|
||||||
|
|
||||||
|
|
||||||
|
/* 创建线程用来控制亮度 */
|
||||||
|
pthread_t thread;
|
||||||
|
pthread_create(&thread, NULL, thread_brightness_control, (void *)fd);
|
||||||
|
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
/* poll */
|
||||||
|
memset(fds, 0, sizeof(fds));
|
||||||
|
fds[0].fd = fd;
|
||||||
|
fds[0].events = POLLIN;
|
||||||
|
if (1 == poll(fds, 1, -1))
|
||||||
|
{
|
||||||
|
/* 把buffer取出队列 */
|
||||||
|
struct v4l2_buffer buf;
|
||||||
|
memset(&buf, 0, sizeof(struct v4l2_buffer));
|
||||||
|
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
|
buf.memory = V4L2_MEMORY_MMAP;
|
||||||
|
|
||||||
|
if (0 != ioctl(fd, VIDIOC_DQBUF, &buf))
|
||||||
|
{
|
||||||
|
perror("Unable to dequeue buffer");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 把buffer的数据存为文件 */
|
||||||
|
sprintf(filename, "video_raw_data_%04d.jpg", file_cnt++);
|
||||||
|
int fd_file = open(filename, O_RDWR | O_CREAT, 0666);
|
||||||
|
if (fd_file < 0)
|
||||||
|
{
|
||||||
|
printf("can not create file : %s\n", filename);
|
||||||
|
}
|
||||||
|
printf("capture to %s\n", filename);
|
||||||
|
write(fd_file, bufs[buf.index], buf.bytesused);
|
||||||
|
close(fd_file);
|
||||||
|
|
||||||
|
/* 把buffer放入队列 */
|
||||||
|
if (0 != ioctl(fd, VIDIOC_QBUF, &buf))
|
||||||
|
{
|
||||||
|
perror("Unable to queue buffer");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 != ioctl(fd, VIDIOC_STREAMOFF, &type))
|
||||||
|
{
|
||||||
|
perror("Unable to stop capture");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
printf("stop capture ok\n");
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user