uwpmedia-playerclosed-captions

How to create a second/bilingual subtitle, the same size to MediaPlayerElement's CC


For some reason, MediaPlayerElement's CC font size is affected by many factors, I can't get the exact font size. Refer to SO link, How to get system's closed caption font size?.

So do anyone has ideas how to create a second/bilingual subtitle, the same size to MediaPlayerElement's CC?


Solution

  • You can use the ControlTemplate that modifies MediaPlayerElement to create your custom subtitle control.

    Making a complete subtitle control is more complicated. I will only provide one idea here.

    1. We need to create a control class derived from MediaPlayerElement as our test case.

    public class CustomMediaPlayerElement:MediaPlayerElement
    {
        public string SecondCaption
        {
            get { return (string)GetValue(SecondCaptionProperty); }
            set { SetValue(SecondCaptionProperty, value); }
        }
        public static readonly DependencyProperty SecondCaptionProperty =
            DependencyProperty.Register("SecondCaption", typeof(string), typeof(CustomMediaPlayerElement), new PropertyMetadata(""));
    
    }
    

    We add a dependency property of SecondCaption, which is the text of the second subtitle we are currently displaying. In the future, we can switch the displayed text with a timer.

    2. Create the custom control template

    Since MediaPlayerElement's CC font size is variable, we can use ViewBox for simulation.

    <Style TargetType="local:CustomMediaPlayerElement" x:Key="BasicMediaStyle">
        <Setter Property="HorizontalAlignment" Value="Stretch" />
        <Setter Property="VerticalAlignment" Value="Stretch" />
        <Setter Property="IsTabStop" Value="False" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="local:CustomMediaPlayerElement">
                    <Grid x:Name="LayoutRoot">
                        <Border Background="Transparent" />
                        <Image  x:Name="PosterImage"
                Visibility="Collapsed"
                Source="{TemplateBinding PosterSource}"
                Stretch="{TemplateBinding Stretch}" />
                        <MediaPlayerPresenter x:Name="MediaPlayerPresenter"
                IsFullWindow="{TemplateBinding IsFullWindow}"
                Stretch="{TemplateBinding Stretch}"
                MediaPlayer="{TemplateBinding MediaPlayer}" />
                        <ContentPresenter     x:Name="TransportControlsPresenter"
                Visibility="{TemplateBinding AreTransportControlsEnabled}" IsTapEnabled="False"/>
                        <Grid x:Name="TimedTextSourcePresenter" />
                        <Grid x:Name="SecondTimedTextSourceContainer">
                            <Viewbox>
                                <Grid>
                                    <TextBlock Text="{TemplateBinding SecondCaption}" FontSize="15" VerticalAlignment="Bottom"
                                           HorizontalAlignment="Center" TextAlignment="Center" Foreground="White"/>
                                </Grid>
                            </Viewbox>
                        </Grid>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    

    3. Add addition properties to make the subtitle display the correct size

    If we only write as above, we will end up with a TextBlock that fills the entire screen. In order for the ViewBox to work as we expect, we need to add some new attributes to make the container where the subtitles are the right size.

    CustomMediaPlayerElement.cs

    public double SourceWidth
    {
        get { return (double)GetValue(SourceWidthProperty); }
        set { SetValue(SourceWidthProperty, value); }
    }
    
    public static readonly DependencyProperty SourceWidthProperty =
        DependencyProperty.Register("SourceWidth", typeof(double), typeof(CustomMediaPlayerElement), new PropertyMetadata(double.NaN));
    
    
    public double SourceHeight
    {
        get { return (double)GetValue(SourceHeightProperty); }
        set { SetValue(SourceHeightProperty, value); }
    }
    
    public static readonly DependencyProperty SourceHeightProperty =
        DependencyProperty.Register("SourceHeight", typeof(double), typeof(CustomMediaPlayerElement), new PropertyMetadata(double.NaN));
    

    CustomeMediaPlayerElement.xaml

    ...
    <Viewbox>
        <Grid Height="{TemplateBinding SourceHeight}" Width="{TemplateBinding SourceWidth}">
            <TextBlock Text="{TemplateBinding SecondCaption}" FontSize="15" VerticalAlignment="Bottom"
                   HorizontalAlignment="Center" TextAlignment="Center" Foreground="White"/>
        </Grid>
    </Viewbox>
    ...
    

    How to use

    <controls:CustomMediaPlayerElement SecondCaption="Hello World" x:Name="MyPlayer"
                                       AreTransportControlsEnabled="True" Style="{StaticResource BasicMediaStyle}"
                                       />
    
    private async Task LoadVideo(StorageFile videoFile)
    {
        var player = new MediaPlayer();
        var source = MediaSource.CreateFromStorageFile(videoFile);
        player.Source = source;
        player.MediaOpened += Media_Opened;
        MyPlayer.SetMediaPlayer(player);
    }
    
    private async void Media_Opened(MediaPlayer sender, object args)
    {
        await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
        {
            MyPlayer.SourceWidth = sender.PlaybackSession.NaturalVideoWidth;
            MyPlayer.SourceHeight = sender.PlaybackSession.NaturalVideoHeight;
        });
    }
    

    In this way, you can get a subtitle control that will scale with MediaPlayerElement, and modify the SecondCaption with the timer to achieve the function of subtitles.

    But as I said before, it is complicated to implement a complete subtitle control. This is just a way to add a new subtitle control, you need to customize according to your needs.

    Thanks.