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 */
59 p_vout = (vout_thread_t *) malloc( sizeof(vout_thread_t) );
62 intf_ErrMsg("error: %s\n", strerror(ENOMEM));
66 /* Initialize thread properties */
70 p_vout->pi_status = (pi_status != NULL) ? pi_status : &i_status;
71 *p_vout->pi_status = THREAD_CREATE;
73 /* Initialize some fields used by the system-dependant method - these fields will
74 * probably be modified by the method, and are only preferences */
75 p_vout->b_grayscale = main_GetIntVariable( VOUT_GRAYSCALE_VAR,
76 VOUT_GRAYSCALE_DEFAULT );
77 p_vout->i_width = i_width;
78 p_vout->i_height = i_height;
79 p_vout->i_bytes_per_line = i_width * 2;
80 p_vout->i_screen_depth = 15;
81 p_vout->i_bytes_per_pixel = 2;
82 p_vout->f_gamma = VOUT_GAMMA;
88 intf_DbgMsg("wished configuration: %dx%d,%d (%d bytes/pixel, %d bytes/line)\n",
89 p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth,
90 p_vout->i_bytes_per_pixel, p_vout->i_bytes_per_line );
92 /* Create and initialize system-dependant method - this function issues its
93 * own error messages */
94 if( vout_SysCreate( p_vout, psz_display, i_root_window ) )
99 intf_DbgMsg("actual configuration: %dx%d,%d (%d bytes/pixel, %d bytes/line)\n",
100 p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth,
101 p_vout->i_bytes_per_pixel, p_vout->i_bytes_per_line );
104 /* Initialize statistics fields */
105 p_vout->render_time = 0;
106 p_vout->c_fps_samples = 0;
109 /* Initialize running properties */
110 p_vout->i_changes = 0;
111 p_vout->last_picture_date = 0;
112 p_vout->last_display_date = 0;
114 /* Create thread and set locks */
115 vlc_mutex_init( &p_vout->picture_lock );
116 vlc_mutex_init( &p_vout->subtitle_lock );
117 vlc_mutex_init( &p_vout->change_lock );
118 vlc_mutex_lock( &p_vout->change_lock );
119 if( vlc_thread_create( &p_vout->thread_id, "video output", (void *) RunThread, (void *) p_vout) )
121 intf_ErrMsg("error: %s\n", strerror(ENOMEM));
122 vout_SysDestroy( p_vout );
127 intf_Msg("Video display initialized (%dx%d, %d bpp)\n",
128 p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth );
130 /* If status is NULL, wait until the thread is created */
131 if( pi_status == NULL )
135 msleep( THREAD_SLEEP );
136 }while( (i_status != THREAD_READY) && (i_status != THREAD_ERROR)
137 && (i_status != THREAD_FATAL) );
138 if( i_status != THREAD_READY )
146 /*******************************************************************************
147 * vout_DestroyThread: destroys a previously created thread
148 *******************************************************************************
149 * Destroy a terminated thread.
150 * The function will request a destruction of the specified thread. If pi_error
151 * is NULL, it will return once the thread is destroyed. Else, it will be
152 * update using one of the THREAD_* constants.
153 *******************************************************************************/
154 void vout_DestroyThread( vout_thread_t *p_vout, int *pi_status )
156 int i_status; /* thread status */
160 p_vout->pi_status = (pi_status != NULL) ? pi_status : &i_status;
161 *p_vout->pi_status = THREAD_DESTROY;
163 /* Request thread destruction */
166 /* If status is NULL, wait until thread has been destroyed */
167 if( pi_status == NULL )
171 msleep( THREAD_SLEEP );
172 }while( (i_status != THREAD_OVER) && (i_status != THREAD_ERROR)
173 && (i_status != THREAD_FATAL) );
177 /*******************************************************************************
178 * vout_DisplaySubtitle: display a subtitle
179 *******************************************************************************
180 * Remove the reservation flag of a subtitle, which will cause it to be ready for
181 * display. The picture does not need to be locked, since it is ignored by
182 * the output thread if is reserved.
183 *******************************************************************************/
184 void vout_DisplaySubtitle( vout_thread_t *p_vout, subtitle_t *p_sub )
187 char psz_begin_date[MSTRTIME_MAX_SIZE]; /* buffer for date string */
188 char psz_end_date[MSTRTIME_MAX_SIZE]; /* buffer for date string */
192 /* Check if status is valid */
193 if( p_sub->i_status != RESERVED_SUBTITLE )
195 intf_DbgMsg("error: subtitle %p has invalid status %d\n", p_sub, p_sub->i_status );
199 /* Remove reservation flag */
200 p_sub->i_status = READY_SUBTITLE;
203 /* Send subtitle informations */
204 intf_DbgMsg("subtitle %p: type=%d, begin date=%s, end date=%s\n", p_sub, p_sub->i_type,
205 mstrtime( psz_begin_date, p_sub->begin_date ),
206 mstrtime( psz_end_date, p_sub->end_date ) );
210 /*******************************************************************************
211 * vout_CreateSubtitle: allocate a subtitle in the video output heap.
212 *******************************************************************************
213 * This function create a reserved subtitle in the video output heap.
214 * A null pointer is returned if the function fails. This method provides an
215 * already allocated zone of memory in the subtitle data fields. It needs locking
216 * since several pictures can be created by several producers threads.
217 *******************************************************************************/
218 subtitle_t *vout_CreateSubtitle( vout_thread_t *p_vout, int i_type,
224 /*******************************************************************************
225 * vout_DestroySubtitle: remove a permanent or reserved subtitle from the heap
226 *******************************************************************************
227 * This function frees a previously reserved subtitle.
228 * It is meant to be used when the construction of a picture aborted.
229 * This function does not need locking since reserved subtitles are ignored by
231 *******************************************************************************/
232 void vout_DestroySubtitle( vout_thread_t *p_vout, subtitle_t *p_sub )
235 /* Check if subtitle status is valid */
236 if( p_sub->i_status != RESERVED_SUBTITLE )
238 intf_DbgMsg("error: subtitle %p has invalid status %d\n", p_sub, p_sub->i_status );
242 p_sub->i_status = DESTROYED_SUBTITLE;
245 intf_DbgMsg("subtitle %p\n", p_sub);
249 /*******************************************************************************
250 * vout_DisplayPicture: display a picture
251 *******************************************************************************
252 * Remove the reservation flag of a picture, which will cause it to be ready for
253 * display. The picture won't be displayed until vout_DatePicture has been
255 *******************************************************************************/
256 void vout_DisplayPicture( vout_thread_t *p_vout, picture_t *p_pic )
258 vlc_mutex_lock( &p_vout->picture_lock );
259 switch( p_pic->i_status )
261 case RESERVED_PICTURE:
262 p_pic->i_status = RESERVED_DISP_PICTURE;
264 case RESERVED_DATED_PICTURE:
265 p_pic->i_status = READY_PICTURE;
269 intf_DbgMsg("error: picture %p has invalid status %d\n", p_pic, p_pic->i_status );
275 intf_DbgMsg("picture %p\n", p_pic );
278 vlc_mutex_unlock( &p_vout->picture_lock );
281 /*******************************************************************************
282 * vout_DatePicture: date a picture
283 *******************************************************************************
284 * Remove the reservation flag of a picture, which will cause it to be ready for
285 * display. The picture won't be displayed until vout_DisplayPicture has been
287 *******************************************************************************/
288 void vout_DatePicture( vout_thread_t *p_vout, picture_t *p_pic, mtime_t date )
290 vlc_mutex_lock( &p_vout->picture_lock );
292 switch( p_pic->i_status )
294 case RESERVED_PICTURE:
295 p_pic->i_status = RESERVED_DATED_PICTURE;
297 case RESERVED_DISP_PICTURE:
298 p_pic->i_status = READY_PICTURE;
302 intf_DbgMsg("error: picture %p has invalid status %d\n", p_pic, p_pic->i_status );
308 intf_DbgMsg("picture %p\n", p_pic);
311 vlc_mutex_unlock( &p_vout->picture_lock );
314 /*******************************************************************************
315 * vout_CreatePicture: allocate a picture in the video output heap.
316 *******************************************************************************
317 * This function create a reserved image in the video output heap.
318 * A null pointer is returned if the function fails. This method provides an
319 * already allocated zone of memory in the picture data fields. It needs locking
320 * since several pictures can be created by several producers threads.
321 *******************************************************************************/
322 picture_t *vout_CreatePicture( vout_thread_t *p_vout, int i_type,
323 int i_width, int i_height )
325 int i_picture; /* picture index */
326 int i_chroma_width = 0; /* chroma width */
327 picture_t * p_free_picture = NULL; /* first free picture */
328 picture_t * p_destroyed_picture = NULL; /* first destroyed picture */
331 vlc_mutex_lock( &p_vout->picture_lock );
334 * Look for an empty place
337 i_picture < VOUT_MAX_PICTURES;
340 if( p_vout->p_picture[i_picture].i_status == DESTROYED_PICTURE )
342 /* Picture is marked for destruction, but is still allocated - note
343 * that if width and type are the same for two pictures, chroma_width
344 * should also be the same */
345 if( (p_vout->p_picture[i_picture].i_type == i_type) &&
346 (p_vout->p_picture[i_picture].i_height == i_height) &&
347 (p_vout->p_picture[i_picture].i_width == i_width) )
349 /* Memory size do match : memory will not be reallocated, and function
350 * can end immediately - this is the best possible case, since no
351 * memory allocation needs to be done */
352 p_vout->p_picture[i_picture].i_status = RESERVED_PICTURE;
354 intf_DbgMsg("picture %p (in destroyed picture slot)\n",
355 &p_vout->p_picture[i_picture] );
357 vlc_mutex_unlock( &p_vout->picture_lock );
358 return( &p_vout->p_picture[i_picture] );
360 else if( p_destroyed_picture == NULL )
362 /* Memory size do not match, but picture index will be kept in
363 * case no other place are left */
364 p_destroyed_picture = &p_vout->p_picture[i_picture];
367 else if( (p_free_picture == NULL) &&
368 (p_vout->p_picture[i_picture].i_status == FREE_PICTURE ))
370 /* Picture is empty and ready for allocation */
371 p_free_picture = &p_vout->p_picture[i_picture];
375 /* If no free picture is available, use a destroyed picture */
376 if( (p_free_picture == NULL) && (p_destroyed_picture != NULL ) )
378 /* No free picture or matching destroyed picture has been found, but
379 * a destroyed picture is still avalaible */
380 free( p_destroyed_picture->p_data );
381 p_free_picture = p_destroyed_picture;
387 if( p_free_picture != NULL )
389 /* Allocate memory */
392 case YUV_420_PICTURE: /* YUV 420: 1,1/4,1/4 samples per pixel */
393 i_chroma_width = i_width / 2;
394 p_free_picture->p_data = malloc( i_height * i_chroma_width * 3 * sizeof( yuv_data_t ) );
395 p_free_picture->p_y = (yuv_data_t *)p_free_picture->p_data;
396 p_free_picture->p_u = (yuv_data_t *)p_free_picture->p_data +i_height*i_chroma_width*4/2;
397 p_free_picture->p_v = (yuv_data_t *)p_free_picture->p_data +i_height*i_chroma_width*5/2;
399 case YUV_422_PICTURE: /* YUV 422: 1,1/2,1/2 samples per pixel */
400 i_chroma_width = i_width / 2;
401 p_free_picture->p_data = malloc( i_height * i_chroma_width * 4 * sizeof( yuv_data_t ) );
402 p_free_picture->p_y = (yuv_data_t *)p_free_picture->p_data;
403 p_free_picture->p_u = (yuv_data_t *)p_free_picture->p_data +i_height*i_chroma_width*2;
404 p_free_picture->p_v = (yuv_data_t *)p_free_picture->p_data +i_height*i_chroma_width*3;
406 case YUV_444_PICTURE: /* YUV 444: 1,1,1 samples per pixel */
407 i_chroma_width = i_width;
408 p_free_picture->p_data = malloc( i_height * i_chroma_width * 3 * sizeof( yuv_data_t ) );
409 p_free_picture->p_y = (yuv_data_t *)p_free_picture->p_data;
410 p_free_picture->p_u = (yuv_data_t *)p_free_picture->p_data +i_height*i_chroma_width;
411 p_free_picture->p_v = (yuv_data_t *)p_free_picture->p_data +i_height*i_chroma_width*2;
415 intf_DbgMsg("error: unknown picture type %d\n", i_type );
416 p_free_picture->p_data = NULL;
421 if( p_free_picture->p_data != NULL )
423 /* Copy picture informations, set some default values */
424 p_free_picture->i_type = i_type;
425 p_free_picture->i_status = RESERVED_PICTURE;
426 p_free_picture->i_matrix_coefficients = 1;
427 p_free_picture->i_width = i_width;
428 p_free_picture->i_height = i_height;
429 p_free_picture->i_chroma_width = i_chroma_width;
430 p_free_picture->i_display_horizontal_offset = 0;
431 p_free_picture->i_display_vertical_offset = 0;
432 p_free_picture->i_display_width = i_width;
433 p_free_picture->i_display_height = i_height;
434 p_free_picture->i_aspect_ratio = AR_SQUARE_PICTURE;
435 p_free_picture->i_refcount = 0;
439 /* Memory allocation failed : set picture as empty */
440 p_free_picture->i_type = EMPTY_PICTURE;
441 p_free_picture->i_status = FREE_PICTURE;
442 p_free_picture = NULL;
443 intf_ErrMsg("warning: %s\n", strerror( ENOMEM ) );
447 intf_DbgMsg("picture %p (in free picture slot)\n", p_free_picture );
449 vlc_mutex_unlock( &p_vout->picture_lock );
450 return( p_free_picture );
453 // No free or destroyed picture could be found
454 intf_DbgMsg( "warning: heap is full\n" );
455 vlc_mutex_unlock( &p_vout->picture_lock );
459 /*******************************************************************************
460 * vout_DestroyPicture: remove a permanent or reserved picture from the heap
461 *******************************************************************************
462 * This function frees a previously reserved picture or a permanent
463 * picture. It is meant to be used when the construction of a picture aborted.
464 * Note that the picture will be destroyed even if it is linked !
465 * This function does not need locking since reserved pictures are ignored by
467 *******************************************************************************/
468 void vout_DestroyPicture( vout_thread_t *p_vout, picture_t *p_pic )
471 /* Check if picture status is valid */
472 if( (p_pic->i_status != RESERVED_PICTURE) &&
473 (p_pic->i_status != RESERVED_DATED_PICTURE) &&
474 (p_pic->i_status != RESERVED_DISP_PICTURE) )
476 intf_DbgMsg("error: picture %p has invalid status %d\n", p_pic, p_pic->i_status );
480 p_pic->i_status = DESTROYED_PICTURE;
483 intf_DbgMsg("picture %p\n", p_pic);
487 /*******************************************************************************
488 * vout_LinkPicture: increment reference counter of a picture
489 *******************************************************************************
490 * This function increment the reference counter of a picture in the video
491 * heap. It needs a lock since several producer threads can access the picture.
492 *******************************************************************************/
493 void vout_LinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
495 vlc_mutex_lock( &p_vout->picture_lock );
499 intf_DbgMsg("picture %p refcount=%d\n", p_pic, p_pic->i_refcount );
502 vlc_mutex_unlock( &p_vout->picture_lock );
505 /*******************************************************************************
506 * vout_UnlinkPicture: decrement reference counter of a picture
507 *******************************************************************************
508 * This function decrement the reference counter of a picture in the video heap.
509 *******************************************************************************/
510 void vout_UnlinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
512 vlc_mutex_lock( &p_vout->picture_lock );
516 if( p_pic->i_refcount < 0 )
518 intf_DbgMsg("error: refcount < 0\n");
519 p_pic->i_refcount = 0;
523 if( (p_pic->i_refcount == 0) && (p_pic->i_status == DISPLAYED_PICTURE) )
525 p_pic->i_status = DESTROYED_PICTURE;
529 intf_DbgMsg("picture %p refcount=%d\n", p_pic, p_pic->i_refcount );
532 vlc_mutex_unlock( &p_vout->picture_lock );
535 /* following functions are local */
537 /*******************************************************************************
538 * InitThread: initialize video output thread
539 *******************************************************************************
540 * This function is called from RunThread and performs the second step of the
541 * initialization. It returns 0 on success. Note that the thread's flag are not
542 * modified inside this function.
543 *******************************************************************************/
544 static int InitThread( vout_thread_t *p_vout )
546 int i_index; /* generic index */
550 *p_vout->pi_status = THREAD_START;
552 /* Initialize output method - this function issues its own error messages */
553 if( vout_SysInit( p_vout ) )
555 *p_vout->pi_status = THREAD_ERROR;
559 /* Initialize pictures and subtitles */
560 for( i_index = 0; i_index < VOUT_MAX_PICTURES; i_index++)
562 p_vout->p_picture[i_index].i_type = EMPTY_PICTURE;
563 p_vout->p_picture[i_index].i_status = FREE_PICTURE;
564 p_vout->p_subtitle[i_index].i_type = EMPTY_SUBTITLE;
565 p_vout->p_subtitle[i_index].i_status= FREE_SUBTITLE;
568 /* Initialize convertion tables and functions */
569 if( vout_InitTables( p_vout ) )
571 intf_ErrMsg("error: can't allocate translation tables\n");
575 /* Mark thread as running and return */
576 p_vout->b_active = 1;
577 *p_vout->pi_status = THREAD_READY;
578 intf_DbgMsg("thread ready\n");
582 /*******************************************************************************
583 * RunThread: video output thread
584 *******************************************************************************
585 * Video output thread. This function does only returns when the thread is
586 * terminated. It handles the pictures arriving in the video heap and the
587 * display device events.
588 *******************************************************************************/
589 static void RunThread( vout_thread_t *p_vout)
591 int i_picture; /* picture index */
592 mtime_t current_date; /* current date */
593 mtime_t pic_date = 0; /* picture date */
594 boolean_t b_display; /* display flag */
595 picture_t * p_pic; /* picture pointer */
598 * Initialize thread and free configuration
600 p_vout->b_error = InitThread( p_vout );
601 if( p_vout->b_error )
603 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 current_date = mdate();
620 for( i_picture = 0; i_picture < VOUT_MAX_PICTURES; i_picture++ )
622 if( (p_vout->p_picture[i_picture].i_status == READY_PICTURE) &&
624 (p_vout->p_picture[i_picture].date < pic_date) ) )
626 p_pic = &p_vout->p_picture[i_picture];
627 pic_date = p_pic->date;
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->picture_lock );
645 p_pic->i_status = p_pic->i_refcount ? DISPLAYED_PICTURE : DESTROYED_PICTURE;
647 intf_DbgMsg( "warning: late picture %p skipped refcount=%d\n", p_pic, p_pic->i_refcount );
649 vlc_mutex_unlock( &p_vout->picture_lock );
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 */
662 * Perform rendering, sleep and display rendered picture
666 /* A picture is ready to be displayed : render it */
667 if( p_vout->b_active )
669 b_display = RenderPicture( p_vout, p_pic, 1 );
672 b_display |= RenderPictureInfo( p_vout, p_pic, b_display );
673 b_display |= RenderInfo( p_vout, b_display );
681 /* Remove picture from heap */
682 vlc_mutex_lock( &p_vout->picture_lock );
683 p_pic->i_status = p_pic->i_refcount ? DISPLAYED_PICTURE : DESTROYED_PICTURE;
684 vlc_mutex_unlock( &p_vout->picture_lock );
688 /* No picture. However, an idle screen may be ready to display */
689 if( p_vout->b_active )
691 b_display = RenderIdle( p_vout, 1 );
694 b_display |= RenderInfo( p_vout, b_display );
703 /* Give back change lock */
704 vlc_mutex_unlock( &p_vout->change_lock );
706 /* Sleep a while or until a given date */
713 msleep( VOUT_IDLE_SLEEP );
716 /* On awakening, take back lock and send immediately picture to display */
717 vlc_mutex_lock( &p_vout->change_lock );
718 if( b_display && p_vout->b_active &&
719 !(p_vout->i_changes & VOUT_NODISPLAY_CHANGE) )
721 vout_SysDisplay( p_vout );
725 * Check events and manage thread
727 if( vout_SysManage( p_vout ) | Manage( p_vout ) )
729 /* A fatal error occured, and the thread must terminate immediately,
730 * without displaying anything - setting b_error to 1 cause the
731 * immediate end of the main while() loop. */
739 if( p_vout->b_error )
741 ErrorThread( p_vout );
746 intf_DbgMsg( "thread end\n" );
749 /*******************************************************************************
750 * ErrorThread: RunThread() error loop
751 *******************************************************************************
752 * This function is called when an error occured during thread main's loop. The
753 * thread can still receive feed, but must be ready to terminate as soon as
755 *******************************************************************************/
756 static void ErrorThread( vout_thread_t *p_vout )
758 /* Wait until a `die' order */
760 while( !p_vout->b_die )
763 msleep( VOUT_IDLE_SLEEP );
767 /*******************************************************************************
768 * EndThread: thread destruction
769 *******************************************************************************
770 * This function is called when the thread ends after a sucessfull
772 *******************************************************************************/
773 static void EndThread( vout_thread_t *p_vout )
775 int * pi_status; /* thread status */
780 pi_status = p_vout->pi_status;
781 *pi_status = THREAD_END;
783 /* Destroy all remaining pictures */
784 for( i_picture = 0; i_picture < VOUT_MAX_PICTURES; i_picture++ )
786 if( p_vout->p_picture[i_picture].i_status != FREE_PICTURE )
788 free( p_vout->p_picture[i_picture].p_data );
792 /* Destroy translation tables */
793 vout_EndTables( p_vout );
795 /* Destroy thread structures allocated by InitThread */
796 vout_SysEnd( p_vout );
797 vout_SysDestroy( p_vout );
801 *pi_status = THREAD_OVER;
804 /*******************************************************************************
805 * RenderBlank: render a blank screen
806 *******************************************************************************
807 * This function is called by all other rendering functions when they arrive on
808 * a non blanked screen.
809 *******************************************************************************/
810 static void RenderBlank( vout_thread_t *p_vout )
813 int i_index; /* current 64 bits sample */
814 int i_width; /* number of 64 bits samples */
815 u64 *p_pic; /* pointer to 64 bits samples */
817 /* Initialize variables */
818 p_pic = vout_SysGetPicture( p_vout );
819 i_width = p_vout->i_bytes_per_line * p_vout->i_height / 256;
821 /* Clear beginning of screen by 256 bytes blocks */
822 for( i_index = 0; i_index < i_width; i_index++ )
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;
830 *p_pic++ = 0; *p_pic++ = 0;
831 *p_pic++ = 0; *p_pic++ = 0;
832 *p_pic++ = 0; *p_pic++ = 0;
833 *p_pic++ = 0; *p_pic++ = 0;
834 *p_pic++ = 0; *p_pic++ = 0;
835 *p_pic++ = 0; *p_pic++ = 0;
836 *p_pic++ = 0; *p_pic++ = 0;
837 *p_pic++ = 0; *p_pic++ = 0;
838 *p_pic++ = 0; *p_pic++ = 0;
839 *p_pic++ = 0; *p_pic++ = 0;
842 /* Clear last pixels */
847 /*******************************************************************************
848 * RenderPicture: render a picture
849 *******************************************************************************
850 * This function convert a picture from a video heap to a pixel-encoded image
851 * and copy it to the current rendering buffer. No lock is required, since the
852 * rendered picture has been determined as existant, and will only be destroyed
853 * by the vout thread later.
854 *******************************************************************************/
855 static int RenderPicture( vout_thread_t *p_vout, picture_t *p_pic, boolean_t b_blank )
857 int i_display_height, i_display_width; /* display dimensions */
858 int i_height, i_width; /* source picture dimensions */
859 int i_scaled_height; /* scaled height of the picture */
860 int i_aspect_scale; /* aspect ratio vertical scale */
861 int i_eol; /* end of line offset for source */
862 byte_t * p_convert_dst; /* convertion destination */
865 /* Start recording render time */
866 p_vout->render_time = mdate();
869 /* Mark last picture date */
870 p_vout->last_picture_date = p_pic->date;
871 i_width = p_pic->i_width;
872 i_height = p_pic->i_height;
873 i_display_width = p_vout->i_width;
874 i_display_height = p_vout->i_height;
876 /* Select scaling depending of aspect ratio */
877 switch( p_pic->i_aspect_ratio )
880 i_aspect_scale = (4 * i_height - 3 * i_width) ?
881 1 + 3 * i_width / ( 4 * i_height - 3 * i_width ) : 0;
883 case AR_16_9_PICTURE:
884 i_aspect_scale = ( 16 * i_height - 9 * i_width ) ?
885 1 + 9 * i_width / ( 16 * i_height - 9 * i_width ) : 0;
887 case AR_221_1_PICTURE:
888 i_aspect_scale = ( 221 * i_height - 100 * i_width ) ?
889 1 + 100 * i_width / ( 221 * i_height - 100 * i_width ) : 0;
891 case AR_SQUARE_PICTURE:
895 i_scaled_height = (i_aspect_scale ? i_height * (i_aspect_scale - 1) / i_aspect_scale : i_height);
897 /* Crop picture if too large for the screen */
898 if( i_width > i_display_width )
900 i_eol = i_width - i_display_width / 16 * 16;
901 i_width = i_display_width / 16 * 16;
907 if( i_scaled_height > i_display_height )
909 i_height = (i_aspect_scale * i_display_height / (i_aspect_scale - 1)) / 2 * 2;
910 i_scaled_height = i_display_height;
912 p_convert_dst = vout_SysGetPicture( p_vout ) +
913 ( i_display_width - i_width ) / 2 * p_vout->i_bytes_per_pixel +
914 ( i_display_height - i_scaled_height ) / 2 * p_vout->i_bytes_per_line;
917 * Choose appropriate rendering function and render picture
919 switch( p_pic->i_type )
921 case YUV_420_PICTURE:
922 p_vout->p_ConvertYUV420( p_vout, p_convert_dst,
923 p_pic->p_y, p_pic->p_u, p_pic->p_v,
924 i_width, i_height, i_eol,
925 p_vout->i_bytes_per_line / p_vout->i_bytes_per_pixel - i_width,
926 i_aspect_scale, p_pic->i_matrix_coefficients );
928 case YUV_422_PICTURE:
929 p_vout->p_ConvertYUV422( p_vout, p_convert_dst,
930 p_pic->p_y, p_pic->p_u, p_pic->p_v,
931 i_width, i_height, i_eol,
932 p_vout->i_bytes_per_line / p_vout->i_bytes_per_pixel - i_width,
933 i_aspect_scale, p_pic->i_matrix_coefficients );
935 case YUV_444_PICTURE:
936 p_vout->p_ConvertYUV444( p_vout, p_convert_dst,
937 p_pic->p_y, p_pic->p_u, p_pic->p_v,
938 i_width, i_height, i_eol,
939 p_vout->i_bytes_per_line / p_vout->i_bytes_per_pixel - i_width,
940 i_aspect_scale, p_pic->i_matrix_coefficients );
944 intf_DbgMsg("error: unknown picture type %d\n", p_pic->i_type );
950 /* End recording render time */
951 p_vout->render_time = mdate() - p_vout->render_time;
956 /*******************************************************************************
957 * RenderPictureInfo: print additionnal informations on a picture
958 *******************************************************************************
959 * This function will print informations such as fps and other picture
960 * dependant informations.
961 *******************************************************************************/
962 static int RenderPictureInfo( vout_thread_t *p_vout, picture_t *p_pic, boolean_t b_blank )
964 char psz_buffer[256]; /* string buffer */
968 * Print FPS rate in upper right corner
970 if( p_vout->c_fps_samples > VOUT_FPS_SAMPLES )
972 sprintf( psz_buffer, "%.2f fps", (double) VOUT_FPS_SAMPLES * 1000000 /
973 ( p_vout->fps_sample[ (p_vout->c_fps_samples - 1) % VOUT_FPS_SAMPLES ] -
974 p_vout->fps_sample[ p_vout->c_fps_samples % VOUT_FPS_SAMPLES ] ) );
975 vout_SysPrint( p_vout, p_vout->i_width, 0, 1, -1, psz_buffer );
979 * Print frames count and loop time in upper left corner
981 sprintf( psz_buffer, "%ld frames render time: %lu us",
982 p_vout->c_fps_samples, (long unsigned) p_vout->render_time );
983 vout_SysPrint( p_vout, 0, 0, -1, -1, psz_buffer );
988 * Print picture information in lower right corner
990 sprintf( psz_buffer, "%s picture %dx%d (%dx%d%+d%+d %s)",
991 (p_pic->i_type == YUV_420_PICTURE) ? "4:2:0" :
992 ((p_pic->i_type == YUV_422_PICTURE) ? "4:2:2" :
993 ((p_pic->i_type == YUV_444_PICTURE) ? "4:4:4" : "ukn-type")),
994 p_pic->i_width, p_pic->i_height,
995 p_pic->i_display_width, p_pic->i_display_height,
996 p_pic->i_display_horizontal_offset, p_pic->i_display_vertical_offset,
997 (p_pic->i_aspect_ratio == AR_SQUARE_PICTURE) ? "sq" :
998 ((p_pic->i_aspect_ratio == AR_3_4_PICTURE) ? "4:3" :
999 ((p_pic->i_aspect_ratio == AR_16_9_PICTURE) ? "16:9" :
1000 ((p_pic->i_aspect_ratio == AR_221_1_PICTURE) ? "2.21:1" : "ukn-ar" ))));
1001 vout_SysPrint( p_vout, p_vout->i_width, p_vout->i_height, 1, 1, psz_buffer );
1007 /*******************************************************************************
1008 * RenderIdle: render idle picture
1009 *******************************************************************************
1010 * This function will clear the display or print a logo.
1011 *******************************************************************************/
1012 static int RenderIdle( vout_thread_t *p_vout, boolean_t b_blank )
1014 /* Blank screen if required */
1015 if( (mdate() - p_vout->last_picture_date > VOUT_IDLE_DELAY) &&
1016 (p_vout->last_picture_date > p_vout->last_display_date) &&
1019 RenderBlank( p_vout );
1020 p_vout->last_display_date = mdate();
1021 vout_SysPrint( p_vout, p_vout->i_width / 2, p_vout->i_height / 2, 0, 0,
1029 /*******************************************************************************
1030 * RenderInfo: render additionnal informations
1031 *******************************************************************************
1032 * This function render informations which do not depend of the current picture
1034 *******************************************************************************/
1035 static int RenderInfo( vout_thread_t *p_vout, boolean_t b_blank )
1037 char psz_buffer[256]; /* string buffer */
1039 int i_ready_pic = 0; /* ready pictures */
1040 int i_reserved_pic = 0; /* reserved pictures */
1041 int i_picture; /* picture index */
1046 * Print thread state in lower left corner
1048 for( i_picture = 0; i_picture < VOUT_MAX_PICTURES; i_picture++ )
1050 switch( p_vout->p_picture[i_picture].i_status )
1052 case RESERVED_PICTURE:
1053 case RESERVED_DATED_PICTURE:
1054 case RESERVED_DISP_PICTURE:
1062 sprintf( psz_buffer, "%dx%d:%d g%+.2f pic: %d/%d/%d",
1063 p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth,
1064 p_vout->f_gamma, i_reserved_pic, i_ready_pic,
1065 VOUT_MAX_PICTURES );
1066 vout_SysPrint( p_vout, 0, p_vout->i_height, -1, 1, psz_buffer );
1071 /*******************************************************************************
1072 * Manage: manage thread
1073 *******************************************************************************
1074 * This function will handle changes in thread configuration.
1075 *******************************************************************************/
1076 static int Manage( vout_thread_t *p_vout )
1078 /* On gamma or grayscale change, rebuild tables */
1079 if( p_vout->i_changes & (VOUT_GAMMA_CHANGE | VOUT_GRAYSCALE_CHANGE) )
1081 vout_ResetTables( p_vout );
1084 /* Clear changes flags which does not need management or have been handled */
1085 p_vout->i_changes &= ~(VOUT_GAMMA_CHANGE | VOUT_GRAYSCALE_CHANGE |
1088 /* Detect unauthorized changes */
1089 if( p_vout->i_changes )
1091 /* Some changes were not acknowledged by vout_SysManage or this function,
1092 * it means they should not be authorized */
1093 intf_ErrMsg( "error: unauthorized changes in the video output thread\n" );