[MPlayer-dev-eng] [PATCH] multicontainer layer/MPEG encoder. Was: RELEASE tomorrow?!

Andriy N. Gritsenko andrej at lucky.net
Mon Dec 9 16:33:05 CET 2002


    Hi!

>Sometime (on Saturday, December  7 at  2:02) I've received something...
>>any preview of your code (espeecially the API) ?

At least it works and produces MPEG-1 files that playable with MPlayer
and displays no errors by mpeg_demux. I just done it so I didn't test
these files under window$. New commandline switch: '-of' (output format)
can be avi or mpeg. Anyone free to expand it for ogm, qt, etc. ;)

    With best wishes.
    Andriy.
-------------- next part --------------
diff -udpr MPlayer-20021209.orig/TOOLS/vivodump.c MPlayer-20021209/TOOLS/vivodump.c
--- MPlayer-20021209.orig/TOOLS/vivodump.c	Sat Dec  1 01:13:05 2001
+++ MPlayer-20021209/TOOLS/vivodump.c	Mon Dec  9 17:15:39 2002
@@ -149,7 +149,7 @@ int pos=0;
 int frames=0;
 FILE *f=fopen("paulvandykforanangel.viv","rb");
 FILE *f2=fopen("GB1.avi","wb");
-aviwrite_t* avi=aviwrite_new_muxer();
+aviwrite_t* avi=aviwrite_new_muxer(CONT_TYPE_AVI);
 aviwrite_stream_t* mux=aviwrite_new_stream(avi,AVIWRITE_TYPE_VIDEO);
 //unsigned char* buffer=malloc(0x200000);
 int i,len;
diff -udpr MPlayer-20021209.orig/cfg-mencoder.h MPlayer-20021209/cfg-mencoder.h
--- MPlayer-20021209.orig/cfg-mencoder.h	Thu Nov 28 00:45:54 2002
+++ MPlayer-20021209/cfg-mencoder.h	Mon Dec  9 17:15:39 2002
@@ -120,6 +120,16 @@ struct config info_conf[]={
 	{NULL, NULL, 0, 0, 0, 0, NULL}
 };
 
+struct config of_conf[]={
+	{"avi", &out_file_format, CONF_TYPE_FLAG, 0, 0, CONT_TYPE_AVI, NULL},
+	{"mpeg", &out_file_format, CONF_TYPE_FLAG, 0, 0, CONT_TYPE_MPEG, NULL},
+	{"help", "\nAvailable output formats:\n"
+	"   avi      - Microsoft Audio/Video Interleaved\n"
+	"   mpeg     - MPEG-1 system stream format\n"
+	"\n", CONF_TYPE_PRINT, CONF_NOCFG, 0, 0, NULL},
+	{NULL, NULL, 0, 0, 0, 0, NULL}
+};
+
 static config_t mencoder_opts[]={
 	/* name, pointer, type, flags, min, max */
 	{"include", cfg_include, CONF_TYPE_FUNC_PARAM, CONF_NOSAVE, 0, 0, NULL}, /* this must be the first!!! */
@@ -146,6 +156,9 @@ static config_t mencoder_opts[]={
 	// outut audio/video codec selection
 	{"oac", oac_conf, CONF_TYPE_SUBCONFIG, 0, 0, 0, NULL},
 	{"ovc", ovc_conf, CONF_TYPE_SUBCONFIG, 0, 0, 0, NULL},
+
+	// output file format
+	{"of", of_conf, CONF_TYPE_SUBCONFIG, 0, 0, 0, NULL},
 
 	// override FOURCC in output file
 	{"ffourcc", &force_fourcc, CONF_TYPE_STRING, 0, 4, 4, NULL},
diff -udpr MPlayer-20021209.orig/libmpdemux/aviwrite.c MPlayer-20021209/libmpdemux/aviwrite.c
--- MPlayer-20021209.orig/libmpdemux/aviwrite.c	Sun Nov  3 11:51:06 2002
+++ MPlayer-20021209/libmpdemux/aviwrite.c	Mon Dec  9 17:15:39 2002
@@ -3,6 +3,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/types.h>
+#include <netinet/in.h>
 
 #include "config.h"
 #include "../version.h"
@@ -27,7 +28,7 @@ extern char *info_copyright;
 extern char *info_sourceform;
 extern char *info_comment;
 
-aviwrite_stream_t* aviwrite_new_stream(aviwrite_t *muxer,int type){
+static aviwrite_stream_t* avifile_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");
@@ -59,12 +60,6 @@ aviwrite_stream_t* aviwrite_new_stream(a
     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){
  int le_len = le2me_32(len);
  int le_id = le2me_32(id);
@@ -93,7 +88,7 @@ if(len>0){
 }
 }
 
-void aviwrite_write_chunk(aviwrite_t *muxer,aviwrite_stream_t *s, FILE *f,int len,unsigned int flags){
+static void avifile_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){
@@ -140,7 +135,7 @@ static void write_avi_list(FILE *f,unsig
 // muxer->streams[i]->wf->cbSize
 #define WFSIZE(wf) (sizeof(WAVEFORMATEX)+(((wf)->cbSize)?((wf)->cbSize-2):0))
 
-void aviwrite_write_header(aviwrite_t *muxer,FILE *f){
+static void avifile_write_header(aviwrite_t *muxer,FILE *f){
   unsigned int riff[3];
   int i;
   unsigned int hdrsize;
@@ -280,7 +275,7 @@ info[i].id=0;
   muxer->movi_start=ftell(f);
 }
 
-void aviwrite_write_index(aviwrite_t *muxer,FILE *f){
+static void avifile_write_index(aviwrite_t *muxer,FILE *f){
   muxer->movi_end=ftell(f);
   if(muxer->idx && muxer->idx_pos>0){
       int i;
@@ -295,3 +290,272 @@ void aviwrite_write_index(aviwrite_t *mu
   muxer->file_end=ftell(f);
 }
 
+static aviwrite_stream_t* mpegfile_new_stream(aviwrite_t *muxer,int type){
+  aviwrite_stream_t *s = avifile_new_stream(muxer, type);
+  if (s) {
+    if (!(s->b_buffer = malloc (AVIWRITE_MPEG_BLOCKSIZE))) {
+      free (s);
+      muxer->avih.dwStreams--;
+      s = NULL;	// no mem?!
+    } else if (type == AVIWRITE_TYPE_VIDEO) {
+      if (muxer->num_videos < 15) {
+	s->ckid = htonl (0x1e0 + muxer->num_videos);
+	muxer->num_videos++;
+//	printf ("Added video stream %d\n", muxer->num_videos);
+      } else {
+	free (s->b_buffer);
+	free (s);
+	s = NULL;
+        muxer->avih.dwStreams--;
+	printf ("MPEG stream can't contain above of 15 video streams!\n");
+      }
+    } else { // AVIWRITE_TYPE_AUDIO
+      if (s->id - muxer->num_videos < 31) {
+	s->ckid = htonl (0x1c0 + s->id - muxer->num_videos);
+//	printf ("Added audio stream %d\n", s->id - muxer->num_videos + 1);
+      } else {
+	free (s->b_buffer);
+	free (s);
+	s = NULL;
+        muxer->avih.dwStreams--;
+	printf ("MPEG stream can't contain above of 31 audio streams!\n");
+      }
+    }
+  }
+  return s;
+}
+
+static void write_mpeg_ts(unsigned char *b, unsigned int ts, char mod) {
+  b[0] = ((ts >> 29) & 0xf) | 1 | mod;
+  b[1] = (ts >> 22) & 0xff;
+  b[2] = ((ts >> 14) & 0xff) | 1;
+  b[3] = (ts >> 7) & 0xff;
+  b[4] = ((ts < 1) & 0xff) | 1;
+}
+
+static void write_mpeg_rate(unsigned char *b, unsigned int rate) {
+  rate /= 50;
+  b[0] = ((rate >> 15) & 0x7f) | 0x80;
+  b[1] = (rate >> 7) & 0xff;
+  b[2] = ((rate < 1) & 0xff) | 1;
+}
+
+static void write_mpeg_std(unsigned char *b, unsigned int size, char mod) {
+  if (size < (128 << 12))
+    size >>= 7; // by 128 bytes
+  else
+    size = (size<<10) | 0x2000; // by 1kbyte
+  b[0] = ((size >> 8) & 0x3f) | 0x40 | mod;
+  b[1] = size & 0xff;
+}
+
+/* 18 bytes reserved for block headers and STD */
+#define AVIWRITE_MPEG_DATASIZE (AVIWRITE_MPEG_BLOCKSIZE-18)
+
+static int write_mpeg_block(aviwrite_t *muxer, aviwrite_stream_t *s, FILE *f, char *bl, size_t len, int isoend){
+  size_t sz; // rest in block buffer
+  unsigned char buff[12]; // 0x1ba header
+  unsigned int mints;
+  unsigned short l1;
+
+  if (s->b_buffer_ptr == 0) {
+    s->b_buffer[0] = 0xf;
+    s->b_buffer_ptr = 1;
+//    sz = AVIWRITE_MPEG_DATASIZE-3;
+    sz = AVIWRITE_MPEG_DATASIZE-1;
+  } else if (s->b_buffer_ptr > AVIWRITE_MPEG_DATASIZE) {
+    printf ("Unknown error in write_mpeg_block()!\n");
+    return 0;
+  }// else if (s->b_buffer_ptr > AVIWRITE_MPEG_DATASIZE-2)
+//    sz = 0;
+  else
+//    sz = AVIWRITE_MPEG_DATASIZE-2 - s->b_buffer_ptr;
+    sz = AVIWRITE_MPEG_DATASIZE - s->b_buffer_ptr;
+//fprintf (stderr, "... new block");
+  if (len > sz)
+    len = sz;
+  *(int *)buff = htonl (0x1ba);
+  write_mpeg_ts (buff+4, muxer->file_end, 0x10);
+  write_mpeg_rate (buff+9, muxer->sysrate);
+  fwrite (buff, 12, 1, f);
+  fwrite (&s->ckid, 4, 1, f);
+  memcpy (&s->b_buffer[s->b_buffer_ptr], bl, len);
+  memset (buff, 0xff, 12); // stuFFing bytes
+  sz -= len;
+  if (sz <= 8) { // no padding
+    l1 = htons (AVIWRITE_MPEG_DATASIZE);
+    fwrite (&l1, 2, 1, f);
+    if (sz)
+      fwrite (buff, sz, 1, f);
+  } else {
+    l1 = htons (s->b_buffer_ptr+len);
+    fwrite (&l1, 2, 1, f);
+  }
+//fprintf (stderr, ".");
+//  write_mpeg_std (buff, s->h.dwSuggestedBufferSize, 0x40);
+//  fwrite (buff, 2, 1, f); // std (0xff ???)
+  if (s->b_buffer_ptr)
+    fwrite (s->b_buffer, s->b_buffer_ptr, 1, f);
+  if (len)
+    fwrite (bl, len, 1, f);
+//fprintf (stderr, ".");
+  if (sz > 8) { // padding block (0x1be)
+    unsigned long l0;
+
+    if (isoend)
+      l0 = htonl (0x1b9);
+    else
+      l0 = htonl (0x1be);
+    sz -= 6;
+    l1 = htons (sz);
+    fwrite (&l0, 4, 1, f);
+    fwrite (&l1, 2, 1, f);
+//fprintf (stderr, ".");
+    memset (s->b_buffer, 0xff, sz); // stuFFing bytes
+    fwrite (s->b_buffer, sz, 1, f);
+  }
+//fprintf (stderr, ".");
+  s->b_buffer_ptr = 0;
+  muxer->movi_end += AVIWRITE_MPEG_BLOCKSIZE;
+  mints = AVIWRITE_MPEG_BLOCKSIZE*90000/muxer->sysrate; // min ts delta
+  sz = (int)(s->timer*90000) - muxer->file_end; // suggested ts delta
+  if (sz > 90000)
+    mints += (sz-90000)/10; // 1s between system and presentation timestamps
+  else if (sz < 30000 && muxer->sysrate < muxer->movi_end/(s->timer*0.98))
+    muxer->sysrate = muxer->movi_end/(s->timer*0.98); // increase rate
+//fprintf (stderr, " %d; sts %u.%03u; new rate %u",
+//	    muxer->movi_end/AVIWRITE_MPEG_BLOCKSIZE,
+//	    muxer->file_end/90000, (muxer->file_end/90)%1000, muxer->sysrate);
+  muxer->file_end += mints; // update the system timestamp
+  return len;
+}
+
+static void set_mpeg_pts(aviwrite_stream_t *s) {
+  if (s->b_buffer_ptr != 0)
+    return; // already set
+  write_mpeg_ts (s->b_buffer, (int)((s->timer+0.5)*90000), 0x20);
+  s->b_buffer_ptr = 5;
+}
+
+static void mpegfile_write_chunk(aviwrite_t *muxer,aviwrite_stream_t *s, FILE *f,int len,unsigned int flags){
+  size_t ptr=0, sz;
+
+//fprintf (stderr, "add to stream %d: frame %d; len %d; pts %.3f", s->id, s->h.dwLength, len, s->timer);
+  if (s->type == AVIWRITE_TYPE_VIDEO && // 39 bytes for Gop+Pic+Slice headers
+      s->b_buffer_ptr > AVIWRITE_MPEG_DATASIZE-39-7) {
+    write_mpeg_block (muxer, s, f, NULL, 0, 0);
+  }
+  // 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++;
+  }
+  if (!muxer->sysrate) {
+    muxer->sysrate = 2108000/8; // constrained stream parameter
+    muxer->file_end = AVIWRITE_MPEG_BLOCKSIZE*90000/muxer->sysrate;
+  } // assumed 2x rate of first frame
+  if ((unsigned int)len > s->h.dwSuggestedBufferSize) s->h.dwSuggestedBufferSize = len;
+  s->size += len;
+  set_mpeg_pts (s);
+  // write out block(s) if it's ready
+//  while (s->b_buffer_ptr+len >= AVIWRITE_MPEG_DATASIZE-7) { // reserved for std and pts
+  while (s->b_buffer_ptr+len >= AVIWRITE_MPEG_DATASIZE-5) { // reserved for pts
+    // write out the block
+    sz = write_mpeg_block (muxer, s, f, &s->buffer[ptr], len, 0);
+    // recalculate the rest of chunk
+    ptr += sz;
+    len -= sz;
+  }
+  s->timer = (double)s->h.dwLength*s->h.dwScale/s->h.dwRate;
+  if (len) { // save rest in buffer
+    set_mpeg_pts (s);
+    memcpy (&s->b_buffer[s->b_buffer_ptr], &s->buffer[ptr], len);
+    s->b_buffer_ptr += len;
+  }
+//fprintf (stderr, "... frame added (inbuf=%u)\n", s->b_buffer_ptr);
+}
+
+static void mpegfile_write_header(aviwrite_t *muxer,FILE *f){
+  unsigned int i;
+  size_t sz = AVIWRITE_MPEG_BLOCKSIZE-24;
+  unsigned char buff[12];
+  aviwrite_stream_t *s = muxer->streams[0];
+  unsigned long l1;
+  unsigned short l2;
+
+//fprintf (stderr, "header");
+  if (s == NULL)
+    return; // no streams!?
+  // packet header (0x1ba) -- rewrite first stream buffer
+  *(long *)buff = htonl (0x1ba);
+  write_mpeg_ts (buff+4, 0, 0x10);
+  write_mpeg_rate (buff+9, muxer->sysrate);
+  fwrite (buff, 12, 1, f);
+  // start system stream (in own block): Sys (0x1bb)
+  l1 = htonl (0x1bb);
+  l2 = htons (6 + 3*muxer->avih.dwStreams);
+  fwrite (&l1, 4, 1, f);
+  fwrite (&l2, 2, 1, f);
+  write_mpeg_rate (buff, muxer->sysrate);
+  // set number of audio/video, no fixed bitrate, no CSPS, no system locks
+  buff[3] = (muxer->avih.dwStreams - muxer->num_videos) << 2;
+  buff[4] = muxer->num_videos | 0x20;
+  buff[5] = 0xff;
+  fwrite (buff, 6, 1, f);
+  for (i = 0; i < muxer->avih.dwStreams; i++) {
+    l1 = ntohl (muxer->streams[i]->ckid);
+    buff[0] = l1 & 0xff;
+//fprintf (stderr, "... stream 0x1%02x", (int)buff[0]);
+    write_mpeg_std (buff+1, muxer->streams[i]->h.dwSuggestedBufferSize, 0xc0);
+    fwrite (buff, 3, 1, f);
+    sz -= 3;
+  }
+  if (sz >= 6) { // padding block
+    l1 = htonl (0x1be);
+    sz -= 6;
+    l2 = htons (sz);
+    fwrite (&l1, 4, 1, f);
+    fwrite (&l2, 2, 1, f);
+  }
+  // stuFFing bytes -- rewrite first stream buffer
+  memset (s->b_buffer, 0xff, sz);
+  fwrite (s->b_buffer, sz, 1, f);
+  muxer->movi_start = 0;
+  muxer->movi_end = AVIWRITE_MPEG_BLOCKSIZE;
+//fprintf (stderr, "... ok\n");
+}
+
+static void mpegfile_write_index(aviwrite_t *muxer,FILE *f){
+  unsigned int i;
+
+  if (!muxer->avih.dwStreams) return; // no streams?!
+  // finish all but one video and audio streams
+  for (i = 0; i < muxer->avih.dwStreams-1; i++)
+    write_mpeg_block (muxer, muxer->streams[i], f, NULL, 0, 0);
+  // end sequence: ISO-11172-End (0x1b9) and finish very last block
+  write_mpeg_block (muxer, muxer->streams[i], f, NULL, 0, 1);
+}
+
+aviwrite_t* aviwrite_new_muxer(int type){
+    aviwrite_t* muxer=malloc(sizeof(aviwrite_t));
+    memset(muxer,0,sizeof(aviwrite_t));
+    switch (type) {
+      case CONT_TYPE_MPEG:
+	muxer->cont_new_stream = &mpegfile_new_stream;
+	muxer->cont_write_chunk = &mpegfile_write_chunk;
+	muxer->cont_write_header = &mpegfile_write_header;
+	muxer->cont_write_index = &mpegfile_write_index;
+	break;
+      case CONT_TYPE_AVI:
+      default:
+	muxer->cont_new_stream = &avifile_new_stream;
+	muxer->cont_write_chunk = &avifile_write_chunk;
+	muxer->cont_write_header = &avifile_write_header;
+	muxer->cont_write_index = &avifile_write_index;
+    }
+    return muxer;
+}
diff -udpr MPlayer-20021209.orig/libmpdemux/aviwrite.h MPlayer-20021209/libmpdemux/aviwrite.h
--- MPlayer-20021209.orig/libmpdemux/aviwrite.h	Thu Aug 29 23:50:49 2002
+++ MPlayer-20021209/libmpdemux/aviwrite.h	Mon Dec  9 17:15:39 2002
@@ -4,6 +4,11 @@
 #define AVIWRITE_TYPE_VIDEO 0
 #define AVIWRITE_TYPE_AUDIO 1
 
+#define CONT_TYPE_AVI 0
+#define CONT_TYPE_MPEG 1
+
+#define AVIWRITE_MPEG_BLOCKSIZE 2048	// 2048 or 2324 - ?
+
 typedef struct {
   // muxer data:
   int type;  // audio or video
@@ -15,6 +20,9 @@ typedef struct {
   unsigned char *buffer;
   unsigned int buffer_size;
   unsigned int buffer_len;
+  // mpeg block buffer:
+  unsigned char *b_buffer;
+  unsigned int b_buffer_ptr;
   // source stream:
   void* source; // sh_audio or sh_video
   int codec; // codec used for encoding. 0 means copy
@@ -30,27 +38,33 @@ typedef struct {
   char *text;
 } aviwrite_info_t;
 
-typedef struct {
+typedef struct aviwrite_t{
   // encoding:
   MainAVIHeader avih;
   unsigned int movi_start;
   unsigned int movi_end;
-  unsigned int file_end;
+  unsigned int file_end; // for MPEG it's system timestamp in 1/90000 s
   // index:
   AVIINDEXENTRY *idx;
   int idx_pos;
   int idx_size;
   // streams:
+  int num_videos;	// for MPEG recalculations
+  unsigned int sysrate;	// max rate in bytes/s
   //int num_streams;
   aviwrite_stream_t* def_v;  // default video stream (for general headers)
   aviwrite_stream_t* streams[AVIWRITE_MAX_STREAMS];
+  void (*cont_write_chunk)(struct aviwrite_t *muxer,aviwrite_stream_t *s, FILE *f,int len,unsigned int flags);
+  void (*cont_write_header)(struct aviwrite_t *muxer,FILE *f);
+  void (*cont_write_index)(struct aviwrite_t *muxer,FILE *f);
+  aviwrite_stream_t* (*cont_new_stream)(struct aviwrite_t *muxer,int type);
 } 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);
+aviwrite_t* aviwrite_new_muxer(int type);
+#define aviwrite_new_stream(muxer,a) muxer->cont_new_stream(muxer,a)
+#define aviwrite_write_chunk(muxer,a,b,c,d) muxer->cont_write_chunk(muxer,a,b,c,d)
+#define aviwrite_write_header(muxer,f) muxer->cont_write_header(muxer,f)
+#define aviwrite_write_index(muxer,f) muxer->cont_write_index(muxer,f)
 
 
 
diff -udpr MPlayer-20021209.orig/mencoder.c MPlayer-20021209/mencoder.c
--- MPlayer-20021209.orig/mencoder.c	Thu Dec  5 02:03:26 2002
+++ MPlayer-20021209/mencoder.c	Mon Dec  9 17:15:39 2002
@@ -107,6 +107,8 @@ static char** video_fm_list=NULL;     //
 static int out_audio_codec=-1;
 static int out_video_codec=-1;
 
+int out_file_format=CONT_TYPE_AVI;	// default to AVI
+
 // audio stream skip/resync functions requires only for seeking.
 // (they should be implemented in the audio codec layer)
 //void skip_audio_frame(sh_audio_t *sh_audio){}
@@ -590,7 +592,7 @@ if(!muxer_f) {
   mencoder_exit(1,NULL);
 }
 
-muxer=aviwrite_new_muxer();
+muxer=aviwrite_new_muxer(out_file_format);
 
 // ============= VIDEO ===============
 


More information about the MPlayer-dev-eng mailing list