使用V4L2 API创建的JPEG图像为深黑色

时间:2018-12-18 01:02:58

标签: c++ jpeg sdl-2 v4l2

我正在尝试使用V4L2 API和网络摄像头拍照 图片存储为JPEG图像。当我使用SDL打开JPEG图像时,图像为黑色,为什么?我需要编辑图像的元数据吗?

我正在使用命令:

c++ final.cpp `sdl2-config --cflags --libs` -lv4l2 -lSDL2_image

使用:

alias c++='g++ -std=c++14'

v4l2-ctl -d /dev/video0 --list-formats-ext的输出:

ioctl: VIDIOC_ENUM_FMT
        Index       : 0
        Type        : Video Capture
        Pixel Format: 'MJPG' (compressed)
        Name        : Motion-JPEG
        Size: Discrete 1280x720
                  Interval: Discrete 0.033s (30.000 fps)
        Size: Discrete 160x120
                  Interval: Discrete 0.033s (30.000 fps)
        Size: Discrete 176x144
                  Interval: Discrete 0.033s (30.000 fps)
        Size: Discrete 320x240
                  Interval: Discrete 0.033s (30.000 fps)
        Size: Discrete 352x288
                  Interval: Discrete 0.033s (30.000 fps)
        Size: Discrete 640x480 <-- I'm interested in this one
                  Interval: Discrete 0.033s (30.000 fps)

图片的元数据:

ExifTool Version Number         : 10.10
File Name                       : image.jpeg
Directory                       : .
File Size                       : 600 kB
File Modification Date/Time     : 2018:12:18 02:17:57+02:00
File Access Date/Time           : 2018:12:18 02:18:00+02:00
File Inode Change Date/Time     : 2018:12:18 02:17:57+02:00
File Permissions                : rw-rw----
File Type                       : JPEG
File Type Extension             : jpg
MIME Type                       : image/jpeg
Image Width                     : 640
Image Height                    : 480
Encoding Process                : Baseline DCT, Huffman coding
Bits Per Sample                 : 8
Color Components                : 3
Y Cb Cr Sub Sampling            : YCbCr4:2:2 (2 1)
Image Size                      : 640x480
Megapixels                      : 0.307

源代码:

#include <iostream>
#include <unistd.h>
#include <fcntl.h>
#include <linux/videodev2.h>
#include <sys/ioctl.h>
#include <string.h>
#include <sys/mman.h>
#include <SDL.h>
#include <SDL_image.h>
#include <thread>
#include <chrono>

using namespace std;

int main(void){
    int fd;
    if((fd = open("/dev/video0", O_RDWR)) < 0){
        perror("open");
        exit(1);
    }

    struct v4l2_capability cap;
    if(ioctl(fd, VIDIOC_QUERYCAP, &cap) < 0){
        perror("VIDIOC_QUERYCAP");
        exit(1);
    }
    if(!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)){
        fprintf(stderr, "The device does not handle single-planarvideo capture.\n");
        exit(1);
    }

    struct v4l2_format format;
    format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    format.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;
    format.fmt.pix.width = 640;
    format.fmt.pix.height = 480;
    if(ioctl(fd, VIDIOC_S_FMT, &format) < 0){
        perror("VIDIOC_S_FMT");
        exit(1);
    }

    struct v4l2_requestbuffers bufrequest;
    bufrequest.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    bufrequest.memory = V4L2_MEMORY_MMAP;
    bufrequest.count = 1;
    if(ioctl(fd, VIDIOC_REQBUFS, &bufrequest) < 0){
        perror("VIDIOC_REQBUFS");
        exit(1);
    }

    struct v4l2_buffer bufferinfo;
    memset(&bufferinfo, 0, sizeof(bufferinfo));
    bufferinfo.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    bufferinfo.memory = V4L2_MEMORY_MMAP;
    bufferinfo.index = 0;
    if(ioctl(fd, VIDIOC_QUERYBUF, &bufferinfo) < 0){
        perror("VIDIOC_QUERYBUF");
        exit(1);
    }

    void* buffer_start = mmap(
    NULL,
    bufferinfo.length,
    PROT_READ | PROT_WRITE,
    MAP_SHARED,
    fd,
    bufferinfo.m.offset);
    if(buffer_start == MAP_FAILED){
        perror("mmap");
        exit(1);
    }
    memset(buffer_start, 0, bufferinfo.length);

    struct v4l2_buffer bufferinfo2;
    memset(&bufferinfo2, 0, sizeof(bufferinfo2));
    bufferinfo2.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    bufferinfo2.memory = V4L2_MEMORY_MMAP;
    bufferinfo2.index = 0;
    int type = bufferinfo2.type;
    if(ioctl(fd, VIDIOC_STREAMON, &type) < 0){
        perror("VIDIOC_STREAMON");
        exit(1);
    }
    if(ioctl(fd, VIDIOC_QBUF, &bufferinfo2) < 0){
        perror("VIDIOC_QBUF");
        exit(1);
    }
    if(ioctl(fd, VIDIOC_DQBUF, &bufferinfo2) < 0){
        perror("VIDIOC_QBUF");
        exit(1);
    }
    if(ioctl(fd, VIDIOC_STREAMOFF, &type) < 0){
        perror("VIDIOC_STREAMOFF");
        exit(1);
    }

    int jpgfile;
    if((jpgfile = open("/home/Micke/Desktop/image.jpeg", O_WRONLY | O_CREAT, 0660)) < 0){
        perror("open");
        exit(1);
    }
    write(jpgfile, buffer_start, bufferinfo2.length);
    close(jpgfile);

    this_thread::sleep_for(chrono::seconds(6));

    SDL_Init(SDL_INIT_VIDEO);

    SDL_Window * window = SDL_CreateWindow("SDL2 Displaying Image",
    SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 1300, 1300, 0);

    SDL_Renderer * renderer = SDL_CreateRenderer(window, -1, 0);
    SDL_Surface * image = IMG_Load("/home/Micke/Desktop/image.jpeg");
    SDL_Texture * texture = SDL_CreateTextureFromSurface(renderer, image);

    bool quit = false;
    SDL_Event event;

    while(!quit){

        SDL_RenderCopy(renderer, texture, NULL, NULL);
        SDL_RenderPresent(renderer);

        while(SDL_PollEvent(&event)){
            if(event.type == SDL_QUIT){
                quit = true;
            }
        }
    }

    SDL_DestroyTexture(texture);
    SDL_FreeSurface(image);
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);

    SDL_Quit();

    close(fd);
    return EXIT_SUCCESS;
}

解决方案:

format.fmt.pix.width = 480;
format.fmt.pix.height = 640;

0 个答案:

没有答案