MediaLiveに打ち上げた映像からなるべく正確な時刻で動画クリップを切り出す
はじめに
清水です。AWS Elemental MediaLiveに打ち上げた映像から、指定した時刻で動画クリップを切り出すことを考えてみました。
なるべく正確に切り出しができるようタイムコードを利用する
MediaLiveに打ち上げた映像を保存したいと考えたとき、まず思いついたのがArchive output groupないしHLS output groupのVOD modeの利用です。前者はデフォルトで300秒ごとに1つのTSファイルが、後者はデフォルトで6秒ごとm3u8ファイルの更新と1つのTSファイルが出力されます。出力先には双方ともAmazon S3が指定できますね。
どちらの出力形式でも、MediaLiveをStartさせRunning状態になったあと、映像が打ち上げられはじめたタイミングで保存が開始されます。映像の打ち上げが終了(もしくは中断)した際は、Archive outputではMediaLiveのStopまで真っ黒な映像が保存され続けます。HLS outputのVOD modeでは設定により挙動が変わり、Input Loss ActionがデフォルトのEMIT_OUTPUT
の場合は真っ黒な映像の保存が続き、PAUSE_OUTPUT
の場合はその間は保存が停止します。
HLS outputのVOD modeでPAUSE_OUTPUT
を使い指定の時刻になったら映像の打ち上げを開始し、動画クリップの終了の段階で映像打ち上げも停止すれば特定の時刻の動画クリップが作成できそうです。ただし、映像を打ち上げる操作をしてから実際に映像の送信が開始され、MediaLive側で保存されはじめるまで若干ながらタイムラグが発生する可能性があります。(映像の打ち上げにOBS Studioを利用、ストリーミングの開始・停止を自動化して確認した際にも数秒のタイムラグが確認できました。)また個人的な経験則ですが、本番(今回であれば動画クリップ開始のタイミング)の数分〜数十分前には映像打ち上げを開始しておきたい、という考えがあります。これはライブ配信本番開始前に内々で映像を確認しておく、ということもありますが、映像の打ち上げ開始直後はストリーミングが安定しない、という印象に基づいたものです。(といっても10年前の経験則ベースです。ネットワークなど十分に安定していれば打ち上げ開始直後など気にしなくてもよいのかもしれません。)
ということで、映像の打ち上げ開始タイミングによらず指定した時刻で動画クリップを切り出す方法を考えてみます。指定した時刻、ということから思いついた方法がタイムコードの利用です。MediaLiveではデフォルトの入力ソースに含まれるタイムコードで出力タイムコードを初期化するEmbeddedモードのほか、MediaLive側のUTCシステム時刻で出力タイムコードを初期化するSystem Clock(UTC)モード、 00:00:00:00
で初期化するStart at 0(Zero-based)が選択できます。(About timecodes and timestamps - MediaLive)MediaLiveに映像を打ち上げる段階でタイムコードを付与し、このタイムコードをもとに動画クリップを作成すれば、時刻に対して正確な切り出しができそうです。
Streaming Softwareによってはタイムコードの付与が難しい場合もあるかと思いますが(例えばOBS Studioではタイムコード付与は難しい認識です)、そんな場合でもSystem ClockモードでMediaLive側のUTCシステム時刻をタイムコードとして付与すれば、ある程度は正確な切り出しができるかと考えます。
MediaLiveでタイムコードを付与したあとの切り出し、実際の動画クリップの作成はAWS Elemental MediaConvertを利用します。MediaConvertでは入力映像の一部を切り出す動画のClippingに対応しています。このClippingの際、タイムコードソースをEmbeddedにすることでタイムコードに則したClippingが行えます。(Specifying input files and input clips - MediaConvert)
この方法の確認のため、本ブログエントリでは以下の構成で確認を行いました。
MediaLiveへのIngest、Streaming SoftwareにはOBS Studioを利用しました。この段階ではタイムコードは付与されません。(以下のようにOBS Studioから送信する映像の左上に時刻を表示していますが、これはブラウザソースを使いJavaScriptでレンダリングしている時刻となります。)
MediaLive側でSystem Clockモードのタイムコードを出力に付与します。MediaLiveではArchive outputならびにHLS outputのVOD modeでS3に動画を出力します。この際、タイムコードの埋め込みのほか、動作確認をしやすくするようタイムコードの焼き付けも行いました。(AWS Elemental MediaLiveで映像へのタイムコードの焼き付けをサポートしました!🔥burn-in🔥 | DevelopersIO
出力された動画ファイルに対して、MediaConvertでタイムコードに則したClippingを行います。同時にMediaConvertでMP4形式に変換し、最終的な動画出力ファイルとしました。
MediaLiveからS3に出力された動画からタイムコードを基準にクリッピングをしてみた
MediaLiveに打ち上げた映像から指定した時刻での動画クリップ切り出しについて、方針と構成について確認できたところで、実際にリソースの作成ならびに動作検証を進めていきます。
MediaLiveリソースの作成
まずは打ち上げ先となるMediaLiveリソースを作成していきます。InputはRTMP (push)のシングル構成で作成しました。
続いて、このInputをアタッチしたChannelリソースを作成します。Channelはシングルパイプラインで、まずChannel template Live event HLS
を選択します。HLS output groupsとして4つのOutputが自動で作成されますが、このうち3つのOutputは後ほど削除します。
ひとまずGeneral settingsの項目に進み、Timecode Configurationの設定を行います。SourceをデフォルトのEMBEDDED
からSYSTEMCLOCK
に変更します。Additional settingsの項目は特に触れません。
Input attachmentsで先ほど作成したInputを指定し、Output gropusのChannel templateで作成したHD (HLS)
の設定に進みます。HLS group destinationには出力先としてS3を指定し、HLS SettingsのCDN SettingsをデフォルトのHLS webdav
からHLS basic put
に変更します。
そのまま画面を下にスクロールし、Manifest and Segmentsの項目のModeをデフォルトのLIVE
からVOD
に変更します。
続いてHLS outputの項目です、4つのうち_720p30
以外はRemove outputのバツ印で削除してしまいます。
残った_720p30
のSettingsに進み、Stream settingsのVideoの項目、Timecodeを展開します。Timecode InsertionでデフォルトのDISABLED
からPIC_TIMING_SEI
に変更して出力にタイムコードメタデータを含めるようにします。またTimecode Burn-in SettingsでデフォルトのDont't include
からTimecode burnin
に変更、Font Size LARGE_48
のPosition BOTTOM_CENTER
でタイムコードの焼き付けを設定します。
さらにOutput groupsでArchiveを追加、Archive group destinationとしてS3の宛先を指定します。
Name modifierも適切に設定したら、SettingsのリンクからOutputのSettingsに進みます。
Stream settingsではWidthを1280
、Heightを720
、Codec SettingsでH264
を選択します。さらにTimecodeの項目を展開し、HLSの設定と同様、Timecode InsertionでデフォルトのDISABLED
からPIC_TIMING_SEI
に変更して出力にタイムコードメタデータを含めるようにします。タイムコードの焼き付けについても、Timecode Burn-in SettingsでデフォルトのDont't include
からTimecode burnin
に変更、Font Size LARGE_48
のPosition BOTTOM_CENTER
で設定します。
以上でMediaLiveのリソース作成が完了です。ChannelをStartさせ、Running状態にしておきます。
OBS Studioの設定と映像の打ち上げ
続いてOBS Studioの設定、ならびに映像の打ち上げを行います。OBS Studioではソースとしてメディアソースを作成、ローカルに保存してあるBig Buck Bunnyの動画ファイルをループ再生しておきます。また確認用として左上に現在時刻を表示させました。以下ブログエントリと同様の設定で、小数点以下1桁までミリ秒表示となります。(フレーム番号ではありません。)
配信の設定として、サービスでカスタム…
を選択、サーバとストリームキーにMediaLiveのRTMP (push) InputのEndponit情報を設定しておきます。
出力設定などは基本的にOBS Studioのデフォルト値を利用します。一般の項目もデフォルト設定のままです。
プラグインAdvanced Scene Switcherを利用して18:54:30
から19:05:30
まで配信するよう設定します。設定手順は先ほどのOBS Studioの自動配信ブログを参照ください。
指定した時刻になり、MediaLiveに映像が送信されていることを確認します。OBS Studio側で配信が完了したらMediaLiveもStopしておきます。
MediaLiveで保存された映像の確認
MediaLiveへ打ち上げた映像をArchive outputならびにHLS output VOD modeで保存できました。この時点で保存された映像を確認しておきましょう
まずはArchive outputで保存した映像です。Rollover Intervalはデフォルト設定としていたので300秒=5分で1つのファイルが生成されます。合計3つのファイルができていました。
ファイルをローカルPCにダウンロード、macOSのクイックルックで映像を確認します。1つ目のarchive.000000.ts
のタイムコード09:55:06:26
のタイミングで、左上OBS Studio側の時刻が18:55:00.0
となっていました。今回はここを切り出しのIn点とします。
なお、OBS Studioの時刻とMediaLiveで付与するタイムコード、つまりMediaLiveのシステム時刻とはこの時点でおよそ7秒の差があることになりますね。今回はこのように検証用に焼き付けたタイムコードをもとにIn点Out点を決めています。詳細は後述しますが、実際にはこのように正確なズレがわかるわけではなく、この対応が必要になる認識です。
Out点はちょうど5分後とします。タイムコードを基準とすると10:00:06:25
となりますね。2つ目のアーカイブ出力ファイルarchive.000001.ts
を確認すると、焼き付けたタイムコードで10:00:06:25
が確認できます。OBS側の時刻も18:59:59.9
を示していますね。
MediaInfoのコマンドライン版で埋め込まれているタイムコードについても確認してみましょう。なお、MediaInfoの出力のAudioとMenuの項目は割愛しています。
まずは1つ目のarchive.000000.ts
、先頭のタイムコードが 09:54:37:22
となっていますね。
$ mediainfo archive.000000.ts
General
ID : 1 (0x1)
Complete name : archive.000000.ts
Format : MPEG-TS
File size : 209 MiB
Duration : 5 min 1 s
Overall bit rate mode : Constant
Overall bit rate : 5 798 kb/s
Frame rate : 30.000 FPS
Video
ID : 481 (0x1E1)
Menu ID : 1 (0x1)
Format : AVC
Format/Info : Advanced Video Codec
Format profile : Main@L3.1
Format settings : CABAC / 2 Ref Frames
Format settings, CABAC : Yes
Format settings, Reference frames : 2 frames
Format settings, Slice count : 2 slices per frame
Codec ID : 27
Duration : 5 min 0 s
Bit rate mode : Constant
Nominal bit rate : 5 000 kb/s
Maximum bit rate : 5 295 kb/s
Width : 1 280 pixels
Height : 720 pixels
Display aspect ratio : 16:9
Frame rate : 30.000 FPS
Color space : YUV
Chroma subsampling : 4:2:0
Bit depth : 8 bits
Scan type : Progressive
Bits/(Pixel*Frame) : 0.181
Time code of first frame : 09:54:37:22
Color range : Limited
Color primaries : BT.709
Transfer characteristics : BT.709
Matrix coefficients : BT.709
続いて2つ目のファイルarchive.000001.ts
です。こちらは先頭のタイムコードが09:59:37:22
となっていることが確認できます。
$ mediainfo archive.000001.ts
General
ID : 1 (0x1)
Complete name : archive.000001.ts
Format : MPEG-TS
File size : 208 MiB
Duration : 5 min 1 s
Overall bit rate mode : Constant
Overall bit rate : 5 798 kb/s
Frame rate : 30.000 FPS
Video
ID : 481 (0x1E1)
Menu ID : 1 (0x1)
Format : AVC
Format/Info : Advanced Video Codec
Format profile : Main@L3.1
Format settings : CABAC / 2 Ref Frames
Format settings, CABAC : Yes
Format settings, Reference frames : 2 frames
Format settings, GOP : M=3, N=90
Format settings, Slice count : 2 slices per frame
Codec ID : 27
Duration : 5 min 0 s
Bit rate mode : Constant
Nominal bit rate : 5 000 kb/s
Maximum bit rate : 5 295 kb/s
Width : 1 280 pixels
Height : 720 pixels
Display aspect ratio : 16:9
Frame rate : 30.000 FPS
Color space : YUV
Chroma subsampling : 4:2:0
Bit depth : 8 bits
Scan type : Progressive
Bits/(Pixel*Frame) : 0.181
Time code of first frame : 09:59:37:22
Color range : Limited
Color primaries : BT.709
Transfer characteristics : BT.709
Matrix coefficients : BT.709
HLS outputのVOD modeで保存した映像についても確認してみます。6秒ごとにセグメントファイルが出力されており、その数は合計122個となりました。
HLSで保存した映像はS3バケットを公開状態にして、macOSのSafariブラウザから再生してみました。hls.m3u8にアクセスします、きれいにシークできなかったのですが、In点Out点として指定するタイムコード09:55:06:26
ならびに10:00:06:25
が含まれたHLSアセットであるこが確認できます。
HLSセグメントファイルについてもMediaInfoで埋め込まれたタイムコードを確認してみましょう。例として、1つ目のhls_720p30_00001.ts
と20番目のhls_720p30_00020.ts
を確認してみました。きちんとセグメントファイルにタイムコードが埋め込まれていることがわかりますね。
$ mediainfo hls_720p30_00001.ts
General
ID : 1 (0x1)
Complete name : hls_720p30_00001.ts
Format : MPEG-TS
File size : 2.52 MiB
Duration : 6 s 513 ms
Overall bit rate mode : Variable
Overall bit rate : 3 245 kb/s
Frame rate : 30.000 FPS
Video
ID : 481 (0x1E1)
Menu ID : 1 (0x1)
Format : AVC
Format/Info : Advanced Video Codec
Format profile : High@L3.1
Format settings : CABAC / 4 Ref Frames
Format settings, CABAC : Yes
Format settings, Reference frames : 4 frames
Codec ID : 27
Duration : 6 s 0 ms
Bit rate mode : Constant
Nominal bit rate : 3 000 kb/s
Maximum bit rate : 3 195 kb/s
Width : 1 280 pixels
Height : 720 pixels
Display aspect ratio : 16:9
Frame rate : 30.000 FPS
Color space : YUV
Chroma subsampling : 4:2:0
Bit depth : 8 bits
Scan type : Progressive
Bits/(Pixel*Frame) : 0.109
Time code of first frame : 09:54:37:22
Color range : Limited
Color primaries : BT.709
Transfer characteristics : BT.709
Matrix coefficients : BT.709
$ mediainfo hls_720p30_00020.ts
General
ID : 1 (0x1)
Complete name : hls_720p30_00020.ts
Format : MPEG-TS
File size : 2.52 MiB
Duration : 6 s 499 ms
Overall bit rate mode : Variable
Overall bit rate : 3 257 kb/s
Frame rate : 30.000 FPS
Video
ID : 481 (0x1E1)
Menu ID : 1 (0x1)
Format : AVC
Format/Info : Advanced Video Codec
Format profile : High@L3.1
Format settings : CABAC / 4 Ref Frames
Format settings, CABAC : Yes
Format settings, Reference frames : 4 frames
Codec ID : 27
Duration : 6 s 0 ms
Bit rate mode : Constant
Nominal bit rate : 3 000 kb/s
Maximum bit rate : 3 195 kb/s
Width : 1 280 pixels
Height : 720 pixels
Display aspect ratio : 16:9
Frame rate : 30.000 FPS
Color space : YUV
Chroma subsampling : 4:2:0
Bit depth : 8 bits
Scan type : Progressive
Bits/(Pixel*Frame) : 0.109
Time code of first frame : 09:56:31:22
Color range : Limited
Color primaries : BT.709
Transfer characteristics : BT.709
Matrix coefficients : BT.709
MediaConvertでタイムコードをもとに動画クリップを切り出し
MediaLiveへ打ち上げS3に保存されたアーカイブならびにHLSアセットの動画にタイムコードが付与されていることが確認できました。このタイムコードを利用して、MediaConvertでClippingして最終的なMP4動画ファイルを作成していきます。
まずはアーカイブ出力を利用するパターンの確認です。
MediaConvertのマネジメントコンソール、(Create job)で進んでAWS integrationのSerice role設定を先にすませておきます。Inputの項目で2つのInputを準備、Input 1から順にアーカイブファイルarchive.000000.ts
、archive.000001.ts
を指定していきます。
また、Video selector > Video correctionのTimecode sourceをデフォルトのStart at 0
からEmbedded
に変更します。2つのInput双方で設定を忘れずに行いましょう。(なお、このTimecode sourceをデフォルトのStart at 0
のままとしてしまうと、Demuxer unable to seek to clipping start timecode [09:55:00:00]
といったError messageと遭遇してしまうことになります。)
Input 1、つまりアーカイブファイルarchive.000000.ts
でInput clipsのStart timecodeを09:55:06:26
に設定します。
同様にInput 2、アーカイブファイルarchive.000001.ts
でInput clipsのEnd timecodeを10:00:06:25
に設定します。
Output groupsではFile groupを選択、Destinationを設定します。
Output settingsでExtensionをmp4
に設定、Encoding settingsのVideoのMax bitrate (bits/s)を2500000
(2.5Mbps)と設定しました。そのほかの項目はデフォルトとします。
これで(Create Job)、MediaConvertの変換が完了したらS3に出力されているMP4ファイルをダウンロードして確認してみましょう。
切り出したMP4ファイルの先頭で、OBS Studio側の時刻が18:55:00.0
、焼き付けたタイムコードが09:55:06:26
となっています。また末尾はOBS Studio側の時刻が18:59:59.9
、焼き付けたタイムコードが10:00:06:25
のフレームでした。MediaLiveで付与したタイムコードで、OBS Studio側の時刻に対して正確な切り出しができていることが確認できますね。
続いて、HLS出力を利用するパターンでも確認しておきます。MediaConvertのJobをアーカイブ出力のパターンのときと同様に作成していきます。Inputは1つのみで、HLSアセットのトップレベルマニフェストファイルhls.m3u8
を指定します。またVideo selectorのVideo correction、Timecode sourceの設定をEmbedded
に設定します。
Input clipsの項目で、Start timecodeならびにEnd timecodeを設定します。アーカイブ出力と同様にStart timecodeを09:55:06:26
、End timecodeを10:00:06:25
に設定しました。
Output settingsについてはDestinationのS3のパスのみ変更、ほかはアーカイブ出力のJobと同様にしました。
MediaConvertの変換が完了したら、こちらもMP4ファイルをダウンロードして中身を確認してみます。アーカイブ出力のときと同様、OBS Studio側の時刻に対して正確に切り出しができていることが確認できますね。(In/Outを同一に設定してしまったので映像的には同じ絵となりますが、左上ファイル名が異なっている点にご注目ください。)
まとめ
MediaLiveで付与したタイムコードをもとにMediaConvertでクリッピングを行うことで、時刻に対してなるべく正確な切り出しができることが確認できました。
今回の検証では、OBS Studio側の時刻とMediaLive側の時刻の差はおよそ7秒で、この調整を動作検証用にMediaLiveで焼き付けたタイムコードなどをもとに行いました。本番の切り出しを行う際には、このような正確なズレは計測できない認識です。この時刻の差のおおよその平均をあらかじめ確認しておき、またクリップの前後にバッファを持たせて切り出しを行うかたちになるかと思います。またMediaLiveにIngestする前の段階(Streaminig Software、エンコーダ側)でタイムコードを埋め込むことができれば、これをもとにしたより正確な切り出しもできそうです。機会があれば試してみたいと思います。
(なお、OBS Studio側の時刻とMediaLive側の時刻の差ですが、今回の検証では7秒とわりと大きい印象でした。再度MediaLiveとOBS Studioの配信を開始しなおして確認してみたところ、2,3秒になることが多かったです。さらに、今回の検証でMediaLiveに保存した映像ですが、焼き付けたタイムコード10:03:00
以降ぐらいではやはり2,3秒のズレとなっていました。今回OBS Studio側で表示した時刻はブラウザJavaScriptベースのものだったのですが、PCでのほか作業などに影響され、ここで一時的にでも遅延などで正確な時刻が表示できなくなっていた、ということなどを疑っています。こちらについても機会があれば、検証し直してみたいと思います。)