[mythtv] [experimental patch] AvFormatDecoder::Reset() fix for ffmpeg

Daniel Thor Kristjansson danielk at mrl.nyu.edu
Thu Feb 17 18:46:24 UTC 2005


When using ffmpeg to play mpeg ts files, AVFD::Reset() does not fully 
delete streams. When I wrote av_remove_stream I did not intend for it to 
be called this way, and it does not remove the stream from the mpegts
state, so if you say switch between two channels that happen to have 
sound on the same pid's ( and hence the same stream id's, :/ ) you'll 
lose sound with the current implementation. But I've gone back and made 
it work by adding a mpegts_remove_stream call which does this, and have 
modified av_remove_stream to call this if we are decoding an mpegts
file.

This actually doesn't change avformatdecoder.cpp at all, but just makes 
the av_remove_stream work like the writer of that rutine expected it 
too.

This patch works as far as letting me change channels in HDTV, but I 
haven't tested this very much yet and have left in extra debugging 
statements, hence it's experimental.

-- Daniel
-------------- next part --------------
Index: libs/libavformat/mpegts.c
===================================================================
RCS file: /var/lib/mythcvs/mythtv/libs/libavformat/mpegts.c,v
retrieving revision 1.24
diff -u -r1.24 mpegts.c
--- libs/libavformat/mpegts.c	18 Nov 2004 05:59:37 -0000	1.24
+++ libs/libavformat/mpegts.c	17 Feb 2005 18:24:09 -0000
@@ -31,6 +31,8 @@
 #define MAX_RESYNC_SIZE 4096
 
 static int add_pes_stream(MpegTSContext *ts, int pid, int stream_type);
+static void mpegts_cleanup_streams(MpegTSContext *ts);
+static void mpegts_add_stream(MpegTSContext *ts, int pid, int type);
 
 enum MpegTSFilterType {
     MPEGTS_PES,
@@ -110,8 +112,8 @@
     int req_sid;
 
     MpegTSFilter *pids[NB_PID_MAX];
-#define PMT_PIDS_MAX 32
-    int pmt_pids_old[PMT_PIDS_MAX];
+#define PMT_PIDS_MAX 64
+    int pid_cnt;
     int pmt_pids[PMT_PIDS_MAX];
 };
 
@@ -385,12 +387,12 @@
     return service;
 }
 
-int pmtInList(int *pids, int pid) {
+static int find_in_list(int *pids, int pid) {
     int i;
     for (i=0; i<PMT_PIDS_MAX; i++)
         if (pids[i]==pid)
-            return 1;
-    return 0;
+            return i;
+    return -1;
 }
 
 static void pmt_cb(void *opaque, const uint8_t *section, int section_len)
@@ -400,6 +402,10 @@
     const uint8_t *p, *p_end;
     int program_info_length, pcr_pid, pid, stream_type, desc_length;
     int changes = 0;
+    int i, new_pids[PMT_PIDS_MAX], new_types[PMT_PIDS_MAX];
+    memset(new_pids, 0, sizeof(int)*PMT_PIDS_MAX);
+    memset(new_types, 0, sizeof(int)*PMT_PIDS_MAX);
+    mpegts_cleanup_streams(ts); /* in case someone else removed streams.. */
     
 #ifdef DEBUG_SI
     printf("PMT:\n");
@@ -428,13 +434,8 @@
     p += program_info_length;
     if (p >= p_end)
         return;
-/* create new streams */
-    int i=0;
-    for (i=0; i<PMT_PIDS_MAX; i++)
-        ts->pmt_pids[i] = 0;
-    for (i=0; i<PMT_PIDS_MAX; i++)
-        if (!ts->pids[ts->pmt_pids_old[i]])
-            ts->pmt_pids_old[i]=0;
+
+    /* create new streams */
 
     for(i=0;;) {
         stream_type = get8(&p, p_end);
@@ -465,12 +466,16 @@
         case STREAM_TYPE_AUDIO_AAC:
         case STREAM_TYPE_AUDIO_AC3:
         case STREAM_TYPE_AUDIO_DTS:
-            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;
+            if (i < PMT_PIDS_MAX) {
+                new_pids[i] = pid;
+                new_types[i] = stream_type;
+                i++;
+            }
+            else
+            {
+                printf("Could not add new pid 0x%x, i = %i, "
+                       "would cause overrun\n", pid, i);
             }
-            ts->pmt_pids[i]=pid; i++;
             break;
         default:
             /* we ignore the other streams */
@@ -479,21 +484,31 @@
     }
 
     /* clear existing streams and filters not in new pmt */
-    for (i=0; i<PMT_PIDS_MAX; i++) 
-        if (ts->pmt_pids_old[i] && !pmtInList(ts->pmt_pids, ts->pmt_pids_old[i])) {
-            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]]);
+    for (i=0; i<ts->pid_cnt; i++) {
+        if (ts->pmt_pids[i] && 
+            find_in_list(new_pids, ts->pmt_pids[i]) != -1) {
+            av_remove_stream(ts->stream, ts->pmt_pids[i]);
+            changes = 1;
+            i--;
+        }        
+    }
+
+    /* add new streams and filters not in old pmt */
+    for (i=0; i<PMT_PIDS_MAX; i++) {
+        if (new_pids[i] && find_in_list(ts->pmt_pids, new_pids[i]) != -1) {
+            mpegts_add_stream(ts, new_pids[i], new_types[i]);
             changes = 1;
         }
-    memcpy(ts->pmt_pids_old, ts->pmt_pids, PMT_PIDS_MAX*sizeof(int));
+    }
 
     /* all parameters are there */
 
     if (ts->set_service_cb)
         ts->set_service_cb(ts->set_service_opaque, 0);
+#if 0 /* if we delete the pmt filter we will never see any new services */
     mpegts_close_filter(ts, ts->pmt_filter);
     ts->pmt_filter = NULL;
+#endif
 
     /* notify stream_changed listeners */
     AVFormatContext *s = ts->stream;
@@ -503,6 +518,56 @@
     }
 }
 
+static void mpegts_cleanup_streams(MpegTSContext *ts)
+{
+    int i;
+    for (i=0; i<ts->pid_cnt; i++)
+    {
+        if (!ts->pids[ts->pmt_pids[i]])
+        {
+            mpegts_remove_stream(ts, ts->pmt_pids[i]);
+            i--;
+        }
+    }
+}
+
+static void mpegts_add_stream(MpegTSContext *ts, int pid, int type)
+{
+    printf("adding pes stream at pid 0x%x with type %i\n", pid, type);
+    if (ts->pid_cnt < PMT_PIDS_MAX)
+    {
+        add_pes_stream(ts, pid, type);
+        ts->pmt_pids[ts->pid_cnt] = pid;
+        ts->pid_cnt++;
+    }
+    else
+    {
+        printf("ERROR: adding pes stream at pid 0x%x, pid_cnt = %i\n",
+               pid, ts->pid_cnt);
+    }
+}
+
+void mpegts_remove_stream(MpegTSContext *ts, int pid)
+{
+    printf("mpegts_remove_stream 0x%x\n", pid);
+    if (ts->pids[pid])
+    {
+        printf("closing filter for pid 0x%x\n", pid);
+        mpegts_close_filter(ts, ts->pids[pid]);
+    }
+    int indx = find_in_list(ts->pmt_pids, pid);
+    if (indx >= 0)
+    {
+        memmove(ts->pmt_pids+indx, ts->pmt_pids+indx+1, PMT_PIDS_MAX-indx-1);
+        ts->pmt_pids[PMT_PIDS_MAX-1] = 0;
+        ts->pid_cnt--;
+    }
+    else
+    {
+        printf("ERROR: closing filter for pid 0x%x, indx = %i\n", pid, indx);
+    }
+}
+
 static void pat_cb(void *opaque, const uint8_t *section, int section_len)
 {
     MpegTSContext *ts = opaque;
Index: libs/libavformat/utils.c
===================================================================
RCS file: /var/lib/mythcvs/mythtv/libs/libavformat/utils.c,v
retrieving revision 1.32
diff -u -r1.32 utils.c
--- libs/libavformat/utils.c	31 Jan 2005 17:15:16 -0000	1.32
+++ libs/libavformat/utils.c	17 Feb 2005 18:24:09 -0000
@@ -17,6 +17,7 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 #include "avformat.h"
+#include "mpegts.h"
 
 #undef NDEBUG
 #include <assert.h>
@@ -2096,7 +2097,14 @@
             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 *));
+                memmove(&s->streams[i], &s->streams[i+1],
+                        (s->nb_streams-i)*sizeof(AVFormatContext *));
+            if (s->iformat && s->priv_data && 
+                (0 == strncmp(s->iformat->name, "mpegts", 6)))
+            {
+                MpegTSContext *context = (MpegTSContext*) s->priv_data;
+                mpegts_remove_stream(context, id);
+            }
             continue;
         }
     for (i=0; i<s->nb_streams; i++)
Index: libs/libavformat/mpegts.h
===================================================================
RCS file: /var/lib/mythcvs/mythtv/libs/libavformat/mpegts.h,v
retrieving revision 1.7
diff -u -r1.7 mpegts.h
--- libs/libavformat/mpegts.h	19 Aug 2004 20:06:27 -0000	1.7
+++ libs/libavformat/mpegts.h	17 Feb 2005 18:24:10 -0000
@@ -53,3 +53,4 @@
 int mpegts_parse_packet(MpegTSContext *ts, AVPacket *pkt,
                         const uint8_t *buf, int len);
 void mpegts_parse_close(MpegTSContext *ts);
+void mpegts_remove_stream(MpegTSContext *ts, int pid);


More information about the mythtv-dev mailing list