Commit 62ee3e00 authored by Jean-Marc Dressler's avatar Jean-Marc Dressler

Corrections de quelques petits bugs et surtout nouvelle synchro qui ne semble

pas trop mal marcher sur ma machine mais qui j'en suis s�r ne marchera pas du
tout sur la votre.

A noter qu'il existe maintenant 3 synchros que l'on peut choisir en changeant
le define dans vpar_synchro.h (POLUX_SYNCHRO, SAM_SYNCHRO, MEUUH_SYNCHRO)
parent 2ebf6c03
......@@ -376,3 +376,11 @@
/* 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
#define VOUT_SYNCHRO_LEVEL_MAX 15
#define VOUT_SYNCHRO_HEAP_IDEAL_SIZE 5
......@@ -159,22 +159,26 @@ typedef struct vout_thread_s
* 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 */
mtime_t p_fps_sample[VOUT_FPS_SAMPLES]; /* FPS samples dates */
#endif
/* Rendering buffers */
int i_buffer_index; /* buffer index */
vout_buffer_t p_buffer[2]; /* buffers properties */
/* Videos heap and translation tables */
/* Videos heap and translation tables */
picture_t p_picture[VOUT_MAX_PICTURES]; /* pictures */
subpicture_t p_subpicture[VOUT_MAX_PICTURES]; /* subpictures */
int i_pictures; /* current heap size */
vout_yuv_t yuv; /* translation tables */
/* Bitmap fonts */
p_vout_font_t p_default_font; /* default font */
p_vout_font_t p_large_font; /* large font */
/* Synchronisation informations - synchro level is updated by the vout
* thread and read by decoder threads */
int i_synchro_level; /* trashing level */
} vout_thread_t;
/* Output methods */
......
......@@ -15,7 +15,7 @@
* "video_fifo.h"
*****************************************************************************/
#define SAM_SYNCHRO
#define POLUX_SYNCHRO
/*****************************************************************************
* video_synchro_t and video_synchro_tab_s : timers for the video synchro
......@@ -80,7 +80,9 @@ typedef struct video_synchro_s
double actual_fps;
} video_synchro_t;
#else
#endif
#ifdef MEUUH_SYNCHRO
typedef struct video_synchro_s
{
int kludge_level, kludge_p, kludge_b, kludge_nbp, kludge_nbb;
......@@ -93,6 +95,27 @@ typedef struct video_synchro_s
#define SYNC_DELAY 500000
#endif
#ifdef POLUX_SYNCHRO
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.r_frame_rate) */
mtime_t i_current_frame_date;
mtime_t i_backward_frame_date;
/* Frame Trashing Section */
int i_b_nb, i_p_nb; /* number of decoded P and B between two I */
int i_b_count, i_p_count, i_i_count;
int i_b_trasher; /* used for brensenham algorithm */
} video_synchro_t;
#endif
/*****************************************************************************
* Prototypes
*****************************************************************************/
......
......@@ -893,11 +893,12 @@ static __inline__ void input_DemuxPES( input_thread_t *p_input,
/* This part of the header does not fit in the current TS packet:
copy the part of the header we are interested in to the
p_pes_header_save buffer. The buffer is dynamicly allocated if
needed so it's time expensive but this situation almost never
occur. */
needed so it's time expensive but this situation almost never occur. */
intf_DbgMsg("Code never tested encountered, WARNING ! (benny)\n");
if( !p_pes->p_pes_header_save )
p_pes->p_pes_header_save = malloc(PES_HEADER_SIZE);
if( !p_pes->p_pes_header_save )
{
p_pes->p_pes_header_save = malloc(PES_HEADER_SIZE);
}
do
{
......
......@@ -50,6 +50,7 @@ static void RenderSubPicture ( vout_thread_t *p_vout,
static void RenderInterface ( vout_thread_t *p_vout );
static int RenderIdle ( 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,
......@@ -210,6 +211,10 @@ vout_thread_t * vout_CreateThread ( char *psz_display, int i_root_window,
p_vout->p_subpicture[i_index].i_type = EMPTY_SUBPICTURE;
p_vout->p_subpicture[i_index].i_status= FREE_SUBPICTURE;
}
p_vout->i_pictures = 0;
/* Initialize synchronization informations */
p_vout->i_synchro_level = VOUT_SYNCHRO_LEVEL_START;
/* Create and initialize system-dependant method - this function issues its
* own error messages */
......@@ -599,6 +604,7 @@ picture_t *vout_CreatePicture( vout_thread_t *p_vout, int i_type,
* can end immediately - this is the best possible case, since no
* memory allocation needs to be done */
p_vout->p_picture[i_picture].i_status = RESERVED_PICTURE;
p_vout->i_pictures++;
#ifdef DEBUG_VIDEO
intf_DbgMsg("picture %p (in destroyed picture slot)\n",
&p_vout->p_picture[i_picture] );
......@@ -682,6 +688,7 @@ picture_t *vout_CreatePicture( vout_thread_t *p_vout, int i_type,
p_free_picture->i_display_height = i_height;
p_free_picture->i_aspect_ratio = AR_SQUARE_PICTURE;
p_free_picture->i_refcount = 0;
p_vout->i_pictures++;
}
else
{
......@@ -711,11 +718,11 @@ picture_t *vout_CreatePicture( vout_thread_t *p_vout, int i_type,
* This function frees a previously reserved picture or a permanent
* picture. It is meant to be used when the construction of a picture aborted.
* Note that the picture will be destroyed even if it is linked !
* This function does not need locking since reserved pictures are ignored by
* the output thread.
*****************************************************************************/
void vout_DestroyPicture( vout_thread_t *p_vout, picture_t *p_pic )
{
vlc_mutex_lock( &p_vout->picture_lock );
#ifdef DEBUG
/* Check if picture status is valid */
if( (p_pic->i_status != RESERVED_PICTURE) &&
......@@ -726,11 +733,13 @@ void vout_DestroyPicture( vout_thread_t *p_vout, picture_t *p_pic )
}
#endif
p_pic->i_status = DESTROYED_PICTURE;
p_pic->i_status = DESTROYED_PICTURE;
p_vout->i_pictures--;
#ifdef DEBUG_VIDEO
intf_DbgMsg("picture %p\n", p_pic);
intf_DbgMsg("picture %p\n", p_pic);
#endif
vlc_mutex_unlock( &p_vout->picture_lock );
}
/*****************************************************************************
......@@ -772,6 +781,7 @@ void vout_UnlinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
if( (p_pic->i_refcount == 0) && (p_pic->i_status == DISPLAYED_PICTURE) )
{
p_pic->i_status = DESTROYED_PICTURE;
p_vout->i_pictures--;
}
#ifdef DEBUG_VIDEO
......@@ -981,18 +991,35 @@ 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
#if 0
if( display_date < current_date )
{
/* Picture is late: it will be destroyed and the thread will sleep and
* go to next picture */
vlc_mutex_lock( &p_vout->picture_lock );
p_pic->i_status = p_pic->i_refcount ? DISPLAYED_PICTURE : DESTROYED_PICTURE;
intf_DbgMsg( "warning: late picture %p skipped refcount=%d\n", p_pic, p_pic->i_refcount );
if( p_pic->i_refcount )
{
p_pic->i_status = DISPLAYED_PICTURE;
}
else
{
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 );
vlc_mutex_unlock( &p_vout->picture_lock );
p_pic = NULL;
display_date = 0;
/* Update synchronization information as if display delay
* was 0 */
Synchronize( p_vout, 0 );
}
else if( display_date > current_date + VOUT_DISPLAY_DELAY )
else
#endif
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 empty loop
......@@ -1000,6 +1027,12 @@ static void RunThread( vout_thread_t *p_vout)
p_pic = NULL;
display_date = 0;
}
else
{
/* Picture will be displayed, update synchronization
* information */
Synchronize( p_vout, display_date - current_date );
}
}
/*
......@@ -1033,7 +1066,15 @@ static void RunThread( vout_thread_t *p_vout)
/* Remove picture from heap */
vlc_mutex_lock( &p_vout->picture_lock );
p_pic->i_status = p_pic->i_refcount ? DISPLAYED_PICTURE : DESTROYED_PICTURE;
if( p_pic->i_refcount )
{
p_pic->i_status = DISPLAYED_PICTURE;
}
else
{
p_pic->i_status = DESTROYED_PICTURE;
p_vout->i_pictures--;
}
vlc_mutex_unlock( &p_vout->picture_lock );
/* Render interface and subpicture */
......@@ -1767,8 +1808,8 @@ static void RenderInfo( vout_thread_t *p_vout )
break;
}
}
sprintf( psz_buffer, "pic: %d/%d/%d",
i_reserved_pic, i_ready_pic, VOUT_MAX_PICTURES );
sprintf( psz_buffer, "pic: %d (%d/%d)/%d",
p_vout->i_pictures, i_reserved_pic, i_ready_pic, VOUT_MAX_PICTURES );
Print( p_vout, 0, 0, LEFT_RALIGN, BOTTOM_RALIGN, psz_buffer );
#endif
}
......@@ -1865,6 +1906,76 @@ 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;
//???? gore following
static int i_panic_count = 0;
static int i_last_synchro_inc = 0;
static float r_synchro_level = VOUT_SYNCHRO_LEVEL_START;
static int i_truc = 1;
//?? heap size is p_vout->i_pictures
//??
if( i_delay < 0 )
{
// intf_Msg("PANIC %d\n", i_panic_count++);
}
/*
if( p_vout->i_pictures > VOUT_SYNCHRO_HEAP_IDEAL_SIZE+1 )
{
i_synchro_inc++;
}
else if( p_vout->i_pictures < VOUT_SYNCHRO_HEAP_IDEAL_SIZE )
{
i_synchro_inc--;
}
*/
if( i_delay < 10000 )
{
i_truc = 4;
}
if( i_delay < 20000 )
{
i_synchro_inc--;
}
else if( i_delay > 50000 )
{
i_synchro_inc++;
}
if( i_synchro_inc*i_last_synchro_inc < 0 )
{
i_truc = 2;
}
else
{
i_truc *= 2;
}
if( i_truc > VOUT_SYNCHRO_LEVEL_MAX || i_delay == 0 )
{
i_truc = 2;
}
r_synchro_level += (float)i_synchro_inc / i_truc;
p_vout->i_synchro_level = (int) r_synchro_level;
if( r_synchro_level > VOUT_SYNCHRO_LEVEL_MAX )
{
r_synchro_level = VOUT_SYNCHRO_LEVEL_MAX;
}
// printf( "synchro level : %d, (%d, %d) (%d, %f) - %Ld\n", p_vout->i_synchro_level,
// i_last_synchro_inc, i_synchro_inc, i_truc, r_synchro_level, i_delay );
i_last_synchro_inc = i_synchro_inc;
}
/*****************************************************************************
* Manage: manage thread
*****************************************************************************
......
......@@ -292,7 +292,9 @@ static int InitThread( vpar_thread_t *p_vpar )
p_vpar->synchro.tab_b[i_dummy].mean = 6;
p_vpar->synchro.tab_b[i_dummy].deviation = .5;
}
#else
#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;
......@@ -300,6 +302,17 @@ static int InitThread( vpar_thread_t *p_vpar )
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.i_p_nb = 5;
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
/* Mark thread as running and return */
intf_DbgMsg("vpar debug: InitThread(%p) succeeded\n", p_vpar);
return( 0 );
......
......@@ -37,6 +37,19 @@
#include "video_parser.h"
#include "video_fifo.h"
static int i_count = 0;
/*
* Welcome to vpar_blocks.c ! Here's where the heavy processor-critical parsing
* task is done. This file is divided in several parts :
......@@ -530,9 +543,11 @@ void vpar_InitDCTTables( vpar_thread_t * p_vpar )
p_vpar->pppl_dct_dc_size[1][0] = pl_dct_dc_chrom_init_table_1;
p_vpar->pppl_dct_dc_size[1][1] = pl_dct_dc_chrom_init_table_2;
memset( p_vpar->ppl_dct_coef[0], MB_ERROR, 16 );
memset( p_vpar->ppl_dct_coef[1], MB_ERROR, 16 );
/* ??? MB_ERROR is replaced by 0 because if we use -1 we
* can block in DecodeMPEG2Intra and others */
memset( p_vpar->ppl_dct_coef[0], 0, 16 );
memset( p_vpar->ppl_dct_coef[1], 0, 16 );
/* For table B14 & B15, we have a pointer to tables */
/* We fill the table thanks to the fonction defined above */
FillDCTTable( p_vpar->ppl_dct_coef[0], pl_DCT_tab0, 256, 60, 4 );
......@@ -1614,14 +1629,24 @@ static __inline__ void ParseMacroblock(
static int pi_x[12] = {0,8,0,8,0,0,0,0,8,8,8,8};
static int pi_y[2][12] = { {0,0,8,8,0,0,8,8,0,0,8,8},
{0,0,1,1,0,0,1,1,0,0,1,1} };
int i_mb, i_b, i_mask;
int i_inc;
macroblock_t * p_mb;
yuv_data_t * p_data1;
yuv_data_t * p_data2;
*pi_mb_address += MacroblockAddressIncrement( p_vpar );
i_count++;
i_inc = MacroblockAddressIncrement( p_vpar );
*pi_mb_address += i_inc;
if( i_inc < 0 )
{
fprintf( stderr, "vpar error: bad address increment (%d)\n", i_inc );
p_vpar->picture.b_error = 1;
return;
}
if( *pi_mb_address - i_mb_previous - 1 )
{
/* Skipped macroblock (ISO/IEC 13818-2 7.6.6). */
......@@ -1833,9 +1858,16 @@ static __inline__ void SliceHeader( vpar_thread_t * p_vpar,
{
RemoveBits( &p_vpar->bit_stream, 8 );
}
}
}
*pi_mb_address = (i_vert_code - 1)*p_vpar->sequence.i_mb_width;
if( *pi_mb_address < i_mb_address_save )
{
fprintf( stderr, "vpar error: slices do not follow, maybe a PES has been trashed\n" );
p_vpar->picture.b_error = 1;
return;
}
/* Reset DC coefficients predictors (ISO/IEC 13818-2 7.2.1). */
p_vpar->mb.pi_dc_dct_pred[0] = p_vpar->mb.pi_dc_dct_pred[1]
= p_vpar->mb.pi_dc_dct_pred[2]
......@@ -1851,9 +1883,12 @@ static __inline__ void SliceHeader( vpar_thread_t * p_vpar,
i_chroma_format, i_structure,
b_second_field );
i_mb_address_save = *pi_mb_address;
if( p_vpar->picture.b_error )
{
return;
}
}
while( ShowBits( &p_vpar->bit_stream, 23 ) && !p_vpar->picture.b_error
&& !p_vpar->b_die );
while( ShowBits( &p_vpar->bit_stream, 23 ) && !p_vpar->b_die );
NextStartCode( p_vpar );
}
......
......@@ -156,10 +156,15 @@ static void __inline__ ReferenceUpdate( vpar_thread_t * p_vpar,
vout_UnlinkPicture( p_vpar->p_vout, p_vpar->sequence.p_forward );
if( p_vpar->sequence.p_backward != NULL )
{
#ifdef POLUX_SYNCHRO
vout_DatePicture( p_vpar->p_vout, p_vpar->sequence.p_backward,
vpar_SynchroDate( p_vpar ) );
#endif
#ifdef SAM_SYNCHRO
vout_DatePicture( p_vpar->p_vout, p_vpar->sequence.p_backward,
vpar_SynchroDate( p_vpar ) );
#else
#endif
#ifdef MEUUH_SYNCHRO
mtime_t date;
date = vpar_SynchroDate( p_vpar );
vout_DatePicture( p_vpar->p_vout, p_vpar->sequence.p_backward,
......@@ -172,15 +177,14 @@ static void __inline__ ReferenceUpdate( vpar_thread_t * p_vpar,
p_vpar->sequence.p_backward = p_newref;
if( p_newref != NULL )
vout_LinkPicture( p_vpar->p_vout, p_newref );
#ifndef SAM_SYNCHRO
#ifdef MEUUH_SYNCHRO
p_vpar->synchro.i_coding_type = i_coding_type;
#endif
}
else if( p_newref != NULL )
{
/* Put date immediately. */
vout_DatePicture( p_vpar->p_vout, p_newref,
vpar_SynchroDate( p_vpar ) );
vout_DatePicture( p_vpar->p_vout, p_newref, vpar_SynchroDate(p_vpar) );
}
}
......@@ -525,7 +529,7 @@ static void PictureHeader( vpar_thread_t * p_vpar )
RemoveBits( &p_vpar->bit_stream, 10 ); /* temporal_reference */
p_vpar->picture.i_coding_type = GetBits( &p_vpar->bit_stream, 3 );
RemoveBits( &p_vpar->bit_stream, 16 ); /* vbv_delay */
if( p_vpar->picture.i_coding_type == P_CODING_TYPE
|| p_vpar->picture.i_coding_type == B_CODING_TYPE )
{
......@@ -646,15 +650,21 @@ static void PictureHeader( vpar_thread_t * p_vpar )
p_vpar->picture.i_coding_type, i_structure );
}
}
#ifdef POLUX_SYNCHRO
else if( !p_vpar->picture.i_current_structure )
{
vpar_SynchroTrash( p_vpar, p_vpar->picture.i_coding_type, i_structure );
}
#endif
if( !b_parsable )
{
/* Update the reference pointers. */
ReferenceUpdate( p_vpar, p_vpar->picture.i_coding_type, NULL );
#ifndef POLUX_SYNCHRO
/* Warn Synchro we have trashed a picture. */
vpar_SynchroTrash( p_vpar, p_vpar->picture.i_coding_type, i_structure );
#endif
/* Update context. */
if( i_structure != FRAME_STRUCTURE )
p_vpar->picture.i_current_structure = i_structure;
......
......@@ -399,7 +399,9 @@ mtime_t vpar_SynchroDate( vpar_thread_t * p_vpar )
return i_displaydate;
}
#else
#endif
#ifdef MEUUH_SYNCHRO
/* synchro a deux balles backportee du decodeur de reference. NE MARCHE PAS
AVEC LES IMAGES MONOTRAMES */
......@@ -516,3 +518,145 @@ void vpar_SynchroKludge( vpar_thread_t * p_vpar, mtime_t date )
}
#endif
#ifdef POLUX_SYNCHRO
void vpar_SynchroSetCurrentDate( 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];
switch( i_coding_type )
{
case B_CODING_TYPE:
if( p_pes->b_has_pts )
{
if( p_pes->i_pts < p_vpar->synchro.i_current_frame_date )
{
fprintf( stderr, "vpar warning: pts_date < current_date\n" );
}
p_vpar->synchro.i_current_frame_date = p_pes->i_pts;
p_pes->b_has_pts = 0;
}
else
{
p_vpar->synchro.i_current_frame_date += 1000000/(1+p_vpar->sequence.r_frame_rate);
}
break;
default:
if( p_vpar->synchro.i_backward_frame_date == 0 )
{
p_vpar->synchro.i_current_frame_date += 1000000/(1+p_vpar->sequence.r_frame_rate);
}
else
{
if( p_vpar->synchro.i_backward_frame_date < p_vpar->synchro.i_current_frame_date )
{
fprintf( stderr, "vpar warning: backward_date < current_date (%Ld)\n",
p_vpar->synchro.i_backward_frame_date - p_vpar->synchro.i_current_frame_date );
}
p_vpar->synchro.i_current_frame_date = p_vpar->synchro.i_backward_frame_date;
p_vpar->synchro.i_backward_frame_date = 0;
}
if( p_pes->b_has_pts )
{
p_vpar->synchro.i_backward_frame_date = 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:
if( p_vpar->synchro.i_i_count != 0 )
{
p_vpar->synchro.i_p_nb = p_vpar->synchro.i_p_count;
p_vpar->synchro.i_b_nb = p_vpar->synchro.i_b_count;
}
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 );
}