话不多说,先看一下最终效果

系统设置默认

在系统设置里面更改字幕的显示效果

需求

要求播放器可以显示第二字幕,类似旁白的文字解释。比如片中出现了一个专业术语,这个时候观众可能有些疑惑。所以需要在屏幕上显示这个专业术语的解释。

1. 解析字幕文件

第二字幕也是字幕文件,需要找专门的类进行解析。而第一字幕则不需要这么麻烦,播放器会自动处理并显示的。

srt字幕文件一般格式如下

  • 字幕序号
  • 字幕显示的起始时间 --> 结束时间
  • 字幕内容(可多行)
  • 空白行(表示本字幕段的结束)

字母序号并不起任何实际的作用,只是用来标明而已,解析的时候用不到

首先加载一个字幕文件,我把文件放在Assets文件夹里面了。

var file = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/secondCC.srt"));
if (file == null)
return;

Stream stream = await file.OpenStreamForReadAsync();

var parser = new SubParser();

SubtitleList = parser.ParseStream(await file.OpenStreamForReadAsync(), encoding, mostLikelyFormat);

代码通过读取srt文件,把内容都存在一个List<SubtitleItem>,

SubtitleItem的model定义为

        public int Number { get; set; }

        public int StartTime { get; set; }

        public int EndTime { get; set; }

        public List<string> Lines { get; set; }

2. 获取系统字幕设置

打开Windows设置——轻松使用——隐藏式字幕

默认情况下所有的设置都是默认,当然你可以自己更改,不过这个将对你的第一字幕产生影响。而我们要达到的效果是同时更改第二字幕的效果。

比如获取字体颜色

            if (Windows.Media.ClosedCaptioning.ClosedCaptionProperties.FontColor != Windows.Media.ClosedCaptioning.ClosedCaptionColor.Default)
richtextblock.Foreground = new SolidColorBrush(Windows.Media.ClosedCaptioning.ClosedCaptionProperties.ComputedFontColor);
else
richtextblock.Foreground = new SolidColorBrush(Colors.White);

字体大小

                //系统默认不返回字体的具体大小,而是一个愚蠢的百分比。官方解释说具体的字体大小会根据窗体大小等一系列因素决定,但是又不给你说怎么个计算方法
//所以这里就先给一个初始值。如果你知道怎么计算或者获取最终大小,请create PR。
double defaultSize = ;
switch (Windows.Media.ClosedCaptioning.ClosedCaptionProperties.FontSize)
{
case Windows.Media.ClosedCaptioning.ClosedCaptionSize.FiftyPercent:
richtextblock.FontSize = defaultSize * .;
break;
case Windows.Media.ClosedCaptioning.ClosedCaptionSize.OneHundredPercent:
richtextblock.FontSize = defaultSize * ;
break;
case Windows.Media.ClosedCaptioning.ClosedCaptionSize.OneHundredFiftyPercent:
richtextblock.FontSize = defaultSize * 1.5;
break;
case Windows.Media.ClosedCaptioning.ClosedCaptionSize.TwoHundredPercent:
richtextblock.FontSize = defaultSize * 2.0;
break;
default:
richtextblock.FontSize = defaultSize * 1.0;
break;
}

背景色

if (Windows.Media.ClosedCaptioning.ClosedCaptionProperties.BackgroundColor != Windows.Media.ClosedCaptioning.ClosedCaptionColor.Default)
{
border.Background = new SolidColorBrush(Windows.Media.ClosedCaptioning.ClosedCaptionProperties.ComputedBackgroundColor); Color backColor = Windows.Media.ClosedCaptioning.ClosedCaptionProperties.ComputedBackgroundColor;
switch (Windows.Media.ClosedCaptioning.ClosedCaptionProperties.BackgroundOpacity)
{
case Windows.Media.ClosedCaptioning.ClosedCaptionOpacity.OneHundredPercent:
border.Background = new SolidColorBrush(Color.FromArgb(, backColor.R, backColor.G, backColor.B));//.Opacity = 1.0;
break;
case Windows.Media.ClosedCaptioning.ClosedCaptionOpacity.SeventyFivePercent:
border.Background = new SolidColorBrush(Color.FromArgb(, backColor.R, backColor.G, backColor.B));
break;
case Windows.Media.ClosedCaptioning.ClosedCaptionOpacity.TwentyFivePercent:
border.Background = new SolidColorBrush(Color.FromArgb(, backColor.R, backColor.G, backColor.B));
break;
case Windows.Media.ClosedCaptioning.ClosedCaptionOpacity.ZeroPercent:
border.Background = new SolidColorBrush(Color.FromArgb(, backColor.R, backColor.G, backColor.B));
break;
default:
border.Background = new SolidColorBrush(Color.FromArgb(, backColor.R, backColor.G, backColor.B));
break;
}
}
else
{
Color backColor = Colors.Black;
switch (Windows.Media.ClosedCaptioning.ClosedCaptionProperties.BackgroundOpacity)
{
case Windows.Media.ClosedCaptioning.ClosedCaptionOpacity.OneHundredPercent:
border.Background = new SolidColorBrush(Color.FromArgb(, backColor.R, backColor.G, backColor.B));//.Opacity = 1.0;
break;
case Windows.Media.ClosedCaptioning.ClosedCaptionOpacity.SeventyFivePercent:
border.Background = new SolidColorBrush(Color.FromArgb(, backColor.R, backColor.G, backColor.B));
break;
case Windows.Media.ClosedCaptioning.ClosedCaptionOpacity.TwentyFivePercent:
border.Background = new SolidColorBrush(Color.FromArgb(, backColor.R, backColor.G, backColor.B));
break;
case Windows.Media.ClosedCaptioning.ClosedCaptionOpacity.ZeroPercent:
border.Background = new SolidColorBrush(Color.FromArgb(, backColor.R, backColor.G, backColor.B));
break;
default:
border.Background = new SolidColorBrush(Color.FromArgb(, backColor.R, backColor.G, backColor.B));
break;
}
}

3. 显示第二字幕

在timer里面,我们需要实时更新字幕内容。

如果字幕文件有自定义的样式,那么最终的样式将会呗保留,而不受系统影响。

try
{
if (SubtitleList != null && SubtitleList.Any())
{
var v = (from item in SubtitleList
where item != null
&& item.StartTime + seekDouble <= MyPlayer.MediaPlayer.PlaybackSession.Position.TotalMilliseconds
&& item.EndTime + seekDouble >= MyPlayer.MediaPlayer.PlaybackSession.Position.TotalMilliseconds
orderby item descending
select item).FirstOrDefault();
CurrentSubtitleItem = v;
if (v != null)
{
richtextblock.Blocks.Clear(); Paragraph myParagraph = new Paragraph();
int nextParagraph = ;
string paragraph = "";
foreach (string item in v.Lines)
{
paragraph += item.Trim().ToString() + "\r\n";
if (GetRun(item) != null)
{
myParagraph.Inlines.Add(GetRun(item.Trim()));
try
{
if (v.Lines[nextParagraph] != null)
{
myParagraph.Inlines.Add(new LineBreak());
}
}
catch (Exception ex) { Debug.WriteLine("nextParagraph ex: " + ex.Message); }
}
nextParagraph++;
}
//Run run = new Run();
//run.Text = paragraph.Trim();
//myParagraph.Inlines.Add(run);
richtextblock.Blocks.Add(myParagraph);
border.Visibility = Visibility.Visible;
}
else
{
border.Visibility = Visibility.Collapsed;
richtextblock.Blocks.Clear();
}
}
else
richtextblock.Blocks.Clear();
}
catch (Exception ex) { Debug.WriteLine("mediaPlayer_PositionChanged ex: " + ex.Message); }

比如字幕文件有

::, --> ::,
::,000When a powerful desire indwells in things touched by mortal souls,When a powerful desire indwells in things touched by mortal souls,
<font color=red>颜色</font>
<i>字体斜体</i>
<u>字体下加划线</u>
<br>换行
<b>字体加粗</b>
::, first line ends ::, --> ::,
::, they become goblins.

那么最终的展示效果为:

紫色效果是系统设置,而颜色在字幕里面内置了红色,那么它将不会受系统影响。

4. 源代码

本代码已经开源,获取请点击,如果可以的话,请点击右上角Star

https://github.com/hupo376787/UWPSecondSubtitle

5. 特别鸣谢

开源动画组织:bbb_sunflower_1080p_60fps_normal.mp4/elephantsdream-clip-h264_sd-aac_eng-aac_spa-aac_eng_commentary-srt_eng-srt_por-srt_swe.mkv

本文的字幕文件解析代码参考了开源代码 ramtinakhttps://github.com/ramtinak/UltraPlayer

UWP实现第二字幕并且跟随系统的设置的更多相关文章

  1. [置顶] iOS 应用程序内部国际化,不跟随系统语言

    前言:网络上关于iOS国际化的文章很多,但基本上都是基于跟随系统语言的国际化,笔者就不赘述了-0 – 今天要讲的是不跟随系统的切换语言版本方案,即程序内部的切换语言版本方案. 一.总则: 应用内部语言 ...

  2. 【Windows 10 应用开发】跟随系统主题颜色

    有些时候,希望应用程序中的某些颜色可以与系统的主题颜色相同,并且当系统主题色改变时进行同步. 实现过程并不复杂,主要用到 UISettings 类,它公开一个 GetColorValue 方法,访问这 ...

  3. Android: 设置 app 字体大小不跟随系统字体调整而变化

    在做 app 内字体大小的需求,类似于 微信中设置字体大小. 那么就需要 app 不跟随系统字体大小调整而变化,找到了两个方法. 方法1: 重写 getResource() 方法,修改 configu ...

  4. iOS 应用程序内部国际化,不跟随系统语言

    前言:网络上关于iOS国际化的文章很多,但基本上都是基于跟随系统语言的国际化,笔者就不赘述了-0 – 今天要讲的是不跟随系统的切换语言版本方案,即程序内部的切换语言版本方案. 一.总则: 应用内部语言 ...

  5. 网页跟随系统 dark mode (暗黑模式) 的实现

    经过几十年的沉默, dark mode(暗黑模式) 又回到了我们面前,越来越多的 APP 有了暗黑主题,越来月多的操作系统原生添加了 "全局暗黑模式", 那么一个网站如何跟随系统的 ...

  6. Linux下锁定账号,禁止登录系统的设置总结【转】

    在我们运维工作中,会经常要求一些用户不允许登陆系统,以加固系统安全.今天这里介绍下锁定账号登陆的几种方法: (推荐使用)这种方式会更加人性化一点,因为不仅可以禁止用户登录,还可以在禁用登陆时给提示告诉 ...

  7. 第三部分:Android 应用程序接口指南---第二节:UI---第五章 设置(Settings)

    第5章 设置(Settings) 应用程序通常包括允许用户修改应用程序的特性和行为的设置功能.例如,一些应用程序允许用户指定通知是否启用或指定多久使用云同步数据.如果你想要为你的应用程序提供设置,你应 ...

  8. Ubuntu14.04、win7双系统如何设置win7为默认启动项

    Ubuntu14.04.win7双系统如何设置win7为默认启动项 Ubuntu14.04.win7双系统设置win7为默认启动项方法: 在启动项选择菜单处记住windows 7对应的序号. 从上至下 ...

  9. iOS 跳转到系统的设置界面

    跳到健康设置   上网找了一下  你会发现很难找到.代码如下  不信你试试 . NSURL *url = [NSURL URLWithString:@"prefs:root=Privacy& ...

随机推荐

  1. Java 8 中如何优雅的处理集合

    Java 8 中如何优雅的处理集合(Stream API) 在Java中,集合和数组是我们经常会用到的数据结构,需要经常对他们做增.删.改.查.聚合.统计.过滤等操作.相比之下,关系型数据库中也同样有 ...

  2. 赛艇表演 51nod提高组模拟试题

    AC通道 题目描述 小明去某个地区观看赛艇比赛,这个地区共有n个城市和m条道路,每个城市都有赛艇比赛,在第i个 城市观看赛艇表演的价钱为ai, 去其他城市观看也需要支付赛艇表演的价格.任意两个城市之间 ...

  3. 编译sifive的freedom-u-sdk

    在其它电脑搭建编译该sdk工程的环境,由于所在电脑的linux系统为新装系统(版本:Ubuntu 20.04 LTS),下面记录了编译过程中遇到的问题,以及解决过程供以后参考 问题1:error &q ...

  4. JAVA自学笔记(3)

    JAVA的心动之旅 Day1 字符串String 1.0 字符串的特点以及创建一个字符串 public class Practice {//构建字符串的3+1种方法 public static voi ...

  5. 00016-layui 动态加载菜单 laytpl

    <%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ i ...

  6. STM32读取HX711(AD)模块数据——压力传感器

    背景:在无人机动力系统的选型时,为了测试无人机的动力系统所能提供的最大拉力,使用压力传感装置测量拉力. 链接: 压力传感器tb链接: HX711模块是一个24位精度的AD模块. (1)https:// ...

  7. 动态ip服务器 动态ip服务器的常用连接方式 收藏版

    动态ip服务器目前比较常用的是VPS也叫作虚拟机.目前比较小型的vps服务器与普通电脑没什么区别,最大的区别就是用户连接zhidao服务器内的ip是固定不变的.而服务器运行的ip是可以动态的. 实现动 ...

  8. Bootstrap解决页面缩小变形的办法

    bootstrap布局是应用得很广泛的一种网页布局方法,例如:我们用一种中间内容很流行的布局分布:3-6-3式布局.代码如下 <style type="text/css"&g ...

  9. python(3.x)自动化全栈开发100天集训计划(跟上进度,到一个新高度)——day1

            Day1 目录: Python介绍 * 了解Python的特点.发展史 * 介绍Python广泛的应用领域和前景 第一个Python程序 * 掌握Python代码的2种执行方式 变量 ...

  10. (Java实现) 均分纸牌

    题目描述 有 N 堆纸牌,编号分别为 1,2,-, N.每堆上有若干张,但纸牌总数必为 N 的倍数.可以在任一堆上取若于张纸牌,然后移动. 移牌规则为:在编号为 1 堆上取的纸牌,只能移到编号为 2 ...