我是靠谱客的博主 听话小虾米,最近开发中收集的这篇文章主要介绍Linux 通过摄像头获取画面 C语言,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

 

前提在已经存在 /dev/video0 设备,大概流程可以在其他博客看到,本文给出了可以直接运行的 c 语言完整代码。作者使用 Jetson nano 加 罗技 c922 摄像头测试

之后会有文章尝试控制各种曝光参数以及编码为视频流

 

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
/* low-level i/o */
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <sys/mman.h>
#include <bits/types/struct_timespec.h>
#include <bits/types/struct_timeval.h>
#include <linux/videodev2.h>
int main(int argc, char* argv[])
{
int fd = open("/dev/video0", O_RDWR);
if (0)
{
//输出所有支持的格式
struct v4l2_fmtdesc fmtdesc;
fmtdesc.index = 0;
fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
printf("Support format:n");
while (ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc) != -1)
{
printf("t%d.%sn", fmtdesc.index + 1, fmtdesc.description);
fmtdesc.index++;
}
printf("enum donen");
}
if (0)
{
//查看当前的输出格式
struct v4l2_format fmt;
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ioctl(fd, VIDIOC_G_FMT, &fmt);
printf("Current data format information : ntwidth: % dntheight: % dn", fmt.fmt.pix.width, fmt.fmt.pix.height);
struct v4l2_fmtdesc fmtdesc2;
fmtdesc2.index = 0;
fmtdesc2.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
while (ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc2) != -1)
{
if (fmtdesc2.pixelformat & fmt.fmt.pix.pixelformat)
{
printf("tformat: % sn", fmtdesc2.description);
break;
}
fmtdesc2.index++;
}
}
{
//设置视频格式
struct v4l2_format fmt;
memset(&fmt, 0, sizeof(fmt));
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.width = 1280;
fmt.fmt.pix.height = 720;
fmt.fmt.pix.pixelformat = 0;
fmt.fmt.pix.field = V4L2_FIELD_ANY;
//设置设备捕获视频的格式
if (ioctl(fd, VIDIOC_S_FMT, &fmt) < 0)
{
printf("set format failedn");
close(fd);
return 0;
}
//如果摄像头不支持我们设置的分辨率格式,则 fmt.fmt.pix.width 会被修改,所以此处建议再次检查 fmt.fmt.pix. 的各种信息
//向驱动申请帧缓存
int CAP_BUF_NUM = 4;
struct v4l2_requestbuffers req;
memset(&req, 0, sizeof(req));
req.count = CAP_BUF_NUM;
//申请一个拥有四个缓冲帧的缓冲区
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
if (ioctl(fd, VIDIOC_REQBUFS, &req) < 0)
{
if (EINVAL == errno)
{
printf(" does not support memory mappingn");
close(fd);
return 0;
}
else
{
printf("does not support memory mapping, unknow errorn");
close(fd);
return 0;
}
}
else
{
printf("alloc successn");
}
if (req.count < CAP_BUF_NUM)
{
printf("Insufficient buffer memoryn");
close(fd);
return 0;
}
else
{
printf("get %d bufsn", req.count);
}
//将帧缓存与本地内存关联
typedef struct VideoBuffer {
//定义一个结构体来映射每个缓冲帧
void* start;
size_t length;
} VideoBuffer;
VideoBuffer* buffers = calloc(req.count, sizeof(*buffers));
struct v4l2_buffer buf;
for (int numBufs = 0; numBufs < req.count; numBufs++) {//映射所有的缓存
memset(&buf, 0, sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = numBufs;
if (ioctl(fd, VIDIOC_QUERYBUF, &buf) == -1) {//获取到对应index的缓存信息,此处主要利用length信息及offset信息来完成后面的mmap操作。
printf("unexpect error %dn", numBufs);
free(buffers);
close(fd);
return 0;
}
buffers[numBufs].length = buf.length;
// 转换成相对地址
buffers[numBufs].start = mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, buf.m.offset); // #include <sys/mman.h>
if (buffers[numBufs].start == MAP_FAILED) {
printf("%d map failed errno %dn", numBufs, errno);
free(buffers);
close(fd);
return 0;
}
//addr 映射起始地址,一般为NULL ,让内核自动选择
//prot 标志映射后能否被读写,其值为PROT_EXEC,PROT_READ,PROT_WRITE, PROT_NONE
//flags 确定此内存映射能否被其他进程共享,MAP_SHARED,MAP_PRIVATE
//fd,offset, 确定被映射的内存地址 返回成功映射后的地址,不成功返回MAP_FAILED ((void*)-1)
//int munmap(void* addr, size_t length);// 最后记得断开映射
//把缓冲帧加入缓冲队列
if (ioctl(fd, VIDIOC_QBUF, &buf) < 0)
{
printf("add buf to queue failed %dn", numBufs);
free(buffers);
close(fd);
return 0;
}
}
int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
/* 打开设备视频流 */
if (ioctl(fd, VIDIOC_STREAMON, &type) < 0)
{
printf("stream open failedn");
free(buffers);
close(fd);
return 0;
}
int franeCount = 9;
while (franeCount--)
{
struct v4l2_buffer capture_buf;
memset(&capture_buf, 0, sizeof(capture_buf));
capture_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
capture_buf.memory = V4L2_MEMORY_MMAP;
/* 将已经捕获好视频的内存拉出已捕获视频的队列 */
if (ioctl(fd, VIDIOC_DQBUF, &capture_buf) < 0)
{
printf("get frame failed %dn", franeCount);
break;
}
else
{
//long long secc = capture_buf.timestamp.tv_sec;
//long long secc2 = capture_buf.timestamp.tv_usec;
//printf("timestamp %lld
%lld", secc, secc2);
//handle frame
{
FILE* f = fopen("/tftpboot/yuv.yuv", "ab");
int wt = fwrite(buffers[capture_buf.index].start, 1, buffers[capture_buf.index].length, f);
printf("wt %dn", wt);
fclose(f);
}
printf("get %d frame successn", franeCount);
//把用完的帧重新插回队列
if (ioctl(fd, VIDIOC_QBUF, &capture_buf) == -1) {
printf("insert buf failed %dn", franeCount);
break;
}
}
}
//清理资源
int ret = ioctl(fd, VIDIOC_STREAMOFF, &type);
for (int i = 0; i < CAP_BUF_NUM; i++)
{
munmap(buffers[i].start, buffers[i].length);
}
free(buffers);
close(fd);
}
return 0;
}

 

最后

以上就是听话小虾米为你收集整理的Linux 通过摄像头获取画面 C语言的全部内容,希望文章能够帮你解决Linux 通过摄像头获取画面 C语言所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(58)

评论列表共有 0 条评论

立即
投稿
返回
顶部