Commit a2972b3c authored by Vincent Seguin's avatar Vincent Seguin

Nouvelle interface, effacement des zones modifi�es d'une image sur 2,

calcul de la taille optimale d'une image, scaling.

-Le scaling donne de bonnes tailles, mais les conversions YUV ne peuvent
pas suivre pour le moment.
-J'ai peut etre un peu cass� le fb et ggi (trop long � compiler pour tester).
En cas de probl�me, je corrige de suite.
-Les idle screens ("no stream") sont temporairement hors service.
parent 32414c55
......@@ -89,7 +89,7 @@ endif
# Libraries
#
LIB += -lpthread
LIB += -lm
LIN += -lm
ifeq ($(VIDEO),X11)
LIB += -L/usr/X11R6/lib
......
......@@ -228,10 +228,17 @@
#define VOUT_WIDTH_DEFAULT 640
#define VOUT_HEIGHT_DEFAULT 480
/* Default video heap size - remember that a decompressed picture is big
/* Video heap size - remember that a decompressed picture is big
* (~1 Mbyte) before using huge values */
#define VOUT_MAX_PICTURES 10
/* Maximum number of active areas in a rendering buffer. Active areas are areas
* of the picture which need to be cleared before re-using the buffer. If a
* picture, including its many additions such as subtitles, additionnal user
* informations and interface, has too many active areas, some of them are
* joined. */
#define VOUT_MAX_AREAS 5
/* Environment variable for grayscale output mode, and default value */
#define VOUT_GRAYSCALE_VAR "vlc_grayscale"
#define VOUT_GRAYSCALE_DEFAULT 0
......
......@@ -117,6 +117,5 @@ typedef struct subtitle_s
#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 */
#define DESTROYED_SUBTITLE 3 /* subtitle is allocated but no more used */
......@@ -24,6 +24,27 @@ typedef struct vout_tables_s
} yuv;
} vout_tables_t;
/*******************************************************************************
* vout_buffer_t: rendering buffer
*******************************************************************************
* This structure store informations about a buffer. Buffers are not completely
* cleared between displays, and modified areas needs to be stored.
*******************************************************************************/
typedef struct vout_buffer_s
{
/* Picture area */
int i_pic_x, i_pic_y; /* picture position */
int i_pic_width, i_pic_height; /* picture extension */
/* Other areas - only vertical extensions of areas are stored */
int i_areas; /* number of areas */
int pi_area_begin[VOUT_MAX_AREAS]; /* beginning of area */
int pi_area_end[VOUT_MAX_AREAS]; /* end of area */
/* Picture data */
byte_t * p_data; /* memory address */
} vout_buffer_t;
/*******************************************************************************
* vout_convert_t: convertion function
*******************************************************************************
......@@ -70,7 +91,6 @@ typedef struct vout_thread_s
p_vout_sys_t p_sys; /* system output method */
/* Current display properties */
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) */
......@@ -79,14 +99,17 @@ typedef struct vout_thread_s
float f_gamma; /* gamma */
/* Pictures and rendering properties */
boolean_t b_grayscale; /* color or grayscale display */
boolean_t b_info; /* print additionnal informations */
boolean_t b_interface; /* render interface */
boolean_t b_scale; /* allow picture scaling */
#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 fps_sample[ VOUT_FPS_SAMPLES ]; /* FPS samples dates */
mtime_t p_fps_sample[ VOUT_FPS_SAMPLES ]; /* FPS samples dates */
#endif
/* Running properties */
......@@ -94,6 +117,10 @@ typedef struct vout_thread_s
mtime_t last_picture_date; /* last picture display date */
mtime_t last_display_date; /* last screen display date */
/* Rendering buffers */
int i_buffer_index; /* buffer index */
vout_buffer_t p_buffer[2]; /* buffers properties */
/* Videos heap and translation tables */
picture_t p_picture[VOUT_MAX_PICTURES]; /* pictures */
subtitle_t p_subtitle[VOUT_MAX_PICTURES]; /* subtitles */
......@@ -111,10 +138,12 @@ typedef struct vout_thread_s
* thread changed a variable */
#define VOUT_INFO_CHANGE 0x0001 /* b_info changed */
#define VOUT_GRAYSCALE_CHANGE 0x0002 /* b_grayscale changed */
#define VOUT_SIZE_CHANGE 0x0008 /* size changed */
#define VOUT_DEPTH_CHANGE 0x0010 /* depth changed */
#define VOUT_GAMMA_CHANGE 0x0080 /* gamma changed */
#define VOUT_NODISPLAY_CHANGE 0xffff /* changes which forbidden display */
#define VOUT_INTF_CHANGE 0x0004 /* b_interface changed */
#define VOUT_SCALE_CHANGE 0x0008 /* b_scale changed */
#define VOUT_SIZE_CHANGE 0x0200 /* size changed */
#define VOUT_DEPTH_CHANGE 0x0400 /* depth changed */
#define VOUT_GAMMA_CHANGE 0x0010 /* gamma changed */
#define VOUT_NODISPLAY_CHANGE 0xff00 /* changes which forbidden display */
/*******************************************************************************
* Prototypes
......@@ -132,7 +161,7 @@ void vout_UnlinkPicture ( vout_thread_t *p_vout, picture_t *p_pi
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 );
void vout_ClearBuffer ( vout_thread_t *p_vout, vout_buffer_t *p_buffer );
......
......@@ -12,7 +12,6 @@ void vout_SysEnd ( p_vout_thread_t p_vout );
void vout_SysDestroy ( p_vout_thread_t p_vout );
int vout_SysManage ( p_vout_thread_t p_vout );
void vout_SysDisplay ( p_vout_thread_t p_vout );
void * vout_SysGetPicture ( p_vout_thread_t p_vout );
......@@ -15,14 +15,15 @@
/*******************************************************************************
* Prototypes
*******************************************************************************/
p_vout_font_t vout_LoadFont ( char *psz_name );
p_vout_font_t vout_LoadFont ( const char *psz_name );
void vout_UnloadFont ( p_vout_font_t p_font );
void vout_TextSize ( p_vout_font_t p_font, int i_style, char *psz_text,
void vout_TextSize ( p_vout_font_t p_font, int i_style,
const char *psz_text,
int *pi_width, int *pi_height );
void vout_Print ( p_vout_font_t p_font, byte_t *p_pic, int i_depth,
int i_bytes_per_pixel, u32 i_char_color,
u32 i_border_color, u32 i_bg_color,
int i_style, char *psz_text );
void vout_Print ( p_vout_font_t p_font, byte_t *p_pic,
int i_bytes_per_pixel, int i_bytes_per_line,
u32 i_char_color, u32 i_border_color, u32 i_bg_color,
int i_style, const char *psz_text );
......
......@@ -228,7 +228,16 @@ int intf_ProcessKey( intf_thread_t *p_intf, int i_key )
vlc_mutex_unlock( &p_intf->p_vout->change_lock );
}
break;
case ' ': /* toggle info */
case ' ': /* toggle interface */
if( p_intf->p_vout != NULL )
{
vlc_mutex_lock( &p_intf->p_vout->change_lock );
p_intf->p_vout->b_interface = !p_intf->p_vout->b_interface;
p_intf->p_vout->i_changes |= VOUT_INTF_CHANGE;
vlc_mutex_unlock( &p_intf->p_vout->change_lock );
}
break;
case 'i': /* toggle info */
if( p_intf->p_vout != NULL )
{
vlc_mutex_lock( &p_intf->p_vout->change_lock );
......@@ -237,6 +246,15 @@ int intf_ProcessKey( intf_thread_t *p_intf, int i_key )
vlc_mutex_unlock( &p_intf->p_vout->change_lock );
}
break;
case 's': /* toggle scaling */
if( p_intf->p_vout != NULL )
{
vlc_mutex_lock( &p_intf->p_vout->change_lock );
p_intf->p_vout->b_scale = !p_intf->p_vout->b_scale;
p_intf->p_vout->i_changes |= VOUT_SCALE_CHANGE;
vlc_mutex_unlock( &p_intf->p_vout->change_lock );
}
break;
default: /* unknown key */
return( 1 );
}
......
......@@ -443,11 +443,13 @@ static void Usage( void )
/* Interfaces keys */
intf_Msg("Interface keys: most interfaces accept the following commands:\n" \
" [space] \ttoggle interface\n"
" [esc], q \tquit\n" \
" 0 - 9 \tselect channel\n" \
" +, -, m \tchange volume, mute\n" \
" g, G, c \tchange gamma, toggle grayscale\n" \
" 0 - 9 \tselect channel\n" \
" [space] \ttoggle info printing\n" \
" i \ttoggle info printing\n" \
" s \ttoggle picture scaling\n" \
);
}
......
......@@ -41,25 +41,11 @@ typedef struct vout_sys_s
{
/* System informations */
int i_fb_dev; /* framebuffer device handle */
size_t i_page_size; /* page size */
struct fb_var_screeninfo var_info; /* framebuffer mode informations */
/* Video memory */
byte_t * p_video;
/* User settings */
boolean_t b_shm; /* shared memory extension flag */
/* Font information */
int i_char_bytes_per_line; /* character width (bytes) */
int i_char_height; /* character height (lines) */
int i_char_interspacing;/* space between centers (pixels) */
byte_t * pi_font; /* pointer to font data */
/* Display buffers information */
int i_buffer_index; /* buffer index */
void * p_image[2]; /* image */
byte_t * p_video; /* base adress */
size_t i_page_size; /* page size */
} vout_sys_t;
/******************************************************************************
......@@ -98,32 +84,18 @@ int vout_SysCreate( vout_thread_t *p_vout, char *psz_display, int i_root_window
/******************************************************************************
* vout_SysInit: initialize framebuffer video thread output method
******************************************************************************
* This function creates the images needed by the output thread. It is called
* at the beginning of the thread, but also each time the display is resized.
******************************************************************************/
int vout_SysInit( vout_thread_t *p_vout )
{
// Blank both screens
memset( p_vout->p_sys->p_video, 0x00, 2*p_vout->p_sys->i_page_size );
//memset( p_vout->p_sys->p_image[0], 0xf0, p_vout->p_sys->i_page_size );
//memset( p_vout->p_sys->p_image[1], 0x0f, p_vout->p_sys->i_page_size );
/* Set buffer index to 0 */
p_vout->p_sys->i_buffer_index = 0;
return( 0 );
}
/******************************************************************************
* vout_SysEnd: terminate FB video thread output method
******************************************************************************
* Destroy the FB images created by vout_SysInit. It is called at the end of
* the thread, but also each time the window is resized.
******************************************************************************/
void vout_SysEnd( vout_thread_t *p_vout )
{
intf_DbgMsg("%p\n", p_vout );
;
}
/******************************************************************************
......@@ -141,19 +113,10 @@ void vout_SysDestroy( vout_thread_t *p_vout )
* vout_SysManage: handle FB events
******************************************************************************
* This function should be called regularly by video output thread. It manages
* console events and allows screen resizing. It returns a non null value on
* error.
* console events. It returns a non null value on error.
******************************************************************************/
int vout_SysManage( vout_thread_t *p_vout )
{
/* XXX */
if( p_vout->i_changes & VOUT_SIZE_CHANGE )
{
intf_DbgMsg("resizing window\n");
p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
FBBlankDisplay( p_vout );
}
return 0;
}
......@@ -165,10 +128,6 @@ int vout_SysManage( vout_thread_t *p_vout )
******************************************************************************/
void vout_SysDisplay( vout_thread_t *p_vout )
{
/* Swap buffers */
//p_vout->p_sys->i_buffer_index = ++p_vout->p_sys->i_buffer_index & 1;
p_vout->p_sys->i_buffer_index = 0;
/* tout est bien affich, on peut changer les 2 crans */
p_vout->p_sys->var_info.xoffset = 0;
p_vout->p_sys->var_info.yoffset =
......@@ -179,16 +138,6 @@ void vout_SysDisplay( vout_thread_t *p_vout )
ioctl( p_vout->p_sys->i_fb_dev, FBIOPAN_DISPLAY, &p_vout->p_sys->var_info );
}
/******************************************************************************
* vout_SysGetPicture: get current display buffer informations
******************************************************************************
* This function returns the address of the current display buffer.
******************************************************************************/
void * vout_SysGetPicture( vout_thread_t *p_vout )
{
return( p_vout->p_sys->p_image[ p_vout->p_sys->i_buffer_index ] );
}
/* following functions are local */
/******************************************************************************
......@@ -291,8 +240,12 @@ static int FBOpenDisplay( vout_thread_t *p_vout )
close( p_vout->p_sys->i_fb_dev );
return( 1 );
}
p_vout->p_sys->p_image[ 0 ] = p_vout->p_sys->p_video;
p_vout->p_sys->p_image[ 1 ] = p_vout->p_sys->p_video + p_vout->p_sys->i_page_size;
/* Set and initialize buffers */
p_vout->p_buffer[0].p_data = p_vout->p_sys->p_video;
p_vout->p_buffer[1].p_data = p_vout->p_sys->p_video + p_vout->p_sys->i_page_size;
vout_ClearBuffer( p_vout, &p_vout->p_buffer[0] );
vout_ClearBuffer( p_vout, &p_vout->p_buffer[1] );
intf_DbgMsg("framebuffer type=%d, visual=%d, ypanstep=%d, ywrap=%d, accel=%d\n",
fix_info.type, fix_info.visual, fix_info.ypanstep, fix_info.ywrapstep, fix_info.accel );
......@@ -310,20 +263,6 @@ static int FBOpenDisplay( vout_thread_t *p_vout )
******************************************************************************/
static void FBCloseDisplay( vout_thread_t *p_vout )
{
// Free font info
free( p_vout->p_sys->pi_font );
// Destroy window and close display
close( p_vout->p_sys->i_fb_dev );
}
/******************************************************************************
* FBBlankDisplay: render a blank screen
******************************************************************************
* This function is called by all other rendering functions when they arrive on
* a non blanked screen.
******************************************************************************/
static void FBBlankDisplay( vout_thread_t *p_vout )
{
memset( p_vout->p_sys->p_video, 0x00, 2*p_vout->p_sys->i_page_size );
}
......@@ -33,13 +33,8 @@ typedef struct vout_sys_s
ggi_visual_t p_display; /* display device */
/* Buffers informations */
int i_buffer_index; /* buffer index */
ggi_directbuffer * p_buffer[2]; /* buffers */
boolean_t b_must_acquire; /* must be acquired before writing */
/* Characters size */
int i_char_width;
int i_char_height;
} vout_sys_t;
/*******************************************************************************
......@@ -72,7 +67,6 @@ int vout_SysCreate( vout_thread_t *p_vout, char *psz_display, int i_root_window
free( p_vout->p_sys );
return( 1 );
}
return( 0 );
}
......@@ -84,10 +78,9 @@ int vout_SysCreate( vout_thread_t *p_vout, char *psz_display, int i_root_window
int vout_SysInit( vout_thread_t *p_vout )
{
/* Acquire first buffer */
p_vout->p_sys->i_buffer_index = 0;
if( p_vout->p_sys->b_must_acquire )
{
ggiResourceAcquire( p_vout->p_sys->p_buffer[ 0 ]->resource, GGI_ACTYPE_WRITE );
ggiResourceAcquire( p_vout->p_sys->p_buffer[ p_vout->i_buffer_index ]->resource, GGI_ACTYPE_WRITE );
}
return( 0 );
......@@ -103,7 +96,7 @@ void vout_SysEnd( vout_thread_t *p_vout )
/* Release buffer */
if( p_vout->p_sys->b_must_acquire )
{
ggiResourceRelease( p_vout->p_sys->p_buffer[ p_vout->p_sys->i_buffer_index ]->resource );
ggiResourceRelease( p_vout->p_sys->p_buffer[ p_vout->i_buffer_index ]->resource );
}
}
......@@ -140,64 +133,20 @@ void vout_SysDisplay( vout_thread_t *p_vout )
/* Change display frame */
if( p_vout->p_sys->b_must_acquire )
{
ggiResourceRelease( p_vout->p_sys->p_buffer[ p_vout->p_sys->i_buffer_index ]->resource );
ggiResourceRelease( p_vout->p_sys->p_buffer[ p_vout->i_buffer_index ]->resource );
}
ggiFlush( p_vout->p_sys->p_display ); // ??
ggiSetDisplayFrame( p_vout->p_sys->p_display,
p_vout->p_sys->p_buffer[ p_vout->p_sys->i_buffer_index ]->frame );
p_vout->p_sys->p_buffer[ p_vout->i_buffer_index ]->frame );
/* Swap buffers and change write frame */
p_vout->p_sys->i_buffer_index = ++p_vout->p_sys->i_buffer_index & 1;
if( p_vout->p_sys->b_must_acquire )
{
ggiResourceAcquire( p_vout->p_sys->p_buffer[ p_vout->p_sys->i_buffer_index ]->resource,
ggiResourceAcquire( p_vout->p_sys->p_buffer[ (p_vout->i_buffer_index + 1) & 1]->resource,
GGI_ACTYPE_WRITE );
}
ggiSetWriteFrame( p_vout->p_sys->p_display,
p_vout->p_sys->p_buffer[ p_vout->p_sys->i_buffer_index ]->frame );
}
/*******************************************************************************
* vout_SysGetPicture: get current display buffer informations
*******************************************************************************
* This function returns the address of the current display buffer.
*******************************************************************************/
void * vout_SysGetPicture( vout_thread_t *p_vout )
{
return( p_vout->p_sys->p_buffer[ p_vout->p_sys->i_buffer_index ]->write );
}
/*******************************************************************************
* vout_SysPrint: print simple text on a picture
*******************************************************************************
* This function will print a simple text on the picture. It is designed to
* print debugging or general informations, not to render subtitles.
*******************************************************************************/
void vout_SysPrint( vout_thread_t *p_vout, int i_x, int i_y, int i_halign,
int i_valign, unsigned char *psz_text )
{
/* Update upper left coordinates according to alignment */
switch( i_halign )
{
case 0: /* centered */
i_x -= p_vout->p_sys->i_char_width * strlen( psz_text ) / 2;
break;
case 1: /* right aligned */
i_x -= p_vout->p_sys->i_char_width * strlen( psz_text );
break;
}
switch( i_valign )
{
case 0: /* centered */
i_y -= p_vout->p_sys->i_char_height / 2;
break;
case 1: /* bottom aligned */
i_y -= p_vout->p_sys->i_char_height;
break;
}
/* Print text */
ggiPuts( p_vout->p_sys->p_display, i_x, i_y, psz_text );
p_vout->p_sys->p_buffer[ (p_vout->i_buffer_index + 1) & 1]->frame );
}
/*******************************************************************************
......@@ -373,6 +322,12 @@ static int GGIOpenDisplay( vout_thread_t *p_vout, char *psz_display )
break;
}
/* Set and initialize buffers */
p_vout->p_buffer[0].p_data = p_vout->p_sys->p_buffer[ 0 ]->write;
p_vout->p_buffer[1].p_data = p_vout->p_sys->p_buffer[ 1 ]->write;
vout_ClearBuffer( p_vout, &p_vout->p_buffer[0] );
vout_ClearBuffer( p_vout, &p_vout->p_buffer[1] );
return( 0 );
}
......
......@@ -34,12 +34,17 @@ static int InitThread ( vout_thread_t *p_vout );
static void RunThread ( vout_thread_t *p_vout );
static void ErrorThread ( vout_thread_t *p_vout );
static void EndThread ( vout_thread_t *p_vout );
static void DestroyThread ( vout_thread_t *p_vout, int i_status );
static void Print ( vout_thread_t *p_vout, int i_x, int i_y, int i_halign, int i_valign, unsigned char *psz_text );
static void RenderBlank ( vout_thread_t *p_vout );
static int RenderPicture ( vout_thread_t *p_vout, picture_t *p_pic, boolean_t b_blank );
static int RenderPictureInfo ( vout_thread_t *p_vout, picture_t *p_pic, boolean_t b_blank );
static int RenderIdle ( vout_thread_t *p_vout, boolean_t b_blank );
static int RenderInfo ( vout_thread_t *p_vout, boolean_t b_balnk );
static void SetBufferArea ( vout_thread_t *p_vout, int i_x, int i_y, int i_w, int i_h );
static void SetBufferPicture ( vout_thread_t *p_vout, picture_t *p_pic );
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 void RenderSubtitle ( vout_thread_t *p_vout, subtitle_t *p_sub );
static void RenderInterface ( vout_thread_t *p_vout );
static void RenderIdle ( vout_thread_t *p_vout );
static void RenderInfo ( vout_thread_t *p_vout );
static int Manage ( vout_thread_t *p_vout );
/******************************************************************************
......@@ -55,6 +60,7 @@ vout_thread_t * vout_CreateThread ( char *psz_display, int i_root_
{
vout_thread_t * p_vout; /* thread descriptor */
int i_status; /* thread status */
int i_index; /* index for array initialization */
/* Allocate descriptor */
intf_DbgMsg("\n");
......@@ -65,7 +71,8 @@ vout_thread_t * vout_CreateThread ( char *psz_display, int i_root_
return( NULL );
}
/* Initialize thread properties */
/* Initialize thread properties - thread id and locks will be initialized
* later */
p_vout->b_die = 0;
p_vout->b_error = 0;
p_vout->b_active = 0;
......@@ -74,23 +81,47 @@ vout_thread_t * vout_CreateThread ( char *psz_display, int i_root_
/* Initialize some fields used by the system-dependant method - these fields will
* probably be modified by the method, and are only preferences */
p_vout->b_grayscale = main_GetIntVariable( VOUT_GRAYSCALE_VAR,
VOUT_GRAYSCALE_DEFAULT );
p_vout->i_width = i_width;
p_vout->i_height = i_height;
p_vout->i_bytes_per_line = i_width * 2;
p_vout->i_screen_depth = 15;
p_vout->i_bytes_per_pixel = 2;
p_vout->f_gamma = VOUT_GAMMA;
#ifdef DEBUG
p_vout->b_info = 1;
#else
p_vout->b_grayscale = main_GetIntVariable( VOUT_GRAYSCALE_VAR,
VOUT_GRAYSCALE_DEFAULT );
p_vout->b_info = 0;
#endif
p_vout->b_interface = 0;
p_vout->b_scale = 0;
intf_DbgMsg("wished configuration: %dx%d,%d (%d bytes/pixel, %d bytes/line)\n",
p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth,
p_vout->i_bytes_per_pixel, p_vout->i_bytes_per_line );
#ifdef STATS
/* Initialize statistics fields */
p_vout->render_time = 0;
p_vout->c_fps_samples = 0;
#endif
/* Initialize running properties */
p_vout->i_changes = 0;
p_vout->last_picture_date = 0;
p_vout->last_display_date = 0;
/* Initialize buffer index */
p_vout->i_buffer_index = 0;
/* Initialize pictures and subtitles - translation tables and functions
* will be initialized later in InitThread */
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_subtitle[i_index].i_type = EMPTY_SUBTITLE;
p_vout->p_subtitle[i_index].i_status= FREE_SUBTITLE;
}
/* Create and initialize system-dependant method - this function issues its
* own error messages */
if( vout_SysCreate( p_vout, psz_display, i_root_window ) )
......@@ -102,7 +133,8 @@ vout_thread_t * vout_CreateThread ( char *psz_display, int i_root_
p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth,
p_vout->i_bytes_per_pixel, p_vout->i_bytes_per_line );
/* Load fonts */
/* Load fonts - fonts must be initialized after the systme method since
* they may be dependant of screen depth and other thread properties */
p_vout->p_default_font = vout_LoadFont( VOUT_DEFAULT_FONT );
if( p_vout->p_default_font == NULL )
{
......@@ -119,17 +151,6 @@ vout_thread_t * vout_CreateThread ( char *psz_display, int i_root_
return( NULL );
}
#ifdef STATS
/* Initialize statistics fields */
p_vout->render_time = 0;
p_vout->c_fps_samples = 0;
#endif
/* Initialize running properties */
p_vout->i_changes = 0;
p_vout->last_picture_date = 0;
p_vout->last_display_date = 0;
/* Create thread and set locks */
vlc_mutex_init( &p_vout->picture_lock );
vlc_mutex_init( &p_vout->subtitle_lock );
......@@ -239,7 +260,7 @@ void vout_DisplaySubtitle( vout_thread_t *p_vout, subtitle_t *p_sub )
subtitle_t *vout_CreateSubtitle( vout_thread_t *p_vout, int i_type,
int i_size )
{
//???
//??
}
/******************************************************************************
......@@ -553,6 +574,26 @@ void vout_UnlinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
vlc_mutex_unlock( &p_vout->picture_lock );
}
/******************************************************************************
* vout_ClearBuffer: clear a whole buffer
******************************************************************************
* This function is called when a buffer is initialized. It clears the whole
* buffer.
******************************************************************************/
void vout_ClearBuffer( vout_thread_t *p_vout, vout_buffer_t *p_buffer )
{
/* No picture previously */
p_buffer->i_pic_x = 0;
p_buffer->i_pic_y = 0;
p_buffer->i_pic_width = 0;
p_buffer->i_pic_height = 0;
/* The first area covers all the screen */
p_buffer->i_areas = 1;
p_buffer->pi_area_begin[0] = 0;
p_buffer->pi_area_end[0] = p_vout->i_height - 1;
}
/* following functions are local */
/******************************************************************************
......@@ -564,8 +605,6 @@ void vout_UnlinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
******************************************************************************/
static int InitThread( vout_thread_t *p_vout )
{
int i_index; /* generic index */
/* Update status */
intf_DbgMsg("\n");
*p_vout->pi_status = THREAD_START;
......@@ -573,19 +612,9 @@ static int InitThread( vout_thread_t *p_vout )
/* Initialize output method - this function issues its own error messages */
if( vout_SysInit( p_vout ) )
{
*p_vout->pi_status = THREAD_ERROR;
return( 1 );
}
/* 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_subtitle[i_index].i_type = EMPTY_SUBTITLE;
p_vout->p_subtitle[i_index].i_status= FREE_SUBTITLE;
}
/* Initialize convertion tables and functions */
if( vout_InitTables( p_vout ) )
{
......@@ -609,20 +638,20 @@ static int InitThread( vout_thread_t *p_vout )
******************************************************************************/
static void RunThread( vout_thread_t *p_vout)
{
int i_picture; /* picture index */
int i_index; /* index in heap */
mtime_t current_date; /* current date */
mtime_t pic_date = 0; /* picture date */
mtime_t display_date; /* display date */
boolean_t b_display; /* display flag */
picture_t * p_pic; /* picture pointer */
subtitle_t * p_sub; /* subtitle pointer */
/*
* Initialize thread and free configuration
* Initialize thread
*/
p_vout->b_error = InitThread( p_vout );
if( p_vout->b_error )
{
//??
free( p_vout ); /* destroy descriptor */
DestroyThread( p_vout, THREAD_ERROR );
return;
}
intf_DbgMsg("\n");
......@@ -633,114 +662,170 @@ static void RunThread( vout_thread_t *p_vout)
*/
while( (!p_vout->b_die) && (!p_vout->b_error) )
{
/* Initialize loop variables */
p_pic = NULL;
p_sub = NULL;
display_date = 0;
current_date = mdate();
/*
* Find the picture to display - this operation does not need lock,
* since only READY_PICTURES are handled
* since only READY_PICTUREs are handled
*/
p_pic = NULL;
current_date = mdate();
for( i_picture = 0; i_picture < VOUT_MAX_PICTURES; i_picture++ )
for( i_index = 0; i_index < VOUT_MAX_PICTURES; i_index++ )
{
if( (p_vout->p_picture[i_picture].i_status == READY_PICTURE) &&
if( (p_vout->p_picture[i_index].i_status == READY_PICTURE) &&
( (p_pic == NULL) ||
(p_vout->p_picture[i_picture].date < pic_date) ) )
(p_vout->p_picture[i_index].date < display_date) ) )
{
p_pic = &p_vout->p_picture[i_picture];
pic_date = p_pic->date;
p_pic = &p_vout->p_picture[i_index];
display_date = p_pic->date;
}
}
/*
* Render picture if any
*/
if( p_pic )
{
#ifdef STATS
/* Computes FPS rate */
p_vout->fps_sample[ p_vout->c_fps_samples++ % VOUT_FPS_SAMPLES ] = pic_date;
p_vout->p_fps_sample[ p_vout->c_fps_samples++ % VOUT_FPS_SAMPLES ] = display_date;
#endif
if( pic_date < current_date )
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;
#ifdef DEBUG_VIDEO
intf_DbgMsg( "warning: late picture %p skipped refcount=%d\n", p_pic, p_pic->i_refcount );
#endif
vlc_mutex_unlock( &p_vout->picture_lock );
p_pic = NULL;
display_date = 0;
}
else if( pic_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 empty loop
* as if no picture were found. The picture state is unchanged */
p_pic = NULL;
display_date = 0;
}
}
/*
* Find the subtitle to display - this operation does not need lock, since
* only READY_SUBTITLEs are handled. If no picture has been selected,
* display_date will depend on the subtitle
*/
//??
/*
* Perform rendering, sleep and display rendered picture
*/
if( p_pic )
if( p_pic ) /* picture and perhaps subtitle */
{
/* A picture is ready to be displayed : render it */
if( p_vout->b_active )
b_display = p_vout->b_active;
if( b_display )
{
b_display = RenderPicture( p_vout, p_pic, 1 );
/* Set picture dimensions and clear buffer */
SetBufferPicture( p_vout, p_pic );
/* Render picture and informations */
RenderPicture( p_vout, p_pic );
if( p_vout->b_info )
{
b_display |= RenderPictureInfo( p_vout, p_pic, b_display );
b_display |= RenderInfo( p_vout, b_display );
RenderPictureInfo( p_vout, p_pic );
RenderInfo( p_vout );
}
}
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 );
/* Render interface and subtitles */
if( b_display && p_vout->b_interface )
{
RenderInterface( p_vout );
}
else
if( p_sub )
{
if( b_display )
{
RenderSubtitle( p_vout, p_sub );
}
/* Remove subtitle from heap */
vlc_mutex_lock( &p_vout->subtitle_lock );
p_sub->i_status = DESTROYED_SUBTITLE;
vlc_mutex_unlock( &p_vout->subtitle_lock );
}
}
else if( p_sub ) /* subtitle alone */
{
/* No picture. However, an idle screen may be ready to display */
if( p_vout->b_active )
b_display = p_vout->b_active;
if( b_display )
{
b_display = RenderIdle( p_vout, 1 );
/* Clear buffer */
SetBufferPicture( p_vout, NULL );
/* Render informations, interface and subtitle */
if( p_vout->b_info )
{
b_display |= RenderInfo( p_vout, b_display );
}
RenderInfo( p_vout );
}
else
if( p_vout->b_interface )
{
b_display = 0;
RenderInterface( p_vout );
}
RenderSubtitle( p_vout, p_sub );
}
/* Remove subtitle from heap */
vlc_mutex_lock( &p_vout->subtitle_lock );
p_sub->i_status = DESTROYED_SUBTITLE;
vlc_mutex_unlock( &p_vout->subtitle_lock );
}
else /* idle screen alone */
{
//??? render on idle screen or interface change
b_display = 0; //???
}
/*
* Sleep, wake up and display rendered picture
*/
#ifdef STATS
/* Store render time */
p_vout->render_time = mdate() - current_date;
#endif
/* Give back change lock */
vlc_mutex_unlock( &p_vout->change_lock );
/* Sleep a while or until a given date */
if( p_pic )
if( display_date != 0 )
{
mwait( pic_date );
mwait( display_date );
}
else
{
msleep( VOUT_IDLE_SLEEP );
}
/* On awakening, take back lock and send immediately picture to display */
/* On awakening, take back lock and send immediately picture to display,
* then swap buffers */
vlc_mutex_lock( &p_vout->change_lock );
if( b_display && p_vout->b_active &&
!(p_vout->i_changes & VOUT_NODISPLAY_CHANGE) )
#ifdef DEBUG_VIDEO
intf_DbgMsg( "picture %p, subtitle %p\n", p_pic, p_sub );
#endif
if( b_display && !(p_vout->i_changes & VOUT_NODISPLAY_CHANGE) )
{
vout_SysDisplay( p_vout );
p_vout->i_buffer_index = ++p_vout->i_buffer_index & 1;
}
/*
......@@ -756,7 +841,7 @@ static void RunThread( vout_thread_t *p_vout)
}
/*
* Error loop
* Error loop - wait until the thread destruction is requested
*/
if( p_vout->b_error )
{
......@@ -765,6 +850,7 @@ static void RunThread( vout_thread_t *p_vout)
/* End of thread */
EndThread( p_vout );
DestroyThread( p_vout, THREAD_OVER );
intf_DbgMsg( "thread end\n" );
}
......@@ -786,43 +872,58 @@ static void ErrorThread( vout_thread_t *p_vout )
}
}
/******************************************************************************
/*******************************************************************************
* EndThread: thread destruction
******************************************************************************
*******************************************************************************
* This function is called when the thread ends after a sucessfull
* initialization.
******************************************************************************/
* initialization. It frees all ressources allocated by InitThread.
*******************************************************************************/
static void EndThread( vout_thread_t *p_vout )
{
int * pi_status; /* thread status */
int i_picture;
int i_index; /* index in heap */
/* Store status */
intf_DbgMsg("\n");
pi_status = p_vout->pi_status;
*pi_status = THREAD_END;
*p_vout->pi_status = THREAD_END;
/* Destroy all remaining pictures */
for( i_picture = 0; i_picture < VOUT_MAX_PICTURES; i_picture++ )
/* Destroy all remaining pictures and subtitles */
for( i_index = 0; i_index < VOUT_MAX_PICTURES; i_index++ )
{
if( p_vout->p_picture[i_picture].i_status != FREE_PICTURE )
if( p_vout->p_picture[i_index].i_status != FREE_PICTURE )
{
free( p_vout->p_picture[i_picture].p_data );
free( p_vout->p_picture[i_index].p_data );
}
if( p_vout->p_subtitle[i_index].i_status != FREE_SUBTITLE )
{
free( p_vout->p_subtitle[i_index].p_data );
}
}
/* Destroy translation tables */
vout_EndTables( p_vout );
vout_SysEnd( p_vout );
}
/*******************************************************************************
* DestroyThread: thread destruction
*******************************************************************************
* This function is called when the thread ends. It frees all ressources
* allocated by CreateThread. Status is available at this stage.
*******************************************************************************/
static void DestroyThread( vout_thread_t *p_vout, int i_status )
{
int *pi_status; /* status adress */
/* Store status adress */
intf_DbgMsg("\n");
pi_status = p_vout->pi_status;
/* Destroy thread structures allocated by Create and InitThread */
vout_SysEnd( p_vout );
vout_UnloadFont( p_vout->p_default_font );
vout_UnloadFont( p_vout->p_large_font );
vout_SysDestroy( p_vout );
free( p_vout );
/* Update status */
*pi_status = THREAD_OVER;
*pi_status = i_status;
}
/*******************************************************************************
......@@ -865,124 +966,346 @@ void Print( vout_thread_t *p_vout, int i_x, int i_y, int i_halign, int i_valign,
return;
}
/* Print text */
vout_Print( p_vout->p_default_font, vout_SysGetPicture( p_vout ) +
/* Set area and print text */
SetBufferArea( p_vout, i_x, i_y, i_text_width, i_text_height );
vout_Print( p_vout->p_default_font, p_vout->p_buffer[ p_vout->i_buffer_index ].p_data +
i_y * p_vout->i_bytes_per_line + i_x * p_vout->i_bytes_per_pixel,
p_vout->i_bytes_per_pixel, p_vout->i_bytes_per_line,
0xffffffff, 0x00000000, 0x00000000, 0, psz_text );
0xffffffff, 0x00000000, 0x00000000, TRANSPARENT_TEXT, psz_text );
}
/******************************************************************************
* RenderBlank: render a blank screen
******************************************************************************
* This function is called by all other rendering functions when they arrive on
* a non blanked screen.
******************************************************************************/
static void RenderBlank( vout_thread_t *p_vout )
/*******************************************************************************
* SetBufferArea: activate an area in current buffer
*******************************************************************************
* This function is called when something is rendered on the current buffer.
* It set the area as active and prepare it to be cleared on next rendering.
* Pay attention to the fact that in this functions, i_h is in fact the end y
* coordinate of the new area.
*******************************************************************************/
static void SetBufferArea( vout_thread_t *p_vout, int i_x, int i_y, int i_w, int i_h )
{
//?? toooooo slow
int i_index; /* current 64 bits sample */
int i_width; /* number of 64 bits samples */
u64 *p_pic; /* pointer to 64 bits samples */
/* Initialize variables */
p_pic = vout_SysGetPicture( p_vout );
i_width = p_vout->i_bytes_per_line * p_vout->i_height / 256;
/* Clear beginning of screen by 256 bytes blocks */
for( i_index = 0; i_index < i_width; i_index++ )
{
*p_pic++ = 0; *p_pic++ = 0;
*p_pic++ = 0; *p_pic++ = 0;
*p_pic++ = 0; *p_pic++ = 0;
*p_pic++ = 0; *p_pic++ = 0;
*p_pic++ = 0; *p_pic++ = 0;
*p_pic++ = 0; *p_pic++ = 0;
*p_pic++ = 0; *p_pic++ = 0;
*p_pic++ = 0; *p_pic++ = 0;
*p_pic++ = 0; *p_pic++ = 0;
*p_pic++ = 0; *p_pic++ = 0;
*p_pic++ = 0; *p_pic++ = 0;
*p_pic++ = 0; *p_pic++ = 0;
*p_pic++ = 0; *p_pic++ = 0;
*p_pic++ = 0; *p_pic++ = 0;
*p_pic++ = 0; *p_pic++ = 0;
*p_pic++ = 0; *p_pic++ = 0;
}
/* Clear last pixels */
//??
}
vout_buffer_t * p_buffer; /* current buffer */
int i_area_begin, i_area_end; /* area vertical extension */
int i_area, i_area_copy; /* area index */
int i_area_shift; /* shift distance for areas */
/* Choose buffer and modify h to end of area position */
p_buffer = &p_vout->p_buffer[ p_vout->i_buffer_index ];
i_h += i_y - 1;
/******************************************************************************
* RenderPicture: render a picture
******************************************************************************
* This function convert a picture from a video heap to a pixel-encoded image
* and copy it to the current rendering buffer. No lock is required, since the
* rendered picture has been determined as existant, and will only be destroyed
* by the vout thread later.
******************************************************************************/
static int RenderPicture( vout_thread_t *p_vout, picture_t *p_pic, boolean_t b_blank )
{
int i_display_height, i_display_width; /* display dimensions */
int i_height, i_width; /* source picture dimensions */
int i_scaled_height; /* scaled height of the picture */
int i_aspect_scale; /* aspect ratio vertical scale */
int i_eol; /* end of line offset for source */
byte_t * p_convert_dst; /* convertion destination */
/*
* Remove part of the area which is inside the picture - this is done
* by calling again SetBufferArea with the correct areas dimensions.
*/
if( (i_x >= p_buffer->i_pic_x) && (i_x + i_w <= p_buffer->i_pic_x + p_buffer->i_pic_width) )
{
i_area_begin = p_buffer->i_pic_y;
i_area_end = i_area_begin + p_buffer->i_pic_height - 1;
#ifdef STATS
/* Start recording render time */
p_vout->render_time = mdate();
if( ((i_y >= i_area_begin) && (i_y <= i_area_end)) ||
((i_h >= i_area_begin) && (i_h <= i_area_end)) ||
((i_y < i_area_begin) && (i_h > i_area_end)) )
{
/* Keep the stripe above the picture, if any */
if( i_y < i_area_begin )
{
SetBufferArea( p_vout, i_x, i_y, i_w, i_area_begin - i_y );
}
/* Keep the stripe below the picture, if any */
if( i_h > i_area_end )
{
SetBufferArea( p_vout, i_x, i_area_end, i_w, i_h - i_area_end );
}
return;
}
}
/* Skip some extensions until interesting areas */
for( i_area = 0;
(i_area < p_buffer->i_areas) &&
(p_buffer->pi_area_end[i_area] + 1 <= i_y);
i_area++ )
{
;
}
if( i_area == p_buffer->i_areas )
{
/* New area is below all existing ones: just add it at the end of the
* array, if possible - else, append it to the last one */
if( i_area < VOUT_MAX_AREAS )
{
p_buffer->pi_area_begin[i_area] = i_y;
p_buffer->pi_area_end[i_area] = i_h;
p_buffer->i_areas++;
}
else
{
#ifdef DEBUG_VIDEO
intf_DbgMsg("areas overflow\n");
#endif
p_buffer->pi_area_end[VOUT_MAX_AREAS - 1] = i_h;
}
}
else
{
i_area_begin = p_buffer->pi_area_begin[i_area];
i_area_end = p_buffer->pi_area_end[i_area];
/* Mark last picture date */
p_vout->last_picture_date = p_pic->date;
i_width = p_pic->i_width;
i_height = p_pic->i_height;
i_display_width = p_vout->i_width;
i_display_height = p_vout->i_height;
if( i_y < i_area_begin )
{
if( i_h >= i_area_begin - 1 )
{
/* Extend area above */
p_buffer->pi_area_begin[i_area] = i_y;
}
else
{
/* Create a new area above : merge last area if overflow, then
* move all old areas down */
if( p_buffer->i_areas == VOUT_MAX_AREAS )
{
#ifdef DEBUG_VIDEO
intf_DbgMsg("areas overflow\n");
#endif
p_buffer->pi_area_end[VOUT_MAX_AREAS - 2] = p_buffer->pi_area_end[VOUT_MAX_AREAS - 1];
}
else
{
p_buffer->i_areas++;
}
for( i_area_copy = p_buffer->i_areas - 1; i_area_copy > i_area; i_area_copy++ )
{
p_buffer->pi_area_begin[i_area_copy] = p_buffer->pi_area_begin[i_area_copy - 1];
p_buffer->pi_area_end[i_area_copy] = p_buffer->pi_area_end[i_area_copy - 1];
}
p_buffer->pi_area_begin[i_area] = i_y;
p_buffer->pi_area_end[i_area] = i_h;
return;
}
}
if( i_h > i_area_end )
{
/* Find further areas which can be merged with the new one */
for( i_area_copy = i_area + 1;
(i_area_copy < p_buffer->i_areas) &&
(p_buffer->pi_area_begin[i_area] <= i_h);
i_area_copy++ )
{
;
}
i_area_copy--;
if( i_area_copy != i_area )
{
/* Merge with last possible areas */
p_buffer->pi_area_end[i_area] = MAX( i_h, p_buffer->pi_area_end[i_area_copy] );
/* Select scaling depending of aspect ratio */
/* Shift lower areas upward */
i_area_shift = i_area_copy - i_area;
p_buffer->i_areas -= i_area_shift;
for( i_area_copy = i_area + 1; i_area_copy < p_buffer->i_areas; i_area_copy++ )
{
p_buffer->pi_area_begin[i_area_copy] = p_buffer->pi_area_begin[i_area_copy + i_area_shift];
p_buffer->pi_area_end[i_area_copy] = p_buffer->pi_area_end[i_area_copy + i_area_shift];
}
}
else
{
/* Extend area below */
p_buffer->pi_area_end[i_area] = i_h;
}
}
}
}
/*******************************************************************************
* SetBufferPicture: clear buffer and set picture area
*******************************************************************************
* This function is called before any rendering. It clears the current
* rendering buffer and set the new picture area. If the picture pointer is
* NULL, then no picture area is defined. Floating operations are avoided since
* some MMX calculations may follow.
*******************************************************************************/
static void SetBufferPicture( vout_thread_t *p_vout, picture_t *p_pic )
{
vout_buffer_t * p_buffer; /* current buffer */
int i_pic_x, i_pic_y; /* picture position */
int i_pic_width, i_pic_height; /* picture dimensions */
int i_old_pic_y, i_old_pic_height; /* old picture area */
int i_vout_width, i_vout_height; /* display dimensions */
int i_area; /* area index */
int i_data_index; /* area data index */
int i_data_size; /* area data size, in 256 bytes blocs */
u64 * p_data; /* area data */
/* Choose buffer and set display dimensions */
p_buffer = &p_vout->p_buffer[ p_vout->i_buffer_index ];
i_vout_width = p_vout->i_width;
i_vout_height = p_vout->i_height;
/*
* Computes new picture size
*/
if( p_pic != NULL )
{
/* Try horizontal scaling first */
i_pic_width = ( p_vout->b_scale || (p_pic->i_width > i_vout_width)) ?
i_vout_width : p_pic->i_width;
i_pic_width = i_pic_width / 16 * 16; //?? currently, width must be multiple of 16
switch( p_pic->i_aspect_ratio )
{
case AR_3_4_PICTURE:
i_aspect_scale = (4 * i_height - 3 * i_width) ?
1 + 3 * i_width / ( 4 * i_height - 3 * i_width ) : 0;
i_pic_height = i_pic_width * 3 / 4;
break;
case AR_16_9_PICTURE:
i_aspect_scale = ( 16 * i_height - 9 * i_width ) ?
1 + 9 * i_width / ( 16 * i_height - 9 * i_width ) : 0;
i_pic_height = i_pic_width * 9 / 16;
break;
case AR_221_1_PICTURE:
i_aspect_scale = ( 221 * i_height - 100 * i_width ) ?
1 + 100 * i_width / ( 221 * i_height - 100 * i_width ) : 0;
i_pic_height = i_pic_width * 100 / 221;
break;
case AR_SQUARE_PICTURE:
default:
i_aspect_scale = 0;
i_pic_height = p_pic->i_height * i_pic_width / p_pic->i_width;
break;
}
i_scaled_height = (i_aspect_scale ? i_height * (i_aspect_scale - 1) / i_aspect_scale : i_height);
/* Crop picture if too large for the screen */
if( i_width > i_display_width )
/* If picture dimensions using horizontal scaling are too large, use
* vertical scaling */
if( i_pic_height > i_vout_height )
{
i_pic_height = ( p_vout->b_scale || (p_pic->i_height > i_vout_height)) ?
i_vout_height : p_pic->i_height;
switch( p_pic->i_aspect_ratio )
{
case AR_3_4_PICTURE:
i_pic_width = i_pic_height * 4 / 3;
break;
case AR_16_9_PICTURE:
i_pic_width = i_pic_height * 16 / 9;
break;
case AR_221_1_PICTURE:
i_pic_width = i_pic_height * 221 / 100;
break;
case AR_SQUARE_PICTURE:
default:
i_pic_width = p_pic->i_width * i_pic_height / p_pic->i_height;
break;
}
i_pic_width = i_pic_width / 16 * 16; //?? currently, width must be multiple of 16
}
/* Set picture position */
i_pic_x = (p_vout->i_width - i_pic_width) / 2;
i_pic_y = (p_vout->i_height - i_pic_height) / 2;
}
else
{
/* No picture: size is 0 */
i_pic_x = 0;
i_pic_y = 0;
i_pic_width = 0;
i_pic_height = 0;
}
/*
* Set new picture size - if is is smaller than the previous one, clear
* around it. Since picture are centered, only their size is tested.
*/
if( (p_buffer->i_pic_width > i_pic_width) || (p_buffer->i_pic_height > i_pic_height) )
{
i_eol = i_width - i_display_width / 16 * 16;
i_width = i_display_width / 16 * 16;
i_old_pic_y = p_buffer->i_pic_y;
i_old_pic_height = p_buffer->i_pic_height;
p_buffer->i_pic_x = i_pic_x;
p_buffer->i_pic_y = i_pic_y;
p_buffer->i_pic_width = i_pic_width;
p_buffer->i_pic_height = i_pic_height;
SetBufferArea( p_vout, 0, i_old_pic_y, p_vout->i_width, i_old_pic_height );
}
else
{
i_eol = 0;
p_buffer->i_pic_x = i_pic_x;
p_buffer->i_pic_y = i_pic_y;
p_buffer->i_pic_width = i_pic_width;
p_buffer->i_pic_height = i_pic_height;
}
if( i_scaled_height > i_display_height )
/*
* Clear areas
*/
for( i_area = 0; i_area < p_buffer->i_areas; i_area++ )
{
#ifdef DEBUG_VIDEO
intf_DbgMsg("clearing picture %p area: %d-%d\n", p_pic,
p_buffer->pi_area_begin[i_area], p_buffer->pi_area_end[i_area]);
#endif
p_data = (u64*) (p_buffer->p_data + p_vout->i_bytes_per_line * p_buffer->pi_area_begin[i_area]);
i_data_size = (p_buffer->pi_area_end[i_area] - p_buffer->pi_area_begin[i_area] + 1) *
p_vout->i_bytes_per_line / 256;
for( i_data_index = 0; i_data_index < i_data_size; i_data_index++ )
{
/* Clear 256 bytes block */
*p_data++ = 0; *p_data++ = 0; *p_data++ = 0; *p_data++ = 0;
*p_data++ = 0; *p_data++ = 0; *p_data++ = 0; *p_data++ = 0;
*p_data++ = 0; *p_data++ = 0; *p_data++ = 0; *p_data++ = 0;
*p_data++ = 0; *p_data++ = 0; *p_data++ = 0; *p_data++ = 0;
*p_data++ = 0; *p_data++ = 0; *p_data++ = 0; *p_data++ = 0;
*p_data++ = 0; *p_data++ = 0; *p_data++ = 0; *p_data++ = 0;
*p_data++ = 0; *p_data++ = 0; *p_data++ = 0; *p_data++ = 0;
*p_data++ = 0; *p_data++ = 0; *p_data++ = 0; *p_data++ = 0;
}
i_data_size = (p_buffer->pi_area_end[i_area] - p_buffer->pi_area_begin[i_area] + 1) *
p_vout->i_bytes_per_line % 256 / 4;
for( i_data_index = 0; i_data_index < i_data_size; i_data_index++ )
{
/* Clear remaining 4 bytes blocks */
*p_data++ = 0;
}
}
/*
* Clear areas array
*/
p_buffer->i_areas = 0;
}
/******************************************************************************
* RenderPicture: render a picture
******************************************************************************
* This function convert a picture from a video heap to a pixel-encoded image
* and copy it to the current rendering buffer. No lock is required, since the
* rendered picture has been determined as existant, and will only be destroyed
* by the vout thread later.
******************************************************************************/
static void RenderPicture( vout_thread_t *p_vout, picture_t *p_pic )
{
vout_buffer_t * p_buffer; /* rendering buffer */
byte_t * p_convert_dst; /* convertion destination */
int i_width, i_height, i_eol, i_pic_eol, i_scale; /* ?? tmp variables*/
/* Get and set rendering informations */
p_buffer = &p_vout->p_buffer[ p_vout->i_buffer_index ];
p_vout->last_picture_date = p_pic->date;
p_convert_dst = p_buffer->p_data + p_buffer->i_pic_x * p_vout->i_bytes_per_pixel +
p_buffer->i_pic_y * p_vout->i_bytes_per_line;
// ?? temporary section: rebuild aspect scale from size informations.
// ?? when definitive convertion prototype will be used, those info will
// ?? no longer be required
i_width = MIN( p_pic->i_width, p_buffer->i_pic_width );
i_eol = p_pic->i_width - i_width / 16 * 16;
i_pic_eol = p_vout->i_bytes_per_line / p_vout->i_bytes_per_pixel - i_width;
if( p_pic->i_height == p_buffer->i_pic_height )
{
i_scale = 0;
}
else
{
i_height = (i_aspect_scale * i_display_height / (i_aspect_scale - 1)) / 2 * 2;
i_scaled_height = i_display_height;
i_scale = p_pic->i_height / (p_pic->i_height - p_buffer->i_pic_height);
}
p_convert_dst = vout_SysGetPicture( p_vout ) +
( i_display_width - i_width ) / 2 * p_vout->i_bytes_per_pixel +
( i_display_height - i_scaled_height ) / 2 * p_vout->i_bytes_per_line;
i_eol = p_pic->i_width - p_buffer->i_pic_width;
i_height = p_pic->i_height * i_width / p_pic->i_width;
// ?? end of temporary code
/*
* Choose appropriate rendering function and render picture
......@@ -992,23 +1315,20 @@ static int RenderPicture( vout_thread_t *p_vout, picture_t *p_pic, boolean_t b_b
case YUV_420_PICTURE:
p_vout->p_ConvertYUV420( p_vout, p_convert_dst,
p_pic->p_y, p_pic->p_u, p_pic->p_v,
i_width, i_height, i_eol,
p_vout->i_bytes_per_line / p_vout->i_bytes_per_pixel - i_width,
i_aspect_scale, p_pic->i_matrix_coefficients );
i_width, i_height, i_eol, i_pic_eol, i_scale,
p_pic->i_matrix_coefficients );
break;
case YUV_422_PICTURE:
p_vout->p_ConvertYUV422( p_vout, p_convert_dst,
p_pic->p_y, p_pic->p_u, p_pic->p_v,
i_width, i_height, i_eol,
p_vout->i_bytes_per_line / p_vout->i_bytes_per_pixel - i_width,
i_aspect_scale, p_pic->i_matrix_coefficients );
i_width, i_height, i_eol, i_pic_eol, i_scale,
p_pic->i_matrix_coefficients );
break;
case YUV_444_PICTURE:
p_vout->p_ConvertYUV444( p_vout, p_convert_dst,
p_pic->p_y, p_pic->p_u, p_pic->p_v,
i_width, i_height, i_eol,
p_vout->i_bytes_per_line / p_vout->i_bytes_per_pixel - i_width,
i_aspect_scale, p_pic->i_matrix_coefficients );
i_width, i_height, i_eol, i_pic_eol, i_scale,
p_pic->i_matrix_coefficients );
break;
#ifdef DEBUG
default:
......@@ -1016,12 +1336,6 @@ static int RenderPicture( vout_thread_t *p_vout, picture_t *p_pic, boolean_t b_b
break;
#endif
}
#ifdef STATS
/* End recording render time */
p_vout->render_time = mdate() - p_vout->render_time;
#endif
return( 1 );
}
/******************************************************************************
......@@ -1030,9 +1344,11 @@ static int RenderPicture( vout_thread_t *p_vout, picture_t *p_pic, boolean_t b_b
* This function will print informations such as fps and other picture
* dependant informations.
******************************************************************************/
static int RenderPictureInfo( vout_thread_t *p_vout, picture_t *p_pic, boolean_t b_blank )
static void RenderPictureInfo( vout_thread_t *p_vout, picture_t *p_pic )
{
#if defined(STATS) || defined(DEBUG)
char psz_buffer[256]; /* string buffer */
#endif
#ifdef STATS
/*
......@@ -1041,16 +1357,16 @@ static int RenderPictureInfo( vout_thread_t *p_vout, picture_t *p_pic, boolean_t
if( p_vout->c_fps_samples > VOUT_FPS_SAMPLES )
{
sprintf( psz_buffer, "%.2f fps", (double) VOUT_FPS_SAMPLES * 1000000 /
( p_vout->fps_sample[ (p_vout->c_fps_samples - 1) % VOUT_FPS_SAMPLES ] -
p_vout->fps_sample[ p_vout->c_fps_samples % VOUT_FPS_SAMPLES ] ) );
( p_vout->p_fps_sample[ (p_vout->c_fps_samples - 1) % VOUT_FPS_SAMPLES ] -
p_vout->p_fps_sample[ p_vout->c_fps_samples % VOUT_FPS_SAMPLES ] ) );
Print( p_vout, p_vout->i_width, 0, 1, -1, psz_buffer );
}
/*
* Print frames count and loop time in upper left corner
*/
sprintf( psz_buffer, "%ld frames render time: %lu us",
p_vout->c_fps_samples, (long unsigned) p_vout->render_time );
sprintf( psz_buffer, "%ld frames rendering: %ld us",
(long) p_vout->c_fps_samples, (long) p_vout->render_time );
Print( p_vout, 0, 0, -1, -1, psz_buffer );
#endif
......@@ -1058,7 +1374,7 @@ static int RenderPictureInfo( vout_thread_t *p_vout, picture_t *p_pic, boolean_t
/*
* Print picture information in lower right corner
*/
sprintf( psz_buffer, "%s picture %dx%d (%dx%d%+d%+d %s)",
sprintf( psz_buffer, "%s picture %dx%d (%dx%d%+d%+d %s) -> %dx%d+%d+%d",
(p_pic->i_type == YUV_420_PICTURE) ? "4:2:0" :
((p_pic->i_type == YUV_422_PICTURE) ? "4:2:2" :
((p_pic->i_type == YUV_444_PICTURE) ? "4:4:4" : "ukn-type")),
......@@ -1068,33 +1384,25 @@ static int RenderPictureInfo( vout_thread_t *p_vout, picture_t *p_pic, boolean_t
(p_pic->i_aspect_ratio == AR_SQUARE_PICTURE) ? "sq" :
((p_pic->i_aspect_ratio == AR_3_4_PICTURE) ? "4:3" :
((p_pic->i_aspect_ratio == AR_16_9_PICTURE) ? "16:9" :
((p_pic->i_aspect_ratio == AR_221_1_PICTURE) ? "2.21:1" : "ukn-ar" ))));
((p_pic->i_aspect_ratio == AR_221_1_PICTURE) ? "2.21:1" : "ukn-ar" ))),
p_vout->p_buffer[ p_vout->i_buffer_index ].i_pic_width,
p_vout->p_buffer[ p_vout->i_buffer_index ].i_pic_height,
p_vout->p_buffer[ p_vout->i_buffer_index ].i_pic_x,
p_vout->p_buffer[ p_vout->i_buffer_index ].i_pic_y );
Print( p_vout, p_vout->i_width, p_vout->i_height, 1, 1, psz_buffer );
#endif
return( 0 );
}
/******************************************************************************
* RenderIdle: render idle picture
******************************************************************************
* This function will clear the display or print a logo.
* This function will print something on the screen.
******************************************************************************/
static int RenderIdle( vout_thread_t *p_vout, boolean_t b_blank )
static void RenderIdle( vout_thread_t *p_vout )
{
/* Blank screen if required */
if( (mdate() - p_vout->last_picture_date > VOUT_IDLE_DELAY) &&
(p_vout->last_picture_date > p_vout->last_display_date) &&
b_blank )
{
RenderBlank( p_vout );
p_vout->last_display_date = mdate();
//??
Print( p_vout, p_vout->i_width / 2, p_vout->i_height / 2, 0, 0,
"no stream" ); //??
return( 1 );
}
return( 0 );
}
/******************************************************************************
......@@ -1103,10 +1411,10 @@ static int RenderIdle( vout_thread_t *p_vout, boolean_t b_blank )
* This function render informations which do not depend of the current picture
* rendered.
******************************************************************************/
static int RenderInfo( vout_thread_t *p_vout, boolean_t b_blank )
static void RenderInfo( vout_thread_t *p_vout )
{
char psz_buffer[256]; /* string buffer */
#ifdef DEBUG
char psz_buffer[256]; /* string buffer */
int i_ready_pic = 0; /* ready pictures */
int i_reserved_pic = 0; /* reserved pictures */
int i_picture; /* picture index */
......@@ -1130,14 +1438,70 @@ static int RenderInfo( vout_thread_t *p_vout, boolean_t b_blank )
break;
}
}
sprintf( psz_buffer, "%dx%d:%d g%+.2f pic: %d/%d/%d",
p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth,
p_vout->f_gamma, i_reserved_pic, i_ready_pic,
VOUT_MAX_PICTURES );
sprintf( psz_buffer, "pic: %d/%d/%d",
i_reserved_pic, i_ready_pic, VOUT_MAX_PICTURES );
Print( p_vout, 0, p_vout->i_height, -1, 1, psz_buffer );
#endif
}
return( 0 );
/*******************************************************************************
* RenderSubtitle: render a subtitle
*******************************************************************************
* This function render a subtitle.
*******************************************************************************/
static void RenderSubtitle( vout_thread_t *p_vout, subtitle_t *p_sub )
{
//??
}
/*******************************************************************************
* RenderInterface: render the interface
*******************************************************************************
* This function render the interface, if any.
* ?? this is obviously only a temporary interface !
*******************************************************************************/
static void RenderInterface( vout_thread_t *p_vout )
{
int i_height, i_text_height; /* total and text height */
int i_width_1, i_width_2; /* text width */
int i_byte; /* byte index */
const char *psz_text_1 = "[1-9] Channel [i]nfo [c]olor [g/G]amma";
const char *psz_text_2 = "[+/-] Volume [m]ute [s]caling [Q]uit";
/* Get text size */
vout_TextSize( p_vout->p_large_font, OUTLINED_TEXT | TRANSPARENT_TEXT, psz_text_1, &i_width_1, &i_height );
vout_TextSize( p_vout->p_large_font, OUTLINED_TEXT | TRANSPARENT_TEXT, psz_text_2, &i_width_2, &i_text_height );
i_height += i_text_height;
/* Render background - effective background color will depend of the screen
* depth */
for( i_byte = (p_vout->i_height - i_height) * p_vout->i_bytes_per_line;
i_byte < p_vout->i_height * p_vout->i_bytes_per_line;
i_byte++ )
{
p_vout->p_buffer[ p_vout->i_buffer_index ].p_data[ i_byte ] = 0x33;
}
/* Render text, if not larger than screen */
if( i_width_1 < p_vout->i_width )
{
vout_Print( p_vout->p_large_font, p_vout->p_buffer[ p_vout->i_buffer_index ].p_data +
(p_vout->i_height - i_height) * p_vout->i_bytes_per_line,
p_vout->i_bytes_per_pixel, p_vout->i_bytes_per_line,
0xffffffff, 0x00000000, 0x00000000,
OUTLINED_TEXT | TRANSPARENT_TEXT, psz_text_1 );
}
if( i_width_2 < p_vout->i_width )
{
vout_Print( p_vout->p_large_font, p_vout->p_buffer[ p_vout->i_buffer_index ].p_data +
(p_vout->i_height - i_height + i_text_height) * p_vout->i_bytes_per_line,
p_vout->i_bytes_per_pixel, p_vout->i_bytes_per_line,
0xffffffff, 0x00000000, 0x00000000,
OUTLINED_TEXT | TRANSPARENT_TEXT, psz_text_2 );
}
/* Activate modified area */
SetBufferArea( p_vout, 0, p_vout->i_height - i_height, p_vout->i_width, i_height );
}
/******************************************************************************
......@@ -1147,6 +1511,14 @@ static int RenderInfo( vout_thread_t *p_vout, boolean_t b_blank )
******************************************************************************/
static int Manage( vout_thread_t *p_vout )
{
#ifdef DEBUG_VIDEO
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 );
}
#endif
/* On gamma or grayscale change, rebuild tables */
if( p_vout->i_changes & (VOUT_GAMMA_CHANGE | VOUT_GRAYSCALE_CHANGE) )
{
......@@ -1155,7 +1527,7 @@ static int Manage( vout_thread_t *p_vout )
/* Clear changes flags which does not need management or have been handled */
p_vout->i_changes &= ~(VOUT_GAMMA_CHANGE | VOUT_GRAYSCALE_CHANGE |
VOUT_INFO_CHANGE );
VOUT_INFO_CHANGE | VOUT_INTF_CHANGE | VOUT_SCALE_CHANGE );
/* Detect unauthorized changes */
if( p_vout->i_changes )
......
......@@ -175,7 +175,7 @@ static void PutByte32( u32 *p_pic, int i_byte, byte_t i_char, byte_t i_border, b
* This function will try to open a .psf font and load it. It will return
* NULL on error.
*******************************************************************************/
vout_font_t *vout_LoadFont( char *psz_name )
vout_font_t *vout_LoadFont( const char *psz_name )
{
int i_char, i_line; /* character and line indexes */
int i_file; /* source file */
......@@ -305,7 +305,7 @@ void vout_UnloadFont( vout_font_t *p_font )
* This function is used to align text. It returns the width and height of a
* given text.
*******************************************************************************/
void vout_TextSize( vout_font_t *p_font, int i_style, char *psz_text, int *pi_width, int *pi_height )
void vout_TextSize( vout_font_t *p_font, int i_style, const char *psz_text, int *pi_width, int *pi_height )
{
switch( p_font->i_type )
{
......@@ -333,7 +333,7 @@ void vout_TextSize( vout_font_t *p_font, int i_style, char *psz_text, int *pi_wi
* loaded bitmap font.
*******************************************************************************/
void vout_Print( vout_font_t *p_font, byte_t *p_pic, int i_bytes_per_pixel, int i_bytes_per_line,
u32 i_char_color, u32 i_border_color, u32 i_bg_color, int i_style, char *psz_text )
u32 i_char_color, u32 i_border_color, u32 i_bg_color, int i_style, const char *psz_text )
{
byte_t *p_char, *p_border; /* character and border mask data */
int i_char_mask, i_border_mask, i_bg_mask; /* masks */
......
......@@ -48,7 +48,6 @@ typedef struct vout_sys_s
GC gc; /* graphic context instance handler */
/* Display buffers and shared memory information */
int i_buffer_index; /* buffer index */
XImage * p_ximage[2]; /* XImage pointer */
XShmSegmentInfo shm_info[2]; /* shared memory zone information */
} vout_sys_t;
......@@ -157,8 +156,11 @@ int vout_SysInit( vout_thread_t *p_vout )
/* Set bytes per line */
p_vout->i_bytes_per_line = p_vout->p_sys->p_ximage[0]->bytes_per_line;
/* Set buffer index to 0 */
p_vout->p_sys->i_buffer_index = 0;
/* Set and initialize buffers */
p_vout->p_buffer[0].p_data = p_vout->p_sys->p_ximage[ 0 ]->data;
p_vout->p_buffer[1].p_data = p_vout->p_sys->p_ximage[ 1 ]->data;
vout_ClearBuffer( p_vout, &p_vout->p_buffer[0] );
vout_ClearBuffer( p_vout, &p_vout->p_buffer[1] );
return( 0 );
}
......@@ -222,7 +224,7 @@ int vout_SysManage( vout_thread_t *p_vout )
intf_ErrMsg("error: can't resize display\n");
return( 1 );
}
intf_Msg("Video display resized to %dx%d\n", p_vout->i_width, p_vout->i_height);
intf_Msg("Video display resized (%dx%d)\n", p_vout->i_width, p_vout->i_height);
}
return 0;
......@@ -240,10 +242,10 @@ void vout_SysDisplay( vout_thread_t *p_vout )
{
/* Display rendered image using shared memory extension */
XShmPutImage(p_vout->p_sys->p_display, p_vout->p_sys->window, p_vout->p_sys->gc,
p_vout->p_sys->p_ximage[ p_vout->p_sys->i_buffer_index ],
p_vout->p_sys->p_ximage[ p_vout->i_buffer_index ],
0, 0, 0, 0,
p_vout->p_sys->p_ximage[ p_vout->p_sys->i_buffer_index ]->width,
p_vout->p_sys->p_ximage[ p_vout->p_sys->i_buffer_index ]->height, True);
p_vout->p_sys->p_ximage[ p_vout->i_buffer_index ]->width,
p_vout->p_sys->p_ximage[ p_vout->i_buffer_index ]->height, True);
/* Send the order to the X server */
XFlush(p_vout->p_sys->p_display);
......@@ -251,27 +253,14 @@ void vout_SysDisplay( vout_thread_t *p_vout )
else /* regular X11 capabilities are used */
{
XPutImage(p_vout->p_sys->p_display, p_vout->p_sys->window, p_vout->p_sys->gc,
p_vout->p_sys->p_ximage[ p_vout->p_sys->i_buffer_index ],
p_vout->p_sys->p_ximage[ p_vout->i_buffer_index ],
0, 0, 0, 0,
p_vout->p_sys->p_ximage[ p_vout->p_sys->i_buffer_index ]->width,
p_vout->p_sys->p_ximage[ p_vout->p_sys->i_buffer_index ]->height);
p_vout->p_sys->p_ximage[ p_vout->i_buffer_index ]->width,
p_vout->p_sys->p_ximage[ p_vout->i_buffer_index ]->height);
/* Send the order to the X server */
XFlush(p_vout->p_sys->p_display);
}
/* Swap buffers */
p_vout->p_sys->i_buffer_index = ++p_vout->p_sys->i_buffer_index & 1;
}
/*******************************************************************************
* vout_SysGetPicture: get current display buffer informations
*******************************************************************************
* This function returns the address of the current display buffer.
*******************************************************************************/
void * vout_SysGetPicture( vout_thread_t *p_vout )
{
return( p_vout->p_sys->p_ximage[ p_vout->p_sys->i_buffer_index ]->data );
}
/* following functions are local */
......
......@@ -10,8 +10,8 @@
/*******************************************************************************
* Preamble
*******************************************************************************/
#include <errno.h>
#include <math.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
......@@ -46,6 +46,7 @@ const int MATRIX_COEFFICIENTS_TABLE[8][4] =
*******************************************************************************/
static int BinaryLog ( u32 i );
static void MaskToShift ( int *pi_right, int *pi_left, u32 i_mask );
static void SetGammaTable ( int *pi_table, double f_gamma );
static void SetTables ( vout_thread_t *p_vout );
static void ConvertY4Gray16 ( p_vout_thread_t p_vout, u16 *p_pic, yuv_data_t *p_y, yuv_data_t *p_u, yuv_data_t *p_v,
......@@ -387,23 +388,37 @@ static void MaskToShift (int *pi_right, int *pi_left, u32 i_mask)
}
/*******************************************************************************
* SetTables: compute tables and set function pointers
* SetGammaTable: return intensity table transformed by gamma curve.
*******************************************************************************
* pi_table is a table of 256 entries from 0 to 255.
*******************************************************************************/
static void SetGammaTable( int *pi_table, double f_gamma )
{
int i_y; /* base intensity */
/* Use exp(gamma) instead of gamma */
f_gamma = exp(f_gamma );
/* Build gamma table */
for( i_y = 0; i_y < 256; i_y++ )
{
pi_table[ i_y ] = pow( (double)i_y / 256, f_gamma ) * 256;
}
}
/*******************************************************************************
* SetTables: compute tables and set function pointers
+ *******************************************************************************/
static void SetTables( vout_thread_t *p_vout )
{
u8 i_gamma[256]; /* gamma table */
int pi_gamma[256]; /* gamma table */
int i_index; /* index in tables */
int i_red_right, i_red_left; /* red shifts */
int i_green_right, i_green_left; /* green shifts */
int i_blue_right, i_blue_left; /* blue shifts */
/*
* Build gamma table
*/
for( i_index = 0; i_index < 256; i_index++ )
{
i_gamma[i_index] = 255. * pow( (double)i_index / 255., exp(p_vout->f_gamma) );
}
/* Build gamma table */
SetGammaTable( pi_gamma, p_vout->f_gamma );
/*
* Set color masks and shifts
......@@ -447,9 +462,9 @@ static void SetTables( vout_thread_t *p_vout )
for( i_index = -384; i_index < 640; i_index++)
{
p_vout->tables.yuv.gray16.p_gray[ i_index ] =
((i_gamma[CLIP_BYTE( i_index )] >> i_red_right) << i_red_left) |
((i_gamma[CLIP_BYTE( i_index )] >> i_green_right) << i_green_left) |
((i_gamma[CLIP_BYTE( i_index )] >> i_blue_right) << i_blue_left);
((pi_gamma[CLIP_BYTE( i_index )] >> i_red_right) << i_red_left) |
((pi_gamma[CLIP_BYTE( i_index )] >> i_green_right) << i_green_left) |
((pi_gamma[CLIP_BYTE( i_index )] >> i_blue_right) << i_blue_left);
}
break;
case 24:
......@@ -458,9 +473,9 @@ static void SetTables( vout_thread_t *p_vout )
for( i_index = -384; i_index < 640; i_index++)
{
p_vout->tables.yuv.gray32.p_gray[ i_index ] =
((i_gamma[CLIP_BYTE( i_index )] >> i_red_right) << i_red_left) |
((i_gamma[CLIP_BYTE( i_index )] >> i_green_right) << i_green_left) |
((i_gamma[CLIP_BYTE( i_index )] >> i_blue_right) << i_blue_left);
((pi_gamma[CLIP_BYTE( i_index )] >> i_red_right) << i_red_left) |
((pi_gamma[CLIP_BYTE( i_index )] >> i_green_right) << i_green_left) |
((pi_gamma[CLIP_BYTE( i_index )] >> i_blue_right) << i_blue_left);
}
break;
}
......@@ -477,9 +492,9 @@ static void SetTables( vout_thread_t *p_vout )
p_vout->tables.yuv.rgb16.p_blue = (u16 *)p_vout->tables.p_base + 2*1024 + 384;
for( i_index = -384; i_index < 640; i_index++)
{
p_vout->tables.yuv.rgb16.p_red[i_index] = (i_gamma[CLIP_BYTE(i_index)]>>i_red_right)<<i_red_left;
p_vout->tables.yuv.rgb16.p_green[i_index] = (i_gamma[CLIP_BYTE(i_index)]>>i_green_right)<<i_green_left;
p_vout->tables.yuv.rgb16.p_blue[i_index] = (i_gamma[CLIP_BYTE(i_index)]>>i_blue_right)<<i_blue_left;
p_vout->tables.yuv.rgb16.p_red[i_index] = (pi_gamma[CLIP_BYTE(i_index)]>>i_red_right)<<i_red_left;
p_vout->tables.yuv.rgb16.p_green[i_index] = (pi_gamma[CLIP_BYTE(i_index)]>>i_green_right)<<i_green_left;
p_vout->tables.yuv.rgb16.p_blue[i_index] = (pi_gamma[CLIP_BYTE(i_index)]>>i_blue_right)<<i_blue_left;
}
break;
case 24:
......@@ -489,9 +504,9 @@ static void SetTables( vout_thread_t *p_vout )
p_vout->tables.yuv.rgb32.p_blue = (u32 *)p_vout->tables.p_base + 2*1024 + 384;
for( i_index = -384; i_index < 640; i_index++)
{
p_vout->tables.yuv.rgb32.p_red[i_index] = (i_gamma[CLIP_BYTE(i_index)]>>i_red_right)<<i_red_left;
p_vout->tables.yuv.rgb32.p_green[i_index] = (i_gamma[CLIP_BYTE(i_index)]>>i_green_right)<<i_green_left;
p_vout->tables.yuv.rgb32.p_blue[i_index] = (i_gamma[CLIP_BYTE(i_index)]>>i_blue_right)<<i_blue_left;
p_vout->tables.yuv.rgb32.p_red[i_index] = (pi_gamma[CLIP_BYTE(i_index)]>>i_red_right)<<i_red_left;
p_vout->tables.yuv.rgb32.p_green[i_index] = (pi_gamma[CLIP_BYTE(i_index)]>>i_green_right)<<i_green_left;
p_vout->tables.yuv.rgb32.p_blue[i_index] = (pi_gamma[CLIP_BYTE(i_index)]>>i_blue_right)<<i_blue_left;
}
break;
}
......
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