+ subpicture_region_t *p_region = p_subpic->p_region;
+ int i_scale_width, i_scale_height;
+ int i_subpic_x = p_subpic->i_x;
+
+ /* Load the blending module */
+ if( !p_spu->p_blend && p_region )
+ {
+ p_spu->p_blend = vlc_object_create( p_spu, VLC_OBJECT_FILTER );
+ vlc_object_attach( p_spu->p_blend, p_spu );
+ p_spu->p_blend->fmt_out.video.i_x_offset =
+ p_spu->p_blend->fmt_out.video.i_y_offset = 0;
+ p_spu->p_blend->fmt_out.video.i_aspect = p_fmt->i_aspect;
+ p_spu->p_blend->fmt_out.video.i_chroma = p_fmt->i_chroma;
+ p_spu->p_blend->fmt_in.video.i_chroma = VLC_FOURCC('Y','U','V','P');
+ /* XXX: We'll also be using it for YUVA and RGBA blending ... */
+
+ p_spu->p_blend->p_module =
+ module_Need( p_spu->p_blend, "video blending", 0, 0 );
+ }
+
+ /* Load the text rendering module */
+ if( !p_spu->p_text && p_region && p_region->fmt.i_chroma == VLC_FOURCC('T','E','X','T') )
+ {
+ char *psz_modulename = NULL;
+
+ p_spu->p_text = vlc_object_create( p_spu, VLC_OBJECT_FILTER );
+ vlc_object_attach( p_spu->p_text, p_spu );
+
+ p_spu->p_text->fmt_out.video.i_width =
+ p_spu->p_text->fmt_out.video.i_visible_width =
+ p_fmt->i_width;
+ p_spu->p_text->fmt_out.video.i_height =
+ p_spu->p_text->fmt_out.video.i_visible_height =
+ p_fmt->i_height;
+
+ p_spu->p_text->pf_sub_buffer_new = spu_new_buffer;
+ p_spu->p_text->pf_sub_buffer_del = spu_del_buffer;
+
+ psz_modulename = var_CreateGetString( p_spu, "text-renderer" );
+ if( psz_modulename && *psz_modulename )
+ {
+ p_spu->p_text->p_module =
+ module_Need( p_spu->p_text, "text renderer",
+ psz_modulename, VLC_TRUE );
+ }
+ if( !p_spu->p_text->p_module )
+ {
+ p_spu->p_text->p_module =
+ module_Need( p_spu->p_text, "text renderer", 0, 0 );
+ }
+ if( psz_modulename ) free( psz_modulename );
+ }
+ if( p_spu->p_text )
+ {
+ if( p_subpic->i_original_picture_height > 0 &&
+ p_subpic->i_original_picture_width > 0 )
+ {
+ p_spu->p_text->fmt_out.video.i_width =
+ p_spu->p_text->fmt_out.video.i_visible_width =
+ p_subpic->i_original_picture_width;
+ p_spu->p_text->fmt_out.video.i_height =
+ p_spu->p_text->fmt_out.video.i_visible_height =
+ p_subpic->i_original_picture_height;
+ }
+ else
+ {
+ p_spu->p_text->fmt_out.video.i_width =
+ p_spu->p_text->fmt_out.video.i_visible_width =
+ p_fmt->i_width;
+ p_spu->p_text->fmt_out.video.i_height =
+ p_spu->p_text->fmt_out.video.i_visible_height =
+ p_fmt->i_height;
+ }
+ }
+
+ i_scale_width = i_scale_width_orig;
+ i_scale_height = i_scale_height_orig;
+
+ if( p_subpic->i_original_picture_height > 0 &&
+ p_subpic->i_original_picture_width > 0 )
+ {
+ i_scale_width = i_scale_width * p_fmt->i_width /
+ p_subpic->i_original_picture_width;
+ i_scale_height = i_scale_height * p_fmt->i_height /
+ p_subpic->i_original_picture_height;
+ }
+ else if( p_subpic->i_original_picture_height > 0 )
+ {
+ i_scale_height = i_scale_height * p_fmt->i_height /
+ p_subpic->i_original_picture_height;
+ i_scale_width = i_scale_height * i_scale_height / p_fmt->i_height;
+ }
+
+ /* Set default subpicture aspect ratio */
+ if( p_region && p_region->fmt.i_aspect &&
+ (!p_region->fmt.i_sar_num || !p_region->fmt.i_sar_den) )
+ {
+ p_region->fmt.i_sar_den = p_region->fmt.i_aspect;
+ p_region->fmt.i_sar_num = VOUT_ASPECT_FACTOR;
+ }
+ if( p_region &&
+ (!p_region->fmt.i_sar_num || !p_region->fmt.i_sar_den) )
+ {
+ p_region->fmt.i_sar_den = p_fmt->i_sar_den;
+ p_region->fmt.i_sar_num = p_fmt->i_sar_num;
+ }
+
+ /* Take care of the aspect ratio */
+ if( p_region && p_region->fmt.i_sar_num * p_fmt->i_sar_den !=
+ p_region->fmt.i_sar_den * p_fmt->i_sar_num )
+ {
+ i_scale_width = i_scale_width *
+ (int64_t)p_region->fmt.i_sar_num * p_fmt->i_sar_den /
+ p_region->fmt.i_sar_den / p_fmt->i_sar_num;
+ i_subpic_x = p_subpic->i_x * i_scale_width / 1000;
+ }
+
+ /* Load the scaling module */
+ if( !p_spu->p_scale && (i_scale_width != 1000 ||
+ i_scale_height != 1000) )
+ {
+ p_spu->p_scale = vlc_object_create( p_spu, VLC_OBJECT_FILTER );
+ vlc_object_attach( p_spu->p_scale, p_spu );
+ p_spu->p_scale->fmt_out.video.i_chroma =
+ p_spu->p_scale->fmt_in.video.i_chroma =
+ VLC_FOURCC('Y','U','V','P');
+ /* XXX: We'll also be using it for YUVA and RGBA blending ... */
+ p_spu->p_scale->fmt_in.video.i_width =
+ p_spu->p_scale->fmt_in.video.i_height = 32;
+ p_spu->p_scale->fmt_out.video.i_width =
+ p_spu->p_scale->fmt_out.video.i_height = 16;
+
+ p_spu->p_scale->pf_vout_buffer_new = spu_new_video_buffer;
+ p_spu->p_scale->pf_vout_buffer_del = spu_del_video_buffer;
+ p_spu->p_scale->p_module =
+ module_Need( p_spu->p_scale, "video filter2", 0, 0 );
+ }
+
+ while( p_region && p_spu->p_blend && p_spu->p_blend->pf_video_blend )
+ {
+ int i_fade_alpha = 255;
+ int i_x_offset = p_region->i_x + i_subpic_x;
+ int i_y_offset = p_region->i_y + p_subpic->i_y;
+
+ if( p_region->fmt.i_chroma == VLC_FOURCC('T','E','X','T') )
+ {
+ if( p_spu->p_text && p_spu->p_text->p_module )
+ {
+ if( p_spu->p_text->pf_render_html && p_region->psz_html )
+ {
+ p_spu->p_text->pf_render_html( p_spu->p_text,
+ p_region, p_region );
+ }
+ else if( p_spu->p_text->pf_render_text )
+ {
+ p_spu->p_text->pf_render_text( p_spu->p_text,
+ p_region, p_region );
+ }
+ }
+ }
+
+ /* Force palette if requested */
+ if( p_spu->b_force_palette &&
+ (VLC_FOURCC('Y','U','V','P') == p_region->fmt.i_chroma) )
+ {
+ memcpy( p_region->fmt.p_palette->palette,
+ p_spu->palette, 16 );
+ }
+
+ /* Scale SPU if necessary */
+ if( p_region->p_cache )
+ {
+ if( i_scale_width * p_region->fmt.i_width / 1000 !=
+ p_region->p_cache->fmt.i_width ||
+ i_scale_height * p_region->fmt.i_height / 1000 !=
+ p_region->p_cache->fmt.i_height )
+ {
+ p_subpic->pf_destroy_region( VLC_OBJECT(p_spu),
+ p_region->p_cache );
+ p_region->p_cache = 0;
+ }
+ }
+
+ if( (i_scale_width != 1000 || i_scale_height != 1000) &&
+ p_spu->p_scale && !p_region->p_cache )
+ {
+ picture_t *p_pic;
+
+ p_spu->p_scale->fmt_in.video = p_region->fmt;
+ p_spu->p_scale->fmt_out.video = p_region->fmt;
+
+ p_region->p_cache =
+ p_subpic->pf_create_region( VLC_OBJECT(p_spu),
+ &p_spu->p_scale->fmt_out.video );
+ if( p_spu->p_scale->fmt_out.video.p_palette )
+ *p_spu->p_scale->fmt_out.video.p_palette =
+ *p_region->fmt.p_palette;
+ p_region->p_cache->p_next = p_region->p_next;
+
+ vout_CopyPicture( p_spu, &p_region->p_cache->picture,
+ &p_region->picture );
+
+ p_spu->p_scale->fmt_out.video.i_width =
+ p_region->fmt.i_width * i_scale_width / 1000;
+ p_spu->p_scale->fmt_out.video.i_visible_width =
+ p_region->fmt.i_visible_width * i_scale_width / 1000;
+ p_spu->p_scale->fmt_out.video.i_height =
+ p_region->fmt.i_height * i_scale_height / 1000;
+ p_spu->p_scale->fmt_out.video.i_visible_height =
+ p_region->fmt.i_visible_height * i_scale_height / 1000;
+ p_region->p_cache->fmt = p_spu->p_scale->fmt_out.video;
+ p_region->p_cache->i_x = p_region->i_x * i_scale_width / 1000;
+ p_region->p_cache->i_y = p_region->i_y * i_scale_height / 1000;
+ p_region->p_cache->i_align = p_region->i_align;
+
+ p_pic = p_spu->p_scale->pf_video_filter(
+ p_spu->p_scale, &p_region->p_cache->picture );
+ if( p_pic )
+ {
+ picture_t p_pic_tmp = p_region->p_cache->picture;
+ p_region->p_cache->picture = *p_pic;
+ *p_pic = p_pic_tmp;
+ free( p_pic );
+ }
+ }
+ if( (i_scale_width != 1000 || i_scale_height != 1000) &&
+ p_spu->p_scale && p_region->p_cache )
+ {
+ p_region = p_region->p_cache;
+ }
+
+ if( p_region->i_align & SUBPICTURE_ALIGN_BOTTOM )
+ {
+ i_y_offset = p_fmt->i_height - p_region->fmt.i_height -
+ p_subpic->i_y - p_region->i_y;
+ }
+ else if ( !(p_region->i_align & SUBPICTURE_ALIGN_TOP) )
+ {
+ i_y_offset = p_fmt->i_height / 2 - p_region->fmt.i_height / 2;
+ }
+
+ if( p_region->i_align & SUBPICTURE_ALIGN_RIGHT )
+ {
+ i_x_offset = p_fmt->i_width - p_region->fmt.i_width -
+ i_subpic_x - p_region->i_x;
+ }
+ else if ( !(p_region->i_align & SUBPICTURE_ALIGN_LEFT) )
+ {
+ i_x_offset = p_fmt->i_width / 2 - p_region->fmt.i_width / 2;
+ }
+
+ if( p_subpic->b_absolute )
+ {
+ i_x_offset = p_region->i_x +
+ i_subpic_x * i_scale_width / 1000;
+ i_y_offset = p_region->i_y +
+ p_subpic->i_y * i_scale_height / 1000;
+
+ }
+
+ i_x_offset = __MAX( i_x_offset, 0 );
+ i_y_offset = __MAX( i_y_offset, 0 );
+
+ if( p_spu->i_margin != 0 && p_spu->b_force_crop == VLC_FALSE )
+ {
+ int i_diff = 0;
+ int i_low = i_y_offset - p_spu->i_margin;
+ int i_high = i_y_offset + p_region->fmt.i_height - p_spu->i_margin;
+
+ /* crop extra margin to keep within bounds */
+ if( i_low < 0 ) i_diff = i_low;
+ if( i_high > (int)p_fmt->i_height ) i_diff = i_high - p_fmt->i_height;
+ i_y_offset -= ( p_spu->i_margin + i_diff );
+ }
+
+ p_spu->p_blend->fmt_in.video = p_region->fmt;
+
+ /* Force cropping if requested */
+ if( p_spu->b_force_crop )
+ {
+ video_format_t *p_fmt = &p_spu->p_blend->fmt_in.video;
+ int i_crop_x = p_spu->i_crop_x * i_scale_width / 1000;
+ int i_crop_y = p_spu->i_crop_y * i_scale_height / 1000;
+ int i_crop_width = p_spu->i_crop_width * i_scale_width / 1000;
+ int i_crop_height = p_spu->i_crop_height * i_scale_height/1000;
+
+ /* 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 = i_x;
+ i_y_offset = i_y;
+ }
+ }
+
+ /* Update the output picture size */
+ p_spu->p_blend->fmt_out.video.i_width =
+ p_spu->p_blend->fmt_out.video.i_visible_width =
+ p_fmt->i_width;
+ p_spu->p_blend->fmt_out.video.i_height =
+ p_spu->p_blend->fmt_out.video.i_visible_height =
+ p_fmt->i_height;
+
+ if( p_subpic->b_fade )
+ {
+ mtime_t i_fade_start = ( p_subpic->i_stop +
+ p_subpic->i_start ) / 2;
+ mtime_t i_now = mdate();
+ if( i_now >= i_fade_start && p_subpic->i_stop > i_fade_start )
+ {
+ i_fade_alpha = 255 * ( p_subpic->i_stop - i_now ) /
+ ( p_subpic->i_stop - i_fade_start );
+ }
+ }
+
+ i_x_offset = __MAX( i_x_offset, 0 );
+ i_y_offset = __MAX( i_y_offset, 0 );
+
+ p_spu->p_blend->pf_video_blend( p_spu->p_blend, p_pic_dst,
+ p_pic_src, &p_region->picture, i_x_offset, i_y_offset,
+ i_fade_alpha * p_subpic->i_alpha / 255 );
+
+ p_region = p_region->p_next;
+ }
+