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 */
79 p_vout->b_grayscale = main_GetIntVariable( VOUT_GRAYSCALE_VAR,
80 VOUT_GRAYSCALE_DEFAULT );
81 p_vout->i_width = i_width;
82 p_vout->i_height = i_height;
83 p_vout->i_bytes_per_line = i_width * 2;
84 p_vout->i_screen_depth = 15;
85 p_vout->i_bytes_per_pixel = 2;
86 p_vout->i_horizontal_scale = 0;
87 p_vout->i_vertical_scale = 0;
88 p_vout->f_gamma = VOUT_GAMMA;
89 intf_DbgMsg("wished configuration: %dx%d,%d (%d bytes/pixel, %d bytes/line), scaling %+d:%+d, gray=%d\n",
90 p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth,
91 p_vout->i_bytes_per_pixel, p_vout->i_bytes_per_line,
92 p_vout->i_horizontal_scale, p_vout->i_vertical_scale, p_vout->b_grayscale );
94 /* Create and initialize system-dependant method - this function issues its
95 * own error messages */
96 if( vout_SysCreate( p_vout, psz_display, i_root_window ) )
101 intf_DbgMsg("actual configuration: %dx%d,%d (%d bytes/pixel, %d bytes/line), scaling %+d:%+d, gray=%d\n",
102 p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth,
103 p_vout->i_bytes_per_pixel, p_vout->i_bytes_per_line,
104 p_vout->i_horizontal_scale, p_vout->i_vertical_scale, p_vout->b_grayscale );
107 /* Initialize statistics fields */
108 p_vout->render_time = 0;
109 p_vout->c_fps_samples = 0;
112 /* Initialize running properties */
113 p_vout->i_changes = 0;
114 p_vout->last_picture_date = 0;
115 p_vout->last_display_date = 0;
117 /* Create thread and set locks */
118 vlc_mutex_init( &p_vout->picture_lock );
119 vlc_mutex_init( &p_vout->subtitle_lock );
120 vlc_mutex_init( &p_vout->change_lock );
121 vlc_mutex_lock( &p_vout->change_lock );
122 if( vlc_thread_create( &p_vout->thread_id, "video output", (void *) RunThread, (void *) p_vout) )
124 intf_ErrMsg("error: %s\n", strerror(ENOMEM));
125 vout_SysDestroy( p_vout );
130 intf_Msg("Video: display initialized (%dx%d, %d bpp)\n",
131 p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth );
133 /* If status is NULL, wait until the thread is created */
134 if( pi_status == NULL )
138 msleep( THREAD_SLEEP );
139 }while( (i_status != THREAD_READY) && (i_status != THREAD_ERROR)
140 && (i_status != THREAD_FATAL) );
141 if( i_status != THREAD_READY )
149 /*******************************************************************************
150 * vout_DestroyThread: destroys a previously created thread
151 *******************************************************************************
152 * Destroy a terminated thread.
153 * The function will request a destruction of the specified thread. If pi_error
154 * is NULL, it will return once the thread is destroyed. Else, it will be
155 * update using one of the THREAD_* constants.
156 *******************************************************************************/
157 void vout_DestroyThread( vout_thread_t *p_vout, int *pi_status )
159 int i_status; /* thread status */
162 p_vout->pi_status = (pi_status != NULL) ? pi_status : &i_status;
163 *p_vout->pi_status = THREAD_DESTROY;
165 /* Request thread destruction */
168 /* If status is NULL, wait until thread has been destroyed */
169 if( pi_status == NULL )
173 msleep( THREAD_SLEEP );
174 }while( (i_status != THREAD_OVER) && (i_status != THREAD_ERROR)
175 && (i_status != THREAD_FATAL) );
179 /*******************************************************************************
180 * vout_DisplaySubtitle: display a subtitle
181 *******************************************************************************
182 * Remove the reservation flag of a subtitle, which will cause it to be ready for
183 * display. The picture does not need to be locked, since it is ignored by
184 * the output thread if is reserved.
185 *******************************************************************************/
186 void vout_DisplaySubtitle( vout_thread_t *p_vout, subtitle_t *p_sub )
189 char psz_begin_date[MSTRTIME_MAX_SIZE]; /* buffer for date string */
190 char psz_end_date[MSTRTIME_MAX_SIZE]; /* buffer for date string */
194 /* Check if status is valid */
195 if( p_sub->i_status != RESERVED_SUBTITLE )
197 intf_DbgMsg("error: subtitle %p has invalid status %d\n", p_sub, p_sub->i_status );
201 /* Remove reservation flag */
202 p_sub->i_status = READY_SUBTITLE;
205 /* Send subtitle informations */
206 intf_DbgMsg("subtitle %p: type=%d, begin date=%s, end date=%s\n", p_sub, p_sub->i_type,
207 mstrtime( psz_begin_date, p_sub->begin_date ),
208 mstrtime( psz_end_date, p_sub->end_date ) );
212 /*******************************************************************************
213 * vout_CreateSubtitle: allocate a subtitle in the video output heap.
214 *******************************************************************************
215 * This function create a reserved subtitle in the video output heap.
216 * A null pointer is returned if the function fails. This method provides an
217 * already allocated zone of memory in the subtitle data fields. It needs locking
218 * since several pictures can be created by several producers threads.
219 *******************************************************************************/
220 subtitle_t *vout_CreateSubtitle( vout_thread_t *p_vout, int i_type,
226 /*******************************************************************************
227 * vout_DestroySubtitle: remove a permanent or reserved subtitle from the heap
228 *******************************************************************************
229 * This function frees a previously reserved subtitle.
230 * It is meant to be used when the construction of a picture aborted.
231 * This function does not need locking since reserved subtitles are ignored by
233 *******************************************************************************/
234 void vout_DestroySubtitle( vout_thread_t *p_vout, subtitle_t *p_sub )
237 /* Check if subtitle status is valid */
238 if( p_sub->i_status != RESERVED_SUBTITLE )
240 intf_DbgMsg("error: subtitle %p has invalid status %d\n", p_sub, p_sub->i_status );
244 p_sub->i_status = DESTROYED_SUBTITLE;
247 intf_DbgMsg("subtitle %p\n", p_sub);
251 /*******************************************************************************
252 * vout_DisplayPicture: display a picture
253 *******************************************************************************
254 * Remove the reservation flag of a picture, which will cause it to be ready for
255 * display. The picture does not need to be locked, since it is ignored by
256 * the output thread if is reserved. The picture won't be displayed until
257 * vout_DatePicture has been called.
258 *******************************************************************************/
259 void vout_DisplayPicture( vout_thread_t *p_vout, picture_t *p_pic )
262 char psz_date[MSTRTIME_MAX_SIZE]; /* buffer for date string */
266 /* Check if picture status is valid */
267 if( p_pic->i_status != RESERVED_PICTURE )
269 intf_DbgMsg("error: picture %p has invalid status %d\n", p_pic, p_pic->i_status );
273 /* Remove reservation flag */
274 p_pic->i_status = READY_PICTURE;
277 /* Send picture informations */
278 intf_DbgMsg("picture %p: type=%d, %dx%d, date=%s\n", p_pic, p_pic->i_type,
279 p_pic->i_width,p_pic->i_height, mstrtime( psz_date, p_pic->date ) );
283 /*******************************************************************************
284 * vout_DatePicture: date a picture
285 *******************************************************************************
286 * Remove the reservation flag of a picture, which will cause it to be ready for
287 * display. The picture does not need to be locked, since it is ignored by
288 * the output thread if is reserved. The picture won't be displayed until
289 * vout_DisplayPicture has been called.
290 *******************************************************************************/
291 void vout_DatePicture( vout_thread_t *p_vout, picture_t *p_pic, mtime_t date )
296 /*******************************************************************************
297 * vout_CreatePicture: allocate a picture in the video output heap.
298 *******************************************************************************
299 * This function create a reserved image in the video output heap.
300 * A null pointer is returned if the function fails. This method provides an
301 * already allocated zone of memory in the picture data fields. It needs locking
302 * since several pictures can be created by several producers threads.
303 *******************************************************************************/
304 picture_t *vout_CreatePicture( vout_thread_t *p_vout, int i_type,
305 int i_width, int i_height )
307 int i_picture; /* picture index */
308 int i_chroma_width = 0; /* chroma width */
309 picture_t * p_free_picture = NULL; /* first free picture */
310 picture_t * p_destroyed_picture = NULL; /* first destroyed picture */
313 vlc_mutex_lock( &p_vout->picture_lock );
316 * Look for an empty place
319 i_picture < VOUT_MAX_PICTURES;
322 if( p_vout->p_picture[i_picture].i_status == DESTROYED_PICTURE )
324 /* Picture is marked for destruction, but is still allocated - note
325 * that if width and type are the same for two pictures, chroma_width
326 * should also be the same */
327 if( (p_vout->p_picture[i_picture].i_type == i_type) &&
328 (p_vout->p_picture[i_picture].i_height == i_height) &&
329 (p_vout->p_picture[i_picture].i_width == i_width) )
331 /* Memory size do match : memory will not be reallocated, and function
332 * can end immediately - this is the best possible case, since no
333 * memory allocation needs to be done */
334 p_vout->p_picture[i_picture].i_status = RESERVED_PICTURE;
336 intf_DbgMsg("picture %p (in destroyed picture slot)\n",
337 &p_vout->p_picture[i_picture] );
339 vlc_mutex_unlock( &p_vout->picture_lock );
340 return( &p_vout->p_picture[i_picture] );
342 else if( p_destroyed_picture == NULL )
344 /* Memory size do not match, but picture index will be kept in
345 * case no other place are left */
346 p_destroyed_picture = &p_vout->p_picture[i_picture];
349 else if( (p_free_picture == NULL) &&
350 (p_vout->p_picture[i_picture].i_status == FREE_PICTURE ))
352 /* Picture is empty and ready for allocation */
353 p_free_picture = &p_vout->p_picture[i_picture];
357 /* If no free picture is available, use a destroyed picture */
358 if( (p_free_picture == NULL) && (p_destroyed_picture != NULL ) )
360 /* No free picture or matching destroyed picture has been found, but
361 * a destroyed picture is still avalaible */
362 free( p_destroyed_picture->p_data );
363 p_free_picture = p_destroyed_picture;
369 if( p_free_picture != NULL )
371 /* Allocate memory */
374 case YUV_420_PICTURE: /* YUV 420: 1,1/4,1/4 samples per pixel */
375 i_chroma_width = i_width / 2;
376 p_free_picture->p_data = malloc( i_height * i_chroma_width * 3 * sizeof( yuv_data_t ) );
377 p_free_picture->p_y = (yuv_data_t *)p_free_picture->p_data;
378 p_free_picture->p_u = (yuv_data_t *)p_free_picture->p_data +i_height*i_chroma_width*4/2;
379 p_free_picture->p_v = (yuv_data_t *)p_free_picture->p_data +i_height*i_chroma_width*5/2;
381 case YUV_422_PICTURE: /* YUV 422: 1,1/2,1/2 samples per pixel */
382 i_chroma_width = i_width / 2;
383 p_free_picture->p_data = malloc( i_height * i_chroma_width * 4 * sizeof( yuv_data_t ) );
384 p_free_picture->p_y = (yuv_data_t *)p_free_picture->p_data;
385 p_free_picture->p_u = (yuv_data_t *)p_free_picture->p_data +i_height*i_chroma_width*2;
386 p_free_picture->p_v = (yuv_data_t *)p_free_picture->p_data +i_height*i_chroma_width*3;
388 case YUV_444_PICTURE: /* YUV 444: 1,1,1 samples per pixel */
389 i_chroma_width = i_width;
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;
393 p_free_picture->p_v = (yuv_data_t *)p_free_picture->p_data +i_height*i_chroma_width*2;
397 intf_DbgMsg("error: unknown picture type %d\n", i_type );
398 p_free_picture->p_data = NULL;
403 if( p_free_picture->p_data != NULL )
405 /* Copy picture informations, set some default values */
406 p_free_picture->i_type = i_type;
407 p_free_picture->i_status = RESERVED_PICTURE;
408 p_free_picture->i_matrix_coefficients = 1;
409 p_free_picture->i_width = i_width;
410 p_free_picture->i_height = i_height;
411 p_free_picture->i_chroma_width = i_chroma_width;
412 p_free_picture->i_display_horizontal_offset = 0;
413 p_free_picture->i_display_vertical_offset = 0;
414 p_free_picture->i_display_width = i_width;
415 p_free_picture->i_display_height = i_height;
416 p_free_picture->i_aspect_ratio = AR_SQUARE_PICTURE;
417 p_free_picture->i_refcount = 0;
421 /* Memory allocation failed : set picture as empty */
422 p_free_picture->i_type = EMPTY_PICTURE;
423 p_free_picture->i_status = FREE_PICTURE;
424 p_free_picture = NULL;
425 intf_ErrMsg("warning: %s\n", strerror( ENOMEM ) );
429 intf_DbgMsg("picture %p (in free picture slot)\n", p_free_picture );
431 vlc_mutex_unlock( &p_vout->picture_lock );
432 return( p_free_picture );
435 // No free or destroyed picture could be found
436 intf_DbgMsg( "warning: heap is full\n" );
437 vlc_mutex_unlock( &p_vout->picture_lock );
441 /*******************************************************************************
442 * vout_DestroyPicture: remove a permanent or reserved picture from the heap
443 *******************************************************************************
444 * This function frees a previously reserved picture or a permanent
445 * picture. It is meant to be used when the construction of a picture aborted.
446 * Note that the picture will be destroyed even if it is linked !
447 * This function does not need locking since reserved pictures are ignored by
449 *******************************************************************************/
450 void vout_DestroyPicture( vout_thread_t *p_vout, picture_t *p_pic )
453 /* Check if picture status is valid */
454 if( p_pic->i_status != RESERVED_PICTURE )
456 intf_DbgMsg("error: picture %p has invalid status %d\n", p_pic, p_pic->i_status );
460 p_pic->i_status = DESTROYED_PICTURE;
463 intf_DbgMsg("picture %p\n", p_pic);
467 /*******************************************************************************
468 * vout_LinkPicture: increment reference counter of a picture
469 *******************************************************************************
470 * This function increment the reference counter of a picture in the video
471 * heap. It needs a lock since several producer threads can access the picture.
472 *******************************************************************************/
473 void vout_LinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
475 vlc_mutex_lock( &p_vout->picture_lock );
477 vlc_mutex_unlock( &p_vout->picture_lock );
480 intf_DbgMsg("picture %p\n", p_pic);
484 /*******************************************************************************
485 * vout_UnlinkPicture: decrement reference counter of a picture
486 *******************************************************************************
487 * This function decrement the reference counter of a picture in the video heap.
488 *******************************************************************************/
489 void vout_UnlinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
491 vlc_mutex_lock( &p_vout->picture_lock );
495 if( p_pic->i_refcount < 0 )
497 intf_DbgMsg("error: refcount < 0\n");
498 p_pic->i_refcount = 0;
502 if( (p_pic->i_refcount == 0) && (p_pic->i_status == DISPLAYED_PICTURE) )
504 p_pic->i_status = DESTROYED_PICTURE;
506 vlc_mutex_unlock( &p_vout->picture_lock );
509 intf_DbgMsg("picture %p\n", p_pic);
513 /* following functions are local */
515 /*******************************************************************************
516 * InitThread: initialize video output thread
517 *******************************************************************************
518 * This function is called from RunThread and performs the second step of the
519 * initialization. It returns 0 on success. Note that the thread's flag are not
520 * modified inside this function.
521 *******************************************************************************/
522 static int InitThread( vout_thread_t *p_vout )
524 int i_index; /* generic index */
527 *p_vout->pi_status = THREAD_START;
529 /* Initialize output method - this function issues its own error messages */
530 if( vout_SysInit( p_vout ) )
532 *p_vout->pi_status = THREAD_ERROR;
536 /* Initialize pictures and subtitles */
537 for( i_index = 0; i_index < VOUT_MAX_PICTURES; i_index++)
539 p_vout->p_picture[i_index].i_type = EMPTY_PICTURE;
540 p_vout->p_picture[i_index].i_status = FREE_PICTURE;
541 p_vout->p_subtitle[i_index].i_type = EMPTY_SUBTITLE;
542 p_vout->p_subtitle[i_index].i_status= FREE_SUBTITLE;
545 /* Initialize convertion tables and functions */
546 if( vout_InitTables( p_vout ) )
548 intf_ErrMsg("error: can't allocate translation tables\n");
552 /* Mark thread as running and return */
553 p_vout->b_active = 1;
554 *p_vout->pi_status = THREAD_READY;
555 intf_DbgMsg("thread ready\n");
559 /*******************************************************************************
560 * RunThread: video output thread
561 *******************************************************************************
562 * Video output thread. This function does only returns when the thread is
563 * terminated. It handles the pictures arriving in the video heap and the
564 * display device events.
565 *******************************************************************************/
566 static void RunThread( vout_thread_t *p_vout)
568 int i_picture; /* picture index */
569 mtime_t current_date; /* current date */
570 mtime_t pic_date = 0; /* picture date */
571 boolean_t b_display; /* display flag */
572 picture_t * p_pic; /* picture pointer */
575 * Initialize thread and free configuration
577 p_vout->b_error = InitThread( p_vout );
578 if( p_vout->b_error )
580 free( p_vout ); /* destroy descriptor */
585 * Main loop - it is not executed if an error occured during
588 while( (!p_vout->b_die) && (!p_vout->b_error) )
591 * Find the picture to display - this operation does not need lock,
592 * since only READY_PICTURES are handled
595 current_date = mdate();
596 for( i_picture = 0; i_picture < VOUT_MAX_PICTURES; i_picture++ )
598 if( (p_vout->p_picture[i_picture].i_status == READY_PICTURE) &&
600 (p_vout->p_picture[i_picture].date < pic_date) ) )
602 p_pic = &p_vout->p_picture[i_picture];
603 pic_date = p_pic->date;
608 * Render picture if any
613 /* Computes FPS rate */
614 p_vout->fps_sample[ p_vout->c_fps_samples++ % VOUT_FPS_SAMPLES ] = pic_date;
616 if( pic_date < current_date )
618 /* Picture is late: it will be destroyed and the thread will sleep and
619 * go to next picture */
620 vlc_mutex_lock( &p_vout->picture_lock );
621 p_pic->i_status = p_pic->i_refcount ? DISPLAYED_PICTURE : DESTROYED_PICTURE;
622 vlc_mutex_unlock( &p_vout->picture_lock );
624 intf_DbgMsg( "warning: late picture %p skipped\n", p_pic );
628 else if( pic_date > current_date + VOUT_DISPLAY_DELAY )
630 /* A picture is ready to be rendered, but its rendering date is
631 * far from the current one so the thread will perform an empty loop
632 * as if no picture were found. The picture state is unchanged */
638 * Perform rendering, sleep and display rendered picture
642 /* A picture is ready to be displayed : render it */
643 if( p_vout->b_active )
645 b_display = RenderPicture( p_vout, p_pic, 1 );
648 b_display |= RenderPictureInfo( p_vout, p_pic, b_display );
649 b_display |= RenderInfo( p_vout, b_display );
657 /* Remove picture from heap */
658 vlc_mutex_lock( &p_vout->picture_lock );
659 p_pic->i_status = p_pic->i_refcount ? DISPLAYED_PICTURE : DESTROYED_PICTURE;
660 vlc_mutex_unlock( &p_vout->picture_lock );
664 /* No picture. However, an idle screen may be ready to display */
665 if( p_vout->b_active )
667 b_display = RenderIdle( p_vout, 1 );
670 b_display |= RenderInfo( p_vout, b_display );
679 /* Give back change lock */
680 vlc_mutex_unlock( &p_vout->change_lock );
682 /* Sleep a while or until a given date */
689 msleep( VOUT_IDLE_SLEEP );
692 /* On awakening, take back lock and send immediately picture to display */
693 vlc_mutex_lock( &p_vout->change_lock );
694 if( b_display && p_vout->b_active &&
695 !(p_vout->i_changes & VOUT_NODISPLAY_CHANGE) )
697 vout_SysDisplay( p_vout );
701 * Check events and manage thread
703 if( vout_SysManage( p_vout ) | Manage( p_vout ) )
705 /* A fatal error occured, and the thread must terminate immediately,
706 * without displaying anything - setting b_error to 1 cause the
707 * immediate end of the main while() loop. */
715 if( p_vout->b_error )
717 ErrorThread( p_vout );
722 intf_DbgMsg( "thread end\n" );
725 /*******************************************************************************
726 * ErrorThread: RunThread() error loop
727 *******************************************************************************
728 * This function is called when an error occured during thread main's loop. The
729 * thread can still receive feed, but must be ready to terminate as soon as
731 *******************************************************************************/
732 static void ErrorThread( vout_thread_t *p_vout )
734 /* Wait until a `die' order */
735 while( !p_vout->b_die )
738 msleep( VOUT_IDLE_SLEEP );
742 /*******************************************************************************
743 * EndThread: thread destruction
744 *******************************************************************************
745 * This function is called when the thread ends after a sucessfull
747 *******************************************************************************/
748 static void EndThread( vout_thread_t *p_vout )
750 int * pi_status; /* thread status */
754 pi_status = p_vout->pi_status;
755 *pi_status = THREAD_END;
757 /* Destroy all remaining pictures */
758 for( i_picture = 0; i_picture < VOUT_MAX_PICTURES; i_picture++ )
760 if( p_vout->p_picture[i_picture].i_status != FREE_PICTURE )
762 free( p_vout->p_picture[i_picture].p_data );
766 /* Destroy translation tables */
767 vout_EndTables( p_vout );
769 /* Destroy thread structures allocated by InitThread */
770 vout_SysEnd( p_vout );
771 vout_SysDestroy( p_vout );
775 *pi_status = THREAD_OVER;
778 /*******************************************************************************
779 * RenderBlank: render a blank screen
780 *******************************************************************************
781 * This function is called by all other rendering functions when they arrive on
782 * a non blanked screen.
783 *******************************************************************************/
784 static void RenderBlank( vout_thread_t *p_vout )
787 int i_index; /* current 32 bits sample */
788 int i_width; /* number of 32 bits samples */
789 u32 *p_pic; /* pointer to 32 bits samples */
791 /* Initialize variables */
792 p_pic = vout_SysGetPicture( p_vout );
793 i_width = p_vout->i_bytes_per_line * p_vout->i_height / 128;
795 /* Clear beginning of screen by 128 bytes blocks */
796 for( i_index = 0; i_index < i_width; i_index++ )
798 *p_pic++ = 0; *p_pic++ = 0;
799 *p_pic++ = 0; *p_pic++ = 0;
800 *p_pic++ = 0; *p_pic++ = 0;
801 *p_pic++ = 0; *p_pic++ = 0;
802 *p_pic++ = 0; *p_pic++ = 0;
803 *p_pic++ = 0; *p_pic++ = 0;
804 *p_pic++ = 0; *p_pic++ = 0;
805 *p_pic++ = 0; *p_pic++ = 0;
806 *p_pic++ = 0; *p_pic++ = 0;
807 *p_pic++ = 0; *p_pic++ = 0;
808 *p_pic++ = 0; *p_pic++ = 0;
809 *p_pic++ = 0; *p_pic++ = 0;
810 *p_pic++ = 0; *p_pic++ = 0;
811 *p_pic++ = 0; *p_pic++ = 0;
812 *p_pic++ = 0; *p_pic++ = 0;
813 *p_pic++ = 0; *p_pic++ = 0;
816 /* Clear last pixels */
821 /*******************************************************************************
822 * RenderPicture: render a picture
823 *******************************************************************************
824 * This function convert a picture from a video heap to a pixel-encoded image
825 * and copy it to the current rendering buffer. No lock is required, since the
826 * rendered picture has been determined as existant, and will only be destroyed
827 * by the vout thread later.
828 *******************************************************************************/
829 static int RenderPicture( vout_thread_t *p_vout, picture_t *p_pic, boolean_t b_blank )
832 /* Start recording render time */
833 p_vout->render_time = mdate();
836 /* Mark last picture date */
837 p_vout->last_picture_date = p_pic->date;
839 /* Blank screen if required */
842 // ????? RenderBlank( p_vout );
848 if( (p_pic->i_width > p_vout->i_width) || (p_pic->i_height > p_vout->i_height) )
851 /* X11: window can be resized, so resize it - the picture won't be
852 * rendered since any alteration of the window size means recreating the
854 /* p_vout->i_new_width = p_pic->i_width;
855 p_vout->i_new_height = p_pic->i_height;*/
857 /* Other drivers: the video output thread can't change its size, so
858 * we need to change the aspect ratio */
864 * Choose appropriate rendering function and render picture
866 switch( p_pic->i_type )
868 case YUV_420_PICTURE:
869 p_vout->p_ConvertYUV420( p_vout, vout_SysGetPicture( p_vout ),
870 p_pic->p_y, p_pic->p_u, p_pic->p_v,
871 p_pic->i_width, p_pic->i_height, 0, 0,
872 4, p_pic->i_matrix_coefficients );
874 case YUV_422_PICTURE:
875 /* ??? p_vout->p_convert_yuv_420( p_vout,
876 p_pic->p_y, p_pic->p_u, p_pic->p_v,
877 i_chroma_width, i_chroma_height,
878 p_vout->i_width / 2, p_vout->i_height,
879 p_vout->i_bytes_per_line,
882 case YUV_444_PICTURE:
883 /* ??? p_vout->p_convert_yuv_420( p_vout,
884 p_pic->p_y, p_pic->p_u, p_pic->p_v,
885 i_chroma_width, i_chroma_height,
886 p_vout->i_width, p_vout->i_height,
887 p_vout->i_bytes_per_line,
892 intf_DbgMsg("error: unknown picture type %d\n", p_pic->i_type );
903 /* End recording render time */
904 p_vout->render_time = mdate() - p_vout->render_time;
909 /*******************************************************************************
910 * RenderPictureInfo: print additionnal informations on a picture
911 *******************************************************************************
912 * This function will print informations such as fps and other picture
913 * dependant informations.
914 *******************************************************************************/
915 static int RenderPictureInfo( vout_thread_t *p_vout, picture_t *p_pic, boolean_t b_blank )
917 char psz_buffer[256]; /* string buffer */
921 * Print FPS rate in upper right corner
923 if( p_vout->c_fps_samples > VOUT_FPS_SAMPLES )
925 sprintf( psz_buffer, "%.2f fps", (double) VOUT_FPS_SAMPLES * 1000000 /
926 ( p_vout->fps_sample[ (p_vout->c_fps_samples - 1) % VOUT_FPS_SAMPLES ] -
927 p_vout->fps_sample[ p_vout->c_fps_samples % VOUT_FPS_SAMPLES ] ) );
928 vout_SysPrint( p_vout, p_vout->i_width, 0, 1, -1, psz_buffer );
932 * Print frames count and loop time in upper left corner
934 sprintf( psz_buffer, "%ld frames render time: %lu us",
935 p_vout->c_fps_samples, (long unsigned) p_vout->render_time );
936 vout_SysPrint( p_vout, 0, 0, -1, -1, psz_buffer );
941 * Print picture information in lower right corner
943 sprintf( psz_buffer, "%s picture %dx%d (%dx%d%+d%+d %s)",
944 (p_pic->i_type == YUV_420_PICTURE) ? "4:2:0" :
945 ((p_pic->i_type == YUV_422_PICTURE) ? "4:2:2" :
946 ((p_pic->i_type == YUV_444_PICTURE) ? "4:4:4" : "ukn-type")),
947 p_pic->i_width, p_pic->i_height,
948 p_pic->i_display_width, p_pic->i_display_height,
949 p_pic->i_display_horizontal_offset, p_pic->i_display_vertical_offset,
950 (p_pic->i_aspect_ratio == AR_SQUARE_PICTURE) ? "sq" :
951 ((p_pic->i_aspect_ratio == AR_3_4_PICTURE) ? "4:3" :
952 ((p_pic->i_aspect_ratio == AR_16_9_PICTURE) ? "16:9" :
953 ((p_pic->i_aspect_ratio == AR_221_1_PICTURE) ? "2.21:1" : "ukn-ar" ))));
954 vout_SysPrint( p_vout, p_vout->i_width, p_vout->i_height, 1, 1, psz_buffer );
960 /*******************************************************************************
961 * RenderIdle: render idle picture
962 *******************************************************************************
963 * This function will clear the display or print a logo.
964 *******************************************************************************/
965 static int RenderIdle( vout_thread_t *p_vout, boolean_t b_blank )
967 /* Blank screen if required */
968 if( (mdate() - p_vout->last_picture_date > VOUT_IDLE_DELAY) &&
969 (p_vout->last_picture_date > p_vout->last_display_date) &&
972 RenderBlank( p_vout );
973 p_vout->last_display_date = mdate();
974 vout_SysPrint( p_vout, p_vout->i_width / 2, p_vout->i_height / 2, 0, 0,
982 /*******************************************************************************
983 * RenderInfo: render additionnal informations
984 *******************************************************************************
985 * This function render informations which do not depend of the current picture
987 *******************************************************************************/
988 static int RenderInfo( vout_thread_t *p_vout, boolean_t b_blank )
990 char psz_buffer[256]; /* string buffer */
992 int i_ready_pic = 0; /* ready pictures */
993 int i_reserved_pic = 0; /* reserved pictures */
994 int i_picture; /* picture index */
999 * Print thread state in lower left corner
1001 for( i_picture = 0; i_picture < VOUT_MAX_PICTURES; i_picture++ )
1003 switch( p_vout->p_picture[i_picture].i_status )
1005 case RESERVED_PICTURE:
1013 sprintf( psz_buffer, "%s %dx%d:%d scaling %+d:%+d g%+.2f pic: %d/%d/%d",
1014 p_vout->b_grayscale ? "gray" : "rgb",
1015 p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth,
1016 p_vout->i_horizontal_scale, p_vout->i_vertical_scale,
1017 p_vout->f_gamma, i_reserved_pic, i_ready_pic,
1018 VOUT_MAX_PICTURES );
1019 vout_SysPrint( p_vout, 0, p_vout->i_height, -1, 1, psz_buffer );
1024 /*******************************************************************************
1025 * Manage: manage thread
1026 *******************************************************************************
1027 * This function will handle changes in thread configuration.
1028 *******************************************************************************/
1029 static int Manage( vout_thread_t *p_vout )
1031 /* On gamma or grayscale change, rebuild tables */
1032 if( p_vout->i_changes & (VOUT_GAMMA_CHANGE | VOUT_GRAYSCALE_CHANGE) )
1034 vout_ResetTables( p_vout );
1037 /* Clear changes flags which does not need management or have been handled */
1038 p_vout->i_changes &= ~(VOUT_INFO_CHANGE | VOUT_GAMMA_CHANGE | VOUT_GRAYSCALE_CHANGE);
1040 /* Detect unauthorized changes */
1041 if( p_vout->i_changes )
1043 /* Some changes were not acknowledged by vout_SysManage or this function,
1044 * it means they should not be authorized */
1045 intf_ErrMsg( "error: unauthorized changes in the video output thread\n" );