>From 42ad78fa964e318df42303d6cef4f8573a310b2d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tobias=20G=C3=BCntner?= <fatbull@web.de>
Date: Mon, 15 Aug 2011 16:58:29 +0000
Subject: [PATCH] Improve stream length calculation

* Ignore invalid timestamps
* Handle timestamp overflow
---
 modules/demux/ps.c |   35 ++++++++++++++++++++++++-----------
 modules/demux/ps.h |    7 +++++--
 2 files changed, 29 insertions(+), 13 deletions(-)
 mode change 100644 => 100755 modules/demux/ps.c
 mode change 100644 => 100755 modules/demux/ps.h

diff --git a/modules/demux/ps.c b/modules/demux/ps.c
old mode 100644
new mode 100755
index 51361bf..9b1e0e8
--- a/modules/demux/ps.c
+++ b/modules/demux/ps.c
@@ -218,13 +218,13 @@ static int Demux2( demux_t *p_demux, bool b_end )
     if( (i_id = ps_pkt_id( p_pkt )) >= 0xc0 )
     {
         ps_track_t *tk = &p_sys->tk[PS_ID_TO_TK(i_id)];
-        if( !ps_pkt_parse_pes( p_pkt, tk->i_skip ) )
+        if( !ps_pkt_parse_pes( p_pkt, tk->i_skip ) && p_pkt->i_pts != VLC_TS_INVALID )
         {
             if( b_end && p_pkt->i_pts > tk->i_last_pts )
             {
                 tk->i_last_pts = p_pkt->i_pts;
             }
-            else if ( tk->i_first_pts == -1 )
+            else if ( tk->i_first_pts == VLC_TS_INVALID )
             {
                 tk->i_first_pts = p_pkt->i_pts;
             }
@@ -260,20 +260,33 @@ static void FindLength( demux_t *p_demux )
         if( i_current_pos >= 0 ) stream_Seek( p_demux->s, i_current_pos );
     }
 
+    /* Find the longest track */
     for( int i = 0; i < PS_TK_COUNT; i++ )
     {
         ps_track_t *tk = &p_sys->tk[i];
-        if( tk->i_first_pts >= 0 && tk->i_last_pts > 0 )
-            if( tk->i_last_pts > tk->i_first_pts )
+        if( tk->i_first_pts >= VLC_TS_0 && tk->i_last_pts >= VLC_TS_0 )
+        {
+            int64_t i_length = (int64_t)tk->i_last_pts - tk->i_first_pts;
+
+            /*
+             * Workaround if timestamps overflow somewhere in a stream.
+             * Note that this only works for one overflow. To find more
+             * overflows, we would have to scan the whole stream. But
+             * since overflows occur (roughly) every 26 hours and most
+             * videos are considerably shorter or do not contain an
+             * overflow at all, this ought to be good enough.
+             */
+            if( i_length < 0 )
+                i_length += PS_PTS_OVERFLOW;
+
+            assert( p_sys->i_length >= 0 );
+            if( i_length > p_sys->i_length )
             {
-                int64_t i_length = (int64_t)tk->i_last_pts - tk->i_first_pts;
-                if( i_length > p_sys->i_length )
-                {
-                    p_sys->i_length = i_length;
-                    p_sys->i_time_track = i;
-                    msg_Dbg( p_demux, "we found a length of: %"PRId64, p_sys->i_length );
-                }
+                p_sys->i_length = i_length;
+                p_sys->i_time_track = i;
+                msg_Dbg( p_demux, "we found a length of: %"PRId64, p_sys->i_length );
             }
+        }
     }
 }
 
diff --git a/modules/demux/ps.h b/modules/demux/ps.h
old mode 100644
new mode 100755
index 674c365..b763eb4
--- a/modules/demux/ps.h
+++ b/modules/demux/ps.h
@@ -45,6 +45,9 @@ static inline int ps_id_to_tk( unsigned i_id )
 #define PS_ID_TO_TK( id ) ps_id_to_tk( id )
 #endif
 
+/* Timestamp overflow period (converted to VLC clock) */
+#define PS_PTS_OVERFLOW (((int64_t)1 << 33) * 100 / 9)
+
 typedef struct ps_psm_t ps_psm_t;
 static inline int ps_id_to_type( const ps_psm_t *, int );
 static inline const uint8_t *ps_id_to_lang( const ps_psm_t *, int );
@@ -71,8 +74,8 @@ static inline void ps_track_init( ps_track_t tk[PS_TK_COUNT] )
         tk[i].i_skip = 0;
         tk[i].i_id   = 0;
         tk[i].es     = NULL;
-        tk[i].i_first_pts = -1;
-        tk[i].i_last_pts = -1;
+        tk[i].i_first_pts = VLC_TS_INVALID;
+        tk[i].i_last_pts = VLC_TS_INVALID;
         es_format_Init( &tk[i].fmt, UNKNOWN_ES, 0 );
     }
 }
-- 
1.7.0.4

