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

帧缓冲显示主要步骤

  1. 打开设备文件, 比如/dev/fb0
  2. 获取framebuffer的一些信息, 比如分辨率
  3. 设置参数
  4. 映射framebuffer内存到用户空间
  5. 写入要显示的画面
/* display.h */
#ifndef DISPLAY_H
#define DISPLAY_H


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

#endif
/* 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;
}
posted @ 2019-05-12 22:15  rootming  阅读(947)  评论(0编辑  收藏  举报