changeset 2575:06d31789d338 libavformat

added structures and code to keep track of pids<->programs mapping: it's needed to decide which pids to discard in order to feed to the caller only AVProgram(s) that have the AV_DISCARD_ALL flag not set
author nicodvb
date Tue, 25 Sep 2007 20:58:37 +0000
parents 9e51e62f5bdd
children df67ee47f76d
files mpegts.c
diffstat 1 files changed, 98 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/mpegts.c	Tue Sep 25 20:49:11 2007 +0000
+++ b/mpegts.c	Tue Sep 25 20:58:37 2007 +0000
@@ -76,6 +76,13 @@
     } 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 @@
     /******************************************/
     /* 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 @@
 
 extern AVInputFormat mpegts_demuxer;
 
+static void clear_program(MpegTSContext *ts, unsigned int programid)
+{
+    int i;
+
+    for(i=0; i<ts->nb_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; i<ts->nb_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; i<ts->nb_prg; i++) {
+        p = &ts->prg[i];
+        for(j=0; j<p->nb_pids; j++) {
+            if(p->pids[j] != pid)
+                continue;
+            //is program with id p->id set to be discarded?
+            for(k=0; k<ts->stream->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 @@
     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 @@
                 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 @@
     if (h->tid != PAT_TID)
         return;
 
+    clear_programs(ts);
     for(;;) {
         sid = get16(&p, p_end);
         if (sid < 0)
@@ -560,6 +653,9 @@
             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 @@
     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) {