[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