現状の ffmpeg では VTT字幕と、映像と音声のセグメントを合わせたマスタープレイリストを作れないので、マスタープレイリストを編集しなければならない。2020年4月9日以降はVTT字幕と、映像と音声のセグメントを合わせたマスタープレイリストを作れるようになった。多くのブラウザがプレイリストの直接再生に対応していないのでライブラリを使う。さらに ARIB字幕のある動画はlibaribb24、またはlibaribcaptionを有効化していないと変換できないうえ、有効化してないときは字幕を無効(-sn)にしないとエラーになる。有効化してないときは字幕の処理は行わない。
ffmpeg で Apple HTTP Live Streaming(HLS)を扱う
準備
HTML5 プレイヤの例
- video-dev/hls.js: JavaScript HLS client using Media Source Extension
- clappr/clappr: An extensible media player for the web.
- MoePlayer/DPlayer: Wow, such a lovely HTML5 danmaku video player
ffmpeg で HLS 出力するときに注意する点はいくつかあり、エンコード設定、解像度やフレームレート、ライブかVODか、遅延、視聴環境などそれぞれに対応する必要があるが、今回は試しやすい Windows10 での Edge、firefox、Chrome で再生確認し、配信環境を nginx、ngrok で作っている。
nginx: download
ngrok – secure introspectable tunnels to localhost
ngrok 導入方法 – Qiita
少しでも安全にngrokを使用する(Basic認証) – Qiita
ARIB字幕を変換するにはlibaribb24、またはlibaribcaptionを有効にする。
ARIB字幕をdemuxする libaribb24
ARIB字幕をdemuxするlibaribcaption
コーデックは H.264/AAC を使うので映像コーデックにはソフトウェアエンコード、ハードウェアエンコードそれぞれ配信環境に合わせて使う。AACエンコーダは配布できない FDK-AAC(-c:a libfdk_aac)があるので、こちらを試すなら media-autobuild_suiteでバイナリを用意する。
- QSV 対応の ffmpeg をつくる
- AMD VCE 対応の ffmpeg をつくる
- 字幕ファイルを動画に焼き付ける subtitles
- ffmpeg に nvenc(cuda)をインストールする
- CUDA を使ったハードウェアアクセレーションフィルタのまとめ
- Vulkan を使ったハードウェアアクセレーションフィルタのまとめ
- ハードウェアデコーダ、フィルタ、エンコーダを組み合わせる
通常のARIB字幕付きHLS配信
デュアルモノラルのときだけ音声コーデックをcopyすると HLS で再生できない。それ以外はコピーしても再生できる(はず)。
[確認]NHK解説放送のmp4エンコード · Issue #244 · l3tnun/EPGStation
ffmpeg -analyzeduration 10MB -probesize 10MB -fix_sub_duration -i input.ts -vf yadif,scale=1280:720 -c:v libx264 -c:a aac -c:s webvtt -map 0:v -map 0:a:0 -map 0:s -f hls -var_stream_map "0:v:0,a:0,s:0,sgroup:subtitle" -master_pl_name master.m3u8 -hls_list_size 0 720p.m3u8
master.m3u8 の出力例。
#EXTM3U #EXT-X-VERSION:3 #EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="subtitle",NAME="subtitle_0",DEFAULT=YES,URI="720p_vtt.m3u8" #EXT-X-STREAM-INF:BANDWIDTH=140800,RESOLUTION=1280x720,CODECS="avc1.64001f,mp4a.40.2",SUBTITLES="subtitle" 720p.m3u8
字幕原語をつける書き換え例。
#EXTM3U #EXT-X-VERSION:3 #EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="subtitle",NAME="Japanese",DEFAULT=YES,LANGUAGE="jp",URI="720p_vtt.m3u8" #EXT-X-STREAM-INF:BANDWIDTH=140800,RESOLUTION=1280x720,CODECS="avc1.64001f,mp4a.40.2",SUBTITLES="subtitle" 720p.m3u8
BANDWIDTHタグはビットレートの目安となり、DEFAULT, AUTOSELECT, FORCEDタグは字幕の表示設定に関わる。GROUP-IDタグで指定したものをSUBTITLESタグで指定することでそのストリームに字幕を載せることができる。
VTT字幕付きで再生するには hls.jsを使う。HLSを使って重い動画をWEBサイトに実装する – Qiitaを参考に、html ファイルを作成して、hls.loadSource 内のプレイリストを master.m3u8 に変更する。参照している(https://cdn.jsdelivr.net/npm/hls.js@latest)は Releases · video-dev/hls.jsの hls.min.js と同じである。
これで最初から字幕付きのHLSで再生できる。最初から字幕を非表示にするにはDEFAULT, AUTOSELECT, FORCEDを無指定にしておく。
映像と音声のプレイリストと字幕のプレイリストを出力する例。
ffmpeg -analyzeduration 10MB -probesize 10MB -fix_sub_duration -i input.ts -vf yadif,scale=1280:720 -c:v libx264 -c:a aac -c:s webvtt -map 0:v -map 0:a:0 -map 0:s -f hls -hls_list_size 0 720p.m3u8
vtt字幕付きのプレイリストは4.3.1時点で通常には読み込めないので入力オプションに-strict experimentalをつける。
コーデックコピーすると字幕はそのままvtt形式になりPCで見るならおそらく再生できる。
ffmpeg -strict experimental -i "https://example.com/master.m3u8" -c copy output.mkv
モバイル端末向けには字幕をmov_text形式に変更しMP4出力にする。
ffmpeg -strict experimental -i "https://example.com/master.m3u8" -c copy -c:s mov_text output.mp4
途中の字幕を映像と一緒にコピーするにはその時間までデコード(入力ファイルの後ろに-ss)してからコーデックコピーする。
ffmpeg -i input -c:v copy -c:a copy -c:s copy -ss 0:23:10.5 -to 0:24:40 output
字幕をファイルではなく映像に焼き付けるにはsubtitles
フィルタを使う。
字幕ファイルは別途ファイルとして入力しなければならない。
ffmpeg -i "https://example.com/master.m3u8" -vf subtitles=sub.vtt -c:a copy output.mp4
複数言語の音声に、言語に合わせたvtt字幕を別ファイルで読み込む場合。
ffmpeg -i sample.mp4 -i sample-vtt-en.vtt -i sample-vtt-es.vtt \ -map 0:v -map 0:a -map 0:a -map 1 -map 2 \ -c:v copy -c:a copy -c:s webvtt \ -metadata:s:s:0 language=en \ -metadata:s:s:1 language=es \ -start_number 0 -hls_time 10 -hls_list_size 0 -f hls \ -var_stream_map "v:0,name:video a:0,s:0,language:eng,name:english a:1,s:1,language:spa,name:espanol" \ -master_pl_name master.m3u8 \ out/sample.m3u8
fmp4 に変更する
上のコマンド例に-hls_segment_type 1を追加する。
ffmpeg -analyzeduration 10MB -probesize 10MB -fix_sub_duration -i input.ts -vf yadif,scale=1280:720 -c:v libx264 -c:a aac -c:s webvtt -map 0:v -map 0:a:0 -map 0:s -f hls -var_stream_map "v:0,a:0,s:0,sgroup:subtitle" -master_pl_name master.m3u8 -hls_list_size 0 -hls_segment_type 1 720p.m3u8
hevcにエンコードする。
ffmpeg -analyzeduration 10MB -probesize 10MB -fix_sub_duration -i input.ts -vf yadif,scale=1280:720 -c:v libx265 -tag:v hvc1 -c:a aac -c:s webvtt -map 0:v -map 0:a:0 -map 0:s -f hls -var_stream_map "v:0,a:0,s:0,sgroup:subtitle" -master_pl_name master.m3u8 -hls_list_size 0 -hls_segment_type 1 720p.m3u8