-/**
- * This function renders all sub picture units in the list.
- */
-void spu_RenderSubpictures( spu_t *p_spu,
- picture_t *p_pic_dst, const video_format_t *p_fmt_dst,
- subpicture_t *p_subpic_list,
- const video_format_t *p_fmt_src )
-{
- const int i_source_video_width = p_fmt_src->i_width;
- const int i_source_video_height = p_fmt_src->i_height;
- const mtime_t i_current_date = mdate();
-
- unsigned int i_subpicture;
- subpicture_t *pp_subpicture[VOUT_MAX_SUBPICTURES];
-
- unsigned int i_subtitle_region_count;
- spu_area_t p_subtitle_area_buffer[VOUT_MAX_SUBPICTURES];
- spu_area_t *p_subtitle_area;
- int i_subtitle_area;
-
- /* Get lock */
- vlc_mutex_lock( &p_spu->subpicture_lock );
-
- /* Preprocess subpictures */
- i_subpicture = 0;
- i_subtitle_region_count = 0;
- for( subpicture_t * p_subpic = p_subpic_list;
- p_subpic != NULL && p_subpic->i_status != FREE_SUBPICTURE; /* Check again status (as we where unlocked) */
- p_subpic = p_subpic->p_next )
- {
- /* */
- if( p_subpic->pf_pre_render )
- p_subpic->pf_pre_render( p_spu, p_subpic, p_fmt_dst );
-
- if( p_subpic->pf_update_regions )
- {
- video_format_t fmt_org = *p_fmt_dst;
- fmt_org.i_width =
- fmt_org.i_visible_width = i_source_video_width;
- fmt_org.i_height =
- fmt_org.i_visible_height = i_source_video_height;
-
- p_subpic->pf_update_regions( p_spu, p_subpic, &fmt_org, i_current_date );
- }
-
- /* */
- if( p_subpic->b_subtitle )
- {
- for( subpicture_region_t *r = p_subpic->p_region; r != NULL; r = r->p_next )
- i_subtitle_region_count++;
- }
-
- /* */
- pp_subpicture[i_subpicture++] = p_subpic;
- }
-
- /* Be sure we have at least 1 picture to process */
- if( i_subpicture <= 0 )
- {
- vlc_mutex_unlock( &p_spu->subpicture_lock );
- return;
- }
-
- /* Now order subpicture array
- * XXX The order is *really* important for overlap subtitles positionning */
- qsort( pp_subpicture, i_subpicture, sizeof(*pp_subpicture), SubpictureCmp );
-
- /* Allocate area array for subtitle overlap */
- i_subtitle_area = 0;
- p_subtitle_area = p_subtitle_area_buffer;
- if( i_subtitle_region_count > sizeof(p_subtitle_area_buffer)/sizeof(*p_subtitle_area_buffer) )
- p_subtitle_area = calloc( i_subtitle_region_count, sizeof(*p_subtitle_area) );
-
- /* Create the blending module */
- if( !p_spu->p_blend )
- SpuRenderCreateBlend( p_spu, p_fmt_dst->i_chroma, p_fmt_dst->i_aspect );
-
- /* Process all subpictures and regions (in the right order) */
- for( unsigned int i_index = 0; i_index < i_subpicture; i_index++ )
- {
- subpicture_t *p_subpic = pp_subpicture[i_index];
- subpicture_region_t *p_region;
-
- if( !p_subpic->p_region )
- continue;
-
- /* FIXME when possible use a better rendering size than source size
- * (max of display size and source size for example) FIXME */
- int i_render_width = p_subpic->i_original_picture_width;
- int i_render_height = p_subpic->i_original_picture_height;
- if( !i_render_width || !i_render_height )
- {
- if( i_render_width != 0 || i_render_height != 0 )
- msg_Err( p_spu, "unsupported original picture size %dx%d",
- i_render_width, i_render_height );
-
- p_subpic->i_original_picture_width = i_render_width = i_source_video_width;
- p_subpic->i_original_picture_height = i_render_height = i_source_video_height;
- }
-
- if( p_spu->p_text )
- {
- p_spu->p_text->fmt_out.video.i_width =
- p_spu->p_text->fmt_out.video.i_visible_width = i_render_width;
-
- p_spu->p_text->fmt_out.video.i_height =
- p_spu->p_text->fmt_out.video.i_visible_height = i_render_height;
- }
-
- /* Compute scaling from picture to source size */
- spu_scale_t scale = spu_scale_createq( i_source_video_width, i_render_width,
- i_source_video_height, i_render_height );
-
- /* Update scaling from source size to display size(p_fmt_dst) */
- scale.w = scale.w * p_fmt_dst->i_width / i_source_video_width;
- scale.h = scale.h * p_fmt_dst->i_height / i_source_video_height;
-
- /* Set default subpicture aspect ratio
- * FIXME if we only handle 1 aspect ratio per picture, why is it set per
- * region ? */
- p_region = p_subpic->p_region;
- if( !p_region->fmt.i_sar_num || !p_region->fmt.i_sar_den )
- {
- if( p_region->fmt.i_aspect != 0 )
- {
- p_region->fmt.i_sar_den = p_region->fmt.i_aspect;
- p_region->fmt.i_sar_num = VOUT_ASPECT_FACTOR;
- }
- else
- {
- p_region->fmt.i_sar_den = p_fmt_dst->i_sar_den;
- p_region->fmt.i_sar_num = p_fmt_dst->i_sar_num;
- }
- }
-
- /* Take care of the aspect ratio */
- if( p_region->fmt.i_sar_num * p_fmt_dst->i_sar_den !=
- p_region->fmt.i_sar_den * p_fmt_dst->i_sar_num )
- {
- /* FIXME FIXME what about region->i_x/i_y ? */
- scale.w = scale.w *
- (int64_t)p_region->fmt.i_sar_num * p_fmt_dst->i_sar_den /
- p_region->fmt.i_sar_den / p_fmt_dst->i_sar_num;
- }
-
- /* Render all regions
- * We always transform non absolute subtitle into absolute one on the
- * first rendering to allow good subtitle overlap support.
- */
- for( p_region = p_subpic->p_region; p_region != NULL; p_region = p_region->p_next )
- {
- spu_area_t area;
-
- /* Check scale validity */
- if( scale.w <= 0 || scale.h <= 0 )
- continue;
-
- /* */
- SpuRenderRegion( p_spu, p_pic_dst, &area,
- p_subpic, p_region, scale, p_fmt_dst,
- p_subtitle_area, i_subtitle_area );
-
- if( p_subpic->b_subtitle )
- {
- area = spu_area_unscaled( area, scale );
- if( !p_subpic->b_absolute && area.i_width > 0 && area.i_height > 0 )
- {
- p_region->i_x = area.i_x;
- p_region->i_y = area.i_y;
- }
- if( p_subtitle_area )
- p_subtitle_area[i_subtitle_area++] = area;
- }
- }
- if( p_subpic->b_subtitle )
- p_subpic->b_absolute = true;
- }
-
- /* */
- if( p_subtitle_area != p_subtitle_area_buffer )
- free( p_subtitle_area );
-
- vlc_mutex_unlock( &p_spu->subpicture_lock );
-}
-
-/*****************************************************************************
- * spu_SortSubpictures: find the subpictures to display
- *****************************************************************************
- * This function parses all subpictures and decides which ones need to be
- * displayed. This operation does not need lock, since only READY_SUBPICTURE
- * are handled. If no picture has been selected, display_date will depend on
- * the subpicture.
- * We also check for ephemer DVD subpictures (subpictures that have
- * to be removed if a newer one is available), which makes it a lot
- * more difficult to guess if a subpicture has to be rendered or not.
- *****************************************************************************/
-subpicture_t *spu_SortSubpictures( spu_t *p_spu, mtime_t display_date,
- bool b_paused, bool b_subtitle_only )
-{
- int i_channel;
- subpicture_t *p_subpic = NULL;
-
- /* Run subpicture filters */
- filter_chain_SubFilter( p_spu->p_chain, display_date );
-
- /* We get an easily parsable chained list of subpictures which
- * ends with NULL since p_subpic was initialized to NULL. */
- for( i_channel = 0; i_channel < p_spu->i_channel; i_channel++ )
- {
- subpicture_t *p_ephemer = NULL;
- mtime_t ephemer_date = 0;
- int i_index;
-
- for( i_index = 0; i_index < VOUT_MAX_SUBPICTURES; i_index++ )
- {
- subpicture_t *p_current = &p_spu->p_subpicture[i_index];
-
- if( p_current->i_channel != i_channel ||
- p_current->i_status != READY_SUBPICTURE ||
- ( b_subtitle_only && !p_current->b_subtitle ) )
- {
- continue;
- }
- if( display_date &&
- display_date < p_current->i_start )
- {
- /* Too early, come back next monday */
- continue;
- }
-
- if( p_current->i_start > ephemer_date )
- ephemer_date = p_current->i_start;
-
- if( display_date > p_current->i_stop &&
- ( !p_current->b_ephemer || p_current->i_stop > p_current->i_start ) &&
- !( p_current->b_subtitle && b_paused ) ) /* XXX Assume that subtitle are pausable */
- {
- /* Too late, destroy the subpic */
- spu_DestroySubpicture( p_spu, &p_spu->p_subpicture[i_index] );
- continue;
- }
-
- /* If this is an ephemer subpic, add it to our list */
- if( p_current->b_ephemer )
- {
- p_current->p_next = p_ephemer;
- p_ephemer = p_current;
-
- continue;
- }
-
- p_current->p_next = p_subpic;
- p_subpic = p_current;
- }
-
- /* If we found ephemer subpictures, check if they have to be
- * displayed or destroyed */
- while( p_ephemer != NULL )
- {
- subpicture_t *p_tmp = p_ephemer;
- p_ephemer = p_ephemer->p_next;
-
- if( p_tmp->i_start < ephemer_date )
- {
- /* Ephemer subpicture has lived too long */
- spu_DestroySubpicture( p_spu, p_tmp );
- }
- else
- {
- /* Ephemer subpicture can still live a bit */
- p_tmp->p_next = p_subpic;
- p_subpic = p_tmp;
- }
- }
- }
-
- return p_subpic;
-}
-
-/*****************************************************************************
- * SpuClearChannel: clear an spu channel
- *****************************************************************************
- * This function destroys the subpictures which belong to the spu channel
- * corresponding to i_channel_id.
- *****************************************************************************/
-static void SpuClearChannel( spu_t *p_spu, int i_channel, bool b_locked )
-{
- int i_subpic; /* subpicture index */
- subpicture_t *p_subpic = NULL; /* first free subpicture */
-
- if( !b_locked )
- vlc_mutex_lock( &p_spu->subpicture_lock );
-
- for( i_subpic = 0; i_subpic < VOUT_MAX_SUBPICTURES; i_subpic++ )
- {
- p_subpic = &p_spu->p_subpicture[i_subpic];
- if( p_subpic->i_status == FREE_SUBPICTURE
- || ( p_subpic->i_status != RESERVED_SUBPICTURE
- && p_subpic->i_status != READY_SUBPICTURE ) )
- {
- continue;
- }
-
- if( p_subpic->i_channel == i_channel )
- {
- while( p_subpic->p_region )
- {
- subpicture_region_t *p_region = p_subpic->p_region;
- p_subpic->p_region = p_region->p_next;
- spu_DestroyRegion( p_spu, p_region );
- }
-
- if( p_subpic->pf_destroy ) p_subpic->pf_destroy( p_subpic );
- p_subpic->i_status = FREE_SUBPICTURE;
- }
- }
-
- if( !b_locked )
- vlc_mutex_unlock( &p_spu->subpicture_lock );
-}
-
-/*****************************************************************************
- * spu_ControlDefault: default methods for the subpicture unit control.
- *****************************************************************************/
-static int spu_vaControlDefault( spu_t *p_spu, int i_query, va_list args )
-{
- int *pi, i;
-
- switch( i_query )
- {
- case SPU_CHANNEL_REGISTER:
- pi = (int *)va_arg( args, int * );
- vlc_mutex_lock( &p_spu->subpicture_lock );
- if( pi )
- *pi = p_spu->i_channel++;
- vlc_mutex_unlock( &p_spu->subpicture_lock );
- break;
-
- case SPU_CHANNEL_CLEAR:
- i = (int)va_arg( args, int );
- SpuClearChannel( p_spu, i, false );
- break;
-
- default:
- msg_Dbg( p_spu, "control query not supported" );
- return VLC_EGENERIC;
- }
-
- return VLC_SUCCESS;
-}