mpegts: Update the PSI/SI table only if the version change

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.

In the most pathologic situation the stream information are lost
and the probe fallback miscategorizes subtitles as mp3 audio.

Avoid 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.

CC: libav-stable@libav.org

Signed-off-by: Luca Barbato <lu_zero@gentoo.org>
pull/135/head
John Högberg 10 years ago committed by Luca Barbato
parent 0c69164f45
commit 82de8d7111
  1. 20
      libavformat/mpegts.c

@ -73,6 +73,7 @@ typedef void SetServiceCallback (void *opaque, int ret);
typedef struct MpegTSSectionFilter { typedef struct MpegTSSectionFilter {
int section_index; int section_index;
int section_h_size; int section_h_size;
int last_ver;
uint8_t *section_buf; uint8_t *section_buf;
unsigned int check_crc : 1; unsigned int check_crc : 1;
unsigned int end_of_section_reached : 1; unsigned int end_of_section_reached : 1;
@ -372,6 +373,8 @@ static MpegTSFilter *mpegts_open_section_filter(MpegTSContext *ts,
sec->opaque = opaque; sec->opaque = opaque;
sec->section_buf = av_malloc(MAX_SECTION_SIZE); sec->section_buf = av_malloc(MAX_SECTION_SIZE);
sec->check_crc = check_crc; sec->check_crc = check_crc;
sec->last_ver = -1;
if (!sec->section_buf) { if (!sec->section_buf) {
av_free(filter); av_free(filter);
return NULL; return NULL;
@ -1255,6 +1258,7 @@ static void m4sl_cb(MpegTSFilter *filter, const uint8_t *section,
int section_len) int section_len)
{ {
MpegTSContext *ts = filter->u.section_filter.opaque; MpegTSContext *ts = filter->u.section_filter.opaque;
MpegTSSectionFilter *tssf = &filter->u.section_filter;
SectionHeader h; SectionHeader h;
const uint8_t *p, *p_end; const uint8_t *p, *p_end;
AVIOContext pb; AVIOContext pb;
@ -1269,6 +1273,9 @@ static void m4sl_cb(MpegTSFilter *filter, const uint8_t *section,
return; return;
if (h.tid != M4OD_TID) if (h.tid != M4OD_TID)
return; 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, mp4_read_od(s, p, (unsigned) (p_end - p), mp4_descr, &mp4_descr_count,
MAX_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) static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len)
{ {
MpegTSContext *ts = filter->u.section_filter.opaque; MpegTSContext *ts = filter->u.section_filter.opaque;
MpegTSSectionFilter *tssf = &filter->u.section_filter;
SectionHeader h1, *h = &h1; SectionHeader h1, *h = &h1;
PESContext *pes; PESContext *pes;
AVStream *st; AVStream *st;
@ -1526,6 +1534,9 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len
p = section; p = section;
if (parse_section_header(h, &p, p_end) < 0) if (parse_section_header(h, &p, p_end) < 0)
return; 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", av_log(ts->stream, AV_LOG_TRACE, "sid=0x%x sec_num=%d/%d\n",
h->id, h->sec_num, h->last_sec_num); 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) static void pat_cb(MpegTSFilter *filter, const uint8_t *section, int section_len)
{ {
MpegTSContext *ts = filter->u.section_filter.opaque; MpegTSContext *ts = filter->u.section_filter.opaque;
MpegTSSectionFilter *tssf = &filter->u.section_filter;
SectionHeader h1, *h = &h1; SectionHeader h1, *h = &h1;
const uint8_t *p, *p_end; const uint8_t *p, *p_end;
int sid, pmt_pid; int sid, pmt_pid;
@ -1670,6 +1682,9 @@ static void pat_cb(MpegTSFilter *filter, const uint8_t *section, int section_len
return; return;
if (h->tid != PAT_TID) if (h->tid != PAT_TID)
return; return;
if (h->version == tssf->last_ver)
return;
tssf->last_ver = h->version;
clear_programs(ts); clear_programs(ts);
for (;;) { 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) static void sdt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len)
{ {
MpegTSContext *ts = filter->u.section_filter.opaque; MpegTSContext *ts = filter->u.section_filter.opaque;
MpegTSSectionFilter *tssf = &filter->u.section_filter;
SectionHeader h1, *h = &h1; SectionHeader h1, *h = &h1;
const uint8_t *p, *p_end, *desc_list_end, *desc_end; const uint8_t *p, *p_end, *desc_list_end, *desc_end;
int onid, val, sid, desc_list_len, desc_tag, desc_len, service_type; 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; return;
if (h->tid != SDT_TID) if (h->tid != SDT_TID)
return; return;
if (h->version == tssf->last_ver)
return;
tssf->last_ver = h->version;
onid = get16(&p, p_end); onid = get16(&p, p_end);
if (onid < 0) if (onid < 0)
return; return;

Loading…
Cancel
Save