Hi,

If a PAT is finished while a PMT section filter is opened but not yet finished, 
the PMT section filter is closed and all the received data is discarded. This 
is usually not an issue but some multiplexers (With very quick PAT/PMT 
repetition settings) consistently emit a PMT section start, then a PAT, and 
then the rest of the PMT, causing the aforementioned behavior to result in no 
PMT being finished. On the worst set of streams I tested libav was completely 
unable to read the stream information and always had to fall back to probing, 
resulting in it interpreting DVB subtitle tracks as MP3 audio.

The attached patch fixes the issue through eliminating redundant PSI/SI table 
updates by checking their version field, which is required by the standard to 
be incremented on every change no matter how minor. The way the demux is set up 
the bug itself looks unavoidable without a rewrite, but preventing a second 
*unaltered* PAT from closing the PMT section filter makes it behave properly 
with a delay of one PMT repetition.

Regards,
John Högberg
From b5bb543d288ef160d494315f0b2ea5a11d5efbaa Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?John=20H=C3=B6gberg?= <john.hogb...@ericsson.com>
Date: Tue, 28 Apr 2015 10:20:33 +0200
Subject: [PATCH] mpegts: fix degradation when PAT arrives while reading PMT.

If a PAT is finished while a PMT section filter is opened but not yet finished, 
the PMT section filter is closed and all the received data is discarded. This 
is usually not an issue but some multiplexers (With very quick PAT/PMT 
repetition settings) consistently emit a PMT section start, then a PAT, and 
then the rest of the PMT, causing the aforementioned behavior to result in no 
PMT being finished. On the worst set of streams I tested libav was completely 
unable to read the stream information and always had to fall back to probing, 
resulting in it interpreting DVB subtitle tracks as MP3 audio.

This commit fixes the issue through eliminating redundant PSI/SI table updates 
by checking their version field, which is required by the standard to be 
incremented on every change no matter how minor. The way the demux is set up 
the bug itself looks unavoidable without a rewrite, but preventing a second 
*unaltered* PAT from closing the PMT section filter makes it behave properly 
with a delay of one PMT repetition.
---
 libavformat/mpegts.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/libavformat/mpegts.c b/libavformat/mpegts.c
index ae9d1f4..358fcc4 100644
--- a/libavformat/mpegts.c
+++ b/libavformat/mpegts.c
@@ -73,6 +73,7 @@ typedef void SetServiceCallback (void *opaque, int ret);
 typedef struct MpegTSSectionFilter {
     int section_index;
     int section_h_size;
+    int last_ver;
     uint8_t *section_buf;
     unsigned int check_crc : 1;
     unsigned int end_of_section_reached : 1;
@@ -372,6 +373,8 @@ static MpegTSFilter 
*mpegts_open_section_filter(MpegTSContext *ts,
     sec->opaque      = opaque;
     sec->section_buf = av_malloc(MAX_SECTION_SIZE);
     sec->check_crc   = check_crc;
+    sec->last_ver = -1;
+
     if (!sec->section_buf) {
         av_free(filter);
         return NULL;
@@ -1255,6 +1258,7 @@ static void m4sl_cb(MpegTSFilter *filter, const uint8_t 
*section,
                     int section_len)
 {
     MpegTSContext *ts = filter->u.section_filter.opaque;
+    MpegTSSectionFilter *tssf = &filter->u.section_filter;
     SectionHeader h;
     const uint8_t *p, *p_end;
     AVIOContext pb;
@@ -1269,6 +1273,9 @@ static void m4sl_cb(MpegTSFilter *filter, const uint8_t 
*section,
         return;
     if (h.tid != M4OD_TID)
         return;
+    if (h.version == tssf->last_ver)
+        return;
+    tssf->last_ver = h.version;
 
     mp4_read_od(s, p, (unsigned) (p_end - p), mp4_descr, &mp4_descr_count,
                 MAX_MP4_DESCR_COUNT);
@@ -1507,6 +1514,7 @@ int ff_parse_mpeg2_descriptor(AVFormatContext *fc, 
AVStream *st, int stream_type
 static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int 
section_len)
 {
     MpegTSContext *ts = filter->u.section_filter.opaque;
+    MpegTSSectionFilter *tssf = &filter->u.section_filter;
     SectionHeader h1, *h = &h1;
     PESContext *pes;
     AVStream *st;
@@ -1526,6 +1534,9 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t 
*section, int section_len
     p = section;
     if (parse_section_header(h, &p, p_end) < 0)
         return;
+    if (h->version == tssf->last_ver)
+        return;
+    tssf->last_ver = h->version;
 
     av_log(ts->stream, AV_LOG_TRACE, "sid=0x%x sec_num=%d/%d\n",
             h->id, h->sec_num, h->last_sec_num);
@@ -1657,6 +1668,7 @@ out:
 static void pat_cb(MpegTSFilter *filter, const uint8_t *section, int 
section_len)
 {
     MpegTSContext *ts = filter->u.section_filter.opaque;
+    MpegTSSectionFilter *tssf = &filter->u.section_filter;
     SectionHeader h1, *h = &h1;
     const uint8_t *p, *p_end;
     int sid, pmt_pid;
@@ -1670,6 +1682,9 @@ static void pat_cb(MpegTSFilter *filter, const uint8_t 
*section, int section_len
         return;
     if (h->tid != PAT_TID)
         return;
+    if (h->version == tssf->last_ver)
+        return;
+    tssf->last_ver = h->version;
 
     clear_programs(ts);
     for (;;) {
@@ -1700,6 +1715,7 @@ static void pat_cb(MpegTSFilter *filter, const uint8_t 
*section, int section_len
 static void sdt_cb(MpegTSFilter *filter, const uint8_t *section, int 
section_len)
 {
     MpegTSContext *ts = filter->u.section_filter.opaque;
+    MpegTSSectionFilter *tssf = &filter->u.section_filter;
     SectionHeader h1, *h = &h1;
     const uint8_t *p, *p_end, *desc_list_end, *desc_end;
     int onid, val, sid, desc_list_len, desc_tag, desc_len, service_type;
@@ -1714,6 +1730,10 @@ static void sdt_cb(MpegTSFilter *filter, const uint8_t 
*section, int section_len
         return;
     if (h->tid != SDT_TID)
         return;
+    if (h->version == tssf->last_ver)
+        return;
+    tssf->last_ver = h->version;
+
     onid = get16(&p, p_end);
     if (onid < 0)
         return;
-- 
1.9.1

_______________________________________________
libav-devel mailing list
libav-devel@libav.org
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to