Linux下通过V4L2从USB相机取MJPEG视频流

避免以后要用到,备用

#include <stdio.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <linux/videodev2.h>
#include<sys/ioctl.h>
#include <setjmp.h>
#include <unistd.h>

#define CAM_DEV "/dev/video14"
#define   WIDTH   1920                       // 图片的宽度
#define   HEIGHT  1080                       // 图片的高度
#define  NB_BUFFER  4   //memory block number
struct pic_data 
{
    unsigned char *tmpbuffer[NB_BUFFER];
    unsigned int tmpbytesused[NB_BUFFER];
}pic;

int cam_fd;

/*
Description.:Initalize V4L2 driver.
*/
int v4l2_init(void)
{
    int i;
    int ret = 0;

    // 1、Open camera device
    if((cam_fd = open(CAM_DEV,O_RDWR)) == -1)
    {
        perror("ERROR opening V4L interface.");
        return -1;
    }

    // 2、Judge if the device is a camera device 
    struct v4l2_capability cam_cap;
    if(ioctl(cam_fd,VIDIOC_QUERYCAP,&cam_cap) == -1)
    {
        perror("Error opening device %s: unable to query device.");
        return -1;
    }
    if((cam_cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0) 
    {
        perror("ERROR video capture not supported.");
        return -1;
    }

    // 3、Setting output parameter.
    struct v4l2_format v4l2_fmt;
    v4l2_fmt.type = V4L2_CAP_VIDEO_CAPTURE;
    v4l2_fmt.fmt.pix.width = WIDTH;
    v4l2_fmt.fmt.pix.height = HEIGHT;
    v4l2_fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;
    if (ioctl (cam_fd, VIDIOC_S_FMT, &v4l2_fmt) == -1) 
    {   
        perror("ERROR camera VIDIOC_S_FMT Failed.");
        return -1;
    }
    // 4、Check whether the parameters are set successfully 
    if (ioctl (cam_fd, VIDIOC_G_FMT, &v4l2_fmt) == -1) 
    {
        perror("ERROR camera VIDIOC_G_FMT Failed.");
        return -1;
    }
    if (v4l2_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG)
    {
        printf("Set VIDIOC_S_FMT sucessful\n");
    }
    // 5、Require buffer to store image data
    struct v4l2_requestbuffers v4l2_req;
    v4l2_req.count = NB_BUFFER;
    v4l2_req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    v4l2_req.memory = V4L2_MEMORY_MMAP;
    if (ioctl (cam_fd, VIDIOC_REQBUFS, &v4l2_req) == -1) 
    {
        perror("ERROR camera VIDIOC_REQBUFS Failed.");
        return -1;
    } 
    // 6、Start memory map
    struct v4l2_buffer v4l2_buf;
    v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    v4l2_buf.memory = V4L2_MEMORY_MMAP;
      for(i = 0; i < NB_BUFFER; i++) 
   {
        v4l2_buf.index = i;
        if(ioctl(cam_fd, VIDIOC_QUERYBUF, &v4l2_buf) < 0)
        {
            perror("Unable to query buffer.");
            return -1;
        }

        pic.tmpbuffer[i] = (unsigned char*)mmap(NULL, v4l2_buf.length, PROT_READ, MAP_SHARED, cam_fd, v4l2_buf.m.offset);
        if(pic.tmpbuffer[i] == MAP_FAILED)
        {
             perror("Unable to map buffer.");
             return -1;
        }
        if(ioctl(cam_fd, VIDIOC_QBUF, &v4l2_buf) < 0)
        {
            perror("Unable to queue buffer.");
            return -1;
        }
   }
    //7、Open stream input 
    int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    if(ioctl(cam_fd, VIDIOC_STREAMON, &type) < 0)
    {
        perror("Unable to start capture.");
        return -1;
    }
    return 0;
}

/*
Description.:Get a jpeg image and save.
*/
int v4l2Grab(void)
{
    //8、Get a image 
    struct v4l2_buffer buff;
    buff.type   = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    buff.memory = V4L2_MEMORY_MMAP;
    if(ioctl(cam_fd, VIDIOC_DQBUF, &buff) < 0)
    {
        printf("camera VIDIOC_DQBUF Failed.\n");
        usleep(1000*1000);
        return -1;
    }

    pic.tmpbytesused[buff.index] = buff.bytesused;
    printf("size : %d\n",pic.tmpbytesused[buff.index]);           

    //9、Save image.
    /*
    int jpg_fd = open("1.jpeg",O_RDWR|O_CREAT,00700);
    if(jpg_fd == -1)
    {
        printf("open ipg Failed!\n ");
        return -1;      
    }
    int writesize = write(jpg_fd, pic.tmpbuffer[buff.index], pic.tmpbytesused[buff.index]);
    printf("Write successfully size : %d\n",writesize);
    close(jpg_fd);
    */
    //10、Queue the buffers.
    if(ioctl(cam_fd, VIDIOC_QBUF, &buff) < 0)
    {
        printf("camera VIDIOC_QBUF Failed.");
        usleep(1000*1000);
        return -1;
    }
    return 0;
}

/*
Description.:Release resource
*/
int v4l2_close(void)
{
    // Remove mmap.
    int i;
    for(i=0; i<NB_BUFFER; i++)
        munmap(pic[0].tmpbuffer[i],pic[0].tmpbytesused[i]);
    close(cam_fd);
    return 0;
}

/*
Description.:main
*/
int main(int argc, char* argv[])
{
    v4l2_init();
    while(1)
    {        
        v4l2Grab();
    }
    v4l2_close();            
    return 0;
}
  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
要通过 pid 和 vid 使用 UVC(USB Video Class)和 v4l2(Video4Linux2)来打开摄像头,你可以使用以下步骤: 1. 使用 libusb 初始化和打开 USB 设备: ```c libusb_device_handle *dev_handle; libusb_init(NULL); dev_handle = libusb_open_device_with_vid_pid(NULL, vid, pid); ``` 请确保将 `vid` 和 `pid` 替换为你要使用的摄像头的供应商 ID 和产品 ID。 2. 使用 libusb 获取 USB 设备的文件描述符: ```c int fd = libusb_get_device_fd(libusb_get_device(dev_handle)); ``` 3. 使用 v4l2 打开摄像头设备: ```c int camera_fd = open("/dev/video0", O_RDWR); if (camera_fd < 0) { printf("无法打开摄像头设备!\n"); // 错误处理 } ``` 请注意,摄像头设备文件的路径可能会因系统而异,通常为 `/dev/video0`。你可以根据你的实际情况进行修改。 4. 使用 v4l2 进行摄像头设置和图像捕获: ```c struct v4l2_format format; format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; format.fmt.pix.width = 640; format.fmt.pix.height = 480; format.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG; format.fmt.pix.field = V4L2_FIELD_NONE; if (ioctl(camera_fd, VIDIOC_S_FMT, &format) < 0) { printf("无法设置摄像头格式!\n"); // 错误处理 } // 进行图像捕获等操作... // 关闭摄像头设备 close(camera_fd); ``` 在上述示例中,我们使用 v4l2 设置了摄像头的格式,包括宽度、高度和像素格式。你可以根据你的需求进行修改。 请注意,上述代码片段仅演示了通过 pid 和 vid 使用 UVC 和 v4l2 打开摄像头的基本步骤。在实际应用中,你可能还需要进行错误处理、图像捕获和处理等操作。 希望以上信息对你有所帮助!如有更多问题,请随时提问。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值