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->f_x_ratio = 1;
87 p_vout->f_y_ratio = 1;
88 p_vout->f_gamma = VOUT_GAMMA;
89 intf_DbgMsg("wished configuration: %dx%d,%d (%d bytes/pixel, %d bytes/line), ratio %.2f:%.2f, 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->f_x_ratio, p_vout->f_y_ratio, 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), ratio %.2f:%.2f, 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->f_x_ratio, p_vout->f_y_ratio, 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.
257 *******************************************************************************/
258 void vout_DisplayPicture( vout_thread_t *p_vout, picture_t *p_pic )
261 char psz_date[MSTRTIME_MAX_SIZE]; /* buffer for date string */
265 /* Check if picture status is valid */
266 if( p_pic->i_status != RESERVED_PICTURE )
268 intf_DbgMsg("error: picture %p has invalid status %d\n", p_pic, p_pic->i_status );
272 /* Remove reservation flag */
273 p_pic->i_status = READY_PICTURE;
276 /* Send picture informations */
277 intf_DbgMsg("picture %p: type=%d, %dx%d, date=%s\n", p_pic, p_pic->i_type,
278 p_pic->i_width,p_pic->i_height, mstrtime( psz_date, p_pic->date ) );
282 /*******************************************************************************
283 * vout_CreatePicture: allocate a picture in the video output heap.
284 *******************************************************************************
285 * This function create a reserved image in the video output heap.
286 * A null pointer is returned if the function fails. This method provides an
287 * already allocated zone of memory in the picture data fields. It needs locking
288 * since several pictures can be created by several producers threads.
289 *******************************************************************************/
290 picture_t *vout_CreatePicture( vout_thread_t *p_vout, int i_type,
291 int i_width, int i_height )
293 int i_picture; /* picture index */
294 int i_chroma_width = 0; /* chroma width */
295 picture_t * p_free_picture = NULL; /* first free picture */
296 picture_t * p_destroyed_picture = NULL; /* first destroyed picture */
299 vlc_mutex_lock( &p_vout->picture_lock );
302 * Look for an empty place
305 i_picture < VOUT_MAX_PICTURES;
308 if( p_vout->p_picture[i_picture].i_status == DESTROYED_PICTURE )
310 /* Picture is marked for destruction, but is still allocated - note
311 * that if width and type are the same for two pictures, chroma_width
312 * should also be the same */
313 if( (p_vout->p_picture[i_picture].i_type == i_type) &&
314 (p_vout->p_picture[i_picture].i_height == i_height) &&
315 (p_vout->p_picture[i_picture].i_width == i_width) )
317 /* Memory size do match : memory will not be reallocated, and function
318 * can end immediately - this is the best possible case, since no
319 * memory allocation needs to be done */
320 p_vout->p_picture[i_picture].i_status = RESERVED_PICTURE;
322 intf_DbgMsg("picture %p (in destroyed picture slot)\n",
323 &p_vout->p_picture[i_picture] );
325 vlc_mutex_unlock( &p_vout->picture_lock );
326 return( &p_vout->p_picture[i_picture] );
328 else if( p_destroyed_picture == NULL )
330 /* Memory size do not match, but picture index will be kept in
331 * case no other place are left */
332 p_destroyed_picture = &p_vout->p_picture[i_picture];
335 else if( (p_free_picture == NULL) &&
336 (p_vout->p_picture[i_picture].i_status == FREE_PICTURE ))
338 /* Picture is empty and ready for allocation */
339 p_free_picture = &p_vout->p_picture[i_picture];
343 /* If no free picture is available, use a destroyed picture */
344 if( (p_free_picture == NULL) && (p_destroyed_picture != NULL ) )
346 /* No free picture or matching destroyed picture has been found, but
347 * a destroyed picture is still avalaible */
348 free( p_destroyed_picture->p_data );
349 p_free_picture = p_destroyed_picture;
355 if( p_free_picture != NULL )
357 /* Allocate memory */
360 case YUV_420_PICTURE: /* YUV 420: 1,1/4,1/4 samples per pixel */
361 i_chroma_width = i_width / 2;
362 p_free_picture->p_data = malloc( i_height * i_chroma_width * 3 * sizeof( yuv_data_t ) );
363 p_free_picture->p_y = (yuv_data_t *)p_free_picture->p_data;
364 p_free_picture->p_u = (yuv_data_t *)p_free_picture->p_data +i_height*i_chroma_width*4/2;
365 p_free_picture->p_v = (yuv_data_t *)p_free_picture->p_data +i_height*i_chroma_width*5/2;
367 case YUV_422_PICTURE: /* YUV 422: 1,1/2,1/2 samples per pixel */
368 i_chroma_width = i_width / 2;
369 p_free_picture->p_data = malloc( i_height * i_chroma_width * 4 * sizeof( yuv_data_t ) );
370 p_free_picture->p_y = (yuv_data_t *)p_free_picture->p_data;
371 p_free_picture->p_u = (yuv_data_t *)p_free_picture->p_data +i_height*i_chroma_width*2;
372 p_free_picture->p_v = (yuv_data_t *)p_free_picture->p_data +i_height*i_chroma_width*3;
374 case YUV_444_PICTURE: /* YUV 444: 1,1,1 samples per pixel */
375 i_chroma_width = i_width;
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;
379 p_free_picture->p_v = (yuv_data_t *)p_free_picture->p_data +i_height*i_chroma_width*2;
383 intf_DbgMsg("error: unknown picture type %d\n", i_type );
384 p_free_picture->p_data = NULL;
389 if( p_free_picture->p_data != NULL )
391 /* Copy picture informations, set some default values */
392 p_free_picture->i_type = i_type;
393 p_free_picture->i_status = RESERVED_PICTURE;
394 p_free_picture->i_matrix_coefficients = 1;
395 p_free_picture->i_width = i_width;
396 p_free_picture->i_height = i_height;
397 p_free_picture->i_chroma_width = i_chroma_width;
398 p_free_picture->i_display_horizontal_offset = 0;
399 p_free_picture->i_display_vertical_offset = 0;
400 p_free_picture->i_display_width = i_width;
401 p_free_picture->i_display_height = i_height;
402 p_free_picture->i_aspect_ratio = AR_SQUARE_PICTURE;
403 p_free_picture->i_refcount = 0;
407 /* Memory allocation failed : set picture as empty */
408 p_free_picture->i_type = EMPTY_PICTURE;
409 p_free_picture->i_status = FREE_PICTURE;
410 p_free_picture = NULL;
411 intf_ErrMsg("warning: %s\n", strerror( ENOMEM ) );
415 intf_DbgMsg("picture %p (in free picture slot)\n", p_free_picture );
417 vlc_mutex_unlock( &p_vout->picture_lock );
418 return( p_free_picture );
421 // No free or destroyed picture could be found
422 intf_DbgMsg( "warning: heap is full\n" );
423 vlc_mutex_unlock( &p_vout->picture_lock );
427 /*******************************************************************************
428 * vout_DestroyPicture: remove a permanent or reserved picture from the heap
429 *******************************************************************************
430 * This function frees a previously reserved picture or a permanent
431 * picture. It is meant to be used when the construction of a picture aborted.
432 * Note that the picture will be destroyed even if it is linked !
433 * This function does not need locking since reserved pictures are ignored by
435 *******************************************************************************/
436 void vout_DestroyPicture( vout_thread_t *p_vout, picture_t *p_pic )
439 /* Check if picture status is valid */
440 if( p_pic->i_status != RESERVED_PICTURE )
442 intf_DbgMsg("error: picture %p has invalid status %d\n", p_pic, p_pic->i_status );
446 p_pic->i_status = DESTROYED_PICTURE;
449 intf_DbgMsg("picture %p\n", p_pic);
453 /*******************************************************************************
454 * vout_LinkPicture: increment reference counter of a picture
455 *******************************************************************************
456 * This function increment the reference counter of a picture in the video
457 * heap. It needs a lock since several producer threads can access the picture.
458 *******************************************************************************/
459 void vout_LinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
461 vlc_mutex_lock( &p_vout->picture_lock );
463 vlc_mutex_unlock( &p_vout->picture_lock );
466 intf_DbgMsg("picture %p\n", p_pic);
470 /*******************************************************************************
471 * vout_UnlinkPicture: decrement reference counter of a picture
472 *******************************************************************************
473 * This function decrement the reference counter of a picture in the video heap.
474 *******************************************************************************/
475 void vout_UnlinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
477 vlc_mutex_lock( &p_vout->picture_lock );
479 if( (p_pic->i_refcount == 0) && (p_pic->i_status == DISPLAYED_PICTURE) )
481 p_pic->i_status = DESTROYED_PICTURE;
483 vlc_mutex_unlock( &p_vout->picture_lock );
486 intf_DbgMsg("picture %p\n", p_pic);
490 /* following functions are local */
492 /*******************************************************************************
493 * InitThread: initialize video output thread
494 *******************************************************************************
495 * This function is called from RunThread and performs the second step of the
496 * initialization. It returns 0 on success. Note that the thread's flag are not
497 * modified inside this function.
498 *******************************************************************************/
499 static int InitThread( vout_thread_t *p_vout )
501 int i_index; /* generic index */
504 *p_vout->pi_status = THREAD_START;
506 /* Initialize output method - this function issues its own error messages */
507 if( vout_SysInit( p_vout ) )
509 *p_vout->pi_status = THREAD_ERROR;
513 /* Initialize pictures and subtitles */
514 for( i_index = 0; i_index < VOUT_MAX_PICTURES; i_index++)
516 p_vout->p_picture[i_index].i_type = EMPTY_PICTURE;
517 p_vout->p_picture[i_index].i_status = FREE_PICTURE;
518 p_vout->p_subtitle[i_index].i_type = EMPTY_SUBTITLE;
519 p_vout->p_subtitle[i_index].i_status= FREE_SUBTITLE;
522 /* Initialize convertion tables and functions */
523 if( vout_InitTables( p_vout ) )
525 intf_ErrMsg("error: can't allocate translation tables\n");
529 /* Mark thread as running and return */
530 p_vout->b_active = 1;
531 *p_vout->pi_status = THREAD_READY;
532 intf_DbgMsg("thread ready\n");
536 /*******************************************************************************
537 * RunThread: video output thread
538 *******************************************************************************
539 * Video output thread. This function does only returns when the thread is
540 * terminated. It handles the pictures arriving in the video heap and the
541 * display device events.
542 *******************************************************************************/
543 static void RunThread( vout_thread_t *p_vout)
545 int i_picture; /* picture index */
546 mtime_t current_date; /* current date */
547 mtime_t pic_date = 0; /* picture date */
548 boolean_t b_display; /* display flag */
549 picture_t * p_pic; /* picture pointer */
552 * Initialize thread and free configuration
554 p_vout->b_error = InitThread( p_vout );
555 if( p_vout->b_error )
557 free( p_vout ); /* destroy descriptor */
562 * Main loop - it is not executed if an error occured during
565 while( (!p_vout->b_die) && (!p_vout->b_error) )
568 * Find the picture to display - this operation does not need lock,
569 * since only READY_PICTURES are handled
572 current_date = mdate();
573 for( i_picture = 0; i_picture < VOUT_MAX_PICTURES; i_picture++ )
575 if( (p_vout->p_picture[i_picture].i_status == READY_PICTURE) &&
577 (p_vout->p_picture[i_picture].date < pic_date) ) )
579 p_pic = &p_vout->p_picture[i_picture];
580 pic_date = p_pic->date;
585 * Render picture if any
590 /* Computes FPS rate */
591 p_vout->fps_sample[ p_vout->c_fps_samples++ % VOUT_FPS_SAMPLES ] = pic_date;
593 if( pic_date < current_date )
595 /* Picture is late: it will be destroyed and the thread will sleep and
596 * go to next picture */
597 vlc_mutex_lock( &p_vout->picture_lock );
598 p_pic->i_status = p_pic->i_refcount ? DISPLAYED_PICTURE : DESTROYED_PICTURE;
599 vlc_mutex_unlock( &p_vout->picture_lock );
601 intf_DbgMsg( "warning: late picture %p skipped\n", p_pic );
605 else if( pic_date > current_date + VOUT_DISPLAY_DELAY )
607 /* A picture is ready to be rendered, but its rendering date is
608 * far from the current one so the thread will perform an empty loop
609 * as if no picture were found. The picture state is unchanged */
615 * Perform rendering, sleep and display rendered picture
619 /* A picture is ready to be displayed : render it */
620 if( p_vout->b_active )
622 b_display = RenderPicture( p_vout, p_pic, 1 );
625 b_display |= RenderPictureInfo( p_vout, p_pic, b_display );
626 b_display |= RenderInfo( p_vout, b_display );
634 /* Remove picture from heap */
635 vlc_mutex_lock( &p_vout->picture_lock );
636 p_pic->i_status = p_pic->i_refcount ? DISPLAYED_PICTURE : DESTROYED_PICTURE;
637 vlc_mutex_unlock( &p_vout->picture_lock );
641 /* No picture. However, an idle screen may be ready to display */
642 if( p_vout->b_active )
644 b_display = RenderIdle( p_vout, 1 );
647 b_display |= RenderInfo( p_vout, b_display );
656 /* Give back change lock */
657 vlc_mutex_unlock( &p_vout->change_lock );
659 /* Sleep a while or until a given date */
666 msleep( VOUT_IDLE_SLEEP );
669 /* On awakening, take back lock and send immediately picture to display */
670 vlc_mutex_lock( &p_vout->change_lock );
671 if( b_display && p_vout->b_active &&
672 !(p_vout->i_changes & VOUT_NODISPLAY_CHANGE) )
674 vout_SysDisplay( p_vout );
678 * Check events and manage thread
680 if( vout_SysManage( p_vout ) | Manage( p_vout ) )
682 /* A fatal error occured, and the thread must terminate immediately,
683 * without displaying anything - setting b_error to 1 cause the
684 * immediate end of the main while() loop. */
692 if( p_vout->b_error )
694 ErrorThread( p_vout );
699 intf_DbgMsg( "thread end\n" );
702 /*******************************************************************************
703 * ErrorThread: RunThread() error loop
704 *******************************************************************************
705 * This function is called when an error occured during thread main's loop. The
706 * thread can still receive feed, but must be ready to terminate as soon as
708 *******************************************************************************/
709 static void ErrorThread( vout_thread_t *p_vout )
711 /* Wait until a `die' order */
712 while( !p_vout->b_die )
715 msleep( VOUT_IDLE_SLEEP );
719 /*******************************************************************************
720 * EndThread: thread destruction
721 *******************************************************************************
722 * This function is called when the thread ends after a sucessfull
724 *******************************************************************************/
725 static void EndThread( vout_thread_t *p_vout )
727 int * pi_status; /* thread status */
731 pi_status = p_vout->pi_status;
732 *pi_status = THREAD_END;
734 /* Destroy all remaining pictures */
735 for( i_picture = 0; i_picture < VOUT_MAX_PICTURES; i_picture++ )
737 if( p_vout->p_picture[i_picture].i_status != FREE_PICTURE )
739 free( p_vout->p_picture[i_picture].p_data );
743 /* Destroy translation tables */
744 vout_EndTables( p_vout );
746 /* Destroy thread structures allocated by InitThread */
747 vout_SysEnd( p_vout );
748 vout_SysDestroy( p_vout );
752 *pi_status = THREAD_OVER;
755 /*******************************************************************************
756 * RenderBlank: render a blank screen
757 *******************************************************************************
758 * This function is called by all other rendering functions when they arrive on
759 * a non blanked screen.
760 *******************************************************************************/
761 static void RenderBlank( vout_thread_t *p_vout )
763 int i_index; /* current 32 bits sample */
764 int i_width; /* number of 32 bits samples */
765 u32 *p_pic; /* pointer to 32 bits samples */
767 /* Initialize variables */
768 p_pic = vout_SysGetPicture( p_vout );
769 i_width = p_vout->i_bytes_per_line * p_vout->i_height / 128;
771 /* Clear beginning of screen by 128 bytes blocks */
772 for( i_index = 0; i_index < i_width; i_index++ )
774 *p_pic++ = 0; *p_pic++ = 0;
775 *p_pic++ = 0; *p_pic++ = 0;
776 *p_pic++ = 0; *p_pic++ = 0;
777 *p_pic++ = 0; *p_pic++ = 0;
778 *p_pic++ = 0; *p_pic++ = 0;
779 *p_pic++ = 0; *p_pic++ = 0;
780 *p_pic++ = 0; *p_pic++ = 0;
781 *p_pic++ = 0; *p_pic++ = 0;
782 *p_pic++ = 0; *p_pic++ = 0;
783 *p_pic++ = 0; *p_pic++ = 0;
784 *p_pic++ = 0; *p_pic++ = 0;
785 *p_pic++ = 0; *p_pic++ = 0;
786 *p_pic++ = 0; *p_pic++ = 0;
787 *p_pic++ = 0; *p_pic++ = 0;
788 *p_pic++ = 0; *p_pic++ = 0;
789 *p_pic++ = 0; *p_pic++ = 0;
792 /* Clear last pixels */
797 /*******************************************************************************
798 * RenderPicture: render a picture
799 *******************************************************************************
800 * This function convert a picture from a video heap to a pixel-encoded image
801 * and copy it to the current rendering buffer. No lock is required, since the
802 * rendered picture has been determined as existant, and will only be destroyed
803 * by the vout thread later.
804 *******************************************************************************/
805 static int RenderPicture( vout_thread_t *p_vout, picture_t *p_pic, boolean_t b_blank )
807 /* Mark last picture date */
808 p_vout->last_picture_date = p_pic->date;
810 /* Blank screen if required */
813 RenderBlank( p_vout );
819 if( (p_pic->i_width > p_vout->i_width) || (p_pic->i_height > p_vout->i_height) )
822 /* X11: window can be resized, so resize it - the picture won't be
823 * rendered since any alteration of the window size means recreating the
825 /* p_vout->i_new_width = p_pic->i_width;
826 p_vout->i_new_height = p_pic->i_height;*/
828 /* Other drivers: the video output thread can't change its size, so
829 * we need to change the aspect ratio */
835 * Choose appropriate rendering function and render picture
837 switch( p_pic->i_type )
839 case YUV_420_PICTURE:
840 p_vout->p_ConvertYUV420( p_vout, vout_SysGetPicture( p_vout ),
841 p_pic->p_y, p_pic->p_u, p_pic->p_v,
842 p_pic->i_width, p_pic->i_height, 0, 0,
843 4, p_pic->i_matrix_coefficients );
845 case YUV_422_PICTURE:
846 /* ??? p_vout->p_convert_yuv_420( p_vout,
847 p_pic->p_y, p_pic->p_u, p_pic->p_v,
848 i_chroma_width, i_chroma_height,
849 p_vout->i_width / 2, p_vout->i_height,
850 p_vout->i_bytes_per_line,
853 case YUV_444_PICTURE:
854 /* ??? p_vout->p_convert_yuv_420( p_vout,
855 p_pic->p_y, p_pic->p_u, p_pic->p_v,
856 i_chroma_width, i_chroma_height,
857 p_vout->i_width, p_vout->i_height,
858 p_vout->i_bytes_per_line,
863 intf_DbgMsg("error: unknown picture type %d\n", p_pic->i_type );
878 /*******************************************************************************
879 * RenderPictureInfo: print additionnal informations on a picture
880 *******************************************************************************
881 * This function will print informations such as fps and other picture
882 * dependant informations.
883 *******************************************************************************/
884 static int RenderPictureInfo( vout_thread_t *p_vout, picture_t *p_pic, boolean_t b_blank )
886 char psz_buffer[256]; /* string buffer */
890 * Print FPS rate in upper right corner
892 if( p_vout->c_fps_samples > VOUT_FPS_SAMPLES )
894 sprintf( psz_buffer, "%.2f fps", (double) VOUT_FPS_SAMPLES * 1000000 /
895 ( p_vout->fps_sample[ (p_vout->c_fps_samples - 1) % VOUT_FPS_SAMPLES ] -
896 p_vout->fps_sample[ p_vout->c_fps_samples % VOUT_FPS_SAMPLES ] ) );
897 vout_SysPrint( p_vout, p_vout->i_width, 0, 1, -1, psz_buffer );
901 * Print frames count and loop time in upper left corner
903 sprintf( psz_buffer, "%ld frames render time: %lu us",
904 p_vout->c_fps_samples, (long unsigned) p_vout->render_time );
905 vout_SysPrint( p_vout, 0, 0, -1, -1, psz_buffer );
910 * Print picture information in lower right corner
912 sprintf( psz_buffer, "%s picture (mc=%d) %dx%d (%dx%d%+d%+d ar=%s)",
913 (p_pic->i_type == YUV_420_PICTURE) ? "4:2:0" :
914 ((p_pic->i_type == YUV_422_PICTURE) ? "4:2:2" :
915 ((p_pic->i_type == YUV_444_PICTURE) ? "4:4:4" : "?")),
916 p_pic->i_matrix_coefficients, p_pic->i_width, p_pic->i_height,
917 p_pic->i_display_width, p_pic->i_display_height,
918 p_pic->i_display_horizontal_offset, p_pic->i_display_vertical_offset,
919 (p_pic->i_aspect_ratio == AR_SQUARE_PICTURE) ? "square" :
920 ((p_pic->i_aspect_ratio == AR_3_4_PICTURE) ? "4:3" :
921 ((p_pic->i_aspect_ratio == AR_16_9_PICTURE) ? "16:9" :
922 ((p_pic->i_aspect_ratio == AR_221_1_PICTURE) ? "2.21:1" : "?" ))));
923 vout_SysPrint( p_vout, p_vout->i_width, p_vout->i_height, 1, 1, psz_buffer );
929 /*******************************************************************************
930 * RenderIdle: render idle picture
931 *******************************************************************************
932 * This function will clear the display or print a logo.
933 *******************************************************************************/
934 static int RenderIdle( vout_thread_t *p_vout, boolean_t b_blank )
936 /* Blank screen if required */
937 if( (mdate() - p_vout->last_picture_date > VOUT_IDLE_DELAY) &&
938 (p_vout->last_picture_date > p_vout->last_display_date) &&
941 RenderBlank( p_vout );
942 p_vout->last_display_date = mdate();
943 vout_SysPrint( p_vout, p_vout->i_width / 2, p_vout->i_height / 2, 0, 0,
951 /*******************************************************************************
952 * RenderInfo: render additionnal informations
953 *******************************************************************************
954 * This function render informations which do not depend of the current picture
956 *******************************************************************************/
957 static int RenderInfo( vout_thread_t *p_vout, boolean_t b_blank )
959 char psz_buffer[256]; /* string buffer */
961 int i_ready_pic = 0; /* ready pictures */
962 int i_reserved_pic = 0; /* reserved pictures */
963 int i_picture; /* picture index */
968 * Print thread state in lower left corner
970 for( i_picture = 0; i_picture < VOUT_MAX_PICTURES; i_picture++ )
972 switch( p_vout->p_picture[i_picture].i_status )
974 case RESERVED_PICTURE:
982 sprintf( psz_buffer, "%s %dx%d:%d %.2f:%.2f g%+.2f pic: %d/%d/%d",
983 p_vout->b_grayscale ? "gray" : "rgb",
984 p_vout->i_width, p_vout->i_height,
985 p_vout->i_screen_depth, p_vout->f_x_ratio, p_vout->f_y_ratio, p_vout->f_gamma,
986 i_reserved_pic, i_ready_pic,
988 vout_SysPrint( p_vout, 0, p_vout->i_height, -1, 1, psz_buffer );
993 /*******************************************************************************
994 * Manage: manage thread
995 *******************************************************************************
996 * This function will handle changes in thread configuration.
997 *******************************************************************************/
998 static int Manage( vout_thread_t *p_vout )
1000 /* On gamma or grayscale change, rebuild tables */
1001 if( p_vout->i_changes & (VOUT_GAMMA_CHANGE | VOUT_GRAYSCALE_CHANGE) )
1003 vout_ResetTables( p_vout );
1006 /* Clear changes flags which does not need management or have been handled */
1007 p_vout->i_changes &= ~(VOUT_INFO_CHANGE | VOUT_GAMMA_CHANGE | VOUT_GRAYSCALE_CHANGE);
1009 /* Detect unauthorized changes */
1010 if( p_vout->i_changes )
1012 /* Some changes were not acknowledged by vout_SysManage or this function,
1013 * it means they should not be authorized */
1014 intf_ErrMsg( "error: unauthorized changes in the video output thread\n" );