動画のストリーミング配信について、しばらく書いて行きます。
初回はシンプルに基本の流れである、変換→CDNで配信→Playerで再生する所までです。
今回、トランスコーダ(変換)は AWS Elemental MediaConvert、オリジン(コンテンツの置き場所)は Amazon S3、CDNは Amazon CloudFront を使用します。
トランスコーダ(変換)
ハードウェアとソフトウェアがあり、フリーだとFFmpegが有名ですね。
ハードウェアは高額(数百〜数千万円)ですが、ElementalがAWSに買収され、クラウド化されたので、使用時間に応じた課金体系で提供されるようになりました。
高額な分、やはり画質はすごく良いです。同じビットレートでも綺麗に再生できます。
また、ソフトウェアも動かすサーバーが必要になるので、その費用を最適化しないと逆にコスト高になります(ローカルで変換してアップロード出来る場合を除く)
ASPサービスと契約する方法もありますが、画質は各社まちまちなので、使用する素材で試した方が良いです。
ビットレート上げれば綺麗になりますが、その分、CDNの費用も上がります。
配信プロトコル
主流はHLSとMPEG-DASH(以降、DASHと記載)で、DRM使わないならHLSだけでも良さそうですが、iOS10以降で、HLS fMP4がサポートされている事と、
MediaConvertがCMAFに対応していて、HLSとDASHの両方を作成でき、
メディアファイルを共有できる(ファイル容量があまり増えない)ので、
今すぐDASHを使わなくても、作成しておいて損はないと思います。
S3とCloudFrontを作成
MediaConvertではS3に素材ファイルを置いて、S3に出力する流れになります。
出力するS3はオリジン(コンテンツの置き場所)にして、CloudFrontで配信、
素材ファイルにはアクセスさせたくないので、別々のバケットを作成します。
パスで分けるという方法もありますが、分かりやすいように。
素材用S3
素材用はデフォルトで作成すればOK
TODO: ライフサイクルルールで一定期間経過したらGlacierに移して、コストを下げたい。
→ s3のライフサイクルルールを設定してみる – Qiita
オリジン用S3とCloudFront
オリジンのS3とCloudFrontは下記を参照してください。
CloudFront(S3オリジン)構築とawsコマンド(S3, CloudFront)メモ
但し、レスポンスヘッダーポリシーでCORSの設定しないと別のドメインからは弾かれます。
TODO: これだとどこかでも許可されるので、ドメインで絞るか署名付きCookieで制限したい。
MediaConvert
素材用S3に素材を置いてから、MediaConvertのジョブを作ります。
TODO: S3設置トリガーで自動で変換したい
→ S3設置トリガーで自動変換と、MediaConvertでCMAFを暗号化(未解決)してみる
今回はテストによく使われるこれをダウンロードしてS3に上げました。
Big Buck Bunny » Download
https://ap-northeast-1.console.aws.amazon.com/mediaconvert/home?region=ap-northeast-1#/jobs/create
入力
出力グループの追加
CMAFグループの設定
送信先
存在しないパスを指定すると作成される。
他のコンテンツと混じらないようにパスを分けておくと良さそう。
出力されるファイル名は入力のファイル名がベースになる。
セグメントの制御
「セグメント化されたファイル」(セグメントの長さ毎に複数のファイルを作成)を選択。
「単一ファイル」(videoとaudioで1ファイルずつ)だと、HLSはChrome/Safari(Mac)とも再生できず、DASHはSafari(Mac)で再生できなくなる(ChromeはOK)。
fMP4には対応しているけど、HLSはファイル毎にリクエストするからかな。
TODO: リアルタイムログかログを使って、人やセッション別に集計したい
→ CloudFrontのリアルタイムログを試す
H.264 出力設定
名前修飾子
「_video」と入力。何でも良いけど設定しないと、HLSはChrome/Safari(Mac)とも再生できず、DASHはChrome(Mac)で再生できなくなる(SafariはOK)。
親と子のm3u8やmpdのファイル名が被ってしまう為かと。
> Big Buck Bunny_video.m3u8
アンダーバーとか入れた方がファイル名はきれい。
解像度
未指定の場合、元の解像度のままになる。解像度を揃えたい場合は指定。
レート制御モード
今回はQVBRを指定。ビットレートを上げずに品質を上げたい場合は「品質チューニングレベル」や「QVBR品質レベル」を変えると良さそう。(変換コストは上がりそうですが)
QVBR レート制御モードの使用 – MediaConvert
TODO: ABR(画質切り替え)とAES(暗号化)も試したい
→ MediaConvertでABR(アダプティブ・ビットレート)を試してみる
→ MediaConvertでHLSをAESで暗号化してみる
AAC 出力設定
名前修飾子
「_audio」と入力。videoと同様に何か設定。
AWS統合
こちらは初回のみ
対象追加はIAMでするか、入出力の組み合わせでロールを作る。
変換待ち
変換中
3秒ほどで開始、
完了率は59のまま変わらなかった。
変換完了
10分弱のコンテンツで、1分半程度(まあまあ早い)
元動画のサイズにも依存すると思う。
再生してみる
S3に出力されたm3u8とmpd(_videoや_audioが付いてないやつ)をCloudFrontのURLに読み替えて使用。
今回は下記(しばらく残しておきます) https://cdn.nightonly.com/Big%20Buck%20Bunny/Big%20Buck%20Bunny.m3u8 https://cdn.nightonly.com/Big%20Buck%20Bunny/Big%20Buck%20Bunny.mpd 単一ファイル -> HLS/DASH:Safari(Mac) NG、Chrome(Mac) OK https://cdn.nightonly.com/Big%20Buck%20Bunny_%E5%8D%98%E4%B8%80%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB/Big%20Buck%20Bunny.m3u8 https://cdn.nightonly.com/Big%20Buck%20Bunny_%E5%8D%98%E4%B8%80%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB/Big%20Buck%20Bunny.mpd 名前修飾子なし -> HLS:Safari/Chrome(Mac) NG、DASH:Safari/Chrome(Mac) OK https://cdn.nightonly.com/Big%20Buck%20Bunny_%E5%90%8D%E5%89%8D%E4%BF%AE%E9%A3%BE%E5%AD%90%E3%81%AA%E3%81%97/Big%20Buck%20Bunny.m3u8 https://cdn.nightonly.com/Big%20Buck%20Bunny_%E5%90%8D%E5%89%8D%E4%BF%AE%E9%A3%BE%E5%AD%90%E3%81%AA%E3%81%97/Big%20Buck%20Bunny.mpd
下記に上記のURLを入れれば再生できます。
hls.js demo
https://hls-js.netlify.app/demo/
Dash JavaScript Player
https://reference.dashif.org/dash.js/v4.3.0/samples/dash-if-reference-player/index.html
HTMLに埋め込んでみる
hls.js
こちらを参考に実装
「Alternative setup」の方はChrome(Android)で再生できませんでした。
GitHub – video-dev/hls.js: HLS.js is a JavaScript library that plays HLS in browsers with support for MSE.
再生ボタン等が出ないので、videoタグにcontrolsを追加
<html> <head> <script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script> </head> <body> <video id="video" controls></video> <script> var video = document.getElementById('video'); var videoSrc = 'https://cdn.nightonly.com/Big%20Buck%20Bunny/Big%20Buck%20Bunny.m3u8'; if (Hls.isSupported()) { var hls = new Hls(); hls.loadSource(videoSrc); hls.attachMedia(video); } else if (video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoSrc; } </script> </body>
Safari(Mac)だとローカルファイルで再生できなかったので、CloudFrontに設置。
https://cdn.nightonly.com/player/hls.html
dash.js
jsは下記CDNのを使用。実際は自分のサーバーに置いた方が良いですがテストなので。
dashjs – Libraries – cdnjs – The #1 free and open source CDN built to make life easier for developers
<html> <head> <script src="https://cdnjs.cloudflare.com/ajax/libs/dashjs/4.3.0/dash.all.min.js"></script> </head> <body> <video id="videoPlayer" controls></video> <script> (function(){ var url = "https://cdn.nightonly.com/Big%20Buck%20Bunny/Big%20Buck%20Bunny.mpd"; var player = dashjs.MediaPlayer().create(); player.initialize(document.querySelector("#videoPlayer"), url, true); })(); </script> </body>
こちらもSafari(Mac)だとローカルファイルで再生できず。
https://cdn.nightonly.com/player/dash.html
検証結果
動画では、全ての環境で再生できるとは限らないので、実端末で検証するのが大事。
メモリが少ないやつでVBR使うと不安定になったりするのでCBR使ったり、ビットレートを落としたりと品質維持するのが大変でした。
今はリソースが多い端末が増えたり、標準化も進んでいるので、全端末検証とかしなくても良さそうですが。
OS | ブラウザ | 結果 |
---|---|---|
macOS Big Sur | Safari 14.1.1 Chrome 99.0 Firefox 98.0 |
HLS/DASH共にOK |
Windows 10 | Edge 99.0 Chrome 100.0 |
HLS/DASH共にOK |
iOS 14.6 | Safari Chrome Firefox Daylight 98.2 |
HLSはOK、DASHはNG |
Android 10 | Chrome 100.0 Firefox Daylight 98.3 |
HLS/DASH共にOK |
“MediaConvertで変換して、ストリーミング配信を試してみる” に対して3件のコメントがあります。