# HG changeset patch # User nicodvb # Date 1109022349 0 # Node ID 70c446099f40648f1a61ef168d691a7207710b71 # Parent eddd61a68410f11f1463e948bf7298722891c7de new mpeg muxer compatible with dvd/[s]vcd; small changes in the muxer layer (sanity checks in the muxer_init functions) diff -r eddd61a68410 -r 70c446099f40 cfg-mencoder.h --- a/cfg-mencoder.h Mon Feb 21 17:40:46 2005 +0000 +++ b/cfg-mencoder.h Mon Feb 21 21:45:49 2005 +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,7 @@ #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" diff -r eddd61a68410 -r 70c446099f40 libmpdemux/muxer.c --- a/libmpdemux/muxer.c Mon Feb 21 17:40:46 2005 +0000 +++ b/libmpdemux/muxer.c Mon Feb 21 21:45:49 2005 +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)); @@ -19,14 +24,17 @@ muxer->file = f; switch (type) { case MUXER_TYPE_MPEG: - muxer_init_muxer_mpeg(muxer); + if(! muxer_init_muxer_mpeg(muxer)) + return NULL; break; case MUXER_TYPE_RAWVIDEO: - muxer_init_muxer_rawvideo(muxer); + if(! muxer_init_muxer_rawvideo(muxer)) + return NULL; break; case MUXER_TYPE_AVI: default: - muxer_init_muxer_avi(muxer); + if(! muxer_init_muxer_avi(muxer)) + return NULL; } return muxer; } diff -r eddd61a68410 -r 70c446099f40 libmpdemux/muxer.h --- a/libmpdemux/muxer.h Mon Feb 21 17:40:46 2005 +0000 +++ b/libmpdemux/muxer.h Mon Feb 21 21:45:49 2005 +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 @@ -58,23 +59,27 @@ int idx_size; // streams: int num_videos; // for MPEG recalculations + int num_audios; unsigned int sysrate; // max rate in bytes/s //int num_streams; muxer_stream_t* def_v; // default video stream (for general headers) muxer_stream_t* streams[MUXER_MAX_STREAMS]; + 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 *); 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 *); #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) #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 *); +int muxer_init_muxer_avi(muxer_t *); +int muxer_init_muxer_mpeg(muxer_t *); +int muxer_init_muxer_rawvideo(muxer_t *); diff -r eddd61a68410 -r 70c446099f40 libmpdemux/muxer_avi.c --- a/libmpdemux/muxer_avi.c Mon Feb 21 17:40:46 2005 +0000 +++ b/libmpdemux/muxer_avi.c Mon Feb 21 21:45:49 2005 +0000 @@ -660,9 +660,10 @@ } } -void muxer_init_muxer_avi(muxer_t *muxer){ +int 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 1; } diff -r eddd61a68410 -r 70c446099f40 libmpdemux/muxer_mpeg.c --- a/libmpdemux/muxer_mpeg.c Mon Feb 21 17:40:46 2005 +0000 +++ b/libmpdemux/muxer_mpeg.c Mon Feb 21 21:45:49 2005 +0000 @@ -14,68 +14,411 @@ #include "ms_hdr.h" #include "muxer.h" +#include "stream.h" +#include "demuxer.h" +#include "stheader.h" +#include "../m_option.h" +#include "mpeg_hdr.h" -// 18 bytes reserved for block headers and STD -#define MUXER_MPEG_DATASIZE (MUXER_MPEG_BLOCKSIZE-18) +#define PACK_HEADER_START_CODE 0x01ba +#define SYSTEM_HEADER_START_CODE 0x01bb +#define PSM_START_CODE 0x01bc + +#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 + +static char ftypes[] = {'?', 'I', 'P', 'B'}; +#define FTYPE(x) (ftypes[(x)]) + + +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 = 0; //dvd +static uint32_t conf_muxrate = 0; //kb/s +static char *conf_vaspect = NULL, *conf_vframerate = NULL; +static uint32_t conf_vwidth = 0, conf_vheight = 0, conf_panscan_width = 0, conf_panscan_height = 0; +static uint32_t conf_vbitrate = 0; +static int conf_init_vpts = 200, conf_init_apts = 200; +static int conf_ts_allframes = 0; +static int conf_init_adelay = 0; +static int conf_drop = 0; +static int conf_skip_padding = 0; +static int conf_noreorder = 0; + +enum FRAME_TYPE { + I_FRAME = 1, + P_FRAME = 2, + B_FRAME = 3 +}; -// ISO-11172 requirements -#define MPEG_MAX_PTS_DELAY 90000 /* 1s */ -#define MPEG_MAX_SCR_INTERVAL 63000 /* 0.7s */ +typedef struct { + uint8_t *buffer; + size_t size; + size_t alloc_size; + uint8_t type; + uint32_t temp_ref; + uint64_t pts, dts, idur; +} mpeg_frame_t; + +typedef struct { + uint8_t cnt; // how many entries we use + struct { + uint8_t id, type; + uint32_t bufsize; + uint32_t format; + } streams[50]; //16 video + 16 audio mpa + 16 audio private + bd/bf for dvd +} sys_info_t; + +typedef struct { + uint8_t cnt; // how many entries we use + struct { + uint8_t id; + uint8_t type; + uint32_t format; + } streams[50]; //16 video + 16 audio mpa + 16 audio private + bd/bf for dvd +} psm_info_t; + + +typedef struct { + int mux; + sys_info_t sys_info; + psm_info_t psm_info; + uint16_t packet_size; + int is_dvd, is_xvcd, is_xsvcd, is_genmpeg1, is_genmpeg2, ts_allframes, has_video, has_audio; + int skip_padding; + int update_system_header, use_psm; + off_t headers_size, data_size; + uint64_t scr, vbytes, abytes, init_delay_pts; + uint32_t muxrate; + uint8_t *buff, *tmp, *residual; + uint32_t residual_cnt, headers_cnt; + double init_adelay; + int drop; + + //video patching parameters + uint8_t vaspect, vframerate; + uint16_t vwidth, vheight, panscan_width, panscan_height; + uint32_t vbitrate; + int patch_seq, patch_sde; + int psm_streams_cnt; +} muxer_priv_t; + + +typedef struct { + int has_pts, has_dts, pes_is_aligned, type, is_late, min_pes_hlen, psm_fixed; + uint64_t pts, last_pts, last_dts, dts, init_pts, init_dts, size, frame_duration, delta_pts, nom_delta_pts, frame_size, last_saved_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; + int32_t last_tr; + uint32_t max_tr; + uint8_t id, reorder, is_mpeg12; + mp_mpeg_header_t picture; +} muxer_headers_t; + -// suggestions -#define MPEG_STARTPTS 45000 /* 0.5s */ -#define MPEG_MIN_PTS_DELAY 9000 /* 0.1s */ -#define MPEG_STARTSCR 9 /* 0.1ms */ +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}, + {"vpswidth", &(conf_panscan_width), CONF_TYPE_INT, CONF_RANGE, 1, 16383, NULL}, + {"vpsheight", &(conf_panscan_height), CONF_TYPE_INT, CONF_RANGE, 1, 16383, NULL}, + {"vbitrate", &(conf_vbitrate), CONF_TYPE_INT, CONF_RANGE, 1, 104857599, NULL}, + {"init_vpts", &(conf_init_vpts), CONF_TYPE_INT, CONF_RANGE, 100, 700, NULL}, //2*frametime at 60fps + {"init_apts", &(conf_init_apts), CONF_TYPE_INT, CONF_RANGE, 100, 700, NULL}, + {"init_adelay", &conf_init_adelay, CONF_TYPE_INT, CONF_RANGE, -32760, -1, NULL}, + {"drop", &conf_drop, CONF_TYPE_FLAG, 0, 0, 1, NULL}, + {"tsaf", &conf_ts_allframes, CONF_TYPE_FLAG, 0, 0, 1, NULL}, + {"skip_padding", &conf_skip_padding, CONF_TYPE_FLAG, 0, 0, 1, NULL}, + {"noreorder", &conf_noreorder, CONF_TYPE_FLAG, 0, 0, 1, NULL}, + {NULL, NULL, 0, 0, 0, 0, NULL} +}; + +static void fix_audio_sys_header(muxer_priv_t *priv, uint8_t id, uint8_t newid, uint32_t size) +{ + uint8_t i; + + for(i = 0; i < priv->sys_info.cnt; i++) + { + if(priv->sys_info.streams[i].id == id) + { + priv->sys_info.streams[i].id = newid; + priv->sys_info.streams[i].type = 1; + priv->sys_info.streams[i].bufsize = size; + } + } +} + +static void fix_buffer_params(muxer_priv_t *priv, uint8_t id, uint32_t size) +{ + uint8_t i; + + for(i = 0; i < priv->sys_info.cnt; i++) + if(priv->sys_info.streams[i].id == id) + priv->sys_info.streams[i].bufsize = size; +} + +static inline int is_mpeg1(uint32_t x) +{ + return ( + (x == 0x10000001) || + (x == mmioFOURCC('m','p','g','1')) || + (x == mmioFOURCC('M','P','G','1')) + ); +} + +static inline int is_mpeg2(uint32_t x) +{ + return ( + (x == 0x10000002) || + (x == mmioFOURCC('m','p','g','2')) || + (x == mmioFOURCC('M','P','G','2')) || + (x == mmioFOURCC('m','p','e','g')) || + (x == mmioFOURCC('M','P','E','G')) + ); +} -//static unsigned int mpeg_min_delay; -//static unsigned int mpeg_max_delay; +static inline int is_mpeg4(uint32_t x) +{ + return ( + (x == 0x10000004) || + (x == mmioFOURCC('d','i','v','x')) || + (x == mmioFOURCC('D','I','V','X')) || + (x == mmioFOURCC('x','v','i','d')) || + (x == mmioFOURCC('X','V','I','D')) || + (x == mmioFOURCC('X','v','i','D')) || + (x == mmioFOURCC('x','v','i','x')) || + (x == mmioFOURCC('X','V','I','X')) || + (x == mmioFOURCC('m','p','4','v')) || + (x == mmioFOURCC('M','P','4','V')) + ); +} + +//from unrarlib.c +static uint32_t CalcCRC32(uint8_t *buff, uint32_t size) +{ + uint32_t i, j, CRCTab[256], crc; + + for(i = 0;i < 256; i++) + { + for(crc = i, j = 0; j < 8; j++) + crc= (crc & 1) ? (crc >> 1)^0xEDB88320L : (crc >> 1); + CRCTab[i] = crc; + } + + + crc = 0xffffffff; + for(i = 0; i < size; i++) + crc = (crc << 8) ^ CRCTab[((crc >> 24) ^ buff[i]) & 0xff]; + + return crc; +} + + +static void add_to_psm(muxer_priv_t *priv, uint8_t id, uint32_t format) +{ + uint8_t i; + + i = priv->psm_info.cnt; + priv->psm_info.streams[i].id = id; + priv->psm_info.streams[i].format = format; + + if(is_mpeg1(format)) + priv->psm_info.streams[i].type = 0x01; + else if(is_mpeg2(format)) + priv->psm_info.streams[i].type = 0x02; + else if(is_mpeg4(format)) + priv->psm_info.streams[i].type = 0x10; + else if(format == AUDIO_MP2 || format == AUDIO_MP3) + priv->psm_info.streams[i].type = 0x03; + else + priv->psm_info.streams[i].type = 0x81; + + if(format == AUDIO_A52) + memcpy((char*) &(priv->psm_info.streams[i].format), "AC-3", 4); + + priv->psm_info.cnt++; +} + + +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; +} + +static uint32_t calc_pack_hlen(muxer_priv_t *priv, 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_msg(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"); + if (muxer->num_videos >= 16) { + mp_msg(MSGT_MUXER, MSGL_ERR, "MPEG files can't contain more than 16 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"); + if (muxer->num_audios >= 16) { + mp_msg(MSGT_MUXER, MSGL_ERR, "MPEG files can't contain more than 16 audio streams!\n"); return NULL; } break; default: - printf ("Unknown stream type!\n"); + mp_msg(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) { - s->ckid = be2me_32 (0x1e0 + muxer->num_videos); + spriv->type = 1; + spriv->init_dts = 0; + spriv->init_pts = conf_init_vpts * 90 * 1024; + spriv->last_pts = spriv->init_pts; + spriv->last_saved_pts = 0; + spriv->init_dts = spriv->last_dts = spriv->init_pts; + spriv->pts = spriv->dts = 0; + spriv->last_dpts = spriv->timer; + spriv->delta_pts = spriv->nom_delta_pts = 0; + spriv->id = 0xe0 + muxer->num_videos; + s->ckid = be2me_32 (0x100 + spriv->id); + if(priv->is_genmpeg1 || priv->is_genmpeg2) { + int n = priv->sys_info.cnt; + + priv->sys_info.streams[n].id = spriv->id; + priv->sys_info.streams[n].type = 1; + priv->sys_info.streams[n].bufsize = (s->h.dwSuggestedBufferSize > 0 ? s->h.dwSuggestedBufferSize : 46*1024); + priv->sys_info.cnt++; + } 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); + bzero(&(spriv->picture), sizeof(spriv->picture)); + if(spriv->framebuf == NULL) { + mp_msg(MSGT_MUXER, MSGL_FATAL, "Couldn't allocate initial frames structure, abort!\n"); + return NULL; + } + if(priv->is_xvcd) + spriv->min_pes_hlen = 18; + else if(priv->is_xsvcd) + spriv->min_pes_hlen = 22; + if(conf_noreorder) + spriv->reorder = 0; + else + spriv->reorder = 1; mp_msg (MSGT_MUXER, MSGL_DBG2, "Added video stream %d, ckid=%X\n", muxer->num_videos, s->ckid); } else { // MUXER_TYPE_AUDIO - s->ckid = be2me_32 (0x1c0 + s->id - muxer->num_videos); + spriv->type = 0; + spriv->pts = 1; + spriv->dts = 0; + spriv->max_pl_size = priv->packet_size - calc_pack_hlen(priv, spriv); + spriv->init_pts = conf_init_apts * 90 * 1024; + spriv->pts = spriv->init_pts; + spriv->dts = 0; + spriv->id = 0xc0 + muxer->num_audios; + s->ckid = be2me_32 (0x100 + spriv->id); + if(priv->is_genmpeg1 || priv->is_genmpeg2) { + int n = priv->sys_info.cnt; + + priv->sys_info.streams[n].id = spriv->id; + priv->sys_info.streams[n].type = 0; + priv->sys_info.streams[n].bufsize = (s->h.dwSuggestedBufferSize > 0 ? s->h.dwSuggestedBufferSize : 4*1024); + priv->sys_info.cnt++; + } + if(priv->is_xvcd) + spriv->min_pes_hlen = 13; + else if(priv->is_xsvcd) + spriv->min_pes_hlen = 17; + + muxer->num_audios++; + priv->has_audio++; s->h.fccType=streamtypeAUDIO; mp_msg (MSGT_MUXER, MSGL_DBG2, "Added audio stream %d, ckid=%X\n", s->id - muxer->num_videos + 1, s->ckid); } @@ -83,364 +426,2016 @@ return s; } -static void write_mpeg_ts(unsigned char *b, unsigned int ts, char mod) { - b[0] = ((ts >> 29) & 0xf) | 1 | mod; +static void write_mpeg_ts(unsigned char *b, uint64_t ts, uint8_t mod) { + ts >>= 10; + b[0] = mod | ((ts >> 29) & 0xf) | 1; 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) { - 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_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, uint8_t mod) +{ + //type = 0:mpeg audio/128, 1:video and pes private streams (including ac3/dts/lpcm)/1024 + if(type == 0) //audio + size = (size + 127) / 128; + else //video or other + size = ((size + 1023) / 1024); + + if(! size) + size++; + + b[0] = ((size >> 8) & 0x3f) | (type==1 ? 0x60 : 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; + uint8_t i; + 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, we'll fix it later + len += 2; + write_mpeg_rate(MUX_MPEG1, &buff[len], muxer->sysrate); + len += 3; + + buff[len++] = 0x4 | (priv->is_xvcd ? 1 : 0); //1 audio stream bound, no fixed, CSPS only for xvcd + buff[len++] = 0xe1; //system_audio_lock, system_video_lock, marker, 1 video stream bound + + buff[len++] = ((priv->mux == MUX_MPEG1) ? 0xff : 0x7f); //in mpeg2 there's the packet rate restriction + + for(i = 0; i < priv->sys_info.cnt; i++) + { + buff[len++] = priv->sys_info.streams[i].id; + write_mpeg_std(&buff[len], priv->sys_info.streams[i].bufsize, priv->sys_info.streams[i].type, + (priv->sys_info.streams[i].type == 1 ? 0xe0: 0xc0)); + len += 2; + } + + *(uint16_t *)(&buff[4]) = be2me_16(len - 6); // length field fixed + + return len; +} + +static int write_mpeg_psm(muxer_t *muxer, char *buff) +{ + int len; + uint8_t i; + uint16_t dlen; + muxer_priv_t *priv; + priv = (muxer_priv_t *) muxer->priv; + + len = 0; + *(uint32_t *)(&buff[len]) = be2me_32(PSM_START_CODE); + len += 4; + *(uint16_t *)(&buff[len]) = 0; //fake length, we'll fix it later + len += 2; + buff[len++] = 0xe0; //1 current, 2 bits reserved, 5 version 0 + buff[len++] = 0xff; //7 reserved, 1 marker + buff[len] = buff[len+1] = 0; //length of the program descriptors (unused) + len += 2; + *(uint16_t *)(&buff[len]) = 0; //length of the es descriptors + len += 2; + + dlen = 0; + for(i = 0; i < priv->psm_info.cnt; i++) + { + if( + (priv->psm_info.streams[i].id == 0xbd) || + (priv->psm_info.streams[i].id >= 0xe0 && priv->psm_info.streams[i].id <= 0xef) || + (priv->psm_info.streams[i].id >= 0xc0 && priv->psm_info.streams[i].id <= 0xcf) + ) + { + buff[len++] = priv->psm_info.streams[i].type; + buff[len++] = priv->psm_info.streams[i].id; + buff[len++] = 0; //len of descriptor upper ... + buff[len++] = 6; //... lower + + //registration descriptor + buff[len++] = 0x5; //tag + buff[len++] = 4; //length: 4 bytes + memcpy(&(buff[len]), (char*) &(priv->psm_info.streams[i].format), 4); + len += 4; + dlen += 10; + } + } + *(uint16_t *)(&buff[10]) = be2me_16(dlen); //length of the es descriptors + + *(uint16_t *)(&buff[4]) = be2me_16(len - 6 + 4); // length field fixed, including size of CRC32 + + *(uint32_t *)(&buff[len]) = CalcCRC32(buff, len); + + len += 4; //for crc + + 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; + } + + if(h->buffer_size > 0) + { + 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, 0x10); // 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 void write_psm_block(muxer_t *muxer, FILE *f) +{ + uint16_t offset, stuffing_len; + muxer_priv_t *priv = (muxer_priv_t *) muxer->priv; + uint8_t *buff = priv->buff; + + offset = write_mpeg_pack_header(muxer, buff); + offset += write_mpeg_psm(muxer, &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; +} + + +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, muxer_priv_t *priv) +{ + uint32_t len; + + if(format == MUX_MPEG1) + len = 6; + else + len = 9; //era 12 + + if(h->pts) + { + len += 5; + if(h->dts) + len += 5; + } + else if(format == MUX_MPEG1) + len += 1; + + if(h->buffer_size > 0) + { + if(format == MUX_MPEG2) + len += 3; + else + len += 2; + } + + len += h->has_pes_priv_headers; + + return len; +} + +static uint32_t calc_pack_hlen(muxer_priv_t *priv, muxer_headers_t *h) +{ + uint32_t len; + + if(priv->mux == MUX_MPEG1) + len = 12; + else + len = 14; + + /*if((priv->is_genmpeg1 || priv->is_genmpeg2) && priv->update_system_header) + len += (6 + (3*priv->sys_info.cnt));*/ + + if(h->min_pes_hlen > 0) + len += h->min_pes_hlen; + else + len += calc_pes_hlen(priv->mux, h, priv); + + return len; } -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_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; + muxer_headers_t *spriv; + + priv = (muxer_priv_t *) muxer->priv; + buff = priv->buff; + + if(isoend) + { + buff[0] = buff[1] = 0; + buff[2] = 1; + buff[3] = 0xb9; + fwrite(buff, 4, 1, f); + return 1; + } + + if((len == 0) || (bl == NULL)) //PACK headers only + { + offset = write_mpeg_pack_header(muxer, buff); + offset += write_mpeg_system_header(muxer, &buff[offset]); + + //priv->update_system_header = 0; + + 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 + { + spriv = (muxer_headers_t *) s->priv; + + mp_msg(MSGT_MUXER, MSGL_V, "\nwrite_mpeg_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, spriv->pts, spriv->dts, priv->scr, priv->packet_size); + + //stflen is the count of stuffing bytes in the pes header itself, + //stuffing_len is the size of the stuffing pes stream (must be at least 7 bytes long) + stflen = stuffing_len = 0; + offset = 0; + offset = pack_hlen = write_mpeg_pack_header(muxer, &buff[offset]); + + if(priv->update_system_header && (priv->is_genmpeg1 || priv->is_genmpeg2)) + { + pack_hlen += write_mpeg_system_header(muxer, &buff[offset]); + priv->update_system_header = 0; + } + + offset = pack_hlen; + + pes_hlen = calc_pes_hlen(priv->mux, spriv, priv); + if(spriv->min_pes_hlen > 0) + { + if(spriv->min_pes_hlen > pes_hlen) + stflen = spriv->min_pes_hlen - pes_hlen; + } + + if((len >= priv->packet_size - pack_hlen - max(pes_hlen, spriv->min_pes_hlen))) + stuffing_len = 0; + else + stuffing_len = priv->packet_size - pack_hlen - max(pes_hlen, spriv->min_pes_hlen) - len; + + if(stuffing_len > 0) + { + if(stuffing_len < 7) + { + if(stflen + stuffing_len > 16) + { + int x = 7 - stuffing_len; + stflen -= x; + stuffing_len += x; + } + else + { + stflen += stuffing_len; + stuffing_len = 0; + } + } + } + + if(priv->skip_padding) //variable packet size, just for fun and to reduce file size + { + stuffing_len = 0; + len = min(len, priv->packet_size - pack_hlen - pes_hlen - stflen); + } + else + 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(spriv, (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); + + 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, spriv: 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 + stflen; + 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); + } +} + +static void patch_panscan(muxer_priv_t *priv, unsigned char *buf) +{ //patches sequence display extension (display_horizontal_size and display_vertical_size) + //1: + int offset = 1; + + if(buf[0] & 0x01) + offset += 3; + + if(priv->panscan_width > 0) + { + buf[offset] = (priv->panscan_width >> 6); + buf[offset+1] = ((priv->panscan_width & 0x3F) << 2) | (buf[offset + 1] & 0x03); + } + + offset++; + + if(priv->panscan_height > 0) + { + buf[offset] = (priv->panscan_height >> 13) << 7; + buf[offset+1] = (priv->panscan_height >> 5) & 0xFF; + buf[offset+2] = ((priv->panscan_height & 0x1F) << 3) | (buf[offset+2] & 0x07); + } +} + + +#define max(a, b) ((a) >= (b) ? (a) : (b)) +#define min(a, b) ((a) <= (b) ? (a) : (b)) + + +static uint32_t get_audio_frame_size(muxer_headers_t *spriv, uint8_t *buf, int format, int samples_ps) +{ + uint32_t sz, tmp; + +#ifdef USE_LIBA52 +#include "../liba52/a52.h" + if(format == 0x2000) + { + int t1, t2, t3; + sz = (uint32_t) 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 int reorder_frame(muxer_headers_t *spriv, uint8_t *ptr, size_t len, uint8_t pt, uint32_t temp_ref, uint64_t idur) +{ + uint16_t idx = 0, move=0; + + /* HOW TO REORDER FRAMES IN DECODING 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; + if(spriv->reorder) + { + //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+move >= 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_msg(MSGT_MUXER, MSGL_FATAL, "Couldn't realloc frame buffer(idx), abort\n"); + return 0; + } + + spriv->framebuf[spriv->framebuf_cnt].size = 0; + spriv->framebuf[spriv->framebuf_cnt].alloc_size = 0; + + spriv->framebuf[spriv->framebuf_cnt].buffer = (uint8_t*) malloc(len); + if(spriv->framebuf[spriv->framebuf_cnt].buffer == NULL) + { + mp_msg(MSGT_MUXER, MSGL_FATAL, "Couldn't realloc frame buffer(frame), abort\n"); + return 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_msg(MSGT_MUXER, MSGL_FATAL, "Couldn't realloc frame buffer(frame), abort\n"); + return 0; + } + spriv->framebuf[idx].alloc_size = len; + } + + mp_msg(MSGT_MUXER, MSGL_DBG2, "\nIDX: %u, type: %c, temp_ref: %u, ptr: %p, len: %u, alloc: %u, buffer: %p\n", + (uint32_t) idx, FTYPE(pt), temp_ref, ptr, (uint32_t) len, (uint32_t) spriv->framebuf[idx].alloc_size, spriv->framebuf[idx].buffer); + + 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].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; + 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)) //pl_size + //if((abytes < apriv->max_pl_size) && (! force)) //pl_size + { + apriv->is_late = 1; + mp_msg(MSGT_MUXER, MSGL_V, "NOT SAVING: %u bytes\n", abytes); + return 0; + } + + abytes = min(abytes, as->b_buffer_len); //available bytes + if(! abytes) + return 0; + + if(as->ckid == be2me_32(0x1bd)) + apriv->has_pes_priv_headers = 4; + else + apriv->has_pes_priv_headers = 0; + + rest = (apriv->size % apriv->frame_size); + if(rest) + rest = apriv->frame_size - rest; + + sz = priv->packet_size - calc_pack_hlen(priv, apriv); //how many payload bytes we are about to write + num_frames = (sz + apriv->frame_size - 1 - rest) / apriv->frame_size; + + mp_msg(MSGT_MUXER, MSGL_V, "\nAUDIO: tot=%llu, sz=%u bytes, FRAMES: %llu * %u, REST: %u, DELTA_PTS: %u\n", + apriv->size, sz, num_frames, (uint32_t) apriv->frame_size, (uint32_t) rest, (uint32_t) ((num_frames * apriv->delta_pts) >> 10)); + + next_pts = ((uint64_t) (num_frames * apriv->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->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((priv->is_xsvcd || priv->is_xvcd) && apriv->size == 0) + apriv->buffer_size = 4*1024; + + if(apriv->pts < priv->scr) + mp_msg(MSGT_MUXER, MSGL_ERR, "\nERROR: SCR: %llu, APTS: %llu, DELTA=-%.3lf secs\n", + priv->scr, apriv->pts, (double) ((priv->scr - apriv->pts)/92160000.0)); + + len = write_mpeg_pack(muxer, as, muxer->file, &(as->b_buffer[as->b_buffer_ptr]), abytes, 0); + if((priv->is_xsvcd || priv->is_xvcd) && apriv->size == 0) + apriv->buffer_size = 0; + + apriv->size += len; + apriv->pts = next_pts; + + mp_msg(MSGT_MUXER, MSGL_DBG2, "NUM_FRAMES: %llu\n", num_frames); + + 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 up to 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 drop_delayed_audio(muxer_t *muxer, muxer_stream_t *as, int64_t size) +{ + //muxer_priv_t *priv = (muxer_priv_t *) muxer->priv; + muxer_headers_t *apriv = (muxer_headers_t *) as->priv; + int64_t size1, div, rest; //initial value + double rest_pts; + + div = size / apriv->frame_size; + rest = size % apriv->frame_size; + if(rest >= apriv->frame_size / 2) + size1 = (div+1) * apriv->frame_size; + else + size1 = (div) * apriv->frame_size; + + fprintf(stderr, "SIZE1: %llu, LEN: %llu\n", size1, (uint64_t)as->b_buffer_len); + size1 = min(size1, as->b_buffer_len); + memmove(as->b_buffer, &(as->b_buffer[size]), as->b_buffer_len - size1); + as->b_buffer_len -= size1; + + rest = size1 - size; + rest_pts = (double) rest / (double) apriv->bitrate; + apriv->pts += (int64_t) (92160000.0 * rest_pts); + mp_msg(MSGT_MUXER, MSGL_V, "DROPPED: %lld bytes, REST= %lld, REST_PTS: %.3lf, AUDIO_PTS%.3lf\n", size1, rest, rest_pts, (double) (apriv->pts/92160000.0)); } -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; + +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; + mp_msg(MSGT_MUXER, MSGL_V, "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 - (90 * 1024 * abs(conf_init_vpts)); + if(priv->init_delay_pts <= priv->scr) + priv->init_delay_pts = last_pts; + mp_msg(MSGT_MUXER, MSGL_INFO, "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=%c, temp_ref=%u\n", n, FTYPE(vpriv->framebuf[n].type), vpriv->framebuf[n].temp_ref); + if(n+1 < vpriv->framebuf_used) + mp_msg(MSGT_MUXER, MSGL_V, "n+1=%d, type=%c, temp_ref=%u\n", n+1, FTYPE(vpriv->framebuf[n+1].type), vpriv->framebuf[n+1].temp_ref); + + if(vpriv->framebuf[n].type == I_FRAME) + { + if(n > 0) + { + found = 1; + break; + } + } + + n++; + } + } + + if(found && (n < vpriv->framebuf_used+1)) + 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; + uint32_t mintr, maxtr; - 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; + ret = 0; + if((vpriv->size == 0) && (fixed == 0)) //first pts adjustment, only at the beginning of the stream to manage BBI structures + { + int delay = 0; + for(i = 0; i < n; i++) + { + if(vpriv->framebuf[i].type == I_FRAME) + { + for(j = i + 1; j < n; j++) + { + if(vpriv->framebuf[i].temp_ref >= vpriv->framebuf[j].temp_ref) + { + ret += vpriv->framebuf[j].idur; + delay++; + fixed = 1; + } + } + if(fixed) + break; + } + } + + if(! fixed) + ret = 0; + else + vpriv->last_pts += ret; + + mp_msg(MSGT_MUXER, MSGL_INFO, "INITIAL DELAY of %d frames\n", delay); + } + + //KLUDGE BEGINS: Gop header (0x000001b8 in the video stream that signals a temp_ref wraparound) is _not_ mandatory, + //so if we don't detect the right wraparound we will have a totally wrong timestamps assignment; let's go on + mintr = vpriv->framebuf[0].temp_ref; + maxtr = vpriv->framebuf[0].temp_ref; + for(i = 0; i < n; i++) + { + mintr = min(vpriv->framebuf[i].temp_ref, mintr); + maxtr = max(vpriv->framebuf[i].temp_ref, maxtr); + } + if(maxtr - mintr > 600) //there must be a temp_ref wraparound + { + mp_msg(MSGT_MUXER, MSGL_INFO, "\nDETECTED possible temp_ref wraparound in the videostreams: n=%d, mintr=%u, maxtr=%u\n", n, mintr, maxtr); + for(i = 0; i < n; i++) + { + if(vpriv->framebuf[i].temp_ref < 1000) + vpriv->framebuf[i].temp_ref += 1024; + } + } + //KLUDGE ENDS + + + for(i = 0; i < n; i++) + { + vpriv->framebuf[i].pts = vpriv->last_pts; + + 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; + } + } + } - 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(vpriv->size == 0) + last_dts = vpriv->init_dts = vpriv->framebuf[0].pts - (ret + vpriv->framebuf[0].idur); + else + last_dts = vpriv->last_dts; + + last_idur = 0; + + mp_msg(MSGT_MUXER, MSGL_V, "\n"); + for(i = 0; i < n; i++) + { + vpriv->framebuf[i].dts = last_dts + last_idur; + last_idur = vpriv->framebuf[i].idur; + last_dts = vpriv->framebuf[i].dts; + mp_msg(MSGT_MUXER, MSGL_V, "I=%d, type: %c, TR: %u, pts=%.3lf, dts=%.3lf, size=%u\n", + i, FTYPE(vpriv->framebuf[i].type), vpriv->framebuf[i].temp_ref, (double) (vpriv->framebuf[i].pts/92160000.0), + (double) (vpriv->framebuf[i].dts/92160000.0), vpriv->framebuf[i].size); + } + + if((vpriv->size == 0) && (priv->init_delay_pts > 0)) + { + uint64_t diff; + + for(i = 0; i < vpriv->framebuf_used; i++) + { + vpriv->framebuf[i].pts += priv->init_delay_pts; + vpriv->framebuf[i].dts += priv->init_delay_pts; + } + + diff = vpriv->framebuf[0].pts - vpriv->framebuf[0].dts; + if(vpriv->init_pts >= diff) + vpriv->init_dts = vpriv->init_pts - diff; + else + vpriv->init_dts = diff; + + vpriv->last_dts += priv->init_delay_pts; + + vpriv->init_pts = 0; + vpriv->last_pts += priv->init_delay_pts; + + priv->init_delay_pts = 0; + mp_msg(MSGT_MUXER, MSGL_INFO, "INIT delayed video timestamps: PTS=%.3lf, DTS=%.3lf, DUR=%.3lf\n", + (double) (vpriv->last_pts/92160000.0), (double) (vpriv->last_dts/92160000.0), (double) (vpriv->framebuf[0].idur/92160000.0)); + } + + return ret; +} + - 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 check_pts(muxer_priv_t *priv, muxer_headers_t *vpriv, int i) +{ + uint64_t dpts; + + dpts = max(vpriv->last_saved_pts, vpriv->pts) - min(vpriv->last_saved_pts, vpriv->pts); + dpts += vpriv->framebuf[i].idur; + + if((!priv->ts_allframes) && ( + (priv->is_dvd && (vpriv->framebuf[i].type != I_FRAME)) || + ((priv->is_genmpeg1 || priv->is_genmpeg2) && (vpriv->framebuf[i].type != I_FRAME) && (dpts < 64512000))) //0.7 seconds + ) + vpriv->pts = vpriv->dts = 0; + + if(vpriv->dts && ((vpriv->dts < priv->scr) || (vpriv->pts <= vpriv->dts))) + { + mp_msg(MSGT_MUXER, MSGL_V, "\nWARNING, SCR: %.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 && (vpriv->pts <= priv->scr)) + { + mp_msg(MSGT_MUXER, MSGL_ERR, "ERROR: SCR: %.3lf, VPTS: %.3lf, DELTA=-%.3lf secs\n", + (double) (priv->scr/92160000.0), (double)(vpriv->pts/92160000.0), (double) ((priv->scr - vpriv->pts)/92160000.0)); + vpriv->pts = vpriv->dts = 0; + } + + if(vpriv->pts) + vpriv->last_saved_pts = vpriv->pts; +} + +static uint32_t calc_audio_chunk_size(muxer_stream_t *as, double duration, int finalize) +{ + muxer_headers_t *apriv; + uint32_t x, div, rest, abytes; + double adur; + uint64_t iaduration; + + apriv = (muxer_headers_t*) as->priv; + abytes = (uint32_t) (duration * apriv->bitrate); //size of audio data to write + x = (abytes + apriv->max_pl_size - 1) / apriv->max_pl_size; + x *= apriv->max_pl_size; + adur = (double) x / (double) apriv->bitrate; + iaduration = (uint64_t) ((double) 92160000 * adur); + + 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; + + return abytes; } -static void set_mpeg_pts(muxer_t *muxer, muxer_stream_t *s, unsigned int pts) { - unsigned int dts, nts; +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, tot = 0, muxrate; + uint32_t offset; + uint64_t idur, init_delay = 0; + 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; + uint64_t iduration; + 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); + + tmp = priv->tmp; + vbytes = 0; + vpriv = (muxer_headers_t*) vs->priv; + + if(priv->residual_cnt) + { + mpeg_frame_t *f = &(vpriv->framebuf[0]); + size_t sz = f->size + priv->residual_cnt; + + if(f->alloc_size < sz) + { + f->buffer = (uint8_t *) realloc(f->buffer, sz); + f->alloc_size = sz; + } + memmove(&(f->buffer[priv->residual_cnt]), f->buffer, f->size); + memcpy(f->buffer, priv->residual, priv->residual_cnt); + f->size += priv->residual_cnt; + priv->residual_cnt = 0; + } + + duration = 0; + iduration = 0; + for(i = 0; i < n; i++) + { + vbytes += vpriv->framebuf[i].size; + iduration += vpriv->framebuf[i].idur; + } + duration = (double) (iduration / 92160000.0); + + if(vpriv->is_mpeg12) + init_delay = fix_pts(priv, vpriv, n); + else + init_delay = 0; + + if(as != NULL) + { + apriv = (muxer_headers_t*) as->priv; + abytes = calc_audio_chunk_size(as, duration, finalize); + + 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((as != NULL) && (init_delay > 0)) + { + if(apriv->size == 0) + apriv->pts += init_delay; + } + + saved = 0; + bytes = vbytes + abytes; + muxrate = (uint32_t) ((double) bytes/duration); + if(muxrate > muxer->sysrate && (priv->is_genmpeg1 || priv->is_genmpeg2)) + { + mp_msg(MSGT_MUXER, MSGL_V, "NEW MUXRATE: %u -> %u\n", muxrate, muxer->sysrate); + muxer->sysrate = muxrate; + } + + idur = 0; + offset = 0; + priv->scr = vpriv->framebuf[0].dts - vpriv->init_dts; + + if((priv->is_xvcd || priv->is_xsvcd) && (vpriv->size == 0)) + vpriv->buffer_size = (priv->is_xvcd ? 46 : 230)*1024; + + i = 0; + while(i < n) + { + int frame_begin = 1, update; + uint32_t pl_size = 0, target_size; + uint8_t *buf; + + mp_msg(MSGT_MUXER, MSGL_V, "FRAME: %d, type: %c, TEMP_REF: %u, SIZE: %u\n", + i, FTYPE(vpriv->framebuf[i].type), vpriv->framebuf[i].temp_ref, vpriv->framebuf[i].size); + + vpriv->pts = vpriv->framebuf[i].pts; + vpriv->dts = vpriv->framebuf[i].dts; + check_pts(priv, vpriv, i); + + if(priv->is_dvd && (vpriv->framebuf[i].type == I_FRAME) && (offset == 0)) + { + write_mpeg_pack(muxer, NULL, muxer->file, NULL, 0, 0); //insert fake Nav Packet + vpriv->pes_is_aligned = 1; + } + + offset = 0; + vbytes = vpriv->framebuf[i].size; + while(vbytes > 0 && (i < n)) + { + target_size = priv->packet_size - calc_pack_hlen(priv, vpriv); + if((vbytes >= target_size) || ((vbytes < target_size) && (i == n-1))) + { + buf = &(vpriv->framebuf[i].buffer[offset]); + pl_size = vbytes; + update = 1; + } + else + { + uint32_t tmp_offset = 0; + + if(offset == 0) + { + vpriv->pts = vpriv->framebuf[i].pts; + vpriv->dts = vpriv->framebuf[i].dts; + check_pts(priv, vpriv, i); + } + else if(i < n-1) + { + vpriv->pts = vpriv->framebuf[i+1].pts; + vpriv->dts = vpriv->framebuf[i+1].dts; + check_pts(priv, vpriv, i+1); + } + else + vpriv->pts = vpriv->dts = 0; + + target_size = priv->packet_size - calc_pack_hlen(priv, vpriv); //it was only priv->packet_size + update = 0; + + while((tmp_offset < target_size) && (i < n)) + { + pl_size = min(target_size - tmp_offset, vbytes); + memcpy(&(tmp[tmp_offset]), &(vpriv->framebuf[i].buffer[offset]), pl_size); + tmp_offset += pl_size; + offset += pl_size; + vbytes -= pl_size; + + if(vbytes == 0) //current frame is saved, pass to the next + { + i++; + vbytes = vpriv->framebuf[i].size; + offset = 0; + frame_begin = 1; + } + } + buf = tmp; + pl_size = tmp_offset; + } + + + if((pl_size < priv->packet_size - calc_pack_hlen(priv, vpriv)) && !finalize && (i >= n - 1)) + { + memcpy(priv->residual, buf, pl_size); + priv->residual_cnt = pl_size; + pl_size = update = vbytes = 0; + } + if(pl_size) + pl_size = write_mpeg_pack(muxer, vs, muxer->file, buf, pl_size, 0); + vpriv->pes_is_aligned = 0; + vpriv->pts = vpriv->dts = 0; + vpriv->buffer_size = 0; + vpriv->size += pl_size; + if(update) + { + vbytes -= pl_size; + offset += pl_size; + } + + /* this is needed to calculate SCR */ + frame_bytes = max(vpriv->framebuf[i].size, priv->packet_size) + priv->packet_size; + if(abytes > 0) + //frame_bytes += min(apriv->max_pl_size, priv->packet_size) + audio_rest; + frame_bytes += min(apriv->max_pl_size, abytes) + audio_rest; + + if(priv->ts_allframes) + { + tot = frame_bytes; + mult = (double) vpriv->framebuf[min(i, n-1)].idur; + } + else + { + tot = bytes; + //mult = (double) (max(iduration, iaduration)); + mult = (double) (iduration); + } + update_scr(priv, pl_size, tot, mult); + + + if(abytes > 0 && frame_begin) //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, tot, mult); + } + } + + frame_begin = 0; + } + + i++; + } + + + if(vpriv->is_mpeg12) + { + for(i = 0; i < n; i++) + { + vpriv->last_dts = vpriv->framebuf[i].dts; + if(vpriv->framebuf[i].pts >= vpriv->last_pts) + { + vpriv->last_pts = vpriv->framebuf[i].pts; + idur = vpriv->framebuf[i].idur; + } + } + + vpriv->last_dts += vpriv->framebuf[n-1].idur; + vpriv->last_pts += idur; + } + + 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 (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); + if((as != NULL) && priv->has_audio) + { + while(abytes > 0) + { + mult = iduration; + 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 uint64_t parse_fps(int fps) +{ + // 90000 * 1024 / fps + switch(fps) + { + case 239760: + return 3843844; + case 240000: + return 3840000; + case 250000: + return 3686400; + case 299700: + return 3075075; + case 300000: + return 3072000; + case 500000: + return 1843200; + case 599400: + return 1537538; + case 600000: + return 1536000; + default: + mp_msg(MSGT_MUXER, MSGL_ERR, "ERROR! unknown fps code: %d", fps); + return 0; + } +} + +static size_t parse_mpeg12_video(muxer_stream_t *s, muxer_priv_t *priv, muxer_headers_t *spriv, float fps, size_t len) +{ + size_t ptr = 0, sz = 0, tmp = 0; + + mp_msg(MSGT_MUXER, MSGL_V,"parse_mpeg12_video, len=%u\n", (uint32_t) len); + if(s->buffer[0] != 0 || s->buffer[1] != 0 || s->buffer[2] != 1 || len<6) + { + mp_msg(MSGT_MUXER, MSGL_ERR,"Unknown video format, possibly non-MPEG1/2 stream, len=%d!\n", len); + return 0; + } + + if(s->buffer[3] == 0 || s->buffer[3] == 0xb3 || s->buffer[3] == 0xb8) + { // Video (0) Sequence header (b3) or GOP (b8) + uint32_t temp_ref; + int pt; + + if(s->buffer[3] == 0xb3) //sequence + { + //uint8_t fps = s->buffer[7] & 0x0f; + mp_header_process_sequence_header(&(spriv->picture), &(s->buffer[4])); + spriv->delta_pts = spriv->nom_delta_pts = parse_fps(spriv->picture.fps); + + spriv->delta_clock = (double) 1/fps; + mp_msg(MSGT_MUXER, MSGL_V, "\nFPS: %.3f, FRAMETIME: %.3lf\n", fps, (double)1/fps); + if(priv->patch_seq) + patch_seq(priv, s->buffer); + + tmp = 12; + if(s->buffer[tmp-1] & 2) + tmp += 64; + + if(s->buffer[tmp-1] & 1) + tmp += 64; + + if(s->buffer[tmp] == 0 && s->buffer[tmp+1] == 0 && s->buffer[tmp+2] == 1 && s->buffer[tmp+3] == 0xb5) + mp_header_process_extension(&(spriv->picture), &(s->buffer[tmp+4])); + } + + + if(spriv->picture.mpeg1 == 0 && priv->patch_sde) + { + while((s->buffer[tmp] != 0 || s->buffer[tmp+1] != 0 || s->buffer[tmp+2] != 1 || s->buffer[tmp+3] != 0xb5 || + ((s->buffer[tmp+4] & 0xf0) != 0x20)) && + (tmp < len-5)) + tmp++; + + if(tmp < len-5) //found + patch_panscan(priv, &(s->buffer[tmp+4])); + } + + + + 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 (ptr >= len-5) + { + pt = 0; // Picture not found?! + temp_ref = 0; + mp_msg(MSGT_MUXER, MSGL_ERR,"Warning: picture not found in GOP!\n"); + } + else + { + pt = (s->buffer[ptr+5] & 0x1c) >> 3; + temp_ref = (s->buffer[ptr+4]<<2)+(s->buffer[ptr+5]>>6); + mp_msg(MSGT_MUXER, MSGL_V, "Video frame type: %c, TR: %d\n", FTYPE(pt), temp_ref); + if(spriv->picture.mpeg1 == 0) + { + size_t tmp = ptr; + + while (ptr < len-5 && + (s->buffer[ptr] != 0 || s->buffer[ptr+1] != 0 || s->buffer[ptr+2] != 1 || s->buffer[ptr+3] != 0xb5)) + ptr++; + if(ptr < len-5) + { + mp_header_process_extension(&(spriv->picture), &(s->buffer[ptr+4])); + if(spriv->picture.display_time >= 50 && spriv->picture.display_time <= 300) + spriv->delta_pts = (spriv->nom_delta_pts * spriv->picture.display_time) / 100; + } + else + spriv->delta_pts = spriv->nom_delta_pts; + + ptr = tmp; + } + } + + switch (pt) { + case 2: // predictive + if (s->ipb[0]) { + sz = len + s->ipb[0]; + s->ipb[0] = max(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; + break; + case 3: // bidirectional + s->ipb[2] += len; + sz = s->ipb[1] + s->ipb[2]; + break; + default: // intra-coded + sz = len; // no extra buffer for it... + } + + reorder_frame(spriv, s->buffer, len, pt, temp_ref, spriv->delta_pts); + } + + mp_msg(MSGT_MUXER, MSGL_V,"parse_mpeg12_video, return %u\n", (uint32_t) len); + return sz; +} + + +static uint64_t fix_mp4_frame_duration(muxer_headers_t *vpriv) +{ + uint64_t mn, md, mx, diff; + uint32_t i; + + mn = mx = vpriv->framebuf[0].pts; + for(i = 0; i < 3; i++) + { + mp_msg(MSGT_DECVIDEO,MSGL_V, "PTS: %llu\n", vpriv->framebuf[i].pts); + if(vpriv->framebuf[i].pts < mn) + mn = vpriv->framebuf[i].pts; + if(vpriv->framebuf[i].pts > mx) + mx = vpriv->framebuf[i].pts; + } + md = mn; + for(i=0; i<3; i++) + { + if((vpriv->framebuf[i].pts > mn) && (vpriv->framebuf[i].pts < mx)) + md = vpriv->framebuf[i].pts; + } + mp_msg(MSGT_DECVIDEO,MSGL_V, "MIN: %llu, mid: %llu, max: %llu\n", mn, md, mx); + + if(mx - md > md - mn) + diff = md - mn; + else + diff = mx - md; + + if(diff > 0) + { + for(i=0; i<3; i++) + { + vpriv->framebuf[i].pts += diff; + vpriv->framebuf[i].dts += i * diff; + mp_msg(MSGT_MUXER, MSGL_V, "FIXED_PTS: %.3lf, FIXED_DTS: %.3lf\n", + (double) (vpriv->framebuf[i].pts/92160000.0), (double) (vpriv->framebuf[i].dts/92160000.0)); + } + return diff; + } + else + return 0; +} + + +static size_t parse_mpeg4_video(muxer_stream_t *s, muxer_priv_t *priv, muxer_headers_t *vpriv, float fps, size_t len) +{ + size_t ptr = 0; + int64_t delta_pts; + uint8_t pt; + + mp_msg(MSGT_MUXER, MSGL_V,"parse_mpeg4_video, len=%u\n", (uint32_t) len); + if(len<6) + { + mp_msg(MSGT_MUXER, MSGL_ERR,"Frame too short: %d, exit!\n", len); + return 0; + } + + while(ptr < len - 5) + { + if(s->buffer[ptr] != 0 || s->buffer[ptr+1] != 0 || s->buffer[ptr+2] != 1) + { + ptr++; + continue; + } + + if(s->buffer[ptr+3] >= 0x20 && s->buffer[ptr+3] <= 0x2f) //VOL + { + mp4_header_process_vol(&(vpriv->picture), &(s->buffer[ptr+4])); + } + else if(s->buffer[ptr+3] == 0xb3) //gov + { + //fprintf(stderr, "\nGOV\n"); + } + else if(s->buffer[ptr+3] == 0xb6) //vop + { + int32_t delta; + mp4_header_process_vop(&(vpriv->picture), &(s->buffer[ptr+4])); + + delta = vpriv->picture.timeinc_unit - vpriv->last_tr; + if((delta > 0) && (delta > (vpriv->picture.timeinc_resolution/2))) + delta -= vpriv->picture.timeinc_resolution; + else if((delta < 0) && (delta < (-vpriv->picture.timeinc_resolution/2))) + delta += vpriv->picture.timeinc_resolution; + + delta_pts = (92160000 * (int64_t) delta) / vpriv->picture.timeinc_resolution; + + pt = vpriv->picture.picture_type + 1; + mp_msg(MSGT_MUXER, MSGL_V, "\nTYPE: %c, RESOLUTION: %d, TEMP: %d, delta: %d, delta_pts: %lld = %.3lf, delta2: %.3lf\n", + FTYPE(pt), vpriv->picture.timeinc_resolution, vpriv->picture.timeinc_unit, delta, delta_pts, (double) (delta_pts/92160000.0), + (double) delta / (double) vpriv->picture.timeinc_resolution); + + vpriv->last_tr = vpriv->picture.timeinc_unit; + + break; + } + + ptr++; + } + + vpriv->last_dts += vpriv->frame_duration; + vpriv->last_pts += delta_pts; + + reorder_frame(vpriv, s->buffer, len, pt, 0, delta_pts); + vpriv->framebuf[vpriv->framebuf_used-1].pts = vpriv->last_pts; + vpriv->framebuf[vpriv->framebuf_used-1].dts = vpriv->last_dts; + vpriv->framebuf[vpriv->framebuf_used-1].idur = vpriv->frame_duration; + + /*mp_msg(MSGT_MUXER, MSGL_V, "\nMPEG4V, PT: %c, LEN=%u, DELTA_PTS: %.3lf, PTS: %.3lf, DTS: %.3lf\n", + FTYPE(pt), len, (delta_pts/92160000.0), + (double) (vpriv->framebuf[vpriv->framebuf_used-1].pts/92160000.0), + (double) (vpriv->framebuf[vpriv->framebuf_used-1].dts/92160000.0), len);*/ + + if(!vpriv->frame_duration && vpriv->framebuf_used == 3) + { + vpriv->frame_duration = fix_mp4_frame_duration(vpriv); + if(vpriv->frame_duration) + { + vpriv->last_pts += vpriv->frame_duration; + vpriv->last_dts = vpriv->framebuf[vpriv->framebuf_used-1].dts; + vpriv->delta_clock = ((double) vpriv->frame_duration)/92160000.0; + mp_msg(MSGT_MUXER, MSGL_INFO, "FRAME DURATION: %llu %.3lf\n", + vpriv->frame_duration, (double) (vpriv->frame_duration/92160000.0)); + } + } + + mp_msg(MSGT_MUXER, MSGL_V, "LAST_PTS: %.3lf, LAST_DTS: %.3lf\n", + (double) (vpriv->last_pts/92160000.0), (double) (vpriv->last_dts/92160000.0)); + + return len; } 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; + uint64_t pts, tmp; 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; - + float fps; + uint32_t stream_format; + f = muxer->file; + + if(s->buffer == NULL) + return; + + pts = 0; if (s->type == MUXER_TYPE_VIDEO) { // try to recognize frame type... - if (s->buffer[0] != 0 || s->buffer[1] != 0 || s->buffer[2] != 1 || len<6) { - printf ("Unknown block type, possibly non-MPEG stream!\n"); - sz = len; -// return; - } else if (s->buffer[3] == 0 || s->buffer[3] == 0xb3 || - s->buffer[3] == 0xb8) { // Picture or GOP - int temp_ref; - int pt; + fps = (float) s->h.dwRate/ (float) s->h.dwScale; + spriv->type = 1; + spriv->has_pes_priv_headers = 0; + stream_format = s->bih->biCompression; - if (s->buffer[3]) { // 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"); - } else { - pt = (s->buffer[ptr+5]>>3) & 7; - temp_ref = (s->buffer[ptr+4]<<2)+(s->buffer[ptr+5]>>6); + if(is_mpeg1(stream_format) || is_mpeg2(stream_format)) + { + spriv->is_mpeg12 = 1; + if(len) + sz = parse_mpeg12_video(s, priv, spriv, fps, len); + else { + tmp = (uint64_t) (92160000 / fps); + spriv->last_pts += tmp; + spriv->last_dts += tmp; } - 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... + } + else if(is_mpeg4(stream_format)) + { + spriv->is_mpeg12 = 0; + spriv->reorder = 0; + if(spriv->size == 0) + priv->use_psm = 1; + if(len) + sz = parse_mpeg4_video(s, priv, spriv, fps, len); + else { + tmp = (uint64_t) (92160000 / fps); + spriv->last_pts += tmp; + spriv->last_dts += tmp; } - } else { - printf ("Unknown block type, possibly non-MPEG stream!\n"); - sz = len; -// return; } + + mp_msg(MSGT_MUXER, MSGL_V,"mpegfile_write_chunk, Video codec=%x, len=%u, mpeg12 returned %u\n", stream_format, (uint32_t) len, (uint32_t) sz); + + ptr = 0; + priv->vbytes += len; + sz <<= 1; } else { // MUXER_TYPE_AUDIO - if (len < 2*MUXER_MPEG_DATASIZE) - sz = 2*MUXER_MPEG_DATASIZE; // min requirement - else - sz = len; - } - 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"); - } 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; + spriv->type = 0; + stream_format = s->wf->wFormatTag; + + mp_msg(MSGT_MUXER, MSGL_V,"\nmpegfile_write_chunk, Audio codec=%x, len=%u, frame size=%u\n", + stream_format, (uint32_t) len, (uint32_t) spriv->frame_size); + 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, stream_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); + spriv->delta_pts = (uint64_t) (92160000 * spriv->frame_size) / spriv->bitrate; + mp_msg(MSGT_MUXER, MSGL_INFO, "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_msg(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_msg(MSGT_MUXER, MSGL_DBG2, "REALLOC(%d) bytes to AUDIO backbuffer\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(stream_format == AUDIO_A52) + { + s->type = 1; + s->ckid = be2me_32 (0x1bd); + if(s->size == 0) + { + spriv->max_pl_size -= 4; + if(priv->is_genmpeg1 || priv->is_genmpeg2) + fix_audio_sys_header(priv, spriv->id, 0xbd, 58*1024); //only one audio at the moment + spriv->id = 0xbd; + } + } + + 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) + { + if(priv->drop) + { + mp_msg(MSGT_MUXER, MSGL_V, "\nDROPPING %llu AUDIO BYTES, DELAY: %.3lf, BR: %u\n", delay_len, priv->init_adelay, spriv->bitrate); + drop_delayed_audio(muxer, s, (int64_t) delay_len); + } + else + { + mp_msg(MSGT_MUXER, MSGL_V, "\nWRITING %llu EARLY 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; + conf_init_adelay = 0; + priv->drop = 0; + } + } + + sz = max(len, 2 * priv->packet_size); } - 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 + + if (s->h.dwSampleSize) { + // 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++; } + 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 genmpeg1/2 and sz > last buffer size in the system header we must write the new sysheader + if(sz > s->h.dwSuggestedBufferSize) { // increase and set STD + s->h.dwSuggestedBufferSize = sz; + if(priv->is_genmpeg1 || priv->is_genmpeg2) { + fix_buffer_params(priv, spriv->id, s->h.dwSuggestedBufferSize); + priv->update_system_header = 1; + } + } + + if(spriv->psm_fixed == 0) { + add_to_psm(priv, spriv->id, stream_format); + spriv->psm_fixed = 1; + priv->psm_streams_cnt++; + if((priv->psm_streams_cnt == muxer->num_videos + muxer->num_audios) && priv->use_psm) + write_psm_block(muxer, muxer->file); } - 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; - } - mp_dbg(MSGT_MUXER, MSGL_DBG3, " next pts=%f\n", s->timer); + + + if(priv->init_adelay != 0) + return; + + 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); + if(priv->is_genmpeg1 || priv->is_genmpeg2) + write_mpeg_pack(muxer, NULL, muxer->file, NULL, 0, 1); //insert fake Nav Packet + + mp_msg(MSGT_MUXER, MSGL_INFO, "\nOverhead: %.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) +{ + muxer_priv_t *priv = (muxer_priv_t*) muxer->priv; + + priv->headers_cnt++; + + if((priv->is_genmpeg1 || priv->is_genmpeg2) && (priv->headers_cnt == muxer->avih.dwStreams)) + { + int i; + for(i = 0; i < muxer->avih.dwStreams; i++) + { + priv->sys_info.streams[i].bufsize = muxer->streams[i]->h.dwSuggestedBufferSize; + mp_msg(MSGT_MUXER, MSGL_V, "IDX: %d, BUFSIZE: %u\n", i, priv->sys_info.streams[i].bufsize); + } + } + + //write the first system header only for generic mpeg1/2 muxes, and only when we have collected all necessary infos + if(priv->is_genmpeg1 || priv->is_genmpeg2 || ((priv->is_xvcd || priv->is_xsvcd) && (priv->headers_cnt == 1))) + { + write_mpeg_pack(muxer, NULL, muxer->file, NULL, 0, 0); + priv->update_system_header = 0; + } + + return; } -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 setup_sys_params(muxer_priv_t *priv) +{ + if(priv->is_dvd) + { + priv->sys_info.cnt = 4; + + priv->sys_info.streams[0].id = 0xb9; + priv->sys_info.streams[0].type = 1; + priv->sys_info.streams[0].bufsize = 232*1024; + + priv->sys_info.streams[1].id = 0xb8; + priv->sys_info.streams[1].type = 0; + priv->sys_info.streams[1].bufsize = 4*1024; + + priv->sys_info.streams[2].id = 0xbd; + priv->sys_info.streams[2].type = 1; + priv->sys_info.streams[2].bufsize = 58*1024; + + priv->sys_info.streams[3].id = 0xbf; + priv->sys_info.streams[3].type = 1; + priv->sys_info.streams[3].bufsize = 2*1024; + } + else if(priv->is_xvcd || priv->is_xsvcd) + { + priv->sys_info.cnt = 2; + + priv->sys_info.streams[0].id = 0xe0; + priv->sys_info.streams[0].type = 1; + priv->sys_info.streams[0].bufsize = (priv->is_xvcd ? 46: 230)*1024; + + priv->sys_info.streams[1].id = 0xc0; + priv->sys_info.streams[1].type = 0; + priv->sys_info.streams[1].bufsize = 4*1024; + } + else + priv->sys_info.cnt = 0; } -static void mpegfile_write_index(muxer_t *muxer){ - unsigned int i; - unsigned int rsr; + +int 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 0; + priv->update_system_header = 1; + + //calloc() already zero-ed all flags, so we assign only the ones we need + + if(conf_mux != NULL) { + if(! strcasecmp(conf_mux, "mpeg2")) + { + priv->mux = MUX_MPEG2; + priv->packet_size = 2048; + priv->is_genmpeg2 = 1; + priv->muxrate = 1800 * 125; //Constrained parameters + } + else if(! strcasecmp(conf_mux, "dvd")) + { + priv->mux = MUX_MPEG2; + priv->is_dvd = 1; + priv->packet_size = 2048; + priv->muxrate = 10080 * 125; + } + else if(! strcasecmp(conf_mux, "xsvcd")) + { + priv->mux = MUX_MPEG2; + priv->is_xsvcd = 1; + priv->packet_size = 2324; + //what's the right muxrate? + priv->muxrate = 2788 * 125; + priv->ts_allframes = 1; + } + else if(! strcasecmp(conf_mux, "xvcd")) + { + priv->mux = MUX_MPEG1; + priv->is_xvcd = 1; + priv->packet_size = 2324; + //what's the right muxrate? + priv->muxrate = 1394 * 125; + priv->ts_allframes = 1; + } + else + { + priv->mux = MUX_MPEG1; + priv->is_genmpeg1 = 1; + priv->packet_size = 2048; + priv->muxrate = 1800 * 125; //Constrained parameters + } + } + + if(conf_ts_allframes) + priv->ts_allframes = 1; + if(conf_muxrate > 0) + priv->muxrate = conf_muxrate * 125; // * 1000 / 8 + if(conf_packet_size) + priv->packet_size = conf_packet_size; + mp_msg(MSGT_MUXER, MSGL_INFO, "PACKET SIZE: %u bytes\n", priv->packet_size); + setup_sys_params(priv); - 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; -} - -void muxer_init_muxer_mpeg(muxer_t *muxer){ + priv->skip_padding = conf_skip_padding; + 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->panscan_width = (uint16_t) conf_panscan_width; + priv->panscan_height = (uint16_t) conf_panscan_height; + priv->vbitrate = ((conf_vbitrate) * 10) >> 2; //*1000 / 400 + + if(priv->vaspect || priv->vframerate || priv->vwidth || priv->vheight || priv->vbitrate || priv->panscan_width || priv->panscan_height) + { + priv->patch_seq = priv->vaspect || priv->vframerate || priv->vwidth || priv->vheight || priv->vbitrate; + priv->patch_sde = priv->panscan_width || priv->panscan_height; + 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->panscan_width || priv->panscan_height) + mp_msg(MSGT_MUXER, MSGL_INFO, " panscan to to %dx%d", priv->panscan_width, priv->panscan_height); + 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; + + + muxer->sysrate = priv->muxrate; // initial muxrate = constrained stream parameter + priv->scr = muxer->file_end = 0; + + if(conf_init_adelay) + priv->init_adelay = (double) conf_init_adelay / (double) 1000.0; + + priv->drop = conf_drop; + + priv->buff = (uint8_t *) malloc(priv->packet_size); + priv->tmp = (uint8_t *) malloc(priv->packet_size); + priv->residual = (uint8_t *) malloc(priv->packet_size); + if((priv->buff == NULL) || (priv->tmp == NULL) || (priv->residual == NULL)) + { + mp_msg(MSGT_MUXER, MSGL_ERR, "\nCouldn't allocate %d bytes, exit\n", priv->packet_size); + return 0; + } + + 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 1; } diff -r eddd61a68410 -r 70c446099f40 libmpdemux/muxer_rawvideo.c --- a/libmpdemux/muxer_rawvideo.c Mon Feb 21 17:40:46 2005 +0000 +++ b/libmpdemux/muxer_rawvideo.c Mon Feb 21 21:45:49 2005 +0000 @@ -90,9 +90,10 @@ return; } -void muxer_init_muxer_rawvideo(muxer_t *muxer){ +int 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 1; }