/*
* 这段代码的功能是使用Linux下的库函数拍一张照片,并且保存起来
*/
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <linux/videodev2.h>
#include "jpeg_enc.h"
#define VW 320
#define VH 240
#define SER_PORT 4455
#define BUF_SIZE 1024
int main(int argc,char *argv[])
{
int devFd,ret;
if(argc!=2)
{
fprintf(stderr,"use:[%s][DEV]\n",argv[0]);
return 1;
}
/******************* open device *********************/
devFd=open(argv[1],O_RDWR);
if(devFd==-1)
{
perror(argv[1]);
return -1;
}
/**************** 查询当前设备支持什么格式 *********************/
struct v4l2_fmtdesc fmtdc;
fmtdc.index=0;
fmtdc.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
ret=ioctl(devFd,VIDIOC_ENUM_FMT,&fmtdc);
if(ret==-1)
{
perror("ENUM FMT");
close(devFd);
return -2;
}
printf("idx:%d flags:%d fmtName:%s\n",fmtdc.index,fmtdc.flags,fmtdc.description);
//set fmt
struct v4l2_format fmt;
fmt.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;//流式数据
fmt.fmt.pix.width =VW;
fmt.fmt.pix.height=VH;
fmt.fmt.pix.pixelformat=fmtdc.pixelformat;
ret=ioctl(devFd,VIDIOC_S_FMT,&fmt);
if(ret==-1)
{
perror("set fmt");
return -4;
}
printf("idx:%d flags:%d fmtName:%s\n",fmtdc.index,fmtdc.flags,fmtdc.description);
if(fmtdc.pixelformat!=V4L2_PIX_FMT_YUYV)
{
printf("format is not YUYV\n");
return ;
}
/***************** 申请采集图形的缓存与映射缓存到用户空间 ******************************/
//用于申请缓存的结构体
struct v4l2_requestbuffers buffers;
buffers.type =V4L2_BUF_TYPE_VIDEO_CAPTURE;
buffers.memory =V4L2_MEMORY_MMAP;
buffers.count =1;
ret=ioctl(devFd,VIDIOC_REQBUFS,&buffers);
if(ret==-1)
{
perror("request buffers");
close(devFd);
return;
}
//将申请到的缓存映射到用户空间,这里的摄像头驱动应该是标准驱动
//用于配置缓存信息的结构体 struct v4l2_buffer - video buffer info
struct v4l2_buffer buf;
memset(&buf,0,sizeof(buf));
buf.index =0;
buf.type =V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory=V4L2_MEMORY_MMAP;
//请求一帧缓存
ret=ioctl(devFd,VIDIOC_QUERYBUF,&buf);
if(ret==-1)
{
perror("query buffer");
close(devFd);
return -5;
}
//把缓存空间映射到用户空间的mapAddr
//通过mapAddr访问图像数据
void *mapAddr = NULL;
int mapAddrLen;
mapAddr = mmap(NULL,buf.length,PROT_READ,MAP_SHARED,devFd,buf.m.offset);
if(mapAddr==MAP_FAILED)
{
perror("mmap mem");
close(devFd);
return -6;
}
mapAddrLen = buf.length;
//将其放入采集队列
ret=ioctl(devFd,VIDIOC_QBUF,&buf);
if(ret==-1)
{
munmap(mapAddr,mapAddrLen);
perror("buffer in queue");
close(devFd);
return -7;
}
//打开摄像头
enum v4l2_buf_type type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
ret=ioctl(devFd,VIDIOC_STREAMON,&type);
if(ret==-1)
{
munmap(mapAddr,mapAddrLen);
perror("start video");
close(devFd);
return -8;
}
printf("camera starts successfully...\n");
printf("snap...\n");
/*******************采集图像数据**************************************/
buf.type =V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory=V4L2_MEMORY_MMAP;
//out queue <如果没采集好 则阻塞>
ret=ioctl(devFd,VIDIOC_DQBUF,&buf);
if(ret==-1)
{
perror("get yuv data");
return 0;
}
char picData[(VW)*(VH)*4];
if(buf.length < (VW)*(VH)*4)
{
memcpy(picData,mapAddr,buf.length);
printf("buf.legth = %d\n",buf.length);
}
else
{
perror("picData[] is too smallto recv data\n");
printf("buf.legth = %d\n",buf.length);
return -9;
}
char jpegData[(VW)*(VH)*4];
int jpegLen = encode_image(mapAddr,jpegData,20,VW,VH);
int jFd = open("j.jpeg",O_RDWR,O_CREAT|O_TRUNC);
if(jFd < 0)
{
perror("open j.jpeg");
close(devFd);
munmap(mapAddr,mapAddrLen);
return -10;
}
ret = write(jFd,jpegData,jpegLen);
close(jFd);
close(devFd);
munmap(mapAddr,mapAddrLen);
return 0;
}