Linux--V4L2应用程序开发(二)获取数据

一、采集数据流程

申请buffer用来放置摄像头数据

  • ioctl VIDIOC_REQBUFS:申请buffer,APP可以申请很多个buffer,但是驱动程序不一定能申请到

  • ioctl VIDIOC_QUERYBUF和mmap:查询buffer信息、映射

    • 如果申请到了N个buffer,这个ioctl就应该执行N次

    • 执行mmap后,APP就可以直接读写这些buffer

  • ioctl VIDIOC_QBUF:把buffer放入"空闲链表"

    • 如果申请到了N个buffer,这个ioctl就应该执行N次

获取数据

  • ioctl VIDIOC_STREAMON:启动摄像头

存储数据

  • 这里是一个循环:使用poll/select监测buffer,然后从"完成链表"中取出buffer,处理后再放入"空闲链表"

    • poll/select

    • ioctl VIDIOC_DQBUF:从"完成链表"中取出buffer

    • 处理:前面使用mmap映射了每个buffer的地址,处理时就可以直接使用地址来访问buffer

    • ioclt VIDIOC_QBUF:把buffer放入"空闲链表"

  • ioctl VIDIOC_STREAMOFF:停止摄像头

二、代码如下:


    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;  

    /*申请buffer*/
    if(0 == ioctl(fd, VIDIOC_REQBUFS,&rb))
    {
        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))/*查询申请到buf是否成功*/
            {
                bufs[i] = mmap(0, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED,fd, buf.m.offset);/*申请成功后,mmap这些buffer*/
                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 ");
    }

    /*把所有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("Uable to queue buffer");
            return -1;
        }
        
    }
    printf("queue buffers ok\n");


    /*启动摄像头*/
    int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    if(0 != ioctl(fd,VIDIOC_STREAMON, &type))
    {
        perror("Uable 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 creat file :%s \n", filename);
            return -1;
        }
        write(fd_file, bufs[buf.index], buf.bytesused);
        close(fd_file);
        /*把buffer放入队列*/
        if(0 != ioctl(fd, VIDIOC_QBUF,&buf))
        {
            perror("Uable to queue buffer");
            return -1;
        }       
        }

    }

    if(0 != ioctl(fd,VIDIOC_STREAMOFF, &type));
    {
        perror("Uable to stop capture");
        return -1;
    }
    printf("stop capture ok\n");
    close(fd);

输出结果为:将每一帧数据采集为jpg格式保存在当前目录下。

三、代码知识点补充

1、mmap()

bufs[i] = mmap(0, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED,fd, buf.m.offset);

        mmap 函数用于将一个文件或设备(如视频设备)的内容映射到进程的地址空间。这样,可以通过指针直接访问文件或设备的内容,而不需要使用系统调用,如 readwrite,从而提高了访问效率。

参数解释

  • addr: 指定映射的起始地址。通常设为 0NULL,表示由内核决定映射区域的起始地址。
  • length: 要映射的文件部分的长度。这里是 buf.length,表示需要映射的缓冲区的大小。
  • prot: 映射区域的保护方式。可以是以下几个值的组合:
    • PROT_READ:页内容可以被读取。
    • PROT_WRITE:页内容可以被写入。
    • PROT_EXEC:页内容可以被执行。
  • flags: 映射对象的类型、映射选项和页是否可以共享等。常用值有:
    • MAP_SHARED:映射区内的写入数据会写回到原文件,同时对其他映射到该文件的进程可见。
    • MAP_PRIVATE:写入数据会产生一个写时拷贝(copy-on-write),对其他映射到该文件的进程不可见。
  • fd: 要映射到内存的文件描述符。这里是视频设备文件描述符 fd
  • offset: 文件映射的起始位置。通常是缓冲区的偏移量,这里是 buf.m.offset

返回值

mmap 成功时返回映射区的指针,失败时返回 MAP_FAILED,并设置 errno 以指示错误。

2、perror()

        perror 函数是 C 标准库中的一个函数,用于输出描述最近一次函数调用发生错误的错误信息。它会根据 errno 的值输出对应的错误消息。errno 是一个全局变量,用于记录最近一次系统调用或库函数调用错误的错误码。

        perror 函数根据 errno 的值,查找并输出对应的错误消息。错误消息通常来自系统定义的一系列错误描述字符串。errno 由最近一次出错的系统调用或标准库函数设置。

  • errno: errno 是由库函数和系统调用设置的全局变量,表示上一次操作的错误码。每个错误码对应一个错误消息。
  • 错误消息查找perror 根据当前 errno 的值,在系统预定义的错误消息列表中查找并输出相应的错误消息。

四、遇到的问题

    /*启动摄像头*/
    int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    if(0 != ioctl(fd,VIDIOC_STREAMON, &type))
    {
        perror("Uable to start capture");
        return -1;
    }
    printf("start capture ok\n");

在if语句后误加了;分号,导致if语句判断没有执行,而perror会一直执行

我是用Windows上的vscode通过ssh链接Ubuntu开发的,VScode没有报错且交叉编译也通过了,所以执行后一直报错Uable to start capture: Invalid argument

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/753139.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

vue-router的学习

vue-router 基于Vue做单页面应用时&#xff0c;vue-router可以帮我们将url地址和组件绑定&#xff0c;在我们切换路由组件时&#xff0c;url改变&#xff0c;页面无需从服务端重新加载&#xff0c;即不用刷新&#xff0c;打个比方&#xff0c;我们用美团外卖点外卖时&#xff…

一文带你彻底搞懂设计模式之单例模式!!由浅入深,图文并茂,超超超详细的单例模式讲解!!

一文带你彻底搞懂设计模式之单例模式&#xff01; 一、什么是单例模式&#xff1f;单例模式分类饿汉式创建单例对象懒汉式创建单例对象 多问一个为什么&#xff1f; 二、为什么要有单例模式&#xff1f;使用单例模式的原因单例模式的应用场景 三、多线程下的单例模式饿汉式懒汉…

【高级篇】InnoDB引擎深入:核心机制与实战优化(十五)

引言 在探索了MySQL集群与分布式技术之后,我们进入了数据库引擎的核心地带——InnoDB。作为MySQL的默认存储引擎,InnoDB凭借其对事务的支持、行级锁定、高效的恢复机制以及复杂的内存管理,成为众多应用场景的首选。本章,我们将深入InnoDB的内部机制,透彻理解锁管理、事务…

【C++】动态内存管理new和delete

文章目录 一、C的内存管理方式二、new和delete的用法1.操作内置类型2.操作自定义内置类型 三、new和delete的底层实现1.operator new和operator delete函数2.new和delete的实现原理 四、定位new表达式五、malloc/free和new/delete的区别 一、C的内存管理方式 之前在C语言的动态…

找不到vcomp140.dll怎么办,总结多种解决方法

​在日常使用电脑的过程中&#xff0c;我们可能会遇到一些错误提示&#xff0c;其中之一就是“vcomp140.dll丢失”。那么&#xff0c;vcomp140.dll是什么&#xff1f;它为什么会丢失&#xff1f;丢失后对电脑有什么影响&#xff1f;又该如何解决呢&#xff1f;本文将详细介绍vc…

leetcode 动态规划(基础版)单词拆分

题目&#xff1a; 题解&#xff1a; 一种可行的dp做法是基于完全背包问题&#xff0c;将s看成是一个背包&#xff0c;wordDict看作是物品&#xff0c;然后往s中放入物品判断最终是否可以变为给定的s即可。这道题和上一题都用到了在dp如何枚举连续子串和状态表示&#xff1a;枚…

一个 API 客户端和一份 TS 学习手册

第75期&#xff1a; Insomnia&#xff1a;超好看的 API 客户端 项目介绍&#xff1a; 一款适用于 GraphQL、REST、WebSockets 和 gRPC 的开源 API 客户端&#xff0c;颜值超高。 跨平台&#xff0c;支持 Mac、Windows 和 Linux。但不支持网页版&#xff0c;需要下载客户端。…

如何借助ai(文心一言)获取tushare的数据

1. 准备工作 确保已安装python &#xff0c;安装Tushare库 和文心一言的地址&#xff08;文心一言&#xff09;&#xff1a; 注册Tushare账号并获取Token&#xff1a;在Tushare官方网站注册账号&#xff0c;并获取个人Token。如下 tushare地址&#xff1a;&#xff08;点击即…

PD快充诱骗芯片工作原理,USB-C充电器出不来电压是什么原因?

一般使用Type-C接口的充电器基本上都是采用新的快充协议——PD快充协议&#xff0c;它不同于以前的USB-A的QC协议&#xff0c;这种协议&#xff0c;默认是没有快充电压输出的&#xff0c;VBUS和GND是0V。 所以&#xff0c;我们可以使用电阻的方式&#xff08;电流小&#xff09…

【Apache Doris】如何实现高并发点查?(原理+实践全析)

【Apache Doris】如何实现高并发点查&#xff1f;&#xff08;原理实践全析&#xff09; 一、背景说明二、原理介绍三、环境信息四、Jmeter初始化五、参数预调六、用例准备七、高并发实测八、影响因素九、总结 本文主要分享 Apache Doris 是如何实现高并发点查的&#xff0c;以…

突破SaaS产品运营困境:多渠道运营如何集中管理?

随着数字化时代的到来&#xff0c;SaaS&#xff08;软件即服务&#xff09;产品已成为企业日常运营不可或缺的工具。然而&#xff0c;在竞争激烈的市场环境下&#xff0c;SaaS产品运营越来越重视多渠道、多平台布局&#xff0c;以更广泛地触及潜在用户&#xff0c;然而&#xf…

《昇思25天学习打卡营第10天 | 昇思MindSporeFCN图像语义分割》

第10天 本节学习了FCN图像语义分割。全卷积网络是用于图像语义分割的一种框架。FCN是首个端到端&#xff08;end to end&#xff09;进行像素级&#xff08;pixel level&#xff09;预测的全卷积网络。FCN有两大明显的优点&#xff1a;一是可以接受任意大小的输入图像&#xff…

2024年跨境电商关键数据统计:市场规模将达到1.976万亿美元

预计2024年跨境电商消费市场规模将达到1.976万亿美元&#xff0c;占全球网上销售总额的31.2%。这一数据无疑展示了跨境电商市场的巨大潜力和迅猛增长趋势。 全球跨境电商的现状与未来 现状 2023年&#xff0c;全球跨境电商市场规模预计达到1.56万亿美元&#xff0c;占全球电子…

JAVA毕业设计145—基于Java+Springboot+vue+uniapp的驾校预约小程序(源代码+数据库+15000字论文)

毕设所有选题&#xff1a; https://blog.csdn.net/2303_76227485/article/details/131104075 基于JavaSpringbootvueuniapp的驾校预约小程序(源代码数据库15000字论文)145 一、系统介绍 本项目前后端分离&#xff0c;分为用户、教练、管理员三种角色 1、用户&#xff1a; …

PHP爬虫类的并发与多线程处理技巧

PHP爬虫类的并发与多线程处理技巧 引言&#xff1a; 随着互联网的快速发展&#xff0c;大量的数据信息存储在各种网站上&#xff0c;获取这些数据已经成为很多业务场景下的需求。而爬虫作为一种自动化获取网络信息的工具&#xff0c;被广泛应用于数据采集、搜索引擎、舆情分析…

unity-特效-雷达扫描效果

使用后处理方式制作 using System; using System.Collections; using System.Collections.Generic; using UnityEngine;public class GlobalScanEffect : MonoBehaviour {public float startScanRange 0;public float maxScanRange 20;public float scanWidth 3;public flo…

洁盟超声波清洗机怎么样?横向测评希亦、洁盟、苏泊尔超声波清洗机谁是实力派

生活中大多数人戴眼镜&#xff0c;但是很多人都不注意眼镜的保养&#xff0c;导致镜片越来越模糊&#xff0c;从而引发多边的状况发生&#xff0c;比如长久戴模糊不清的眼镜&#xff0c;视力会受到影响随之下降。甚至是眼镜长期不清洗&#xff0c;上面的灰尘、细菌会影响眼部健…

极限竞速地平线4卡顿?这样做快速解决地平线4卡顿问题

极限竞速地平线4全新开放式剧情的设计让玩家的每一次行动都能推动游戏的进程。时间、天气和四季的变化&#xff0c;都将在极限竞速地平线4这里得到真实的呈现。玩家将有机会在壮丽的原生4K和HDR画质下&#xff0c;欣赏到英国那湖泊、山谷、城堡和无数美景&#xff0c;体验一段从…

使用 Rustup 管理 Rust 版本

文章目录 安装 Rustup配置镜像源安装 Rustup 安装 RustVS Code插件创建项目代码示例 Rust 官网&#xff1a;https://www.rust-lang.org/zh-CN/Crates 包管理&#xff1a;https://crates.io/Rust 程序设计语言&#xff1a;https://kaisery.github.io/trpl-zh-cn/通过例子学 Rust…

docker 搭建 AI大数据模型 --- 使用GPU

docker 搭建 AI大数据模型 — 使用GPU方式 搭建本地大模型&#xff0c;最简单的方法&#xff01;效果直逼GPT 服务器GPU系统HP580 G8P40Rocky9.2 安装程序AnythingLLM前端界面Open WebUIChatOllamaollama 一、AnythingLLM 介绍 AnythingLLM 是 Mintplex Labs Inc. 开发的一…