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