]> git.sesse.net Git - vlc/blobdiff - src/video_parser/vpar_synchro.c
The motion compensation routines are now modules as well ; choose your
[vlc] / src / video_parser / vpar_synchro.c
index e54801992a7d0e09781b45dfea0b80fd5f80225b..d96433e64db3f6e492a8dd620d2268df07da40db 100644 (file)
@@ -2,7 +2,7 @@
  * vpar_synchro.c : frame dropping routines
  *****************************************************************************
  * Copyright (C) 1999, 2000 VideoLAN
- * $Id: vpar_synchro.c,v 1.62 2000/12/21 17:19:54 massiot Exp $
+ * $Id: vpar_synchro.c,v 1.78 2001/01/18 05:13:23 sam Exp $
  *
  * Authors: Christophe Massiot <massiot@via.ecp.fr>
  *          Samuel Hocevar <sam@via.ecp.fr>
@@ -41,6 +41,8 @@
  * Please bear in mind that B's and IP's will be inverted when displaying
  * (decoding order != presentation order). Thus, t1 < t0.
  *
+ * FIXME: write a few words about stream structure changes.
+ *
  * 2. Definitions
  *    ===========
  * t[0..12]     : Presentation timestamps of pictures 0..12.
  *
  * 3. General considerations
  *    ======================
- * We define to types of machines :
- *      2T > tauP  : machines capable of decoding all P pictures
+ * We define three types of machines :
  *      14T > tauI : machines capable of decoding all I pictures
+ *      2T > tauP  : machines capable of decoding all P pictures
+ *      T > tauB   : machines capable of decoding all B pictures
  *
  * 4. Decoding of an I picture
  *    ========================
@@ -67,7 +70,7 @@
  * before displaying :
  *      t0 - t > tau´I + DELTA
  *
- * 4. Decoding of a P picture
+ * 5. Decoding of a P picture
  *    =======================
  * On fast machines, we decode all P's.
  * Otherwise :
  * I picture, which is more important.
  *      t12 - t > tau´P + tau´I + DELTA
  *
- * 5. Decoding of a B picture
+ * 6. Decoding of a B picture
  *    =======================
- * First criterion : have time to decode it.
+ * On fast machines, we decode all B's. Otherwise :
  *      t1 - t > tau´B + DELTA
- *
- * Second criterion : it shouldn't prevent us from displaying the forthcoming
- * P picture, which is more important.
- *      t4 - t > tau´B + tau´P + DELTA
+ * Since the next displayed I or P is already decoded, we don't have to
+ * worry about it.
  *
  * I hope you will have a pleasant flight and do not forget your life
  * jacket.
- *                                                  --Meuuh (2000-11-09)
+ *                                                  --Meuuh (2000-12-29)
  */
 
 /*****************************************************************************
 #include "video.h"
 #include "video_output.h"
 
+#include "video_decoder.h"
+#include "vdec_motion.h"
 #include "../video_decoder/vdec_idct.h"
-#include "../video_decoder/video_decoder.h"
-#include "../video_decoder/vdec_motion.h"
 
-#include "../video_decoder/vpar_blocks.h"
+#include "vpar_blocks.h"
 #include "../video_decoder/vpar_headers.h"
 #include "../video_decoder/vpar_synchro.h"
 #include "../video_decoder/video_parser.h"
  * Local prototypes
  */
 static int  SynchroType( void );
-static void SynchroNewPicture( vpar_thread_t * p_vpar, int i_coding_type );
 
 /* Error margins */
 #define DELTA                   (int)(0.040*CLOCK_FREQ)
@@ -151,6 +151,11 @@ void vpar_SynchroInit( vpar_thread_t * p_vpar )
     p_vpar->synchro.b_dropped_last = 0;
     p_vpar->synchro.current_pts = mdate() + DEFAULT_PTS_DELAY;
     p_vpar->synchro.backward_pts = 0;
+    p_vpar->synchro.i_current_period = p_vpar->synchro.i_backward_period = 0;
+#ifdef STATS
+    p_vpar->synchro.i_trashed_pic = p_vpar->synchro.i_not_chosen_pic = 
+        p_vpar->synchro.i_pic = 0;
+#endif
 }
 
 /*****************************************************************************
@@ -224,7 +229,7 @@ boolean_t vpar_SynchroChoose( vpar_thread_t * p_vpar, int i_coding_type,
 #endif
 
         now = mdate();
-        period = 1000000 / (p_vpar->sequence.i_frame_rate) * 1001;
+        period = 1000000 * 1001 / p_vpar->sequence.i_frame_rate;
 
         vlc_mutex_lock( &p_vpar->p_vout->change_lock );
         tau_yuv = p_vpar->p_vout->render_time;
@@ -235,10 +240,6 @@ boolean_t vpar_SynchroChoose( vpar_thread_t * p_vpar, int i_coding_type,
         switch( i_coding_type )
         {
         case I_CODING_TYPE:
-            /* Stream structure changes */
-            if( S.i_eta_p )
-                S.i_n_p = S.i_eta_p;
-
             if( S.backward_pts )
             {
                 pts = S.backward_pts;
@@ -263,23 +264,17 @@ boolean_t vpar_SynchroChoose( vpar_thread_t * p_vpar, int i_coding_type,
                 b_decode = (pts - now) > (TAU_PRIME(I_CODING_TYPE) + DELTA);
             }
             if( !b_decode )
-                intf_WarnMsg( 3, "vpar synchro warning: trashing I\n" );
+                intf_WarnMsg( 3, "vpar synchro warning: trashing I" );
             break;
 
         case P_CODING_TYPE:
-            /* Stream structure changes */
-            if( S.i_eta_b )
-                S.i_n_b = S.i_eta_b;
-            if( S.i_eta_p + 1 > S.i_n_p )
-                S.i_n_p++;
-
             if( S.backward_pts )
             {
                 pts = S.backward_pts;
             }
             else
             {
-                pts = S.current_pts + period * (S.i_n_b + 2);
+                pts = S.current_pts + period * (S.i_n_b + 1);
             }
 
             if( (1 + S.i_n_p * (S.i_n_b + 1)) * period >
@@ -296,7 +291,7 @@ boolean_t vpar_SynchroChoose( vpar_thread_t * p_vpar, int i_coding_type,
                     /* next I */
                     b_decode &= (pts - now
                                   + period
-                              * ( (S.i_n_p - S.i_eta_p - 1) * (1 + S.i_n_b) - 1 ))
+                              * ( (S.i_n_p - S.i_eta_p) * (1 + S.i_n_b) - 1 ))
                                 > (TAU_PRIME(P_CODING_TYPE)
                                     + TAU_PRIME(I_CODING_TYPE) + DELTA);
                 }
@@ -308,22 +303,11 @@ boolean_t vpar_SynchroChoose( vpar_thread_t * p_vpar, int i_coding_type,
             break;
 
         case B_CODING_TYPE:
-            /* Stream structure changes */
-            if( S.i_eta_b + 1 > S.i_n_b )
-                S.i_n_b++;
-
-            pts = S.current_pts + period;
+            pts = S.current_pts;
 
             if( (S.i_n_b + 1) * period > S.p_tau[P_CODING_TYPE] )
             {
                 b_decode = (pts - now) > (TAU_PRIME(B_CODING_TYPE) + DELTA);
-
-                /* Remember that S.i_eta_b is for the moment only eta_b - 1. */
-                b_decode &= (pts - now
-                             + period
-                             * ( 2 * S.i_n_b - S.i_eta_b + 2))
-                               > (TAU_PRIME(B_CODING_TYPE)
-                                   + TAU_PRIME(P_CODING_TYPE) + DELTA);
             }
             else
             {
@@ -333,11 +317,17 @@ boolean_t vpar_SynchroChoose( vpar_thread_t * p_vpar, int i_coding_type,
 
         vlc_mutex_unlock( &p_vpar->synchro.fifo_lock );
 #ifdef DEBUG_VPAR
-        intf_DbgMsg("vpar synchro debug: %s picture scheduled for %s, %s (%lld)\n",
+        intf_DbgMsg("vpar synchro debug: %s picture scheduled for %s, %s (%lld)",
                     i_coding_type == B_CODING_TYPE ? "B" :
                     (i_coding_type == P_CODING_TYPE ? "P" : "I"),
                     mstrtime(p_date, pts), b_decode ? "decoding" : "trashed",
                     S.p_tau[i_coding_type]);
+#endif
+#ifdef STATS
+        if( !b_decode )
+        {
+            S.i_not_chosen_pic++;
+        }
 #endif
         return( b_decode );
 #undef S
@@ -346,12 +336,11 @@ boolean_t vpar_SynchroChoose( vpar_thread_t * p_vpar, int i_coding_type,
 }
 
 /*****************************************************************************
- * vpar_SynchroTrash : Update timers when we trash a picture
+ * vpar_SynchroTrash : Update counters when we trash a picture
  *****************************************************************************/
 void vpar_SynchroTrash( vpar_thread_t * p_vpar, int i_coding_type,
                         int i_structure )
 {
-    SynchroNewPicture( p_vpar, i_coding_type );
 #ifdef STATS
     p_vpar->synchro.i_trashed_pic++;
 #endif
@@ -376,11 +365,9 @@ void vpar_SynchroDecode( vpar_thread_t * p_vpar, int i_coding_type,
     else
     {
         /* FIFO full, panic() */
-        intf_ErrMsg("vpar error: synchro fifo full, estimations will be biased\n");
+        intf_ErrMsg("vpar error: synchro fifo full, estimations will be biased");
     }
     vlc_mutex_unlock( &p_vpar->synchro.fifo_lock );
-
-    SynchroNewPicture( p_vpar, i_coding_type );
 }
 
 /*****************************************************************************
@@ -408,7 +395,7 @@ void vpar_SynchroEnd( vpar_thread_t * p_vpar, int i_garbage )
             p_vpar->synchro.pi_meaningful[i_coding_type]++;
         }
 #ifdef DEBUG_VPAR
-        intf_DbgMsg("vpar synchro debug: finished decoding %s (%lld)\n",
+        intf_DbgMsg("vpar synchro debug: finished decoding %s (%lld)",
                     i_coding_type == B_CODING_TYPE ? "B" :
                     (i_coding_type == P_CODING_TYPE ? "P" : "I"), tau);
 #endif
@@ -428,6 +415,148 @@ mtime_t vpar_SynchroDate( vpar_thread_t * p_vpar )
     return( p_vpar->synchro.current_pts );
 }
 
+/*****************************************************************************
+ * vpar_SynchroNewPicture: Update stream structure and PTS
+ *****************************************************************************/
+void vpar_SynchroNewPicture( vpar_thread_t * p_vpar, int i_coding_type,
+                             int i_repeat_field )
+{
+    mtime_t         period = 1000000 * 1001 / p_vpar->sequence.i_frame_rate;
+
+    switch( i_coding_type )
+    {
+    case I_CODING_TYPE:
+        if( p_vpar->synchro.i_eta_p
+                && p_vpar->synchro.i_eta_p != p_vpar->synchro.i_n_p )
+        {
+            intf_WarnMsg( 1, "Stream periodicity changed from P[%d] to P[%d]",
+                          p_vpar->synchro.i_n_p, p_vpar->synchro.i_eta_p );
+            p_vpar->synchro.i_n_p = p_vpar->synchro.i_eta_p;
+        }
+        p_vpar->synchro.i_eta_p = p_vpar->synchro.i_eta_b = 0;
+#ifdef STATS
+        if( p_vpar->synchro.i_type == VPAR_SYNCHRO_DEFAULT )
+        {
+            intf_Msg( "vpar synchro stats: I(%lld) P(%lld)[%d] B(%lld)[%d] YUV(%lld) : trashed %d:%d/%d",
+                  p_vpar->synchro.p_tau[I_CODING_TYPE],
+                  p_vpar->synchro.p_tau[P_CODING_TYPE],
+                  p_vpar->synchro.i_n_p,
+                  p_vpar->synchro.p_tau[B_CODING_TYPE],
+                  p_vpar->synchro.i_n_b,
+                  p_vpar->p_vout->render_time,
+                  p_vpar->synchro.i_not_chosen_pic,
+                  p_vpar->synchro.i_trashed_pic -
+                  p_vpar->synchro.i_not_chosen_pic,
+                  p_vpar->synchro.i_pic );
+            p_vpar->synchro.i_trashed_pic = p_vpar->synchro.i_not_chosen_pic
+                = p_vpar->synchro.i_pic = 0;
+        }
+#endif
+        break;
+    case P_CODING_TYPE:
+        p_vpar->synchro.i_eta_p++;
+        if( p_vpar->synchro.i_eta_b
+                && p_vpar->synchro.i_eta_b != p_vpar->synchro.i_n_b )
+        {
+            intf_WarnMsg( 1, "Stream periodicity changed from B[%d] to B[%d]",
+                          p_vpar->synchro.i_n_b, p_vpar->synchro.i_eta_b );
+            p_vpar->synchro.i_n_b = p_vpar->synchro.i_eta_b;
+        }
+        p_vpar->synchro.i_eta_b = 0;
+        break;
+    case B_CODING_TYPE:
+        p_vpar->synchro.i_eta_b++;
+        break;
+    }
+
+    p_vpar->synchro.current_pts += p_vpar->synchro.i_current_period
+                                        * (period >> 1);
+
+#define PTS_THRESHOLD   (period >> 2)
+    if( i_coding_type == B_CODING_TYPE )
+    {
+        /* A video frame can be displayed 1, 2 or 3 times, according to
+         * repeat_first_field, top_field_first, progressive_sequence and
+         * progressive_frame. */
+        p_vpar->synchro.i_current_period = i_repeat_field;
+
+        if( p_vpar->sequence.next_pts )
+        {
+            if( p_vpar->sequence.next_pts - p_vpar->synchro.current_pts
+                    > PTS_THRESHOLD
+                 || p_vpar->synchro.current_pts - p_vpar->sequence.next_pts
+                    > PTS_THRESHOLD )
+            {
+                intf_WarnMsg( 2,
+                        "vpar synchro warning: pts != current_date (%lld)",
+                        p_vpar->synchro.current_pts
+                            - p_vpar->sequence.next_pts );
+            }
+            p_vpar->synchro.current_pts = p_vpar->sequence.next_pts;
+            p_vpar->sequence.next_pts = 0;
+        }
+    }
+    else
+    {
+        p_vpar->synchro.i_current_period = p_vpar->synchro.i_backward_period;
+        p_vpar->synchro.i_backward_period = i_repeat_field;
+
+        if( p_vpar->synchro.backward_pts )
+        {
+            if( p_vpar->sequence.next_dts && 
+                (p_vpar->sequence.next_dts - p_vpar->synchro.backward_pts
+                    > PTS_THRESHOLD
+              || p_vpar->synchro.backward_pts - p_vpar->sequence.next_dts
+                    > PTS_THRESHOLD) )
+            {
+                intf_WarnMsg( 2,
+                        "vpar synchro warning: backward_pts != dts (%lld)",
+                        p_vpar->sequence.next_dts
+                            - p_vpar->synchro.backward_pts );
+            }
+            if( p_vpar->synchro.backward_pts - p_vpar->synchro.current_pts
+                    > PTS_THRESHOLD
+                 || p_vpar->synchro.current_pts - p_vpar->synchro.backward_pts
+                    > PTS_THRESHOLD )
+            {
+                intf_WarnMsg( 2,
+                   "vpar synchro warning: backward_pts != current_pts (%lld)",
+                   p_vpar->synchro.current_pts - p_vpar->synchro.backward_pts );
+            }
+            p_vpar->synchro.current_pts = p_vpar->synchro.backward_pts;
+            p_vpar->synchro.backward_pts = 0;
+        }
+        else if( p_vpar->sequence.next_dts )
+        {
+            if( p_vpar->sequence.next_dts - p_vpar->synchro.current_pts
+                    > PTS_THRESHOLD
+                 || p_vpar->synchro.current_pts - p_vpar->sequence.next_dts
+                    > PTS_THRESHOLD )
+            {
+                intf_WarnMsg( 2,
+                        "vpar synchro warning: dts != current_pts (%lld)",
+                        p_vpar->synchro.current_pts
+                            - p_vpar->sequence.next_dts );
+            }
+            /* By definition of a DTS. */
+            p_vpar->synchro.current_pts = p_vpar->sequence.next_dts;
+            p_vpar->sequence.next_dts = 0;
+        }
+
+        if( p_vpar->sequence.next_pts )
+        {
+            /* Store the PTS for the next time we have to date an I picture. */
+            p_vpar->synchro.backward_pts = p_vpar->sequence.next_pts;
+            p_vpar->sequence.next_pts = 0;
+        }
+    }
+#undef PTS_THRESHOLD
+
+#ifdef STATS
+    p_vpar->synchro.i_pic++;
+#endif
+}
+
 /*****************************************************************************
  * SynchroType: Get the user's synchro type
  *****************************************************************************
@@ -484,84 +613,3 @@ static int SynchroType( void )
     return VPAR_SYNCHRO_DEFAULT;
 }
 
-/*****************************************************************************
- * SynchroNewPicture: Update stream structure and PTS
- *****************************************************************************/
-static void SynchroNewPicture( vpar_thread_t * p_vpar, int i_coding_type )
-{
-    pes_packet_t * p_pes;
-
-    switch( i_coding_type )
-    {
-    case I_CODING_TYPE:
-        p_vpar->synchro.i_eta_p = p_vpar->synchro.i_eta_b = 0;
-#ifdef STATS
-        if( p_vpar->synchro.i_type == VPAR_SYNCHRO_DEFAULT )
-        {
-            intf_Msg( "vpar synchro stats: I(%lld) P(%lld)[%d] B(%lld)[%d] YUV(%lld) : %d/%d\n",
-                  p_vpar->synchro.p_tau[I_CODING_TYPE],
-                  p_vpar->synchro.p_tau[P_CODING_TYPE],
-                  p_vpar->synchro.i_n_p,
-                  p_vpar->synchro.p_tau[B_CODING_TYPE],
-                  p_vpar->synchro.i_n_b,
-                  p_vpar->p_vout->render_time,
-                  1 + p_vpar->synchro.i_n_p * (1 + p_vpar->synchro.i_n_b) -
-                  p_vpar->synchro.i_trashed_pic,
-                  1 + p_vpar->synchro.i_n_p * (1 + p_vpar->synchro.i_n_b) );
-            p_vpar->synchro.i_trashed_pic = 0;
-        }
-#endif
-        break;
-    case P_CODING_TYPE:
-        p_vpar->synchro.i_eta_b = 0;
-        p_vpar->synchro.i_eta_p++;
-        break;
-    case B_CODING_TYPE:
-        p_vpar->synchro.i_eta_b++;
-        break;
-    }
-
-    p_pes = DECODER_FIFO_START( *p_vpar->bit_stream.p_decoder_fifo );
-
-    if( i_coding_type == B_CODING_TYPE )
-    {
-        if( p_pes->b_has_pts )
-        {
-            if( p_pes->i_pts < p_vpar->synchro.current_pts )
-            {
-                intf_WarnMsg( 2,
-                        "vpar synchro warning: pts_date < current_date\n" );
-            }
-            p_vpar->synchro.current_pts = p_pes->i_pts;
-            p_pes->b_has_pts = 0;
-        }
-        else
-        {
-            p_vpar->synchro.current_pts += 1000000 / (p_vpar->sequence.i_frame_rate) * 1001;
-        }
-    }
-    else
-    {
-        if( p_vpar->synchro.backward_pts == 0 )
-        {
-            p_vpar->synchro.current_pts += 1000000 / (p_vpar->sequence.i_frame_rate) * 1001;
-        }
-        else
-        {
-            if( p_vpar->synchro.backward_pts < p_vpar->synchro.current_pts )
-            {
-                intf_WarnMsg( 2,
-                        "vpar warning: backward_date < current_date\n" );
-            }
-            p_vpar->synchro.current_pts = p_vpar->synchro.backward_pts;
-            p_vpar->synchro.backward_pts = 0;
-        }
-
-        if( p_pes->b_has_pts )
-        {
-            /* Store the PTS for the next time we have to date an I picture. */
-            p_vpar->synchro.backward_pts = p_pes->i_pts;
-            p_pes->b_has_pts = 0;
-        }
-    }
-}