]> git.sesse.net Git - vlc/blobdiff - src/video_parser/vpar_synchro.c
* libdvdcss enhancements by Billy Biggs <vektor@dumbterm.net>. This breaks
[vlc] / src / video_parser / vpar_synchro.c
index 47dc95efe2e790ed6fcb1a73cd6550be4748ffbc..4633896c154cdbae96af1846da780befd3f0cb39 100644 (file)
@@ -2,7 +2,7 @@
  * vpar_synchro.c : frame dropping routines
  *****************************************************************************
  * Copyright (C) 1999, 2000 VideoLAN
- * $Id: vpar_synchro.c,v 1.72 2001/01/15 13:25:09 massiot Exp $
+ * $Id: vpar_synchro.c,v 1.91 2001/07/11 02:01:05 sam Exp $
  *
  * Authors: Christophe Massiot <massiot@via.ecp.fr>
  *          Samuel Hocevar <sam@via.ecp.fr>
@@ -41,8 +41,6 @@
  * 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.
  *****************************************************************************/
 #include "defs.h"
 
+#include <string.h>                                    /* memcpy(), memset() */
+
 #include "config.h"
 #include "common.h"
 #include "threads.h"
 #include "mtime.h"
-#include "plugins.h"
 
 #include "intf_msg.h"
 
 #include "video_output.h"
 
 #include "video_decoder.h"
-#include "../video_decoder/vdec_idct.h"
-#include "../video_decoder/vdec_motion.h"
+#include "vdec_motion.h"
 
-#include "../video_decoder/vpar_blocks.h"
-#include "../video_decoder/vpar_headers.h"
-#include "../video_decoder/vpar_synchro.h"
-#include "../video_decoder/video_parser.h"
+#include "vpar_blocks.h"
+#include "vpar_headers.h"
+#include "vpar_synchro.h"
+#include "video_parser.h"
 
 #include "main.h"
 
@@ -130,7 +128,6 @@ static int  SynchroType( void );
 
 /* Error margins */
 #define DELTA                   (int)(0.040*CLOCK_FREQ)
-#define PTS_THRESHOLD           (int)(0.030*CLOCK_FREQ)
 
 #define DEFAULT_NB_P            5
 #define DEFAULT_NB_B            1
@@ -152,6 +149,7 @@ 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;
@@ -222,20 +220,23 @@ boolean_t vpar_SynchroChoose( vpar_thread_t * p_vpar, int i_coding_type,
                                             + tau_yuv)
 #define S                           p_vpar->synchro
         /* VPAR_SYNCHRO_DEFAULT */
-        mtime_t         now, pts, period, tau_yuv;
+        mtime_t         now, period, tau_yuv;
+        mtime_t         pts = 0;
         boolean_t       b_decode = 0;
-#ifdef DEBUG_VPAR
+#ifdef TRACE_VPAR
         char            p_date[MSTRTIME_MAX_SIZE];
 #endif
 
         now = mdate();
-        period = 1000000 / (p_vpar->sequence.i_frame_rate) * 1001;
+        period = 1000000 * 1001 / p_vpar->sequence.i_frame_rate
+                    * p_vpar->sequence.i_current_rate / DEFAULT_RATE;
 
         vlc_mutex_lock( &p_vpar->p_vout->change_lock );
         tau_yuv = p_vpar->p_vout->render_time;
         vlc_mutex_unlock( &p_vpar->p_vout->change_lock );
-
+#ifdef VDEC_SMP
         vlc_mutex_lock( &p_vpar->synchro.fifo_lock );
+#endif
 
         switch( i_coding_type )
         {
@@ -264,7 +265,8 @@ 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" );
+                intf_WarnMsg( 1, "vpar synchro warning: trashing I (%lld)",
+                             pts - now);
             break;
 
         case P_CODING_TYPE:
@@ -315,8 +317,10 @@ boolean_t vpar_SynchroChoose( vpar_thread_t * p_vpar, int i_coding_type,
             }
         }
 
+#ifdef VDEC_SMP
         vlc_mutex_unlock( &p_vpar->synchro.fifo_lock );
-#ifdef DEBUG_VPAR
+#endif
+#ifdef TRACE_VPAR
         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"),
@@ -352,7 +356,9 @@ void vpar_SynchroTrash( vpar_thread_t * p_vpar, int i_coding_type,
 void vpar_SynchroDecode( vpar_thread_t * p_vpar, int i_coding_type,
                          int i_structure )
 {
+#ifdef VDEC_SMP
     vlc_mutex_lock( &p_vpar->synchro.fifo_lock );
+#endif
 
     if( ((p_vpar->synchro.i_end + 1 - p_vpar->synchro.i_start)
             % MAX_DECODING_PIC) )
@@ -365,9 +371,12 @@ 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");
+        intf_ErrMsg("vpar error: synchro fifo full, estimations will be biased (%d:%d)",
+                    p_vpar->synchro.i_start, p_vpar->synchro.i_end);
     }
+#ifdef VDEC_SMP
     vlc_mutex_unlock( &p_vpar->synchro.fifo_lock );
+#endif
 }
 
 /*****************************************************************************
@@ -378,32 +387,50 @@ void vpar_SynchroEnd( vpar_thread_t * p_vpar, int i_garbage )
     mtime_t     tau;
     int         i_coding_type;
 
+#ifdef VDEC_SMP
     vlc_mutex_lock( &p_vpar->synchro.fifo_lock );
+#endif
+
+    i_coding_type = p_vpar->synchro.pi_coding_types[p_vpar->synchro.i_start];
 
-    if (!i_garbage)
+    if( !i_garbage )
     {
         tau = mdate() - p_vpar->synchro.p_date_fifo[p_vpar->synchro.i_start];
-        i_coding_type = p_vpar->synchro.pi_coding_types[p_vpar->synchro.i_start];
-
-        /* Mean with average tau, to ensure stability. */
-        p_vpar->synchro.p_tau[i_coding_type] =
-            (p_vpar->synchro.pi_meaningful[i_coding_type]
-             * p_vpar->synchro.p_tau[i_coding_type] + tau)
-            / (p_vpar->synchro.pi_meaningful[i_coding_type] + 1);
-        if( p_vpar->synchro.pi_meaningful[i_coding_type] < MAX_PIC_AVERAGE )
+
+        /* If duration too high, something happened (pause ?), so don't
+         * take it into account. */
+        if( tau < 3 * p_vpar->synchro.p_tau[i_coding_type]
+             || !p_vpar->synchro.pi_meaningful[i_coding_type] )
         {
-            p_vpar->synchro.pi_meaningful[i_coding_type]++;
+            /* Mean with average tau, to ensure stability. */
+            p_vpar->synchro.p_tau[i_coding_type] =
+                (p_vpar->synchro.pi_meaningful[i_coding_type]
+                 * p_vpar->synchro.p_tau[i_coding_type] + tau)
+                / (p_vpar->synchro.pi_meaningful[i_coding_type] + 1);
+            if( p_vpar->synchro.pi_meaningful[i_coding_type] < MAX_PIC_AVERAGE )
+            {
+                p_vpar->synchro.pi_meaningful[i_coding_type]++;
+            }
         }
-#ifdef DEBUG_VPAR
+
+#ifdef TRACE_VPAR
         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
     }
+    else
+    {
+        intf_DbgMsg("vpar synchro debug: aborting %s",
+                    i_coding_type == B_CODING_TYPE ? "B" :
+                    (i_coding_type == P_CODING_TYPE ? "P" : "I"));
+    }
 
     FIFO_INCREMENT( i_start );
 
+#ifdef VDEC_SMP
     vlc_mutex_unlock( &p_vpar->synchro.fifo_lock );
+#endif
 }
 
 /*****************************************************************************
@@ -419,17 +446,22 @@ mtime_t vpar_SynchroDate( vpar_thread_t * p_vpar )
  * vpar_SynchroNewPicture: Update stream structure and PTS
  *****************************************************************************/
 void vpar_SynchroNewPicture( vpar_thread_t * p_vpar, int i_coding_type,
-                             boolean_t b_repeat_field )
+                             int i_repeat_field )
 {
-    mtime_t         period = 1000000 / (p_vpar->sequence.i_frame_rate) * 1001;
+    mtime_t         period = 1000000 * 1001 / p_vpar->sequence.i_frame_rate
+                              * p_vpar->sequence.i_current_rate / DEFAULT_RATE;
+#if 0
+    mtime_t         now = mdate(); 
+#endif
 
     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 )
+             && p_vpar->synchro.i_eta_p != p_vpar->synchro.i_n_p )
         {
-            intf_WarnMsg( 1, "Stream periodicity changed from P[%d] to P[%d]",
+            intf_WarnMsg( 3, "vpar info: 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;
         }
@@ -456,9 +488,10 @@ void vpar_SynchroNewPicture( vpar_thread_t * p_vpar, int i_coding_type,
     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 )
+             && p_vpar->synchro.i_eta_b != p_vpar->synchro.i_n_b )
         {
-            intf_WarnMsg( 1, "Stream periodicity changed from B[%d] to B[%d]",
+            intf_WarnMsg( 3, "vpar info: 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;
         }
@@ -469,20 +502,17 @@ void vpar_SynchroNewPicture( vpar_thread_t * p_vpar, int i_coding_type,
         break;
     }
 
-    if( b_repeat_field )
-    {
-        /* MPEG-2 repeat_first_field */
-        /* FIXME : this is not exactly what we should do, repeat_first_field
-         * only regards the next picture */
-        p_vpar->synchro.current_pts += period + (period >> 1);
-    }
-    else
-    {
-        p_vpar->synchro.current_pts += period;
-    }
-
+    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
@@ -501,6 +531,9 @@ void vpar_SynchroNewPicture( vpar_thread_t * p_vpar, int i_coding_type,
     }
     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 && 
@@ -511,10 +544,9 @@ void vpar_SynchroNewPicture( vpar_thread_t * p_vpar, int i_coding_type,
             {
                 intf_WarnMsg( 2,
                         "vpar synchro warning: backward_pts != dts (%lld)",
-                        p_vpar->synchro.backward_pts
-                            - p_vpar->sequence.next_dts );
+                        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
@@ -551,6 +583,25 @@ void vpar_SynchroNewPicture( vpar_thread_t * p_vpar, int i_coding_type,
             p_vpar->sequence.next_pts = 0;
         }
     }
+#undef PTS_THRESHOLD
+
+#if 0
+    /* Removed for incompatibility with slow motion */
+    if( p_vpar->synchro.current_pts + DEFAULT_PTS_DELAY < now )
+    {
+        /* We cannot be _that_ late, something must have happened, reinit
+         * the dates. */
+        intf_WarnMsg( 2, "PTS << now (%lld), resetting",
+                      now - p_vpar->synchro.current_pts - DEFAULT_PTS_DELAY );
+        p_vpar->synchro.current_pts = now + DEFAULT_PTS_DELAY;
+    }
+    if( p_vpar->synchro.backward_pts
+         && p_vpar->synchro.backward_pts + DEFAULT_PTS_DELAY < now )
+    {
+        /* The same. */
+        p_vpar->synchro.backward_pts = 0;
+    }
+#endif
 
 #ifdef STATS
     p_vpar->synchro.i_pic++;