diff options
author | nicodvb <nicodvb@b3059339-0415-0410-9bf9-f77b7e298cf2> | 2005-02-21 21:45:49 +0000 |
---|---|---|
committer | nicodvb <nicodvb@b3059339-0415-0410-9bf9-f77b7e298cf2> | 2005-02-21 21:45:49 +0000 |
commit | 10069de306ed73689d8b62dd5ae72814e6ed03d1 (patch) | |
tree | 4006f167d138393e040bebd2a4ebd6ed00e0be34 | |
parent | 4dc848b8033d0f67ce1639a7505442be8ba3e87c (diff) | |
download | mpv-10069de306ed73689d8b62dd5ae72814e6ed03d1.tar.bz2 mpv-10069de306ed73689d8b62dd5ae72814e6ed03d1.tar.xz |
new mpeg muxer compatible with dvd/[s]vcd; small changes in the muxer layer (sanity checks in the muxer_init functions)
git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@14754 b3059339-0415-0410-9bf9-f77b7e298cf2
-rw-r--r-- | cfg-mencoder.h | 2 | ||||
-rw-r--r-- | libmpdemux/muxer.c | 14 | ||||
-rw-r--r-- | libmpdemux/muxer.h | 15 | ||||
-rw-r--r-- | libmpdemux/muxer_avi.c | 3 | ||||
-rw-r--r-- | libmpdemux/muxer_mpeg.c | 2691 | ||||
-rw-r--r-- | libmpdemux/muxer_rawvideo.c | 3 |
6 files changed, 2370 insertions, 358 deletions
diff --git a/cfg-mencoder.h b/cfg-mencoder.h index d0ec47be12..cb8a43b0b2 100644 --- a/cfg-mencoder.h +++ b/cfg-mencoder.h @@ -72,6 +72,7 @@ extern m_option_t x264encopts_conf[]; #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 @@ m_option_t mencoder_opts[]={ #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 --git a/libmpdemux/muxer.c b/libmpdemux/muxer.c index 23fbce98ba..7209a07e05 100644 --- a/libmpdemux/muxer.c +++ b/libmpdemux/muxer.c @@ -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_t *muxer_new_muxer(int type,FILE *f){ 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 --git a/libmpdemux/muxer.h b/libmpdemux/muxer.h index 2056ee9c5c..1983a3ea2a 100644 --- a/libmpdemux/muxer.h +++ b/libmpdemux/muxer.h @@ -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 @@ typedef struct { 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 @@ typedef struct muxer_t{ 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 --git a/libmpdemux/muxer_avi.c b/libmpdemux/muxer_avi.c index 509d2b7eb5..c156fe89bc 100644 --- a/libmpdemux/muxer_avi.c +++ b/libmpdemux/muxer_avi.c @@ -660,9 +660,10 @@ static void avifile_write_index(muxer_t *muxer){ } } -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 --git a/libmpdemux/muxer_mpeg.c b/libmpdemux/muxer_mpeg.c index edf46f31bc..b514ea08e8 100644 --- a/libmpdemux/muxer_mpeg.c +++ b/libmpdemux/muxer_mpeg.c @@ -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 -// ISO-11172 requirements -#define MPEG_MAX_PTS_DELAY 90000 /* 1s */ -#define MPEG_MAX_SCR_INTERVAL 63000 /* 0.7s */ +#define PES_PRIVATE1 0x01bd +#define PES_PRIVATE2 0x01bf -// suggestions -#define MPEG_STARTPTS 45000 /* 0.5s */ -#define MPEG_MIN_PTS_DELAY 9000 /* 0.1s */ -#define MPEG_STARTSCR 9 /* 0.1ms */ +#define MUX_MPEG1 1 +#define MUX_MPEG2 2 -//static unsigned int mpeg_min_delay; -//static unsigned int mpeg_max_delay; +#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 +}; + +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; + + +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 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 @@ static muxer_stream_t* mpegfile_new_stream(muxer_t *muxer,int type){ 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_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 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 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_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; + |