V4L2访问摄像头扩展单元命令

我们可以通过IOCTL访问扩展单元,调用方法如下:

ioctl(fd, UVCIOC_CTRL_QUERY, struct uvc_xu_control_query *);

访问不同的扩展命令只需要修改uvc_xu_control_query 结构体里面内容即可。

uvc_xu_control_query 结构体如下:

struct uvc_xu_control_query {
    __u8 unit;//扩展单元ID
    __u8 selector;//扩展命令ID
    __u8 query;//特定请求,如UVC_GET_CUR
                /* defined in linux/usb/video.h A.8.  */
    __u16 size;//数据长度
    __u8 *data;//数据buf
};

假如我们访问失败,可能有一下几个原因:

1.扩展描述符中没有打开该命令,扩展单元协议可参照UVC 扩展单元描述符 - USB中文网

2.该扩展命令不支持GET_INFO或者GET_LEN

3.该扩展命令支持GET_LEN,但是返回的长度和我们定义的长度不一致

在开发过程中还遇到通过libuvc能够调用成功,但是v4l2调用失败,这是因为libuvc并不是严格按照UVC协议。

写了段示例代码如下:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>   
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <string.h>
#include <linux/videodev2.h>
#include <linux/uvcvideo.h>
#include <linux/usb/video.h>
#include <errno.h>

#define UVC_EU1_ID 0x06
#define EU1_TEST_CMD 0x3b
#define EU1_TEST_CMD_LEN 0x01

int main(int argc,char **argv){
    int fd = open("/dev/video0",O_RDWR);
    if(fd <= 0)
    {
        printf("open failed!\n");
        return -1;
    }
    unsigned char buf[EU1_TEST_CMD_LEN];
    struct uvc_xu_control_query xu_ctrl_query =
    {
        .unit     = UVC_EU1_ID,
        .selector = EU1_TEST_CMD,
        .query    = UVC_GET_CUR,
        .size     = EU1_TEST_CMD_LEN,
        .data     = buf,
    };    
    int ret = ioctl(fd, UVCIOC_CTRL_QUERY, &xu_ctrl_query);
    if(ret < 0)
    {
        printf("query fail!\n");
        printf("%s\n",strerror(errno));
    }else{    
        printf("query success!\n");
        int i;
        printf("data:");
        for(i = 0;i < EU1_TEST_CMD_LEN;i++)
        {
            printf("%#x ",buf[i]);
        }
        printf("\n");
    }
    close(fd);
    return 0;
}

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 13
    评论
好的,以下是一个基本的 C++ 代码示例,可用于使用 V4L2 调用摄像头拍照: ```c++ #include <iostream> #include <fcntl.h> #include <unistd.h> #include <sys/ioctl.h> #include <linux/videodev2.h> using namespace std; int main(int argc, char* argv[]) { const char* device = "/dev/video0"; // 摄像头设备名称 int fd = open(device, O_RDWR); // 打开设备 if (fd == -1) { cerr << "Failed to open device!" << endl; return -1; } // 查询设备参数 v4l2_capability cap; if (ioctl(fd, VIDIOC_QUERYCAP, &cap) == -1) { cerr << "Failed to query device capabilities!" << endl; close(fd); return -1; } // 设置摄像头参数 v4l2_format fmt; fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; fmt.fmt.pix.width = 640; fmt.fmt.pix.height = 480; fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_JPEG; fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; if (ioctl(fd, VIDIOC_S_FMT, &fmt) == -1) { cerr << "Failed to set device format!" << endl; close(fd); return -1; } // 请求缓冲帧 v4l2_requestbuffers req; req.count = 1; req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; req.memory = V4L2_MEMORY_MMAP; if (ioctl(fd, VIDIOC_REQBUFS, &req) == -1) { cerr << "Failed to request buffers!" << endl; close(fd); return -1; } // 映射缓冲帧 v4l2_buffer buf; buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = 0; if (ioctl(fd, VIDIOC_QUERYBUF, &buf) == -1) { cerr << "Failed to query buffer!" << endl; close(fd); return -1; } void* ptr = mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, buf.m.offset); if (ptr == MAP_FAILED) { cerr << "Failed to map buffer!" << endl; close(fd); return -1; } // 开始捕获图像 if (ioctl(fd, VIDIOC_STREAMON, &buf.type) == -1) { cerr << "Failed to start streaming!" << endl; close(fd); return -1; } // 获取图像数据 if (ioctl(fd, VIDIOC_QBUF, &buf) == -1) { cerr << "Failed to enqueue buffer!" << endl; close(fd); return -1; } fd_set fds; FD_ZERO(&fds); FD_SET(fd, &fds); timeval tv; tv.tv_sec = 2; tv.tv_usec = 0; // 等待数据准备就绪 int r = select(fd + 1, &fds, NULL, NULL, &tv); if (r == -1) { cerr << "Failed to wait for data!" << endl; close(fd); return -1; } else if (r == 0) { cerr << "Timeout waiting for data!" << endl; close(fd); return -1; } // 获取图像数据 if (ioctl(fd, VIDIOC_DQBUF, &buf) == -1) { cerr << "Failed to dequeue buffer!" << endl; close(fd); return -1; } // 写入图像文件 string filename = "image.jpg"; ofstream ofs(filename, ios::binary); ofs.write((const char*)ptr, buf.bytesused); ofs.close(); cout << "Image saved to " << filename << endl; // 停止捕获图像 if (ioctl(fd, VIDIOC_STREAMOFF, &buf.type) == -1) { cerr << "Failed to stop streaming!" << endl; close(fd); return -1; } // 关闭设备 close(fd); return 0; } ``` 这个代码示例将从 `/dev/video0` 设备读取摄像头的图像数据,并将其保存为 JPEG 格式的文件。你可以根据需要更改摄像头设备名称以及图像的宽度、高度和格式。 注意,这个代码示例只是一个基本的框架,你需要根据自己的需求对其进行修改和扩展。例如,你可能需要添加对摄像头参数的查询、设置和调整,或者添加对多个缓冲帧的支持。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

老吕丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值