如何解决如何使用 YUV SDL_overlay 保存图像?
我目前正在尝试使用一些 SDL 和 V4L2 来保存和显示我的网络摄像头(Linux 操作系统)的一些帧。问题是我找不到在本地保存帧的方法。
代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <linux/videodev2.h>
#include <stdbool.h>
#include <SDL/SDL.h>
#include <SDL/SDL_image.h>
/* Webcam image dimensions. */
int pix_w = 640;
int pix_h = 480;
int nBytes; // for SDL_YUY2_OVERLAY
/* webcam device */
const char* p_devName = "/dev/video0";
int g_fd;
/* V4L2 buffers */
void *g_buf;
struct v4l2_buffer g_bufInfo;
/* SDL surface and overlay */
SDL_Surface *p_screen = NULL;
SDL_Overlay *g_sdloverlay = NULL;
/* to trap Ctrl-C */
bool volatile goON = true;
bool openDev ()
{
g_fd = open(p_devName,O_RDWR);
if (g_fd < 0) {
perror ("Failed to open device");
return false;
}
struct v4l2_capability cap;
if (ioctl (g_fd,VIdioC_QUERYCAP,&cap) < 0) {
perror ("VIdioC_QUERYCAP Failed");
return false;
}
if (! (cap. capabilities & (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING))) {
perror ("Caps insufficient");
return false;
}
struct v4l2_format format;
format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
format.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
format.fmt.pix.width = pix_w;
format.fmt.pix.height = pix_h;
if(ioctl(g_fd,VIdioC_S_FMT,&format) < 0){
perror("VIdioC_S_FMT not supported");
return false;
}
return true;
}
bool setupBufs ()
{
struct v4l2_requestbuffers reqBufs;
reqBufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
reqBufs.memory = V4L2_MEMORY_MMAP;
reqBufs.count = 1;
if(ioctl(g_fd,VIdioC_REQBUFS,&reqBufs) < 0){
perror("VIdioC_REQBUFS");
return false;
}
memset(&g_bufInfo,sizeof(g_bufInfo));
g_bufInfo.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
g_bufInfo.memory = V4L2_MEMORY_MMAP;
g_bufInfo.index = 0;
if(ioctl(g_fd,VIdioC_QUERYBUF,&g_bufInfo) < 0){
perror("VIdioC_QUERYBUF");
return false;
}
g_buf = mmap (NULL,g_bufInfo.length,PROT_READ | PROT_WRITE,MAP_SHARED,g_fd,g_bufInfo.m.offset);
if(g_buf == MAP_Failed){
perror("mmap Failed");
return false;
}
memset(g_buf,g_bufInfo.length);
int type = g_bufInfo.type;
if(ioctl(g_fd,VIdioC_STREAMON,&type) < 0){
perror("VIdioC_STREAMON");
return false;
}
printf ("setupBufs done. Len %d\n",g_bufInfo.length);
return true;
}
bool grabNext ()
{
if(ioctl(g_fd,VIdioC_QBUF,&g_bufInfo) < 0){
perror("VIdioC_QBUF");
return false;
}
// The buffer's waiting in the outgoing queue.
if(ioctl(g_fd,VIdioC_DQBUF,&g_bufInfo) < 0){
perror("VIdioC_QBUF");
return false;
}
return 1;
}
bool streamOff ()
{
int type = g_bufInfo.type;
if(ioctl(g_fd,VIdioC_STREAMOFF,&type) < 0){
perror("VIdioC_STREAMOFF");
return false;
}
close (g_fd);
return 1;
}
bool initSDL ()
{
if (SDL_Init(SDL_INIT_VIDEO)) {
perror ("SDL init Failed");
return false;
}
p_screen = SDL_SetVideoMode (pix_w,pix_h,0);
if (!p_screen) {
perror ("SDL_SetVideoMode Failed");
return false;
}
g_sdloverlay = SDL_CreateYUVOverlay (pix_w,SDL_YUY2_OVERLAY,p_screen);
if (!g_sdloverlay) {
perror ("SDL_CreateYUVOverlay Failed");
return false;
}
return true;
}
void quitSDL ()
{
SDL_FreeYUVOverlay (g_sdloverlay);
SDL_Quit ();
}
int i = 0;
void displaySDL ()
{
SDL_LockYUVOverlay (g_sdloverlay); // Lock the image
// can avoid this if we can mmap the overlay's pixels to v4l
memcpy (g_sdloverlay-> pixels [0],g_buf,nBytes);
//printf("PIXEL_0 : %u\n",g_sdloverlay->pixels[0][0]);
//SDL_LockSurface(p_screen);
char indexfile[100];
sprintf(indexfile,"test-%d.bmp",i);
SDL_SaveBMP(p_screen,indexfile);
//SDL_UnlockSurface(p_screen);
SDL_UnlockYUVOverlay (g_sdloverlay);
i++;
SDL_Rect rect = {.x = 100,.y = 100,.w = pix_w,.h = pix_h};
SDL_displayYUVOverlay (g_sdloverlay,&rect);
}
void sigHandler (int foo)
{
(void)foo;
goON = false;
}
int main ()
{
signal (SIGINT,sigHandler);
nBytes = pix_w * pix_h * 2;
if (!openDev ()) {
return 1;
}
if (!setupBufs ()) {
return 1;
}
if (!initSDL ()) {
return 1;
}
int i =0 ;
while (goON) {
//if (i == 10)
// break;
i++;
grabNext ();
displaySDL ();
usleep (33000);
}
streamOff ();
quitSDL ();
return 0;
}
我设法保存了用于显示帧的 sdl_surface,但图像始终是全黑的。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。