ffmpeg で Apple HTTP Live Streaming(HLS)を扱う


ffmpeg で Apple HTTP Live Streaming(通称、HLS)形式に出力する方法。各セグメントの動画ファイルは .ts でプレイリストとなるマニフェストは .m3u8 で出力される。また segment muxer のオプションを使うことでより詳細な設定ができる。

詳細な分割設定ができる Segment

HTTP Live Streaming (HLS) – Apple Developer
(PDF) Apple の HTTPライブストリーミングの概要(日本語)
HLS の公式ドキュメント:draft-pantos-http-live-streaming – HTTP Live Streaming

基本コマンド

ffmpeg -i input output.m3u8

.mp4 を HLS 形式にコーデックコピーする例
ffmpeg -i input.mp4 -bsf:v h264_mp4toannexb -c copy output.m3u8

.mp4 から暗号化とセグメントの時間指定(60秒)をする例(file.keyinfo は後述)
ffmpeg -i input.mp4 -c:v libx264 -c:a aac -hls_key_info_file file.keyinfo -hls_list_size 0 -hls_time 60 output.m3u8

一般的な配信用の HLS 出力コマンド例
ffmpeg -i input -vcodec libx264 -acodec aac -flags +loop-global_header -bsf:v h264_mp4toannexb -f segment -segment_format mpegts -segment_time 10 -segment_list output.m3u8 output_%04d.ts

セグメントを出力して連結した動画も出力するコマンド例は4通りある

Creating multiple outputs – trac.ffmpeg.org

  1. セグメントと連結した動画の2種類エンコードする。つまり負荷も2倍
    ffmpeg -i input -vcodec libx264 -acodec aac -flags +loop-global_header -bsf:v h264_mp4toannexb -f segment -segment_format mpegts -segment_time 10 -segment_list output.m3u8 output_%04d.ts -vcodec libx264 -acodec aac -flags +loop-global_header -bsf:v h264_mp4toannexb output.ts
  2. 上の2種類エンコードせずに、udp などにエンコードした映像を流して再度 ffmpeg で -c copy で取り込みセグメントと連結した動画の2種類を出力する
    ffmpeg -re -i input -vcodec libx264 -acodec aac -flags +loop-global_header -bsf:v h264_mp4toannexb -f mpegts "udp://localhost:8080"
    ffmpeg -i "udp://localhost:8080" -c copy -f segment -segment_format mpegts -segment_time 10 -segment_list output.m3u8 -c copy output_%04d.ts -c copy output.ts -y
  3. すべてのセグメントを書き込むように設定し、ffmpeg でマニフェストを読み込み -c copy で連結する
    ffmpeg -i input -vcodec libx264 -acodec aac -flags +loop-global_header -bsf:v h264_mp4toannexb -f segment -hls_list_size 0 -segment_format mpegts -segment_time 10 -segment_list output.m3u8 output_%04d.ts
    ffmpeg -i "output.m3u8" -c copy output.ts
  4. tee muxer を使って1度のエンコードで2出力する
    ffmpeg -i input -vcodec libx264 -acodec aac -flags +loop-global_header -bsf:v h264_mp4toannexb -f segment -hls_list_size 0 -segment_format mpegts -segment_time 10 -segment_list output.m3u8 -f tee -map 0:v -map 0:a "[f=hls]output.m3u8|output.ts"

公式ドキュメント:FFmpeg Formats Documentation : hls

オプション

ヘルプコマンド ffmpeg -h muxer=hls

  • start_number [int64]
    セグメントの開始番号。開始番号を変更するのであり、映像の開始をずらすのではない
    範囲:0 から I64_MAX まで
    既定値:0
  • hls_time [float]
    各セグメントファイルの動画時間。指定した時間が来たら次のキーフレームで分割される
    範囲:0 から FLT_MAX まで
    既定値:2
  • hls_init_time[float]
    最初のセグメントファイルの動画時間。0 だと最初のキーフレームが来たら分割する。挙動は hls_time と同じ
    既定値:0
  • hls_list_size [int]
    マニフェストに記載されるセグメント数。0 はすべて
    範囲:0 から INT_MAX まで
    既定値:5
  • hls_ts_options [string]
  • hls_vtt_options [string]
  • hls_wrap [int]
    セグメント数の上限を指定する。上限に達すると最初のセグメントから上書きするので容量の削減になる。しかし 3.3(予定) 以降から 非推奨になり代わりに hls_list_size(マニフェストに表示されるセグメント数), hls_flags delete_segments を併用する
    範囲:0 から INT_MAX まで
    既定値:0
  • hls_allow_cache [int]
    キャッシュを許可するかどうかを明示的に指定する
    1 は許可するかもしれない、0 は許可してはならない
    範囲:-1, 0, 1
    既定値:-1
  • hls_base_url [string]
    各セグメントに URL をつける。各セグメントに絶対パスを指定するときに使う
    既定値:なし
  • hls_segment_filename [string]
    hls_flags single_file を使っていないときに、各セグメントのファイル名を指定する。マニフェスト出力の前に指定する。指定しなければマニフェストファイル名に連番が振られる。Windows 環境では drawtext の時と同じように %s が使えず、組み合わせによってもエラーになる
    Windows の ffmpeg で生放送する方法 : drawtext(テキスト描写)
    例:file%03d.ts(file000.ts, file001.ts, file002.ts, …)
    既定値:なし
  • hls_segment_size [int]
    セグメント1つのバイト単位のファイルサイズ制限
    範囲:0 から INT_MAX まで
    既定値:0(無制限)
  • hls_key_info_file [string]
    セグメントの暗号化で使うファイルを指定する。key には 16バイトのバイナリを、IV には 16進数の文字列を指定する。書式は後述
    既定値:なし
  • hls_subtitle_path [string]
    字幕ファイルのパス指定
    既定値:なし
  • hls_flags[flags]
    • single_file
      一時ファイル名で出力して処理が終わったらファイル名を変える
    • temp_file
      1つだけのセグメントで出力
    • delete_segments
      マニフェストに記載されていないセグメントを順番に削除していく。hls_list_size 0 を併用すると効果が無い
    • round_durations
      マニフェストに記載されている1秒未満の時間を四捨五入する
    • discont_start
      マニフェストに #EXT-X-DISCONTINUITY を最初につける。セグメントが不連続してるフラグ。配信が止まったとき仕切り直すときにつける
    • omit_endlist
      マニフェストの末端に追記される #EXT-X-ENDLIST を省略する
    • split_by_time
      時間指定で分割するのでキーフレーム以外で分割されることもある。特定のプレイヤーで挙動がよくなるかもしれないが一般的にはよくならない。hls_time と併用する
    • append_list
      マニフェストの末端に記載されている #EXT-X-ENDLISTを削除し、新しいセグメントを追記し再び最後に #EXT-X-ENDLIST を追加する
    • program_date_time
      #EXT-X-PROGRAM-DATE-TIME タグを追加する
    • second_level_segment_index
      use_localtime を使ったときにセグメントのファイル名にインデックスを含める
    • second_level_segment_duration
      use_localtime を使ったときにセグメントのファイル名に動画時間を含める
    • second_level_segment_size
      use_localtime を使ったときにセグメントのファイル名にファイルサイズを含める
  • use_localtime[boolean]
    セグメントのファイル名に strftime を割り当てる。hls_segment_filenameuse_localtime_mkdir で使う
    例:-use_localtime 1 -hls_segment_filename %Y%m%d.ts(20160420.ts)
    既定値:0
  • use_localtime_mkdir[boolean]
    セグメントの末端のディレクトリ指定に strftime を割り当てる。hls_segment_filename を併用する。ディレクトリがなければつくる
    例:-use_localtime 1 -use_localtime_mkdir 1 -hls_segment_filename “%Y%m%d/%Y%m%d.ts”(20160420/20160420.ts)
    既定値:0
  • hls_playlist_type[int]
    • event
      マニフェストに #EXT-X-PLAYLIST-TYPE:EVENT をつけ、hls_list_size 0 も強制される
    • vod
      マニフェストに #EXT-X-PLAYLIST-TYPE:VOD をつけ、hls_list_size 0 も強制される
  • method[string]
    指定した HTTP メソッドでセグメントファイルを作る。これを使うには HTTP サーバがそのメソッドに対応していなければならない
    例:HTTP PUT メソッドでセグメントファイルをアップロードし、refresh 時間毎に m3u8 ファイルが同じメソッドで更新される
    既定値:PUT
    ffmpeg -re -i in.ts -f hls -method PUT http://example.com/live/out.m3u8

  • hls_start_number_source [int] 各セグメントのファイル名の様式
    • 0, generic:各セグメントのファイル名に連番が付く。既定値
    • 1, epoch:各セグメントのファイル名に unix time が付く
    • 2, datetime:各セグメントのファイル名に年月日と時間が付く

hls_key_info_file の書式

書式

key URI
key file path
IV (optional)

http://server/file.key
/path/to/file.key
0123456789ABCDEF0123456789ABCDEF

file.key を openssl で作って暗号化するシェルスクリプト

#!/bin/sh
BASE_URL=${1:-'.'}
openssl rand 16 > file.key
echo $BASE_URL/file.key > file.keyinfo
echo file.key >> file.keyinfo
echo $(openssl rand -hex 16) >> file.keyinfo
ffmpeg -f lavfi -i testsrc2 -t 10 -c:v libx264 -hls_key_info_file file.keyinfo output.m3u8

上のシェルスクリプトで作られる file.keyinfo の例

./file.key
file.key
50d6dc6e65d9aa0f810a3f699950c8a0

openssl で復号する例
K の指定値は file.key をバイナリエディタで読むことが出来る
openssl aes-128-cbc -d -in output0.ts -out output.ts -K A4856CAC48F1E48D16688FEDE9925265 -iv 50d6dc6e65d9aa0f810a3f699950c8a0

ffmpeg で復号する例
ffmpeg -i output.m3u8 -c copy output.ts

output.m3u8 の中身

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:10
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-KEY:METHOD=AES-128,URI="./file.key",IV=0x50d6dc6e65d9aa0f810a3f699950c8a0
#EXTINF:10.000000,
output0.ts
#EXT-X-ENDLIST

追記
オプションが追加されていたので追加した。2016年7月30日
オプションが追加されていたので追加し文章を直した。2016年9月6日
オプションが追加されていたので追加した。2016年9月11日
オプションが追加されていたので追加し順番を直した。2017年2月12日
セグメントを出力して連結した動画も出力するコマンド例。2017年3月26日
hls_key_info_file の書式をわかりやすく書き直した。2017年4月17日

ffmpeg で Apple HTTP Live Streaming(HLS)を扱う」への1件のフィードバック

コメントを残す

メールアドレスが公開されることはありません。

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)