ZBLOG

linux v4l2如何实时边实时显示采集画面,边等待接受用户点击进行拍照

在Linux下使用V4L2(Video4Linux2)进行实时视频采集并允许用户点击拍照,通常涉及几个步骤。以下是一个基本的实现方案,涵盖如何实时显示捕获画面,并在用户点击时保存当前帧。

1. 环境准备

确保安装了必要的库和工具:

sudo apt-get install v4l-utils libv4l-dev libsdl2-dev

2. V4L2 示例代码

下面是一个简单示例代码,用于打开摄像头、显示视频流以及处理用户点击以拍照:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <linux/videodev2.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <SDL2/SDL.h>

#define VIDEO_DEVICE "/dev/video0"
#define WIDTH 640
#define HEIGHT 480

struct buffer {
    void *start;
    size_t length;
};

int main() {
    int fd = open(VIDEO_DEVICE, O_RDWR);
    if (fd == -1) {
        perror("Opening video device");
        return EXIT_FAILURE;
    }

    struct v4l2_capability cap;
    ioctl(fd, VIDIOC_QUERYCAP, &cap);

    struct v4l2_format fmt;
    memset(&fmt, 0, sizeof(fmt));
    fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    fmt.fmt.pix.width = WIDTH;
    fmt.fmt.pix.height = HEIGHT;
    fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; // YUV format
    fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;

    ioctl(fd, VIDIOC_S_FMT, &fmt);

    // Allocate buffers for video streaming
    struct v4l2_requestbuffers req;
    memset(&req, 0, sizeof(req));
    req.count = 1; // Use only one buffer for simplicity
    req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    req.memory = V4L2_MEMORY_MMAP;

    ioctl(fd, VIDIOC_REQBUFS, &req);

    struct buffer *buffers = calloc(1, sizeof(*buffers));
    
   // Memory mapping the buffer
   struct v4l2_buffer buf;
   memset(&buf, 0, sizeof(buf));
   buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
   buf.memory = V4L2_MEMORY_MMAP;

   ioctl(fd, VIDIOC_QUERYBUF, &buf);
   
   buffers[0].length = buf.length; 
   buffers[0].start = mmap(NULL,
                             buf.length,
                             PROT_READ | PROT_WRITE,
                             MAP_SHARED,
                             fd,
                             buf.m.offset);

   // Start capturing frames
   ioctl(fd, VIDIOC_STREAMON, &buf.type);
   
   // Initialize SDL for displaying video frames
   SDL_Init(SDL_INIT_VIDEO);
   SDL_Window *window = SDL_CreateWindow("Video Capture", 
                                         SDL_WINDOWPOS_UNDEFINED,
                                         SDL_WINDOWPOS_UNDEFINED,
                                         WIDTH,
                                         HEIGHT,
                                         SDL_WINDOW_SHOWN);
   
   SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, 0);
   SDL_Texture *texture = SDL_CreateTexture(renderer,
                                            SDL_PIXELFORMAT_YV12,
                                            SDL_TEXTUREACCESS_STREAMING,
                                            WIDTH,
                                            HEIGHT);

while (1) {
       // Dequeue a buffer and get a frame from it.
       ioctl(fd, VIDIOC_DQBUF,&buf); 

       // Update texture with new frame data
       SDL_UpdateTexture(texture,NULL,buffers[0].start,buffers[0].length/WIDTH); 

       // Clear the renderer and copy the texture to it.
       SDL_RenderClear(renderer); 
       SDL_RenderCopy(renderer,textur,NULL,NULL);
       
       /* Wait for user input */
       while (SDL_PollEvent(NULL)) {
            if(event.type ==SDL_QUIT) goto cleanup;

            if(event.type ==SDL_MOUSEBUTTONDOWN) {
                printf("Taking snapshot...\n");
                FILE* file=fopen("snapshot.yuyv","wb"); 
                fwrite(buffers[0].start,sizeof(char),buffers[0].length,file); 
                fclose(file);
            }
         }
         // Render the updated frame onto the window.
         SDL_RenderPresent(renderer); 

         ioctl(fd,VIOCG_QBUF,&buf);  
}

cleanup:
      munmap(buffers[0].start,buffers[0].length);     
      free(buffers);     
      close(fd);     
      SDL_DestroyTexture(texture);
      SDL_DestroyRenderer(renderer); 
      SDL_DestroyWindow(window); 
      return EXIT_SUCCESS; 
}

注意事项

  • 格式: 本例中使用的是YUYV格式,可以根据需要修改。
  • 事件处理: 使用SDL_PollEvent等待鼠标事件,当检测到鼠标点击时调用拍照函数,保存当前帧到文件。
  • 性能: 此代码片段较为基础,实际应用中可能需要更复杂的错误处理和性能优化(如多线程)。
  • 图像保存:这里直接将YUYV数据写入文件,实际使用中你可能想要将其转换为JPEG或PNG格式。

通过以上步骤,你可以构建一个简单的程序来实时显示视频流并支持拍照功能。希望这个示例能对你有所帮助!


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

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

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

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

联系我们

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

微信号:3007537140

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

关注我们
x

注册

已经有帐号?