使用Linux的V4L2编程部分参考:
使用YUY2(YUV)与RGB之间相互转化参考:
本文是基于Linux开发板的V4L2摄像头调用程序,包括YUYV解码为RGB,以及将摄像头数据显示在开发板屏幕上。代码未封装,可直接在linux下编译使用。
工作流程:打开设备 —> 检查和设置设备属性 —> 设置帧格式 —> 设置一种输入输出方法(缓冲区管理) —> 循环获取数据 —> 数据解码 —> 显示在lcd上 —> 关闭设备。
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/videodev2.h>
#include <string.h>
#include <sys/mman.h>
#include <errno.h>
#include <pthread.h>
#include <linux/fb.h>
#include <stdbool.h>
unsigned int *lcdptr = NULL; //lcd映射内存首地址
int lcd_width; //lcd屏幕宽
int lcd_height; //lcd屏幕高
int camera_width = 640; //camere屏幕宽
int camera_height = 480; //camera屏幕高
void lcd_show_rgb(unsigned char *rgbdata,int width,int height); //在lcd上显示
int YUV2RGB(void* pYUV, void* pRGB, int width, int height, bool alphaYUV, bool alphaRGB); //YUYV格式转换为RGB格式
int main(void)
{
int lcdfd = open("/dev/fb0", O_RDWR); //打开 LCD屏幕
if(lcdfd < 0)
{
perror("/dev/fb0");
exit(-1);
}
//获取屏幕宽高
struct fb_var_screeninfo lcdvar;
ioctl(lcdfd, FBIOGET_VSCREENINFO , &lcdvar);
lcd_width = lcdvar.xres;
lcd_height = lcdvar.yres;
//4 = 透明度 + RGB
lcdptr = (unsigned int *)mmap( NULL, lcd_width*lcd_height*4 , //映射fb内存空间长度
PROT_READ | PROT_WRITE, //可读可写
MAP_SHARED, //进程间共享机制
lcdfd, //lcd的文件描述符
0);
//1.打开摄像头设备
int fd = open("/dev/video1",O_RDWR); //video0 或 video1
if(fd < 0)
{
perror("打开设备失败");
return -1;
}
//2.获取摄像头支持的格式 ioctl(文件描述符,命令,与命令对应的结构体)
//查询并显示所有支持的格式:VIDIOC_ENUM_FMT ,获取对应结构体
/*struct v4l2_fmtdesc
{
u32 index; // 要查询的格式序号,应用程序设置
enum v4l2_buf_type type; // 帧类型,应用程序设置
u32 flags; // 是否为压缩格式
u8 description[32]; // 格式名称
u32 pixelformat; // 格式
u32 reserved[4]; // 保留
};
*/
//3.配置摄像头采集格式
//查看或设置当前格式: VIDIOC_G_FMT, VIDIOC_S_FMT
/*
struct v4l2_format
{
enum v4l2_buf_type type; // 帧类型,应用程序设置
union fmt
{
struct v4l2_pix_format pix; // 视频设备使用
struct v4l2_window win;
struct v4l2_vbi_format vbi;
struct v4l2_sliced_vbi_format sliced;
u8 raw_data[200];
};
};
struct v4l2_pix_format
{
u32 width; // 帧宽,单位像素
u32 height; // 帧高,单位像素
u32 pixelformat; // 帧格式
enum v4l2_field field;
u32 bytesperline;
u32 sizeimage;
enum v4l2_colorspace colorspace;
u32 priv;
};
*/
struct v4l2_format vfmt;
vfmt.type=V4L2_BUF_TYPE_VIDEO_CAPTURE; //设置类型摄像头采集
vfmt.fmt.pix.width = camera_width; //设置宽
vfmt.fmt.pix.height = camera_height; //设置高
vfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; //根据摄像头设置格式
int ret;
ret = ioctl(fd, VIDIOC_S_FMT, &vfmt);
if(ret < 0)
{
perror("设置格式失败");
}
printf("Current data format information:\n\twidth:%d\n\theigh