@ -50,9 +50,14 @@ typedef struct {
int video_bound ;
int is_mpeg2 ;
int is_vcd ;
int is_svcd ;
int scr_stream_index ; /* stream from which the system clock is
computed ( VBR case ) */
int64_t last_scr ; /* current system clock */
double vcd_padding_bitrate ;
int64_t vcd_padding_bytes_written ;
} MpegMuxContext ;
# define PACK_START_CODE ((unsigned int)0x000001ba)
@ -80,6 +85,7 @@ static const int lpcm_freq_tab[4] = { 48000, 96000, 44100, 32000 };
extern AVOutputFormat mpeg1system_mux ;
extern AVOutputFormat mpeg1vcd_mux ;
extern AVOutputFormat mpeg2vob_mux ;
extern AVOutputFormat mpeg2svcd_mux ;
static int put_pack_header ( AVFormatContext * ctx ,
uint8_t * buf , int64_t timestamp )
@ -117,7 +123,7 @@ static int put_pack_header(AVFormatContext *ctx,
return pbBufPtr ( & pb ) - pb . buf ;
}
static int put_system_header ( AVFormatContext * ctx , uint8_t * buf )
static int put_system_header ( AVFormatContext * ctx , uint8_t * buf , int only_for_stream_id )
{
MpegMuxContext * s = ctx - > priv_data ;
int size , rate_bound , i , private_stream_coded , id ;
@ -132,40 +138,67 @@ static int put_system_header(AVFormatContext *ctx, uint8_t *buf)
rate_bound = s - > mux_rate ; /* maximum bit rate of the multiplexed stream */
put_bits ( & pb , 22 , rate_bound ) ;
put_bits ( & pb , 1 , 1 ) ; /* marker */
put_bits ( & pb , 6 , s - > audio_bound ) ;
if ( s - > is_vcd & & only_for_stream_id = = VIDEO_ID ) {
/* This header applies only to the video stream (see VCD standard p. IV-7)*/
put_bits ( & pb , 6 , 0 ) ;
} else
put_bits ( & pb , 6 , s - > audio_bound ) ;
put_bits ( & pb , 1 , 1 ) ; /* variable bitrate */
if ( s - > is_vcd )
put_bits ( & pb , 1 , 0 ) ; /* see VCD standard, p. IV-7*/
else
put_bits ( & pb , 1 , 1 ) ; /* variable bitrate*/
put_bits ( & pb , 1 , 1 ) ; /* non constrainted bit stream */
put_bits ( & pb , 1 , 0 ) ; /* audio locked */
put_bits ( & pb , 1 , 0 ) ; /* video locked */
if ( s - > is_vcd ) {
/* see VCD standard p IV-7 */
put_bits ( & pb , 1 , 1 ) ; /* audio locked */
put_bits ( & pb , 1 , 1 ) ; /* video locked */
} else {
put_bits ( & pb , 1 , 0 ) ; /* audio locked */
put_bits ( & pb , 1 , 0 ) ; /* video locked */
}
put_bits ( & pb , 1 , 1 ) ; /* marker */
put_bits ( & pb , 5 , s - > video_bound ) ;
if ( s - > is_vcd & & only_for_stream_id = = AUDIO_ID ) {
/* This header applies only to the audio stream (see VCD standard p. IV-7)*/
put_bits ( & pb , 5 , 0 ) ;
} else
put_bits ( & pb , 5 , s - > video_bound ) ;
put_bits ( & pb , 8 , 0xff ) ; /* reserved byte */
/* audio stream info */
private_stream_coded = 0 ;
for ( i = 0 ; i < ctx - > nb_streams ; i + + ) {
StreamInfo * stream = ctx - > streams [ i ] - > priv_data ;
id = stream - > id ;
if ( id < 0xc0 ) {
/* special case for private streams (AC3 use that) */
if ( private_stream_coded )
continue ;
private_stream_coded = 1 ;
id = 0xbd ;
}
put_bits ( & pb , 8 , id ) ; /* stream ID */
put_bits ( & pb , 2 , 3 ) ;
if ( id < 0xe0 ) {
/* audio */
put_bits ( & pb , 1 , 0 ) ;
put_bits ( & pb , 13 , stream - > max_buffer_size / 128 ) ;
} else {
/* video */
put_bits ( & pb , 1 , 1 ) ;
put_bits ( & pb , 13 , stream - > max_buffer_size / 1024 ) ;
/* For VCDs, only include the stream info for the stream
that the pack which contains this system belongs to .
( see VCD standard p . IV - 7 ) */
if ( ! s - > is_vcd | | stream - > id = = only_for_stream_id
| | only_for_stream_id = = 0 ) {
id = stream - > id ;
if ( id < 0xc0 ) {
/* special case for private streams (AC3 use that) */
if ( private_stream_coded )
continue ;
private_stream_coded = 1 ;
id = 0xbd ;
}
put_bits ( & pb , 8 , id ) ; /* stream ID */
put_bits ( & pb , 2 , 3 ) ;
if ( id < 0xe0 ) {
/* audio */
put_bits ( & pb , 1 , 0 ) ;
put_bits ( & pb , 13 , stream - > max_buffer_size / 128 ) ;
} else {
/* video */
put_bits ( & pb , 1 , 1 ) ;
put_bits ( & pb , 13 , stream - > max_buffer_size / 1024 ) ;
}
}
}
flush_put_bits ( & pb ) ;
@ -202,15 +235,21 @@ static int mpeg_mux_init(AVFormatContext *ctx)
int bitrate , i , mpa_id , mpv_id , ac3_id , lpcm_id , j ;
AVStream * st ;
StreamInfo * stream ;
int audio_bitrate ;
int video_bitrate ;
s - > packet_number = 0 ;
s - > is_vcd = ( ctx - > oformat = = & mpeg1vcd_mux ) ;
s - > is_mpeg2 = ( ctx - > oformat = = & mpeg2vob_mux ) ;
s - > is_svcd = ( ctx - > oformat = = & mpeg2svcd_mux ) ;
s - > is_mpeg2 = ( ctx - > oformat = = & mpeg2vob_mux | | ctx - > oformat = = & mpeg2svcd_mux ) ;
if ( s - > is_vcd )
s - > packet_size = 2324 ; /* VCD packet size */
if ( s - > is_vcd | | s - > is_svcd )
s - > packet_size = 2324 ; /* VCD/SVCD packet size */
else
s - > packet_size = 2048 ;
s - > vcd_padding_bytes_written = 0 ;
s - > vcd_padding_bitrate = 0 ;
s - > audio_bound = 0 ;
s - > video_bound = 0 ;
@ -266,14 +305,55 @@ static int mpeg_mux_init(AVFormatContext *ctx)
if ( s - > scr_stream_index = = - 1 )
s - > scr_stream_index = 0 ;
/* we increase slightly the bitrate to take into account the
headers . XXX : compute it exactly */
bitrate = 200 0;
bitrate = 0 ;
audio_bitrate = 0 ;
video_ bitrate = 0 ;
for ( i = 0 ; i < ctx - > nb_streams ; i + + ) {
st = ctx - > streams [ i ] ;
stream = ( StreamInfo * ) st - > priv_data ;
bitrate + = st - > codec . bit_rate ;
if ( stream - > id = = AUDIO_ID )
audio_bitrate + = st - > codec . bit_rate ;
else if ( stream - > id = = VIDEO_ID )
video_bitrate + = st - > codec . bit_rate ;
}
if ( s - > is_vcd ) {
double overhead_rate ;
/* The VCD standard mandates that the mux_rate field is 3528
( see standard p . IV - 6 ) .
The value is actually " wrong " , i . e . if you calculate
it using the normal formula and the 75 sectors per second transfer
rate you get a different value because the real pack size is 2324 ,
not 2352. But the standard explicitly specifies that the mux_rate
field in the header must have this value . */
s - > mux_rate = 2352 * 75 / 50 ; /* = 3528*/
/* The VCD standard states that the muxed stream must be
exactly 75 packs / second ( the data rate of a single speed cdrom ) .
Since the video bitrate ( probably 1150000 bits / sec ) will be below
the theoretical maximum we have to add some padding packets
to make up for the lower data rate .
( cf . VCD standard p . IV - 6 ) */
/* Add the header overhead to the data rate.
2279 data bytes per audio pack , 2294 data bytes per video pack */
overhead_rate = ( ( audio_bitrate / 8.0 ) / 2279 ) * ( 2324 - 2279 ) ;
overhead_rate + = ( ( video_bitrate / 8.0 ) / 2294 ) * ( 2324 - 2294 ) ;
overhead_rate * = 8 ;
/* Add padding so that the full bitrate is 2324*75 bytes/sec */
s - > vcd_padding_bitrate = 2324 * 75 * 8 - ( bitrate + overhead_rate ) ;
} else {
/* we increase slightly the bitrate to take into account the
headers . XXX : compute it exactly */
bitrate + = 2000 ;
s - > mux_rate = ( bitrate + ( 8 * 50 ) - 1 ) / ( 8 * 50 ) ;
}
s - > mux_rate = ( bitrate + ( 8 * 50 ) - 1 ) / ( 8 * 50 ) ;
if ( s - > is_vcd | | s - > is_mpeg2 )
/* every packet */
@ -290,8 +370,10 @@ static int mpeg_mux_init(AVFormatContext *ctx)
/* every 200 packets. Need to look at the spec. */
s - > system_header_freq = s - > pack_header_freq * 40 ;
else if ( s - > is_vcd )
/* every 40 packets, this is my invention */
s - > system_header_freq = s - > pack_header_freq * 40 ;
/* the standard mandates that there are only two system headers
in the whole file : one in the first packet of each stream .
( see standard p . IV - 7 and IV - 8 ) */
s - > system_header_freq = 0x7fffffff ;
else
s - > system_header_freq = s - > pack_header_freq * 5 ;
@ -323,6 +405,30 @@ static inline void put_timestamp(ByteIOContext *pb, int id, int64_t timestamp)
}
/* return the number of padding bytes that should be inserted into
the multiplexed stream . */
static int get_vcd_padding_size ( AVFormatContext * ctx , int64_t pts )
{
MpegMuxContext * s = ctx - > priv_data ;
int pad_bytes = 0 ;
if ( s - > vcd_padding_bitrate > 0 & & pts ! = AV_NOPTS_VALUE )
{
int64_t full_pad_bytes ;
full_pad_bytes = ( int64_t ) ( ( s - > vcd_padding_bitrate * ( pts / 90000.0 ) ) / 8.0 ) ;
pad_bytes = ( int ) ( full_pad_bytes - s - > vcd_padding_bytes_written ) ;
if ( pad_bytes < 0 )
/* might happen if we have already padded to a later timestamp. This
can occur if another stream has already advanced further . */
pad_bytes = 0 ;
}
return pad_bytes ;
}
/* return the exact available payload size for the next packet for
stream ' stream_index ' . ' pts ' and ' dts ' are only used to know if
timestamps are needed in the packet header . */
@ -333,6 +439,8 @@ static int get_packet_payload_size(AVFormatContext *ctx, int stream_index,
int buf_index ;
StreamInfo * stream ;
stream = ctx - > streams [ stream_index ] - > priv_data ;
buf_index = 0 ;
if ( ( ( s - > packet_number % s - > pack_header_freq ) = = 0 ) ) {
/* pack header size */
@ -340,41 +448,100 @@ static int get_packet_payload_size(AVFormatContext *ctx, int stream_index,
buf_index + = 14 ;
else
buf_index + = 12 ;
if ( ( s - > packet_number % s - > system_header_freq ) = = 0 )
buf_index + = s - > system_header_size ;
if ( s - > is_vcd ) {
/* there is exactly one system header for each stream in a VCD MPEG,
One in the very first video packet and one in the very first
audio packet ( see VCD standard p . IV - 7 and IV - 8 ) . */
if ( stream - > packet_number = = 0 )
/* The system headers refer only to the stream they occur in,
so they have a constant size . */
buf_index + = 15 ;
} else {
if ( ( s - > packet_number % s - > system_header_freq ) = = 0 )
buf_index + = s - > system_header_size ;
}
}
/* packet header size */
buf_index + = 6 ;
if ( s - > is_mpeg2 )
buf_index + = 3 ;
if ( pts ! = AV_NOPTS_VALUE ) {
if ( dts ! = pts )
buf_index + = 5 + 5 ;
else
buf_index + = 5 ;
} else {
if ( ! s - > is_mpeg2 )
buf_index + + ;
}
stream = ctx - > streams [ stream_index ] - > priv_data ;
if ( stream - > id < 0xc0 ) {
/* AC3/LPCM private data header */
buf_index + = 4 ;
if ( stream - > id > = 0xa0 ) {
int n ;
if ( s - > is_vcd & & stream - > packet_number = = 0 )
/* the first pack of each stream contains only the pack header,
the system header and some padding ( see VCD standard p . IV - 6 )
Add the padding size , so that the actual payload becomes 0. */
buf_index + = s - > packet_size - buf_index ;
else {
/* packet header size */
buf_index + = 6 ;
if ( s - > is_mpeg2 )
buf_index + = 3 ;
/* NOTE: we round the payload size to an integer number of
LPCM samples */
n = ( s - > packet_size - buf_index ) % stream - > lpcm_align ;
if ( n )
buf_index + = ( stream - > lpcm_align - n ) ;
if ( pts ! = AV_NOPTS_VALUE ) {
if ( dts ! = pts )
buf_index + = 5 + 5 ;
else
buf_index + = 5 ;
} else {
if ( ! s - > is_mpeg2 )
buf_index + + ;
}
if ( stream - > id < 0xc0 ) {
/* AC3/LPCM private data header */
buf_index + = 4 ;
if ( stream - > id > = 0xa0 ) {
int n ;
buf_index + = 3 ;
/* NOTE: we round the payload size to an integer number of
LPCM samples */
n = ( s - > packet_size - buf_index ) % stream - > lpcm_align ;
if ( n )
buf_index + = ( stream - > lpcm_align - n ) ;
}
}
if ( s - > is_vcd & & stream - > id = = AUDIO_ID )
/* The VCD standard demands that 20 zero bytes follow
each audio packet ( see standard p . IV - 8 ) . */
buf_index + = 20 ;
}
return s - > packet_size - buf_index ;
}
/* Write an MPEG padding packet header. */
static int put_padding_header ( AVFormatContext * ctx , uint8_t * buf , int full_padding_size )
{
MpegMuxContext * s = ctx - > priv_data ;
int size = full_padding_size - 6 ; /* subtract header length */
buf [ 0 ] = ( uint8_t ) ( PADDING_STREAM > > 24 ) ;
buf [ 1 ] = ( uint8_t ) ( PADDING_STREAM > > 16 ) ;
buf [ 2 ] = ( uint8_t ) ( PADDING_STREAM > > 8 ) ;
buf [ 3 ] = ( uint8_t ) ( PADDING_STREAM ) ;
buf [ 4 ] = ( uint8_t ) ( size > > 8 ) ;
buf [ 5 ] = ( uint8_t ) ( size & 0xff ) ;
if ( ! s - > is_mpeg2 ) {
buf [ 6 ] = 0x0f ;
return 7 ;
} else
return 6 ;
}
static void put_padding_packet ( AVFormatContext * ctx , ByteIOContext * pb , int packet_bytes )
{
uint8_t buffer [ 7 ] ;
int size , i ;
size = put_padding_header ( ctx , buffer , packet_bytes ) ;
put_buffer ( pb , buffer , size ) ;
packet_bytes - = size ;
for ( i = 0 ; i < packet_bytes ; i + + )
put_byte ( pb , 0xff ) ;
}
/* flush the packet on stream stream_index */
static void flush_packet ( AVFormatContext * ctx , int stream_index ,
int64_t pts , int64_t dts , int64_t scr )
@ -385,6 +552,8 @@ static void flush_packet(AVFormatContext *ctx, int stream_index,
int size , payload_size , startcode , id , stuffing_size , i , header_len ;
int packet_size ;
uint8_t buffer [ 128 ] ;
int zero_trail_bytes = 0 ;
int pad_packet_bytes = 0 ;
id = stream - > id ;
@ -394,109 +563,151 @@ static void flush_packet(AVFormatContext *ctx, int stream_index,
# endif
buf_ptr = buffer ;
if ( ( ( s - > packet_number % s - > pack_header_freq ) = = 0 ) ) {
/* output pack and systems header if needed */
size = put_pack_header ( ctx , buf_ptr , scr ) ;
buf_ptr + = size ;
if ( ( s - > packet_number % s - > system_header_freq ) = = 0 ) {
size = put_system_header ( ctx , buf_ptr ) ;
buf_ptr + = size ;
if ( s - > is_vcd ) {
/* there is exactly one system header for each stream in a VCD MPEG,
One in the very first video packet and one in the very first
audio packet ( see VCD standard p . IV - 7 and IV - 8 ) . */
if ( stream - > packet_number = = 0 ) {
size = put_system_header ( ctx , buf_ptr , id ) ;
buf_ptr + = size ;
}
} else {
if ( ( s - > packet_number % s - > system_header_freq ) = = 0 ) {
size = put_system_header ( ctx , buf_ptr , 0 ) ;
buf_ptr + = size ;
}
}
}
size = buf_ptr - buffer ;
put_buffer ( & ctx - > pb , buffer , size ) ;
/* packet header */
if ( s - > is_mpeg2 ) {
header_len = 3 ;
} else {
header_len = 0 ;
}
if ( pts ! = AV_NOPTS_VALUE ) {
if ( dts ! = pts )
header_len + = 5 + 5 ;
else
header_len + = 5 ;
} else {
if ( ! s - > is_mpeg2 )
header_len + + ;
packet_size = s - > packet_size - size ;
if ( s - > is_vcd & & id = = AUDIO_ID )
/* The VCD standard demands that 20 zero bytes follow
each audio pack ( see standard p . IV - 8 ) . */
zero_trail_bytes + = 20 ;
if ( s - > is_vcd & & stream - > packet_number = = 0 ) {
/* the first pack of each stream contains only the pack header,
the system header and lots of padding ( see VCD standard p . IV - 6 ) .
In the case of an audio pack , 20 zero bytes are also added at
the end . */
pad_packet_bytes = packet_size - zero_trail_bytes ;
}
packet_size = s - > packet_size - ( size + 6 ) ;
payload_size = packet_size - header_len ;
if ( id < 0xc0 ) {
startcode = PRIVATE_STREAM_1 ;
payload_size - = 4 ;
if ( id > = 0xa0 )
payload_size - = 3 ;
} else {
startcode = 0x100 + id ;
}
packet_size - = pad_packet_bytes + zero_trail_bytes ;
stuffing_size = payload_size - stream - > buffer_ptr ;
if ( stuffing_size < 0 )
stuffing_size = 0 ;
put_be32 ( & ctx - > pb , startcode ) ;
if ( packet_size > 0 ) {
put_be16 ( & ctx - > pb , packet_size ) ;
/* packet header size */
packet_size - = 6 ;
/* packet header */
if ( s - > is_mpeg2 ) {
header_len = 3 ;
} else {
header_len = 0 ;
}
if ( pts ! = AV_NOPTS_VALUE ) {
if ( dts ! = pts )
header_len + = 5 + 5 ;
else
header_len + = 5 ;
} else {
if ( ! s - > is_mpeg2 )
header_len + + ;
}
if ( ! s - > is_mpeg2 )
for ( i = 0 ; i < stuffing_size ; i + + )
put_byte ( & ctx - > pb , 0xff ) ;
payload_size = packet_size - header_len ;
if ( id < 0xc0 ) {
startcode = PRIVATE_STREAM_1 ;
payload_size - = 4 ;
if ( id > = 0xa0 )
payload_size - = 3 ;
} else {
startcode = 0x100 + id ;
}
if ( s - > is_mpeg2 ) {
put_byte ( & ctx - > pb , 0x80 ) ; /* mpeg2 id */
stuffing_size = payload_size - stream - > buffer_ptr ;
if ( stuffing_size < 0 )
stuffing_size = 0 ;
put_be32 ( & ctx - > pb , startcode ) ;
if ( pts ! = AV_NOPTS_VALUE ) {
if ( dts ! = pts ) {
put_byte ( & ctx - > pb , 0xc0 ) ; /* flags */
put_byte ( & ctx - > pb , header_len - 3 + stuffing_size ) ;
put_timestamp ( & ctx - > pb , 0x03 , pts ) ;
put_timestamp ( & ctx - > pb , 0x01 , dts ) ;
put_be16 ( & ctx - > pb , packet_size ) ;
if ( ! s - > is_mpeg2 )
for ( i = 0 ; i < stuffing_size ; i + + )
put_byte ( & ctx - > pb , 0xff ) ;
if ( s - > is_mpeg2 ) {
put_byte ( & ctx - > pb , 0x80 ) ; /* mpeg2 id */
if ( pts ! = AV_NOPTS_VALUE ) {
if ( dts ! = pts ) {
put_byte ( & ctx - > pb , 0xc0 ) ; /* flags */
put_byte ( & ctx - > pb , header_len - 3 + stuffing_size ) ;
put_timestamp ( & ctx - > pb , 0x03 , pts ) ;
put_timestamp ( & ctx - > pb , 0x01 , dts ) ;
} else {
put_byte ( & ctx - > pb , 0x80 ) ; /* flags */
put_byte ( & ctx - > pb , header_len - 3 + stuffing_size ) ;
put_timestamp ( & ctx - > pb , 0x02 , pts ) ;
}
} else {
put_byte ( & ctx - > pb , 0x80 ) ; /* flags */
put_byte ( & ctx - > pb , 0x0 0 ) ; /* flags */
put_byte ( & ctx - > pb , header_len - 3 + stuffing_size ) ;
put_timestamp ( & ctx - > pb , 0x02 , pts ) ;
}
} else {
put_byte ( & ctx - > pb , 0x00 ) ; /* flags */
put_byte ( & ctx - > pb , header_len - 3 + stuffing_size ) ;
}
} else {
if ( pts ! = AV_NOPTS_VALUE ) {
if ( dts ! = pts ) {
put_timestamp ( & ctx - > pb , 0x03 , pts ) ;
put_timestamp ( & ctx - > pb , 0x01 , dts ) ;
if ( pts ! = AV_NOPTS_VALUE ) {
if ( dts ! = pts ) {
put_timestamp ( & ctx - > pb , 0x03 , pts ) ;
put_timestamp ( & ctx - > pb , 0x01 , dts ) ;
} else {
put_timestamp ( & ctx - > pb , 0x02 , pts ) ;
}
} else {
put_tim estamp ( & ctx - > pb , 0x02 , pts ) ;
put_by te ( & ctx - > pb , 0x0f ) ;
}
} else {
put_byte ( & ctx - > pb , 0x0f ) ;
}
}
if ( startcode = = PRIVATE_STREAM_1 ) {
put_byte ( & ctx - > pb , id ) ;
if ( id > = 0xa0 ) {
/* LPCM (XXX: check nb_frames) */
put_byte ( & ctx - > pb , 7 ) ;
put_be16 ( & ctx - > pb , 4 ) ; /* skip 3 header bytes */
put_byte ( & ctx - > pb , stream - > lpcm_header [ 0 ] ) ;
put_byte ( & ctx - > pb , stream - > lpcm_header [ 1 ] ) ;
put_byte ( & ctx - > pb , stream - > lpcm_header [ 2 ] ) ;
} else {
/* AC3 */
put_byte ( & ctx - > pb , stream - > nb_frames ) ;
put_be16 ( & ctx - > pb , stream - > frame_start_offset ) ;
if ( startcode = = PRIVATE_STREAM_1 ) {
put_byte ( & ctx - > pb , id ) ;
if ( id > = 0xa0 ) {
/* LPCM (XXX: check nb_frames) */
put_byte ( & ctx - > pb , 7 ) ;
put_be16 ( & ctx - > pb , 4 ) ; /* skip 3 header bytes */
put_byte ( & ctx - > pb , stream - > lpcm_header [ 0 ] ) ;
put_byte ( & ctx - > pb , stream - > lpcm_header [ 1 ] ) ;
put_byte ( & ctx - > pb , stream - > lpcm_header [ 2 ] ) ;
} else {
/* AC3 */
put_byte ( & ctx - > pb , stream - > nb_frames ) ;
put_be16 ( & ctx - > pb , stream - > frame_start_offset ) ;
}
}
if ( s - > is_mpeg2 )
for ( i = 0 ; i < stuffing_size ; i + + )
put_byte ( & ctx - > pb , 0xff ) ;
/* output data */
put_buffer ( & ctx - > pb , stream - > buffer , payload_size - stuffing_size ) ;
}
if ( s - > is_mpeg2 )
for ( i = 0 ; i < stuffing_size ; i + + )
put_byte ( & ctx - > pb , 0xff ) ;
if ( pad_packet_bytes > 0 )
put_padding_packet ( ctx , & ctx - > pb , pad_packet_bytes ) ;
/* output data */
put_buffer ( & ctx - > pb , stream - > buffer , payload_size - stuffing_size ) ;
for ( i = 0 ; i < zero_trail_bytes ; i + + )
put_byte ( & ctx - > pb , 0x00 ) ;
put_flush_packet ( & ctx - > pb ) ;
s - > packet_number + + ;
@ -505,6 +716,31 @@ static void flush_packet(AVFormatContext *ctx, int stream_index,
stream - > frame_start_offset = 0 ;
}
static void put_vcd_padding_sector ( AVFormatContext * ctx )
{
/* There are two ways to do this padding: writing a sector/pack
of 0 values , or writing an MPEG padding pack . Both seem to
work with most decoders , BUT the VCD standard only allows a 0 - sector
( see standard p . IV - 4 , IV - 5 ) .
So a 0 - sector it is . . . */
MpegMuxContext * s = ctx - > priv_data ;
int i ;
for ( i = 0 ; i < s - > packet_size ; i + + )
put_byte ( & ctx - > pb , 0 ) ;
s - > vcd_padding_bytes_written + = s - > packet_size ;
put_flush_packet ( & ctx - > pb ) ;
/* increasing the packet number is correct. The SCR of the following packs
is calculated from the packet_number and it has to include the padding
sector ( it represents the sector index , not the MPEG pack index )
( see VCD standard p . IV - 6 ) */
s - > packet_number + + ;
}
/* XXX: move that to upper layer */
/* XXX: we assume that there are always 'max_b_frames' between
reference frames . A better solution would be to use the AVFrame pts
@ -549,6 +785,43 @@ static void compute_pts_dts(AVStream *st, int64_t *ppts, int64_t *pdts,
* pdts = dts & ( ( 1LL < < 33 ) - 1 ) ;
}
static int64_t update_scr ( AVFormatContext * ctx , int stream_index , int64_t pts )
{
MpegMuxContext * s = ctx - > priv_data ;
int64_t scr ;
if ( s - > is_vcd )
/* Since the data delivery rate is constant, SCR is computed
using the formula C + i * 1200 where C is the start constant
and i is the pack index .
It is recommended that SCR 0 is at the beginning of the VCD front
margin ( a sequence of empty Form 2 sectors on the CD ) .
It is recommended that the front margin is 30 sectors long , so
we use C = 30 * 1200 = 36000
( Note that even if the front margin is not 30 sectors the file
will still be correct according to the standard . It just won ' t have
the " recommended " value ) . */
scr = 36000 + s - > packet_number * 1200 ;
else {
/* XXX I believe this calculation of SCR is wrong. SCR
specifies at which time the data should enter the decoder .
Two packs cannot enter the decoder at the same time . */
/* XXX: system clock should be computed precisely, especially for
CBR case . The current mode gives at least something coherent */
if ( stream_index = = s - > scr_stream_index
& & pts ! = AV_NOPTS_VALUE )
scr = pts ;
else
scr = s - > last_scr ;
}
s - > last_scr = scr ;
return scr ;
}
static int mpeg_mux_write_packet ( AVFormatContext * ctx , int stream_index ,
const uint8_t * buf , int size ,
int64_t timestamp )
@ -558,15 +831,13 @@ static int mpeg_mux_write_packet(AVFormatContext *ctx, int stream_index,
StreamInfo * stream = st - > priv_data ;
int64_t pts , dts , new_start_pts , new_start_dts ;
int len , avail_size ;
compute_pts_dts ( st , & pts , & dts , timestamp ) ;
/* XXX: system clock should be computed precisely, especially for
CBR case . The current mode gives at least something coherent */
if ( stream_index = = s - > scr_stream_index )
s - > last_scr = pts ;
#if 0
update_scr ( ctx , stream_index , pts ) ;
printf ( " %d: pts=%0.3f dts=%0.3f scr=%0.3f \n " ,
stream_index ,
pts / 90000.0 ,
@ -586,10 +857,15 @@ static int mpeg_mux_write_packet(AVFormatContext *ctx, int stream_index,
new_start_pts ,
new_start_dts ) ;
if ( stream - > buffer_ptr > = avail_size ) {
update_scr ( ctx , stream_index , stream - > start_pts ) ;
/* unlikely case: outputing the pts or dts increase the packet
size so that we cannot write the start of the next
packet . In this case , we must flush the current packet with
padding */
padding .
Note : this always happens for the first audio and video packet
in a VCD file , since they do not carry any data . */
flush_packet ( ctx , stream_index ,
stream - > start_pts , stream - > start_dts , s - > last_scr ) ;
stream - > buffer_ptr = 0 ;
@ -611,10 +887,23 @@ static int mpeg_mux_write_packet(AVFormatContext *ctx, int stream_index,
buf + = len ;
size - = len ;
if ( stream - > buffer_ptr > = avail_size ) {
update_scr ( ctx , stream_index , stream - > start_pts ) ;
/* if packet full, we send it now */
flush_packet ( ctx , stream_index ,
stream - > start_pts , stream - > start_dts , s - > last_scr ) ;
stream - > buffer_ptr = 0 ;
if ( s - > is_vcd ) {
/* Write one or more padding sectors, if necessary, to reach
the constant overall bitrate . */
int vcd_pad_bytes ;
while ( ( vcd_pad_bytes = get_vcd_padding_size ( ctx , stream - > start_pts ) ) > = s - > packet_size )
put_vcd_padding_sector ( ctx ) ;
}
/* Make sure only the FIRST pes packet for this frame has
a timestamp */
stream - > start_pts = AV_NOPTS_VALUE ;
@ -635,6 +924,8 @@ static int mpeg_mux_end(AVFormatContext *ctx)
for ( i = 0 ; i < ctx - > nb_streams ; i + + ) {
stream = ctx - > streams [ i ] - > priv_data ;
if ( stream - > buffer_ptr > 0 ) {
update_scr ( ctx , i , stream - > start_pts ) ;
/* NOTE: we can always write the remaining data as it was
tested before in mpeg_mux_write_packet ( ) */
flush_packet ( ctx , i , stream - > start_pts , stream - > start_dts ,
@ -1139,7 +1430,7 @@ static int mpegps_read_seek(AVFormatContext *s,
start_pos = pos ;
// read the next timestamp
dts = mpegps_read_dts ( s , stream_index , & pos , 1 ) ;
dts = mpegps_read_dts ( s , stream_index , & pos , 1 ) ;
if ( pos = = pos_max )
no_change + + ;
else
@ -1214,6 +1505,23 @@ static AVOutputFormat mpeg2vob_mux = {
mpeg_mux_write_packet ,
mpeg_mux_end ,
} ;
/* Same as mpeg2vob_mux except that the pack size is 2324 */
static AVOutputFormat mpeg2svcd_mux = {
" svcd " ,
" MPEG2 PS format (VOB) " ,
" video/mpeg " ,
" vob " ,
sizeof ( MpegMuxContext ) ,
CODEC_ID_MP2 ,
CODEC_ID_MPEG2VIDEO ,
mpeg_mux_init ,
mpeg_mux_write_packet ,
mpeg_mux_end ,
} ;
# endif //CONFIG_ENCODERS
AVInputFormat mpegps_demux = {
@ -1233,6 +1541,7 @@ int mpegps_init(void)
av_register_output_format ( & mpeg1system_mux ) ;
av_register_output_format ( & mpeg1vcd_mux ) ;
av_register_output_format ( & mpeg2vob_mux ) ;
av_register_output_format ( & mpeg2svcd_mux ) ;
# endif //CONFIG_ENCODERS
av_register_input_format ( & mpegps_demux ) ;
return 0 ;