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 *******************************************************************************/
25 #include "vlc_thread.h"
27 #include "video_output.h"
28 #include "video_sys.h"
31 /*******************************************************************************
33 *******************************************************************************/
34 #define CLIP_BYTE( i_val ) ( (i_val < 0) ? 0 : ((i_val > 255) ? 255 : i_val) )
36 /*******************************************************************************
38 *******************************************************************************/
40 /* RGB/YUV inversion matrix (ISO/IEC 13818-2 section 6.3.6, table 6.9) */
41 int matrix_coefficients[8][4] =
43 {117504, 138453, 13954, 34903}, /* no sequence_display_extension */
44 {117504, 138453, 13954, 34903}, /* ITU-R Rec. 709 (1990) */
45 {104597, 132201, 25675, 53279}, /* unspecified */
46 {104597, 132201, 25675, 53279}, /* reserved */
47 {104448, 132798, 24759, 53109}, /* FCC */
48 {104597, 132201, 25675, 53279}, /* ITU-R Rec. 624-4 System B, G */
49 {104597, 132201, 25675, 53279}, /* SMPTE 170M */
50 {117579, 136230, 16907, 35559} /* SMPTE 240M (1987) */
53 /*******************************************************************************
55 *******************************************************************************/
56 static int InitThread ( vout_thread_t *p_vout );
57 static void RunThread ( vout_thread_t *p_vout );
58 static void ErrorThread ( vout_thread_t *p_vout );
59 static void EndThread ( vout_thread_t *p_vout );
61 static void RenderPicture ( vout_thread_t *p_vout, picture_t *p_pic );
63 /*******************************************************************************
64 * vout_CreateThread: creates a new video output thread
65 *******************************************************************************
66 * This function creates a new video output thread, and returns a pointer
67 * to its description. On error, it returns NULL.
68 * Following configuration properties are used:
69 * VIDEO_CFG_SIZE video heap maximal size
70 * VIDEO_CFG_WIDTH window width
71 * VIDEO_CFG_HEIGHT window height
72 * Using X11 display method (the only one supported yet):
73 * VIDEO_CFG_DISPLAY display used
74 * VIDEO_CFG_TITLE window title
75 * VIDEO_CFG_SHM_EXT try to use XShm extension
76 * If pi_status is NULL, then the function will block until the thread is ready.
77 * If not, pi_error will be updated using one of the THREAD_* constants.
78 *******************************************************************************/
79 vout_thread_t * vout_CreateThread (
80 #if defined(VIDEO_X11)
81 char *psz_display, Window root_window,
82 #elif defined(VIDEO_FB)
85 int i_width, int i_height, int *pi_status
88 vout_thread_t * p_vout; /* thread descriptor */
89 int i_status; /* thread status */
91 /* Allocate descriptor and create method */
92 p_vout = (vout_thread_t *) malloc( sizeof(vout_thread_t) );
93 if( p_vout == NULL ) /* error */
97 intf_DbgMsg( "0x%x\n", p_vout );
98 if( vout_SysCreate( p_vout
99 #if defined(VIDEO_X11)
100 , psz_display, root_window
101 #elif defined(VIDEO_FB)
111 p_vout->i_width = i_width;
112 p_vout->i_height = i_height;
113 p_vout->pi_status = (pi_status != NULL) ? pi_status : &i_status;
114 *p_vout->pi_status = THREAD_CREATE;
117 p_vout->b_active = 0;
119 /* Create thread and set locks */
120 vlc_mutex_init( &p_vout->lock );
121 if( vlc_thread_create( &p_vout->thread_id, "video output",
122 (void *) RunThread, (void *) p_vout) )
124 intf_ErrMsg("vout error: %s\n", strerror(ENOMEM));
125 vout_SysDestroy( p_vout );
130 /* If status is NULL, wait until the thread is created */
131 if( pi_status == NULL )
135 msleep( THREAD_SLEEP );
136 }while( (i_status != THREAD_READY) && (i_status != THREAD_ERROR)
137 && (i_status != THREAD_FATAL) );
138 if( i_status != THREAD_READY )
147 /*******************************************************************************
148 * vout_DestroyThread: destroys a previously created thread
149 *******************************************************************************
150 * Destroy a terminated thread.
151 * The function will request a destruction of the specified thread. If pi_error
152 * is NULL, it will return once the thread is destroyed. Else, it will be
153 * update using one of the THREAD_* constants.
154 *******************************************************************************/
155 void vout_DestroyThread( vout_thread_t *p_vout, int *pi_status )
157 int i_status; /* thread status */
159 intf_DbgMsg( "0x%x\n", p_vout );
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_DisplayPicture: display a picture
181 *******************************************************************************
182 * Remove the reservation flag of a picture, which will cause it to be ready for
184 *******************************************************************************/
185 void vout_DisplayPicture( vout_thread_t *p_vout, picture_t *p_pic )
187 vlc_mutex_lock( &p_vout->lock );
189 /* Remove reservation flag */
190 p_pic->i_status = READY_PICTURE;
194 p_vout->c_pictures++;
197 vlc_mutex_unlock( &p_vout->lock );
200 /*******************************************************************************
201 * vout_CreatePicture: allocate a picture in the video output heap.
202 *******************************************************************************
203 * This function create a reserved image in the video output heap.
204 * A null pointer is returned if the function fails. This method provides an
205 * already allocated zone of memory in the picture data fields.
206 *******************************************************************************/
207 picture_t *vout_CreatePicture( vout_thread_t *p_vout, int i_type,
208 int i_width, int i_height, int i_bytes_per_line )
210 int i_picture; /* picture index */
211 picture_t * p_free_picture = NULL; /* first free picture */
212 picture_t * p_destroyed_picture = NULL; /* first destroyed picture */
215 vlc_mutex_lock( &p_vout->lock );
218 * Look for an empty place
221 i_picture < VOUT_MAX_PICTURES;
224 if( p_vout->p_picture[i_picture].i_status == DESTROYED_PICTURE )
226 /* Picture is marked for destruction, but is still allocated */
227 if( (p_vout->p_picture[i_picture].i_type == i_type) &&
228 (p_vout->p_picture[i_picture].i_height == i_height) &&
229 (p_vout->p_picture[i_picture].i_bytes_per_line == i_bytes_per_line) )
231 /* Memory size do match : memory will not be reallocated, and function
232 * can end immediately - this is the best possible case, since no
233 * memory allocation needs to be done */
234 p_vout->p_picture[i_picture].i_width = i_width;
235 p_vout->p_picture[i_picture].i_status = RESERVED_PICTURE;
236 vlc_mutex_unlock( &p_vout->lock );
237 return( &p_vout->p_picture[i_picture] );
239 else if( p_destroyed_picture == NULL )
241 /* Memory size do not match, but picture index will be kept in
242 * case no other place are left */
243 p_destroyed_picture = &p_vout->p_picture[i_picture];
246 else if( (p_free_picture == NULL) &&
247 (p_vout->p_picture[i_picture].i_status == FREE_PICTURE ))
249 /* Picture is empty and ready for allocation */
250 p_free_picture = &p_vout->p_picture[i_picture];
254 /* If no free picture is available, use a destroyed picture */
255 if( (p_free_picture == NULL) && (p_destroyed_picture != NULL ) )
257 /* No free picture or matching destroyed picture has been found, but
258 * a destroyed picture is still avalaible */
259 free( p_destroyed_picture->p_data );
260 p_free_picture = p_destroyed_picture;
266 if( p_free_picture != NULL )
268 /* Allocate memory */
271 case YUV_420_PICTURE: /* YUV picture: 3*16 ?? bits per pixel */
272 case YUV_422_PICTURE:
273 case YUV_444_PICTURE:
274 p_free_picture->p_data = malloc( 3 * i_height * i_bytes_per_line );
275 p_free_picture->p_y = (yuv_data_t *) p_free_picture->p_data;
276 p_free_picture->p_u = (yuv_data_t *)(p_free_picture->p_data + i_height * i_bytes_per_line);
277 p_free_picture->p_v = (yuv_data_t *)(p_free_picture->p_data + i_height * i_bytes_per_line * 2);
281 intf_DbgMsg("0x%x error: unknown picture type %d\n", p_vout, i_type );
282 p_free_picture->p_data = NULL;
286 if( p_free_picture->p_data != NULL )
288 /* Copy picture informations */
289 p_free_picture->i_type = i_type;
290 p_free_picture->i_status = RESERVED_PICTURE;
291 p_free_picture->i_width = i_width;
292 p_free_picture->i_height = i_height;
293 p_free_picture->i_bytes_per_line = i_bytes_per_line;
294 p_free_picture->i_refcount = 0;
298 /* Memory allocation failed : set picture as empty */
299 p_free_picture->i_type = EMPTY_PICTURE;
300 p_free_picture->i_status = FREE_PICTURE;
301 p_free_picture = NULL;
302 intf_DbgMsg("0x%x malloc for new picture failed\n");
305 vlc_mutex_unlock( &p_vout->lock );
306 return( p_free_picture );
309 // No free or destroyed picture could be found
310 intf_DbgMsg("0x%x no picture available\n");
311 vlc_mutex_unlock( &p_vout->lock );
315 /*******************************************************************************
316 * vout_RemovePicture: remove a permanent or reserved picture from the heap
317 *******************************************************************************
318 * This function frees a previously reserved picture or a permanent
319 * picture. It is meant to be used when the construction of a picture aborted.
320 * Note that the picture will be destroyed even if it is linked !
321 *******************************************************************************/
322 void vout_DestroyPicture( vout_thread_t *p_vout, picture_t *p_pic )
324 vlc_mutex_lock( &p_vout->lock );
326 /* Mark picture for destruction */
327 p_pic->i_status = DESTROYED_PICTURE;
328 intf_DbgMsg("%p -> picture %p destroyed\n", p_vout, p_pic );
330 vlc_mutex_unlock( &p_vout->lock );
333 /*******************************************************************************
334 * vout_LinkPicture: increment reference counter of a picture
335 *******************************************************************************
336 * This function increment the reference counter of a picture in the video
338 *******************************************************************************/
339 void vout_LinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
341 vlc_mutex_lock( &p_vout->lock );
343 vlc_mutex_unlock( &p_vout->lock );
346 /*******************************************************************************
347 * vout_UnlinkPicture: decrement reference counter of a picture
348 *******************************************************************************
349 * This function decrement the reference counter of a picture in the video heap.
350 *******************************************************************************/
351 void vout_UnlinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
353 vlc_mutex_lock( &p_vout->lock );
355 if( (p_pic->i_refcount == 0) && (p_pic->i_status == DISPLAYED_PICTURE) )
357 p_pic->i_status = DESTROYED_PICTURE;
359 vlc_mutex_unlock( &p_vout->lock );
362 /* following functions are local */
364 /*******************************************************************************
365 * InitThread: initialize video output thread
366 *******************************************************************************
367 * This function is called from RunThread and performs the second step of the
368 * initialization. It returns 0 on success. Note that the thread's flag are not
369 * modified inside this function.
370 *******************************************************************************/
371 static int InitThread( vout_thread_t *p_vout )
373 int i_index; /* generic index */
374 int i_pixel_size; /* pixel size, in bytes, for translations tables */
377 *p_vout->pi_status = THREAD_START;
379 /* Initialize pictures */
380 for( i_index = 0; i_index < VOUT_MAX_PICTURES; i_index++)
382 p_vout->p_picture[i_index].i_type = EMPTY_PICTURE;
383 p_vout->p_picture[i_index].i_status= FREE_PICTURE;
386 /* Initialize other properties */
387 p_vout->i_pictures = 0;
390 p_vout->c_idle_loops = 0;
391 p_vout->c_pictures = 0;
392 p_vout->c_rendered_pictures = 0;
395 /* Initialize output method - width, height, screen depth and bytes per
396 * pixel are initialized by this call. */
397 if( vout_SysInit( p_vout ) ) /* error */
399 *p_vout->pi_status = THREAD_ERROR;
403 /* Allocate translation tables */
404 switch( p_vout->i_bytes_per_pixel )
406 case 2: /* 15 or 16 bpp, use 16 bits translations tables */
407 i_pixel_size = sizeof( u16 );
409 case 3: /* 24 or 32 bpp, use 32 bits translations tables */
411 i_pixel_size = sizeof( u32 );
414 p_vout->pi_trans16_red = p_vout->pi_trans32_red = malloc( 1024 * i_pixel_size );
415 p_vout->pi_trans16_green = p_vout->pi_trans32_green = malloc( 1024 * i_pixel_size );
416 p_vout->pi_trans16_blue = p_vout->pi_trans32_blue = malloc( 1024 * i_pixel_size );
417 if( (p_vout->pi_trans16_red == NULL) ||
418 (p_vout->pi_trans16_green == NULL ) ||
419 (p_vout->pi_trans16_blue == NULL ) )
421 if( p_vout->pi_trans16_red != NULL )
423 free( p_vout->pi_trans16_red );
425 if( p_vout->pi_trans16_green != NULL )
427 free( p_vout->pi_trans16_green );
429 if( p_vout->pi_trans16_blue != NULL )
431 free( p_vout->pi_trans16_blue );
433 intf_ErrMsg("vout error: %s\n", strerror(ENOMEM) );
434 *p_vout->pi_status = THREAD_ERROR;
438 /* Translate translation tables */
439 p_vout->pi_trans16_red += 384;
440 p_vout->pi_trans16_green += 384;
441 p_vout->pi_trans16_blue += 384;
442 p_vout->pi_trans32_red += 384;
443 p_vout->pi_trans32_green += 384;
444 p_vout->pi_trans32_blue += 384;
446 /* Build translation tables */
447 switch( p_vout->i_screen_depth )
450 for( i_index = -384; i_index < 640; i_index++)
452 p_vout->pi_trans16_red[i_index] = (CLIP_BYTE( i_index ) & 0xf8)<<7;
453 p_vout->pi_trans16_green[i_index] = (CLIP_BYTE( i_index ) & 0xf8)<<2;
454 p_vout->pi_trans16_blue[i_index] = CLIP_BYTE( i_index ) >> 3;
458 for( i_index = -384; i_index < 640; i_index++)
460 p_vout->pi_trans16_red[i_index] = (CLIP_BYTE( i_index ) & 0xf8)<<8;
461 p_vout->pi_trans16_green[i_index] = (CLIP_BYTE( i_index ) & 0xf8)<<3;
462 p_vout->pi_trans16_blue[i_index] = CLIP_BYTE( i_index ) >> 3;
466 for( i_index = -384; i_index < 640; i_index++)
468 p_vout->pi_trans32_red[i_index] = CLIP_BYTE( i_index ) <<16;
469 p_vout->pi_trans32_green[i_index] = CLIP_BYTE( i_index ) <<8;
470 p_vout->pi_trans32_blue[i_index] = CLIP_BYTE( i_index ) ;
477 /* Mark thread as running and return */
478 *p_vout->pi_status = THREAD_READY;
479 intf_DbgMsg("%p -> succeeded\n", p_vout);
483 /*******************************************************************************
484 * RunThread: video output thread
485 *******************************************************************************
486 * Video output thread. This function does only returns when the thread is
487 * terminated. It handles the pictures arriving in the video heap and the
488 * display device events.
489 *******************************************************************************/
490 static void RunThread( vout_thread_t *p_vout)
492 int i_picture; /* picture index */
493 int i_err; /* error code */
494 mtime_t current_date; /* current date */
495 picture_t * p_pic = NULL;
497 char sz_date[MSTRTIME_MAX_SIZE]; /* date buffer */
501 * Initialize thread and free configuration
503 intf_DbgMsg( "0x%x begin\n", p_vout );
504 p_vout->b_error = InitThread( p_vout );
505 if( p_vout->b_error )
507 free( p_vout ); /* destroy descriptor */
512 * Main loop - it is not executed if an error occured during
515 while( (!p_vout->b_die) && (!p_vout->b_error) )
518 * Find the picture to display - this is the only operation requiring
519 * the lock on the picture, since once a READY_PICTURE has been found,
520 * it can't be modified by the other threads (except if it is unliked,
521 * but its data remains)
523 vlc_mutex_lock( &p_vout->lock );
525 for( i_picture = 0; i_picture < VOUT_MAX_PICTURES; i_picture++ )
527 if( (p_vout->p_picture[i_picture].i_status == READY_PICTURE) &&
529 (p_vout->p_picture[i_picture].date < p_pic->date) ) )
531 p_pic = &p_vout->p_picture[i_picture];
535 vlc_mutex_unlock( &p_vout->lock );
538 * Render picture if any
542 current_date = mdate();
543 if( p_pic->date < current_date )
545 /* Picture is late: it will be destroyed and the thread will go
546 * immediately to next picture */
547 vlc_mutex_lock( &p_vout->lock );
548 if( p_pic->i_refcount )
550 p_pic->i_status = DISPLAYED_PICTURE;
554 p_pic->i_status = DESTROYED_PICTURE;
556 vlc_mutex_unlock( &p_vout->lock );
557 intf_ErrMsg( "vout error: picture %p was late - skipped\n", p_pic );
560 else if( p_pic->date > current_date + VOUT_DISPLAY_DELAY )
562 /* A picture is ready to be rendered, but its rendering date is
563 * far from the current one so the thread will perform an empty loop
564 * as if no picture were found. The picture state is unchanged */
569 /* Picture has not yet been displayed, and has a valid display
570 * date : render it */
571 RenderPicture( p_vout, p_pic );
576 * Check events, sleep and display picture
578 i_err = vout_SysManage( p_vout );
581 /* A fatal error occured, and the thread must terminate immediately,
582 * without displaying anything - setting b_error to 1 cause the
583 * immediate end of the main while() loop. */
590 /* A picture is ready to be displayed : sleep until its display date */
591 mwait( p_pic->date );
595 vout_SysDisplay( p_vout );
598 /* Picture has been displayed : destroy it */
599 vlc_mutex_lock( &p_vout->lock );
600 if( p_pic->i_refcount )
602 p_pic->i_status = DISPLAYED_PICTURE;
606 p_pic->i_status = DESTROYED_PICTURE;
608 vlc_mutex_unlock( &p_vout->lock );
612 /* Sleep to wait for new pictures */
613 msleep( VOUT_IDLE_SLEEP );
615 /* Update counters */
616 p_vout->c_idle_loops++;
622 /* Update counters */
630 if( p_vout->b_error )
632 ErrorThread( p_vout );
637 intf_DbgMsg( "0x%x end\n", p_vout );
640 /*******************************************************************************
641 * ErrorThread: RunThread() error loop
642 *******************************************************************************
643 * This function is called when an error occured during thread main's loop. The
644 * thread can still receive feed, but must be ready to terminate as soon as
646 *******************************************************************************/
647 static void ErrorThread( vout_thread_t *p_vout )
649 /* Wait until a `die' order */
650 while( !p_vout->b_die )
653 msleep( VOUT_IDLE_SLEEP );
657 /*******************************************************************************
658 * EndThread: thread destruction
659 *******************************************************************************
660 * This function is called when the thread ends after a sucessfull
662 *******************************************************************************/
663 static void EndThread( vout_thread_t *p_vout )
665 int * pi_status; /* thread status */
669 pi_status = p_vout->pi_status;
670 *pi_status = THREAD_END;
672 /* Destroy all remaining pictures */
673 for( i_picture = 0; i_picture < VOUT_MAX_PICTURES; i_picture++ )
675 if( p_vout->p_picture[i_picture].i_status != FREE_PICTURE )
677 free( p_vout->p_picture[i_picture].p_data );
681 /* Destroy translation tables - remeber these tables are translated */
682 free( p_vout->pi_trans16_red - 384 );
683 free( p_vout->pi_trans16_green - 384 );
684 free( p_vout->pi_trans16_blue - 384 );
686 /* Destroy thread structures allocated by InitThread */
687 vout_SysEnd( p_vout );
688 vout_SysDestroy( p_vout ); /* destroy output method */
692 *pi_status = THREAD_OVER;
693 intf_DbgMsg("%p\n", p_vout);
696 /*******************************************************************************
697 * RenderPicture: render a picture
698 *******************************************************************************
699 * This function convert a picture from a video heap to a pixel-encoded image
700 * and copy it to the current rendering buffer. No lock is required, since the
701 * rendered picture has been determined as existant, and will only be destroyed
702 * by the vout thread later.
703 *******************************************************************************/
704 static void RenderPicture( vout_thread_t *p_vout, picture_t *p_pic )
706 intf_DbgMsg("0x%x Picture 0x%x type=%d, %dx%d\n",
707 p_vout, p_pic, p_pic->i_type, p_pic->i_width, p_pic->i_height );