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 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 /*******************************************************************************
157 *******************************************************************************/
158 static int InitThread ( vout_thread_t *p_vout );
159 static void RunThread ( vout_thread_t *p_vout );
160 static void ErrorThread ( vout_thread_t *p_vout );
161 static void EndThread ( vout_thread_t *p_vout );
162 static void BuildTables ( vout_thread_t *p_vout );
163 static void RenderPicture ( vout_thread_t *p_vout, picture_t *p_pic );
164 static void RenderYUVGrayPicture ( vout_thread_t *p_vout, picture_t *p_pic );
165 static void RenderYUV16Picture ( vout_thread_t *p_vout, picture_t *p_pic );
166 static void RenderYUV32Picture ( vout_thread_t *p_vout, picture_t *p_pic );
167 static void RenderInfo ( vout_thread_t *p_vout );
168 static int RenderIdle ( vout_thread_t *p_vout, int i_level );
170 /*******************************************************************************
171 * vout_CreateThread: creates a new video output thread
172 *******************************************************************************
173 * This function creates a new video output thread, and returns a pointer
174 * to its description. On error, it returns NULL.
175 * If pi_status is NULL, then the function will block until the thread is ready.
176 * If not, it will be updated using one of the THREAD_* constants.
177 *******************************************************************************/
178 vout_thread_t * vout_CreateThread (
180 char *psz_display, Window root_window,
182 int i_width, int i_height, int *pi_status
185 vout_thread_t * p_vout; /* thread descriptor */
186 int i_status; /* thread status */
188 /* Allocate descriptor */
189 p_vout = (vout_thread_t *) malloc( sizeof(vout_thread_t) );
192 intf_ErrMsg("error: %s\n", strerror(ENOMEM));
196 /* Initialize some fields used by the system-dependant method - these fields will
197 * probably be modified by the method */
203 p_vout->b_grayscale = main_GetIntVariable( VOUT_GRAYSCALE_VAR,
204 VOUT_GRAYSCALE_DEFAULT );
205 p_vout->i_width = i_width;
206 p_vout->i_height = i_height;
207 p_vout->i_bytes_per_line = i_width * 2;
208 p_vout->i_screen_depth = 15;
209 p_vout->i_bytes_per_pixel = 2;
210 p_vout->f_x_ratio = 1;
211 p_vout->f_y_ratio = 1;
212 p_vout->f_gamma = VOUT_GAMMA;
213 intf_DbgMsg("wished configuration: %dx%d,%d (%d bytes/pixel, %d bytes/line), ratio %.2f:%.2f, gray=%d\n",
214 p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth,
215 p_vout->i_bytes_per_pixel, p_vout->i_bytes_per_line,
216 p_vout->f_x_ratio, p_vout->f_y_ratio, p_vout->b_grayscale );
218 /* Create and initialize system-dependant method - this function issues its
219 * own error messages */
220 if( vout_SysCreate( p_vout
221 #if defined(VIDEO_X11)
222 , psz_display, root_window
229 intf_DbgMsg("actual configuration: %dx%d,%d (%d bytes/pixel, %d bytes/line), ratio %.2f:%.2f, gray=%d\n",
230 p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth,
231 p_vout->i_bytes_per_pixel, p_vout->i_bytes_per_line,
232 p_vout->f_x_ratio, p_vout->f_y_ratio, p_vout->b_grayscale );
234 /* Terminate the initialization */
237 p_vout->b_active = 0;
238 p_vout->pi_status = (pi_status != NULL) ? pi_status : &i_status;
239 *p_vout->pi_status = THREAD_CREATE;
242 p_vout->c_idle_loops = 0;
243 p_vout->c_fps_samples = 0;
245 p_vout->b_gamma_change = 0;
246 p_vout->i_new_width = p_vout->i_width;
247 p_vout->i_new_height = p_vout->i_height;
249 /* Create thread and set locks */
250 vlc_mutex_init( &p_vout->lock );
251 if( vlc_thread_create( &p_vout->thread_id, "video output",
252 (void *) RunThread, (void *) p_vout) )
254 intf_ErrMsg("error: %s\n", strerror(ENOMEM));
255 vout_SysDestroy( p_vout );
260 intf_Msg("Video: display initialized (%dx%d, %d bpp)\n",
261 p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth );
263 /* If status is NULL, wait until the thread is created */
264 if( pi_status == NULL )
268 msleep( THREAD_SLEEP );
269 }while( (i_status != THREAD_READY) && (i_status != THREAD_ERROR)
270 && (i_status != THREAD_FATAL) );
271 if( i_status != THREAD_READY )
279 /*******************************************************************************
280 * vout_DestroyThread: destroys a previously created thread
281 *******************************************************************************
282 * Destroy a terminated thread.
283 * The function will request a destruction of the specified thread. If pi_error
284 * is NULL, it will return once the thread is destroyed. Else, it will be
285 * update using one of the THREAD_* constants.
286 *******************************************************************************/
287 void vout_DestroyThread( vout_thread_t *p_vout, int *pi_status )
289 int i_status; /* thread status */
292 p_vout->pi_status = (pi_status != NULL) ? pi_status : &i_status;
293 *p_vout->pi_status = THREAD_DESTROY;
295 /* Request thread destruction */
298 /* If status is NULL, wait until thread has been destroyed */
299 if( pi_status == NULL )
303 msleep( THREAD_SLEEP );
304 }while( (i_status != THREAD_OVER) && (i_status != THREAD_ERROR)
305 && (i_status != THREAD_FATAL) );
309 /*******************************************************************************
310 * vout_DisplayPicture: display a picture
311 *******************************************************************************
312 * Remove the reservation flag of a picture, which will cause it to be ready for
313 * display. The picture does not need to be locked, since it is ignored by
314 * the output thread if is reserved.
315 *******************************************************************************/
316 void vout_DisplayPicture( vout_thread_t *p_vout, picture_t *p_pic )
319 char psz_date[MSTRTIME_MAX_SIZE]; /* buffer for date string */
323 /* Check if picture status is valid */
324 if( p_pic->i_status != RESERVED_PICTURE )
326 intf_DbgMsg("error: picture %d has invalid status %d\n", p_pic, p_pic->i_status );
330 /* Remove reservation flag */
331 p_pic->i_status = READY_PICTURE;
334 /* Send picture informations */
335 intf_DbgMsg("picture %p: type=%d, %dx%d, date=%s\n", p_pic, p_pic->i_type,
336 p_pic->i_width,p_pic->i_height, mstrtime( psz_date, p_pic->date ) );
340 /*******************************************************************************
341 * vout_CreatePicture: allocate a picture in the video output heap.
342 *******************************************************************************
343 * This function create a reserved image in the video output heap.
344 * A null pointer is returned if the function fails. This method provides an
345 * already allocated zone of memory in the picture data fields. It needs locking
346 * since several pictures can be created by several producers threads.
347 *******************************************************************************/
348 picture_t *vout_CreatePicture( vout_thread_t *p_vout, int i_type,
349 int i_width, int i_height, int i_bytes_per_line )
351 int i_picture; /* picture index */
352 picture_t * p_free_picture = NULL; /* first free picture */
353 picture_t * p_destroyed_picture = NULL; /* first destroyed picture */
356 vlc_mutex_lock( &p_vout->lock );
359 * Look for an empty place
362 i_picture < VOUT_MAX_PICTURES;
365 if( p_vout->p_picture[i_picture].i_status == DESTROYED_PICTURE )
367 /* Picture is marked for destruction, but is still allocated */
368 if( (p_vout->p_picture[i_picture].i_type == i_type) &&
369 (p_vout->p_picture[i_picture].i_height == i_height) &&
370 (p_vout->p_picture[i_picture].i_bytes_per_line == i_bytes_per_line) )
372 /* Memory size do match : memory will not be reallocated, and function
373 * can end immediately - this is the best possible case, since no
374 * memory allocation needs to be done */
375 p_vout->p_picture[i_picture].i_width = i_width;
376 p_vout->p_picture[i_picture].i_status = RESERVED_PICTURE;
378 intf_DbgMsg("picture %p (in destroyed picture slot)\n",
379 &p_vout->p_picture[i_picture] );
381 vlc_mutex_unlock( &p_vout->lock );
382 return( &p_vout->p_picture[i_picture] );
384 else if( p_destroyed_picture == NULL )
386 /* Memory size do not match, but picture index will be kept in
387 * case no other place are left */
388 p_destroyed_picture = &p_vout->p_picture[i_picture];
391 else if( (p_free_picture == NULL) &&
392 (p_vout->p_picture[i_picture].i_status == FREE_PICTURE ))
394 /* Picture is empty and ready for allocation */
395 p_free_picture = &p_vout->p_picture[i_picture];
399 /* If no free picture is available, use a destroyed picture */
400 if( (p_free_picture == NULL) && (p_destroyed_picture != NULL ) )
402 /* No free picture or matching destroyed picture has been found, but
403 * a destroyed picture is still avalaible */
404 free( p_destroyed_picture->p_data );
405 p_free_picture = p_destroyed_picture;
411 if( p_free_picture != NULL )
413 /* Allocate memory */
416 case YUV_420_PICTURE: /* YUV picture: bits per pixel */
417 case YUV_422_PICTURE:
418 case YUV_444_PICTURE:
419 p_free_picture->p_data = malloc( 3 * i_height * i_bytes_per_line );
420 p_free_picture->p_y = (yuv_data_t *) p_free_picture->p_data;
421 p_free_picture->p_u = (yuv_data_t *)(p_free_picture->p_data + i_height * i_bytes_per_line);
422 p_free_picture->p_v = (yuv_data_t *)(p_free_picture->p_data + i_height * i_bytes_per_line * 2);
426 intf_DbgMsg("error: unknown picture type %d\n", i_type );
427 p_free_picture->p_data = NULL;
432 if( p_free_picture->p_data != NULL )
434 /* Copy picture informations */
435 p_free_picture->i_type = i_type;
436 p_free_picture->i_status = RESERVED_PICTURE;
437 p_free_picture->i_width = i_width;
438 p_free_picture->i_height = i_height;
439 p_free_picture->i_bytes_per_line = i_bytes_per_line;
440 p_free_picture->i_refcount = 0;
441 p_free_picture->i_matrix_coefficients = 1;
445 /* Memory allocation failed : set picture as empty */
446 p_free_picture->i_type = EMPTY_PICTURE;
447 p_free_picture->i_status = FREE_PICTURE;
448 p_free_picture = NULL;
449 intf_ErrMsg("warning: %s\n", strerror( ENOMEM ) );
453 intf_DbgMsg("picture %p (in free picture slot)\n", p_free_picture );
455 vlc_mutex_unlock( &p_vout->lock );
456 return( p_free_picture );
459 // No free or destroyed picture could be found
460 intf_DbgMsg( "warning: heap is full\n" );
461 vlc_mutex_unlock( &p_vout->lock );
465 /*******************************************************************************
466 * vout_DestroyPicture: remove a permanent or reserved picture from the heap
467 *******************************************************************************
468 * This function frees a previously reserved picture or a permanent
469 * picture. It is meant to be used when the construction of a picture aborted.
470 * Note that the picture will be destroyed even if it is linked !
471 * This function does not need locking since reserved pictures are ignored by
473 *******************************************************************************/
474 void vout_DestroyPicture( vout_thread_t *p_vout, picture_t *p_pic )
477 /* Check if picture status is valid */
478 if( p_pic->i_status != RESERVED_PICTURE )
480 intf_DbgMsg("error: picture %d has invalid status %d\n", p_pic, p_pic->i_status );
484 p_pic->i_status = DESTROYED_PICTURE;
487 intf_DbgMsg("picture %p\n", p_pic);
491 /*******************************************************************************
492 * vout_LinkPicture: increment reference counter of a picture
493 *******************************************************************************
494 * This function increment the reference counter of a picture in the video
495 * heap. It needs a lock since several producer threads can access the picture.
496 *******************************************************************************/
497 void vout_LinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
499 vlc_mutex_lock( &p_vout->lock );
501 vlc_mutex_unlock( &p_vout->lock );
504 intf_DbgMsg("picture %p\n", p_pic);
508 /*******************************************************************************
509 * vout_UnlinkPicture: decrement reference counter of a picture
510 *******************************************************************************
511 * This function decrement the reference counter of a picture in the video heap.
512 *******************************************************************************/
513 void vout_UnlinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
515 vlc_mutex_lock( &p_vout->lock );
517 if( (p_pic->i_refcount == 0) && (p_pic->i_status == DISPLAYED_PICTURE) )
519 p_pic->i_status = DESTROYED_PICTURE;
521 vlc_mutex_unlock( &p_vout->lock );
524 intf_DbgMsg("picture %p\n", p_pic);
528 /* following functions are local */
530 /*******************************************************************************
531 * InitThread: initialize video output thread
532 *******************************************************************************
533 * This function is called from RunThread and performs the second step of the
534 * initialization. It returns 0 on success. Note that the thread's flag are not
535 * modified inside this function.
536 *******************************************************************************/
537 static int InitThread( vout_thread_t *p_vout )
539 int i_index; /* generic index */
542 *p_vout->pi_status = THREAD_START;
544 /* Initialize pictures */
545 for( i_index = 0; i_index < VOUT_MAX_PICTURES; i_index++)
547 p_vout->p_picture[i_index].i_type = EMPTY_PICTURE;
548 p_vout->p_picture[i_index].i_status= FREE_PICTURE;
551 /* Initialize output method - this function issues its own error messages */
552 if( vout_SysInit( p_vout ) )
554 *p_vout->pi_status = THREAD_ERROR;
558 /* Allocate translation tables */
559 p_vout->p_trans_base = malloc( 4 * 1024 * p_vout->i_bytes_per_pixel );
560 if( p_vout->p_trans_base == NULL )
562 intf_ErrMsg("error: %s\n", strerror(ENOMEM));
565 p_vout->p_trans_red = p_vout->p_trans_base + 384 *p_vout->i_bytes_per_pixel;
566 p_vout->p_trans_green = p_vout->p_trans_base + ( 1024 + 384)*p_vout->i_bytes_per_pixel;
567 p_vout->p_trans_blue = p_vout->p_trans_base + (2*1024 + 384)*p_vout->i_bytes_per_pixel;
568 p_vout->p_trans_gray = p_vout->p_trans_base + (3*1024 + 384)*p_vout->i_bytes_per_pixel;
570 /* Build translation tables */
571 BuildTables( p_vout );
573 /* Mark thread as running and return */
574 p_vout->b_active = 1;
575 *p_vout->pi_status = THREAD_READY;
576 intf_DbgMsg("thread ready\n");
580 /*******************************************************************************
581 * RunThread: video output thread
582 *******************************************************************************
583 * Video output thread. This function does only returns when the thread is
584 * terminated. It handles the pictures arriving in the video heap and the
585 * display device events.
586 *******************************************************************************/
587 static void RunThread( vout_thread_t *p_vout)
589 int i_picture; /* picture index */
590 int i_err; /* error code */
591 int i_idle_level = 0; /* idle level */
592 mtime_t current_date; /* current date */
593 mtime_t pic_date = 0; /* picture date */
594 mtime_t last_date = 0; /* last picture date */
595 boolean_t b_display; /* display flag */
596 picture_t * p_pic; /* picture pointer */
599 * Initialize thread and free configuration
601 p_vout->b_error = InitThread( p_vout );
602 if( p_vout->b_error )
604 free( p_vout ); /* destroy descriptor */
609 * Main loop - it is not executed if an error occured during
612 while( (!p_vout->b_die) && (!p_vout->b_error) )
615 * Find the picture to display - this operation does not need lock,
616 * since only READY_PICTURES are handled
619 for( i_picture = 0; i_picture < VOUT_MAX_PICTURES; i_picture++ )
621 if( (p_vout->p_picture[i_picture].i_status == READY_PICTURE) &&
623 (p_vout->p_picture[i_picture].date < pic_date) ) )
625 p_pic = &p_vout->p_picture[i_picture];
626 pic_date = p_pic->date;
629 current_date = mdate();
632 * Render picture if any
637 /* Computes FPS rate */
638 p_vout->fps_sample[ p_vout->c_fps_samples++ % VOUT_FPS_SAMPLES ] = pic_date;
640 if( pic_date < current_date )
642 /* Picture is late: it will be destroyed and the thread will sleep and
643 * go to next picture */
644 vlc_mutex_lock( &p_vout->lock );
645 p_pic->i_status = p_pic->i_refcount ? DISPLAYED_PICTURE : DESTROYED_PICTURE;
646 vlc_mutex_unlock( &p_vout->lock );
648 intf_DbgMsg( "warning: late picture %p skipped\n", p_pic );
652 else if( pic_date > current_date + VOUT_DISPLAY_DELAY )
654 /* A picture is ready to be rendered, but its rendering date is
655 * far from the current one so the thread will perform an empty loop
656 * as if no picture were found. The picture state is unchanged */
661 /* Picture has not yet been displayed, and has a valid display
662 * date : render it, then mark it as displayed */
663 if( p_vout->b_active )
665 RenderPicture( p_vout, p_pic );
667 vlc_mutex_lock( &p_vout->lock );
668 p_pic->i_status = p_pic->i_refcount ? DISPLAYED_PICTURE : DESTROYED_PICTURE;
669 vlc_mutex_unlock( &p_vout->lock );
674 * Rebuild tables if gamma has changed
676 if( p_vout->b_gamma_change )
678 p_vout->b_gamma_change = 0;
679 BuildTables( p_vout );
683 * Check events, sleep and display picture
685 i_err = vout_SysManage( p_vout );
688 /* A fatal error occured, and the thread must terminate immediately,
689 * without displaying anything - setting b_error to 1 cause the
690 * immediate end of the main while() loop. */
697 /* A picture is ready to be displayed : remove blank screen flag */
698 last_date = pic_date;
702 /* Render additionnal informations */
703 if( p_vout->b_active && p_vout->b_info )
705 RenderInfo( p_vout );
708 /* Sleep until its display date */
713 /* If last picture was a long time ago, increase idle level, reset
714 * date and render idle screen */
715 if( !i_err && (current_date - last_date > VOUT_IDLE_DELAY) )
717 last_date = current_date;
718 b_display = p_vout->b_active && RenderIdle( p_vout, i_idle_level++ );
726 /* Update counters */
727 p_vout->c_idle_loops++;
730 /* Sleep to wait for new pictures */
731 msleep( VOUT_IDLE_SLEEP );
734 /* On awakening, send immediately picture to display */
735 if( b_display && p_vout->b_active )
737 vout_SysDisplay( p_vout );
742 /* Update counters */
750 if( p_vout->b_error )
752 ErrorThread( p_vout );
757 intf_DbgMsg( "thread end\n" );
760 /*******************************************************************************
761 * ErrorThread: RunThread() error loop
762 *******************************************************************************
763 * This function is called when an error occured during thread main's loop. The
764 * thread can still receive feed, but must be ready to terminate as soon as
766 *******************************************************************************/
767 static void ErrorThread( vout_thread_t *p_vout )
769 /* Wait until a `die' order */
770 while( !p_vout->b_die )
773 msleep( VOUT_IDLE_SLEEP );
777 /*******************************************************************************
778 * EndThread: thread destruction
779 *******************************************************************************
780 * This function is called when the thread ends after a sucessfull
782 *******************************************************************************/
783 static void EndThread( vout_thread_t *p_vout )
785 int * pi_status; /* thread status */
789 pi_status = p_vout->pi_status;
790 *pi_status = THREAD_END;
792 /* Destroy all remaining pictures */
793 for( i_picture = 0; i_picture < VOUT_MAX_PICTURES; i_picture++ )
795 if( p_vout->p_picture[i_picture].i_status != FREE_PICTURE )
797 free( p_vout->p_picture[i_picture].p_data );
801 /* Destroy translation tables */
802 free( p_vout->p_trans_base );
804 /* Destroy thread structures allocated by InitThread */
805 vout_SysEnd( p_vout );
806 vout_SysDestroy( p_vout );
810 *pi_status = THREAD_OVER;
813 /*******************************************************************************
814 * BuildTables: build YUV translation tables
815 *******************************************************************************
816 * This function will build translations tables according to pixel width and
818 *******************************************************************************/
819 static void BuildTables( vout_thread_t *p_vout )
821 u16 * p_trans16_red = (u16 *) p_vout->p_trans_red;
822 u16 * p_trans16_green = (u16 *) p_vout->p_trans_green;
823 u16 * p_trans16_blue = (u16 *) p_vout->p_trans_blue;
824 u16 * p_trans16_gray = (u16 *) p_vout->p_trans_gray;
825 u32 * p_trans32_red = (u32 *) p_vout->p_trans_red;
826 u32 * p_trans32_green = (u32 *) p_vout->p_trans_green;
827 u32 * p_trans32_blue = (u32 *) p_vout->p_trans_blue;
828 u32 * p_trans32_gray = (u32 *) p_vout->p_trans_gray;
829 u8 i_gamma[256]; /* gamma table */
830 int i_index; /* index in tables */
832 /* Build gamma table */
833 for( i_index = 0; i_index < 256; i_index++ )
835 i_gamma[i_index] = 255. * pow( (double)i_index / 255., p_vout->f_gamma );
838 /* Build red, green, blue and gray tables */
839 switch( p_vout->i_screen_depth )
842 for( i_index = -384; i_index < 640; i_index++)
844 p_trans16_red[i_index] = (i_gamma[CLIP_BYTE( i_index )] & 0xf8)<<7;
845 p_trans16_green[i_index] = (i_gamma[CLIP_BYTE( i_index )] & 0xf8)<<2;
846 p_trans16_blue[i_index] = i_gamma[CLIP_BYTE( i_index )] >> 3;
847 p_trans16_gray[i_index] = p_trans16_red[i_index] |
848 p_trans16_green[i_index] | p_trans16_blue[i_index];
852 for( i_index = -384; i_index < 640; i_index++)
854 p_trans16_red[i_index] = (i_gamma[CLIP_BYTE( i_index )] & 0xf8)<<8;
855 p_trans16_green[i_index] = (i_gamma[CLIP_BYTE( i_index )] & 0xfc)<<3;
856 p_trans16_blue[i_index] = i_gamma[CLIP_BYTE( i_index )] >> 3;
857 p_trans16_gray[i_index] = p_trans16_red[i_index] |
858 p_trans16_green[i_index] | p_trans16_blue[i_index];
862 for( i_index = -384; i_index < 640; i_index++)
864 p_trans32_red[i_index] = i_gamma[CLIP_BYTE( i_index )] <<16;
865 p_trans32_green[i_index] = i_gamma[CLIP_BYTE( i_index )] <<8;
866 p_trans32_blue[i_index] = i_gamma[CLIP_BYTE( i_index )] ;
867 p_trans32_gray[i_index] = p_trans32_red[i_index] |
868 p_trans32_green[i_index] | p_trans32_blue[i_index];
873 intf_DbgMsg("error: invalid screen depth %d\n", p_vout->i_screen_depth );
879 /*******************************************************************************
880 * RenderPicture: render a picture
881 *******************************************************************************
882 * This function convert a picture from a video heap to a pixel-encoded image
883 * and copy it to the current rendering buffer. No lock is required, since the
884 * rendered picture has been determined as existant, and will only be destroyed
885 * by the vout thread later.
886 * ???? 24 and 32 bpp should probably be separated
887 *******************************************************************************/
888 static void RenderPicture( vout_thread_t *p_vout, picture_t *p_pic )
891 /* Send picture informations */
892 intf_DbgMsg("picture %p\n", p_pic );
894 /* Store rendering start date */
895 p_vout->picture_render_time = mdate();
898 switch( p_pic->i_type )
900 case YUV_420_PICTURE: /* YUV picture: YUV transformation */
901 case YUV_422_PICTURE:
902 case YUV_444_PICTURE:
903 if( p_vout->b_grayscale ) /* grayscale */
905 RenderYUVGrayPicture( p_vout, p_pic );
907 else if( p_vout->i_bytes_per_pixel == 2 ) /* color 15 or 16 bpp */
909 RenderYUV16Picture( p_vout, p_pic );
911 else if( p_vout->i_bytes_per_pixel == 4 ) /* color 32 bpp */
913 RenderYUV32Picture( p_vout, p_pic );
918 intf_DbgMsg("error: unknown picture type %d\n", p_pic->i_type );
924 /* Computes rendering time */
925 p_vout->picture_render_time = mdate() - p_vout->picture_render_time;
929 /*******************************************************************************
930 * RenderYUVGrayPicture: render YUV picture in grayscale
931 *******************************************************************************
932 * Performs the YUV convertion. The picture sent to this function should only
933 * have YUV_420, YUV_422 or YUV_444 types.
934 *******************************************************************************/
935 static void RenderYUVGrayPicture( vout_thread_t *p_vout, picture_t *p_pic )
937 int i_pic_x, i_pic_y; /* x,y coordinates in picture */
938 int i_width, i_height; /* picture size */
939 int i_eol_offset; /* pixels from end of line to next line */
940 yuv_data_t *p_y; /* Y data base adress */
941 u16 * p_pic16; /* destination picture, 15 or 16 bpp */
942 u32 * p_pic32; /* destination picture, 32 bpp */
943 u16 * p_trans16_gray; /* transformation table, 15 or 16 bpp */
944 u32 * p_trans32_gray; /* transformation table, 32 bpp */
946 /* Set the base pointers and transformation parameters */
948 i_width = p_pic->i_width;
949 i_height = p_pic->i_height;
950 i_eol_offset = p_vout->i_bytes_per_line / p_vout->i_bytes_per_pixel - i_width;
952 /* Get base adress for destination image and translation tables, then
954 switch( p_vout->i_screen_depth )
958 p_trans16_gray = (u16 *) p_vout->p_trans_gray;
959 p_pic16 = (u16 *) vout_SysGetPicture( p_vout );
960 YUV_GRAYSCALE( p_trans16_gray, p_pic16 );
963 p_trans32_gray = (u32 *) p_vout->p_trans_gray;
964 p_pic32 = (u32 *) vout_SysGetPicture( p_vout );
965 YUV_GRAYSCALE( p_trans32_gray, p_pic32 );
969 intf_DbgMsg("error: invalid screen depth %d\n", p_vout->i_screen_depth );
976 /*******************************************************************************
977 * RenderYUV16Picture: render a 15 or 16 bpp YUV picture
978 *******************************************************************************
979 * Performs the YUV convertion. The picture sent to this function should only
980 * have YUV_420, YUV_422 or YUV_444 types.
981 *******************************************************************************/
982 static void RenderYUV16Picture( vout_thread_t *p_vout, picture_t *p_pic )
984 int i_crv, i_cbu, i_cgu, i_cgv; /* transformation coefficients */
985 int i_pic_x, i_pic_y; /* x,y coordinates in picture */
986 int i_y, i_u, i_v; /* Y, U and V samples */
987 int i_width, i_height; /* picture size */
988 int i_chroma_width; /* chroma width */
989 int i_eol_offset; /* pixels from end of line to next line */
990 yuv_data_t *p_y; /* Y data base adress */
991 yuv_data_t *p_u; /* U data base adress */
992 yuv_data_t *p_v; /* V data base adress */
993 u16 * p_data; /* base adress for destination picture */
994 u16 * p_trans_red; /* red transformation table */
995 u16 * p_trans_green; /* green transformation table */
996 u16 * p_trans_blue; /* blue transformation table */
998 /* Choose transformation matrix coefficients */
999 i_crv = MATRIX_COEFFICIENTS_TABLE[p_pic->i_matrix_coefficients][0];
1000 i_cbu = MATRIX_COEFFICIENTS_TABLE[p_pic->i_matrix_coefficients][1];
1001 i_cgu = MATRIX_COEFFICIENTS_TABLE[p_pic->i_matrix_coefficients][2];
1002 i_cgv = MATRIX_COEFFICIENTS_TABLE[p_pic->i_matrix_coefficients][3];
1004 /* Choose the conversions tables and picture address */
1005 p_trans_red = (u16 *) p_vout->p_trans_red;
1006 p_trans_green = (u16 *) p_vout->p_trans_green;
1007 p_trans_blue = (u16 *) p_vout->p_trans_blue;
1008 p_data = (u16 *) vout_SysGetPicture( p_vout );
1010 /* Set the base pointers and transformation parameters */
1014 i_width = p_pic->i_width;
1015 i_height = p_pic->i_height;
1016 i_chroma_width = i_width / 2;
1017 i_eol_offset = p_vout->i_bytes_per_line / 2 - i_width;
1019 /* Do YUV transformation - the loops are repeated for optimization */
1020 switch( p_pic->i_type )
1022 case YUV_420_PICTURE: /* 15 or 16 bpp 420 transformation */
1024 vout_YUV420_16_MMX( p_y, p_u, p_v,
1026 i_width, i_chroma_width,
1028 0, 0, p_vout->i_bytes_per_line,
1029 p_vout->i_screen_depth == 15 );
1038 case YUV_422_PICTURE: /* 15 or 16 bpp 422 transformation */
1045 case YUV_444_PICTURE: /* 15 or 16 bpp 444 transformation */
1055 /*******************************************************************************
1056 * RenderYUV32Picture: render a 32 bpp YUV picture
1057 *******************************************************************************
1058 * Performs the YUV convertion. The picture sent to this function should only
1059 * have YUV_420, YUV_422 or YUV_444 types.
1060 *******************************************************************************/
1061 static void RenderYUV32Picture( vout_thread_t *p_vout, picture_t *p_pic )
1063 int i_crv, i_cbu, i_cgu, i_cgv; /* transformation coefficients */
1064 int i_pic_x, i_pic_y; /* x,y coordinates in picture */
1065 int i_y, i_u, i_v; /* Y, U and V samples */
1066 int i_width, i_height; /* picture size */
1067 int i_chroma_width; /* chroma width */
1068 int i_eol_offset; /* pixels from end of line to next line */
1069 yuv_data_t *p_y; /* Y data base adress */
1070 yuv_data_t *p_u; /* U data base adress */
1071 yuv_data_t *p_v; /* V data base adress */
1072 u32 * p_data; /* base adress for destination picture */
1073 u32 * p_trans_red; /* red transformation table */
1074 u32 * p_trans_green; /* green transformation table */
1075 u32 * p_trans_blue; /* blue transformation table */
1077 /* Choose transformation matrix coefficients */
1078 i_crv = MATRIX_COEFFICIENTS_TABLE[p_pic->i_matrix_coefficients][0];
1079 i_cbu = MATRIX_COEFFICIENTS_TABLE[p_pic->i_matrix_coefficients][1];
1080 i_cgu = MATRIX_COEFFICIENTS_TABLE[p_pic->i_matrix_coefficients][2];
1081 i_cgv = MATRIX_COEFFICIENTS_TABLE[p_pic->i_matrix_coefficients][3];
1083 /* Choose the conversions tables and picture address */
1084 p_trans_red = (u32 *) p_vout->p_trans_red;
1085 p_trans_green = (u32 *) p_vout->p_trans_green;
1086 p_trans_blue = (u32 *) p_vout->p_trans_blue;
1087 p_data = (u32 *) vout_SysGetPicture( p_vout );
1089 /* Set the base pointers and transformation parameters */
1093 i_width = p_pic->i_width;
1094 i_height = p_pic->i_height;
1095 i_chroma_width = i_width / 2;
1096 i_eol_offset = p_vout->i_bytes_per_line / p_vout->i_bytes_per_pixel - i_width;
1098 /* Do YUV transformation - the loops are repeated for optimization */
1099 switch( p_pic->i_type )
1101 case YUV_420_PICTURE: /* 32 bpp 420 transformation */
1108 case YUV_422_PICTURE: /* 32 bpp 422 transformation */
1115 case YUV_444_PICTURE: /* 32 bpp 444 transformation */
1125 /*******************************************************************************
1126 * RenderInfo: print additionnal informations on a picture
1127 *******************************************************************************
1128 * This function will add informations such as fps and buffer size on a picture
1129 *******************************************************************************/
1130 static void RenderInfo( vout_thread_t *p_vout )
1132 char psz_buffer[256]; /* string buffer */
1134 int i_ready_pic = 0; /* ready pictures */
1135 int i_reserved_pic = 0; /* reserved pictures */
1136 int i_picture; /* picture index */
1140 /* Print FPS rate in upper right corner */
1141 if( p_vout->c_fps_samples > VOUT_FPS_SAMPLES )
1143 sprintf( psz_buffer, "%.2f fps", (double) VOUT_FPS_SAMPLES * 1000000 /
1144 ( p_vout->fps_sample[ (p_vout->c_fps_samples - 1) % VOUT_FPS_SAMPLES ] -
1145 p_vout->fps_sample[ p_vout->c_fps_samples % VOUT_FPS_SAMPLES ] ) );
1146 vout_SysPrint( p_vout, p_vout->i_width, 0, 1, -1, psz_buffer );
1149 /* Print statistics in upper left corner */
1150 sprintf( psz_buffer, "gamma=%.2f %ld frames (%.1f %% idle)",
1151 p_vout->f_gamma, p_vout->c_fps_samples, p_vout->c_loops ?
1152 (double ) p_vout->c_idle_loops * 100 / p_vout->c_loops : 100. );
1153 vout_SysPrint( p_vout, 0, 0, -1, -1, psz_buffer );
1157 /* Print heap state in lower left corner */
1158 for( i_picture = 0; i_picture < VOUT_MAX_PICTURES; i_picture++ )
1160 switch( p_vout->p_picture[i_picture].i_status )
1162 case RESERVED_PICTURE:
1170 sprintf( psz_buffer, "video heap: %d/%d/%d", i_reserved_pic, i_ready_pic,
1171 VOUT_MAX_PICTURES );
1172 vout_SysPrint( p_vout, 0, p_vout->i_height, -1, 1, psz_buffer );
1176 /* Print rendering statistics in lower right corner */
1177 sprintf( psz_buffer, "picture rendering time: %lu us",
1178 (unsigned long) p_vout->picture_render_time );
1179 vout_SysPrint( p_vout, p_vout->i_width, p_vout->i_height, 1, 1, psz_buffer );
1183 /*******************************************************************************
1184 * RenderIdle: render idle picture
1185 *******************************************************************************
1186 * This function will clear the display or print a logo. Level will vary from 0
1187 * to a very high value that noone should never reach. It returns non 0 if
1188 * something needs to be displayed and 0 if the previous picture can be kept.
1189 *******************************************************************************/
1190 static int RenderIdle( vout_thread_t *p_vout, int i_level )
1192 byte_t *pi_pic; /* pointer to picture data */
1194 /* Get frame pointer and clear display */
1195 pi_pic = vout_SysGetPicture( p_vout );
1200 case 0: /* level 0: clear screen */
1201 memset( pi_pic, 0, p_vout->i_bytes_per_line * p_vout->i_height );
1203 case 1: /* level 1: "no stream" */
1204 memset( pi_pic, 0, p_vout->i_bytes_per_line * p_vout->i_height );
1205 vout_SysPrint( p_vout, p_vout->i_width / 2, p_vout->i_height / 2,
1206 0, 0, "no stream" );
1208 case 50: /* level 50: copyright message */
1209 memset( pi_pic, 0, p_vout->i_bytes_per_line * p_vout->i_height );
1210 vout_SysPrint( p_vout, p_vout->i_width / 2, p_vout->i_height / 2,
1211 0, 0, COPYRIGHT_MESSAGE );
1213 default: /* other levels: keep previous picture */