Commit bad6f235 authored by Christophe Massiot's avatar Christophe Massiot

* Totally new frame dropping algorithm.

  * Fixed a bug in video_ouput.c which made the stream go backwards
    sometimes.
  * Fixed a bug in video_ouput.c which trashed more late pictures than
    necessary.
  * Fixed the DEBUG mode in the Makefile.
  * Fixed a bug in mwait() which made us wait too long.

Ca va tuer.
parent 7e4135b3
......@@ -8,6 +8,13 @@
mode.
* Added --broadcast option for network input.
* Screen is now emptied when framebuffer output exits.
* Totally new frame dropping algorithm.
* Fixed a bug in video_ouput.c which made the stream go backwards
sometimes.
* Fixed a bug in video_ouput.c which trashed more late pictures than
necessary.
* Fixed the DEBUG mode in the Makefile.
* Fixed a bug in mwait() which made us wait too long.
Mon, 28 Aug 2000 02:34:18 +0200
0.1.99i :
......
......@@ -106,10 +106,6 @@ endif
else
CFLAGS += -march=pentium
endif
# Eventual MMX optimizations for x86
ifneq (,$(findstring mmx,$(ARCH)))
CFLAGS += -DHAVE_MMX
endif
endif
# Optimizations for PowerPC
......@@ -127,9 +123,16 @@ ifneq (,$(findstring sparc,$(ARCH)))
CFLAGS += -mhard-float
endif
# End of optimizations
# /debug
endif
# Eventual MMX optimizations for x86
ifneq (,$(findstring mmx,$(ARCH)))
CFLAGS += -DHAVE_MMX
endif
# End of optimizations
#
# C compiler flags: dependancies
#
......
......@@ -343,6 +343,9 @@
/* Number of pictures required to computes the FPS rate */
#define VOUT_FPS_SAMPLES 20
/* Better be in advance when awakening than late... */
#define VOUT_MWAIT_TOLERANCE ((int)(0.020*CLOCK_FREQ))
/*
* Framebuffer settings
*/
......@@ -361,7 +364,7 @@
* It should be approximately the time needed to perform a complete picture
* loop. Since it only happens when the video heap is full, it does not need
* to be too low, even if it blocks the decoder. */
#define VPAR_OUTMEM_SLEEP ((int)(0.050*CLOCK_FREQ))
#define VPAR_OUTMEM_SLEEP ((int)(0.020*CLOCK_FREQ))
/* Optimization level, from 0 to 2 - 1 is generally a good compromise. Remember
* that raising this level dramatically lengthens the compilation time. */
......@@ -438,11 +441,3 @@
/* Maximal number of commands which can be saved in history list */
#define INTF_CONSOLE_MAX_HISTORY 20
/*****************************************************************************
* Synchro configuration
*****************************************************************************/
#define VOUT_SYNCHRO_LEVEL_START 5 << 10
#define VOUT_SYNCHRO_LEVEL_MAX 15 << 10
#define VOUT_SYNCHRO_HEAP_IDEAL_SIZE 5
......@@ -135,7 +135,7 @@ typedef struct vout_thread_s
p_vout_sys_t p_sys; /* system output method */
vdec_DecodeMacroblock_t *
vdec_DecodeMacroblock; /* decoder function to use */
/* Current display properties */
u16 i_changes; /* changes made to the thread */
int i_width; /* current output method width */
......@@ -181,6 +181,7 @@ typedef struct vout_thread_s
boolean_t b_info; /* print additional information */
boolean_t b_interface; /* render interface */
boolean_t b_scale; /* allow picture scaling */
mtime_t render_time; /* last picture render time */
/* Idle screens management */
mtime_t last_display_date; /* last non idle display date */
......@@ -190,7 +191,6 @@ typedef struct vout_thread_s
#ifdef STATS
/* Statistics - these numbers are not supposed to be accurate, but are a
* good indication of the thread status */
mtime_t render_time; /* last picture render time */
count_t c_fps_samples; /* picture counts */
mtime_t p_fps_sample[VOUT_FPS_SAMPLES]; /* FPS samples dates */
#endif
......@@ -208,10 +208,6 @@ typedef struct vout_thread_s
/* Bitmap fonts */
p_vout_font_t p_default_font; /* default font */
p_vout_font_t p_large_font; /* large font */
/* Synchronization informations - synchro level is updated by the vout
* thread and read by decoder threads */
int i_synchro_level; /* trashing level */
} vout_thread_t;
/* Flags for changes - these flags are set in the i_changes field when another
......@@ -224,7 +220,9 @@ typedef struct vout_thread_s
#define VOUT_DEPTH_CHANGE 0x0400 /* depth changed */
#define VOUT_GAMMA_CHANGE 0x0010 /* gamma changed */
#define VOUT_YUV_CHANGE 0x0800 /* change yuv tables */
#define VOUT_NODISPLAY_CHANGE 0xff00 /* changes which forbidden display */
/* Disabled for thread deadlocks issues --Meuuh */
//#define VOUT_NODISPLAY_CHANGE 0xff00 /* changes which forbidden display */
/*****************************************************************************
* Macros
......
......@@ -3,9 +3,7 @@
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
*
* Authors: Samuel Hocevar <sam@via.ecp.fr>
* Jean-Marc Dressler <polux@via.ecp.fr>
* Christophe Massiot <massiot@via.ecp.fr>
* Author: Christophe Massiot <massiot@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -35,102 +33,58 @@
* "video_fifo.h"
*****************************************************************************/
#define SAM_SYNCHRO
//#define POLUX_SYNCHRO
//#define MEUUH_SYNCHRO
/*****************************************************************************
* video_synchro_t and video_synchro_tab_s : timers for the video synchro
*****************************************************************************/
#ifdef SAM_SYNCHRO
#define MAX_DECODING_PIC 16
#define MAX_PIC_AVERAGE 8
/* Read the discussion on top of vpar_synchro.c for more information. */
typedef struct video_synchro_s
{
/* synchro algorithm */
int i_type;
int i_type;
/* fifo containing decoding dates */
mtime_t i_date_fifo[16];
unsigned int i_start;
unsigned int i_stop;
/* mean decoding time */
mtime_t i_delay;
mtime_t i_theorical_delay;
/* dates */
mtime_t i_last_pts; /* pts of the last displayed image */
mtime_t i_last_seen_I_pts; /* date of the last I we decoded */
mtime_t i_last_kept_I_pts; /* pts of last non-dropped I image */
/* P images since the last I */
unsigned int i_P_seen;
unsigned int i_P_kept;
/* B images since the last I */
unsigned int i_B_seen;
unsigned int i_B_kept;
/* can we display pictures ? */
boolean_t b_all_I;
boolean_t b_all_P;
int displayable_p;
boolean_t b_all_B;
int displayable_b;
boolean_t b_dropped_last;
} video_synchro_t;
#define FIFO_INCREMENT( i_counter ) \
p_vpar->synchro.i_counter = (p_vpar->synchro.i_counter + 1) & 0xf;
#define VPAR_SYNCHRO_DEFAULT 0
#define VPAR_SYNCHRO_I 1
#define VPAR_SYNCHRO_Iplus 2
#define VPAR_SYNCHRO_IP 3
#define VPAR_SYNCHRO_IPplus 4
#define VPAR_SYNCHRO_IPB 5
mtime_t p_date_fifo[MAX_DECODING_PIC];
int pi_coding_types[MAX_DECODING_PIC];
unsigned int i_start, i_end;
vlc_mutex_t fifo_lock;
/* stream properties */
unsigned int i_n_p, i_n_b;
/* decoding values */
mtime_t p_tau[4]; /* average decoding durations */
unsigned int pi_meaningful[4]; /* number of durations read */
/* and p_vout->render_time (read with p_vout->change_lock) */
/* stream context */
unsigned int i_eta_p, i_eta_b;
boolean_t b_dropped_last; /* for special synchros below */
mtime_t backward_pts, current_pts;
#ifdef STATS
unsigned int i_B_self, i_B_next, i_B_last, i_B_I;
#endif
#ifdef MEUUH_SYNCHRO
typedef struct video_synchro_s
{
int kludge_level, kludge_p, kludge_b, kludge_nbp, kludge_nbb;
int kludge_nbframes;
mtime_t kludge_date, kludge_prevdate;
int i_coding_type;
} video_synchro_t;
#define SYNC_TOLERATE ((int)(0.010*CLOCK_FREQ)) /* 10 ms */
#define SYNC_DELAY ((int)(0.500*CLOCK_FREQ)) /* 500 ms */
#endif
#ifdef POLUX_SYNCHRO
#define SYNC_AVERAGE_COUNT 10
typedef struct video_synchro_s
{
/* Date Section */
/* Dates needed to compute the date of the current frame
* We also use the stream frame rate (sequence.i_frame_rate) */
mtime_t i_current_frame_date;
mtime_t i_backward_frame_date;
#define FIFO_INCREMENT( i_counter ) \
p_vpar->synchro.i_counter = \
(p_vpar->synchro.i_counter + 1) % MAX_DECODING_PIC;
/* Frame Trashing Section */
int i_b_nb, i_p_nb; /* number of decoded P and B between two I */
float r_b_average, r_p_average;
int i_b_count, i_p_count, i_i_count;
int i_b_trasher; /* used for brensenham algorithm */
} video_synchro_t;
#endif
/* Synchro algorithms */
#define VPAR_SYNCHRO_DEFAULT 0
#define VPAR_SYNCHRO_I 1
#define VPAR_SYNCHRO_Iplus 2
#define VPAR_SYNCHRO_IP 3
#define VPAR_SYNCHRO_IPplus 4
#define VPAR_SYNCHRO_IPB 5
/*****************************************************************************
* Prototypes
*****************************************************************************/
void vpar_SynchroInit ( struct vpar_thread_s * p_vpar );
boolean_t vpar_SynchroChoose ( struct vpar_thread_s * p_vpar,
int i_coding_type, int i_structure );
void vpar_SynchroTrash ( struct vpar_thread_s * p_vpar,
......@@ -139,7 +93,3 @@ void vpar_SynchroDecode ( struct vpar_thread_s * p_vpar,
int i_coding_type, int i_structure );
void vpar_SynchroEnd ( struct vpar_thread_s * p_vpar );
mtime_t vpar_SynchroDate ( struct vpar_thread_s * p_vpar );
#ifndef SAM_SYNCHRO
void vpar_SynchroKludge ( struct vpar_thread_s *, mtime_t );
#endif
......@@ -118,7 +118,9 @@ void mwait( mtime_t date )
gettimeofday( &tv_date, NULL );
/* calculate delay and check if current date is before wished date */
delay = date - (mtime_t) tv_date.tv_sec * 1000000 - (mtime_t) tv_date.tv_usec;
delay = date - (mtime_t) tv_date.tv_sec * 1000000 - (mtime_t) tv_date.tv_usec - 10000;
/* Linux/i386 has a granularity of 10 ms. It's better to be in advance
* than to be late. */
if( delay <= 0 ) /* wished date is now or already passed */
{
return;
......
......@@ -74,7 +74,6 @@ static void RenderInterface ( vout_thread_t *p_vout );
static int RenderIdle ( vout_thread_t *p_vout );
static int RenderSplash ( vout_thread_t *p_vout );
static void RenderInfo ( vout_thread_t *p_vout );
static void Synchronize ( vout_thread_t *p_vout, s64 i_delay );
static int Manage ( vout_thread_t *p_vout );
static int Align ( vout_thread_t *p_vout, int *pi_x,
int *pi_y, int i_width, int i_height,
......@@ -175,10 +174,10 @@ vout_thread_t * vout_CreateThread ( char *psz_display, int i_root_window,
p_vout->last_display_date = 0;
p_vout->last_idle_date = 0;
p_vout->init_display_date = mdate();
p_vout->render_time = 10000;
#ifdef STATS
/* Initialize statistics fields */
p_vout->render_time = 0;
p_vout->c_fps_samples = 0;
#endif
......@@ -199,9 +198,6 @@ vout_thread_t * vout_CreateThread ( char *psz_display, int i_root_window,
}
p_vout->i_pictures = 0;
/* Initialize synchronization information */
p_vout->i_synchro_level = VOUT_SYNCHRO_LEVEL_START;
/* Create and initialize system-dependant method - this function issues its
* own error messages */
if( p_vout->p_sys_create( p_vout, psz_display, i_root_window, p_data ) )
......@@ -950,10 +946,6 @@ static int InitThread( vout_thread_t *p_vout )
*****************************************************************************/
static void RunThread( vout_thread_t *p_vout)
{
/* XXX?? welcome to gore land */
static int i_trash_count = 0;
static mtime_t last_display_date = 0;
int i_index; /* index in heap */
mtime_t current_date; /* current date */
mtime_t display_date; /* display date */
......@@ -1005,12 +997,7 @@ static void RunThread( vout_thread_t *p_vout)
/* Computes FPS rate */
p_vout->p_fps_sample[ p_vout->c_fps_samples++ % VOUT_FPS_SAMPLES ] = display_date;
#endif
/* XXX?? */
i_trash_count++;
//fprintf( stderr, "gap : %Ld\n", display_date-last_display_date );
last_display_date = display_date;
#if 1
if( display_date < current_date && i_trash_count > 4 )
if( display_date < current_date )
{
/* Picture is late: it will be destroyed and the thread
* will sleep and go to next picture */
......@@ -1025,20 +1012,12 @@ last_display_date = display_date;
p_pic->i_status = DESTROYED_PICTURE;
p_vout->i_pictures--;
}
intf_DbgMsg( "warning: late picture %p skipped refcount=%d\n", p_pic, p_pic->i_refcount );
intf_ErrMsg( "warning: late picture skipped (%p)\n", p_pic );
vlc_mutex_unlock( &p_vout->picture_lock );
/* Update synchronization information as if display delay
* was 0 */
Synchronize( p_vout, display_date - current_date );
p_pic = NULL;
display_date = 0;
i_trash_count = 0;
continue;
}
else
#endif
if( display_date > current_date + VOUT_DISPLAY_DELAY )
else if( display_date > current_date + VOUT_DISPLAY_DELAY )
{
/* A picture is ready to be rendered, but its rendering date
* is far from the current one so the thread will perform an
......@@ -1047,12 +1026,6 @@ last_display_date = display_date;
p_pic = NULL;
display_date = 0;
}
else
{
/* Picture will be displayed, update synchronization
* information */
Synchronize( p_vout, display_date - current_date );
}
}
/*
* Find the subpictures to display - this operation does not need
......@@ -1070,11 +1043,9 @@ last_display_date = display_date;
}
}
/*
* Perform rendering, sleep and display rendered picture
*/
if( p_pic ) /* picture and perhaps subpicture */
{
b_display = p_vout->b_active;
......@@ -1173,18 +1144,28 @@ last_display_date = display_date;
* Sleep, wake up and display rendered picture
*/
#ifdef STATS
/* Store render time */
p_vout->render_time = mdate() - current_date;
#endif
if( display_date != 0 )
{
/* Store render time */
p_vout->render_time += mdate() - current_date;
p_vout->render_time >>= 1;
}
/* Give back change lock */
vlc_mutex_unlock( &p_vout->change_lock );
#ifdef DEBUG_VIDEO
{
char psz_date[MSTRTIME_MAX_SIZE];
intf_DbgMsg( "picture %p waiting until %s\n", p_pic,
mstrtime(psz_date, display_date),
}
#endif
/* Sleep a while or until a given date */
if( display_date != 0 )
{
mwait( display_date );
mwait( display_date - VOUT_MWAIT_TOLERANCE );
}
else
{
......@@ -1196,9 +1177,9 @@ last_display_date = display_date;
vlc_mutex_lock( &p_vout->change_lock );
#ifdef DEBUG_VIDEO
intf_DbgMsg( "picture %p, subpicture %p in buffer %d, display=%d\n", p_pic, p_subpic,
p_vout->i_buffer_index, b_display && !(p_vout->i_changes & VOUT_NODISPLAY_CHANGE) );
p_vout->i_buffer_index, b_display /* && !(p_vout->i_changes & VOUT_NODISPLAY_CHANGE) */ );
#endif
if( b_display && !(p_vout->i_changes & VOUT_NODISPLAY_CHANGE) )
if( b_display /* && !(p_vout->i_changes & VOUT_NODISPLAY_CHANGE) */ )
{
p_vout->p_sys_display( p_vout );
#ifndef SYS_BEOS
......@@ -2017,81 +1998,6 @@ static void RenderInterface( vout_thread_t *p_vout )
SetBufferArea( p_vout, 0, p_vout->i_height - i_height, p_vout->i_width, i_height );
}
/*****************************************************************************
* Synchronize: update synchro level depending of heap state
*****************************************************************************
* This function is called during the main vout loop.
*****************************************************************************/
static void Synchronize( vout_thread_t *p_vout, s64 i_delay )
{
int i_synchro_inc = 0;
/* XXX?? gore following */
static int i_panic_count = 0;
static int i_last_synchro_inc = 0;
static int i_synchro_level = VOUT_SYNCHRO_LEVEL_START;
static int i_truc = 10;
if( i_delay < 0 )
{
//fprintf( stderr, "PANIC %d\n", i_panic_count );
i_panic_count++;
}
i_truc *= 2;
if( p_vout->i_pictures > VOUT_SYNCHRO_HEAP_IDEAL_SIZE+1 )
{
i_truc = 40;
i_synchro_inc += p_vout->i_pictures - VOUT_SYNCHRO_HEAP_IDEAL_SIZE - 1;
}
else
{
if( p_vout->i_pictures < VOUT_SYNCHRO_HEAP_IDEAL_SIZE )
{
i_truc = 32;
i_synchro_inc += p_vout->i_pictures - VOUT_SYNCHRO_HEAP_IDEAL_SIZE;
}
}
if( i_truc > VOUT_SYNCHRO_LEVEL_MAX >> 5 ||
i_synchro_inc*i_last_synchro_inc < 0 )
{
i_truc = 32;
}
if( i_delay < 6000 )
{
i_truc = 16;
i_synchro_inc -= 2;
}
else if( i_delay < 70000 )
{
i_truc = 24+(24*i_delay)/70000;
if( i_truc < 16 )
i_truc = 16;
i_synchro_inc -= 1+(5*(70000-i_delay))/70000;
}
else if( i_delay > 100000 )
{
i_synchro_level += 1 << 10;
if( i_delay > 130000 )
i_synchro_level += 1 << 10;
}
i_synchro_level += ( i_synchro_inc << 10 ) / i_truc;
p_vout->i_synchro_level = ( i_synchro_level + (1 << 9) );
if( i_synchro_level > VOUT_SYNCHRO_LEVEL_MAX )
{
i_synchro_level = VOUT_SYNCHRO_LEVEL_MAX;
}
//fprintf( stderr, "synchro level : %d, heap : %d (%d, %d) (%d, %f) - %Ld\n", p_vout->i_synchro_level,
// p_vout->i_pictures, i_last_synchro_inc, i_synchro_inc, i_truc, r_synchro_level, i_delay );
i_last_synchro_inc = i_synchro_inc;
}
/*****************************************************************************
* Manage: manage thread
*****************************************************************************
......@@ -2103,7 +2009,7 @@ static int Manage( vout_thread_t *p_vout )
if( p_vout->i_changes )
{
intf_DbgMsg("changes: 0x%x (no display: 0x%x)\n", p_vout->i_changes,
p_vout->i_changes & VOUT_NODISPLAY_CHANGE );
0 /* p_vout->i_changes & VOUT_NODISPLAY_CHANGE */ );
}
#endif
......
......@@ -66,7 +66,6 @@ static int InitThread ( vpar_thread_t *p_vpar );
static void RunThread ( vpar_thread_t *p_vpar );
static void ErrorThread ( vpar_thread_t *p_vpar );
static void EndThread ( vpar_thread_t *p_vpar );
static int SynchroType ( );
/*****************************************************************************
* vpar_CreateThread: create a generic parser thread
......@@ -78,7 +77,8 @@ static int SynchroType ( );
*****************************************************************************/
#include "main.h"
#include "interface.h"
extern main_t* p_main;
extern main_t * p_main;
vpar_thread_t * vpar_CreateThread( /* video_cfg_t *p_cfg, */ input_thread_t *p_input /*,
vout_thread_t *p_vout, int *pi_status */ )
{
......@@ -277,54 +277,7 @@ static int InitThread( vpar_thread_t *p_vpar )
/*
* Initialize the synchro properties
*/
#ifdef SAM_SYNCHRO
/* Get an possible synchro algorithm */
p_vpar->synchro.i_type = SynchroType();
/* last seen PTS */
p_vpar->synchro.i_last_pts = 0;
/* for i frames */
p_vpar->synchro.i_last_seen_I_pts = 0;
p_vpar->synchro.i_last_kept_I_pts = 0;
/* the fifo */
p_vpar->synchro.i_start = 0;
p_vpar->synchro.i_stop = 0;
/* mean decoding time - at least 200 ms for a slow machine */
p_vpar->synchro.i_delay = 200000;
p_vpar->synchro.i_theorical_delay = 40000; /* 25 fps */
/* assume we can display all Is and 2 Ps */
p_vpar->synchro.b_all_I = 1 << 10;
p_vpar->synchro.b_all_P = 0;
p_vpar->synchro.displayable_p = 2 << 10;
p_vpar->synchro.b_all_B = 0;
p_vpar->synchro.displayable_b = 0;
p_vpar->synchro.b_dropped_last = 0;
/* assume there were about 3 P and 6 B images between I's */
p_vpar->synchro.i_P_seen = p_vpar->synchro.i_P_kept = 1 << 10;
p_vpar->synchro.i_B_seen = p_vpar->synchro.i_B_kept = 1 << 10;
#endif
#ifdef MEUUH_SYNCHRO
p_vpar->synchro.kludge_level = 5;
p_vpar->synchro.kludge_nbp = p_vpar->synchro.kludge_p = 5;
p_vpar->synchro.kludge_nbb = p_vpar->synchro.kludge_b = 6;
p_vpar->synchro.kludge_b = 0;
p_vpar->synchro.kludge_prevdate = 0;
#endif
#ifdef POLUX_SYNCHRO
p_vpar->synchro.i_current_frame_date = 0;
p_vpar->synchro.i_backward_frame_date = 0;
p_vpar->synchro.r_p_average = p_vpar->synchro.i_p_nb = 6;
p_vpar->synchro.r_b_average = p_vpar->synchro.i_b_nb = 6;
p_vpar->synchro.i_p_count = 0;
p_vpar->synchro.i_b_count = 0;
p_vpar->synchro.i_i_count = 0;
#endif
vpar_SynchroInit( p_vpar );
/* Mark thread as running and return */
intf_DbgMsg("vpar debug: InitThread(%p) succeeded\n", p_vpar);
......@@ -476,61 +429,3 @@ static void EndThread( vpar_thread_t *p_vpar )
intf_DbgMsg("vpar debug: EndThread(%p)\n", p_vpar);
}
/*****************************************************************************
* SynchroType: Get the user's synchro type
*****************************************************************************
* This function is called at initialization.
*****************************************************************************/
static int SynchroType( )
{
char * psz_synchro = main_GetPszVariable( VPAR_SYNCHRO_VAR, NULL );
if( psz_synchro == NULL )
{
return VPAR_SYNCHRO_DEFAULT;
}
switch( *psz_synchro++ )
{
case 'i':
case 'I':
switch( *psz_synchro++ )
{
case '\0':
return VPAR_SYNCHRO_I;
case '+':
if( *psz_synchro ) return 0;
return VPAR_SYNCHRO_Iplus;
case 'p':
case 'P':
switch( *psz_synchro++ )
{
case '\0':
return VPAR_SYNCHRO_IP;
case '+':
if( *psz_synchro ) return 0;
return VPAR_SYNCHRO_IPplus;
case 'b':
case 'B':
if( *psz_synchro ) return 0;
return VPAR_SYNCHRO_IPB;
default:
return VPAR_SYNCHRO_DEFAULT;
}
default:
return VPAR_SYNCHRO_DEFAULT;
}
}
return VPAR_SYNCHRO_DEFAULT;
}
......@@ -3,9 +3,9 @@
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
*
* Authors: Samuel Hocevar <sam@via.ecp.fr>
* Jean-Marc Dressler <polu@via.ecp.fr>
* Christophe Massiot <massiot@via.ecp.fr>
* Authors: Christophe Massiot <massiot@via.ecp.fr>
* Samuel Hocevar <sam@via.ecp.fr>
* Jean-Marc Dressler <polux@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -22,6 +22,80 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
/*
* DISCUSSION : How to Write an efficient Frame-Dropping Algorithm
* ==========
*
* This implementation is based on mathematical and statistical
* developments. Older implementations used an enslavement, considering
* that if we're late when reading an I picture, we will decode one frame
* less. It had a tendancy to derive, and wasn't responsive enough, which
* would have caused trouble with the stream control stuff.
*
* 1. Structure of a picture stream
* =============================
* Between 2 I's, we have for instance :
* I B P B P B P B P B P B I
* t0 t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t11 t12
* Please bear in mind that B's and IP's will be inverted when displaying
* (decoding order != presentation order). Thus, t1 < t0.
*
* 2. Definitions
* ===========
* t[0..12] : Presentation timestamps of pictures 0..12.
* t : Current timestamp, at the moment of the decoding.
* T : Picture period, T = 1/frame_rate.
* tau[I,P,B] : Mean time to decode an [I,P,B] picture.
* tauYUV : Mean time to render a picture (given by the video_output).
* tau[I,P,B] = 2 * tau[I,P,B] + tauYUV
* : Mean time + typical difference (estimated to tau, that
* needs to be confirmed) + render time.
* DELTA : A given error margin.
*
* 3. Decoding of an I picture
* ========================
* On fast machines (ie. those who can decode all Is), we decode all I.
* Otherwise :
* We can decode an I picture if we simply have enough time to decode it
* before displaying :
* t0 - t > tauI + DELTA
*
* 4. Decoding of a P picture
* =======================
* On fast machines (ie. those who can decode all Ps), we decode all P.
* Otherwise :
* First criterion : have time to decode it.
* t2 - t > tauP + DELTA
*
* Second criterion : it shouldn't prevent us from decoding the forthcoming I
* picture, which is more important.
* t12 - t > tauP + tauI + DELTA
*
* 5. Decoding of a B picture
* =======================
* First criterion : have time to decode it.
* t1 - t > tauB + DELTA
*
* Second criterion : it shouldn't prevent us from decoding all P pictures
* until the next I, which are more important.
* t4 - t > tauB + tauP + DELTA
* [...]
* t10 - t > tauB + 4 * tauP + DELTA
* It is possible to demonstrate that if the first and the last inequations
* are verified, the inequations in between will be verified too.
*
* Third criterion : it shouldn't prevent us from decoding the forthcoming I
* picture, which is more important.
* t12 - t > tauB + 4 * tauP + tauI + DELTA
*
* If STATS is defined, the counters in p_vpar->synchro will refer to the
* number of failures of these inequations.
*
* I hope you will have a pleasant flight and do not forget your life
* jacket.
* --Meuuh (2000-11-09)
*/
/*****************************************************************************
* Preamble
*****************************************************************************/
......@@ -53,151 +127,39 @@
#include "vpar_synchro.h"
#include "video_parser.h"
#define MAX_COUNT 3
#include "main.h"
/*
* Local prototypes
*/
static int SynchroType( void );
static void SynchroNewPicture( vpar_thread_t * p_vpar, int i_coding_type );
#ifdef SAM_SYNCHRO
/* Error margins */
#define DELTA_I (int)(0.010*CLOCK_FREQ)
#define DELTA_P (int)(0.010*CLOCK_FREQ)
#define DELTA_B (int)(0.060*CLOCK_FREQ)
#define DEFAULT_NB_P 5
#define DEFAULT_NB_B 1
/*****************************************************************************
* vpar_SynchroUpdateStructures : Update the synchro structures
* vpar_SynchroInit : You know what ?
*****************************************************************************/
void vpar_SynchroUpdateStructures( vpar_thread_t * p_vpar,
int i_coding_type, boolean_t b_kept )
void vpar_SynchroInit( vpar_thread_t * p_vpar )
{
int i_can_display;
mtime_t i_pts;
pes_packet_t * p_pes = p_vpar->bit_stream.p_decoder_fifo->buffer[
p_vpar->bit_stream.p_decoder_fifo->i_start ];
/* try to guess the current DTS and PTS */
if( p_pes->b_has_pts )
{
i_pts = p_pes->i_pts;
/* if the image is I type, then the presentation timestamp is
* the PTS of the PES. Otherwise, we calculate it with the
* theorical framerate value */
if( i_coding_type == I_CODING_TYPE )
{
p_vpar->synchro.i_last_pts = p_pes->i_pts;
}
else
{
p_vpar->synchro.i_last_pts += p_vpar->synchro.i_theorical_delay;
}
p_pes->b_has_pts = 0;
}
else
{
p_vpar->synchro.i_last_pts += p_vpar->synchro.i_theorical_delay;
i_pts = p_vpar->synchro.i_last_pts;
}
/* update structures */
switch(i_coding_type)
{
case P_CODING_TYPE:
p_vpar->synchro.i_P_seen += 1024;
if( b_kept ) p_vpar->synchro.i_P_kept += 1024;
break;
case B_CODING_TYPE:
p_vpar->synchro.i_B_seen += 1024;
if( b_kept ) p_vpar->synchro.i_B_kept += 1024;
break;
case I_CODING_TYPE:
/* update the last I PTS we have, we need it to
* calculate the theorical framerate */
if (i_pts != p_vpar->synchro.i_last_seen_I_pts)
{
if ( p_vpar->synchro.i_last_seen_I_pts )
{
p_vpar->synchro.i_theorical_delay =
1024 * ( i_pts - p_vpar->synchro.i_last_seen_I_pts )
/ ( 1024 + p_vpar->synchro.i_B_seen
+ p_vpar->synchro.i_P_seen);
}
p_vpar->synchro.i_last_seen_I_pts = i_pts;
}
/* now we calculated all statistics, it's time to
* decide what we have the time to display */
i_can_display =
( (i_pts - p_vpar->synchro.i_last_kept_I_pts) << 10 )
/ p_vpar->synchro.i_delay;
p_vpar->synchro.b_all_I = 0;
p_vpar->synchro.b_all_B = 0;
p_vpar->synchro.b_all_P = 0;
p_vpar->synchro.displayable_p = 0;
p_vpar->synchro.displayable_b = 0;
if( ( p_vpar->synchro.b_all_I = ( i_can_display >= 1024 ) ) )
{
i_can_display -= 1024;
if( !( p_vpar->synchro.b_all_P
= ( i_can_display > p_vpar->synchro.i_P_seen ) ) )
{
p_vpar->synchro.displayable_p = i_can_display;
}
else
{
i_can_display -= p_vpar->synchro.i_P_seen;
if( !( p_vpar->synchro.b_all_B
= ( i_can_display > p_vpar->synchro.i_B_seen ) ) )
{
p_vpar->synchro.displayable_b = i_can_display;
}
}
}
#if 0
if( p_vpar->synchro.b_all_I )
intf_ErrMsg( " I: 1024/1024 " );
if( p_vpar->synchro.b_all_P )
intf_ErrMsg( "P: %i/%i ", p_vpar->synchro.i_P_seen,
p_vpar->synchro.i_P_seen );
else if( p_vpar->synchro.displayable_p > 0 )
intf_ErrMsg( "P: %i/%i ", p_vpar->synchro.displayable_p,
p_vpar->synchro.i_P_seen );
else
intf_ErrMsg( " " );
if( p_vpar->synchro.b_all_B )
intf_ErrMsg( "B: %i/%i", p_vpar->synchro.i_B_seen,
p_vpar->synchro.i_B_seen );
else if( p_vpar->synchro.displayable_b > 0 )
intf_ErrMsg( "B: %i/%i", p_vpar->synchro.displayable_b,
p_vpar->synchro.i_B_seen );
else
intf_ErrMsg( " " );
intf_ErrMsg( " Decoding: " );
/*intf_ErrMsg( "\n" );*/
#endif
p_vpar->synchro.i_P_seen = 0;
p_vpar->synchro.i_B_seen = 0;
/* update some values */
if( b_kept )
{
p_vpar->synchro.i_last_kept_I_pts = i_pts;
p_vpar->synchro.i_P_kept = 0;
p_vpar->synchro.i_B_kept = 0;
}
break;
}
p_vpar->synchro.i_type = SynchroType();
p_vpar->synchro.i_start = p_vpar->synchro.i_end = 0;
vlc_mutex_init( &p_vpar->synchro.fifo_lock );
/* We use a fake stream pattern, which is often right. */
p_vpar->synchro.i_n_p = p_vpar->synchro.i_eta_p = DEFAULT_NB_P;
p_vpar->synchro.i_n_b = p_vpar->synchro.i_eta_b = DEFAULT_NB_B;
memset( p_vpar->synchro.p_tau, 0, 4 * sizeof(mtime_t) );
memset( p_vpar->synchro.pi_meaningful, 0, 4 * sizeof(unsigned int) );
p_vpar->synchro.b_dropped_last = 0;
p_vpar->synchro.current_pts = mdate() + INPUT_PTS_DELAY;
p_vpar->synchro.backward_pts = 0;
}
/*****************************************************************************
......@@ -206,26 +168,22 @@ void vpar_SynchroUpdateStructures( vpar_thread_t * p_vpar,
boolean_t vpar_SynchroChoose( vpar_thread_t * p_vpar, int i_coding_type,
int i_structure )
{
mtime_t i_delay = p_vpar->synchro.i_last_pts - mdate();
/* For clarity reasons, we separated the special synchros code from the
* mathematical synchro */
switch( i_coding_type )
if( p_vpar->synchro.i_type != VPAR_SYNCHRO_DEFAULT )
{
switch( i_coding_type )
{
case I_CODING_TYPE:
if( p_vpar->synchro.i_type != VPAR_SYNCHRO_DEFAULT )
/* I, IP, IP+, IPB */
if( p_vpar->synchro.i_type == VPAR_SYNCHRO_Iplus )
{
/* I, IP, IP+, IPB */
if( p_vpar->synchro.i_type == VPAR_SYNCHRO_Iplus )
{
p_vpar->synchro.b_dropped_last = 1;
}
return( 1 );
p_vpar->synchro.b_dropped_last = 1;
}
return( p_vpar->synchro.b_all_I );
return( 1 );
case P_CODING_TYPE:
if( p_vpar->synchro.i_type == VPAR_SYNCHRO_I ) /* I */
{
return( 0 );
......@@ -244,71 +202,161 @@ boolean_t vpar_SynchroChoose( vpar_thread_t * p_vpar, int i_coding_type,
}
}
if( p_vpar->synchro.i_type >= VPAR_SYNCHRO_IP ) /* IP, IP+, IPB */
return( 1 ); /* IP, IP+, IPB */
case B_CODING_TYPE:
if( p_vpar->synchro.i_type <= VPAR_SYNCHRO_IP ) /* I, IP */
{
return( 1 );
return( 0 );
}
if( p_vpar->synchro.b_all_P )
else if( p_vpar->synchro.i_type == VPAR_SYNCHRO_IPB ) /* IPB */
{
return( 1 );
}
if( p_vpar->synchro.displayable_p * i_delay
< p_vpar->synchro.i_delay )
{
return( 0 );
}
p_vpar->synchro.b_dropped_last ^= 1; /* IP+ */
return( !p_vpar->synchro.b_dropped_last );
}
return( 0 ); /* never reached but gcc yells at me */
}
else
{
#define TAU_PRIME( coding_type ) (p_vpar->synchro.p_tau[(coding_type)] \
+ (p_vpar->synchro.p_tau[(coding_type)] >> 1) \
+ tau_yuv)
#define S p_vpar->synchro
/* VPAR_SYNCHRO_DEFAULT */
mtime_t now, pts, period, tau_yuv;
boolean_t b_decode = 0, b_decode2;
p_vpar->synchro.displayable_p -= 1024;
now = mdate();
period = 1000000 / (p_vpar->sequence.i_frame_rate) * 1001;
return( 1 );
//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 );
case B_CODING_TYPE:
vlc_mutex_lock( &p_vpar->synchro.fifo_lock );
if( p_vpar->synchro.i_type != VPAR_SYNCHRO_DEFAULT )
switch( i_coding_type )
{
case I_CODING_TYPE:
/* Stream structure changes */
S.i_n_p = S.i_eta_p || DEFAULT_NB_P;
if( S.backward_pts )
{
if( p_vpar->synchro.i_type <= VPAR_SYNCHRO_IP ) /* I, IP */
{
return( 0 );
}
else if( p_vpar->synchro.i_type == VPAR_SYNCHRO_IPB ) /* IPB */
{
return( 1 );
}
pts = S.backward_pts;
}
else
{
pts = S.current_pts + period * S.i_n_b;
}
if( p_vpar->synchro.b_dropped_last ) /* IP+ */
{
p_vpar->synchro.b_dropped_last = 0;
return( 1 );
}
b_decode = ( (1 + S.i_n_p * (S.i_n_b + 1)) * period >
S.p_tau[I_CODING_TYPE] ) ||
( (pts - now) > (TAU_PRIME(I_CODING_TYPE) + DELTA_I) );
if( !b_decode )
intf_Msg("vpar synchro: trashing I\n");
break;
p_vpar->synchro.b_dropped_last = 1;
return( 0 );
}
case P_CODING_TYPE:
/* Stream structure changes */
S.i_n_b = S.i_eta_b || DEFAULT_NB_B;
if( S.i_eta_p + 1 > S.i_n_p )
S.i_n_p++;
if( p_vpar->synchro.b_all_B )
if( S.backward_pts )
{
return( 1 );
pts = S.backward_pts;
}
if( p_vpar->synchro.displayable_b <= 0 )
else
{
return( 0 );
pts = S.current_pts + period * S.i_n_b;
}
if( i_delay < 0 )
if( (S.i_n_b + 1) * period > S.p_tau[P_CODING_TYPE] )
{
p_vpar->synchro.displayable_b -= 512;
return( 0 );
b_decode = (pts - now > 0);
}
else
{
b_decode = (pts - now) > (TAU_PRIME(P_CODING_TYPE) + DELTA_P);
/* next I */
b_decode &= (pts - now
+ period
* ( (S.i_n_p - S.i_eta_p - 1) * (1 + S.i_n_b) - 1 ))
> (TAU_PRIME(P_CODING_TYPE)
+ TAU_PRIME(I_CODING_TYPE) + DELTA_P);
}
break;
p_vpar->synchro.displayable_b -= 1024;
return( 1 );
}
case B_CODING_TYPE:
/* Stream structure changes */
if( S.i_eta_b + 1 > S.i_n_b )
S.i_n_b++;
return( 0 );
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_B);
#ifdef STATS
S.i_B_self += !b_decode;
#endif
/* Remember that S.i_eta_b is for the moment only eta_b - 1. */
if( S.i_eta_p != S.i_n_p ) /* next P */
{
b_decode2 = (pts - now
+ period
* ( 2 * S.i_n_b - S.i_eta_b - 1))
> (TAU_PRIME(B_CODING_TYPE)
+ TAU_PRIME(P_CODING_TYPE) + DELTA_B);
b_decode &= b_decode2;
#ifdef STATS
S.i_B_next += !b_decode2;
#endif
}
if( S.i_eta_p < S.i_n_p - 1 ) /* last P */
{
b_decode2 = (pts - now
+ period
* ( (S.i_n_p - S.i_eta_p) * (1 + S.i_n_b)
+ S.i_n_b - (S.i_eta_b + 1) + 1))
> (TAU_PRIME(B_CODING_TYPE)
+ (S.i_n_p - S.i_eta_p)
* TAU_PRIME(P_CODING_TYPE)
+ DELTA_B);
b_decode &= b_decode2;
#ifdef STATS
S.i_B_last += !b_decode2;
#endif
}
b_decode2 = (pts - now
+ period
* ( (S.i_n_p - S.i_eta_p + 1) * (1 + S.i_n_b)
+ S.i_n_b - (S.i_eta_b + 1) + 1 ))
> (TAU_PRIME(B_CODING_TYPE)
+ (S.i_n_p - S.i_eta_p)
* TAU_PRIME(P_CODING_TYPE)
+ TAU_PRIME(I_CODING_TYPE)
+ DELTA_B);
b_decode &= b_decode2;
#ifdef STATS
S.i_B_I += !b_decode2;
#endif
}
else
{
b_decode = 0;
}
}
vlc_mutex_unlock( &p_vpar->synchro.fifo_lock );
return( b_decode );
#undef S
#undef TAU_PRIME
}
}
/*****************************************************************************
......@@ -317,22 +365,33 @@ boolean_t vpar_SynchroChoose( vpar_thread_t * p_vpar, int i_coding_type,
void vpar_SynchroTrash( vpar_thread_t * p_vpar, int i_coding_type,
int i_structure )
{
vpar_SynchroUpdateStructures (p_vpar, i_coding_type, 0);
SynchroNewPicture( p_vpar, i_coding_type );
}
/*****************************************************************************
* vpar_SynchroDecode : Update timers when we decide to decode a picture
*****************************************************************************/
void vpar_SynchroDecode( vpar_thread_t * p_vpar, int i_coding_type,
int i_structure )
int i_structure )
{
vpar_SynchroUpdateStructures (p_vpar, i_coding_type, 1);
vlc_mutex_lock( &p_vpar->synchro.fifo_lock );
p_vpar->synchro.i_date_fifo[p_vpar->synchro.i_stop] = mdate();
if( ((p_vpar->synchro.i_end + 1 - p_vpar->synchro.i_start)
% MAX_DECODING_PIC) )
{
p_vpar->synchro.p_date_fifo[p_vpar->synchro.i_end] = mdate();
p_vpar->synchro.pi_coding_types[p_vpar->synchro.i_end] = i_coding_type;
FIFO_INCREMENT( i_stop );
FIFO_INCREMENT( i_end );
}
else
{
/* FIFO full, panic() */
intf_ErrMsg("vpar error: synchro fifo full, estimations will be biased\n");
}
vlc_mutex_unlock( &p_vpar->synchro.fifo_lock );
SynchroNewPicture( p_vpar, i_coding_type );
}
/*****************************************************************************
......@@ -340,29 +399,27 @@ void vpar_SynchroDecode( vpar_thread_t * p_vpar, int i_coding_type,
*****************************************************************************/
void vpar_SynchroEnd( vpar_thread_t * p_vpar )
{
if( p_vpar->synchro.i_stop != p_vpar->synchro.i_start )
{
mtime_t i_delay;
mtime_t tau;
int i_coding_type;
i_delay = ( mdate() -
p_vpar->synchro.i_date_fifo[p_vpar->synchro.i_start] )
/ ( (p_vpar->synchro.i_stop - p_vpar->synchro.i_start) & 0x0f );
vlc_mutex_lock( &p_vpar->synchro.fifo_lock );
p_vpar->synchro.i_delay =
( 7 * p_vpar->synchro.i_delay + i_delay ) >> 3;
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];
#if 0
intf_ErrMsg( "decode %lli (mean %lli, theorical %lli)\n",
i_delay, p_vpar->synchro.i_delay,
p_vpar->synchro.i_theorical_delay );
#endif
}
else
/* 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 )
{
intf_ErrMsg( "vpar error: critical ! fifo full\n" );
p_vpar->synchro.pi_meaningful[i_coding_type]++;
}
FIFO_INCREMENT( i_start );
vlc_mutex_unlock( &p_vpar->synchro.fifo_lock );
}
/*****************************************************************************
......@@ -370,174 +427,137 @@ void vpar_SynchroEnd( vpar_thread_t * p_vpar )
*****************************************************************************/
mtime_t vpar_SynchroDate( vpar_thread_t * p_vpar )
{
#if 0
/* No need to lock, since PTS are only used by the video parser. */
return( p_vpar->synchro.current_pts );
}
mtime_t i_displaydate = p_vpar->synchro.i_last_pts;
/*****************************************************************************
* SynchroType: Get the user's synchro type
*****************************************************************************
* This function is called at initialization.
*****************************************************************************/
static int SynchroType( void )
{
char * psz_synchro = main_GetPszVariable( VPAR_SYNCHRO_VAR, NULL );
static mtime_t i_delta = 0;
if( psz_synchro == NULL )
{
return VPAR_SYNCHRO_DEFAULT;
}
intf_ErrMsg( "displaying image with delay %lli and delta %lli\n",
i_displaydate - mdate(),
i_displaydate - i_delta );
switch( *psz_synchro++ )
{
case 'i':
case 'I':
switch( *psz_synchro++ )
{
case '\0':
return VPAR_SYNCHRO_I;
intf_ErrMsg ( "theorical fps: %f - actual fps: %f \n",
1000000.0 / p_vpar->synchro.i_theorical_delay, 1000000.0 / p_vpar->synchro.i_delay );
case '+':
if( *psz_synchro ) return 0;
return VPAR_SYNCHRO_Iplus;
i_delta = i_displaydate;
case 'p':
case 'P':
switch( *psz_synchro++ )
{
case '\0':
return VPAR_SYNCHRO_IP;
return i_displaydate;
#else
static s64 i_last_date = 0;
//printf("%d: %lld\n", p_vpar->picture.i_coding_type, p_vpar->synchro.i_last_pts - i_last_date);
//i_last_date = p_vpar->synchro.i_last_pts;
return p_vpar->synchro.i_last_pts;
case '+':
if( *psz_synchro ) return 0;
return VPAR_SYNCHRO_IPplus;
#endif
}
case 'b':
case 'B':
if( *psz_synchro ) return 0;
return VPAR_SYNCHRO_IPB;
#endif
default:
return VPAR_SYNCHRO_DEFAULT;
}
default:
return VPAR_SYNCHRO_DEFAULT;
}
}
#ifdef POLUX_SYNCHRO
return VPAR_SYNCHRO_DEFAULT;
}
void vpar_SynchroSetCurrentDate( vpar_thread_t * p_vpar, int i_coding_type )
/*****************************************************************************
* SynchroNewPicture: Update stream structure and PTS
*****************************************************************************/
static void SynchroNewPicture( vpar_thread_t * p_vpar, int i_coding_type )
{
pes_packet_t * p_pes =
p_vpar->bit_stream.p_decoder_fifo->buffer[p_vpar->bit_stream.p_decoder_fifo->i_start];
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
intf_Msg( "vpar synchro stats: I(%lld) P(%lld) B(%lld)[%d:%d:%d:%d] YUV(%lld)\n",
p_vpar->synchro.p_tau[I_CODING_TYPE],
p_vpar->synchro.p_tau[P_CODING_TYPE],
p_vpar->synchro.p_tau[B_CODING_TYPE],
p_vpar->synchro.i_B_self, p_vpar->synchro.i_B_next,
p_vpar->synchro.i_B_last, p_vpar->synchro.i_B_I,
p_vpar->p_vout->render_time );
p_vpar->synchro.i_B_self = p_vpar->synchro.i_B_next =
p_vpar->synchro.i_B_last = p_vpar->synchro.i_B_I = 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.i_current_frame_date )
if( p_pes->i_pts < p_vpar->synchro.current_pts )
{
intf_ErrMsg( "vpar warning: pts_date < current_date\n" );
intf_ErrMsg("vpar warning: pts_date < current_date\n");
}
p_vpar->synchro.i_current_frame_date = p_pes->i_pts;
p_vpar->synchro.current_pts = p_pes->i_pts;
p_pes->b_has_pts = 0;
}
else
{
p_vpar->synchro.i_current_frame_date += 1000000 / (p_vpar->sequence.i_frame_rate) * 1001;
p_vpar->synchro.current_pts += 1000000 / (p_vpar->sequence.i_frame_rate) * 1001;
}
break;
default:
if( p_vpar->synchro.i_backward_frame_date == 0 )
}
else
{
if( p_vpar->synchro.backward_pts == 0 )
{
p_vpar->synchro.i_current_frame_date += 1000000 / (p_vpar->sequence.i_frame_rate) * 1001;
p_vpar->synchro.current_pts += 1000000 / (p_vpar->sequence.i_frame_rate) * 1001;
}
else
{
if( p_vpar->synchro.i_backward_frame_date < p_vpar->synchro.i_current_frame_date )
if( p_vpar->synchro.backward_pts < p_vpar->synchro.current_pts )
{
intf_ErrMsg( "vpar warning: backward_date < current_date (%Ld)\n",
p_vpar->synchro.i_backward_frame_date - p_vpar->synchro.i_current_frame_date );
intf_ErrMsg("vpar warning: backward_date < current_date\n");
}
p_vpar->synchro.i_current_frame_date = p_vpar->synchro.i_backward_frame_date;
p_vpar->synchro.i_backward_frame_date = 0;
p_vpar->synchro.current_pts = p_vpar->synchro.backward_pts;
p_vpar->synchro.backward_pts = 0;
}
if( p_pes->b_has_pts )
{
p_vpar->synchro.i_backward_frame_date = p_pes->i_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;
}
break;
}
}
boolean_t vpar_SynchroChoose( vpar_thread_t * p_vpar, int i_coding_type,
int i_structure )
{
boolean_t b_result = 1;
int i_synchro_level = p_vpar->p_vout->i_synchro_level;
vpar_SynchroSetCurrentDate( p_vpar, i_coding_type );
/*
* The synchro level is updated by the video input (see SynchroLevelUpdate)
* so we just use the synchro_level to decide which frame to trash
*/
switch( i_coding_type )
{
case I_CODING_TYPE:
p_vpar->synchro.r_p_average =
(p_vpar->synchro.r_p_average*(SYNC_AVERAGE_COUNT-1)+p_vpar->synchro.i_p_count)/SYNC_AVERAGE_COUNT;
p_vpar->synchro.r_b_average =
(p_vpar->synchro.r_b_average*(SYNC_AVERAGE_COUNT-1)+p_vpar->synchro.i_b_count)/SYNC_AVERAGE_COUNT;
p_vpar->synchro.i_p_nb = (int)(p_vpar->synchro.r_p_average+0.5);
p_vpar->synchro.i_b_nb = (int)(p_vpar->synchro.r_b_average+0.5);
p_vpar->synchro.i_p_count = p_vpar->synchro.i_b_count = 0;
p_vpar->synchro.i_b_trasher = p_vpar->synchro.i_b_nb / 2;
p_vpar->synchro.i_i_count++;
break;
case P_CODING_TYPE:
p_vpar->synchro.i_p_count++;
if( p_vpar->synchro.i_p_count > i_synchro_level )
{
b_result = 0;
}
break;
case B_CODING_TYPE:
p_vpar->synchro.i_b_count++;
if( p_vpar->synchro.i_p_nb >= i_synchro_level )
{
/* We must trash all the B */
b_result = 0;
}
else
{
/* We use the brensenham algorithm to decide which B to trash */
p_vpar->synchro.i_b_trasher +=
p_vpar->synchro.i_b_nb - (i_synchro_level-p_vpar->synchro.i_p_nb);
if( p_vpar->synchro.i_b_trasher >= p_vpar->synchro.i_b_nb )
{
b_result = 0;
p_vpar->synchro.i_b_trasher -= p_vpar->synchro.i_b_nb;
}
}
break;
}
return( b_result );
}
void vpar_SynchroTrash( vpar_thread_t * p_vpar, int i_coding_type,
int i_structure )
{
vpar_SynchroChoose( p_vpar, i_coding_type, i_structure );
}
void vpar_SynchroUpdateLevel()
{
//vlc_mutex_lock( &level_lock );
//vlc_mutex_unlock( &level_lock );
}
mtime_t vpar_SynchroDate( vpar_thread_t * p_vpar )
{
return( p_vpar->synchro.i_current_frame_date );
}
/* functions with no use */
void vpar_SynchroEnd( vpar_thread_t * p_vpar )
{
}
void vpar_SynchroDecode( vpar_thread_t * p_vpar, int i_coding_type,
int i_structure )
{
}
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment