/**
* 1. 打开设备
* 2. 获取设备能力
* 3. 设置视频格式
* 4. 进行内核空间和用户空间的内存映射
* 5. 开启视频流
* 6. 获取视频流
* 7. 关闭视频流
* 8. 取消映射
* 9. 关闭设备
*
*
*
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
const int WIDTH = 480;
const int HEIGHT = 640;
const char deviceNmae[] = "/dev/video0";
typedef struct VideoBuffer
{ //定义一个结构体来映射每个缓冲帧
void *start;
size_t length;
} VideoBuffer;
int main(int argc, char const *argv[])
{
int fd = open(deviceNmae, O_RDWR);
if (fd < 0)
{
perror("open()");
return -1;
}
/*1. 查询能力 */
struct v4l2_capability stCap;
int s32Ret = ioctl(fd, VIDIOC_QUERYCAP, &stCap);
if (s32Ret < 0)
{
perror("VIDIOC_QUERYCAP()");
return -2;
}
else
{
printf("Driver Name:%s\nCard Name:%s\nBus info:%s\nDriver Version:%u.%u.%u\n",
stCap.driver, stCap.card, stCap.bus_info, (stCap.version >> 16) & 0XFF,
(stCap.version >> 8) & 0XFF, stCap.version & 0XFF);
}
//获取成功,检查是否有视频捕获功能
if(!(stCap.capabilities & V4L2_CAP_VIDEO_CAPTURE)){
fprintf(stderr, "%s is no video capture device\n",deviceNmae);
return -1;
}
/*2. 获取当前驱动支持的视频格式 */
struct v4l2_fmtdesc stFmtdesc;
stFmtdesc.index = 0;
stFmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
printf("Support format:\n");
while (ioctl(fd, VIDIOC_ENUM_FMT, &stFmtdesc) != -1)
{
printf("\t%d.%s\n", stFmtdesc.index + 1, stFmtdesc.description);
stFmtdesc.index++;
}
/* 3. 设置当前视频捕获格式 */
struct v4l2_format stFormat;
stFormat.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
stFormat.fmt.pix.width = WIDTH;
stFormat.fmt.pix.height = HEIGHT;
stFormat.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
s32Ret = ioctl(fd, VIDIOC_S_FMT, &stFormat);
if (s32Ret < 0)
{
perror("VIDIOC_S_FMT");
return -3;
}
/* 设置视频流参数 */
struct v4l2_streamparm stream_parm;
stream_parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
stream_parm.parm.capture.timeperframe.denominator = 10; //fps
stream_parm.parm.capture.timeperframe.numerator = 1;
s32Ret = ioctl(fd, VIDIOC_S_PARM, &stream_parm);
if (s32Ret < 0)
{
printf("Unable to set frame rate\n");
goto exit;
}
/* 4. 向驱动申请视频流数据的帧缓冲区,进行内核空间和用户控件的内存映射 */
struct v4l2_requestbuffers stReq;
stReq.count = 4;
stReq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
stReq.memory = V4L2_MEMORY_MMAP;
s32Ret = ioctl(fd, VIDIOC_REQBUFS, &stReq);
if (s32Ret < 0)
{
perror("VIDIOC_REQBUFS");
goto exit;
}
VideoBuffer* buffers = calloc( stReq.count, sizeof(*buffers) );
struct v4l2_buffer stBuf;
for (int i_cnt = 0; i_cnt < 4; i_cnt++)
{
stBuf.index = i_cnt;
stBuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
stBuf.memory = V4L2_MEMORY_MMAP;
s32Ret = ioctl(fd, VIDIOC_QUERYBUF, &stBuf);
if (s32Ret)
{
perror("VIDIOC_QUERYBUF");
goto exit;
}
printf("%d\n",stBuf.length);
buffers[i_cnt].length = stBuf.length;
buffers[i_cnt].start = (char *)mmap(NULL, stBuf.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); //隐射一块用户空间到内核空间 此时的 buffers[] 和已经和申请的四个v4l2_buffer,已经对应。
if (buffers[i_cnt].start == MAP_FAILED)
{
perror("mmap()");
goto exit;
}
//将刚申请好的v4l2_buffer 加入可捕获视频的队列
s32Ret = ioctl(fd, VIDIOC_QBUF, &stBuf);
if (s32Ret < 0)
{
perror("VIDIOC_QBUF");
goto exit;
}
}
enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
s32Ret = ioctl(fd, VIDIOC_STREAMON, &type);
if (s32Ret < 0)
{
perror("VIDIOC_STREAMON");
goto exit;
}
FILE *file = fopen("my.yuv", "wb");
int s32Cnt = 0;
while (s32Cnt < 500)
{
/* 6. 获取视频流 */
stBuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
s32Ret = ioctl(fd, VIDIOC_DQBUF, &stBuf);
if (s32Ret < 0)
{
perror("VIDIOC_DQBUF");
goto exit;
}
s32Ret = fwrite(buffers[stBuf.index].start, stBuf.bytesused, 1, file);
// char buff[640*480*2] = {0};
// s32Ret = fwrite(buff, 640*480*2, 1, file);
if (s32Ret < 0)
{
perror("fwrite()");
goto exit;
}
printf("[%d:%d]\n", s32Cnt,stBuf.bytesused);
s32Ret = ioctl(fd, VIDIOC_QBUF, &stBuf);
if (s32Ret < 0)
{
perror("VIDIOC_QBUF");
goto exit;
}
s32Cnt++;
}
s32Ret = ioctl(fd, VIDIOC_STREAMOFF, &type);
if (s32Ret < 0)
{
perror("VIDIOC_STREAMON");
goto exit;
}
exit:
fclose(file);
for (int i = 0; i < 4; i++)
{
munmap(buffers[i].start, buffers[i].length);
}
close(fd);
return 0;
}
为啥我采集处理的视频,那么多的彩色呢?发愁人啊。
ffmpeg -video_size 640*480 -pixel_format yuv422p -framerate 10 -i my.yuv -vcodec h264 outpu.mp4
使用ffmpeg 将分辨率为640*480的yuv422p,10帧的视频编码压缩为mp4
推荐阅读:v4l2的学习建议和流程解析