AWS Elemental MediaLive から MP4 でアーカイブ出力したい
急速に拡大する動画配信
いよいよ来週から MLB が開幕しますね!🧢 ここ数年で動画配信サービスの規模はどんどん拡大し、スポーツ中継も場所・時間を問わず視聴できるようになりました。実は DX・メディアデザイン局でも バーチャル高校野球 という高校野球を中心に LIVE・VOD 配信しているサービスの配信技術に携わっています。2023 年の第 105 回全国高等学校野球選手権大会からは地方大会および全国大会の全試合を LIVE 配信しており、その試合数は 3,500 程度になっています。短期間で多くの試合を配信するので、同時にたくさんの試合を配信しなければいけません。また、LIVE 配信した後に VOD として配信するコンテンツも増え、LIVE 配信機会の増加に伴ってトランスコーダにアーカイブ設定を追加し、出力したファイルを MP4 形式で保管する機会も多くなりました。
AWS Elemental MediaLive のアーカイブ設定
同時配信数が多くなると、どうしてもオンプレミスでは捌ききれないため、クラウドサービスを使用することになります。AWS Elemental MediaLive はもはや LIVE 配信をするうえでなくてはならないサービスです。しかし、現時点 (2025/03) では AWS Elemental MediaLive をトランスコーダとして使用した場合、アーカイブ出力するファイル形式に MP4 を指定することができません。ですので、いったん TS 形式で出力し簡易編集後に MP4 形式で書き出したりと、何らかの方法でコンバートすることになります。AWS Elemental MediaConvert を使用すれば、MP4 への自動変換は容易なのですが、数が多くなると利用料が嵩むのが難点です。
そこで、安価に MP4 形式でアーカイブを作成できないものか検討 & 実験してみましたので、2 回に分けて実験結果を記録していきます。
成果物
早速作ったモノから紹介します。
当初何を考えていたかというと、
-
MediaConvert を使いたいけど高額… 💸
-
代わりにコンテナ立ち上げて ffmpeg を使えばいいのでは?
ということで、MediaLive から S3 への TS 出力をトリガに Lambda で ECS を起動して ffmpeg を走らせようとしました。しかしふと 「MediaLive のアーカイブ出力分も節約できるのでは?🤔」 と思い、MediaLive の起動をトリガに m3u8 を ffmpeg で収録する設計に変更しました。
それぞれのサービスの役割と設計ポイントを紹介します。
MediaLive
言わずもがな、動画配信で必要なトランスコードをしています。HLS 出力してくれます。
EventBridge
EventBridge は MediaLive が RUNNING 状態になったことをトリがに Lambda を起動させる役割をしています。
イベントパターンは下記のようになります。
{ "account": ["{AWS_ACCOUNT_ID}"], "detail": { "state": ["RUNNING"] }, "detail-type": ["MediaLive Channel State Change"], "source": ["aws.medialive"] }
Lambda
EventBridge から呼び出されて、ECS を起動させます。S3 で MediaLive の ID と出力される m3u8 の対応を管理しているので、S3 からそのデータを読み込んで MediaLive の ID に対応する m3u8 の URL を ECS 起動時に環境変数として渡しています。ECS はエントリプロセス完了後に勝手に停止してくれるので、何も考えずに MediaLive 起動の度に ECS タスクを起動してあげるだけで OK です。
ECR / ECS
ffmpeg を用いて Lambda から渡された m3u8 を MP4 形式で収録し、S3 へ出力しています。アーカイブの重要度次第では、Fargate Spot でも十分かもしれません。細かい点ですが、ECS が起動してすぐの状態だと m3u8 がまだ生成されていないということもあるので、起動してから n 分間は m3u8 が見つかるまで ffmpeg をリトライし続けるという処理としていました。しかしあまりにリトライ時間を長くとってしまうと ECS 費用がもったいないことになります。
ECR については ECS で使用するイメージを保存しているのみですので、特筆事項はありません。特に変わったオプションも必要ない ffmpeg を動かすだけなのでイメージサイズも大きくならないですし、古いイメージを残し続けないようするくらいでしょうか。基本ですね。
VPC
Public subnet を選択しました。はじめのうちは Private subnet で構築していましたが、Private subnet の場合は NAT Gateway を使用せざるを得ず、ずっと m3u8 を収録し続けているとこの料金が高額になってしまいます。どうせ公開範囲を限定せずに配信している動画ですし、ECS 上にはシークレット情報を取り扱うこともないため Public subnet で十分と判断しています。
CloudWatch
なんでもかんでもログ出力してしまうと、案外無視できない料金になってしまうので注意が必要ですが、デバッグ用になくてはならないので必要な分は出力するようにしています。ffmpeg の出力なんかは特に出力が多くなってしまいますので、忘れずに -loglevel error
オプションをつけてあげましょう。
その他
ここまでが根幹となっている部分です。根幹以外の部分は必要に応じて…という感じですが、あったらいいかなと思い構築してみたものを一応紹介させていただきます。
まず、ECS が万が一予期せずダウンした時に備えて EventBridge + SNS + Chatbot で Slack 通知し、すぐに気づける体制としました。ダウンした ECS で収録していた m3u8 を配信している MediaLive の ID を入力して、Lambda を手動実行すればすぐに収録再開できます。
そして、念には念をの「ECS がなぜか停止していませんでした 😇」対策ということで、EventBridge Scheduler を用いて、 毎日定時にLambda から起動中の ECS を全て停止させる 仕組みも加えています。夜間通したテスト配信を知らず知らずに収録するのももったいないですよね。当たり前ですが毎日決まった時間には配信が終わっているはずという運用でしか使用できません。
おわりに
実験的に昨夏の高校野球の一部期間で稼働させてみたところ、同時に 100 を超える配信が行われている日でもほぼ落ちることなく MP4 を出力できていました。
とはいえ、短い期間でも 100% 稼働ではなかったり、MediaLive は起動し続けているが一時的に Input がなくなって m3u8 が生成されなくなってしまうような場合も考えられるので、当初考えていた MediaLive からは TS 形式で出力しておいてそれを ffmpeg でコンバートする方法か、はじめから MediaConvert を使用してしまうのが確実ですね。ですので「アーカイブがあったらいいな」「トラブル時の確認として使用するかも」くらいの費用を抑えたいシーンでのみ使うことになりそうです。気になる費用については次回の記事で記載させていただきます。