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 Thu Jul 20 15:14:06 CEST 2000
0.1.99e : 0.1.99e :
......
...@@ -8,6 +8,11 @@ A typical way to configure the vlc is : ...@@ -8,6 +8,11 @@ A typical way to configure the vlc is :
./configure --prefix=/usr --enable-mmx --enable-gnome ./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. See `./configure --help' for more information.
Then, run `make', and `make install' to install it. Then, run `make', and `make install' to install it.
......
...@@ -79,12 +79,14 @@ endif ...@@ -79,12 +79,14 @@ endif
# C compiler flags: compilation # C compiler flags: compilation
# #
CCFLAGS += $(DEFINE) $(INCLUDE) CCFLAGS += $(DEFINE) $(INCLUDE)
CCFLAGS += -Wall CCFLAGS += -Wall -Winline
CCFLAGS += -D_REENTRANT CCFLAGS += -D_REENTRANT
CCFLAGS += -D_GNU_SOURCE CCFLAGS += -D_GNU_SOURCE
# flags needed for clean beos compilation # flags needed for clean beos compilation
ifeq ($(SYS),beos)
CCFLAGS += -Wno-multichar -Wno-ctor-dtor-privacy -Woverloaded-virtual CCFLAGS += -Wno-multichar -Wno-ctor-dtor-privacy -Woverloaded-virtual
endif
# Optimizations : don't compile debug versions with them # Optimizations : don't compile debug versions with them
ifeq ($(DEBUG),0) ifeq ($(DEBUG),0)
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
.\" First parameter, NAME, should be all caps .\" First parameter, NAME, should be all caps
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
.\" other parameters are allowed: see man(7), man(1) .\" 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. .\" Please adjust this date whenever revising the manpage.
.\" .\"
.\" Some roff macros, for reference: .\" Some roff macros, for reference:
...@@ -36,7 +36,7 @@ A summary of options is included below. ...@@ -36,7 +36,7 @@ A summary of options is included below.
Disable audio output. Disable audio output.
.TP .TP
.B \-\-aout <plugin> .B \-\-aout <plugin>
Specify an audio output plugin. Specify an audio output plugin: "dsp", "esd", for instance.
.TP .TP
.B \-\-stereo, \-\-mono .B \-\-stereo, \-\-mono
Choose stereo or mono audio output Choose stereo or mono audio output
...@@ -45,7 +45,10 @@ Choose stereo or mono audio output ...@@ -45,7 +45,10 @@ Choose stereo or mono audio output
Disable video output. Disable video output.
.TP .TP
.B \-\-vout <plugin> .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 .TP
.B \-\-display <display> .B \-\-display <display>
Specify the display name. Specify the display name.
......
...@@ -90,13 +90,13 @@ typedef struct picture_s ...@@ -90,13 +90,13 @@ typedef struct picture_s
#define YUV_444_PICTURE 102 /* 4:4:4 YUV picture */ #define YUV_444_PICTURE 102 /* 4:4:4 YUV picture */
/* Pictures status */ /* Pictures status */
#define FREE_PICTURE 0 /* picture is free and not allocated */ #define FREE_PICTURE 0 /* free and not allocated */
#define RESERVED_PICTURE 1 /* picture is allocated and reserved */ #define RESERVED_PICTURE 1 /* allocated and reserved */
#define RESERVED_DATED_PICTURE 2 /* picture is waiting for DisplayPicture */ #define RESERVED_DATED_PICTURE 2 /* waiting for DisplayPicture */
#define RESERVED_DISP_PICTURE 3 /* picture is waiting for a DatePixture */ #define RESERVED_DISP_PICTURE 3 /* waiting for a DatePicture */
#define READY_PICTURE 4 /* picture is ready for display */ #define READY_PICTURE 4 /* ready for display */
#define DISPLAYED_PICTURE 5/* picture has been displayed but is linked */ #define DISPLAYED_PICTURE 5 /* been displayed but is linked */
#define DESTROYED_PICTURE 6 /* picture is allocated but no more used */ #define DESTROYED_PICTURE 6 /* allocated but no more used */
/* Aspect ratios (ISO/IEC 13818-2 section 6.3.3, table 6-3) */ /* Aspect ratios (ISO/IEC 13818-2 section 6.3.3, table 6-3) */
#define AR_SQUARE_PICTURE 1 /* square pixels */ #define AR_SQUARE_PICTURE 1 /* square pixels */
...@@ -105,9 +105,9 @@ typedef struct picture_s ...@@ -105,9 +105,9 @@ typedef struct picture_s
#define AR_221_1_PICTURE 4 /* 2.21:1 picture (movie) */ #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. * 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 * Subtitle type and flags should only be modified by the output thread. Note
* that an empty subtitle MUST have its flags set to 0. * that an empty subtitle MUST have its flags set to 0.
...@@ -118,7 +118,7 @@ typedef struct subpicture_s ...@@ -118,7 +118,7 @@ typedef struct subpicture_s
int i_type; /* type */ int i_type; /* type */
int i_status; /* flags */ int i_status; /* flags */
int i_size; /* data size */ 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 */ /* Other properties */
mtime_t begin_date; /* beginning of display date */ mtime_t begin_date; /* beginning of display date */
...@@ -126,7 +126,7 @@ typedef struct subpicture_s ...@@ -126,7 +126,7 @@ typedef struct subpicture_s
/* Display properties - these properties are only indicative and may be /* Display properties - these properties are only indicative and may be
* changed by the video output thread, or simply ignored depending of the * 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_x; /* offset from alignment position */
int i_y; /* offset from alignment position */ int i_y; /* offset from alignment position */
int i_width; /* picture width */ int i_width; /* picture width */
...@@ -160,29 +160,29 @@ typedef struct subpicture_s ...@@ -160,29 +160,29 @@ typedef struct subpicture_s
} subpicture_t; } subpicture_t;
/* Subpicture type */ /* Subpicture type */
#define EMPTY_SUBPICTURE 0 /* subtitle slot is empty and available */ #define EMPTY_SUBPICTURE 0 /* subtitle slot is empty and available */
#define DVD_SUBPICTURE 100 /* DVD subpicture unit */ #define DVD_SUBPICTURE 100 /* DVD subpicture unit */
#define TEXT_SUBPICTURE 200 /* single line text */ #define TEXT_SUBPICTURE 200 /* single line text */
/* Subpicture status */ /* Subpicture status */
#define FREE_SUBPICTURE 0 /* subpicture is free and not allocated */ #define FREE_SUBPICTURE 0 /* free and not allocated */
#define RESERVED_SUBPICTURE 1 /* subpicture is allocated and reserved */ #define RESERVED_SUBPICTURE 1 /* allocated and reserved */
#define READY_SUBPICTURE 2 /* subpicture is ready for display */ #define READY_SUBPICTURE 2 /* ready for display */
#define DESTROYED_SUBPICTURE 3/* subpicture is allocated but no more used */ #define DESTROYED_SUBPICTURE 3 /* allocated but not used anymore */
/* Alignment types */ /* Alignment types */
#define RIGHT_ALIGN 10 /* x is absolute for right */ #define RIGHT_ALIGN 10 /* x is absolute for right */
#define LEFT_ALIGN 11 /* x is absolute for left */ #define LEFT_ALIGN 11 /* x is absolute for left */
#define RIGHT_RALIGN 12 /* x is relative for right from right */ #define RIGHT_RALIGN 12 /* x is relative for right from right */
#define LEFT_RALIGN 13 /* x is relative for left from left */ #define LEFT_RALIGN 13 /* x is relative for left from left */
#define CENTER_ALIGN 20 /* x, y are absolute for center */ #define CENTER_ALIGN 20 /* x, y are absolute for center */
#define CENTER_RALIGN 21 /* x, y are relative for center from center */ #define CENTER_RALIGN 21 /* x,y are relative for center from center */
#define BOTTOM_ALIGN 30 /* y is absolute for bottom */ #define BOTTOM_ALIGN 30 /* y is absolute for bottom */
#define TOP_ALIGN 31 /* y is absolute for top */ #define TOP_ALIGN 31 /* y is absolute for top */
#define BOTTOM_RALIGN 32 /* y is relative for bottom from bottom */ #define BOTTOM_RALIGN 32 /* y is relative for bottom from bottom */
#define TOP_RALIGN 33 /* y is relative for top from top */ #define TOP_RALIGN 33 /* y is relative for top from top */
#define SUBTITLE_RALIGN 34 /* y is relative for center from subtitle */ #define SUBTITLE_RALIGN 34 /* y is relative for center from subtitle */
...@@ -24,10 +24,10 @@ ...@@ -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 * This is the prototype common to all conversion functions. The type of p_pic
* will change depending of the screen depth treated. * will change depending on the processed screen depth.
* Parameters: * Parameters:
* p_vout video output thread * p_vout video output thread
* p_pic picture address * p_pic picture address
...@@ -45,13 +45,13 @@ typedef void (vout_yuv_convert_t)( p_vout_thread_t p_vout, void *p_pic, ...@@ -45,13 +45,13 @@ typedef void (vout_yuv_convert_t)( p_vout_thread_t p_vout, void *p_pic,
int i_matrix_coefficients ); 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 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_Convert420; /* YUV 4:2:0 converter */
vout_yuv_convert_t * p_Convert422; /* YUV 4:2:2 converter */ vout_yuv_convert_t * p_Convert422; /* YUV 4:2:2 converter */
vout_yuv_convert_t * p_Convert444; /* YUV 4:4:4 converter */ vout_yuv_convert_t * p_Convert444; /* YUV 4:4:4 converter */
...@@ -69,21 +69,21 @@ typedef struct vout_yuv_s ...@@ -69,21 +69,21 @@ typedef struct vout_yuv_s
} yuv; } yuv;
/* Temporary conversion buffer and offset array */ /* Temporary conversion buffer and offset array */
void * p_buffer; /* convertion buffer */ void * p_buffer; /* conversion buffer */
int * p_offset; /* offset array */ int * p_offset; /* offset array */
} vout_yuv_t; } vout_yuv_t;
/***************************************************************************** /*****************************************************************************
* vout_buffer_t: rendering buffer * 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. * cleared between displays, and modified areas need to be stored.
*****************************************************************************/ *****************************************************************************/
typedef struct vout_buffer_s typedef struct vout_buffer_s
{ {
/* Picture area */ /* Picture area */
int i_pic_x, i_pic_y; /* picture position */ 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 */ /* Other areas - only vertical extensions of areas are stored */
int i_areas; /* number of areas */ int i_areas; /* number of areas */
...@@ -172,7 +172,7 @@ typedef struct vout_thread_s ...@@ -172,7 +172,7 @@ typedef struct vout_thread_s
/* Pictures and rendering properties */ /* Pictures and rendering properties */
boolean_t b_grayscale; /* color or grayscale display */ 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_interface; /* render interface */
boolean_t b_scale; /* allow picture scaling */ boolean_t b_scale; /* allow picture scaling */
...@@ -192,7 +192,7 @@ typedef struct vout_thread_s ...@@ -192,7 +192,7 @@ typedef struct vout_thread_s
int i_buffer_index; /* buffer index */ int i_buffer_index; /* buffer index */
vout_buffer_t p_buffer[2]; /* buffers properties */ 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 */ picture_t p_picture[VOUT_MAX_PICTURES]; /* pictures */
subpicture_t p_subpicture[VOUT_MAX_PICTURES]; /* subpictures */ subpicture_t p_subpicture[VOUT_MAX_PICTURES]; /* subpictures */
int i_pictures; /* current heap size */ int i_pictures; /* current heap size */
...@@ -202,7 +202,7 @@ typedef struct vout_thread_s ...@@ -202,7 +202,7 @@ typedef struct vout_thread_s
p_vout_font_t p_default_font; /* default font */ p_vout_font_t p_default_font; /* default font */
p_vout_font_t p_large_font; /* large 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 */ * thread and read by decoder threads */
int i_synchro_level; /* trashing level */ int i_synchro_level; /* trashing level */
} vout_thread_t; } vout_thread_t;
......
...@@ -73,7 +73,6 @@ int aout_EsdOpen( aout_thread_t *p_aout ) ...@@ -73,7 +73,6 @@ int aout_EsdOpen( aout_thread_t *p_aout )
int i_mode = ESD_STREAM; int i_mode = ESD_STREAM;
int i_func = ESD_PLAY; int i_func = ESD_PLAY;
fprintf(stderr, "aout-esd !!\n");
/* Allocate structure */ /* Allocate structure */
p_aout->p_sys = malloc( sizeof( aout_sys_t ) ); p_aout->p_sys = malloc( sizeof( aout_sys_t ) );
if( p_aout->p_sys == NULL ) 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 * Provides functions to perform the YUV conversion. The functions provided here
* are a complete and portable C implementation, and may be replaced in certain * are a complete and portable C implementation, and may be replaced in certain
* case by optimized functions. * case by optimized functions.
...@@ -55,31 +55,23 @@ int yuv_MMXInit( vout_thread_t *p_vout ) ...@@ -55,31 +55,23 @@ int yuv_MMXInit( vout_thread_t *p_vout )
{ {
size_t tables_size; /* tables size, in bytes */ size_t tables_size; /* tables size, in bytes */
/* Computes tables size - 3 Bpp use 32 bits pixel entries in tables */ /* Computes tables size for 8bbp only */
switch( p_vout->i_bytes_per_pixel ) if( p_vout->i_bytes_per_pixel == 1 )
{ {
case 1:
tables_size = sizeof( u8 ) tables_size = sizeof( u8 )
* (p_vout->b_grayscale ? GRAY_TABLE_SIZE : PALETTE_TABLE_SIZE); * (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 */ /* Allocate memory */
p_vout->yuv.p_base = malloc( tables_size ); p_vout->yuv.p_base = malloc( tables_size );
if( p_vout->yuv.p_base == NULL ) if( p_vout->yuv.p_base == NULL )
{
intf_ErrMsg("error: %s\n", strerror(ENOMEM));
return( 1 );
}
}
else
{ {
intf_ErrMsg("error: %s\n", strerror(ENOMEM)); p_vout->yuv.p_base = NULL;
return( 1 );
} }
/* Allocate memory for conversion buffer and offset array */ /* Allocate memory for conversion buffer and offset array */
...@@ -111,7 +103,11 @@ int yuv_MMXInit( vout_thread_t *p_vout ) ...@@ -111,7 +103,11 @@ int yuv_MMXInit( vout_thread_t *p_vout )
*****************************************************************************/ *****************************************************************************/
void yuv_MMXEnd( 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_buffer );
free( p_vout->yuv.p_offset ); free( p_vout->yuv.p_offset );
} }
...@@ -130,25 +126,6 @@ int yuv_MMXReset( vout_thread_t *p_vout ) ...@@ -130,25 +126,6 @@ int yuv_MMXReset( vout_thread_t *p_vout )
/* following functions are local */ /* 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 * SetYUV: compute tables and set function pointers
+ *****************************************************************************/ + *****************************************************************************/
...@@ -166,136 +143,103 @@ void SetYUV( vout_thread_t *p_vout ) ...@@ -166,136 +143,103 @@ void SetYUV( vout_thread_t *p_vout )
if( p_vout->b_grayscale ) if( p_vout->b_grayscale )
{ {
/* Grayscale: build gray table */ /* 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++) 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; /* the colors have been allocated, we can set the palette */
case 3: p_vout->p_set_palette( p_vout, bright, bright, bright, transp );
case 4: p_vout->i_white_pixel = 0xff;
p_vout->yuv.yuv.p_gray32 = (u32 *)p_vout->yuv.p_base + GRAY_MARGIN; p_vout->i_black_pixel = 0x00;
for( i_index = 0; i_index < GRAY_MARGIN; i_index++ ) p_vout->i_gray_pixel = 0x44;
{ p_vout->i_blue_pixel = 0x3b;
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;
}
} }
else else
{ {
/* Color: build red, green and blue tables */ /* 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 for ( u = 0; u <= 256; u += 32 )
#define RGB_MAX 255 for ( v = 0; v <= 256; v += 32 )
#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 ) uvr = (V_RED_COEF*(v-128)) >> SHIFT;
for ( v = 0; v <= 256; v += 32 ) 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; /* this one should never happen unless someone fscked up my code */
uvg = (U_GREEN_COEF*(u-128) + V_GREEN_COEF*(v-128)) >> SHIFT; if(j == 256) { intf_ErrMsg( "vout error: no colors left to build palette\n" ); break; }
uvb = (U_BLUE_COEF*(u-128)) >> SHIFT;
r = y + uvr; /* clip the colors */
g = y + uvg; red[j] = CLIP( r );
b = y + uvb; green[j] = CLIP( g );
blue[j] = CLIP( b );
if( r >= RGB_MIN && g >= RGB_MIN && b >= RGB_MIN transp[j] = 0;
&& r <= RGB_MAX && g <= RGB_MAX && b <= RGB_MAX )
{ /* allocate color */
/* this one should never happen unless someone fscked up my code */ lookup[i] = 1;
if(j == 256) { intf_ErrMsg( "vout error: no colors left to build palette\n" ); break; } p_vout->yuv.yuv.p_rgb8[i++] = j;
j++;
/* clip the colors */ }
red[j] = CLIP( r ); else
green[j] = CLIP( g ); {
blue[j] = CLIP( b ); lookup[i] = 0;
transp[j] = 0; p_vout->yuv.yuv.p_rgb8[i++] = 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 */ /* the colors have been allocated, we can set the palette */
/* there will eventually be a way to know which colors /* there will eventually be a way to know which colors
* couldn't be allocated and try to find a replacement */ * couldn't be allocated and try to find a replacement */
p_vout->p_set_palette( p_vout, red, green, blue, transp ); p_vout->p_set_palette( p_vout, red, green, blue, transp );
p_vout->i_white_pixel = 0xff; p_vout->i_white_pixel = 0xff;
p_vout->i_black_pixel = 0x00; p_vout->i_black_pixel = 0x00;
p_vout->i_gray_pixel = 0x44; p_vout->i_gray_pixel = 0x44;
p_vout->i_blue_pixel = 0x3b; p_vout->i_blue_pixel = 0x3b;
i = 0; i = 0;
/* this loop allocates colors that got outside /* this loop allocates colors that got outside
* the RGB cube */ * the RGB cube */
for ( y = 0; y <= 256; y += 16 ) 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 ) for ( v = 0; v <= 256; v += 32 )
{ {
int u2, v2; int u2, v2;
...@@ -331,60 +275,9 @@ void SetYUV( vout_thread_t *p_vout ) ...@@ -331,60 +275,9 @@ void SetYUV( vout_thread_t *p_vout )
} }
i++; i++;
} }
i += 128-81;
} }
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 );
} }
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 * Provides functions to perform the YUV conversion. The functions provided here
* are a complete and portable C implementation, and may be replaced in certain * are a complete and portable C implementation, and may be replaced in certain
* case by optimized functions. * case by optimized functions.
...@@ -28,30 +28,11 @@ ...@@ -28,30 +28,11 @@
* Constants * 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_MARGIN 384
#define GRAY_TABLE_SIZE 1024 /* total table size */ #define GRAY_TABLE_SIZE 1024 /* total table size */
#define PALETTE_TABLE_SIZE 2176 /* YUV -> 8bpp palette lookup table */ #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 */ /* argument lists for YUV functions */
#define YUV_ARGS_8BPP p_vout_thread_t p_vout, u8 *p_pic, yuv_data_t *p_y, \ #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, \ 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 ) ...@@ -99,7 +99,10 @@ void ConvertYUV420RGB16( YUV_ARGS_16BPP )
__asm__( MMX_INIT_16 __asm__( MMX_INIT_16
: : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) ); : : "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) ); : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) );
p_y += 8; 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 * Provides functions to perform the YUV conversion. The functions provided here
* are a complete and portable C implementation, and may be replaced in certain * are a complete and portable C implementation, and may be replaced in certain
* case by optimized functions. * 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 * Provides functions to perform the YUV conversion. The functions provided here
* are a complete and portable C implementation, and may be replaced in certain * are a complete and portable C implementation, and may be replaced in certain
* case by optimized functions. * 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 * Provides functions to perform the YUV conversion. The functions provided here
* are a complete and portable C implementation, and may be replaced in certain * are a complete and portable C implementation, and may be replaced in certain
* case by optimized functions. * case by optimized functions.
......
/***************************************************************************** /*****************************************************************************
* video_yuv_asm.h: YUV transformation assembly * video_yuv_asm.h: MMX YUV transformation assembly
***************************************************************************** *****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN * Copyright (C) 1999, 2000 VideoLAN
* *
...@@ -82,7 +82,7 @@ movq %%mm1, %%mm3 # Copy 4 Cr 00 v3 00 v2 00 v1 00 v0 \n\ ...@@ -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_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_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_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\ paddsw %%mm3, %%mm2 # Cb green + Cr green -> Cgreen \n\
\n\ \n\
# convert the luma part \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 * Copyright (C) 1999, 2000 VideoLAN
* *
......
...@@ -74,6 +74,25 @@ void aout_Thread_U16_Stereo ( aout_thread_t * p_aout ); ...@@ -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__ 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 ); 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 * aout_CreateThread: initialize audio thread
*****************************************************************************/ *****************************************************************************/
...@@ -467,25 +486,6 @@ void aout_DestroyFifo( aout_fifo_t * p_fifo ) ...@@ -467,25 +486,6 @@ void aout_DestroyFifo( aout_fifo_t * p_fifo )
/* Following functions are local */ /* 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 * NextFrame
*****************************************************************************/ *****************************************************************************/
......
...@@ -92,13 +92,15 @@ static __inline__ void input_DemuxTS( input_thread_t *p_input, ...@@ -92,13 +92,15 @@ static __inline__ void input_DemuxTS( input_thread_t *p_input,
static __inline__ void input_DemuxPES( input_thread_t *p_input, static __inline__ void input_DemuxPES( input_thread_t *p_input,
ts_packet_t *ts_packet, ts_packet_t *ts_packet,
es_descriptor_t *p_es_descriptor, 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, static __inline__ void input_ParsePES( input_thread_t *p_input,
es_descriptor_t *p_es_descriptor ); es_descriptor_t *p_es_descriptor );
static __inline__ void input_DemuxPSI( input_thread_t *p_input, static __inline__ void input_DemuxPSI( input_thread_t *p_input,
ts_packet_t *ts_packet, ts_packet_t *ts_packet,
es_descriptor_t *p_es_descriptor, 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 * input_CreateThread: creates a new input thread
...@@ -108,8 +110,9 @@ static __inline__ void input_DemuxPSI( input_thread_t *p_input, ...@@ -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 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. * 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, input_thread_t *input_CreateThread ( int i_method, void *p_source, int i_port,
p_vout_thread_t p_vout, p_aout_thread_t p_aout, int *pi_status ) 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 */ input_thread_t * p_input; /* thread descriptor */
int i_status; /* thread status */ int i_status; /* thread status */
...@@ -343,528 +346,376 @@ static int InitThread( input_thread_t *p_input ) ...@@ -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 )
{ {
/* int i_data_offset; /* Offset of the interesting data in the TS packet */
* Initialize thread and free configuration u16 i_data_length; /* Length of those data */
*/ //boolean_t b_first_section; /* another section in the TS packet ? */
p_input->b_error = InitThread( p_input );
if( p_input->b_error ) 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 */ /* Was data lost since the last TS packet ? */
return; 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 );
}
} }
/* We are looking for the beginning of a new section */
/* else
* 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( b_unit_start )
if( (input_ReadPacket( p_input )) == (-1) )
{ {
/* FIXME??: Normally, a thread can't kill itself, but we don't have /* Get the offset at which the data for that section can be found
* any method in case of an error condition ... */ * The offset is stored in the pointer_field since we are
p_input->b_error = 1; * 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
} }
/* /* The section we will deal with during the first iteration of the
* Error loop * following loop is the first one contained in the TS packet */
*/ // b_first_section = 1;
if( p_input->b_error )
/* 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 */ /* Init the reassembly of that section */
EndThread( p_input ); p_psi->b_running_section = 1;
intf_DbgMsg("thread end\n"); 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;
/***************************************************************************** /* Copy those data in the section buffer */
* ErrorThread: RunThread() error loop memcpy( &p_psi->buffer[p_psi->i_current_position], &p_ts_packet->buffer[i_data_offset],
***************************************************************************** i_data_length );
* 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 );
}
}
/***************************************************************************** /* Interesting data are now after the ones we copied, since no gap is
* EndThread: end the input thread * allowed between 2 sections in a TS packets */
*****************************************************************************/ i_data_offset += i_data_length;
static void EndThread( input_thread_t * p_input )
{
int * pi_status; /* threas status */
int i_es_loop; /* es index */
/* Store status */ /* Decode the packet if it is now complete */
intf_DbgMsg("\n"); if (p_psi->i_length == p_psi->i_current_position + i_data_length)
pi_status = p_input->pi_status; {
*pi_status = THREAD_END; /* Packet is complete, decode it */
//intf_DbgMsg( "SECTION COMPLETE: starting decoding of its data\n" );
input_PsiDecode( p_input, p_psi );
/* Close input method */ /* Prepare the buffer to receive a new section */
p_input->p_Close( p_input ); p_psi->i_current_position = 0;
p_psi->b_running_section = 0;
/* Destroy all decoder threads */ /* The new section won't be the first anymore */
for( i_es_loop = 0; //b_first_section = 0;
(i_es_loop < INPUT_MAX_ES) && (p_input->pp_selected_es[i_es_loop] != NULL) ; }
i_es_loop++ ) else
{
switch( p_input->pp_selected_es[i_es_loop]->i_type )
{ {
case MPEG1_VIDEO_ES: /* Prepare the buffer to receive the next part of the section */
case MPEG2_VIDEO_ES: p_psi->i_current_position += i_data_length;
vpar_DestroyThread( (vpar_thread_t*)(p_input->pp_selected_es[i_es_loop]->p_dec) /*, NULL */ ); //intf_DbgMsg( "Section not complete, waiting for the end\n" );
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] );
} }
input_NetlistEnd( p_input ); /* clean netlist */ /* Relase the TS packet, we don't need it anymore */
input_PsiEnd( p_input ); /* clean PSI information */ input_NetlistFreeTS( p_input, p_ts_packet );
input_PcrEnd( p_input ); /* clean PCR information */
free( p_input ); /* free input_thread structure */
/* Update status */ #undef p_psi
*pi_status = THREAD_OVER;
} }
/***************************************************************************** /*****************************************************************************
* 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 */ decoder_fifo_t * p_fifo;
int i_current_index; u8 i_pes_header_size;
int i_packet_size; ts_packet_t * p_ts;
#ifdef INPUT_LIFO_TS_NETLIST int i_ts_payload_size;
int i_meanwhile_released;
int i_currently_removed;
#endif
ts_packet_t * p_ts_packet;
/* 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 */ #define p_pes (p_es_descriptor->p_pes_packet)
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 );
}
/* Remove the TS packets we have just filled from the netlist */ //intf_DbgMsg("End of PES packet %p\n", p_pes);
#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; /* First read the 6 header bytes common to all PES packets:
if( i_meanwhile_released ) 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 /* Trash the packet and set p_pes to NULL to be sure the next PES
efficiency reasons, other threads (including ourselves, with packet will have its b_data_lost flag set */
input_DemuxPacket) might have released packets to the netlist. intf_DbgMsg("Corrupted PES packet (size doesn't match) : trashed\n");
So we have to copy these iovec where they should go. input_NetlistFreePES( p_input, p_pes );
p_pes = NULL;
BTW, that explains why the TS netlist is /* Stats XXX?? */
(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;
} }
else else
{ {
/* Nothing happened. */ /* The PES packet is valid. Check its type to test if it may
p_input->netlist.i_ts_index = i_current_index; carry additional informations in a header extension */
} p_pes->i_stream_id = p_pes->p_pes_header[3];
vlc_mutex_unlock( &p_input->netlist.lock );
#else /* FIFO netlist */ switch( p_pes->i_stream_id )
/* & is modulo ; that's where we make the loop. */ {
p_input->netlist.i_ts_start = i_current_index & INPUT_MAX_TS; case 0xBE: /* Padding */
#endif 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 default:
p_input->c_packets_read += i_current_index - i_base_index; switch( p_pes->p_pes_header[8] & 0xc0 )
p_input->c_bytes += (i_current_index - i_base_index) * TS_PACKET_SIZE; {
#endif case 0x80: /* MPEG2: 10xx xxxx */
return( 0 ); 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;
/***************************************************************************** /* Now parse the optional header extensions (in the limit of
* input_SortPacket: find out whether we need that packet the 14 bytes */
*****************************************************************************/ if( p_pes->b_has_pts )
static __inline__ void input_SortPacket( input_thread_t *p_input, {
ts_packet_t *p_ts_packet ) pcr_descriptor_t * p_pcr;
{
int i_current_pid;
int i_es_loop;
/* Verify that sync_byte, error_indicator and scrambling_control are p_pcr = p_input->p_pcr;
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;
//intf_DbgMsg("input debug: pid %d received (%p)\n", p_pes->i_pts =
// i_current_pid, p_ts_packet); ( ((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. */ if( p_pcr->i_synchro_state )
vlc_mutex_lock( &p_input->es_lock ); {
switch( p_pcr->i_synchro_state )
{
case SYNCHRO_NOT_STARTED:
p_pes->b_has_pts = 0;
break;
/* Verify that we actually want this PID. */ case SYNCHRO_START:
for( i_es_loop = 0; i_es_loop < INPUT_MAX_SELECTED_ES; i_es_loop++ ) p_pes->i_pts += p_pcr->delta_pcr;
{ p_pcr->delta_absolute = mdate() - p_pes->i_pts + INPUT_PTS_DELAY;
if( p_input->pp_selected_es[i_es_loop] != NULL) p_pes->i_pts += p_pcr->delta_absolute;
{ p_pcr->i_synchro_state = 0;
if( (*p_input->pp_selected_es[i_es_loop]).i_id break;
== 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. */ case SYNCHRO_REINIT: /* We skip a PES */
input_DemuxTS( p_input, p_ts_packet, p_pes->b_has_pts = 0;
p_input->pp_selected_es[i_es_loop] ); p_pcr->i_synchro_state = SYNCHRO_START;
return; break;
}
}
else
{
p_pes->i_pts += p_pcr->delta_pcr + p_pcr->delta_absolute;
}
} }
}
else
{
/* pp_selected_es should not contain any hole. */
break; 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
}
/***************************************************************************** default: /* MPEG1 or some strange thing */
* input_DemuxTS: first step of demultiplexing: the TS header /* since this isn't supported yet, we certainly gonna crash */
***************************************************************************** intf_ErrMsg( "FIXME: unknown PES type %.2x\n",
* Stream must also only contain PES and PSI, so PID must have been filtered p_pes->p_pes_header[8] );
*****************************************************************************/ i_pes_header_size = 6;
static __inline__ void input_DemuxTS( input_thread_t *p_input, break;
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);
#ifdef STATS }
p_es_descriptor->c_packets++; break;
p_es_descriptor->c_bytes += TS_PACKET_SIZE; }
#endif
/* Extract flags values from TS common header. */ /* Now we've parsed the header, we just have to indicate in some
b_unit_start = (p[1] & 0x40); * specific TS packets where the PES payload begins (renumber
b_adaption = (p[3] & 0x20); * i_payload_start), so that the decoders can find the beginning
b_payload = (p[3] & 0x10); * 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, /* Now we can eventually put the PES packet in the decoder's
so that there is nothing to do: skip this possibility */ * PES fifo */
if( p[4] ) switch( p_es_descriptor->i_type )
{ {
/* If the packet has both adaptation_field and payload, adaptation_field case MPEG1_VIDEO_ES:
cannot be more than 182 bytes long; if there is only an case MPEG2_VIDEO_ES:
adaptation_field, it must fill the next 183 bytes. */ p_fifo = &(((vpar_thread_t*)(p_es_descriptor->p_dec))->fifo);
if( b_payload ? (p[4] > 182) : (p[4] != 183) ) break;
{
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;
}
/* No we are sure that the byte containing flags is present: read it */ case MPEG1_AUDIO_ES:
else case MPEG2_AUDIO_ES:
{ p_fifo = &(((adec_thread_t*)(p_es_descriptor->p_dec))->fifo);
/* discontinuity_indicator */ break;
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);
/* If the PID carries the PCR, there will be a system time-base case AC3_AUDIO_ES:
discontinuity. We let the PCR decoder handle that. */ p_fifo = &(((ac3dec_thread_t *)(p_es_descriptor->p_dec))->fifo);
p_es_descriptor->b_discontinuity = 1; break;
/* There also may be a continuity_counter discontinuity: case LPCM_AUDIO_ES:
resynchronise our counter with the one of the stream */ p_fifo = &(((lpcmdec_thread_t *)(p_es_descriptor->p_dec))->fifo);
p_es_descriptor->i_continuity_counter = (p[3] & 0x0f) - 1; break;
}
/* random_access_indicator */ case DVD_SPU_ES:
p_es_descriptor->b_random |= p[5] & 0x40; /* 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, default:
we pass it along to the PCR decoder. */ /* This should never happen */
if( (p_es_descriptor->b_pcr) && (p[5] & 0x10) ) intf_DbgMsg("Unknown stream type (%d, %d): PES trashed\n",
{ p_es_descriptor->i_id, p_es_descriptor->i_type);
/* There should be a PCR field in the packet, check if the p_fifo = NULL;
adaption field is long enough to carry it */ break;
if( p[4] >= 7 )
{
/* Call the PCR decoder */
input_PcrDecode( p_input, p_es_descriptor, &p[6] );
}
}
}
} }
}
/* Check the continuity of the stream. */ if( p_fifo != NULL )
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 vlc_mutex_lock( &p_fifo->data_lock );
continuity_counter wrapped and we received a dup packet: as we if( DECODER_FIFO_ISFULL( *p_fifo ) )
don't know, do as if we missed a packet to be sure to recover {
from this situation */ /* The FIFO is full !!! This should not happen. */
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 );
#ifdef STATS #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 #endif
} input_NetlistFreePES( p_input, p_pes );
else intf_DbgMsg("PES trashed - fifo full ! (%d, %d)\n",
{ p_es_descriptor->i_id, p_es_descriptor->i_type);
if( p_es_descriptor->b_psi ) }
{ else
/* The payload contains PSI tables */ {
input_DemuxPSI( p_input, p_ts_packet, p_es_descriptor, //intf_DbgMsg("Putting %p into fifo %p/%d\n",
b_unit_start, b_lost ); // 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 else
{ {
/* The payload carries a PES stream */ intf_DbgMsg("No fifo to receive PES %p: trash\n", p_pes);
input_DemuxPES( p_input, p_ts_packet, p_es_descriptor, #ifdef STATS
b_unit_start, b_lost ); 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_pes
#undef p
} }
/***************************************************************************** /*****************************************************************************
* input_DemuxPES: * input_DemuxPES:
***************************************************************************** *****************************************************************************
...@@ -928,8 +779,9 @@ static __inline__ void input_DemuxPES( input_thread_t *p_input, ...@@ -928,8 +779,9 @@ static __inline__ void input_DemuxPES( input_thread_t *p_input,
i_dummy = 0; i_dummy = 0;
do do
{ {
memcpy(p_pes->p_pes_header_save + i_dummy, memcpy( p_pes->p_pes_header_save + i_dummy,
&p_ts->buffer[p_ts->i_payload_start], i_ts_payload_size); &p_ts->buffer[p_ts->i_payload_start],
i_ts_payload_size);
i_dummy += i_ts_payload_size; i_dummy += i_ts_payload_size;
p_ts = p_ts->p_next_ts; p_ts = p_ts->p_next_ts;
...@@ -1075,377 +927,523 @@ static __inline__ void input_DemuxPES( input_thread_t *p_input, ...@@ -1075,377 +927,523 @@ static __inline__ void input_DemuxPES( input_thread_t *p_input,
#undef p_pes #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, static __inline__ void input_DemuxTS( input_thread_t *p_input,
es_descriptor_t *p_es_descriptor ) ts_packet_t *p_ts_packet,
es_descriptor_t *p_es_descriptor )
{ {
decoder_fifo_t * p_fifo; int i_dummy;
u8 i_pes_header_size; boolean_t b_adaption; /* Adaption field is present */
ts_packet_t * p_ts; boolean_t b_payload; /* Packet carries payload */
int i_ts_payload_size; 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: /* Extract flags values from TS common header. */
use them to test the PES validity */ b_unit_start = (p[1] & 0x40);
if( (p_pes->p_pes_header[0] || p_pes->p_pes_header[1] || b_adaption = (p[3] & 0x20);
(p_pes->p_pes_header[2] != 1)) || b_payload = (p[3] & 0x10);
/* packet_start_code_prefix != 0x000001 */
((p_pes->i_pes_real_size) && /* Extract adaption field informations if any */
(p_pes->i_pes_real_size != p_pes->i_pes_size)) ) if( !b_adaption )
/* PES_packet_length is set and != total received payload */
{ {
/* Trash the packet and set p_pes to NULL to be sure the next PES /* We don't have any adaptation_field, so payload start immediately
packet will have its b_data_lost flag set */ after the 4 byte TS header */
intf_DbgMsg("Corrupted PES packet (size doesn't match) : trashed\n"); p_ts_packet->i_payload_start = 4;
input_NetlistFreePES( p_input, p_pes );
p_pes = NULL;
/* Stats XXX?? */
} }
else else
{ {
/* The PES packet is valid. Check its type to test if it may /* p[4] is adaptation_field_length minus one */
carry additional informations in a header extension */ p_ts_packet->i_payload_start = 5 + p[4];
p_pes->i_stream_id = p_pes->p_pes_header[3];
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 */ /* If the packet has both adaptation_field and payload, adaptation_field
case 0xBC: /* Program stream map */ cannot be more than 182 bytes long; if there is only an
case 0xBF: /* Private stream 2 */ adaptation_field, it must fill the next 183 bytes. */
case 0xB0: /* ECM */ if( b_payload ? (p[4] > 182) : (p[4] != 183) )
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 )
{ {
case 0x80: /* MPEG2: 10xx xxxx */ intf_DbgMsg("input debug: invalid TS adaptation field (%p)\n",
case 0x00: /* FIXME: This shouldn't be allowed !! */ p_ts_packet);
/* The PES header contains at least 3 more bytes: parse them */ #ifdef STATS
p_pes->b_data_alignment = p_pes->p_pes_header[6] & 0x04; p_es_descriptor->c_invalid_packets++;
p_pes->b_has_pts = p_pes->p_pes_header[7] & 0x80; #endif
i_pes_header_size = p_pes->p_pes_header[8] + 9; b_trash = 1;
}
/* Now parse the optional header extensions (in the limit of /* No we are sure that the byte containing flags is present: read it */
the 14 bytes */ else
if( p_pes->b_has_pts ) {
/* discontinuity_indicator */
if( p[5] & 0x80 )
{ {
pcr_descriptor_t * p_pcr; intf_DbgMsg("discontinuity_indicator encountered by TS demux " \
"(position read: %d, saved: %d)\n", p[5] & 0x80,
p_pcr = p_input->p_pcr; p_es_descriptor->i_continuity_counter);
p_pes->i_pts = /* If the PID carries the PCR, there will be a system time-base
( ((mtime_t)(p_pes->p_pes_header[9] & 0x0E) << 29) | discontinuity. We let the PCR decoder handle that. */
(((mtime_t)U16_AT(p_pes->p_pes_header + 10) << 14) - (1 << 14)) | p_es_descriptor->b_discontinuity = 1;
((mtime_t)U16_AT(p_pes->p_pes_header + 12) >> 1) ) * 300;
p_pes->i_pts /= 27;
if( p_pcr->i_synchro_state ) /* There also may be a continuity_counter discontinuity:
{ resynchronise our counter with the one of the stream */
switch( p_pcr->i_synchro_state ) p_es_descriptor->i_continuity_counter = (p[3] & 0x0f) - 1;
{ }
case SYNCHRO_NOT_STARTED:
p_pes->b_has_pts = 0;
break;
case SYNCHRO_START: /* random_access_indicator */
p_pes->i_pts += p_pcr->delta_pcr; p_es_descriptor->b_random |= p[5] & 0x40;
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;
case SYNCHRO_REINIT: /* We skip a PES */ /* If this is a PCR_PID, and this TS packet contains a PCR,
p_pes->b_has_pts = 0; we pass it along to the PCR decoder. */
p_pcr->i_synchro_state = SYNCHRO_START; if( (p_es_descriptor->b_pcr) && (p[5] & 0x10) )
break; {
} /* There should be a PCR field in the packet, check if the
} adaption field is long enough to carry it */
else 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 /* Trash the packet if it has no payload or if it is bad */
* specific TS packets where the PES payload begins (renumber if( b_trash )
* i_payload_start), so that the decoders can find the beginning {
* of their data right out of the box. */ input_NetlistFreeTS( p_input, p_ts_packet );
p_ts = p_pes->p_first_ts; #ifdef STATS
i_ts_payload_size = p_ts->i_payload_end - p_ts->i_payload_start; p_input->c_packets_trashed++;
while( i_pes_header_size > i_ts_payload_size ) #endif
}
else
{
if( p_es_descriptor->b_psi )
{ {
/* These packets are entirely filled by the PES header. */ /* The payload contains PSI tables */
i_pes_header_size -= i_ts_payload_size; input_DemuxPSI( p_input, p_ts_packet, p_es_descriptor,
p_ts->i_payload_start = p_ts->i_payload_end; b_unit_start, b_lost );
/* 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. */ else
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 )
{ {
case MPEG1_VIDEO_ES: /* The payload carries a PES stream */
case MPEG2_VIDEO_ES: input_DemuxPES( p_input, p_ts_packet, p_es_descriptor,
p_fifo = &(((vpar_thread_t*)(p_es_descriptor->p_dec))->fifo); b_unit_start, b_lost );
break; }
}
case MPEG1_AUDIO_ES: #undef p
case MPEG2_AUDIO_ES: }
p_fifo = &(((adec_thread_t*)(p_es_descriptor->p_dec))->fifo);
break;
case AC3_AUDIO_ES: /*****************************************************************************
p_fifo = &(((ac3dec_thread_t *)(p_es_descriptor->p_dec))->fifo); * input_SortPacket: find out whether we need that packet
break; *****************************************************************************/
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: /* Verify that sync_byte, error_indicator and scrambling_control are
p_fifo = &(((lpcmdec_thread_t *)(p_es_descriptor->p_dec))->fifo); what we expected. */
break; 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: //intf_DbgMsg("input debug: pid %d received (%p)\n",
/* we skip the first byte at the beginning of the // i_current_pid, p_ts_packet);
* 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;
default: /* Lock current ES state. */
/* This should never happen */ vlc_mutex_lock( &p_input->es_lock );
intf_DbgMsg("Unknown stream type (%d, %d): PES trashed\n",
p_es_descriptor->i_id, p_es_descriptor->i_type);
p_fifo = NULL;
break;
}
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( p_input->pp_selected_es[i_es_loop] != NULL)
if( DECODER_FIFO_ISFULL( *p_fifo ) )
{ {
/* The FIFO is full !!! This should not happen. */ if( (*p_input->pp_selected_es[i_es_loop]).i_id
#ifdef STATS == i_current_pid )
p_input->c_packets_trashed += p_pes->i_ts_packets; {
p_es_descriptor->c_invalid_packets += p_pes->i_ts_packets; /* Don't need the lock anymore, since the value pointed
#endif out by p_input->pp_selected_es[i_es_loop] can only be
input_NetlistFreePES( p_input, p_pes ); modified from inside the input_thread (by the PSI
intf_DbgMsg("PES trashed - fifo full ! (%d, %d)\n", decoder): interface thread is only allowed to modify
p_es_descriptor->i_id, p_es_descriptor->i_type); 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", /* pp_selected_es should not contain any hole. */
// p_pes, p_fifo, p_fifo->i_end); break;
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 vlc_mutex_unlock( &p_input->es_lock );
{ }
intf_DbgMsg("No fifo to receive PES %p: trash\n", p_pes);
/* 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 #ifdef STATS
p_input->c_packets_trashed += p_pes->i_ts_packets; p_input->c_packets_trashed++;
p_es_descriptor->c_invalid_packets += p_pes->i_ts_packets;
#endif #endif
input_NetlistFreePES( p_input, p_pes );
}
}
#undef p_pes
} }
/***************************************************************************** /*****************************************************************************
* input_DemuxPSI: * input_ReadPacket: reads a packet from the network or the file
*****************************************************************************
* 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 __inline__ void input_DemuxPSI( input_thread_t *p_input, static __inline__ int input_ReadPacket( 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 )
{ {
int i_data_offset; /* Offset of the interesting data in the TS packet */ int i_base_index; /* index of the first free iovec */
u16 i_data_length; /* Length of those data */ int i_current_index;
//boolean_t b_first_section; /* another section in the TS packet ? */ 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); /* In this function, we only care about the TS netlist. PES netlist
ASSERT(p_ts_packet); * is for the demultiplexer. */
ASSERT(p_es_descriptor); #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 BTW, that explains why the TS netlist is
* the do-while loop that follows -> Compute the i_data_offset variable: (INPUT_MAX_TS +1) + (TS_READ_ONCE -1) large. */
* 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 ? */ i_currently_removed = i_current_index - i_base_index;
if( p_psi->b_running_section ) if( i_meanwhile_released < i_currently_removed )
{
/* Was data lost since the last TS packet ? */
if( b_packet_lost )
{ {
/* Discard the packet and wait for the begining of a new one /* Copy all iovecs in that case */
* to resynch */ memcpy( &p_input->netlist.p_ts_free[p_input->netlist.i_ts_index]
p_psi->b_running_section = 0; + i_currently_removed,
p_psi->i_current_position = 0; &p_input->netlist.p_ts_free[p_input->netlist.i_ts_index],
intf_DbgMsg( "PSI section(s) discarded due to packet loss\n" ); i_meanwhile_released * sizeof(struct iovec) );
} }
else else
{ {
/* The data that complete a previously began section are always at /* We have fewer places than items, so we only move
* the beginning of the TS payload... */ i_currently_removed of them. */
i_data_offset = p_ts_packet->i_payload_start; memcpy( &p_input->netlist.p_ts_free[i_base_index],
/* ...Unless there is a pointer field, that we have to bypass */ &p_input->netlist.p_ts_free[p_input->netlist.i_ts_index],
if( b_unit_start ) i_currently_removed * sizeof(struct iovec) );
i_data_offset++;
//intf_DbgMsg( "New part of the section received at offset %d\n", i_data_offset );
} }
/* 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 else
{ {
if( b_unit_start ) /* Nothing happened. */
{ p_input->netlist.i_ts_index = i_current_index;
/* 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" );
}
} }
/* The section we will deal with during the first iteration of the vlc_mutex_unlock( &p_input->netlist.lock );
* 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 #else /* FIFO netlist */
* decode the sections that could have been completed. /* & is modulo ; that's where we make the loop. */
* Stop when we reach the end of the packet or stuffing bytes */ p_input->netlist.i_ts_start = i_current_index & INPUT_MAX_TS;
while( i_data_offset < TS_PACKET_SIZE && p_ts_packet->buffer[i_data_offset] != 0xFF ) #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 free( p_input ); /* destroy descriptor */
* the p_psi struct to start its decoding */ return;
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;
}
/* Init the reassembly of that section */ /*
p_psi->b_running_section = 1; * Main loop
p_psi->i_current_position = 0; */
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 */ #ifdef STATS
if( p_psi->i_length - p_psi->i_current_position > TS_PACKET_SIZE - i_data_offset) p_input->c_loops++;
i_data_length = TS_PACKET_SIZE - i_data_offset; #endif
else }
i_data_length = p_psi->i_length - p_psi->i_current_position;
/* Copy those data in the section buffer */ /*
memcpy( &p_psi->buffer[p_psi->i_current_position], &p_ts_packet->buffer[i_data_offset], * Error loop
i_data_length ); */
if( p_input->b_error )
{
ErrorThread( p_input );
}
/* Interesting data are now after the ones we copied, since no gap is /* End of thread */
* allowed between 2 sections in a TS packets */ EndThread( p_input );
i_data_offset += i_data_length; 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; * ErrorThread: RunThread() error loop
p_psi->b_running_section = 0; *****************************************************************************
* 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; * EndThread: end the input thread
} *****************************************************************************/
else 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 */ case MPEG1_VIDEO_ES:
p_psi->i_current_position += i_data_length; case MPEG2_VIDEO_ES:
//intf_DbgMsg( "Section not complete, waiting for the end\n" ); 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_NetlistEnd( p_input ); /* clean netlist */
input_NetlistFreeTS( p_input, p_ts_packet ); 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 @@ ...@@ -12,7 +12,7 @@
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or * the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 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, ...@@ -194,7 +194,7 @@ vout_thread_t * vout_CreateThread ( char *psz_display, int i_root_window,
} }
p_vout->i_pictures = 0; p_vout->i_pictures = 0;
/* Initialize synchronization informations */ /* Initialize synchronization information */
p_vout->i_synchro_level = VOUT_SYNCHRO_LEVEL_START; p_vout->i_synchro_level = VOUT_SYNCHRO_LEVEL_START;
/* Create and initialize system-dependant method - this function issues its /* 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 ) ...@@ -347,7 +347,7 @@ void vout_DisplaySubPicture( vout_thread_t *p_vout, subpicture_t *p_subpic )
p_subpic->i_status = READY_SUBPICTURE; p_subpic->i_status = READY_SUBPICTURE;
#ifdef DEBUG_VIDEO #ifdef DEBUG_VIDEO
/* Send subpicture informations */ /* Send subpicture information */
intf_DbgMsg("subpicture %p: type=%d, begin date=%s, end date=%s\n", intf_DbgMsg("subpicture %p: type=%d, begin date=%s, end date=%s\n",
p_subpic, p_subpic->i_type, p_subpic, p_subpic->i_type,
mstrtime( psz_begin_date, p_subpic->begin_date ), mstrtime( psz_begin_date, p_subpic->begin_date ),
...@@ -356,7 +356,7 @@ void vout_DisplaySubPicture( vout_thread_t *p_vout, subpicture_t *p_subpic ) ...@@ -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. * This function create a reserved subpicture in the video output heap.
* A null pointer is returned if the function fails. This method provides an * 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, ...@@ -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 ) ) 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 */ * found, but a destroyed subpicture is still avalaible */
free( p_destroyed_subpic->p_data ); free( p_destroyed_subpic->p_data );
p_free_subpic = p_destroyed_subpic; p_free_subpic = p_destroyed_subpic;
...@@ -443,7 +443,8 @@ subpicture_t *vout_CreateSubPicture( vout_thread_t *p_vout, int i_type, ...@@ -443,7 +443,8 @@ subpicture_t *vout_CreateSubPicture( vout_thread_t *p_vout, int i_type,
} }
if( p_free_subpic->p_data != NULL ) 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_type = i_type;
p_free_subpic->i_status = RESERVED_SUBPICTURE; p_free_subpic->i_status = RESERVED_SUBPICTURE;
p_free_subpic->i_size = i_size; p_free_subpic->i_size = i_size;
...@@ -460,7 +461,7 @@ subpicture_t *vout_CreateSubPicture( vout_thread_t *p_vout, int i_type, ...@@ -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_type = EMPTY_SUBPICTURE;
p_free_subpic->i_status = FREE_SUBPICTURE; p_free_subpic->i_status = FREE_SUBPICTURE;
p_free_subpic = NULL; p_free_subpic = NULL;
intf_ErrMsg("warning: %s\n", strerror( ENOMEM ) ); intf_ErrMsg("spu warning: %s\n", strerror( ENOMEM ) );
} }
#ifdef DEBUG_VIDEO #ifdef DEBUG_VIDEO
...@@ -471,7 +472,7 @@ subpicture_t *vout_CreateSubPicture( vout_thread_t *p_vout, int i_type, ...@@ -471,7 +472,7 @@ subpicture_t *vout_CreateSubPicture( vout_thread_t *p_vout, int i_type,
} }
/* No free or destroyed subpicture could be found */ /* 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 ); vlc_mutex_unlock( &p_vout->subpicture_lock );
return( NULL ); return( NULL );
} }
...@@ -677,7 +678,7 @@ picture_t *vout_CreatePicture( vout_thread_t *p_vout, int i_type, ...@@ -677,7 +678,7 @@ picture_t *vout_CreatePicture( vout_thread_t *p_vout, int i_type,
if( p_free_picture->p_data != NULL ) 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_type = i_type;
p_free_picture->i_status = RESERVED_PICTURE; p_free_picture->i_status = RESERVED_PICTURE;
p_free_picture->i_matrix_coefficients = 1; p_free_picture->i_matrix_coefficients = 1;
...@@ -698,7 +699,7 @@ picture_t *vout_CreatePicture( vout_thread_t *p_vout, int i_type, ...@@ -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_type = EMPTY_PICTURE;
p_free_picture->i_status = FREE_PICTURE; p_free_picture->i_status = FREE_PICTURE;
p_free_picture = NULL; p_free_picture = NULL;
intf_ErrMsg("warning: %s\n", strerror( ENOMEM ) ); intf_ErrMsg("vout warning: %s\n", strerror( ENOMEM ) );
} }
#ifdef DEBUG_VIDEO #ifdef DEBUG_VIDEO
...@@ -709,7 +710,7 @@ picture_t *vout_CreatePicture( vout_thread_t *p_vout, int i_type, ...@@ -709,7 +710,7 @@ picture_t *vout_CreatePicture( vout_thread_t *p_vout, int i_type,
} }
/* No free or destroyed picture could be found */ /* 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 ); vlc_mutex_unlock( &p_vout->picture_lock );
return( NULL ); return( NULL );
} }
...@@ -1075,7 +1076,7 @@ last_display_date = display_date; ...@@ -1075,7 +1076,7 @@ last_display_date = display_date;
/* Set picture dimensions and clear buffer */ /* Set picture dimensions and clear buffer */
SetBufferPicture( p_vout, p_pic ); SetBufferPicture( p_vout, p_pic );
/* Render picture and informations */ /* Render picture and information */
RenderPicture( p_vout, p_pic ); RenderPicture( p_vout, p_pic );
if( p_vout->b_info ) if( p_vout->b_info )
{ {
...@@ -1279,7 +1280,7 @@ static void DestroyThread( vout_thread_t *p_vout, int i_status ) ...@@ -1279,7 +1280,7 @@ static void DestroyThread( vout_thread_t *p_vout, int i_status )
* Print: print simple text on a picture * Print: print simple text on a picture
***************************************************************************** *****************************************************************************
* This function will print a simple text on the picture. It is designed to * 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 ) 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 ...@@ -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 ) if( i_area == p_buffer->i_areas )
{ {
/* New area is below all existing ones: just add it at the end of the /* 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 ) if( i_area < VOUT_MAX_AREAS )
{ {
p_buffer->pi_area_begin[i_area] = i_y; 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 ...@@ -1368,7 +1369,7 @@ static void SetBufferArea( vout_thread_t *p_vout, int i_x, int i_y, int i_w, int
else else
{ {
#ifdef DEBUG_VIDEO #ifdef DEBUG_VIDEO
intf_DbgMsg("areas overflow\n"); intf_DbgMsg("area overflow\n");
#endif #endif
p_buffer->pi_area_end[VOUT_MAX_AREAS - 1] = i_h; 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 ) ...@@ -1605,10 +1606,10 @@ static void SetBufferPicture( vout_thread_t *p_vout, picture_t *p_pic )
/***************************************************************************** /*****************************************************************************
* RenderPicture: render a picture * RenderPicture: render a picture
***************************************************************************** *****************************************************************************
* This function convert a picture from a video heap to a pixel-encoded image * This function converts 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 * and copies it to the current rendering buffer. No lock is required, since
* rendered picture has been determined as existant, and will only be destroyed * the * rendered picture has been determined as existant, and will only be
* by the vout thread later. * destroyed by the vout thread later.
*****************************************************************************/ *****************************************************************************/
static void RenderPicture( vout_thread_t *p_vout, picture_t *p_pic ) 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 ) ...@@ -1619,7 +1620,7 @@ static void RenderPicture( vout_thread_t *p_vout, picture_t *p_pic )
vout_buffer_t * p_buffer; /* rendering buffer */ vout_buffer_t * p_buffer; /* rendering buffer */
byte_t * p_pic_data; /* convertion destination */ 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_buffer = &p_vout->p_buffer[ p_vout->i_buffer_index ];
p_pic_data = p_buffer->p_data + p_pic_data = p_buffer->p_data +
p_buffer->i_pic_x * p_vout->i_bytes_per_pixel + 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 ) ...@@ -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 * This function will print information such as fps and other picture
* dependant informations. * dependant information.
*****************************************************************************/ *****************************************************************************/
static void RenderPictureInfo( vout_thread_t *p_vout, picture_t *p_pic ) static void RenderPictureInfo( vout_thread_t *p_vout, picture_t *p_pic )
{ {
...@@ -1768,10 +1769,10 @@ static int RenderIdle( vout_thread_t *p_vout ) ...@@ -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 * This function renders information which do not depend on the current
* rendered. * picture rendered.
*****************************************************************************/ *****************************************************************************/
static void RenderInfo( vout_thread_t *p_vout ) static void RenderInfo( vout_thread_t *p_vout )
{ {
...@@ -1809,7 +1810,7 @@ static void RenderInfo( vout_thread_t *p_vout ) ...@@ -1809,7 +1810,7 @@ static void RenderInfo( vout_thread_t *p_vout )
/***************************************************************************** /*****************************************************************************
* RenderSubPicture: render a subpicture * 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 ) 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 ) ...@@ -1881,7 +1882,7 @@ static void RenderSubPicture( vout_thread_t *p_vout, subpicture_t *p_subpic )
/***************************************************************************** /*****************************************************************************
* RenderInterface: render the interface * 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 ) static void RenderInterface( vout_thread_t *p_vout )
{ {
......
...@@ -22,11 +22,11 @@ ...@@ -22,11 +22,11 @@
/* Text styles - these are primary text styles, used by the vout_Print function. /* Text styles - these are primary text styles, used by the vout_Print function.
* They may be ignored or interpreted by higher level functions */ * They may be ignored or interpreted by higher level functions */
#define WIDE_TEXT 1 /* interspacing is doubled */ #define WIDE_TEXT 1<<0 /* interspacing is doubled */
#define ITALIC_TEXT 2 /* italic */ #define ITALIC_TEXT 1<<1 /* italic */
#define OPAQUE_TEXT 4 /* text with background */ #define OPAQUE_TEXT 1<<2 /* text with background */
#define OUTLINED_TEXT 8 /* border around letters */ #define OUTLINED_TEXT 1<<3 /* border around letters */
#define VOID_TEXT 16 /* no foreground */ #define VOID_TEXT 1<<4 /* no foreground */
/***************************************************************************** /*****************************************************************************
......
...@@ -46,10 +46,10 @@ ...@@ -46,10 +46,10 @@
#include "main.h" #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 * 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 ) int vout_InitYUV( vout_thread_t *p_vout )
{ {
...@@ -76,7 +76,7 @@ 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 * This function will initialize the tables allocated by vout_InitYUV and
* set functions pointers. * set functions pointers.
...@@ -88,7 +88,7 @@ int vout_ResetYUV( vout_thread_t *p_vout ) ...@@ -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 * Free memory allocated by vout_InitYUV
*****************************************************************************/ *****************************************************************************/
......
...@@ -159,7 +159,7 @@ void vpar_SynchroUpdateStructures( vpar_thread_t * p_vpar, ...@@ -159,7 +159,7 @@ void vpar_SynchroUpdateStructures( vpar_thread_t * p_vpar,
#if 1 #if 1
if( p_vpar->synchro.b_all_I ) if( p_vpar->synchro.b_all_I )
intf_ErrMsg( "I: 1/1 " ); intf_ErrMsg( " I: 1/1 " );
if( p_vpar->synchro.b_all_P ) if( p_vpar->synchro.b_all_P )
intf_ErrMsg( "P: %i/%i ", p_vpar->synchro.i_P_seen, intf_ErrMsg( "P: %i/%i ", p_vpar->synchro.i_P_seen,
p_vpar->synchro.i_P_seen ); p_vpar->synchro.i_P_seen );
...@@ -172,7 +172,7 @@ void vpar_SynchroUpdateStructures( vpar_thread_t * p_vpar, ...@@ -172,7 +172,7 @@ void vpar_SynchroUpdateStructures( vpar_thread_t * p_vpar,
else if( p_vpar->synchro.displayable_b > 0 ) else if( p_vpar->synchro.displayable_b > 0 )
intf_ErrMsg( "B: %.2f/%i", p_vpar->synchro.displayable_b, intf_ErrMsg( "B: %.2f/%i", p_vpar->synchro.displayable_b,
p_vpar->synchro.i_B_seen ); p_vpar->synchro.i_B_seen );
intf_ErrMsg( "\n" ); intf_ErrMsg( " " );
#endif #endif
p_vpar->synchro.i_P_seen = 0; p_vpar->synchro.i_P_seen = 0;
p_vpar->synchro.i_B_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