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 );
43 static int RenderInfo ( vout_thread_t *p_vout );
44 static int Manage ( vout_thread_t *p_vout );
46 /*******************************************************************************
47 * vout_CreateThread: creates a new video output thread
48 *******************************************************************************
49 * This function creates a new video output thread, and returns a pointer
50 * to its description. On error, it returns NULL.
51 * If pi_status is NULL, then the function will block until the thread is ready.
52 * If not, it will be updated using one of the THREAD_* constants.
53 *******************************************************************************/
54 vout_thread_t * vout_CreateThread (
56 char *psz_display, Window root_window,
58 int i_width, int i_height, int *pi_status
61 vout_thread_t * p_vout; /* thread descriptor */
62 int i_status; /* thread status */
64 /* Allocate descriptor */
65 p_vout = (vout_thread_t *) malloc( sizeof(vout_thread_t) );
68 intf_ErrMsg("error: %s\n", strerror(ENOMEM));
72 /* Initialize thread properties */
76 p_vout->pi_status = (pi_status != NULL) ? pi_status : &i_status;
77 *p_vout->pi_status = THREAD_CREATE;
79 /* Initialize some fields used by the system-dependant method - these fields will
80 * probably be modified by the method, and are only preferences */
86 p_vout->b_grayscale = main_GetIntVariable( VOUT_GRAYSCALE_VAR,
87 VOUT_GRAYSCALE_DEFAULT );
88 p_vout->i_width = i_width;
89 p_vout->i_height = i_height;
90 p_vout->i_bytes_per_line = i_width * 2;
91 p_vout->i_screen_depth = 15;
92 p_vout->i_bytes_per_pixel = 2;
93 p_vout->f_x_ratio = 1;
94 p_vout->f_y_ratio = 1;
95 p_vout->f_gamma = VOUT_GAMMA;
96 intf_DbgMsg("wished configuration: %dx%d,%d (%d bytes/pixel, %d bytes/line), ratio %.2f:%.2f, gray=%d\n",
97 p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth,
98 p_vout->i_bytes_per_pixel, p_vout->i_bytes_per_line,
99 p_vout->f_x_ratio, p_vout->f_y_ratio, p_vout->b_grayscale );
101 /* Create and initialize system-dependant method - this function issues its
102 * own error messages */
103 if( vout_SysCreate( p_vout
104 #if defined(VIDEO_X11)
105 , psz_display, root_window
112 intf_DbgMsg("actual configuration: %dx%d,%d (%d bytes/pixel, %d bytes/line), ratio %.2f:%.2f, gray=%d\n",
113 p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth,
114 p_vout->i_bytes_per_pixel, p_vout->i_bytes_per_line,
115 p_vout->f_x_ratio, p_vout->f_y_ratio, p_vout->b_grayscale );
118 /* Initialize statistics fields */
119 p_vout->loop_time = 0;
120 p_vout->c_fps_samples = 0;
123 /* Create thread and set locks */
124 vlc_mutex_init( &p_vout->picture_lock );
125 vlc_mutex_init( &p_vout->subtitle_lock );
126 if( vlc_thread_create( &p_vout->thread_id, "video output",
127 (void *) RunThread, (void *) p_vout) )
129 intf_ErrMsg("error: %s\n", strerror(ENOMEM));
130 vout_SysDestroy( p_vout );
135 intf_Msg("Video: display initialized (%dx%d, %d bpp)\n",
136 p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth );
138 /* If status is NULL, wait until the thread is created */
139 if( pi_status == NULL )
143 msleep( THREAD_SLEEP );
144 }while( (i_status != THREAD_READY) && (i_status != THREAD_ERROR)
145 && (i_status != THREAD_FATAL) );
146 if( i_status != THREAD_READY )
154 /*******************************************************************************
155 * vout_DestroyThread: destroys a previously created thread
156 *******************************************************************************
157 * Destroy a terminated thread.
158 * The function will request a destruction of the specified thread. If pi_error
159 * is NULL, it will return once the thread is destroyed. Else, it will be
160 * update using one of the THREAD_* constants.
161 *******************************************************************************/
162 void vout_DestroyThread( vout_thread_t *p_vout, int *pi_status )
164 int i_status; /* thread status */
167 p_vout->pi_status = (pi_status != NULL) ? pi_status : &i_status;
168 *p_vout->pi_status = THREAD_DESTROY;
170 /* Request thread destruction */
173 /* If status is NULL, wait until thread has been destroyed */
174 if( pi_status == NULL )
178 msleep( THREAD_SLEEP );
179 }while( (i_status != THREAD_OVER) && (i_status != THREAD_ERROR)
180 && (i_status != THREAD_FATAL) );
184 /*******************************************************************************
185 * vout_DisplaySubtitle: display a subtitle
186 *******************************************************************************
187 * Remove the reservation flag of a subtitle, which will cause it to be ready for
188 * display. The picture does not need to be locked, since it is ignored by
189 * the output thread if is reserved.
190 *******************************************************************************/
191 void vout_DisplaySubtitle( vout_thread_t *p_vout, subtitle_t *p_sub )
194 char psz_begin_date[MSTRTIME_MAX_SIZE]; /* buffer for date string */
195 char psz_end_date[MSTRTIME_MAX_SIZE]; /* buffer for date string */
199 /* Check if status is valid */
200 if( p_sub->i_status != RESERVED_SUBTITLE )
202 intf_DbgMsg("error: subtitle %p has invalid status %d\n", p_sub, p_sub->i_status );
206 /* Remove reservation flag */
207 p_sub->i_status = READY_SUBTITLE;
210 /* Send subtitle informations */
211 intf_DbgMsg("subtitle %p: type=%d, begin date=%s, end date=%s\n", p_sub, p_sub->i_type,
212 mstrtime( psz_begin_date, p_sub->begin_date ),
213 mstrtime( psz_end_date, p_sub->end_date ) );
217 /*******************************************************************************
218 * vout_CreateSubtitle: allocate a subtitle in the video output heap.
219 *******************************************************************************
220 * This function create a reserved subtitle in the video output heap.
221 * A null pointer is returned if the function fails. This method provides an
222 * already allocated zone of memory in the subtitle data fields. It needs locking
223 * since several pictures can be created by several producers threads.
224 *******************************************************************************/
225 subtitle_t *vout_CreateSubtitle( vout_thread_t *p_vout, int i_type,
231 /*******************************************************************************
232 * vout_DestroySubtitle: remove a permanent or reserved subtitle from the heap
233 *******************************************************************************
234 * This function frees a previously reserved subtitle.
235 * It is meant to be used when the construction of a picture aborted.
236 * This function does not need locking since reserved subtitles are ignored by
238 *******************************************************************************/
239 void vout_DestroySubtitle( vout_thread_t *p_vout, subtitle_t *p_sub )
242 /* Check if subtitle status is valid */
243 if( p_sub->i_status != RESERVED_SUBTITLE )
245 intf_DbgMsg("error: subtitle %p has invalid status %d\n", p_sub, p_sub->i_status );
249 p_sub->i_status = DESTROYED_SUBTITLE;
252 intf_DbgMsg("subtitle %p\n", p_sub);
256 /*******************************************************************************
257 * vout_DisplayPicture: display a picture
258 *******************************************************************************
259 * Remove the reservation flag of a picture, which will cause it to be ready for
260 * display. The picture does not need to be locked, since it is ignored by
261 * the output thread if is reserved.
262 *******************************************************************************/
263 void vout_DisplayPicture( vout_thread_t *p_vout, picture_t *p_pic )
266 char psz_date[MSTRTIME_MAX_SIZE]; /* buffer for date string */
270 /* Check if picture status is valid */
271 if( p_pic->i_status != RESERVED_PICTURE )
273 intf_DbgMsg("error: picture %p has invalid status %d\n", p_pic, p_pic->i_status );
277 /* Remove reservation flag */
278 p_pic->i_status = READY_PICTURE;
281 /* Send picture informations */
282 intf_DbgMsg("picture %p: type=%d, %dx%d, date=%s\n", p_pic, p_pic->i_type,
283 p_pic->i_width,p_pic->i_height, mstrtime( psz_date, p_pic->date ) );
287 /*******************************************************************************
288 * vout_CreatePicture: allocate a picture in the video output heap.
289 *******************************************************************************
290 * This function create a reserved image in the video output heap.
291 * A null pointer is returned if the function fails. This method provides an
292 * already allocated zone of memory in the picture data fields. It needs locking
293 * since several pictures can be created by several producers threads.
294 *******************************************************************************/
295 picture_t *vout_CreatePicture( vout_thread_t *p_vout, int i_type,
296 int i_width, int i_height )
298 int i_picture; /* picture index */
299 int i_chroma_width = 0; /* chroma width */
300 picture_t * p_free_picture = NULL; /* first free picture */
301 picture_t * p_destroyed_picture = NULL; /* first destroyed picture */
304 vlc_mutex_lock( &p_vout->picture_lock );
307 * Look for an empty place
310 i_picture < VOUT_MAX_PICTURES;
313 if( p_vout->p_picture[i_picture].i_status == DESTROYED_PICTURE )
315 /* Picture is marked for destruction, but is still allocated - note
316 * that if width and type are the same for two pictures, chroma_width
317 * should also be the same */
318 if( (p_vout->p_picture[i_picture].i_type == i_type) &&
319 (p_vout->p_picture[i_picture].i_height == i_height) &&
320 (p_vout->p_picture[i_picture].i_width == i_width) )
322 /* Memory size do match : memory will not be reallocated, and function
323 * can end immediately - this is the best possible case, since no
324 * memory allocation needs to be done */
325 p_vout->p_picture[i_picture].i_status = RESERVED_PICTURE;
327 intf_DbgMsg("picture %p (in destroyed picture slot)\n",
328 &p_vout->p_picture[i_picture] );
330 vlc_mutex_unlock( &p_vout->picture_lock );
331 return( &p_vout->p_picture[i_picture] );
333 else if( p_destroyed_picture == NULL )
335 /* Memory size do not match, but picture index will be kept in
336 * case no other place are left */
337 p_destroyed_picture = &p_vout->p_picture[i_picture];
340 else if( (p_free_picture == NULL) &&
341 (p_vout->p_picture[i_picture].i_status == FREE_PICTURE ))
343 /* Picture is empty and ready for allocation */
344 p_free_picture = &p_vout->p_picture[i_picture];
348 /* If no free picture is available, use a destroyed picture */
349 if( (p_free_picture == NULL) && (p_destroyed_picture != NULL ) )
351 /* No free picture or matching destroyed picture has been found, but
352 * a destroyed picture is still avalaible */
353 free( p_destroyed_picture->p_data );
354 p_free_picture = p_destroyed_picture;
360 if( p_free_picture != NULL )
362 /* Allocate memory */
365 case YUV_420_PICTURE: /* YUV 420: 1,1/4,1/4 samples per pixel */
366 i_chroma_width = i_width / 2;
367 p_free_picture->p_data = malloc( i_height * i_chroma_width * 3 * sizeof( yuv_data_t ) );
368 p_free_picture->p_y = (yuv_data_t *)p_free_picture->p_data;
369 p_free_picture->p_u = (yuv_data_t *)p_free_picture->p_data +i_height*i_chroma_width*4/2;
370 p_free_picture->p_v = (yuv_data_t *)p_free_picture->p_data +i_height*i_chroma_width*5/2;
372 case YUV_422_PICTURE: /* YUV 422: 1,1/2,1/2 samples per pixel */
373 i_chroma_width = i_width / 2;
374 p_free_picture->p_data = malloc( i_height * i_chroma_width * 4 * sizeof( yuv_data_t ) );
375 p_free_picture->p_y = (yuv_data_t *)p_free_picture->p_data;
376 p_free_picture->p_u = (yuv_data_t *)p_free_picture->p_data +i_height*i_chroma_width*2;
377 p_free_picture->p_v = (yuv_data_t *)p_free_picture->p_data +i_height*i_chroma_width*3;
379 case YUV_444_PICTURE: /* YUV 444: 1,1,1 samples per pixel */
380 i_chroma_width = i_width;
381 p_free_picture->p_data = malloc( i_height * i_chroma_width * 3 * sizeof( yuv_data_t ) );
382 p_free_picture->p_y = (yuv_data_t *)p_free_picture->p_data;
383 p_free_picture->p_u = (yuv_data_t *)p_free_picture->p_data +i_height*i_chroma_width;
384 p_free_picture->p_v = (yuv_data_t *)p_free_picture->p_data +i_height*i_chroma_width*2;
388 intf_DbgMsg("error: unknown picture type %d\n", i_type );
389 p_free_picture->p_data = NULL;
394 if( p_free_picture->p_data != NULL )
396 /* Copy picture informations, set some default values */
397 p_free_picture->i_type = i_type;
398 p_free_picture->i_status = RESERVED_PICTURE;
399 p_free_picture->i_matrix_coefficients = 1;
400 p_free_picture->i_width = i_width;
401 p_free_picture->i_height = i_height;
402 p_free_picture->i_chroma_width = i_chroma_width;
403 p_free_picture->i_display_horizontal_offset = 0;
404 p_free_picture->i_display_vertical_offset = 0;
405 p_free_picture->i_display_width = i_width;
406 p_free_picture->i_display_height = i_height;
407 p_free_picture->i_aspect_ratio = AR_SQUARE_PICTURE;
408 p_free_picture->i_refcount = 0;
412 /* Memory allocation failed : set picture as empty */
413 p_free_picture->i_type = EMPTY_PICTURE;
414 p_free_picture->i_status = FREE_PICTURE;
415 p_free_picture = NULL;
416 intf_ErrMsg("warning: %s\n", strerror( ENOMEM ) );
420 intf_DbgMsg("picture %p (in free picture slot)\n", p_free_picture );
422 vlc_mutex_unlock( &p_vout->picture_lock );
423 return( p_free_picture );
426 // No free or destroyed picture could be found
427 intf_DbgMsg( "warning: heap is full\n" );
428 vlc_mutex_unlock( &p_vout->picture_lock );
432 /*******************************************************************************
433 * vout_DestroyPicture: remove a permanent or reserved picture from the heap
434 *******************************************************************************
435 * This function frees a previously reserved picture or a permanent
436 * picture. It is meant to be used when the construction of a picture aborted.
437 * Note that the picture will be destroyed even if it is linked !
438 * This function does not need locking since reserved pictures are ignored by
440 *******************************************************************************/
441 void vout_DestroyPicture( vout_thread_t *p_vout, picture_t *p_pic )
444 /* Check if picture status is valid */
445 if( p_pic->i_status != RESERVED_PICTURE )
447 intf_DbgMsg("error: picture %p has invalid status %d\n", p_pic, p_pic->i_status );
451 p_pic->i_status = DESTROYED_PICTURE;
454 intf_DbgMsg("picture %p\n", p_pic);
458 /*******************************************************************************
459 * vout_LinkPicture: increment reference counter of a picture
460 *******************************************************************************
461 * This function increment the reference counter of a picture in the video
462 * heap. It needs a lock since several producer threads can access the picture.
463 *******************************************************************************/
464 void vout_LinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
466 vlc_mutex_lock( &p_vout->picture_lock );
468 vlc_mutex_unlock( &p_vout->picture_lock );
471 intf_DbgMsg("picture %p\n", p_pic);
475 /*******************************************************************************
476 * vout_UnlinkPicture: decrement reference counter of a picture
477 *******************************************************************************
478 * This function decrement the reference counter of a picture in the video heap.
479 *******************************************************************************/
480 void vout_UnlinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
482 vlc_mutex_lock( &p_vout->picture_lock );
484 if( (p_pic->i_refcount == 0) && (p_pic->i_status == DISPLAYED_PICTURE) )
486 p_pic->i_status = DESTROYED_PICTURE;
488 vlc_mutex_unlock( &p_vout->picture_lock );
491 intf_DbgMsg("picture %p\n", p_pic);
495 /* following functions are local */
497 /*******************************************************************************
498 * InitThread: initialize video output thread
499 *******************************************************************************
500 * This function is called from RunThread and performs the second step of the
501 * initialization. It returns 0 on success. Note that the thread's flag are not
502 * modified inside this function.
503 *******************************************************************************/
504 static int InitThread( vout_thread_t *p_vout )
506 int i_index; /* generic index */
509 *p_vout->pi_status = THREAD_START;
511 /* Initialize output method - this function issues its own error messages */
512 if( vout_SysInit( p_vout ) )
514 *p_vout->pi_status = THREAD_ERROR;
518 /* Initialize pictures and subtitles */
519 for( i_index = 0; i_index < VOUT_MAX_PICTURES; i_index++)
521 p_vout->p_picture[i_index].i_type = EMPTY_PICTURE;
522 p_vout->p_picture[i_index].i_status = FREE_PICTURE;
523 p_vout->p_subtitle[i_index].i_type = EMPTY_SUBTITLE;
524 p_vout->p_subtitle[i_index].i_status= FREE_SUBTITLE;
527 /* Initialize convertion tables and functions */
528 if( vout_InitTables( p_vout ) )
530 intf_ErrMsg("error: can't allocate translation tables\n");
534 /* Mark thread as running and return */
535 p_vout->b_active = 1;
536 *p_vout->pi_status = THREAD_READY;
537 intf_DbgMsg("thread ready\n");
541 /*******************************************************************************
542 * RunThread: video output thread
543 *******************************************************************************
544 * Video output thread. This function does only returns when the thread is
545 * terminated. It handles the pictures arriving in the video heap and the
546 * display device events.
547 *******************************************************************************/
548 static void RunThread( vout_thread_t *p_vout)
550 int i_picture; /* picture index */
551 mtime_t current_date; /* current date */
552 mtime_t pic_date = 0; /* picture date */
553 boolean_t b_display; /* display flag */
554 picture_t * p_pic; /* picture pointer */
557 * Initialize thread and free configuration
559 p_vout->b_error = InitThread( p_vout );
560 if( p_vout->b_error )
562 free( p_vout ); /* destroy descriptor */
567 * Main loop - it is not executed if an error occured during
570 while( (!p_vout->b_die) && (!p_vout->b_error) )
573 * Find the picture to display - this operation does not need lock,
574 * since only READY_PICTURES are handled
577 current_date = mdate();
578 for( i_picture = 0; i_picture < VOUT_MAX_PICTURES; i_picture++ )
580 if( (p_vout->p_picture[i_picture].i_status == READY_PICTURE) &&
582 (p_vout->p_picture[i_picture].date < pic_date) ) )
584 p_pic = &p_vout->p_picture[i_picture];
585 pic_date = p_pic->date;
590 * Render picture if any
595 /* Computes FPS rate */
596 p_vout->fps_sample[ p_vout->c_fps_samples++ % VOUT_FPS_SAMPLES ] = pic_date;
598 if( pic_date < current_date )
600 /* Picture is late: it will be destroyed and the thread will sleep and
601 * go to next picture */
602 vlc_mutex_lock( &p_vout->picture_lock );
603 p_pic->i_status = p_pic->i_refcount ? DISPLAYED_PICTURE : DESTROYED_PICTURE;
604 vlc_mutex_unlock( &p_vout->picture_lock );
606 intf_DbgMsg( "warning: late picture %p skipped\n", p_pic );
610 else if( pic_date > current_date + VOUT_DISPLAY_DELAY )
612 /* A picture is ready to be rendered, but its rendering date is
613 * far from the current one so the thread will perform an empty loop
614 * as if no picture were found. The picture state is unchanged */
621 * Perform rendering, sleep and display rendered picture
625 /* A picture is ready to be displayed : render it */
626 if( p_vout->b_active )
628 RenderPicture( p_vout, p_pic );
631 RenderPictureInfo( p_vout, p_pic );
632 RenderInfo( p_vout );
641 /* Remove picture from heap */
642 vlc_mutex_lock( &p_vout->picture_lock );
643 p_pic->i_status = p_pic->i_refcount ? DISPLAYED_PICTURE : DESTROYED_PICTURE;
644 vlc_mutex_unlock( &p_vout->picture_lock );
648 /* No picture. However, an idle screen may be ready to display */
649 b_display = p_vout->b_active && ( RenderIdle( p_vout ) |
650 ( p_vout->b_info && RenderInfo( p_vout ) ));
653 /* Sleep a while or until a given date */
657 /* Computes loop time */
658 p_vout->loop_time = mdate() - current_date;
664 msleep( VOUT_IDLE_SLEEP );
667 /* On awakening, send immediately picture to display */
668 if( b_display && p_vout->b_active )
670 vout_SysDisplay( p_vout );
674 * Check events and manage thread
676 if( vout_SysManage( p_vout ) | Manage( p_vout ) )
678 /* A fatal error occured, and the thread must terminate immediately,
679 * without displaying anything - setting b_error to 1 cause the
680 * immediate end of the main while() loop. */
688 if( p_vout->b_error )
690 ErrorThread( p_vout );
695 intf_DbgMsg( "thread end\n" );
698 /*******************************************************************************
699 * ErrorThread: RunThread() error loop
700 *******************************************************************************
701 * This function is called when an error occured during thread main's loop. The
702 * thread can still receive feed, but must be ready to terminate as soon as
704 *******************************************************************************/
705 static void ErrorThread( vout_thread_t *p_vout )
707 /* Wait until a `die' order */
708 while( !p_vout->b_die )
711 msleep( VOUT_IDLE_SLEEP );
715 /*******************************************************************************
716 * EndThread: thread destruction
717 *******************************************************************************
718 * This function is called when the thread ends after a sucessfull
720 *******************************************************************************/
721 static void EndThread( vout_thread_t *p_vout )
723 int * pi_status; /* thread status */
727 pi_status = p_vout->pi_status;
728 *pi_status = THREAD_END;
730 /* Destroy all remaining pictures */
731 for( i_picture = 0; i_picture < VOUT_MAX_PICTURES; i_picture++ )
733 if( p_vout->p_picture[i_picture].i_status != FREE_PICTURE )
735 free( p_vout->p_picture[i_picture].p_data );
739 /* Destroy translation tables */
740 vout_EndTables( p_vout );
742 /* Destroy thread structures allocated by InitThread */
743 vout_SysEnd( p_vout );
744 vout_SysDestroy( p_vout );
748 *pi_status = THREAD_OVER;
751 /*******************************************************************************
752 * RenderPicture: render a picture
753 *******************************************************************************
754 * This function convert a picture from a video heap to a pixel-encoded image
755 * and copy it to the current rendering buffer. No lock is required, since the
756 * rendered picture has been determined as existant, and will only be destroyed
757 * by the vout thread later.
758 *******************************************************************************/
759 static void RenderPicture( vout_thread_t *p_vout, picture_t *p_pic )
764 if( (p_pic->i_width > p_vout->i_width) || (p_pic->i_height > p_vout->i_height) )
767 /* X11: window can be resized, so resize it - the picture won't be
768 * rendered since any alteration of the window size means recreating the
770 /* p_vout->i_new_width = p_pic->i_width;
771 p_vout->i_new_height = p_pic->i_height;*/
774 /* Other drivers: the video output thread can't change its size, so
775 * we need to change the aspect ratio */
781 * Choose appropriate rendering function and render picture
783 switch( p_pic->i_type )
785 case YUV_420_PICTURE:
786 p_vout->p_ConvertYUV420( p_vout, vout_SysGetPicture( p_vout ),
787 p_pic->p_y, p_pic->p_u, p_pic->p_v,
788 p_pic->i_width, p_pic->i_height, 0, 0,
789 4, p_pic->i_matrix_coefficients );
791 case YUV_422_PICTURE:
792 /* ??? p_vout->p_convert_yuv_420( p_vout,
793 p_pic->p_y, p_pic->p_u, p_pic->p_v,
794 i_chroma_width, i_chroma_height,
795 p_vout->i_width / 2, p_vout->i_height,
796 p_vout->i_bytes_per_line,
799 case YUV_444_PICTURE:
800 /* ??? p_vout->p_convert_yuv_420( p_vout,
801 p_pic->p_y, p_pic->p_u, p_pic->p_v,
802 i_chroma_width, i_chroma_height,
803 p_vout->i_width, p_vout->i_height,
804 p_vout->i_bytes_per_line,
809 intf_DbgMsg("error: unknown picture type %d\n", p_pic->i_type );
822 /*******************************************************************************
823 * RenderPictureInfo: print additionnal informations on a picture
824 *******************************************************************************
825 * This function will add informations such as fps and buffer size on a picture
826 *******************************************************************************/
827 static void RenderPictureInfo( vout_thread_t *p_vout, picture_t *p_pic )
829 char psz_buffer[256]; /* string buffer */
831 int i_ready_pic = 0; /* ready pictures */
832 int i_reserved_pic = 0; /* reserved pictures */
833 int i_picture; /* picture index */
838 * Print FPS rate in upper right corner
840 if( p_vout->c_fps_samples > VOUT_FPS_SAMPLES )
842 sprintf( psz_buffer, "%.2f fps", (double) VOUT_FPS_SAMPLES * 1000000 /
843 ( p_vout->fps_sample[ (p_vout->c_fps_samples - 1) % VOUT_FPS_SAMPLES ] -
844 p_vout->fps_sample[ p_vout->c_fps_samples % VOUT_FPS_SAMPLES ] ) );
845 vout_SysPrint( p_vout, p_vout->i_width, 0, 1, -1, psz_buffer );
849 * Print statistics in upper left corner
851 sprintf( psz_buffer, "gamma=%.2f %ld frames",
852 p_vout->f_gamma, p_vout->c_fps_samples );
853 vout_SysPrint( p_vout, 0, 0, -1, -1, psz_buffer );
858 * Print heap state in lower left corner
860 for( i_picture = 0; i_picture < VOUT_MAX_PICTURES; i_picture++ )
862 switch( p_vout->p_picture[i_picture].i_status )
864 case RESERVED_PICTURE:
872 sprintf( psz_buffer, "video heap: %d/%d/%d", i_reserved_pic, i_ready_pic,
874 vout_SysPrint( p_vout, 0, p_vout->i_height, -1, 1, psz_buffer );
882 /*******************************************************************************
883 * RenderIdle: render idle picture
884 *******************************************************************************
885 * This function will clear the display or print a logo.
886 *******************************************************************************/
887 static int RenderIdle( vout_thread_t *p_vout )
893 /*******************************************************************************
894 * RenderInfo: render additionnal informations
895 *******************************************************************************
897 *******************************************************************************/
898 static int RenderInfo( vout_thread_t *p_vout )
904 /*******************************************************************************
905 * Manage: manage thread
906 *******************************************************************************
908 *******************************************************************************/
909 static int Manage( vout_thread_t *p_vout )
913 /* Detect unauthorized changes */
914 if( p_vout->i_changes )
916 /* Some changes were not acknowledged by vout_SysManage or this function,
917 * it means they should not be authorized */
918 intf_ErrMsg( "error: unauthorized changes in the video output thread\n" );