V4L2捕捉画面+H264压缩视频+帧缓冲显示视频————帧缓冲显示视频

Posted rootming

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了V4L2捕捉画面+H264压缩视频+帧缓冲显示视频————帧缓冲显示视频相关的知识,希望对你有一定的参考价值。

帧缓冲显示主要步骤

  1. 打开设备文件, 比如/dev/fb0
  2. 获取framebuffer的一些信息, 比如分辨率
  3. 设置参数
  4. 映射framebuffer内存到用户空间
  5. 写入要显示的画面
/* display.c */
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <linux/fb.h>
#include <pthread.h>

#include "config.h"
#include "queue.h"
#include "display.h"

typedef enum {
    DISPLAY_STATE_STOP,
    DISPLAY_STATE_START
} eDisplayState;

static struct {
    int DevFd;
    int ScreenSize;
    uint8_t* pMmap;
    eDisplayState State;
    pthread_t DisplayThreadId;
    sQueue QueuePrivateData;
    uint32_t ScreenWidth;
    uint32_t ScreenHeight;
} sDisplayPrivateData;

static const int BufferSize = CONFIG_CAPTURE_WIDTH * CONFIG_CAPTURE_HEIGHT * 4;

extern int Yuyv2Rgb32(uint8_t* pYuv, uint8_t* pRgb, uint32_t Width, uint32_t Height);

int DisplayInit(const char* pDevName)
{
    QueueInit(&sDisplayPrivateData.QueuePrivateData);

    struct fb_fix_screeninfo FbFix;
    struct fb_var_screeninfo FbVar;

    if((sDisplayPrivateData.DevFd = open(pDevName, O_RDWR)) < 0){
        perror("Open Framebuffer Device");
        return -1;
    }

    printf("Open Framebuffer Device:%s successful!\n", pDevName);

    if(ioctl(sDisplayPrivateData.DevFd, FBIOGET_FSCREENINFO, &FbFix)){
        perror("Get Fb_fix_info error!");
        return -1;
    }
    printf("Get Fb_fix_info successful!\n");

    if(ioctl(sDisplayPrivateData.DevFd, FBIOGET_VSCREENINFO, &FbVar)){
        printf("Get Fb_var_info error!\n");
        return -1;
    }
    printf("Get Fb_var_info successful!\n");
    
    printf("Screen origin param: physics resultion %dx%d, line length: %d\n", FbVar.xres, FbVar.yres, FbFix.line_length);
    printf("Screen origin param: virtual resultion %dx%d\n", FbVar.xres_virtual, FbVar.yres_virtual);

    // FbVar.xres = CONFIG_CAPTURE_WIDTH;
    // FbVar.yres = CONFIG_CAPTURE_HEIGHT;
    FbVar.xres_virtual = CONFIG_CAPTURE_WIDTH;
    FbVar.yres_virtual = CONFIG_CAPTURE_WIDTH;

    if(ioctl(sDisplayPrivateData.DevFd, FBIOPUT_VSCREENINFO, &FbVar)) {
        printf("Set Fb_var_info error!\n");
        // return -1;
    }
    printf("Set Fb_var_info successful!\n");

    if(ioctl(sDisplayPrivateData.DevFd, FBIOGET_VSCREENINFO, &FbVar)) {
        printf("Get Fb_var_info error!\n");
        return -1;
    }
    printf("Get Fb_var_info successful!\n");
    
    printf("Screen after param: physics resultion %dx%d, line length: %d\n", FbVar.xres, FbVar.yres, FbFix.line_length);
    printf("Screen after param: virtual resultion %dx%d\n", FbVar.xres_virtual, FbVar.yres_virtual);

    sDisplayPrivateData.ScreenWidth = FbVar.xres;
    sDisplayPrivateData.ScreenHeight = FbVar.yres;

    sDisplayPrivateData.ScreenSize = FbVar.xres * FbVar.yres * (FbVar.bits_per_pixel / 8);

    printf("Screen size: %d\n", sDisplayPrivateData.ScreenSize);

    sDisplayPrivateData.pMmap = mmap(NULL, sDisplayPrivateData.ScreenSize, PROT_READ | PROT_WRITE, MAP_SHARED, sDisplayPrivateData.DevFd, 0);
    if(!sDisplayPrivateData.pMmap){
        perror("Memory Mmap error");
        return -1;
    }

    printf("Memory Mmap successful!\n");

    return 0;

}

static void* DisplayThread(void* pParam)
{
    int Ret = -1;
    sDisplayPrivateData.State = DISPLAY_STATE_START;

    uint8_t* pRgbBuffer = malloc(BufferSize);
    if(!pRgbBuffer) {
        perror("Malloc failed");
        return NULL;
    }

    while(sDisplayPrivateData.State == DISPLAY_STATE_START) {
        sQueueData QueueData;
        Ret = QueuePopData(&sDisplayPrivateData.QueuePrivateData, &QueueData);

        if(Ret) {
            continue;
        }

        Yuyv2Rgb32(QueueData.pData, pRgbBuffer, CONFIG_CAPTURE_WIDTH, CONFIG_CAPTURE_HEIGHT);
        // printf("Copy length: %d\n", BufferSize);

        // memcpy(sDisplayPrivateData.pMmap, pRgbBuffer, BufferSize);

        uint32_t CopyWidthLength = sDisplayPrivateData.ScreenWidth > CONFIG_CAPTURE_WIDTH ?
                                    CONFIG_CAPTURE_WIDTH : sDisplayPrivateData.ScreenWidth;

        for(int i = 0; i < CONFIG_CAPTURE_HEIGHT; i++) {
            memcpy(sDisplayPrivateData.pMmap + sDisplayPrivateData.ScreenWidth * 4 * i, 
                &pRgbBuffer[CONFIG_CAPTURE_WIDTH * 4 * i], 
                    CopyWidthLength * 4);
        }

        QueueCallback(&QueueData);
    }

    free(pRgbBuffer);
    DisplayStop();

    return NULL;
}

int DisplayStart(void)
{
    if(sDisplayPrivateData.State == DISPLAY_STATE_START) {
        return -1;
    }
    pthread_create(&sDisplayPrivateData.DisplayThreadId, NULL, DisplayThread, (void *)NULL);
    return 0;

}

int DisplayStop(void)
{
    if(sDisplayPrivateData.State == DISPLAY_STATE_STOP) {
        return 0;
    }
    sDisplayPrivateData.State = DISPLAY_STATE_STOP;
    pthread_join(sDisplayPrivateData.DisplayThreadId, NULL);
    munmap(sDisplayPrivateData.pMmap, sDisplayPrivateData.ScreenSize);
    close(sDisplayPrivateData.DevFd);
    printf("Display thread stop\n");
    return 0;
}
/* display.h */
#ifndef DISPLAY_H
#define DISPLAY_H


int DisplayInit(const char* pDevName);
int DisplayStart(void);
int DisplayStop(void);

#endif

以上是关于V4L2捕捉画面+H264压缩视频+帧缓冲显示视频————帧缓冲显示视频的主要内容,如果未能解决你的问题,请参考以下文章

视频压缩格式H.264中时间冗余与运动补偿问题

摄像头v4l2编写,实现视频在帧缓冲显示

如何使用 c++ 使用 v4l2 API 连续捕获 h264 视频?

音视频入门——H.264编码(宏块+片+帧)浅析

Linux应用开发第七章摄像头V4L2编程应用开发

如何 开发 v4l2 tuener驱动