summaryrefslogtreecommitdiffstats
path: root/libmpdemux
diff options
context:
space:
mode:
authornicodvb <nicodvb@b3059339-0415-0410-9bf9-f77b7e298cf2>2005-02-21 21:45:49 +0000
committernicodvb <nicodvb@b3059339-0415-0410-9bf9-f77b7e298cf2>2005-02-21 21:45:49 +0000
commit10069de306ed73689d8b62dd5ae72814e6ed03d1 (patch)
tree4006f167d138393e040bebd2a4ebd6ed00e0be34 /libmpdemux
parent4dc848b8033d0f67ce1639a7505442be8ba3e87c (diff)
downloadmpv-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
Diffstat (limited to 'libmpdemux')
-rw-r--r--libmpdemux/muxer.c14
-rw-r--r--libmpdemux/muxer.h15
-rw-r--r--libmpdemux/muxer_avi.c3
-rw-r--r--libmpdemux/muxer_mpeg.c2691
-rw-r--r--libmpdemux/muxer_rawvideo.c3
5 files changed, 2368 insertions, 358 deletions
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;
+ *(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;