summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libavformat/mpegts.c53
1 files changed, 33 insertions, 20 deletions
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);