diff --git a/libavformat/mpegts.c b/libavformat/mpegts.c index ee69e2ca29..bde0eeec35 100644 --- a/libavformat/mpegts.c +++ b/libavformat/mpegts.c @@ -107,11 +107,19 @@ struct MpegTSFilter { } u; }; -#define MAX_PIDS_PER_PROGRAM 64 +struct Stream { + int idx; + int stream_identifier; +}; + +#define MAX_STREAMS_PER_PROGRAM 128 +#define MAX_PIDS_PER_PROGRAM (MAX_STREAMS_PER_PROGRAM + 2) struct Program { unsigned int id; // program id/service id unsigned int nb_pids; unsigned int pids[MAX_PIDS_PER_PROGRAM]; + unsigned int nb_streams; + struct Stream streams[MAX_STREAMS_PER_PROGRAM]; /** have we found pmt for this program */ int pmt_found; @@ -291,6 +299,7 @@ static void clear_program(struct Program *p) if (!p) return; p->nb_pids = 0; + p->nb_streams = 0; p->pmt_found = 0; } @@ -2193,25 +2202,20 @@ int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type } static AVStream *find_matching_stream(MpegTSContext *ts, int pid, unsigned int programid, - int stream_identifier, int pmt_stream_idx) + int stream_identifier, int pmt_stream_idx, struct Program *p) { AVFormatContext *s = ts->stream; int i; AVStream *found = NULL; - for (i = 0; i < s->nb_streams; i++) { - AVStream *st = s->streams[i]; - if (st->program_num != programid) - continue; - if (stream_identifier != -1) { /* match based on "stream identifier descriptor" if present */ - if (st->stream_identifier == stream_identifier+1) { - found = st; - break; - } - } else if (st->pmt_stream_idx == pmt_stream_idx) { /* match based on position within the PMT */ - found = st; - break; + if (stream_identifier) { /* match based on "stream identifier descriptor" if present */ + for (i = 0; i < p->nb_streams; i++) { + if (p->streams[i].stream_identifier == stream_identifier) + if (!found || pmt_stream_idx == i) /* fallback to idx based guess if multiple streams have the same identifier */ + found = s->streams[p->streams[i].idx]; } + } else if (pmt_stream_idx < p->nb_streams) { /* match based on position within the PMT */ + found = s->streams[p->streams[pmt_stream_idx].idx]; } if (found) { @@ -2270,6 +2274,7 @@ 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; + struct Program old_program; SectionHeader h1, *h = &h1; PESContext *pes; AVStream *st; @@ -2303,6 +2308,10 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len return; prg = get_program(ts, h->id); + if (prg) + old_program = *prg; + else + clear_program(&old_program); if (ts->skip_unknown_pmt && !prg) return; @@ -2360,7 +2369,7 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len if (prg) prg->pmt_found = 1; - for (i = 0; ; i++) { + for (i = 0; i < MAX_STREAMS_PER_PROGRAM; i++) { st = 0; pes = NULL; stream_type = get8(&p, p_end); @@ -2373,14 +2382,13 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len if (pid == ts->current_pid) goto out; - if (ts->merge_pmt_versions) - stream_identifier = parse_stream_identifier_desc(p, p_end); + stream_identifier = parse_stream_identifier_desc(p, p_end) + 1; /* now create stream */ if (ts->pids[pid] && ts->pids[pid]->type == MPEGTS_PES) { pes = ts->pids[pid]->u.pes_filter.opaque; if (ts->merge_pmt_versions && !pes->st) { - st = find_matching_stream(ts, pid, h->id, stream_identifier, i); + st = find_matching_stream(ts, pid, h->id, stream_identifier, i, &old_program); if (st) { pes->st = st; pes->stream_type = stream_type; @@ -2402,7 +2410,7 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len mpegts_close_filter(ts, ts->pids[pid]); // wrongly added sdt filter probably pes = add_pes_stream(ts, pid, pcr_pid); if (ts->merge_pmt_versions && pes && !pes->st) { - st = find_matching_stream(ts, pid, h->id, stream_identifier, i); + st = find_matching_stream(ts, pid, h->id, stream_identifier, i, &old_program); if (st) { pes->st = st; pes->stream_type = stream_type; @@ -2424,7 +2432,7 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len st = ts->stream->streams[idx]; } if (ts->merge_pmt_versions && !st) { - st = find_matching_stream(ts, pid, h->id, stream_identifier, i); + st = find_matching_stream(ts, pid, h->id, stream_identifier, i, &old_program); } if (!st) { st = avformat_new_stream(ts->stream, NULL); @@ -2449,6 +2457,11 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len mpegts_set_stream_info(st, pes, stream_type, prog_reg_desc); add_pid_to_program(prg, pid); + if (prg) { + prg->streams[i].idx = st->index; + prg->streams[i].stream_identifier = stream_identifier; + prg->nb_streams++; + } av_program_add_stream_index(ts->stream, h->id, st->index);