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);
+
+
+