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 *******************************************************************************/
19 #include <X11/Xlib.h> /* for video_sys.h in X11 mode */
25 #include "vlc_thread.h"
27 #include "video_output.h"
28 #include "video_sys.h"
29 #include "video_yuv.h"
33 /*******************************************************************************
35 *******************************************************************************/
36 static int InitThread ( vout_thread_t *p_vout );
37 static void RunThread ( vout_thread_t *p_vout );
38 static void ErrorThread ( vout_thread_t *p_vout );
39 static void EndThread ( vout_thread_t *p_vout );
40 static void RenderPicture ( vout_thread_t *p_vout, picture_t *p_pic );
41 static void RenderPictureInfo ( vout_thread_t *p_vout, picture_t *p_pic );
42 static int RenderIdle ( vout_thread_t *p_vout, int i_level );
44 /*******************************************************************************
45 * vout_CreateThread: creates a new video output thread
46 *******************************************************************************
47 * This function creates a new video output thread, and returns a pointer
48 * to its description. On error, it returns NULL.
49 * If pi_status is NULL, then the function will block until the thread is ready.
50 * If not, it will be updated using one of the THREAD_* constants.
51 *******************************************************************************/
52 vout_thread_t * vout_CreateThread (
54 char *psz_display, Window root_window,
56 int i_width, int i_height, int *pi_status
59 vout_thread_t * p_vout; /* thread descriptor */
60 int i_status; /* thread status */
62 /* Allocate descriptor */
63 p_vout = (vout_thread_t *) malloc( sizeof(vout_thread_t) );
66 intf_ErrMsg("error: %s\n", strerror(ENOMEM));
70 /* Initialize thread properties */
74 p_vout->pi_status = (pi_status != NULL) ? pi_status : &i_status;
75 *p_vout->pi_status = THREAD_CREATE;
77 /* Initialize some fields used by the system-dependant method - these fields will
78 * probably be modified by the method, and are only preferences */
84 p_vout->b_grayscale = main_GetIntVariable( VOUT_GRAYSCALE_VAR,
85 VOUT_GRAYSCALE_DEFAULT );
86 p_vout->i_width = i_width;
87 p_vout->i_height = i_height;
88 p_vout->i_bytes_per_line = i_width * 2;
89 p_vout->i_screen_depth = 15;
90 p_vout->i_bytes_per_pixel = 2;
91 p_vout->f_x_ratio = 1;
92 p_vout->f_y_ratio = 1;
93 p_vout->f_gamma = VOUT_GAMMA;
94 intf_DbgMsg("wished configuration: %dx%d,%d (%d bytes/pixel, %d bytes/line), ratio %.2f:%.2f, gray=%d\n",
95 p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth,
96 p_vout->i_bytes_per_pixel, p_vout->i_bytes_per_line,
97 p_vout->f_x_ratio, p_vout->f_y_ratio, p_vout->b_grayscale );
99 /* Create and initialize system-dependant method - this function issues its
100 * own error messages */
101 if( vout_SysCreate( p_vout
102 #if defined(VIDEO_X11)
103 , psz_display, root_window
110 intf_DbgMsg("actual configuration: %dx%d,%d (%d bytes/pixel, %d bytes/line), ratio %.2f:%.2f, gray=%d\n",
111 p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth,
112 p_vout->i_bytes_per_pixel, p_vout->i_bytes_per_line,
113 p_vout->f_x_ratio, p_vout->f_y_ratio, p_vout->b_grayscale );
115 /* Initialize changement properties */
116 p_vout->b_gamma_change = 0;
117 p_vout->i_new_width = p_vout->i_width;
118 p_vout->i_new_height = p_vout->i_height;
121 /* Initialize statistics fields */
123 p_vout->c_idle_loops = 0;
124 p_vout->c_fps_samples = 0;
127 /* Create thread and set locks */
128 vlc_mutex_init( &p_vout->lock );
129 if( vlc_thread_create( &p_vout->thread_id, "video output",
130 (void *) RunThread, (void *) p_vout) )
132 intf_ErrMsg("error: %s\n", strerror(ENOMEM));
133 vout_SysDestroy( p_vout );
138 intf_Msg("Video: display initialized (%dx%d, %d bpp)\n",
139 p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth );
141 /* If status is NULL, wait until the thread is created */
142 if( pi_status == NULL )
146 msleep( THREAD_SLEEP );
147 }while( (i_status != THREAD_READY) && (i_status != THREAD_ERROR)
148 && (i_status != THREAD_FATAL) );
149 if( i_status != THREAD_READY )
157 /*******************************************************************************
158 * vout_DestroyThread: destroys a previously created thread
159 *******************************************************************************
160 * Destroy a terminated thread.
161 * The function will request a destruction of the specified thread. If pi_error
162 * is NULL, it will return once the thread is destroyed. Else, it will be
163 * update using one of the THREAD_* constants.
164 *******************************************************************************/
165 void vout_DestroyThread( vout_thread_t *p_vout, int *pi_status )
167 int i_status; /* thread status */
170 p_vout->pi_status = (pi_status != NULL) ? pi_status : &i_status;
171 *p_vout->pi_status = THREAD_DESTROY;
173 /* Request thread destruction */
176 /* If status is NULL, wait until thread has been destroyed */
177 if( pi_status == NULL )
181 msleep( THREAD_SLEEP );
182 }while( (i_status != THREAD_OVER) && (i_status != THREAD_ERROR)
183 && (i_status != THREAD_FATAL) );
187 /*******************************************************************************
188 * vout_DisplayPicture: display a picture
189 *******************************************************************************
190 * Remove the reservation flag of a picture, which will cause it to be ready for
191 * display. The picture does not need to be locked, since it is ignored by
192 * the output thread if is reserved.
193 *******************************************************************************/
194 void vout_DisplayPicture( vout_thread_t *p_vout, picture_t *p_pic )
197 char psz_date[MSTRTIME_MAX_SIZE]; /* buffer for date string */
201 /* Check if picture status is valid */
202 if( p_pic->i_status != RESERVED_PICTURE )
204 intf_DbgMsg("error: picture %d has invalid status %d\n", p_pic, p_pic->i_status );
208 /* Remove reservation flag */
209 p_pic->i_status = READY_PICTURE;
212 /* Send picture informations */
213 intf_DbgMsg("picture %p: type=%d, %dx%d, date=%s\n", p_pic, p_pic->i_type,
214 p_pic->i_width,p_pic->i_height, mstrtime( psz_date, p_pic->date ) );
218 /*******************************************************************************
219 * vout_CreatePicture: allocate a picture in the video output heap.
220 *******************************************************************************
221 * This function create a reserved image in the video output heap.
222 * A null pointer is returned if the function fails. This method provides an
223 * already allocated zone of memory in the picture data fields. It needs locking
224 * since several pictures can be created by several producers threads.
225 *******************************************************************************/
226 picture_t *vout_CreatePicture( vout_thread_t *p_vout, int i_type,
227 int i_width, int i_height )
229 int i_picture; /* picture index */
230 int i_chroma_width = 0; /* chroma width */
231 picture_t * p_free_picture = NULL; /* first free picture */
232 picture_t * p_destroyed_picture = NULL; /* first destroyed picture */
235 vlc_mutex_lock( &p_vout->lock );
238 * Look for an empty place
241 i_picture < VOUT_MAX_PICTURES;
244 if( p_vout->p_picture[i_picture].i_status == DESTROYED_PICTURE )
246 /* Picture is marked for destruction, but is still allocated - note
247 * that if width and type are the same for two pictures, chroma_width
248 * should also be the same */
249 if( (p_vout->p_picture[i_picture].i_type == i_type) &&
250 (p_vout->p_picture[i_picture].i_height == i_height) &&
251 (p_vout->p_picture[i_picture].i_width == i_width) )
253 /* Memory size do match : memory will not be reallocated, and function
254 * can end immediately - this is the best possible case, since no
255 * memory allocation needs to be done */
256 p_vout->p_picture[i_picture].i_status = RESERVED_PICTURE;
258 intf_DbgMsg("picture %p (in destroyed picture slot)\n",
259 &p_vout->p_picture[i_picture] );
261 vlc_mutex_unlock( &p_vout->lock );
262 return( &p_vout->p_picture[i_picture] );
264 else if( p_destroyed_picture == NULL )
266 /* Memory size do not match, but picture index will be kept in
267 * case no other place are left */
268 p_destroyed_picture = &p_vout->p_picture[i_picture];
271 else if( (p_free_picture == NULL) &&
272 (p_vout->p_picture[i_picture].i_status == FREE_PICTURE ))
274 /* Picture is empty and ready for allocation */
275 p_free_picture = &p_vout->p_picture[i_picture];
279 /* If no free picture is available, use a destroyed picture */
280 if( (p_free_picture == NULL) && (p_destroyed_picture != NULL ) )
282 /* No free picture or matching destroyed picture has been found, but
283 * a destroyed picture is still avalaible */
284 free( p_destroyed_picture->p_data );
285 p_free_picture = p_destroyed_picture;
291 if( p_free_picture != NULL )
293 /* Allocate memory */
296 case YUV_420_PICTURE: /* YUV 420: 1,1/4,1/4 samples per pixel */
297 i_chroma_width = i_width / 2;
298 p_free_picture->p_data = malloc( i_height * i_chroma_width * 3 * sizeof( yuv_data_t ) );
299 p_free_picture->p_y = (yuv_data_t *)p_free_picture->p_data;
300 p_free_picture->p_u = (yuv_data_t *)p_free_picture->p_data +i_height*i_chroma_width*4/2;
301 p_free_picture->p_v = (yuv_data_t *)p_free_picture->p_data +i_height*i_chroma_width*5/2;
303 case YUV_422_PICTURE: /* YUV 422: 1,1/2,1/2 samples per pixel */
304 i_chroma_width = i_width / 2;
305 p_free_picture->p_data = malloc( i_height * i_chroma_width * 4 * sizeof( yuv_data_t ) );
306 p_free_picture->p_y = (yuv_data_t *)p_free_picture->p_data;
307 p_free_picture->p_u = (yuv_data_t *)p_free_picture->p_data +i_height*i_chroma_width*2;
308 p_free_picture->p_v = (yuv_data_t *)p_free_picture->p_data +i_height*i_chroma_width*3;
310 case YUV_444_PICTURE: /* YUV 444: 1,1,1 samples per pixel */
311 i_chroma_width = i_width;
312 p_free_picture->p_data = malloc( i_height * i_chroma_width * 3 * sizeof( yuv_data_t ) );
313 p_free_picture->p_y = (yuv_data_t *)p_free_picture->p_data;
314 p_free_picture->p_u = (yuv_data_t *)p_free_picture->p_data +i_height*i_chroma_width;
315 p_free_picture->p_v = (yuv_data_t *)p_free_picture->p_data +i_height*i_chroma_width*2;
319 intf_DbgMsg("error: unknown picture type %d\n", i_type );
320 p_free_picture->p_data = NULL;
325 if( p_free_picture->p_data != NULL )
327 /* Copy picture informations, set some default values */
328 p_free_picture->i_type = i_type;
329 p_free_picture->i_status = RESERVED_PICTURE;
330 p_free_picture->i_matrix_coefficients = 1;
331 p_free_picture->i_width = i_width;
332 p_free_picture->i_height = i_height;
333 p_free_picture->i_chroma_width = i_chroma_width;
334 p_free_picture->i_display_horizontal_offset = 0;
335 p_free_picture->i_display_vertical_offset = 0;
336 p_free_picture->i_display_width = i_width;
337 p_free_picture->i_display_height = i_height;
338 p_free_picture->i_aspect_ratio = AR_SQUARE_PICTURE;
339 p_free_picture->i_refcount = 0;
343 /* Memory allocation failed : set picture as empty */
344 p_free_picture->i_type = EMPTY_PICTURE;
345 p_free_picture->i_status = FREE_PICTURE;
346 p_free_picture = NULL;
347 intf_ErrMsg("warning: %s\n", strerror( ENOMEM ) );
351 intf_DbgMsg("picture %p (in free picture slot)\n", p_free_picture );
353 vlc_mutex_unlock( &p_vout->lock );
354 return( p_free_picture );
357 // No free or destroyed picture could be found
358 intf_DbgMsg( "warning: heap is full\n" );
359 vlc_mutex_unlock( &p_vout->lock );
363 /*******************************************************************************
364 * vout_DestroyPicture: remove a permanent or reserved picture from the heap
365 *******************************************************************************
366 * This function frees a previously reserved picture or a permanent
367 * picture. It is meant to be used when the construction of a picture aborted.
368 * Note that the picture will be destroyed even if it is linked !
369 * This function does not need locking since reserved pictures are ignored by
371 *******************************************************************************/
372 void vout_DestroyPicture( vout_thread_t *p_vout, picture_t *p_pic )
375 /* Check if picture status is valid */
376 if( p_pic->i_status != RESERVED_PICTURE )
378 intf_DbgMsg("error: picture %d has invalid status %d\n", p_pic, p_pic->i_status );
382 p_pic->i_status = DESTROYED_PICTURE;
385 intf_DbgMsg("picture %p\n", p_pic);
389 /*******************************************************************************
390 * vout_LinkPicture: increment reference counter of a picture
391 *******************************************************************************
392 * This function increment the reference counter of a picture in the video
393 * heap. It needs a lock since several producer threads can access the picture.
394 *******************************************************************************/
395 void vout_LinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
397 vlc_mutex_lock( &p_vout->lock );
399 vlc_mutex_unlock( &p_vout->lock );
402 intf_DbgMsg("picture %p\n", p_pic);
406 /*******************************************************************************
407 * vout_UnlinkPicture: decrement reference counter of a picture
408 *******************************************************************************
409 * This function decrement the reference counter of a picture in the video heap.
410 *******************************************************************************/
411 void vout_UnlinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
413 vlc_mutex_lock( &p_vout->lock );
415 if( (p_pic->i_refcount == 0) && (p_pic->i_status == DISPLAYED_PICTURE) )
417 p_pic->i_status = DESTROYED_PICTURE;
419 vlc_mutex_unlock( &p_vout->lock );
422 intf_DbgMsg("picture %p\n", p_pic);
426 /* following functions are local */
428 /*******************************************************************************
429 * InitThread: initialize video output thread
430 *******************************************************************************
431 * This function is called from RunThread and performs the second step of the
432 * initialization. It returns 0 on success. Note that the thread's flag are not
433 * modified inside this function.
434 *******************************************************************************/
435 static int InitThread( vout_thread_t *p_vout )
437 int i_index; /* generic index */
440 *p_vout->pi_status = THREAD_START;
442 /* Initialize output method - this function issues its own error messages */
443 if( vout_SysInit( p_vout ) )
445 *p_vout->pi_status = THREAD_ERROR;
449 /* Initialize pictures */
450 for( i_index = 0; i_index < VOUT_MAX_PICTURES; i_index++)
452 p_vout->p_picture[i_index].i_type = EMPTY_PICTURE;
453 p_vout->p_picture[i_index].i_status= FREE_PICTURE;
456 /* Initialize convertion tables and functions */
457 if( vout_InitTables( p_vout ) )
459 intf_ErrMsg("error: can't allocate translation tables\n");
463 /* Mark thread as running and return */
464 p_vout->b_active = 1;
465 *p_vout->pi_status = THREAD_READY;
466 intf_DbgMsg("thread ready\n");
470 /*******************************************************************************
471 * RunThread: video output thread
472 *******************************************************************************
473 * Video output thread. This function does only returns when the thread is
474 * terminated. It handles the pictures arriving in the video heap and the
475 * display device events.
476 *******************************************************************************/
477 static void RunThread( vout_thread_t *p_vout)
479 int i_picture; /* picture index */
480 int i_err; /* error code */
481 int i_idle_level = 0; /* idle level */
482 mtime_t current_date; /* current date */
483 mtime_t pic_date = 0; /* picture date */
484 mtime_t last_date = 0; /* last picture date */
485 boolean_t b_display; /* display flag */
486 picture_t * p_pic; /* picture pointer */
489 * Initialize thread and free configuration
491 p_vout->b_error = InitThread( p_vout );
492 if( p_vout->b_error )
494 free( p_vout ); /* destroy descriptor */
499 * Main loop - it is not executed if an error occured during
502 while( (!p_vout->b_die) && (!p_vout->b_error) )
505 * Find the picture to display - this operation does not need lock,
506 * since only READY_PICTURES are handled
509 for( i_picture = 0; i_picture < VOUT_MAX_PICTURES; i_picture++ )
511 if( (p_vout->p_picture[i_picture].i_status == READY_PICTURE) &&
513 (p_vout->p_picture[i_picture].date < pic_date) ) )
515 p_pic = &p_vout->p_picture[i_picture];
516 pic_date = p_pic->date;
519 current_date = mdate();
522 * Render picture if any
527 /* Computes FPS rate */
528 p_vout->fps_sample[ p_vout->c_fps_samples++ % VOUT_FPS_SAMPLES ] = pic_date;
530 if( pic_date < current_date )
532 /* Picture is late: it will be destroyed and the thread will sleep and
533 * go to next picture */
534 vlc_mutex_lock( &p_vout->lock );
535 p_pic->i_status = p_pic->i_refcount ? DISPLAYED_PICTURE : DESTROYED_PICTURE;
536 vlc_mutex_unlock( &p_vout->lock );
538 intf_DbgMsg( "warning: late picture %p skipped\n", p_pic );
542 else if( pic_date > current_date + VOUT_DISPLAY_DELAY )
544 /* A picture is ready to be rendered, but its rendering date is
545 * far from the current one so the thread will perform an empty loop
546 * as if no picture were found. The picture state is unchanged */
551 /* Picture has not yet been displayed, and has a valid display
552 * date : render it, then mark it as displayed */
553 if( p_vout->b_active )
555 RenderPicture( p_vout, p_pic );
558 RenderPictureInfo( p_vout, p_pic );
561 vlc_mutex_lock( &p_vout->lock );
562 p_pic->i_status = p_pic->i_refcount ? DISPLAYED_PICTURE : DESTROYED_PICTURE;
563 vlc_mutex_unlock( &p_vout->lock );
568 * Rebuild tables if gamma has changed
570 if( p_vout->b_gamma_change )
573 p_vout->b_gamma_change = 0;
574 vout_ResetTables( p_vout ); // ?? test return value
578 * Check events, sleep and display picture
580 i_err = vout_SysManage( p_vout );
583 /* A fatal error occured, and the thread must terminate immediately,
584 * without displaying anything - setting b_error to 1 cause the
585 * immediate end of the main while() loop. */
592 /* A picture is ready to be displayed : remove blank screen flag */
593 last_date = pic_date;
597 /* Sleep until its display date */
602 /* If last picture was a long time ago, increase idle level, reset
603 * date and render idle screen */
604 if( !i_err && (current_date - last_date > VOUT_IDLE_DELAY) )
606 last_date = current_date;
607 b_display = p_vout->b_active && RenderIdle( p_vout, i_idle_level++ );
615 /* Update counters */
616 p_vout->c_idle_loops++;
619 /* Sleep to wait for new pictures */
620 msleep( VOUT_IDLE_SLEEP );
623 /* On awakening, send immediately picture to display */
624 if( b_display && p_vout->b_active )
626 vout_SysDisplay( p_vout );
631 /* Update counters */
639 if( p_vout->b_error )
641 ErrorThread( p_vout );
646 intf_DbgMsg( "thread end\n" );
649 /*******************************************************************************
650 * ErrorThread: RunThread() error loop
651 *******************************************************************************
652 * This function is called when an error occured during thread main's loop. The
653 * thread can still receive feed, but must be ready to terminate as soon as
655 *******************************************************************************/
656 static void ErrorThread( vout_thread_t *p_vout )
658 /* Wait until a `die' order */
659 while( !p_vout->b_die )
662 msleep( VOUT_IDLE_SLEEP );
666 /*******************************************************************************
667 * EndThread: thread destruction
668 *******************************************************************************
669 * This function is called when the thread ends after a sucessfull
671 *******************************************************************************/
672 static void EndThread( vout_thread_t *p_vout )
674 int * pi_status; /* thread status */
678 pi_status = p_vout->pi_status;
679 *pi_status = THREAD_END;
681 /* Destroy all remaining pictures */
682 for( i_picture = 0; i_picture < VOUT_MAX_PICTURES; i_picture++ )
684 if( p_vout->p_picture[i_picture].i_status != FREE_PICTURE )
686 free( p_vout->p_picture[i_picture].p_data );
690 /* Destroy translation tables */
691 vout_EndTables( p_vout );
693 /* Destroy thread structures allocated by InitThread */
694 vout_SysEnd( p_vout );
695 vout_SysDestroy( p_vout );
699 *pi_status = THREAD_OVER;
702 /*******************************************************************************
703 * RenderPicture: render a picture
704 *******************************************************************************
705 * This function convert a picture from a video heap to a pixel-encoded image
706 * and copy it to the current rendering buffer. No lock is required, since the
707 * rendered picture has been determined as existant, and will only be destroyed
708 * by the vout thread later.
709 *******************************************************************************/
710 static void RenderPicture( vout_thread_t *p_vout, picture_t *p_pic )
713 /* Send picture informations and store rendering start date */
714 intf_DbgMsg("picture %p\n", p_pic );
715 p_vout->picture_render_time = mdate();
721 if( (p_pic->i_width > p_vout->i_width) || (p_pic->i_height > p_vout->i_height) )
724 /* X11: window can be resized, so resize it - the picture won't be
725 * rendered since any alteration of the window size means recreating the
727 p_vout->i_new_width = p_pic->i_width;
728 p_vout->i_new_height = p_pic->i_height;
731 /* Other drivers: the video output thread can't change its size, so
732 * we need to change the aspect ratio */
738 * Choose appropriate rendering function and render picture
740 switch( p_pic->i_type )
742 case YUV_420_PICTURE:
743 p_vout->p_ConvertYUV420( p_vout, vout_SysGetPicture( p_vout ),
744 p_pic->p_y, p_pic->p_u, p_pic->p_v,
745 p_pic->i_width, p_pic->i_height, 0, 0,
746 4, p_pic->i_matrix_coefficients );
748 case YUV_422_PICTURE:
749 /* ??? p_vout->p_convert_yuv_420( p_vout,
750 p_pic->p_y, p_pic->p_u, p_pic->p_v,
751 i_chroma_width, i_chroma_height,
752 p_vout->i_width / 2, p_vout->i_height,
753 p_vout->i_bytes_per_line,
756 case YUV_444_PICTURE:
757 /* ??? p_vout->p_convert_yuv_420( p_vout,
758 p_pic->p_y, p_pic->p_u, p_pic->p_v,
759 i_chroma_width, i_chroma_height,
760 p_vout->i_width, p_vout->i_height,
761 p_vout->i_bytes_per_line,
766 intf_DbgMsg("error: unknown picture type %d\n", p_pic->i_type );
777 /* Computes rendering time */
778 p_vout->picture_render_time = mdate() - p_vout->picture_render_time;
784 /*******************************************************************************
785 * RenderPictureInfo: print additionnal informations on a picture
786 *******************************************************************************
787 * This function will add informations such as fps and buffer size on a picture
788 *******************************************************************************/
789 static void RenderPictureInfo( vout_thread_t *p_vout, picture_t *p_pic )
791 char psz_buffer[256]; /* string buffer */
793 int i_ready_pic = 0; /* ready pictures */
794 int i_reserved_pic = 0; /* reserved pictures */
795 int i_picture; /* picture index */
800 * Print FPS rate in upper right corner
802 if( p_vout->c_fps_samples > VOUT_FPS_SAMPLES )
804 sprintf( psz_buffer, "%.2f fps", (double) VOUT_FPS_SAMPLES * 1000000 /
805 ( p_vout->fps_sample[ (p_vout->c_fps_samples - 1) % VOUT_FPS_SAMPLES ] -
806 p_vout->fps_sample[ p_vout->c_fps_samples % VOUT_FPS_SAMPLES ] ) );
807 vout_SysPrint( p_vout, p_vout->i_width, 0, 1, -1, psz_buffer );
811 * Print statistics in upper left corner
813 sprintf( psz_buffer, "gamma=%.2f %ld frames (%.1f %% idle)",
814 p_vout->f_gamma, p_vout->c_fps_samples, p_vout->c_loops ?
815 (double ) p_vout->c_idle_loops * 100 / p_vout->c_loops : 100. );
816 vout_SysPrint( p_vout, 0, 0, -1, -1, psz_buffer );
821 * Print heap state in lower left corner
823 for( i_picture = 0; i_picture < VOUT_MAX_PICTURES; i_picture++ )
825 switch( p_vout->p_picture[i_picture].i_status )
827 case RESERVED_PICTURE:
835 sprintf( psz_buffer, "video heap: %d/%d/%d", i_reserved_pic, i_ready_pic,
837 vout_SysPrint( p_vout, 0, p_vout->i_height, -1, 1, psz_buffer );
842 * Print picture info in lower right corner
844 switch( p_pic->i_type )
846 case YUV_420_PICTURE:
847 sprintf( psz_buffer, "YUV 4:2:0 picture, rendering time: %lu us",
848 (unsigned long) p_vout->picture_render_time );
850 case YUV_422_PICTURE:
851 sprintf( psz_buffer, "YUV 4:2:2 picture, rendering time: %lu us",
852 (unsigned long) p_vout->picture_render_time );
854 case YUV_444_PICTURE:
855 sprintf( psz_buffer, "YUV 4:4:4 picture, rendering time: %lu us",
856 (unsigned long) p_vout->picture_render_time );
859 sprintf( psz_buffer, "unknown picture, rendering time: %lu us",
860 (unsigned long) p_vout->picture_render_time );
863 vout_SysPrint( p_vout, p_vout->i_width, p_vout->i_height, 1, 1, psz_buffer );
867 /*******************************************************************************
868 * RenderIdle: render idle picture
869 *******************************************************************************
870 * This function will clear the display or print a logo. Level will vary from 0
871 * to a very high value that noone should never reach. It returns non 0 if
872 * something needs to be displayed and 0 if the previous picture can be kept.
873 *******************************************************************************/
874 static int RenderIdle( vout_thread_t *p_vout, int i_level )
876 byte_t *pi_pic; /* pointer to picture data */
878 /* Get frame pointer and clear display */
879 pi_pic = vout_SysGetPicture( p_vout );
884 case 0: /* level 0: clear screen */
885 memset( pi_pic, 0, p_vout->i_bytes_per_line * p_vout->i_height );
887 case 1: /* level 1: "no stream" */
888 memset( pi_pic, 0, p_vout->i_bytes_per_line * p_vout->i_height );
889 vout_SysPrint( p_vout, p_vout->i_width / 2, p_vout->i_height / 2,
892 case 50: /* level 50: copyright message */
893 memset( pi_pic, 0, p_vout->i_bytes_per_line * p_vout->i_height );
894 vout_SysPrint( p_vout, p_vout->i_width / 2, p_vout->i_height / 2,
895 0, 0, COPYRIGHT_MESSAGE );
897 default: /* other levels: keep previous picture */