From eec1547db3df45ab168970b6bbc8c3d5d3d49a7d Mon Sep 17 00:00:00 2001
From: Marton Balint <cus@passwd.hu>
Date: Tue, 24 Nov 2020 22:58:18 +0100
Subject: [PATCH] avformat/mpegts: use stream index based lookup with
merge_pmt_versions if stream identifier matches multiple streams
Also make sure we are checking the old state of the streams because otherwise
some streams might already have the newly parsed stream identifiers which
corrupts matching.
Fixes streams having the same identifier mixed up on pmt version change.
Fixes ticket #9006.
Signed-off-by: Marton Balint <cus@passwd.hu>
---
libavformat/mpegts.c | 53 +++++++++++++++++++++++++++++++++++---------
1 file changed, 42 insertions(+), 11 deletions(-)
diff --git a/libavformat/mpegts.c b/libavformat/mpegts.c
index 7549fc91c9..0bf06b3986 100644
|
a
|
b
|
struct Program {
|
| 116 | 116 | int pmt_found; |
| 117 | 117 | }; |
| 118 | 118 | |
| | 119 | struct Stream { |
| | 120 | int pmt_stream_idx; |
| | 121 | int stream_identifier; |
| | 122 | int program_num; |
| | 123 | }; |
| | 124 | |
| 119 | 125 | struct MpegTSContext { |
| 120 | 126 | const AVClass *class; |
| 121 | 127 | /* user data */ |
| … |
… |
int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type
|
| 2201 | 2207 | return 0; |
| 2202 | 2208 | } |
| 2203 | 2209 | |
| 2204 | | static AVStream *find_matching_stream(MpegTSContext *ts, int pid, unsigned int programid, |
| | 2210 | static AVStream* find_matching_stream(MpegTSContext *ts, struct Stream *old_streams, int nb_old_streams, int pid, unsigned int programid, |
| 2205 | 2211 | int stream_identifier, int pmt_stream_idx) |
| 2206 | 2212 | { |
| 2207 | 2213 | AVFormatContext *s = ts->stream; |
| 2208 | 2214 | int i; |
| 2209 | 2215 | AVStream *found = NULL; |
| | 2216 | AVStream *idxfound = NULL; |
| 2210 | 2217 | |
| 2211 | | for (i = 0; i < s->nb_streams; i++) { |
| 2212 | | AVStream *st = s->streams[i]; |
| | 2218 | for (i = 0; i < nb_old_streams; i++) { |
| | 2219 | struct Stream *st = old_streams + i; |
| 2213 | 2220 | if (st->program_num != programid) |
| 2214 | 2221 | continue; |
| 2215 | 2222 | if (stream_identifier != -1) { /* match based on "stream identifier descriptor" if present */ |
| 2216 | 2223 | if (st->stream_identifier == stream_identifier+1) { |
| 2217 | | found = st; |
| 2218 | | break; |
| | 2224 | if (found) { /* fallback to idx based guess if multiple streams have the same identifier */ |
| | 2225 | stream_identifier = -1; |
| | 2226 | found = NULL; |
| | 2227 | } else { |
| | 2228 | found = s->streams[i]; |
| | 2229 | } |
| 2219 | 2230 | } |
| 2220 | | } else if (st->pmt_stream_idx == pmt_stream_idx) { /* match based on position within the PMT */ |
| 2221 | | found = st; |
| 2222 | | break; |
| | 2231 | } |
| | 2232 | if (st->pmt_stream_idx == pmt_stream_idx) { /* match based on position within the PMT */ |
| | 2233 | if (!idxfound) |
| | 2234 | idxfound = s->streams[i]; |
| 2223 | 2235 | } |
| 2224 | 2236 | } |
| 2225 | 2237 | |
| | 2238 | if (!found) |
| | 2239 | found = idxfound; |
| | 2240 | |
| 2226 | 2241 | if (found) { |
| 2227 | 2242 | av_log(ts->stream, AV_LOG_VERBOSE, |
| 2228 | 2243 | "re-using existing %s stream %d (pid=0x%x) for new pid=0x%x\n", |
| … |
… |
static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len
|
| 2288 | 2303 | uint32_t prog_reg_desc = 0; /* registration descriptor */ |
| 2289 | 2304 | int stream_identifier = -1; |
| 2290 | 2305 | |
| | 2306 | struct Stream *old_streams = NULL; |
| | 2307 | int nb_old_streams = 0; |
| | 2308 | |
| 2291 | 2309 | int mp4_descr_count = 0; |
| 2292 | 2310 | Mp4Descr mp4_descr[MAX_MP4_DESCR_COUNT] = { { 0 } }; |
| 2293 | 2311 | int i; |
| … |
… |
static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len
|
| 2361 | 2379 | |
| 2362 | 2380 | set_pmt_found(ts, h->id); |
| 2363 | 2381 | |
| | 2382 | if (ts->merge_pmt_versions) { |
| | 2383 | old_streams = av_malloc_array(sizeof(struct Stream), ts->stream->nb_streams); |
| | 2384 | if (!old_streams) |
| | 2385 | goto out; |
| | 2386 | nb_old_streams = ts->stream->nb_streams; |
| | 2387 | for (i = 0; i < nb_old_streams; i++) { |
| | 2388 | AVStream *st = ts->stream->streams[i]; |
| | 2389 | old_streams[i].pmt_stream_idx = st->pmt_stream_idx; |
| | 2390 | old_streams[i].stream_identifier = st->stream_identifier; |
| | 2391 | old_streams[i].program_num = st->program_num; |
| | 2392 | } |
| | 2393 | } |
| 2364 | 2394 | |
| 2365 | 2395 | for (i = 0; ; i++) { |
| 2366 | 2396 | st = 0; |
| … |
… |
static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len
|
| 2382 | 2412 | if (ts->pids[pid] && ts->pids[pid]->type == MPEGTS_PES) { |
| 2383 | 2413 | pes = ts->pids[pid]->u.pes_filter.opaque; |
| 2384 | 2414 | if (ts->merge_pmt_versions && !pes->st) { |
| 2385 | | st = find_matching_stream(ts, pid, h->id, stream_identifier, i); |
| | 2415 | st = find_matching_stream(ts, old_streams, nb_old_streams, pid, h->id, stream_identifier, i); |
| 2386 | 2416 | if (st) { |
| 2387 | 2417 | pes->st = st; |
| 2388 | 2418 | pes->stream_type = stream_type; |
| … |
… |
static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len
|
| 2404 | 2434 | mpegts_close_filter(ts, ts->pids[pid]); // wrongly added sdt filter probably |
| 2405 | 2435 | pes = add_pes_stream(ts, pid, pcr_pid); |
| 2406 | 2436 | if (ts->merge_pmt_versions && pes && !pes->st) { |
| 2407 | | st = find_matching_stream(ts, pid, h->id, stream_identifier, i); |
| | 2437 | st = find_matching_stream(ts, old_streams, nb_old_streams, pid, h->id, stream_identifier, i); |
| 2408 | 2438 | if (st) { |
| 2409 | 2439 | pes->st = st; |
| 2410 | 2440 | pes->stream_type = stream_type; |
| … |
… |
static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len
|
| 2426 | 2456 | st = ts->stream->streams[idx]; |
| 2427 | 2457 | } |
| 2428 | 2458 | if (ts->merge_pmt_versions && !st) { |
| 2429 | | st = find_matching_stream(ts, pid, h->id, stream_identifier, i); |
| | 2459 | st = find_matching_stream(ts, old_streams, nb_old_streams, pid, h->id, stream_identifier, i); |
| 2430 | 2460 | } |
| 2431 | 2461 | if (!st) { |
| 2432 | 2462 | st = avformat_new_stream(ts->stream, NULL); |
| … |
… |
static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len
|
| 2481 | 2511 | mpegts_open_pcr_filter(ts, pcr_pid); |
| 2482 | 2512 | |
| 2483 | 2513 | out: |
| | 2514 | av_free(old_streams); |
| 2484 | 2515 | for (i = 0; i < mp4_descr_count; i++) |
| 2485 | 2516 | av_free(mp4_descr[i].dec_config_descr); |
| 2486 | 2517 | } |