diff --git a/libavformat/mpegts.c b/libavformat/mpegts.c index d5a74ff6c5..825eadc779 100644 --- a/libavformat/mpegts.c +++ b/libavformat/mpegts.c @@ -76,6 +76,13 @@ struct MpegTSFilter { } u; }; +#define MAX_PIDS_PER_PROGRAM 64 +typedef struct { + unsigned int id; //program id/service id + unsigned int nb_pids; + unsigned int pids[MAX_PIDS_PER_PROGRAM]; +} Program_t; + struct MpegTSContext { /* user data */ AVFormatContext *stream; @@ -99,6 +106,9 @@ struct MpegTSContext { /******************************************/ /* private mpegts data */ /* scan context */ + /** structure to keep track of Program->pids mapping */ + unsigned int nb_prg; + Program_t *prg; /** filters for various streams specified by PMT + for the PAT and PMT */ @@ -136,6 +146,85 @@ struct PESContext { extern AVInputFormat mpegts_demuxer; +static void clear_program(MpegTSContext *ts, unsigned int programid) +{ + int i; + + for(i=0; inb_prg; i++) + if(ts->prg[i].id == programid) + ts->prg[i].nb_pids = 0; +} + +static void clear_programs(MpegTSContext *ts) +{ + av_freep(&ts->prg); + ts->nb_prg=0; +} + +static void add_pat_entry(MpegTSContext *ts, unsigned int programid) +{ + Program_t *p; + void *tmp = av_realloc(ts->prg, (ts->nb_prg+1)*sizeof(Program_t)); + if(!tmp) + return; + ts->prg = tmp; + p = &ts->prg[ts->nb_prg]; + p->id = programid; + p->nb_pids = 0; + ts->nb_prg++; +} + +static void add_pid_to_pmt(MpegTSContext *ts, unsigned int programid, unsigned int pid) +{ + int i; + Program_t *p = NULL; + for(i=0; inb_prg; i++) { + if(ts->prg[i].id == programid) { + p = &ts->prg[i]; + break; + } + } + if(!p) + return; + + if(p->nb_pids >= MAX_PIDS_PER_PROGRAM) + return; + p->pids[p->nb_pids++] = pid; +} + +/** + * \brief discard_pid() decides if the pid is to be discarded according + * to caller's programs selection + * \param ts : - TS context + * \param pid : - pid + * \return 1 if the pid is only comprised in programs that have .discard=AVDISCARD_ALL + * 0 otherwise + */ +static int discard_pid(MpegTSContext *ts, unsigned int pid) +{ + int i, j, k; + int used = 0, discarded = 0; + Program_t *p; + for(i=0; inb_prg; i++) { + p = &ts->prg[i]; + for(j=0; jnb_pids; j++) { + if(p->pids[j] != pid) + continue; + //is program with id p->id set to be discarded? + for(k=0; kstream->nb_programs; k++) { + if(ts->stream->programs[k]->id == p->id) { + if(ts->stream->programs[k]->discard == AVDISCARD_ALL) + discarded++; + else + used++; + } + } + } + } + + return (!used && discarded); +} + /** * Assembles PES packets out of TS packets, and then calls the "section_cb" * function when they are complete. @@ -403,9 +492,11 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len if (h->tid != PMT_TID) return; + clear_program(ts, h->id); pcr_pid = get16(&p, p_end) & 0x1fff; if (pcr_pid < 0) return; + add_pid_to_pmt(ts, h->id, pcr_pid); #ifdef DEBUG_SI av_log(ts->stream, AV_LOG_DEBUG, "pcr_pid=0x%x\n", pcr_pid); #endif @@ -505,6 +596,7 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len if (pes) st = new_pes_av_stream(pes, 0); } + add_pid_to_pmt(ts, h->id, pid); break; default: /* we ignore the other streams */ @@ -544,6 +636,7 @@ static void pat_cb(MpegTSFilter *filter, const uint8_t *section, int section_len if (h->tid != PAT_TID) return; + clear_programs(ts); for(;;) { sid = get16(&p, p_end); if (sid < 0) @@ -560,6 +653,9 @@ static void pat_cb(MpegTSFilter *filter, const uint8_t *section, int section_len av_new_program(ts->stream, sid); ts->stop_parse--; mpegts_open_section_filter(ts, pmt_pid, pmt_cb, ts, 1); + add_pat_entry(ts, sid); + add_pid_to_pmt(ts, sid, 0); //add pat pid to program + add_pid_to_pmt(ts, sid, pmt_pid); } } /* not found */ @@ -887,6 +983,8 @@ static void handle_packet(MpegTSContext *ts, const uint8_t *packet) const uint8_t *p, *p_end; pid = AV_RB16(packet + 1) & 0x1fff; + if(pid && discard_pid(ts, pid)) + return; is_start = packet[1] & 0x40; tss = ts->pids[pid]; if (ts->auto_guess && tss == NULL && is_start) {