[mythtv] [patch] pmt tracking bugfix

Daniel Thor Kristjansson danielk at mrl.nyu.edu
Sat Nov 13 18:58:33 UTC 2004


This patch fixes a bug in the PMT tracking code for MPEG-TS streams.

This patch delays the call to avformatdecoder's HandleStreamChange() 
until the stream is fully initialized.

-- Daniel
-------------- next part --------------
Index: libs/libavformat/utils.c
===================================================================
RCS file: /var/lib/mythcvs/mythtv/libs/libavformat/utils.c,v
retrieving revision 1.26
diff -u -r1.26 utils.c
--- libs/libavformat/utils.c	22 Oct 2004 09:56:15 -0000	1.26
+++ libs/libavformat/utils.c	13 Nov 2004 18:49:20 -0000
@@ -1817,17 +1817,36 @@
  */
 AVStream *av_new_stream(AVFormatContext *s, int id)
 {
-    AVStream *st;
+    AVStream *st = av_mallocz(sizeof(AVStream));
+    if (st) {
+        avcodec_get_context_defaults(&st->codec);
+        AVStream *stream = av_add_stream(s, st, id);
+        if (!stream)
+            av_free(st);
+        return stream;
+    }
+    return NULL;
+}
+
+/**
+ * Add a stream to an MPEG media stream. This is used by mpegts 
+ * instead of av_new_stream, so we can track new streams
+ * as indicated by the PMT.
+ *
+ * @param s MPEG media stream handle
+ * @param st new media stream
+ * @param id file format dependent stream id 
+ */
+AVStream *av_add_stream(AVFormatContext *s, AVStream *st, int id)
+{
+    if (!st)
+        return NULL;
 
     av_remove_stream(s, id);
 
     if (s->nb_streams >= MAX_STREAMS)
         return NULL;
 
-    st = av_mallocz(sizeof(AVStream));
-    if (!st)
-        return NULL;
-    avcodec_get_context_defaults(&st->codec);
     if (s->iformat) {
         /* no default bitrate if decoding */
         st->codec.bit_rate = 0;
@@ -1843,27 +1862,28 @@
     st->last_IP_pts = AV_NOPTS_VALUE;
 
     s->streams[s->nb_streams++] = st;
-    if (s->streams_changed)
-	s->streams_changed(s->stream_change_data);
     return st;
 }
 
+/**
+ * Remove a stream from a media stream. This is used by mpegts,
+ * so we can track streams as indicated by the PMT.
+ *
+ * @param s MPEG media stream handle
+ * @param id stream id of stream to remove
+ */
 void av_remove_stream(AVFormatContext *s, int id) {
-    //printf("av_remove_stream 0x%x -- IGNORED \n", id);
-    //return; // TODO HACK 
     int i;
     for (i=0; i<s->nb_streams; i++)
-	if (s->streams[i]->id == id) {
-	    printf("av_remove_stream 0x%x\n", id);
-	    s->nb_streams--;
-	    if (s->nb_streams-i>0)
-		memmove(&s->streams[i], &s->streams[i+1], (s->nb_streams-i)*sizeof(AVFormatContext *));
-	    if (s->streams_changed)
-		s->streams_changed(s->stream_change_data);
-	    continue;
-	}
+        if (s->streams[i]->id == id) {
+            printf("av_remove_stream 0x%x\n", id);
+            s->nb_streams--;
+            if (s->nb_streams-i>0)
+                memmove(&s->streams[i], &s->streams[i+1], (s->nb_streams-i)*sizeof(AVFormatContext *));
+            continue;
+        }
     for (i=0; i<s->nb_streams; i++)
-	s->streams[i]->index=i;
+        s->streams[i]->index=i;
 }
 
 /************************************************************/
Index: libs/libavformat/mpegts.c
===================================================================
RCS file: /var/lib/mythcvs/mythtv/libs/libavformat/mpegts.c,v
retrieving revision 1.21
diff -u -r1.21 mpegts.c
--- libs/libavformat/mpegts.c	23 Oct 2004 12:04:58 -0000	1.21
+++ libs/libavformat/mpegts.c	13 Nov 2004 18:49:20 -0000
@@ -399,6 +399,7 @@
     SectionHeader h1, *h = &h1;
     const uint8_t *p, *p_end;
     int program_info_length, pcr_pid, pid, stream_type, desc_length;
+    int changes = 0;
     
 #ifdef DEBUG_SI
     printf("PMT:\n");
@@ -467,6 +468,7 @@
             if (!pmtInList(ts->pmt_pids_old, pid)) {
                 printf("adding pes stream at pid 0x%x with type %i\n", pid, stream_type);
                 add_pes_stream(ts, pid, stream_type);
+                changes = 1;
             }
             ts->pmt_pids[i]=pid; i++;
             break;
@@ -482,6 +484,7 @@
             printf("closing filter for pid 0x%x\n", ts->pmt_pids_old[i]);
             av_remove_stream(ts->stream, ts->pmt_pids_old[i]);
             mpegts_close_filter(ts, ts->pids[ts->pmt_pids_old[i]]);
+            changes = 1;
         }
     memcpy(ts->pmt_pids_old, ts->pmt_pids, PMT_PIDS_MAX*sizeof(int));
 
@@ -491,6 +494,13 @@
         ts->set_service_cb(ts->set_service_opaque, 0);
     mpegts_close_filter(ts, ts->pmt_filter);
     ts->pmt_filter = NULL;
+
+    /* notify stream_changed listeners */
+    AVFormatContext *s = ts->stream;
+    if (changes && s->streams_changed) {
+        printf("streams_changed()\n");
+        s->streams_changed(s->stream_change_data);
+    }
 }
 
 static void pat_cb(void *opaque, const uint8_t *section, int section_len)
@@ -791,14 +801,17 @@
     av_set_pts_info(st, 60, 1, 90000);
 }
 
-static void create_stream(PESContext *pes, int code)
+static int create_stream(PESContext *pes, int code)
 {
-    pes->st = av_new_stream(pes->stream, pes->pid);
-    if (pes->st) {
-        init_stream(pes->st, pes->stream_type, code);
-        pes->st->priv_data = pes;
-        pes->st->need_parsing = 1;
-    }
+    CHECKED_ALLOCZ(pes->st, sizeof(AVStream));
+    avcodec_get_context_defaults(&pes->st->codec); // sets codec defaults
+    init_stream(pes->st, pes->stream_type, code);  // sets codec type and id
+    pes->st->priv_data = pes;
+    pes->st->need_parsing = 1;
+
+    pes->st = av_add_stream(pes->stream, pes->st, pes->pid);
+fail: //for the CHECKED_ALLOCZ macro
+    return (pes->st)? 0 : -1;
 }
 
 
@@ -842,8 +855,10 @@
                           (code >= 0x1e0 && code <= 0x1ef) ||
                           (code == 0x1bd)))
                         goto skip;
-                    if (!pes->st) 
-                        create_stream(pes, code);
+                    if (!pes->st && -1==create_stream(pes, code)) {
+                        av_log(NULL, AV_LOG_ERROR, "Error: create_stream() failed in mpegts_push_data");
+                        goto skip;
+                    }
                     pes->state = MPEGTS_PESHEADER_FILL;
                     pes->total_size = (pes->header[4] << 8) | pes->header[5];
                     /* NOTE: a zero total size means the PES size is
@@ -938,8 +953,10 @@
     }
 
     /* create a PES context */
-    if (!(pes=av_mallocz(sizeof(PESContext))))
+    if (!(pes=av_mallocz(sizeof(PESContext)))) {
+        av_log(NULL, AV_LOG_ERROR, "Error: av_mallocz() failed in add_pes_stream");
         return -1;
+    }
     pes->ts = ts;
     pes->stream = ts->stream;
     pes->pid = pid;
@@ -947,10 +964,17 @@
     tss = mpegts_open_pes_filter(ts, pid, mpegts_push_data, pes);
     if (!tss) {
         av_free(pes);
+        av_log(NULL, AV_LOG_ERROR, "Error: unable to open mpegts PES filter in add_pes_stream");
+        return -1;
+    }
+    if (!pes->st && -1==create_stream(pes, -1)) {
+        av_log(NULL, AV_LOG_ERROR, "Error: create_stream() failed in add_pes_stream");
         return -1;
     }
-    if (!pes->st)
-        create_stream(pes, -1);
+
+    assert(pes->stream_type==stream_type);
+    assert(pes->st->codec.codec_type);
+    assert(pes->st->codec.codec_id);
 
     return 0;
 }
Index: libs/libavformat/avformat.h
===================================================================
RCS file: /var/lib/mythcvs/mythtv/libs/libavformat/avformat.h,v
retrieving revision 1.24
diff -u -r1.24 avformat.h
--- libs/libavformat/avformat.h	22 Oct 2004 09:56:15 -0000	1.24
+++ libs/libavformat/avformat.h	13 Nov 2004 18:49:21 -0000
@@ -558,6 +558,7 @@
 int av_read_pause(AVFormatContext *s);
 void av_close_input_file(AVFormatContext *s);
 AVStream *av_new_stream(AVFormatContext *s, int id);
+AVStream *av_add_stream(AVFormatContext *s, AVStream *st, int id);
 void av_remove_stream(AVFormatContext *s, int id);
 void av_set_pts_info(AVStream *s, int pts_wrap_bits,
                      int pts_num, int pts_den);


More information about the mythtv-dev mailing list