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

系统设置默认

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

需求

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

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. 性能测试之服务器监控和Prometheus推荐

    服务器的监控,也是采用Prometheus和Grafana.可以监控服务器系统负载.CPU使用率.网络流量.磁盘使用率.磁盘读写速度.IO耗时.网络信息. 效果图 安装使用 安装启动node_expo ...

  2. Java——读取和写入txt文件

    package com.java.test.a; import java.io.BufferedReader; import java.io.BufferedWriter; import java.i ...

  3. 【Copy攻城狮日志】Node快速重命名文件,告别Potplay字幕困扰问题

    ↑开局一张图,故事全靠编↑ 前言 Copy攻城狮日志的惯例,开局一张图,开始为您讲述一个鲜为人知的故事.故事的开头要从本大狮从盗版网站下载udemy课程的犯罪伊始说起,去年的某月某天,我真正接触到了“ ...

  4. 查看包名和Activity的小工具

    添加到右键菜单,很方便. 做个记录:请移步原文

  5. linux高级管理第十二章--rsync

    实验部分 1.安装rsync 2.配置文件 3.配置密码 4.后续 5.为了测试,创建几个文件 配置实时同步 1.调整inotify内核参数 安装inotify-tools 测试同步 编写脚本 验证 ...

  6. [设计模式](转)Java中的24种设计模式与7大原则

    *:first-child { margin-top: 0 !important; } body > *:last-child { margin-bottom: 0 !important; } ...

  7. [SD心灵鸡汤]002.每月一则 - 2015.06

    1.用最多的梦面对未来 2.自己要先看得起自己,别人才会看得起你 3.一个今天胜过两个明天 4.要铭记在心:每天都是一年中最美好的日子 5.乐观者在灾祸中看到机会:悲观者在机会中看到灾祸 6.有勇气并 ...

  8. ie时间格式NAN-NAN-NAN

    js的日期对象可以识别的日期字符串有四种: 1.YYYY-MM-DD 2019-11-11 01:01:012.MM-DD-YYYY 11-11-2019 01:01:013.YYYY/MM/DD 2 ...

  9. 【Hadoop】namenode与secondarynamenode的checkpoint合并元数据

    Checkpoint Node(检查点节点) NameNode persists its namespace using two files: fsimage, which is the latest ...

  10. Window10:不能建立到远程计算机的连接,你可能需要更改此连接的网络设置。

    一,右键我的电脑点击管理. 二,在系统工具中找到设备管理,在设备管理中找到网络适配器. 三,在网络适配器中找到WAN Miniport(IP) 四,找到WAN Miniport(IP)右键放心卸载,作 ...