我正在尝试使用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;