ZBLOG

Linux C++ 使用v4l2采集HDMI IN的视频数据

使用V4L2(Video4Linux2)在Linux环境下采集HDMI输入的视频数据可以分为几个步骤。以下是一个基本的流程和代码示例,以帮助您理解如何实现这一目标。

环境准备

  1. 确保您的Linux系统已经安装了V4L2开发库,可以通过以下命令安装:

    sudo apt-get install libv4l-dev
    
  2. 确保您的视频采集设备已经连接并且支持V4L2接口。

C++代码示例

以下是一个简单的C++程序,用于打开视频设备,设置参数,并读取帧数据:

#include <iostream>
#include <cstring>
#include <unistd.h>
#include <fcntl.h>
#include <linux/videodev2.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <opencv2/opencv.hpp>

#define DEVICE "/dev/video0" // 请根据实际情况修改

int main() {
    int fd = open(DEVICE, O_RDWR);
    if (fd == -1) {
        std::cerr << "无法打开设备: " << DEVICE << std::endl;
        return 1;
    }

    // 获取摄像头的能力
    struct v4l2_capability cap;
    if (ioctl(fd, VIDIOC_QUERYCAP, &cap) == -1) {
        std::cerr << "无法获取设备能力" << std::endl;
        close(fd);
        return 1;
    }

    // 设置格式
    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 = V4L2_PIX_FMT_YUYV; // 常见格式之一
    fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;

    if (ioctl(fd, VIDIOC_S_FMT, &fmt) == -1) {
        std::cerr << "无法设置格式" << std::endl;
        close(fd);
        return 1;
    }

    // 请求缓冲区
    struct v4l2_requestbuffers reqbufs;
    memset(&reqbufs, 0, sizeof(reqbufs));
    
    reqbufs.count = 1; 
    reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    reqbufs.memory = V4L2_MEMORY_MMAP;

    if (ioctl(fd, VIDIOC_REQBUFS, &reqbufs) == -1) {
        std::cerr << "请求缓冲区失败" << std::endl;
        close(fd);
        return 1;
    }

   // 映射缓冲区
   struct v4l2_buffer buf;
   memset(&buf, 0, sizeof(buf));

   buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
   buf.memory = V4L2_MEMORY_MMAP;

   if (ioctl(fd, VIDIOC_QUERYBUF, &buf) == -1) {
       std::cerr << "查询缓冲区失败" << std::endl;
       close(fd);
       return 1;
   }
   
   void* buffer_start = mmap(NULL,
                              buf.length,
                              PROT_READ | PROT_WRITE,
                              MAP_SHARED,
                              fd,
                              buf.m.offset);

   if (buffer_start == MAP_FAILED) {
       std::cerr << "映射缓冲区失败" << std::endl;
       close(fd);
       return 1;
   }

   // 开始捕获视频流
   if (ioctl(fd, VIDIOC_STREAMON, &buf.type) == -1) {
       std::cerr << "启动视频流失败" << std::endl;
       munmap(buffer_start, buf.length);
       close(fd);
       return 1; 
   }

   while (true) {
      // 准备并捕获一帧图像      
      ioctl(fd, VIDIOC_QBUF,&buf);       
      ioctl(fd,Vidioc_DQBUF,&buf);

      cv::Mat img(fmt.fmt.pix.height,(fmt.fmt.pix.width),CV_8UC3,(uint8_t*)buffer_start);

      cv::imshow("Frame", img);        
      char c =(char)cvWaitKey(33);  
      if(c==27)
         break;     
   }

     ioctl(fd,Vidioc_Streamoff,&buf.type);     
     munmap(buffer_start,sizeof(buffer));  
     close(fd);        

     return 0;   
}

编译与运行

将上述代码保存为 video_capture.cpp,然后使用以下命令编译:

g++ video_capture.cpp -o video_capture `pkg-config --cflags --libs opencv`

运行程序:

./video_capture

注意事项

  • 请确保使用适合您设备的分辨率和像素格式。
  • 上述代码没有处理错误和异常,仅作为学习示例。在生产环境中,应增加更多的错误检查。
  • 使用 OpenCV 库来处理图像,如果未安装,请使用包管理器进行安装。

这个基础框架可以扩展以包括更复杂的功能,比如编码、保存到文件等。希望这对你有帮助!如果有其他问题,欢迎继续提问。


内容由零声教学AI助手提供,问题来源于学员提问

本站部分文章来源于网络,版权归原作者所有,如有侵权请联系站长删除。
转载请注明出处:https://sdn.0voice.com/?id=7604

分享:
扫描分享到社交APP
上一篇
下一篇
发表列表
游客 游客
此处应有掌声~
评论列表

还没有评论,快来说点什么吧~

联系我们

在线咨询: 点击这里给我发消息

微信号:3007537140

上班时间: 10:30-22:30

关注我们
x

注册

已经有帐号?