UWP实现第二字幕并且跟随系统的设置
话不多说,先看一下最终效果
系统设置默认

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

需求
要求播放器可以显示第二字幕,类似旁白的文字解释。比如片中出现了一个专业术语,这个时候观众可能有些疑惑。所以需要在屏幕上显示这个专业术语的解释。
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
本文的字幕文件解析代码参考了开源代码 ramtinak:https://github.com/ramtinak/UltraPlayer
UWP实现第二字幕并且跟随系统的设置的更多相关文章
- [置顶] iOS 应用程序内部国际化,不跟随系统语言
前言:网络上关于iOS国际化的文章很多,但基本上都是基于跟随系统语言的国际化,笔者就不赘述了-0 – 今天要讲的是不跟随系统的切换语言版本方案,即程序内部的切换语言版本方案. 一.总则: 应用内部语言 ...
- 【Windows 10 应用开发】跟随系统主题颜色
有些时候,希望应用程序中的某些颜色可以与系统的主题颜色相同,并且当系统主题色改变时进行同步. 实现过程并不复杂,主要用到 UISettings 类,它公开一个 GetColorValue 方法,访问这 ...
- Android: 设置 app 字体大小不跟随系统字体调整而变化
在做 app 内字体大小的需求,类似于 微信中设置字体大小. 那么就需要 app 不跟随系统字体大小调整而变化,找到了两个方法. 方法1: 重写 getResource() 方法,修改 configu ...
- iOS 应用程序内部国际化,不跟随系统语言
前言:网络上关于iOS国际化的文章很多,但基本上都是基于跟随系统语言的国际化,笔者就不赘述了-0 – 今天要讲的是不跟随系统的切换语言版本方案,即程序内部的切换语言版本方案. 一.总则: 应用内部语言 ...
- 网页跟随系统 dark mode (暗黑模式) 的实现
经过几十年的沉默, dark mode(暗黑模式) 又回到了我们面前,越来越多的 APP 有了暗黑主题,越来月多的操作系统原生添加了 "全局暗黑模式", 那么一个网站如何跟随系统的 ...
- Linux下锁定账号,禁止登录系统的设置总结【转】
在我们运维工作中,会经常要求一些用户不允许登陆系统,以加固系统安全.今天这里介绍下锁定账号登陆的几种方法: (推荐使用)这种方式会更加人性化一点,因为不仅可以禁止用户登录,还可以在禁用登陆时给提示告诉 ...
- 第三部分:Android 应用程序接口指南---第二节:UI---第五章 设置(Settings)
第5章 设置(Settings) 应用程序通常包括允许用户修改应用程序的特性和行为的设置功能.例如,一些应用程序允许用户指定通知是否启用或指定多久使用云同步数据.如果你想要为你的应用程序提供设置,你应 ...
- Ubuntu14.04、win7双系统如何设置win7为默认启动项
Ubuntu14.04.win7双系统如何设置win7为默认启动项 Ubuntu14.04.win7双系统设置win7为默认启动项方法: 在启动项选择菜单处记住windows 7对应的序号. 从上至下 ...
- iOS 跳转到系统的设置界面
跳到健康设置 上网找了一下 你会发现很难找到.代码如下 不信你试试 . NSURL *url = [NSURL URLWithString:@"prefs:root=Privacy& ...
随机推荐
- 程序员使用IDEA这些插件后,办公效率提升100%(持续更新中)
IDEA一些不错的插件分享 目录 IDEA一些不错的插件分享 插件集合 CamelCase Translation LiveEdit MarkDown Navigator Jrebel CheckSt ...
- SQL——表连接JOIN
JOIN - 用于根据两个或多个表中的列之间的关系,从这些表中查询数据. 语法:SELECT columnName(s) FROM tableName1 JOIN tableName2 -- 查 ...
- solr学习(笔记) windows10+jdk1.8+tomcat8环境部署
一:准备环境 1.1 »tomcat8.5下载地址:https://tomcat.apache.org/download-80.cgi 1.2 solr各版本下载地址:http://archive.a ...
- 【转】shell的反引号、单引号、双引号的作用
Linux Shell中有三种引号,分别为双引号(" ").单引号(' ')以及反引号(` `). 其中双引号对字符串中出现的$.''.`和\进行替换:单引号不进行替换,将字符串中 ...
- 五、Spring Web应用程序构建
内容 映射请求到Spring控制器 透明地绑定表单参数 校验表单提交 关键词 模型-视图-控制器(Model-View-Controller,MVC) 处理器映射(handle mapping) 视图 ...
- 在 MacOS 中使用 multipass 安装 microk8s 环境
在 MacOS 中使用 multipass 安装 microk8s 环境 Multipass & MicroK8s 介绍 What is Kubernetes? Kubernetes clus ...
- day1_计算机基础
一.计算器5大组成:计算机硬件:(计算机是奴隶) 1.五大组成 控制器 运算器 存储器I/O:内存+外存 ...
- 【Java8新特性】重复注解与类型注解,你真的学会了吗?
写在前面 在Java8之前,在某个类或者方法,字段或者参数上标注注解时,同一个注解只能标注一次.但是在Java8中,新增了重复注解和类型注解,也就是说,从Java8开始,支持在某个类或者方法,字段或者 ...
- Beta冲刺 ——5.27
这个作业属于哪个课程 软件工程 这个作业要求在哪里 Beta冲刺 这个作业的目标 Beta冲刺 作业正文 正文 github链接 项目地址 其他参考文献 无 一.会议内容 1.组员一起学习Git分支管 ...
- Java实现第七届蓝桥杯国赛 赢球票
标题:赢球票 某机构举办球票大奖赛.获奖选手有机会赢得若干张球票. 主持人拿出 N 张卡片(上面写着 1~N 的数字),打乱顺序,排成一个圆圈. 你可以从任意一张卡片开始顺时针数数: 1,2,3- 如 ...