Commit 52d7937c authored by Sam Hocevar's avatar Sam Hocevar

. rajout de l'option -Winline

 . fix de certaines fonctions qui devraient �tre inlin�es
 . gain de place dans la YUVMMX
parent e13aed00
[]
0.1.99f :
* plugin detection now works
* "gvlc", "fbvlc", "ggivlc" aliases now work
* fixed functions that weren't properly inlined
* removed bloat from the MMX YUV plugin
Thu Jul 20 15:14:06 CEST 2000
0.1.99e :
......
......@@ -8,6 +8,11 @@ A typical way to configure the vlc is :
./configure --prefix=/usr --enable-mmx --enable-gnome
For a full compilation, you may try :
./configure --prefix=/usr --enable-mmx --enable-gnome --enable-fb \
--enable-glide --enable-ggi --enable-mga --enable-esd
See `./configure --help' for more information.
Then, run `make', and `make install' to install it.
......
......@@ -79,12 +79,14 @@ endif
# C compiler flags: compilation
#
CCFLAGS += $(DEFINE) $(INCLUDE)
CCFLAGS += -Wall
CCFLAGS += -Wall -Winline
CCFLAGS += -D_REENTRANT
CCFLAGS += -D_GNU_SOURCE
# flags needed for clean beos compilation
ifeq ($(SYS),beos)
CCFLAGS += -Wno-multichar -Wno-ctor-dtor-privacy -Woverloaded-virtual
endif
# Optimizations : don't compile debug versions with them
ifeq ($(DEBUG),0)
......
......@@ -2,7 +2,7 @@
.\" First parameter, NAME, should be all caps
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
.\" other parameters are allowed: see man(7), man(1)
.TH VLC 1 "March 13, 2000"
.TH VLC 1 "July 30, 2000"
.\" Please adjust this date whenever revising the manpage.
.\"
.\" Some roff macros, for reference:
......@@ -36,7 +36,7 @@ A summary of options is included below.
Disable audio output.
.TP
.B \-\-aout <plugin>
Specify an audio output plugin.
Specify an audio output plugin: "dsp", "esd", for instance.
.TP
.B \-\-stereo, \-\-mono
Choose stereo or mono audio output
......@@ -45,7 +45,10 @@ Choose stereo or mono audio output
Disable video output.
.TP
.B \-\-vout <plugin>
Specify a video output plugin.
Specify a video output plugin: "gnome", "fb", "glide", for instance.
.TP
.B \-\-yuv <plugin>
Specify a YUV plugin: "mmx", "nommx", for instance.
.TP
.B \-\-display <display>
Specify the display name.
......
......@@ -90,13 +90,13 @@ typedef struct picture_s
#define YUV_444_PICTURE 102 /* 4:4:4 YUV picture */
/* Pictures status */
#define FREE_PICTURE 0 /* picture is free and not allocated */
#define RESERVED_PICTURE 1 /* picture is allocated and reserved */
#define RESERVED_DATED_PICTURE 2 /* picture is waiting for DisplayPicture */
#define RESERVED_DISP_PICTURE 3 /* picture is waiting for a DatePixture */
#define READY_PICTURE 4 /* picture is ready for display */
#define DISPLAYED_PICTURE 5/* picture has been displayed but is linked */
#define DESTROYED_PICTURE 6 /* picture is allocated but no more used */
#define FREE_PICTURE 0 /* free and not allocated */
#define RESERVED_PICTURE 1 /* allocated and reserved */
#define RESERVED_DATED_PICTURE 2 /* waiting for DisplayPicture */
#define RESERVED_DISP_PICTURE 3 /* waiting for a DatePicture */
#define READY_PICTURE 4 /* ready for display */
#define DISPLAYED_PICTURE 5 /* been displayed but is linked */
#define DESTROYED_PICTURE 6 /* allocated but no more used */
/* Aspect ratios (ISO/IEC 13818-2 section 6.3.3, table 6-3) */
#define AR_SQUARE_PICTURE 1 /* square pixels */
......@@ -105,9 +105,9 @@ typedef struct picture_s
#define AR_221_1_PICTURE 4 /* 2.21:1 picture (movie) */
/*****************************************************************************
* subpicture_t: video sub picture unit
* subpicture_t: video subtitle
*****************************************************************************
* Any sub picture unit destined to be displayed by a video output thread should
* Any subtitle destined to be displayed by a video output thread should
* be stored in this structure from it's creation to it's effective display.
* Subtitle type and flags should only be modified by the output thread. Note
* that an empty subtitle MUST have its flags set to 0.
......@@ -118,7 +118,7 @@ typedef struct subpicture_s
int i_type; /* type */
int i_status; /* flags */
int i_size; /* data size */
struct subpicture_s * p_next; /* next SPU to be displayed */
struct subpicture_s * p_next; /* next subtitle to be displayed */
/* Other properties */
mtime_t begin_date; /* beginning of display date */
......@@ -126,7 +126,7 @@ typedef struct subpicture_s
/* Display properties - these properties are only indicative and may be
* changed by the video output thread, or simply ignored depending of the
* subpicture type. */
* subtitle type. */
int i_x; /* offset from alignment position */
int i_y; /* offset from alignment position */
int i_width; /* picture width */
......@@ -160,29 +160,29 @@ typedef struct subpicture_s
} subpicture_t;
/* Subpicture type */
#define EMPTY_SUBPICTURE 0 /* subtitle slot is empty and available */
#define DVD_SUBPICTURE 100 /* DVD subpicture unit */
#define TEXT_SUBPICTURE 200 /* single line text */
#define EMPTY_SUBPICTURE 0 /* subtitle slot is empty and available */
#define DVD_SUBPICTURE 100 /* DVD subpicture unit */
#define TEXT_SUBPICTURE 200 /* single line text */
/* Subpicture status */
#define FREE_SUBPICTURE 0 /* subpicture is free and not allocated */
#define RESERVED_SUBPICTURE 1 /* subpicture is allocated and reserved */
#define READY_SUBPICTURE 2 /* subpicture is ready for display */
#define DESTROYED_SUBPICTURE 3/* subpicture is allocated but no more used */
#define FREE_SUBPICTURE 0 /* free and not allocated */
#define RESERVED_SUBPICTURE 1 /* allocated and reserved */
#define READY_SUBPICTURE 2 /* ready for display */
#define DESTROYED_SUBPICTURE 3 /* allocated but not used anymore */
/* Alignment types */
#define RIGHT_ALIGN 10 /* x is absolute for right */
#define LEFT_ALIGN 11 /* x is absolute for left */
#define RIGHT_RALIGN 12 /* x is relative for right from right */
#define LEFT_RALIGN 13 /* x is relative for left from left */
#define CENTER_ALIGN 20 /* x, y are absolute for center */
#define CENTER_RALIGN 21 /* x, y are relative for center from center */
#define BOTTOM_ALIGN 30 /* y is absolute for bottom */
#define TOP_ALIGN 31 /* y is absolute for top */
#define BOTTOM_RALIGN 32 /* y is relative for bottom from bottom */
#define TOP_RALIGN 33 /* y is relative for top from top */
#define SUBTITLE_RALIGN 34 /* y is relative for center from subtitle */
#define RIGHT_ALIGN 10 /* x is absolute for right */
#define LEFT_ALIGN 11 /* x is absolute for left */
#define RIGHT_RALIGN 12 /* x is relative for right from right */
#define LEFT_RALIGN 13 /* x is relative for left from left */
#define CENTER_ALIGN 20 /* x, y are absolute for center */
#define CENTER_RALIGN 21 /* x,y are relative for center from center */
#define BOTTOM_ALIGN 30 /* y is absolute for bottom */
#define TOP_ALIGN 31 /* y is absolute for top */
#define BOTTOM_RALIGN 32 /* y is relative for bottom from bottom */
#define TOP_RALIGN 33 /* y is relative for top from top */
#define SUBTITLE_RALIGN 34 /* y is relative for center from subtitle */
......@@ -24,10 +24,10 @@
*****************************************************************************/
/*****************************************************************************
* vout_yuv_convert_t: YUV convertion function
* vout_yuv_convert_t: YUV conversion function
*****************************************************************************
* This is the prototype common to all convertion functions. The type of p_pic
* will change depending of the screen depth treated.
* This is the prototype common to all conversion functions. The type of p_pic
* will change depending on the processed screen depth.
* Parameters:
* p_vout video output thread
* p_pic picture address
......@@ -45,13 +45,13 @@ typedef void (vout_yuv_convert_t)( p_vout_thread_t p_vout, void *p_pic,
int i_matrix_coefficients );
/*****************************************************************************
* vout_yuv_t: pre-calculated YUV convertion tables
* vout_yuv_t: pre-calculated YUV conversion tables
*****************************************************************************
* These tables are used by convertion and scaling functions.
* These tables are used by conversion and scaling functions.
*****************************************************************************/
typedef struct vout_yuv_s
{
/* Convertion functions */
/* conversion functions */
vout_yuv_convert_t * p_Convert420; /* YUV 4:2:0 converter */
vout_yuv_convert_t * p_Convert422; /* YUV 4:2:2 converter */
vout_yuv_convert_t * p_Convert444; /* YUV 4:4:4 converter */
......@@ -69,21 +69,21 @@ typedef struct vout_yuv_s
} yuv;
/* Temporary conversion buffer and offset array */
void * p_buffer; /* convertion buffer */
void * p_buffer; /* conversion buffer */
int * p_offset; /* offset array */
} vout_yuv_t;
/*****************************************************************************
* vout_buffer_t: rendering buffer
*****************************************************************************
* This structure store informations about a buffer. Buffers are not completely
* This structure stores information about a buffer. Buffers are not completely
* cleared between displays, and modified areas need 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 */
int i_pic_width, i_pic_height; /* picture size */
/* Other areas - only vertical extensions of areas are stored */
int i_areas; /* number of areas */
......@@ -172,7 +172,7 @@ typedef struct vout_thread_s
/* Pictures and rendering properties */
boolean_t b_grayscale; /* color or grayscale display */
boolean_t b_info; /* print additionnal informations */
boolean_t b_info; /* print additional information */
boolean_t b_interface; /* render interface */
boolean_t b_scale; /* allow picture scaling */
......@@ -192,7 +192,7 @@ typedef struct vout_thread_s
int i_buffer_index; /* buffer index */
vout_buffer_t p_buffer[2]; /* buffers properties */
/* Videos heap and translation tables */
/* Video heap and translation tables */
picture_t p_picture[VOUT_MAX_PICTURES]; /* pictures */
subpicture_t p_subpicture[VOUT_MAX_PICTURES]; /* subpictures */
int i_pictures; /* current heap size */
......@@ -202,7 +202,7 @@ typedef struct vout_thread_s
p_vout_font_t p_default_font; /* default font */
p_vout_font_t p_large_font; /* large font */
/* Synchronisation informations - synchro level is updated by the vout
/* Synchronization informations - synchro level is updated by the vout
* thread and read by decoder threads */
int i_synchro_level; /* trashing level */
} vout_thread_t;
......
......@@ -73,7 +73,6 @@ int aout_EsdOpen( aout_thread_t *p_aout )
int i_mode = ESD_STREAM;
int i_func = ESD_PLAY;
fprintf(stderr, "aout-esd !!\n");
/* Allocate structure */
p_aout->p_sys = malloc( sizeof( aout_sys_t ) );
if( p_aout->p_sys == NULL )
......
/*****************************************************************************
* video_yuv.c: YUV transformation functions
* video_yuv.c: MMX YUV transformation functions
* Provides functions to perform the YUV conversion. The functions provided here
* are a complete and portable C implementation, and may be replaced in certain
* case by optimized functions.
......@@ -55,31 +55,23 @@ int yuv_MMXInit( vout_thread_t *p_vout )
{
size_t tables_size; /* tables size, in bytes */
/* Computes tables size - 3 Bpp use 32 bits pixel entries in tables */
switch( p_vout->i_bytes_per_pixel )
/* Computes tables size for 8bbp only */
if( p_vout->i_bytes_per_pixel == 1 )
{
case 1:
tables_size = sizeof( u8 )
* (p_vout->b_grayscale ? GRAY_TABLE_SIZE : PALETTE_TABLE_SIZE);
break;
case 2:
tables_size = sizeof( u16 )
* (p_vout->b_grayscale ? GRAY_TABLE_SIZE : RGB_TABLE_SIZE);
break;
case 3:
case 4:
default:
tables_size = sizeof( u32 )
* (p_vout->b_grayscale ? GRAY_TABLE_SIZE : RGB_TABLE_SIZE);
break;
}
/* Allocate memory */
p_vout->yuv.p_base = malloc( tables_size );
if( p_vout->yuv.p_base == NULL )
/* Allocate memory */
p_vout->yuv.p_base = malloc( tables_size );
if( p_vout->yuv.p_base == NULL )
{
intf_ErrMsg("error: %s\n", strerror(ENOMEM));
return( 1 );
}
}
else
{
intf_ErrMsg("error: %s\n", strerror(ENOMEM));
return( 1 );
p_vout->yuv.p_base = NULL;
}
/* Allocate memory for conversion buffer and offset array */
......@@ -111,7 +103,11 @@ int yuv_MMXInit( vout_thread_t *p_vout )
*****************************************************************************/
void yuv_MMXEnd( vout_thread_t *p_vout )
{
free( p_vout->yuv.p_base );
if( p_vout->i_bytes_per_pixel == 1 )
{
free( p_vout->yuv.p_base );
}
free( p_vout->yuv.p_buffer );
free( p_vout->yuv.p_offset );
}
......@@ -130,25 +126,6 @@ int yuv_MMXReset( vout_thread_t *p_vout )
/* following functions are local */
/*****************************************************************************
* SetGammaTable: return intensity table transformed by gamma curve.
*****************************************************************************
* pi_table is a table of 256 entries from 0 to 255.
*****************************************************************************/
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;
}
}
/*****************************************************************************
* SetYUV: compute tables and set function pointers
+ *****************************************************************************/
......@@ -166,136 +143,103 @@ void SetYUV( vout_thread_t *p_vout )
if( p_vout->b_grayscale )
{
/* Grayscale: build gray table */
switch( p_vout->i_bytes_per_pixel )
if( p_vout->i_bytes_per_pixel == 1 )
{
case 1:
{
u16 bright[256], transp[256];
u16 bright[256], transp[256];
p_vout->yuv.yuv.p_gray8 = (u8 *)p_vout->yuv.p_base + GRAY_MARGIN;
for( i_index = 0; i_index < GRAY_MARGIN; i_index++ )
{
p_vout->yuv.yuv.p_gray8[ -i_index ] = RGB2PIXEL( p_vout, pi_gamma[0], pi_gamma[0], pi_gamma[0] );
p_vout->yuv.yuv.p_gray8[ 256 + i_index ] = RGB2PIXEL( p_vout, pi_gamma[255], pi_gamma[255], pi_gamma[255] );
}
for( i_index = 0; i_index < 256; i_index++)
{
p_vout->yuv.yuv.p_gray8[ i_index ] = pi_gamma[ i_index ];
bright[ i_index ] = i_index << 8;
transp[ i_index ] = 0;
}
/* the colors have been allocated, we can set the palette */
p_vout->p_set_palette( p_vout, bright, bright, bright, transp );
p_vout->i_white_pixel = 0xff;
p_vout->i_black_pixel = 0x00;
p_vout->i_gray_pixel = 0x44;
p_vout->i_blue_pixel = 0x3b;
break;
}
case 2:
p_vout->yuv.yuv.p_gray16 = (u16 *)p_vout->yuv.p_base + GRAY_MARGIN;
for( i_index = 0; i_index < GRAY_MARGIN; i_index++ )
{
p_vout->yuv.yuv.p_gray16[ -i_index ] = RGB2PIXEL( p_vout, pi_gamma[0], pi_gamma[0], pi_gamma[0] );
p_vout->yuv.yuv.p_gray16[ 256 + i_index ] = RGB2PIXEL( p_vout, pi_gamma[255], pi_gamma[255], pi_gamma[255] );
}
for( i_index = 0; i_index < 256; i_index++)
{
p_vout->yuv.yuv.p_gray16[ i_index ] = RGB2PIXEL( p_vout, pi_gamma[i_index], pi_gamma[i_index], pi_gamma[i_index] );
bright[ i_index ] = i_index << 8;
transp[ i_index ] = 0;
}
break;
case 3:
case 4:
p_vout->yuv.yuv.p_gray32 = (u32 *)p_vout->yuv.p_base + GRAY_MARGIN;
for( i_index = 0; i_index < GRAY_MARGIN; i_index++ )
{
p_vout->yuv.yuv.p_gray32[ -i_index ] = RGB2PIXEL( p_vout, pi_gamma[0], pi_gamma[0], pi_gamma[0] );
p_vout->yuv.yuv.p_gray32[ 256 + i_index ] = RGB2PIXEL( p_vout, pi_gamma[255], pi_gamma[255], pi_gamma[255] );
}
for( i_index = 0; i_index < 256; i_index++)
{
p_vout->yuv.yuv.p_gray32[ i_index ] = RGB2PIXEL( p_vout, pi_gamma[i_index], pi_gamma[i_index], pi_gamma[i_index] );
}
break;
}
/* the colors have been allocated, we can set the palette */
p_vout->p_set_palette( p_vout, bright, bright, bright, transp );
p_vout->i_white_pixel = 0xff;
p_vout->i_black_pixel = 0x00;
p_vout->i_gray_pixel = 0x44;
p_vout->i_blue_pixel = 0x3b;
}
}
else
{
/* Color: build red, green and blue tables */
switch( p_vout->i_bytes_per_pixel )
if( p_vout->i_bytes_per_pixel == 1 )
{
case 1:
#define RGB_MIN 0
#define RGB_MAX 255
#define CLIP( x ) ( ((x < 0) ? 0 : (x > 255) ? 255 : x) << 8 )
#define SHIFT 20
#define U_GREEN_COEF ((int)(-0.391 * (1<<SHIFT) / 1.164))
#define U_BLUE_COEF ((int)(2.018 * (1<<SHIFT) / 1.164))
#define V_RED_COEF ((int)(1.596 * (1<<SHIFT) / 1.164))
#define V_GREEN_COEF ((int)(-0.813 * (1<<SHIFT) / 1.164))
int y,u,v;
int r,g,b;
int uvr, uvg, uvb;
int i = 0, j = 0;
u16 red[256], green[256], blue[256], transp[256];
unsigned char lookup[PALETTE_TABLE_SIZE];
p_vout->yuv.yuv.p_rgb8 = (u8 *)p_vout->yuv.p_base;
/* this loop calculates the intersection of an YUV box
* and the RGB cube. */
for ( y = 0; y <= 256; y += 16 )
{
#define RGB_MIN 0
#define RGB_MAX 255
#define CLIP( x ) ( ((x < 0) ? 0 : (x > 255) ? 255 : x) << 8 )
int y,u,v;
int r,g,b;
int uvr, uvg, uvb;
int i = 0, j = 0;
u16 red[256], green[256], blue[256], transp[256];
unsigned char lookup[PALETTE_TABLE_SIZE];
p_vout->yuv.yuv.p_rgb8 = (u8 *)p_vout->yuv.p_base;
/* this loop calculates the intersection of an YUV box
* and the RGB cube. */
for ( y = 0; y <= 256; y += 16 )
for ( u = 0; u <= 256; u += 32 )
for ( v = 0; v <= 256; v += 32 )
{
for ( u = 0; u <= 256; u += 32 )
for ( v = 0; v <= 256; v += 32 )
uvr = (V_RED_COEF*(v-128)) >> SHIFT;
uvg = (U_GREEN_COEF*(u-128) + V_GREEN_COEF*(v-128)) >> SHIFT;
uvb = (U_BLUE_COEF*(u-128)) >> SHIFT;
r = y + uvr;
g = y + uvg;
b = y + uvb;
if( r >= RGB_MIN && g >= RGB_MIN && b >= RGB_MIN
&& r <= RGB_MAX && g <= RGB_MAX && b <= RGB_MAX )
{
uvr = (V_RED_COEF*(v-128)) >> SHIFT;
uvg = (U_GREEN_COEF*(u-128) + V_GREEN_COEF*(v-128)) >> SHIFT;
uvb = (U_BLUE_COEF*(u-128)) >> SHIFT;
r = y + uvr;
g = y + uvg;
b = y + uvb;
if( r >= RGB_MIN && g >= RGB_MIN && b >= RGB_MIN
&& r <= RGB_MAX && g <= RGB_MAX && b <= RGB_MAX )
{
/* this one should never happen unless someone fscked up my code */
if(j == 256) { intf_ErrMsg( "vout error: no colors left to build palette\n" ); break; }
/* clip the colors */
red[j] = CLIP( r );
green[j] = CLIP( g );
blue[j] = CLIP( b );
transp[j] = 0;
/* allocate color */
lookup[i] = 1;
p_vout->yuv.yuv.p_rgb8[i++] = j;
j++;
}
else
{
lookup[i] = 0;
p_vout->yuv.yuv.p_rgb8[i++] = 0;
}
/* this one should never happen unless someone fscked up my code */
if(j == 256) { intf_ErrMsg( "vout error: no colors left to build palette\n" ); break; }
/* clip the colors */
red[j] = CLIP( r );
green[j] = CLIP( g );
blue[j] = CLIP( b );
transp[j] = 0;
/* allocate color */
lookup[i] = 1;
p_vout->yuv.yuv.p_rgb8[i++] = j;
j++;
}
else
{
lookup[i] = 0;
p_vout->yuv.yuv.p_rgb8[i++] = 0;
}
i += 128-81;
}
i += 128-81;
}
/* the colors have been allocated, we can set the palette */
/* there will eventually be a way to know which colors
* couldn't be allocated and try to find a replacement */
p_vout->p_set_palette( p_vout, red, green, blue, transp );
/* the colors have been allocated, we can set the palette */
/* there will eventually be a way to know which colors
* couldn't be allocated and try to find a replacement */
p_vout->p_set_palette( p_vout, red, green, blue, transp );
p_vout->i_white_pixel = 0xff;
p_vout->i_black_pixel = 0x00;
p_vout->i_gray_pixel = 0x44;
p_vout->i_blue_pixel = 0x3b;
p_vout->i_white_pixel = 0xff;
p_vout->i_black_pixel = 0x00;
p_vout->i_gray_pixel = 0x44;
p_vout->i_blue_pixel = 0x3b;
i = 0;
/* this loop allocates colors that got outside
* the RGB cube */
for ( y = 0; y <= 256; y += 16 )
i = 0;
/* this loop allocates colors that got outside
* the RGB cube */
for ( y = 0; y <= 256; y += 16 )
{
for ( u = 0; u <= 256; u += 32 )
{
for ( u = 0; u <= 256; u += 32 )
for ( v = 0; v <= 256; v += 32 )
{
int u2, v2;
......@@ -331,60 +275,9 @@ void SetYUV( vout_thread_t *p_vout )
}
i++;
}
i += 128-81;
}
break;
}
case 2:
p_vout->yuv.yuv.p_rgb16 = (u16 *)p_vout->yuv.p_base;
for( i_index = 0; i_index < RED_MARGIN; i_index++ )
{
p_vout->yuv.yuv.p_rgb16[RED_OFFSET - RED_MARGIN + i_index] = RGB2PIXEL( p_vout, pi_gamma[0], 0, 0 );
p_vout->yuv.yuv.p_rgb16[RED_OFFSET + 256 + i_index] = RGB2PIXEL( p_vout, pi_gamma[255], 0, 0 );
i += 128-81;
}
for( i_index = 0; i_index < GREEN_MARGIN; i_index++ )
{
p_vout->yuv.yuv.p_rgb16[GREEN_OFFSET - GREEN_MARGIN + i_index] = RGB2PIXEL( p_vout, 0, pi_gamma[0], 0 );
p_vout->yuv.yuv.p_rgb16[GREEN_OFFSET + 256 + i_index] = RGB2PIXEL( p_vout, 0, pi_gamma[255], 0 );
}
for( i_index = 0; i_index < BLUE_MARGIN; i_index++ )
{
p_vout->yuv.yuv.p_rgb16[BLUE_OFFSET - BLUE_MARGIN + i_index] = RGB2PIXEL( p_vout, 0, 0, pi_gamma[0] );
p_vout->yuv.yuv.p_rgb16[BLUE_OFFSET + BLUE_MARGIN + i_index] = RGB2PIXEL( p_vout, 0, 0, pi_gamma[255] );
}
for( i_index = 0; i_index < 256; i_index++ )
{
p_vout->yuv.yuv.p_rgb16[RED_OFFSET + i_index] = RGB2PIXEL( p_vout, pi_gamma[ i_index ], 0, 0 );
p_vout->yuv.yuv.p_rgb16[GREEN_OFFSET + i_index] = RGB2PIXEL( p_vout, 0, pi_gamma[ i_index ], 0 );
p_vout->yuv.yuv.p_rgb16[BLUE_OFFSET + i_index] = RGB2PIXEL( p_vout, 0, 0, pi_gamma[ i_index ] );
}
break;
case 3:
case 4:
p_vout->yuv.yuv.p_rgb32 = (u32 *)p_vout->yuv.p_base;
for( i_index = 0; i_index < RED_MARGIN; i_index++ )
{
p_vout->yuv.yuv.p_rgb32[RED_OFFSET - RED_MARGIN + i_index] = RGB2PIXEL( p_vout, pi_gamma[0], 0, 0 );
p_vout->yuv.yuv.p_rgb32[RED_OFFSET + 256 + i_index] = RGB2PIXEL( p_vout, pi_gamma[255], 0, 0 );
}
for( i_index = 0; i_index < GREEN_MARGIN; i_index++ )
{
p_vout->yuv.yuv.p_rgb32[GREEN_OFFSET - GREEN_MARGIN + i_index] = RGB2PIXEL( p_vout, 0, pi_gamma[0], 0 );
p_vout->yuv.yuv.p_rgb32[GREEN_OFFSET + 256 + i_index] = RGB2PIXEL( p_vout, 0, pi_gamma[255], 0 );
}
for( i_index = 0; i_index < BLUE_MARGIN; i_index++ )
{
p_vout->yuv.yuv.p_rgb32[BLUE_OFFSET - BLUE_MARGIN + i_index] = RGB2PIXEL( p_vout, 0, 0, pi_gamma[0] );
p_vout->yuv.yuv.p_rgb32[BLUE_OFFSET + BLUE_MARGIN + i_index] = RGB2PIXEL( p_vout, 0, 0, pi_gamma[255] );
}
for( i_index = 0; i_index < 256; i_index++ )
{
p_vout->yuv.yuv.p_rgb32[RED_OFFSET + i_index] = RGB2PIXEL( p_vout, pi_gamma[ i_index ], 0, 0 );
p_vout->yuv.yuv.p_rgb32[GREEN_OFFSET + i_index] = RGB2PIXEL( p_vout, 0, pi_gamma[ i_index ], 0 );
p_vout->yuv.yuv.p_rgb32[BLUE_OFFSET + i_index] = RGB2PIXEL( p_vout, 0, 0, pi_gamma[ i_index ] );
}
break;
}
}
......
/*****************************************************************************
* video_yuv.h: YUV transformation functions
* video_yuv.h: MMX YUV transformation functions
* Provides functions to perform the YUV conversion. The functions provided here
* are a complete and portable C implementation, and may be replaced in certain
* case by optimized functions.
......@@ -28,30 +28,11 @@
* Constants
*****************************************************************************/
/* Margins and offsets in conversion tables - Margins are used in case a RGB
* RGB conversion would give a value outside the 0-255 range. Offsets have been
* calculated to avoid using the same cache line for 2 tables. conversion tables
* are 2*MARGIN + 256 long and stores pixels.*/
#define RED_MARGIN 178
#define GREEN_MARGIN 135
#define BLUE_MARGIN 224
#define RED_OFFSET 1501 /* 1323 to 1935 */
#define GREEN_OFFSET 135 /* 0 to 526 */
#define BLUE_OFFSET 818 /* 594 to 1298 */
#define RGB_TABLE_SIZE 1935 /* total table size */
#define GRAY_MARGIN 384
#define GRAY_TABLE_SIZE 1024 /* total table size */
#define PALETTE_TABLE_SIZE 2176 /* YUV -> 8bpp palette lookup table */
/* macros used for YUV pixel conversions */
#define SHIFT 20
#define U_GREEN_COEF ((int)(-0.391 * (1<<SHIFT) / 1.164))
#define U_BLUE_COEF ((int)(2.018 * (1<<SHIFT) / 1.164))
#define V_RED_COEF ((int)(1.596 * (1<<SHIFT) / 1.164))
#define V_GREEN_COEF ((int)(-0.813 * (1<<SHIFT) / 1.164))
/* argument lists for YUV functions */
#define YUV_ARGS_8BPP p_vout_thread_t p_vout, u8 *p_pic, yuv_data_t *p_y, \
yuv_data_t *p_u, yuv_data_t *p_v, int i_width, int i_height, int i_pic_width, \
......
......@@ -99,7 +99,10 @@ void ConvertYUV420RGB16( YUV_ARGS_16BPP )
__asm__( MMX_INIT_16
: : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) );
__asm__( ".align 8" MMX_YUV_MUL MMX_YUV_ADD MMX_UNPACK_16
__asm__( ".align 8"
MMX_YUV_MUL
MMX_YUV_ADD
MMX_UNPACK_16
: : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) );
p_y += 8;
......
/*****************************************************************************
* video_yuv24.c: YUV transformation functions for 24 bpp
* video_yuv24.c: MMX YUV transformation functions for 24 bpp
* Provides functions to perform the YUV conversion. The functions provided here
* are a complete and portable C implementation, and may be replaced in certain
* case by optimized functions.
......
/*****************************************************************************
* video_yuv32.c: YUV transformation functions for 32 bpp
* video_yuv32.c: MMX YUV transformation functions for 32 bpp
* Provides functions to perform the YUV conversion. The functions provided here
* are a complete and portable C implementation, and may be replaced in certain
* case by optimized functions.
......
/*****************************************************************************
* video_yuv8.c: YUV transformation functions for 8bpp
* video_yuv8.c: MMX YUV transformation functions for 8bpp
* Provides functions to perform the YUV conversion. The functions provided here
* are a complete and portable C implementation, and may be replaced in certain
* case by optimized functions.
......
/*****************************************************************************
* video_yuv_asm.h: YUV transformation assembly
* video_yuv_asm.h: MMX YUV transformation assembly
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
*
......@@ -82,7 +82,7 @@ movq %%mm1, %%mm3 # Copy 4 Cr 00 v3 00 v2 00 v1 00 v0 \n\
pmulhw mmx_U_green, %%mm2 # Mul Cb with green coeff -> Cb green \n\
pmulhw mmx_V_green, %%mm3 # Mul Cr with green coeff -> Cr green \n\
pmulhw mmx_U_blue, %%mm0 # Mul Cb -> Cblue 00 b3 00 b2 00 b1 00 b0 \n\
pmulhw mmx_V_red, %%mm1 # Mul Cr -> Cred 00 r3 00 r2 00 r1 00 \n\
pmulhw mmx_V_red, %%mm1 # Mul Cr -> Cred 00 r3 00 r2 00 r1 00 r0 \n\
paddsw %%mm3, %%mm2 # Cb green + Cr green -> Cgreen \n\
\n\
# convert the luma part \n\
......
/*****************************************************************************
* video_yuv_macros.h: YUV transformation macros
* video_yuv_macros.h: MMX YUV transformation macros
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
*
......
......@@ -74,6 +74,25 @@ void aout_Thread_U16_Stereo ( aout_thread_t * p_aout );
static __inline__ void InitializeIncrement( aout_increment_t * p_increment, long l_numerator, long l_denominator );
static __inline__ int NextFrame( aout_thread_t * p_aout, aout_fifo_t * p_fifo, mtime_t aout_date );
/*****************************************************************************
* InitializeIncrement
*****************************************************************************/
static __inline__ void InitializeIncrement( aout_increment_t * p_increment, long l_numerator, long l_denominator )
{
p_increment->l_remainder = -l_denominator;
p_increment->l_euclidean_integer = 0;
while ( l_numerator >= l_denominator )
{
p_increment->l_euclidean_integer++;
l_numerator -= l_denominator;
}
p_increment->l_euclidean_remainder = l_numerator;
p_increment->l_euclidean_denominator = l_denominator;
}
/*****************************************************************************
* aout_CreateThread: initialize audio thread
*****************************************************************************/
......@@ -467,25 +486,6 @@ void aout_DestroyFifo( aout_fifo_t * p_fifo )
/* Following functions are local */
/*****************************************************************************
* InitializeIncrement
*****************************************************************************/
static __inline__ void InitializeIncrement( aout_increment_t * p_increment, long l_numerator, long l_denominator )
{
p_increment->l_remainder = -l_denominator;
p_increment->l_euclidean_integer = 0;
while ( l_numerator >= l_denominator )
{
p_increment->l_euclidean_integer++;
l_numerator -= l_denominator;
}
p_increment->l_euclidean_remainder = l_numerator;
p_increment->l_euclidean_denominator = l_denominator;
}
/*****************************************************************************
* NextFrame
*****************************************************************************/
......
......@@ -92,13 +92,15 @@ static __inline__ void input_DemuxTS( input_thread_t *p_input,
static __inline__ void input_DemuxPES( input_thread_t *p_input,
ts_packet_t *ts_packet,
es_descriptor_t *p_es_descriptor,
boolean_t b_unit_start, boolean_t b_packet_lost );
boolean_t b_unit_start,
boolean_t b_packet_lost );
static __inline__ void input_ParsePES( input_thread_t *p_input,
es_descriptor_t *p_es_descriptor );
static __inline__ void input_DemuxPSI( input_thread_t *p_input,
ts_packet_t *ts_packet,
es_descriptor_t *p_es_descriptor,
boolean_t b_unit_start, boolean_t b_packet_lost );
boolean_t b_unit_start,
boolean_t b_packet_lost );
/*****************************************************************************
* input_CreateThread: creates a new input thread
......@@ -108,8 +110,9 @@ static __inline__ void input_DemuxPSI( input_thread_t *p_input,
* If pi_status is NULL, then the function will block until the thread is ready.
* If not, it will be updated using one of the THREAD_* constants.
*****************************************************************************/
input_thread_t *input_CreateThread ( int i_method, void *p_source, int i_port, int i_vlan,
p_vout_thread_t p_vout, p_aout_thread_t p_aout, int *pi_status )
input_thread_t *input_CreateThread ( int i_method, void *p_source, int i_port,
int i_vlan, p_vout_thread_t p_vout,
p_aout_thread_t p_aout, int *pi_status )
{
input_thread_t * p_input; /* thread descriptor */
int i_status; /* thread status */
......@@ -343,528 +346,376 @@ static int InitThread( input_thread_t *p_input )
}
/*****************************************************************************
* RunThread: main thread loop
* input_DemuxPSI:
*****************************************************************************
* Thread in charge of processing the network packets and demultiplexing.
* Notice that current ES state has been locked by input_SortPacket.
* (No more true, changed by benny - FIXME: See if it's ok, and definitely
* change the code ?? )
*****************************************************************************/
static void RunThread( input_thread_t *p_input )
static __inline__ void input_DemuxPSI( input_thread_t *p_input,
ts_packet_t *p_ts_packet,
es_descriptor_t *p_es_descriptor,
boolean_t b_unit_start,
boolean_t b_packet_lost )
{
/*
* Initialize thread and free configuration
*/
p_input->b_error = InitThread( p_input );
if( p_input->b_error )
int i_data_offset; /* Offset of the interesting data in the TS packet */
u16 i_data_length; /* Length of those data */
//boolean_t b_first_section; /* another section in the TS packet ? */
ASSERT(p_input);
ASSERT(p_ts_packet);
ASSERT(p_es_descriptor);
#define p_psi (p_es_descriptor->p_psi_section)
//intf_DbgMsg( "input debug: PSI demultiplexing %p (%p)\n", p_ts_packet, p_input);
//intf_DbgMsg( "Packet: %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x (unit start: %d)\n", p_ts_packet->buffer[p_ts_packet->i_payload_start], p_ts_packet->buffer[p_ts_packet->i_payload_start+1], p_ts_packet->buffer[p_ts_packet->i_payload_start+2], p_ts_packet->buffer[p_ts_packet->i_payload_start+3], p_ts_packet->buffer[p_ts_packet->i_payload_start+4], p_ts_packet->buffer[p_ts_packet->i_payload_start+5], p_ts_packet->buffer[p_ts_packet->i_payload_start+6], p_ts_packet->buffer[p_ts_packet->i_payload_start+7], p_ts_packet->buffer[p_ts_packet->i_payload_start+8], p_ts_packet->buffer[p_ts_packet->i_payload_start+9], p_ts_packet->buffer[p_ts_packet->i_payload_start+10], p_ts_packet->buffer[p_ts_packet->i_payload_start+11], p_ts_packet->buffer[p_ts_packet->i_payload_start+12], p_ts_packet->buffer[p_ts_packet->i_payload_start+13], p_ts_packet->buffer[p_ts_packet->i_payload_start+14], p_ts_packet->buffer[p_ts_packet->i_payload_start+15], p_ts_packet->buffer[p_ts_packet->i_payload_start+16], p_ts_packet->buffer[p_ts_packet->i_payload_start+17], p_ts_packet->buffer[p_ts_packet->i_payload_start+18], p_ts_packet->buffer[p_ts_packet->i_payload_start+19], p_ts_packet->buffer[p_ts_packet->i_payload_start+20], b_unit_start);
/* Try to find the beginning of the payload in the packet to initialise
* the do-while loop that follows -> Compute the i_data_offset variable:
* by default, the value is set so that we won't enter in the while loop.
* It will be set to a correct value if the data are not corrupted */
i_data_offset = TS_PACKET_SIZE;
/* Has the reassembly of a section already begun in a previous packet ? */
if( p_psi->b_running_section )
{
free( p_input ); /* destroy descriptor */
return;
/* Was data lost since the last TS packet ? */
if( b_packet_lost )
{
/* Discard the packet and wait for the begining of a new one
* to resynch */
p_psi->b_running_section = 0;
p_psi->i_current_position = 0;
intf_DbgMsg( "PSI section(s) discarded due to packet loss\n" );
}
else
{
/* The data that complete a previously began section are always at
* the beginning of the TS payload... */
i_data_offset = p_ts_packet->i_payload_start;
/* ...Unless there is a pointer field, that we have to bypass */
if( b_unit_start )
i_data_offset++;
//intf_DbgMsg( "New part of the section received at offset %d\n", i_data_offset );
}
}
/*
* Main loop
*/
intf_DbgMsg("\n");
while( !p_input->b_die && !p_input->b_error )
/* We are looking for the beginning of a new section */
else
{
/* Scatter read the UDP packet from the network or the file. */
if( (input_ReadPacket( p_input )) == (-1) )
if( b_unit_start )
{
/* FIXME??: Normally, a thread can't kill itself, but we don't have
* any method in case of an error condition ... */
p_input->b_error = 1;
/* Get the offset at which the data for that section can be found
* The offset is stored in the pointer_field since we are
* interested in the first section of the TS packet. Note that
* the +1 is to bypass the pointer field */
i_data_offset = p_ts_packet->i_payload_start +
p_ts_packet->buffer[p_ts_packet->i_payload_start] + 1;
//intf_DbgMsg( "New section beginning at offset %d in TS packet\n", i_data_offset );
}
else
{
/* This may either mean that the TS is bad or that the packet
* contains the end of a section that had been discarded in a
* previous loop: trash the TS packet since we cannot do
* anything with those data: */
p_psi->b_running_section = 0;
p_psi->i_current_position = 0;
intf_DbgMsg( "PSI packet discarded due to lack of synchronisation\n" );
}
#ifdef STATS
p_input->c_loops++;
#endif
}
/*
* Error loop
*/
if( p_input->b_error )
/* The section we will deal with during the first iteration of the
* following loop is the first one contained in the TS packet */
// b_first_section = 1;
/* Reassemble the pieces of sections contained in the TS packet and
* decode the sections that could have been completed.
* Stop when we reach the end of the packet or stuffing bytes */
while( i_data_offset < TS_PACKET_SIZE && p_ts_packet->buffer[i_data_offset] != 0xFF )
{
ErrorThread( p_input );
}
/* If the current section is a new one, reinit the data fields of
* the p_psi struct to start its decoding */
if( !p_psi->b_running_section )
{
/* Read the length of the new section */
p_psi->i_length = (U16_AT(&p_ts_packet->buffer[i_data_offset+1]) & 0xFFF) + 3;
//intf_DbgMsg( "Section length %d\n", p_psi->i_length );
if( p_psi->i_length > PSI_SECTION_SIZE )
{
/* The TS packet is corrupted, stop here to avoid possible
* a seg fault */
intf_DbgMsg( "PSI Section size is too big, aborting its reception\n" );
break;
}
/* End of thread */
EndThread( p_input );
intf_DbgMsg("thread end\n");
}
/* Init the reassembly of that section */
p_psi->b_running_section = 1;
p_psi->i_current_position = 0;
}
/* Compute the length of data related to the section in this TS packet */
if( p_psi->i_length - p_psi->i_current_position > TS_PACKET_SIZE - i_data_offset)
i_data_length = TS_PACKET_SIZE - i_data_offset;
else
i_data_length = p_psi->i_length - p_psi->i_current_position;
/*****************************************************************************
* ErrorThread: RunThread() error loop
*****************************************************************************
* This function is called when an error occured during thread main's loop.
*****************************************************************************/
static void ErrorThread( input_thread_t *p_input )
{
/* Wait until a `die' order */
intf_DbgMsg("\n");
while( !p_input->b_die )
{
/* Sleep a while */
msleep( VOUT_IDLE_SLEEP );
}
}
/* Copy those data in the section buffer */
memcpy( &p_psi->buffer[p_psi->i_current_position], &p_ts_packet->buffer[i_data_offset],
i_data_length );
/*****************************************************************************
* EndThread: end the input thread
*****************************************************************************/
static void EndThread( input_thread_t * p_input )
{
int * pi_status; /* threas status */
int i_es_loop; /* es index */
/* Interesting data are now after the ones we copied, since no gap is
* allowed between 2 sections in a TS packets */
i_data_offset += i_data_length;
/* Store status */
intf_DbgMsg("\n");
pi_status = p_input->pi_status;
*pi_status = THREAD_END;
/* Decode the packet if it is now complete */
if (p_psi->i_length == p_psi->i_current_position + i_data_length)
{
/* Packet is complete, decode it */
//intf_DbgMsg( "SECTION COMPLETE: starting decoding of its data\n" );
input_PsiDecode( p_input, p_psi );
/* Close input method */
p_input->p_Close( p_input );
/* Prepare the buffer to receive a new section */
p_psi->i_current_position = 0;
p_psi->b_running_section = 0;
/* Destroy all decoder threads */
for( i_es_loop = 0;
(i_es_loop < INPUT_MAX_ES) && (p_input->pp_selected_es[i_es_loop] != NULL) ;
i_es_loop++ )
{
switch( p_input->pp_selected_es[i_es_loop]->i_type )
/* The new section won't be the first anymore */
//b_first_section = 0;
}
else
{
case MPEG1_VIDEO_ES:
case MPEG2_VIDEO_ES:
vpar_DestroyThread( (vpar_thread_t*)(p_input->pp_selected_es[i_es_loop]->p_dec) /*, NULL */ );
break;
case MPEG1_AUDIO_ES:
case MPEG2_AUDIO_ES:
adec_DestroyThread( (adec_thread_t*)(p_input->pp_selected_es[i_es_loop]->p_dec) );
break;
case AC3_AUDIO_ES:
ac3dec_DestroyThread( (ac3dec_thread_t *)(p_input->pp_selected_es[i_es_loop]->p_dec) );
break;
case LPCM_AUDIO_ES:
lpcmdec_DestroyThread((lpcmdec_thread_t *)(p_input->pp_selected_es[i_es_loop]->p_dec) );
break;
case DVD_SPU_ES:
spudec_DestroyThread( (spudec_thread_t *)(p_input->pp_selected_es[i_es_loop]->p_dec) );
break;
case 0:
/* Special streams for the PSI decoder, PID 0 and 1 */
break;
#ifdef DEBUG
default:
intf_DbgMsg("error: unknown decoder type %d\n", p_input->pp_selected_es[i_es_loop]->i_type );
break;
#endif
/* Prepare the buffer to receive the next part of the section */
p_psi->i_current_position += i_data_length;
//intf_DbgMsg( "Section not complete, waiting for the end\n" );
}
//intf_DbgMsg( "Must loop ? Next data offset: %d, stuffing: %d\n",
// i_data_offset, p_ts_packet->buffer[i_data_offset] );
}
input_NetlistEnd( p_input ); /* clean netlist */
input_PsiEnd( p_input ); /* clean PSI information */
input_PcrEnd( p_input ); /* clean PCR information */
free( p_input ); /* free input_thread structure */
/* Relase the TS packet, we don't need it anymore */
input_NetlistFreeTS( p_input, p_ts_packet );
/* Update status */
*pi_status = THREAD_OVER;
#undef p_psi
}
/*****************************************************************************
* input_ReadPacket: reads a packet from the network or the file
* input_ParsePES
*****************************************************************************
* Parse a finished PES packet and analyze its header.
*****************************************************************************/
static __inline__ int input_ReadPacket( input_thread_t *p_input )
static __inline__ void input_ParsePES( input_thread_t *p_input,
es_descriptor_t *p_es_descriptor )
{
int i_base_index; /* index of the first free iovec */
int i_current_index;
int i_packet_size;
#ifdef INPUT_LIFO_TS_NETLIST
int i_meanwhile_released;
int i_currently_removed;
#endif
ts_packet_t * p_ts_packet;
decoder_fifo_t * p_fifo;
u8 i_pes_header_size;
ts_packet_t * p_ts;
int i_ts_payload_size;
/* In this function, we only care about the TS netlist. PES netlist
* is for the demultiplexer. */
#ifdef INPUT_LIFO_TS_NETLIST
i_base_index = p_input->netlist.i_ts_index;
/* Verify that we still have packets in the TS netlist */
if( (INPUT_MAX_TS + INPUT_TS_READ_ONCE - 1 - p_input->netlist.i_ts_index) <= INPUT_TS_READ_ONCE )
{
intf_ErrMsg("input error: TS netlist is empty !\n");
return( -1 );
}
#else /* FIFO netlist */
i_base_index = p_input->netlist.i_ts_start;
if( p_input->netlist.i_ts_start + INPUT_TS_READ_ONCE -1 > INPUT_MAX_TS )
{
/* The netlist is splitted in 2 parts. We must gather them to consolidate
the FIFO (we make the loop easily in having the same iovec at the far
end and in the beginning of netlist_free).
That's why the netlist is (INPUT_MAX_TS +1) + (INPUT_TS_READ_ONCE -1)
large. */
memcpy( p_input->netlist.p_ts_free + INPUT_MAX_TS + 1,
p_input->netlist.p_ts_free,
(p_input->netlist.i_ts_start + INPUT_TS_READ_ONCE - 1 - INPUT_MAX_TS)
* sizeof(struct iovec) );
}
/* Verify that we still have packets in the TS netlist */
if( ((p_input->netlist.i_ts_end -1 - p_input->netlist.i_ts_start) & INPUT_MAX_TS) <= INPUT_TS_READ_ONCE )
{
intf_ErrMsg("input error: TS netlist is empty !\n");
return( -1 );
}
#endif /* FIFO netlist */
/* Scatter read the buffer. */
i_packet_size = (*p_input->p_Read)( p_input,
&p_input->netlist.p_ts_free[i_base_index],
INPUT_TS_READ_ONCE );
if( i_packet_size == (-1) )
{
#if 0
intf_DbgMsg("Read packet %d %p %d %d\n", i_base_index,
&p_input->netlist.p_ts_free[i_base_index],
p_input->netlist.i_ts_start,
p_input->netlist.i_ts_end);
#endif
intf_ErrMsg("input error: readv() failed (%s)\n", strerror(errno));
return( -1 );
}
if( i_packet_size == 0 )
{
/* No packet has been received, so stop here. */
return( 0 );
}
/* Demultiplex the TS packets (1..INPUT_TS_READ_ONCE) received. */
for( i_current_index = i_base_index;
(i_packet_size -= TS_PACKET_SIZE) >= 0;
i_current_index++ )
{
/* BTW, something REALLY bad could happen if we receive packets with
a wrong size. */
p_ts_packet = (ts_packet_t*)(p_input->netlist.p_ts_free[i_current_index].iov_base);
/* Don't cry :-), we are allowed to do that cast, because initially,
our buffer was malloc'ed with sizeof(ts_packet_t) */
/* Find out if we need this packet and demultiplex. */
input_SortPacket( p_input /* for current PIDs and netlist */,
p_ts_packet);
}
if( i_packet_size > 0 )
{
intf_ErrMsg("input error: wrong size\n");
return( -1 );
}
#define p_pes (p_es_descriptor->p_pes_packet)
/* Remove the TS packets we have just filled from the netlist */
#ifdef INPUT_LIFO_TS_NETLIST
/* We need to take a lock here while we're calculating index positions. */
vlc_mutex_lock( &p_input->netlist.lock );
//intf_DbgMsg("End of PES packet %p\n", p_pes);
i_meanwhile_released = i_base_index - p_input->netlist.i_ts_index;
if( i_meanwhile_released )
/* First read the 6 header bytes common to all PES packets:
use them to test the PES validity */
if( (p_pes->p_pes_header[0] || p_pes->p_pes_header[1] ||
(p_pes->p_pes_header[2] != 1)) ||
/* packet_start_code_prefix != 0x000001 */
((p_pes->i_pes_real_size) &&
(p_pes->i_pes_real_size != p_pes->i_pes_size)) )
/* PES_packet_length is set and != total received payload */
{
/* That's where it becomes funny :-). Since we didn't take locks for
efficiency reasons, other threads (including ourselves, with
input_DemuxPacket) might have released packets to the netlist.
So we have to copy these iovec where they should go.
BTW, that explains why the TS netlist is
(INPUT_MAX_TS +1) + (TS_READ_ONCE -1) large. */
i_currently_removed = i_current_index - i_base_index;
if( i_meanwhile_released < i_currently_removed )
{
/* Copy all iovecs in that case */
memcpy( &p_input->netlist.p_ts_free[p_input->netlist.i_ts_index]
+ i_currently_removed,
&p_input->netlist.p_ts_free[p_input->netlist.i_ts_index],
i_meanwhile_released * sizeof(struct iovec) );
}
else
{
/* We have fewer places than items, so we only move
i_currently_removed of them. */
memcpy( &p_input->netlist.p_ts_free[i_base_index],
&p_input->netlist.p_ts_free[p_input->netlist.i_ts_index],
i_currently_removed * sizeof(struct iovec) );
}
/* Update i_netlist_index with the information gathered above. */
p_input->netlist.i_ts_index += i_currently_removed;
/* Trash the packet and set p_pes to NULL to be sure the next PES
packet will have its b_data_lost flag set */
intf_DbgMsg("Corrupted PES packet (size doesn't match) : trashed\n");
input_NetlistFreePES( p_input, p_pes );
p_pes = NULL;
/* Stats XXX?? */
}
else
{
/* Nothing happened. */
p_input->netlist.i_ts_index = i_current_index;
}
vlc_mutex_unlock( &p_input->netlist.lock );
/* The PES packet is valid. Check its type to test if it may
carry additional informations in a header extension */
p_pes->i_stream_id = p_pes->p_pes_header[3];
#else /* FIFO netlist */
/* & is modulo ; that's where we make the loop. */
p_input->netlist.i_ts_start = i_current_index & INPUT_MAX_TS;
#endif
switch( p_pes->i_stream_id )
{
case 0xBE: /* Padding */
case 0xBC: /* Program stream map */
case 0xBF: /* Private stream 2 */
case 0xB0: /* ECM */
case 0xB1: /* EMM */
case 0xFF: /* Program stream directory */
case 0xF2: /* DSMCC stream */
case 0xF8: /* ITU-T H.222.1 type E stream */
/* The payload begins immediatly after the 6 bytes header, so
we have finished with the parsing */
i_pes_header_size = 6;
break;
#ifdef STATS
p_input->c_packets_read += i_current_index - i_base_index;
p_input->c_bytes += (i_current_index - i_base_index) * TS_PACKET_SIZE;
#endif
return( 0 );
}
default:
switch( p_pes->p_pes_header[8] & 0xc0 )
{
case 0x80: /* MPEG2: 10xx xxxx */
case 0x00: /* FIXME: This shouldn't be allowed !! */
/* The PES header contains at least 3 more bytes: parse them */
p_pes->b_data_alignment = p_pes->p_pes_header[6] & 0x04;
p_pes->b_has_pts = p_pes->p_pes_header[7] & 0x80;
i_pes_header_size = p_pes->p_pes_header[8] + 9;
/*****************************************************************************
* input_SortPacket: find out whether we need that packet
*****************************************************************************/
static __inline__ void input_SortPacket( input_thread_t *p_input,
ts_packet_t *p_ts_packet )
{
int i_current_pid;
int i_es_loop;
/* Now parse the optional header extensions (in the limit of
the 14 bytes */
if( p_pes->b_has_pts )
{
pcr_descriptor_t * p_pcr;
/* Verify that sync_byte, error_indicator and scrambling_control are
what we expected. */
if( !(p_ts_packet->buffer[0] == 0x47) || (p_ts_packet->buffer[1] & 0x80) ||
(p_ts_packet->buffer[3] & 0xc0) )
{
intf_DbgMsg("input debug: invalid TS header (%p)\n", p_ts_packet);
}
else
{
/* Get the PID of the packet. Note that ntohs is needed, for endianness
purposes (see man page). */
i_current_pid = U16_AT(&p_ts_packet->buffer[1]) & 0x1fff;
p_pcr = p_input->p_pcr;
//intf_DbgMsg("input debug: pid %d received (%p)\n",
// i_current_pid, p_ts_packet);
p_pes->i_pts =
( ((mtime_t)(p_pes->p_pes_header[9] & 0x0E) << 29) |
(((mtime_t)U16_AT(p_pes->p_pes_header + 10) << 14) - (1 << 14)) |
((mtime_t)U16_AT(p_pes->p_pes_header + 12) >> 1) ) * 300;
p_pes->i_pts /= 27;
/* Lock current ES state. */
vlc_mutex_lock( &p_input->es_lock );
if( p_pcr->i_synchro_state )
{
switch( p_pcr->i_synchro_state )
{
case SYNCHRO_NOT_STARTED:
p_pes->b_has_pts = 0;
break;
/* Verify that we actually want this PID. */
for( i_es_loop = 0; i_es_loop < INPUT_MAX_SELECTED_ES; i_es_loop++ )
{
if( p_input->pp_selected_es[i_es_loop] != NULL)
{
if( (*p_input->pp_selected_es[i_es_loop]).i_id
== i_current_pid )
{
/* Don't need the lock anymore, since the value pointed
out by p_input->pp_selected_es[i_es_loop] can only be
modified from inside the input_thread (by the PSI
decoder): interface thread is only allowed to modify
the pp_selected_es table */
vlc_mutex_unlock( &p_input->es_lock );
case SYNCHRO_START:
p_pes->i_pts += p_pcr->delta_pcr;
p_pcr->delta_absolute = mdate() - p_pes->i_pts + INPUT_PTS_DELAY;
p_pes->i_pts += p_pcr->delta_absolute;
p_pcr->i_synchro_state = 0;
break;
/* We're interested. Pass it to the demultiplexer. */
input_DemuxTS( p_input, p_ts_packet,
p_input->pp_selected_es[i_es_loop] );
return;
case SYNCHRO_REINIT: /* We skip a PES */
p_pes->b_has_pts = 0;
p_pcr->i_synchro_state = SYNCHRO_START;
break;
}
}
else
{
p_pes->i_pts += p_pcr->delta_pcr + p_pcr->delta_absolute;
}
}
}
else
{
/* pp_selected_es should not contain any hole. */
break;
}
}
vlc_mutex_unlock( &p_input->es_lock );
}
/* We weren't interested in receiving this packet. Give it back to the
netlist. */
//intf_DbgMsg("SortPacket: freeing unwanted TS %p (pid %d)\n", p_ts_packet,
// U16_AT(&p_ts_packet->buffer[1]) & 0x1fff);
input_NetlistFreeTS( p_input, p_ts_packet );
#ifdef STATS
p_input->c_packets_trashed++;
#endif
}
/*****************************************************************************
* input_DemuxTS: first step of demultiplexing: the TS header
*****************************************************************************
* Stream must also only contain PES and PSI, so PID must have been filtered
*****************************************************************************/
static __inline__ void input_DemuxTS( input_thread_t *p_input,
ts_packet_t *p_ts_packet,
es_descriptor_t *p_es_descriptor )
{
int i_dummy;
boolean_t b_adaption; /* Adaption field is present */
boolean_t b_payload; /* Packet carries payload */
boolean_t b_unit_start; /* A PSI or a PES start in the packet */
boolean_t b_trash = 0; /* Must the packet be trashed ? */
boolean_t b_lost = 0; /* Was there a packet lost ? */
ASSERT(p_input);
ASSERT(p_ts_packet);
ASSERT(p_es_descriptor);
#define p (p_ts_packet->buffer)
//intf_DbgMsg("input debug: TS-demultiplexing packet %p, pid %d, number %d\n",
// p_ts_packet, U16_AT(&p[1]) & 0x1fff, p[3] & 0x0f);
default: /* MPEG1 or some strange thing */
/* since this isn't supported yet, we certainly gonna crash */
intf_ErrMsg( "FIXME: unknown PES type %.2x\n",
p_pes->p_pes_header[8] );
i_pes_header_size = 6;
break;
#ifdef STATS
p_es_descriptor->c_packets++;
p_es_descriptor->c_bytes += TS_PACKET_SIZE;
#endif
}
break;
}
/* Extract flags values from TS common header. */
b_unit_start = (p[1] & 0x40);
b_adaption = (p[3] & 0x20);
b_payload = (p[3] & 0x10);
/* Now we've parsed the header, we just have to indicate in some
* specific TS packets where the PES payload begins (renumber
* i_payload_start), so that the decoders can find the beginning
* of their data right out of the box. */
p_ts = p_pes->p_first_ts;
i_ts_payload_size = p_ts->i_payload_end - p_ts->i_payload_start;
while( i_pes_header_size > i_ts_payload_size )
{
/* These packets are entirely filled by the PES header. */
i_pes_header_size -= i_ts_payload_size;
p_ts->i_payload_start = p_ts->i_payload_end;
/* Go to the next TS packet: here we won't have to test it is
* not NULL because we trash the PES packets when packet lost
* occurs */
p_ts = p_ts->p_next_ts;
i_ts_payload_size = p_ts->i_payload_end - p_ts->i_payload_start;
}
/* This last packet is partly header, partly payload. */
p_ts->i_payload_start += i_pes_header_size;
/* Extract adaption field informations if any */
if( !b_adaption )
{
/* We don't have any adaptation_field, so payload start immediately
after the 4 byte TS header */
p_ts_packet->i_payload_start = 4;
}
else
{
/* p[4] is adaptation_field_length minus one */
p_ts_packet->i_payload_start = 5 + p[4];
/* The adaption field can be limited to the adaptation_field_length byte,
so that there is nothing to do: skip this possibility */
if( p[4] )
/* Now we can eventually put the PES packet in the decoder's
* PES fifo */
switch( p_es_descriptor->i_type )
{
/* If the packet has both adaptation_field and payload, adaptation_field
cannot be more than 182 bytes long; if there is only an
adaptation_field, it must fill the next 183 bytes. */
if( b_payload ? (p[4] > 182) : (p[4] != 183) )
{
intf_DbgMsg("input debug: invalid TS adaptation field (%p)\n",
p_ts_packet);
#ifdef STATS
p_es_descriptor->c_invalid_packets++;
#endif
b_trash = 1;
}
case MPEG1_VIDEO_ES:
case MPEG2_VIDEO_ES:
p_fifo = &(((vpar_thread_t*)(p_es_descriptor->p_dec))->fifo);
break;
/* No we are sure that the byte containing flags is present: read it */
else
{
/* discontinuity_indicator */
if( p[5] & 0x80 )
{
intf_DbgMsg("discontinuity_indicator encountered by TS demux " \
"(position read: %d, saved: %d)\n", p[5] & 0x80,
p_es_descriptor->i_continuity_counter);
case MPEG1_AUDIO_ES:
case MPEG2_AUDIO_ES:
p_fifo = &(((adec_thread_t*)(p_es_descriptor->p_dec))->fifo);
break;
/* If the PID carries the PCR, there will be a system time-base
discontinuity. We let the PCR decoder handle that. */
p_es_descriptor->b_discontinuity = 1;
case AC3_AUDIO_ES:
p_fifo = &(((ac3dec_thread_t *)(p_es_descriptor->p_dec))->fifo);
break;
/* There also may be a continuity_counter discontinuity:
resynchronise our counter with the one of the stream */
p_es_descriptor->i_continuity_counter = (p[3] & 0x0f) - 1;
}
case LPCM_AUDIO_ES:
p_fifo = &(((lpcmdec_thread_t *)(p_es_descriptor->p_dec))->fifo);
break;
/* random_access_indicator */
p_es_descriptor->b_random |= p[5] & 0x40;
case DVD_SPU_ES:
/* we skip the first byte at the beginning of the
* subpicture payload, it only contains the SPU ID. */
p_ts->i_payload_start++;
p_fifo = &(((spudec_thread_t *)(p_es_descriptor->p_dec))->fifo);
break;
/* If this is a PCR_PID, and this TS packet contains a PCR,
we pass it along to the PCR decoder. */
if( (p_es_descriptor->b_pcr) && (p[5] & 0x10) )
{
/* There should be a PCR field in the packet, check if the
adaption field is long enough to carry it */
if( p[4] >= 7 )
{
/* Call the PCR decoder */
input_PcrDecode( p_input, p_es_descriptor, &p[6] );
}
}
}
default:
/* This should never happen */
intf_DbgMsg("Unknown stream type (%d, %d): PES trashed\n",
p_es_descriptor->i_id, p_es_descriptor->i_type);
p_fifo = NULL;
break;
}
}
/* Check the continuity of the stream. */
i_dummy = ((p[3] & 0x0f) - p_es_descriptor->i_continuity_counter) & 0x0f;
if( i_dummy == 1 )
{
/* Everything is ok, just increase our counter */
p_es_descriptor->i_continuity_counter++;
}
else
{
if( !b_payload && i_dummy == 0 )
{
/* This is a packet without payload, this is allowed by the draft
As there is nothing interesting in this packet (except PCR that
have already been handled), we can trash the packet. */
intf_DbgMsg("Packet without payload received by TS demux\n");
b_trash = 1;
}
else if( i_dummy <= 0 )
{
/* Duplicate packet: mark it as being to be trashed. */
intf_DbgMsg("Duplicate packet received by TS demux\n");
b_trash = 1;
}
else if( p_es_descriptor->i_continuity_counter == 0xFF )
{
/* This means that the packet is the first one we receive for this
ES since the continuity counter ranges between 0 and 0x0F
excepts when it has been initialized by the input: Init the
counter to the correct value. */
intf_DbgMsg("First packet for PID %d received by TS demux\n",
p_es_descriptor->i_id);
p_es_descriptor->i_continuity_counter = (p[3] & 0x0f);
}
else
if( p_fifo != NULL )
{
/* This can indicate that we missed a packet or that the
continuity_counter wrapped and we received a dup packet: as we
don't know, do as if we missed a packet to be sure to recover
from this situation */
intf_DbgMsg("Packet lost by TS demux: current %d, packet %d\n",
p_es_descriptor->i_continuity_counter & 0x0f,
p[3] & 0x0f);
b_lost = 1;
p_es_descriptor->i_continuity_counter = p[3] & 0x0f;
}
}
/* Trash the packet if it has no payload or if it is bad */
if( b_trash )
{
input_NetlistFreeTS( p_input, p_ts_packet );
vlc_mutex_lock( &p_fifo->data_lock );
if( DECODER_FIFO_ISFULL( *p_fifo ) )
{
/* The FIFO is full !!! This should not happen. */
#ifdef STATS
p_input->c_packets_trashed++;
p_input->c_packets_trashed += p_pes->i_ts_packets;
p_es_descriptor->c_invalid_packets += p_pes->i_ts_packets;
#endif
}
else
{
if( p_es_descriptor->b_psi )
{
/* The payload contains PSI tables */
input_DemuxPSI( p_input, p_ts_packet, p_es_descriptor,
b_unit_start, b_lost );
input_NetlistFreePES( p_input, p_pes );
intf_DbgMsg("PES trashed - fifo full ! (%d, %d)\n",
p_es_descriptor->i_id, p_es_descriptor->i_type);
}
else
{
//intf_DbgMsg("Putting %p into fifo %p/%d\n",
// p_pes, p_fifo, p_fifo->i_end);
p_fifo->buffer[p_fifo->i_end] = p_pes;
DECODER_FIFO_INCEND( *p_fifo );
/* Warn the decoder that it's got work to do. */
vlc_cond_signal( &p_fifo->data_wait );
}
vlc_mutex_unlock( &p_fifo->data_lock );
}
else
{
/* The payload carries a PES stream */
input_DemuxPES( p_input, p_ts_packet, p_es_descriptor,
b_unit_start, b_lost );
intf_DbgMsg("No fifo to receive PES %p: trash\n", p_pes);
#ifdef STATS
p_input->c_packets_trashed += p_pes->i_ts_packets;
p_es_descriptor->c_invalid_packets += p_pes->i_ts_packets;
#endif
input_NetlistFreePES( p_input, p_pes );
}
}
#undef p
#undef p_pes
}
/*****************************************************************************
* input_DemuxPES:
*****************************************************************************
......@@ -928,8 +779,9 @@ static __inline__ void input_DemuxPES( input_thread_t *p_input,
i_dummy = 0;
do
{
memcpy(p_pes->p_pes_header_save + i_dummy,
&p_ts->buffer[p_ts->i_payload_start], i_ts_payload_size);
memcpy( p_pes->p_pes_header_save + i_dummy,
&p_ts->buffer[p_ts->i_payload_start],
i_ts_payload_size);
i_dummy += i_ts_payload_size;
p_ts = p_ts->p_next_ts;
......@@ -1075,377 +927,523 @@ static __inline__ void input_DemuxPES( input_thread_t *p_input,
#undef p_pes
}
/*****************************************************************************
* input_ParsePES
* input_DemuxTS: first step of demultiplexing: the TS header
*****************************************************************************
* Parse a finished PES packet and analyze its header.
* Stream must also only contain PES and PSI, so PID must have been filtered
*****************************************************************************/
static __inline__ void input_ParsePES( input_thread_t *p_input,
es_descriptor_t *p_es_descriptor )
static __inline__ void input_DemuxTS( input_thread_t *p_input,
ts_packet_t *p_ts_packet,
es_descriptor_t *p_es_descriptor )
{
decoder_fifo_t * p_fifo;
u8 i_pes_header_size;
ts_packet_t * p_ts;
int i_ts_payload_size;
int i_dummy;
boolean_t b_adaption; /* Adaption field is present */
boolean_t b_payload; /* Packet carries payload */
boolean_t b_unit_start; /* A PSI or a PES start in the packet */
boolean_t b_trash = 0; /* Must the packet be trashed ? */
boolean_t b_lost = 0; /* Was there a packet lost ? */
ASSERT(p_input);
ASSERT(p_ts_packet);
ASSERT(p_es_descriptor);
#define p (p_ts_packet->buffer)
#define p_pes (p_es_descriptor->p_pes_packet)
//intf_DbgMsg("input debug: TS-demultiplexing packet %p, pid %d, number %d\n",
// p_ts_packet, U16_AT(&p[1]) & 0x1fff, p[3] & 0x0f);
//intf_DbgMsg("End of PES packet %p\n", p_pes);
#ifdef STATS
p_es_descriptor->c_packets++;
p_es_descriptor->c_bytes += TS_PACKET_SIZE;
#endif
/* First read the 6 header bytes common to all PES packets:
use them to test the PES validity */
if( (p_pes->p_pes_header[0] || p_pes->p_pes_header[1] ||
(p_pes->p_pes_header[2] != 1)) ||
/* packet_start_code_prefix != 0x000001 */
((p_pes->i_pes_real_size) &&
(p_pes->i_pes_real_size != p_pes->i_pes_size)) )
/* PES_packet_length is set and != total received payload */
/* Extract flags values from TS common header. */
b_unit_start = (p[1] & 0x40);
b_adaption = (p[3] & 0x20);
b_payload = (p[3] & 0x10);
/* Extract adaption field informations if any */
if( !b_adaption )
{
/* Trash the packet and set p_pes to NULL to be sure the next PES
packet will have its b_data_lost flag set */
intf_DbgMsg("Corrupted PES packet (size doesn't match) : trashed\n");
input_NetlistFreePES( p_input, p_pes );
p_pes = NULL;
/* Stats XXX?? */
/* We don't have any adaptation_field, so payload start immediately
after the 4 byte TS header */
p_ts_packet->i_payload_start = 4;
}
else
{
/* The PES packet is valid. Check its type to test if it may
carry additional informations in a header extension */
p_pes->i_stream_id = p_pes->p_pes_header[3];
/* p[4] is adaptation_field_length minus one */
p_ts_packet->i_payload_start = 5 + p[4];
switch( p_pes->i_stream_id )
/* The adaption field can be limited to the adaptation_field_length byte,
so that there is nothing to do: skip this possibility */
if( p[4] )
{
case 0xBE: /* Padding */
case 0xBC: /* Program stream map */
case 0xBF: /* Private stream 2 */
case 0xB0: /* ECM */
case 0xB1: /* EMM */
case 0xFF: /* Program stream directory */
case 0xF2: /* DSMCC stream */
case 0xF8: /* ITU-T H.222.1 type E stream */
/* The payload begins immediatly after the 6 bytes header, so
we have finished with the parsing */
i_pes_header_size = 6;
break;
default:
switch( p_pes->p_pes_header[8] & 0xc0 )
/* If the packet has both adaptation_field and payload, adaptation_field
cannot be more than 182 bytes long; if there is only an
adaptation_field, it must fill the next 183 bytes. */
if( b_payload ? (p[4] > 182) : (p[4] != 183) )
{
case 0x80: /* MPEG2: 10xx xxxx */
case 0x00: /* FIXME: This shouldn't be allowed !! */
/* The PES header contains at least 3 more bytes: parse them */
p_pes->b_data_alignment = p_pes->p_pes_header[6] & 0x04;
p_pes->b_has_pts = p_pes->p_pes_header[7] & 0x80;
i_pes_header_size = p_pes->p_pes_header[8] + 9;
intf_DbgMsg("input debug: invalid TS adaptation field (%p)\n",
p_ts_packet);
#ifdef STATS
p_es_descriptor->c_invalid_packets++;
#endif
b_trash = 1;
}
/* Now parse the optional header extensions (in the limit of
the 14 bytes */
if( p_pes->b_has_pts )
/* No we are sure that the byte containing flags is present: read it */
else
{
/* discontinuity_indicator */
if( p[5] & 0x80 )
{
pcr_descriptor_t * p_pcr;
p_pcr = p_input->p_pcr;
intf_DbgMsg("discontinuity_indicator encountered by TS demux " \
"(position read: %d, saved: %d)\n", p[5] & 0x80,
p_es_descriptor->i_continuity_counter);
p_pes->i_pts =
( ((mtime_t)(p_pes->p_pes_header[9] & 0x0E) << 29) |
(((mtime_t)U16_AT(p_pes->p_pes_header + 10) << 14) - (1 << 14)) |
((mtime_t)U16_AT(p_pes->p_pes_header + 12) >> 1) ) * 300;
p_pes->i_pts /= 27;
/* If the PID carries the PCR, there will be a system time-base
discontinuity. We let the PCR decoder handle that. */
p_es_descriptor->b_discontinuity = 1;
if( p_pcr->i_synchro_state )
{
switch( p_pcr->i_synchro_state )
{
case SYNCHRO_NOT_STARTED:
p_pes->b_has_pts = 0;
break;
/* There also may be a continuity_counter discontinuity:
resynchronise our counter with the one of the stream */
p_es_descriptor->i_continuity_counter = (p[3] & 0x0f) - 1;
}
case SYNCHRO_START:
p_pes->i_pts += p_pcr->delta_pcr;
p_pcr->delta_absolute = mdate() - p_pes->i_pts + INPUT_PTS_DELAY;
p_pes->i_pts += p_pcr->delta_absolute;
p_pcr->i_synchro_state = 0;
break;
/* random_access_indicator */
p_es_descriptor->b_random |= p[5] & 0x40;
case SYNCHRO_REINIT: /* We skip a PES */
p_pes->b_has_pts = 0;
p_pcr->i_synchro_state = SYNCHRO_START;
break;
}
}
else
/* If this is a PCR_PID, and this TS packet contains a PCR,
we pass it along to the PCR decoder. */
if( (p_es_descriptor->b_pcr) && (p[5] & 0x10) )
{
/* There should be a PCR field in the packet, check if the
adaption field is long enough to carry it */
if( p[4] >= 7 )
{
p_pes->i_pts += p_pcr->delta_pcr + p_pcr->delta_absolute;
/* Call the PCR decoder */
input_PcrDecode( p_input, p_es_descriptor, &p[6] );
}
}
break;
default: /* MPEG1 or some strange thing */
/* since this isn't supported yet, we certainly gonna crash */
intf_ErrMsg( "FIXME: unknown PES type %.2x\n",
p_pes->p_pes_header[8] );
i_pes_header_size = 6;
break;
}
break;
}
}
/* Check the continuity of the stream. */
i_dummy = ((p[3] & 0x0f) - p_es_descriptor->i_continuity_counter) & 0x0f;
if( i_dummy == 1 )
{
/* Everything is ok, just increase our counter */
p_es_descriptor->i_continuity_counter++;
}
else
{
if( !b_payload && i_dummy == 0 )
{
/* This is a packet without payload, this is allowed by the draft
As there is nothing interesting in this packet (except PCR that
have already been handled), we can trash the packet. */
intf_DbgMsg("Packet without payload received by TS demux\n");
b_trash = 1;
}
else if( i_dummy <= 0 )
{
/* Duplicate packet: mark it as being to be trashed. */
intf_DbgMsg("Duplicate packet received by TS demux\n");
b_trash = 1;
}
else if( p_es_descriptor->i_continuity_counter == 0xFF )
{
/* This means that the packet is the first one we receive for this
ES since the continuity counter ranges between 0 and 0x0F
excepts when it has been initialized by the input: Init the
counter to the correct value. */
intf_DbgMsg("First packet for PID %d received by TS demux\n",
p_es_descriptor->i_id);
p_es_descriptor->i_continuity_counter = (p[3] & 0x0f);
}
else
{
/* This can indicate that we missed a packet or that the
continuity_counter wrapped and we received a dup packet: as we
don't know, do as if we missed a packet to be sure to recover
from this situation */
intf_DbgMsg("Packet lost by TS demux: current %d, packet %d\n",
p_es_descriptor->i_continuity_counter & 0x0f,
p[3] & 0x0f);
b_lost = 1;
p_es_descriptor->i_continuity_counter = p[3] & 0x0f;
}
}
/* Now we've parsed the header, we just have to indicate in some
* specific TS packets where the PES payload begins (renumber
* i_payload_start), so that the decoders can find the beginning
* of their data right out of the box. */
p_ts = p_pes->p_first_ts;
i_ts_payload_size = p_ts->i_payload_end - p_ts->i_payload_start;
while( i_pes_header_size > i_ts_payload_size )
/* Trash the packet if it has no payload or if it is bad */
if( b_trash )
{
input_NetlistFreeTS( p_input, p_ts_packet );
#ifdef STATS
p_input->c_packets_trashed++;
#endif
}
else
{
if( p_es_descriptor->b_psi )
{
/* These packets are entirely filled by the PES header. */
i_pes_header_size -= i_ts_payload_size;
p_ts->i_payload_start = p_ts->i_payload_end;
/* Go to the next TS packet: here we won't have to test it is
* not NULL because we trash the PES packets when packet lost
* occurs */
p_ts = p_ts->p_next_ts;
i_ts_payload_size = p_ts->i_payload_end - p_ts->i_payload_start;
/* The payload contains PSI tables */
input_DemuxPSI( p_input, p_ts_packet, p_es_descriptor,
b_unit_start, b_lost );
}
/* This last packet is partly header, partly payload. */
p_ts->i_payload_start += i_pes_header_size;
/* Now we can eventually put the PES packet in the decoder's
* PES fifo */
switch( p_es_descriptor->i_type )
else
{
case MPEG1_VIDEO_ES:
case MPEG2_VIDEO_ES:
p_fifo = &(((vpar_thread_t*)(p_es_descriptor->p_dec))->fifo);
break;
/* The payload carries a PES stream */
input_DemuxPES( p_input, p_ts_packet, p_es_descriptor,
b_unit_start, b_lost );
}
}
case MPEG1_AUDIO_ES:
case MPEG2_AUDIO_ES:
p_fifo = &(((adec_thread_t*)(p_es_descriptor->p_dec))->fifo);
break;
#undef p
}
case AC3_AUDIO_ES:
p_fifo = &(((ac3dec_thread_t *)(p_es_descriptor->p_dec))->fifo);
break;
/*****************************************************************************
* input_SortPacket: find out whether we need that packet
*****************************************************************************/
static __inline__ void input_SortPacket( input_thread_t *p_input,
ts_packet_t *p_ts_packet )
{
int i_current_pid;
int i_es_loop;
case LPCM_AUDIO_ES:
p_fifo = &(((lpcmdec_thread_t *)(p_es_descriptor->p_dec))->fifo);
break;
/* Verify that sync_byte, error_indicator and scrambling_control are
what we expected. */
if( !(p_ts_packet->buffer[0] == 0x47) || (p_ts_packet->buffer[1] & 0x80) ||
(p_ts_packet->buffer[3] & 0xc0) )
{
intf_DbgMsg("input debug: invalid TS header (%p)\n", p_ts_packet);
}
else
{
/* Get the PID of the packet. Note that ntohs is needed, for endianness
purposes (see man page). */
i_current_pid = U16_AT(&p_ts_packet->buffer[1]) & 0x1fff;
case DVD_SPU_ES:
/* we skip the first byte at the beginning of the
* subpicture payload, it only contains the SPU ID. */
p_ts->i_payload_start++;
p_fifo = &(((spudec_thread_t *)(p_es_descriptor->p_dec))->fifo);
break;
//intf_DbgMsg("input debug: pid %d received (%p)\n",
// i_current_pid, p_ts_packet);
default:
/* This should never happen */
intf_DbgMsg("Unknown stream type (%d, %d): PES trashed\n",
p_es_descriptor->i_id, p_es_descriptor->i_type);
p_fifo = NULL;
break;
}
/* Lock current ES state. */
vlc_mutex_lock( &p_input->es_lock );
if( p_fifo != NULL )
/* Verify that we actually want this PID. */
for( i_es_loop = 0; i_es_loop < INPUT_MAX_SELECTED_ES; i_es_loop++ )
{
vlc_mutex_lock( &p_fifo->data_lock );
if( DECODER_FIFO_ISFULL( *p_fifo ) )
if( p_input->pp_selected_es[i_es_loop] != NULL)
{
/* The FIFO is full !!! This should not happen. */
#ifdef STATS
p_input->c_packets_trashed += p_pes->i_ts_packets;
p_es_descriptor->c_invalid_packets += p_pes->i_ts_packets;
#endif
input_NetlistFreePES( p_input, p_pes );
intf_DbgMsg("PES trashed - fifo full ! (%d, %d)\n",
p_es_descriptor->i_id, p_es_descriptor->i_type);
if( (*p_input->pp_selected_es[i_es_loop]).i_id
== i_current_pid )
{
/* Don't need the lock anymore, since the value pointed
out by p_input->pp_selected_es[i_es_loop] can only be
modified from inside the input_thread (by the PSI
decoder): interface thread is only allowed to modify
the pp_selected_es table */
vlc_mutex_unlock( &p_input->es_lock );
/* We're interested. Pass it to the demultiplexer. */
input_DemuxTS( p_input, p_ts_packet,
p_input->pp_selected_es[i_es_loop] );
return;
}
}
else
else
{
//intf_DbgMsg("Putting %p into fifo %p/%d\n",
// p_pes, p_fifo, p_fifo->i_end);
p_fifo->buffer[p_fifo->i_end] = p_pes;
DECODER_FIFO_INCEND( *p_fifo );
/* Warn the decoder that it's got work to do. */
vlc_cond_signal( &p_fifo->data_wait );
/* pp_selected_es should not contain any hole. */
break;
}
vlc_mutex_unlock( &p_fifo->data_lock );
}
else
{
intf_DbgMsg("No fifo to receive PES %p: trash\n", p_pes);
vlc_mutex_unlock( &p_input->es_lock );
}
/* We weren't interested in receiving this packet. Give it back to the
netlist. */
//intf_DbgMsg("SortPacket: freeing unwanted TS %p (pid %d)\n", p_ts_packet,
// U16_AT(&p_ts_packet->buffer[1]) & 0x1fff);
input_NetlistFreeTS( p_input, p_ts_packet );
#ifdef STATS
p_input->c_packets_trashed += p_pes->i_ts_packets;
p_es_descriptor->c_invalid_packets += p_pes->i_ts_packets;
p_input->c_packets_trashed++;
#endif
input_NetlistFreePES( p_input, p_pes );
}
}
#undef p_pes
}
/*****************************************************************************
* input_DemuxPSI:
*****************************************************************************
* Notice that current ES state has been locked by input_SortPacket.
* (No more true, changed by benny - FIXME: See if it's ok, and definitely
* change the code ?? )
* input_ReadPacket: reads a packet from the network or the file
*****************************************************************************/
static __inline__ void input_DemuxPSI( input_thread_t *p_input,
ts_packet_t *p_ts_packet,
es_descriptor_t *p_es_descriptor,
boolean_t b_unit_start, boolean_t b_packet_lost )
static __inline__ int input_ReadPacket( input_thread_t *p_input )
{
int i_data_offset; /* Offset of the interesting data in the TS packet */
u16 i_data_length; /* Length of those data */
//boolean_t b_first_section; /* another section in the TS packet ? */
int i_base_index; /* index of the first free iovec */
int i_current_index;
int i_packet_size;
#ifdef INPUT_LIFO_TS_NETLIST
int i_meanwhile_released;
int i_currently_removed;
#endif
ts_packet_t * p_ts_packet;
ASSERT(p_input);
ASSERT(p_ts_packet);
ASSERT(p_es_descriptor);
/* In this function, we only care about the TS netlist. PES netlist
* is for the demultiplexer. */
#ifdef INPUT_LIFO_TS_NETLIST
i_base_index = p_input->netlist.i_ts_index;
#define p_psi (p_es_descriptor->p_psi_section)
/* Verify that we still have packets in the TS netlist */
if( (INPUT_MAX_TS + INPUT_TS_READ_ONCE - 1 - p_input->netlist.i_ts_index) <= INPUT_TS_READ_ONCE )
{
intf_ErrMsg("input error: TS netlist is empty !\n");
return( -1 );
}
//intf_DbgMsg( "input debug: PSI demultiplexing %p (%p)\n", p_ts_packet, p_input);
#else /* FIFO netlist */
i_base_index = p_input->netlist.i_ts_start;
if( p_input->netlist.i_ts_start + INPUT_TS_READ_ONCE -1 > INPUT_MAX_TS )
{
/* The netlist is splitted in 2 parts. We must gather them to consolidate
the FIFO (we make the loop easily in having the same iovec at the far
end and in the beginning of netlist_free).
That's why the netlist is (INPUT_MAX_TS +1) + (INPUT_TS_READ_ONCE -1)
large. */
memcpy( p_input->netlist.p_ts_free + INPUT_MAX_TS + 1,
p_input->netlist.p_ts_free,
(p_input->netlist.i_ts_start + INPUT_TS_READ_ONCE - 1 - INPUT_MAX_TS)
* sizeof(struct iovec) );
}
/* Verify that we still have packets in the TS netlist */
if( ((p_input->netlist.i_ts_end -1 - p_input->netlist.i_ts_start) & INPUT_MAX_TS) <= INPUT_TS_READ_ONCE )
{
intf_ErrMsg("input error: TS netlist is empty !\n");
return( -1 );
}
#endif /* FIFO netlist */
/* Scatter read the buffer. */
i_packet_size = (*p_input->p_Read)( p_input,
&p_input->netlist.p_ts_free[i_base_index],
INPUT_TS_READ_ONCE );
if( i_packet_size == (-1) )
{
#if 0
intf_DbgMsg("Read packet %d %p %d %d\n", i_base_index,
&p_input->netlist.p_ts_free[i_base_index],
p_input->netlist.i_ts_start,
p_input->netlist.i_ts_end);
#endif
intf_ErrMsg("input error: readv() failed (%s)\n", strerror(errno));
return( -1 );
}
if( i_packet_size == 0 )
{
/* No packet has been received, so stop here. */
return( 0 );
}
/* Demultiplex the TS packets (1..INPUT_TS_READ_ONCE) received. */
for( i_current_index = i_base_index;
(i_packet_size -= TS_PACKET_SIZE) >= 0;
i_current_index++ )
{
/* BTW, something REALLY bad could happen if we receive packets with
a wrong size. */
p_ts_packet = (ts_packet_t*)(p_input->netlist.p_ts_free[i_current_index].iov_base);
/* Don't cry :-), we are allowed to do that cast, because initially,
our buffer was malloc'ed with sizeof(ts_packet_t) */
/* Find out if we need this packet and demultiplex. */
input_SortPacket( p_input /* for current PIDs and netlist */,
p_ts_packet);
}
if( i_packet_size > 0 )
{
intf_ErrMsg("input error: wrong size\n");
return( -1 );
}
//intf_DbgMsg( "Packet: %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x (unit start: %d)\n", p_ts_packet->buffer[p_ts_packet->i_payload_start], p_ts_packet->buffer[p_ts_packet->i_payload_start+1], p_ts_packet->buffer[p_ts_packet->i_payload_start+2], p_ts_packet->buffer[p_ts_packet->i_payload_start+3], p_ts_packet->buffer[p_ts_packet->i_payload_start+4], p_ts_packet->buffer[p_ts_packet->i_payload_start+5], p_ts_packet->buffer[p_ts_packet->i_payload_start+6], p_ts_packet->buffer[p_ts_packet->i_payload_start+7], p_ts_packet->buffer[p_ts_packet->i_payload_start+8], p_ts_packet->buffer[p_ts_packet->i_payload_start+9], p_ts_packet->buffer[p_ts_packet->i_payload_start+10], p_ts_packet->buffer[p_ts_packet->i_payload_start+11], p_ts_packet->buffer[p_ts_packet->i_payload_start+12], p_ts_packet->buffer[p_ts_packet->i_payload_start+13], p_ts_packet->buffer[p_ts_packet->i_payload_start+14], p_ts_packet->buffer[p_ts_packet->i_payload_start+15], p_ts_packet->buffer[p_ts_packet->i_payload_start+16], p_ts_packet->buffer[p_ts_packet->i_payload_start+17], p_ts_packet->buffer[p_ts_packet->i_payload_start+18], p_ts_packet->buffer[p_ts_packet->i_payload_start+19], p_ts_packet->buffer[p_ts_packet->i_payload_start+20], b_unit_start);
/* Remove the TS packets we have just filled from the netlist */
#ifdef INPUT_LIFO_TS_NETLIST
/* We need to take a lock here while we're calculating index positions. */
vlc_mutex_lock( &p_input->netlist.lock );
i_meanwhile_released = i_base_index - p_input->netlist.i_ts_index;
if( i_meanwhile_released )
{
/* That's where it becomes funny :-). Since we didn't take locks for
efficiency reasons, other threads (including ourselves, with
input_DemuxPacket) might have released packets to the netlist.
So we have to copy these iovec where they should go.
/* Try to find the beginning of the payload in the packet to initialise
* the do-while loop that follows -> Compute the i_data_offset variable:
* by default, the value is set so that we won't enter in the while loop.
* It will be set to a correct value if the data are not corrupted */
i_data_offset = TS_PACKET_SIZE;
BTW, that explains why the TS netlist is
(INPUT_MAX_TS +1) + (TS_READ_ONCE -1) large. */
/* Has the reassembly of a section already begun in a previous packet ? */
if( p_psi->b_running_section )
{
/* Was data lost since the last TS packet ? */
if( b_packet_lost )
i_currently_removed = i_current_index - i_base_index;
if( i_meanwhile_released < i_currently_removed )
{
/* Discard the packet and wait for the begining of a new one
* to resynch */
p_psi->b_running_section = 0;
p_psi->i_current_position = 0;
intf_DbgMsg( "PSI section(s) discarded due to packet loss\n" );
/* Copy all iovecs in that case */
memcpy( &p_input->netlist.p_ts_free[p_input->netlist.i_ts_index]
+ i_currently_removed,
&p_input->netlist.p_ts_free[p_input->netlist.i_ts_index],
i_meanwhile_released * sizeof(struct iovec) );
}
else
{
/* The data that complete a previously began section are always at
* the beginning of the TS payload... */
i_data_offset = p_ts_packet->i_payload_start;
/* ...Unless there is a pointer field, that we have to bypass */
if( b_unit_start )
i_data_offset++;
//intf_DbgMsg( "New part of the section received at offset %d\n", i_data_offset );
/* We have fewer places than items, so we only move
i_currently_removed of them. */
memcpy( &p_input->netlist.p_ts_free[i_base_index],
&p_input->netlist.p_ts_free[p_input->netlist.i_ts_index],
i_currently_removed * sizeof(struct iovec) );
}
/* Update i_netlist_index with the information gathered above. */
p_input->netlist.i_ts_index += i_currently_removed;
}
/* We are looking for the beginning of a new section */
else
{
if( b_unit_start )
{
/* Get the offset at which the data for that section can be found
* The offset is stored in the pointer_field since we are
* interested in the first section of the TS packet. Note that
* the +1 is to bypass the pointer field */
i_data_offset = p_ts_packet->i_payload_start +
p_ts_packet->buffer[p_ts_packet->i_payload_start] + 1;
//intf_DbgMsg( "New section beginning at offset %d in TS packet\n", i_data_offset );
}
else
{
/* This may either mean that the TS is bad or that the packet
* contains the end of a section that had been discarded in a
* previous loop: trash the TS packet since we cannot do
* anything with those data: */
p_psi->b_running_section = 0;
p_psi->i_current_position = 0;
intf_DbgMsg( "PSI packet discarded due to lack of synchronisation\n" );
}
/* Nothing happened. */
p_input->netlist.i_ts_index = i_current_index;
}
/* The section we will deal with during the first iteration of the
* following loop is the first one contained in the TS packet */
// b_first_section = 1;
vlc_mutex_unlock( &p_input->netlist.lock );
/* Reassemble the pieces of sections contained in the TS packet and
* decode the sections that could have been completed.
* Stop when we reach the end of the packet or stuffing bytes */
while( i_data_offset < TS_PACKET_SIZE && p_ts_packet->buffer[i_data_offset] != 0xFF )
#else /* FIFO netlist */
/* & is modulo ; that's where we make the loop. */
p_input->netlist.i_ts_start = i_current_index & INPUT_MAX_TS;
#endif
#ifdef STATS
p_input->c_packets_read += i_current_index - i_base_index;
p_input->c_bytes += (i_current_index - i_base_index) * TS_PACKET_SIZE;
#endif
return( 0 );
}
/*****************************************************************************
* RunThread: main thread loop
*****************************************************************************
* Thread in charge of processing the network packets and demultiplexing.
*****************************************************************************/
static void RunThread( input_thread_t *p_input )
{
/*
* Initialize thread and free configuration
*/
p_input->b_error = InitThread( p_input );
if( p_input->b_error )
{
/* If the current section is a new one, reinit the data fields of
* the p_psi struct to start its decoding */
if( !p_psi->b_running_section )
{
/* Read the length of the new section */
p_psi->i_length = (U16_AT(&p_ts_packet->buffer[i_data_offset+1]) & 0xFFF) + 3;
//intf_DbgMsg( "Section length %d\n", p_psi->i_length );
if( p_psi->i_length > PSI_SECTION_SIZE )
{
/* The TS packet is corrupted, stop here to avoid possible
* a seg fault */
intf_DbgMsg( "PSI Section size is too big, aborting its reception\n" );
break;
}
free( p_input ); /* destroy descriptor */
return;
}
/* Init the reassembly of that section */
p_psi->b_running_section = 1;
p_psi->i_current_position = 0;
/*
* Main loop
*/
intf_DbgMsg("\n");
while( !p_input->b_die && !p_input->b_error )
{
/* Scatter read the UDP packet from the network or the file. */
if( (input_ReadPacket( p_input )) == (-1) )
{
/* FIXME??: Normally, a thread can't kill itself, but we don't have
* any method in case of an error condition ... */
p_input->b_error = 1;
}
/* Compute the length of data related to the section in this TS packet */
if( p_psi->i_length - p_psi->i_current_position > TS_PACKET_SIZE - i_data_offset)
i_data_length = TS_PACKET_SIZE - i_data_offset;
else
i_data_length = p_psi->i_length - p_psi->i_current_position;
#ifdef STATS
p_input->c_loops++;
#endif
}
/* Copy those data in the section buffer */
memcpy( &p_psi->buffer[p_psi->i_current_position], &p_ts_packet->buffer[i_data_offset],
i_data_length );
/*
* Error loop
*/
if( p_input->b_error )
{
ErrorThread( p_input );
}
/* Interesting data are now after the ones we copied, since no gap is
* allowed between 2 sections in a TS packets */
i_data_offset += i_data_length;
/* End of thread */
EndThread( p_input );
intf_DbgMsg("thread end\n");
}
/* Decode the packet if it is now complete */
if (p_psi->i_length == p_psi->i_current_position + i_data_length)
{
/* Packet is complete, decode it */
//intf_DbgMsg( "SECTION COMPLETE: starting decoding of its data\n" );
input_PsiDecode( p_input, p_psi );
/* Prepare the buffer to receive a new section */
p_psi->i_current_position = 0;
p_psi->b_running_section = 0;
/*****************************************************************************
* ErrorThread: RunThread() error loop
*****************************************************************************
* This function is called when an error occured during thread main's loop.
*****************************************************************************/
static void ErrorThread( input_thread_t *p_input )
{
/* Wait until a `die' order */
intf_DbgMsg("\n");
while( !p_input->b_die )
{
/* Sleep a while */
msleep( VOUT_IDLE_SLEEP );
}
}
/* The new section won't be the first anymore */
//b_first_section = 0;
}
else
/*****************************************************************************
* EndThread: end the input thread
*****************************************************************************/
static void EndThread( input_thread_t * p_input )
{
int * pi_status; /* threas status */
int i_es_loop; /* es index */
/* Store status */
intf_DbgMsg("\n");
pi_status = p_input->pi_status;
*pi_status = THREAD_END;
/* Close input method */
p_input->p_Close( p_input );
/* Destroy all decoder threads */
for( i_es_loop = 0;
(i_es_loop < INPUT_MAX_ES) && (p_input->pp_selected_es[i_es_loop] != NULL) ;
i_es_loop++ )
{
switch( p_input->pp_selected_es[i_es_loop]->i_type )
{
/* Prepare the buffer to receive the next part of the section */
p_psi->i_current_position += i_data_length;
//intf_DbgMsg( "Section not complete, waiting for the end\n" );
case MPEG1_VIDEO_ES:
case MPEG2_VIDEO_ES:
vpar_DestroyThread( (vpar_thread_t*)(p_input->pp_selected_es[i_es_loop]->p_dec) /*, NULL */ );
break;
case MPEG1_AUDIO_ES:
case MPEG2_AUDIO_ES:
adec_DestroyThread( (adec_thread_t*)(p_input->pp_selected_es[i_es_loop]->p_dec) );
break;
case AC3_AUDIO_ES:
ac3dec_DestroyThread( (ac3dec_thread_t *)(p_input->pp_selected_es[i_es_loop]->p_dec) );
break;
case LPCM_AUDIO_ES:
lpcmdec_DestroyThread((lpcmdec_thread_t *)(p_input->pp_selected_es[i_es_loop]->p_dec) );
break;
case DVD_SPU_ES:
spudec_DestroyThread( (spudec_thread_t *)(p_input->pp_selected_es[i_es_loop]->p_dec) );
break;
case 0:
/* Special streams for the PSI decoder, PID 0 and 1 */
break;
#ifdef DEBUG
default:
intf_DbgMsg("error: unknown decoder type %d\n", p_input->pp_selected_es[i_es_loop]->i_type );
break;
#endif
}
//intf_DbgMsg( "Must loop ? Next data offset: %d, stuffing: %d\n",
// i_data_offset, p_ts_packet->buffer[i_data_offset] );
}
/* Relase the TS packet, we don't need it anymore */
input_NetlistFreeTS( p_input, p_ts_packet );
input_NetlistEnd( p_input ); /* clean netlist */
input_PsiEnd( p_input ); /* clean PSI information */
input_PcrEnd( p_input ); /* clean PCR information */
free( p_input ); /* free input_thread structure */
#undef p_psi
/* Update status */
*pi_status = THREAD_OVER;
}
......@@ -12,7 +12,7 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
......@@ -194,7 +194,7 @@ vout_thread_t * vout_CreateThread ( char *psz_display, int i_root_window,
}
p_vout->i_pictures = 0;
/* Initialize synchronization informations */
/* Initialize synchronization information */
p_vout->i_synchro_level = VOUT_SYNCHRO_LEVEL_START;
/* Create and initialize system-dependant method - this function issues its
......@@ -347,7 +347,7 @@ void vout_DisplaySubPicture( vout_thread_t *p_vout, subpicture_t *p_subpic )
p_subpic->i_status = READY_SUBPICTURE;
#ifdef DEBUG_VIDEO
/* Send subpicture informations */
/* Send subpicture information */
intf_DbgMsg("subpicture %p: type=%d, begin date=%s, end date=%s\n",
p_subpic, p_subpic->i_type,
mstrtime( psz_begin_date, p_subpic->begin_date ),
......@@ -356,7 +356,7 @@ void vout_DisplaySubPicture( vout_thread_t *p_vout, subpicture_t *p_subpic )
}
/*****************************************************************************
* vout_CreateSubPicture: allocate an subpicture in the video output heap.
* vout_CreateSubPicture: allocate a subpicture in the video output heap.
*****************************************************************************
* This function create a reserved subpicture in the video output heap.
* A null pointer is returned if the function fails. This method provides an
......@@ -411,10 +411,10 @@ subpicture_t *vout_CreateSubPicture( vout_thread_t *p_vout, int i_type,
}
}
/* If no free subpicture is available, use a destroyed subpicture */
/* If no free subpictures are available, use a destroyed subpicture */
if( (p_free_subpic == NULL) && (p_destroyed_subpic != NULL ) )
{
/* No free subpicture or matching destroyed subpicture has been
/* No free subpicture or matching destroyed subpictures have been
* found, but a destroyed subpicture is still avalaible */
free( p_destroyed_subpic->p_data );
p_free_subpic = p_destroyed_subpic;
......@@ -443,7 +443,8 @@ subpicture_t *vout_CreateSubPicture( vout_thread_t *p_vout, int i_type,
}
if( p_free_subpic->p_data != NULL )
{ /* Copy subpicture informations, set some default values */
{
/* Copy subpicture information, set some default values */
p_free_subpic->i_type = i_type;
p_free_subpic->i_status = RESERVED_SUBPICTURE;
p_free_subpic->i_size = i_size;
......@@ -460,7 +461,7 @@ subpicture_t *vout_CreateSubPicture( vout_thread_t *p_vout, int i_type,
p_free_subpic->i_type = EMPTY_SUBPICTURE;
p_free_subpic->i_status = FREE_SUBPICTURE;
p_free_subpic = NULL;
intf_ErrMsg("warning: %s\n", strerror( ENOMEM ) );
intf_ErrMsg("spu warning: %s\n", strerror( ENOMEM ) );
}
#ifdef DEBUG_VIDEO
......@@ -471,7 +472,7 @@ subpicture_t *vout_CreateSubPicture( vout_thread_t *p_vout, int i_type,
}
/* No free or destroyed subpicture could be found */
intf_DbgMsg( "warning: heap is full\n" );
intf_DbgMsg( "warning: subpicture heap is full\n" );
vlc_mutex_unlock( &p_vout->subpicture_lock );
return( NULL );
}
......@@ -677,7 +678,7 @@ picture_t *vout_CreatePicture( vout_thread_t *p_vout, int i_type,
if( p_free_picture->p_data != NULL )
{
/* Copy picture informations, set some default values */
/* Copy picture information, set some default values */
p_free_picture->i_type = i_type;
p_free_picture->i_status = RESERVED_PICTURE;
p_free_picture->i_matrix_coefficients = 1;
......@@ -698,7 +699,7 @@ picture_t *vout_CreatePicture( vout_thread_t *p_vout, int i_type,
p_free_picture->i_type = EMPTY_PICTURE;
p_free_picture->i_status = FREE_PICTURE;
p_free_picture = NULL;
intf_ErrMsg("warning: %s\n", strerror( ENOMEM ) );
intf_ErrMsg("vout warning: %s\n", strerror( ENOMEM ) );
}
#ifdef DEBUG_VIDEO
......@@ -709,7 +710,7 @@ picture_t *vout_CreatePicture( vout_thread_t *p_vout, int i_type,
}
/* No free or destroyed picture could be found */
intf_DbgMsg( "warning: heap is full\n" );
intf_DbgMsg( "warning: picture heap is full\n" );
vlc_mutex_unlock( &p_vout->picture_lock );
return( NULL );
}
......@@ -1075,7 +1076,7 @@ last_display_date = display_date;
/* Set picture dimensions and clear buffer */
SetBufferPicture( p_vout, p_pic );
/* Render picture and informations */
/* Render picture and information */
RenderPicture( p_vout, p_pic );
if( p_vout->b_info )
{
......@@ -1279,7 +1280,7 @@ static void DestroyThread( vout_thread_t *p_vout, int i_status )
* Print: 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.
* print debugging or general information.
*****************************************************************************/
void Print( vout_thread_t *p_vout, int i_x, int i_y, int i_h_align, int i_v_align, unsigned char *psz_text )
{
......@@ -1358,7 +1359,7 @@ static void SetBufferArea( vout_thread_t *p_vout, int i_x, int i_y, int i_w, int
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 */
* array, if possible - otherwise, append it to the last one */
if( i_area < VOUT_MAX_AREAS )
{
p_buffer->pi_area_begin[i_area] = i_y;
......@@ -1368,7 +1369,7 @@ static void SetBufferArea( vout_thread_t *p_vout, int i_x, int i_y, int i_w, int
else
{
#ifdef DEBUG_VIDEO
intf_DbgMsg("areas overflow\n");
intf_DbgMsg("area overflow\n");
#endif
p_buffer->pi_area_end[VOUT_MAX_AREAS - 1] = i_h;
}
......@@ -1605,10 +1606,10 @@ static void SetBufferPicture( vout_thread_t *p_vout, picture_t *p_pic )
/*****************************************************************************
* 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.
* This function converts a picture from a video heap to a pixel-encoded image
* and copies 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 )
{
......@@ -1619,7 +1620,7 @@ static void RenderPicture( vout_thread_t *p_vout, picture_t *p_pic )
vout_buffer_t * p_buffer; /* rendering buffer */
byte_t * p_pic_data; /* convertion destination */
/* Get and set rendering informations */
/* Get and set rendering information */
p_buffer = &p_vout->p_buffer[ p_vout->i_buffer_index ];
p_pic_data = p_buffer->p_data +
p_buffer->i_pic_x * p_vout->i_bytes_per_pixel +
......@@ -1673,10 +1674,10 @@ static void RenderPicture( vout_thread_t *p_vout, picture_t *p_pic )
}
/*****************************************************************************
* RenderPictureInfo: print additionnal informations on a picture
* RenderPictureInfo: print additionnal information on a picture
*****************************************************************************
* This function will print informations such as fps and other picture
* dependant informations.
* This function will print information such as fps and other picture
* dependant information.
*****************************************************************************/
static void RenderPictureInfo( vout_thread_t *p_vout, picture_t *p_pic )
{
......@@ -1768,10 +1769,10 @@ static int RenderIdle( vout_thread_t *p_vout )
}
/*****************************************************************************
* RenderInfo: render additionnal informations
* RenderInfo: render additionnal information
*****************************************************************************
* This function render informations which do not depend of the current picture
* rendered.
* This function renders information which do not depend on the current
* picture rendered.
*****************************************************************************/
static void RenderInfo( vout_thread_t *p_vout )
{
......@@ -1809,7 +1810,7 @@ static void RenderInfo( vout_thread_t *p_vout )
/*****************************************************************************
* RenderSubPicture: render a subpicture
*****************************************************************************
* This function render a sub picture unit.
* This function renders a sub picture unit.
*****************************************************************************/
static void RenderSubPicture( vout_thread_t *p_vout, subpicture_t *p_subpic )
{
......@@ -1881,7 +1882,7 @@ static void RenderSubPicture( vout_thread_t *p_vout, subpicture_t *p_subpic )
/*****************************************************************************
* RenderInterface: render the interface
*****************************************************************************
* This function render the interface, if any.
* This function renders the interface, if any.
*****************************************************************************/
static void RenderInterface( vout_thread_t *p_vout )
{
......
......@@ -22,11 +22,11 @@
/* Text styles - these are primary text styles, used by the vout_Print function.
* They may be ignored or interpreted by higher level functions */
#define WIDE_TEXT 1 /* interspacing is doubled */
#define ITALIC_TEXT 2 /* italic */
#define OPAQUE_TEXT 4 /* text with background */
#define OUTLINED_TEXT 8 /* border around letters */
#define VOID_TEXT 16 /* no foreground */
#define WIDE_TEXT 1<<0 /* interspacing is doubled */
#define ITALIC_TEXT 1<<1 /* italic */
#define OPAQUE_TEXT 1<<2 /* text with background */
#define OUTLINED_TEXT 1<<3 /* border around letters */
#define VOID_TEXT 1<<4 /* no foreground */
/*****************************************************************************
......
......@@ -46,10 +46,10 @@
#include "main.h"
/*****************************************************************************
* vout_InitYUV: allocate and initialize translations tables
* vout_InitYUV: allocate and initialize translation tables
*****************************************************************************
* This function will allocate memory to store translation tables, depending
* of the screen depth.
* on the screen depth.
*****************************************************************************/
int vout_InitYUV( vout_thread_t *p_vout )
{
......@@ -76,7 +76,7 @@ int vout_InitYUV( vout_thread_t *p_vout )
}
/*****************************************************************************
* vout_ResetYUV: re-initialize translations tables
* vout_ResetYUV: re-initialize translation tables
*****************************************************************************
* This function will initialize the tables allocated by vout_InitYUV and
* set functions pointers.
......@@ -88,7 +88,7 @@ int vout_ResetYUV( vout_thread_t *p_vout )
}
/*****************************************************************************
* vout_EndYUV: destroy translations tables
* vout_EndYUV: destroy translation tables
*****************************************************************************
* Free memory allocated by vout_InitYUV
*****************************************************************************/
......
......@@ -159,7 +159,7 @@ void vpar_SynchroUpdateStructures( vpar_thread_t * p_vpar,
#if 1
if( p_vpar->synchro.b_all_I )
intf_ErrMsg( "I: 1/1 " );
intf_ErrMsg( " I: 1/1 " );
if( p_vpar->synchro.b_all_P )
intf_ErrMsg( "P: %i/%i ", p_vpar->synchro.i_P_seen,
p_vpar->synchro.i_P_seen );
......@@ -172,7 +172,7 @@ void vpar_SynchroUpdateStructures( vpar_thread_t * p_vpar,
else if( p_vpar->synchro.displayable_b > 0 )
intf_ErrMsg( "B: %.2f/%i", p_vpar->synchro.displayable_b,
p_vpar->synchro.i_B_seen );
intf_ErrMsg( "\n" );
intf_ErrMsg( " " );
#endif
p_vpar->synchro.i_P_seen = 0;
p_vpar->synchro.i_B_seen = 0;
......
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