[vlc-devel] [PATCH] Allow mpeg2-ts skip forward/backward

Steve Bennett steveb at workware.net.au
Thu Apr 14 02:01:56 CEST 2011


Allow skip forward/backward and display total time for
mpeg2 transport streams (e.g. dvb-t).

The (possibly discontinous) embedded PCR is used to estimate the mux
rate and thus relate the current time index to the current file position.

See: https://trac.videolan.org/vlc/ticket/2985

Signed-off-by: Steve Bennett <steveb at workware.net.au>
---
 modules/demux/ts.c |   80 +++++++++++++++++++++++++++++++++++++--------------
 1 files changed, 58 insertions(+), 22 deletions(-)

diff --git a/modules/demux/ts.c b/modules/demux/ts.c
index 4c209f2..0ed5683 100644
--- a/modules/demux/ts.c
+++ b/modules/demux/ts.c
@@ -330,6 +330,11 @@ struct demux_sys_t
     /* how many TS packet we read at once */
     int         i_ts_read;
 
+    /* guess mux rate */
+    mtime_t     i_first_pcr;
+    int64_t     i_first_streampos;
+    int         i_mux_rate;
+
     /* All pid */
     ts_pid_t    pid[8192];
 
@@ -1213,41 +1218,40 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
             return VLC_EGENERIC;
 
         return VLC_SUCCESS;
-#if 0
 
     case DEMUX_GET_TIME:
         pi64 = (int64_t*)va_arg( args, int64_t * );
-        if( p_sys->i_time < 0 )
+        i64 = stream_Size( p_demux->s );
+        if( i64 > 0 )
         {
-            *pi64 = 0;
-            return VLC_EGENERIC;
+            /* Calculate time based on position and mux rate */
+            if (p_sys->i_mux_rate > 0)
+            {
+                *pi64 = INT64_C(1000000) * ( stream_Tell( p_demux->s ) / 50 ) / p_sys->i_mux_rate;
+                return VLC_SUCCESS;
+            }
         }
-        *pi64 = p_sys->i_time;
-        return VLC_SUCCESS;
+        else if( DVBEventInformation( p_demux, pi64, NULL ) == 0)
+            return VLC_SUCCESS;
+        *pi64 = 0;
+        return VLC_EGENERIC;
 
     case DEMUX_GET_LENGTH:
         pi64 = (int64_t*)va_arg( args, int64_t * );
-        if( p_sys->i_mux_rate > 0 )
+        i64 = stream_Size( p_demux->s );
+        if( i64 > 0 )
         {
-            *pi64 = INT64_C(1000000) * ( stream_Size( p_demux->s ) / 50 ) /
-                    p_sys->i_mux_rate;
-            return VLC_SUCCESS;
+            if( p_sys->i_mux_rate > 0 )
+            {
+                *pi64 = INT64_C(1000000) * ( stream_Size( p_demux->s ) / 50 ) / p_sys->i_mux_rate;
+                return VLC_SUCCESS;
+            }
         }
+        else if( DVBEventInformation( p_demux, NULL, pi64 ) == 0)
+            return VLC_SUCCESS;
         *pi64 = 0;
         return VLC_EGENERIC;
-#else
-    case DEMUX_GET_TIME:
-        pi64 = (int64_t*)va_arg( args, int64_t * );
-        if( DVBEventInformation( p_demux, pi64, NULL ) )
-            *pi64 = 0;
-        return VLC_SUCCESS;
 
-    case DEMUX_GET_LENGTH:
-        pi64 = (int64_t*)va_arg( args, int64_t * );
-        if( DVBEventInformation( p_demux, NULL, pi64 ) )
-            *pi64 = 0;
-        return VLC_SUCCESS;
-#endif
     case DEMUX_SET_GROUP:
     {
         vlc_list_t *p_list;
@@ -1858,6 +1862,38 @@ static void PCRHandle( demux_t *p_demux, ts_pid_t *pid, block_t *p_bk )
                               ( (mtime_t)p[9] << 1 ) |
                               ( (mtime_t)p[10] >> 7 );
 
+        if (p_sys->i_first_pcr == 0)
+        {
+            /* Save this pcr and stream position */
+            p_sys->i_first_pcr = i_pcr;
+            p_sys->i_first_streampos = stream_Tell( p_demux->s );
+        }
+        else if (p_sys->i_mux_rate <= 0)
+        {
+            if ((i_pcr - p_sys->i_first_pcr) * 100 / 9 >= 10000)
+            {
+                /* Have at least 10ms, so calculate (guess) the mux rate
+                 * based on pcr and stream positions
+                 */
+
+                /* Mux rate is in units of 50 bytes/s */
+                p_sys->i_mux_rate = (stream_Tell( p_demux->s ) - p_sys->i_first_streampos)
+                    * 1000000 / 50 / ((i_pcr - p_sys->i_first_pcr) * 100 / 9);
+                msg_Dbg(p_demux, "Calculated mux rate=%d (50 bytes/sec) = %dbits/s",
+                    p_sys->i_mux_rate, p_sys->i_mux_rate * 50 * 8);
+
+                /* If there is a disjunction or the pcr wraps,
+                 * we may get a horribly wrong answer
+                 */
+                if (p_sys->i_mux_rate < 5000 || p_sys->i_mux_rate > 50000)
+                {
+                    msg_Warn( p_demux, "Unreasonable mux rate, retrying");
+                    p_sys->i_first_pcr = 0;
+                    p_sys->i_mux_rate = 0;
+                }
+            }
+        }
+
         /* Search program and set the PCR */
         for( int i = 0; i < p_sys->i_pmt; i++ )
         {
-- 
1.5.5.3




More information about the vlc-devel mailing list