X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fvideo_output%2Fvout_subpictures.c;h=0c261aba9a97f07b5f478d80517d91aae78a7842;hb=eff9d25c7739b479a1692e40bc33a3f64648e985;hp=4dbab1accdc84cb4b8d8d162356726a0d02c65b3;hpb=53b978f8650fd329bf5298a05c9f8a055ac56fe4;p=vlc diff --git a/src/video_output/vout_subpictures.c b/src/video_output/vout_subpictures.c index 4dbab1accd..0c261aba9a 100644 --- a/src/video_output/vout_subpictures.c +++ b/src/video_output/vout_subpictures.c @@ -2,7 +2,7 @@ * vout_subpictures.c : subpicture management functions ***************************************************************************** * Copyright (C) 2000 VideoLAN - * $Id: vout_subpictures.c,v 1.5 2002/01/04 14:01:35 sam Exp $ + * $Id: vout_subpictures.c,v 1.23 2003/12/09 19:15:03 yoann Exp $ * * Authors: Vincent Seguin * Samuel Hocevar @@ -25,76 +25,67 @@ /***************************************************************************** * Preamble *****************************************************************************/ -#include /* ENOMEM */ #include /* free() */ #include /* sprintf() */ #include /* strerror() */ -#include +#include -#include "video.h" +#include "vlc_video.h" #include "video_output.h" -/***************************************************************************** - * Local prototypes - *****************************************************************************/ -static void vout_RenderRGBSPU( const vout_thread_t *p_vout, picture_t *p_pic, - const subpicture_t *p_spu ); -static void vout_RenderYUVSPU( const vout_thread_t *p_vout, picture_t *p_pic, - const subpicture_t *p_spu ); - -/* FIXME: fake palette - the real one has to be sought in the .IFO */ -static int p_palette[4] = { 0x0000, 0x0000, 0xffff, 0x8888 }; - -/***************************************************************************** - * vout_DisplaySubPicture: display a subpicture unit - ***************************************************************************** - * Remove the reservation flag of a subpicture, which will cause it to be ready - * for display. The picture does not need to be locked, since it is ignored by - * the output thread if is reserved. - *****************************************************************************/ +/** + * Display a subpicture unit + * + * Remove the reservation flag of a subpicture, which will cause it to be + * ready for display. + * \param p_vout the video output this subpicture should be displayed on + * \param p_subpic the subpicture to display + */ void vout_DisplaySubPicture( vout_thread_t *p_vout, subpicture_t *p_subpic ) { -#ifdef TRACE_VOUT - char psz_start[ MSTRTIME_MAX_SIZE ]; /* buffer for date string */ - char psz_stop[ MSTRTIME_MAX_SIZE ]; /* buffer for date string */ -#endif + int i_margin; -#ifdef DEBUG /* Check if status is valid */ if( p_subpic->i_status != RESERVED_SUBPICTURE ) { - intf_ErrMsg("error: subpicture %p has invalid status #%d", p_subpic, - p_subpic->i_status ); + msg_Err( p_vout, "subpicture %p has invalid status #%d", + p_subpic, p_subpic->i_status ); + } + + /* If the user requested an SPU margin, we force the position after + * having checked that it was a valid value. */ + i_margin = config_GetInt( p_vout, "spumargin" ); + + if( i_margin >= 0 ) + { + if( p_subpic->i_height + (unsigned int)i_margin + <= p_vout->output.i_height ) + { + p_subpic->i_y = p_vout->output.i_height + - i_margin - p_subpic->i_height; + } } -#endif /* Remove reservation flag */ p_subpic->i_status = READY_SUBPICTURE; - -#ifdef TRACE_VOUT - /* Send subpicture information */ - intf_DbgMsg("subpicture %p: type=%d, begin date=%s, end date=%s", - p_subpic, p_subpic->i_type, - mstrtime( psz_start, p_subpic->i_start ), - mstrtime( psz_stop, p_subpic->i_stop ) ); -#endif } -/***************************************************************************** - * vout_CreateSubPicture: allocate a subpicture in the video output heap. - ***************************************************************************** +/** + * Allocate a subpicture in the video output heap. + * * This function create a reserved subpicture in the video output heap. * A null pointer is returned if the function fails. This method provides an * already allocated zone of memory in the spu data fields. It needs locking * since several pictures can be created by several producers threads. - *****************************************************************************/ -subpicture_t *vout_CreateSubPicture( vout_thread_t *p_vout, int i_type, - int i_size ) + * \param p_vout the vout in which to create the subpicture + * \param i_type the type of the subpicture + * \return NULL on error, a reserved subpicture otherwise + */ +subpicture_t *vout_CreateSubPicture( vout_thread_t *p_vout, int i_type ) { int i_subpic; /* subpicture index */ - subpicture_t * p_free_subpic = NULL; /* first free subpicture */ - subpicture_t * p_destroyed_subpic = NULL; /* first destroyed subpic */ + subpicture_t * p_subpic = NULL; /* first free subpicture */ /* Get lock */ vlc_mutex_lock( &p_vout->subpicture_lock ); @@ -104,196 +95,103 @@ subpicture_t *vout_CreateSubPicture( vout_thread_t *p_vout, int i_type, */ for( i_subpic = 0; i_subpic < VOUT_MAX_SUBPICTURES; i_subpic++ ) { - if( p_vout->p_subpicture[i_subpic].i_status == DESTROYED_SUBPICTURE ) - { - /* Subpicture is marked for destruction, but is still allocated */ - if( (p_vout->p_subpicture[i_subpic].i_type == i_type) && - (p_vout->p_subpicture[i_subpic].i_size >= i_size) ) - { - /* Memory size do match or is smaller : memory will not be - * reallocated, and function can end immediately - this is - * the best possible case, since no memory allocation needs - * to be done */ - p_vout->p_subpicture[i_subpic].i_status = RESERVED_SUBPICTURE; -#ifdef TRACE_VOUT - intf_DbgMsg("subpicture %p (in destroyed subpicture slot)", - &p_vout->p_subpicture[i_subpic] ); -#endif - vlc_mutex_unlock( &p_vout->subpicture_lock ); - return( &p_vout->p_subpicture[i_subpic] ); - } - else if( p_destroyed_subpic == NULL ) - { - /* Memory size do not match, but subpicture index will be kept - * in case we find no other place */ - p_destroyed_subpic = &p_vout->p_subpicture[i_subpic]; - } - } - else if( (p_free_subpic == NULL) && - (p_vout->p_subpicture[i_subpic].i_status == FREE_SUBPICTURE )) + if( p_vout->p_subpicture[i_subpic].i_status == FREE_SUBPICTURE ) { /* Subpicture is empty and ready for allocation */ - p_free_subpic = &p_vout->p_subpicture[i_subpic]; + p_subpic = &p_vout->p_subpicture[i_subpic]; + p_vout->p_subpicture[i_subpic].i_status = RESERVED_SUBPICTURE; + break; } } - /* If no free subpictures are available, use a destroyed subpicture */ - if( (p_free_subpic == NULL) && (p_destroyed_subpic != NULL ) ) + /* If no free subpicture could be found */ + if( p_subpic == NULL ) { - /* No free subpicture or matching destroyed subpictures have been - * found, but a destroyed subpicture is still avalaible */ - free( p_destroyed_subpic->p_data ); - p_free_subpic = p_destroyed_subpic; + msg_Err( p_vout, "subpicture heap is full" ); + vlc_mutex_unlock( &p_vout->subpicture_lock ); + return NULL; } - /* - * Prepare subpicture - */ - if( p_free_subpic != NULL ) - { - /* Allocate memory */ - switch( i_type ) - { - case TEXT_SUBPICTURE: /* text subpicture */ - p_free_subpic->p_data = memalign( 16, i_size + 1 ); - break; - case DVD_SUBPICTURE: /* DVD subpicture unit */ - p_free_subpic->p_data = memalign( 16, i_size ); - break; -#ifdef DEBUG - default: - intf_ErrMsg("error: unknown subpicture type %d", i_type ); - p_free_subpic->p_data = NULL; - break; -#endif - } + /* Copy subpicture information, set some default values */ + p_subpic->i_type = i_type; + p_subpic->i_status = RESERVED_SUBPICTURE; - if( p_free_subpic->p_data != NULL ) - { - /* Copy subpicture information, set some default values */ - p_free_subpic->i_type = i_type; - p_free_subpic->i_status = RESERVED_SUBPICTURE; - p_free_subpic->i_size = i_size; - p_free_subpic->i_x = 0; - p_free_subpic->i_y = 0; - p_free_subpic->i_width = 0; - p_free_subpic->i_height = 0; - p_free_subpic->i_horizontal_align = CENTER_RALIGN; - p_free_subpic->i_vertical_align = CENTER_RALIGN; - } - else - { - /* Memory allocation failed : set subpicture as empty */ - p_free_subpic->i_type = EMPTY_SUBPICTURE; - p_free_subpic->i_status = FREE_SUBPICTURE; - p_free_subpic = NULL; - intf_ErrMsg( "vout error: spu allocation returned %s", - strerror( ENOMEM ) ); - } + p_subpic->i_start = 0; + p_subpic->i_stop = 0; + p_subpic->b_ephemer = VLC_FALSE; -#ifdef TRACE_VOUT - intf_DbgMsg("subpicture %p (in free subpicture slot)", p_free_subpic ); -#endif - vlc_mutex_unlock( &p_vout->subpicture_lock ); - return( p_free_subpic ); - } + p_subpic->i_x = 0; + p_subpic->i_y = 0; + p_subpic->i_width = 0; + p_subpic->i_height = 0; - /* No free or destroyed subpicture could be found */ - intf_DbgMsg( "warning: subpicture heap is full" ); vlc_mutex_unlock( &p_vout->subpicture_lock ); - return( NULL ); + + return p_subpic; } -/***************************************************************************** - * vout_DestroySubPicture: remove a subpicture from the heap - ***************************************************************************** +/** + * Remove a subpicture from the heap + * * This function frees a previously reserved subpicture. * It is meant to be used when the construction of a picture aborted. * This function does not need locking since reserved subpictures are ignored * by the output thread. - *****************************************************************************/ + */ void vout_DestroySubPicture( vout_thread_t *p_vout, subpicture_t *p_subpic ) { -#ifdef DEBUG - /* Check if status is valid */ - if( ( p_subpic->i_status != RESERVED_SUBPICTURE ) - && ( p_subpic->i_status != READY_SUBPICTURE ) ) - { - intf_ErrMsg("error: subpicture %p has invalid status %d", - p_subpic, p_subpic->i_status ); - } -#endif - - p_subpic->i_status = DESTROYED_SUBPICTURE; - -#ifdef TRACE_VOUT - intf_DbgMsg("subpicture %p", p_subpic); -#endif + /* Get lock */ + vlc_mutex_lock( &p_vout->subpicture_lock ); + + /* There can be race conditions so we need to check the status */ + if( p_subpic->i_status == FREE_SUBPICTURE ) + { + vlc_mutex_unlock( &p_vout->subpicture_lock ); + return; + } + + /* Check if status is valid */ + if( ( p_subpic->i_status != RESERVED_SUBPICTURE ) + && ( p_subpic->i_status != READY_SUBPICTURE ) ) + { + msg_Err( p_vout, "subpicture %p has invalid status %d", + p_subpic, p_subpic->i_status ); + } + + if( p_subpic->pf_destroy ) + { + p_subpic->pf_destroy( p_subpic ); + } + + if( p_subpic == p_vout->p_last_osd_message ) + { + p_vout->p_last_osd_message = NULL; + } + + p_subpic->i_status = FREE_SUBPICTURE; + + vlc_mutex_unlock( &p_vout->subpicture_lock ); } /***************************************************************************** * vout_RenderSubPictures: render a subpicture list ***************************************************************************** - * This function renders a sub picture unit. + * This function renders all sub picture units in the list. *****************************************************************************/ void vout_RenderSubPictures( vout_thread_t *p_vout, picture_t *p_pic, subpicture_t *p_subpic ) { -#if 0 - p_vout_font_t p_font; /* text font */ - int i_width, i_height; /* subpicture dimensions */ -#endif + /* Get lock */ + vlc_mutex_lock( &p_vout->subpicture_lock ); - while( p_subpic != NULL ) + /* Check i_status again to make sure spudec hasn't destroyed the subpic */ + while( p_subpic != NULL && p_subpic->i_status != FREE_SUBPICTURE ) { - switch( p_subpic->i_type ) - { - case DVD_SUBPICTURE: /* DVD subpicture unit */ - vout_RenderRGBSPU( p_vout, p_pic, p_subpic ); - vout_RenderYUVSPU( p_vout, p_pic, p_subpic ); - break; - -#if 0 - case TEXT_SUBPICTURE: /* single line text */ - /* Select default font if not specified */ - p_font = p_subpic->type.text.p_font; - if( p_font == NULL ) - { - p_font = p_vout->p_default_font; - } - - /* Compute text size (width and height fields are ignored) - * and print it */ - vout_TextSize( p_font, p_subpic->type.text.i_style, - p_subpic->p_data, &i_width, &i_height ); - if( !Align( p_vout, &p_subpic->i_x, &p_subpic->i_y, - i_width, i_height, p_subpic->i_horizontal_align, - p_subpic->i_vertical_align ) ) - { - vout_Print( p_font, - p_vout->p_buffer[ p_vout->i_buffer_index ].p_data + - p_subpic->i_x * p_vout->i_bytes_per_pixel + - p_subpic->i_y * p_vout->i_bytes_per_line, - p_vout->i_bytes_per_pixel, p_vout->i_bytes_per_line, p_subpic->type.text.i_char_color, - p_subpic->type.text.i_border_color, - p_subpic->type.text.i_bg_color, - p_subpic->type.text.i_style, p_subpic->p_data, 100 ); - SetBufferArea( p_vout, p_subpic->i_x, p_subpic->i_y, - i_width, i_height ); - } - break; -#endif - - default: -#ifdef DEBUG - intf_ErrMsg( "error: unknown subpicture %p type %d", - p_subpic, p_subpic->i_type ); -#endif - break; - } - + p_subpic->pf_render( p_vout, p_pic, p_subpic ); p_subpic = p_subpic->p_next; } + + vlc_mutex_unlock( &p_vout->subpicture_lock ); } /***************************************************************************** @@ -322,9 +220,10 @@ subpicture_t *vout_SortSubPictures( vout_thread_t *p_vout, if( p_vout->p_subpicture[i_index].i_status == READY_SUBPICTURE ) { /* If it is a DVD subpicture, check its date */ - if( p_vout->p_subpicture[i_index].i_type == DVD_SUBPICTURE ) + if( p_vout->p_subpicture[i_index].i_type == MEMORY_SUBPICTURE ) { - if( display_date > p_vout->p_subpicture[i_index].i_stop ) + if( !p_vout->p_subpicture[i_index].b_ephemer + && display_date > p_vout->p_subpicture[i_index].i_stop ) { /* Too late, destroy the subpic */ vout_DestroySubPicture( p_vout, @@ -332,7 +231,8 @@ subpicture_t *vout_SortSubPictures( vout_thread_t *p_vout, continue; } - if( display_date < p_vout->p_subpicture[i_index].i_start ) + if( display_date + && display_date < p_vout->p_subpicture[i_index].i_start ) { /* Too early, come back next monday */ continue; @@ -406,158 +306,3 @@ subpicture_t *vout_SortSubPictures( vout_thread_t *p_vout, return p_subpic; } -/***************************************************************************** - * vout_RenderRGBSPU: draw an SPU on a picture - ***************************************************************************** - * This is a fast implementation of the subpicture drawing code. The data - * has been preprocessed once in spu_decoder.c, so we don't need to parse the - * RLE buffer again and again. Most sanity checks are done in spu_decoder.c - * so that this routine can be as fast as possible. - *****************************************************************************/ -static void vout_RenderRGBSPU( const vout_thread_t *p_vout, picture_t *p_pic, - const subpicture_t *p_spu ) -{ -#if 0 - int i_len, i_color; - u16 *p_source = (u16 *)p_spu->p_data; - - int i_xscale = ( p_buffer->i_pic_width << 6 ) / p_pic->i_width; - int i_yscale = ( p_buffer->i_pic_height << 6 ) / p_pic->i_height; - - int i_width = p_spu->i_width * i_xscale; - int i_height = p_spu->i_height * i_yscale; - - int i_x, i_y, i_ytmp, i_yreal, i_ynext; - - u8 *p_dest = p_buffer->p_data + ( i_width >> 6 ) * i_bytes_per_pixel - /* Add the picture coordinates and the SPU coordinates */ - + ( p_buffer->i_pic_x + ((p_spu->i_x * i_xscale) >> 6)) - * i_bytes_per_pixel - + ( p_buffer->i_pic_y + ((p_spu->i_y * i_yscale) >> 6)) - * i_bytes_per_line; - - /* Draw until we reach the bottom of the subtitle */ - i_y = 0; - - while( i_y < i_height ) - { - i_ytmp = i_y >> 6; - i_y += i_yscale; - - /* Check whether we need to draw one line or more than one */ - if( i_ytmp + 1 >= ( i_y >> 6 ) ) - { - /* Just one line : we precalculate i_y >> 6 */ - i_yreal = i_bytes_per_line * i_ytmp; - - /* Draw until we reach the end of the line */ - i_x = i_width; - - while( i_x ) - { - /* Get the RLE part */ - i_color = *p_source & 0x3; - - /* Draw the line */ - if( i_color ) - { - i_len = i_xscale * ( *p_source++ >> 2 ); - - memset( p_dest - i_bytes_per_pixel * ( i_x >> 6 ) - + i_yreal, - p_palette[ i_color ], - i_bytes_per_pixel * ( ( i_len >> 6 ) + 1 ) ); - - i_x -= i_len; - continue; - } - - i_x -= i_xscale * ( *p_source++ >> 2 ); - } - } - else - { - i_yreal = i_bytes_per_line * i_ytmp; - i_ynext = i_bytes_per_line * i_y >> 6; - - /* Draw until we reach the end of the line */ - i_x = i_width; - - while( i_x ) - { - /* Get the RLE part */ - i_color = *p_source & 0x3; - - /* Draw as many lines as needed */ - if( i_color ) - { - i_len = i_xscale * ( *p_source++ >> 2 ); - - for( i_ytmp = i_yreal ; - i_ytmp < i_ynext ; - i_ytmp += i_bytes_per_line ) - { - memset( p_dest - i_bytes_per_pixel * ( i_x >> 6 ) - + i_ytmp, - p_palette[ i_color ], - i_bytes_per_pixel * ( ( i_len >> 6 ) + 1 ) ); - } - - i_x -= i_len; - continue; - } - - i_x -= i_xscale * ( *p_source++ >> 2 ); - } - } - } -#endif -} - -/***************************************************************************** - * vout_RenderYUVSPU: draw an SPU on an YUV overlay - ***************************************************************************** - * This is a fast implementation of the subpicture drawing code. The data - * has been preprocessed once in spu_decoder.c, so we don't need to parse the - * RLE buffer again and again. Most sanity checks are done in spu_decoder.c - * so that this routine can be as fast as possible. - *****************************************************************************/ -static void vout_RenderYUVSPU( const vout_thread_t *p_vout, picture_t *p_pic, - const subpicture_t *p_spu ) -{ - int i_len, i_color; - u16 *p_source = (u16 *)p_spu->p_data; - - int i_x, i_y; - - u8 *p_dest = p_pic->p->p_pixels + p_spu->i_x + p_spu->i_width - + p_vout->output.i_width * ( p_spu->i_y + p_spu->i_height ); - - /* Draw until we reach the bottom of the subtitle */ - i_y = p_spu->i_height * p_vout->output.i_width; - - while( i_y ) - { - /* Draw until we reach the end of the line */ - i_x = p_spu->i_width; - - while( i_x ) - { - /* Draw the line if needed */ - i_color = *p_source & 0x3; - - if( i_color ) - { - i_len = *p_source++ >> 2; - memset( p_dest - i_x - i_y, p_palette[ i_color ], i_len ); - i_x -= i_len; - continue; - } - - i_x -= *p_source++ >> 2; - } - - i_y -= p_vout->output.i_width; - } -} -