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& ...
随机推荐
- Linux——vim操作
查看文件:vim 文件名 进入vim命令后: Shift+g:到达文件底部 /搜索内容:搜索文件中字符串:点击“N”键,查看下一个搜索内容位置
- 实验五:shell脚本编程
项目 内容 这个作业属于哪个课程 班级课程的主页链接 这个作业的要求在哪里 作业要求链接地址 学号-姓名 17043133-木腾飞 作业学习目标 1.了解shell 脚本的概念及应用2.掌握shell ...
- 这次终于可以愉快的进行 appium 自动化测试了
appium 是进行 app 自动化测试非常成熟的一套框架.但是因为 appium 设计到的安装内容比较多,很多同学入门都跪在了环境安装的部分.本篇讲述 appium 安卓环境的搭建,希望让更多童鞋轻 ...
- Javascript函数闭包详解(通俗易懂
许多书上闭包过于复杂讲解难懂,自己理解了一下并总结啦~ 讲闭包之前,需要先明白以下几个概念. 总之,函数执行时所在的作用域,是定义时的作用域,而不是调用时所在的作用域. 1.执行上下文(executi ...
- 一篇文章,全面掌握Git
版本控制 版本控制就是记录项目文件的历史变化.它为我们查阅日志,回退,协作等方面提供了有力的帮助. 版本控制一般分为集中化版本控制和分布式版本控制. 集中化主要的版本数据都保存服务端. 分布式版本数据 ...
- 50个SQL语句(MySQL版) 问题七
--------------------------表结构-------------------------- student(StuId,StuName,StuAge,StuSex) 学生表 tea ...
- 多用户vps管理面板怎么安装,有没有好用的vps管理工具
一.VPS安装VPSMate控制面板步骤 1.使用SSH连接到VPS.使用命令获取VPSMate安装包: wget http://www.vpsmate.org/tools/install.py ...
- Spring相关面试题-整理
1.什么是Spring MVC?简单介绍一下你对Spring MVC的理解? Spring MVC是一个基于Java的实现了MVC设计模式的请求驱动类型的轻量级Web框架,通过把Model,View, ...
- lua string方法拓展
--[[-- 用指定字符或字符串分割输入字符串,返回包含分割结果的数组 local input = "Hello,World" local res = string.split(i ...
- Rocket - diplomacy - misaligned
https://mp.weixin.qq.com/s/poCJBcx45clXHm6Uuv8M6w 介绍AddressSet.misaligned的实现.之前介绍的比较概括,也有偏差.这里根据实际执行 ...