- i_y_offset = spu_scale_h( p_area->i_y, p_area->scale );
-
- /* */
- if( b_force_palette )
- {
- /* It looks so wrong I won't comment
- * p_palette->palette is [256][4] with a int i_entries
- * p_spu->palette is [4][4]
- * */
- p_region->fmt.p_palette->i_entries = 4;
- memcpy( p_region->fmt.p_palette->palette, p_spu->palette, 4*sizeof(uint32_t) );
- }
-
- /* */
- p_region_fmt = &p_region->fmt;
- p_region_picture = p_region->p_picture;
-
-
- /* Scale from rendered size to destination size */
- p_scale = b_using_palette ? p_spu->p_scale_yuvp : p_spu->p_scale;
-
- if( p_scale &&
- ( scale_size.w != SCALE_UNIT || scale_size.h != SCALE_UNIT || b_force_palette ) )
- {
- const unsigned i_dst_width = spu_scale_w( p_region->fmt.i_width, scale_size );
- const unsigned i_dst_height = spu_scale_h( p_region->fmt.i_height, scale_size );
-
- /* TODO when b_using_palette is true, we should first convert it to YUVA to allow
- * a proper rescaling */
-
- /* Destroy if cache is unusable
- * FIXME do not always destroy the region it can sometimes be reused
- * if same size and same palette if present */
- if( p_region->p_private )
- {
- SpuRegionPrivateDestroy( p_region->p_private );
- p_region->p_private = NULL;
- }
-
- /* Scale if needed into cache */
- if( !p_region->p_private )
- {
- picture_t *p_pic;
-
- p_scale->fmt_in.video = p_region->fmt;
- p_scale->fmt_out.video = p_region->fmt;
-
- p_scale->fmt_out.video.i_width = i_dst_width;
- p_scale->fmt_out.video.i_height = i_dst_height;
-
- p_scale->fmt_out.video.i_visible_width =
- spu_scale_w( p_region->fmt.i_visible_width, scale_size );
- p_scale->fmt_out.video.i_visible_height =
- spu_scale_h( p_region->fmt.i_visible_height, scale_size );
-
- p_region->p_private = SpuRegionPrivateCreate( &p_scale->fmt_out.video );
-
- if( p_scale->p_module )
- {
- picture_Yield( p_region->p_picture );
- p_region->p_private->p_picture = p_scale->pf_video_filter( p_scale, p_region->p_picture );
- }
- if( !p_region->p_private->p_picture )
- {
- msg_Err( p_spu, "scaling failed (module not loaded)" );
- SpuRegionPrivateDestroy( p_region->p_private );
- p_region->p_private = NULL;
- }
- }
-
- /* And use the scaled picture */
- if( p_region->p_private )
- {
- p_region_fmt = &p_region->p_private->fmt;
- p_region_picture = p_region->p_private->p_picture;
- }
- }
-
- /* Force cropping if requested */
- if( b_force_crop )
- {
- video_format_t *p_fmt = p_region_fmt;
- int i_crop_x = spu_scale_w( p_spu->i_crop_x, scale_size );
- int i_crop_y = spu_scale_h( p_spu->i_crop_y, scale_size );
- int i_crop_width = spu_scale_w( p_spu->i_crop_width, scale_size );
- int i_crop_height= spu_scale_h( p_spu->i_crop_height,scale_size );
-
- /* Find the intersection */
- if( i_crop_x + i_crop_width <= i_x_offset ||
- i_x_offset + (int)p_fmt->i_visible_width < i_crop_x ||
- i_crop_y + i_crop_height <= i_y_offset ||
- i_y_offset + (int)p_fmt->i_visible_height < i_crop_y )
- {
- /* No intersection */
- p_fmt->i_visible_width = p_fmt->i_visible_height = 0;
- }
- else
- {
- int i_x, i_y, i_x_end, i_y_end;
- i_x = __MAX( i_crop_x, i_x_offset );
- i_y = __MAX( i_crop_y, i_y_offset );
- i_x_end = __MIN( i_crop_x + i_crop_width,
- i_x_offset + (int)p_fmt->i_visible_width );
- i_y_end = __MIN( i_crop_y + i_crop_height,
- i_y_offset + (int)p_fmt->i_visible_height );
-
- p_fmt->i_x_offset = i_x - i_x_offset;
- p_fmt->i_y_offset = i_y - i_y_offset;
- p_fmt->i_visible_width = i_x_end - i_x;
- p_fmt->i_visible_height = i_y_end - i_y;
-
- i_x_offset = __MAX( i_x, 0 );
- i_y_offset = __MAX( i_y, 0 );
- }
- b_restore_format = true;
- }
-
- /* Update the blender */
- SpuRenderUpdateBlend( p_spu, p_fmt->i_width, p_fmt->i_height, p_region_fmt );
-
- if( p_spu->p_blend->p_module )
- {
- const int i_alpha = SpuRegionAlpha( p_subpic, p_region );
-
- p_spu->p_blend->pf_video_blend( p_spu->p_blend, p_pic_dst,
- p_region_picture, i_x_offset, i_y_offset, i_alpha );
- }
- else
- {
- msg_Err( p_spu, "blending %4.4s to %4.4s failed",
- (char *)&p_spu->p_blend->fmt_out.video.i_chroma,
- (char *)&p_spu->p_blend->fmt_out.video.i_chroma );
- }
-
-exit:
- if( b_rerender_text )
- {
- /* Some forms of subtitles need to be re-rendered more than
- * once, eg. karaoke. We therefore restore the region to its
- * pre-rendered state, so the next time through everything is
- * calculated again.
- */
- picture_Release( p_region->p_picture );
- p_region->p_picture = NULL;
- if( p_region->p_private )
- {
- SpuRegionPrivateDestroy( p_region->p_private );
- p_region->p_private = NULL;
- }
- p_region->i_align &= ~SUBPICTURE_RENDERED;
- }
- if( b_restore_format )
- p_region->fmt = fmt_original;
-}
-
-/**
- * This function compares two 64 bits integers.
- * It can be used by qsort.
- */
-static int IntegerCmp( int64_t i0, int64_t i1 )
-{
- return i0 < i1 ? -1 : i0 > i1 ? 1 : 0;
-}
-/**
- * This function compares 2 subpictures using the following properties
- * (ordered by priority)
- * 1. absolute positionning
- * 2. start time
- * 3. creation order
- *
- * It can be used by qsort.
- *
- * XXX spu_RenderSubpictures depends heavily on this order.
- */
-static int SubpictureCmp( const void *s0, const void *s1 )
-{
- subpicture_t *p_subpic0 = *(subpicture_t**)s0;
- subpicture_t *p_subpic1 = *(subpicture_t**)s1;
- int r;
-
- r = IntegerCmp( !p_subpic0->b_absolute, !p_subpic1->b_absolute );
- if( !r )
- r = IntegerCmp( p_subpic0->i_start, p_subpic1->i_start );
- if( !r )
- r = IntegerCmp( p_subpic0->i_order, p_subpic1->i_order );
- return r;
-}
-/**
- * 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;