Mercurial > mplayer.hg
changeset 2529:266dab71162b
AVI muxer rewritten
author | arpi |
---|---|
date | Mon, 29 Oct 2001 00:55:15 +0000 |
parents | 96803377ad53 |
children | 6fe4d4a5a0ff |
files | libmpdemux/aviwrite.c libmpdemux/aviwrite.h |
diffstat | 2 files changed, 193 insertions(+), 118 deletions(-) [+] |
line wrap: on
line diff
--- a/libmpdemux/aviwrite.c Mon Oct 29 00:48:20 2001 +0000 +++ b/libmpdemux/aviwrite.c Mon Oct 29 00:55:15 2001 +0000 @@ -1,17 +1,56 @@ #include <stdio.h> #include <stdlib.h> -#include <unistd.h> +#include <string.h> + +//#include "stream.h" +//#include "demuxer.h" +//#include "stheader.h" #include "wine/mmreg.h" #include "wine/avifmt.h" #include "wine/vfw.h" -extern char* encode_name; -extern char* encode_index_name; +#include "aviwrite.h" -void write_avi_chunk(FILE *f,unsigned int id,int len,void* data){ +aviwrite_stream_t* aviwrite_new_stream(aviwrite_t *muxer,int type){ + aviwrite_stream_t* s; + if(muxer->avih.dwStreams>=AVIWRITE_MAX_STREAMS){ + printf("Too many streams! increase AVIWRITE_MAX_STREAMS !\n"); + return NULL; + } + s=malloc(sizeof(aviwrite_stream_t)); + memset(s,0,sizeof(aviwrite_stream_t)); + if(!s) return NULL; // no mem!? + muxer->streams[muxer->avih.dwStreams]=s; + s->type=type; + s->id=muxer->avih.dwStreams; + s->timer=0.0; + switch(type){ + case AVIWRITE_TYPE_VIDEO: + s->ckid=mmioFOURCC(('0'+s->id/10),('0'+(s->id%10)),'d','c'); + s->h.fccType=streamtypeVIDEO; + if(!muxer->def_v) muxer->def_v=s; + break; + case AVIWRITE_TYPE_AUDIO: + s->ckid=mmioFOURCC(('0'+s->id/10),('0'+(s->id%10)),'w','b'); + s->h.fccType=streamtypeAUDIO; + break; + default: + printf("WarninG! unknown stream type: %d\n",type); + return NULL; + } + muxer->avih.dwStreams++; + return s; +} +aviwrite_t* aviwrite_new_muxer(){ + aviwrite_t* muxer=malloc(sizeof(aviwrite_t)); + memset(muxer,0,sizeof(aviwrite_t)); + return muxer; +} + +static 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){ @@ -34,11 +73,39 @@ } } } +} + +void aviwrite_write_chunk(aviwrite_t *muxer,aviwrite_stream_t *s, FILE *f,int len,unsigned int flags){ + + // add to the index: + if(muxer->idx_pos>=muxer->idx_size){ + muxer->idx_size+=256; // 4kB + muxer->idx=realloc(muxer->idx,16*muxer->idx_size); + } + muxer->idx[muxer->idx_pos].ckid=s->ckid; + muxer->idx[muxer->idx_pos].dwFlags=flags; // keyframe? + muxer->idx[muxer->idx_pos].dwChunkOffset=ftell(f)-(muxer->movi_start-4); + muxer->idx[muxer->idx_pos].dwChunkLength=len; + ++muxer->idx_pos; + + // write out the chunk: + write_avi_chunk(f,s->ckid,len,s->buffer); + + // alter counters: + if(s->h.dwSampleSize){ + // CBR + s->h.dwLength+=len/s->h.dwSampleSize; + if(len%s->h.dwSampleSize) printf("Warning! len isn't divisable by samplesize!\n"); + } else { + // VBR + s->h.dwLength++; + } + s->timer=(double)s->h.dwLength*s->h.dwScale/s->h.dwRate; + if(len>s->h.dwSuggestedBufferSize) s->h.dwSuggestedBufferSize=len; } - -void write_avi_list(FILE *f,unsigned int id,int len){ +static 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); @@ -46,127 +113,86 @@ 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){ +void aviwrite_write_header(aviwrite_t *muxer,FILE *f){ unsigned int riff[3]; + int i; + unsigned int hdrsize; // RIFF header: riff[0]=mmioFOURCC('R','I','F','F'); - riff[1]=wah.file_end; // filesize + riff[1]=muxer->file_end; // filesize riff[2]=formtypeAVI; // 'AVI ' fwrite(&riff,12,1,f); + + // update AVI header: + if(muxer->def_v){ + muxer->avih.dwMicroSecPerFrame=1000000.0*muxer->def_v->h.dwScale/muxer->def_v->h.dwRate; + muxer->avih.dwMaxBytesPerSec=1000000; // dummy!!!!! FIXME + muxer->avih.dwPaddingGranularity=2; // ??? + muxer->avih.dwFlags|=AVIF_ISINTERLEAVED|AVIF_TRUSTCKTYPE; + muxer->avih.dwTotalFrames=muxer->def_v->h.dwLength; + muxer->avih.dwSuggestedBufferSize=muxer->def_v->h.dwSuggestedBufferSize; + muxer->avih.dwWidth=muxer->def_v->bih->biWidth; + muxer->avih.dwHeight=muxer->def_v->bih->biHeight; + } + // 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: + hdrsize=sizeof(muxer->avih)+8; + // calc total header size: + for(i=0;i<muxer->avih.dwStreams;i++){ + hdrsize+=12; // LIST + hdrsize+=sizeof(muxer->streams[i]->h)+8; // strh + switch(muxer->streams[i]->type){ + case AVIWRITE_TYPE_VIDEO: + hdrsize+=muxer->streams[i]->bih->biSize+8; // strf + break; + case AVIWRITE_TYPE_AUDIO: + hdrsize+=sizeof(WAVEFORMATEX)+muxer->streams[i]->wf->cbSize+8; // strf + break; + } + } + write_avi_list(f,listtypeAVIHEADER,hdrsize); + write_avi_chunk(f,ckidAVIMAINHDR,sizeof(muxer->avih),&muxer->avih); + + // stream headers: + for(i=0;i<muxer->avih.dwStreams;i++){ + hdrsize=sizeof(muxer->streams[i]->h)+8; // strh + switch(muxer->streams[i]->type){ + case AVIWRITE_TYPE_VIDEO: + hdrsize+=muxer->streams[i]->bih->biSize+8; // strf + break; + case AVIWRITE_TYPE_AUDIO: + hdrsize+=sizeof(WAVEFORMATEX)+muxer->streams[i]->wf->cbSize+8; // strf + break; + } + write_avi_list(f,listtypeSTREAMHEADER,hdrsize); + write_avi_chunk(f,ckidSTREAMHEADER,sizeof(muxer->streams[i]->h),&muxer->streams[i]->h); // strh + switch(muxer->streams[i]->type){ + case AVIWRITE_TYPE_VIDEO: + write_avi_chunk(f,ckidSTREAMFORMAT,muxer->streams[i]->bih->biSize,muxer->streams[i]->bih); + break; + case AVIWRITE_TYPE_AUDIO: + write_avi_chunk(f,ckidSTREAMFORMAT,sizeof(WAVEFORMATEX)+muxer->streams[i]->wf->cbSize,muxer->streams[i]->wf); + break; + } + } + + // 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); + write_avi_list(f,listtypeAVIMOVIE,muxer->movi_end-ftell(f)-12); + muxer->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 aviwrite_write_index(aviwrite_t *muxer,FILE *f){ + muxer->movi_end=ftell(f); + if(muxer->idx && muxer->idx_pos>0){ + // fixup index entries: +// int i; +// for(i=0;i<muxer->idx_pos;i++) muxer->idx[i].dwChunkOffset-=muxer->movi_start-4; + // write index chunk: + write_avi_chunk(f,ckidAVINEWINDEX,16*muxer->idx_pos,muxer->idx); + muxer->avih.dwFlags|=AVIF_HASINDEX; + } + muxer->file_end=ftell(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); - -} - - -
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmpdemux/aviwrite.h Mon Oct 29 00:55:15 2001 +0000 @@ -0,0 +1,49 @@ + +#define AVIWRITE_MAX_STREAMS 16 + +#define AVIWRITE_TYPE_VIDEO 0 +#define AVIWRITE_TYPE_AUDIO 1 + +typedef struct { + // muxer data: + int type; // audio or video + int id; // stream no + unsigned int ckid; // chunk id (00dc 01wb etc) + double timer; + // buffering: + unsigned char *buffer; + unsigned int buffer_size; + // source stream: + void* source; // sh_audio or sh_video + int codec; // codec used for encoding. 0 means copy + // avi stream header: + AVIStreamHeader h; // Rate/Scale and SampleSize must be filled by caller! + // stream specific: + WAVEFORMATEX *wf; + BITMAPINFOHEADER *bih; // in format +} aviwrite_stream_t; + +typedef struct { + // encoding: + MainAVIHeader avih; + unsigned int movi_start; + unsigned int movi_end; + unsigned int file_end; + // index: + AVIINDEXENTRY *idx; + int idx_pos; + int idx_size; + // streams: + //int num_streams; + aviwrite_stream_t* def_v; // default video stream (for general headers) + aviwrite_stream_t* streams[AVIWRITE_MAX_STREAMS]; +} aviwrite_t; + +aviwrite_stream_t* aviwrite_new_stream(aviwrite_t *muxer,int type); +aviwrite_t* aviwrite_new_muxer(); +void aviwrite_write_chunk(aviwrite_t *muxer,aviwrite_stream_t *s, FILE *f,int len,unsigned int flags); +void aviwrite_write_header(aviwrite_t *muxer,FILE *f); +void aviwrite_write_index(aviwrite_t *muxer,FILE *f); + + +