ffmpeg

以下は,知的好奇心の赴くままに、手に入れた知識である。
信じすぎず、参考程度にすること。

ffmpegとは

・Fast Forward Moving Picture Experts Group; FFmpeg (参考:mpeg
・音声,動画などのマルチメディアやストリーミングを扱うオープンソース.つまり,音楽,動画を扱うソフト.
・特定の分野に関連したライブラリが用意されている.ライブラリを直接利用もできる.
 libavcodec: ffmpegがサポートするエンコーダ,デコーダ.
 libavformat: 様々フォーマットに対応したmuxer, demuxer.
 libavfilter: 音声,動画を編集する膨大なフィルター.
 ffmpeg: メインのトランスコードエンジン.(これを呼び出すことが一番多い)
 ffplay: 音声,動画を再生する最小限のアプリ.
 ffprobe: 音声,動画の情報(fps, ストリーム数 etc.)を読み取る.

・無料で利用可能.(GPL,LGPLライセンス).商用も可能らしい.
・トランスコーディング(:他の圧縮信号に変換すること)や, ストリーミング(:再生すること)に長けている.
・Cで書かれてる.
・様々なコーデック,フォーマット,デバイス,プロトコルに対応.
・20年以上も開発中.
・様々なyoutube,iTunes,VLCでも使われている.

インストール

公式のビルダーってのはない.

オープンソースを入れて自分でビルドする

自分でコンパイルするのは大変そうではある.
Snapshot: https://ffmpeg.org/releases/ffmpeg-snapsot.tar.bz2
Git: git clone https://ffmpeg.org/ffmpeg.git ffmpeg

既にビルドされたものをインストールする

こっちの方が楽でしょう.
ubuntuのAPT,macOSのhomeburew等のパッケージ管理ライブラリがある場合,ダウンロードとインストールをしてくれるので楽.
windowsの場合,https://ffmpeg.org/downloard.html(サードパーティのやつ)

大体6ヶ月に一回メジャーリリースが行われる.
ビルドによっては,DLLファイルやライブラリが渡されることもあるので注意.

macOSにインストール

パッケージ管理のhomebrewを使う.

brew install ffmpeg

ffmpeg, ffprobe, ffplayがコマンドで打てるはず.

Ubuntuにインストール

パッケージ管理のAPTを使う

sudo apt
sudo apt install ffmpeg

ffmpeg, ffprobe, ffplayがコマンドで打てるはず.
(inputファイルがありませんエラーが出るはずという意_)

Windowsにインストール

パッケージ管理システムがないのでダウンロードしてインストールする.
https://ffmpeg.org/downloard.html
のWindowsマークにカーソル当てると,pre-builtしたものをダウンロードできるリンクが現れる.
gyan.devをクリック.
複数のバージョン,ブランチがある.
リリースのところから,最新のessensialの.zipファイルでいいと思う.
スタティックビルドのため,ffmpeg, ffplay, ffprobeの依存関係が単一の実行ファイルにある.DLLファイルが必要ない.
"shared"のやつを選ぶと,DLLファイルとライブラリが別れて展開される.
(どちらにも長所短所がある)
.7zパッケージだと展開するのに7-Zipツールのインストールが必要.

普通はGドライブに展開?
binフォルダ内に,ffmpeg, ffprobe, ffplayがあるはず.

環境変数の設定

毎回フルパスを入力しなくてもいいように,下記のいずれかの環境変数を設定しておこう.
・user Path variable (上の方にあるやつ)だと,ユーザのみ.
・system Path varivable (下の方にあるやつ)だと,そのマシンを使うユーザ全てが利用可能.
......./binフォルダのパスを設定する.
ffmpeg, ffprobe, ffplayもできるはず.

ffprobeについて

ffprobeを打つと,バージョン,ビルド方法,設定が表示される.
ffprobe version 4.4.2-0ubuntu0.22.04.1 (バージョン)
built with gcc 11 (Ubuntu 11.2.0-19ubuntu1) (ビルド方法)
configuration: ....... (ビルド時の設定)



メディアファイルの基礎

画像

解像度

HD (High Definition)といえば1280x720.
FHD (Full High Definition)といえば1920x1080.
UHD (Ultra High Definition),WFHD (Quad Full High Definition): 3840x2160(FHDの2倍2倍).テレビにおける4kはこれ[1]
4K: 4096x2160.デジタルシネマにおける4Kはこれ[1].演算がしやすいように16の倍数[1]
[1] https://www.for-a.co.jp/products/articles/tech_4k8k_04/

アスペクト比:

width / height

音声

サンプルとは

音を構成する最小要素.音の深度.
8, 16, 24, 32 bitで表される.

周波数

周波数は,単位時間当りのサンプルの数.
44.1 kHz,48 kHzなど.

チャンネル数

幾つのサンプルのシーケンスがあるか.
一つならモノ,二つならステレオ.
5.1,7.1などもある.
チャンネルは全て同時に再生される.

トラック

チャンネルの集まり.
複数のオーディオトラックを同時に再生したり,しなかったり.
ビデオトラックと一緒に再生したり.


動画

フレームレート

一般的なのは,以下のようなもの.
23.98,24,25,29.97,30,50,59.94,60.
テレビやアプリ由来の規格であるため様々ある?

圧縮

これは複雑.
基本的には,冗長な部分をカットしている.
冗長な部分とは,主に2種類.
1.フレーム内の空間的な冗長性.
フレーム状のある点近傍画素は似たものが多い?ので,画質を大きく落とさずとも少ないビット数で符号化が可能.
一般的ファイルを圧縮するのにも同様に使われる.
2.時間的冗長性.
連続フレーム間で似たものが多い場合,圧縮できる.

トラック

音声トラックと一緒.

ストリーム

コンテナに入る音声トラックや動画トラックのこと.
動画ストリームは一般的に1コンテナに一つ.だが,理論的には複数入れるのも可能.
音声ストリームは複数あることもある.


コーデックコンテナ

コーデック (codec)

COder, DECoderを繋げたもの.
エンコード,デコードのフォーマットを意味する.
エンコード,デコードを行うプラグインを呼ぶこともある.
生の音声や動画データは非常に大きく,エンコードしなければとても不便.

一般的な動画コーデックに,以下のものがある.
H.264: インターネットで広く使われている,
H.265: H.265の後継.
VP9: Googleが開発.

圧縮率は下がるものの質を劣化させずに,編集時のデコードしやすくしたものもある.
Prores: Appleのもの.
DNxHD: AVIDのもの.

音声のコーデックのうち,よく使われているものの一例.
PCM:圧縮されていない.
Vorbis:??
AAC,MP3:圧縮されている.

録音,編集用の高品質なものを保存するためのコーデックもあれば,
圧縮やストリーミングに適したコーデックもある.
有料なものもある.

コンテナ

メディアを包むパッケージで,ファイルの形式を示す.
ストリームがいくつあるのか,音声トラックがどこにあるのか等,データの構成を表す.

動画+音声のコンテナ一例:
MP4: 有名.
MXF: 放送業界で有名.高品質のもの.
QuickTime, MOV.
MKV.

音声のみコンテナ一例:
WAV: 高品質.PCMオーディオに使われる.
M4A: AACオーディオに使われる.

適したコーデックを用いるために,いくつもの種類がある.



トランスコーディング

あるエンコーディングから別のエンコーディングに変換すること.
トランスミキシング?の意味でも使われるが,これはコーデックはそのままで,コンテナだけ変えたやつ.対応によっては再生できなくなる.

トランスコーディングで可能なこと

トランスコーディング中に,再生された動画中のスナップショットを取得する.
フレームレートの変換.
ビットレートの変換.
ビットレート:1秒当り,どれほどのビットが保存,転送されるか.
GOP (:画像グループ)の変更.iFrame onlyはGOPサイズが1で高画質.
ロゴ,透かし,別画像の重ね合わせ.
字幕やキャプションの抽出.書き込み.
タイムコードの変更.タイムコードはカメラによって埋め込まれる.フレームの識別に使われる.
解像度の変更.3840x2160 → 1920x1080 etc.
音声の増幅,正規化.
音声チャンネルを重ね合わせる.
1部の音声のみ抽出.例えば複数の言語のチャンネルがある場合に,一つの言語ver.を作成できる.
動画全体をダウンロードせずとも,音声だけダウンロード.
サンプリングを下げる.高サンプリング周波数で録音.低くしてストリーミング,再生.
音声から波形画像作成.
動画の操作.反転,切り抜き,白黒,動画in動画,ノイズ削除etc.






メディアのストリーム情報,フォーマット情報

ffprobeで解像度,コーデック,チャンネル数などメディアのストリームに関することを調べられる.

duration (再生時間), Stream (??)など

ffprobe input.mp4

input.mp4:
http等のURLでも可能.
あんまり使う情報じゃないかも.
-v error を付与することで,エラー時以外は出力されなくなる.
エラーがあるかの判断に使える?
以降,この出力はあんまり必要ないなので,毎回-v errorを入れておけば良い.

ffprobe -v error input.mp4 -flag1 -flag2 ...

のように以下に記載するflagを追記していけば良い.

フォーマットを表示する

-show_format

nb_streams: ストリーム数
format_long_name: コンテナ
duration: 再生時間

全ストリーム表示する

-show_streams

H.264コーデックのビデオストリーム,aacコーデックのオーディオストリーム等についてが出力される.

ビデオ/オーディオストリームの情報のみ出力

ビデオストリーム

-select_streams v

オーディオストリーム

-select_streams a 


フィルターをかけて出力

ストリームのコーデック名のみ

-show_entries stream=codec_name

フォーマットのフォーマット名のみ

-show_entries format=format_name

フレームレート

-show_entries stream=r_frame_rate

再生時間

-show_entries stream=duration


出力形式をフォーマットをCSV, XML, JSONに変更

-print_format json

-print_formatの後に,csv, xml, jsonを記述.

出力時のラッパーを出力しない

[STREAM] [/STREAM] がいらない

-print_format default=noprint_wrappers=1


さらに出力時のラベルを出力しない

(出力)codec_name=h.264 の "codec_name="の部分

-print_format default=noprint_wrappers=1:nokey=1







再生する (ffplay)

ffplay input.mp4

実際のサイズと同じ大きさのウィンドウで再生される.
inputにはhttpからのURLも可能.
動画,音声,画像ファイルを再生,表示できる.

ウィンドウの大きさを変える

-x 600 -y 600

動画のアスペクト比は変更されない.
動画とウィンドウのアスペクト比の差の部分は黒塗りされる.
どちらか一方のみ指定すれば,自動的に動画サイズが調整される.

タイトルバーいらない

-noborder


ウィンドウの位置

-top 0 -left 0


フルスクリーン再生

-fs


音声いらない

-an


動画いらない

-vn

音声がヴィジュアル化されて見える.

波形見る

-vn -showmode waves


ループさせる

-loop 0

フラグの後に回数.0 (以下?)は無限.

再生中の操作

一時停止/再生

space

ミュート/ミュート解除

m

フルスクリーン

f
double lmb

※lmb: left mouse button

音量上げ/下げ

0/9

モード切替 (動画+音声/波形/音声)

w

コマ送り

s

10秒送り/戻し

left/right arrow

1分送り/戻し

up/down arrow

終了

esc
q



動画を画像にする

gifにする

ffmpeg -i in.mp4 -vf "palettegen" -y palette.png
ffmpeg -i input.mp4 -i palette.png -r 24 -y out.gif

  

連番画像で保存する

ffmpeg -i input.mp4 image_%03d.png






ffmpegの仕組み

流れ

Input File → 分解.動画,音声etc.(Demux) → 圧縮を戻す(デコード) → 処理 →・・・→ 処理 → 圧縮(エンコード)→ パッキング(Mux)→ 出力
Demuxer, Muxerはlibavformatライブラリが担当.
デコード,エンコードはlibavcodecライブラリが担当.
処理はlibavfilterが担当.
なお,デコーダや処理をするフィルタでは,音声・動画を同時に処理することは通常ない.

上記の流れの処理のところを書いていく.

コマンド

基本的に,入力,フィルター,出力の順.
プロトコル,フィルター or デバイスを指定できる.

ffmpeg [-f <device or formats>] -i [protocol:]input filter, .., [-f <device or filter>] [protocol:]output

※[]は,オプションの意.


出力に関するオプション

verbose(?): -v
-v error: エラー時以外出力しない
-v quiet: 何も出力しない
-v trace: ファイルの構造を出力

プロトコル

プロトコルは,file:,http:,atp:,rtp:など.

デバイス/フォーマット

入力/出力のデバイス,フォーマットは,それぞれの前に-fで指定.
・フォーマットとは,Demuxer, Muxerのこと.MOVとか.
・デバイスとは,物理的ハードとか,仮想的なデバイス.
input側のデバイスはdemuxerとして,output側のデバイスはmuxerとして使われる.


サポートしているプロトコル,デバイス,フォーマットの確認

ffmpeg -protocols
ffmepg -devices
ffmepg -formats

それぞれ,入力/出力の内,一方しか対応していないものもあるので注意.



Input/Outputについて

Input/Outputがファイルの場合

相対,絶対パスいずれも可能.マウントされた場所も可能.
プロトコルは必要ない.デフォルトでfile:なんだと思う.
基本的には,拡張子からdemuxer, muxerを自動で決めてくれるので,フォーマットの指定(-f)はいらない.
しかし,拡張子を持たないものを扱う場合,フォーマットの指定が必要.

Input/OutputがUNIXファイル,標準入力/出力の場合

UNIXファイルにはpipeプロトコルを使える.
標準入力/出力には,input/outputを- (マイナス符号)とすれば良い.この場合,拡張子がないので,フォーマットの指定は必要.
ディスクへ書き込まずに出力を消費する場合に便利(そんなことある?).
また,seekが必要(標準入力とかの話)なことに注意(?).

簡単な画像を入力に

デバイスで lavfiの指定が必要.

テスト用画像

ffmpeg -f lavfi -i testsrc=duration=1:size=1920x1080

色画像

ffmpeg -f lavfi -i color=color=red

lavfi: LibAVFormatInputの略.仮想デバイス.
(色画像の大きさ指定するにはどうしたらいいんだろ)

スクショを入力に

Windows

ffmpeg -f gdigrab -i desktop

macOS

ffmpeg -f avfoundation -i "1"

Linux

ffmpeg -f xllgrab -i $DISPLAY

inputの入力名を出力するコマンドもある(?).

Webカメラを入力に

Windows

ffmpeg -f dshow -i video="USB2.0 HD UVC WebCam"

macOS

ffmpeg -f avfoundation -i "default"

Linux

ffmpeg -f v412 -i /dev/video0


マイクを入力に

Windows

ffmpeg -f dshow -i video="Microphone (Realtek)"

macOS

ffmpeg -f avfoundation -i "2"

Linux

ffmpeg -f alsa -i hw:1


入力ファイルの長さを時間で指定

ffmpeg -i input -to 10 out

-to <sec>
<sec>秒まで入力される.

複数の入力

複数のメディアを入力できる.

-i input0 -i input1 -i input2 -i input3 ..

順番で0, 1, 2, 3, ..とインデックスが割り振られる.

出力時のストリームの選択

特定のストリームを選択することがよくある.
次の表記で選択する.

-map 入力メディアのインデックス:ストリームのタイプ:ストリームのインデックス
-map 入力メディアのインデックス:ストリームのインデックス

選択をしない場合の出力は,デフォルトで出力が1動画,1音声ストリームになる.

入力の全てのストリームを選択

-map 0

0は,入力のうち,インデックス0の入力のもの.

入力の動画/音声の選択

-map 0:v
-map 0:a


入力の一つ目のうちの,音声のうちの,一つ目のストリーム

-map 0:a:0


入力の一つ目のうち,3つ目のストリーム

-map 0:2


入力のストリームを確認

ffprobe input -show_streams

詳しくはメディアの情報の項目を参照.

異なる入力からストリームを複数選択する

-map 1:0 -map 0:1
-map 1:v -map 0:a

入力二つ目の一つ目ストリーム(動画),入力一つ目の二つ目ストリーム(音声).




フィルターについて

基本的にlivavfilterライブラリにある.
「フィルター=キー=引数:キー=引数...」の順番で入力する.
決まった順番通りなら,引数だけでも.
キーは長い名前,短い名前の2種類あるものもある.
繋げたりもできる(後述),全体を""で囲む.

filter=key1=arg1:key2=arg2..

例:

scale=width=1920:height=1080
scale=w=1920:h=1080
scale=1920:1080


さまざまなものがある.
入力:単一→出力:単一 拡大とか.
入力:単一→出力:複数 分割とか.
入力:複数→出力:単一 重ね合わせとか.


入出力にラベリング

フィルタを接続する場合に必要.
[ブラケット]を用いる
ストリームの選択も可能

[in_1][in_2]filter=hoge[out_1][out_3]
[0:v][0:a:2]filter=hoge


フィルターをつなげる

コンマ,で繋げる.

filter1=hoge1,filter2=hoge2,filter3=hoge3


フィルターを列挙する

ある入力をフィルター1,フィルター2,フィルター3で編集して,別のある入力をフィルターA,フィルターB,フィルターCで編集してという場合の話.
セミコロン;でつなげる.
-vf,-v,-filter_complexで指定する.

単一入力、単一出力 ビデオ処理の場合:-vf

ffmpeg -i input -vf "split[bg][ol];[bg]scale=w=1920:h=1080,format=gray[bg_out];[ol]scale=-1:480:,hflip[ol_out];[bg_out][ol_out]overlay=x=W-w:y=(H-h)/2" out

ある動画を,二つ(background; bg,overlay; ol)に分ける(split).
bgの方を,サイズを指定(scale)してグレー画像に(format).
olの方を,サイズ指定(scale)して,水平反転(hflip).
bhにolを重ねる(overlay).

単一入力、単一出力 音声処理の場合:-af

音声を二つに分ける:

asplit=2

音声のボリュームを2倍に:

volume=bolume=2

二つのチャンネル(ch0, ch1)を重ね合わせる:

pan=mono|c0=c0+c1

2チャンネルを重ねる:

amerge=input=2

例:4chある音声データのうち、2つのボリュームを2倍、2つのボリュームを0.5倍に。

ffmpeg -y -i four_ch_stream.wav -af "asplit=2[voice][bg];[voice]volume=volume=2,pan=mono|c0=c0+c1[voice_out];[bg]volume=volume=0.5,pan=mono|c0=c2+c3[bg_out];[voice_out][bg_out]amerge=input=2" audio_out.wav


上記以外 の場合:-filter_complex

例:動画に小さくしたロゴを貼り、HD、SDで出力。音声を4ch → 2chにして出力。

ffmpe -v error -y input.mp4 -i logo.png -filter_complex "[1:v]scale=-1:200[small_logo];[0:v][small_logo]overlay=x=W-w-50:y=H-h-50,split=2[sd_in][hd_in];[sd_in]scale=-2:480[sd];[hd_in]scale=-2:1080[hd];[0:a]pan=stereo|FL=c0+c2|FR=c1+c3[stereo_mix]" -map [sd] sd.mp4 -map [hd] hd.mp4 -map [stereo_mix] stereo_mix.mp3




エンコードについて

とても重要。質、サイズを決定する部分。
ネットでストリーミングするならサイズは大きくしたが方が良い。
アプリによってどのコーデックに対応しているかは異なる。
ただし、どのコンテナに入るコーデックの組み合わせは制限がある。
オプションを受け付けられる.多くのエンコーダに使えるもの(グローバルオプション)もあれば,特定のエンコーダにのみ使えるもの(プライベートオプション)もある.

グローバルオプションの例:
プロファイル,ビットレート,GOPサイズ.
プライベートオプションの例:
H.264エンコーダに,x264オプション.

エンコーダの確認

ffprobe -v error input -select_streams v -show_entries stream=codec_name -print_format default=noprint_wrappers=1

-v error:
エラー時以外,設定等の情報が出力されなくなる.なくてもできる.
-select_streams v:
動画ストリームを出力する.音声ならv→aに.ない場合,全てのストリームを出力.
-show_entries stream=codec_name:
コード名を出力.
-print_format default=noprint_wrappers=1:
ラッパーを出力しない.ないと,[STREAM]とかの文字列(邪魔)が出てくる.

トランスコード

ffmpeg -v error -y -i input.hoge1 out.hoge2

特にコーデックを指定しない場合,指定した拡張子(コンテナ)に基づいて,自動的にコーデックを選択する.

エンコーダの指定

動画ストリームをH.264エンコーダで指定する場合:

ffmpeg -v error -y -i input -vcodec lib264 output

動画の場合,-vcodec で指定する.音声なら-acodec.
libx264はH.264エンコーダのこと.

使えるエンコーダについて, 

ffmpeg -encoders

どのエンコーダが使えて,それをどうして指定するかがわかる.



H.264エンコーダについて

Advanced Video Coding(; AVC)としても知られ,最も普及しているフォーマット.
amazon, youtube, netflix, ブルーレイディスクなどに用いられてる.
さまざまなオプションを指定できる.

プロファイル

-profile

ベースラインの高さを指定できる.
指定しない場合,libx264エンコーダが自動的に設定.

レート

レートコントロールモードたるものがある。2種類。

・品質重視用:CRF
ビットレートが一定でなくても、一定レベルの品質。
ファイルサイズは気にしない.
0(最高品質)-51(最悪品質)の数字を引数に取る.指定しない場合,デフォルトの23.
17-28くらいがいいと思う.

・ビットレートを一定にする用:Two-pass ABR
品質は一定でなくても,ビットレートが大体一定.
ストリーミング等,一定のビットレートが必要な時用,
特定のパラメータで2回実行する必要ある.

そもそも,ビットレートを指定するには,-b:vオプションを使う.
2 Mbpsにする場合:

ffmpeg -v error 0 -y -i input input -vcodec libx264 -b:v 2M output

しかし,これだとおおよそのビットレートにしかできない.
1回のみだとどんなフレームがあるかわからないので.技術的な限界といえる.

そこで,Two-pass ABRと呼ばれる2回実行することで,割と正確なビットレートにしてくれる.

ffmpeg -v error 0 -y -i input -vcodec libx264 -b:v 2M -pass 1 -f null /dev/null
ffmpeg -v error 0 -y -i input -vcodec libx264 -b:v 2M -pass 2 -f null output


エンコード時間の選択

早いほど圧縮率が小さく,サイズが大きくなる.
選択する例:

time ffmpeg -v error -y -i input -vcodec libx264 -preset medium output

ultrafast, superfast, veryfast, faster, fast, medium, slow, slower, veryslow, placebo
から選択する.指定しない場合,mediumがデフォルト.
頭のtimeは,時間を出力してくれる.なくても実行可能.



ストリーミングについて

Netflix, Youtubeなどのプラットフォーム,Over The Top (; OTT)や,Vido On Demand (; VOD)と呼ばれることもあるが,これらのサービスにおけるストリーミングについての説明.
ここでは,ネット上において,メディア全体が利用可能になるをの待たずに,メディアを利用できる状態の時にストリーミングと呼ぶ.
例@えば,動画をローカルに保存してさいせいできる状態はストリーミングと呼ばない
ネットの動画を一通りダウンロードしてから再生されるのもストリーミングと呼ばない.
再生開始前に,必要最小限な部分のみダウンロードされ,全体をダウンロードする前に再生されるものをストリーミング呼ぶことにする.

Youtube, Netflixは,サーバ上で全体が利用可能である状態なメディアをストリームしている.
ライブ配信などは,カメラ等のソースからサーバ上ですぐにメディアの変換をしてストリームしている.

ライブストリーム

サーバのカメラからのストリーミングをingestと呼ぶ.
クライアントのサーバからのストリームをdistribution, delivery, last mile deliveryなどと呼ぶ.
重量なのは,ユーザ側のデリバリーの方.特に次の三つが重要.
・即座に再生が可能であること.ストリーミングの基本.
・メディアの任意の部分から即座に再生が可能であること.これも基本的に求められる.
・ネット状況の変化に拘らず再生できること.

ストリームプロトコル

プロトコル:クライアント,サーバがストリーミングメディアと通信するための方式.
たくさん開発されているが,3つ説明.
それぞれに特徴があり,それぞれに適している状況が違う.
ingestに適したもの.distributionに適したものとか.

Real-Time Messaging Protocol; RTMP

TCPベースのプロトコル.
パケットロスに対してかなり信頼性が高い.
低遅延.
Macromedia社の開発.Adobeが買収.
Adobe Flash playerの会社.
スマホが普及する前はストリーミングの一般的な方法で,ingestとdistributionの両方に広く使われていた.
今は更新されておらず,distributionとしての利用は減少中.
RTMPのストリームを再生するには,ブラウザのプラグインflash等が必要.
flashは,パフォーマンス,セキュリティ,バッテリー消費とかで広く批判され使用されなくなる.
HTML5に置き換わる.ただ,RTMPの配信を行うにはRTMPサーバが別途必要でめんどくさい.
ただ,特にingentでは人気のあるプロトコル.
youtube,facebookのライブ配信はこのプロトコル.
他のプロトコルよりも遅延が小さい.

HTTP

ウェブブラウザの読み込み.TCPベース.
ファイアウォールにブロックされることが少ない.これが大きな利点.
別途サーバは不要.古いウェブサーバでも利用可能.
ブラウザでも,HTML5はFlashのようなプラグインを必要とせず,動画の再生を可能に.
簡単にストリーミングできる.
最近のウェブブラウザでは,Media Source Extensions; MSEに対応.
これにより,HTTPでメディアをどう取得するのか,どうデコーダに送信するのかを細かく制御できるようになった.
これは,ブラウザが最近のストリーミング手法(HLS,MPEG-DASH)をJavaScriptで適応するプロトコルである.これらの手法はHTTPに基づいてる.
広く対応しているので,distributionとしても最も人気のある手法.ingestとしてはそんなに.可能ではある.
RTPと比べると遅延あり.一般的なingestでは不人気.
早いものも開発されてきてるが,普及していない.

Secure Reliable Transport; SRT

Haivision社が開発.比較的新しい.
転送層が大きく異なる.UDPベース.
他のプロトコルと比べて,初めのハンドシェーキングがなく,超高速.
UDPベースだがエラー訂正機構もあるため,不安定なネットでも信頼できる.
ユーザ側はブラウザがUDPに対応してないので,ほとんど使用されない.
一方で,ingest側はRTPに変わる候補に.



FFmpegでは,ネットワークストリーミングプロトコル上で,メディアを再生,したりストリームしたりできる.

ネットからHTTPプロトコルでストリームを再生

ABC News Liveをストリームで取得してみる.
ABC News LiveのYoutubeから,デベロッパーツールでネットワークトラフィックを見る.
"m3u8"を検索し,"Name"項目の最上位のもののリンクコピー."3324f...."で始まる名前。
youtubeじゃダメそう.ABC Newsの公式HP(2022年8月)で.
開発者ツールを開いた状態で、HPにとぶことに注意。そうでないと、初めの方で読み込まれるみたいで、表示されなかった。
ffplay http:// ...... を実行すると,ウィンドウが開き,再生される.音量調整は9 (下げ), 0(上げ) .
下のようなコマンドが紹介されていた.

ffplay -v quiet -y 200 "https://....."

-v quiet は余分な出力をさせないためだと思うが,-y 200があると,404Errorになる.なしで実行した.
そんなこともなかった。

ネットからHTTPプロトコルでストリームを取得し,ローカルRTMサーバにパブリック

ローカルにRTMPサーバを立てとく。
たて方:TODO

ffmpeg -v quiet -i "http://..." -vf "scale=-2:200,drawtext=fontfile='/System/Library/Fonts/AppleSDGothicNeo.ttc':text=RTMP:fontsize=30:x=10:y=20:fontcolor=#000000:box=1:boxborderw=5:boxcolor=#ff8888" -vcodec libx264 -f flv rtmp://localhost:1935/live/rtmpdemo


ローカルRTMPサーバからストリーム取得、再生

ffplay -v quiet rtmp://localhost:1935/live/rtmpdemo


ローカルRTMPサーバからストリーム取得、ローカルSRTサーバにパブリック

ローカルにSRTサーバたてとく。
立て方:TODO
どうやって建てるんだ??

ffmpeg -v quiet -i rtmp://localhost:1935/live/rtmpdemo -vf "drawtext=fontfile='/System/Livrary/Fonts/AppleSDGothicNeo.ttc':text=SRT:fontsize=30:x=10:y=60:fontcolor=#000000:box=1:boxborderw=5:boxcolor=#ff888888" -vcodec libx264 -f mpegts srt://localhost:1935?streamid=input/live/srtdemo



プログレッシブダウンロード

ストリーミングと対比されるみたい。
ダウンロードしながら再生する。

メディア再生時の流れ

プレイヤーはメディアファイルのはじめの数バイトを読み込み、ファイルの形式を判断・サポートの是非を判断する。
形式がわかれば、さらにどんなメディアが入っているのかをしらべる。ビデオやオーディオのトラック数や幅、高さ、コーデックなど。
そのコーデックに対応していれば、そのデコーダを準備する。
そして最後に、時間に対応するデータの位置が示されたインデックスを調べる。これは例えば、t=5秒のビデオのデータはどこにあるのかとか。目次のようなもの。インデックスが最後にデータに格納されているのは、初めてファイルへの書き込みする際に、メディアの長さや各フレーム、データやオーディオサンプルの終わる場所がわからず、エンコーダがメディア全体のインデックスを構築して書き込むことができないから。

MP4ファイルの構成

AppleのQuickTimeのファイル形式の一つ。QTコンテナとかMOVコンテナも似た構造をもつ。
いくつかのセクションに分かれており、アトム、またはボックスと呼ばれる。

セクション

ftypeアトム:

ファイル形式(mp4, QuickTime etc.)についての情報がある。

mdatアトム:

エンコードされたメディアがひと塊のデータとして格納されている。

moovアトム:

メディアのメタデータを格納している。メディアのトラック、コーデック情報やインデックスなど。
これらのセクションが階層的に並んでいる。並び方は主に2つ。

階層

Non-fast-started mp4

ftype -> mdat -> moovの順番。
前述のように、書き込み時にはmoov情報がわからないので、最後に格納されてる。
HTTPで動画を再生する場合、はじめにmoovアトムを読み取る必要がある。 そのためには、ファイル全体をダウンロードするか、サーバから部分的にmoovアトムだけだけダウンロードしなくてはならない。この部分的にというのは、サーバ次第でできたりできなかったり。部分的ダウンロードができないと、シークができない。

Fast-started mp4

ftype -> moov -> mdatの順番。
ファイル全体をダウンロードする必要なし。順番に読み取っていけば良いので、moovアトムを見つけるための遅延もなく、スムーズに再生できる。

部分的ダウンロードの不可とシークの不可は一致。
さらにFast-startedの是非で以下4通りに場合分けできる。
・部分ダウンロード不可、Non-fast-started
全ファイルダウンロード、シーク不可。最悪。
・部分ダウンロード不可、Fast-started
シーク不可。
・部分ダウンロード可能、Non-fast-started
再生時にmoov探すための遅延が生じる。
・シーク可能、Fast-started
遅延もなく、シークも可能。理想。


階層の種類の見分け方

構造を解析するサイトとかある。
以下のコードでffmpegでも可能。

ffmpeg -v trace -i input

type:から始まる部分で,アトム,サイズ情報を見れる.
ただ,他のいらない情報も出てくるので,以下のようにやれば良い.

ffmpeg -v trace -i input 2>&1 | grep -e type:\'mdat\' -e type:\'moov\'

出力された順番の階層になってる.

Fast-started mp4にする

次のオプションをつける.多分出力前.

-movflags +faststart

なお,一度Non-fasted-started状態にしたから,mdatアトムとmoovアトムを変更している.→ちょっと時間かかる?

Non-fast-started mp4ファイル -> Fast-started mp4に変更

ffmepg -i input.mp4 -movflags +faststart -c copy out.mp4

-c copyオプションは,既にエンコードされたストリームを使用する場合.多分この方が早い.



アダプティブストリーミング

通常,動画は解像度・品質が固定されている.
ビデオの平均ビットレートがネットワーク帯域幅より大きい場合,止まって再生してを繰り返す.
そこで,アダプティブストリーミングによって,利用可能なネット帯域幅やプレイヤーのサイズなどに合わせて加増度を変化させる.

アダプティブストリーミングでは,メディアが数秒のファイルに分割されている.
プレイヤーはその数秒のファイルをダウンロードしつつ,ネット帯域幅が足りているかor余っているかを確認し続ける.
もし足りなくなったら or 余っていたら,帯域幅に適合するビットレートに変更する.


また,画面の大きさによっても,解像度が変更される.
例えば,480p,720pの中間にある解像度の場合,近い方が採用される.

アダプティブストリーミングの手法については主にHLS,DASHがある.



HLS vs. DASH

共通点

HTTPベースのため,専用サーバを必要とせず,従来のインフラのみで,ウェブ上でのストリーミングが可能.
アダプティブストリーミングにも記述したが,メディアを小さく分割して行う.
変種ストリームを記述したファイル(マニフェスト)があり,プレイヤーがこれを読み取る.
(多分,どのときにどの解像度で,みたいな.)
メディアソースの拡張機能であるMSEを使い,JavaScritptで再生できる.

HTTP Live Streaming; HLS

Appleが開発.2009年リリース.
最も普及してるストリームフォーマット.
最近の主要ブラウザで公式にHLSをサポートしているのは,Safariのみ.

コーデックはかなり限定的.H264, H.265のみ.

コンテナはTranspot Stream; TS形式か,fragmented MP4; fMP4.
昔はTSが唯一の形式.昔からあるので信頼性低めのUDPでも動作する.

マニフェストファイル(プレイリストとも呼ばれる)はM3U8ファイル.2部構成?
・マスタープレイリスト:メディアの情報を指してる
・メディアプレイリスト:セグメントをリストアップ


例:HLSストリームのファイル)
adaptive.m3u8 ← マスタープレイリスト
adaptive-240p-500k.m3u8 ← メディアプレイリスト1
adaptive-480p-2M.m3u8 ← メディアプレイリスト2
adaptive-720p-4M.m3u8 ← メディアプレイリスト3
adaptive-240p-500k-001.ts ← 以下,セグメントファイル
adaptive-240p-500k-002.ts
adaptive-240p-500k-003.ts
...

マスタープレイリストには,以下の情報が記載されている.
・ヘッダー情報
・バリデーションリスト(以下項目のこと)
 ・ビットレート
 ・解像度
 ・コーデックス
 ・それぞれのメディアプレイリスト

メディアプレイリストには,以下の情報が記載されている.
・ヘッダー情報
・.TSファイルのリスト
・そのファイルの時間

このメディアプレイリストの順番でシームレスに再生される.

Dynamic Adaptive Streaming over HTTP; DASH

MPEG(Motion Picture Experts Group)が開発.MPEG-DASHとも呼ばれる. 
MPEGはMP4とか開発したところ.
2012年にストリーミングの国際基準になる.(HLSとの違い)
公式にサポートしてるブラウザはない.

コーデックには依存しない.

コンテナはfMP4のみ.
fMP4は信頼性の高いネット,HTTPとかでパフォーマンスを発揮する.

マニフェストファイル(プレイリスト)はMedia Presentation Description; MPDファイル.
HLSのように分かれてないけど,複雑で冗長になってる.XML形式.

例:MPEG-DASHストリームのファイル)
adaptive.mpd ← マスタープレイリスト
init-stream3.m4s ← ストリームの初期化ファイル
init-stream2.m4s
init-stream1.m4s
init-stream0.m4s
chunk-stream3-00354.m4s ← 実際のメディアセグメント
chunk-stream3-00353.m4s ← chunkと呼ばれる?
chunk-stream3-00352.m4s ← mp4ファイルなんだと思う
...

マスタープレイリストは,HLSのものより冗長だけど,同じような情報が含まれている.
・ヘッダー情報
・ビットレート
・解像度
・コーデックス
・各ストリームでのセグメント情報



ビデオ圧縮の予備知識

ビデオは圧縮されると,一連のフレームで構成される.
それらフレームは,エンコード方法によって,いくつかのタイプに割り振られる.

フレームの種類

I(読:アイ)フレーム:
他フレームに依存しない(Independent)フレーム.独立してデコードが可能.
画像の全てのデータがそのまま含まれるので,多くのビット数を要する,
そのため,ビデオ全体のサイズに大きく作用する.
Iフレームから次のIフレーム手前までのグループをGOPという.(後述)

Pフレーム:
予測(Predicted)フレーム.前のフレーム(Iフレーム?)との差分をデータ化したもの.
差分は結構小さいので,ストレージをそんなに使用しない.

Bフレーム:
双方向予測(Bi directional predicted)フレーム.前と後ろのフレームに依存.
Pフレームよりもさらにストレージの消費が小さい.

Group Of Pictures; GOP

Iフレームから次のIフレーム手前までのフレームのグループ.
そのフレーム数をGOPサイズという.
あるGOP内のフレームがが別のGOPのフレームを参照しない構造をClosed GOP構造と呼ぶ.
最近の技術では,GOP間の参照も可能になっており,これをOpen GOP構造と呼ぶ.



セグメントの分解について

エンコードすることで,これらのI, P, Bフレーム群を分割し,ストリーミングをおこなっている.
では,どう分割するのが良いのか.

セグメント間の参照

通信良好状態用のストリームA,通信不良状態用のストリームBとする.
ビットレートはAの方が高い.
A→Bに切り替える際,もし切り替え後のBフレームがひとつ前のフレームを参照する場合,その参照フレームがあるセグメント全体をダウンロードしなくてはならない.もうAでストリーミングし終わっていたところと同じ部分をBでもダウンロードするという無駄なことになってしまう.
したがって,各セグメントは独立し,セグメント間の参照はあってはならない.つまり,セグメントはひとつ以上のClosed GOPを持つ.

セグメントの長さ

ストリームの切り替え時,セグメントの途中での切り替えは不可であり,セグメントのダウンロードが完了してから,次のセグメントをダウンロードする.
したがって,セグメントが長い場合,セグメントのダウンロードが終わるまでのその分だけ長く待つことになる.しかし,GOPサイズが上がり,Iフレームの数が少なくなるので,圧縮率は良くなる.
一方セグメントが短い場合,1セグメントには1Iフレームが必要であるため,その分圧縮率が低くなる.
そうすると動画の品質が犠牲に.保存,転送時にもオーバーヘッドが発生(時間がかかるということ).
つまり,セグメントの長さについては,圧縮率とストリームの切り替えの柔軟性がトレードオフ関係になる.
Appleは6秒推奨.2-4秒が良いっていう人もいるらしい.

コーデックについて

ストリームをエンコードするコーデックはH.264が一番無難.HLS, DASH両方で可能.
新しいコーデックとして,H265, VP9がある.H.264と同一品質でより圧縮率が高い,

H.265については,HLS,DASH両方でサポートされているもののH.264ほどの互換性はない.
そのまま再生でいないブラウザある.Chormeでもまだ?

VP9については,DASHのみサポート.だが,互換性はH.265より高い.

コンテナについて

TS か fragment MP4; fMP4の2択.

TSコンテナは,HLSのバージョン3の初期からサポートしていた唯一のもの.
古いプレイヤーを使う場合はこれ一択.基本オーディオと動画が一緒にミキシングされてる.
元々は信頼性の低い条件下で動作するように開発されてるので,より堅牢な設計になっており,オーバーヘッドがある.

HTTPベースのアダプティブストリーミングでは,fMP4の方が効率的.
MPEG-DASHが基準になると,fMP4が一般的になった.
AppleでもfMP4に対応.
セグメントは独立しておらず,ヘッダーが初期化セグメントに格納されている.
ストリーミング以外で個別のセグメントを再生したいなら,初期化する必要あり.


音声のミキシングについて

エンコード時に,セグメントに動画と音声をミキシングできる.
クライアント側の出の処理が減る.低ビットレートの時は,低品質の動画,音声を再生できるようになる.

動画と音声を一緒にミキシングせずにエンコードも可能.
ネットのに拘らず,一定の音声を再生したい場合はこっち.
動画は画質悪くなったりするけど,音声は一定.
アプリとかではこっちの方が実用的?



HLSかMPEG-DASHの選択

コーデック対応等の観点からすると,MPEGーDASHの方がやや先行.
しかし,HLSも更新されてきてるので,実用的にはそんな変わらない.

ひとつ考慮すべきは,MPEG-DASHがJavaScriptを必要とすること.
HLSはSafariならそのまま再生できる.

あるいは,二つとも用意しとく.
いくつかのビットレートでメディアを用意し,HLS,MPEGーDASHで使えるコーデックを用いてエンコードし,fMP4のセグメントに分解しておく.
MPEG-DASHのマニフェストファイル(.mpd),HLSのマスタープレイリスト(.m3u8)の二つを作成する.
これらのファイルは通常小さなテキストファイルのため,メディアファイルに比べて小さい領域しか使わない.
そして,クライアントの要件に応じて,どちらのストリームを使うかを判断することが可能.


ffmpegでストリーミング①:HLS,TSコンテナ,動画・音声muxed

ffmpeg -y -i input.mp4 \
> -filter_compolex "[0:v]fps=30,split=3[720_in][480_in][240_in]:[720_in]scale=-2:720[720_out]:[480_in]scale=-2:480[480_out]:[240_in]scale=-2:240[240_out]" \
> -map [720_out] -map [480_out] -map [240_out] -map 0:a -map 0:a -map 0:a \
> -b:v:0 3500k -maxrate:v:0 3500k -bufsize:v:0 3500k \
> -b:v:1 1690k -maxrate:v:1 1690k -bufsize:v:1 1690k \
> -b:v:2 326k -maxrate:v:2 326k -bufsize:v:2 326k \
> -b:a:0 128k \
> -b:a:1 96k \
> -b:a:2 64k \
> -x264-params "keyint=60:min-keyint=60:scenecut=0" \
> -var_stream_map "v:0,a:0,name:720p-4M v:1,a:1,name:480p-2M v:2,a:2,name:240p-500k" \
> -hls_time 2 \
> -hls_list_size 0 \
> -hls_segment_filename adaptive-%v-%03d.ts \
> -master_pl_name adaptive.m3u8 \
> adaptive-%v.m3u8

a[0:v]fps=30

わかりやすくするために,fps=30と明示.

split=3[720_in][480_in][240_in]:

異なるビットレートでストリームするために,3つに分ける.[]はラベル.

[720_in]scale=-2:720[720_out]:[480_in]scale=-2:480[480_out]:[240_in]scale=-2:240[240_out]

各サイズにする.

-map [720_out] -map [480_out] -map [240_out] -map 0:a -map 0:a -map 0:a \

各動画,各動画のそれぞれで使用する音声(同一)をマッピング.次のコマンドで使用.

-b:v:0 3500k -maxrate:v:0 3500k -bufsize:v:0 3500k
-b:a:0 128k
平均?ビットレート,最大ビットレート,バッファイサイズのみ指定.
エンコーダはこれの範囲内にしようと頑張ってくれる.

-x264-params "keyint=60:min-keyint=60:scenecut=0"

どれだけiフレームを生成するか.libx264エンコーダに渡される.
keyintにiフレームの最大間隔.min-keyintに最小間隔.scenecutの有効無効(デフォで有効?).
ffmpegでは,iframeでセグメントが始まるようにかつ,各セグメントが独立するように分割を行う.
そのため,このパラメータをうまく指定してiフレーム作成しないと,思ったようなセグメントの長さにならない.
うまくできれば,思った通りの長さ(最後のセグメントは残りになるけど)になる.
今回は30 fpsの動画で,2秒のセグメントにしたいので,60フレーム毎としている.
また,libx264エンコーダは自動的に画面が切り替わる時にiフレームを入れてくれる(scenecut).
が,今回はGOPのサイズを一定にして,セグメント時間を一定にしたいので,無効(0)にする.

-hls_time 2

セグメントの時間2秒.iフレームがどれだけあるかによって変わるので,平均がこれに近いような値にしてくれる.
-x264-params パラメータで指定するともっと正確になる.

-var_stream_map "v:0,a:0,name:720p-4M v:1,a:1,name:480p-2M v:2,a:2,name:240p-500k"

ストリームの構成.

-hls_list_size 0

マニフェスト内の全てのセグメントを保持する.(?)
これない場合,近いところのセグメントしか保持されない.(?)
プレイヤーに近いところから開始させるならいらない.(?)
多分,シークしたらすぐ再生できるみたいなこと?

-hls_segment_filename adaptive-%v-%03d.ts

セグメントファイル名の指定.
たくさんあるので,テンプレート構文で.

-master_pl_name adaptive.m3u8

マスタープレイリストファイル名の指定.

adaptive-%v.m3u8

?

ffmpegでストリーミング②:HLS,TSコンテナ,動画・音声別

ffmpeg -y -i input \
> -filter_complex "[0:v]fps=30,split=3[720_in][480_in][240_in]:[720_in]scale=-2:720[720_out]:[480_in]scale=-2:480[480_out]:[240_in]scale=-2:240[240_out]" \
> -map [720_out] -map [480_out] -map [240_out]  -map 0:a \
> -b:v:0 3500k -maxrate:v:0 3500k -bufsize:v:0 3500k \
> -b:v:1 1690k -maxrate:v:1 1690k -bufsize:v:1 1690k \
> -b:v:2 326k -maxrate:v:2 326k -bufsize:v:2 326k \
> -b:a:0 128k \
> -x264-params "keyint=60:min-keyint=60:scenecut=0" \
> -var_stream_map "a:0,agroup:a128,name:audio-128k v:0,agroup:a128,name:720p-4M v:1,agroup:a128,name:480p-2M v:2,agroup:a128,name:240p-500k" \
> -hls_time 2 \
> -hls_list_size 0 \
> -hls_segment_filename adaptive-%v-%03d.ts \
> -master_pl_name adaptive.m3u8 \
> adaptive-%v.m3u8

はじめの方が前項と同じ.

-map [720_out] -map [480_out] -map [240_out] -map 0:a

音声は1度しか指定しない.128 kpbsのみ.

-var_stream_map "a:0,agroup:a128,name:audio-128k v:0,agroup:a128,name:720p-4M v:1,agroup:a128,name:480p-2M v:2,agroup:a128,name:240p-500k"

音声に"a128"という識別子と,"audio-128k"というラベルを貼る.
各動画で,"a128"を指定してやる.

これで,音声と動画が別セグメントになってるはず.

ffmpegでストリーミング③:HLS,fMP4コンテナ

ffmpeg -y -i input \
> -filter_complex "[0:v]fps=30,split=3[720_in][480_in][240_in]:[720_in]scale=-2:720[720_out]:[480_in]scale=-2:480[480_out]:[240_in]scale=-2:240[240_out]" \
> -map [720_out] -map [480_out] -map [240_out]  -map 0:a \
> -b:v:0 3500k -maxrate:v:0 3500k -bufsize:v:0 3500k \
> -b:v:1 1690k -maxrate:v:1 1690k -bufsize:v:1 1690k \
> -b:v:2 326k -maxrate:v:2 326k -bufsize:v:2 326k \
> -b:a:0 128k \
> -x264-params "keyint=60:min-keyint=60:scenecut=0" \
> -var_stream_map "a:0,agroup:a128,name:audio-128k v:0,agroup:a128,name:720p-4M v:1,agroup:a128,name:480p-2M v:2,agroup:a128,name:240p-500k" \
> -hls_segment_type fmp4 \
> -hls_time 2 \
> -hls_list_size 0 \
> -hls_fmp4_init_filename adaptive-%v-init.m4s \
> -hls_segment_filename adaptive-%v-%03d.m4s \
> -master_pl_name adaptive.m3u8 \
> adaptive-%v.m3u8

-hls_segment_type fmp4

ここの部分を追加して,Fragmented-MP4に指定.

-hls_fmp4_init_filename adaptive-%v-init.m4s
-hls_segment_filename adaptive-%v-%03d.m4s

fmp4では,初期化セグメントとデータセグメントに分かれるので,これも指定.
.m4sに注意.

ffmpegでストリーミング④:DASH,fMP4コンテナ

ffmpeg -y -i input \
> -filter_complex "[0:v]fps=30,split=3[720_in][480_in][240_in]:[720_in]scale=-2:720[720_out]:[480_in]scale=-2:480[480_out]:[240_in]scale=-2:240[240_out]" \
> -map [720_out] -map [480_out] -map [240_out]  -map 0:a \
> -b:v:0 3500k -maxrate:v:0 3500k -bufsize:v:0 3500k \
> -b:v:1 1690k -maxrate:v:1 1690k -bufsize:v:1 1690k \
> -b:v:2 326k -maxrate:v:2 326k -bufsize:v:2 326k \
> -b:a:0 128k \
> -x264-params "keyint=60:min-keyint=60:scenecut=0" \
> -seg_duratin 2 \
> adaptive.mpd

大体同じ.

adaptive.mpd

HLSではなく,DASHを用いる用に.mpdファイルで指定..

-seg_duratin 2

セグメント時間は,-hls_timeに代わってにこれを用いる.

名前の指定とかはffmpegのDASH muxerではサポートされてない.
自動的に生成される.

また,ffmpegではMPEG-DASHでミキサーするには制限があるらしく,音声と動画を一緒にミキサーはできないらしい.
基本的なことはできる.


ffmpegでストリーミング⑤:HLS+DASH

ffmpeg -y -i input \
> -filter_complex "[0:v]fps=30,split=3[720_in][480_in][240_in]:[720_in]scale=-2:720[720_out]:[480_in]scale=-2:480[480_out]:[240_in]scale=-2:240[240_out]" \
> -map [720_out] -map [480_out] -map [240_out]  -map 0:a \
> -b:v:0 3500k -maxrate:v:0 3500k -bufsize:v:0 3500k \
> -b:v:1 1690k -maxrate:v:1 1690k -bufsize:v:1 1690k \
> -b:v:2 326k -maxrate:v:2 326k -bufsize:v:2 326k \
> -b:a:0 128k \
> -x264-params "keyint=60:min-keyint=60:scenecut=0" \
> -hls_playlist 1 \
> -hls_master_name adaptive.m3u8 \
> -seg_duratin 2 \
> adaptive.mpd


-hls_playlist 1
-hls_master_name adaptive.m3u8

HLSマスタープレイリストの名前を指定するこの2行を追加.

プレイヤー側で,.m3u8と.mpdの再生ができる.







音声フィルタ

音声チャンネルを統合する: amerge

チャンネルを重ねることができる.ステレオをモノにとか.

inputs=2


amix

音声ストリームのマージ.
ただし,音声が正規化?されるため,全体的に小さくなる.

input

入力ストリーム数.必須?

音声チャンネルを同一にする
pan



動画フィルタ

scale
overlay
解像度の変更: scale
scale=480:-2

解像度の指定.指定しない場合は,inputの動画サイズと同じ.


余白を追加する: pad
w:h:

動画を貼り付けるx, 動画を貼り付けるy

使える定数

・入力ビデオの幅/高さ: in_w, iw / in_h, ih
・出力ビデオの幅/高さ: out_w, ow / out_h, oh
・入力ビデオの iw / ih
・入力ビデオのアスペクト比: sar

サイズ確認

ffprobe -v error input -select_streams v -show_streams v -show_entries stream=width,height

画像でも可能.

動画再生

ffplay input.mp4 -v error -an -top 240 -y 835


-v

出力オプション

error

エラー時のみ出力.

quiet

出力0.

-an

音なし

-top -y

動画ウィンドウの位置.


動画をトリミングする

開始時刻と終了時刻
を指定する

ffmepg -y -v error -i input -ss 00:02:22.000 -to 320.0 output

-ss

開始時刻。
タイムコード形式(hh:mm:ss.sss) か、秒数形式で指定。

-to

終了時間。
タイムコード形式(hh:mm:ss.sss) か、秒数形式で指定。

開始時刻とトリミング時間を指定する

ffmepg -y -v error -i input -ss 00:02:22.000 -t 5 output

-ss

開始時刻。
タイムコード形式(hh:mm:ss.sss) か、秒数形式で指定。

-t

トリミング秒数。

動画をクロップする

https://ffmpeg.org/ffmpeg-filters.html#toc-crop

位置サイズを数値指定する

Crop area with size 100x100 at position (12,34).
crop=100:100:12:34
Using named options, the example above becomes:
crop=w=100:h=100:x=12:y=34

x, yのデフォは中央
w, hのみで中央クロップ

crop=100:100



動画をつなげる (Merging, Stitching)

ステップ1:リスト作る

list.txt
file 'input1.mp4'
file 'input2.mp4'
file 'input3.mp4'

ただし,ファイルのコーデック,fpsが同一でなければならない.

ステップ2:連結する

ffmpeg -y -v error -f concat -i list.txt output.mp4

エラー

Unsafe file name 'input.MP4'
list.txt: Operation not permitted

-safe 0
をつける.

ffmpeg -y -v error -safe 0 -f concat -i list.txt output.mp4




サムネ作成

1枚出力する場合

ffmpeg -v error -i input.mp4 -ss 2 -vframes 1 -vf scale=480:-2 out.jpg


-ss:

開始位置.
タイムコード形式(hh:mm:ss.sss) か,秒数形式で指定.

-vframes:

出力する何フレーム数.



複数出力する場合

ffmpeg -v error -i input -vf fps=1,scale=480:-2 out_%2d.jpg

fps

出力頻度.=1なら1秒に1枚出力.

out_%2d.jpg

%2dとすることで,out_01.jpg, out_02.jpg, out_03.jpg, ... となる.



サイズ変更

ffmpeg -v error -y -i input -vf scale=1280:720 cow_720p.mp4

 -vf scale

横:縦. -1, -2にすると自動で変更.
-1の場合,いいように勝手に丸めてくれる ,奇数だとダメ.
-2の場合,偶数になるように丸めてくれる
また,アスペクト比を維持しながら,特定の枠内に収めたい場合は引数を以下のようにする.

w:h:force_original_aspect_ratio=decrease


余白を作り動画のアスペクト比を変更

ffmpeg -v error -y -i input -vf "scale=640:480:force_original_aspect_ratio=decrease,pad=640:480:(ow-iw)/2:(oh-ih)/2" out

このコマンドでは,中央に貼り付けてる.
黒い余白ができる.




動画に重ねる

ffmpeg -v error -y -i input.mp4 -i input.png -filter_complex "overlay=x=main_w-overlay_w-50:y=50" out.mp4

-filter_complex "overlay"

2つの入力を受け取る.重ねられる下側 (main),重ねる上側の順(overlay).
2つの入力があるため,-filter_complexフラグが必要.(参照:ffmpeg フィルター)

x:
overlayの左上の位置x.

y:

overlayの左上の位置y.

なお,以下のように指定できる.
overlay_w, overlay_h: overlayのw, h.
main_w, main_h: mainのw, h.

左上:

x=50:y=50

右上:

x=main_w-overlay_w-50:y=50

右下:

W-w-50:H-h-50


透過して重ねる

ffmpeg -v error -y -i input.mp4 -i input.png -filter_complex "[1:v]colorchannelmixer=aa=0.4[transparent_img];[0:v][transparent_img]overlay=x=main_w-overlay_w-50:y=50" out.mp4

画像の方に,透明化のフィルタを加える

colorchannel=aa

透明化フィルタ.

aa:

透明度.

サイズ変更して重ねる

ffmpeg -v error -y -i input.mp4 -i input.png -filter_complex "[1:v]scale=-1:100[smaller_img];[0:v][smaller_img]overlay=x=main_w-overlay_w-50:y=50" out.mp4

スケール変更フィルタを追加.

2枚重ねる

ffmpeg -v error -y -i input.mp4 -i img1.png -i img2.png -filter_complex "[1:v]scale=-1:100[smaller_img1];[0:v][smaller_img1]overlay=x=main_w-overlay_w:y=50[after_img1]:[after_img1][2:v]overlay=W-w-50:H-h-50" out.mp4



テキストの描画

ffplayで様子見ながらやるといい.

ffplay input.mp4 -v error -an -top 240 -y 835 -vf "drawtext=fontfile='/System/Library/Fonts/Supplemental/Academy Engraved LET Fonts.ttf':text=HOGEEE:fontsize=48:x=100:y=100"

drawtext

テキストの描画フィルタ.

fontifile

'/path/to/font.tff'


text

描画する文字列.

fontsize

文字サイズ.デフォルトは結構小さい.10前後?
動画の高さの半分の大きさにするには,
fontsize=h/2

x, y

描画する位置.デフォルトは0, 0 (左上).
中央に描画させるなら,
x=(w-text_w)/2:y=(h-text_h)/2

下から徐々に上がってくるようにするなら
y=(h-t*200)

使用できる変数・定数

t: 時間 mili seconds?
w, h: フレームの幅,高さ.
text_w, text_h: 描画テキストの幅,高さ.

fontcolor

文字色.
green,redといった文字列 または,RGBaの16進数で指定できる.

enable

描画に関する制限.2秒から3秒まで描画とか.

時間で指定

'between(t,3,4)'
動画の3秒から4秒まで描画.

timecode

タイムコード(経過時間とか)を描画.
text=:としておく.
開始時のタイムコードを引数にとる.'\:00\:00\:00\:00'

rate

タイムコード用のfps.
rate=30000/1001

box

囲みボックスのon.
有効にする場合,1を引数に取る.

boxborderw

囲みボックスの線幅.

boxcolor

囲みボックスの色.塗りつぶし?


四角を描画する

ffmpeg -i input.mp4 -vf "drawbox=drawbox=x=10:y=20:w=200:h=60:color=red@0.5
:t=3" output.mp4

動画の幅,高さは変数iwihで扱える.
x, y:
左上からのx, y座標.マイナスも可能.
w, h:
描画する四角の幅,高さ.線幅も含まれる.+2t
color; c:
色.何色ができるのかは知らない.

@0.5
透過率.1は透過せず.0.9でもしてない気がする.
t=fillでぬりつぶし.




音声チャンネルの情報

ffprobe -v error input.m4a -select_streams a -show_entries stream=index,codec_name,channels -print_format json

-show_entries

出力する情報を限定する.

stream

ストリーム情報のうち,指定したものを出力する.
コーデック:codec_name
チャンネル数:channels





音声チャンネルを抽出

2ストリーム x 2ch. の場合.

ffmpeg -v error -y -i input.m4a -filter_complex "amerge=input=2,asplit=4[audio0][audio1][audio2][audio3];[audio0]pan=mono|c0=c0[ch0];[audio1]pan=mono|c0=c1[ch1]:[audio2]pan=mono|c0=c2[ch2];[audio3]pan=mono|c0=c3[ch3]" -map [ch0] ch0.m4a -map [ch1] ch1.m4a -map [ch2] ch2.m4a -map [ch3] ch3.m4a 


複数チャンネルを持つストリームが複数ある場合,1ストリームにした方が操作しやすい.

amerge

音声ストリームのマージ.

input

入力ストリーム数.必須?

asplit

音声ストリームを分割する.
分割数が必要.

各チャンネルをものチャンネルとして出力する.

pan

複数のチャンネルをミックスしたり,レイアウトできる.
はじめに,チャンネル数,チャンネルレイアウトを指定する.

モノチャンネルの場合: mono
ステレオの場合: streo
その後,各チャンネルの構成を指定する.各構成は|で区切る.

pan=mono|c0=c0

構成部分について,左側は出力チャンネル.モノチャンネルなら単一チャンネルなので,c0だけ指定しておく.
右側は構成するチャンネル.入力が4チャンネルなら,c0, c1, c2, c3から指定.
ステレオなら,FL(Front Left), FR(Front Right)を指定してやる.

pan=stereo|FL=c0+c3|FR=c1+c2


音声チャンネルを別チャンネルとして統合

ffmpeg -v error -y -i ch0.m4a -i ch1.m4a -i ch2.m4a -filter_ocmplex "amerge=input=3" out.m4a


amerge

音声ストリームのマージ.

input

入力ストリーム数.必須?

音声チャンネルを同一チャンネルに統合

音声正規化

ffmpeg -v error -y -i ch0.m4a -i ch1.m4a -i ch2.m4a -filter_complex "amix=input=3" out.m4a


音声そのまま

ffmpeg -v error -y -i ch0.m4a -i ch1.m4a -i ch2.m4a -filter_complex "amerge=input=3,pan=mono|c0=c0+c1+c2+c3" out.m4a


音声のゲインを各チャンネルで変えて結合

ffmpeg -v error -y -i ch0.m4a -i ch1.m4a -i ch2.m4a -filter_complex "amerge=input=3,pan=mono|c0=2*c0+c1+0.5*c2+0.1*c3" out.m4a


複数音声チャンネルをステレオに

ffmpeg -v error -y -i ch0.m4a -i ch1.m4a -i ch2.m4a -i ch3.m4a -filter_complex "amerge=inputs=4,pan=stereo|FL=c0+c2|FR=c1+c3" out.m4a


エラー

zsh: no matches found: [hoge]

[hoge]を""で囲む. -map "[ch0]"