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 *******************************************************************************/
21 #include "vlc_thread.h"
23 #include "video_output.h"
24 #include "video_sys.h"
25 #include "video_yuv.h"
29 /*******************************************************************************
31 *******************************************************************************/
32 static int InitThread ( vout_thread_t *p_vout );
33 static void RunThread ( vout_thread_t *p_vout );
34 static void ErrorThread ( vout_thread_t *p_vout );
35 static void EndThread ( vout_thread_t *p_vout );
36 static void RenderBlank ( vout_thread_t *p_vout );
37 static int RenderPicture ( vout_thread_t *p_vout, picture_t *p_pic, boolean_t b_blank );
38 static int RenderPictureInfo ( vout_thread_t *p_vout, picture_t *p_pic, boolean_t b_blank );
39 static int RenderIdle ( vout_thread_t *p_vout, boolean_t b_blank );
40 static int RenderInfo ( vout_thread_t *p_vout, boolean_t b_balnk );
41 static int Manage ( vout_thread_t *p_vout );
43 /*******************************************************************************
44 * vout_CreateThread: creates a new video output thread
45 *******************************************************************************
46 * This function creates a new video output thread, and returns a pointer
47 * to its description. On error, it returns NULL.
48 * If pi_status is NULL, then the function will block until the thread is ready.
49 * If not, it will be updated using one of the THREAD_* constants.
50 *******************************************************************************/
51 vout_thread_t * vout_CreateThread ( char *psz_display, int i_root_window,
52 int i_width, int i_height, int *pi_status )
54 vout_thread_t * p_vout; /* thread descriptor */
55 int i_status; /* thread status */
57 /* Allocate descriptor */
58 p_vout = (vout_thread_t *) malloc( sizeof(vout_thread_t) );
61 intf_ErrMsg("error: %s\n", strerror(ENOMEM));
65 /* Initialize thread properties */
69 p_vout->pi_status = (pi_status != NULL) ? pi_status : &i_status;
70 *p_vout->pi_status = THREAD_CREATE;
72 /* Initialize some fields used by the system-dependant method - these fields will
73 * probably be modified by the method, and are only preferences */
74 p_vout->b_grayscale = main_GetIntVariable( VOUT_GRAYSCALE_VAR,
75 VOUT_GRAYSCALE_DEFAULT );
76 p_vout->i_width = i_width;
77 p_vout->i_height = i_height;
78 p_vout->i_bytes_per_line = i_width * 2;
79 p_vout->i_screen_depth = 15;
80 p_vout->i_bytes_per_pixel = 2;
81 p_vout->f_gamma = VOUT_GAMMA;
87 intf_DbgMsg("wished configuration: %dx%d,%d (%d bytes/pixel, %d bytes/line)\n",
88 p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth,
89 p_vout->i_bytes_per_pixel, p_vout->i_bytes_per_line );
91 /* Create and initialize system-dependant method - this function issues its
92 * own error messages */
93 if( vout_SysCreate( p_vout, psz_display, i_root_window ) )
98 intf_DbgMsg("actual configuration: %dx%d,%d (%d bytes/pixel, %d bytes/line)\n",
99 p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth,
100 p_vout->i_bytes_per_pixel, p_vout->i_bytes_per_line );
103 /* Initialize statistics fields */
104 p_vout->render_time = 0;
105 p_vout->c_fps_samples = 0;
108 /* Initialize running properties */
109 p_vout->i_changes = 0;
110 p_vout->last_picture_date = 0;
111 p_vout->last_display_date = 0;
113 /* Create thread and set locks */
114 vlc_mutex_init( &p_vout->picture_lock );
115 vlc_mutex_init( &p_vout->subtitle_lock );
116 vlc_mutex_init( &p_vout->change_lock );
117 vlc_mutex_lock( &p_vout->change_lock );
118 if( vlc_thread_create( &p_vout->thread_id, "video output", (void *) RunThread, (void *) p_vout) )
120 intf_ErrMsg("error: %s\n", strerror(ENOMEM));
121 vout_SysDestroy( p_vout );
126 intf_Msg("Video: display initialized (%dx%d, %d bpp)\n",
127 p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth );
129 /* If status is NULL, wait until the thread is created */
130 if( pi_status == NULL )
134 msleep( THREAD_SLEEP );
135 }while( (i_status != THREAD_READY) && (i_status != THREAD_ERROR)
136 && (i_status != THREAD_FATAL) );
137 if( i_status != THREAD_READY )
145 /*******************************************************************************
146 * vout_DestroyThread: destroys a previously created thread
147 *******************************************************************************
148 * Destroy a terminated thread.
149 * The function will request a destruction of the specified thread. If pi_error
150 * is NULL, it will return once the thread is destroyed. Else, it will be
151 * update using one of the THREAD_* constants.
152 *******************************************************************************/
153 void vout_DestroyThread( vout_thread_t *p_vout, int *pi_status )
155 int i_status; /* thread status */
158 p_vout->pi_status = (pi_status != NULL) ? pi_status : &i_status;
159 *p_vout->pi_status = THREAD_DESTROY;
161 /* Request thread destruction */
164 /* If status is NULL, wait until thread has been destroyed */
165 if( pi_status == NULL )
169 msleep( THREAD_SLEEP );
170 }while( (i_status != THREAD_OVER) && (i_status != THREAD_ERROR)
171 && (i_status != THREAD_FATAL) );
175 /*******************************************************************************
176 * vout_DisplaySubtitle: display a subtitle
177 *******************************************************************************
178 * Remove the reservation flag of a subtitle, which will cause it to be ready for
179 * display. The picture does not need to be locked, since it is ignored by
180 * the output thread if is reserved.
181 *******************************************************************************/
182 void vout_DisplaySubtitle( vout_thread_t *p_vout, subtitle_t *p_sub )
185 char psz_begin_date[MSTRTIME_MAX_SIZE]; /* buffer for date string */
186 char psz_end_date[MSTRTIME_MAX_SIZE]; /* buffer for date string */
190 /* Check if status is valid */
191 if( p_sub->i_status != RESERVED_SUBTITLE )
193 intf_DbgMsg("error: subtitle %p has invalid status %d\n", p_sub, p_sub->i_status );
197 /* Remove reservation flag */
198 p_sub->i_status = READY_SUBTITLE;
201 /* Send subtitle informations */
202 intf_DbgMsg("subtitle %p: type=%d, begin date=%s, end date=%s\n", p_sub, p_sub->i_type,
203 mstrtime( psz_begin_date, p_sub->begin_date ),
204 mstrtime( psz_end_date, p_sub->end_date ) );
208 /*******************************************************************************
209 * vout_CreateSubtitle: allocate a subtitle in the video output heap.
210 *******************************************************************************
211 * This function create a reserved subtitle in the video output heap.
212 * A null pointer is returned if the function fails. This method provides an
213 * already allocated zone of memory in the subtitle data fields. It needs locking
214 * since several pictures can be created by several producers threads.
215 *******************************************************************************/
216 subtitle_t *vout_CreateSubtitle( vout_thread_t *p_vout, int i_type,
222 /*******************************************************************************
223 * vout_DestroySubtitle: remove a permanent or reserved subtitle from the heap
224 *******************************************************************************
225 * This function frees a previously reserved subtitle.
226 * It is meant to be used when the construction of a picture aborted.
227 * This function does not need locking since reserved subtitles are ignored by
229 *******************************************************************************/
230 void vout_DestroySubtitle( vout_thread_t *p_vout, subtitle_t *p_sub )
233 /* Check if subtitle status is valid */
234 if( p_sub->i_status != RESERVED_SUBTITLE )
236 intf_DbgMsg("error: subtitle %p has invalid status %d\n", p_sub, p_sub->i_status );
240 p_sub->i_status = DESTROYED_SUBTITLE;
243 intf_DbgMsg("subtitle %p\n", p_sub);
247 /*******************************************************************************
248 * vout_DisplayPicture: display a picture
249 *******************************************************************************
250 * Remove the reservation flag of a picture, which will cause it to be ready for
251 * display. The picture won't be displayed until vout_DatePicture has been
253 *******************************************************************************/
254 void vout_DisplayPicture( vout_thread_t *p_vout, picture_t *p_pic )
256 vlc_mutex_lock( &p_vout->picture_lock );
257 switch( p_pic->i_status )
259 case RESERVED_PICTURE:
260 p_pic->i_status = RESERVED_DISP_PICTURE;
262 case RESERVED_DATED_PICTURE:
263 p_pic->i_status = READY_PICTURE;
267 intf_DbgMsg("error: picture %p has invalid status %d\n", p_pic, p_pic->i_status );
271 vlc_mutex_unlock( &p_vout->picture_lock );
274 intf_DbgMsg("picture %p\n", p_pic );
278 /*******************************************************************************
279 * vout_DatePicture: date a picture
280 *******************************************************************************
281 * Remove the reservation flag of a picture, which will cause it to be ready for
282 * display. The picture won't be displayed until vout_DisplayPicture has been
284 *******************************************************************************/
285 void vout_DatePicture( vout_thread_t *p_vout, picture_t *p_pic, mtime_t date )
287 vlc_mutex_lock( &p_vout->picture_lock );
289 switch( p_pic->i_status )
291 case RESERVED_PICTURE:
292 p_pic->i_status = RESERVED_DATED_PICTURE;
294 case RESERVED_DISP_PICTURE:
295 p_pic->i_status = READY_PICTURE;
299 intf_DbgMsg("error: picture %p has invalid status %d\n", p_pic, p_pic->i_status );
303 vlc_mutex_unlock( &p_vout->picture_lock );
306 intf_DbgMsg("picture %p\n", p_pic);
310 /*******************************************************************************
311 * vout_CreatePicture: allocate a picture in the video output heap.
312 *******************************************************************************
313 * This function create a reserved image in the video output heap.
314 * A null pointer is returned if the function fails. This method provides an
315 * already allocated zone of memory in the picture data fields. It needs locking
316 * since several pictures can be created by several producers threads.
317 *******************************************************************************/
318 picture_t *vout_CreatePicture( vout_thread_t *p_vout, int i_type,
319 int i_width, int i_height )
321 int i_picture; /* picture index */
322 int i_chroma_width = 0; /* chroma width */
323 picture_t * p_free_picture = NULL; /* first free picture */
324 picture_t * p_destroyed_picture = NULL; /* first destroyed picture */
327 vlc_mutex_lock( &p_vout->picture_lock );
330 * Look for an empty place
333 i_picture < VOUT_MAX_PICTURES;
336 if( p_vout->p_picture[i_picture].i_status == DESTROYED_PICTURE )
338 /* Picture is marked for destruction, but is still allocated - note
339 * that if width and type are the same for two pictures, chroma_width
340 * should also be the same */
341 if( (p_vout->p_picture[i_picture].i_type == i_type) &&
342 (p_vout->p_picture[i_picture].i_height == i_height) &&
343 (p_vout->p_picture[i_picture].i_width == i_width) )
345 /* Memory size do match : memory will not be reallocated, and function
346 * can end immediately - this is the best possible case, since no
347 * memory allocation needs to be done */
348 p_vout->p_picture[i_picture].i_status = RESERVED_PICTURE;
350 intf_DbgMsg("picture %p (in destroyed picture slot)\n",
351 &p_vout->p_picture[i_picture] );
353 vlc_mutex_unlock( &p_vout->picture_lock );
354 return( &p_vout->p_picture[i_picture] );
356 else if( p_destroyed_picture == NULL )
358 /* Memory size do not match, but picture index will be kept in
359 * case no other place are left */
360 p_destroyed_picture = &p_vout->p_picture[i_picture];
363 else if( (p_free_picture == NULL) &&
364 (p_vout->p_picture[i_picture].i_status == FREE_PICTURE ))
366 /* Picture is empty and ready for allocation */
367 p_free_picture = &p_vout->p_picture[i_picture];
371 /* If no free picture is available, use a destroyed picture */
372 if( (p_free_picture == NULL) && (p_destroyed_picture != NULL ) )
374 /* No free picture or matching destroyed picture has been found, but
375 * a destroyed picture is still avalaible */
376 free( p_destroyed_picture->p_data );
377 p_free_picture = p_destroyed_picture;
383 if( p_free_picture != NULL )
385 /* Allocate memory */
388 case YUV_420_PICTURE: /* YUV 420: 1,1/4,1/4 samples per pixel */
389 i_chroma_width = i_width / 2;
390 p_free_picture->p_data = malloc( i_height * i_chroma_width * 3 * sizeof( yuv_data_t ) );
391 p_free_picture->p_y = (yuv_data_t *)p_free_picture->p_data;
392 p_free_picture->p_u = (yuv_data_t *)p_free_picture->p_data +i_height*i_chroma_width*4/2;
393 p_free_picture->p_v = (yuv_data_t *)p_free_picture->p_data +i_height*i_chroma_width*5/2;
395 case YUV_422_PICTURE: /* YUV 422: 1,1/2,1/2 samples per pixel */
396 i_chroma_width = i_width / 2;
397 p_free_picture->p_data = malloc( i_height * i_chroma_width * 4 * sizeof( yuv_data_t ) );
398 p_free_picture->p_y = (yuv_data_t *)p_free_picture->p_data;
399 p_free_picture->p_u = (yuv_data_t *)p_free_picture->p_data +i_height*i_chroma_width*2;
400 p_free_picture->p_v = (yuv_data_t *)p_free_picture->p_data +i_height*i_chroma_width*3;
402 case YUV_444_PICTURE: /* YUV 444: 1,1,1 samples per pixel */
403 i_chroma_width = i_width;
404 p_free_picture->p_data = malloc( i_height * i_chroma_width * 3 * sizeof( yuv_data_t ) );
405 p_free_picture->p_y = (yuv_data_t *)p_free_picture->p_data;
406 p_free_picture->p_u = (yuv_data_t *)p_free_picture->p_data +i_height*i_chroma_width;
407 p_free_picture->p_v = (yuv_data_t *)p_free_picture->p_data +i_height*i_chroma_width*2;
411 intf_DbgMsg("error: unknown picture type %d\n", i_type );
412 p_free_picture->p_data = NULL;
417 if( p_free_picture->p_data != NULL )
419 /* Copy picture informations, set some default values */
420 p_free_picture->i_type = i_type;
421 p_free_picture->i_status = RESERVED_PICTURE;
422 p_free_picture->i_matrix_coefficients = 1;
423 p_free_picture->i_width = i_width;
424 p_free_picture->i_height = i_height;
425 p_free_picture->i_chroma_width = i_chroma_width;
426 p_free_picture->i_display_horizontal_offset = 0;
427 p_free_picture->i_display_vertical_offset = 0;
428 p_free_picture->i_display_width = i_width;
429 p_free_picture->i_display_height = i_height;
430 p_free_picture->i_aspect_ratio = AR_SQUARE_PICTURE;
431 p_free_picture->i_refcount = 0;
435 /* Memory allocation failed : set picture as empty */
436 p_free_picture->i_type = EMPTY_PICTURE;
437 p_free_picture->i_status = FREE_PICTURE;
438 p_free_picture = NULL;
439 intf_ErrMsg("warning: %s\n", strerror( ENOMEM ) );
443 intf_DbgMsg("picture %p (in free picture slot)\n", p_free_picture );
445 vlc_mutex_unlock( &p_vout->picture_lock );
446 return( p_free_picture );
449 // No free or destroyed picture could be found
450 intf_DbgMsg( "warning: heap is full\n" );
451 vlc_mutex_unlock( &p_vout->picture_lock );
455 /*******************************************************************************
456 * vout_DestroyPicture: remove a permanent or reserved picture from the heap
457 *******************************************************************************
458 * This function frees a previously reserved picture or a permanent
459 * picture. It is meant to be used when the construction of a picture aborted.
460 * Note that the picture will be destroyed even if it is linked !
461 * This function does not need locking since reserved pictures are ignored by
463 *******************************************************************************/
464 void vout_DestroyPicture( vout_thread_t *p_vout, picture_t *p_pic )
467 /* Check if picture status is valid */
468 if( (p_pic->i_status != RESERVED_PICTURE) &&
469 (p_pic->i_status != RESERVED_DATED_PICTURE) &&
470 (p_pic->i_status != RESERVED_DISP_PICTURE) )
472 intf_DbgMsg("error: picture %p has invalid status %d\n", p_pic, p_pic->i_status );
476 p_pic->i_status = DESTROYED_PICTURE;
479 intf_DbgMsg("picture %p\n", p_pic);
483 /*******************************************************************************
484 * vout_LinkPicture: increment reference counter of a picture
485 *******************************************************************************
486 * This function increment the reference counter of a picture in the video
487 * heap. It needs a lock since several producer threads can access the picture.
488 *******************************************************************************/
489 void vout_LinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
491 vlc_mutex_lock( &p_vout->picture_lock );
493 vlc_mutex_unlock( &p_vout->picture_lock );
496 intf_DbgMsg("picture %p\n", p_pic);
500 /*******************************************************************************
501 * vout_UnlinkPicture: decrement reference counter of a picture
502 *******************************************************************************
503 * This function decrement the reference counter of a picture in the video heap.
504 *******************************************************************************/
505 void vout_UnlinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
507 vlc_mutex_lock( &p_vout->picture_lock );
511 if( p_pic->i_refcount < 0 )
513 intf_DbgMsg("error: refcount < 0\n");
514 p_pic->i_refcount = 0;
518 if( (p_pic->i_refcount == 0) && (p_pic->i_status == DISPLAYED_PICTURE) )
520 p_pic->i_status = DESTROYED_PICTURE;
522 vlc_mutex_unlock( &p_vout->picture_lock );
525 intf_DbgMsg("picture %p\n", p_pic);
529 /* following functions are local */
531 /*******************************************************************************
532 * InitThread: initialize video output thread
533 *******************************************************************************
534 * This function is called from RunThread and performs the second step of the
535 * initialization. It returns 0 on success. Note that the thread's flag are not
536 * modified inside this function.
537 *******************************************************************************/
538 static int InitThread( vout_thread_t *p_vout )
540 int i_index; /* generic index */
543 *p_vout->pi_status = THREAD_START;
545 /* Initialize output method - this function issues its own error messages */
546 if( vout_SysInit( p_vout ) )
548 *p_vout->pi_status = THREAD_ERROR;
552 /* Initialize pictures and subtitles */
553 for( i_index = 0; i_index < VOUT_MAX_PICTURES; i_index++)
555 p_vout->p_picture[i_index].i_type = EMPTY_PICTURE;
556 p_vout->p_picture[i_index].i_status = FREE_PICTURE;
557 p_vout->p_subtitle[i_index].i_type = EMPTY_SUBTITLE;
558 p_vout->p_subtitle[i_index].i_status= FREE_SUBTITLE;
561 /* Initialize convertion tables and functions */
562 if( vout_InitTables( p_vout ) )
564 intf_ErrMsg("error: can't allocate translation tables\n");
568 /* Mark thread as running and return */
569 p_vout->b_active = 1;
570 *p_vout->pi_status = THREAD_READY;
571 intf_DbgMsg("thread ready\n");
575 /*******************************************************************************
576 * RunThread: video output thread
577 *******************************************************************************
578 * Video output thread. This function does only returns when the thread is
579 * terminated. It handles the pictures arriving in the video heap and the
580 * display device events.
581 *******************************************************************************/
582 static void RunThread( vout_thread_t *p_vout)
584 int i_picture; /* picture index */
585 mtime_t current_date; /* current date */
586 mtime_t pic_date = 0; /* picture date */
587 boolean_t b_display; /* display flag */
588 picture_t * p_pic; /* picture pointer */
591 * Initialize thread and free configuration
593 p_vout->b_error = InitThread( p_vout );
594 if( p_vout->b_error )
596 free( p_vout ); /* destroy descriptor */
601 * Main loop - it is not executed if an error occured during
604 while( (!p_vout->b_die) && (!p_vout->b_error) )
607 * Find the picture to display - this operation does not need lock,
608 * since only READY_PICTURES are handled
611 current_date = mdate();
612 for( i_picture = 0; i_picture < VOUT_MAX_PICTURES; i_picture++ )
614 if( (p_vout->p_picture[i_picture].i_status == READY_PICTURE) &&
616 (p_vout->p_picture[i_picture].date < pic_date) ) )
618 p_pic = &p_vout->p_picture[i_picture];
619 pic_date = p_pic->date;
624 * Render picture if any
629 /* Computes FPS rate */
630 p_vout->fps_sample[ p_vout->c_fps_samples++ % VOUT_FPS_SAMPLES ] = pic_date;
632 if( pic_date < current_date )
634 /* Picture is late: it will be destroyed and the thread will sleep and
635 * go to next picture */
636 vlc_mutex_lock( &p_vout->picture_lock );
637 p_pic->i_status = p_pic->i_refcount ? DISPLAYED_PICTURE : DESTROYED_PICTURE;
638 vlc_mutex_unlock( &p_vout->picture_lock );
640 intf_DbgMsg( "warning: late picture %p skipped\n", p_pic );
644 else if( pic_date > current_date + VOUT_DISPLAY_DELAY )
646 /* A picture is ready to be rendered, but its rendering date is
647 * far from the current one so the thread will perform an empty loop
648 * as if no picture were found. The picture state is unchanged */
654 * Perform rendering, sleep and display rendered picture
658 /* A picture is ready to be displayed : render it */
659 if( p_vout->b_active )
661 b_display = RenderPicture( p_vout, p_pic, 1 );
664 b_display |= RenderPictureInfo( p_vout, p_pic, b_display );
665 b_display |= RenderInfo( p_vout, b_display );
673 /* Remove picture from heap */
674 vlc_mutex_lock( &p_vout->picture_lock );
675 p_pic->i_status = p_pic->i_refcount ? DISPLAYED_PICTURE : DESTROYED_PICTURE;
676 vlc_mutex_unlock( &p_vout->picture_lock );
680 /* No picture. However, an idle screen may be ready to display */
681 if( p_vout->b_active )
683 b_display = RenderIdle( p_vout, 1 );
686 b_display |= RenderInfo( p_vout, b_display );
695 /* Give back change lock */
696 vlc_mutex_unlock( &p_vout->change_lock );
698 /* Sleep a while or until a given date */
705 msleep( VOUT_IDLE_SLEEP );
708 /* On awakening, take back lock and send immediately picture to display */
709 vlc_mutex_lock( &p_vout->change_lock );
710 if( b_display && p_vout->b_active &&
711 !(p_vout->i_changes & VOUT_NODISPLAY_CHANGE) )
713 vout_SysDisplay( p_vout );
717 * Check events and manage thread
719 if( vout_SysManage( p_vout ) | Manage( p_vout ) )
721 /* A fatal error occured, and the thread must terminate immediately,
722 * without displaying anything - setting b_error to 1 cause the
723 * immediate end of the main while() loop. */
731 if( p_vout->b_error )
733 ErrorThread( p_vout );
738 intf_DbgMsg( "thread end\n" );
741 /*******************************************************************************
742 * ErrorThread: RunThread() error loop
743 *******************************************************************************
744 * This function is called when an error occured during thread main's loop. The
745 * thread can still receive feed, but must be ready to terminate as soon as
747 *******************************************************************************/
748 static void ErrorThread( vout_thread_t *p_vout )
750 /* Wait until a `die' order */
751 while( !p_vout->b_die )
754 msleep( VOUT_IDLE_SLEEP );
758 /*******************************************************************************
759 * EndThread: thread destruction
760 *******************************************************************************
761 * This function is called when the thread ends after a sucessfull
763 *******************************************************************************/
764 static void EndThread( vout_thread_t *p_vout )
766 int * pi_status; /* thread status */
770 pi_status = p_vout->pi_status;
771 *pi_status = THREAD_END;
773 /* Destroy all remaining pictures */
774 for( i_picture = 0; i_picture < VOUT_MAX_PICTURES; i_picture++ )
776 if( p_vout->p_picture[i_picture].i_status != FREE_PICTURE )
778 free( p_vout->p_picture[i_picture].p_data );
782 /* Destroy translation tables */
783 vout_EndTables( p_vout );
785 /* Destroy thread structures allocated by InitThread */
786 vout_SysEnd( p_vout );
787 vout_SysDestroy( p_vout );
791 *pi_status = THREAD_OVER;
794 /*******************************************************************************
795 * RenderBlank: render a blank screen
796 *******************************************************************************
797 * This function is called by all other rendering functions when they arrive on
798 * a non blanked screen.
799 *******************************************************************************/
800 static void RenderBlank( vout_thread_t *p_vout )
803 int i_index; /* current 32 bits sample */
804 int i_width; /* number of 32 bits samples */
805 u32 *p_pic; /* pointer to 32 bits samples */
807 /* Initialize variables */
808 p_pic = vout_SysGetPicture( p_vout );
809 i_width = p_vout->i_bytes_per_line * p_vout->i_height / 128;
811 /* Clear beginning of screen by 128 bytes blocks */
812 for( i_index = 0; i_index < i_width; i_index++ )
814 *p_pic++ = 0; *p_pic++ = 0;
815 *p_pic++ = 0; *p_pic++ = 0;
816 *p_pic++ = 0; *p_pic++ = 0;
817 *p_pic++ = 0; *p_pic++ = 0;
818 *p_pic++ = 0; *p_pic++ = 0;
819 *p_pic++ = 0; *p_pic++ = 0;
820 *p_pic++ = 0; *p_pic++ = 0;
821 *p_pic++ = 0; *p_pic++ = 0;
822 *p_pic++ = 0; *p_pic++ = 0;
823 *p_pic++ = 0; *p_pic++ = 0;
824 *p_pic++ = 0; *p_pic++ = 0;
825 *p_pic++ = 0; *p_pic++ = 0;
826 *p_pic++ = 0; *p_pic++ = 0;
827 *p_pic++ = 0; *p_pic++ = 0;
828 *p_pic++ = 0; *p_pic++ = 0;
829 *p_pic++ = 0; *p_pic++ = 0;
832 /* Clear last pixels */
837 /*******************************************************************************
838 * RenderPicture: render a picture
839 *******************************************************************************
840 * This function convert a picture from a video heap to a pixel-encoded image
841 * and copy it to the current rendering buffer. No lock is required, since the
842 * rendered picture has been determined as existant, and will only be destroyed
843 * by the vout thread later.
844 *******************************************************************************/
845 static int RenderPicture( vout_thread_t *p_vout, picture_t *p_pic, boolean_t b_blank )
847 int i_display_height, i_display_width; /* display dimensions */
848 int i_height, i_width; /* source picture dimensions */
849 int i_scaled_height; /* scaled height of the picture */
850 int i_aspect_scale; /* aspect ratio vertical scale */
851 int i_eol; /* end of line offset for source */
852 byte_t * p_convert_dst; /* convertion destination */
855 /* Start recording render time */
856 p_vout->render_time = mdate();
859 /* Mark last picture date */
860 p_vout->last_picture_date = p_pic->date;
861 i_width = p_pic->i_width;
862 i_height = p_pic->i_height;
863 i_display_width = p_vout->i_width;
864 i_display_height = p_vout->i_height;
866 /* Select scaling depending of aspect ratio */
867 switch( p_pic->i_aspect_ratio )
870 i_aspect_scale = (4 * i_height - 3 * i_width) ?
871 1 + 3 * i_width / ( 4 * i_height - 3 * i_width ) : 0;
873 case AR_16_9_PICTURE:
874 i_aspect_scale = ( 16 * i_height - 9 * i_width ) ?
875 1 + 9 * i_width / ( 16 * i_height - 9 * i_width ) : 0;
877 case AR_221_1_PICTURE:
878 i_aspect_scale = ( 221 * i_height - 100 * i_width ) ?
879 1 + 100 * i_width / ( 221 * i_height - 100 * i_width ) : 0;
881 case AR_SQUARE_PICTURE:
885 i_scaled_height = (i_aspect_scale ? i_height * (i_aspect_scale - 1) / i_aspect_scale : i_height);
887 /* Crop picture if too large for the screen */
888 if( i_width > i_display_width )
890 i_eol = i_width - i_display_width / 16 * 16;
891 i_width = i_display_width / 16 * 16;
897 if( i_scaled_height > i_display_height )
899 i_height = (i_aspect_scale * i_display_height / (i_aspect_scale - 1)) / 2 * 2;
900 i_scaled_height = i_display_height;
902 p_convert_dst = vout_SysGetPicture( p_vout ) +
903 ( i_display_width - i_width ) / 2 * p_vout->i_bytes_per_pixel +
904 ( i_display_height - i_scaled_height ) / 2 * p_vout->i_bytes_per_line;
907 * Choose appropriate rendering function and render picture
909 switch( p_pic->i_type )
911 case YUV_420_PICTURE:
912 p_vout->p_ConvertYUV420( p_vout, p_convert_dst,
913 p_pic->p_y, p_pic->p_u, p_pic->p_v,
914 i_width, i_height, i_eol,
915 p_vout->i_bytes_per_line / p_vout->i_bytes_per_pixel - i_width,
916 i_aspect_scale, p_pic->i_matrix_coefficients );
918 case YUV_422_PICTURE:
919 p_vout->p_ConvertYUV422( p_vout, p_convert_dst,
920 p_pic->p_y, p_pic->p_u, p_pic->p_v,
921 i_width, i_height, i_eol,
922 p_vout->i_bytes_per_line / p_vout->i_bytes_per_pixel - i_width,
923 i_aspect_scale, p_pic->i_matrix_coefficients );
925 case YUV_444_PICTURE:
926 p_vout->p_ConvertYUV444( p_vout, p_convert_dst,
927 p_pic->p_y, p_pic->p_u, p_pic->p_v,
928 i_width, i_height, i_eol,
929 p_vout->i_bytes_per_line / p_vout->i_bytes_per_pixel - i_width,
930 i_aspect_scale, p_pic->i_matrix_coefficients );
934 intf_DbgMsg("error: unknown picture type %d\n", p_pic->i_type );
940 /* End recording render time */
941 p_vout->render_time = mdate() - p_vout->render_time;
946 /*******************************************************************************
947 * RenderPictureInfo: print additionnal informations on a picture
948 *******************************************************************************
949 * This function will print informations such as fps and other picture
950 * dependant informations.
951 *******************************************************************************/
952 static int RenderPictureInfo( vout_thread_t *p_vout, picture_t *p_pic, boolean_t b_blank )
954 char psz_buffer[256]; /* string buffer */
958 * Print FPS rate in upper right corner
960 if( p_vout->c_fps_samples > VOUT_FPS_SAMPLES )
962 sprintf( psz_buffer, "%.2f fps", (double) VOUT_FPS_SAMPLES * 1000000 /
963 ( p_vout->fps_sample[ (p_vout->c_fps_samples - 1) % VOUT_FPS_SAMPLES ] -
964 p_vout->fps_sample[ p_vout->c_fps_samples % VOUT_FPS_SAMPLES ] ) );
965 vout_SysPrint( p_vout, p_vout->i_width, 0, 1, -1, psz_buffer );
969 * Print frames count and loop time in upper left corner
971 sprintf( psz_buffer, "%ld frames render time: %lu us",
972 p_vout->c_fps_samples, (long unsigned) p_vout->render_time );
973 vout_SysPrint( p_vout, 0, 0, -1, -1, psz_buffer );
978 * Print picture information in lower right corner
980 sprintf( psz_buffer, "%s picture %dx%d (%dx%d%+d%+d %s)",
981 (p_pic->i_type == YUV_420_PICTURE) ? "4:2:0" :
982 ((p_pic->i_type == YUV_422_PICTURE) ? "4:2:2" :
983 ((p_pic->i_type == YUV_444_PICTURE) ? "4:4:4" : "ukn-type")),
984 p_pic->i_width, p_pic->i_height,
985 p_pic->i_display_width, p_pic->i_display_height,
986 p_pic->i_display_horizontal_offset, p_pic->i_display_vertical_offset,
987 (p_pic->i_aspect_ratio == AR_SQUARE_PICTURE) ? "sq" :
988 ((p_pic->i_aspect_ratio == AR_3_4_PICTURE) ? "4:3" :
989 ((p_pic->i_aspect_ratio == AR_16_9_PICTURE) ? "16:9" :
990 ((p_pic->i_aspect_ratio == AR_221_1_PICTURE) ? "2.21:1" : "ukn-ar" ))));
991 vout_SysPrint( p_vout, p_vout->i_width, p_vout->i_height, 1, 1, psz_buffer );
997 /*******************************************************************************
998 * RenderIdle: render idle picture
999 *******************************************************************************
1000 * This function will clear the display or print a logo.
1001 *******************************************************************************/
1002 static int RenderIdle( vout_thread_t *p_vout, boolean_t b_blank )
1004 /* Blank screen if required */
1005 if( (mdate() - p_vout->last_picture_date > VOUT_IDLE_DELAY) &&
1006 (p_vout->last_picture_date > p_vout->last_display_date) &&
1009 RenderBlank( p_vout );
1010 p_vout->last_display_date = mdate();
1011 vout_SysPrint( p_vout, p_vout->i_width / 2, p_vout->i_height / 2, 0, 0,
1019 /*******************************************************************************
1020 * RenderInfo: render additionnal informations
1021 *******************************************************************************
1022 * This function render informations which do not depend of the current picture
1024 *******************************************************************************/
1025 static int RenderInfo( vout_thread_t *p_vout, boolean_t b_blank )
1027 char psz_buffer[256]; /* string buffer */
1029 int i_ready_pic = 0; /* ready pictures */
1030 int i_reserved_pic = 0; /* reserved pictures */
1031 int i_picture; /* picture index */
1036 * Print thread state in lower left corner
1038 for( i_picture = 0; i_picture < VOUT_MAX_PICTURES; i_picture++ )
1040 switch( p_vout->p_picture[i_picture].i_status )
1042 case RESERVED_PICTURE:
1043 case RESERVED_DATED_PICTURE:
1044 case RESERVED_DISP_PICTURE:
1052 sprintf( psz_buffer, "%dx%d:%d g%+.2f pic: %d/%d/%d",
1053 p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth,
1054 p_vout->f_gamma, i_reserved_pic, i_ready_pic,
1055 VOUT_MAX_PICTURES );
1056 vout_SysPrint( p_vout, 0, p_vout->i_height, -1, 1, psz_buffer );
1061 /*******************************************************************************
1062 * Manage: manage thread
1063 *******************************************************************************
1064 * This function will handle changes in thread configuration.
1065 *******************************************************************************/
1066 static int Manage( vout_thread_t *p_vout )
1068 /* On gamma or grayscale change, rebuild tables */
1069 if( p_vout->i_changes & (VOUT_GAMMA_CHANGE | VOUT_GRAYSCALE_CHANGE) )
1071 vout_ResetTables( p_vout );
1074 /* Clear changes flags which does not need management or have been handled */
1075 p_vout->i_changes &= ~(VOUT_GAMMA_CHANGE | VOUT_GRAYSCALE_CHANGE |
1078 /* Detect unauthorized changes */
1079 if( p_vout->i_changes )
1081 /* Some changes were not acknowledged by vout_SysManage or this function,
1082 * it means they should not be authorized */
1083 intf_ErrMsg( "error: unauthorized changes in the video output thread\n" );