@ -19,7 +19,6 @@
# include "avformat.h"
# include "avformat.h"
# define MAX_PAYLOAD_SIZE 4096
# define MAX_PAYLOAD_SIZE 4096
# define NB_STREAMS 2
//#define DEBUG_SEEK
//#define DEBUG_SEEK
typedef struct {
typedef struct {
@ -29,6 +28,7 @@ typedef struct {
int max_buffer_size ; /* in bytes */
int max_buffer_size ; /* in bytes */
int packet_number ;
int packet_number ;
int64_t start_pts ;
int64_t start_pts ;
int64_t start_dts ;
} StreamInfo ;
} StreamInfo ;
typedef struct {
typedef struct {
@ -43,6 +43,9 @@ typedef struct {
int video_bound ;
int video_bound ;
int is_mpeg2 ;
int is_mpeg2 ;
int is_vcd ;
int is_vcd ;
int scr_stream_index ; /* stream from which the system clock is
computed ( VBR case ) */
int64_t last_scr ; /* current system clock */
} MpegMuxContext ;
} MpegMuxContext ;
# define PACK_START_CODE ((unsigned int)0x000001ba)
# define PACK_START_CODE ((unsigned int)0x000001ba)
@ -181,11 +184,14 @@ static int mpeg_mux_init(AVFormatContext *ctx)
/* startcode(4) + length(2) + flags(1) */
/* startcode(4) + length(2) + flags(1) */
s - > packet_data_max_size = s - > packet_size - 7 ;
s - > packet_data_max_size = s - > packet_size - 7 ;
if ( s - > is_mpeg2 )
s - > packet_data_max_size - = 2 ;
s - > audio_bound = 0 ;
s - > audio_bound = 0 ;
s - > video_bound = 0 ;
s - > video_bound = 0 ;
mpa_id = AUDIO_ID ;
mpa_id = AUDIO_ID ;
ac3_id = 0x80 ;
ac3_id = 0x80 ;
mpv_id = VIDEO_ID ;
mpv_id = VIDEO_ID ;
s - > scr_stream_index = - 1 ;
for ( i = 0 ; i < ctx - > nb_streams ; i + + ) {
for ( i = 0 ; i < ctx - > nb_streams ; i + + ) {
st = ctx - > streams [ i ] ;
st = ctx - > streams [ i ] ;
stream = av_mallocz ( sizeof ( StreamInfo ) ) ;
stream = av_mallocz ( sizeof ( StreamInfo ) ) ;
@ -203,6 +209,9 @@ static int mpeg_mux_init(AVFormatContext *ctx)
s - > audio_bound + + ;
s - > audio_bound + + ;
break ;
break ;
case CODEC_TYPE_VIDEO :
case CODEC_TYPE_VIDEO :
/* by default, video is used for the SCR computation */
if ( s - > scr_stream_index = = - 1 )
s - > scr_stream_index = i ;
stream - > id = mpv_id + + ;
stream - > id = mpv_id + + ;
stream - > max_buffer_size = 46 * 1024 ;
stream - > max_buffer_size = 46 * 1024 ;
s - > video_bound + + ;
s - > video_bound + + ;
@ -211,6 +220,9 @@ static int mpeg_mux_init(AVFormatContext *ctx)
av_abort ( ) ;
av_abort ( ) ;
}
}
}
}
/* if no SCR, use first stream (audio) */
if ( s - > scr_stream_index = = - 1 )
s - > scr_stream_index = 0 ;
/* we increase slightly the bitrate to take into account the
/* we increase slightly the bitrate to take into account the
headers . XXX : compute it exactly */
headers . XXX : compute it exactly */
@ -245,8 +257,10 @@ static int mpeg_mux_init(AVFormatContext *ctx)
stream = ctx - > streams [ i ] - > priv_data ;
stream = ctx - > streams [ i ] - > priv_data ;
stream - > buffer_ptr = 0 ;
stream - > buffer_ptr = 0 ;
stream - > packet_number = 0 ;
stream - > packet_number = 0 ;
stream - > start_pts = - 1 ;
stream - > start_pts = AV_NOPTS_VALUE ;
stream - > start_dts = AV_NOPTS_VALUE ;
}
}
s - > last_scr = 0 ;
return 0 ;
return 0 ;
fail :
fail :
for ( i = 0 ; i < ctx - > nb_streams ; i + + ) {
for ( i = 0 ; i < ctx - > nb_streams ; i + + ) {
@ -255,28 +269,37 @@ static int mpeg_mux_init(AVFormatContext *ctx)
return - ENOMEM ;
return - ENOMEM ;
}
}
static inline void put_timestamp ( ByteIOContext * pb , int id , int64_t timestamp )
{
put_byte ( pb ,
( id < < 4 ) |
( ( ( timestamp > > 30 ) & 0x07 ) < < 1 ) |
1 ) ;
put_be16 ( pb , ( uint16_t ) ( ( ( ( timestamp > > 15 ) & 0x7fff ) < < 1 ) | 1 ) ) ;
put_be16 ( pb , ( uint16_t ) ( ( ( ( timestamp ) & 0x7fff ) < < 1 ) | 1 ) ) ;
}
/* flush the packet on stream stream_index */
/* flush the packet on stream stream_index */
static void flush_packet ( AVFormatContext * ctx , int stream_index )
static void flush_packet ( AVFormatContext * ctx , int stream_index ,
int64_t pts , int64_t dts , int64_t scr )
{
{
MpegMuxContext * s = ctx - > priv_data ;
MpegMuxContext * s = ctx - > priv_data ;
StreamInfo * stream = ctx - > streams [ stream_index ] - > priv_data ;
StreamInfo * stream = ctx - > streams [ stream_index ] - > priv_data ;
uint8_t * buf_ptr ;
uint8_t * buf_ptr ;
int size , payload_size , startcode , id , len , stuffing_size , i , header_len ;
int size , payload_size , startcode , id , len , stuffing_size , i , header_len ;
int64_t timestamp ;
uint8_t buffer [ 128 ] ;
uint8_t buffer [ 128 ] ;
id = stream - > id ;
id = stream - > id ;
timestamp = stream - > start_pts ;
#if 0
#if 0
printf ( " packet ID=%2x PTS=%0.3f \n " ,
printf ( " packet ID=%2x PTS=%0.3f \n " ,
id , time stamp / 90000.0 ) ;
id , p ts / 90000.0 ) ;
# endif
# endif
buf_ptr = buffer ;
buf_ptr = buffer ;
if ( ( ( s - > packet_number % s - > pack_header_freq ) = = 0 ) ) {
if ( ( ( s - > packet_number % s - > pack_header_freq ) = = 0 ) ) {
/* output pack and systems header if needed */
/* output pack and systems header if needed */
size = put_pack_header ( ctx , buf_ptr , timestamp ) ;
size = put_pack_header ( ctx , buf_ptr , scr ) ;
buf_ptr + = size ;
buf_ptr + = size ;
if ( ( s - > packet_number % s - > system_header_freq ) = = 0 ) {
if ( ( s - > packet_number % s - > system_header_freq ) = = 0 ) {
size = put_system_header ( ctx , buf_ptr ) ;
size = put_system_header ( ctx , buf_ptr ) ;
@ -288,10 +311,20 @@ static void flush_packet(AVFormatContext *ctx, int stream_index)
/* packet header */
/* packet header */
if ( s - > is_mpeg2 ) {
if ( s - > is_mpeg2 ) {
header_len = 8 ;
header_len = 3 ;
} else {
} else {
header_len = 5 ;
header_len = 0 ;
}
}
if ( pts ! = AV_NOPTS_VALUE ) {
if ( dts ! = AV_NOPTS_VALUE )
header_len + = 5 + 5 ;
else
header_len + = 5 ;
} else {
if ( ! s - > is_mpeg2 )
header_len + + ;
}
payload_size = s - > packet_size - ( size + 6 + header_len ) ;
payload_size = s - > packet_size - ( size + 6 + header_len ) ;
if ( id < 0xc0 ) {
if ( id < 0xc0 ) {
startcode = PRIVATE_STREAM_1 ;
startcode = PRIVATE_STREAM_1 ;
@ -312,15 +345,34 @@ static void flush_packet(AVFormatContext *ctx, int stream_index)
if ( s - > is_mpeg2 ) {
if ( s - > is_mpeg2 ) {
put_byte ( & ctx - > pb , 0x80 ) ; /* mpeg2 id */
put_byte ( & ctx - > pb , 0x80 ) ; /* mpeg2 id */
put_byte ( & ctx - > pb , 0x80 ) ; /* flags */
put_byte ( & ctx - > pb , 0x05 ) ; /* header len (only pts is included) */
if ( pts ! = AV_NOPTS_VALUE ) {
if ( dts ! = AV_NOPTS_VALUE ) {
put_byte ( & ctx - > pb , 0xc0 ) ; /* flags */
put_byte ( & ctx - > pb , header_len - 3 ) ;
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 ) ;
put_timestamp ( & ctx - > pb , 0x02 , pts ) ;
}
} else {
put_byte ( & ctx - > pb , 0x00 ) ; /* flags */
put_byte ( & ctx - > pb , header_len - 3 ) ;
}
} else {
if ( pts ! = AV_NOPTS_VALUE ) {
if ( dts ! = AV_NOPTS_VALUE ) {
put_timestamp ( & ctx - > pb , 0x03 , pts ) ;
put_timestamp ( & ctx - > pb , 0x01 , dts ) ;
} else {
put_timestamp ( & ctx - > pb , 0x02 , pts ) ;
}
} else {
put_byte ( & ctx - > pb , 0x0f ) ;
}
}
}
put_byte ( & ctx - > pb ,
( 0x02 < < 4 ) |
( ( ( timestamp > > 30 ) & 0x07 ) < < 1 ) |
1 ) ;
put_be16 ( & ctx - > pb , ( uint16_t ) ( ( ( ( timestamp > > 15 ) & 0x7fff ) < < 1 ) | 1 ) ) ;
put_be16 ( & ctx - > pb , ( uint16_t ) ( ( ( ( timestamp ) & 0x7fff ) < < 1 ) | 1 ) ) ;
if ( startcode = = PRIVATE_STREAM_1 ) {
if ( startcode = = PRIVATE_STREAM_1 ) {
put_byte ( & ctx - > pb , id ) ;
put_byte ( & ctx - > pb , id ) ;
@ -345,7 +397,6 @@ static void flush_packet(AVFormatContext *ctx, int stream_index)
s - > packet_number + + ;
s - > packet_number + + ;
stream - > packet_number + + ;
stream - > packet_number + + ;
stream - > start_pts = - 1 ;
}
}
static int mpeg_mux_write_packet ( AVFormatContext * ctx , int stream_index ,
static int mpeg_mux_write_packet ( AVFormatContext * ctx , int stream_index ,
@ -354,13 +405,28 @@ static int mpeg_mux_write_packet(AVFormatContext *ctx, int stream_index,
MpegMuxContext * s = ctx - > priv_data ;
MpegMuxContext * s = ctx - > priv_data ;
AVStream * st = ctx - > streams [ stream_index ] ;
AVStream * st = ctx - > streams [ stream_index ] ;
StreamInfo * stream = st - > priv_data ;
StreamInfo * stream = st - > priv_data ;
int64_t dts ;
int len ;
int len ;
/* 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
printf ( " %d: pts=%0.3f scr=%0.3f \n " ,
stream_index , pts / 90000.0 , s - > last_scr / 90000.0 ) ;
# endif
/* XXX: currently no way to pass dts, will change soon */
dts = AV_NOPTS_VALUE ;
/* we assume here that pts != AV_NOPTS_VALUE */
if ( stream - > start_pts = = AV_NOPTS_VALUE ) {
stream - > start_pts = pts ;
stream - > start_dts = dts ;
}
while ( size > 0 ) {
while ( size > 0 ) {
/* set pts */
if ( stream - > start_pts = = - 1 ) {
stream - > start_pts = pts ;
}
len = s - > packet_data_max_size - stream - > buffer_ptr ;
len = s - > packet_data_max_size - stream - > buffer_ptr ;
if ( len > size )
if ( len > size )
len = size ;
len = size ;
@ -370,9 +436,12 @@ static int mpeg_mux_write_packet(AVFormatContext *ctx, int stream_index,
size - = len ;
size - = len ;
while ( stream - > buffer_ptr > = s - > packet_data_max_size ) {
while ( stream - > buffer_ptr > = s - > packet_data_max_size ) {
/* output the packet */
/* output the packet */
if ( stream - > start_pts = = - 1 )
flush_packet ( ctx , stream_index ,
stream - > start_pts = pts ;
stream - > start_pts , stream - > start_dts , s - > last_scr ) ;
flush_packet ( ctx , stream_index ) ;
/* Make sure only the FIRST pes packet for this frame has
a timestamp */
stream - > start_pts = AV_NOPTS_VALUE ;
stream - > start_dts = AV_NOPTS_VALUE ;
}
}
}
}
return 0 ;
return 0 ;
@ -380,14 +449,15 @@ static int mpeg_mux_write_packet(AVFormatContext *ctx, int stream_index,
static int mpeg_mux_end ( AVFormatContext * ctx )
static int mpeg_mux_end ( AVFormatContext * ctx )
{
{
MpegMuxContext * s = ctx - > priv_data ;
StreamInfo * stream ;
StreamInfo * stream ;
int i ;
int i ;
/* flush each packet */
/* flush each packet */
for ( i = 0 ; i < ctx - > nb_streams ; i + + ) {
for ( i = 0 ; i < ctx - > nb_streams ; i + + ) {
stream = ctx - > streams [ i ] - > priv_data ;
stream = ctx - > streams [ i ] - > priv_data ;
if ( stream - > buffer_ptr > 0 ) {
while ( stream - > buffer_ptr > 0 ) {
flush_packet ( ctx , i ) ;
flush_packet ( ctx , i , AV_NOPTS_VALUE , AV_NOPTS_VALUE , s - > last_scr ) ;
}
}
}
}
@ -676,7 +746,7 @@ static int mpegps_read_packet(AVFormatContext *s,
len = mpegps_read_pes_header ( s , NULL , & startcode , & pts , & dts , 1 ) ;
len = mpegps_read_pes_header ( s , NULL , & startcode , & pts , & dts , 1 ) ;
if ( len < 0 )
if ( len < 0 )
return len ;
return len ;
/* now find stream */
/* now find stream */
for ( i = 0 ; i < s - > nb_streams ; i + + ) {
for ( i = 0 ; i < s - > nb_streams ; i + + ) {
st = s - > streams [ i ] ;
st = s - > streams [ i ] ;
@ -728,12 +798,14 @@ static int mpegps_read_packet(AVFormatContext *s,
st - > codec . bit_rate = st - > codec . channels * st - > codec . sample_rate * 2 ;
st - > codec . bit_rate = st - > codec . channels * st - > codec . sample_rate * 2 ;
}
}
av_new_packet ( pkt , len ) ;
av_new_packet ( pkt , len ) ;
//printf("\nRead Packet ID: %x PTS: %f Size: %d", startcode,
// (float)pts/90000, len);
get_buffer ( & s - > pb , pkt - > data , pkt - > size ) ;
get_buffer ( & s - > pb , pkt - > data , pkt - > size ) ;
pkt - > pts = pts ;
pkt - > pts = pts ;
pkt - > dts = dts ;
pkt - > dts = dts ;
pkt - > stream_index = st - > index ;
pkt - > stream_index = st - > index ;
#if 0
printf ( " %d: pts=%0.3f dts=%0.3f \n " ,
pkt - > stream_index , pkt - > pts / 90000.0 , pkt - > dts / 90000.0 ) ;
# endif
return 0 ;
return 0 ;
}
}