* 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>
* 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"
/* 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
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;
+ 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 )
{
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:
}
}
+#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"),
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) )
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
}
/*****************************************************************************
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
}
/*****************************************************************************
* 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;
}
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;
}
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
}
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 &&
{
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
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++;