動画のストリーミング配信について、しばらく書いて行きます。
初回はシンプルに基本の流れである、変換→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

こちらを参考に実装
GitHub – Dash-Industry-Forum/dash.js: A reference client implementation for the playback of MPEG DASH via Javascript and compliant browsers.

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件のコメントがあります。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です