mpv/aviwrite.c

162 lines
4.0 KiB
C

void write_avi_chunk(FILE *f,unsigned int id,int len,void* data){
fwrite(&id,4,1,f);
fwrite(&len,4,1,f);
if(len>0){
if(data){
// DATA
fwrite(data,len,1,f);
if(len&1){ // padding
unsigned char zerobyte=0;
fwrite(&zerobyte,1,1,f);
}
} else {
// JUNK
char *avi_junk_data="[= MPlayer junk data! =]";
if(len&1) ++len; // padding
while(len>0){
int l=strlen(avi_junk_data);
if(l>len) l=len;
fwrite(avi_junk_data,l,1,f);
len-=l;
}
}
}
}
void write_avi_list(FILE *f,unsigned int id,int len){
unsigned int list_id=FOURCC_LIST;
len+=4; // list fix
fwrite(&list_id,4,1,f);
fwrite(&len,4,1,f);
fwrite(&id,4,1,f);
}
struct {
MainAVIHeader avih;
AVIStreamHeader video;
BITMAPINFOHEADER bih;
unsigned int movi_start;
unsigned int movi_end;
unsigned int file_end;
} wah;
void write_avi_header(FILE *f){
unsigned int riff[3];
// RIFF header:
riff[0]=mmioFOURCC('R','I','F','F');
riff[1]=wah.file_end; // filesize
riff[2]=formtypeAVI; // 'AVI '
fwrite(&riff,12,1,f);
// AVI header:
write_avi_list(f,listtypeAVIHEADER,sizeof(wah.avih)+8+12+sizeof(wah.video)+8+sizeof(wah.bih)+8);
write_avi_chunk(f,ckidAVIMAINHDR,sizeof(wah.avih),&wah.avih);
// stream header:
write_avi_list(f,listtypeSTREAMHEADER,sizeof(wah.video)+8+sizeof(wah.bih)+8);
write_avi_chunk(f,ckidSTREAMHEADER,sizeof(wah.video),&wah.video);
write_avi_chunk(f,ckidSTREAMFORMAT,sizeof(wah.bih),&wah.bih);
// JUNK:
write_avi_chunk(f,ckidAVIPADDING,2048-(ftell(f)&2047)-8,NULL);
// 'movi' header:
write_avi_list(f,listtypeAVIMOVIE,wah.movi_end-ftell(f)-12);
wah.movi_start=ftell(f);
}
// called _before_ encoding: (write placeholders and video info)
void write_avi_header_1(FILE *f,int fcc,float fps,int width,int height){
int frames=8*3600*fps; // 8 hours
wah.file_end=
wah.movi_end=0x7f000000;
wah.avih.dwMicroSecPerFrame=1000000.0f/fps;
wah.avih.dwMaxBytesPerSec=fps*500000; // ?????
wah.avih.dwPaddingGranularity=1; // padding
wah.avih.dwFlags=AVIF_ISINTERLEAVED;
wah.avih.dwTotalFrames=frames;
wah.avih.dwInitialFrames=0;
wah.avih.dwStreams=1;
wah.avih.dwSuggestedBufferSize=0x10000; // 1MB
wah.avih.dwWidth=width;
wah.avih.dwHeight=height;
wah.avih.dwReserved[0]=
wah.avih.dwReserved[1]=
wah.avih.dwReserved[2]=
wah.avih.dwReserved[3]=0;
wah.video.fccType=streamtypeVIDEO;
wah.video.fccHandler=fcc;
wah.video.dwFlags=0;
wah.video.wPriority=0;
wah.video.wLanguage=0;
wah.video.dwInitialFrames=0;
wah.video.dwScale=10000;
wah.video.dwRate=fps*10000;
wah.video.dwStart=0;
wah.video.dwLength=frames;
wah.video.dwSuggestedBufferSize=0x100000; // 1MB ????
wah.video.dwQuality=10000;
wah.video.dwSampleSize=width*height*3;
wah.bih.biSize=sizeof(wah.bih); // 40 ?
wah.bih.biWidth=width;
wah.bih.biHeight=height;
wah.bih.biPlanes=1;
wah.bih.biBitCount=24;
wah.bih.biCompression=fcc;
wah.bih.biSizeImage=3*width*height;
wah.bih.biXPelsPerMeter=
wah.bih.biYPelsPerMeter=
wah.bih.biClrUsed=
wah.bih.biClrImportant=0;
write_avi_header(f);
}
void avi_fixate(){
// append index and fix avi headers:
FILE *f1=fopen(encode_name,"r+");
FILE *f2;
if(!f1) return; // error
fseek(f1,0,SEEK_END);
wah.file_end=wah.movi_end=ftell(f1);
// index:
if(encode_index_name && (f2=fopen(encode_index_name,"rb"))){
AVIINDEXENTRY idx;
unsigned int pos=0;
int frames=0;
write_avi_chunk(f1,ckidAVINEWINDEX,0,NULL);
while(fread(&idx,sizeof(idx),1,f2)>0){
idx.dwChunkOffset-=wah.movi_start-4;
fwrite(&idx,sizeof(idx),1,f1);
++frames;
}
fclose(f2);
unlink(encode_index_name);
wah.file_end=ftell(f1);
// re-write idx1 length:
pos=wah.file_end-wah.movi_end-8;
fseek(f1,wah.movi_end+4,SEEK_SET);
fwrite(&pos,4,1,f1);
// fixup frames:
wah.avih.dwTotalFrames=frames;
wah.video.dwLength=frames;
}
// re-write avi header:
fseek(f1,0,SEEK_SET);
write_avi_header(f1);
fclose(f1);
}