474
458
*****************************************************************************
475
459
* This function renders all sub picture units in the list.
476
460
*****************************************************************************/
461
static void SpuRenderCreateBlend( spu_t *p_spu, vlc_fourcc_t i_chroma, int i_aspect )
465
assert( !p_spu->p_blend );
468
p_blend = vlc_custom_create( p_spu, sizeof(filter_t),
469
VLC_OBJECT_GENERIC, "blend" );
473
es_format_Init( &p_blend->fmt_in, VIDEO_ES, 0 );
475
es_format_Init( &p_blend->fmt_out, VIDEO_ES, 0 );
476
p_blend->fmt_out.video.i_x_offset = 0;
477
p_blend->fmt_out.video.i_y_offset = 0;
478
p_blend->fmt_out.video.i_chroma = i_chroma;
479
p_blend->fmt_out.video.i_aspect = i_aspect;
481
/* The blend module will be loaded when needed with the real
483
p_blend->p_module = NULL;
486
vlc_object_attach( p_blend, p_spu );
488
static void SpuRenderUpdateBlend( spu_t *p_spu, int i_out_width, int i_out_height, const video_format_t *p_in_fmt )
490
filter_t *p_blend = p_spu->p_blend;
495
if( p_blend->p_module && p_blend->fmt_in.video.i_chroma != p_in_fmt->i_chroma )
497
/* The chroma is not the same, we need to reload the blend module
498
* XXX to match the old behaviour just test !p_blend->fmt_in.video.i_chroma */
499
module_Unneed( p_blend, p_blend->p_module );
500
p_blend->p_module = NULL;
504
p_blend->fmt_in.video = *p_in_fmt;
507
p_blend->fmt_out.video.i_width =
508
p_blend->fmt_out.video.i_visible_width = i_out_width;
509
p_blend->fmt_out.video.i_height =
510
p_blend->fmt_out.video.i_visible_height = i_out_height;
513
if( !p_blend->p_module )
514
p_blend->p_module = module_Need( p_blend, "video blending", 0, 0 );
516
static void SpuRenderCreateAndLoadText( spu_t *p_spu, int i_width, int i_height )
520
assert( !p_spu->p_text );
523
p_text = vlc_custom_create( p_spu, sizeof(filter_t),
524
VLC_OBJECT_GENERIC, "spu text" );
528
es_format_Init( &p_text->fmt_in, VIDEO_ES, 0 );
530
es_format_Init( &p_text->fmt_out, VIDEO_ES, 0 );
531
p_text->fmt_out.video.i_width =
532
p_text->fmt_out.video.i_visible_width = i_width;
533
p_text->fmt_out.video.i_height =
534
p_text->fmt_out.video.i_visible_height = i_height;
536
p_text->pf_sub_buffer_new = spu_new_buffer;
537
p_text->pf_sub_buffer_del = spu_del_buffer;
539
vlc_object_attach( p_text, p_spu );
541
/* FIXME TOCHECK shouldn't module_Need( , , psz_modulename, false ) do the
542
* same than these 2 calls ? */
543
char *psz_modulename = var_CreateGetString( p_spu, "text-renderer" );
544
if( psz_modulename && *psz_modulename )
546
p_text->p_module = module_Need( p_text, "text renderer",
547
psz_modulename, true );
549
free( psz_modulename );
551
if( !p_text->p_module )
552
p_text->p_module = module_Need( p_text, "text renderer", NULL, false );
555
static filter_t *CreateAndLoadScale( vlc_object_t *p_obj, vlc_fourcc_t i_chroma )
559
p_scale = vlc_custom_create( p_obj, sizeof(filter_t),
560
VLC_OBJECT_GENERIC, "scale" );
564
es_format_Init( &p_scale->fmt_in, VIDEO_ES, 0 );
565
p_scale->fmt_in.video.i_chroma = i_chroma;
566
p_scale->fmt_in.video.i_width =
567
p_scale->fmt_in.video.i_height = 32;
569
es_format_Init( &p_scale->fmt_out, VIDEO_ES, 0 );
570
p_scale->fmt_out.video.i_chroma = i_chroma;
571
p_scale->fmt_out.video.i_width =
572
p_scale->fmt_out.video.i_height = 16;
574
p_scale->pf_vout_buffer_new = spu_new_video_buffer;
575
p_scale->pf_vout_buffer_del = spu_del_video_buffer;
577
vlc_object_attach( p_scale, p_obj );
578
p_scale->p_module = module_Need( p_scale, "video filter2", 0, 0 );
583
static void SpuRenderCreateAndLoadScale( spu_t *p_spu )
585
/* FIXME: We'll also be using it for YUVA and RGBA blending ... */
587
assert( !p_spu->p_scale );
588
assert( !p_spu->p_scale_yuvp );
589
p_spu->p_scale = CreateAndLoadScale( VLC_OBJECT(p_spu), VLC_FOURCC('Y','U','V','A') );
590
p_spu->p_scale_yuvp = p_spu->p_scale_yuvp = CreateAndLoadScale( VLC_OBJECT(p_spu), VLC_FOURCC('Y','U','V','P') );
593
static void SpuRenderText( spu_t *p_spu, bool *pb_rerender_text,
594
subpicture_t *p_subpic, subpicture_region_t *p_region, int i_min_scale_ratio )
596
assert( p_region->fmt.i_chroma == VLC_FOURCC('T','E','X','T') );
598
if( !p_spu->p_text || !p_spu->p_text->p_module )
601
/* Setup 3 variables which can be used to render
602
* time-dependent text (and effects). The first indicates
603
* the total amount of time the text will be on screen,
604
* the second the amount of time it has already been on
605
* screen (can be a negative value as text is layed out
606
* before it is rendered) and the third is a feedback
607
* variable from the renderer - if the renderer sets it
608
* then this particular text is time-dependent, eg. the
609
* visual progress bar inside the text in karaoke and the
610
* text needs to be rendered multiple times in order for
611
* the effect to work - we therefore need to return the
612
* region to its original state at the end of the loop,
613
* instead of leaving it in YUVA or YUVP.
614
* Any renderer which is unaware of how to render
615
* time-dependent text can happily ignore the variables
616
* and render the text the same as usual - it should at
617
* least show up on screen, but the effect won't change
618
* the text over time.
621
/* FIXME why these variables are recreated every time and not
622
* when text renderer module was created ? */
623
var_Create( p_spu->p_text, "spu-duration", VLC_VAR_TIME );
624
var_Create( p_spu->p_text, "spu-elapsed", VLC_VAR_TIME );
625
var_Create( p_spu->p_text, "text-rerender", VLC_VAR_BOOL );
626
var_Create( p_spu->p_text, "scale", VLC_VAR_INTEGER );
628
var_SetTime( p_spu->p_text, "spu-duration", p_subpic->i_stop - p_subpic->i_start );
629
var_SetTime( p_spu->p_text, "spu-elapsed", mdate() - p_subpic->i_start );
630
var_SetBool( p_spu->p_text, "text-rerender", false );
631
var_SetInteger( p_spu->p_text, "scale", i_min_scale_ratio );
633
if( p_spu->p_text->pf_render_html && p_region->psz_html )
635
p_spu->p_text->pf_render_html( p_spu->p_text,
636
p_region, p_region );
638
else if( p_spu->p_text->pf_render_text )
640
p_spu->p_text->pf_render_text( p_spu->p_text,
641
p_region, p_region );
643
*pb_rerender_text = var_GetBool( p_spu->p_text, "text-rerender" );
645
var_Destroy( p_spu->p_text, "spu-duration" );
646
var_Destroy( p_spu->p_text, "spu-elapsed" );
647
var_Destroy( p_spu->p_text, "text-rerender" );
648
var_Destroy( p_spu->p_text, "scale" );
651
p_region->i_align |= SUBPICTURE_RENDERED;
654
static void SpuRenderRegion( spu_t *p_spu,
655
picture_t *p_pic_dst, picture_t *p_pic_src,
656
subpicture_t *p_subpic, subpicture_region_t *p_region,
657
const int i_scale_width_orig, const int i_scale_height_orig,
658
const int pi_subpic_x[SCALE_SIZE],
659
const int pi_scale_width[SCALE_SIZE],
660
const int pi_scale_height[SCALE_SIZE],
661
const video_format_t *p_fmt )
663
video_format_t fmt_original;
664
bool b_rerender_text;
665
bool b_restore_format = false;
674
vlc_assert_locked( &p_spu->subpicture_lock );
676
fmt_original = p_region->fmt;
677
b_rerender_text = false;
678
if( p_region->fmt.i_chroma == VLC_FOURCC('T','E','X','T') )
680
SpuRenderText( p_spu, &b_rerender_text, p_subpic, p_region, __MIN(i_scale_width_orig, i_scale_height_orig) );
681
b_restore_format = b_rerender_text;
683
/* Check if the rendering has failed ... */
684
if( p_region->fmt.i_chroma == VLC_FOURCC('T','E','X','T') )
688
if( p_region->i_align & SUBPICTURE_RENDERED )
690
/* We are using a region which come from rendered text */
691
i_scale_idx = SCALE_TEXT;
692
i_inv_scale_x = i_scale_width_orig;
693
i_inv_scale_y = i_scale_height_orig;
697
i_scale_idx = SCALE_DEFAULT;
698
i_inv_scale_x = 1000;
699
i_inv_scale_y = 1000;
702
i_x_offset = (p_region->i_x + pi_subpic_x[ i_scale_idx ]) * i_inv_scale_x / 1000;
703
i_y_offset = (p_region->i_y + p_subpic->i_y) * i_inv_scale_y / 1000;
705
/* Force palette if requested
706
* FIXME b_force_palette and b_force_crop are applied to all subpictures using palette
707
* instead of only the right one (being the dvd spu).
709
const bool b_using_palette = p_region->fmt.i_chroma == VLC_FOURCC('Y','U','V','P');
710
const bool b_force_palette = b_using_palette && p_spu->b_force_palette;
711
const bool b_force_crop = b_force_palette && p_spu->b_force_crop;
713
if( b_force_palette )
715
/* It looks so wrong I won't comment
716
* p_palette->palette is [256][4] with a int i_entries
717
* p_spu->palette is [4][4]
719
p_region->fmt.p_palette->i_entries = 4;
720
memcpy( p_region->fmt.p_palette->palette, p_spu->palette, 4*sizeof(uint32_t) );
723
if( b_using_palette )
724
p_scale = p_spu->p_scale_yuvp;
726
p_scale = p_spu->p_scale;
729
( ( pi_scale_width[i_scale_idx] > 0 && pi_scale_width[i_scale_idx] != 1000 ) ||
730
( pi_scale_height[i_scale_idx] > 0 && pi_scale_height[i_scale_idx] != 1000 ) ||
731
( b_force_palette ) ) )
733
const unsigned i_dst_width = p_region->fmt.i_width * pi_scale_width[i_scale_idx] / 1000;
734
const unsigned i_dst_height = p_region->fmt.i_height * pi_scale_height[i_scale_idx] / 1000;
736
/* Destroy if cache is unusable */
737
if( p_region->p_cache )
739
if( p_region->p_cache->fmt.i_width != i_dst_width ||
740
p_region->p_cache->fmt.i_height != i_dst_height ||
743
p_subpic->pf_destroy_region( VLC_OBJECT(p_spu),
745
p_region->p_cache = NULL;
749
/* Scale if needed into cache */
750
if( !p_region->p_cache )
754
p_scale->fmt_in.video = p_region->fmt;
755
p_scale->fmt_out.video = p_region->fmt;
758
p_subpic->pf_create_region( VLC_OBJECT(p_spu),
759
&p_scale->fmt_out.video );
760
p_region->p_cache->p_next = p_region->p_next;
762
if( p_scale->fmt_out.video.p_palette )
763
*p_scale->fmt_out.video.p_palette =
764
*p_region->fmt.p_palette;
766
vout_CopyPicture( p_spu, &p_region->p_cache->picture,
767
&p_region->picture );
769
p_scale->fmt_out.video.i_width = i_dst_width;
770
p_scale->fmt_out.video.i_height = i_dst_height;
772
p_scale->fmt_out.video.i_visible_width =
773
p_region->fmt.i_visible_width * pi_scale_width[ i_scale_idx ] / 1000;
774
p_scale->fmt_out.video.i_visible_height =
775
p_region->fmt.i_visible_height * pi_scale_height[ i_scale_idx ] / 1000;
777
p_region->p_cache->fmt = p_scale->fmt_out.video;
778
p_region->p_cache->i_x = p_region->i_x * pi_scale_width[ i_scale_idx ] / 1000;
779
p_region->p_cache->i_y = p_region->i_y * pi_scale_height[ i_scale_idx ] / 1000;
780
p_region->p_cache->i_align = p_region->i_align;
781
p_region->p_cache->i_alpha = p_region->i_alpha;
784
if( p_scale->p_module )
785
p_pic = p_scale->pf_video_filter( p_scale, &p_region->p_cache->picture );
787
msg_Err( p_spu, "scaling failed (module not loaded)" );
791
p_region->p_cache->picture = *p_pic;
796
p_subpic->pf_destroy_region( VLC_OBJECT(p_spu),
798
p_region->p_cache = NULL;
802
/* And use the scaled picture */
803
if( p_region->p_cache )
805
p_region = p_region->p_cache;
806
fmt_original = p_region->fmt;
810
if( p_region->i_align & SUBPICTURE_ALIGN_BOTTOM )
812
i_y_offset = p_fmt->i_height - p_region->fmt.i_height -
813
(p_subpic->i_y + p_region->i_y) * i_inv_scale_y / 1000;
815
else if ( !(p_region->i_align & SUBPICTURE_ALIGN_TOP) )
817
i_y_offset = p_fmt->i_height / 2 - p_region->fmt.i_height / 2;
820
if( p_region->i_align & SUBPICTURE_ALIGN_RIGHT )
822
i_x_offset = p_fmt->i_width - p_region->fmt.i_width -
823
(pi_subpic_x[ i_scale_idx ] + p_region->i_x)
824
* i_inv_scale_x / 1000;
826
else if ( !(p_region->i_align & SUBPICTURE_ALIGN_LEFT) )
828
i_x_offset = p_fmt->i_width / 2 - p_region->fmt.i_width / 2;
831
if( p_subpic->b_absolute )
833
i_x_offset = (p_region->i_x +
834
pi_subpic_x[ i_scale_idx ] *
835
pi_scale_width[ i_scale_idx ] / 1000)
836
* i_inv_scale_x / 1000;
837
i_y_offset = (p_region->i_y +
838
p_subpic->i_y * pi_scale_height[ i_scale_idx ] / 1000)
839
* i_inv_scale_y / 1000;
843
i_x_offset = __MAX( i_x_offset, 0 );
844
i_y_offset = __MAX( i_y_offset, 0 );
846
if( p_spu->i_margin != 0 && !b_force_crop )
849
int i_low = (i_y_offset - p_spu->i_margin) * i_inv_scale_y / 1000;
850
int i_high = i_low + p_region->fmt.i_height;
852
/* crop extra margin to keep within bounds */
855
if( i_high > (int)p_fmt->i_height )
856
i_diff = i_high - p_fmt->i_height;
857
i_y_offset -= ( p_spu->i_margin * i_inv_scale_y / 1000 + i_diff );
860
/* Force cropping if requested */
863
video_format_t *p_fmt = &p_region->fmt;
864
int i_crop_x = p_spu->i_crop_x * pi_scale_width[ i_scale_idx ] / 1000
865
* i_inv_scale_x / 1000;
866
int i_crop_y = p_spu->i_crop_y * pi_scale_height[ i_scale_idx ] / 1000
867
* i_inv_scale_y / 1000;
868
int i_crop_width = p_spu->i_crop_width * pi_scale_width[ i_scale_idx ] / 1000
869
* i_inv_scale_x / 1000;
870
int i_crop_height = p_spu->i_crop_height * pi_scale_height[ i_scale_idx ] / 1000
871
* i_inv_scale_y / 1000;
873
/* Find the intersection */
874
if( i_crop_x + i_crop_width <= i_x_offset ||
875
i_x_offset + (int)p_fmt->i_visible_width < i_crop_x ||
876
i_crop_y + i_crop_height <= i_y_offset ||
877
i_y_offset + (int)p_fmt->i_visible_height < i_crop_y )
879
/* No intersection */
880
p_fmt->i_visible_width = p_fmt->i_visible_height = 0;
884
int i_x, i_y, i_x_end, i_y_end;
885
i_x = __MAX( i_crop_x, i_x_offset );
886
i_y = __MAX( i_crop_y, i_y_offset );
887
i_x_end = __MIN( i_crop_x + i_crop_width,
888
i_x_offset + (int)p_fmt->i_visible_width );
889
i_y_end = __MIN( i_crop_y + i_crop_height,
890
i_y_offset + (int)p_fmt->i_visible_height );
892
p_fmt->i_x_offset = i_x - i_x_offset;
893
p_fmt->i_y_offset = i_y - i_y_offset;
894
p_fmt->i_visible_width = i_x_end - i_x;
895
p_fmt->i_visible_height = i_y_end - i_y;
900
b_restore_format = true;
903
i_x_offset = __MAX( i_x_offset, 0 );
904
i_y_offset = __MAX( i_y_offset, 0 );
906
/* Compute alpha blend value */
908
if( p_subpic->b_fade )
910
mtime_t i_fade_start = ( p_subpic->i_stop +
911
p_subpic->i_start ) / 2;
912
mtime_t i_now = mdate();
913
if( i_now >= i_fade_start && p_subpic->i_stop > i_fade_start )
915
i_fade_alpha = 255 * ( p_subpic->i_stop - i_now ) /
916
( p_subpic->i_stop - i_fade_start );
920
/* Update the blender */
921
SpuRenderUpdateBlend( p_spu, p_fmt->i_width, p_fmt->i_height, &p_region->fmt );
923
if( p_spu->p_blend->p_module )
925
p_spu->p_blend->pf_video_blend( p_spu->p_blend, p_pic_dst,
926
p_pic_src, &p_region->picture, i_x_offset, i_y_offset,
927
i_fade_alpha * p_subpic->i_alpha * p_region->i_alpha / 65025 );
931
msg_Err( p_spu, "blending %4.4s to %4.4s failed",
932
(char *)&p_spu->p_blend->fmt_out.video.i_chroma,
933
(char *)&p_spu->p_blend->fmt_out.video.i_chroma );
937
if( b_rerender_text )
939
/* Some forms of subtitles need to be re-rendered more than
940
* once, eg. karaoke. We therefore restore the region to its
941
* pre-rendered state, so the next time through everything is
944
p_region->picture.pf_release( &p_region->picture );
945
memset( &p_region->picture, 0, sizeof( picture_t ) );
946
p_region->i_align &= ~SUBPICTURE_RENDERED;
948
if( b_restore_format )
949
p_region->fmt = fmt_original;
477
952
void spu_RenderSubpictures( spu_t *p_spu, video_format_t *p_fmt,
478
953
picture_t *p_pic_dst, picture_t *p_pic_src,
479
954
subpicture_t *p_subpic,
480
955
int i_scale_width_orig, int i_scale_height_orig )
957
int i_source_video_width;
958
int i_source_video_height;
959
subpicture_t *p_subpic_v;
483
962
vlc_mutex_lock( &p_spu->subpicture_lock );
964
for( p_subpic_v = p_subpic;
965
p_subpic_v != NULL && p_subpic_v->i_status != FREE_SUBPICTURE;
966
p_subpic_v = p_subpic_v->p_next )
968
if( p_subpic_v->pf_pre_render )
969
p_subpic_v->pf_pre_render( p_fmt, p_spu, p_subpic_v );
972
if( i_scale_width_orig <= 0 )
973
i_scale_width_orig = 1000;
974
if( i_scale_height_orig <= 0 )
975
i_scale_height_orig = 1000;
977
i_source_video_width = p_fmt->i_width * 1000 / i_scale_width_orig;
978
i_source_video_height = p_fmt->i_height * 1000 / i_scale_height_orig;
485
980
/* Check i_status again to make sure spudec hasn't destroyed the subpic */
486
while( p_subpic != NULL && p_subpic->i_status != FREE_SUBPICTURE )
981
for( ; ( p_subpic != NULL ) && ( p_subpic->i_status != FREE_SUBPICTURE ); p_subpic = p_subpic->p_next )
488
subpicture_region_t *p_region = p_subpic->p_region;
489
int i_scale_width, i_scale_height;
490
int i_subpic_x = p_subpic->i_x;
492
/* Load the blending module */
493
if( !p_spu->p_blend && p_region )
495
p_spu->p_blend = vlc_object_create( p_spu, VLC_OBJECT_FILTER );
496
vlc_object_attach( p_spu->p_blend, p_spu );
497
p_spu->p_blend->fmt_out.video.i_x_offset =
498
p_spu->p_blend->fmt_out.video.i_y_offset = 0;
499
p_spu->p_blend->fmt_out.video.i_aspect = p_fmt->i_aspect;
500
p_spu->p_blend->fmt_out.video.i_chroma = p_fmt->i_chroma;
501
p_spu->p_blend->fmt_in.video.i_chroma = VLC_FOURCC('Y','U','V','P');
503
p_spu->p_blend->p_module =
504
module_Need( p_spu->p_blend, "video blending", 0, 0 );
507
/* Load the text rendering module */
508
if( !p_spu->p_text && p_region && p_region->fmt.i_chroma == VLC_FOURCC('T','E','X','T') )
510
char *psz_modulename = NULL;
512
p_spu->p_text = vlc_object_create( p_spu, VLC_OBJECT_FILTER );
513
vlc_object_attach( p_spu->p_text, p_spu );
515
p_spu->p_text->fmt_out.video.i_width =
516
p_spu->p_text->fmt_out.video.i_visible_width =
518
p_spu->p_text->fmt_out.video.i_height =
519
p_spu->p_text->fmt_out.video.i_visible_height =
522
p_spu->p_text->pf_sub_buffer_new = spu_new_buffer;
523
p_spu->p_text->pf_sub_buffer_del = spu_del_buffer;
525
psz_modulename = var_CreateGetString( p_spu, "text-renderer" );
526
if( psz_modulename && *psz_modulename )
528
p_spu->p_text->p_module =
529
module_Need( p_spu->p_text, "text renderer", psz_modulename, VLC_TRUE );
531
if( !p_spu->p_text->p_module )
533
p_spu->p_text->p_module =
534
module_Need( p_spu->p_text, "text renderer", 0, 0 );
536
if( psz_modulename ) free( psz_modulename );
983
subpicture_region_t *p_region;
984
int pi_scale_width[ SCALE_SIZE ];
985
int pi_scale_height[ SCALE_SIZE ];
986
int pi_subpic_x[ SCALE_SIZE ];
989
/* If the source video and subtitles stream agree on the size of
990
* the video then disregard all further references to the subtitle
993
if( ( i_source_video_height == p_subpic->i_original_picture_height ) &&
994
( i_source_video_width == p_subpic->i_original_picture_width ) )
996
/* FIXME this looks wrong */
997
p_subpic->i_original_picture_height = 0;
998
p_subpic->i_original_picture_width = 0;
1001
for( k = 0; k < SCALE_SIZE ; k++ )
1002
pi_subpic_x[ k ] = p_subpic->i_x;
1004
if( p_subpic->pf_update_regions )
1006
/* TODO do not reverse the scaling that was done before calling
1007
* spu_RenderSubpictures, just pass it along (or do it inside
1008
* spu_RenderSubpictures) */
1009
video_format_t fmt_org = *p_fmt;
1011
fmt_org.i_visible_width = i_source_video_width;
1013
fmt_org.i_visible_height = i_source_video_height;
1015
p_subpic->pf_update_regions( &fmt_org, p_spu, p_subpic, mdate() );
1019
p_region = p_subpic->p_region;
1023
/* Create the blending module */
1024
if( !p_spu->p_blend )
1025
SpuRenderCreateBlend( p_spu, p_fmt->i_chroma, p_fmt->i_aspect );
1027
/* Load the text rendering module; it is possible there is a
1028
* text region somewhere in the subpicture other than the first
1029
* element in the region list, so just load it anyway as we'll
1030
* probably want it sooner or later. */
1031
if( !p_spu->p_text )
1032
SpuRenderCreateAndLoadText( p_spu, p_fmt->i_width, p_fmt->i_height );
538
1034
if( p_spu->p_text )
540
if( p_subpic->i_original_picture_height > 0 &&
541
p_subpic->i_original_picture_width > 0 )
543
p_spu->p_text->fmt_out.video.i_width =
544
p_spu->p_text->fmt_out.video.i_visible_width =
545
p_subpic->i_original_picture_width;
546
p_spu->p_text->fmt_out.video.i_height =
547
p_spu->p_text->fmt_out.video.i_visible_height =
548
p_subpic->i_original_picture_height;
552
p_spu->p_text->fmt_out.video.i_width =
553
p_spu->p_text->fmt_out.video.i_visible_width =
555
p_spu->p_text->fmt_out.video.i_height =
556
p_spu->p_text->fmt_out.video.i_visible_height =
561
i_scale_width = i_scale_width_orig;
562
i_scale_height = i_scale_height_orig;
1036
subpicture_region_t *p_text_region = p_subpic->p_region;
1038
/* Only overwrite the size fields if the region is still in
1039
* pre-rendered TEXT format. We have to traverse the subregion
1040
* list because if more than one subregion is present, the text
1041
* region isn't guarentteed to be the first in the list, and
1042
* only text regions use this flag. All of this effort assists
1043
* with the rescaling of text that has been rendered at native
1044
* resolution, rather than video resolution.
1046
while( p_text_region &&
1047
p_text_region->fmt.i_chroma != VLC_FOURCC('T','E','X','T') )
1049
p_text_region = p_text_region->p_next;
1052
if( p_text_region &&
1053
( ( p_text_region->i_align & SUBPICTURE_RENDERED ) == 0 ) )
1055
if( p_subpic->i_original_picture_height > 0 &&
1056
p_subpic->i_original_picture_width > 0 )
1058
p_spu->p_text->fmt_out.video.i_width =
1059
p_spu->p_text->fmt_out.video.i_visible_width =
1060
p_subpic->i_original_picture_width;
1061
p_spu->p_text->fmt_out.video.i_height =
1062
p_spu->p_text->fmt_out.video.i_visible_height =
1063
p_subpic->i_original_picture_height;
1067
p_spu->p_text->fmt_out.video.i_width =
1068
p_spu->p_text->fmt_out.video.i_visible_width =
1070
p_spu->p_text->fmt_out.video.i_height =
1071
p_spu->p_text->fmt_out.video.i_visible_height =
1077
* scale[] allows to pass from rendered size (by text module) to video output size */
1078
pi_scale_width[SCALE_TEXT] = p_fmt->i_width * 1000 /
1079
p_spu->p_text->fmt_out.video.i_width;
1080
pi_scale_height[SCALE_TEXT]= p_fmt->i_height * 1000 /
1081
p_spu->p_text->fmt_out.video.i_height;
1085
/* Just set a value to avoid using invalid memory while looping over the array */
1086
pi_scale_width[SCALE_TEXT] =
1087
pi_scale_height[SCALE_TEXT]= 1000;
1091
* scale[] allows to pass from native (either video or original) size to output size */
564
1093
if( p_subpic->i_original_picture_height > 0 &&
565
1094
p_subpic->i_original_picture_width > 0 )
567
i_scale_width = i_scale_width * p_fmt->i_width /
568
p_subpic->i_original_picture_width;
569
i_scale_height = i_scale_height * p_fmt->i_height /
570
p_subpic->i_original_picture_height;
572
else if( p_subpic->i_original_picture_height > 0 )
574
i_scale_height = i_scale_height * p_fmt->i_height /
575
p_subpic->i_original_picture_height;
576
i_scale_width = i_scale_height * i_scale_height / p_fmt->i_height;
1096
pi_scale_width[SCALE_DEFAULT] = p_fmt->i_width * 1000 / p_subpic->i_original_picture_width;
1097
pi_scale_height[SCALE_DEFAULT] = p_fmt->i_height * 1000 / p_subpic->i_original_picture_height;
1101
pi_scale_width[ SCALE_DEFAULT ] = i_scale_width_orig;
1102
pi_scale_height[ SCALE_DEFAULT ] = i_scale_height_orig;
1105
for( k = 0; k < SCALE_SIZE ; k++ )
1107
/* Case of both width and height being specified has been dealt
1108
* with above by instead rendering to an output pane of the
1109
* explicit dimensions specified - we don't need to scale it.
1111
if( p_subpic->i_original_picture_height > 0 &&
1112
p_subpic->i_original_picture_width <= 0 )
1114
pi_scale_height[ k ] = pi_scale_height[ k ] * i_source_video_height /
1115
p_subpic->i_original_picture_height;
1116
pi_scale_width[ k ] = pi_scale_width[ k ] * i_source_video_height /
1117
p_subpic->i_original_picture_height;
579
1121
/* Set default subpicture aspect ratio */
580
if( p_region && p_region->fmt.i_aspect &&
581
(!p_region->fmt.i_sar_num || !p_region->fmt.i_sar_den) )
583
p_region->fmt.i_sar_den = p_region->fmt.i_aspect;
584
p_region->fmt.i_sar_num = VOUT_ASPECT_FACTOR;
587
(!p_region->fmt.i_sar_num || !p_region->fmt.i_sar_den) )
589
p_region->fmt.i_sar_den = p_fmt->i_sar_den;
590
p_region->fmt.i_sar_num = p_fmt->i_sar_num;
1122
if( !p_region->fmt.i_sar_num || !p_region->fmt.i_sar_den )
1124
if( p_region->fmt.i_aspect != 0 )
1126
p_region->fmt.i_sar_den = p_region->fmt.i_aspect;
1127
p_region->fmt.i_sar_num = VOUT_ASPECT_FACTOR;
1131
p_region->fmt.i_sar_den = p_fmt->i_sar_den;
1132
p_region->fmt.i_sar_num = p_fmt->i_sar_num;
593
1136
/* Take care of the aspect ratio */
594
if( p_region && p_region->fmt.i_sar_num * p_fmt->i_sar_den !=
595
p_region->fmt.i_sar_den * p_fmt->i_sar_num )
597
i_scale_width = i_scale_width *
598
(int64_t)p_region->fmt.i_sar_num * p_fmt->i_sar_den /
599
p_region->fmt.i_sar_den / p_fmt->i_sar_num;
600
i_subpic_x = p_subpic->i_x * i_scale_width / 1000;
603
/* Load the scaling module */
604
if( !p_spu->p_scale && (i_scale_width != 1000 ||
605
i_scale_height != 1000) )
607
p_spu->p_scale = vlc_object_create( p_spu, VLC_OBJECT_FILTER );
608
vlc_object_attach( p_spu->p_scale, p_spu );
609
p_spu->p_scale->fmt_out.video.i_chroma =
610
p_spu->p_scale->fmt_in.video.i_chroma =
611
VLC_FOURCC('Y','U','V','P');
612
p_spu->p_scale->fmt_in.video.i_width =
613
p_spu->p_scale->fmt_in.video.i_height = 32;
614
p_spu->p_scale->fmt_out.video.i_width =
615
p_spu->p_scale->fmt_out.video.i_height = 16;
617
p_spu->p_scale->pf_vout_buffer_new = spu_new_video_buffer;
618
p_spu->p_scale->pf_vout_buffer_del = spu_del_video_buffer;
619
p_spu->p_scale->p_module =
620
module_Need( p_spu->p_scale, "video filter2", 0, 0 );
623
while( p_region && p_spu->p_blend && p_spu->p_blend->pf_video_blend )
625
int i_fade_alpha = 255;
626
int i_x_offset = p_region->i_x + i_subpic_x;
627
int i_y_offset = p_region->i_y + p_subpic->i_y;
629
if( p_region->fmt.i_chroma == VLC_FOURCC('T','E','X','T') )
631
if( p_spu->p_text && p_spu->p_text->p_module &&
632
p_spu->p_text->pf_render_text )
634
p_region->i_align = p_subpic->i_flags;
635
p_spu->p_text->pf_render_text( p_spu->p_text,
636
p_region, p_region );
640
/* Force palette if requested */
641
if( p_spu->b_force_palette &&
642
(VLC_FOURCC('Y','U','V','P') == p_region->fmt.i_chroma) )
644
memcpy( p_region->fmt.p_palette->palette,
645
p_spu->palette, 16 );
648
/* Scale SPU if necessary */
649
if( p_region->p_cache )
651
if( i_scale_width * p_region->fmt.i_width / 1000 !=
652
p_region->p_cache->fmt.i_width ||
653
i_scale_height * p_region->fmt.i_height / 1000 !=
654
p_region->p_cache->fmt.i_height )
656
p_subpic->pf_destroy_region( VLC_OBJECT(p_spu),
658
p_region->p_cache = 0;
662
if( (i_scale_width != 1000 || i_scale_height != 1000) &&
663
p_spu->p_scale && !p_region->p_cache )
667
p_spu->p_scale->fmt_in.video = p_region->fmt;
668
p_spu->p_scale->fmt_out.video = p_region->fmt;
671
p_subpic->pf_create_region( VLC_OBJECT(p_spu),
672
&p_spu->p_scale->fmt_out.video );
673
if( p_spu->p_scale->fmt_out.video.p_palette )
674
*p_spu->p_scale->fmt_out.video.p_palette =
675
*p_region->fmt.p_palette;
676
p_region->p_cache->p_next = p_region->p_next;
678
vout_CopyPicture( p_spu, &p_region->p_cache->picture,
679
&p_region->picture );
681
p_spu->p_scale->fmt_out.video.i_width =
682
p_region->fmt.i_width * i_scale_width / 1000;
683
p_spu->p_scale->fmt_out.video.i_visible_width =
684
p_region->fmt.i_visible_width * i_scale_width / 1000;
685
p_spu->p_scale->fmt_out.video.i_height =
686
p_region->fmt.i_height * i_scale_height / 1000;
687
p_spu->p_scale->fmt_out.video.i_visible_height =
688
p_region->fmt.i_visible_height * i_scale_height / 1000;
689
p_region->p_cache->fmt = p_spu->p_scale->fmt_out.video;
690
p_region->p_cache->i_x = p_region->i_x * i_scale_width / 1000;
691
p_region->p_cache->i_y = p_region->i_y * i_scale_height / 1000;
693
p_pic = p_spu->p_scale->pf_video_filter(
694
p_spu->p_scale, &p_region->p_cache->picture );
697
picture_t p_pic_tmp = p_region->p_cache->picture;
698
p_region->p_cache->picture = *p_pic;
703
if( (i_scale_width != 1000 || i_scale_height != 1000) &&
704
p_spu->p_scale && p_region->p_cache )
706
p_region = p_region->p_cache;
709
if( p_subpic->i_flags & SUBPICTURE_ALIGN_BOTTOM )
711
i_y_offset = p_fmt->i_height - p_region->fmt.i_height -
714
else if ( !(p_subpic->i_flags & SUBPICTURE_ALIGN_TOP) )
716
i_y_offset = p_fmt->i_height / 2 - p_region->fmt.i_height / 2;
719
if( p_subpic->i_flags & SUBPICTURE_ALIGN_RIGHT )
721
i_x_offset = p_fmt->i_width - p_region->fmt.i_width -
724
else if ( !(p_subpic->i_flags & SUBPICTURE_ALIGN_LEFT) )
726
i_x_offset = p_fmt->i_width / 2 - p_region->fmt.i_width / 2;
729
if( p_subpic->b_absolute )
731
i_x_offset = p_region->i_x +
732
i_subpic_x * i_scale_width / 1000;
733
i_y_offset = p_region->i_y +
734
p_subpic->i_y * i_scale_height / 1000;
738
i_x_offset = __MAX( i_x_offset, 0 );
739
i_y_offset = __MAX( i_y_offset, 0 );
741
if( p_spu->i_margin != 0 && p_spu->b_force_crop == VLC_FALSE )
744
int i_low = i_y_offset - p_spu->i_margin;
745
int i_high = i_y_offset + p_region->fmt.i_height - p_spu->i_margin;
747
/* crop extra margin to keep within bounds */
748
if( i_low < 0 ) i_diff = i_low;
749
if( i_high > (int)p_fmt->i_height ) i_diff = i_high - p_fmt->i_height;
750
i_y_offset -= ( p_spu->i_margin + i_diff );
753
p_spu->p_blend->fmt_in.video = p_region->fmt;
755
/* Force cropping if requested */
756
if( p_spu->b_force_crop )
758
video_format_t *p_fmt = &p_spu->p_blend->fmt_in.video;
759
int i_crop_x = p_spu->i_crop_x * i_scale_width / 1000;
760
int i_crop_y = p_spu->i_crop_y * i_scale_height / 1000;
761
int i_crop_width = p_spu->i_crop_width * i_scale_width / 1000;
762
int i_crop_height = p_spu->i_crop_height * i_scale_height/1000;
764
/* Find the intersection */
765
if( i_crop_x + i_crop_width <= i_x_offset ||
766
i_x_offset + (int)p_fmt->i_visible_width < i_crop_x ||
767
i_crop_y + i_crop_height <= i_y_offset ||
768
i_y_offset + (int)p_fmt->i_visible_height < i_crop_y )
770
/* No intersection */
771
p_fmt->i_visible_width = p_fmt->i_visible_height = 0;
775
int i_x, i_y, i_x_end, i_y_end;
776
i_x = __MAX( i_crop_x, i_x_offset );
777
i_y = __MAX( i_crop_y, i_y_offset );
778
i_x_end = __MIN( i_crop_x + i_crop_width,
779
i_x_offset + (int)p_fmt->i_visible_width );
780
i_y_end = __MIN( i_crop_y + i_crop_height,
781
i_y_offset + (int)p_fmt->i_visible_height );
783
p_fmt->i_x_offset = i_x - i_x_offset;
784
p_fmt->i_y_offset = i_y - i_y_offset;
785
p_fmt->i_visible_width = i_x_end - i_x;
786
p_fmt->i_visible_height = i_y_end - i_y;
793
/* Update the output picture size */
794
p_spu->p_blend->fmt_out.video.i_width =
795
p_spu->p_blend->fmt_out.video.i_visible_width =
797
p_spu->p_blend->fmt_out.video.i_height =
798
p_spu->p_blend->fmt_out.video.i_visible_height =
801
if( p_subpic->b_fade )
803
mtime_t i_fade_start = ( p_subpic->i_stop +
804
p_subpic->i_start ) / 2;
805
mtime_t i_now = mdate();
806
if( i_now >= i_fade_start && p_subpic->i_stop > i_fade_start )
808
i_fade_alpha = 255 * ( p_subpic->i_stop - i_now ) /
809
( p_subpic->i_stop - i_fade_start );
813
i_x_offset = __MAX( i_x_offset, 0 );
814
i_y_offset = __MAX( i_y_offset, 0 );
816
p_spu->p_blend->pf_video_blend( p_spu->p_blend, p_pic_dst,
817
p_pic_src, &p_region->picture, i_x_offset, i_y_offset,
818
i_fade_alpha * p_subpic->i_alpha / 255 );
820
p_region = p_region->p_next;
823
p_subpic = p_subpic->p_next;
1137
if( ( p_region->fmt.i_sar_num * p_fmt->i_sar_den ) !=
1138
( p_region->fmt.i_sar_den * p_fmt->i_sar_num ) )
1140
for( k = 0; k < SCALE_SIZE; k++ )
1142
pi_scale_width[k] = pi_scale_width[ k ] *
1143
(int64_t)p_region->fmt.i_sar_num * p_fmt->i_sar_den /
1144
p_region->fmt.i_sar_den / p_fmt->i_sar_num;
1146
pi_subpic_x[k] = p_subpic->i_x * pi_scale_width[ k ] / 1000;
1150
/* Load the scaling module when needed */
1151
if( !p_spu->p_scale )
1153
bool b_scale_used = false;
1155
for( k = 0; k < SCALE_SIZE; k++ )
1157
const int i_scale_w = pi_scale_width[k];
1158
const int i_scale_h = pi_scale_height[k];
1159
if( ( i_scale_w > 0 && i_scale_w != 1000 ) || ( i_scale_h > 0 && i_scale_h != 1000 ) )
1160
b_scale_used = true;
1164
SpuRenderCreateAndLoadScale( p_spu );
1167
for( ; p_region != NULL; p_region = p_region->p_next )
1168
SpuRenderRegion( p_spu, p_pic_dst, p_pic_src,
1169
p_subpic, p_region, i_scale_width_orig, i_scale_height_orig,
1170
pi_subpic_x, pi_scale_width, pi_scale_height,
826
1174
vlc_mutex_unlock( &p_spu->subpicture_lock );