Linux限制摄像头buffer,Linux的帧缓冲(Frame Buffer)之三:LCD上显示摄像头

一个简单的应用程序,来实现在LCD上显示当前camera的图像数据,也可以根据键盘输入保存摄像头数据到BMP图片中。

(1) 如下:

文件头和全局变量:

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

static unsigned int capframe = 0;//保存的图片计数

static char filename[30];//保存的图片文件名

FILE *bmpFile;//保存图片时创建的文件指针

unsigned char bmp_head_t[] = {//66字节的BMP位图头

0x42,0x4d,0x42,0x58,0x02,0x00,0x00,0x00,0x00,0x00,

0x42,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0xf0,0x00,

0x00,0x00,0x40,0x01,0x00,0x00,0x01,0x00,0x10,0x00,

0x03,0x00,0x00,0x00,0x00,0x58,0x02,0x00,0x00,0x00,

0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,

0x00,0x00,0x00,0x00,0x00,0xf8,0x00,0x00,0xe0,0x07,

0x00,0x00,0x1f,0x00,0x00,0x00

};

static char *vf_buff;//从摄像头读取数据保存的内存指针

static int fb_bpp;//帧缓冲设备的每像素位数

unsigned char bmp_head[54];//54字节的BMP位图头

static int cam_fp = -1;//打开的摄像头句柄

static int fb_fp = -1;//打开的帧缓冲句柄

static char *fb_addr = NULL;//帧缓冲mmap的映射返回地址

static char *cam_name = "/dev/video1";//摄像头设备路径和名字

int width=0;//帧缓冲的resolution width

int height=0;//帧缓冲的resolution height

主函数如下:

int main(int argc, char *argv[])

{

struct timeval tv1;//监控键盘输入的select时间参数

unsigned long size;//一帧画面的字节数

int index=0;//V4L2 input索引号

struct v4l2_capability cap;//V4L2设备功能结构体变量

struct v4l2_input i;//V4L2设备输入信息

struct v4l2_framebuffer fb;//V4L2的一帧设备缓存

int on=1;//控制V4L2设备overlay的参数

int tmp;

fd_set fds1;//监控键盘输入的select fd_set变量

int fd;//监控键盘输入的select句柄

char cmd[256];//存储从键盘读入的字符串

cam_fp = cam_init();//获得摄像头句柄

fb_fp = fb_init();//获得帧缓冲句柄

size=width*height*fb_bpp/8;

if((tmp=ioctl(cam_fp, VIDIOC_QUERYCAP, &cap))<0) {//查询驱动功能

printf("VIDIOC_QUERYCAP error, ret=0x%x\n",tmp);

goto err;

}

printf("Driver:%s, Card:%s, cap=0x%x\n",cap.driver,cap.card,cap.capabilities);

memset(&i, 0, sizeof(i));

i.index=index;

if(ioctl(cam_fp, VIDIOC_ENUMINPUT, &i)<0)//枚举输入源

goto err;

printf("input name:%s\n",i.name);

index=0;

if(ioctl(cam_fp, VIDIOC_S_INPUT, &index)<0)//设置输入源

goto err;

if(ioctl(cam_fp, VIDIOC_S_OUTPUT, &index)<0)//设置输出源

goto err;

if(ioctl(cam_fp, VIDIOC_G_FBUF, &fb)<0)//获取V4L2设备FB属性参数

goto err;

printf("g_fbuf:capabilities=0x%x,flags=0x%x,width=%d,height=%d\npixelformat=0x%x,bytesperline=%d,colorspace=%d,base=0x%x\n",

fb.capability,fb.flags,fb.fmt.width,fb.fmt.height,fb.fmt.pixelformat,

fb.fmt.bytesperline,fb.fmt.colorspace,fb.base);

fb.capability = cap.capabilities;//V4L2设备功能赋值给V4L2的FB功能属性

fb.fmt.width =width;//LCD的FB宽度赋值给V4L2的FB宽度

fb.fmt.height = height;//LCD的FB高度赋值给V4L2的FB高度

fb.fmt.pixelformat = (fb_bpp==32)?V4L2_PIX_FMT_BGR32:V4L2_PIX_FMT_RGB565;//赋值V4L2的FB像素位数

if(ioctl(cam_fp, VIDIOC_S_FBUF, &fb)<0)//设置新的FB属性给摄像头

goto err;

on = 1;

if(ioctl(cam_fp, VIDIOC_OVERLAY, &on)<0)//使能摄像头的overlay

goto err;

vf_buff = (char*)malloc(size);

if(vf_buff==NULL)

goto err;

if(fb_bpp==16){//16位BMP

*((unsigned int*)(bmp_head_t+18)) = width;

*((unsigned int*)(bmp_head_t+22)) = height;

*((unsigned short*)(bmp_head_t+28)) = 16;

}else{

bmp_head[0] = 'B';

bmp_head[1] = 'M';

*((unsigned int*)(bmp_head+2)) = (width*fb_bpp/8)*height+54;//整个位图大小

*((unsigned int*)(bmp_head+10)) = 54;//从54字节开始存图像

*((unsigned int*)(bmp_head+14)) = 40;//图像描述信息块的大小

*((unsigned int*)(bmp_head+18)) = width;

*((unsigned int*)(bmp_head+22)) = height;

*((unsigned short*)(bmp_head+26)) = 1;//图像的plane总数

*((unsigned short*)(bmp_head+28)) = fb_bpp;

*((unsigned short*)(bmp_head+34)) = (width*fb_bpp/8)*height;//图像数据区大小

}

while(1)

{

if (!read_data(cam_fp, vf_buff, width, height, fb_bpp))//读摄像头数据到vf_buff

{

printf("read error\n");

}

memcpy(fb_addr,vf_buff,width*height*fb_bpp/8);//将读到的图像数据从内存拷贝到帧缓冲地址

fd=0;//键盘句柄

tv1.tv_sec=0;

tv1.tv_usec=0;//无限等待

FD_ZERO(&fds1);

FD_SET(fd,&fds1);//绑定句柄跟监控对象

select(fd+1,&fds1,NULL,NULL,&tv1);//监控键盘输入

if(FD_ISSET(fd,&fds1))//如果键盘有输入

{

memset(cmd,0,sizeof(cmd));

read(fd,cmd,256);//读取键盘输入的字符

if(strncmp(cmd,"quit",4)==0){//如果键盘输入quit

printf("-->quit\n");

on=0;

if(ioctl(cam_fp, VIDIOC_OVERLAY, &on)<0)//关掉V4L2设备的overlay

goto err;

close(fb_fp);

close(cam_fp);//释放FB跟摄像头的句柄

return 0;

}else if(strncmp(cmd,"capt",4)==0){//如果键盘输入capt

printf("-->capture\n");

printf("write to img --> ");

writeImageToFile(size);//把FB数据保存到位图中

printf("OK\n");

}

}

}

err:

if (cam_fp)

close(cam_fp);

if (fb_fp)

close(fb_fp);

return 1;

}

(2)子函数叙述如下。FB和摄像头的初始化如下:

static inline int fb_init(void)

{

int dev_fp = -1;

int fb_size;

struct fb_var_screeninfo vinfo;

dev_fp = open("/dev/graphics/fb0", O_RDWR);

if (dev_fp < 0) {

perror("/dev/fb0");

return -1;

}

if (ioctl(dev_fp, FBIOGET_VSCREENINFO, &vinfo)) {//获取FB基本信息

printf("Error reading variable information.\n");

exit(1);

}

width=vinfo.xres;

height=vinfo.yres;

fb_bpp=vinfo.bits_per_pixel;//将FB值赋值给全局变量

if(fb_bpp==24) fb_bpp=32;

fb_size=width*height*fb_bpp/8;//一帧FB的字节大小

if ((fb_addr = (char*)mmap(0, fb_size,

PROT_READ | PROT_WRITE, MAP_SHARED, dev_fp, 0)) < 0) {//从文件的0位置开始在内存中自动映射fb_size大小空间

perror("mmap()");

return -1;

}

printf("%dx%d bpp:%d mmaped 0x%08x\n",width,height,fb_bpp,fb_addr);

return dev_fp;

}

static inline int cam_init(void)

{

int dev_fp = -1;

dev_fp = open(cam_name, O_RDWR);

if (dev_fp < 0) {

printf("error open %s\n",cam_name);

return -1;

}

return dev_fp;

}

从摄像头读数据到内存中:

static inline int read_data(int fp, char *buf, int width, int height, int bpp)

{

int ret=0;

if ((ret = read(fp, buf, (width*height*bpp/8))) != (width*height*bpp/8)) {

printf("read %d--0x%x\n",ret,ret);

return 0;

}

return ret;

}

把内存中图像存储成BMP

void writeImageToFile(unsigned int size)

{

capframe++; //图像序号计数

sprintf(filename,"/tmp/0%d.bmp",capframe); //位图的文件名

bmpFile=fopen(filename, "w+");//可写可追加内容的方式创建文件

if(fb_bpp == 16)

fwrite(bmp_head_t,1,66,bmpFile);

else

fwrite(bmp_head,1,54,bmpFile);//往文件中写入BMP位图头

fwrite(vf_buff,1,size,bmpFile);//在继续往文件中追加位图数据

fclose(bmpFile);

}

(3)使用的makefile如下:

CROSS_COMPILE = /home/zhangcheng/gcc/arm-2008q3/bin/arm-linux-

CC = $(CROSS_COMPILE)gcc

cam2fb: cam2fb.c

$(CC) -o cam2fb cam2fb.c -static

执行make编译后,看到属性是不可执行属性,所以先将其属性改成可执行。通过adb将这个可执行文件拷贝入/data内,先修改其属性后,再用./执行即可。过一会儿,即可在LCD上显示camera捕获的动态图像,同时adb显示如下:

(4)该程序还可以实现输入键盘字符quit退出,输入键盘字符capt保存当前图片到某个目前下成一个BMP,由于没有键盘输入,该部分无法验证。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在C++中,您可以使用OpenCV的`cv::Mat`类和缓冲Frame Buffer)之间进行转换。下面是一些示例代码,演示了如何将`cv::Mat`与缓冲之间进行相互转换。 ```cpp #include <opencv2/opencv.hpp> int main() { // 获取缓冲的宽度和高度 int width = 1920; int height = 1080; // 创建一个空的cv::Mat对象 cv::Mat frame; // 创建一个缓冲,用于存储图像数据 unsigned char* frameBuffer = new unsigned char[width * height * 3]; // 假设每个像素有3个通道 // 将缓冲数据复制到cv::Mat对象中 frame = cv::Mat(height, width, CV_8UC3, frameBuffer); // 假设每个像素有3个通道 // 在cv::Mat对象上进行图像处理 cv::cvtColor(frame, frame, cv::COLOR_BGR2GRAY); // 将cv::Mat对象转换为缓冲数据 unsigned char* convertedFrameBuffer = frame.data; // 进行其他操作... // 释放缓冲内存 delete[] frameBuffer; return 0; } ``` 在这个示例中,我们首先创建了一个空的`cv::Mat`对象,然后创建了一个缓冲数组用于存储图像数据。接下来,我们使用`cv::Mat`的构造函数将缓冲数据复制到`cv::Mat`对象中。然后,我们可以在`cv::Mat`对象上进行图像处理操作,例如转换为灰度图像。最后,我们可以通过访问`cv::Mat`对象的`data`成员将其转换回缓冲数据。 请注意,示例中的代码假设每个像素有3个通道(BGR格式),如果您使用其他图像格式,需要根据实际情况进行调整。另外,确保在将缓冲数据复制到`cv::Mat`对象时,分配的内存大小和数据布局与缓冲一致。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值