Commit 57509f75 authored by Vincent Seguin's avatar Vincent Seguin

Toujours du nettoyage.

Une API pour les sous titres.
parent 653053d2
......@@ -120,9 +120,8 @@
#define INTF_IDLE_SLEEP 100000
/* Factor for changing gamma, and minimum and maximum values */
#define INTF_GAMMA_FACTOR 1.1
#define INTF_GAMMA_MIN 0.1
#define INTF_GAMMA_MAX 10
#define INTF_GAMMA_FACTOR .1
#define INTF_GAMMA_MAX 3
/*
* X11 settings
......@@ -247,7 +246,7 @@
#define VOUT_GRAYSCALE_DEFAULT 0
/* Default gamma */
#define VOUT_GAMMA 1.
#define VOUT_GAMMA 0.
/*
* Time settings
......@@ -338,7 +337,7 @@
/* Define to enable messages queues - disabling messages queue can be usefull
* when debugging, since it allows messages which would not otherwise be printed,
* due to a crash, to be printed anyway */
//#define INTF_MSG_QUEUE
#define INTF_MSG_QUEUE
/* Format of the header for debug messages. The arguments following this header
* are the file (char *), the function (char *) and the line (int) in which the
......
......@@ -24,7 +24,7 @@ typedef u8 yuv_data_t;
* Picture type and flags should only be modified by the output thread. Note
* that an empty picture MUST have its flags set to 0.
*******************************************************************************/
typedef struct
typedef struct picture_s
{
/* Type and flags - should NOT be modified except by the vout thread */
int i_type; /* picture type */
......@@ -69,7 +69,6 @@ typedef struct
yuv_data_t * p_v; /* pointer to beginning of V image in p_data */
} picture_t;
/* Pictures types */
#define EMPTY_PICTURE 0 /* picture slot is empty and available */
#define YUV_420_PICTURE 100 /* 4:2:0 YUV picture */
......@@ -88,3 +87,38 @@ typedef struct
#define AR_3_4_PICTURE 2 /* 3:4 picture (TV) */
#define AR_16_9_PICTURE 3 /* 16:9 picture (wide screen) */
#define AR_221_1_PICTURE 4 /* 2.21:1 picture (movie) */
/*******************************************************************************
* subtitle_t: video subtitle
*******************************************************************************
* Any subtitle destined to be displayed by a video output thread should be
* stored in this structure from it's creation to it's effective display.
* Subtitle type and flags should only be modified by the output thread. Note
* that an empty subtitle MUST have its flags set to 0.
*******************************************************************************/
typedef struct subtitle_s
{
/* Type and flags - should NOT be modified except by the vout thread */
int i_type; /* subtitle type */
int i_status; /* subtitle flags */
/* Other properties */
mtime_t begin_date; /* beginning of display date */
mtime_t end_date; /* end of display date */
/* Subtitle data - data can always be freely modified. p_data itself
* (the pointer) should NEVER be modified. */
void * p_data; /* subtitle data */
} subtitle_t;
/* Subtitle types */
#define EMPTY_SUBTITLE 0 /* subtitle slot is empty and available */
#define RLE_SUBTITLE 100 /* RLE encoded subtitle */
/* Subtitle status */
#define FREE_SUBTITLE 0 /* subtitle is free and not allocated */
#define RESERVED_SUBTITLE 1 /* subtitle is allocated and reserved */
#define READY_SUBTITLE 2 /* subtitle is ready for display */
#define DISPLAYED_SUBTITLE 3 /* subtitle has been displayed but is linked */
#define DESTROYED_SUBTITLE 4 /* subtitle is allocated but no more used */
......@@ -84,46 +84,40 @@ typedef struct vout_thread_s
boolean_t b_die; /* `die' flag */
boolean_t b_error; /* `error' flag */
boolean_t b_active; /* `active' flag */
pthread_t thread_id; /* id for pthread functions */
pthread_mutex_t lock; /* thread lock */
vlc_thread_t thread_id; /* id for pthread functions */
vlc_mutex_t picture_lock; /* picture heap lock */
vlc_mutex_t subtitle_lock; /* subtitle heap lock */
int * pi_status; /* temporary status flag */
p_vout_sys_t p_sys; /* system output method */
/* Current display properties */
boolean_t b_info; /* print additionnal informations */
boolean_t b_grayscale; /* color or grayscale display */
boolean_t b_info; /* print additionnal informations */
boolean_t b_grayscale; /* color or grayscale display */
int i_width; /* current output method width */
int i_height; /* current output method height */
int i_bytes_per_line;/* bytes per line (including virtual) */
int i_screen_depth; /* bits per pixel - FIXED */
int i_bytes_per_pixel; /* real screen depth - FIXED */
int i_bytes_per_line;/* bytes per line (including virtual) */
int i_screen_depth; /* bits per pixel */
int i_bytes_per_pixel; /* real screen depth */
float f_x_ratio; /* horizontal display ratio */
float f_y_ratio; /* vertical display ratio */
float f_gamma; /* gamma */
/* Changed properties values - some of them are treated directly by the
* thread, the over may be ignored or handled by vout_SysManage */
//?? info, grayscale, width, height, bytes per line, x ratio, y ratio, gamma
boolean_t b_gamma_change; /* gamma change indicator */
int i_new_width; /* new width */
int i_new_height; /* new height */
float f_gamma; /* gamma */
#ifdef STATS
/* Statistics - these numbers are not supposed to be accurate, but are a
* good indication of the thread status */
count_t c_loops; /* number of loops */
count_t c_idle_loops; /* number of idle loops */
count_t c_fps_samples; /* picture counts */
mtime_t loop_time; /* last picture loop time */
count_t c_fps_samples; /* picture counts */
mtime_t fps_sample[ VOUT_FPS_SAMPLES ]; /* FPS samples dates */
#endif
#ifdef DEBUG_VIDEO
/* Additionnal video debugging informations */
mtime_t picture_render_time; /* last picture rendering time */
#endif
/* Video heap and translation tables */
/* Running properties */
u16 i_changes; /* changes made to the thread */
mtime_t last_picture_date; /* last picture display date */
mtime_t last_idle_date; /* last idle screen displaydate */
/* Videos heap and translation tables */
picture_t p_picture[VOUT_MAX_PICTURES]; /* pictures */
subtitle_t p_subtitle[VOUT_MAX_PICTURES]; /* subtitles */
vout_tables_t tables; /* translation tables */
vout_convert_t * p_ConvertYUV420; /* YUV 4:2:0 converter */
vout_convert_t * p_ConvertYUV422; /* YUV 4:2:2 converter */
......@@ -131,25 +125,34 @@ typedef struct vout_thread_s
vout_scale_t * p_Scale; /* scaler */
} vout_thread_t;
/* Flags for changes - these flags are set in the i_changes field when another
* thread changed a variable */
#define VOUT_INFO_CHANGE 0x0001 /* b_info changed */
#define VOUT_GRAYSCALE_CHANGE 0x0002 /* b_grayscale changed */
#define VOUT_SIZE_CHANGE 0x0004 /* size changed */
#define VOUT_DEPTH_CHANGE 0x0008 /* depth changed */
#define VOUT_RATIO_CHANGE 0x0010 /* display ratio changed */
#define VOUT_GAMMA_CHANGE 0x0020 /* gamma changed */
/*******************************************************************************
* Prototypes
*******************************************************************************/
vout_thread_t * vout_CreateThread (
vout_thread_t * vout_CreateThread (
#ifdef VIDEO_X11
char *psz_display, Window root_window,
char *psz_display, Window root_window,
#endif
int i_width, int i_height, int *pi_status
);
void vout_DestroyThread ( vout_thread_t *p_vout, int *pi_status );
picture_t * vout_CreatePicture ( vout_thread_t *p_vout, int i_type,
int i_width, int i_height );
void vout_DestroyPicture ( vout_thread_t *p_vout, picture_t *p_pic );
void vout_DisplayPicture ( vout_thread_t *p_vout, picture_t *p_pic );
void vout_LinkPicture ( vout_thread_t *p_vout, picture_t *p_pic );
void vout_UnlinkPicture ( vout_thread_t *p_vout, picture_t *p_pic );
int i_width, int i_height, int *pi_status
);
void vout_DestroyThread ( vout_thread_t *p_vout, int *pi_status );
picture_t * vout_CreatePicture ( vout_thread_t *p_vout, int i_type,
int i_width, int i_height );
void vout_DestroyPicture ( vout_thread_t *p_vout, picture_t *p_pic );
void vout_DisplayPicture ( vout_thread_t *p_vout, picture_t *p_pic );
void vout_LinkPicture ( vout_thread_t *p_vout, picture_t *p_pic );
void vout_UnlinkPicture ( vout_thread_t *p_vout, picture_t *p_pic );
subtitle_t * vout_CreateSubtitle ( vout_thread_t *p_vout, int i_type, int i_size );
void vout_DestroySubtitle ( vout_thread_t *p_vout, subtitle_t *p_sub );
void vout_DisplaySubtitle ( vout_thread_t *p_vout, subtitle_t *p_sub );
......
......@@ -33,5 +33,5 @@ void ConvertYUV420RGB16MMX( u8* p_y, u8* p_u, u8 *p_v,
unsigned int i_ypitch, unsigned int i_vpitch,
unsigned int i_aspect, u8 *p_pic,
u32 i_dci_offset, u32 i_offset_to_line_0,
int CCOPitch, int i_colortype );
int i_pitch, int i_colortype );
#endif
......@@ -421,6 +421,17 @@ static void Usage( void )
intf_Msg("VLANs (Virtual Local Aera Networks) parameters:\n" \
" vlan_server=<host>[:<port>] VLANs server address and port\n" \
);
/* Interfaces keys */
intf_Msg("Interface keys: most interface accept the following commands:\n" \
" [esc], q quit\n" \
" +, - change volume\n" \
" m mute\n" \
" f fullscreen\n" \
" 0 - 9 select channel\n" \
" [space] toggle info printing\n" \
" g, G change gamma\n" \
);
}
/*******************************************************************************
......
......@@ -122,15 +122,11 @@ void vout_SysDestroy( vout_thread_t *p_vout )
* vout_SysManage: handle Sys events
*******************************************************************************
* This function should be called regularly by video output thread. It returns
* a negative value if something happened which does not allow the thread to
* continue, and a positive one if the thread can go on, but the images have
* been modified and therefore it is useless to display them.
* a non null value if an error occured.
*******************************************************************************/
int vout_SysManage( vout_thread_t *p_vout )
{
//??
return( 0 );
return( 0 );
}
/*******************************************************************************
......
......@@ -39,7 +39,9 @@ static void ErrorThread ( vout_thread_t *p_vout );
static void EndThread ( vout_thread_t *p_vout );
static void RenderPicture ( vout_thread_t *p_vout, picture_t *p_pic );
static void RenderPictureInfo ( vout_thread_t *p_vout, picture_t *p_pic );
static int RenderIdle ( vout_thread_t *p_vout, int i_level );
static int RenderIdle ( vout_thread_t *p_vout );
static int RenderInfo ( vout_thread_t *p_vout );
static int Manage ( vout_thread_t *p_vout );
/*******************************************************************************
* vout_CreateThread: creates a new video output thread
......@@ -112,20 +114,15 @@ vout_thread_t * vout_CreateThread (
p_vout->i_bytes_per_pixel, p_vout->i_bytes_per_line,
p_vout->f_x_ratio, p_vout->f_y_ratio, p_vout->b_grayscale );
/* Initialize changement properties */
p_vout->b_gamma_change = 0;
p_vout->i_new_width = p_vout->i_width;
p_vout->i_new_height = p_vout->i_height;
#ifdef STATS
/* Initialize statistics fields */
p_vout->c_loops = 0;
p_vout->c_idle_loops = 0;
p_vout->c_fps_samples = 0;
p_vout->loop_time = 0;
p_vout->c_fps_samples = 0;
#endif
/* Create thread and set locks */
vlc_mutex_init( &p_vout->lock );
vlc_mutex_init( &p_vout->picture_lock );
vlc_mutex_init( &p_vout->subtitle_lock );
if( vlc_thread_create( &p_vout->thread_id, "video output",
(void *) RunThread, (void *) p_vout) )
{
......@@ -184,6 +181,78 @@ void vout_DestroyThread( vout_thread_t *p_vout, int *pi_status )
}
}
/*******************************************************************************
* vout_DisplaySubtitle: display a subtitle
*******************************************************************************
* Remove the reservation flag of a subtitle, which will cause it to be ready for
* display. The picture does not need to be locked, since it is ignored by
* the output thread if is reserved.
*******************************************************************************/
void vout_DisplaySubtitle( vout_thread_t *p_vout, subtitle_t *p_sub )
{
#ifdef DEBUG_VIDEO
char psz_begin_date[MSTRTIME_MAX_SIZE]; /* buffer for date string */
char psz_end_date[MSTRTIME_MAX_SIZE]; /* buffer for date string */
#endif
#ifdef DEBUG
/* Check if status is valid */
if( p_sub->i_status != RESERVED_SUBTITLE )
{
intf_DbgMsg("error: subtitle %p has invalid status %d\n", p_sub, p_sub->i_status );
}
#endif
/* Remove reservation flag */
p_sub->i_status = READY_SUBTITLE;
#ifdef DEBUG_VIDEO
/* Send subtitle informations */
intf_DbgMsg("subtitle %p: type=%d, begin date=%s, end date=%s\n", p_sub, p_sub->i_type,
mstrtime( psz_begin_date, p_sub->begin_date ),
mstrtime( psz_end_date, p_sub->end_date ) );
#endif
}
/*******************************************************************************
* vout_CreateSubtitle: allocate a subtitle in the video output heap.
*******************************************************************************
* This function create a reserved subtitle in the video output heap.
* A null pointer is returned if the function fails. This method provides an
* already allocated zone of memory in the subtitle data fields. It needs locking
* since several pictures can be created by several producers threads.
*******************************************************************************/
subtitle_t *vout_CreateSubtitle( vout_thread_t *p_vout, int i_type,
int i_size )
{
//???
}
/*******************************************************************************
* vout_DestroySubtitle: remove a permanent or reserved subtitle from the heap
*******************************************************************************
* This function frees a previously reserved subtitle.
* It is meant to be used when the construction of a picture aborted.
* This function does not need locking since reserved subtitles are ignored by
* the output thread.
*******************************************************************************/
void vout_DestroySubtitle( vout_thread_t *p_vout, subtitle_t *p_sub )
{
#ifdef DEBUG
/* Check if subtitle status is valid */
if( p_sub->i_status != RESERVED_SUBTITLE )
{
intf_DbgMsg("error: subtitle %p has invalid status %d\n", p_sub, p_sub->i_status );
}
#endif
p_sub->i_status = DESTROYED_SUBTITLE;
#ifdef DEBUG_VIDEO
intf_DbgMsg("subtitle %p\n", p_sub);
#endif
}
/*******************************************************************************
* vout_DisplayPicture: display a picture
*******************************************************************************
......@@ -201,7 +270,7 @@ void vout_DisplayPicture( vout_thread_t *p_vout, picture_t *p_pic )
/* Check if picture status is valid */
if( p_pic->i_status != RESERVED_PICTURE )
{
intf_DbgMsg("error: picture %d has invalid status %d\n", p_pic, p_pic->i_status );
intf_DbgMsg("error: picture %p has invalid status %d\n", p_pic, p_pic->i_status );
}
#endif
......@@ -232,7 +301,7 @@ picture_t *vout_CreatePicture( vout_thread_t *p_vout, int i_type,
picture_t * p_destroyed_picture = NULL; /* first destroyed picture */
/* Get lock */
vlc_mutex_lock( &p_vout->lock );
vlc_mutex_lock( &p_vout->picture_lock );
/*
* Look for an empty place
......@@ -258,7 +327,7 @@ picture_t *vout_CreatePicture( vout_thread_t *p_vout, int i_type,
intf_DbgMsg("picture %p (in destroyed picture slot)\n",
&p_vout->p_picture[i_picture] );
#endif
vlc_mutex_unlock( &p_vout->lock );
vlc_mutex_unlock( &p_vout->picture_lock );
return( &p_vout->p_picture[i_picture] );
}
else if( p_destroyed_picture == NULL )
......@@ -350,13 +419,13 @@ picture_t *vout_CreatePicture( vout_thread_t *p_vout, int i_type,
#ifdef DEBUG_VIDEO
intf_DbgMsg("picture %p (in free picture slot)\n", p_free_picture );
#endif
vlc_mutex_unlock( &p_vout->lock );
vlc_mutex_unlock( &p_vout->picture_lock );
return( p_free_picture );
}
// No free or destroyed picture could be found
intf_DbgMsg( "warning: heap is full\n" );
vlc_mutex_unlock( &p_vout->lock );
vlc_mutex_unlock( &p_vout->picture_lock );
return( NULL );
}
......@@ -375,7 +444,7 @@ void vout_DestroyPicture( vout_thread_t *p_vout, picture_t *p_pic )
/* Check if picture status is valid */
if( p_pic->i_status != RESERVED_PICTURE )
{
intf_DbgMsg("error: picture %d has invalid status %d\n", p_pic, p_pic->i_status );
intf_DbgMsg("error: picture %p has invalid status %d\n", p_pic, p_pic->i_status );
}
#endif
......@@ -394,9 +463,9 @@ void vout_DestroyPicture( vout_thread_t *p_vout, picture_t *p_pic )
*******************************************************************************/
void vout_LinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
{
vlc_mutex_lock( &p_vout->lock );
vlc_mutex_lock( &p_vout->picture_lock );
p_pic->i_refcount++;
vlc_mutex_unlock( &p_vout->lock );
vlc_mutex_unlock( &p_vout->picture_lock );
#ifdef DEBUG_VIDEO
intf_DbgMsg("picture %p\n", p_pic);
......@@ -410,13 +479,13 @@ void vout_LinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
*******************************************************************************/
void vout_UnlinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
{
vlc_mutex_lock( &p_vout->lock );
vlc_mutex_lock( &p_vout->picture_lock );
p_pic->i_refcount--;
if( (p_pic->i_refcount == 0) && (p_pic->i_status == DISPLAYED_PICTURE) )
{
p_pic->i_status = DESTROYED_PICTURE;
}
vlc_mutex_unlock( &p_vout->lock );
vlc_mutex_unlock( &p_vout->picture_lock );
#ifdef DEBUG_VIDEO
intf_DbgMsg("picture %p\n", p_pic);
......@@ -446,11 +515,13 @@ static int InitThread( vout_thread_t *p_vout )
return( 1 );
}
/* Initialize pictures */
/* Initialize pictures and subtitles */
for( i_index = 0; i_index < VOUT_MAX_PICTURES; i_index++)
{
p_vout->p_picture[i_index].i_type = EMPTY_PICTURE;
p_vout->p_picture[i_index].i_status= FREE_PICTURE;
p_vout->p_picture[i_index].i_type = EMPTY_PICTURE;
p_vout->p_picture[i_index].i_status = FREE_PICTURE;
p_vout->p_subtitle[i_index].i_type = EMPTY_SUBTITLE;
p_vout->p_subtitle[i_index].i_status= FREE_SUBTITLE;
}
/* Initialize convertion tables and functions */
......@@ -477,11 +548,8 @@ static int InitThread( vout_thread_t *p_vout )
static void RunThread( vout_thread_t *p_vout)
{
int i_picture; /* picture index */
int i_err; /* error code */
int i_idle_level = 0; /* idle level */
mtime_t current_date; /* current date */
mtime_t pic_date = 0; /* picture date */
mtime_t last_date = 0; /* last picture date */
boolean_t b_display; /* display flag */
picture_t * p_pic; /* picture pointer */
......@@ -506,6 +574,7 @@ static void RunThread( vout_thread_t *p_vout)
* since only READY_PICTURES are handled
*/
p_pic = NULL;
current_date = mdate();
for( i_picture = 0; i_picture < VOUT_MAX_PICTURES; i_picture++ )
{
if( (p_vout->p_picture[i_picture].i_status == READY_PICTURE) &&
......@@ -516,8 +585,7 @@ static void RunThread( vout_thread_t *p_vout)
pic_date = p_pic->date;
}
}
current_date = mdate();
/*
* Render picture if any
*/
......@@ -531,9 +599,9 @@ static void RunThread( vout_thread_t *p_vout)
{
/* Picture is late: it will be destroyed and the thread will sleep and
* go to next picture */
vlc_mutex_lock( &p_vout->lock );
vlc_mutex_lock( &p_vout->picture_lock );
p_pic->i_status = p_pic->i_refcount ? DISPLAYED_PICTURE : DESTROYED_PICTURE;
vlc_mutex_unlock( &p_vout->lock );
vlc_mutex_unlock( &p_vout->picture_lock );
#ifdef DEBUG_VIDEO
intf_DbgMsg( "warning: late picture %p skipped\n", p_pic );
#endif
......@@ -546,91 +614,72 @@ static void RunThread( vout_thread_t *p_vout)
* as if no picture were found. The picture state is unchanged */
p_pic = NULL;
}
else
{
/* Picture has not yet been displayed, and has a valid display
* date : render it, then mark it as displayed */
if( p_vout->b_active )
{
RenderPicture( p_vout, p_pic );
if( p_vout->b_info )
{
RenderPictureInfo( p_vout, p_pic );
}
}
vlc_mutex_lock( &p_vout->lock );
p_pic->i_status = p_pic->i_refcount ? DISPLAYED_PICTURE : DESTROYED_PICTURE;
vlc_mutex_unlock( &p_vout->lock );
}
}
/*
* Rebuild tables if gamma has changed
/*
* Perform rendering, sleep and display rendered picture
*/
if( p_vout->b_gamma_change )
if( p_pic )
{
//??
p_vout->b_gamma_change = 0;
vout_ResetTables( p_vout ); // ?? test return value
}
/* A picture is ready to be displayed : render it */
if( p_vout->b_active )
{
RenderPicture( p_vout, p_pic );
if( p_vout->b_info )
{
RenderPictureInfo( p_vout, p_pic );
RenderInfo( p_vout );
}
b_display = 1;
}
else
{
b_display = 0;
}
/* Remove picture from heap */
vlc_mutex_lock( &p_vout->picture_lock );
p_pic->i_status = p_pic->i_refcount ? DISPLAYED_PICTURE : DESTROYED_PICTURE;
vlc_mutex_unlock( &p_vout->picture_lock );
}
else
{
/* No picture. However, an idle screen may be ready to display */
b_display = p_vout->b_active && ( RenderIdle( p_vout ) |
( p_vout->b_info && RenderInfo( p_vout ) ));
}
/* Sleep a while or until a given date */
if( p_pic )
{
#ifdef STATS
/* Computes loop time */
p_vout->loop_time = mdate() - current_date;
#endif
mwait( pic_date );
}
else
{
msleep( VOUT_IDLE_SLEEP );
}
/* On awakening, send immediately picture to display */
if( b_display && p_vout->b_active )
{
vout_SysDisplay( p_vout );
}
/*
* Check events, sleep and display picture
* Check events and manage thread
*/
i_err = vout_SysManage( p_vout );
if( i_err < 0 )
if( vout_SysManage( p_vout ) | Manage( p_vout ) )
{
/* A fatal error occured, and the thread must terminate immediately,
* without displaying anything - setting b_error to 1 cause the
* immediate end of the main while() loop. */
p_vout->b_error = 1;
}
else
{
if( p_pic )
{
/* A picture is ready to be displayed : remove blank screen flag */
last_date = pic_date;
i_idle_level = 0;
b_display = 1;
/* Sleep until its display date */
mwait( pic_date );
}
else
{
/* If last picture was a long time ago, increase idle level, reset
* date and render idle screen */
if( !i_err && (current_date - last_date > VOUT_IDLE_DELAY) )
{
last_date = current_date;
b_display = p_vout->b_active && RenderIdle( p_vout, i_idle_level++ );
}
else
{
b_display = 0;
}
#ifdef STATS
/* Update counters */
p_vout->c_idle_loops++;
#endif
/* Sleep to wait for new pictures */
msleep( VOUT_IDLE_SLEEP );
}
/* On awakening, send immediately picture to display */
if( b_display && p_vout->b_active )
{
vout_SysDisplay( p_vout );
}
}
#ifdef STATS
/* Update counters */
p_vout->c_loops++;
#endif
}
}
/*
......@@ -709,12 +758,6 @@ static void EndThread( vout_thread_t *p_vout )
*******************************************************************************/
static void RenderPicture( vout_thread_t *p_vout, picture_t *p_pic )
{
#ifdef DEBUG_VIDEO
/* Send picture informations and store rendering start date */
intf_DbgMsg("picture %p\n", p_pic );
p_vout->picture_render_time = mdate();
#endif
/*
* Prepare scaling
*/
......@@ -724,8 +767,8 @@ static void RenderPicture( vout_thread_t *p_vout, picture_t *p_pic )