[FFmpeg-devel] [PATCH] avformat/mpegts: skip subtitle PES packets if PCR not available
Jan Ekström
jeebjp at gmail.com
Sat Dec 15 03:31:44 EET 2018
Fixes issues when a subtitle packet is received before PCR for the
program has been received, leading to wildly jumping timestamps
on the lavf client side as well as in the re-ordering logic.
This usually happens in case of multiplexes where the PCR of a
program is not taken into account with subtitle tracks' DTS/PTS.
In case someone actually wants to pass through all received packets,
the behavior can be controlled with an AVOption.
---
libavformat/mpegts.c | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/libavformat/mpegts.c b/libavformat/mpegts.c
index edf6b5701d..50404e8272 100644
--- a/libavformat/mpegts.c
+++ b/libavformat/mpegts.c
@@ -59,6 +59,12 @@ enum MpegTSFilterType {
MPEGTS_PCR,
};
+enum MpegTSPESSkipMode {
+ MPEGTS_PES_SKIP_MODE_SUBTITLES = 0,
+ MPEGTS_PES_SKIP_MODE_NONE,
+ MPEGTS_PES_SKIP_MODE_MAX,
+};
+
typedef struct MpegTSFilter MpegTSFilter;
typedef int PESCallback (MpegTSFilter *f, const uint8_t *buf, int len,
@@ -150,6 +156,8 @@ struct MpegTSContext {
int resync_size;
int merge_pmt_versions;
+ enum MpegTSPESSkipMode pes_packet_skip_mode;
+
/******************************************/
/* private mpegts data */
/* scan context */
@@ -182,6 +190,10 @@ static const AVOption options[] = {
{.i64 = 0}, 0, 1, 0 },
{"skip_clear", "skip clearing programs", offsetof(MpegTSContext, skip_clear), AV_OPT_TYPE_BOOL,
{.i64 = 0}, 0, 1, 0 },
+ {"skip_pes_packets_without_pcr", "Skip PES packets without PCR matching to rule", offsetof(MpegTSContext, pes_packet_skip_mode), AV_OPT_TYPE_INT,
+ {.i64 = MPEGTS_PES_SKIP_MODE_SUBTITLES}, MPEGTS_PES_SKIP_MODE_SUBTITLES, MPEGTS_PES_SKIP_MODE_MAX - 1, AV_OPT_FLAG_DECODING_PARAM , "skip_pes_packets_without_pcr"},
+ { "subtitles", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_PES_SKIP_MODE_SUBTITLES }, INT_MIN, INT_MAX, AV_OPT_FLAG_DECODING_PARAM, "skip_pes_packets_without_pcr" },
+ { "none", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_PES_SKIP_MODE_NONE }, INT_MIN, INT_MAX, AV_OPT_FLAG_DECODING_PARAM, "skip_pes_packets_without_pcr" },
{ NULL },
};
@@ -1219,6 +1231,7 @@ skip:
|| pes->st->codecpar->codec_id == AV_CODEC_ID_DVB_SUBTITLE)
) {
AVProgram *p = NULL;
+ int pcr_found = 0;
while ((p = av_find_program_from_stream(pes->stream, p, pes->st->index))) {
if (p->pcr_pid != -1 && p->discard != AVDISCARD_ALL) {
MpegTSFilter *f = pes->ts->pids[p->pcr_pid];
@@ -1242,6 +1255,7 @@ skip:
// and the pcr error to this packet should be no more than 100 ms.
// TODO: we should interpolate the PCR, not just use the last one
int64_t pcr = f->last_pcr / 300;
+ pcr_found = 1;
pes->st->pts_wrap_reference = st->pts_wrap_reference;
pes->st->pts_wrap_behavior = st->pts_wrap_behavior;
if (pes->dts == AV_NOPTS_VALUE || pes->dts < pcr) {
@@ -1258,6 +1272,14 @@ skip:
}
}
}
+
+ if (!pcr_found &&
+ ts->pes_packet_skip_mode != MPEGTS_PES_SKIP_MODE_NONE) {
+ av_log(pes->stream, AV_LOG_VERBOSE,
+ "Skipping non-trustworthy PES packet for PID %d as PCR hasn't been received yet.\n",
+ pes->pid);
+ pes->state = MPEGTS_SKIP;
+ }
}
}
break;
--
2.20.0
More information about the ffmpeg-devel
mailing list