播放摄像头 sdl2.0 显示v4l2

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了播放摄像头 sdl2.0 显示v4l2相关的知识,希望对你有一定的参考价值。

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

#define LOAD_BGRA    0  
#define LOAD_RGB24   0  
#define LOAD_BGR24   0  
#define LOAD_YUV422P 1  
  
//Bit per Pixel  
#if LOAD_BGRA  
const int bpp=32;  
#elif LOAD_RGB24|LOAD_BGR24  
const int bpp=24;  
#elif LOAD_YUV422P  
const int bpp=16;  
#endif  
int screen_w=640,screen_h=480;  
const int pixel_w=640,pixel_h=480;  
unsigned char buffer[pixel_w*pixel_h*bpp/8];  
unsigned char buffer_convert[pixel_w*pixel_h*4];  
struct buffers
{
void* start;
unsigned int length;
}*buffers;
void errmsg(const char* fun_name)
{
        printf("%s error\n",fun_name);
        exit(-1);
}
int main()
{

     int fd = open("/dev/video0",O_RDWR);
          if(fd < 0)
         errmsg("open");
         int ret = -1;
    struct v4l2_capability cap;
         ret = ioctl(fd,VIDIOC_QUERYCAP,&cap);
         if(ret < 0 )
             {
        perror("ioctl");
        return -1;
             }
     printf("%s \n%s\n%s\n %08x %08x\n",cap.driver,cap.card,cap.bus_info,cap.version,cap.capabilities);
          printf("V4L2_CAP_VIDEO_CAPTURE = %08x    %d \n",V4L2_CAP_VIDEO_CAPTURE,V4L2_CAP_VIDEO_CAPTURE&cap.capabilities);

           if(!(V4L2_CAP_VIDEO_CAPTURE&cap.capabilities))
           {
                 errmsg( "capture not support");
        exit(-1);
           }
//  
    struct v4l2_fmtdesc fmtdesc; 
    fmtdesc.index=0; 
    fmtdesc.type=V4L2_BUF_TYPE_VIDEO_CAPTURE; 
    printf("Support format:\n");
         while(ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc) != -1)
        {
         printf("%d.%s type=%08x  flags=%08x pixelformat=%08x\n",fmtdesc.index+1,fmtdesc.description,fmtdesc.type,fmtdesc.flags,fmtdesc.pixelformat);
          fmtdesc.index++;
           }
    struct v4l2_requestbuffers req; 
          req.count=4; req.type=V4L2_BUF_TYPE_VIDEO_CAPTURE; 
          req.memory=V4L2_MEMORY_MMAP; 
        ret =  ioctl(fd,VIDIOC_REQBUFS,&req);
        if(ret < 0 )
        {
            perror("ioctl23");
                  exit(-1);
        }
     buffers = (struct buffers*)calloc (req.count, sizeof (*buffers));
     if (!buffers) {
     fprintf (stderr, "Out of memory/n");
     exit (-1);
     }
     struct v4l2_buffer buf;
     for (unsigned int n_buffers = 0; n_buffers < req.count; ++n_buffers)
     {
     memset(&buf,0,sizeof(buf));
     buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
     buf.memory = V4L2_MEMORY_MMAP;
     buf.index = n_buffers;
     if (-1 == ioctl (fd, VIDIOC_QUERYBUF, &buf))
         {
            perror("ioctl33");
                exit(-1);
         }
     buffers[n_buffers].length = buf.length;
     buffers[n_buffers].start =mmap (NULL,buf.length,PROT_READ | PROT_WRITE ,MAP_SHARED,fd, buf.m.offset);
     if (MAP_FAILED == buffers[n_buffers].start)
         {
          perror("mmap");
            exit(-1);
         }
     }
     unsigned int i;
     enum v4l2_buf_type type;
     for (i = 0; i < 4; ++i) 
     {
     buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
     buf.memory = V4L2_MEMORY_MMAP;
     buf.index = i;
    ret  =  ioctl (fd, VIDIOC_QBUF, &buf);
    if(ret < 0)
    {
     perror("ioctl 44");
        exit(-1);
    }
     }
     type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
     ret = ioctl (fd, VIDIOC_STREAMON, &type);
     if(ret < 0)
    {
     perror("ioctl 44");
        exit(-1);
    }
    if(SDL_Init(SDL_INIT_VIDEO)) {    
        printf( "Could not initialize SDL - %s\n", SDL_GetError());   
        return -1;  
    }   
    SDL_Window *screen;   
    //SDL 2.0 Support for multiple windows  
    screen = SDL_CreateWindow("Simplest Video Play SDL2", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,  
        screen_w, screen_h,SDL_WINDOW_OPENGL|SDL_WINDOW_RESIZABLE);  
    if(!screen) {    
        printf("SDL: could not create window - exiting:%s\n",SDL_GetError());    
        return -1;  
    }  
    SDL_Renderer* sdlRenderer = SDL_CreateRenderer(screen, -1, 0);    
    Uint32 pixformat=0;  
#if LOAD_BGRA  
    //Note: ARGB8888 in "Little Endian" system stores as B|G|R|A  
    pixformat= SDL_PIXELFORMAT_ARGB8888;    
#elif LOAD_RGB24  
    pixformat= SDL_PIXELFORMAT_RGB888;    
#elif LOAD_BGR24  
    pixformat= SDL_PIXELFORMAT_BGR888;    
#elif LOAD_YUV422P  
    //IYUV: Y + U + V  (3 planes)  
    //YV12: Y + V + U  (3 planes)  
    pixformat= SDL_PIXELFORMAT_YUY2; // SDL_PIXELFORMAT_IYUV;    
#endif  
    SDL_Texture* sdlTexture = SDL_CreateTexture(sdlRenderer,pixformat, SDL_TEXTUREACCESS_STREAMING,pixel_w,pixel_h);  
SDL_Rect sdlRect;     
//     struct v4l2_buffer buf; CLEAR (buf);
while(1)
{
memset(&buf,0,sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
ioctl (fd, VIDIOC_DQBUF, &buf); 
 if(ret < 0)
{
 perror("ioctl 56");
    exit(-1);
}
//process_image (buffers[buf.index.]start); //
printf("%d\n",buffers[buf.index].length);
#if LOAD_BGRA  
            //We don‘t need to change Endian  
            //Because input BGRA pixel data(B|G|R|A) is same as ARGB8888 in Little Endian (B|G|R|A)  
            SDL_UpdateTexture( sdlTexture, NULL, buffer, pixel_w*4);    
#elif LOAD_RGB24|LOAD_BGR24  
            //change 24bit to 32 bit  
            //and in Windows we need to change Endian  
            CONVERT_24to32(buffer,buffer_convert,pixel_w,pixel_h);  
            SDL_UpdateTexture( sdlTexture, NULL, buffer_convert, pixel_w*4);    
#elif LOAD_YUV422P  
            SDL_UpdateTexture( sdlTexture, NULL, buffers[buf.index].start, pixel_w*2);    
#endif  
            //FIX: If window is resize  
            sdlRect.x = 0;    
            sdlRect.y = 0;    
            sdlRect.w = screen_w;    
            sdlRect.h = screen_h;    
            SDL_RenderClear( sdlRenderer );     
            SDL_RenderCopy( sdlRenderer, sdlTexture, NULL, &sdlRect);    
            SDL_RenderPresent( sdlRenderer );    
            //Delay 40ms  
            SDL_Delay(40);  
ret = ioctl (fd,VIDIOC_QBUF,&buf); 
 if(ret < 0)
{
 perror("ioctl 67");
    exit(-1);
}
}
close(fd);
return  0 ;
}

笔记本的摄像头640*480  yuv422    g++ video0.c -std=c++0x   -lSDL2 /usr/local/lib/libSDL2_image.a

以上是关于播放摄像头 sdl2.0 显示v4l2的主要内容,如果未能解决你的问题,请参考以下文章

V4L2 采用多线程采集视频 , 保存的视频播放卡顿的问题

最简单的基于FFMPEG+SDL的视频播放器 ver2 (採用SDL2.0)

android摄像头(camera)之 v4l2的c测试代码

V4L2采集图像并在LCD上显示的图像格式问题

V4L2抓取USB摄像头YUV视频数据代码

如何在Android用FFmpeg+SDL2.0解码显示图像