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 );
481 if( p_pic->i_refcount < 0 )
483 intf_DbgMsg("error: refcount < 0\n");
484 p_pic->i_refcount = 0;
488 if( (p_pic->i_refcount == 0) && (p_pic->i_status == DISPLAYED_PICTURE) )
490 p_pic->i_status = DESTROYED_PICTURE;
492 vlc_mutex_unlock( &p_vout->picture_lock );
495 intf_DbgMsg("picture %p\n", p_pic);
499 /* following functions are local */
501 /*******************************************************************************
502 * InitThread: initialize video output thread
503 *******************************************************************************
504 * This function is called from RunThread and performs the second step of the
505 * initialization. It returns 0 on success. Note that the thread's flag are not
506 * modified inside this function.
507 *******************************************************************************/
508 static int InitThread( vout_thread_t *p_vout )
510 int i_index; /* generic index */
513 *p_vout->pi_status = THREAD_START;
515 /* Initialize output method - this function issues its own error messages */
516 if( vout_SysInit( p_vout ) )
518 *p_vout->pi_status = THREAD_ERROR;
522 /* Initialize pictures and subtitles */
523 for( i_index = 0; i_index < VOUT_MAX_PICTURES; i_index++)
525 p_vout->p_picture[i_index].i_type = EMPTY_PICTURE;
526 p_vout->p_picture[i_index].i_status = FREE_PICTURE;
527 p_vout->p_subtitle[i_index].i_type = EMPTY_SUBTITLE;
528 p_vout->p_subtitle[i_index].i_status= FREE_SUBTITLE;
531 /* Initialize convertion tables and functions */
532 if( vout_InitTables( p_vout ) )
534 intf_ErrMsg("error: can't allocate translation tables\n");
538 /* Mark thread as running and return */
539 p_vout->b_active = 1;
540 *p_vout->pi_status = THREAD_READY;
541 intf_DbgMsg("thread ready\n");
545 /*******************************************************************************
546 * RunThread: video output thread
547 *******************************************************************************
548 * Video output thread. This function does only returns when the thread is
549 * terminated. It handles the pictures arriving in the video heap and the
550 * display device events.
551 *******************************************************************************/
552 static void RunThread( vout_thread_t *p_vout)
554 int i_picture; /* picture index */
555 mtime_t current_date; /* current date */
556 mtime_t pic_date = 0; /* picture date */
557 boolean_t b_display; /* display flag */
558 picture_t * p_pic; /* picture pointer */
561 * Initialize thread and free configuration
563 p_vout->b_error = InitThread( p_vout );
564 if( p_vout->b_error )
566 free( p_vout ); /* destroy descriptor */
571 * Main loop - it is not executed if an error occured during
574 while( (!p_vout->b_die) && (!p_vout->b_error) )
577 * Find the picture to display - this operation does not need lock,
578 * since only READY_PICTURES are handled
581 current_date = mdate();
582 for( i_picture = 0; i_picture < VOUT_MAX_PICTURES; i_picture++ )
584 if( (p_vout->p_picture[i_picture].i_status == READY_PICTURE) &&
586 (p_vout->p_picture[i_picture].date < pic_date) ) )
588 p_pic = &p_vout->p_picture[i_picture];
589 pic_date = p_pic->date;
594 * Render picture if any
599 /* Computes FPS rate */
600 p_vout->fps_sample[ p_vout->c_fps_samples++ % VOUT_FPS_SAMPLES ] = pic_date;
602 if( pic_date < current_date )
604 /* Picture is late: it will be destroyed and the thread will sleep and
605 * go to next picture */
606 vlc_mutex_lock( &p_vout->picture_lock );
607 p_pic->i_status = p_pic->i_refcount ? DISPLAYED_PICTURE : DESTROYED_PICTURE;
608 vlc_mutex_unlock( &p_vout->picture_lock );
610 intf_DbgMsg( "warning: late picture %p skipped\n", p_pic );
614 else if( pic_date > current_date + VOUT_DISPLAY_DELAY )
616 /* A picture is ready to be rendered, but its rendering date is
617 * far from the current one so the thread will perform an empty loop
618 * as if no picture were found. The picture state is unchanged */
624 * Perform rendering, sleep and display rendered picture
628 /* A picture is ready to be displayed : render it */
629 if( p_vout->b_active )
631 b_display = RenderPicture( p_vout, p_pic, 1 );
634 b_display |= RenderPictureInfo( p_vout, p_pic, b_display );
635 b_display |= RenderInfo( p_vout, b_display );
643 /* Remove picture from heap */
644 vlc_mutex_lock( &p_vout->picture_lock );
645 p_pic->i_status = p_pic->i_refcount ? DISPLAYED_PICTURE : DESTROYED_PICTURE;
646 vlc_mutex_unlock( &p_vout->picture_lock );
650 /* No picture. However, an idle screen may be ready to display */
651 if( p_vout->b_active )
653 b_display = RenderIdle( p_vout, 1 );
656 b_display |= RenderInfo( p_vout, b_display );
665 /* Give back change lock */
666 vlc_mutex_unlock( &p_vout->change_lock );
668 /* Sleep a while or until a given date */
675 msleep( VOUT_IDLE_SLEEP );
678 /* On awakening, take back lock and send immediately picture to display */
679 vlc_mutex_lock( &p_vout->change_lock );
680 if( b_display && p_vout->b_active &&
681 !(p_vout->i_changes & VOUT_NODISPLAY_CHANGE) )
683 vout_SysDisplay( p_vout );
687 * Check events and manage thread
689 if( vout_SysManage( p_vout ) | Manage( p_vout ) )
691 /* A fatal error occured, and the thread must terminate immediately,
692 * without displaying anything - setting b_error to 1 cause the
693 * immediate end of the main while() loop. */
701 if( p_vout->b_error )
703 ErrorThread( p_vout );
708 intf_DbgMsg( "thread end\n" );
711 /*******************************************************************************
712 * ErrorThread: RunThread() error loop
713 *******************************************************************************
714 * This function is called when an error occured during thread main's loop. The
715 * thread can still receive feed, but must be ready to terminate as soon as
717 *******************************************************************************/
718 static void ErrorThread( vout_thread_t *p_vout )
720 /* Wait until a `die' order */
721 while( !p_vout->b_die )
724 msleep( VOUT_IDLE_SLEEP );
728 /*******************************************************************************
729 * EndThread: thread destruction
730 *******************************************************************************
731 * This function is called when the thread ends after a sucessfull
733 *******************************************************************************/
734 static void EndThread( vout_thread_t *p_vout )
736 int * pi_status; /* thread status */
740 pi_status = p_vout->pi_status;
741 *pi_status = THREAD_END;
743 /* Destroy all remaining pictures */
744 for( i_picture = 0; i_picture < VOUT_MAX_PICTURES; i_picture++ )
746 if( p_vout->p_picture[i_picture].i_status != FREE_PICTURE )
748 free( p_vout->p_picture[i_picture].p_data );
752 /* Destroy translation tables */
753 vout_EndTables( p_vout );
755 /* Destroy thread structures allocated by InitThread */
756 vout_SysEnd( p_vout );
757 vout_SysDestroy( p_vout );
761 *pi_status = THREAD_OVER;
764 /*******************************************************************************
765 * RenderBlank: render a blank screen
766 *******************************************************************************
767 * This function is called by all other rendering functions when they arrive on
768 * a non blanked screen.
769 *******************************************************************************/
770 static void RenderBlank( vout_thread_t *p_vout )
773 int i_index; /* current 32 bits sample */
774 int i_width; /* number of 32 bits samples */
775 u32 *p_pic; /* pointer to 32 bits samples */
777 /* Initialize variables */
778 p_pic = vout_SysGetPicture( p_vout );
779 i_width = p_vout->i_bytes_per_line * p_vout->i_height / 128;
781 /* Clear beginning of screen by 128 bytes blocks */
782 for( i_index = 0; i_index < i_width; i_index++ )
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;
790 *p_pic++ = 0; *p_pic++ = 0;
791 *p_pic++ = 0; *p_pic++ = 0;
792 *p_pic++ = 0; *p_pic++ = 0;
793 *p_pic++ = 0; *p_pic++ = 0;
794 *p_pic++ = 0; *p_pic++ = 0;
795 *p_pic++ = 0; *p_pic++ = 0;
796 *p_pic++ = 0; *p_pic++ = 0;
797 *p_pic++ = 0; *p_pic++ = 0;
798 *p_pic++ = 0; *p_pic++ = 0;
799 *p_pic++ = 0; *p_pic++ = 0;
802 /* Clear last pixels */
807 /*******************************************************************************
808 * RenderPicture: render a picture
809 *******************************************************************************
810 * This function convert a picture from a video heap to a pixel-encoded image
811 * and copy it to the current rendering buffer. No lock is required, since the
812 * rendered picture has been determined as existant, and will only be destroyed
813 * by the vout thread later.
814 *******************************************************************************/
815 static int RenderPicture( vout_thread_t *p_vout, picture_t *p_pic, boolean_t b_blank )
818 /* Start recording render time */
819 p_vout->render_time = mdate();
822 /* Mark last picture date */
823 p_vout->last_picture_date = p_pic->date;
825 /* Blank screen if required */
828 // ????? RenderBlank( p_vout );
834 if( (p_pic->i_width > p_vout->i_width) || (p_pic->i_height > p_vout->i_height) )
837 /* X11: window can be resized, so resize it - the picture won't be
838 * rendered since any alteration of the window size means recreating the
840 /* p_vout->i_new_width = p_pic->i_width;
841 p_vout->i_new_height = p_pic->i_height;*/
843 /* Other drivers: the video output thread can't change its size, so
844 * we need to change the aspect ratio */
850 * Choose appropriate rendering function and render picture
852 switch( p_pic->i_type )
854 case YUV_420_PICTURE:
855 p_vout->p_ConvertYUV420( p_vout, vout_SysGetPicture( p_vout ),
856 p_pic->p_y, p_pic->p_u, p_pic->p_v,
857 p_pic->i_width, p_pic->i_height, 0, 0,
858 4, p_pic->i_matrix_coefficients );
860 case YUV_422_PICTURE:
861 /* ??? p_vout->p_convert_yuv_420( p_vout,
862 p_pic->p_y, p_pic->p_u, p_pic->p_v,
863 i_chroma_width, i_chroma_height,
864 p_vout->i_width / 2, p_vout->i_height,
865 p_vout->i_bytes_per_line,
868 case YUV_444_PICTURE:
869 /* ??? p_vout->p_convert_yuv_420( p_vout,
870 p_pic->p_y, p_pic->p_u, p_pic->p_v,
871 i_chroma_width, i_chroma_height,
872 p_vout->i_width, p_vout->i_height,
873 p_vout->i_bytes_per_line,
878 intf_DbgMsg("error: unknown picture type %d\n", p_pic->i_type );
889 /* End recording render time */
890 p_vout->render_time = mdate() - p_vout->render_time;
895 /*******************************************************************************
896 * RenderPictureInfo: print additionnal informations on a picture
897 *******************************************************************************
898 * This function will print informations such as fps and other picture
899 * dependant informations.
900 *******************************************************************************/
901 static int RenderPictureInfo( vout_thread_t *p_vout, picture_t *p_pic, boolean_t b_blank )
903 char psz_buffer[256]; /* string buffer */
907 * Print FPS rate in upper right corner
909 if( p_vout->c_fps_samples > VOUT_FPS_SAMPLES )
911 sprintf( psz_buffer, "%.2f fps", (double) VOUT_FPS_SAMPLES * 1000000 /
912 ( p_vout->fps_sample[ (p_vout->c_fps_samples - 1) % VOUT_FPS_SAMPLES ] -
913 p_vout->fps_sample[ p_vout->c_fps_samples % VOUT_FPS_SAMPLES ] ) );
914 vout_SysPrint( p_vout, p_vout->i_width, 0, 1, -1, psz_buffer );
918 * Print frames count and loop time in upper left corner
920 sprintf( psz_buffer, "%ld frames render time: %lu us",
921 p_vout->c_fps_samples, (long unsigned) p_vout->render_time );
922 vout_SysPrint( p_vout, 0, 0, -1, -1, psz_buffer );
927 * Print picture information in lower right corner
929 sprintf( psz_buffer, "%s picture %dx%d (%dx%d%+d%+d %s)",
930 (p_pic->i_type == YUV_420_PICTURE) ? "4:2:0" :
931 ((p_pic->i_type == YUV_422_PICTURE) ? "4:2:2" :
932 ((p_pic->i_type == YUV_444_PICTURE) ? "4:4:4" : "ukn-type")),
933 p_pic->i_width, p_pic->i_height,
934 p_pic->i_display_width, p_pic->i_display_height,
935 p_pic->i_display_horizontal_offset, p_pic->i_display_vertical_offset,
936 (p_pic->i_aspect_ratio == AR_SQUARE_PICTURE) ? "sq" :
937 ((p_pic->i_aspect_ratio == AR_3_4_PICTURE) ? "4:3" :
938 ((p_pic->i_aspect_ratio == AR_16_9_PICTURE) ? "16:9" :
939 ((p_pic->i_aspect_ratio == AR_221_1_PICTURE) ? "2.21:1" : "ukn-ar" ))));
940 vout_SysPrint( p_vout, p_vout->i_width, p_vout->i_height, 1, 1, psz_buffer );
946 /*******************************************************************************
947 * RenderIdle: render idle picture
948 *******************************************************************************
949 * This function will clear the display or print a logo.
950 *******************************************************************************/
951 static int RenderIdle( vout_thread_t *p_vout, boolean_t b_blank )
953 /* Blank screen if required */
954 if( (mdate() - p_vout->last_picture_date > VOUT_IDLE_DELAY) &&
955 (p_vout->last_picture_date > p_vout->last_display_date) &&
958 RenderBlank( p_vout );
959 p_vout->last_display_date = mdate();
960 vout_SysPrint( p_vout, p_vout->i_width / 2, p_vout->i_height / 2, 0, 0,
968 /*******************************************************************************
969 * RenderInfo: render additionnal informations
970 *******************************************************************************
971 * This function render informations which do not depend of the current picture
973 *******************************************************************************/
974 static int RenderInfo( vout_thread_t *p_vout, boolean_t b_blank )
976 char psz_buffer[256]; /* string buffer */
978 int i_ready_pic = 0; /* ready pictures */
979 int i_reserved_pic = 0; /* reserved pictures */
980 int i_picture; /* picture index */
985 * Print thread state in lower left corner
987 for( i_picture = 0; i_picture < VOUT_MAX_PICTURES; i_picture++ )
989 switch( p_vout->p_picture[i_picture].i_status )
991 case RESERVED_PICTURE:
999 sprintf( psz_buffer, "%s %dx%d:%d %.2f:%.2f g%+.2f pic: %d/%d/%d",
1000 p_vout->b_grayscale ? "gray" : "rgb",
1001 p_vout->i_width, p_vout->i_height,
1002 p_vout->i_screen_depth, p_vout->f_x_ratio, p_vout->f_y_ratio, p_vout->f_gamma,
1003 i_reserved_pic, i_ready_pic,
1004 VOUT_MAX_PICTURES );
1005 vout_SysPrint( p_vout, 0, p_vout->i_height, -1, 1, psz_buffer );
1010 /*******************************************************************************
1011 * Manage: manage thread
1012 *******************************************************************************
1013 * This function will handle changes in thread configuration.
1014 *******************************************************************************/
1015 static int Manage( vout_thread_t *p_vout )
1017 /* On gamma or grayscale change, rebuild tables */
1018 if( p_vout->i_changes & (VOUT_GAMMA_CHANGE | VOUT_GRAYSCALE_CHANGE) )
1020 vout_ResetTables( p_vout );
1023 /* Clear changes flags which does not need management or have been handled */
1024 p_vout->i_changes &= ~(VOUT_INFO_CHANGE | VOUT_GAMMA_CHANGE | VOUT_GRAYSCALE_CHANGE);
1026 /* Detect unauthorized changes */
1027 if( p_vout->i_changes )
1029 /* Some changes were not acknowledged by vout_SysManage or this function,
1030 * it means they should not be authorized */
1031 intf_ErrMsg( "error: unauthorized changes in the video output thread\n" );