avi视频协议的理解


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <malloc.h>
#include <wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>

#define JPEG_MAX_SIZE 2000000   //JPEG图像最大字节数
#define JPEG_NUM 400 //JPEG图像数量
static int nframes;           //总帧数
static int totalsize;         //帧的总大小

int main(void){

	struct avi{
	    struct riff{
			unsigned char id[4];
			unsigned int size;
			unsigned char type[4];
		}r1;
		
		
	    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即可
			}a1;
			
			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;      
				}s1;
				
			    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即可
				}q1;
				
			}w1;
			
		}a1;
		
		struct movi{
			unsigned char id[4];
			unsigned int size;
			unsigned char type[4];
		}movi1;
		
	}HEAD;
	

	//--------------------------------------------------------------------------------------	
	FILE *fp_jpg;
	FILE *fp;
	int filesize;
	unsigned char jpg_data[JPEG_MAX_SIZE];
	
	char filename[10];
	int i = 0;
	
	fp= fopen("sample.avi","wb");
    
	//AVI文件偏移量设置到movi list head后,从该位置向后依次写入JPEG数据

    fseek(fp,sizeof(HEAD),SEEK_SET);
	//--------------------------------------------------------
	
	for (i = 0; i < JPEG_NUM; i++)
	{
		memset(filename, 0, 10);
		memset(jpg_data, 0, JPEG_MAX_SIZE);
		
		sprintf(filename, "%d", i);  //int转字符
		fp_jpg = fopen(filename, "rb");
		
		if (fp_jpg != NULL)
		{
			/*获取JPEG数据大小*/
			fseek(fp_jpg, 0, SEEK_END);
			filesize = ftell(fp_jpg);
			fseek(fp_jpg, 0, SEEK_SET);
			
			/*将JPEG数据读到缓冲区*/
			fread(jpg_data, filesize, 1, fp_jpg);
			
			/*将JPEG数据写入AVI文件*/
			unsigned char tmp[4] = {'0', '0', 'd', 'c'};  //00dc = 压缩的视频数据
			
			fwrite(tmp, 4, 1, fp);    //写入是否是压缩的视频数据信息
			fwrite(&filesize, 4, 1, fp);   //写入4字节对齐后的JPEG图像大小
			fwrite(jpg_data, filesize, 1, fp); //写入真正的JPEG数据
			
			nframes += 1;
			totalsize += filesize;
		}
		
		fclose(fp_jpg);
	}
	
	int width=1280;
	int height=720;
	
	
	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/23, 25000, 0, 0,nframes, 0, 1, 1000000, 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, 23, 0, nframes, 100000, 0xFFFFFF, 0,
				{0, 0, width, height}
			},
			{
				{'s', 't', 'r', 'f'},
				sizeof(AVI_STRF_CHUNK) - 8,
				sizeof(AVI_STRF_CHUNK) - 8,
				width, height, 1, 24,
				{'J', 'P', 'E', 'G'},
				width * height * 3, 0, 0, 0, 0
			}
		}
		
	},

	{
		{'L', 'I', 'S', 'T'},
		4 + nframes * 8 + totalsize,
		{'m', 'o', 'v', 'i'}
	}
	};
	
	
	fseek(fp, 0, SEEK_SET);
	
    fwrite(&avi_head,sizeof(avi_head),1,fp);
	
	fclose(fp);
	printf("end\n");
	
	return 0;
}

特别注意,avi没有时间戳,它的帧率由strh中的rate/scale=帧率决定,通过这个比率可以操控制作视频的快进与慢放。

下一步加入ALSA音频

可以把avi文件理解为由无数个struct结构组成的:

1. struct  avifile {  'RIFF',   'AVI',   struct. movi, struct   hdrl}     

2.  struct  hdrl {  'LIST', 'hdal', struct  avih,  struct stream0,struct stream1,struct  stream2};     

3.  struct  stream  {'LIST' , 'STRL',  struct   strh, struct   strf }

4.  struct   movi {  'LIST' ,  'movi'}

5.  n*  struct   data {  '00db' ,data}    循环写入帧数据    

在avi文件中都是按照这个镶嵌顺序顺序写入的。

1. avifile:

  struct avifile
{
          unsigned char id[4];
          unsigned int size;
          unsigned char type[4];

         struct.  movi;

          struct   hdrl       avi_hdrl;
}

2.  struct   hdrl

typedef struct   hdrl
{
    unsigned char id[4];    //块ID,固定为LIST
    unsigned int size;      //块大小,等于struct avi_hdrl_list去掉id和size的大小
    unsigned char type[4];  //块类型,固定为hdrl
    struct   avih;
    struct   stream;
}

3.  struct   avih

 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即可
}

4 . 含两个struct  strh,struct  strf

struct stream {

                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即可
    AVI_RECT_FRAME rcFrame;         //这个流在视频主窗口中的显示位置,设为{0,0,width,height}即可
},

 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即可
}

}
         

typedef struct avi_rect_frame
{
    short left;
    short top;
    short right;
    short bottom;
}AVI_RECT_FRAME;

       上面的4个结构体都是镶嵌的,在文件中都是顺序写入的,甚至可以把这几个组织称一个                     struct

5. struct   movi

 struct movi
{
    unsigned char id[4];      //块ID,固定为LIST
    unsigned int size;
    unsigned char type[4];  //固定为MOVI
}

 6. 写data

        struct   data {

               unsigned  char id[4];     //   00dc    表示第一个流为视频压缩数据

               unsigned int   len;       // 每帧数据大小

               void  *data ;         //数据

        }

最后写数据可以理解为是struct,但不用结构处理,而是直接先写4字节的00dc, 再写文件长度,最后直接写入帧数据,这样就完成一帧图片的写入,前面的几个结构需要全部要写入的总帧数和总字节数,都是在最后写入数据完成后再回写回去的。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值