#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打开,估计是文件头,和存储音视频数据还不完善。
编程中发现,头文件结构中很多参数要求很不严格,只有少数几个很重要,甚至结构中的结构长度的准确度也可以不严格。
其实,这个程序就是为后期的用摄像头录像,麦克风录音作准备的,此程序用的音频我就是用麦克风录制的。