代码文件:libavformat/mpegtsenc.c
##1.PAT/PMT插入间隔
1.1.插入间隔实质是根据ts->pat_period*90000.0) ,sdt_packet_period和 force_pat共同决定的;
static void retransmit_si_info(AVFormatContext *s, int force_pat, int64_t dts)
{
......
if (++ts->pat_packet_count == ts->pat_packet_period ||
(dts != AV_NOPTS_VALUE && ts->last_pat_ts == AV_NOPTS_VALUE) ||
(dts != AV_NOPTS_VALUE && dts - ts->last_pat_ts >= ts->pat_period*90000.0) ||
force_pat) {
ts->pat_packet_count = 0;
if (dts != AV_NOPTS_VALUE)
ts->last_pat_ts = FFMAX(dts, ts->last_pat_ts);
mpegts_write_pat(s);
for (i = 0; i < ts->nb_services; i++)
mpegts_write_pmt(s, ts->services[i]);
}
......
}
1.2.force_pat的计算,实质是可以通过强制给flags设置MPEGTS_FLAG_PAT_PMT_AT_FRAMES即可。
......
int force_pat = st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && key && !ts_st->prev_payload_key;
......
if (ts->flags & MPEGTS_FLAG_PAT_PMT_AT_FRAMES && st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
force_pat = 1;
}
......
1.3.sdt_packet_period的计算,我们是无法更改的
if (ts->mux_rate > 1) {
......
ts->pat_packet_period = (int64_t)ts->mux_rate * PAT_RETRANS_TIME /
(TS_PACKET_SIZE * 8 * 1000);
......
} else {
......
/* Arbitrary values, PAT/PMT will also be written on video key frames */
ts->sdt_packet_period = 200;
ts->pat_packet_period = 40;
......
if (ts->pat_period < INT_MAX/2) {
ts->pat_packet_period = INT_MAX;
}
if (ts->sdt_period < INT_MAX/2) {
ts->sdt_packet_period = INT_MAX;
}
......
}
1.4.总结
<1>pat/pmt插入时间间隔根据mux_rate的值不同,计算方式有区别:当mux_rate大于1时,可根据设定的间隔发送pat/pmt表;当mux_rate不大于1时,则发送间隔为固定值;
<2>若希望按照设定好的间隔发送PAT和PMT表,首先需要设置"mux_rate"的值,其次需要配置"mpegts_flags"选项的"pat_pmt_at_frames"属性OPT_SET(ofmt_ctx->priv_data,“mpegts_flags”,“pat_pmt_at_frames”);
<3>对于25帧视频默认的信息: muxrate VBR, pcr every 2 pkts, sdt every 200, pat/pmt every 40 pkts
<4>值得注意的是:当我们将pat_period和sdt_period设置过小时,ts->pat_packet_period和ts->sdt_packet_period将会新被设定为INT_MAX;
##2.PCR
###2.1.PCR插入间隔
if (ts->mux_rate > 1) {
service->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");
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;
}
......
if (ts_st->pid == ts_st->service->pcr_pid) {
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;
write_pcr = 1;
}
}
###2.2.PCR计算
pcr的计算在ffmpeg中有两个方法,代码如下:
if (ts->mux_rate > 1)
pcr = get_pcr(ts, s->pb);
else
pcr = (dts - delay) * 300;
2.2.1.使用muxrate(即插空包)
if (ts->mux_rate > 1) {
if (ts->copyts < 1)
ts->first_pcr = av_rescale(s->max_delay, PCR_TIME_BASE, AV_TIME_BASE);
}
static int64_t get_pcr(const MpegTSWrite *ts, AVIOContext *pb)
{
return av_rescale(avio_tell(pb) + 11, 8 * PCR_TIME_BASE, ts->mux_rate) +
ts->first_pcr;
}
展开为:(avio_tell(pb) + 11)* (8 * PCR_TIME_BASE)/ts->mux_rate + ts->first_pcr
2.2.2.不插空包(即VBR)
pcr = (dts - delay) * 300 (时间基准27Mhz)
2.3.总结
<1>PCR的值和插入时间间隔根据mux_rate的值不同,计算方式都有区别;
<2>当我们设定了mux_rate大于1时,根据我们设定的pcr间隔(默认30ms)进行发送,pcr值为(avio_tell(pb) + 11)* (8 * PCR_TIME_BASE)/ts->mux_rate + ts->first_pcr
<3>当我们设定了mux_rate不大于1时,pcr计算是根据ts_st->user_tb.den / (10 * ts_st->user_tb.num)来计算的。对于25帧视频来说pcr_packet_period值为2,pcr计算方式为(dts - delay) * 300