微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何使用 YUV SDL_overlay 保存图像?

如何解决如何使用 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 举报,一经查实,本站将立刻删除。