Index: cfg-mencoder.h =================================================================== RCS file: /cvsroot/mplayer/main/cfg-mencoder.h,v retrieving revision 1.89 diff -c -u -c -u -r1.89 cfg-mencoder.h --- cfg-mencoder.h 21 Sep 2004 19:45:49 -0000 1.89 +++ cfg-mencoder.h 21 Nov 2004 09:55:24 -0000 @@ -72,6 +72,7 @@ #endif extern m_option_t nuvopts_conf[]; +extern m_option_t mpegopts_conf[]; m_option_t ovc_conf[]={ {"copy", &out_video_codec, CONF_TYPE_FLAG, 0, 0, VCODEC_COPY, NULL}, @@ -269,6 +270,8 @@ #endif {"nuvopts", nuvopts_conf, CONF_TYPE_SUBCONFIG, 0, 0, 0, NULL}, + {"mpegopts", mpegopts_conf, CONF_TYPE_SUBCONFIG, 0, 0, 0, NULL}, + #define MAIN_CONF #include "cfg-common.h" Index: mencoder.c =================================================================== RCS file: /cvsroot/mplayer/main/mencoder.c,v retrieving revision 1.257 diff -c -u -c -u -r1.257 mencoder.c --- mencoder.c 15 Nov 2004 09:09:27 -0000 1.257 +++ mencoder.c 21 Nov 2004 09:55:25 -0000 @@ -385,7 +385,8 @@ int decoded_frameno=0; int next_frameno=-1; - +sh_video_t *vsh = NULL; +sh_audio_t *ash = NULL; unsigned int timer_start; mp_msg_init(); @@ -637,6 +638,8 @@ mencoder_exit(1,NULL); } +if(out_file_format==MUXER_TYPE_MPEG) + audio_preload = 0; muxer=muxer_new_muxer(out_file_format,muxer_f); // ============= VIDEO =============== @@ -647,6 +650,9 @@ mux_v->buffer=malloc(mux_v->buffer_size); mux_v->source=sh_video; +mux_v->osh = new_osh_audio(mux_v); +memcpy(mux_v->osh, sh_video, sizeof(sh_video_t)); +vsh = (sh_video_t *) mux_v->osh; mux_v->h.dwSampleSize=0; // VBR #ifdef USE_LIBAVCODEC @@ -741,6 +747,7 @@ { mux_v->bih->biCompression = mmioFOURCC(force_fourcc[0], force_fourcc[1], force_fourcc[2], force_fourcc[3]); + vsh->format = mux_v->bih->biCompression; mp_msg(MSGT_FIXME, MSGL_FIXME, MSGTR_ForcingOutputFourcc, mux_v->bih->biCompression, (char *)&mux_v->bih->biCompression); } @@ -758,6 +765,10 @@ mencoder_exit(1,MSGTR_MemAllocFailed); mux_a->source=sh_audio; +mux_a->osh = new_osh_audio(mux_a); +memcpy(mux_a->osh, sh_audio, sizeof(sh_audio_t)); +ash = (sh_audio_t *) mux_a->osh; + mux_a->codec=out_audio_codec; @@ -1060,6 +1071,7 @@ } if (verbose>1) print_wave_header(mux_a->wf); +ash->format = mux_a->wf->wFormatTag; if(audio_delay!=0.0){ mux_a->h.dwStart=audio_delay*mux_a->h.dwRate/mux_a->h.dwScale; @@ -1391,6 +1403,8 @@ switch(mux_v->codec){ case VCODEC_COPY: mux_v->buffer=start; + vsh->fps = sh_video->fps; + vsh->frametime = sh_video->frametime; if(skip_flag<=0) muxer_write_chunk(mux_v,in_size,(sh_video->ds->flags&1)?0x10:0); break; case VCODEC_FRAMENO: @@ -1401,6 +1415,8 @@ // decode_video will callback down to ve_*.c encoders, through the video filters blit_frame=decode_video(sh_video,start,in_size, skip_flag>0 && (!sh_video->vfilter || ((vf_instance_t *)sh_video->vfilter)->control(sh_video->vfilter, VFCTRL_SKIP_NEXT_FRAME, 0) != CONTROL_TRUE)); + vsh->fps = (force_ofps ? force_ofps : sh_video->fps); + vsh->frametime = 1.0/vsh->fps; if(!blit_frame){ badframes++; if(skip_flag<=0){ Index: libmpdemux/muxer.c =================================================================== RCS file: /cvsroot/mplayer/main/libmpdemux/muxer.c,v retrieving revision 1.5 diff -c -u -c -u -r1.5 muxer.c --- libmpdemux/muxer.c 28 Apr 2004 10:18:33 -0000 1.5 +++ libmpdemux/muxer.c 21 Nov 2004 09:55:25 -0000 @@ -12,6 +12,11 @@ #include "ms_hdr.h" #include "muxer.h" +#include "stream.h" +#include "demuxer.h" +#include "mp_msg.h" +#include "help_mp.h" +#include "stheader.h" muxer_t *muxer_new_muxer(int type,FILE *f){ muxer_t* muxer=malloc(sizeof(muxer_t)); @@ -30,3 +35,32 @@ } return muxer; } + + +sh_audio_t* new_osh_audio(muxer_stream_t *s) +{ + return (sh_audio_t*)calloc(1, sizeof(sh_audio_t)); +} + +void free_osh_audio(sh_audio_t* sh) +{ + mp_msg(MSGT_DEMUXER,MSGL_V,"DEMUXER: freeing sh_audio at %p \n", sh); + if(sh->wf) + free(sh->wf); + free(sh); +} + +sh_audio_t* new_osh_video(muxer_stream_t *s) +{ + return (sh_video_t*)calloc(1, sizeof(sh_video_t)); +} + + +void free_osh_video(sh_video_t* sh) +{ + mp_msg(MSGT_DEMUXER,MSGL_V,"DEMUXER: freeing sh_video at %p \n",sh); + if(sh->bih) + free(sh->bih); + free(sh); +} + Index: libmpdemux/muxer.h =================================================================== RCS file: /cvsroot/mplayer/main/libmpdemux/muxer.h,v retrieving revision 1.11 diff -c -u -c -u -r1.11 muxer.h --- libmpdemux/muxer.h 24 Mar 2004 15:16:36 -0000 1.11 +++ libmpdemux/muxer.h 21 Nov 2004 09:55:25 -0000 @@ -8,7 +8,6 @@ #define MUXER_TYPE_MPEG 1 #define MUXER_TYPE_RAWVIDEO 2 -#define MUXER_MPEG_BLOCKSIZE 2048 // 2048 or 2324 - ? typedef struct { // muxer data: @@ -24,7 +23,9 @@ unsigned int buffer_len; // mpeg block buffer: unsigned char *b_buffer; - unsigned int b_buffer_ptr; + 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 // source stream: void* source; // sh_audio or sh_video int codec; // codec used for encoding. 0 means copy @@ -38,6 +39,7 @@ size_t ipb[3]; // sizes of I/P/B frames // muxer of that stream struct muxer_t *muxer; + void *osh; void *priv; // private stream specific data stored by the muxer } muxer_stream_t; @@ -67,6 +69,7 @@ void (*cont_write_index)(struct muxer_t *); muxer_stream_t* (*cont_new_stream)(struct muxer_t *,int); FILE* file; + void *priv; } muxer_t; muxer_t *muxer_new_muxer(int type,FILE *); @@ -75,6 +78,6 @@ #define muxer_write_header(muxer) muxer->cont_write_header(muxer) #define muxer_write_index(muxer) muxer->cont_write_index(muxer) -void muxer_init_muxer_avi(muxer_t *); -void muxer_init_muxer_mpeg(muxer_t *); -void muxer_init_muxer_rawvideo(muxer_t *); +muxer_t *muxer_init_muxer_avi(muxer_t *); +muxer_t *muxer_init_muxer_mpeg(muxer_t *); +muxer_t *muxer_init_muxer_rawvideo(muxer_t *); Index: libmpdemux/muxer_avi.c =================================================================== RCS file: /cvsroot/mplayer/main/libmpdemux/muxer_avi.c,v retrieving revision 1.29 diff -c -u -c -u -r1.29 muxer_avi.c --- libmpdemux/muxer_avi.c 5 Sep 2004 16:55:06 -0000 1.29 +++ libmpdemux/muxer_avi.c 21 Nov 2004 09:55:25 -0000 @@ -660,9 +660,10 @@ } } -void muxer_init_muxer_avi(muxer_t *muxer){ +muxer_t *muxer_init_muxer_avi(muxer_t *muxer){ 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; } Index: libmpdemux/muxer_mpeg.c =================================================================== RCS file: /cvsroot/mplayer/main/libmpdemux/muxer_mpeg.c,v retrieving revision 1.4 diff -c -u -c -u -r1.4 muxer_mpeg.c --- libmpdemux/muxer_mpeg.c 28 Apr 2004 10:18:33 -0000 1.4 +++ libmpdemux/muxer_mpeg.c 21 Nov 2004 09:55:25 -0000 @@ -14,76 +14,247 @@ #include "ms_hdr.h" #include "muxer.h" +#include "stream.h" +#include "demuxer.h" +#include "stheader.h" +#include "../m_option.h" + +#define PACK_HEADER_START_CODE 0x01ba +#define SYSTEM_HEADER_START_CODE 0x01bb + +#define PES_PRIVATE1 0x01bd +#define PES_PRIVATE2 0x01bf + +#define MUX_MPEG1 1 +#define MUX_MPEG2 2 + +#define VIDEO_MPEG1 0x10000001 +#define VIDEO_MPEG2 0x10000002 +#define AUDIO_MP2 0x50 +#define AUDIO_MP3 0x55 +#define AUDIO_A52 0x2000 +#define AUDIO_LPCM 0x10001 /* only a placeholder at the moment */ + +#define ASPECT_1_1 1 +#define ASPECT_4_3 2 +#define ASPECT_16_9 3 +#define ASPECT_2_21_1 4 + +#define FRAMERATE_23976 1 +#define FRAMERATE_24 2 +#define FRAMERATE_25 3 +#define FRAMERATE_2997 4 +#define FRAMERATE_30 5 +#define FRAMERATE_50 6 +#define FRAMERATE_5994 7 +#define FRAMERATE_60 8 + +#define FRAMETYPE(x) ((x) == 1 ? 'I' : ((x) == 2 ? 'P' : 'B')) + +static const char *framerates[] = { + "unchanged", "23.976", "24", "25", "29.97", "30", "50", "59.94", "60" +}; + +static const char *aspect_ratios[] = { + "unchanged", "1/1", "4/3", "16/9", "2.21/1" +}; + +static char *conf_mux = "mpeg2"; +static uint16_t conf_packet_size = 2048; //dvd +static uint32_t conf_muxrate = 2080; //kb/s +static char *conf_vaspect = NULL, *conf_vframerate = NULL; +static uint32_t conf_vwidth = 0, conf_vheight = 0; +static uint32_t conf_vbitrate = 0; +static int conf_init_vpts = 200, conf_init_apts = 200; +static int conf_use_ppts = 0, conf_use_bpts = 0; +static int conf_init_adelay = 0; + +enum FRAME_TYPE { + I_FRAME = 1, + P_FRAME = 2, + B_FRAME = 3 +}; + +typedef struct { + uint8_t *buffer; + size_t size; + size_t alloc_size; + uint8_t type; + uint32_t temp_ref; + double duration; + uint64_t pts, dts, idur; + uint32_t gop; +} mpeg_frame_t; + +typedef struct { + int mux; + uint16_t packet_size; + int is_dvd, is_xvcd, is_xsvcd, use_ppts, use_bpts, has_video, has_audio, use_isoend; + int use_padding; + int use_system_header; + off_t headers_size, data_size; + uint64_t scr, vbytes, abytes, init_delay_pts; + uint32_t muxrate; + uint8_t *buff; + //video patching parameters + uint8_t vaspect, vframerate; + uint16_t vwidth, vheight; + uint32_t vbitrate; + int patch_seq; + int vbuffer_size; + double init_adelay; +} muxer_priv_t; + + +typedef struct { + int has_pts, has_dts, pes_is_aligned, type, is_late, variable_framerate; + uint64_t pts, last_pts, last_dts, dts, frame_size, init_pts, init_dts, size, last_duration, delta_pts; + uint32_t buffer_size; + uint8_t pes_priv_headers[4], has_pes_priv_headers; //for A52 and LPCM + uint32_t bitrate, rest; + int32_t compensate; + double delta_clock, timer, aframe_delta_pts, last_dpts; + mpeg_frame_t *framebuf; + uint16_t framebuf_cnt; + uint16_t framebuf_used; + uint16_t max_pl_size; +} muxer_headers_t; + + +m_option_t mpegopts_conf[] = { + {"format", &(conf_mux), CONF_TYPE_STRING, 0, 0 ,0, NULL}, + {"size", &(conf_packet_size), CONF_TYPE_INT, CONF_RANGE, 0, 65535, NULL}, + {"muxrate", &(conf_muxrate), CONF_TYPE_INT, CONF_RANGE, 0, 12000000, NULL}, //12 Mb/s + {"vaspect", &(conf_vaspect), CONF_TYPE_STRING, 0, 0, 0, NULL}, + {"vframerate", &(conf_vframerate), CONF_TYPE_STRING, 0, 0, 0, NULL}, + {"vwidth", &(conf_vwidth), CONF_TYPE_INT, CONF_RANGE, 1, 4095, NULL}, + {"vheight", &(conf_vheight), CONF_TYPE_INT, CONF_RANGE, 1, 4095, NULL}, + {"vbitrate", &(conf_vbitrate), CONF_TYPE_INT, CONF_RANGE, 1, 104857599, NULL}, + {"init_vpts", &(conf_init_vpts), CONF_TYPE_INT, CONF_RANGE, 35, 500, NULL}, //2*frametime at 60fps + {"init_apts", &(conf_init_apts), CONF_TYPE_INT, CONF_RANGE, 35, 500, NULL}, + {"init_adelay", &conf_init_adelay, CONF_TYPE_INT, 0, 0, 0, NULL}, + {"use_ppts", &conf_use_ppts, CONF_TYPE_FLAG, 0, 0, 1, NULL}, + {"use_bpts", &conf_use_bpts, CONF_TYPE_FLAG, 0, 0, 1, NULL}, + {NULL, NULL, 0, 0, 0, 0, NULL} +}; + + +static mpeg_frame_t *init_frames(uint16_t num, size_t size) +{ + mpeg_frame_t *tmp; + uint16_t i; + + tmp = (mpeg_frame_t *) calloc(num, sizeof(mpeg_frame_t)); + if(tmp == NULL) + return NULL; + + for(i=0; i < num; i++) + { + tmp[i].buffer = (uint8_t *) calloc(1, size); + if(tmp[i].buffer == NULL) + return NULL; + tmp[i].size = 0; + tmp[i].alloc_size = size; + tmp[i].pts = 0; + } + + return tmp; +} -// 18 bytes reserved for block headers and STD -#define MUXER_MPEG_DATASIZE (MUXER_MPEG_BLOCKSIZE-18) - -// ISO-11172 requirements -#define MPEG_MAX_PTS_DELAY 90000 /* 1s */ -#define MPEG_MAX_SCR_INTERVAL 63000 /* 0.7s */ - -// suggestions -#define MPEG_STARTPTS 45000 /* 0.5s */ -#define MPEG_MIN_PTS_DELAY 9000 /* 0.1s */ -#define MPEG_STARTSCR 9 /* 0.1ms */ - -//static unsigned int mpeg_min_delay; -//static unsigned int mpeg_max_delay; +static uint32_t calc_pack_hlen(int format, muxer_headers_t *h); static muxer_stream_t* mpegfile_new_stream(muxer_t *muxer,int type){ + muxer_priv_t *priv = (muxer_priv_t*) muxer->priv; muxer_stream_t *s; + muxer_headers_t *spriv; if (!muxer) return NULL; if(muxer->avih.dwStreams>=MUXER_MAX_STREAMS){ - printf("Too many streams! increase MUXER_MAX_STREAMS !\n"); + mp_dbg(MSGT_MUXER, MSGL_ERR, "Too many streams! increase MUXER_MAX_STREAMS !\n"); return NULL; } switch (type) { case MUXER_TYPE_VIDEO: if (muxer->num_videos >= 15) { - printf ("MPEG stream can't contain above of 15 video streams!\n"); + mp_dbg(MSGT_MUXER, MSGL_ERR, "MPEG stream can't contain above of 15 video streams!\n"); return NULL; } break; case MUXER_TYPE_AUDIO: if (muxer->avih.dwStreams - muxer->num_videos >= 31) { - printf ("MPEG stream can't contain above of 31 audio streams!\n"); + mp_dbg(MSGT_MUXER, MSGL_ERR, "MPEG stream can't contain above of 31 audio streams!\n"); return NULL; } break; default: - printf ("Unknown stream type!\n"); + mp_dbg(MSGT_MUXER, MSGL_ERR, "Unknown stream type!\n"); return NULL; } - s=malloc(sizeof(muxer_stream_t)); - memset(s,0,sizeof(muxer_stream_t)); + s = (muxer_stream_t*) calloc(1, sizeof(muxer_stream_t)); if(!s) return NULL; // no mem!? - if (!(s->b_buffer = malloc (MUXER_MPEG_BLOCKSIZE))) { + if (!(s->b_buffer = malloc(priv->packet_size))) { free (s); return NULL; // no mem?! } + s->b_buffer_size = priv->packet_size; + s->b_buffer_ptr = 0; + s->b_buffer_len = 0; + s->priv = (muxer_headers_t*) calloc(1, sizeof(muxer_headers_t)); + if(s->priv == NULL) { + free(s); + return NULL; + } + spriv = (muxer_headers_t *) s->priv; muxer->streams[muxer->avih.dwStreams]=s; s->type=type; s->id=muxer->avih.dwStreams; - s->timer=0.0; - s->size=0; s->muxer=muxer; + if (type == MUXER_TYPE_VIDEO) { + spriv->init_dts = 0; + spriv->init_pts = conf_init_vpts * 90 * 1024; + spriv->last_pts = spriv->init_pts; + spriv->init_dts = spriv->last_dts = spriv->init_pts; + spriv->pts = spriv->dts = 0; + spriv->last_dpts = spriv->timer; + spriv->delta_pts = 0; s->ckid = be2me_32 (0x1e0 + muxer->num_videos); muxer->num_videos++; + priv->has_video++; s->h.fccType=streamtypeVIDEO; if(!muxer->def_v) muxer->def_v=s; + spriv->framebuf_cnt = 30; + spriv->framebuf_used = 0; + spriv->framebuf = init_frames(spriv->framebuf_cnt, (size_t) 5000); + if(spriv->framebuf == NULL) { + mp_msg(MSGT_MUXER, MSGL_FATAL, "Couldn't allocate initial frames structure, abort!\n"); + return NULL; + } + if(priv->is_dvd) + priv->vbuffer_size = 232*1024; + else if(priv->is_xsvcd) + priv->vbuffer_size = 92*1024; + else //if(priv->is_vcd) + priv->vbuffer_size = 46*1024; mp_msg (MSGT_MUXER, MSGL_DBG2, "Added video stream %d, ckid=%X\n", muxer->num_videos, s->ckid); } else { // MUXER_TYPE_AUDIO + spriv->pts = 1; + spriv->dts = 0; + spriv->max_pl_size = priv->packet_size - calc_pack_hlen(priv->mux, spriv); + spriv->init_pts = conf_init_apts * 90 * 1024; + spriv->pts = spriv->init_pts; + spriv->dts = 0; s->ckid = be2me_32 (0x1c0 + s->id - muxer->num_videos); s->h.fccType=streamtypeAUDIO; + priv->has_audio++; mp_msg (MSGT_MUXER, MSGL_DBG2, "Added audio stream %d, ckid=%X\n", s->id - muxer->num_videos + 1, s->ckid); } muxer->avih.dwStreams++; return s; } -static void write_mpeg_ts(unsigned char *b, unsigned int ts, char mod) { +static void write_mpeg_ts(unsigned char *b, uint64_t ts, char mod) { + ts >>= 10; b[0] = ((ts >> 29) & 0xf) | 1 | mod; b[1] = (ts >> 22) & 0xff; b[2] = ((ts >> 14) & 0xff) | 1; @@ -91,356 +262,1440 @@ b[4] = ((ts << 1) & 0xff) | 1; } -static void write_mpeg_rate(unsigned char *b, unsigned int rate) { - if (rate) - rate--; // for round upward - rate /= 50; - rate++; // round upward - 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) - size--; // for round upward - if (size < (128 << 8)) - size >>= 7; // by 128 bytes - else { - size >>= 10; - size |= 0x2000; // by 1kbyte - } - size++; // round upward - b[0] = ((size >> 8) & 0x3f) | 0x40 | mod; - b[1] = size & 0xff; -} - -static int write_mpeg_block(muxer_t *muxer, muxer_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=0; - uint16_t l1; - - mp_dbg(MSGT_MUXER, MSGL_DBG3, " MPEG block: size=%u, scr=%u, rate=%u, id=%X;", len, muxer->file_end, muxer->sysrate, s->ckid); - if (s->b_buffer_ptr == 0) { // 00001111 if no PTS - s->b_buffer[0] = 0xf; - s->b_buffer_ptr = 1; - sz = MUXER_MPEG_DATASIZE-1; - } else if (s->b_buffer_ptr > MUXER_MPEG_DATASIZE) { - printf ("Unknown error in write_mpeg_block()!\n"); - return 0; - } else { - sz = MUXER_MPEG_DATASIZE - s->b_buffer_ptr; - if (s->b_buffer[7] == 0xff) // PTS not set yet - s->b_buffer[11] = 0xf; // terminate stuFFing bytes - } - if (len > sz) - len = sz; - *(uint32_t *)buff = be2me_32 (0x1ba); - write_mpeg_ts (buff+4, muxer->file_end, 0x20); // 0010 and SCR - write_mpeg_rate (buff+9, muxer->sysrate); - fwrite (buff, 12, 1, f); - fwrite (&s->ckid, 4, 1, f); // stream_id - memset (buff, 0xff, 12); // stuFFing bytes - sz -= len; - // calculate padding bytes in buffer - while (mints < s->b_buffer_ptr && s->b_buffer[mints] == 0xff) mints++; - if (mints+sz < 12) { // cannot write padding block so write up to 12 stuFFing bytes - l1 = be2me_16 (MUXER_MPEG_DATASIZE); - fwrite (&l1, 2, 1, f); - mints = 0; // so stuFFed bytes will be written all - if (sz) - fwrite (buff, sz, 1, f); - sz = 0; // no padding block anyway - } else { // use padding block - if (sz > 6) // sufficient for PAD header so don't shorter data - mints = 0; - else - sz += mints; // skip stuFFing bytes (sz>8 here) - l1 = be2me_16 (s->b_buffer_ptr+len-mints); - fwrite (&l1, 2, 1, f); - } - if (s->b_buffer_ptr) - fwrite (s->b_buffer+mints, s->b_buffer_ptr-mints, 1, f); - if (len) - fwrite (bl, len, 1, f); - if (sz > 6) { // padding block (0x1be) - uint32_t l0; - if (isoend) - l0 = be2me_32 (0x1b9); - else - l0 = be2me_32 (0x1be); - sz -= 6; - l1 = be2me_16 (sz); - fwrite (&l0, 4, 1, f); - fwrite (&l1, 2, 1, f); - memset (s->b_buffer, 0xff, sz); // stuFFing bytes - fwrite (s->b_buffer, sz, 1, f); - } - s->b_buffer_ptr = 0; - muxer->movi_end += MUXER_MPEG_BLOCKSIZE; - // prepare timestamps for next pack - mints = (MUXER_MPEG_BLOCKSIZE*90000/muxer->sysrate)+1; // min ts delta - sz = (int)(s->timer*90000) + MPEG_STARTPTS; // new PTS - if (sz > muxer->file_end) - sz -= muxer->file_end; // suggested ts delta - else - { - sz = 0; - printf ("Error in stream: PTS earlier than SCR!\n"); - } - if (sz > MPEG_MAX_PTS_DELAY) { -// printf ("Warning: attempt to set PTS to SCR delay to %u \n", sz); - mints = sz-MPEG_MAX_PTS_DELAY; // try to compensate - if (mints > MPEG_MAX_SCR_INTERVAL) { - printf ("Error in stream: SCR interval %u is too big!\n", mints); - } - } else if (sz > 54000) // assume 0.3...0.7s is optimal - mints += (sz-45000)>>2; // reach 0.5s in 4 blocks ? - else if (sz < 27000) { - unsigned int newsysrate = 0; - - if (s->timer > 0.5) // too early to calculate??? - newsysrate = muxer->movi_end/(s->timer*0.4); // pike-factor 2.5 (8dB) - if (sz < MPEG_MIN_PTS_DELAY) - printf ("Error in stream: PTS to SCR delay %u is too little!\n", sz); - if (muxer->sysrate < newsysrate) - muxer->sysrate = newsysrate; // increase next rate to current rate - else if (!newsysrate) - muxer->sysrate += muxer->sysrate>>3; // increase next rate by 25% - } - muxer->file_end += mints; // update the system timestamp - return len; -} - -static void set_mpeg_pts(muxer_t *muxer, muxer_stream_t *s, unsigned int pts) { - unsigned int dts, nts; - - if (s->b_buffer_ptr != 0 && s->b_buffer[7] != 0xff) - return; // already set - if (s->b_buffer_ptr == 0) { - memset (s->b_buffer, 0xff, 7); // reserved for PTS or STD, stuFFing for now - s->b_buffer_ptr = 12; - } - dts = (int)(s->timer*90000) + MPEG_STARTPTS; // PTS - if (pts) { - write_mpeg_ts (s->b_buffer+2, pts, 0x30); // 0011 and both PTS/DTS - } else { - write_mpeg_ts (s->b_buffer+7, dts, 0x20); // 0010 and PTS only - return; - } - nts = dts - muxer->file_end; -// if (nts < mpeg_min_delay) mpeg_min_delay = nts; -// if (nts > mpeg_max_delay) mpeg_max_delay = nts; - nts = 180000*s->h.dwScale/s->h.dwRate; // two frames - if (dts-nts < muxer->file_end) { - dts += muxer->file_end; - dts /= 2; // calculate average time - printf ("Warning: DTS to SCR delay is too small\n"); - } - else - dts -= nts/2; // one frame :) - mp_dbg(MSGT_MUXER, MSGL_DBG3, ", dts=%u", dts); - write_mpeg_ts (s->b_buffer+7, dts, 0x10); +static void write_mpeg_rate(int type, unsigned char *b, unsigned int rate) +{ + rate = (rate+49) / 50; + + if(type == MUX_MPEG1) + { + b[0] = ((rate >> 15) & 0x7f) | 0x80; + b[1] = (rate >> 7) & 0xff; + b[2] = ((rate << 1) & 0xff) | 1; + } + else + { + b[0] = (rate >> 14); + b[1] = (rate >> 6) & 0xff; + b[2] = ((rate & 0x3f) << 2) | 0x03; + } +} + + +static void write_mpeg_std(unsigned char *b, unsigned int size, unsigned int type, char mod) +{ + //type = 0:mpeg audio/128, 1:video and pes private streams (including ac3/dts/lpcm)/1024 + if (size) + size--; // for round upward + if(type == 0) + size >>= 7; + else + { + size >>= 10; + size |= 0x2000; // by 1kbyte + } + + size++; // round upward + b[0] = ((size >> 8) & 0x3f) | 0x40 | mod; + b[1] = size & 0xff; +} + +static void write_mpeg2_scr(unsigned char *b, uint64_t ts) +{ + uint16_t t1, t2, t3; + ts >>= 10; + ts &= 0x1FFFFFFFFULL; //33 bits, no extension; input must be * 92160000 + t1 = (ts >> 30) & 0x7;; + t2 = (ts >> 15) & 0x7fff; + t3 = ts & 0x7fff; + + b[0] = (t1 << 3 ) | 0x44 | ((t2 >> 13) & 0x3); + b[1] = (t2 >> 5); + b[2] = (t2 & 0x1f) << 3 | 0x4 | ((t3 >> 13) & 0x3); + b[3] = (t3 >> 5); + b[4] = (t3 & 0x1f) << 3 | 0x4; + b[5] = 1; +} + + +static int write_mpeg_pack_header(muxer_t *muxer, char *buff) +{ + int len; + muxer_priv_t *priv; + + priv = (muxer_priv_t *) muxer->priv; + *(uint32_t *)buff = be2me_32(PACK_HEADER_START_CODE); + if(priv->mux==MUX_MPEG1) + { + write_mpeg_ts(&buff[4], priv->scr, 0x20); // 0010 and SCR + write_mpeg_rate(priv->mux, &buff[9], muxer->sysrate); + len = 12; + } + else + { + write_mpeg2_scr(&buff[4], priv->scr); // 0010 and SCR + write_mpeg_rate(priv->mux, &buff[10], muxer->sysrate); + buff[13] = 0xf8; //5 bits reserved + 3 set to 0 to indicate 0 stuffing bytes + len = 14; + } + + return len; +} + + +static int write_mpeg_system_header(muxer_t *muxer, char *buff) +{ + int len; + muxer_priv_t *priv; + priv = (muxer_priv_t *) muxer->priv; + + len = 0; + *(uint32_t *)(&buff[len]) = be2me_32(SYSTEM_HEADER_START_CODE); + len += 4; + *(uint16_t *)(&buff[len]) = 0; //fake length + len += 2; + write_mpeg_rate(MUX_MPEG1, &buff[len], muxer->sysrate); + len += 3; + buff[len++] = 0x4; //1 audio stream bound, no fixed, no csps + buff[len++] = 0xe1; //system_audio_lock, system_video_lock, marker, 1 video stream bound + buff[len++] = (priv->mux == MUX_MPEG1 ? 0xff : 0x7f); + + buff[len++] = 0xb9; // all video streams + write_mpeg_std(&buff[len], priv->vbuffer_size, 1, 0xc0); //this is an approximation, let's see... + len += 2; + + buff[len++] = 0xb8; // all MPEG audio streams + write_mpeg_std(&buff[len], 4*1024, 0, 0xc0); + len += 2; + + buff[len++] = 0xbd; // all private1 streams + write_mpeg_std(&buff[len], 58*1024, 1, 0xc0); + len += 2; + + buff[len++] = 0xbf; // all private2 streams + write_mpeg_std(&buff[len], 2*1024, 1, 0xc0); + len += 2; + + *(uint16_t *)(&buff[4]) = be2me_16(len - 6); // fix length field + + return len; +} + + + +static int write_mpeg_pes_header(muxer_headers_t *h, uint8_t *pes_id, uint8_t *buff, uint16_t plen, int stuffing_len, int mux_type) +{ + int len; + + len = 0; + memcpy(&buff[len], pes_id, 4); + len += 4; + + buff[len] = buff[len+1] = 0; //fake len + len += 2; + + if(mux_type == MUX_MPEG1) + { + if(stuffing_len > 0) + { + memset(&buff[len], 0xff, stuffing_len); + len += stuffing_len; + } + write_mpeg_std(&buff[len], h->buffer_size, h->type, 0x40); // 01 is pes1 format + len += 2; + + } + else //MPEG2 + { + buff[len] = (h->pes_is_aligned ? 0x84 : 0x80); //0x10... + len++; + buff[len] = ((h->buffer_size > 0) ? 1 : 0) | (h->pts ? (h->dts ? 0xC0 : 0x80) : 0); //pes extension + pts/dts flags + len++; + buff[len] = (h->pts ? (h->dts ? 10 : 5) : 0) + ((h->buffer_size > 0) ? 3 : 0) + stuffing_len;//pts + std + stuffing + len++; + } + + + if(h->pts) + { + write_mpeg_ts(&buff[len], h->pts, (h->dts ? 0x30 : 0x20)); // 001x and both PTS/DTS + len += 5; + + if(h->dts) + { + write_mpeg_ts(&buff[len], h->dts, 0x1); // 0001 before DTS + len += 5; + } + } + else + { + if(mux_type == MUX_MPEG1) + { + buff[len] = 0x0f; + len += 1; + } + } + + + if(mux_type == MUX_MPEG2) + { + if(h->buffer_size > 0) + { + buff[len] = 0x10; //std flag + len++; + + write_mpeg_std(&buff[len], h->buffer_size, h->type, 0x40); + len += 2; + } + + if(stuffing_len > 0) + { + memset(&buff[len], 0xff, stuffing_len); + len += stuffing_len; + } + } + + if(h->has_pes_priv_headers > 0) + { + memcpy(&buff[len], h->pes_priv_headers, h->has_pes_priv_headers); + len += h->has_pes_priv_headers; + } + + *((uint16_t*) &buff[4]) = be2me_16(len + plen - 6); //fix pes packet size + return len; +} + + +static void write_pes_padding(uint8_t *buff, uint16_t len) +{ + //6 header bytes + len-6 0xff chars + buff[0] = buff[1] = 0; + buff[2] = 1; + buff[3] = 0xbe; + *((uint16_t*) &buff[4]) = be2me_16(len - 6); + memset(&buff[6], 0xff, len - 6); +} + + +static int write_nav_pack(uint8_t *buff) +{ + // concatenation of pes_private2 + 03d4 x 0 and pes_private2 + 03fa x 0 + int len; + + mp_msg(MSGT_MUXER, MSGL_V, "NAV\n"); + len = 0; + *(uint32_t *)(&buff[len]) = be2me_32(PES_PRIVATE2); + len += 4; + buff[len++] = 0x3; + buff[len++] = 0xd4; + memset(&buff[len], 0, 0x03d4); + len += 0x03d4; + + *(uint32_t *)(&buff[len]) = be2me_32(PES_PRIVATE2); + len += 4; + buff[len++] = 0x3; + buff[len++] = 0xfa; + memset(&buff[len], 0, 0x03fa); + len += 0x03fa; + + return len; +} + +static uint32_t calc_pes_hlen(int format, muxer_headers_t *h) +{ + uint32_t len; + + if(format == MUX_MPEG1) + len = 8; + else + len = 9; //era 12 + + if(h->pts) + { + len += 5; + if(h->dts) + len += 5; + } + else if(format == MUX_MPEG1) + len += 1; + + if(format == MUX_MPEG2) + { + if(h->buffer_size > 0) + len += 3; + } + + len += h->has_pes_priv_headers; + + return len; +} + +static uint32_t calc_pack_hlen(int format, muxer_headers_t *h) +{ + uint32_t len; + + if(format == MUX_MPEG1) + len = 12; + else + len = 14; + + len += calc_pes_hlen(format, h); + + return len; +} + + +static int write_mpeg_pack(muxer_t *muxer, muxer_stream_t *s, FILE *f, char *bl, uint32_t len, int isoend) +{ + size_t tot, offset, pes_hlen, pack_hlen; + muxer_priv_t *priv; + uint8_t *buff; + int stuffing_len = 0, stflen, pl; + muxer_headers_t *headers; + uint32_t divd; + + priv = (muxer_priv_t *) muxer->priv; + divd = (priv->mux == MUX_MPEG1 ? 1 : 1); + buff = priv->buff; + + if(isoend) + { + buff[0] = buff[1] = 0; + buff[1] = 1; + buff[2] = 0xb9; + fwrite(buff, 4, 1, f); + return 1; + } + + if((len == 0) || (bl == NULL)) //PACK headers only + { + offset = write_mpeg_pack_header(muxer, buff); + + if(priv->use_system_header) + offset += write_mpeg_system_header(muxer, &buff[offset]); + + if(priv->is_dvd) + offset += write_nav_pack(&buff[offset]); + + stuffing_len = priv->packet_size - offset; + if(stuffing_len > 0) + { + //insert a PES padding packet + write_pes_padding(&buff[offset], stuffing_len); + offset += stuffing_len; + } + + fwrite(buff, offset, 1, f); + priv->headers_size += offset; + tot = offset; + muxer->movi_end += tot; + + return tot; + } + else + { + headers = (muxer_headers_t *) s->priv; + + mp_msg(MSGT_MUXER, MSGL_V, "\nmpeg_write_pack(MUX=%d, len=%u, rate=%u, id=%X, pts: %llu, dts: %llu, scr: %llu, PACK_size:%u\n", + priv->mux, len, muxer->sysrate, s->ckid, headers->pts, headers->dts, priv->scr, priv->packet_size); + + offset = 0; + offset = pack_hlen = write_mpeg_pack_header(muxer, &buff[offset]); + + pl = pes_hlen = calc_pes_hlen(priv->mux, headers); + if(len >= priv->packet_size - pack_hlen - pes_hlen) + stuffing_len = 0; + else + stuffing_len = priv->packet_size - pack_hlen - pes_hlen - len; + + if(stuffing_len < 8) + { + stflen = stuffing_len; + stuffing_len = 0; + } + else + stflen = 0; + + len = priv->packet_size - pack_hlen - pes_hlen - stflen - stuffing_len; + mp_msg(MSGT_MUXER, MSGL_V, "LEN=%d, pack: %d, pes: %d, stf: %d, stf2: %d\n", len, pack_hlen, pes_hlen, stflen, stuffing_len); + + pes_hlen = write_mpeg_pes_header(headers, (uint8_t *) &s->ckid, &buff[offset], len, stflen, priv->mux); + + offset += pes_hlen; + + fwrite(buff, offset, 1, f); + mp_msg(MSGT_MUXER, MSGL_V, "pack_len = %u, pes_hlen = %u, stuffing_len: %d+%d, SCRIVO: %d bytes di payload\n", pack_hlen, pes_hlen, stuffing_len, stflen, len); + fwrite(bl, len, 1, f); //era base + + offset += len; + + if(stuffing_len > 0) + { + //insert a PES padding packet + mp_msg(MSGT_MUXER, MSGL_V, "STUFFING: %d\n", stuffing_len); + write_pes_padding(buff, stuffing_len); + fwrite(buff, stuffing_len, 1, f); + } + else + stuffing_len = 0; + + offset += stuffing_len; + + mp_msg(MSGT_MUXER, MSGL_V, "\nwritten len=%d, headers: pack(%d), pes(%d), stuffing(%d) tot(%d), offset: %d\n", + len, pack_hlen, pes_hlen, stuffing_len, pack_hlen + pes_hlen + stuffing_len, offset); + + priv->headers_size += pack_hlen + pes_hlen + stuffing_len; + priv->data_size += len; + muxer->movi_end += offset; + + return len; + } +} + + +static void patch_seq(muxer_priv_t *priv, unsigned char *buf) +{ + if(priv->vwidth > 0) + { + buf[4] = (priv->vwidth >> 4) & 0xff; + buf[5] &= 0x0f; + buf[5] |= (priv->vwidth & 0x0f) << 4; + } + + if(priv->vheight > 0) + { + buf[5] &= 0xf0; + buf[5] |= (priv->vheight >> 8) & 0x0f; + buf[6] = priv->vheight & 0xff; + } + + if(priv->vaspect > 0) + buf[7] = (buf[7] & 0x0f) | (priv->vaspect << 4); + + if(priv->vframerate > 0) + buf[7] = (buf[7] & 0xf0) | priv->vframerate; + + if(priv->vbitrate > 0) + { + buf[8] = (priv->vbitrate >> 10); + buf[9] = (priv->vbitrate >> 2); + buf[10] = (buf[10] & 0x3f) | (unsigned char) ((priv->vbitrate & 0x4) << 2); + } +} + +#define max(a, b) ((a) >= (b) ? (a) : (b)) +#define min(a, b) ((a) <= (b) ? (a) : (b)) + + +static int get_audio_frame_size(muxer_headers_t *spriv, uint8_t *buf, int format, int samples_ps) +{ + int sz; + uint32_t tmp; + +#ifdef USE_LIBA52 +#include "../liba52/a52.h" + if(format == 0x2000) + { + int t1, t2, t3; + sz = a52_syncinfo(buf, &t1, &t2, &t3); + if(sz) + return sz; + } +#endif + tmp = spriv->bitrate * (format == 0x2000 ? 1536 : 1152); + sz = tmp / samples_ps; + if(sz % 2) + sz++; + + return sz; +} + +static uint64_t delta_pts_old(int fps) +{ + if(fps >= 23960 && fps <= 23980) + return 3754; + if(fps >= 23990 && fps <= 24010) + return 3750; + if(fps >= 24990 && fps <= 25010) + return 3600; + if(fps >= 29960 && fps <= 29980) + return 3003; + if(fps >= 29990 && fps <= 30010) + return 3000; + if(fps >= 49990 && fps <= 50010) + return 1800; + if(fps >= 59930 && fps <= 59950) + return 1502; + if(fps >= 59990 && fps <= 60010) + return 1500; + + return 0; +} + +static uint64_t delta_pts(int fps) +{ //1024 * 92160000/fps + if(fps >= 23960 && fps <= 23980) + return 3843844; //3754; + if(fps >= 23990 && fps <= 24010) + return 3840000; //3750; + if(fps >= 24990 && fps <= 25010) + return 3686400; //3600; + if(fps >= 29960 && fps <= 29980) + return 3075075; //; 3003; + if(fps >= 29990 && fps <= 30010) + return 3072000; //3000; + if(fps >= 49990 && fps <= 50010) + return 1843200; //1800; + if(fps >= 59930 && fps <= 59950) + return 1537538; //1502; + if(fps >= 59990 && fps <= 60010) + return 1536000; //1500; + + return 0; +} + + +static int reorder_frame(muxer_headers_t *spriv, uint8_t *ptr, size_t len, uint8_t pt, uint32_t temp_ref, double duration, uint64_t idur) +{ + uint16_t idx = 0, move=0; + + /* HOW TO REORDER FRAMES IN DECODER ORDER: + current frame is n + IF pt(n)==I or P and + n>0 && temp_ref(n) > temp_ref(n-1) && pt(n-1 .. n-m)==B + then insert frame n before frame n-m + and shift forward the others + */ + + idx = spriv->framebuf_used; + //stores the frame in decoding order + if((idx > 0) && ((pt == I_FRAME) || (pt == P_FRAME))) + { + if((spriv->framebuf[idx - 1].type == B_FRAME) && (spriv->framebuf[idx - 1].temp_ref == temp_ref-1)) + { + while((spriv->framebuf[idx - 1].type == B_FRAME) && (spriv->framebuf[idx - 1].temp_ref < temp_ref) && (idx > 0)) + idx--; + move = spriv->framebuf_used - idx; //from idx there are 'move' frames to move forward + } + } + + //now idx is the position where we should store the frame + if(idx >= spriv->framebuf_cnt) + { //realloc + //fprintf(stderr, "\nREALLOC1: %d\n", (int) spriv->framebuf_cnt+1); + spriv->framebuf = (mpeg_frame_t*) realloc(spriv->framebuf, (spriv->framebuf_cnt+1)*sizeof(mpeg_frame_t)); + if(spriv->framebuf == NULL) + { + mp_dbg(MSGT_MUXER, MSGL_FATAL, "Couldn't realloc frame buffer(idx), abort\n"); + return 0; + } + + //fprintf(stderr, "\nREALLOC2: %d\n", len); + spriv->framebuf[spriv->framebuf_cnt].buffer = (uint8_t*) calloc(1, len); + if(spriv->framebuf[spriv->framebuf_cnt].buffer == NULL) + { + mp_dbg(MSGT_MUXER, MSGL_FATAL, "Couldn't realloc frame buffer(frame), abort\n"); + return 0; + } + spriv->framebuf[spriv->framebuf_cnt].size = 0; + spriv->framebuf[spriv->framebuf_cnt].alloc_size = len; + spriv->framebuf_cnt++; + } + + + while(move > 0) + { + mpeg_frame_t f; + f = spriv->framebuf[move + idx]; + spriv->framebuf[move + idx] = spriv->framebuf[move + idx - 1]; + spriv->framebuf[move + idx - 1] = f; + move--; + } + + if(spriv->framebuf[idx].alloc_size < len) + { + spriv->framebuf[idx].buffer = realloc(spriv->framebuf[idx].buffer, len); + if(spriv->framebuf[idx].buffer == NULL) + { + mp_dbg(MSGT_MUXER, MSGL_FATAL, "Couldn't realloc frame buffer(frame), abort\n"); + return 0; + } + spriv->framebuf[idx].alloc_size = len; + } + + memcpy(spriv->framebuf[idx].buffer, ptr, len); + spriv->framebuf[idx].size = len; + spriv->framebuf[idx].temp_ref = temp_ref; + spriv->framebuf[idx].type = pt; + spriv->framebuf[idx].duration = duration; + spriv->framebuf[idx].idur = idur; + spriv->framebuf_used++; + + return 1; +} + +static uint32_t dump_audio(muxer_t *muxer, muxer_stream_t *as, uint32_t abytes, int force) +{ + uint32_t len = 0, sz; + uint64_t num_frames = 0, next_pts; + uint16_t rest, x; + int64_t tmp; + double delta_pts; + muxer_priv_t *priv = (muxer_priv_t *) muxer->priv; + muxer_headers_t *apriv = (muxer_headers_t*) as->priv; + + if((abytes < apriv->frame_size) && (! force)) + { + apriv->is_late = 1; + mp_msg(MSGT_MUXER, MSGL_V, "NOT SAVING: %u bytes\n", abytes); + return 0; + } + + sz = priv->packet_size - calc_pack_hlen(priv->mux, apriv); + abytes = min(abytes, as->b_buffer_len); + if(abytes > 0) + { + rest = (apriv->size % apriv->frame_size); + if(rest) + rest = apriv->frame_size - rest; + + len = min(priv->packet_size, abytes); + x = min(len, sz); + if(x >= rest) + x -= rest; + else + x = 0; + + num_frames = (x + apriv->frame_size - 1) / apriv->frame_size; + next_pts = ((uint64_t) (num_frames * 92160000 * apriv->aframe_delta_pts)) + apriv->pts; + if(((priv->scr + (63000*1024)) < next_pts) && (priv->scr < apriv->pts) && (! force)) + { + apriv->is_late = 1; + return 0; + } + + if(as->ckid == be2me_32(0x1bd)) + { + apriv->has_pes_priv_headers = 4; + apriv->pes_priv_headers[0] = 0x80; + apriv->pes_priv_headers[1] = num_frames; + apriv->pes_priv_headers[2] = ((rest+1) >> 8) & 0xff; //256 * 0 ... + apriv->pes_priv_headers[3] = (rest+1) & 0xff; // + 1 byte(s) to skip + } + + if(len <= rest) + { + apriv->last_pts = apriv->pts; + apriv->pts = 0; + } + else + apriv->last_pts = 0; + + len = write_mpeg_pack(muxer, as, muxer->file, &(as->b_buffer[as->b_buffer_ptr]), len, 0); + apriv->size += len; + if(len >= rest) + x = len - rest; + else + x = 0; + + if(apriv->last_pts != 0) + { + apriv->pts = apriv->last_pts; + apriv->last_pts = 0; + } + + num_frames = (x + apriv->frame_size - 1) / apriv->frame_size; //int part only rounded to next + delta_pts = (double)num_frames * apriv->aframe_delta_pts; + apriv->timer += delta_pts; + apriv->pts += (uint64_t) (delta_pts * 92160000.0); + //apriv->pts += num_frames * apriv->delta_pts; + + mp_msg(MSGT_MUXER, MSGL_DBG2, "NUM_FRAMES: %llu, DPTS: %.3lf\n", num_frames, delta_pts); + + tmp = apriv->pts - priv->scr; + if((abs(tmp) > (63000*1024)) || (apriv->pts < priv->scr)) + { + double d; + d = (double) apriv->frame_size / (double) apriv->bitrate; + d *= (tmp - (63000*1024)); + apriv->compensate = (uint32_t) d; + + if(abs(tmp) > 92160000) //usually 1 second it still acceptable + mp_msg(MSGT_MUXER, MSGL_ERR, "\nWARNING: SCR: %llu, APTS: %llu, DELTA=%.3lf secs, BYTES=%d\n", priv->scr, apriv->pts, + (((double) tmp)/92160000.0), apriv->compensate); + } + + mp_msg(MSGT_MUXER, MSGL_V, "\nWRITTEN AUDIO: %u bytes, TIMER: %.3lf, FRAMES: %llu * %u, DELTA_PTS: %.3lf\n", + len, (double) (apriv->pts/92160000), num_frames, (uint32_t) apriv->frame_size, delta_pts); + + as->b_buffer_ptr += len; + as->b_buffer_len -= len; + } + + if(as->b_buffer_len > 0) + memmove(as->b_buffer, &(as->b_buffer[as->b_buffer_ptr]), as->b_buffer_len); + as->b_buffer_ptr = 0; + + return len; +} + + +static void save_delayed_audio(muxer_t *muxer, muxer_stream_t *as, uint64_t dur) +{ + + muxer_priv_t *priv = (muxer_priv_t *) muxer->priv; + muxer_headers_t *apriv = (muxer_headers_t *) as->priv; + uint64_t init_pts, last_pts; //initial value + + init_pts = apriv->pts; + fprintf(stderr, "DUR: %llu, DIFF: %llu\n", dur, apriv->pts - init_pts); + while(dur > apriv->pts - init_pts) + { + priv->scr = (92160000 * apriv->size) / apriv->bitrate; + last_pts = apriv->pts; + dump_audio(muxer, as, as->b_buffer_len, 0); + mp_msg(MSGT_MUXER, MSGL_V, "DUR: %llu, DIFF: %llu, SCR: %llu\n", dur, apriv->pts - init_pts, priv->scr); + } + + //priv->init_delay_pts = last_pts; + priv->init_delay_pts = (90 * 1024 * abs(conf_init_adelay)) + apriv->init_pts; + if(priv->init_delay_pts <= priv->scr) + priv->init_delay_pts = last_pts; + mp_msg(MSGT_MUXER, MSGL_V, "INIT_VPTS: %llu (%.3lf)\n", priv->init_delay_pts, (double) (priv->init_delay_pts/92160000.0)); +} + + +static inline void update_scr(muxer_priv_t *priv, uint32_t len, uint32_t totlen, double mult) +{ + uint64_t delta_scr; + double perc; + + perc = (double) len / (double) totlen; + + delta_scr = (uint64_t) (mult * perc); + priv->scr += delta_scr; + + mp_msg(MSGT_MUXER, MSGL_V, "UPDATE SCR TO %llu (%.3lf): mult is %.3lf, perc: %.3lf, %u/%u, delta: %llu\n", + priv->scr, (double) (priv->scr/92160000.0), mult, perc, len, totlen, delta_scr); +} + +static int calc_frames_to_flush(muxer_headers_t *vpriv) +{ + int n, found = 0; + + if(vpriv->framebuf_used > 0) + { + n = 0; + //let's count how many frames we'll store in the next pack sequence + mp_msg(MSGT_MUXER, MSGL_V, "\n"); + while(n < vpriv->framebuf_used) + { + mp_msg(MSGT_MUXER, MSGL_V, "n=%d, type=%d, temp_ref=%u\n", n, vpriv->framebuf[n].type, vpriv->framebuf[n].temp_ref); + if(vpriv->framebuf[n].type == I_FRAME) + { + if((n > 0) && (n < vpriv->framebuf_used)) + { + if(vpriv->framebuf[n].temp_ref < vpriv->framebuf[n+1].temp_ref) + { + found = 1; + break; + } + } + } + else + { + if(n < vpriv->framebuf_used) + { + if((vpriv->framebuf[n+1].type == I_FRAME) && + (vpriv->framebuf[n+1].temp_ref <= vpriv->framebuf[n].temp_ref)) + { + n++; + found = 1; + break; + } + } + } + + n++; + } + } + + if(found) + return n; + else + return 0; +} + +static uint64_t fix_pts(muxer_priv_t *priv, muxer_headers_t *vpriv, int n) +{ + int i, j, fixed = 0; + uint64_t last_dts, last_idur, ret; + + if(priv->init_delay_pts > 0) + { + for(i = 0; i < vpriv->framebuf_used; i++) + { + vpriv->framebuf[i].pts += priv->init_delay_pts; + vpriv->framebuf[i].dts += priv->init_delay_pts; + } + + + vpriv->init_pts = 0; + vpriv->last_pts = priv->init_delay_pts; + if(vpriv->last_pts > vpriv->framebuf[0].idur) + { + vpriv->init_dts = vpriv->framebuf[0].idur; + vpriv->last_dts = vpriv->last_pts - vpriv->framebuf[0].idur; + } + else + { + vpriv->init_dts = 0; + vpriv->last_dts = 0; + } + + priv->init_delay_pts = 0; + mp_msg(MSGT_MUXER, MSGL_INFO, "PTS: %llu, DTS: %llu, DUR: %llu\n", vpriv->last_pts, vpriv->last_dts, vpriv->framebuf[0].idur); + } + + + last_dts = vpriv->last_dts; + last_idur = ret = 0; + + if((vpriv->size == 0) && (fixed == 0)) + { + for(i = 0; i < n; i++) + { + for(j = i + 1; j < n; j++) + { + if(vpriv->framebuf[i].temp_ref >= vpriv->framebuf[j].temp_ref) + { + ret = j * vpriv->framebuf[0].idur; + vpriv->last_pts += ret; + fixed = 1; + break; + } + } + if(fixed) + break; + } + + if(! fixed) + { + j = 1; + vpriv->last_pts += vpriv->framebuf[0].idur; + } + mp_msg(MSGT_MUXER, MSGL_INFO, "INITIAL DELAY of %d frames\n", j); + } + + if((vpriv->size == 0) && (vpriv->last_dts >= vpriv->last_pts)) + vpriv->init_dts = vpriv->last_dts = vpriv->init_pts - vpriv->framebuf[0].idur; + + for(i = 0; i < n; i++) + { + vpriv->framebuf[i].pts = vpriv->last_pts; + vpriv->framebuf[i].dts = last_dts + last_idur; + last_idur = vpriv->framebuf[i].idur; + last_dts = vpriv->framebuf[i].dts; + + + for(j = 0; j < n; j++) + { + if((vpriv->framebuf[i].temp_ref >= vpriv->framebuf[j].temp_ref) && (i != j)) + { + vpriv->framebuf[i].pts += vpriv->framebuf[j].idur; + } + } + } + + return ret; +} + +static int flush_buffers(muxer_t *muxer, int finalize) +{ + int i, n, pl_size, found; + size_t saved; + uint32_t abytes, vbytes, bytes = 0, frame_bytes = 0, audio_rest = 0; + uint32_t div, rest; + uint64_t idur, init_delay; + muxer_stream_t *s, *vs, *as; + muxer_headers_t *vpriv = NULL, *apriv = NULL; + muxer_priv_t *priv = (muxer_priv_t *) muxer->priv; + uint8_t *tmp; + double mult, duration, dpts; + mpeg_frame_t temp_frame; + + /* + analyzes all streams and decides what to flush + trying to respect an interleaving distribution + equal to the v_bitrate/a_bitrate proportion + */ +init: + n = 0; + vs = as = NULL; + abytes = vbytes = found = 0; + for(i = 0; i < muxer->avih.dwStreams; i++) + { + s = muxer->streams[i]; + if(s->type == MUXER_TYPE_VIDEO) + { + vs = muxer->streams[i]; + vpriv = (muxer_headers_t*) vs->priv; + n = found = calc_frames_to_flush(vpriv); + } + else if(s->type == MUXER_TYPE_AUDIO) + as = s; + } + + if((! found) && finalize) + { + if(vpriv != NULL) + found = n = vpriv->framebuf_used; + } + + if(found) + { + mp_msg(MSGT_MUXER, MSGL_V, "\nVIDEO, FLUSH %d frames (of %d), 0 to %d\n", n, vpriv->framebuf_used, n-1); + + vbytes = 0; + vpriv = (muxer_headers_t*) vs->priv; + + duration = 0; + for(i = 0; i < n; i++) + { + vbytes += vpriv->framebuf[i].size; + duration += vpriv->framebuf[i].duration; + } + mult = duration * 92160000.0; + + if(as != NULL) + { + apriv = (muxer_headers_t*) as->priv; + abytes = (uint32_t) (duration * apriv->bitrate); //size of audio data to write + + abytes -= apriv->compensate; + div = abytes / apriv->max_pl_size; + rest = abytes % apriv->max_pl_size; + if(apriv->compensate > 0) + abytes = apriv->max_pl_size * (div - 1); + else if(apriv->compensate < 0) + abytes = apriv->max_pl_size * (div + 1); + else + abytes = apriv->max_pl_size * (rest ? div + 1 : div); + apriv->compensate = 0; + + + if(finalize) + abytes = as->b_buffer_len; + + if(abytes / apriv->max_pl_size > n) + audio_rest = (abytes - (apriv->max_pl_size * n)) / n; + else + audio_rest = 0; + + if(as->b_buffer_len < abytes) + { + mp_msg(MSGT_MUXER, MSGL_V, "Not enough audio data (%u < %u), exit\n", as->b_buffer_len, abytes); + return 0; + } + } + + if(finalize) + mp_msg(MSGT_MUXER, MSGL_V, "FORCED, N=%d, abytes=%u\n", n, abytes); + + tmp = (uint8_t*) malloc(priv->packet_size); + if(tmp == NULL) + { + fprintf(stderr, "COULDN'T ALLOC %d bytes, exit\n", priv->packet_size); + return 0; + } + + init_delay = fix_pts(priv, vpriv, n); + if((as != NULL) && (init_delay > 0)) + { + if(apriv->size == 0) + apriv->pts += init_delay; + } + + saved = 0; + bytes = vbytes + abytes; + + idur = 0; + priv->scr = vpriv->framebuf[0].dts - vpriv->init_dts; + for(i = 0; i < n; i++) + { + uint32_t offset = 0; + int frame_begin = 1; + + mp_msg(MSGT_MUXER, MSGL_V, "FRAME: %d, type: %c, TEMP_REF: %u, SIZE: %u, NEW VIDEO CLOCK: %.3lf, DELTA: %.3lf\n", + i, FRAMETYPE(vpriv->framebuf[i].type), vpriv->framebuf[i].temp_ref, vpriv->framebuf[i].size, vpriv->timer, vpriv->framebuf[0].duration); + + //priv->scr = (uint64_t) (vpriv->timer * 92160000); + + mult = vpriv->framebuf[i].duration * 92160000; + frame_bytes = vpriv->framebuf[i].size + saved; + if(abytes > 0) + frame_bytes += min(apriv->max_pl_size, abytes) + audio_rest; + + + if(saved > 0) + { + size_t pl; + pl = min(priv->packet_size - saved, vpriv->framebuf[i].size); + memcpy(&tmp[saved], vpriv->framebuf[i].buffer, pl); + pl = write_mpeg_pack(muxer, vs, muxer->file, tmp, saved + pl, 0); + update_scr(priv, pl, frame_bytes, mult); + + vpriv->size += pl; + offset = pl - saved; + + vbytes = vpriv->framebuf[i].size - offset; + saved = 0; + } + else + { + vbytes = vpriv->framebuf[i].size; + offset = 0; + } + + + while((vbytes > 0) && (saved == 0)) + { + pl_size = min(priv->packet_size, vbytes); + + // remaining data is too little to fill a pack, must be stored + // in a new pack with next frame + if((pl_size < priv->packet_size-26) && (i < n-1)) + { + memcpy(tmp, &(vpriv->framebuf[i].buffer[offset]), pl_size); + saved = pl_size; + } + else + { + if(vpriv->framebuf[i].type == I_FRAME && (vbytes == vpriv->framebuf[i].size)) + { + write_mpeg_pack(muxer, NULL, muxer->file, NULL, 0, 0); //insert fake Nav Packet + vpriv->pes_is_aligned = 1; + } + + dpts = vpriv->timer + vpriv->framebuf[0].duration - vpriv->last_dpts; + if(((vpriv->framebuf[i].type == I_FRAME) || (dpts >= 0.7)) + && (frame_begin == 1)) + { + if((vpriv->framebuf[i].type == I_FRAME) || + ((vpriv->framebuf[i].type == P_FRAME) && priv->use_ppts) || + ((vpriv->framebuf[i].type == B_FRAME) && priv->use_bpts)) + { + vpriv->dts = (uint64_t)(vpriv->timer * 92160000) + vpriv->init_dts; //next dts + vpriv->dts = vpriv->framebuf[i].dts; + vpriv->pts = vpriv->framebuf[i].pts; + + if((vpriv->dts < priv->scr) || (vpriv->pts < vpriv->dts)) + { + mp_msg(MSGT_MUXER, MSGL_ERR, "\nSCR: %.3lf, DTS: %.3lf, PTS: %.3lf\n", (double) priv->scr/92160000.0, + (double) vpriv->dts/92160000.0, (double) vpriv->pts/92160000.0); + vpriv->dts = 0; + } + + if(vpriv->pts < priv->scr) + vpriv->pts = 0; + else + { + vpriv->last_dpts = vpriv->timer; + if(abs(vpriv->pts - priv->scr) > 92160000) + mp_msg(MSGT_MUXER, MSGL_ERR, "WARNING: SCR: %llu, VPTS: %llu, DELTA=%.3lf secs\n", priv->scr, vpriv->pts, ((double) (vpriv->pts - priv->scr)/92160000.0)); + } + } + } + + pl_size = write_mpeg_pack(muxer, vs, muxer->file, &(vpriv->framebuf[i].buffer[offset]), vbytes, 0); + vpriv->pes_is_aligned = 0; + vpriv->pts = vpriv->dts = 0; + update_scr(priv, pl_size, frame_bytes, mult); + vbytes -= pl_size; + vpriv->size += pl_size; + offset += pl_size; + } + frame_begin = 0; + } + + vpriv->timer += vpriv->framebuf[i].duration; + if(vpriv->framebuf[i].pts >= vpriv->last_pts) + { + vpriv->last_pts = vpriv->framebuf[i].pts; + idur = vpriv->framebuf[i].idur; + } + //vpriv->last_pts = max(vpriv->last_pts, vpriv->framebuf[i].pts); + vpriv->last_dts = vpriv->framebuf[i].dts; + + if(abytes > 0) //it's time to save audio + { + pl_size = dump_audio(muxer, as, abytes, finalize); + if(pl_size > 0) + { + abytes -= pl_size; + update_scr(priv, pl_size, frame_bytes, mult); + } + } + } + + vpriv->last_pts += idur; + vpriv->last_dts += vpriv->framebuf[n-1].idur; + if(idur == 0) + fprintf(stderr, "\nN: %d, IDUR=0\n", n); + //fprintf(stderr, "\nN: %d, LAST_DTS: %.3lf, LAST_PTS: %.3lf,\n", n,(double) (vpriv->last_dts/92160000.0), (double) (vpriv->last_pts/92160000.0)); + free(tmp); + + for(i = n; i < vpriv->framebuf_used; i++) + { + temp_frame = vpriv->framebuf[i - n]; + vpriv->framebuf[i - n] = vpriv->framebuf[i]; + vpriv->framebuf[i] = temp_frame; + } + vpriv->framebuf_used -= n; + + + if((as != NULL) && priv->has_audio) + { + while(abytes > 0) + { + mult = duration * 92160000.0; + pl_size = dump_audio(muxer, as, abytes, finalize); + if(pl_size > 0) + { + update_scr(priv, pl_size, bytes, mult); + abytes -= pl_size; + } + else + break; + } + } + + + //goto init; + } + + muxer->file_end = priv->scr; + return found; } static void mpegfile_write_chunk(muxer_stream_t *s,size_t len,unsigned int flags){ - size_t ptr=0, sz; - unsigned int pts=0; + size_t ptr=0, sz = 0, pos; + uint64_t pts; + int gop = 0; muxer_t *muxer = s->muxer; + muxer_priv_t *priv = (muxer_priv_t *)muxer->priv; + muxer_headers_t *spriv = (muxer_headers_t*) s->priv; FILE *f; - + sh_audio_t *ash = NULL; + sh_video_t *vsh; + f = muxer->file; + + if((s->buffer == NULL) || (len == 0)) + return; + + pts = 0; if (s->type == MUXER_TYPE_VIDEO) { // try to recognize frame type... + vsh = (sh_video_t *) s->osh; + spriv->type = 1; + spriv->has_pes_priv_headers = 0; + //fprintf(stderr, "VIDEO: %u bytes\n", (uint32_t) len); if (s->buffer[0] != 0 || s->buffer[1] != 0 || s->buffer[2] != 1 || len<6) { - printf ("Unknown block type, possibly non-MPEG stream!\n"); + mp_msg(MSGT_MUXER, MSGL_ERR,"Unknown block type 1, possibly non-MPEG stream, len=%d!\n", len); sz = len; -// return; + return; //era commentato } else if (s->buffer[3] == 0 || s->buffer[3] == 0xb3 || - s->buffer[3] == 0xb8) { // Picture or GOP - int temp_ref; + s->buffer[3] == 0xb8) { // Video (0) Sequence header (b3) or GOP (b8) + uint32_t temp_ref; int pt; + + if(s->buffer[3] == 0xb3) //sequence + { + if((spriv->delta_clock != vsh->frametime) || (spriv->delta_pts == 0)) + { + spriv->delta_pts = delta_pts((int) (vsh->fps * 1000.0)); + fprintf(stderr, "DELTA_PTS: %llu, FPS=%d (%.3lf)\n", spriv->delta_pts, (int) (vsh->fps * 1000.0), vsh->fps); + } + if((spriv->delta_clock != vsh->frametime) && (spriv->size != 0)) + spriv->variable_framerate = 1; + spriv->delta_clock = vsh->frametime; + /* + if(s->size == 0) + spriv->init_dts = spriv->last_dts = spriv->init_pts - spriv->delta_pts; + */ + mp_msg(MSGT_MUXER, MSGL_V, "\nFPS: %.3f, FRAMETIME: %.3lf\n", vsh->fps, vsh->frametime); + if(priv->patch_seq) + patch_seq(priv, s->buffer); + } + + if(s->buffer[3] != 0xb8) { + pos = ptr; + while (ptr < len-5 && (s->buffer[ptr] != 0 || s->buffer[ptr+1] != 0 || + s->buffer[ptr+2] != 1 || s->buffer[ptr+3] != 0xb8)) ptr++; + if(ptr < len - 5) + gop = 1; + ptr = pos; + } - if (s->buffer[3]) { // GOP -- scan for Picture + s->h.dwSuggestedBufferSize = (priv->mux == MUX_MPEG2 ? 232*1024 : 46*1024); + 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++; - if (s->b_buffer_ptr > MUXER_MPEG_DATASIZE-39-12) { // 39 bytes for Gop+Pic+Slice headers - write_mpeg_block (muxer, s, f, NULL, 0, 0); - } } if (ptr >= len-5) { pt = 0; // Picture not found?! temp_ref = 0; - printf ("Warning: picture not found in GOP!\n"); + mp_dbg(MSGT_MUXER, MSGL_ERR,"Warning: picture not found in GOP!\n"); } else { pt = (s->buffer[ptr+5]>>3) & 7; temp_ref = (s->buffer[ptr+4]<<2)+(s->buffer[ptr+5]>>6); } + ptr = 0; - temp_ref += s->gop_start; - switch (pt) { - case 2: // predictive - if (s->ipb[0]) { - sz = len + s->ipb[0]; - if (s->ipb[0] < s->ipb[2]) - s->ipb[0] = s->ipb[2]; - s->ipb[2] = 0; - } else if (s->ipb[2]) { - sz = len + s->ipb[2]; - s->ipb[0] = s->ipb[2]; - s->ipb[2] = 0; - } else - sz = 4 * len; // no bidirectional frames yet? - s->ipb[1] = len; - // pictires may be not in frame sequence so recalculate timer - pts = (int)(90000*((double)temp_ref*s->h.dwScale/s->h.dwRate)) + MPEG_STARTPTS; - break; - case 3: // bidirectional - s->ipb[2] += len; - sz = s->ipb[1] + s->ipb[2]; - // pictires may be not in frame sequence so recalculate timer - s->timer = (double)temp_ref*s->h.dwScale/s->h.dwRate; - break; - default: // intra-coded - // pictires may be not in frame sequence so recalculate timer - pts = (int)(90000*((double)temp_ref*s->h.dwScale/s->h.dwRate)) + MPEG_STARTPTS; - sz = len; // no extra buffer for it... - } + + reorder_frame(spriv, s->buffer, len, pt, temp_ref, spriv->delta_clock, spriv->delta_pts); + + s->timer += spriv->delta_clock; + s->size += len; + priv->vbytes += len; } else { - printf ("Unknown block type, possibly non-MPEG stream!\n"); + mp_msg(MSGT_MUXER, MSGL_ERR, "Unknown block type 2, possibly non-MPEG stream!\n"); sz = len; -// return; + return; //era commentato } sz <<= 1; } else { // MUXER_TYPE_AUDIO - if (len < 2*MUXER_MPEG_DATASIZE) - sz = 2*MUXER_MPEG_DATASIZE; // min requirement - else - sz = len; + //fprintf(stderr, "AUDIO: %u bytes, DELAY: %u\n", (uint32_t) len, s->h.dwStart); + spriv->type = 0; + ash = (sh_audio_t *) s->osh; + + if(spriv->bitrate == 0) + spriv->bitrate = s->wf->nAvgBytesPerSec; + // I need to know the audio frame size + if(spriv->frame_size == 0) + { + spriv->frame_size = get_audio_frame_size(spriv, s->buffer, ash->format, s->wf->nSamplesPerSec); + spriv->aframe_delta_pts = ((double) spriv->frame_size / (double) spriv->bitrate); + spriv->delta_pts = (uint64_t) (spriv->aframe_delta_pts * 92160000); + fprintf(stderr, "AUDIO FRAME SIZE: %u, DELTA_PTS: %llu (%.3lf)\n", (uint32_t) spriv->frame_size, spriv->delta_pts, spriv->aframe_delta_pts); + } + + + if(s->b_buffer_size - s->b_buffer_len < len) + { + s->b_buffer = realloc(s->b_buffer, len + s->b_buffer_len); + if(s->b_buffer == NULL) + { + mp_dbg(MSGT_MUXER, MSGL_FATAL, "\nFATAL! couldn't realloc %d bytes\n", len + s->b_buffer_len); + return; + } + + s->b_buffer_size = len + s->b_buffer_len; + mp_dbg(MSGT_MUXER, MSGL_V, "REALLOC(%d)\n", s->b_buffer_size); + } + memcpy(&(s->b_buffer[s->b_buffer_ptr + s->b_buffer_len]), s->buffer, len); + s->b_buffer_len += len; + + if(ash->format == AUDIO_A52) + { + s->type = 1; + s->ckid = be2me_32 (0x1bd); + s->h.dwSuggestedBufferSize = 58*1024; + if(s->size == 0) + spriv->max_pl_size -= 4; + } + else + s->h.dwSuggestedBufferSize = 4*1024; + + s->size += len; + if(spriv->bitrate > 0) + s->timer += (double) len / (double) spriv->bitrate; + + if(priv->init_adelay < 0) + { + uint64_t delay_len; + priv->abytes += len; + delay_len = (uint64_t) abs((priv->init_adelay * (double) spriv->bitrate)); + if(priv->abytes >= delay_len) + { + fprintf(stderr, "\nSCRIVO %llu AUDIO BYTES, delay: %.3lf, BR: %u\n", delay_len, priv->init_adelay, spriv->bitrate); + save_delayed_audio(muxer, s, (uint64_t) (92160000 * (-priv->init_adelay))); + priv->init_adelay = 0.0; + } + } } + mp_dbg(MSGT_MUXER, MSGL_DBG3, "\nMPEG chunk: size=%u, pts=%f", len, s->timer); - set_mpeg_pts (muxer, s, pts); - // 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"); + // CBR + s->h.dwLength += len/s->h.dwSampleSize; + if (len%s->h.dwSampleSize) mp_msg(MSGT_MUXER, MSGL_ERR, "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 = MUXER_MPEG_BLOCKSIZE*90000/muxer->sysrate + MPEG_STARTSCR+1; - } - if (sz > s->h.dwSuggestedBufferSize) { // increase and set STD - s->h.dwSuggestedBufferSize = sz; - if (s->b_buffer[2] != 0xff) // has both PTS and DTS - write_mpeg_std (s->b_buffer, s->h.dwSuggestedBufferSize, 0x40); // 01 - else // has only PTS - write_mpeg_std (s->b_buffer+5, s->h.dwSuggestedBufferSize, 0x40); // 01 - } - s->size += len; - // write out block(s) if it's ready - while (s->b_buffer_ptr+len >= MUXER_MPEG_DATASIZE-12) { // reserved for std and 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 - if (s->b_buffer_ptr == 0) { - memset (s->b_buffer, 0xff, 12); // stuFFing bytes for now - if (s->type == MUXER_TYPE_AUDIO && s->h.dwSampleSize) { // CBR audio - sz = s->h.dwLength - len/s->h.dwSampleSize; // first sample number - write_mpeg_ts (s->b_buffer+7, - (int)(90000*((double)sz*s->h.dwScale/s->h.dwRate)) + MPEG_STARTPTS, - 0x20); // 0010 and PTS only - } - s->b_buffer_ptr = 12; - } - memcpy (s->b_buffer+s->b_buffer_ptr, s->buffer+ptr, len); - s->b_buffer_ptr += len; + // VBR + s->h.dwLength++; } - mp_dbg(MSGT_MUXER, MSGL_DBG3, " next pts=%f\n", s->timer); + + if (sz > s->h.dwSuggestedBufferSize) // increase and set STD + s->h.dwSuggestedBufferSize = spriv->buffer_size = sz; + + if(priv->init_adelay == 0) + flush_buffers(muxer, 0); +} + + +static void mpegfile_write_index(muxer_t *muxer) +{ + muxer_priv_t *priv = (muxer_priv_t *) muxer->priv; + + while(flush_buffers(muxer, 0) > 0); + flush_buffers(muxer, 1); + priv->is_dvd = 0; + if(priv->use_isoend) + write_mpeg_pack(muxer, NULL, muxer->file, NULL, 0, 1); //insert fake Nav Packet + + fprintf(stderr, "\nOH: %.3lf%% (%llu / %llu)\n", 100.0 * (double)priv->headers_size / (double)priv->data_size, priv->headers_size, priv->data_size); } -static void mpegfile_write_header(muxer_t *muxer){ - unsigned int i; - size_t sz = MUXER_MPEG_BLOCKSIZE-24; - unsigned char buff[12]; - muxer_stream_t *s = muxer->streams[0]; - uint32_t l1; - uint16_t l2; - FILE *f = muxer->file; - - if (s == NULL) - return; // no streams!? - // packet header (0x1ba) -- rewrite first stream buffer - *(uint32_t *)buff = be2me_32 (0x1ba); - write_mpeg_ts (buff+4, MPEG_STARTSCR, 0x20); // 0010 -- pack - write_mpeg_rate (buff+9, muxer->sysrate); - fwrite (buff, 12, 1, f); - // start system stream (in own block): Sys (0x1bb) - l1 = be2me_32 (0x1bb); - l2 = be2me_16 (6 + 3*muxer->avih.dwStreams); // header_length - fwrite (&l1, 4, 1, f); - fwrite (&l2, 2, 1, f); - write_mpeg_rate (buff, muxer->sysrate); // rate_bound - // set number of audio/video, fixed_flag=CSPS_flag=system_*_lock_flag=0 - buff[3] = (muxer->avih.dwStreams - muxer->num_videos) << 2; // audio_bound - buff[4] = muxer->num_videos | 0x20; - buff[5] = 0xff; // reserved_byte - fwrite (buff, 6, 1, f); - for (i = 0; i < muxer->avih.dwStreams; i++) { - buff[0] = ((char *)&muxer->streams[i]->ckid)[3]; // last char in big endian -//fprintf (stderr, "... stream 0x1%02x; bufsize %u", (int)buff[0], muxer->streams[i]->h.dwSuggestedBufferSize); - write_mpeg_std (buff+1, muxer->streams[i]->h.dwSuggestedBufferSize, 0xc0); // 11 - fwrite (buff, 3, 1, f); - sz -= 3; - } - if (sz >= 6) { // padding block - l1 = be2me_32 (0x1be); - sz -= 6; - l2 = be2me_16 (sz); - fwrite (&l1, 4, 1, f); - fwrite (&l2, 2, 1, f); - } - s->b_buffer[0] = 0x0f; // end of list - next bit has to be 0 - // stuFFing bytes -- rewrite first stream buffer - if (sz > 1) - memset (s->b_buffer+1, 0xff, sz-1); - fwrite (s->b_buffer, sz, 1, f); - muxer->movi_start = 0; - muxer->movi_end = MUXER_MPEG_BLOCKSIZE; -} - -static void mpegfile_write_index(muxer_t *muxer){ - unsigned int i; - unsigned int rsr; - - if (!muxer->avih.dwStreams) return; // no streams?! - // finish all but one video and audio streams - rsr = muxer->sysrate; // reserve it since it's silly change it at that point - for (i = 0; i < muxer->avih.dwStreams-1; i++) - write_mpeg_block (muxer, muxer->streams[i], muxer->file, NULL, 0, 0); - // end sequence: ISO-11172-End (0x1b9) and finish very last block - write_mpeg_block (muxer, muxer->streams[i], muxer->file, NULL, 0, 1); -//fprintf (stderr, "PTS to SCR delay: min %u.%03u, max %u.%03u\n", -// mpeg_min_delay/90000, (mpeg_min_delay/90)%1000, -// mpeg_max_delay/90000, (mpeg_max_delay/90)%1000); - muxer->sysrate = rsr; +static void mpegfile_write_header(muxer_t *muxer) +{ + muxer_priv_t *priv = (muxer_priv_t*) muxer->priv; + //write_mpeg_pack(muxer, NULL, muxer->file, NULL); + if(! priv->is_dvd) + priv->use_system_header = 0; + muxer->cont_write_header = NULL; //why does mencoder call me twice??????? + + return; } -void muxer_init_muxer_mpeg(muxer_t *muxer){ + +muxer_t *muxer_init_muxer_mpeg(muxer_t *muxer){ + muxer_priv_t *priv; + priv = (muxer_priv_t *) calloc(1, sizeof(muxer_priv_t)); + if(priv == NULL) + return NULL; + priv->use_system_header = 0; + priv->is_dvd = 0; + priv->use_isoend = 1; + priv->packet_size = conf_packet_size; + + if(conf_mux != NULL) { + if(! strcasecmp(conf_mux, "mpeg2")) + priv->mux = MUX_MPEG2; + else if(! strcasecmp(conf_mux, "dvd")) + { + priv->mux = MUX_MPEG2; + priv->is_dvd = 1; + priv->is_xvcd = 0; + priv->is_xsvcd = 0; + priv->use_system_header = 1; + priv->use_isoend = 0; + priv->packet_size = 2048; + priv->muxrate = 10080 * 125; + } + else if(! strcasecmp(conf_mux, "xsvcd")) + { + priv->mux = MUX_MPEG2; + priv->is_dvd = 0; + priv->is_xvcd = 0; + priv->is_xsvcd = 1; + priv->use_system_header = 1; + priv->use_isoend = 0; + priv->packet_size = 2324; + } + else if(! strcasecmp(conf_mux, "xvcd")) + { + priv->mux = MUX_MPEG1; + priv->is_dvd = 0; + priv->is_xvcd = 1; + priv->is_xsvcd = 0; + priv->use_system_header = 1; + priv->use_isoend = 0; + priv->packet_size = 2324; + } + else + priv->mux = MUX_MPEG1; + } + + priv->patch_seq = 0; + priv->vaspect = 0; // no change + if(conf_vaspect != NULL) + { + if(! strcmp(conf_vaspect, "1/1")) + priv->vaspect = ASPECT_1_1; + else if(! strcmp(conf_vaspect, "4/3")) + priv->vaspect = ASPECT_4_3; + else if(! strcmp(conf_vaspect, "16/9")) + priv->vaspect = ASPECT_16_9; + else if(! strcmp(conf_vaspect, "2.21/1")) + priv->vaspect = ASPECT_2_21_1; + } + + priv->vframerate = 0; // no change + if(conf_vframerate != NULL) + { + if(! strcmp(conf_vframerate, "23.976")) + priv->vframerate = FRAMERATE_23976; + else if(! strcmp(conf_vframerate, "24")) + priv->vframerate = FRAMERATE_24; + else if(! strcmp(conf_vframerate, "25")) + priv->vframerate = FRAMERATE_25; + else if(! strcmp(conf_vframerate, "29.97")) + priv->vframerate = FRAMERATE_2997; + else if(! strcmp(conf_vframerate, "30")) + priv->vframerate = FRAMERATE_30; + else if(! strcmp(conf_vframerate, "50")) + priv->vframerate = FRAMERATE_50; + else if(! strcmp(conf_vframerate, "59.94")) + priv->vframerate = FRAMERATE_5994; + else if(! strcmp(conf_vframerate, "60")) + priv->vframerate = FRAMERATE_60; + } + + priv->vwidth = (uint16_t) conf_vwidth; + priv->vheight = (uint16_t) conf_vheight; + priv->vbitrate = ((conf_vbitrate) * 10) >> 2; //*1000 / 400 + + if(priv->vaspect || priv->vframerate || priv->vwidth || priv->vheight || priv->vbitrate) + { + priv->patch_seq = 1; + mp_msg(MSGT_MUXER, MSGL_INFO, "MPEG MUXER, patching"); + if(priv->vwidth || priv->vheight) + mp_msg(MSGT_MUXER, MSGL_INFO, " resolution to %dx%d", priv->vwidth, priv->vheight); + if(priv->vframerate) + mp_msg(MSGT_MUXER, MSGL_INFO, " framerate to %s fps", framerates[priv->vframerate]); + if(priv->vaspect) + mp_msg(MSGT_MUXER, MSGL_INFO, " aspect ratio to %s", aspect_ratios[priv->vaspect]); + if(priv->vbitrate) + mp_msg(MSGT_MUXER, MSGL_INFO, " bitrate to %u", conf_vbitrate); + mp_msg(MSGT_MUXER, MSGL_INFO, "\n"); + } + + priv->has_video = priv->has_audio = 0; + + if(conf_muxrate > 0) + priv->muxrate = conf_muxrate * 125; // * 1000 / 8 + muxer->sysrate = priv->muxrate; // initial muxrate = constrained stream parameter + priv->scr = muxer->file_end = 0; + + priv->use_ppts = conf_use_ppts; + priv->use_bpts = conf_use_bpts; + + priv->init_adelay = (double) conf_init_adelay / (double) 1000.0; + + priv->buff = (uint8_t *) malloc(priv->packet_size); + if(priv->buff == NULL) + { + mp_msg(MSGT_MUXER, MSGL_ERR, "\nCouldn't allocate %d bytes, exit\n", priv->packet_size); + return NULL; + } + + muxer->priv = (void *) priv; 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; -// mpeg_min_delay = mpeg_max_delay = MPEG_STARTPTS-MPEG_STARTSCR; + return muxer; } Index: libmpdemux/muxer_rawvideo.c =================================================================== RCS file: /cvsroot/mplayer/main/libmpdemux/muxer_rawvideo.c,v retrieving revision 1.2 diff -c -u -c -u -r1.2 muxer_rawvideo.c --- libmpdemux/muxer_rawvideo.c 28 Aug 2004 20:31:41 -0000 1.2 +++ libmpdemux/muxer_rawvideo.c 21 Nov 2004 09:55:25 -0000 @@ -90,9 +90,10 @@ return; } -void muxer_init_muxer_rawvideo(muxer_t *muxer){ +muxer_t *muxer_init_muxer_rawvideo(muxer_t *muxer){ muxer->cont_new_stream = &rawvideofile_new_stream; muxer->cont_write_chunk = &rawvideofile_write_chunk; muxer->cont_write_header = &rawvideofile_write_header; muxer->cont_write_index = &rawvideofile_write_index; + return muxer; }