c 为无声avi视频添加wave音乐(估计是全网实战具体编写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>

static int q=0;
static int sp=0;
static int aq=0;
//static int at=0;
static unsigned int vzj=0;
static unsigned int azj=0;
int main(void){
	
	struct file{
		struct riff{
			char id[4];
			unsigned int size;
			char type[4];
			
			struct hdrl{
				
				char id[4];
				unsigned int size;
				unsigned char type[4]; 
				
				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; //指定读取本文件建议使用的缓冲区大小,通常为存储一桢图像                   
					unsigned int width;             //视频主窗口宽度(单位:像素)
					unsigned int height;            //视频主窗口高度(单位:像素)
					unsigned int reserved[4];       //保留段,设为0即可
					
				}av;
				
				struct strl{
					unsigned char id[4];    //块ID,固定为LIST
					unsigned int size;      //块大小,等于struct avi_strl_list去掉id和size的大小
					unsigned char type[4];  //strl
					
					struct strh1{
						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即可
						short left;                  //这个流在视频主窗口中的显示位置,设为{0,0,width,height}即可
						short top;
						short right;
						short bottom;
					}sh1;
					struct strf1{
						unsigned char id[4];             //块ID,固定为strf
						unsigned int size;               //块大小,等于struct avi_strf_chunk去掉id和size的大小
						//_BITMAPINFOHEADER 结构
						int       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];    //指定压缩的自下而上位图的压缩类型 
						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;
				
				struct strl2{
					unsigned char id[4];    //块ID,固定为LIST
					unsigned int size;      //块大小,等于struct avi_strl_list去掉id和size的大小
					unsigned char type[4];  //strl
					
					struct  strh2{
						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即可
						short left;                  //这个流在视频主窗口中的显示位置,设为{0,0,width,height}即可
						short top;
						short right;
						short bottom;
					}sh2;
					struct  strf2{
						char id[4];        //strf
						int size; 
						short wFormatTag;       //波形音频格式类型,格式标记在 Microsoft Corporation 中注册,用于许多压缩算法,
						short nChannels;        //声道数                                                    85= WAVE_FORMAT_PCM
						int nSamplesPerSec;  //采样率,以每秒样本数 (赫) ,常见值为 8.0 kHz、11.025 kHz、22.05 kHz 和 44.1 kHz
						int nAvgBytesPerSec; //格式标记所需的平均数据传输速率(以字节/秒为单位)=nsam*nblock
						short nBlockAlign;      //阻止对齐(以字节为单位),nBlockAlign 必须等于 nChannels 和 wBitsPerSample 的乘积除以 8 (位/字节)
						short  wBitsPerSample;// 如果 wFormatTag WAVE_FORMAT_PCM,则 wBitsPerSample 应等于 8 或 16
						short biSize;           //追加到 WAVEFORMATEX 结构末尾的额外格式信息的大小(以字节为单位)
					}sf2;
				}sl2;
			}hd;
			
			struct movi{
				char id[4];
				unsigned int size;
				char type[4]; 
			}mo;
			
		}ri;
		
	}head;
	
	
	
	FILE *fo=fopen("/home/wzpc/Videos/demo.avi","w+b");     //生成avi
	FILE *f=fopen("/home/wzpc/Videos/tra_mjpg.avi","rb");   //无声视频文件
	FILE *af=fopen("/home/wzpc/Music/musicdemo.wav","r+b");      //wav 文件
	fseek(fo,sizeof(head),SEEK_SET);
	
	
	if(f==NULL){
		puts("file_in error");
		exit(-1);
	}
	if(af==NULL){
		puts("file2_in error");
		exit(-1);
	}
	fseek(f,0,SEEK_END);
	int flen=ftell(f);
	fseek(f,0,SEEK_SET);
	fseek(af,0,SEEK_END);
	int aflen=ftell(af);
	fseek(af,0,SEEK_SET);
	
	int tf=fileno(f);
	int taf=fileno(af);
	
	char *mf=mmap(NULL,flen,PROT_READ,MAP_SHARED,tf,0);
	char *maf=mmap(NULL,aflen,PROT_READ,MAP_SHARED,taf,0);
	
	for(int t=0;t<aflen;t++){
		if((mf[t]=='d')&&(mf[t+1]=='a')&&(mf[t+2]=='t')&&(mf[t+3])=='a'){
			aq=t;
			
		}
	}
	
	for(int t=0;t<flen;t++){
		if((mf[t]=='m')&&(mf[t+1]=='o')&&(mf[t+2]=='v')&&(mf[t+3])=='i'){
			q=t;
			
		}
	}
	
	sp=q+4;
	int movisize=0;
	memcpy(&movisize,&mf[q-4],4);        //movi 总字节数
	//movi 数据开始偏移
	for(int k=0;k<15;k++){                //写15帧图片数据
		char c00dc[]={'0','0','d','c'};
		fwrite(c00dc,4,1,fo);               //写00dc
		unsigned int csize=0;
		memcpy(&csize,&mf[sp+4],4);         //取长度
		
		fwrite(&csize,4,1,fo);              //写长度
		fwrite(&mf[sp+8],csize,1,fo);       //写数据
		
		sp=sp+8+csize;                          //下一个循环偏移地址
		vzj=vzj+8+csize;
		
	}
	
	
	char c01wb[]={'0','1','w','b'};
	fwrite(c01wb,4,1,fo);              //写audio标志00wb
	int at;
	memcpy(&at,&maf[aq+4],4);
	fwrite(&maf[aq+4],4,1,fo);         //写audio长度
	
	int ap=aq+8; 
	while(azj<at){
		for(int k=0;k<44100;k++){              //写4069个字节的声音数据
			if(azj<at){	
				
				fwrite(&maf[ap+0],44100,1,fo);         //写audio数据
				ap=ap+44100;                        //下个循环的偏移
				azj=azj+44100;
			}
		}
	}
	
	while(vzj<=movisize){							   
		for(int k=0;k<15;k++){                //写15帧图片数据
			char c00dc[]={'0','0','d','c'};
			fwrite(c00dc,4,1,fo);               //写00dc
			unsigned int csize=0;
			memcpy(&csize,&mf[sp+4],4);         //取长度
			
			fwrite(&csize,4,1,fo);              //写长度
			fwrite(&mf[sp+8],csize,1,fo);       //写数据
			
			sp=sp+8+csize;                          //下一个循环偏移地址
			vzj=vzj+8+csize;
			
		}
	

		int ap=aq+8; 
		while(azj<at){
		for(int k=0;k<44100;k++){              //写4069个字节的声音数据
			if(azj<at){	
				
				fwrite(&maf[ap+0],44100,1,fo);         //写audio数据
				ap=ap+44100;                        //下个循环的偏移
				azj=azj+44100;
			}
		}
		}
	}
	//----------------------------------------------	
	typedef struct file File;
	File   ffile={
		{//riff
			{'R','I','F','F'},
			vzj+azj+4+8,
			{'A','V','I',' '},
			
			//hdrl
			{
				{'L','I','S','T'},
				sizeof(head.ri.hd)-8,
				{'s','t','r','l'},
				//avih
				{
					{'a','v','i','h'},
					sizeof(head.ri.hd.av)-8,
					33367,5723556,0,0,509,1,2,190976,720,486,{0,0,0,0}	
					
				},
				//strl1
				{
					{'L','I','S','T'},
					sizeof(head.ri.hd.sl1)-8,
					{'s','t','r','l'},
					{   //strh1
						{'s', 't', 'r', 'h'},
						sizeof(head.ri.hd.sl1.sh1)-8,
						{'v', 'i', 'd', 's'},
						{'M', 'J', 'P', 'G'},
						0, 0, 0, 0, 1001, 30000, 0, 509, 190976,0xFFFFFF, 0,
						0, 0, 720, 486
					},
					{   //strf1
						{'s','t','r','f'},
						sizeof(head.ri.hd.sl1.sf1)-8,
						sizeof(head.ri.hd.sl1.sf1)-8,
						720,486,1,24,
						{'M','J','P','G'},
						190964,0,0,0,0
					}
				},
				//strl2
				{
					{'L','I','S','T'},
					sizeof(head.ri.hd.sl2)-8,
					
					{'s','t','r','l'},
					{   //strh2
						{'s','t','r','h'},
						sizeof(head.ri.hd.sl2.sh2)-8,
						{'a','u','d','s'},
						{0},
						0,0,0,0,1001,5000,0,0,176400,0xfffffff,44100,
						0,0,0,0
						
					},
					{   //strf2
						
						{'s','t','r','f'},
						sizeof(head.ri.hd.sl2.sf2)-8,
						1,1,44100, 176400,4,16,0
						
					}
				}
			},
			
			//movi
			{
				{'L','I','S','T'},
				movisize,
				{'m','o','v','i'}
			}
			
		}
	};
	fseek(fo,0,SEEK_SET);
	fwrite(&ffile,sizeof(ffile),1,fo);
	//-----------------------------------------	
	puts("over");		
	return 0;
}

程序基本上可用,还没完全理解视频与音频交叉贮存。完善中。

此程序现在只能用ffplay打开,估计是文件头,和存储音视频数据还不完善。

编程中发现,头文件结构中很多参数要求很不严格,只有少数几个很重要,甚至结构中的结构长度的准确度也可以不严格。

其实,这个程序就是为后期的用摄像头录像,麦克风录音作准备的,此程序用的音频我就是用麦克风录制的。

相关推荐
五味香9 分钟前
Linux学习,ip 命令
linux·服务器·c语言·开发语言·git·学习·tcp/ip
小奥超人22 分钟前
PPT技巧:如何合并PPT文件?
windows·经验分享·microsoft·powerpoint·办公技巧
lb36363636361 小时前
整数储存形式(c基础)
c语言·开发语言
浪里个浪的10241 小时前
【C语言】从3x5矩阵计算前三行平均值并扩展到4x5矩阵
c语言·开发语言·矩阵
<但凡.1 小时前
编程之路,从0开始:知识补充篇
c语言·数据结构·算法
f狐0狸x2 小时前
【数据结构副本篇】顺序表 链表OJ
c语言·数据结构·算法·链表
CoderBob2 小时前
【EmbeddedGUI】脏矩阵设计说明
c语言·单片机
浪里个浪的10242 小时前
【C语言】计算3x3矩阵每行的最大值并存入第四列
c语言·开发语言·矩阵
敲敲敲-敲代码3 小时前
游戏设计:推箱子【easyx图形界面/c语言】
c语言·开发语言·游戏
simple_ssn3 小时前
【C语言刷力扣】1502.判断能否形成等差数列
c语言·算法·leetcode