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

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

MPEG-DASH は以下より
ffmpeg で MPEG-DASH を扱う

マニフェスト作成の参考になる::HTTP Live Streaming Examples – Apple Developer
HTTP Live Streaming(HLS)- Apple Developer
(PDF)Apple の HTTPライブストリーミングの概要(日本語): web.archive.org
HLS のドキュメントを簡潔にしたもの:General Authoring Requirements
HLS の公式ドキュメント:HTTP Live Streaming
HLS 2nd Edition の草案ドキュメント:HTTP Live Streaming 2nd Edition

基本コマンド

動画ファイルからライブ配信する場合には -re をつけて、VOD 配信には -re はつけない。.mp4 ファイルから .ts ファイルで出力するときには -bsf:v h264_mp4toannexb をつける。

ffmpeg -i input -f hls output.m3u8

.mp4 を HLS 形式にコーデックコピーする例。(-bsf:v h264_mp4toannexb を付けないとエラーで処理が止まっていたが止まらなくなった)詳しくはここ-hls_list_size 0 ですべてのセグメントをマニフェストに書き込む。
ffmpeg -i input.mp4 -bsf:v h264_mp4toannexb -c copy -f hls -hls_list_size 0 output.m3u8
ffmpeg -i input.mp4 -c copy -f hls -hls_list_size 0 output.m3u8

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

H.265(HEVC)の fmp4 での HLS 出力コマンド例。
wiki: Encode / H.265 – trac.ffmpeg.org
movenc: allow alternative hvc1 h.265 codec tag
ffmpeg -i input -vcodec libx265 -acodec aac -tag:v hvc1 -f hls -hls_list_size 0 -hls_segment_type fmp4 -movflags +faststart output.m3u8

公式ドキュメント

オプション

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

  • -start_number [int64]
    セグメントの開始番号。開始番号を変更するのであり、映像の開始をずらすのではない
    範囲:0 から I64_MAX まで
    既定値:0
  • -hls_time [float]
    各セグメントの動画時間。指定した時間が来たら次のキーフレームで分割される。任意の時間で分割する場合にはGOPのフレーム間隔(group of picture size)を決めるエンコードオプションの -g(keyint)、-keyint_min を併用する。-sc_threshold 0 をつけるとキーフレームがシーンチェンジにで入らなくなり意図したセグメント分割になる
    範囲:0 から FLT_MAX まで
    既定値:2
  • -hls_init_time[float]
    最初のセグメントの動画時間。0 だと最初のキーフレームが来たら分割する。挙動は -hls_time と同じ
    既定値:0
  • -hls_list_size [int]
    マニフェストに記載されるセグメント数。0 はすべて
    範囲:0 から INT_MAX まで
    既定値:5
  • -hls_delete_threshold [int]
    ディスクから削除せずに残すセグメント数。-hls_flags +delete_segments と併用。詳しくは後述
    範囲:1 から INT_MAX まで
    既定値:1
  • -hls_ts_options [string]
    set hls mpegts list of options for the container format used for hls
  • -hls_vtt_options [string]
    set hls vtt list of options for the container format used for hls
  • -hls_wrap [int]
    セグメント数の上限を指定する。上限に達すると最初のセグメントから上書きするので容量の削減になる。しかし 廃止予定 なので代わりに -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つのバイト単位のファイルサイズ制限。マニフェストはバイトレンジ(#EXT-X-BYTERANGE)分割になる。-hls_flags single_file を併用するとファイルサイズ制限の効果が無い
    範囲:0 から INT_MAX まで
    既定値:0(無制限)
  • -hls_key_info_file [string]
    セグメントの暗号化で使うファイルを指定する。key には 16バイトのバイナリ、または16文字の16進数の文字列を、IV に32文字の16進数の文字列を指定する。書式は後述
    既定値:なし
  • -hls_enc [boolean]
    有効にするとオプションで指定したキーファイルの URI と IV をマニフェストに書き込む。-hls_enc_key-hls_enc_iv を指定する。無効にすると暗号化しない。-hls_key_info_file と併用すると -hls_key_info_file が優先される
    規定値:0
  • -hls_enc_key [string]
    指定した16文字の16進数の文字列からキーファイルを作成する
  • -hls_enc_key_url [string]
    -hls_enc 1 で暗号化したときに既定値ではマニフェストと同じ場所に「ファイル名.m3u8.key」が出力されるが、パスとキーファイル名を指定するとそれがマニフェストに記載される。マニフェストの保存先をカレント以外で出力したときにキーファイルが参照できないときはこのオプションでファイル名を指定する
    例:-hls_enc_key_url “L:\hoge/\piyo.key”
    例:-hls_enc_key_url “hoge/\piyo.key”
  • -hls_enc_iv [string]
    指定した32文字の16進数の文字列からIV を作成する。無指定だと IV=0x00000000000000000000000000000000 がマニフェストに記載される
  • -hls_subtitle_path [string]
    字幕ファイルのパス指定。無指定だとセグメント、マニフェストと同じ場所になる。挙動の確認ができない
    既定値:なし
  • -hls_segment_type [int]
    セグメントのファイルタイプの指定。詳しくはここ1, fmp4 にするとマニフェストのバージョンは 7 になる
    範囲:0(mpegts), 1(fmp4)
    既定値:0
  • -hls_fmp4_init_filename [string]
    EXT-X-MAP 用 mp4 のファイル名の指定
    既定値:init.mp4
  • -hls_flags[flags]
    フラグの指定。+で複数のオプションをつなげられる
    • single_file
      セグメントを分割せずに1つのファイルで出力する。マニフェストのバージョンは 4 以降になる。いわゆるバイトレンジ。#EXT-X-BYTERANGE
    • temp_file
      セグメントを .temp で一時出力し、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 を使ったときにセグメントのファイル名にファイルサイズを含める
    • periodic_rekey
      キーファイルが動的に書き換えられるのに対応して再読み込みする。現時点では ffmpeg 単体で -hls_key_info_file をセグメントの途中で書き換えることは出来ない(はず)
  • -use_localtime[boolean]
    セグメントのファイル名に strftime を割り当てる。廃止予定なので –strftime を使う。-use_localtime_mkdir、-hls_segment_filename を併用する
    既定値:0
  • -strftime[boolean]
    セグメントのファイル名に strftime を割り当てる。-use_localtime の代わりに使う。-strftime_mkdir、-hls_segment_filename を併用する
    例:-strftime 1 -hls_segment_filename %Y%m%d.ts(20160420.ts)
    既定値:0
  • -use_localtime_mkdir[boolean]
    セグメントの末端のディレクトリ指定に strftime を割り当てる。廃止予定なので -strftime_mkdir を使う。-use_localtime、-hls_segment_filename を併用する。ディレクトリがなければつくる
    既定値:0
  • -strftime_mkdir[boolean]
    セグメントの末端のディレクトリ指定に strftime を割り当てる。-use_localtime_mkdir の代わりに使う。-strftime, -hls_segment_filename を併用する。ディレクトリがなければつくる
    例:-strftime 1 -strftime_mkdir 1 -hls_segment_filename “%Y%m%d/%Y%m%d.ts”(20160420/20160420.ts)
    そのほかに、%H%M%S、時間分秒も使える
    既定値:0
  • -hls_playlist_type[int]
    • 0:何もつけない。既定値
    • 1, event
      マニフェストに #EXT-X-PLAYLIST-TYPE:EVENT をつけ、-hls_list_size 0(マニフェストにすべてのセグメント名を書き込む)も強制される
    • 2, 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:各セグメントのファイル名に年月日と時間が付く
  • -http_user_agent[string]
    HTTP ヘッダの User-Agent フィールドを優先させる
    既定値:なし
  • -var_stream_map[string]
    マニフェストにどの映像や音声を記載するのかを指定する
    1入力の映像と音声と、2入力の映像と音声をそれぞれのマニフェストで出力する例。スペースを空けると別マニフェストになる
    例:”v:0,a:0 v:1,a:1″
    既定値:1入力の映像と音声
  • -cc_stream_map[string]
    Closed captions をマニフェストに記載するのかを指定する
    既定値:無指定(指定しないと出力しない、未確認)
  • -master_pl_name[string]
    複数のマニフェストを参照するマスタープレイリストのファイル名を指定する
    既定値:無指定(指定しないと出力しない)
  • -master_pl_publish_rate[int]
    最初の何セグメントを出力したときにマスタープレイリストを出力するか
    既定値:0
    範囲:0 から INT_MAX まで
  • -http_persistent[boolean]
    HTTP 接続を継続する
    既定値:0
  • -timeout[duration]
    I/O 処理のタイムアウト時間を指定する
    既定値:-0.000001
  • -ignore_io_errors[boolean]
    ネットワーク越しの長時間配信で IO エラーが出たときに無視する
    既定値:0
  • -headers[string]
    既定値のヘッダから書き換える

エンコード設定

うまく配信するには GOP サイズであったり、映像と音声の同期問題であったり、遅延だったり色々と解決しなければならない問題も多い。

GOPサイズなら -g と、オープンGOP、クローズドGOP の設定。通常は圧縮率の高いオープンGOP、つまり設定変更しない。
-flag +cgop、-flag -cgopCompressor 4 ユーザーズマニュアル: MPEG-2 に関する参考情報

シーンチェンジにキーフレームを入れずにキーフレーム間隔を固定するなら、-sc_threshold 0ffmpeg Documentation

映像と音声の同期問題は固定フレームの指定 -r と、-vsync cfrffmpeg でのフレームレート設定の違い

遅延はエンコード設定とマニフェストにいくつのセグメントを記載する -hls_list_size と、セグメント時間 -hls_time が大きく依存する。また segment muxer にあるキーフレームで分割しない -break_non_keyframes を使う方法もある。

またバッファの調整では、エンコーダ側(配信側)の設定とデコーダ側(視聴者側)の設定も考える。

Raspberry PIとffmpegとWebカメラ、USBマイクを利用してHLSストリーミング&保存 – Qiita
ffmpeg – ffmpegのsegment_timeオプションが効かないのか – スタック・オーバーフロー

再生確認

mp4をFFmpegでhlsに変換し、ストリーミング再生 を引用し、hls.js, plyr.js を使って再生する。

コマンド例(video フォルダに出力)
ffmpeg -re -i input.mp4 -bsf:v h264_mp4toannexb -c copy -f hls -hls_list_size 0 -flags +global_header video/video.m3u8

削除するセグメント数を調整する

-hls_flags +delete_segments でマニフェストに記載されていないセグメントを削除できる。以前までは消されずに残っているセグメント数は -hls_list_size + 1 だったのが、-hls_flags +delete_segments を併用すると残すセグメント数を調整できる。

マニフェストに記載されるセグメント数は -hls_list_size の 10。
ffmpeg -i input -c copy -f hls -hls_list_size 10 output.m3u8

マニフェストに記載されるセグメント数は -hls_list_size の 10 で、データが残っているのは -hls_list_size の 10 + 1 = 11。
ffmpeg -i input -c copy -f hls -hls_list_size 10 -hls_flags +delete_segments output.m3u8

マニフェストに記載されるセグメント数は -hls_list_size の 10 で、データが残っているのは -hls_list_size 10-hls_delete_threshold 5 の 10 + 5 = 15。
ffmpeg -i input -c copy -f hls -hls_list_size 10 -hls_flags +delete_segments -hls_delete_threshold 5 output.m3u8

マスタープレイリストを作成する

複数のプレイリストをまとめたマスタープレイリストを作成する例。出力マニフェスト名は、output_0.m3u8、output_1.m3u8 とそれらを参照する master.m3u8。-map で指定した順番が -var_stream_map で指定する順番になる。逆に master.m3u8 からそれぞれの映像と音声をデコードするには -map で指定できるが、-map 0 のように単純に数値指定する方法と、-map p:0 (p はプレイリスト)のように映像と音声を合わせてデコードする方法がある。
ffmpeg -i input1 -i input2 -c copy -map 0:v -map 0:a -map 1:v -map 1:a -f hls -hls_list_size 0 -master_pl_name master.m3u8 -master_pl_publish_rate 4 -var_stream_map "v:0,a:0 v:1,a:1" %v-output.m3u8

1つの動画を複数の解像度にリサイズしてマスタープレイリストで出力する例。しかし出力自体は問題ないが最初のセグメント分割の時に、「Cannot use rename on non file protocol, this may lead to races and temporary partial files.」のエラーが出て回避方法がよく分からない。2019年7月時点ではエラーは出なくなった。
ffmpeg -i input -filter_complex split[0][1];[0]scale=1280:-2[0v];[1]scale=640:-2[1v] -map [0v] -map 0:a -c:v:0 libx264 -c:a:0 copy -map [1v] -map 0:a -c:v:1 libx264 -c:a:1 aac -b:a:1 96k -f hls -hls_list_size 0 -master_pl_name master.m3u8 -master_pl_publish_rate 4 -var_stream_map "v:0,a:0 v:1,a:1" %v-output.m3u8

-filter_complex を使わずに個別にフィルタを当てる方法もある。
ffmpeg -i input -filter:v:0 scale=1280:-2 -c:v:0 libx264 -c:a:0 copy -filter:v:1 scale=640:-2 -c:v:1 libx264 -c:a:1 aac -b:a:1 96k -map 0:v -map 0:v -map 0:a -map 0:a -f hls -hls_list_size 0 -master_pl_name master.m3u8 -master_pl_publish_rate 4 -var_stream_map "v:0,a:0 v:1,a:1" %v-output.m3u8

tee を使いマスタープレイリストとそれらのセグメントを1つに合わせた動画も出力する例。
ffmpeg -i input -filter:v:0 scale=1280:-2 -c:v:0 libx264 -c:a:0 copy -filter:v:1 scale=640:-2 -c:v:1 libx264 -c:a:1 aac -b:a:1 96k -map v:0 -map v:0 -map a:0 -map a:0 -flags +global_header -f tee "[select=\'v:0,a:0,v:1,a:1\':f=hls:master_pl_publish_rate=4:hls_list_size=0:var_stream_map=\'v:0,a:0 v:1,a:1\':master_pl_name=playlist.m3u8:hls_segment_filename=out_%v_%d.ts]out_%v.m3u8|[select=\'v:0,a:0\':movflags=+faststart]out1.mp4|[select=\'v:1,a:1\':movflags=+faststart]out2.mp4"

読みやすく改行したもの。

ffmpeg -i input \
-filter:v:0 scale=1280:-2 -c:v:0 libx264 -c:a:0 copy \
-filter:v:1 scale=640:-2 -c:v:1 libx264 -c:a:1 aac -b:a:1 96k \
-map v:0 -map v:0 -map a:0 -map a:0 -flags +global_header -f tee \
"[select=\'v:0,a:0,v:1,a:1\':f=hls:master_pl_publish_rate=4:hls_list_size=0:\
var_stream_map=\'v:0,a:0 v:1,a:1\':master_pl_name=playlist.m3u8:\
hls_segment_filename=out_%v_%d.ts]out_%v.m3u8|\
[select=\'v:0,a:0\':movflags=+faststart]out1.mp4|\
[select=\'v:1,a:1\':movflags=+faststart]out2.mp4"

詳しい書式は 1つの出力内容を複数に振り分ける tee を参照。

分割ファイルと連結ファイルを同時出力する

セグメントを出力して連結した動画も出力するコマンド例は5通りある。セグメントを連結するのにマニフェストがない場合は concat することで連結できる。

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
  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出力する(これが一番おすすめ)
    1つの出力内容を複数に振り分ける tee
    ffmpeg -i input.mp4 -vcodec libx264 -acodec aac -map 0:v -map 0:a -flags +global_header -f tee "[f=hls:hls_time=10:onfail=ignore]output0.m3u8|[bsfs/v=h264_mp4toannexb:onfail=ignore]output.ts"
  5. 配信で個別セグメントは出力せずにバイトレンジで出力するなら -hls_flags single_file を使う。出力ファイルは output.m3u8 と output.ts だけ
    ffmpeg -i input -f hls -hls_flags +single_file output.m3u8

hls_key_info_file の書式

書式

key URI
key file path
IV (optional)

http://example.com/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 A4856CAC48F1E48D -iv 50d6dc6e65d9aa0f810a3f699950c8a0

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

ffmpeg で復号する例(mp4)。
ffmpeg -i output.m3u8 -c copy -bsf:a aac_adtstoasc output.mp4

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

ffmpeg でローカルファイルを復号してプレビューする。
ffmpeg -re -allowed_extensions ALL -i output.m3u8 -f sdl -
ffplay -allowed_extensions ALL -i output.m3u8

hls_enc, hls_enc_key, hls_enc_iv で暗号化する

コマンド例、output.m3u8.key が -hls_enc_key で作られる。
ffmpeg -i input.ts -hls_enc 1 -hls_enc_key A4856CAC48F1E48D -hls_enc_iv 50d6dc6e65d9aa0f810a3f699950c8a0 -c copy -f hls output.m3u8

output.m3u8 の中身。

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:4
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-KEY:METHOD=AES-128,URI="output.m3u8.key",IV=0x35306436646336653635643961613066
#EXTINF:3.920844,
output0.ts
#EXTINF:1.251333,
output1.ts
略
#EXT-X-ENDLIST

キーファイルのファイル名とパスの設定は -hls_enc_key_url を使う。
ffmpeg -i input.ts -c copy -f hls -hls_enc 1 -hls_enc_key A4856CAC48F1E48D -hls_enc_iv 50d6dc6e65d9aa0f810a3f699950c8a0 -hls_enc_key_url hoge.key output.m3u8

output.m3u8 の中身。

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:4
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-KEY:METHOD=AES-128,URI="hoge.key",IV=0x35306436646336653635643961613066
#EXTINF:3.920844,
output0.ts
#EXTINF:1.251333,
output1.ts
略
#EXT-X-ENDLIST

保存した m3u8 やセグメントから動画に変換する

HLS 配信している動画でマニフェストやセグメントを保存した場合にマニフェストを書き換えて ffmpeg で動画にする方法。主な用途はライブ配信で過去のセグメントがマニフェストに載っていない場合に、セグメントが連番で推測しやすくアクセスも出来る場合である。

まずマニフェストに記載してあるセグメントを絶対パスにし、最後の行に #EXT-X-ENDLIST がなければ追加する。同様に暗号用の key も絶対パスにする。これのアクセスに cookie や UA が必要な場合は -headers-user_agent を指定する。各セグメントを保存した場合はファイルパスに注意する。
-user_agent"Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:56.0) Gecko/20100101 Firefox/56.0" のように指定する。headers
"Cookie: _alid_=hogehoge==; hdntl=exp=15123456..." のように指定する。

ffmpeg -protocol_whitelist http,https,tls,tcp,crypto,file -allowed_extensions ALL -analyzeduration 30M -probesize 30M -i master.m3u8 -c copy output.ts
ffmpeg -protocol_whitelist http,https,tls,tcp,crypto,file -allowed_extensions ALL -analyzeduration 30M -probesize 30M -i master.m3u8 -movflags +faststart -c copy -bsf:a aac_adtstoasc output.mp4

セグメントが多いとコンソールのログが長くなり処理が遅くなるので、-loglevel 0
で非表示にすることもできる。
ffmpeg -protocol_whitelist http,https,tls,tcp,crypto,file -allowed_extensions ALL -analyzeduration 30M -probesize 30M -i master.m3u8 -c copy output.ts -loglevel 0
ffmpeg -protocol_whitelist http,https,tls,tcp,crypto,file -allowed_extensions ALL -analyzeduration 30M -probesize 30M -i master.m3u8 -movflags +faststart -c copy -bsf:a aac_adtstoasc output.mp4 -loglevel 0

セグメントの開始がキーフレームでは無くて音声は流れるのに映像がすぐに動かない場合は入力ファイルの前に -ss 0 を追加するとキーフレームまでの映像をカットする。
ffmpeg -protocol_whitelist http,https,tls,tcp,crypto,file -allowed_extensions ALL -analyzeduration 30M -probesize 30M -ss 0 -i master.m3u8 -c copy output.ts
ffmpeg -protocol_whitelist http,https,tls,tcp,crypto,file -allowed_extensions ALL -analyzeduration 30M -probesize 30M -ss 0 -i master.m3u8 -movflags +faststart -c copy -bsf:a aac_adtstoasc output.mp4

m3u8 を読み込む

HLS配信されているマニフェストを保存せずにそのまま読み込んで復号し動画で出力するコマンド。cookie や UA を指定して接続もできる。それらを調べるには開発ツールを有効にしてマニフェストだけを開き「Copy as CURL」で調べられる。

コマンド例
ffmpeg -user_agent "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:56.0) Gecko/20100101 Firefox/56.0" -headers "Cookie: _alid_=hogehoge==; hdntl=exp=15123456..." -i "https://example.com/master.m3u8" -c copy output.ts
ffmpeg -user_agent "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:56.0) Gecko/20100101 Firefox/56.0" -headers "Cookie: _alid_=hogehoge==; hdntl=exp=15123456..." -i "https://example.com/master.m3u8"-movflags +faststart -c copy -bsf:a aac_adtstoasc output.mp4

How to enable cookies in ffmpeg HLS – Stack Overflow

更新履歴

オプションが追加されていたので追加した。2016年7月30日
オプションが追加されていたので追加し文章を直した。2016年9月6日
オプションが追加されていたので追加した。2016年9月11日
オプションが追加されていたので追加し順番を直した。2017年2月12日
セグメントを出力して連結した動画も出力するコマンド例。2017年3月26日
hls_key_info_file の書式をわかりやすく書き直した。2017年4月17日
hls_enc, hls_enc_key, hls_enc_key_url, hls_enc_iv のオプションを追加した。 2017年6月8日
concat する方法のリンクが間違ってたのを直した。2017年6月12日
fragment mp4 のオプションを追加した。2017年7月20日
fragment mp4 の記述が間違っているので一度削除。2017年7月22日
fragment mp4 のコマンド例を追加したが、#EXT-X-MAP:URI=”(null)” になるのを回避する方法が分からない。periodic_rekey のフラグ追加。2017年8月10日
ネットから保存した m3u8 から動画に変換するを追加。2017年10月11日
livestreamer、streamlink では使えなかったので記述を削除した。streamlink は file プロトコルが使える 2017年10月12日
新しいオプションを追加し、マスタープレイリストを出力するコマンド例を追加。2017年12月9日
cookie 指定を headers のオプションに変更しコマンド例を追加。2018年2月21日
use_localtime, use_localtime_mkdir が廃止予定になったので代替のオプションを追加。再生確認の項目追加。オプションの追加。2018年9月10日
GOP、映像音声同期、遅延について追記。2018年11月24日
loop-global_header を loop+global_header に直した。2019年6月19日
.ts 出力には movflags +faststart を消した。2019年7月1日
hls_delete_threshold の説明を追加した。2019年7月5日
記事の順番を見直し目次を細分化した。2019年7月6日
master_pl_name, tee の併用例を追記した。2019年7月30日

One thought on “ffmpeg で Apple HTTP Live Streaming(HLS)を扱う”

コメントを残す

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

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