From 7a8f8317fd501364b3c76156189c2100d338097f Mon Sep 17 00:00:00 2001 From: nicodvb Date: Mon, 21 Nov 2005 22:53:14 +0000 Subject: [PATCH] buffering in the muxer layer; patch by Corey Hickey (bugfood-ml ad fatooh punctum org) plus small fixes by me git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@17024 b3059339-0415-0410-9bf9-f77b7e298cf2 --- AUTHORS | 1 + libmpdemux/muxer.c | 102 ++++++++++++++++++++++++++++++++++++ libmpdemux/muxer.h | 20 ++++++- libmpdemux/muxer_avi.c | 11 ---- libmpdemux/muxer_lavf.c | 9 +--- libmpdemux/muxer_mpeg.c | 12 ++--- libmpdemux/muxer_rawaudio.c | 13 ----- libmpdemux/muxer_rawvideo.c | 11 ---- mencoder.c | 7 --- 9 files changed, 126 insertions(+), 60 deletions(-) diff --git a/AUTHORS b/AUTHORS index cb1e4be00e..b808961f7b 100644 --- a/AUTHORS +++ b/AUTHORS @@ -343,6 +343,7 @@ Hess, Andreas Hickey, Corey * telecine/interlacing HOWTO for the MEncoder documentation * advanced audio usage guide for the MPlayer documentation + * muxer frame buffer for MEncoder Hidvégi, Zoltán (Zoli) * filmdint video filter diff --git a/libmpdemux/muxer.c b/libmpdemux/muxer.c index fae7f453d3..e367198df2 100644 --- a/libmpdemux/muxer.c +++ b/libmpdemux/muxer.c @@ -48,3 +48,105 @@ muxer_t *muxer_new_muxer(int type,FILE *f){ } return muxer; } + +/* buffer frames until we either: + * (a) have at least one frame from each stream + * (b) run out of memory */ +void muxer_write_chunk(muxer_stream_t *s, size_t len, unsigned int flags) { + if (s->muxer->muxbuf_skip_buffer) { + s->muxer->cont_write_chunk(s, len, flags); + } + else { + int num = s->muxer->muxbuf_num++; + muxbuf_t *buf, *tmp; + + tmp = realloc(s->muxer->muxbuf, (num+1) * sizeof(muxbuf_t)); + if(!tmp) { + mp_msg(MSGT_MUXER, MSGL_FATAL, "Muxer frame buffer cannot reallocate memory!\n"); + return; + } + s->muxer->muxbuf = tmp; + buf = s->muxer->muxbuf + num; + + /* buffer this frame */ + buf->stream = s; + buf->timer = s->timer; + buf->len = len; + buf->flags = flags; + buf->buffer = malloc(len * sizeof (unsigned char)); + if (!buf->buffer) { + mp_msg(MSGT_MUXER, MSGL_FATAL, "Muxer frame buffer cannot allocate memory!\n"); + return; + } + memcpy(buf->buffer, s->buffer, buf->len); + s->muxbuf_seen = 1; + + /* see if we need to keep buffering */ + s->muxer->muxbuf_skip_buffer = 1; + for (num = 0; s->muxer->streams[num]; ++num) + if (!s->muxer->streams[num]->muxbuf_seen) + s->muxer->muxbuf_skip_buffer = 0; + + /* see if we can flush buffer now */ + if (s->muxer->muxbuf_skip_buffer) { + muxbuf_t *tmp_buf = malloc(sizeof(muxbuf_t)); + if (!tmp_buf) { + mp_msg(MSGT_MUXER, MSGL_FATAL, "Muxer frame buffer cannot allocate memory!\n"); + return; + } + mp_msg(MSGT_MUXER, MSGL_V, "Muxer frame buffer sending %d frame(s) to muxer.\n", + s->muxer->muxbuf_num); + + /* fix parameters for all streams */ + for (num = 0; s->muxer->streams[num]; ++num) { + muxer_stream_t *str = s->muxer->streams[num]; + if(str->muxer->fix_stream_parameters) + muxer_stream_fix_parameters(str->muxer, str); + } + + /* write header */ + mp_msg(MSGT_MUXER, MSGL_INFO, MSGTR_WritingAVIHeader); + if (s->muxer->cont_write_header) + muxer_write_header(s->muxer); + + /* send all buffered frames to muxer */ + for (num = 0; num < s->muxer->muxbuf_num; ++num) { + buf = s->muxer->muxbuf + num; + s = buf->stream; + + /* 1. save timer and buffer (might have changed by now) */ + tmp_buf->timer = s->timer; + tmp_buf->buffer = s->buffer; + + /* 2. move stored timer and buffer into stream and mux it */ + s->timer = buf->timer; + s->buffer = buf->buffer; + s->muxer->cont_write_chunk(s, buf->len, buf->flags); + + /* 3. restore saved timer and buffer */ + s->timer = tmp_buf->timer; + s->buffer = tmp_buf->buffer; + } + free(tmp_buf); + + free(s->muxer->muxbuf); + s->muxer->muxbuf_num = 0; + } + } + + /* this code moved directly from muxer_avi.c */ + // alter counters: + if(s->h.dwSampleSize){ + // CBR + s->h.dwLength+=len/s->h.dwSampleSize; + if(len%s->h.dwSampleSize) mp_msg(MSGT_MUXER, MSGL_WARN, "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; + s->size+=len; + + return; +} + diff --git a/libmpdemux/muxer.h b/libmpdemux/muxer.h index caa6068959..cff3bbafd8 100644 --- a/libmpdemux/muxer.h +++ b/libmpdemux/muxer.h @@ -28,6 +28,8 @@ typedef struct { unsigned int b_buffer_size; //size of b_buffer unsigned int b_buffer_ptr; //index to next data to write unsigned int b_buffer_len; //len of next data to write + // muxer frame buffer: + unsigned int muxbuf_seen; // source stream: void* source; // sh_audio or sh_video int codec; // codec used for encoding. 0 means copy @@ -37,7 +39,6 @@ typedef struct { WAVEFORMATEX *wf; BITMAPINFOHEADER *bih; // in format // mpeg specific: - unsigned int gop_start; // frame number of this GOP start size_t ipb[3]; // sizes of I/P/B frames // muxer of that stream struct muxer_t *muxer; @@ -66,6 +67,11 @@ typedef struct muxer_t{ //int num_streams; muxer_stream_t* def_v; // default video stream (for general headers) muxer_stream_t* streams[MUXER_MAX_STREAMS]; + // muxer frame buffer: + struct muxbuf_t * muxbuf; + int muxbuf_num; + int muxbuf_skip_buffer; + // functions: void (*fix_stream_parameters)(muxer_stream_t *); void (*cont_write_chunk)(muxer_stream_t *,size_t,unsigned int); void (*cont_write_header)(struct muxer_t *); @@ -75,10 +81,20 @@ typedef struct muxer_t{ void *priv; } muxer_t; +/* muxer frame buffer */ +typedef struct muxbuf_t { + muxer_stream_t *stream; /* pointer back to corresponding stream */ + double timer; /* snapshot of stream timer */ + unsigned char *buffer; + size_t len; + unsigned int flags; +} muxbuf_t; + + muxer_t *muxer_new_muxer(int type,FILE *); #define muxer_new_stream(muxer,a) muxer->cont_new_stream(muxer,a) #define muxer_stream_fix_parameters(muxer, a) muxer->fix_stream_parameters(a) -#define muxer_write_chunk(a,b,c) a->muxer->cont_write_chunk(a,b,c) +void muxer_write_chunk(muxer_stream_t *s, size_t len, unsigned int flags); #define muxer_write_header(muxer) muxer->cont_write_header(muxer) #define muxer_write_index(muxer) muxer->cont_write_index(muxer) diff --git a/libmpdemux/muxer_avi.c b/libmpdemux/muxer_avi.c index 1585d5de55..b9a3ec9183 100644 --- a/libmpdemux/muxer_avi.c +++ b/libmpdemux/muxer_avi.c @@ -241,20 +241,9 @@ static void avifile_write_chunk(muxer_stream_t *s,size_t len,unsigned int flags) // write out the chunk: write_avi_chunk(muxer->file,s->ckid,len,s->buffer); /* unsigned char */ - // alter counters: if (len > s->h.dwSuggestedBufferSize){ s->h.dwSuggestedBufferSize = len; } - if(s->h.dwSampleSize){ - // CBR - s->h.dwLength+=len/s->h.dwSampleSize; - if(len%s->h.dwSampleSize) mp_msg(MSGT_MUXER, MSGL_WARN, "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; - s->size+=len; if((unsigned int)len>s->h.dwSuggestedBufferSize) s->h.dwSuggestedBufferSize=len; muxer->file_end += 8 + paddedlen; diff --git a/libmpdemux/muxer_lavf.c b/libmpdemux/muxer_lavf.c index 98f4b2dc96..a2e1b5888b 100644 --- a/libmpdemux/muxer_lavf.c +++ b/libmpdemux/muxer_lavf.c @@ -103,6 +103,7 @@ static muxer_stream_t* lavf_new_stream(muxer_t *muxer, int type) mp_msg(MSGT_MUXER, MSGL_ERR, "Could not alloc muxer_stream, EXIT\n"); return NULL; } + muxer->streams[muxer->avih.dwStreams] = stream; stream->b_buffer = (unsigned char *)malloc(2048); if(!stream->b_buffer) { @@ -230,8 +231,6 @@ static void write_chunk(muxer_stream_t *stream, size_t len, unsigned int flags) muxer_stream_priv_t *spriv = (muxer_stream_priv_t *) stream->priv; AVPacket pkt; - stream->size += len; - if(len) { av_init_packet(&pkt); @@ -259,12 +258,6 @@ static void write_chunk(muxer_stream_t *stream, size_t len, unsigned int flags) } } - if(stream->h.dwSampleSize) // CBR - stream->h.dwLength += len / stream->h.dwSampleSize; - else // VBR - stream->h.dwLength++; - - stream->timer = (double) stream->h.dwLength * stream->h.dwScale / stream->h.dwRate; return; } diff --git a/libmpdemux/muxer_mpeg.c b/libmpdemux/muxer_mpeg.c index edd9b75ee6..4086a1d9c7 100644 --- a/libmpdemux/muxer_mpeg.c +++ b/libmpdemux/muxer_mpeg.c @@ -1991,7 +1991,6 @@ static size_t parse_mpeg12_video(muxer_stream_t *s, muxer_priv_t *priv, muxer_he if(s->buffer[3]) { // Sequence or GOP -- scan for Picture - s->gop_start = s->h.dwLength; while (ptr < len-5 && (s->buffer[ptr] != 0 || s->buffer[ptr+1] != 0 || s->buffer[ptr+2] != 1 || s->buffer[ptr+3] != 0)) ptr++; @@ -2454,10 +2453,8 @@ static void mpegfile_write_chunk(muxer_stream_t *s,size_t len,unsigned int flags priv->vbytes += len; sz <<= 1; - s->h.dwLength++; - s->size += len; - s->timer = (double)s->h.dwLength*s->h.dwScale/s->h.dwRate; } else { // MUXER_TYPE_AUDIO + double fake_timer; spriv->type = 0; stream_format = s->wf->wFormatTag; @@ -2522,9 +2519,7 @@ static void mpegfile_write_chunk(muxer_stream_t *s,size_t len,unsigned int flags } } - parse_audio(s, 0, &nf, &(s->timer)); - s->h.dwLength += nf; - s->size += len; + parse_audio(s, 0, &nf, &fake_timer); sz = max(len, 2 * priv->packet_size); } @@ -2557,12 +2552,13 @@ static void mpegfile_write_chunk(muxer_stream_t *s,size_t len,unsigned int flags static void mpegfile_write_index(muxer_t *muxer) { int i, nf; + double fake_timer; muxer_priv_t *priv = (muxer_priv_t *) muxer->priv; for(i = 0; i < muxer->avih.dwStreams; i++) { if(muxer->streams[i]->type == MUXER_TYPE_AUDIO) - parse_audio(muxer->streams[i], 1, &nf, &(muxer->streams[i]->timer)); + parse_audio(muxer->streams[i], 1, &nf, &fake_timer); } while(flush_buffers(muxer, 0) > 0); flush_buffers(muxer, 1); diff --git a/libmpdemux/muxer_rawaudio.c b/libmpdemux/muxer_rawaudio.c index a9904b6e9a..71bf56628e 100644 --- a/libmpdemux/muxer_rawaudio.c +++ b/libmpdemux/muxer_rawaudio.c @@ -51,19 +51,6 @@ static void rawaudiofile_write_chunk(muxer_stream_t *s,size_t len,unsigned int f // write out the chunk: if (s->type==MUXER_TYPE_AUDIO) fwrite(s->buffer,len,1,muxer->file); - - // alter counters: - if(s->h.dwSampleSize){ - // CBR - s->h.dwLength+=len/s->h.dwSampleSize; - if(len%s->h.dwSampleSize) - mp_msg(MSGT_MUXER,MSGL_WARN,MSGTR_WarningLenIsntDivisible); - } else { - // VBR - s->h.dwLength++; - } - s->timer=(double)s->h.dwLength*s->h.dwScale/s->h.dwRate; - s->size+=len; } static void rawaudiofile_write_header(muxer_t *muxer){ diff --git a/libmpdemux/muxer_rawvideo.c b/libmpdemux/muxer_rawvideo.c index 9ef82c3ab1..00c4436562 100644 --- a/libmpdemux/muxer_rawvideo.c +++ b/libmpdemux/muxer_rawvideo.c @@ -57,17 +57,6 @@ static void rawvideofile_write_chunk(muxer_stream_t *s,size_t len,unsigned int f if (s->type == MUXER_TYPE_VIDEO) write_rawvideo_chunk(muxer->file,len,s->buffer); /* unsigned char */ - // 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; - s->size+=len; // if((unsigned int)len>s->h.dwSuggestedBufferSize) s->h.dwSuggestedBufferSize=len; } diff --git a/mencoder.c b/mencoder.c index 892fa4e7a7..2a6dd432c9 100644 --- a/mencoder.c +++ b/mencoder.c @@ -833,8 +833,6 @@ if ((force_fourcc != NULL) && (strlen(force_fourcc) >= 4)) mux_v->bih->biCompression, (char *)&mux_v->bih->biCompression); } -if(muxer->fix_stream_parameters) - muxer_stream_fix_parameters(muxer,mux_v); //if(demuxer->file_format!=DEMUXER_TYPE_AVI) pts_from_bps=0; // it must be 0 for mpeg/asf! // ============= AUDIO =============== @@ -933,14 +931,9 @@ if(audio_delay_fix!=0.0){ mux_a->h.dwStart=audio_delay_fix*mux_a->h.dwRate/mux_a->h.dwScale; mp_msg(MSGT_MENCODER, MSGL_INFO, MSGTR_SettingAudioDelay,mux_a->h.dwStart*mux_a->h.dwScale/(float)mux_a->h.dwRate); } -if(muxer->fix_stream_parameters) - muxer_stream_fix_parameters(muxer,mux_a); } // if(sh_audio) -mp_msg(MSGT_MENCODER, MSGL_INFO, MSGTR_WritingAVIHeader); -if (muxer->cont_write_header) muxer_write_header(muxer); - decoded_frameno=0; signal(SIGINT,exit_sighandler); // Interrupt from keyboard