1 /*******************************************************************************
2 * video_output.c : video output thread
4 *******************************************************************************
5 * This module describes the programming interface for video output threads.
6 * It includes functions allowing to open a new thread, send pictures to a
7 * thread, and destroy a previously oppenned video output thread.
8 *******************************************************************************/
10 /*******************************************************************************
12 *******************************************************************************/
20 #include <X11/Xlib.h> /* for video_sys.h in X11 mode */
26 #include "vlc_thread.h"
28 #include "video_output.h"
29 #include "video_sys.h"
33 /*******************************************************************************
35 *******************************************************************************/
37 /* CLIP_BYTE: return value if between 0 and 255, else return nearest boundary
38 * (0 or 255), used to build translations tables */
39 #define CLIP_BYTE( i_val ) ( (i_val < 0) ? 0 : ((i_val > 255) ? 255 : i_val) )
41 /* YUV_GRAYSCALE: parametric macro for YUV grayscale transformation.
42 * Due to the high performance need of this loop, all possible conditions
43 * evaluations are made outside the transformation loop. However, the code does
44 * not change much for two different loops. This macro allows to change slightly
45 * the content of the loop without having to copy and paste code. It is used in
46 * RenderYUVPicture function. */
47 #define YUV_GRAYSCALE( TRANS_GRAY, P_PIC ) \
49 for (i_pic_y=0; i_pic_y < p_pic->i_height ; i_pic_y++) \
51 for (i_pic_x=0; i_pic_x< p_pic->i_width; i_pic_x+=16) \
53 /* Convert 16 pixels (width is always multiple of 16 */ \
54 *P_PIC++ = TRANS_GRAY[ *p_y++ ]; \
55 *P_PIC++ = TRANS_GRAY[ *p_y++ ]; \
56 *P_PIC++ = TRANS_GRAY[ *p_y++ ]; \
57 *P_PIC++ = TRANS_GRAY[ *p_y++ ]; \
58 *P_PIC++ = TRANS_GRAY[ *p_y++ ]; \
59 *P_PIC++ = TRANS_GRAY[ *p_y++ ]; \
60 *P_PIC++ = TRANS_GRAY[ *p_y++ ]; \
61 *P_PIC++ = TRANS_GRAY[ *p_y++ ]; \
62 *P_PIC++ = TRANS_GRAY[ *p_y++ ]; \
63 *P_PIC++ = TRANS_GRAY[ *p_y++ ]; \
64 *P_PIC++ = TRANS_GRAY[ *p_y++ ]; \
65 *P_PIC++ = TRANS_GRAY[ *p_y++ ]; \
66 *P_PIC++ = TRANS_GRAY[ *p_y++ ]; \
67 *P_PIC++ = TRANS_GRAY[ *p_y++ ]; \
68 *P_PIC++ = TRANS_GRAY[ *p_y++ ]; \
69 *P_PIC++ = TRANS_GRAY[ *p_y++ ]; \
71 /* Skip until beginning of next line */ \
72 P_PIC += i_eol_offset; \
75 /* YUV_TRANSFORM: parametric macro for YUV transformation.
76 * Due to the high performance need of this loop, all possible conditions
77 * evaluations are made outside the transformation loop. However, the code does
78 * not change much for two different loops. This macro allows to change slightly
79 * the content of the loop without having to copy and paste code. It is used in
80 * RenderYUVPicture function. */
81 #define YUV_TRANSFORM( CHROMA, TRANS_RED, TRANS_GREEN, TRANS_BLUE, P_PIC ) \
83 for (i_pic_y=0; i_pic_y < p_pic->i_height ; i_pic_y++) \
85 for (i_pic_x=0; i_pic_x< p_pic->i_width; i_pic_x+=2 ) \
87 /* First sample (complete) */ \
88 i_y = 76309 * *p_y++ - 1188177; \
92 TRANS_RED [(i_y+i_crv*i_v) >>16] | \
93 TRANS_GREEN [(i_y-i_cgu*i_u-i_cgv*i_v) >>16] | \
94 TRANS_BLUE [(i_y+i_cbu*i_u) >>16]; \
95 i_y = 76309 * *p_y++ - 1188177; \
96 /* Second sample (partial) */ \
100 i_v = *p_v++ - 128; \
103 TRANS_RED [(i_y+i_crv*i_v) >>16] | \
104 TRANS_GREEN [(i_y-i_cgu*i_u-i_cgv*i_v) >>16] | \
105 TRANS_BLUE [(i_y+i_cbu*i_u) >>16]; \
107 if( (CHROMA == 420) && !(i_pic_y & 0x1) ) \
109 p_u -= i_chroma_width; \
110 p_v -= i_chroma_width; \
112 /* Skip until beginning of next line */ \
113 P_PIC += i_eol_offset; \
116 /*******************************************************************************
118 *******************************************************************************/
120 /* RGB/YUV inversion matrix (ISO/IEC 13818-2 section 6.3.6, table 6.9) */
121 const int MATRIX_COEFFICIENTS_TABLE[8][4] =
123 {117504, 138453, 13954, 34903}, /* no sequence_display_extension */
124 {117504, 138453, 13954, 34903}, /* ITU-R Rec. 709 (1990) */
125 {104597, 132201, 25675, 53279}, /* unspecified */
126 {104597, 132201, 25675, 53279}, /* reserved */
127 {104448, 132798, 24759, 53109}, /* FCC */
128 {104597, 132201, 25675, 53279}, /* ITU-R Rec. 624-4 System B, G */
129 {104597, 132201, 25675, 53279}, /* SMPTE 170M */
130 {117579, 136230, 16907, 35559} /* SMPTE 240M (1987) */
133 /*******************************************************************************
134 * External prototypes
135 *******************************************************************************/
137 /* YUV transformations for MMX - in video_yuv_mmx.S
138 * p_y, p_u, p_v: Y U and V planes
139 * i_width, i_height: frames dimensions (pixels)
140 * i_ypitch, i_vpitch: Y and V lines sizes (bytes)
141 * i_aspect: vertical aspect factor
143 * i_dci_offset: ?? x offset for left image border
144 * i_offset_to_line_0: ?? x offset for left image border
145 * i_pitch: RGB line size (bytes)
146 * i_colortype: 0 for 565, 1 for 555 */
147 void vout_YUV420_16_MMX( u8* p_y, u8* p_u, u8 *p_v,
148 unsigned int i_width, unsigned int i_height,
149 unsigned int i_ypitch, unsigned int i_vpitch,
150 unsigned int i_aspect, u8 *p_pic,
151 u32 i_dci_offset, u32 i_offset_to_line_0,
152 int CCOPitch, int i_colortype );
155 /* Optimized YUV functions: translations and tables building - in video_yuv_c.c
156 * ??? looks efficient, but does not work well - ask walken */
157 void yuvToRgb16 ( unsigned char * Y,
158 unsigned char * U, unsigned char * V,
159 short * dest, short table[1935], int width);
160 int rgbTable16 (short table [1935],
161 int redMask, int greenMask, int blueMask,
162 unsigned char gamma[256]);
165 /*******************************************************************************
167 *******************************************************************************/
168 static int InitThread ( vout_thread_t *p_vout );
169 static void RunThread ( vout_thread_t *p_vout );
170 static void ErrorThread ( vout_thread_t *p_vout );
171 static void EndThread ( vout_thread_t *p_vout );
172 static void BuildTables ( vout_thread_t *p_vout );
173 static void RenderPicture ( vout_thread_t *p_vout, picture_t *p_pic );
174 static void RenderYUVGrayPicture ( vout_thread_t *p_vout, picture_t *p_pic );
175 static void RenderYUV16Picture ( vout_thread_t *p_vout, picture_t *p_pic );
176 static void RenderYUV32Picture ( vout_thread_t *p_vout, picture_t *p_pic );
177 static void RenderPictureInfo ( vout_thread_t *p_vout, picture_t *p_pic );
178 static int RenderIdle ( vout_thread_t *p_vout, int i_level );
180 /*******************************************************************************
181 * vout_CreateThread: creates a new video output thread
182 *******************************************************************************
183 * This function creates a new video output thread, and returns a pointer
184 * to its description. On error, it returns NULL.
185 * If pi_status is NULL, then the function will block until the thread is ready.
186 * If not, it will be updated using one of the THREAD_* constants.
187 *******************************************************************************/
188 vout_thread_t * vout_CreateThread (
190 char *psz_display, Window root_window,
192 int i_width, int i_height, int *pi_status
195 vout_thread_t * p_vout; /* thread descriptor */
196 int i_status; /* thread status */
198 /* Allocate descriptor */
199 p_vout = (vout_thread_t *) malloc( sizeof(vout_thread_t) );
202 intf_ErrMsg("error: %s\n", strerror(ENOMEM));
206 /* Initialize some fields used by the system-dependant method - these fields will
207 * probably be modified by the method */
213 p_vout->b_grayscale = main_GetIntVariable( VOUT_GRAYSCALE_VAR,
214 VOUT_GRAYSCALE_DEFAULT );
215 p_vout->i_width = i_width;
216 p_vout->i_height = i_height;
217 p_vout->i_bytes_per_line = i_width * 2;
218 p_vout->i_screen_depth = 15;
219 p_vout->i_bytes_per_pixel = 2;
220 p_vout->f_x_ratio = 1;
221 p_vout->f_y_ratio = 1;
222 p_vout->f_gamma = VOUT_GAMMA;
223 intf_DbgMsg("wished configuration: %dx%d,%d (%d bytes/pixel, %d bytes/line), ratio %.2f:%.2f, gray=%d\n",
224 p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth,
225 p_vout->i_bytes_per_pixel, p_vout->i_bytes_per_line,
226 p_vout->f_x_ratio, p_vout->f_y_ratio, p_vout->b_grayscale );
228 /* Create and initialize system-dependant method - this function issues its
229 * own error messages */
230 if( vout_SysCreate( p_vout
231 #if defined(VIDEO_X11)
232 , psz_display, root_window
239 intf_DbgMsg("actual configuration: %dx%d,%d (%d bytes/pixel, %d bytes/line), ratio %.2f:%.2f, gray=%d\n",
240 p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth,
241 p_vout->i_bytes_per_pixel, p_vout->i_bytes_per_line,
242 p_vout->f_x_ratio, p_vout->f_y_ratio, p_vout->b_grayscale );
244 /* Terminate the initialization */
247 p_vout->b_active = 0;
248 p_vout->pi_status = (pi_status != NULL) ? pi_status : &i_status;
249 *p_vout->pi_status = THREAD_CREATE;
252 p_vout->c_idle_loops = 0;
253 p_vout->c_fps_samples = 0;
255 p_vout->b_gamma_change = 0;
256 p_vout->i_new_width = p_vout->i_width;
257 p_vout->i_new_height = p_vout->i_height;
259 /* Create thread and set locks */
260 vlc_mutex_init( &p_vout->lock );
261 if( vlc_thread_create( &p_vout->thread_id, "video output",
262 (void *) RunThread, (void *) p_vout) )
264 intf_ErrMsg("error: %s\n", strerror(ENOMEM));
265 vout_SysDestroy( p_vout );
270 intf_Msg("Video: display initialized (%dx%d, %d bpp)\n",
271 p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth );
273 /* If status is NULL, wait until the thread is created */
274 if( pi_status == NULL )
278 msleep( THREAD_SLEEP );
279 }while( (i_status != THREAD_READY) && (i_status != THREAD_ERROR)
280 && (i_status != THREAD_FATAL) );
281 if( i_status != THREAD_READY )
289 /*******************************************************************************
290 * vout_DestroyThread: destroys a previously created thread
291 *******************************************************************************
292 * Destroy a terminated thread.
293 * The function will request a destruction of the specified thread. If pi_error
294 * is NULL, it will return once the thread is destroyed. Else, it will be
295 * update using one of the THREAD_* constants.
296 *******************************************************************************/
297 void vout_DestroyThread( vout_thread_t *p_vout, int *pi_status )
299 int i_status; /* thread status */
302 p_vout->pi_status = (pi_status != NULL) ? pi_status : &i_status;
303 *p_vout->pi_status = THREAD_DESTROY;
305 /* Request thread destruction */
308 /* If status is NULL, wait until thread has been destroyed */
309 if( pi_status == NULL )
313 msleep( THREAD_SLEEP );
314 }while( (i_status != THREAD_OVER) && (i_status != THREAD_ERROR)
315 && (i_status != THREAD_FATAL) );
319 /*******************************************************************************
320 * vout_DisplayPicture: display a picture
321 *******************************************************************************
322 * Remove the reservation flag of a picture, which will cause it to be ready for
323 * display. The picture does not need to be locked, since it is ignored by
324 * the output thread if is reserved.
325 *******************************************************************************/
326 void vout_DisplayPicture( vout_thread_t *p_vout, picture_t *p_pic )
329 char psz_date[MSTRTIME_MAX_SIZE]; /* buffer for date string */
333 /* Check if picture status is valid */
334 if( p_pic->i_status != RESERVED_PICTURE )
336 intf_DbgMsg("error: picture %d has invalid status %d\n", p_pic, p_pic->i_status );
340 /* Remove reservation flag */
341 p_pic->i_status = READY_PICTURE;
344 /* Send picture informations */
345 intf_DbgMsg("picture %p: type=%d, %dx%d, date=%s\n", p_pic, p_pic->i_type,
346 p_pic->i_width,p_pic->i_height, mstrtime( psz_date, p_pic->date ) );
350 /*******************************************************************************
351 * vout_CreatePicture: allocate a picture in the video output heap.
352 *******************************************************************************
353 * This function create a reserved image in the video output heap.
354 * A null pointer is returned if the function fails. This method provides an
355 * already allocated zone of memory in the picture data fields. It needs locking
356 * since several pictures can be created by several producers threads.
357 *******************************************************************************/
358 picture_t *vout_CreatePicture( vout_thread_t *p_vout, int i_type,
359 int i_width, int i_height, int i_bytes_per_line )
361 int i_picture; /* picture index */
362 picture_t * p_free_picture = NULL; /* first free picture */
363 picture_t * p_destroyed_picture = NULL; /* first destroyed picture */
366 vlc_mutex_lock( &p_vout->lock );
369 * Look for an empty place
372 i_picture < VOUT_MAX_PICTURES;
375 if( p_vout->p_picture[i_picture].i_status == DESTROYED_PICTURE )
377 /* Picture is marked for destruction, but is still allocated */
378 if( (p_vout->p_picture[i_picture].i_type == i_type) &&
379 (p_vout->p_picture[i_picture].i_height == i_height) &&
380 (p_vout->p_picture[i_picture].i_bytes_per_line == i_bytes_per_line) )
382 /* Memory size do match : memory will not be reallocated, and function
383 * can end immediately - this is the best possible case, since no
384 * memory allocation needs to be done */
385 p_vout->p_picture[i_picture].i_width = i_width;
386 p_vout->p_picture[i_picture].i_status = RESERVED_PICTURE;
388 intf_DbgMsg("picture %p (in destroyed picture slot)\n",
389 &p_vout->p_picture[i_picture] );
391 vlc_mutex_unlock( &p_vout->lock );
392 return( &p_vout->p_picture[i_picture] );
394 else if( p_destroyed_picture == NULL )
396 /* Memory size do not match, but picture index will be kept in
397 * case no other place are left */
398 p_destroyed_picture = &p_vout->p_picture[i_picture];
401 else if( (p_free_picture == NULL) &&
402 (p_vout->p_picture[i_picture].i_status == FREE_PICTURE ))
404 /* Picture is empty and ready for allocation */
405 p_free_picture = &p_vout->p_picture[i_picture];
409 /* If no free picture is available, use a destroyed picture */
410 if( (p_free_picture == NULL) && (p_destroyed_picture != NULL ) )
412 /* No free picture or matching destroyed picture has been found, but
413 * a destroyed picture is still avalaible */
414 free( p_destroyed_picture->p_data );
415 p_free_picture = p_destroyed_picture;
421 if( p_free_picture != NULL )
423 /* Allocate memory */
426 case YUV_420_PICTURE: /* YUV 420: 1,1/4,1/4 samples per pixel */
427 p_free_picture->p_data = malloc( i_height * i_bytes_per_line * 3 / 2 );
428 p_free_picture->p_y = (yuv_data_t *) p_free_picture->p_data;
429 p_free_picture->p_u = (yuv_data_t *)(p_free_picture->p_data + i_height * i_bytes_per_line);
430 p_free_picture->p_v = (yuv_data_t *)(p_free_picture->p_data + i_height * i_bytes_per_line * 5 / 4);
432 case YUV_422_PICTURE: /* YUV 422: 1,1/2,1/2 samples per pixel */
433 p_free_picture->p_data = malloc( 2 * i_height * i_bytes_per_line );
434 p_free_picture->p_y = (yuv_data_t *) p_free_picture->p_data;
435 p_free_picture->p_u = (yuv_data_t *)(p_free_picture->p_data + i_height * i_bytes_per_line);
436 p_free_picture->p_v = (yuv_data_t *)(p_free_picture->p_data + i_height * i_bytes_per_line * 3 / 2);
438 case YUV_444_PICTURE: /* YUV 444: 1,1,1 samples per pixel */
439 p_free_picture->p_data = malloc( 3 * i_height * i_bytes_per_line );
440 p_free_picture->p_y = (yuv_data_t *) p_free_picture->p_data;
441 p_free_picture->p_u = (yuv_data_t *)(p_free_picture->p_data + i_height * i_bytes_per_line);
442 p_free_picture->p_v = (yuv_data_t *)(p_free_picture->p_data + i_height * i_bytes_per_line * 2);
446 intf_DbgMsg("error: unknown picture type %d\n", i_type );
447 p_free_picture->p_data = NULL;
452 if( p_free_picture->p_data != NULL )
454 /* Copy picture informations */
455 p_free_picture->i_type = i_type;
456 p_free_picture->i_status = RESERVED_PICTURE;
457 p_free_picture->i_width = i_width;
458 p_free_picture->i_height = i_height;
459 p_free_picture->i_bytes_per_line = i_bytes_per_line;
460 p_free_picture->i_refcount = 0;
461 p_free_picture->i_matrix_coefficients = 1;
465 /* Memory allocation failed : set picture as empty */
466 p_free_picture->i_type = EMPTY_PICTURE;
467 p_free_picture->i_status = FREE_PICTURE;
468 p_free_picture = NULL;
469 intf_ErrMsg("warning: %s\n", strerror( ENOMEM ) );
473 intf_DbgMsg("picture %p (in free picture slot)\n", p_free_picture );
475 vlc_mutex_unlock( &p_vout->lock );
476 return( p_free_picture );
479 // No free or destroyed picture could be found
480 intf_DbgMsg( "warning: heap is full\n" );
481 vlc_mutex_unlock( &p_vout->lock );
485 /*******************************************************************************
486 * vout_DestroyPicture: remove a permanent or reserved picture from the heap
487 *******************************************************************************
488 * This function frees a previously reserved picture or a permanent
489 * picture. It is meant to be used when the construction of a picture aborted.
490 * Note that the picture will be destroyed even if it is linked !
491 * This function does not need locking since reserved pictures are ignored by
493 *******************************************************************************/
494 void vout_DestroyPicture( vout_thread_t *p_vout, picture_t *p_pic )
497 /* Check if picture status is valid */
498 if( p_pic->i_status != RESERVED_PICTURE )
500 intf_DbgMsg("error: picture %d has invalid status %d\n", p_pic, p_pic->i_status );
504 p_pic->i_status = DESTROYED_PICTURE;
507 intf_DbgMsg("picture %p\n", p_pic);
511 /*******************************************************************************
512 * vout_LinkPicture: increment reference counter of a picture
513 *******************************************************************************
514 * This function increment the reference counter of a picture in the video
515 * heap. It needs a lock since several producer threads can access the picture.
516 *******************************************************************************/
517 void vout_LinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
519 vlc_mutex_lock( &p_vout->lock );
521 vlc_mutex_unlock( &p_vout->lock );
524 intf_DbgMsg("picture %p\n", p_pic);
528 /*******************************************************************************
529 * vout_UnlinkPicture: decrement reference counter of a picture
530 *******************************************************************************
531 * This function decrement the reference counter of a picture in the video heap.
532 *******************************************************************************/
533 void vout_UnlinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
535 vlc_mutex_lock( &p_vout->lock );
537 if( (p_pic->i_refcount == 0) && (p_pic->i_status == DISPLAYED_PICTURE) )
539 p_pic->i_status = DESTROYED_PICTURE;
541 vlc_mutex_unlock( &p_vout->lock );
544 intf_DbgMsg("picture %p\n", p_pic);
548 /* following functions are local */
550 /*******************************************************************************
551 * InitThread: initialize video output thread
552 *******************************************************************************
553 * This function is called from RunThread and performs the second step of the
554 * initialization. It returns 0 on success. Note that the thread's flag are not
555 * modified inside this function.
556 *******************************************************************************/
557 static int InitThread( vout_thread_t *p_vout )
559 int i_index; /* generic index */
562 *p_vout->pi_status = THREAD_START;
564 /* Initialize pictures */
565 for( i_index = 0; i_index < VOUT_MAX_PICTURES; i_index++)
567 p_vout->p_picture[i_index].i_type = EMPTY_PICTURE;
568 p_vout->p_picture[i_index].i_status= FREE_PICTURE;
571 /* Initialize output method - this function issues its own error messages */
572 if( vout_SysInit( p_vout ) )
574 *p_vout->pi_status = THREAD_ERROR;
578 /* Allocate translation tables */
579 p_vout->p_trans_base = malloc( ( 4 * 1024 + 1935 ) * p_vout->i_bytes_per_pixel );
580 if( p_vout->p_trans_base == NULL )
582 intf_ErrMsg("error: %s\n", strerror(ENOMEM));
585 p_vout->p_trans_red = p_vout->p_trans_base + 384 *p_vout->i_bytes_per_pixel;
586 p_vout->p_trans_green = p_vout->p_trans_base + ( 1024 + 384)*p_vout->i_bytes_per_pixel;
587 p_vout->p_trans_blue = p_vout->p_trans_base + (2*1024 + 384)*p_vout->i_bytes_per_pixel;
588 p_vout->p_trans_gray = p_vout->p_trans_base + (3*1024 + 384)*p_vout->i_bytes_per_pixel;
589 p_vout->p_trans_optimized = p_vout->p_trans_base + (4*1024 )*p_vout->i_bytes_per_pixel;
591 /* Build translation tables */
592 BuildTables( p_vout );
594 /* Mark thread as running and return */
595 p_vout->b_active = 1;
596 *p_vout->pi_status = THREAD_READY;
597 intf_DbgMsg("thread ready\n");
601 /*******************************************************************************
602 * RunThread: video output thread
603 *******************************************************************************
604 * Video output thread. This function does only returns when the thread is
605 * terminated. It handles the pictures arriving in the video heap and the
606 * display device events.
607 *******************************************************************************/
608 static void RunThread( vout_thread_t *p_vout)
610 int i_picture; /* picture index */
611 int i_err; /* error code */
612 int i_idle_level = 0; /* idle level */
613 mtime_t current_date; /* current date */
614 mtime_t pic_date = 0; /* picture date */
615 mtime_t last_date = 0; /* last picture date */
616 boolean_t b_display; /* display flag */
617 picture_t * p_pic; /* picture pointer */
620 * Initialize thread and free configuration
622 p_vout->b_error = InitThread( p_vout );
623 if( p_vout->b_error )
625 free( p_vout ); /* destroy descriptor */
630 * Main loop - it is not executed if an error occured during
633 while( (!p_vout->b_die) && (!p_vout->b_error) )
636 * Find the picture to display - this operation does not need lock,
637 * since only READY_PICTURES are handled
640 for( i_picture = 0; i_picture < VOUT_MAX_PICTURES; i_picture++ )
642 if( (p_vout->p_picture[i_picture].i_status == READY_PICTURE) &&
644 (p_vout->p_picture[i_picture].date < pic_date) ) )
646 p_pic = &p_vout->p_picture[i_picture];
647 pic_date = p_pic->date;
650 current_date = mdate();
653 * Render picture if any
658 /* Computes FPS rate */
659 p_vout->fps_sample[ p_vout->c_fps_samples++ % VOUT_FPS_SAMPLES ] = pic_date;
661 if( pic_date < current_date )
663 /* Picture is late: it will be destroyed and the thread will sleep and
664 * go to next picture */
665 vlc_mutex_lock( &p_vout->lock );
666 p_pic->i_status = p_pic->i_refcount ? DISPLAYED_PICTURE : DESTROYED_PICTURE;
667 vlc_mutex_unlock( &p_vout->lock );
669 intf_DbgMsg( "warning: late picture %p skipped\n", p_pic );
673 else if( pic_date > current_date + VOUT_DISPLAY_DELAY )
675 /* A picture is ready to be rendered, but its rendering date is
676 * far from the current one so the thread will perform an empty loop
677 * as if no picture were found. The picture state is unchanged */
682 /* Picture has not yet been displayed, and has a valid display
683 * date : render it, then mark it as displayed */
684 if( p_vout->b_active )
686 RenderPicture( p_vout, p_pic );
689 RenderPictureInfo( p_vout, p_pic );
692 vlc_mutex_lock( &p_vout->lock );
693 p_pic->i_status = p_pic->i_refcount ? DISPLAYED_PICTURE : DESTROYED_PICTURE;
694 vlc_mutex_unlock( &p_vout->lock );
699 * Rebuild tables if gamma has changed
701 if( p_vout->b_gamma_change )
703 p_vout->b_gamma_change = 0;
704 BuildTables( p_vout );
708 * Check events, sleep and display picture
710 i_err = vout_SysManage( p_vout );
713 /* A fatal error occured, and the thread must terminate immediately,
714 * without displaying anything - setting b_error to 1 cause the
715 * immediate end of the main while() loop. */
722 /* A picture is ready to be displayed : remove blank screen flag */
723 last_date = pic_date;
727 /* Sleep until its display date */
732 /* If last picture was a long time ago, increase idle level, reset
733 * date and render idle screen */
734 if( !i_err && (current_date - last_date > VOUT_IDLE_DELAY) )
736 last_date = current_date;
737 b_display = p_vout->b_active && RenderIdle( p_vout, i_idle_level++ );
745 /* Update counters */
746 p_vout->c_idle_loops++;
749 /* Sleep to wait for new pictures */
750 msleep( VOUT_IDLE_SLEEP );
753 /* On awakening, send immediately picture to display */
754 if( b_display && p_vout->b_active )
756 vout_SysDisplay( p_vout );
761 /* Update counters */
769 if( p_vout->b_error )
771 ErrorThread( p_vout );
776 intf_DbgMsg( "thread end\n" );
779 /*******************************************************************************
780 * ErrorThread: RunThread() error loop
781 *******************************************************************************
782 * This function is called when an error occured during thread main's loop. The
783 * thread can still receive feed, but must be ready to terminate as soon as
785 *******************************************************************************/
786 static void ErrorThread( vout_thread_t *p_vout )
788 /* Wait until a `die' order */
789 while( !p_vout->b_die )
792 msleep( VOUT_IDLE_SLEEP );
796 /*******************************************************************************
797 * EndThread: thread destruction
798 *******************************************************************************
799 * This function is called when the thread ends after a sucessfull
801 *******************************************************************************/
802 static void EndThread( vout_thread_t *p_vout )
804 int * pi_status; /* thread status */
808 pi_status = p_vout->pi_status;
809 *pi_status = THREAD_END;
811 /* Destroy all remaining pictures */
812 for( i_picture = 0; i_picture < VOUT_MAX_PICTURES; i_picture++ )
814 if( p_vout->p_picture[i_picture].i_status != FREE_PICTURE )
816 free( p_vout->p_picture[i_picture].p_data );
820 /* Destroy translation tables */
821 free( p_vout->p_trans_base );
823 /* Destroy thread structures allocated by InitThread */
824 vout_SysEnd( p_vout );
825 vout_SysDestroy( p_vout );
829 *pi_status = THREAD_OVER;
832 /*******************************************************************************
833 * BuildTables: build YUV translation tables
834 *******************************************************************************
835 * This function will build translations tables according to pixel width and
837 *******************************************************************************/
838 static void BuildTables( vout_thread_t *p_vout )
840 u16 * p_trans16_red = (u16 *) p_vout->p_trans_red;
841 u16 * p_trans16_green = (u16 *) p_vout->p_trans_green;
842 u16 * p_trans16_blue = (u16 *) p_vout->p_trans_blue;
843 u16 * p_trans16_gray = (u16 *) p_vout->p_trans_gray;
844 u32 * p_trans32_red = (u32 *) p_vout->p_trans_red;
845 u32 * p_trans32_green = (u32 *) p_vout->p_trans_green;
846 u32 * p_trans32_blue = (u32 *) p_vout->p_trans_blue;
847 u32 * p_trans32_gray = (u32 *) p_vout->p_trans_gray;
848 u8 i_gamma[256]; /* gamma table */
849 int i_index; /* index in tables */
851 /* Build gamma table */
852 for( i_index = 0; i_index < 256; i_index++ )
854 i_gamma[i_index] = 255. * pow( (double)i_index / 255., p_vout->f_gamma );
857 /* Build red, green, blue and gray tables */
858 switch( p_vout->i_screen_depth )
861 for( i_index = -384; i_index < 640; i_index++)
863 p_trans16_red[i_index] = (i_gamma[CLIP_BYTE( i_index )] & 0xf8)<<7;
864 p_trans16_green[i_index] = (i_gamma[CLIP_BYTE( i_index )] & 0xf8)<<2;
865 p_trans16_blue[i_index] = i_gamma[CLIP_BYTE( i_index )] >> 3;
866 p_trans16_gray[i_index] = p_trans16_red[i_index] |
867 p_trans16_green[i_index] | p_trans16_blue[i_index];
871 for( i_index = -384; i_index < 640; i_index++)
873 p_trans16_red[i_index] = (i_gamma[CLIP_BYTE( i_index )] & 0xf8)<<8;
874 p_trans16_green[i_index] = (i_gamma[CLIP_BYTE( i_index )] & 0xfc)<<3;
875 p_trans16_blue[i_index] = i_gamma[CLIP_BYTE( i_index )] >> 3;
876 p_trans16_gray[i_index] = p_trans16_red[i_index] |
877 p_trans16_green[i_index] | p_trans16_blue[i_index];
881 for( i_index = -384; i_index < 640; i_index++)
883 p_trans32_red[i_index] = i_gamma[CLIP_BYTE( i_index )] <<16;
884 p_trans32_green[i_index] = i_gamma[CLIP_BYTE( i_index )] <<8;
885 p_trans32_blue[i_index] = i_gamma[CLIP_BYTE( i_index )] ;
886 p_trans32_gray[i_index] = p_trans32_red[i_index] |
887 p_trans32_green[i_index] | p_trans32_blue[i_index];
892 intf_DbgMsg("error: invalid screen depth %d\n", p_vout->i_screen_depth );
897 /* Build red, green and blue tables for optimized transformation */
899 switch( p_vout->i_screen_depth )
902 rgbTable16( (short *) p_vout->p_trans_optimized, 0xf800, 0x07e0, 0x01f, i_gamma );
907 /*******************************************************************************
908 * RenderPicture: render a picture
909 *******************************************************************************
910 * This function convert a picture from a video heap to a pixel-encoded image
911 * and copy it to the current rendering buffer. No lock is required, since the
912 * rendered picture has been determined as existant, and will only be destroyed
913 * by the vout thread later.
914 * ???? 24 and 32 bpp should probably be separated
915 *******************************************************************************/
916 static void RenderPicture( vout_thread_t *p_vout, picture_t *p_pic )
919 /* Send picture informations */
920 intf_DbgMsg("picture %p\n", p_pic );
922 /* Store rendering start date */
923 p_vout->picture_render_time = mdate();
926 /* Change aspect ratio or resize frame to fit frame */
927 if( (p_pic->i_width > p_vout->i_width) || (p_pic->i_height > p_vout->i_height) )
930 /* X11: window can be resized, so resize it - the picture won't be
931 * rendered since any alteration of the window size means recreating the
933 p_vout->i_new_width = p_pic->i_width;
934 p_vout->i_new_height = p_pic->i_height;
937 /* Other drivers: the video output thread can't change its size, so
938 * we need to change the aspect ratio */
943 /* Choose appropriate rendering function */
944 switch( p_pic->i_type )
946 case YUV_420_PICTURE: /* YUV picture: YUV transformation */
947 case YUV_422_PICTURE:
948 case YUV_444_PICTURE:
949 if( p_vout->b_grayscale ) /* grayscale */
951 RenderYUVGrayPicture( p_vout, p_pic );
953 else if( p_vout->i_bytes_per_pixel == 2 ) /* color 15 or 16 bpp */
955 RenderYUV16Picture( p_vout, p_pic );
957 else if( p_vout->i_bytes_per_pixel == 4 ) /* color 32 bpp */
959 RenderYUV32Picture( p_vout, p_pic );
964 intf_DbgMsg("error: unknown picture type %d\n", p_pic->i_type );
970 /* Computes rendering time */
971 p_vout->picture_render_time = mdate() - p_vout->picture_render_time;
975 /*******************************************************************************
976 * RenderYUVGrayPicture: render YUV picture in grayscale
977 *******************************************************************************
978 * Performs the YUV convertion. The picture sent to this function should only
979 * have YUV_420, YUV_422 or YUV_444 types.
980 *******************************************************************************/
981 static void RenderYUVGrayPicture( vout_thread_t *p_vout, picture_t *p_pic )
983 int i_pic_x, i_pic_y; /* x,y coordinates in picture */
984 int i_width, i_height; /* picture size */
985 int i_eol_offset; /* pixels from end of line to next line */
986 yuv_data_t *p_y; /* Y data base adress */
987 u16 * p_pic16; /* destination picture, 15 or 16 bpp */
988 u32 * p_pic32; /* destination picture, 32 bpp */
989 u16 * p_trans16_gray; /* transformation table, 15 or 16 bpp */
990 u32 * p_trans32_gray; /* transformation table, 32 bpp */
992 /* Set the base pointers and transformation parameters */
994 i_width = p_pic->i_width;
995 i_height = p_pic->i_height;
996 i_eol_offset = p_vout->i_bytes_per_line / p_vout->i_bytes_per_pixel - i_width;
998 /* Get base adress for destination image and translation tables, then
1000 switch( p_vout->i_screen_depth )
1004 p_trans16_gray = (u16 *) p_vout->p_trans_gray;
1005 p_pic16 = (u16 *) vout_SysGetPicture( p_vout );
1006 YUV_GRAYSCALE( p_trans16_gray, p_pic16 );
1009 p_trans32_gray = (u32 *) p_vout->p_trans_gray;
1010 p_pic32 = (u32 *) vout_SysGetPicture( p_vout );
1011 YUV_GRAYSCALE( p_trans32_gray, p_pic32 );
1015 intf_DbgMsg("error: invalid screen depth %d\n", p_vout->i_screen_depth );
1022 /*******************************************************************************
1023 * RenderYUV16Picture: render a 15 or 16 bpp YUV picture
1024 *******************************************************************************
1025 * Performs the YUV convertion. The picture sent to this function should only
1026 * have YUV_420, YUV_422 or YUV_444 types.
1027 *******************************************************************************/
1028 static void RenderYUV16Picture( vout_thread_t *p_vout, picture_t *p_pic )
1030 int i_crv, i_cbu, i_cgu, i_cgv; /* transformation coefficients */
1031 int i_pic_x, i_pic_y; /* x,y coordinates in picture */
1032 int i_y, i_u, i_v; /* Y, U and V samples */
1033 int i_width, i_height; /* picture size */
1034 int i_chroma_width; /* chroma width */
1035 int i_eol_offset; /* pixels from end of line to next line */
1036 yuv_data_t *p_y; /* Y data base adress */
1037 yuv_data_t *p_u; /* U data base adress */
1038 yuv_data_t *p_v; /* V data base adress */
1039 u16 * p_data; /* base adress for destination picture */
1040 u16 * p_trans_red; /* red transformation table */
1041 u16 * p_trans_green; /* green transformation table */
1042 u16 * p_trans_blue; /* blue transformation table */
1044 /* Choose transformation matrix coefficients */
1045 i_crv = MATRIX_COEFFICIENTS_TABLE[p_pic->i_matrix_coefficients][0];
1046 i_cbu = MATRIX_COEFFICIENTS_TABLE[p_pic->i_matrix_coefficients][1];
1047 i_cgu = MATRIX_COEFFICIENTS_TABLE[p_pic->i_matrix_coefficients][2];
1048 i_cgv = MATRIX_COEFFICIENTS_TABLE[p_pic->i_matrix_coefficients][3];
1050 /* Choose the conversions tables and picture address */
1051 p_trans_red = (u16 *) p_vout->p_trans_red;
1052 p_trans_green = (u16 *) p_vout->p_trans_green;
1053 p_trans_blue = (u16 *) p_vout->p_trans_blue;
1054 p_data = (u16 *) vout_SysGetPicture( p_vout );
1056 /* Set the base pointers and transformation parameters */
1060 i_width = p_pic->i_width;
1061 i_height = p_pic->i_height;
1062 i_chroma_width = i_width / 2;
1063 i_eol_offset = p_vout->i_bytes_per_line / 2 - i_width;
1065 /* Do YUV transformation - the loops are repeated for optimization */
1066 switch( p_pic->i_type )
1068 case YUV_420_PICTURE: /* 15 or 16 bpp 420 transformation */
1070 vout_YUV420_16_MMX( p_y, p_u, p_v,
1072 i_width, i_chroma_width,
1074 0, 0, p_vout->i_bytes_per_line,
1075 p_vout->i_screen_depth == 15 );
1082 //??? yuvToRgb16( p_y, p_u, p_v, p_data, p_vout->p_trans_optimized, i_width*i_height );
1085 case YUV_422_PICTURE: /* 15 or 16 bpp 422 transformation */
1092 case YUV_444_PICTURE: /* 15 or 16 bpp 444 transformation */
1102 /*******************************************************************************
1103 * RenderYUV32Picture: render a 32 bpp YUV picture
1104 *******************************************************************************
1105 * Performs the YUV convertion. The picture sent to this function should only
1106 * have YUV_420, YUV_422 or YUV_444 types.
1107 *******************************************************************************/
1108 static void RenderYUV32Picture( vout_thread_t *p_vout, picture_t *p_pic )
1110 int i_crv, i_cbu, i_cgu, i_cgv; /* transformation coefficients */
1111 int i_pic_x, i_pic_y; /* x,y coordinates in picture */
1112 int i_y, i_u, i_v; /* Y, U and V samples */
1113 int i_width, i_height; /* picture size */
1114 int i_chroma_width; /* chroma width */
1115 int i_eol_offset; /* pixels from end of line to next line */
1116 yuv_data_t *p_y; /* Y data base adress */
1117 yuv_data_t *p_u; /* U data base adress */
1118 yuv_data_t *p_v; /* V data base adress */
1119 u32 * p_data; /* base adress for destination picture */
1120 u32 * p_trans_red; /* red transformation table */
1121 u32 * p_trans_green; /* green transformation table */
1122 u32 * p_trans_blue; /* blue transformation table */
1124 /* Choose transformation matrix coefficients */
1125 i_crv = MATRIX_COEFFICIENTS_TABLE[p_pic->i_matrix_coefficients][0];
1126 i_cbu = MATRIX_COEFFICIENTS_TABLE[p_pic->i_matrix_coefficients][1];
1127 i_cgu = MATRIX_COEFFICIENTS_TABLE[p_pic->i_matrix_coefficients][2];
1128 i_cgv = MATRIX_COEFFICIENTS_TABLE[p_pic->i_matrix_coefficients][3];
1130 /* Choose the conversions tables and picture address */
1131 p_trans_red = (u32 *) p_vout->p_trans_red;
1132 p_trans_green = (u32 *) p_vout->p_trans_green;
1133 p_trans_blue = (u32 *) p_vout->p_trans_blue;
1134 p_data = (u32 *) vout_SysGetPicture( p_vout );
1136 /* Set the base pointers and transformation parameters */
1140 i_width = p_pic->i_width;
1141 i_height = p_pic->i_height;
1142 i_chroma_width = i_width / 2;
1143 i_eol_offset = p_vout->i_bytes_per_line / p_vout->i_bytes_per_pixel - i_width;
1145 /* Do YUV transformation - the loops are repeated for optimization */
1146 switch( p_pic->i_type )
1148 case YUV_420_PICTURE: /* 32 bpp 420 transformation */
1155 case YUV_422_PICTURE: /* 32 bpp 422 transformation */
1162 case YUV_444_PICTURE: /* 32 bpp 444 transformation */
1172 /*******************************************************************************
1173 * RenderPictureInfo: print additionnal informations on a picture
1174 *******************************************************************************
1175 * This function will add informations such as fps and buffer size on a picture
1176 *******************************************************************************/
1177 static void RenderPictureInfo( vout_thread_t *p_vout, picture_t *p_pic )
1179 char psz_buffer[256]; /* string buffer */
1181 int i_ready_pic = 0; /* ready pictures */
1182 int i_reserved_pic = 0; /* reserved pictures */
1183 int i_picture; /* picture index */
1188 * Print FPS rate in upper right corner
1190 if( p_vout->c_fps_samples > VOUT_FPS_SAMPLES )
1192 sprintf( psz_buffer, "%.2f fps", (double) VOUT_FPS_SAMPLES * 1000000 /
1193 ( p_vout->fps_sample[ (p_vout->c_fps_samples - 1) % VOUT_FPS_SAMPLES ] -
1194 p_vout->fps_sample[ p_vout->c_fps_samples % VOUT_FPS_SAMPLES ] ) );
1195 vout_SysPrint( p_vout, p_vout->i_width, 0, 1, -1, psz_buffer );
1199 * Print statistics in upper left corner
1201 sprintf( psz_buffer, "gamma=%.2f %ld frames (%.1f %% idle)",
1202 p_vout->f_gamma, p_vout->c_fps_samples, p_vout->c_loops ?
1203 (double ) p_vout->c_idle_loops * 100 / p_vout->c_loops : 100. );
1204 vout_SysPrint( p_vout, 0, 0, -1, -1, psz_buffer );
1209 * Print heap state in lower left corner
1211 for( i_picture = 0; i_picture < VOUT_MAX_PICTURES; i_picture++ )
1213 switch( p_vout->p_picture[i_picture].i_status )
1215 case RESERVED_PICTURE:
1223 sprintf( psz_buffer, "video heap: %d/%d/%d", i_reserved_pic, i_ready_pic,
1224 VOUT_MAX_PICTURES );
1225 vout_SysPrint( p_vout, 0, p_vout->i_height, -1, 1, psz_buffer );
1230 * Print picture info in lower right corner
1232 switch( p_pic->i_type )
1234 case YUV_420_PICTURE:
1235 sprintf( psz_buffer, "YUV 4:2:0 picture, rendering time: %lu us",
1236 (unsigned long) p_vout->picture_render_time );
1238 case YUV_422_PICTURE:
1239 sprintf( psz_buffer, "YUV 4:2:2 picture, rendering time: %lu us",
1240 (unsigned long) p_vout->picture_render_time );
1242 case YUV_444_PICTURE:
1243 sprintf( psz_buffer, "YUV 4:4:4 picture, rendering time: %lu us",
1244 (unsigned long) p_vout->picture_render_time );
1247 sprintf( psz_buffer, "unknown picture, rendering time: %lu us",
1248 (unsigned long) p_vout->picture_render_time );
1251 vout_SysPrint( p_vout, p_vout->i_width, p_vout->i_height, 1, 1, psz_buffer );
1255 /*******************************************************************************
1256 * RenderIdle: render idle picture
1257 *******************************************************************************
1258 * This function will clear the display or print a logo. Level will vary from 0
1259 * to a very high value that noone should never reach. It returns non 0 if
1260 * something needs to be displayed and 0 if the previous picture can be kept.
1261 *******************************************************************************/
1262 static int RenderIdle( vout_thread_t *p_vout, int i_level )
1264 byte_t *pi_pic; /* pointer to picture data */
1266 /* Get frame pointer and clear display */
1267 pi_pic = vout_SysGetPicture( p_vout );
1272 case 0: /* level 0: clear screen */
1273 memset( pi_pic, 0, p_vout->i_bytes_per_line * p_vout->i_height );
1275 case 1: /* level 1: "no stream" */
1276 memset( pi_pic, 0, p_vout->i_bytes_per_line * p_vout->i_height );
1277 vout_SysPrint( p_vout, p_vout->i_width / 2, p_vout->i_height / 2,
1278 0, 0, "no stream" );
1280 case 50: /* level 50: copyright message */
1281 memset( pi_pic, 0, p_vout->i_bytes_per_line * p_vout->i_height );
1282 vout_SysPrint( p_vout, p_vout->i_width / 2, p_vout->i_height / 2,
1283 0, 0, COPYRIGHT_MESSAGE );
1285 default: /* other levels: keep previous picture */