summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libavformat/mpegtsenc.c90
1 files changed, 54 insertions, 36 deletions
diff --git a/libavformat/mpegtsenc.c b/libavformat/mpegtsenc.c
index f4c1bb4717..59516e0c96 100644
--- a/libavformat/mpegtsenc.c
+++ b/libavformat/mpegtsenc.c
@@ -84,6 +84,7 @@ typedef struct MpegTSWrite {
int onid;
int tsid;
int64_t first_pcr;
+ int64_t next_pcr;
int mux_rate; ///< set to 1 when VBR
int pes_payload_size;
@@ -237,10 +238,9 @@ typedef struct MpegTSWriteStream {
int payload_flags;
uint8_t *payload;
AVFormatContext *amux;
- AVRational user_tb;
- int pcr_packet_count;
- int pcr_packet_period;
+ int64_t pcr_period; /* PCR period in PCR time base */
+ int64_t last_pcr;
/* For Opus */
int opus_queued_samples;
@@ -793,31 +793,28 @@ static void enable_pcr_generation_for_stream(AVFormatContext *s, AVStream *pcr_s
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);
+ ts_st->pcr_period = av_rescale(ts->pcr_period, PCR_TIME_BASE, 1000);
} else {
+ /* For VBR we select the highest multiple of frame duration which is less than 100 ms. */
+ int64_t frame_period = 0;
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);
+ av_log(s, AV_LOG_WARNING, "frame size not set\n");
+ frame_size = 512;
}
- } 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);
+ frame_period = av_rescale_rnd(frame_size, PCR_TIME_BASE, pcr_st->codecpar->sample_rate, AV_ROUND_UP);
+ } else if (pcr_st->avg_frame_rate.num) {
+ frame_period = av_rescale_rnd(pcr_st->avg_frame_rate.den, PCR_TIME_BASE, pcr_st->avg_frame_rate.num, AV_ROUND_UP);
}
- if (!ts_st->pcr_packet_period)
- ts_st->pcr_packet_period = 1;
+ if (frame_period > 0 && frame_period <= PCR_TIME_BASE / 10)
+ ts_st->pcr_period = frame_period * (PCR_TIME_BASE / 10 / frame_period);
+ else
+ ts_st->pcr_period = 1;
}
// output a PCR as soon as possible
- ts_st->pcr_packet_count = ts_st->pcr_packet_period;
+ ts_st->last_pcr = ts->first_pcr - ts_st->pcr_period;
}
static void select_pcr_streams(AVFormatContext *s)
@@ -843,7 +840,8 @@ static void select_pcr_streams(AVFormatContext *s)
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);
+ av_log(s, AV_LOG_VERBOSE, "service %i using PCR in pid=%i, pcr_period=%"PRId64"ms\n",
+ service->sid, service->pcr_pid, av_rescale(ts_st->pcr_period, 1000, PCR_TIME_BASE));
}
}
}
@@ -907,7 +905,6 @@ static int mpegts_init(AVFormatContext *s)
}
st->priv_data = ts_st;
- ts_st->user_tb = st->time_base;
avpriv_set_pts_info(st, 33, 1, 90000);
ts_st->payload = av_mallocz(ts->pes_payload_size);
@@ -987,15 +984,15 @@ static int mpegts_init(AVFormatContext *s)
(TS_PACKET_SIZE * 8 * 1000);
ts->pat_packet_period = (int64_t)ts->mux_rate * PAT_RETRANS_TIME /
(TS_PACKET_SIZE * 8 * 1000);
-
- if (ts->copyts < 1)
- ts->first_pcr = av_rescale(s->max_delay, PCR_TIME_BASE, AV_TIME_BASE);
} 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->copyts < 1)
+ ts->first_pcr = av_rescale(s->max_delay, PCR_TIME_BASE, AV_TIME_BASE);
+
select_pcr_streams(s);
ts->last_pat_ts = AV_NOPTS_VALUE;
@@ -1183,7 +1180,6 @@ static void mpegts_write_pes(AVFormatContext *s, AVStream *st,
uint8_t *q;
int val, is_start, len, header_len, write_pcr, is_dvb_subtitle, is_dvb_teletext, flags;
int afc_len, stuffing_len;
- int64_t pcr = -1; /* avoid warning */
int64_t delay = av_rescale(s->max_delay, 90000, AV_TIME_BASE);
int force_pat = st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && key && !ts_st->prev_payload_key;
@@ -1194,16 +1190,42 @@ static void mpegts_write_pes(AVFormatContext *s, AVStream *st,
is_start = 1;
while (payload_size > 0) {
+ int64_t pcr = -1; /* avoid warning */
+
retransmit_si_info(s, force_pat, dts);
force_pat = 0;
write_pcr = 0;
- if (ts_st->pcr_packet_period) {
- if (ts->mux_rate > 1 || is_start) // VBR pcr period is based on frames
- ts_st->pcr_packet_count++;
- if (ts_st->pcr_packet_count >=
- ts_st->pcr_packet_period) {
- ts_st->pcr_packet_count = 0;
+ if (ts->mux_rate > 1) {
+ /* Send PCR packets for all PCR streams if needed */
+ pcr = get_pcr(ts, s->pb);
+ if (pcr >= ts->next_pcr) {
+ int64_t next_pcr = INT64_MAX;
+ for (int i = 0; i < s->nb_streams; i++) {
+ /* Make the current stream the last, because for that we
+ * can insert the pcr into the payload later */
+ int st2_index = i < st->index ? i : (i + 1 == s->nb_streams ? st->index : i + 1);
+ AVStream *st2 = s->streams[st2_index];
+ MpegTSWriteStream *ts_st2 = st2->priv_data;
+ if (ts_st2->pcr_period) {
+ if (pcr - ts_st2->last_pcr >= ts_st2->pcr_period) {
+ ts_st2->last_pcr = FFMAX(pcr - ts_st2->pcr_period, ts_st2->last_pcr + ts_st2->pcr_period);
+ if (st2 != st) {
+ mpegts_insert_pcr_only(s, st2);
+ pcr = get_pcr(ts, s->pb);
+ } else {
+ write_pcr = 1;
+ }
+ }
+ next_pcr = FFMIN(next_pcr, ts_st2->last_pcr + ts_st2->pcr_period);
+ }
+ }
+ ts->next_pcr = next_pcr;
+ }
+ } else if (ts_st->pcr_period && dts != AV_NOPTS_VALUE) {
+ pcr = (dts - delay) * 300;
+ if (pcr - ts_st->last_pcr >= ts_st->pcr_period && is_start) {
+ ts_st->last_pcr = FFMAX(pcr - ts_st->pcr_period, ts_st->last_pcr + ts_st->pcr_period);
write_pcr = 1;
}
}
@@ -1236,7 +1258,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->pcr_packet_period)
+ if (ts_st->pcr_period)
write_pcr = 1;
set_af_flag(buf, 0x40);
q = get_ts_payload_start(buf);
@@ -1245,10 +1267,6 @@ static void mpegts_write_pes(AVFormatContext *s, AVStream *st,
set_af_flag(buf, 0x10);
q = get_ts_payload_start(buf);
// add 11, pcr references the last byte of program clock reference base
- if (ts->mux_rate > 1)
- pcr = get_pcr(ts, s->pb);
- else
- pcr = (dts - delay) * 300;
if (dts != AV_NOPTS_VALUE && dts < pcr / 300)
av_log(s, AV_LOG_WARNING, "dts < pcr, TS is invalid\n");
extend_af(buf, write_pcr_bits(q, pcr));