@ -57,8 +57,6 @@ typedef struct MpegTSService {
uint8_t name [ 256 ] ;
uint8_t provider_name [ 256 ] ;
int pcr_pid ;
int pcr_packet_count ;
int pcr_packet_period ;
AVProgram * program ;
} MpegTSService ;
@ -228,7 +226,6 @@ static int mpegts_write_section1(MpegTSSection *s, int tid, int id,
# define PCR_RETRANS_TIME 20
typedef struct MpegTSWriteStream {
struct MpegTSService * service ;
int pid ; /* stream associated pid */
int cc ;
int discontinuity ;
@ -242,6 +239,9 @@ typedef struct MpegTSWriteStream {
AVFormatContext * amux ;
AVRational user_tb ;
int pcr_packet_count ;
int pcr_packet_period ;
/* For Opus */
int opus_queued_samples ;
int opus_pending_trim_start ;
@ -769,12 +769,73 @@ static void section_write_packet(MpegTSSection *s, const uint8_t *packet)
avio_write ( ctx - > pb , packet , TS_PACKET_SIZE ) ;
}
static void enable_pcr_generation_for_stream ( AVFormatContext * s , AVStream * pcr_st )
{
MpegTSWrite * ts = s - > priv_data ;
MpegTSWriteStream * ts_st = pcr_st - > priv_data ;
if ( ts - > mux_rate > 1 ) {
ts_st - > pcr_packet_period = ( int64_t ) ts - > mux_rate * ts - > pcr_period /
( TS_PACKET_SIZE * 8 * 1000 ) ;
} else {
if ( pcr_st - > codecpar - > codec_type = = AVMEDIA_TYPE_AUDIO ) {
int frame_size = av_get_audio_frame_duration2 ( pcr_st - > codecpar , 0 ) ;
if ( ! frame_size ) {
av_log ( s , AV_LOG_WARNING , " frame size not set \n " ) ;
ts_st - > pcr_packet_period =
pcr_st - > codecpar - > sample_rate / ( 10 * 512 ) ;
} else {
ts_st - > pcr_packet_period =
pcr_st - > codecpar - > sample_rate / ( 10 * frame_size ) ;
}
} else {
// max delta PCR 0.1s
// TODO: should be avg_frame_rate
ts_st - > pcr_packet_period =
ts_st - > user_tb . den / ( 10 * ts_st - > user_tb . num ) ;
}
if ( ! ts_st - > pcr_packet_period )
ts_st - > pcr_packet_period = 1 ;
}
// output a PCR as soon as possible
ts_st - > pcr_packet_count = ts_st - > pcr_packet_period ;
}
static void select_pcr_streams ( AVFormatContext * s )
{
MpegTSWrite * ts = s - > priv_data ;
for ( int i = 0 ; i < ts - > nb_services ; i + + ) {
MpegTSService * service = ts - > services [ i ] ;
AVStream * pcr_st = NULL ;
AVProgram * program = service - > program ;
int nb_streams = program ? program - > nb_stream_indexes : s - > nb_streams ;
for ( int j = 0 ; j < nb_streams ; j + + ) {
AVStream * st = s - > streams [ program ? program - > stream_index [ j ] : j ] ;
if ( ! pcr_st | |
pcr_st - > codecpar - > codec_type ! = AVMEDIA_TYPE_VIDEO & & st - > codecpar - > codec_type = = AVMEDIA_TYPE_VIDEO )
{
pcr_st = st ;
}
}
if ( pcr_st ) {
MpegTSWriteStream * ts_st = pcr_st - > priv_data ;
service - > pcr_pid = ts_st - > pid ;
enable_pcr_generation_for_stream ( s , pcr_st ) ;
av_log ( s , AV_LOG_VERBOSE , " service %i using PCR in pid=%i \n " , service - > sid , service - > pcr_pid ) ;
}
}
}
static int mpegts_init ( AVFormatContext * s )
{
MpegTSWrite * ts = s - > priv_data ;
MpegTSWriteStream * ts_st ;
MpegTSService * service ;
AVStream * st , * pcr_st = NULL ;
AVStream * st ;
AVDictionaryEntry * title , * provider ;
int i , j ;
const char * service_name ;
@ -853,7 +914,6 @@ static int mpegts_init(AVFormatContext *s)
/* assign pids to each stream */
for ( i = 0 ; i < s - > nb_streams ; i + + ) {
AVProgram * program ;
st = s - > streams [ i ] ;
ts_st = av_mallocz ( sizeof ( MpegTSWriteStream ) ) ;
@ -872,17 +932,6 @@ static int mpegts_init(AVFormatContext *s)
goto fail ;
}
program = av_find_program_from_stream ( s , NULL , i ) ;
if ( program ) {
for ( j = 0 ; j < ts - > nb_services ; j + + ) {
if ( ts - > services [ j ] - > program = = program ) {
service = ts - > services [ j ] ;
break ;
}
}
}
ts_st - > service = service ;
/* MPEG pid values < 16 are reserved. Applications which set st->id in
* this range are assigned a calculated pid . */
if ( st - > id < 16 ) {
@ -895,10 +944,12 @@ static int mpegts_init(AVFormatContext *s)
ret = AVERROR ( EINVAL ) ;
goto fail ;
}
if ( ts_st - > pid = = service - > pmt . pid ) {
av_log ( s , AV_LOG_ERROR , " Duplicate stream id %d \n " , ts_st - > pid ) ;
ret = AVERROR ( EINVAL ) ;
goto fail ;
for ( j = 0 ; j < ts - > nb_services ; j + + ) {
if ( ts_st - > pid = = ts - > services [ j ] - > pmt . pid ) {
av_log ( s , AV_LOG_ERROR , " Duplicate stream id %d \n " , ts_st - > pid ) ;
ret = AVERROR ( EINVAL ) ;
goto fail ;
}
}
for ( j = 0 ; j < i ; j + + ) {
if ( pids [ j ] = = ts_st - > pid ) {
@ -913,12 +964,6 @@ static int mpegts_init(AVFormatContext *s)
ts_st - > first_pts_check = 1 ;
ts_st - > cc = 15 ;
ts_st - > discontinuity = ts - > flags & MPEGTS_FLAG_DISCONT ;
/* update PCR pid by using the first video stream */
if ( st - > codecpar - > codec_type = = AVMEDIA_TYPE_VIDEO & &
service - > pcr_pid = = 0x1fff ) {
service - > pcr_pid = ts_st - > pid ;
pcr_st = st ;
}
if ( st - > codecpar - > codec_id = = AV_CODEC_ID_AAC & &
st - > codecpar - > extradata_size > 0 ) {
AVStream * ast ;
@ -953,17 +998,7 @@ static int mpegts_init(AVFormatContext *s)
av_freep ( & pids ) ;
/* if no video stream, use the first stream as PCR */
if ( service - > pcr_pid = = 0x1fff & & s - > nb_streams > 0 ) {
pcr_st = s - > streams [ 0 ] ;
ts_st = pcr_st - > priv_data ;
service - > pcr_pid = ts_st - > pid ;
} else
ts_st = pcr_st - > priv_data ;
if ( ts - > mux_rate > 1 ) {
service - > pcr_packet_period = ( int64_t ) ts - > mux_rate * ts - > pcr_period /
( TS_PACKET_SIZE * 8 * 1000 ) ;
ts - > sdt_packet_period = ( int64_t ) ts - > mux_rate * SDT_RETRANS_TIME /
( TS_PACKET_SIZE * 8 * 1000 ) ;
ts - > pat_packet_period = ( int64_t ) ts - > mux_rate * PAT_RETRANS_TIME /
@ -975,26 +1010,10 @@ static int mpegts_init(AVFormatContext *s)
/* Arbitrary values, PAT/PMT will also be written on video key frames */
ts - > sdt_packet_period = 200 ;
ts - > pat_packet_period = 40 ;
if ( pcr_st - > codecpar - > codec_type = = AVMEDIA_TYPE_AUDIO ) {
int frame_size = av_get_audio_frame_duration2 ( pcr_st - > codecpar , 0 ) ;
if ( ! frame_size ) {
av_log ( s , AV_LOG_WARNING , " frame size not set \n " ) ;
service - > pcr_packet_period =
pcr_st - > codecpar - > sample_rate / ( 10 * 512 ) ;
} else {
service - > pcr_packet_period =
pcr_st - > codecpar - > sample_rate / ( 10 * frame_size ) ;
}
} else {
// max delta PCR 0.1s
// TODO: should be avg_frame_rate
service - > pcr_packet_period =
ts_st - > user_tb . den / ( 10 * ts_st - > user_tb . num ) ;
}
if ( ! service - > pcr_packet_period )
service - > pcr_packet_period = 1 ;
}
select_pcr_streams ( s ) ;
ts - > last_pat_ts = AV_NOPTS_VALUE ;
ts - > last_sdt_ts = AV_NOPTS_VALUE ;
// The user specified a period, use only it
@ -1005,8 +1024,6 @@ static int mpegts_init(AVFormatContext *s)
ts - > sdt_packet_period = INT_MAX ;
}
// output a PCR as soon as possible
service - > pcr_packet_count = service - > pcr_packet_period ;
ts - > pat_packet_count = ts - > pat_packet_period - 1 ;
ts - > sdt_packet_count = ts - > sdt_packet_period - 1 ;
@ -1015,8 +1032,7 @@ static int mpegts_init(AVFormatContext *s)
else
av_log ( s , AV_LOG_VERBOSE , " muxrate %d, " , ts - > mux_rate ) ;
av_log ( s , AV_LOG_VERBOSE ,
" pcr every %d pkts, sdt every %d, pat/pmt every %d pkts \n " ,
service - > pcr_packet_period ,
" sdt every %d, pat/pmt every %d pkts \n " ,
ts - > sdt_packet_period , ts - > pat_packet_period ) ;
if ( ts - > m2ts_mode = = - 1 ) {
@ -1198,12 +1214,12 @@ static void mpegts_write_pes(AVFormatContext *s, AVStream *st,
force_pat = 0 ;
write_pcr = 0 ;
if ( ts_st - > pid = = ts_st - > service - > pcr_pi d ) {
if ( ts_st - > pcr_packet_perio d ) {
if ( ts - > mux_rate > 1 | | is_start ) // VBR pcr period is based on frames
ts_st - > service - > pcr_packet_count + + ;
if ( ts_st - > service - > pcr_packet_count > =
ts_st - > service - > pcr_packet_period ) {
ts_st - > service - > pcr_packet_count = 0 ;
ts_st - > pcr_packet_count + + ;
if ( ts_st - > pcr_packet_count > =
ts_st - > pcr_packet_period ) {
ts_st - > pcr_packet_count = 0 ;
write_pcr = 1 ;
}
}
@ -1236,7 +1252,7 @@ static void mpegts_write_pes(AVFormatContext *s, AVStream *st,
}
if ( key & & is_start & & pts ! = AV_NOPTS_VALUE ) {
// set Random Access for key frames
if ( ts_st - > pid = = ts_st - > service - > pcr_pi d )
if ( ts_st - > pcr_packet_perio d )
write_pcr = 1 ;
set_af_flag ( buf , 0x40 ) ;
q = get_ts_payload_start ( buf ) ;