[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