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 */
74 p_vout->b_grayscale = main_GetIntVariable( VOUT_GRAYSCALE_VAR,
75 VOUT_GRAYSCALE_DEFAULT );
76 p_vout->i_width = i_width;
77 p_vout->i_height = i_height;
78 p_vout->i_bytes_per_line = i_width * 2;
79 p_vout->i_screen_depth = 15;
80 p_vout->i_bytes_per_pixel = 2;
81 p_vout->f_gamma = VOUT_GAMMA;
87 intf_DbgMsg("wished configuration: %dx%d,%d (%d bytes/pixel, %d bytes/line)\n",
88 p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth,
89 p_vout->i_bytes_per_pixel, p_vout->i_bytes_per_line );
91 /* Create and initialize system-dependant method - this function issues its
92 * own error messages */
93 if( vout_SysCreate( p_vout, psz_display, i_root_window ) )
98 intf_DbgMsg("actual configuration: %dx%d,%d (%d bytes/pixel, %d bytes/line)\n",
99 p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth,
100 p_vout->i_bytes_per_pixel, p_vout->i_bytes_per_line );
103 /* Initialize statistics fields */
104 p_vout->render_time = 0;
105 p_vout->c_fps_samples = 0;
108 /* Initialize running properties */
109 p_vout->i_changes = 0;
110 p_vout->last_picture_date = 0;
111 p_vout->last_display_date = 0;
113 /* Create thread and set locks */
114 vlc_mutex_init( &p_vout->picture_lock );
115 vlc_mutex_init( &p_vout->subtitle_lock );
116 vlc_mutex_init( &p_vout->change_lock );
117 vlc_mutex_lock( &p_vout->change_lock );
118 if( vlc_thread_create( &p_vout->thread_id, "video output", (void *) RunThread, (void *) p_vout) )
120 intf_ErrMsg("error: %s\n", strerror(ENOMEM));
121 vout_SysDestroy( p_vout );
126 intf_Msg("Video: display initialized (%dx%d, %d bpp)\n",
127 p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth );
129 /* If status is NULL, wait until the thread is created */
130 if( pi_status == NULL )
134 msleep( THREAD_SLEEP );
135 }while( (i_status != THREAD_READY) && (i_status != THREAD_ERROR)
136 && (i_status != THREAD_FATAL) );
137 if( i_status != THREAD_READY )
145 /*******************************************************************************
146 * vout_DestroyThread: destroys a previously created thread
147 *******************************************************************************
148 * Destroy a terminated thread.
149 * The function will request a destruction of the specified thread. If pi_error
150 * is NULL, it will return once the thread is destroyed. Else, it will be
151 * update using one of the THREAD_* constants.
152 *******************************************************************************/
153 void vout_DestroyThread( vout_thread_t *p_vout, int *pi_status )
155 int i_status; /* thread status */
158 p_vout->pi_status = (pi_status != NULL) ? pi_status : &i_status;
159 *p_vout->pi_status = THREAD_DESTROY;
161 /* Request thread destruction */
164 /* If status is NULL, wait until thread has been destroyed */
165 if( pi_status == NULL )
169 msleep( THREAD_SLEEP );
170 }while( (i_status != THREAD_OVER) && (i_status != THREAD_ERROR)
171 && (i_status != THREAD_FATAL) );
175 /*******************************************************************************
176 * vout_DisplaySubtitle: display a subtitle
177 *******************************************************************************
178 * Remove the reservation flag of a subtitle, which will cause it to be ready for
179 * display. The picture does not need to be locked, since it is ignored by
180 * the output thread if is reserved.
181 *******************************************************************************/
182 void vout_DisplaySubtitle( vout_thread_t *p_vout, subtitle_t *p_sub )
185 char psz_begin_date[MSTRTIME_MAX_SIZE]; /* buffer for date string */
186 char psz_end_date[MSTRTIME_MAX_SIZE]; /* buffer for date string */
190 /* Check if status is valid */
191 if( p_sub->i_status != RESERVED_SUBTITLE )
193 intf_DbgMsg("error: subtitle %p has invalid status %d\n", p_sub, p_sub->i_status );
197 /* Remove reservation flag */
198 p_sub->i_status = READY_SUBTITLE;
201 /* Send subtitle informations */
202 intf_DbgMsg("subtitle %p: type=%d, begin date=%s, end date=%s\n", p_sub, p_sub->i_type,
203 mstrtime( psz_begin_date, p_sub->begin_date ),
204 mstrtime( psz_end_date, p_sub->end_date ) );
208 /*******************************************************************************
209 * vout_CreateSubtitle: allocate a subtitle in the video output heap.
210 *******************************************************************************
211 * This function create a reserved subtitle in the video output heap.
212 * A null pointer is returned if the function fails. This method provides an
213 * already allocated zone of memory in the subtitle data fields. It needs locking
214 * since several pictures can be created by several producers threads.
215 *******************************************************************************/
216 subtitle_t *vout_CreateSubtitle( vout_thread_t *p_vout, int i_type,
222 /*******************************************************************************
223 * vout_DestroySubtitle: remove a permanent or reserved subtitle from the heap
224 *******************************************************************************
225 * This function frees a previously reserved subtitle.
226 * It is meant to be used when the construction of a picture aborted.
227 * This function does not need locking since reserved subtitles are ignored by
229 *******************************************************************************/
230 void vout_DestroySubtitle( vout_thread_t *p_vout, subtitle_t *p_sub )
233 /* Check if subtitle status is valid */
234 if( p_sub->i_status != RESERVED_SUBTITLE )
236 intf_DbgMsg("error: subtitle %p has invalid status %d\n", p_sub, p_sub->i_status );
240 p_sub->i_status = DESTROYED_SUBTITLE;
243 intf_DbgMsg("subtitle %p\n", p_sub);
247 /*******************************************************************************
248 * vout_DisplayPicture: display a picture
249 *******************************************************************************
250 * Remove the reservation flag of a picture, which will cause it to be ready for
251 * display. The picture does not need to be locked, since it is ignored by
252 * the output thread if is reserved. The picture won't be displayed until
253 * vout_DatePicture has been called.
254 *******************************************************************************/
255 void vout_DisplayPicture( vout_thread_t *p_vout, picture_t *p_pic )
258 char psz_date[MSTRTIME_MAX_SIZE]; /* buffer for date string */
262 /* Check if picture status is valid */
263 if( p_pic->i_status != RESERVED_PICTURE )
265 intf_DbgMsg("error: picture %p has invalid status %d\n", p_pic, p_pic->i_status );
269 /* Remove reservation flag */
270 p_pic->i_status = READY_PICTURE;
273 /* Send picture informations */
274 intf_DbgMsg("picture %p: type=%d, %dx%d, date=%s\n", p_pic, p_pic->i_type,
275 p_pic->i_width,p_pic->i_height, mstrtime( psz_date, p_pic->date ) );
279 /*******************************************************************************
280 * vout_DatePicture: date a picture
281 *******************************************************************************
282 * Remove the reservation flag of a picture, which will cause it to be ready for
283 * display. The picture does not need to be locked, since it is ignored by
284 * the output thread if is reserved. The picture won't be displayed until
285 * vout_DisplayPicture has been called.
286 *******************************************************************************/
287 void vout_DatePicture( vout_thread_t *p_vout, picture_t *p_pic, mtime_t date )
292 /*******************************************************************************
293 * vout_CreatePicture: allocate a picture in the video output heap.
294 *******************************************************************************
295 * This function create a reserved image in the video output heap.
296 * A null pointer is returned if the function fails. This method provides an
297 * already allocated zone of memory in the picture data fields. It needs locking
298 * since several pictures can be created by several producers threads.
299 *******************************************************************************/
300 picture_t *vout_CreatePicture( vout_thread_t *p_vout, int i_type,
301 int i_width, int i_height )
303 int i_picture; /* picture index */
304 int i_chroma_width = 0; /* chroma width */
305 picture_t * p_free_picture = NULL; /* first free picture */
306 picture_t * p_destroyed_picture = NULL; /* first destroyed picture */
309 vlc_mutex_lock( &p_vout->picture_lock );
312 * Look for an empty place
315 i_picture < VOUT_MAX_PICTURES;
318 if( p_vout->p_picture[i_picture].i_status == DESTROYED_PICTURE )
320 /* Picture is marked for destruction, but is still allocated - note
321 * that if width and type are the same for two pictures, chroma_width
322 * should also be the same */
323 if( (p_vout->p_picture[i_picture].i_type == i_type) &&
324 (p_vout->p_picture[i_picture].i_height == i_height) &&
325 (p_vout->p_picture[i_picture].i_width == i_width) )
327 /* Memory size do match : memory will not be reallocated, and function
328 * can end immediately - this is the best possible case, since no
329 * memory allocation needs to be done */
330 p_vout->p_picture[i_picture].i_status = RESERVED_PICTURE;
332 intf_DbgMsg("picture %p (in destroyed picture slot)\n",
333 &p_vout->p_picture[i_picture] );
335 vlc_mutex_unlock( &p_vout->picture_lock );
336 return( &p_vout->p_picture[i_picture] );
338 else if( p_destroyed_picture == NULL )
340 /* Memory size do not match, but picture index will be kept in
341 * case no other place are left */
342 p_destroyed_picture = &p_vout->p_picture[i_picture];
345 else if( (p_free_picture == NULL) &&
346 (p_vout->p_picture[i_picture].i_status == FREE_PICTURE ))
348 /* Picture is empty and ready for allocation */
349 p_free_picture = &p_vout->p_picture[i_picture];
353 /* If no free picture is available, use a destroyed picture */
354 if( (p_free_picture == NULL) && (p_destroyed_picture != NULL ) )
356 /* No free picture or matching destroyed picture has been found, but
357 * a destroyed picture is still avalaible */
358 free( p_destroyed_picture->p_data );
359 p_free_picture = p_destroyed_picture;
365 if( p_free_picture != NULL )
367 /* Allocate memory */
370 case YUV_420_PICTURE: /* YUV 420: 1,1/4,1/4 samples per pixel */
371 i_chroma_width = i_width / 2;
372 p_free_picture->p_data = malloc( i_height * i_chroma_width * 3 * sizeof( yuv_data_t ) );
373 p_free_picture->p_y = (yuv_data_t *)p_free_picture->p_data;
374 p_free_picture->p_u = (yuv_data_t *)p_free_picture->p_data +i_height*i_chroma_width*4/2;
375 p_free_picture->p_v = (yuv_data_t *)p_free_picture->p_data +i_height*i_chroma_width*5/2;
377 case YUV_422_PICTURE: /* YUV 422: 1,1/2,1/2 samples per pixel */
378 i_chroma_width = i_width / 2;
379 p_free_picture->p_data = malloc( i_height * i_chroma_width * 4 * sizeof( yuv_data_t ) );
380 p_free_picture->p_y = (yuv_data_t *)p_free_picture->p_data;
381 p_free_picture->p_u = (yuv_data_t *)p_free_picture->p_data +i_height*i_chroma_width*2;
382 p_free_picture->p_v = (yuv_data_t *)p_free_picture->p_data +i_height*i_chroma_width*3;
384 case YUV_444_PICTURE: /* YUV 444: 1,1,1 samples per pixel */
385 i_chroma_width = i_width;
386 p_free_picture->p_data = malloc( i_height * i_chroma_width * 3 * sizeof( yuv_data_t ) );
387 p_free_picture->p_y = (yuv_data_t *)p_free_picture->p_data;
388 p_free_picture->p_u = (yuv_data_t *)p_free_picture->p_data +i_height*i_chroma_width;
389 p_free_picture->p_v = (yuv_data_t *)p_free_picture->p_data +i_height*i_chroma_width*2;
393 intf_DbgMsg("error: unknown picture type %d\n", i_type );
394 p_free_picture->p_data = NULL;
399 if( p_free_picture->p_data != NULL )
401 /* Copy picture informations, set some default values */
402 p_free_picture->i_type = i_type;
403 p_free_picture->i_status = RESERVED_PICTURE;
404 p_free_picture->i_matrix_coefficients = 1;
405 p_free_picture->i_width = i_width;
406 p_free_picture->i_height = i_height;
407 p_free_picture->i_chroma_width = i_chroma_width;
408 p_free_picture->i_display_horizontal_offset = 0;
409 p_free_picture->i_display_vertical_offset = 0;
410 p_free_picture->i_display_width = i_width;
411 p_free_picture->i_display_height = i_height;
412 p_free_picture->i_aspect_ratio = AR_SQUARE_PICTURE;
413 p_free_picture->i_refcount = 0;
417 /* Memory allocation failed : set picture as empty */
418 p_free_picture->i_type = EMPTY_PICTURE;
419 p_free_picture->i_status = FREE_PICTURE;
420 p_free_picture = NULL;
421 intf_ErrMsg("warning: %s\n", strerror( ENOMEM ) );
425 intf_DbgMsg("picture %p (in free picture slot)\n", p_free_picture );
427 vlc_mutex_unlock( &p_vout->picture_lock );
428 return( p_free_picture );
431 // No free or destroyed picture could be found
432 intf_DbgMsg( "warning: heap is full\n" );
433 vlc_mutex_unlock( &p_vout->picture_lock );
437 /*******************************************************************************
438 * vout_DestroyPicture: remove a permanent or reserved picture from the heap
439 *******************************************************************************
440 * This function frees a previously reserved picture or a permanent
441 * picture. It is meant to be used when the construction of a picture aborted.
442 * Note that the picture will be destroyed even if it is linked !
443 * This function does not need locking since reserved pictures are ignored by
445 *******************************************************************************/
446 void vout_DestroyPicture( vout_thread_t *p_vout, picture_t *p_pic )
449 /* Check if picture status is valid */
450 if( p_pic->i_status != RESERVED_PICTURE )
452 intf_DbgMsg("error: picture %p has invalid status %d\n", p_pic, p_pic->i_status );
456 p_pic->i_status = DESTROYED_PICTURE;
459 intf_DbgMsg("picture %p\n", p_pic);
463 /*******************************************************************************
464 * vout_LinkPicture: increment reference counter of a picture
465 *******************************************************************************
466 * This function increment the reference counter of a picture in the video
467 * heap. It needs a lock since several producer threads can access the picture.
468 *******************************************************************************/
469 void vout_LinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
471 vlc_mutex_lock( &p_vout->picture_lock );
473 vlc_mutex_unlock( &p_vout->picture_lock );
476 intf_DbgMsg("picture %p\n", p_pic);
480 /*******************************************************************************
481 * vout_UnlinkPicture: decrement reference counter of a picture
482 *******************************************************************************
483 * This function decrement the reference counter of a picture in the video heap.
484 *******************************************************************************/
485 void vout_UnlinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
487 vlc_mutex_lock( &p_vout->picture_lock );
491 if( p_pic->i_refcount < 0 )
493 intf_DbgMsg("error: refcount < 0\n");
494 p_pic->i_refcount = 0;
498 if( (p_pic->i_refcount == 0) && (p_pic->i_status == DISPLAYED_PICTURE) )
500 p_pic->i_status = DESTROYED_PICTURE;
502 vlc_mutex_unlock( &p_vout->picture_lock );
505 intf_DbgMsg("picture %p\n", p_pic);
509 /* following functions are local */
511 /*******************************************************************************
512 * InitThread: initialize video output thread
513 *******************************************************************************
514 * This function is called from RunThread and performs the second step of the
515 * initialization. It returns 0 on success. Note that the thread's flag are not
516 * modified inside this function.
517 *******************************************************************************/
518 static int InitThread( vout_thread_t *p_vout )
520 int i_index; /* generic index */
523 *p_vout->pi_status = THREAD_START;
525 /* Initialize output method - this function issues its own error messages */
526 if( vout_SysInit( p_vout ) )
528 *p_vout->pi_status = THREAD_ERROR;
532 /* Initialize pictures and subtitles */
533 for( i_index = 0; i_index < VOUT_MAX_PICTURES; i_index++)
535 p_vout->p_picture[i_index].i_type = EMPTY_PICTURE;
536 p_vout->p_picture[i_index].i_status = FREE_PICTURE;
537 p_vout->p_subtitle[i_index].i_type = EMPTY_SUBTITLE;
538 p_vout->p_subtitle[i_index].i_status= FREE_SUBTITLE;
541 /* Initialize convertion tables and functions */
542 if( vout_InitTables( p_vout ) )
544 intf_ErrMsg("error: can't allocate translation tables\n");
548 /* Mark thread as running and return */
549 p_vout->b_active = 1;
550 *p_vout->pi_status = THREAD_READY;
551 intf_DbgMsg("thread ready\n");
555 /*******************************************************************************
556 * RunThread: video output thread
557 *******************************************************************************
558 * Video output thread. This function does only returns when the thread is
559 * terminated. It handles the pictures arriving in the video heap and the
560 * display device events.
561 *******************************************************************************/
562 static void RunThread( vout_thread_t *p_vout)
564 int i_picture; /* picture index */
565 mtime_t current_date; /* current date */
566 mtime_t pic_date = 0; /* picture date */
567 boolean_t b_display; /* display flag */
568 picture_t * p_pic; /* picture pointer */
571 * Initialize thread and free configuration
573 p_vout->b_error = InitThread( p_vout );
574 if( p_vout->b_error )
576 free( p_vout ); /* destroy descriptor */
581 * Main loop - it is not executed if an error occured during
584 while( (!p_vout->b_die) && (!p_vout->b_error) )
587 * Find the picture to display - this operation does not need lock,
588 * since only READY_PICTURES are handled
591 current_date = mdate();
592 for( i_picture = 0; i_picture < VOUT_MAX_PICTURES; i_picture++ )
594 if( (p_vout->p_picture[i_picture].i_status == READY_PICTURE) &&
596 (p_vout->p_picture[i_picture].date < pic_date) ) )
598 p_pic = &p_vout->p_picture[i_picture];
599 pic_date = p_pic->date;
604 * Render picture if any
609 /* Computes FPS rate */
610 p_vout->fps_sample[ p_vout->c_fps_samples++ % VOUT_FPS_SAMPLES ] = pic_date;
612 if( pic_date < current_date )
614 /* Picture is late: it will be destroyed and the thread will sleep and
615 * go to next picture */
616 vlc_mutex_lock( &p_vout->picture_lock );
617 p_pic->i_status = p_pic->i_refcount ? DISPLAYED_PICTURE : DESTROYED_PICTURE;
618 vlc_mutex_unlock( &p_vout->picture_lock );
620 intf_DbgMsg( "warning: late picture %p skipped\n", p_pic );
624 else if( pic_date > current_date + VOUT_DISPLAY_DELAY )
626 /* A picture is ready to be rendered, but its rendering date is
627 * far from the current one so the thread will perform an empty loop
628 * as if no picture were found. The picture state is unchanged */
634 * Perform rendering, sleep and display rendered picture
638 /* A picture is ready to be displayed : render it */
639 if( p_vout->b_active )
641 b_display = RenderPicture( p_vout, p_pic, 1 );
644 b_display |= RenderPictureInfo( p_vout, p_pic, b_display );
645 b_display |= RenderInfo( p_vout, b_display );
653 /* Remove picture from heap */
654 vlc_mutex_lock( &p_vout->picture_lock );
655 p_pic->i_status = p_pic->i_refcount ? DISPLAYED_PICTURE : DESTROYED_PICTURE;
656 vlc_mutex_unlock( &p_vout->picture_lock );
660 /* No picture. However, an idle screen may be ready to display */
661 if( p_vout->b_active )
663 b_display = RenderIdle( p_vout, 1 );
666 b_display |= RenderInfo( p_vout, b_display );
675 /* Give back change lock */
676 vlc_mutex_unlock( &p_vout->change_lock );
678 /* Sleep a while or until a given date */
685 msleep( VOUT_IDLE_SLEEP );
688 /* On awakening, take back lock and send immediately picture to display */
689 vlc_mutex_lock( &p_vout->change_lock );
690 if( b_display && p_vout->b_active &&
691 !(p_vout->i_changes & VOUT_NODISPLAY_CHANGE) )
693 vout_SysDisplay( p_vout );
697 * Check events and manage thread
699 if( vout_SysManage( p_vout ) | Manage( p_vout ) )
701 /* A fatal error occured, and the thread must terminate immediately,
702 * without displaying anything - setting b_error to 1 cause the
703 * immediate end of the main while() loop. */
711 if( p_vout->b_error )
713 ErrorThread( p_vout );
718 intf_DbgMsg( "thread end\n" );
721 /*******************************************************************************
722 * ErrorThread: RunThread() error loop
723 *******************************************************************************
724 * This function is called when an error occured during thread main's loop. The
725 * thread can still receive feed, but must be ready to terminate as soon as
727 *******************************************************************************/
728 static void ErrorThread( vout_thread_t *p_vout )
730 /* Wait until a `die' order */
731 while( !p_vout->b_die )
734 msleep( VOUT_IDLE_SLEEP );
738 /*******************************************************************************
739 * EndThread: thread destruction
740 *******************************************************************************
741 * This function is called when the thread ends after a sucessfull
743 *******************************************************************************/
744 static void EndThread( vout_thread_t *p_vout )
746 int * pi_status; /* thread status */
750 pi_status = p_vout->pi_status;
751 *pi_status = THREAD_END;
753 /* Destroy all remaining pictures */
754 for( i_picture = 0; i_picture < VOUT_MAX_PICTURES; i_picture++ )
756 if( p_vout->p_picture[i_picture].i_status != FREE_PICTURE )
758 free( p_vout->p_picture[i_picture].p_data );
762 /* Destroy translation tables */
763 vout_EndTables( p_vout );
765 /* Destroy thread structures allocated by InitThread */
766 vout_SysEnd( p_vout );
767 vout_SysDestroy( p_vout );
771 *pi_status = THREAD_OVER;
774 /*******************************************************************************
775 * RenderBlank: render a blank screen
776 *******************************************************************************
777 * This function is called by all other rendering functions when they arrive on
778 * a non blanked screen.
779 *******************************************************************************/
780 static void RenderBlank( vout_thread_t *p_vout )
783 int i_index; /* current 32 bits sample */
784 int i_width; /* number of 32 bits samples */
785 u32 *p_pic; /* pointer to 32 bits samples */
787 /* Initialize variables */
788 p_pic = vout_SysGetPicture( p_vout );
789 i_width = p_vout->i_bytes_per_line * p_vout->i_height / 128;
791 /* Clear beginning of screen by 128 bytes blocks */
792 for( i_index = 0; i_index < i_width; i_index++ )
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;
800 *p_pic++ = 0; *p_pic++ = 0;
801 *p_pic++ = 0; *p_pic++ = 0;
802 *p_pic++ = 0; *p_pic++ = 0;
803 *p_pic++ = 0; *p_pic++ = 0;
804 *p_pic++ = 0; *p_pic++ = 0;
805 *p_pic++ = 0; *p_pic++ = 0;
806 *p_pic++ = 0; *p_pic++ = 0;
807 *p_pic++ = 0; *p_pic++ = 0;
808 *p_pic++ = 0; *p_pic++ = 0;
809 *p_pic++ = 0; *p_pic++ = 0;
812 /* Clear last pixels */
817 /*******************************************************************************
818 * RenderPicture: render a picture
819 *******************************************************************************
820 * This function convert a picture from a video heap to a pixel-encoded image
821 * and copy it to the current rendering buffer. No lock is required, since the
822 * rendered picture has been determined as existant, and will only be destroyed
823 * by the vout thread later.
824 *******************************************************************************/
825 static int RenderPicture( vout_thread_t *p_vout, picture_t *p_pic, boolean_t b_blank )
827 int i_display_height, i_display_width; /* display dimensions */
828 int i_height, i_width; /* source picture dimensions */
829 int i_scaled_height; /* scaled height of the picture */
830 int i_aspect_scale; /* aspect ratio vertical scale */
831 int i_eol; /* end of line offset for source */
832 byte_t * p_convert_dst; /* convertion destination */
835 /* Start recording render time */
836 p_vout->render_time = mdate();
839 /* Mark last picture date */
840 p_vout->last_picture_date = p_pic->date;
841 i_width = p_pic->i_width;
842 i_height = p_pic->i_height;
843 i_display_width = p_vout->i_width;
844 i_display_height = p_vout->i_height;
846 /* Select scaling depending of aspect ratio */
847 switch( p_pic->i_aspect_ratio )
850 i_aspect_scale = (4 * i_height - 3 * i_width) ?
851 1 + 3 * i_width / ( 4 * i_height - 3 * i_width ) : 0;
853 case AR_16_9_PICTURE:
854 i_aspect_scale = ( 16 * i_height - 9 * i_width ) ?
855 1 + 9 * i_width / ( 16 * i_height - 9 * i_width ) : 0;
857 case AR_221_1_PICTURE:
858 i_aspect_scale = ( 221 * i_height - 100 * i_width ) ?
859 1 + 100 * i_width / ( 221 * i_height - 100 * i_width ) : 0;
861 case AR_SQUARE_PICTURE:
865 i_scaled_height = (i_aspect_scale ? i_height * (i_aspect_scale - 1) / i_aspect_scale : i_height);
867 /* Crop picture if too large for the screen */
868 if( i_width > i_display_width )
870 i_eol = i_width - i_display_width / 16 * 16;
871 i_width = i_display_width / 16 * 16;
877 if( i_scaled_height > i_display_height )
879 i_height = (i_aspect_scale * i_display_height / (i_aspect_scale - 1)) / 2 * 2;
880 i_scaled_height = i_display_height;
882 p_convert_dst = vout_SysGetPicture( p_vout ) +
883 ( i_display_width - i_width ) / 2 * p_vout->i_bytes_per_pixel +
884 ( i_display_height - i_scaled_height ) / 2 * p_vout->i_bytes_per_line;
887 * Choose appropriate rendering function and render picture
889 switch( p_pic->i_type )
891 case YUV_420_PICTURE:
892 p_vout->p_ConvertYUV420( p_vout, p_convert_dst,
893 p_pic->p_y, p_pic->p_u, p_pic->p_v,
894 i_width, i_height, i_eol,
895 p_vout->i_bytes_per_line / p_vout->i_bytes_per_pixel - i_width,
896 i_aspect_scale, p_pic->i_matrix_coefficients );
898 case YUV_422_PICTURE:
899 p_vout->p_ConvertYUV422( p_vout, p_convert_dst,
900 p_pic->p_y, p_pic->p_u, p_pic->p_v,
901 i_width, i_height, i_eol,
902 p_vout->i_bytes_per_line / p_vout->i_bytes_per_pixel - i_width,
903 i_aspect_scale, p_pic->i_matrix_coefficients );
905 case YUV_444_PICTURE:
906 p_vout->p_ConvertYUV444( p_vout, p_convert_dst,
907 p_pic->p_y, p_pic->p_u, p_pic->p_v,
908 i_width, i_height, i_eol,
909 p_vout->i_bytes_per_line / p_vout->i_bytes_per_pixel - i_width,
910 i_aspect_scale, p_pic->i_matrix_coefficients );
914 intf_DbgMsg("error: unknown picture type %d\n", p_pic->i_type );
920 /* End recording render time */
921 p_vout->render_time = mdate() - p_vout->render_time;
926 /*******************************************************************************
927 * RenderPictureInfo: print additionnal informations on a picture
928 *******************************************************************************
929 * This function will print informations such as fps and other picture
930 * dependant informations.
931 *******************************************************************************/
932 static int RenderPictureInfo( vout_thread_t *p_vout, picture_t *p_pic, boolean_t b_blank )
934 char psz_buffer[256]; /* string buffer */
938 * Print FPS rate in upper right corner
940 if( p_vout->c_fps_samples > VOUT_FPS_SAMPLES )
942 sprintf( psz_buffer, "%.2f fps", (double) VOUT_FPS_SAMPLES * 1000000 /
943 ( p_vout->fps_sample[ (p_vout->c_fps_samples - 1) % VOUT_FPS_SAMPLES ] -
944 p_vout->fps_sample[ p_vout->c_fps_samples % VOUT_FPS_SAMPLES ] ) );
945 vout_SysPrint( p_vout, p_vout->i_width, 0, 1, -1, psz_buffer );
949 * Print frames count and loop time in upper left corner
951 sprintf( psz_buffer, "%ld frames render time: %lu us",
952 p_vout->c_fps_samples, (long unsigned) p_vout->render_time );
953 vout_SysPrint( p_vout, 0, 0, -1, -1, psz_buffer );
958 * Print picture information in lower right corner
960 sprintf( psz_buffer, "%s picture %dx%d (%dx%d%+d%+d %s)",
961 (p_pic->i_type == YUV_420_PICTURE) ? "4:2:0" :
962 ((p_pic->i_type == YUV_422_PICTURE) ? "4:2:2" :
963 ((p_pic->i_type == YUV_444_PICTURE) ? "4:4:4" : "ukn-type")),
964 p_pic->i_width, p_pic->i_height,
965 p_pic->i_display_width, p_pic->i_display_height,
966 p_pic->i_display_horizontal_offset, p_pic->i_display_vertical_offset,
967 (p_pic->i_aspect_ratio == AR_SQUARE_PICTURE) ? "sq" :
968 ((p_pic->i_aspect_ratio == AR_3_4_PICTURE) ? "4:3" :
969 ((p_pic->i_aspect_ratio == AR_16_9_PICTURE) ? "16:9" :
970 ((p_pic->i_aspect_ratio == AR_221_1_PICTURE) ? "2.21:1" : "ukn-ar" ))));
971 vout_SysPrint( p_vout, p_vout->i_width, p_vout->i_height, 1, 1, psz_buffer );
977 /*******************************************************************************
978 * RenderIdle: render idle picture
979 *******************************************************************************
980 * This function will clear the display or print a logo.
981 *******************************************************************************/
982 static int RenderIdle( vout_thread_t *p_vout, boolean_t b_blank )
984 /* Blank screen if required */
985 if( (mdate() - p_vout->last_picture_date > VOUT_IDLE_DELAY) &&
986 (p_vout->last_picture_date > p_vout->last_display_date) &&
989 RenderBlank( p_vout );
990 p_vout->last_display_date = mdate();
991 vout_SysPrint( p_vout, p_vout->i_width / 2, p_vout->i_height / 2, 0, 0,
999 /*******************************************************************************
1000 * RenderInfo: render additionnal informations
1001 *******************************************************************************
1002 * This function render informations which do not depend of the current picture
1004 *******************************************************************************/
1005 static int RenderInfo( vout_thread_t *p_vout, boolean_t b_blank )
1007 char psz_buffer[256]; /* string buffer */
1009 int i_ready_pic = 0; /* ready pictures */
1010 int i_reserved_pic = 0; /* reserved pictures */
1011 int i_picture; /* picture index */
1016 * Print thread state in lower left corner
1018 for( i_picture = 0; i_picture < VOUT_MAX_PICTURES; i_picture++ )
1020 switch( p_vout->p_picture[i_picture].i_status )
1022 case RESERVED_PICTURE:
1030 sprintf( psz_buffer, "%dx%d:%d g%+.2f pic: %d/%d/%d",
1031 p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth,
1032 p_vout->f_gamma, i_reserved_pic, i_ready_pic,
1033 VOUT_MAX_PICTURES );
1034 vout_SysPrint( p_vout, 0, p_vout->i_height, -1, 1, psz_buffer );
1039 /*******************************************************************************
1040 * Manage: manage thread
1041 *******************************************************************************
1042 * This function will handle changes in thread configuration.
1043 *******************************************************************************/
1044 static int Manage( vout_thread_t *p_vout )
1046 /* On gamma or grayscale change, rebuild tables */
1047 if( p_vout->i_changes & (VOUT_GAMMA_CHANGE | VOUT_GRAYSCALE_CHANGE) )
1049 vout_ResetTables( p_vout );
1052 /* Clear changes flags which does not need management or have been handled */
1053 p_vout->i_changes &= ~(VOUT_GAMMA_CHANGE | VOUT_GRAYSCALE_CHANGE |
1056 /* Detect unauthorized changes */
1057 if( p_vout->i_changes )
1059 /* Some changes were not acknowledged by vout_SysManage or this function,
1060 * it means they should not be authorized */
1061 intf_ErrMsg( "error: unauthorized changes in the video output thread\n" );