Commit 57429088 authored by Vincent Seguin's avatar Vincent Seguin

Integration de display.c � vout.

Mise au point du driver X11 (plus de XShm error).
Incrustation de texte en X11, calcul des FPS, etc...
Int�gration de la conversion MMX.
Mode 'niveaux de gris' pour les machines lentes non MMX (les pauvres !)
Attention: les drivers GGI et FB ne sont pas � jour...
parent cf9e7c61
......@@ -5,3 +5,4 @@ gmon.out
vlc
vlc.init
vlc-debug.log
vlc-debug.ct
......@@ -215,7 +215,7 @@ endif
ifeq ($(ARCH),MMX)
ASM_OBJ = video_decoder_ref/idctmmx.o \
video_decoder_ref/yuv12-rgb16.o
video_output/yuv-mmx.o
endif
C_OBJ = $(interface_obj) \
......
......@@ -60,7 +60,7 @@
//#define MPEG2_COMPLIANT
/* Define for profiling support */
//#define STATS
#define STATS
/* Define for unthreaded version of the program - ?? not yet implemented */
//#define NO_THREAD
......@@ -230,6 +230,13 @@
* (~1 Mbyte) before using huge values */
#define VOUT_MAX_PICTURES 10
/* Environment variable for grayscale output mode, and default value */
#define VOUT_GRAYSCALE_VAR "vlc_grayscale"
#define VOUT_GRAYSCALE_DEFAULT 0
/* Number of pictures required to computes the FPS rate */
#define VOUT_FPS_SAMPLES 5
/*
* Time settings
*/
......@@ -237,7 +244,7 @@
/* Time during which the thread will sleep if it has nothing to
* display (in micro-seconds) */
/* ?? this constant will probably evolve to a calculated value */
#define VOUT_IDLE_SLEEP 50000
#define VOUT_IDLE_SLEEP 20000
/* Maximum lap of time allowed between the beginning of rendering and
* display. If, compared to the current date, the next image is too
......@@ -245,7 +252,7 @@
* at least VOUT_IDLE_SLEEP plus the time required to render a few
* images, to avoid trashing of decoded images */
/* ?? this constant will probably evolve to a calculated value */
#define VOUT_DISPLAY_DELAY 150000
#define VOUT_DISPLAY_DELAY 100000
/*
* Framebuffer settings
......@@ -262,6 +269,11 @@
/* Allow use of X11 XShm (shared memory) extension if possible */
#define VOUT_XSHM 1
/* Font maximum and minimum characters - characters outside this range are not
* printed - maximum range is 0-256 */
#define VOUT_MIN_CHAR 1
#define VOUT_MAX_CHAR 128
/*******************************************************************************
* Video parser configuration
*******************************************************************************/
......@@ -363,12 +375,12 @@
/* Maximal size of the message queue - in case of overflow, all messages in the
* queue are printed by the calling thread */
#define INTF_MSG_QSIZE 32
#define INTF_MSG_QSIZE 64
/* 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
......
......@@ -45,4 +45,5 @@ extern main_t *p_main;
*******************************************************************************/
int main_GetIntVariable( char *psz_name, int i_default );
char * main_GetPszVariable( char *psz_name, char *psz_default );
void main_PutIntVariable( char *psz_name, int i_value );
void main_PutPszVariable( char *psz_name, char *psz_value );
......@@ -14,7 +14,7 @@
/*******************************************************************************
* yuv_data_t: type for storing one Y, U or V sample.
*******************************************************************************/
typedef s16 yuv_data_t;
typedef u8 yuv_data_t;
/*******************************************************************************
* picture_t: video picture
......
......@@ -25,8 +25,11 @@ typedef struct vout_thread_s
int * pi_status; /* temporary status flag */
/* Common display properties */
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 */
int i_bytes_per_pixel; /* real screen depth */
float f_x_ratio; /* horizontal display ratio */
......@@ -34,9 +37,18 @@ typedef struct vout_thread_s
#ifdef STATS
/* Statistics */
count_t c_loops; /* number of loops */
count_t c_idle_loops; /* number of idle loops */
count_t c_pictures; /* number of pictures added to heap */
count_t c_loops; /* number of loops */
count_t c_idle_loops; /* number of idle loops */
count_t c_pictures; /* number of pictures added to heap */
/* FPS */
mtime_t fps_sample[ VOUT_FPS_SAMPLES ]; /* samples dates */
int i_fps_index; /* index in samples */
#endif
#ifdef DEBUG_VIDEO
/* Video debugging informations */
mtime_t picture_render_time; /* last picture rendering time */
#endif
/* Output method */
......@@ -49,12 +61,12 @@ typedef struct vout_thread_s
/* YUV translation tables, for 15,16 and 24/32 bpp displays. 16 bits and 32
* bits pointers points on the same data.
* CAUTION: these tables are translated: their origin is -384 */
u16 * pi_trans16_red;
u16 * pi_trans16_green;
u16 * pi_trans16_blue;
u32 * pi_trans32_red;
u32 * pi_trans32_green;
u32 * pi_trans32_blue;
u16 * pi_trans16_red;
u16 * pi_trans16_green;
u16 * pi_trans16_blue;
u32 * pi_trans32_red;
u32 * pi_trans32_green;
u32 * pi_trans32_blue;
} vout_thread_t;
/*******************************************************************************
......
......@@ -16,6 +16,10 @@ 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 );
byte_t * vout_SysGetPicture ( p_vout_thread_t p_vout, int *pi_eol_offset );
byte_t * vout_SysGetPicture ( p_vout_thread_t p_vout );
void vout_SysPrint ( p_vout_thread_t p_vout, int i_x, int i_y,
int i_halign, int i_valign,
unsigned char *psz_text );
......@@ -68,15 +68,12 @@
/* Video */
#include "video.h"
#include "video_sys.h"
#include "video_output.h"
#include "video_decoder.h"
/* Interface */
#include "intf_cmd.h"
#include "intf_ctrl.h"
#include "intf_sys.h"
#include "intf_console.h"
#include "interface.h"
#include "main.h"
......
......@@ -119,8 +119,8 @@ p_intf_msg_t intf_MsgCreate( void )
{
#ifdef INTF_MSG_QUEUE
/* Message queue initialization */
vlc_mutex_init( &p_intf_msg->lock ); /* intialize lock */
p_intf_msg->i_count = 0; /* queue is empty */
vlc_mutex_init( &p_msg->lock ); /* intialize lock */
p_msg->i_count = 0; /* queue is empty */
#endif
#ifdef DEBUG_LOG
......@@ -293,9 +293,9 @@ void _intf_DbgMsgImm( char *psz_file, char *psz_function, int i_line,
#ifdef INTF_MSG_QUEUE
void intf_FlushMsg( void )
{
vlc_mutex_lock( &p_program_data->intf_msg.lock ); /* get lock */
FlushLockedMsg( &p_program_data->intf_msg ); /* flush messages */
vlc_mutex_unlock( &p_program_data->intf_msg.lock ); /* give lock back */
vlc_mutex_lock( &p_main->p_msg->lock ); /* get lock */
FlushLockedMsg( p_main->p_msg ); /* flush messages */
vlc_mutex_unlock( &p_main->p_msg->lock ); /* give lock back */
}
#endif
......@@ -325,7 +325,7 @@ static void QueueMsg( intf_msg_t *p_msg, int i_type, char *psz_format, va_list a
vasprintf( &psz_str, psz_format, ap );
if( psz_str == NULL )
{
fprintf(stderr, "Warning: can't store following message (%s): ",
fprintf(stderr, "warning: can't store following message (%s): ",
strerror(errno) );
vfprintf(stderr, psz_format, ap );
exit( errno );
......@@ -336,7 +336,7 @@ static void QueueMsg( intf_msg_t *p_msg, int i_type, char *psz_format, va_list a
if( p_msg->i_count == INTF_MSG_QSIZE ) /* flush queue if needed */
{
#ifdef DEBUG /* in debug mode, queue overflow causes a warning */
fprintf(stderr, "Warning: message queue overflow\n" );
fprintf(stderr, "warning: message queue overflow\n" );
#endif
FlushLockedMsg( p_msg );
}
......@@ -381,7 +381,7 @@ static void QueueDbgMsg(intf_msg_t *p_msg, char *psz_file, char *psz_function,
vasprintf( &psz_str, psz_format, ap );
if( psz_str == NULL )
{
fprintf(stderr, "Warning: can't store following message (%s): ",
fprintf(stderr, "warning: can't store following message (%s): ",
strerror(errno) );
fprintf(stderr, INTF_MSG_DBG_FORMAT, psz_file, psz_function, i_line );
vfprintf(stderr, psz_format, ap );
......@@ -393,7 +393,7 @@ static void QueueDbgMsg(intf_msg_t *p_msg, char *psz_file, char *psz_function,
if( p_msg->i_count == INTF_MSG_QSIZE ) /* flush queue if needed */
{
#ifdef DEBUG /* in debug mode, queue overflow causes a warning */
fprintf(stderr, "Warning: message queue overflow\n" );
fprintf(stderr, "warning: message queue overflow\n" );
#endif
FlushLockedMsg( p_msg );
}
......@@ -481,7 +481,7 @@ static void PrintMsg( intf_msg_item_t *p_msg )
/* Check if formatting function suceeded */
if( psz_msg == NULL )
{
fprintf( stderr, "intf error: *** can not format message (%s): %s ***\n",
fprintf( stderr, "error: can not format message (%s): %s\n",
strerror( errno ), p_msg->psz_msg );
return;
}
......@@ -519,7 +519,7 @@ static void PrintMsg( intf_msg_item_t *p_msg )
#else
static void PrintMsg( interface_msg_message_t *p_msg )
static void PrintMsg( intf_msg_item_t *p_msg )
{
/*
* Print messages on screen
......@@ -534,8 +534,7 @@ static void PrintMsg( interface_msg_message_t *p_msg )
fprintf( stderr, p_msg->psz_msg );
break;
case INTF_MSG_INTF: /* interface messages */
intf_PrintXConsole( &p_main->intf_thread.xconsole,
p_msg->psz_msg );
intf_ConsolePrint( p_main->p_intf->p_console, p_msg->psz_msg );
break;
}
}
......
......@@ -38,16 +38,11 @@
#define OPT_NOAUDIO 150
#define OPT_STEREO 151
#define OPT_MONO 152
#define OPT_RATE 153
#define OPT_NOVIDEO 160
#define OPT_XDGA 161
#define OPT_XSHM 162
#define OPT_XNOSHM 163
#define OPT_XNODGA 164
#define OPT_COLOR 161
#define OPT_NOVLANS 170
#define OPT_VLAN_SERVER 171
/* Long options */
static const struct option longopts[] =
......@@ -64,6 +59,8 @@ static const struct option longopts[] =
/* Video options */
{ "novideo", 0, 0, OPT_NOVIDEO },
{ "grayscale", 0, 0, 'g' },
{ "color", 0, 0, OPT_COLOR },
/* VLAN management options */
{ "novlans", 0, 0, OPT_NOVLANS },
......@@ -72,7 +69,7 @@ static const struct option longopts[] =
};
/* Short options */
static const char *psz_shortopts = "h";
static const char *psz_shortopts = "hg";
/*******************************************************************************
* Global variable program_data - this is the one and only, see main.h
......@@ -187,18 +184,19 @@ int main( int i_argc, char *ppsz_argv[], char *ppsz_env[] )
*******************************************************************************/
int main_GetIntVariable( char *psz_name, int i_default )
{
char *psz_env;
char * psz_env; /* environment value */
char * psz_end; /* end of parsing index */
long int i_value; /* value */
psz_env = getenv( psz_name );
if( psz_env )
{
psz_env = strchr( psz_env, '=' );
if( psz_env )
{
return( atoi( psz_env + 1) );
}
{
i_value = strtol( psz_env, &psz_end, 0 );
if( (*psz_env != '\0') && (*psz_end == '\0') )
{
return( i_value );
}
}
return( i_default );
}
......@@ -214,16 +212,52 @@ char * main_GetPszVariable( char *psz_name, char *psz_default )
psz_env = getenv( psz_name );
if( psz_env )
{
psz_env = strchr( psz_env, '=' );
if( psz_env )
{
return( psz_env + 1 );
}
return( psz_env );
}
return( psz_default );
}
/*******************************************************************************
* main_PutPszVariable: set the string value of an environment variable
*******************************************************************************
* This function is used to set some default parameters in modules. The use of
* this function will cause some memory leak: since some systems use the pointer
* passed to putenv to store the environment string, it can't be freed.
*******************************************************************************/
void main_PutPszVariable( char *psz_name, char *psz_value )
{
char *psz_env;
psz_env = malloc( strlen(psz_name) + strlen(psz_value) + 2 );
if( psz_env == NULL )
{
intf_ErrMsg("error: %s\n", strerror(ENOMEM));
}
else
{
sprintf( psz_env, "%s=%s", psz_name, psz_value );
if( putenv( psz_env ) )
{
intf_ErrMsg("error: %s\n", strerror(errno));
}
}
}
/*******************************************************************************
* main_PutIntVariable: set the integer value of an environment variable
*******************************************************************************
* This function is used to set some default parameters in modules. The use of
* this function will cause some memory leak: since some systems use the pointer
* passed to putenv to store the environment string, it can't be freed.
*******************************************************************************/
void main_PutIntVariable( char *psz_name, int i_value )
{
char psz_value[ 256 ]; /* buffer for value */
sprintf(psz_value, "%d", i_value );
main_PutPszVariable( psz_name, psz_value );
}
/* following functions are local */
/*******************************************************************************
......@@ -299,19 +333,23 @@ static int GetConfiguration( int i_argc, char *ppsz_argv[], char *ppsz_env[] )
case OPT_NOAUDIO: /* --noaudio */
p_main->b_audio = 0;
break;
case OPT_STEREO: /* --stereo */
// ?? should be replaced by a putenv
//p_main->p_aout->dsp.b_stereo = 1;
case OPT_STEREO: /* --stereo */
main_PutIntVariable( AOUT_STEREO_VAR, 1 );
break;
case OPT_MONO: /* --mono */
// ?? should be replaced by a putenv
//p_main->p_aout->dsp.b_stereo = 0;
main_PutIntVariable( AOUT_STEREO_VAR, 0 );
break;
/* Video options */
case OPT_NOVIDEO: /* --novideo */
p_main->b_video = 0;
break;
case 'g': /* -g, --grayscale */
main_PutIntVariable( VOUT_GRAYSCALE_VAR, 1 );
break;
case OPT_COLOR: /* --color */
main_PutIntVariable( VOUT_GRAYSCALE_VAR, 0 );
break;
/* VLAN management options */
case OPT_NOVLANS: /* --novlans */
......@@ -352,10 +390,12 @@ static void Usage( void )
/* Options */
intf_Msg("Options:" \
" -h, --help print usage\n" \
" -g, --grayscale grayscale video\n" \
" --noaudio disable audio\n" \
" --stereo enable stereo\n" \
" --mono disable stereo\n"
" --novideo disable video\n" \
" --color color video\n" \
" --novlans disable vlans\n" \
);
......@@ -374,6 +414,7 @@ static void Usage( void )
/* Video parameters */
intf_Msg("Video parameters:\n" \
" " VOUT_FB_DEV_VAR "=<filename> framebuffer device path\n" \
" " VOUT_GRAYSCALE_VAR "={1|0} grayscale or color output\n" \
);
/* Vlan parameters */
......
......@@ -12,6 +12,7 @@
* Preamble
******************************************************************************/
#include <stdio.h>
#include <unistd.h>
#include <sys/time.h>
#include "common.h"
......@@ -82,24 +83,25 @@ void mwait( mtime_t date )
{
return;
}
#ifndef usleep
tv_delay.tv_sec = delay / 1000000;
tv_delay.tv_usec = delay % 1000000;
/* see msleep() about select() errors */
select( 0, NULL, NULL, NULL, &tv_delay );
#else
usleep( delay );
#endif
}
/******************************************************************************
* msleep: more precise sleep() (inline function) (ok ?)
******************************************************************************
* This function uses select() in a classical way to implement a sleep() call
* with a microsecond precision.
* For synchronization purposes, mwait() should be prefered.
******************************************************************************
* ?? decalre as inline
* Portable usleep() function.
******************************************************************************/
void msleep( mtime_t delay )
{
#ifndef usleep
struct timeval tv_delay;
tv_delay.tv_sec = delay / 1000000;
......@@ -109,4 +111,7 @@ void msleep( mtime_t delay )
* (i.e. when a signal is sent to the thread, or when memory is full), and
* can be ingnored. */
select( 0, NULL, NULL, NULL, &tv_delay );
#else
usleep( delay );
#endif
}
......@@ -137,13 +137,10 @@ void vout_SysDisplay( vout_thread_t *p_vout )
/*******************************************************************************
* vout_SysGetPicture: get current display buffer informations
*******************************************************************************
* This function returns the address of the current display buffer, and the
* number of samples per line. For 15, 16 and 32 bits displays, this value is
* the number of pixels in a line.
* This function returns the address of the current display buffer.
*******************************************************************************/
byte_t * vout_SysGetPicture( vout_thread_t *p_vout, int *pi_eol_offset )
byte_t * vout_SysGetPicture( vout_thread_t *p_vout )
{
*pi_eol_offset = p_vout->i_width;
//????
// return( p_vout->p_sys->p_ximage[ p_vout->p_sys->i_buffer_index ].data );
}
......
/*******************************************************************************
* video_output.c : video output thread
* (c)1999 VideoLAN
* (c)2000 VideoLAN
*******************************************************************************
* This module describes the programming interface for video output threads.
* It includes functions allowing to open a new thread, send pictures to a
......@@ -27,6 +27,7 @@
#include "video_output.h"
#include "video_sys.h"
#include "intf_msg.h"
#include "main.h"
/*******************************************************************************
* Macros
......@@ -36,6 +37,25 @@
* (0 or 255) */
#define CLIP_BYTE( i_val ) ( (i_val < 0) ? 0 : ((i_val > 255) ? 255 : i_val) )
/* YUV_GRAYSCALE: parametric macro for YUV grayscale transformation.
* Due to the high performance need of this loop, all possible conditions
* evaluations are made outside the transformation loop. However, the code does
* not change much for two different loops. This macro allows to change slightly
* the content of the loop without having to copy and paste code. It is used in
* RenderYUVPicture function. */
#define YUV_GRAYSCALE( TRANS_RED, TRANS_GREEN, TRANS_BLUE, P_PIC ) \
/* Main loop */ \
for (i_pic_y=0; i_pic_y < p_pic->i_height ; i_pic_y++) \
{ \
for (i_pic_x=0; i_pic_x< p_pic->i_width; i_pic_x++) \
{ \
i_y = *p_y++; \
*P_PIC++ = TRANS_RED[i_y] | TRANS_GREEN[i_y] | TRANS_BLUE[i_y]; \
} \
/* Skip until beginning of next line */ \
P_PIC += i_eol_offset; \
}
/* YUV_TRANSFORM: parametric macro for YUV transformation.
* Due to the high performance need of this loop, all possible conditions
* evaluations are made outside the transformation loop. However, the code does
......@@ -70,11 +90,11 @@ for (i_pic_y=0; i_pic_y < p_pic->i_height ; i_pic_y++) \
} \
if( (CHROMA == 420) && !(i_pic_y & 0x1) ) \
{ \
p_u -= p_pic->i_width; \
p_v -= p_pic->i_width; \
p_u -= i_chroma_width; \
p_v -= i_chroma_width; \
} \
/* Skip until beginning of next line */ \
P_PIC += i_pic_eol_offset - p_pic->i_width; \
P_PIC += i_eol_offset; \
}
/*******************************************************************************
......@@ -82,7 +102,7 @@ for (i_pic_y=0; i_pic_y < p_pic->i_height ; i_pic_y++) \
*******************************************************************************/
/* RGB/YUV inversion matrix (ISO/IEC 13818-2 section 6.3.6, table 6.9) */
int matrix_coefficients_table[8][4] =
const int MATRIX_COEFFICIENTS_TABLE[8][4] =
{
{117504, 138453, 13954, 34903}, /* no sequence_display_extension */
{117504, 138453, 13954, 34903}, /* ITU-R Rec. 709 (1990) */
......@@ -94,15 +114,40 @@ int matrix_coefficients_table[8][4] =
{117579, 136230, 16907, 35559} /* SMPTE 240M (1987) */
};
/*******************************************************************************
* External prototypes
*******************************************************************************/
#ifdef HAVE_MMX
/* YUV transformations for MMX - in yuv-mmx.S
* p_y, p_u, p_v: Y U and V planes
* i_width, i_height: frames dimensions (pixels)
* i_ypitch, i_vpitch: Y and V lines sizes (bytes)
* i_aspect: vertical aspect factor
* pi_pic: RGB frame
* i_dci_offset: ?? x offset for left image border
* i_offset_to_line_0: ?? x offset for left image border
* i_pitch: RGB line size (bytes)
* i_colortype: 0 for 565, 1 for 555 */
void vout_YUV420_16_MMX( u8* p_y, u8* p_u, u8 *p_v,
unsigned int i_width, unsigned int i_height,
unsigned int i_ypitch, unsigned int i_vpitch,
unsigned int i_aspect, u8 *pi_pic,
u32 i_dci_offset, u32 i_offset_to_line_0,
int CCOPitch, int i_colortype );
#endif
/*******************************************************************************
* Local prototypes
*******************************************************************************/
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 RenderPicture ( vout_thread_t *p_vout, picture_t *p_pic );
static void RenderYUVPicture( vout_thread_t *p_vout, picture_t *p_pic );
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 RenderPicture ( vout_thread_t *p_vout, picture_t *p_pic );
static void RenderYUVGrayPicture ( vout_thread_t *p_vout, picture_t *p_pic );
static void RenderYUV16Picture ( vout_thread_t *p_vout, picture_t *p_pic );
static void RenderYUV32Picture ( vout_thread_t *p_vout, picture_t *p_pic );
static void RenderInfo ( vout_thread_t *p_vout );
/*******************************************************************************
* vout_CreateThread: creates a new video output thread
......@@ -132,15 +177,20 @@ vout_thread_t * vout_CreateThread (
/* Initialize some fields used by the system-dependant method - these fields will
* probably be modified by the method */
p_vout->b_info = 0;
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_x_ratio = 1;
p_vout->f_y_ratio = 1;
intf_DbgMsg("wished configuration: %dx%dx%d (%d bytes per pixel), ratio %f:%f\n",
intf_DbgMsg("wished configuration: %dx%d,%d (%d bytes/pixel, %d bytes/line), ratio %.2f:%.2f, gray=%d\n",
p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth,
p_vout->i_bytes_per_pixel, p_vout->f_x_ratio, p_vout->f_y_ratio );
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 );
/* Create and initialize system-dependant method - this function issues its
* own error messages */
......@@ -153,9 +203,10 @@ vout_thread_t * vout_CreateThread (
free( p_vout );
return( NULL );
}
intf_DbgMsg("actual configuration: %dx%dx%d (%d bytes per pixel), ratio %f:%f\n",
intf_DbgMsg("actual configuration: %dx%d,%d (%d bytes/pixel, %d bytes/line), ratio %.2f:%.2f, gray=%d\n",
p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth,
p_vout->i_bytes_per_pixel, p_vout->f_x_ratio, p_vout->f_y_ratio );
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 );
/* Terminate the initialization */
p_vout->b_die = 0;
......@@ -166,7 +217,7 @@ vout_thread_t * vout_CreateThread (
#ifdef STATS
p_vout->c_loops = 0;
p_vout->c_idle_loops = 0;
p_vout->c_pictures = 0;
p_vout->c_pictures = 0;
#endif
/* Create thread and set locks */
......@@ -237,7 +288,20 @@ void vout_DestroyThread( vout_thread_t *p_vout, int *pi_status )
*******************************************************************************/
void vout_DisplayPicture( vout_thread_t *p_vout, picture_t *p_pic )
{
vlc_mutex_lock( &p_vout->lock );
#ifdef DEBUG_VIDEO
char psz_date[MSTRTIME_MAX_SIZE]; /* buffer for date string */
#endif
vlc_mutex_lock( &p_vout->lock );
#ifdef DEBUG_VIDEO
/* 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 );
}
#endif
/* Remove reservation flag */
p_pic->i_status = READY_PICTURE;
......@@ -247,6 +311,12 @@ void vout_DisplayPicture( vout_thread_t *p_vout, picture_t *p_pic )
p_vout->c_pictures++;
#endif
#ifdef DEBUG_VIDEO
/* Send picture informations */
intf_DbgMsg("picture %p: type=%d, %dx%d, date=%s\n", p_pic, p_pic->i_type,
p_pic->i_width,p_pic->i_height, mstrtime( psz_date, p_pic->date ) );
#endif
vlc_mutex_unlock( &p_vout->lock );
}
......@@ -286,6 +356,10 @@ picture_t *vout_CreatePicture( vout_thread_t *p_vout, int i_type,
* memory allocation needs to be done */
p_vout->p_picture[i_picture].i_width = i_width;
p_vout->p_picture[i_picture].i_status = RESERVED_PICTURE;
#ifdef DEBUG_VIDEO
intf_DbgMsg("picture %p (in destroyed picture slot)\n",
&p_vout->p_picture[i_picture] );
#endif
vlc_mutex_unlock( &p_vout->lock );
return( &p_vout->p_picture[i_picture] );
}
......@@ -331,7 +405,7 @@ picture_t *vout_CreatePicture( vout_thread_t *p_vout, int i_type,
break;
#ifdef DEBUG
default:
intf_DbgMsg("unknown picture type %d\n", i_type );
intf_DbgMsg("error: unknown picture type %d\n", i_type );
p_free_picture->p_data = NULL;
break;
#endif
......@@ -340,13 +414,13 @@ picture_t *vout_CreatePicture( vout_thread_t *p_vout, int i_type,
if( p_free_picture->p_data != NULL )
{
/* Copy picture informations */
p_free_picture->i_type = i_type;
p_free_picture->i_status = RESERVED_PICTURE;
p_free_picture->i_width = i_width;
p_free_picture->i_height = i_height;
p_free_picture->i_bytes_per_line = i_bytes_per_line;
p_free_picture->i_refcount = 0;
p_free_picture->i_matrix_coefficients = 1; // ?? default value
p_free_picture->i_type = i_type;
p_free_picture->i_status = RESERVED_PICTURE;
p_free_picture->i_width = i_width;
p_free_picture->i_height = i_height;
p_free_picture->i_bytes_per_line = i_bytes_per_line;
p_free_picture->i_refcount = 0;
p_free_picture->i_matrix_coefficients = 1;
}
else
{
......@@ -357,18 +431,21 @@ picture_t *vout_CreatePicture( vout_thread_t *p_vout, int i_type,
intf_ErrMsg("warning: %s\n", strerror( ENOMEM ) );
}
#ifdef DEBUG_VIDEO
intf_DbgMsg("picture %p (in free picture slot)\n", p_free_picture );
#endif
vlc_mutex_unlock( &p_vout->lock );
return( p_free_picture );
}
// No free or destroyed picture could be found
intf_DbgMsg( "heap is full\n" );
intf_DbgMsg( "warning: heap is full\n" );
vlc_mutex_unlock( &p_vout->lock );
return( NULL );
}
/*******************************************************************************
* vout_RemovePicture: remove a permanent or reserved picture from the heap
* vout_DestroyPicture: remove a permanent or reserved picture from the heap
*******************************************************************************
* This function frees a previously reserved picture or a permanent
* picture. It is meant to be used when the construction of a picture aborted.
......@@ -377,7 +454,22 @@ picture_t *vout_CreatePicture( vout_thread_t *p_vout, int i_type,
void vout_DestroyPicture( vout_thread_t *p_vout, picture_t *p_pic )
{
vlc_mutex_lock( &p_vout->lock );
#ifdef DEBUG_VIDEO
/* 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 );
}
#endif
p_pic->i_status = DESTROYED_PICTURE;
#ifdef DEBUG_VIDEO
intf_DbgMsg("picture %p\n", p_pic);
#endif
vlc_mutex_unlock( &p_vout->lock );
}
......@@ -391,6 +483,11 @@ void vout_LinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
{
vlc_mutex_lock( &p_vout->lock );
p_pic->i_refcount++;
#ifdef DEBUG_VIDEO
intf_DbgMsg("picture %p\n", p_pic);
#endif
vlc_mutex_unlock( &p_vout->lock );
}
......@@ -407,6 +504,11 @@ void vout_UnlinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
{
p_pic->i_status = DESTROYED_PICTURE;
}
#ifdef DEBUG_VIDEO
intf_DbgMsg("picture %p\n", p_pic);
#endif
vlc_mutex_unlock( &p_vout->lock );
}
......@@ -435,6 +537,12 @@ static int InitThread( vout_thread_t *p_vout )
p_vout->p_picture[i_index].i_status= FREE_PICTURE;
}
#ifdef STATS
/* Initialize FPS index - since samples won't be used until a minimum of
* pictures, they don't need to be initialized */
p_vout->i_fps_index = 0;
#endif
/* Initialize output method - this function issues its own error messages */
if( vout_SysInit( p_vout ) )
{
......@@ -457,7 +565,7 @@ static int InitThread( vout_thread_t *p_vout )
break;
#ifdef DEBUG
default:
intf_DbgMsg("invalid bytes_per_pixel %d\n", p_vout->i_bytes_per_pixel );
intf_DbgMsg("error: invalid bytes_per_pixel %d\n", p_vout->i_bytes_per_pixel );
i_pixel_size = sizeof( u32 );
break;
#endif
......@@ -512,7 +620,7 @@ static int InitThread( vout_thread_t *p_vout )
for( i_index = -384; i_index < 640; i_index++)
{
p_vout->pi_trans16_red[i_index] = (CLIP_BYTE( i_index ) & 0xf8)<<8;
p_vout->pi_trans16_green[i_index] = (CLIP_BYTE( i_index ) & 0xf8)<<3;
p_vout->pi_trans16_green[i_index] = (CLIP_BYTE( i_index ) & 0xfc)<<3;
p_vout->pi_trans16_blue[i_index] = CLIP_BYTE( i_index ) >> 3;
}
break;
......@@ -527,7 +635,7 @@ static int InitThread( vout_thread_t *p_vout )
break;
#ifdef DEBUG
default:
intf_DbgMsg("invalid screen depth %d\n", p_vout->i_screen_depth );
intf_DbgMsg("error: invalid screen depth %d\n", p_vout->i_screen_depth );
break;
#endif
}
......@@ -535,7 +643,7 @@ static int InitThread( vout_thread_t *p_vout )
/* Mark thread as running and return */
p_vout->b_active = 1;
*p_vout->pi_status = THREAD_READY;
intf_DbgMsg("thread ready");
intf_DbgMsg("thread ready\n");
return(0);
}
......@@ -551,7 +659,8 @@ static void RunThread( vout_thread_t *p_vout)
int i_picture; /* picture index */
int i_err; /* error code */
mtime_t current_date; /* current date */
picture_t * p_pic = NULL; /* picture pointer */
picture_t * p_pic; /* picture pointer */
mtime_t pic_date = 0; /* picture date */
/*
* Initialize thread and free configuration
......@@ -575,18 +684,18 @@ static void RunThread( vout_thread_t *p_vout)
* it can't be modified by the other threads (except if it is unliked,
* but its data remains)
*/
p_pic = NULL;
vlc_mutex_lock( &p_vout->lock );
for( i_picture = 0; i_picture < VOUT_MAX_PICTURES; i_picture++ )
{
if( (p_vout->p_picture[i_picture].i_status == READY_PICTURE) &&
( (p_pic == NULL) ||
(p_vout->p_picture[i_picture].date < p_pic->date) ) )
(p_vout->p_picture[i_picture].date < pic_date) ) )
{
p_pic = &p_vout->p_picture[i_picture];
pic_date = p_pic->date;
}
}
vlc_mutex_unlock( &p_vout->lock );
/*
......@@ -594,8 +703,16 @@ static void RunThread( vout_thread_t *p_vout)
*/
if( p_pic )
{
#ifdef STATS
/* Computes FPS rate */
p_vout->fps_sample[ p_vout->i_fps_index++ ] = pic_date;
if( p_vout->i_fps_index == VOUT_FPS_SAMPLES )
{
p_vout->i_fps_index = 0;
}
#endif
current_date = mdate();
if( p_pic->date < current_date )
if( pic_date < current_date )
{
/* Picture is late: it will be destroyed and the thread will go
* immediately to next picture */
......@@ -608,11 +725,14 @@ static void RunThread( vout_thread_t *p_vout)
{
p_pic->i_status = DESTROYED_PICTURE;
}
#ifdef DEBUG_VIDEO
intf_DbgMsg( "warning: late picture %p skipped\n", p_pic );
#endif
vlc_mutex_unlock( &p_vout->lock );
intf_ErrMsg( "warning: late picture skipped\n" );
p_pic = NULL;
}
else if( p_pic->date > current_date + VOUT_DISPLAY_DELAY )
else if( pic_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
......@@ -622,8 +742,24 @@ static void RunThread( vout_thread_t *p_vout)
else
{
/* Picture has not yet been displayed, and has a valid display
* date : render it */
* date : render it, then forget it */
RenderPicture( p_vout, p_pic );
vlc_mutex_lock( &p_vout->lock );
if( p_pic->i_refcount )
{
p_pic->i_status = DISPLAYED_PICTURE;
}
else
{
p_pic->i_status = DESTROYED_PICTURE;
}
vlc_mutex_unlock( &p_vout->lock );
/* Print additional informations */
if( p_vout->b_info )
{
RenderInfo( p_vout );
}
}
}
......@@ -643,24 +779,12 @@ static void RunThread( vout_thread_t *p_vout)
if( p_pic )
{
/* A picture is ready to be displayed : sleep until its display date */
mwait( p_pic->date );
mwait( pic_date );
if( !i_err )
{
vout_SysDisplay( p_vout );
}
/* Picture has been displayed : destroy it */
vlc_mutex_lock( &p_vout->lock );
if( p_pic->i_refcount )
{
p_pic->i_status = DISPLAYED_PICTURE;
}
else
{
p_pic->i_status = DESTROYED_PICTURE;
}
vlc_mutex_unlock( &p_vout->lock );
}
else
{
......@@ -754,156 +878,302 @@ static void EndThread( vout_thread_t *p_vout )
* 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.
* ???? 24 and 32 bpp should probably be separated
*******************************************************************************/
static void RenderPicture( vout_thread_t *p_vout, picture_t *p_pic )
{
#ifdef DEBUG_VIDEO
/* Send picture informations */
intf_DbgMsg("picture %p\n", p_pic );
/* Store rendering start date */
p_vout->picture_render_time = mdate();
#endif
switch( p_pic->i_type )
{
case YUV_420_PICTURE: /* YUV picture: YUV transformation */
case YUV_422_PICTURE:
case YUV_444_PICTURE:
RenderYUVPicture( p_vout, p_pic );
if( p_vout->b_grayscale ) /* grayscale */
{
RenderYUVGrayPicture( p_vout, p_pic );
}
else if( p_vout->i_bytes_per_pixel == 2 ) /* color 15 or 16 bpp */
{
RenderYUV16Picture( p_vout, p_pic );
}
else /* color 24 or 32 bpp */
{
RenderYUV32Picture( p_vout, p_pic );
}
break;
#ifdef DEBUG
default:
intf_DbgMsg("unknown picture type %d\n", p_pic->i_type );
intf_DbgMsg("error: unknown picture type %d\n", p_pic->i_type );
break;
#endif
}
#ifdef DEBUG_VIDEO
/* Computes rendering time */
p_vout->picture_render_time = mdate() - p_vout->picture_render_time;
#endif
}
/*******************************************************************************
* RenderYUVPicture: render a YUV picture
* RenderYUVGrayPicture: render a 15, 16, 24 or 32 bpp YUV picture in grayscale
*******************************************************************************
* Performs the YUV convertion. The picture sent to this function should only
* have YUV_420, YUV_422 or YUV_444 types.
*******************************************************************************/
static void RenderYUVPicture( vout_thread_t *p_vout, picture_t *p_pic )
static void RenderYUVGrayPicture( vout_thread_t *p_vout, picture_t *p_pic )
{
int i_crv;
int i_cbu;
int i_cgu;
int i_cgv;
int i_pic_x; /* x coordinate in picture */
int i_pic_y; /* y coordinate in picture */
int i_pic_x, i_pic_y; /* x,y coordinates in picture */
int i_width, i_height; /* picture size */
int i_eol_offset; /* pixels from end of line to next line */
yuv_data_t *p_y; /* Y data base adress */
yuv_data_t *p_u; /* U data base adress */
yuv_data_t *p_v; /* V data base adress */
yuv_data_t i_y; /* Y sample */
yuv_data_t i_u; /* U sample */
yuv_data_t i_v; /* V sample */
u16 *pi_pic16; /* base adress for destination picture */
u32 *pi_pic32; /* base adress for destination picture */
int i_pic_eol_offset; /* end of line offset */
/* Choose transformation matrix coefficients */
i_crv = matrix_coefficients_table[p_pic->i_matrix_coefficients][0];
i_cbu = matrix_coefficients_table[p_pic->i_matrix_coefficients][1];
i_cgu = matrix_coefficients_table[p_pic->i_matrix_coefficients][2];
i_cgv = matrix_coefficients_table[p_pic->i_matrix_coefficients][3];
/* Set the base pointers */
p_y = p_pic->p_y;
p_u = p_pic->p_u;
p_v = p_pic->p_v;
/* Get base adress for destination image */
pi_pic32 = (u32 *)pi_pic16 =
(u16 *)vout_SysGetPicture( p_vout, &i_pic_eol_offset );
u16 * pi_pic16; /* destination picture, 15 or 16 bpp */
u32 * pi_pic32; /* destination picture, 24 or 32 bpp */
u16 * pi_trans16_red; /* red transformation table */
u16 * pi_trans16_green; /* green transformation table */
u16 * pi_trans16_blue; /* blue transformation table */
u32 * pi_trans32_red; /* red transformation table */
u32 * pi_trans32_green; /* green transformation table */
u32 * pi_trans32_blue; /* blue transformation table */
/* Set the base pointers and transformation parameters */
p_y = p_pic->p_y;
i_width = p_pic->i_width;
i_height = p_pic->i_height;
i_eol_offset = p_vout->i_bytes_per_line / p_vout->i_bytes_per_pixel - i_width;
//?? copy used values (translation, height, width) to local variables ?
/* Do YUV transformation - the loops are repeated for optimization */
/* Get base adress for destination image and translation tables, then
* transform image */
switch( p_vout->i_screen_depth )
{
case 15:
case 16:
switch( p_pic->i_type )
{
case YUV_420_PICTURE: /* 15 or 16 bpp 420 transformation */
//#ifdef HAVE_MMX
// ?? MMX
//#else
YUV_TRANSFORM( 420,
p_vout->pi_trans16_red,
p_vout->pi_trans16_green,
p_vout->pi_trans16_blue,
pi_pic16 );
//#endif
break;
case YUV_422_PICTURE: /* 15 or 16 bpp 422 transformation */
YUV_TRANSFORM( 422,
p_vout->pi_trans16_red,
p_vout->pi_trans16_green,
p_vout->pi_trans16_blue,
pi_pic16 );
break;
case YUV_444_PICTURE: /* 15 or 16 bpp 444 transformation */
YUV_TRANSFORM( 444,
p_vout->pi_trans16_red,
p_vout->pi_trans16_green,
p_vout->pi_trans16_blue,
pi_pic16 );
break;
}
break;
case 24: // ?? probably wrong !
switch( p_pic->i_type )
{
case YUV_420_PICTURE: /* 24 bpp 420 transformation */
YUV_TRANSFORM( 420,
p_vout->pi_trans32_red,
p_vout->pi_trans32_green,
p_vout->pi_trans32_blue,
pi_pic32 );
break;
case YUV_422_PICTURE: /* 24 bpp 422 transformation */
YUV_TRANSFORM( 422,
p_vout->pi_trans32_red,
p_vout->pi_trans32_green,
p_vout->pi_trans32_blue,
pi_pic32 );
break;
case YUV_444_PICTURE: /* 24 bpp 444 transformation */
YUV_TRANSFORM( 444,
p_vout->pi_trans32_red,
p_vout->pi_trans32_green,
p_vout->pi_trans32_blue,
pi_pic32 );
break;
}
pi_trans16_red = p_vout->pi_trans16_red;
pi_trans16_green = p_vout->pi_trans16_green;
pi_trans16_blue = p_vout->pi_trans16_blue;
pi_pic16 = (u16 *) vout_SysGetPicture( p_vout );
YUV_GRAYSCALE( pi_trans16_red, pi_trans16_green, pi_trans16_blue,
pi_pic16 );
break;
case 24:
case 32:
switch( p_pic->i_type )
{
case YUV_420_PICTURE: /* 32 bpp 420 transformation */
YUV_TRANSFORM( 420,
p_vout->pi_trans32_red,
p_vout->pi_trans32_green,
p_vout->pi_trans32_blue,
pi_pic32 );
break;
case YUV_422_PICTURE: /* 32 bpp 422 transformation */
YUV_TRANSFORM( 422,
p_vout->pi_trans32_red,
p_vout->pi_trans32_green,
p_vout->pi_trans32_blue,
pi_pic32 );
break;
case YUV_444_PICTURE: /* 32 bpp 444 transformation */
YUV_TRANSFORM( 444,
p_vout->pi_trans32_red,
p_vout->pi_trans32_green,
p_vout->pi_trans32_blue,
pi_pic32 );
break;
}
pi_trans32_red = p_vout->pi_trans32_red;
pi_trans32_green = p_vout->pi_trans32_green;
pi_trans32_blue = p_vout->pi_trans32_blue;
pi_pic32 = (u32 *) vout_SysGetPicture( p_vout );
YUV_GRAYSCALE( pi_trans32_red, pi_trans32_green, pi_trans32_blue,
pi_pic32 );
break;
#ifdef DEBUG
default:
intf_DbgMsg("error: invalid screen depth %d\n", p_vout->i_screen_depth );
break;
#endif
}
}
/*******************************************************************************
* RenderYUV16Picture: render a 15 or 16 bpp YUV picture
*******************************************************************************
* Performs the YUV convertion. The picture sent to this function should only
* have YUV_420, YUV_422 or YUV_444 types.
*******************************************************************************/
static void RenderYUV16Picture( vout_thread_t *p_vout, picture_t *p_pic )
{
int i_crv, i_cbu, i_cgu, i_cgv; /* transformation coefficients */
int i_pic_x, i_pic_y; /* x,y coordinates in picture */
int i_y, i_u, i_v; /* Y, U and V samples */
int i_width, i_height; /* picture size */
int i_chroma_width; /* chroma width */
int i_eol_offset; /* pixels from end of line to next line */
yuv_data_t *p_y; /* Y data base adress */
yuv_data_t *p_u; /* U data base adress */
yuv_data_t *p_v; /* V data base adress */
u16 * pi_pic; /* base adress for destination picture */
u16 * pi_trans_red; /* red transformation table */
u16 * pi_trans_green; /* green transformation table */
u16 * pi_trans_blue; /* blue transformation table */
/* Choose transformation matrix coefficients */
i_crv = MATRIX_COEFFICIENTS_TABLE[p_pic->i_matrix_coefficients][0];
i_cbu = MATRIX_COEFFICIENTS_TABLE[p_pic->i_matrix_coefficients][1];
i_cgu = MATRIX_COEFFICIENTS_TABLE[p_pic->i_matrix_coefficients][2];
i_cgv = MATRIX_COEFFICIENTS_TABLE[p_pic->i_matrix_coefficients][3];
/* Choose the conversions tables */
pi_trans_red = p_vout->pi_trans16_red;
pi_trans_green = p_vout->pi_trans16_green;
pi_trans_blue = p_vout->pi_trans16_blue;
/* Set the base pointers and transformation parameters */
p_y = p_pic->p_y;
p_u = p_pic->p_u;
p_v = p_pic->p_v;
i_width = p_pic->i_width;
i_height = p_pic->i_height;
i_chroma_width = i_width / 2;
i_eol_offset = p_vout->i_bytes_per_line / 2 - i_width;
/* Get base adress for destination image */
pi_pic = (u16 *)vout_SysGetPicture( p_vout );
/* Do YUV transformation - the loops are repeated for optimization */
switch( p_pic->i_type )
{
case YUV_420_PICTURE: /* 15 or 16 bpp 420 transformation */
#ifdef HAVE_MMX
vout_YUV420_16_MMX( p_y, p_u, p_v,
i_width, i_height,
i_width, i_chroma_width,
0, (u8 *) pi_pic,
0, 0, p_vout->i_bytes_per_line,
p_vout->i_screen_depth == 15 );
#else
YUV_TRANSFORM( 420,
pi_trans_red,
pi_trans_green,
pi_trans_blue,
pi_pic );
#endif
break;
case YUV_422_PICTURE: /* 15 or 16 bpp 422 transformation */
YUV_TRANSFORM( 422,
pi_trans_red,
pi_trans_green,
pi_trans_blue,
pi_pic );
break;
case YUV_444_PICTURE: /* 15 or 16 bpp 444 transformation */
YUV_TRANSFORM( 444,
pi_trans_red,
pi_trans_green,
pi_trans_blue,
pi_pic );
break;
}
}
/*******************************************************************************
* RenderYUV32Picture: render a 24 or 32 bpp YUV picture
*******************************************************************************
* Performs the YUV convertion. The picture sent to this function should only
* have YUV_420, YUV_422 or YUV_444 types.
*******************************************************************************/
static void RenderYUV32Picture( vout_thread_t *p_vout, picture_t *p_pic )
{
int i_crv, i_cbu, i_cgu, i_cgv; /* transformation coefficients */
int i_pic_x, i_pic_y; /* x,y coordinates in picture */
int i_y, i_u, i_v; /* Y, U and V samples */
int i_width, i_height; /* picture size */
int i_chroma_width; /* chroma width */
int i_eol_offset; /* pixels from end of line to next line */
yuv_data_t *p_y; /* Y data base adress */
yuv_data_t *p_u; /* U data base adress */
yuv_data_t *p_v; /* V data base adress */
u32 * pi_pic; /* base adress for destination picture */
u32 * pi_trans_red; /* red transformation table */
u32 * pi_trans_green; /* green transformation table */
u32 * pi_trans_blue; /* blue transformation table */
/* Choose transformation matrix coefficients */
i_crv = MATRIX_COEFFICIENTS_TABLE[p_pic->i_matrix_coefficients][0];
i_cbu = MATRIX_COEFFICIENTS_TABLE[p_pic->i_matrix_coefficients][1];
i_cgu = MATRIX_COEFFICIENTS_TABLE[p_pic->i_matrix_coefficients][2];
i_cgv = MATRIX_COEFFICIENTS_TABLE[p_pic->i_matrix_coefficients][3];
/* Choose the conversions tables */
pi_trans_red = p_vout->pi_trans32_red;
pi_trans_green = p_vout->pi_trans32_green;
pi_trans_blue = p_vout->pi_trans32_blue;
/* Set the base pointers and transformation parameters */
p_y = p_pic->p_y;
p_u = p_pic->p_u;
p_v = p_pic->p_v;
i_width = p_pic->i_width;
i_height = p_pic->i_height;
i_chroma_width = i_width / 2;
i_eol_offset = p_vout->i_bytes_per_line / p_vout->i_bytes_per_pixel - i_width;
/* Get base adress for destination image */
pi_pic = (u32 *)vout_SysGetPicture( p_vout );
/* Do YUV transformation - the loops are repeated for optimization */
switch( p_pic->i_type )
{
case YUV_420_PICTURE: /* 24 or 32 bpp 420 transformation */
YUV_TRANSFORM( 420,
pi_trans_red,
pi_trans_green,
pi_trans_blue,
pi_pic );
break;
case YUV_422_PICTURE: /* 24 or 32 bpp 422 transformation */
YUV_TRANSFORM( 422,
pi_trans_red,
pi_trans_green,
pi_trans_blue,
pi_pic );
break;
case YUV_444_PICTURE: /* 24 or 32 bpp 444 transformation */
YUV_TRANSFORM( 444,
pi_trans_red,
pi_trans_green,
pi_trans_blue,
pi_pic );
break;
}
}
/*******************************************************************************
* RenderInfo: print additionnal informations on a picture
*******************************************************************************
* This function will add informations such as fps and buffer size on a picture
*******************************************************************************/
static void RenderInfo( vout_thread_t *p_vout )
{
char psz_buffer[256]; /* string buffer */
#ifdef STATS
/* Print FPS rate */
if( p_vout->c_pictures > VOUT_FPS_SAMPLES )
{
sprintf( psz_buffer, "%.2f fps", (double) VOUT_FPS_SAMPLES * 1000000 /
( p_vout->fps_sample[ (p_vout->i_fps_index + (VOUT_FPS_SAMPLES - 1)) %
VOUT_FPS_SAMPLES ] -
p_vout->fps_sample[ p_vout->i_fps_index ] ) );
vout_SysPrint( p_vout, p_vout->i_width, 0, 1, -1, psz_buffer );
}
/* Print statistics */
sprintf( psz_buffer, "%ld pictures, %.1f %% idle loops", p_vout->c_pictures,
(double) p_vout->c_idle_loops * 100 / p_vout->c_loops );
vout_SysPrint( p_vout, 0, 0, -1, -1, psz_buffer );
#endif
#ifdef DEBUG
default:
intf_DbgMsg("invalid screen depth %d\n", p_vout->i_screen_depth );
break;
/* Print heap size */
sprintf( psz_buffer, "video heap size: %d (%.1f %%)", p_vout->i_pictures,
(double) p_vout->i_pictures * 100 / VOUT_MAX_PICTURES );
vout_SysPrint( p_vout, 0, p_vout->i_height, -1, 1, psz_buffer );
#endif
#ifdef DEBUG_VIDEO
/* Print rendering statistics */
sprintf( psz_buffer, "picture rendering time: %lu us",
(unsigned long) p_vout->picture_render_time );
vout_SysPrint( p_vout, p_vout->i_width, p_vout->i_height, 1, 1, psz_buffer );
#endif
}
}
......@@ -47,6 +47,12 @@ typedef struct vout_sys_s
Window window; /* window instance handler */
GC gc; /* graphic context instance handler */
/* 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 and shared memory information */
int i_buffer_index; /* buffer index */
XImage * p_ximage[2]; /* XImage pointer */
......@@ -58,7 +64,7 @@ typedef struct vout_sys_s
*******************************************************************************/
static int X11OpenDisplay ( vout_thread_t *p_vout, char *psz_display, Window root_window );
static void X11CloseDisplay ( vout_thread_t *p_vout );
static int X11GetFont ( vout_thread_t *p_vout );
static int X11CreateWindow ( vout_thread_t *p_vout );
static void X11DestroyWindow ( vout_thread_t *p_vout );
static int X11CreateImage ( vout_thread_t *p_vout, XImage **pp_ximage );
......@@ -68,6 +74,7 @@ static int X11CreateShmImage ( vout_thread_t *p_vout, XImage **pp_ximage,
static void X11DestroyShmImage ( vout_thread_t *p_vout, XImage *p_ximage,
XShmSegmentInfo *p_shm_info );
/*******************************************************************************
* vout_SysCreate: allocate X11 video thread output method
*******************************************************************************
......@@ -201,30 +208,10 @@ void vout_SysDestroy( vout_thread_t *p_vout )
*******************************************************************************/
int vout_SysManage( vout_thread_t *p_vout )
{
boolean_t b_resized;
//??
return 0;
/* ?? this function should not receive any usefull X11 messages, since they
* have tobe treated by the main interface window - check it. */
return 0; //??
/* If window has been resized, re-create images */
/* ?? if( b_resized )
{
intf_DbgMsg("%p -> resizing window\n", p_vout);
X11DestroyImages( p_vout );
if( X11CreateImages( p_vout ) )
{ */
/* A fatal error occured: images could not be re-created. Note
* that in this case, the images pointers will be NULL, so the
* image destructor will know it does not need to destroy them. */
/* return( -1 );
}
return( 1 );
}*/
return( 0 );
// ?? if resized: end/init again, return >0
}
/*******************************************************************************
......@@ -246,10 +233,6 @@ void vout_SysDisplay( vout_thread_t *p_vout )
/* Send the order to the X server */
XFlush(p_vout->p_sys->p_display);
/* ?? wait until effective display ? */
/* do XNextEvent(Display_Ptr, &xev);
while(xev.type!=CompletionType);*/
}
else /* regular X11 capabilities are used */
{
......@@ -270,16 +253,84 @@ void vout_SysDisplay( vout_thread_t *p_vout )
/*******************************************************************************
* vout_SysGetPicture: get current display buffer informations
*******************************************************************************
* This function returns the address of the current display buffer, and the
* number of samples per line. For 15, 16 and 32 bits displays, this value is
* the number of pixels in a line.
* This function returns the address of the current display buffer.
*******************************************************************************/
byte_t * vout_SysGetPicture( vout_thread_t *p_vout, int *pi_eol_offset )
byte_t * vout_SysGetPicture( vout_thread_t *p_vout )
{
*pi_eol_offset = p_vout->i_width;
return( p_vout->p_sys->p_ximage[ p_vout->p_sys->i_buffer_index ]->data );
}
/*******************************************************************************
* 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.
* Since there is no way to print text on an Ximage directly, this function
* copy directly the pixels from a font.
*******************************************************************************/
void vout_SysPrint( vout_thread_t *p_vout, int i_x, int i_y, int i_halign,
int i_valign, unsigned char *psz_text )
{
int i_line; /* line in character matrix */
int i_byte; /* byte offset in character line */
int i_height; /* character height */
int i_char_bytes_per_line; /* total bytes per line */
byte_t * pi_pic; /* picture data */
byte_t * pi_char; /* character data */
/* Update upper left coordinates according to alignment */
switch( i_halign )
{
case 0: /* centered */
i_x -= p_vout->p_sys->i_char_interspacing * strlen( psz_text ) / 2;
break;
case 1: /* right aligned */
i_x -= p_vout->p_sys->i_char_interspacing * 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;
}
/* Copy used variables to local */
i_height = p_vout->p_sys->i_char_height;
i_char_bytes_per_line = p_vout->p_sys->i_char_bytes_per_line;
/* Print text */
for( ; *psz_text != '\0'; psz_text++ )
{
if( (*psz_text >= VOUT_MIN_CHAR) && (*psz_text < VOUT_MAX_CHAR) )
{
/* Select character */
pi_char = p_vout->p_sys->pi_font + (*psz_text - VOUT_MIN_CHAR) *
i_height * i_char_bytes_per_line;
pi_pic = p_vout->p_sys->p_ximage[ p_vout->p_sys->i_buffer_index ]->data +
i_y * p_vout->i_bytes_per_line + i_x * p_vout->i_bytes_per_pixel;
/* Copy character */
for( i_line = 0; i_line < i_height; i_line++ )
{
/* Copy line */
for( i_byte = 0; i_byte < i_char_bytes_per_line; i_byte++ )
{
pi_pic[ i_byte ] = *pi_char++;
}
/* Go to next line */
pi_pic += p_vout->i_bytes_per_line;
}
}
/* Jump to next character */
i_x += p_vout->p_sys->i_char_interspacing;
}
}
/* following functions are local */
......@@ -326,15 +377,25 @@ static int X11OpenDisplay( vout_thread_t *p_vout, char *psz_display, Window root
XCloseDisplay( p_vout->p_sys->p_display );
return( 1 );
break;
}
}
/* Create a window */
if( X11CreateWindow( p_vout ) ) /* create window */
/* Create a window and set line length */
if( X11CreateWindow( p_vout ) )
{
intf_ErrMsg("error: can't open a window\n");
XCloseDisplay( p_vout->p_sys->p_display );
return( 1 );
}
p_vout->i_bytes_per_line = p_vout->i_width * p_vout->i_bytes_per_pixel;
/* Get font information */
if( X11GetFont( p_vout ) )
{
intf_ErrMsg("error: can't read default font\n");
X11DestroyWindow( p_vout );
XCloseDisplay( p_vout->p_sys->p_display );
return( 1 );
}
return( 0 );
}
......@@ -347,10 +408,101 @@ static int X11OpenDisplay( vout_thread_t *p_vout, char *psz_display, Window root
*******************************************************************************/
static void X11CloseDisplay( vout_thread_t *p_vout )
{
// Free font info
free( p_vout->p_sys->pi_font );
// Destroy window and close display
X11DestroyWindow( p_vout );
XCloseDisplay( p_vout->p_sys->p_display );
}
/*******************************************************************************
* X11GetFont: get default font bitmap informations
*******************************************************************************
* This function will convert a font into a bitmap for later use by the
* vout_SysPrint function.
*******************************************************************************/
static int X11GetFont( vout_thread_t *p_vout )
{
XFontStruct * p_font_info; /* font information structure */
Pixmap pixmap; /* pixmap used to draw characters */
GC gc; /* graphic context */
XGCValues gc_values; /* graphic context properties */
XImage * p_ximage; /* ximage for character */
unsigned char i_char; /* character index */
int i_char_width; /* character width (pixels) */
int i_char_bytes; /* total character size */
/* Load font */
p_font_info = XLoadQueryFont( p_vout->p_sys->p_display, "fixed" );
if( p_font_info == NULL )
{
intf_ErrMsg("error: can't load 'fixed' font\n");
return( 1 );
}
/* Get character size */
i_char_width = p_font_info->max_bounds.lbearing +
p_font_info->max_bounds.rbearing;
p_vout->p_sys->i_char_bytes_per_line = i_char_width * p_vout->i_bytes_per_pixel;
p_vout->p_sys->i_char_height = p_font_info->max_bounds.ascent +
p_font_info->max_bounds.descent;
i_char_bytes = p_vout->p_sys->i_char_bytes_per_line *
p_vout->p_sys->i_char_height;
p_vout->p_sys->i_char_interspacing = p_font_info->max_bounds.width;
/* Allocate font descriptor */
p_vout->p_sys->pi_font = malloc( i_char_bytes * ( VOUT_MAX_CHAR - VOUT_MIN_CHAR ) );
if( p_vout->p_sys->pi_font == NULL )
{
intf_ErrMsg("error: %s\n", strerror( ENOMEM ) );
XFreeFont( p_vout->p_sys->p_display, p_font_info );
return( 1 );
}
/* Create drawable and graphic context */
gc_values.foreground = XBlackPixel( p_vout->p_sys->p_display,
p_vout->p_sys->i_screen );
gc_values.background = XBlackPixel( p_vout->p_sys->p_display,
p_vout->p_sys->i_screen );
gc_values.font = p_font_info->fid;
pixmap = XCreatePixmap( p_vout->p_sys->p_display, p_vout->p_sys->window,
i_char_width,
p_vout->p_sys->i_char_height *(VOUT_MAX_CHAR-VOUT_MIN_CHAR),
p_vout->i_screen_depth );
gc = XCreateGC( p_vout->p_sys->p_display, pixmap,
GCForeground | GCBackground | GCFont, &gc_values );
/* Clear pixmap and invert graphic context */
XFillRectangle( p_vout->p_sys->p_display, pixmap, gc, 0, 0, i_char_width,
p_vout->p_sys->i_char_height*(VOUT_MAX_CHAR-VOUT_MIN_CHAR) );
XSetForeground( p_vout->p_sys->p_display, gc,
XWhitePixel( p_vout->p_sys->p_display, p_vout->p_sys->i_screen ) );
XSetBackground( p_vout->p_sys->p_display, gc,
XBlackPixel( p_vout->p_sys->p_display, p_vout->p_sys->i_screen ) );
/* Copy characters bitmaps to font descriptor */
for( i_char = VOUT_MIN_CHAR; i_char < VOUT_MAX_CHAR; i_char++ )
{
XDrawString( p_vout->p_sys->p_display, pixmap, gc, 0,
p_font_info->max_bounds.ascent +
(i_char-VOUT_MIN_CHAR) * p_vout->p_sys->i_char_height,
&i_char, 1 );
}
p_ximage = XGetImage( p_vout->p_sys->p_display, pixmap, 0, 0, i_char_width,
p_vout->p_sys->i_char_height*(VOUT_MAX_CHAR-VOUT_MIN_CHAR),
-1, ZPixmap );
memcpy( p_vout->p_sys->pi_font, p_ximage->data,
i_char_bytes*(VOUT_MAX_CHAR-VOUT_MIN_CHAR));
/* Free resources, unload font and return */
XDestroyImage( p_ximage );
XFreeGC( p_vout->p_sys->p_display, gc );
XFreePixmap( p_vout->p_sys->p_display, pixmap );
XFreeFont( p_vout->p_sys->p_display, p_font_info );
return( 0 );
}
/*******************************************************************************
* X11CreateWindow: create X11 vout window
*******************************************************************************
......@@ -436,9 +588,7 @@ static int X11CreateImage( vout_thread_t *p_vout, XImage **pp_ximage )
int i_quantum; /* XImage quantum (see below) */
/* Allocate memory for image */
pb_data = (byte_t *) malloc( p_vout->i_bytes_per_pixel
* p_vout->i_width
* p_vout->i_height );
pb_data = (byte_t *) malloc( p_vout->i_bytes_per_line * p_vout->i_height );
if( !pb_data ) /* error */
{
intf_ErrMsg("error: %s\n", strerror(ENOMEM));
......@@ -447,13 +597,13 @@ static int X11CreateImage( vout_thread_t *p_vout, XImage **pp_ximage )
/* Optimize the quantum of a scanline regarding its size - the quantum is
a diviser of the number of bits between the start of two scanlines. */
if( !(( p_vout->i_width * p_vout->i_bytes_per_pixel ) % 32) )
if( !(( p_vout->i_bytes_per_line ) % 32) )
{
i_quantum = 32;
}
else
{
if( !(( p_vout->i_width * p_vout->i_bytes_per_pixel ) % 16) )
if( !(( p_vout->i_bytes_per_line ) % 16) )
{
i_quantum = 16;
}
......@@ -485,12 +635,6 @@ static int X11CreateImage( vout_thread_t *p_vout, XImage **pp_ximage )
* The order of the operations respects the recommandations of the mit-shm
* document by J.Corbet and K.Packard. Most of the parameters were copied from
* there.
* ?? error on failure:
* X Error of failed request: BadAccess (attempt to access private resource denied)
* Major opcode of failed request: 129 (MIT-SHM)
* Minor opcode of failed request: 1 (X_ShmAttach)
* Serial number of failed request: 17
* Current serial number in output stream: 18
*******************************************************************************/
static int X11CreateShmImage( vout_thread_t *p_vout, XImage **pp_ximage,
XShmSegmentInfo *p_shm_info)
......@@ -544,6 +688,10 @@ static int X11CreateShmImage( vout_thread_t *p_vout, XImage **pp_ximage,
XDestroyImage( *pp_ximage );
return( 1 );
}
/* Send image to X server. This instruction is required, since having
* built a Shm XImage and not using it causes an error on XCloseDisplay */
XFlush( p_vout->p_sys->p_display );
return( 0 );
}
......
/*
*-------------------------------------------------------------------------
*cxm12161 -- This function performs YUV12-to-RGB16 color conversion for H26x.
* It handles any format in which there are three fields, the low
* order field being B and fully contained in the low order byte, the
* second field being G and being somewhere in bits 4 through 11,
* and the high order field being R and fully contained in the high
* order byte.
*
* The YUV12 input is planar, 8 bits per pel. The Y plane may have
* a pitch of up to 768. It may have a width less than or equal
* to the pitch. It must be DWORD aligned, and preferably QWORD
* aligned. Pitch and Width must be a multiple of four. For best
* performance, Pitch should not be 4 more than a multiple of 32.
* Height may be any amount, but must be a multiple of two. The U
* and V planes may have a different pitch than the Y plane, subject
* to the same limitations.
*/
//.include iammx.inc
//.include locals.inc
.data
.align 16
RGB_formats:
.long RGB565
.long RGB555
.long RGB664
.long RGB655
Minusg: .long 0x00800080, 0x00800080
Yadd: .long 0x10101010, 0x10101010
VtR: .long 0x00660066, 0x00660066
VtG: .long 0x00340034, 0x00340034
UtG: .long 0x00190019, 0x00190019
UtB: .long 0x00810081, 0x00810081
Ymul: .long 0x004a004a, 0x004a004a
UVtG: .long 0x00340019, 0x00340019
VtRUtB: .long 0x01990205, 0x01990205
fourbitu: .quad 0xf0f0f0f0f0f0f0f0
fivebitu: .quad 0xe0e0e0e0e0e0e0e0
sixbitu: .quad 0xc0c0c0c0c0c0c0c0
.text
#define LocalFrameSize 156
#define RegisterStorageSize 16
/* Arguments: */
#define YPlane LocalFrameSize + RegisterStorageSize + 4
#define UPlane LocalFrameSize + RegisterStorageSize + 8
#define VPlane LocalFrameSize + RegisterStorageSize + 12
#define FrameWidth LocalFrameSize + RegisterStorageSize + 16
#define FrameHeight LocalFrameSize + RegisterStorageSize + 20
#define YPitch LocalFrameSize + RegisterStorageSize + 24
#define ChromaPitch LocalFrameSize + RegisterStorageSize + 28
#define AspectAdjustmentCount LocalFrameSize + RegisterStorageSize + 32
#define ColorConvertedFrame LocalFrameSize + RegisterStorageSize + 36
#define DCIOffset LocalFrameSize + RegisterStorageSize + 40
#define CCOffsetToLine0 LocalFrameSize + RegisterStorageSize + 44
#define CCOPitch LocalFrameSize + RegisterStorageSize + 48
#define CCType LocalFrameSize + RegisterStorageSize + 52
#define EndOfArgList LocalFrameSize + RegisterStorageSize + 56
/* Locals (on local stack frame) */
#define CCOCursor 0
#define CCOSkipDistance 4
#define ChromaLineLen 8
#define YCursor 12
#define DistanceFromVToU 16
#define EndOfChromaLine 20
#define AspectCount 24
#define AspectBaseCount 28
#define tmpYCursorEven 32
#define tmpYCursorOdd 36
#define tmpCCOPitch 40
#define temp_mmx 44
#define RLeftShift 92
#define GLeftShift 100
#define RRightShift 108
#define GRightShift 116
#define BRightShift 124
#define RUpperLimit 132
#define GUpperLimit 140
#define BUpperLimit 148
/*
* extern void C MMX_YUV12ToRGB16 (
* U8* YPlane,
* U8* UPlane,
* U8* VPlane,
* UN FrameWidth,
* UN FrameHeight,
* UN YPitch,
* UN VPitch,
* UN AspectAdjustmentCount,
* U8* ColorConvertedFrame,
* U32 DCIOffset,
* U32 CCOffsetToLine0,
* IN CCOPitch,
* IN CCType)
*
* The local variables are on the stack,
* The tables are in the one and only data segment.
*
* CCOffsetToLine0 is relative to ColorConvertedFrame.
* CCType used by RGB color convertors to determine the exact conversion type.
* RGB565 = 0
* RGB555 = 1
* RGB664 = 2
* RGB655 = 3
*/
.globl yuv_2_rgb
yuv_2_rgb:
pushl %esi
pushl %edi
pushl %ebp
pushl %ebx
subl $LocalFrameSize,%esp
movl CCType(%esp),%eax
cmpl $4,%eax
jae finish
jmp *RGB_formats(,%eax,4)
RGB555:
xorl %eax,%eax
movl $2,%ebx /* 10-8 for byte shift */
movl %ebx,RLeftShift(%esp)
movl %eax,RLeftShift+4(%esp)
movl $5,%ebx
movl %ebx,GLeftShift(%esp)
movl %eax,GLeftShift+4(%esp)
movl $9,%ebx
movl %ebx,RRightShift(%esp)
movl %eax,RRightShift+4(%esp)
movl %ebx,GRightShift(%esp)
movl %eax,GRightShift+4(%esp)
movl %ebx,BRightShift(%esp)
movl %eax,BRightShift+4(%esp)
movq fivebitu,%mm0
movq %mm0,RUpperLimit(%esp)
movq %mm0,GUpperLimit(%esp)
movq %mm0,BUpperLimit(%esp)
jmp RGBEND
RGB664:
xorl %eax,%eax
movl $2,%ebx /* 8-6 */
movl %ebx,RLeftShift(%esp)
movl %eax,RLeftShift+4(%esp)
movl $4,%ebx
movl %ebx,GLeftShift(%esp)
movl %eax,GLeftShift+4(%esp)
movl $8,%ebx
movl %ebx,RRightShift(%esp)
movl %eax,RRightShift+4(%esp)
movl %ebx,GRightShift(%esp)
movl %eax,GRightShift+4(%esp)
movl $10,%ebx
movl %ebx,BRightShift(%esp)
movl %eax,BRightShift+4(%esp)
movq sixbitu,%mm0
movq %mm0,RUpperLimit(%esp)
movq %mm0,GUpperLimit(%esp)
movq fourbitu,%mm0
movq %mm0,BUpperLimit(%esp)
jmp RGBEND
RGB655:
xorl %eax,%eax
movl $2,%ebx /* 8-6 */
movl %ebx,RLeftShift(%esp)
movl %eax,RLeftShift+4(%esp)
movl $5,%ebx
movl %ebx,GLeftShift(%esp)
movl %eax,GLeftShift+4(%esp)
movl $8,%ebx
movl %ebx,RRightShift(%esp)
movl %eax,RRightShift+4(%esp)
movl $9,%ebx
movl %ebx,GRightShift(%esp)
movl %eax,GRightShift+4(%esp)
movl %ebx,BRightShift(%esp)
movl %eax,BRightShift+4(%esp)
movq sixbitu,%mm0
movq %mm0,RUpperLimit(%esp)
movq fivebitu,%mm0
movq %mm0,GUpperLimit(%esp)
movq %mm0,BUpperLimit(%esp)
jmp RGBEND
RGB565:
xorl %eax,%eax
movl $3,%ebx /* 8-5 */
movl %ebx,RLeftShift(%esp)
movl %eax,RLeftShift+4(%esp)
movl $5,%ebx
movl %ebx,GLeftShift(%esp)
movl %eax,GLeftShift+4(%esp)
movl $9,%ebx
movl %ebx,RRightShift(%esp)
movl %eax,RRightShift+4(%esp)
movl %ebx,BRightShift(%esp)
movl %eax,BRightShift+4(%esp)
movl $8,%ebx
movl %ebx,GRightShift(%esp)
movl %eax,GRightShift+4(%esp)
movq fivebitu,%mm0
movq %mm0,RUpperLimit(%esp)
movq %mm0,BUpperLimit(%esp)
movq sixbitu,%mm0
movq %mm0,GUpperLimit(%esp)
// jmp RGBEND
RGBEND:
movl VPlane(%esp),%ebx
movl UPlane(%esp),%ecx
subl %ebx,%ecx
movl %ecx,DistanceFromVToU(%esp)
movl ColorConvertedFrame(%esp),%eax
addl DCIOffset(%esp),%eax
addl CCOffsetToLine0(%esp),%eax
movl %eax,CCOCursor(%esp)
movl YPitch(%esp),%ecx
movl FrameWidth(%esp),%ebx
movl CCOPitch(%esp),%eax
subl %ebx,%eax /* CCOPitch-FrameWidth */
subl %ebx,%eax /* CCOPitch-2*FrameWidth */
sarl %ebx /* FrameWidth/2 */
movl YPlane(%esp),%esi /* Fetch cursor over luma plane. */
movl %ebx,ChromaLineLen(%esp) /* FrameWidth/2 */
movl %eax,CCOSkipDistance(%esp) /* CCOPitch-3*FrameWidth */
movl %esi,YCursor(%esp)
movl AspectAdjustmentCount(%esp),%edx
movl VPlane(%esp),%esi
cmpl $1,%edx
je finish
movl %edx,AspectCount(%esp)
movl %edx,AspectBaseCount(%esp)
xorl %eax,%eax
movl ChromaLineLen(%esp),%edi
movl %edi,EndOfChromaLine(%esp)
movl CCOCursor(%esp),%edi
movl DistanceFromVToU(%esp),%edx
movl YCursor(%esp),%ebp /* Fetch Y Pitch. */
movl FrameWidth(%esp),%ebx
addl %ebx,%ebp
movl %ebp,tmpYCursorEven(%esp)
movl YPitch(%esp),%eax
addl %eax,%ebp
movl %ebp,tmpYCursorOdd(%esp)
sarl %ebx
addl %ebx,%esi
addl %esi,%edx
negl %ebx
movl %ebx,FrameWidth(%esp)
/*
* Register Usage:
*/
PrepareChromaLine:
movl AspectCount(%esp),%ebp
movl FrameWidth(%esp),%ebx
subl $2,%ebp
movl CCOPitch(%esp),%eax
movl %eax,tmpCCOPitch(%esp)
ja continue
xorl %eax,%eax
addl AspectAdjustmentCount(%esp),%ebp
movl %eax,tmpCCOPitch(%esp)
continue:
movl %ebp,AspectCount(%esp)
do_next_8x2_block:
movl tmpYCursorEven(%esp),%ebp
/* here is even line */
movd (%edx,%ebx,),%mm1 /* 4 u values */
pxor %mm0,%mm0 /* mm0=0 */
movd (%esi,%ebx,),%mm2 /* 4 v values */
punpcklbw %mm0,%mm1 /* get 4 unsign u */
psubw Minusg,%mm1 /* get 4 unsign u-128 */
punpcklbw %mm0,%mm2 /* get unsign v */
psubw Minusg,%mm2 /* get unsign v-128 */
movq %mm1,%mm3 /* save the u-128 unsign */
movq %mm1,%mm5 /* save u-128 unsign */
punpcklwd %mm2,%mm1 /* get 2 low u, v unsign pairs */
pmaddwd UVtG,%mm1
punpckhwd %mm2,%mm3 /* create high 2 unsign uv pairs */
pmaddwd UVtG,%mm3
movq %mm2,temp_mmx(%esp) /* save v-128 */
movq (%ebp,%ebx,2),%mm6 /* mm6 has 8 y pixels */
psubusb Yadd,%mm6 /* mm6 has 8 y-16 pixels */
packssdw %mm3,%mm1 /* packed the results to signed words */
movq %mm6,%mm7 /* save the 8 y-16 pixels */
punpcklbw %mm0,%mm6 /* mm6 has 4 low y-16 unsign */
pmullw Ymul,%mm6
punpckhbw %mm0,%mm7 /* mm7 has 4 high y-16 unsign */
pmullw Ymul,%mm7
movq %mm1,%mm4
movq %mm1,temp_mmx+8(%esp) /* save 4 chroma G values */
punpcklwd %mm1,%mm1 /* chroma G replicate low 2 */
movq %mm6,%mm0 /* low y */
punpckhwd %mm4,%mm4 /* chroma G replicate high 2 */
movq %mm7,%mm3 /* high y */
psubw %mm1,%mm6 /* 4 low G */
psraw GRightShift(%esp),%mm6
psubw %mm4,%mm7 /* 4 high G values in signed 16 bit */
movq %mm5,%mm2
punpcklwd %mm5,%mm5 /* replicate the 2 low u pixels */
pmullw UtB,%mm5
punpckhwd %mm2,%mm2
psraw GRightShift(%esp),%mm7
pmullw UtB,%mm2
packuswb %mm7,%mm6 /* mm6: G7 G6 G5 G4 G3 G2 G1 G0 */
movq %mm5,temp_mmx+16(%esp) /* low chroma B */
paddw %mm0,%mm5 /* 4 low B values in signed 16 bit */
movq %mm2,temp_mmx+40(%esp) /* high chroma B */
paddw %mm3,%mm2 /* 4 high B values in signed 16 bit */
psraw BRightShift(%esp),%mm5 /* low B scaled down by 6+(8-5) */
psraw BRightShift(%esp),%mm2 /* high B scaled down by 6+(8-5) */
packuswb %mm2,%mm5 /* mm5: B7 B6 B5 B4 B3 B2 B1 B0 */
movq temp_mmx(%esp),%mm2 /* 4 v values */
movq %mm5,%mm1 /* save B */
movq %mm2,%mm7
punpcklwd %mm2,%mm2 /* replicate the 2 low v pixels */
pmullw VtR,%mm2
punpckhwd %mm7,%mm7
pmullw VtR,%mm7
paddusb BUpperLimit(%esp),%mm1 /* mm1: saturate B+0FF-15 */
movq %mm2,temp_mmx+24(%esp) /* low chroma R */
paddw %mm0,%mm2 /* 4 low R values in signed 16 bit */
psraw RRightShift(%esp),%mm2 /* low R scaled down by 6+(8-5) */
pxor %mm4,%mm4 /* mm4=0 for 8-&gt;16 conversion */
movq %mm7,temp_mmx+32(%esp) /* high chroma R */
paddw %mm3,%mm7 /* 4 high R values in signed 16 bit */
psraw RRightShift(%esp),%mm7 /* high R scaled down by 6+(8-5) */
psubusb BUpperLimit(%esp),%mm1
packuswb %mm7,%mm2 /* mm2: R7 R6 R5 R4 R3 R2 R1 R0 */
paddusb GUpperLimit(%esp),%mm6 /* G fast patch ih */
psubusb GUpperLimit(%esp),%mm6 /* fast patch ih */
paddusb RUpperLimit(%esp),%mm2 /* R */
psubusb RUpperLimit(%esp),%mm2
/*
* here we are packing from RGB24 to RGB16
* input:
* mm6: G7 G6 G5 G4 G3 G2 G1 G0
* mm1: B7 B6 B5 B4 B3 B2 B1 B0
* mm2: R7 R6 R5 R4 R3 R2 R1 R0
* assuming 8 original pixels in 0-H representation on mm6, mm5, mm2
* when H=2**xBITS-1 (x is for R G B)
* output:
* mm1- result: 4 low RGB16
* mm7- result: 4 high RGB16
* using: mm0- zero register
* mm3- temporary results
* algorithm:
* for (i=0; i&lt;8; i++) {
* RGB[i]=256*(R[i]&lt;&lt;(8-5))+(G[i]&lt;&lt;5)+B[i];
* }
*/
psllq RLeftShift(%esp),%mm2 /* position R in the most significant
part of the byte */
movq %mm1,%mm7 /* mm1: Save B */
/*
* note: no need for shift to place B on the least significant part of the byte
* R in left position, B in the right position so they can be combined
*/
punpcklbw %mm2,%mm1 /* mm1: 4 low 16 bit RB */
pxor %mm0,%mm0 /* mm0: 0 */
punpckhbw %mm2,%mm7 /* mm5: 4 high 16 bit RB */
movq %mm6,%mm3 /* mm3: G */
punpcklbw %mm0,%mm6 /* mm6: low 4 G 16 bit */
psllw GLeftShift(%esp),%mm6 /* shift low G 5 positions */
punpckhbw %mm0,%mm3 /* mm3: high 4 G 16 bit */
por %mm6,%mm1 /* mm1: low RBG16 */
psllw GLeftShift(%esp),%mm3 /* shift high G 5 positions */
por %mm3,%mm7 /* mm5: high RBG16 */
movl tmpYCursorOdd(%esp),%ebp /* moved to here to save cycles
before odd line */
movq %mm1,(%edi) /* !! aligned */
/*- start odd line */
movq (%ebp,%ebx,2),%mm1 /* mm1 has 8 y pixels */
pxor %mm2,%mm2
psubusb Yadd,%mm1 /* mm1 has 8 pixels y-16 */
movq %mm1,%mm5
punpcklbw %mm2,%mm1 /* get 4 low y-16 unsign pixels word */
pmullw Ymul,%mm1 /* low 4 luminance contribution */
punpckhbw %mm2,%mm5 /* 4 high y-16 */
pmullw Ymul,%mm5 /* high 4 luminance contribution */
movq %mm7,8(%edi) /* !! aligned */
movq %mm1,%mm0
paddw temp_mmx+24(%esp),%mm0 /* low 4 R */
movq %mm5,%mm6
psraw RRightShift(%esp),%mm0 /* low R scaled down by 6+(8-5) */
paddw temp_mmx+32(%esp),%mm5 /* high 4 R */
movq %mm1,%mm2
psraw RRightShift(%esp),%mm5 /* high R scaled down by 6+(8-5) */
paddw temp_mmx+16(%esp),%mm2 /* low 4 B */
packuswb %mm5,%mm0 /* mm0: R7 R6 R5 R4 R3 R2 R1 R0 */
psraw BRightShift(%esp),%mm2 /* low B scaled down by 6+(8-5) */
movq %mm6,%mm5
paddw temp_mmx+40(%esp),%mm6 /* high 4 B */
psraw BRightShift(%esp),%mm6 /* high B scaled down by 6+(8-5) */
movq temp_mmx+8(%esp),%mm3 /* chroma G low 4 */
packuswb %mm6,%mm2 /* mm2: B7 B6 B5 B4 B3 B2 B1 B0 */
movq %mm3,%mm4
punpcklwd %mm3,%mm3 /* replicate low 2 */
punpckhwd %mm4,%mm4 /* replicate high 2 */
psubw %mm3,%mm1 /* 4 low G */
psraw GRightShift(%esp),%mm1 /* low G scaled down by 6+(8-5) */
psubw %mm4,%mm5 /* 4 high G values in signed 16 bit */
psraw GRightShift(%esp),%mm5 /* high G scaled down by 6+(8-5) */
paddusb BUpperLimit(%esp),%mm2 /* mm1: saturate B+0FF-15 */
packuswb %mm5,%mm1 /*mm1: G7 G6 G5 G4 G3 G2 G1 G0 */
psubusb BUpperLimit(%esp),%mm2
paddusb GUpperLimit(%esp),%mm1 /* G */
psubusb GUpperLimit(%esp),%mm1
paddusb RUpperLimit(%esp),%mm0 /* R */
movl tmpCCOPitch(%esp),%eax
psubusb RUpperLimit(%esp),%mm0
/*
* here we are packing from RGB24 to RGB16
* mm1: G7 G6 G5 G4 G3 G2 G1 G0
* mm2: B7 B6 B5 B4 B3 B2 B1 B0
* mm0: R7 R6 R5 R4 R3 R2 R1 R0
* output:
* mm2- result: 4 low RGB16
* mm7- result: 4 high RGB16
* using: mm4- zero register
* mm3- temporary results
*/
psllq RLeftShift(%esp),%mm0 /* position R in the most significant
part of the byte */
movq %mm2,%mm7 /* mm7: Save B */
/*
* note: no need for shift to place B on the least significant part of the byte
* R in left position, B in the right position so they can be combined
*/
punpcklbw %mm0,%mm2 /* mm1: 4 low 16 bit RB */
pxor %mm4,%mm4 /* mm4: 0 */
movq %mm1,%mm3 /* mm3: G */
punpckhbw %mm0,%mm7 /* mm7: 4 high 16 bit RB */
punpcklbw %mm4,%mm1 /* mm1: low 4 G 16 bit */
punpckhbw %mm4,%mm3 /* mm3: high 4 G 16 bit */
psllw GLeftShift(%esp),%mm1 /* shift low G 5 positions */
por %mm1,%mm2 /* mm2: low RBG16 */
psllw GLeftShift(%esp),%mm3 /* shift high G 5 positions */
por %mm3,%mm7 /* mm7: high RBG16 */
movq %mm2,(%edi,%eax,)
movq %mm7,8(%edi,%eax,) /* aligned */
addl $16,%edi /* ih take 16 bytes (8 pixels-16 bit) */
addl $4,%ebx /* ? to take 4 pixels together
instead of 2 */
jl do_next_8x2_block
addl CCOSkipDistance(%esp),%edi /* go to begin of next line */
addl tmpCCOPitch(%esp),%edi /* skip odd line (if it is needed) */
// Leax AspectCount
// Lebp CCOPitch ; skip odd line
// sub eax, 2
// jg @f
// Addeax AspectBaseCount
// xor ebp, ebp
//@@:
// Seax AspectCount
// add edi, ebp
movl YPitch(%esp),%eax
movl tmpYCursorOdd(%esp),%ebp
addl %eax,%ebp /* skip one line */
// lea ebp, [ebp+2*eax] /* skip two lines */
movl %ebp,tmpYCursorEven(%esp)
// Sebp tmpYCursorOdd
addl %eax,%ebp /* skip one line */
movl %ebp,tmpYCursorOdd(%esp)
// Lebp tmpYCursorEven
// lea ebp, [ebp+2*eax]
// Sebp tmpYCursorEven
addl ChromaPitch(%esp),%esi
addl ChromaPitch(%esp),%edx
// Leax YLimit /* Done with last line? */
// cmp ebp, eax
// jbe PrepareChromaLine
subw $2,FrameHeight(%esp)
ja PrepareChromaLine
/******************************************************************************/
finish:
emms
addl $LocalFrameSize,%esp
popl %ebx
popl %ebp
popl %edi
popl %esi
ret
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