c 实用化的摄像头生成avi视频程序(加入精确的时间控制)

I时间控制是指:生成了n张图片帧用了多少时间m。帧率等于n/m。对应于头文件,m等于scale,  n等于rate.为了精确,采用微秒计时。

I此程序生成的视频远好于ffmpeg,可能是此程序没有压缩数据原因吧。

现在的帧率不高,是因为只用了一个摄像头缓存区。

avi 头文件


#ifndef AVI_H
#define AVI_H
#include 
 

//FILE * avi_ks(void);
//int avi_add(FILE*fp,char *data,int size);
//int avi_end(FILE *f_file);

struct avi{
	struct riff{
		unsigned char id[4];
		unsigned int size;
		unsigned char type[4];
	}ri1;
	
	
	struct hdrl{
		unsigned char id[4];    //块ID,固定为LIST
		unsigned int size;      //块大小,等于struct avi_hdrl_list去掉id和size的大小
		unsigned char type[4];  //块类型,固定为hdrl
		
		struct avih{
			unsigned char id[4];            //块ID,固定为avih
			unsigned int size;              //块大小,等于struct avi_avih_chunk去掉id和size的大小
			unsigned int us_per_frame;      //视频帧间隔时间(以微秒为单位)
			unsigned int max_bytes_per_sec; //AVI文件的最大数据率
			unsigned int padding;           //设为0即可
			unsigned int flags;             //AVI文件全局属性,如是否含有索引块、音视频数据是否交叉存储等
			unsigned int total_frames;      //总帧数
			unsigned int init_frames;       //为交互格式指定初始帧数(非交互格式应该指定为0)
			unsigned int streams;           //文件包含的流的个数,仅有视频流时为1
			unsigned int suggest_buff_size; //指定读取本文件建议使用的缓冲区大小,通常为存储一桢图像                                            //以及同步声音所需的数据之和,不指定时设为0
			unsigned int width;             //视频主窗口宽度(单位:像素)
			unsigned int height;            //视频主窗口高度(单位:像素)
			unsigned int reserved[4];       //保留段,设为0即可
		}ah1;
		
		struct   strl{
			unsigned char id[4];    //块ID,固定为LIST
			unsigned int size;      //块大小,等于struct avi_strl_list去掉id和size的大小
			unsigned char type[4];  //块类型,固定为strl
			
			struct strh{
				unsigned char id[4];            //块ID,固定为strh
				unsigned int size;              //块大小,等于struct avi_strh_chunk去掉id和size的大小
				unsigned char stream_type[4];   //流的类型,vids表示视频流,auds表示音频流
				unsigned char codec[4];         //指定处理这个流需要的解码器,如JPEG
				unsigned int flags;             //标记,如是否允许这个流输出、调色板是否变化等,一般设为0即可
				unsigned short priority;        //流的优先级,视频流设为0即可
				unsigned short language;        //音频语言代号,视频流设为0即可
				unsigned int init_frames;       //为交互格式指定初始帧数(非交互格式应该指定为0)
				unsigned int scale;             //
				unsigned int rate;              //对于视频流,rate / scale = 帧率fps
				unsigned int start;             //对于视频流,设为0即可
				unsigned int length;            //对于视频流,length即总帧数
				unsigned int suggest_buff_size; //读取这个流数据建议使用的缓冲区大小
				unsigned int quality;           //流数据的质量指标
				unsigned int sample_size;       //音频采样大小,视频流设为0即可
				struct rcFrame{                 //这个流在视频主窗口中的显示位置,设为{0,0,width,height}即可
					
					short left;
					short top;
					short right;
					short bottom;
				} AVI_RECT_FRAME;      
			}sh1;
			
			struct strf{
				unsigned char id[4];             //块ID,固定为strf
				unsigned int size;               //块大小,等于struct avi_strf_chunk去掉id和size的大小
				unsigned int size1;              //size1含义和值同size一样
				unsigned int width;              //视频主窗口宽度(单位:像素)
				unsigned int height;             //视频主窗口高度(单位:像素)
				unsigned short planes;           //始终为1
				unsigned short bitcount;         //每个像素占的位数,只能是1、4、8、16、24和32中的一个
				unsigned char compression[4];    //视频流编码格式,如JPEG、MJPG等
				unsigned int image_size;         //视频图像大小,等于width * height * bitcount / 8
				unsigned int x_pixels_per_meter; //显示设备的水平分辨率,设为0即可
				unsigned int y_pixels_per_meter; //显示设备的垂直分辨率,设为0即可
				unsigned int num_colors;         //含义不清楚,设为0即可
				unsigned int imp_colors;         //含义不清楚,设为0即可
			}sf1;
			
		}sl1;
		
	}hd1;
	
	struct movi{
		unsigned char id[4];
		unsigned int size;
		unsigned char type[4];
	}movi1;
	
}HEAD;

#endif

主程序


#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include "Avi.h"
#include 

#define wid  1280            //摄像头图像宽度
#define hei  720             //图像高度
#define bitlen 24            //图像采样宽度
#define perframe  30          //先预估一帧率,可以为摄像头最大帧率,实际使用时的帧率小于次值
#define   jhframe  30         //准备要录像的图片帧数,控制录像的时间长度

static int nframes=0;           //总帧数
static int totalsize=0;         //总字节数


FILE * avi_ks(void) {
	
	FILE *fp = fopen("sample.avi", "w+b");
	
	fseek(fp, sizeof(HEAD), SEEK_SET);
	
	return fp;
}

int avi_add(FILE*fp, char *data, int size) {
	
	unsigned char tmp[4] = {'0', '0', 'd', 'c'};  //00dc = 压缩的视频数据
	fwrite(tmp, 4, 1, fp);    //写入是否是压缩的视频数据信息
	fwrite(&size, 4, 1, fp);   //写入4字节对齐后的JPEG图像大小
	fwrite(data, size, 1, fp); //写入真正的JPEG数据
	return 0;
}

//----------------------------------------------------------------------------------
int avi_end(FILE *f_file) {
	
	int width = wid;
	int height = hei;
	
	typedef  struct hdrl AVI_HDRL_LIST;
	typedef  struct movi AVI_LIST_HEAD;
	typedef  struct avih AVI_AVIH_CHUNK;
	typedef  struct strl AVI_STRL_LIST;
	typedef  struct strh  AVI_STRH_CHUNK;
	typedef  struct strf  AVI_STRF_CHUNK;
	typedef  struct  avi   AVI_HEAD;
	
	AVI_HEAD  avi_head = {
		
		{
			{'R', 'I', 'F', 'F'},
			4 + sizeof(AVI_HDRL_LIST) + sizeof(AVI_LIST_HEAD) + nframes * 8 + totalsize,
			{'A', 'V', 'I', ' '}
		},
		
		{
			{'L', 'I', 'S', 'T'},
			sizeof(AVI_HDRL_LIST) - 8,
			{'h', 'd', 'r', 'l'},
			{
				{'a', 'v', 'i', 'h'},
				sizeof(AVI_AVIH_CHUNK) - 8,
				1000000/perframe,width*height*bitlen*perframe/8, 0, 0, nframes,
				0, 1,width*height*bitlen/8, width, height,
				{0, 0, 0, 0}
			},
			{
				{'L', 'I', 'S', 'T'},
				sizeof(AVI_STRL_LIST) - 8,
				{'s', 't', 'r', 'l'},
				{
					{'s', 't', 'r', 'h'},
					sizeof(AVI_STRH_CHUNK) - 8,
					{'v', 'i', 'd', 's'},
					{'J', 'P', 'E', 'G'},
					0, 0, 0, 0, 
					1,         //4750
					20000,        //20000
					0, nframes,width*height*bitlen*perframe/8,10000, 0,
					{0, 0, width, height}
				},
				{
					{'s', 't', 'r', 'f'},
					sizeof(AVI_STRF_CHUNK) - 8,
					sizeof(AVI_STRF_CHUNK) - 8,
					width, height, 1,
					bitlen,
					{'J', 'P', 'E', 'G'},
					width * height *bitlen/8, 0, 0, 0, 0
				}
			}
			
		},
		
		{
			{'L', 'I', 'S', 'T'},
			4 + nframes * 8 + totalsize,
			{'m', 'o', 'v', 'i'}
		}
	};
	
	
	fseek(f_file, 0, SEEK_SET);
	
	fwrite(&avi_head, sizeof(HEAD), 1, f_file);
	

	return 0;
}


int main(void){
	int fd = open("/dev/video0", O_RDWR);
	if(fd < 0)
	{
		perror("打开设备失败");
		return -1;
	}
	struct v4l2_format vfmt;
	vfmt.type=1;
	vfmt.fmt.pix.width=wid;         
	vfmt.fmt.pix.height=hei;
	vfmt.fmt.pix.pixelformat=V4L2_PIX_FMT_MJPEG; 
	int ret = ioctl(fd, VIDIOC_S_FMT, &vfmt);
	if(ret < 0)
	{
		perror("设置格式失败");
	}
	
	struct v4l2_requestbuffers reqbuffer;
	reqbuffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	reqbuffer.count = 1; 
	reqbuffer.memory = V4L2_MEMORY_MMAP ;
	ret  = ioctl(fd, VIDIOC_REQBUFS, &reqbuffer);
	if(ret < 0)
	{
		perror("申请队列空间失败");
	}
	
	struct v4l2_buffer mapbuffer;
	unsigned char *mptr;
	unsigned int  size;
	mapbuffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	mapbuffer.index = 0;
	
	ret = ioctl(fd, VIDIOC_QUERYBUF, &mapbuffer);//查询缓冲区状态
	if(ret < 0)
	{
		perror("查询内核空间队列失败");
	}
	
	int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	ret = ioctl(fd, VIDIOC_STREAMON, &type);     //启动流
	if(ret < 0)
	{
		perror("开启失败");
	}
	
	mptr= (unsigned char *)mmap(NULL, mapbuffer.length, PROT_READ|PROT_WRITE, 
		MAP_SHARED, fd,0);       //设备映射到缓冲区内存
	size=mapbuffer.length;
	
	ret  = ioctl(fd, VIDIOC_QBUF, &mapbuffer);    //把缓冲区数据放入读队列中
	if(ret < 0)                                   
	{
		perror("放回失败");
	}
//---------------------------------------------------------------------------
	FILE *file=avi_ks();
	
	struct timeval start,end;  
	gettimeofday(&start, NULL );         //微秒记时开始
	
	
	while(nframes

 

 

 

 

 

 

你可能感兴趣的:(c语言,音视频,microsoft)