はじめに
動画と字幕をリアルタイムに合成するhtmlを作ったので共有させていただきます。
(webサーバ上のページから再生できるよう改修しました。)

サンプル
github
ソース
function st_sub(){
document.getElementById('file').addEventListener('change', handleFileSelect, false);
}
function sleep(second) {
return new Promise(resolve => {
setTimeout(() => {
resolve()
}, second * 1000)
})
}
//******************************* srt file time style changer ***********************************
function sec_calc(str_mat2){
i_hh=str_mat2.substring(0,2)
i_mm=str_mat2.substring(3,5)
i_ss=str_mat2.substring(6,8)
i_ms=str_mat2.substring(9,12)
str_sec=(parseInt(i_hh*3600)+parseInt(i_mm*60)+parseInt(i_ss))+"."+(i_ms)
int_sec=str_sec
return int_sec
}
/**********************************/
async function handleFileSelect(ev){
var reader = new FileReader();
for (let i = 0; i < ev.target.files.length; i++) {
let file = ev.target.files[i];
s_name=file.name
splt=s_name.split(".")
if(splt[1]!="srt"){
v.src = URL.createObjectURL(file);
await sleep(1)
v.load()
await sleep(1)
v.play()
reader.onload = function(evt) {
var subtitles;
let subtitle = evt.target.result;
_subtitle(subtitle);
}
}else{
reader.readAsText(file,"Shift_JIS");
}
}
};
//**************************** display subtitle **************************************
function _subtitle(text) {
let Subtitle = text;
let Pattern = /(\d+)\n([\d:,]+)\s+-{2}\>\s+([\d:,]+)\n([\s\S]*?(?=\n{2}|$))/g;
let _regExp = new RegExp(Pattern);
if (typeof (text) != "string") throw "Sorry, Parser accept string only.";
if (Subtitle === null) return Subtitle;
let Parse = Subtitle.replace(/\r\n|\r|\n/g, '\n');
let Matches;
//*************//
v.addEventListener("timeupdate", function(){
document.getElementById("subtitle").style.top = document.getElementById("subtitles_position").value+"%";
document.getElementById("subtitle").style.fontSize = document.getElementById("fnt_siz").value+"px";
while ((Matches = Pattern.exec(Parse)) != null) {
int_start_sec=sec_calc(Matches[2])
int_end_sec=sec_calc(Matches[3])
int_v_time=v.currentTime+parseFloat(document.getElementById("delay").value)
if(int_v_time > parseFloat(int_start_sec)){
if(int_v_time < parseFloat(int_end_sec)){
document.getElementById("subtitle").innerHTML = Matches[4].replace('\n','<br />');
}
if(int_v_time > parseFloat(int_end_sec)){
document.getElementById("subtitle").innerHTML = "";
}
}
}
},false);
}
body{
text-align: center;
background-color:#000000;
}
.disp_no{display:none;}
.inps{background-color: #8f8f8f;text-align:right;}
.w32{width:32px;}
#sel_file{width:100%;text-align:right;}
#v{
width:100%;
margin-right: auto;
margin-left: auto;
margin-bottom:15px;
}
#files_label{
margin-right:5px;
color:#000000;
font-size:12px;
padding:0px 5px 0px 5px;
cursor:pointer;
}
#subtitle{
z-index: 3;
left:50%;
top:58%;
line-height:120%;
height:3em;
/*display:table-cell;
vertical-align:bottom;*/
display:flex;
flex-direction: column;
justify-content: flex-end;
position:absolute;
text-align:center;
transform: translate(-50%, -50%);
color:#cccccc;
font-size: 30px;
font-weight: bold;
margin-right:auto;margin-left:auto;
text-shadow:3px 0px 1px #111, 0px 3px 1px #111, -3px 0px 1px #111, 0px -3px 1px #111, 3px 3px 1px #111, -3px 3px 1px #111, -3px -3px 1px #111, 3px -3px 1px #111;
/* ,4px 0px 0px #ccc, 0px 4px 0px #ccc, -4px 0px 0px #ccc, 0px -4px 0px #ccc, 4px 4px 0px #ccc, -4px 4px 0px #ccc, -4px -4px 0px #ccc, 4px -4px 0px #ccc */
}
<html>
<head>
<meta http-equiv="Content-Security-Policy" content="default-src 'self' data: gap: https://ssl.gstatic.com; connect-src ; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src * blob:; media-src * blob:">
<link rel="stylesheet" href="css/base.css">
</head>
<body onload="st_sub()">
<video id="v" controls autobuffer></video>
<div id="subtitle"></div><br />
<div id="sel_file" style="color:#8f8f8f;">
<label for="file" id="files_label" class="inps" >
Select srt file<input type="file" id="file" class="disp_no" name="file[]" multiple />
</label>
Sub Pos Top<input type="text" id="subtitles_position" value="58" class="inps w32">%
Font<input type="text" id="fnt_siz" value="30" class="inps w32">px
Delay<input type="text" id="delay" value="0" class="inps w32">Sec
</div>
</body>
<footer>
<script src="js/play_movie_with_subtitles.js"></script>
</footer>
</html>
使い方
まずブラウザで表示できる動画ファイルと、字幕ファイル(srt形式)を用意し
一つのフォルダにまとめておく必要があります。

srt形式が不明な場合
srtファイルとは などで検索してみてください。
ちなみに形式は下記のような形式
メモ帳などで編集可能です
1
00:00:43,209 --> 00:00:44,919
やってまいりました今日という日
2
00:00:45,211 --> 00:00:48,882
1967年1月27日
大統領も声明を発表
3
00:00:49,257 --> 00:00:53,261
index.html を準備し 開きます
開くと
このような画面になります。

右下に Select srt file というボタンがあるのでクリックし
先程用意したフォルダを探します

字幕ファイルと 動画ファイル の2つともを選択すると
字幕を合成した動画の再生が始まります

字幕の微調整は
右下の部分で
Sub posが 字幕の縦位置の調整になります。
半角数字の入力で即時反映です
うまい具合の位置でないとシークバーの操作ができなくなります。

字幕のタイミング調整
遅くする場合は数値を入力
早くする場合は-(マイナス)付きの数字を入力
どれだけ調整してもタイミングがズレる場合は
動画のバージョン(ディレクターズカット版など)と
字幕のバージョンがあっていない可能性があります。
正しい字幕ファイルを入手するか
メモ帳などでsrtファイルを編集するなどしてみてください。

なぜ作ったか
動画ファイルも字幕ファイルもあるのに合わせて再生するには
アプリのインストールが必要だとのこと。
そんな大仰なことか?と疑問に思い
そのくらいならhtml+javascriptでできるのでは?と考えたためです。
で、誰かそのくらいならもう書いてるだろうと探したのですが
見当たらなかったため書きました。
コード進行が古風ですがご了承ください。
