Streaming Conference #2 -TELETEXT-
こんにちは、Fennecエバンジェリストです。 最近暇で暇でしょうがないので何かアウトプットしようと、先日Streaming Conference #2にてLTをしてきました。 表題は**# TELETEXT**で、字幕放送についてご紹介しました。
動画のストリーミングサービスはインターネットでは常に注目され続けている技術の中心に位置するものです。 動画というとビデオとオーディオの二つのみを指すことがほとんどですが、動画配信においては忘れてはいけないのがテレテキスト、字幕放送です。 地上デジタル放送でも字幕放送によって演者の話し声を文字情報として伝えるものがいくつかありますが、インターネット動画ストリーミングにおいては忘れられている存在にも思える2018年。 そんなテレテキストについて少しでも興味を持ってもらおうと、いくつがWebにおける字幕放送の表現の例をご紹介してきました。
目次
Open 目次
EXAMPLE 1 -字幕放送-
はじめに例としてあげた字幕放送はスライド6ページ目で、一般的なWebメディアにおける黒背景白文字の音声字幕と地上デジタル放送のような演者ごとに色分けされた字幕放送の表現についての紹介をしました。 前途の通りSpectacleを用いてWebページとして行なったのはこの例を見せるためでもあり、WebページにYouTubeの動画を埋め込みたかったからです。 このデモでは動画に流れる音声の文字起こしをし、タイミングを合わせてクローズドキャプショントラックとして表示していました。 デモのために用意した字幕は以下の通りです。ちなみにSafariでしか動作確認してません。
WEBVTT
00:00:00.500 --> 00:00:02.500 line:90%
<c>けものフレンズ</c>
00:00:04.000 --> 00:00:06.500 line:90% align:start position:30%
<c>♪ 〜</c>
00:00:08.500 --> 00:00:11.500 line:90%
<v bag>(かばん) どこ ここ? うわ〜!
00:00:11.500 --> 00:00:13.500 line:90%
<v serval>(サーバル) そこだ〜!
00:00:13.500 --> 00:00:14.800 position:80% line:90%
<v bag><ruby>食<rt>た</rt></ruby>べないでくださ〜い!
00:00:14.800 --> 00:00:16.500 position:30% line:90%
<v serval>た <ruby>食<rt>た</rt></ruby>べないよ!
00:00:16.000 --> 00:00:17.900 line:60%
<v bag>サーバル…さん。
00:00:17.900 --> 00:00:21.000 position:60% line:80% align:end
<v serval>ここは ジャパリパーク だよ!
<ruby>私<rt>わたし</rt></ruby>はサーバル!
00:00:21.000 --> 00:00:24.000 position:60% line:80% align:end
<v serval>この<ruby>辺<rt>へん</rt></ruby>は <ruby>私<rt>わたし</rt></ruby>のナワバリなの
このファイルを.vttファイルに保存し、HTML5ビデオの<track>タグにて指定してあげると、動画に文字を表示することができます。
WebVTTの<v>
タグで、演者の指定を行っています。
このままだと位置はWebVTTのposition
line
、align
@font-face {
font-family: '和田研中丸ゴシック2004絵文字';
src: url(wlcmaru2004emoji.ttf);
}
video::cue {
font: 1.1em/1.4 '和田研中丸ゴシック2004絵文字';
}
video::cue(c) {
font-family: 'Hiragino Kaku Gothic ProN';
background: -webkit-linear-gradient(rgba(0,0,0,0.5), rgba(0,0,0,0.5));
}
video::cue(v[voice="bag"]) {
color: cyan;
}
video::cue(v[voice="serval"]) {
color: yellow;
}
WebVTTの策定は紹介した通りまだドラフト段階であることから、ブラウザ実装は不安定で、例えば背景の色指定はrgba()単体では指定できず、グラデーションやテクスチャなどに変えてからじゃないとダメだったり、ルビがおかしかったりします。 現状でもルビの使用や背景色にこだわらなければ十分実用できるでしょう。正式版になるころには地上デジタル放送と同様の字幕放送が楽に実装できるようになると思うと、今後が楽しみになること請け合いです。
EXAMPLE 2 -KARAOKE-
スライド11ページ目で紹介したWebVTTによるカラオケデモです。JavaScriptを一切用いずに、動画上にカラオケのように歌詞を表示することができます。ちなみにSafariでしか動作確認してません。
WEBVTT
0 - Title
00:00:00.000 --> 00:00:01.800 line:50%
<c.title>ようこそジャパリパークへ</c>
0 - Info
00:00:00.000 --> 00:00:01.800 line:90% align:right
作詞 大石昌良
作曲 大石昌良
00:00:01.800 --> 00:00:08.000 line:6 position:5% align:left
<00:00:03.200><c>Wel</c><00:00:03.300><c>come</c><00:00:03.600><c> to</c><00:00:03.800><c> よ</c><00:00:04.000><c>う</c><00:00:04.300><c>こそ</c><00:00:04.500><c>ジャ</c><00:00:04.800><c>パリ</c><00:00:05.000><c>パーク!</c>
00:00:03.600 --> 00:00:13.000 line:8 position:25% align:left
<00:00:05.600><c>今日</c><00:00:05.800><c>も</c><00:00:06.200><c>ドッ</c><00:00:06.500><c>タン</c><00:00:06.800><c>バッ</c><00:00:07.100><c>タン</c><00:00:07.500><c>大</c><00:00:08.200><c>騒</c><00:00:08.800><c>ぎ</c>
00:00:11.000 --> 00:00:15.500 line:6 position:15% align:left
<00:00:13.200><c>うー!</c><00:00:13.900><c>がぉー!</c>
00:00:13.200 --> 00:00:19.000 line:8 position:25% align:left
<00:00:14.700><c>高</c><00:00:15.000><c>ら</c><00:00:15.200><c>か</c><00:00:15.500><c>に</c><00:00:15.900><c>笑</c><00:00:16.100><c>い</c><00:00:16.300><c>笑</c><00:00:16.700><c>え</c><00:00:16.900><c>ば</c><00:00:17.300><c> フ</c><00:00:17.500><c>レ</c><00:00:17.700><c>ン</c><00:00:17.900><c>ズ</c>
00:00:16.000 --> 00:00:22.000 line:6 position:15% align:left
<00:00:18.600><c>(フ</c><00:00:18.800><c>レ</c><00:00:19.000><c>ン</c><00:00:19.200><c>ズ)</c>
00:00:19.800 --> 00:00:26.000 line:9 position:15% align:left
<00:00:23.800><c>喧嘩して すっちゃかめっちゃかしても</c>
今回はようこそジャパリパークへの歌詞を引用してご紹介します。ノリのよい曲調でテンポの良い歌詞で気に入ってます。上記歌詞に引用した高らかに笑い笑えばフレンズの部分は特に現代社会を生きる日本人に足りない精神だとも言えます。
WebVTTには、テキストにタイムスタンプタグを打ち込むことによって、動画の時間と同期してタグの前後に属性の変化が起こります。それを用いて、CSSで色付けをおこなうことで、カラオケのように時間に沿った文字の変更をJavaScriptなしで実現しています。
video::cue {
font-family: 'Hiragino Kaku Gothic ProN';
}
video::cue(.title), video::cue(:past), video::cue(:future) {
font-family: 'Hiragino Mincho ProN';
}
video::cue(.title) {
color: lightblue;
font-size: 1.6em;
}
video::cue(:past) {
color: red;
}
video::cue(:future) {
color: white;
}
タイムスタンプタグのある::cue
擬似要素には:future
擬似クラスが当てられ、指定した時刻をすぎるとそれ以前の部分には:past
に変化します。それぞれの擬似クラスに対して文字色を指定することで、このようにカラオケ風な表示をしています。
ドラフト仕様のためか、タイムスタンプタグの擬似クラスを適用するには要素で囲む必要があるようで、<c>
スパンタグで囲んでますが、これのせいもあって作るのに半日かかりました。
しかしJavaScriptなしでこのような面白い表現ができるのは、Webメディアにおけるテレテキストの未来を感じさせてくれること間違いなしですね。
EXAMPLE 3 -LIVE comment-
最後に紹介したのは背景に流した動画にテレテキストを取得させ、スライド上にライブコメントを流すというもの。プレゼンテーション中に#streamingconfで呟かれたものを取得して流していましたが、ツイ廃のせいか、Twitter APIを叩くと頻繁に420 Exceeded connection limit for userエラーが出て取得がうまくいかなかったりしていました。 ストリーミング勉強会での発表なので上記2つのようなオンデマンド配信に対するテレテキストのデモだけではなく、ストリーミング動画に対してもテレテキストは面白い使い方ができるということをご紹介した形となります。 このデモでは前途の通り動画中にテレテキストを表示するのではなく、動画からとりだしてJavaScriptでHTML要素としてスライド中に表示しました。 Slideshareにあげたスライド15ページ目で紹介したのですが、残念ながらライブであるという都合に加え背景動画のPDF化ができなかったため、実際の表示は想像で補ってください。
Webでの動画ストリーミングの形式はいろいろあるのはご存知の通りですが、今回はSafariでプレゼンテーションを行ったため、HLSを用いてコメントを流しました。 HLSではビデオやオーディオだけではなく、テレテキストもストリーミングできるというのは意外と知られていなかったりします。しかもライブで。
配信方法はHLSの動画をセグメント単位で切り出して行うのと同様に、メディアプレイリストを作成してテレテキストもセグメント単位で送り出してあげることでできます。
HLSの仕様でもWebVTTが扱えることが記されており、動画とタイミングを同期するため、X-TIMESTAMP-MAP
メタデータをWebVTTに追記することなどが書かれています。
いろいろ試行錯誤した結果、このメタデータの指定にはMPEG-2 timeを記載する必要があるのと、ライブで字幕を取得するためには動画セグメントが等間隔でないとうまくいかなかったりしたので、今回はfMP4ではなくMPEG-TSでの配信をしました。
ほんとはHEVC使いたかったんだけどね。
動画は事前に撮影したものをエンコードし、mediafilesegmenterでちょうど4秒ごとにTSに切り出したものを、Liveでプレイリストに入れて読み込むようにしておきました。
各プレイリストとWebVTTは以下のような感じで配信していました。バックエンドはGoで、muxとanacondaとm3u8を用いています。
master.m3u8
#EXTM3U
#EXT-X-VERSION:6
#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="tweet",NAME="Tweet",DEFAULT=YES,AUTOSELECT=YES,LANGUAGE="ja",URI="subtitle.m3u8"
#EXT-X-STREAM-INF:PROGRAM-ID=0,BANDWIDTH=1024000,SUBTITLES="tweet"
media.m3u8
media.m3u8
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:28
#EXT-X-TARGETDURATION:4
#EXTINF:4.000,
ts/segment28.ts
#EXTINF:4.000,
ts/segment29.ts
#EXTINF:4.000,
ts/segment20.ts
subtitle.m3u8
#EXTM3U
#EXT-X-VERSION:7
#EXT-X-MEDIA-SEQUENCE:28
#EXT-X-TARGETDURATION:4
#EXTINF:4.000,
sub/segment28.vtt
segment28.vtt
WEBVTT
X-TIMESTAMP-MAP=MPEGTS:900000,LOCAL:00:00:00.000
NOTE start 1m52s -> 1m56s
00:01:53.686 --> 00:01:54.686
エンジニア引退しよ...
00:01:53.796 --> 00:01:54.796
退職しました
00:01:54.922 --> 00:01:54.922
あ〜水素の音〜〜
00:01:55.078 --> 00:01:56.078
アイドル相手の示談金いくらだろう
億とかもらえるのかな
HTMLで<video src="live/master.m3u8" playsinline muted autoplay></video>
と書くだけで、HLSが勝手に動画とテレテキストを4秒間隔で取得してきてくれます(Safariでのみ確認済み)。
そう、JavaScriptでコメントを逐一読み込みに行かなくても、ブラウザ側が勝手に読み込んでくれるのです。WebSocketもXHRも使わずに(ただし完全なリアルタイムではなく、今回は4秒の遅延が生じている)。
スライド9ページ目で紹介した通り、WebVTTはVideo要素で扱えるDOM APIが提供されています。それを叩いて動画で表示されるテレテキストをDOMに引っ張ってきて、スライドの上にコメントを流すようにしていました。
document.querySelector('video#bg').addEventListener('play', function() {
const {textTracks} = this // WebVTT track
if (textTracks.length != 1) {
console.error("Error: %s", "WebVTT track loading failed.")
return
}
const textTrack = textTracks[0]
// Set visibility to hidden on video.
textTrack.mode = 'hidden'
// WebVTT DOM API event 'cuechange'
textTrack.addEventListener('cuechange', function() {
// textTrack.activeCues includes current active subtitle text and more.
[...this.activeCues].forEach(cue => {
const {text} = cue
// Duplication check
if ([...document.querySelectorAll('.comment')].filter(c => c.innerText == text).length) {
// Duplicated comment will not be shown.
return
}
document.querySelectorAll('.comment').forEach(c => {
const rect = c.getBoundingClientRect()
if (rect.left + rect.width < 0) {
// Clear invisible comment from DOM.
c.parentElement.removeChild(c)
}
})
// Get all comment lines of visible comments.
const commentLines = [...document.querySelectorAll('.comment')].map(c => c.style.animationName)
// Find available comment line on view.
const available = [...Array(12)].map((_,i) => `line${i}`).filter(l => !commentLines.includes(l))
if (!available[0]) {
// No placeable comment line available; skip this comment
return
}
const s = document.createElement('span')
s.className = 'comment'
s.innerText = text
s.style.animationName = available[0]
document.querySelector('#screen').append(s)
})
}, false)
})
まとめ
いかがでしょうか。テレテキストの可能性や重要性に気づいてもらえたら嬉しいです。 もっと字幕放送を使ったWebストリーミングサービスが増えたらいいな。