#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <asm/types.h> /* for videodev2.h */
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <error.h>
#include <errno.h>
#include <malloc.h>
#include <linux/fb.h>
#include <linux/videodev2.h>
#include <assert.h>
#include "v4l2_device.h"
struct buffer *buffers=NULL;
/********************************
*函数功能:初始化摄像头+显示摄像头信息
*********************************/
void init_device(Cam_dev *camdev,Fb_dev *myfb)
{
unsigned int n_buffers;
struct v4l2_requestbuffers req;
struct v4l2_capability cap;
struct v4l2_fmtdesc fmtdesc;
struct v4l2_format fmt;
//0、打开摄像头
if((camdev->cfd=open(dev_name,O_RDWR|O_NONBLOCK,0))<0)
{
printf("device:%s open failed!!\n",dev_name);
exit(-1);
}
//1、查询摄像头信息并打印
if (ioctl(camdev->cfd, VIDIOC_QUERYCAP, &cap) == -1)
{
printf("Error opening device %s: unable to query device.\n",dev_name);
exit(-1);
}
else
{
/*打印信息*/
printf("*************Camera-params***************\n");
printf("driver:\t\t%s\n", cap.driver);
printf("card:\t\t%s\n", cap.card);
printf("bus_info:\t%s\n", cap.bus_info);
printf("version:\t%d\n", cap.version);
printf("capabilities:\t%x\n", cap.capabilities);
printf("*****************end*********************\n");
/*检测摄像头是否支持图像抓取功能*/
if ((cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == V4L2_CAP_VIDEO_CAPTURE)
{
printf("Device %s: supports capture.\n",dev_name);
}
/*检测摄像头是否支持视频流*/
if ((cap.capabilities & V4L2_CAP_STREAMING) == V4L2_CAP_STREAMING)
{
printf("Device %s: supports streaming.\n",dev_name);
}
}
//2、打印所有支持格式
///////////////////////////////////////////////////////////////
printf("Support format:\n");
fmtdesc.index = 0;
fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
while(ioctl(camdev->cfd,VIDIOC_ENUM_FMT,&fmtdesc)!=-1)
{
printf("\t%d.%s\n",fmtdesc.index+1,fmtdesc.description);
fmtdesc.index++;
}
/////////////////////////////////////////////////////////////////
//3、设置摄像头格式
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.height = myfb->iHeight;
fmt.fmt.pix.width = myfb->iWidth;
fmt.fmt.pix.field = V4L2_FIELD_ANY;//V4L2_FIELD_INTERLACED;
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
if (-1 == ioctl(camdev->cfd, VIDIOC_S_FMT, &fmt))
{
printf("VIDIOC_S_FMT error!\n");
exit(-1);
}
if(ioctl(camdev->cfd, VIDIOC_G_FMT, &fmt) == -1)
{
printf("Unable to get format\n");
exit(-1);
}
printf("fmt.type:\t\t%d\n",fmt.type);
printf("pix.pixelformat:\t%c%c%c%c\n",fmt.fmt.pix.pixelformat & 0xFF, (fmt.fmt.pix.pixelformat >> 8) & 0xFF,(fmt.fmt.pix.pixelformat >> 16) & 0xFF, (fmt.fmt.pix.pixelformat >> 24) & 0xFF);
printf("pix.height:\t\t%d\n",fmt.fmt.pix.height);
printf("pix.width:\t\t%d\n",fmt.fmt.pix.width);
printf("pix.field:\t\t%d\n",fmt.fmt.pix.field);
//保存摄像头图像像素信息
camdev->cWidth = fmt.fmt.pix.width;
camdev->cHeight = fmt.fmt.pix.height;
camdev->cLineBytes = fmt.fmt.pix. bytesperline;
camdev->cTotalBytes = fmt.fmt.pix. sizeimage;
//4、请求四个缓冲帧
req.count = REBUF_CNT;
req.memory = V4L2_MEMORY_MMAP;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if(ioctl(camdev->cfd,VIDIOC_REQBUFS,&req)==-1)
{
printf("request for buffers error!\n");
}
if (req.count < 2)
{
printf("Insufficient buffer memory on %s\n",dev_name);
exit(-1);
}
//2、分配图像缓冲结构 (mmap for buffers)
buffers = calloc(req.count, sizeof (struct buffer));
if (!buffers)
{
printf ("Out of memory: error!\n");
exit(-1);
}
//3、把内核空间中的图像缓冲区映射到用户空间
for (n_buffers = 0; n_buffers < req.count; ++n_buffers)
{
struct v4l2_buffer buf;
CLEAR(buf);
buf.index = n_buffers;
buf.memory = V4L2_MEMORY_MMAP;
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
/*获取要映射屏幕大小*/
if (-1 == ioctl(camdev->cfd, VIDIOC_QUERYBUF, &buf))
{
printf ("VIDIOC_QUERYBUF error!\n");
exit(-1);
}
/*这里的输出是为了检查有关参数的大小*/
camdev->cTotalBytes = buf.length;
buffers[n_buffers].length = buf.length;
buffers[n_buffers].start =
mmap(NULL /* start anywhere */,
buf.length,
PROT_READ | PROT_WRITE /* required */,
MAP_SHARED /* recommended */,
camdev->cfd, buf.m.offset);
/*不成功则退出*/
if (MAP_FAILED == buffers[n_buffers].start)
{
printf ("mmap error!\n");
exit(-1);
}
}
/*将缓冲帧放入队列*/
for (n_buffers = 0; n_buffers < req.count; ++n_buffers)
{
struct v4l2_buffer buf;
CLEAR(buf);
buf.index = n_buffers;
buf.memory = V4L2_MEMORY_MMAP;
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (-1 == ioctl(camdev->cfd, VIDIOC_QBUF, &buf))
{
printf ("VIDIOC_QBUF error!\n");
exit(-1);
}
}
camdev->displaybuf =(char*)malloc(camdev->cTotalBytes);
}
/********************************
*函数功能:启动捕获图像
*********************************/
void start_capture(int cfd)
{
/*帧类型,应用程序设置 */
enum v4l2_buf_type type;
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
/*启动数据流*/
if (-1 == ioctl(cfd, VIDIOC_STREAMON, &type))
{
printf ("VIDIOC_STREAMON error!\n");
exit(-1);
}
printf ("Start Video Capturing!\n");
}
void display_pic(Cam_dev *camdev,Fb_dev *myfb)
{
struct v4l2_buffer buf;
unsigned char* ptmp;
unsigned long i,j;
CLEAR (buf);
buf.memory = V4L2_MEMORY_MMAP;
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
/*取出一缓冲帧*/
if (-1 == ioctl(camdev->cfd, VIDIOC_DQBUF, &buf))
{
printf(" VIDIOC_DQBUF error!\n");
exit(-1);
}
/*检查缓冲帧是否有效*/
assert(buf.index < 4);
/*图片格式转换:YUV422->RGB565*/
ptmp = (unsigned char*)buffers[buf.index].start;
Pyuv422torgb565(ptmp,camdev->displaybuf,camdev->cHeight,camdev->cWidth);
/*图像放大后LCD显示*/
//PicZoomF(camdev,myfb);
/*小图像居中显示*/
PicMerge(camdev,myfb);
if (-1 == ioctl(camdev->cfd, VIDIOC_QBUF, &buf))
{
printf("VIDIOC_QBUF error!\n");
exit(-1);
}
}
/*
*函数功能:居中显示小的图像
*/
int PicMerge(Cam_dev *camdev,Fb_dev *myfb)
{
int i;
int iX,iY;
unsigned char *pucSrc;
unsigned char *pucDst;
iX = (myfb->iWidth -camdev->cWidth )/2;
iY = (myfb->iHeight -camdev->cHeight )/2;
//指向放缩后的图像
pucSrc = camdev->displaybuf;
//计算空出来的起始的空格
pucDst = myfb->fb_addr + iY * myfb->iLineBytes + iX *myfb->iBpp/8;
for (i = 0; i <camdev->cHeight; i++)
{
memcpy(pucDst, pucSrc, camdev->cLineBytes);
pucSrc += camdev->cLineBytes;
pucDst += myfb->iLineBytes;
}
return 0;
}
int PicZoomF(Cam_dev *camdev,Fb_dev *myfb)
{
unsigned long dwDstWidth = myfb->iWidth;
unsigned long* pdwSrcXTable;
unsigned long x;
unsigned long y;
unsigned long dwSrcY;
unsigned char *pucDest;
unsigned char *pucSrc;
unsigned long dwPixelBytes =myfb->iBpp/2;
//创建了放一行像素的空间
pdwSrcXTable = malloc(sizeof(unsigned long) * dwDstWidth);
if (NULL == pdwSrcXTable)