mpv * Linux でハードウェアビデオアクセラレーション

この話は

  • 各ビデオカードにはビデオエンコード/デコード支援チップが載っている
  • QSVとかUVDとかVCEとかNVENCとかNVDECとか名前がついてる
  • Linux的にはVDPAUとVA-APIというAPIがある
  • Nvidiaの場合はNVENC直 (NVDEC直も可)
  • CUDAを使ったCUVIDってのもある
  • mpvで再生支援するのが便利

っていうのは理解しているという前提で始まる。

それは、「結局渡すべきパラメータはなに?」って話である。 なお、VDPAU及びVA-APIは有効である前提で話す。それがわからない人はArchwikiへGo

はじめに

mpvを使うと非常に便利で、

$ mpv video.mp4

みたいな話なんだけれども、mpvには--hwdec--voというオプションがあり、ハードウェアビデオアクセラレーションを行う場合はこれらを指定する。

で、--hwdecは話としては簡単だ。ハードウェアデコーダを使うという話。つまりはコーデック的な話。

じゃ--voは? という話になるのだが、これは「ビデオ出力ドライバ」の指定。 なんじゃそら…という感じなのだけれど、「エンコードと描画レイヤーは別の話」みたいなことらしい。 だからSDLとか、Direct3Dとか出てくる。 YUVビデオとかそのまま書くんじゃないの?とかいう気持ちになったけれど、そんなことはないようで、「ハードウェアでデコードしたらハードウェアで書くところまでしないと効果なし」みたいな話になるようだ。

とはいえ、--vox11なんてすると凄まじくCPU負荷が増えてしまうし、xvを使う理由も全くない。 だから現実的な選択肢としては、vdpau, vaapi, gpuの3つだ。

試してみる

vdpau + vdpau

VDPAUでデコードしてVDPAUで出力する、というのは悪くないようだ。

ただし、この場合ポストプロセスはVDPAUでやることになる。 VDPAUはポストプロセスに対応しているからできるのだけど、一部使えなくなるものもある。例えば、ズームは効かなくなる。

vdpau + gpu

VDPAUで出力するよりも軽い。

そしてフィルタ等はすべて使える。

vaapi + vaapi

ちゃんとアクセラレーションが効いて軽くなるけれど、エフェクト、フィルタなどは一切使えなくなる。 マニュアルにも、だめなシステム向けだと書いてある。

vaapi + gpu

VA-APIだと--vogpu指定にすべきなようだ。

ちなみに、VDPAUだと--voを書かなくても十分アクセラレーションが効くのだけど、VA-APIの場合は--vo必須。

NVDEC / CUVID

--vogpu一択。ほかはそもそも使えない。

結局…?

Intel

alias mpv='mpv --hwdec=vaapi --vo=gpu,vaapi'

AMD, Nvidia (nvドライバ)

alias mpv='mpv --hwdec=vdpau --vo=gpu,vdpau'

Intel同様にVA-APIを使っても構わない。 ただ、再生だけを考えるならVDPAUのほうが少し良い感じがする。

nvドライバ環境でハードウェアビデオアクセラレーションすべきかどうか自体が疑問。

Nvidia (nvidiaドライバ)

alias mpv='mpv --hwdec=nvdec --vo=gpu --profile=gpu-hq'

NVDEC直のほうが速い。

gpu-hq

通常の--vo=gpuはフェイルセーフで、--profile=gpu-hqすると品質優先、とのことなのだけど、 試してみた限りでは、特にgpu-hqして問題になるケースは見つからなかったので、--profile=gpu-hqつけても良いかもしれない。

その場合はfallback用に指定しているvaapivdpauvoは必要ないというか、つけないほうが良い。

私の設定

alias mpvpau="mpv --loop-playlist=yes --hwdec=vdpau --vo=gpu --profile=gpu-hq --prefetch-playlist=yes --video-latency-hacks=yes --osd-font='Fira Sans' --osd-font-size=23 --sub-font='MotoyaLCedar' --sub-font-size=32 --sub-blur=3.5 --script=playlistmanager --script-opts=playlistmanager-loadfiles_on_start=yes"
alias mpvva="mpv --loop-playlist=yes --hwdec=vaapi --vo=gpu --profile=gpu-hq --prefetch-playlist=yes --video-latency-hacks=yes --osd-font='Fira Sans' --osd-font-size=23 --sub-font='MotoyaLCedar' --sub-font-size=32 --sub-blur=3.5 --script=playlistmanager --script-opts=playlistmanager-loadfiles_on_start=yes"
alias mpvnv="mpv --loop-playlist=yes --hwdec=nvdec --vo=gpu --profile=gpu-hq --prefetch-playlist=yes --video-latency-hacks=yes --osd-font='Fira Sans' --osd-font-size=23 --sub-font='MotoyaLCedar' --sub-font-size=32 --sub-blur=3.5 --script=playlistmanager --script-opts=playlistmanager-loadfiles_on_start=yes"
alias mpvcud="mpv --loop-playlist=yes --hwdec=cuda --vo=gpu --profile=gpu-hq --prefetch-playlist=yes --video-latency-hacks=yes --osd-font='Fira Sans' --osd-font-size=23 --sub-font='MotoyaLCedar' --sub-font-size=32 --sub-blur=3.5 --script=playlistmanager --script-opts=playlistmanager-loadfiles_on_start=yes"
alias mpv="mpv --hwdec=auto --vo=gpu --sub-font='MotoyaLCedar' --sub-font-size=32 --sub-blur=3.5"

playlistmanagerスクリプトを使っている。 単独のmpvコマンドだけが単一ファイル用。

LinuxでNvidiaもIntelもおかしなことになっているのでRadeonにかえてみた

もういやだ

パワフルなThinkStation P720ワークステーションだが、最近様子がおかしい。 Nvidiaではおなじみの

  • 画面が点滅する
  • X11 APIでスクリーンキャストするとウィンドウが消えてしまう (だからスクリーンショットでもウィンドウが消える)

という問題は直る気配がない…どころか、従来はVblankとFlippingを禁止すれば抑制できたのだが、最近はダメだ。 さらにいえば、Nvidia固有だったこの問題は、最近ではIntelでも発生する、というかINtelのほうがひどくなっている。

そして、追加で

  • Libreofficeが使っているSAL PLUGINとglibの連携が腐ってしまって、ほとんど操作不能なレベルでフリーズする
  • Vivaldiでありとあらゆる操作においてフリーズする

という問題が追加された。 Libreofficeの問題は最初Nvidiaだけだったが、現在はIntelでも発生するし、SAL_USE_VCLPLUGIN=genで防げたのだが、現在はこれも無理である。

そして、4kディスプレイにしてからビデオメモリが足りないのか、ウィンドウを開いていくとウィンドウ領域がグリッド状に表示され、かすかにウィンドウが見える場合もあるがほとんどの場合見えず、操作もできないという状態になる、ということに悩まされた。 作業効率が恐ろしく悪いことになってしまうため、毎日とてもストレスだし、貴重な時間を、1日で1-2時間程度失っている状態だった。

もうこれは耐えられない。

一方、Godavariはこのような問題を発生しない。 「じゃあGodavariでやれよ」と思うかもしれないが、Godavariは全面的にとっても非力である。よく馬鹿にされるくらいには。

それで、現在の出費は痛いし、TSMCは7mmプロセッサを控えている状態だというのはわかっているが、 結局のところRadeon 3000シリーズは噂の域を出ないということも踏まえて、思い切ってRadeon RX580を購入することにした。

なぜRX580か

最大の理由はLinuxにおけるパフォーマンスである。

WindowsにおいてはVega RXもそれなりの性能を示すようだが、Linuxにおいては多くの場合Vega RXとの性能差は誤差の範疇に留まる。 Vega RXでもGTX1060は越えない、というような所ぅたいだ。

にもかかわらずVega RXはずっと高値を維持しており、相当にコストパフォーマンスが悪い。 しかも、Vega RXはNvidiaと比べても相当燃費が悪いようで、「電気をめちゃくちゃ食う」のである。

そもそも私のP720はQuadro P6000のSLIを想定しているためキャパシティとしては耐えられないこともないのだが、家の電気回線はそうではないし、 無駄な電気は使いたくない。

また、Vega RXのパフォーマンスはVega RX 64であっても「Nvidia GTX1070に届かない程度」というのがWindowsにおいても現実であるようで、 ゲームのことを考えて高性能なカードを選ぶ、という気にもなれなかった。

タイミングは悪いなぁ、やたら高いなぁと思いつつも、Linuxにおいてはベストな選択肢となりそうなRX580を選択したということだ。

製品はAMD専門メーカーSapphireのゲーミング向けNITRO+シリーズSA-RX580-8GDN+001V2 VD6801を選択した。 オーバークロック製品で、発熱量は多いが性能は高いようだ。

P720にSapphire NITRO+ RX580は「ギリギリ入る」

製品が届いてびっくりした。 「大きい」

いやもう、比べるのが無意味なぐらい大きい。 「ミドルクラスだし、GTX960と同じくらいだろう」とか思ってサイズのことは一切気にしなかったのだが、「これはやばいかもしれない」と感じるほど大きかった。 ゲーミング向けトップモデルはこれより大きいのか!?

入らないかもしれない、と懸念したが、結局はギリギリながら収まった。 上下とも入るが、下段に関しては電源配線に触れてしまう。 また、サイドパネルに接触するため、サイドパネルがしめづらくなる。

「普通に入る」とは言い難い、「かろうじて入った」である。 だが、入る。

なお、SA-RX580-8GDN+001V2は補助電源が8ピン+6ピンというGTX1080Ti並の要求で、P720の標準の補助電源は2本であるためこれを全部使ってしまい、SLI構成はできない。 汎用の拡張コネクタがあるのだが、こちらは専用品で、なおかつLenovoとして単体の販売はしていないので、Crossfire構成にしたい場合は予めP6000のような「補助電源を2つ使う」ビデオカードを2枚構成にしておく必要がある。

クーリングパイプがまるでインテークマニホールドのようで、さらにSAPPHIREのロゴが青く輝き、大変かっこいい。 まぁ、P720の場合サイドパネルが透明なわけでもないので、全く見えないが。

消費電力は

4114+Quadro P400構成と比較すると、アイドル時で107Wと、約60W増えた。 運用時も140から220Wで、60W増加と見ていいだろう。 ただし、変動しやすくなったため、平均すると80W増加とみたほうがいいかもしれない。

ただし、変動しやすくなったのは、「今までP400で処理しきれなかった分を即座に処理する瞬発力があるため」と見ることができ、効率的には変わっていないかもしれない。

「省電力」という印象はなくなってしまったが、性能を考えればまぁ想定通りといったところ。

問題は解消したか

ほぼyesである。

  • 画面の点滅はなくなった。代わりにログイン時に画面がおかしくなることがあるが、支障は実際にはない
  • スクリーンショット、及びスクリーンキャスティングでウィンドウが消える不具合はなくなった
  • Libreofficeがフリーズする問題は解消された
  • Vivaldiが異様にフリーズするという問題は 軽減された
  • ウィンドウが表示できなくなる問題は解消された

また、私が非常に不満としていた、私お気に入りのフラゲ1が重すぎるという問題が事実上解消された。

この問題自体はつい先日からChromiumがマルチスレッドでFlashを処理してくれるようになり、最大で12.5%(5スレッド)で処理してくれるためにかなり軽減されてはいたのだが、 ビデオ描画のもたつきがなくなったためか、全く支障なくなった。 不思議なものだ。 まぁ、Flashはビデオアクセラレーションの対象ではあるのだが。

ちなみに、このゲームがあまりにも重いのは「4114が非力で、うち特有の問題」と考えていたのだが、先日Thinkpad X1でやってみたところ、とてもプレイできないくらい重かった。 というわけで、むしろ「このハイパフォーマンスマシンですらもこの程度」という状態だったと考えられる。 恐らくはWindowsであれば支障ないのだろう。

Vivaldiの重さはどこから

RX580になってVivaldiが操作のたびに、あるいはフォーカスするたびに止まる (タブ=レンダリングプロセスが止まるのではなく、Vivaldi全体が止まる)という問題は解消された。

ちなみに、Intelはこの問題はより深刻で、Vivaldiを立ち上げたあとメニュー操作をするとウィンドウマネージャごと固まってしまう。

だが、依然としてふたつの問題がある。

ひとつは、右クリックでメニューを開くとかなり長い時間固まるということだ。 これはstraceしてみると

read(17, "!", 2)                        = 1
write(18, "!", 1)                       = 1
openat(AT_FDCWD, "/usr/local/share/fonts/Commercial/FONT-COMP-SET21/Fontstyles2/FontGraphic_Mac/UniversalWalk.otf", O_RDONLY) = 251
fstat(251, {st_mode=S_IFREG|0644, st_size=8832, ...}) = 0
mmap(NULL, 8832, PROT_READ, MAP_PRIVATE, 251, 0) = 0x7fc6fd5f7000
close(251)                              = 0
munmap(0x7fc6fd5f7000, 8832)            = 0
openat(AT_FDCWD, "/usr/local/share/fonts/Commercial/FONT-COMP-SET21/Fontstyles2/FontGraphic_Mac/UniversalWalk.otf", O_RDONLY) = 251
fstat(251, {st_mode=S_IFREG|0644, st_size=8832, ...}) = 0
mmap(NULL, 8832, PROT_READ, MAP_PRIVATE, 251, 0) = 0x7fc6fd5f7000
close(251)                              = 0
munmap(0x7fc6fd5f7000, 8832)            = 0
openat(AT_FDCWD, "/usr/local/share/fonts/Commercial/FONT-COMP-SET21/Fontstyles2/FontGraphic_Mac/UniversalWalk.otf", O_RDONLY) = 251
fstat(251, {st_mode=S_IFREG|0644, st_size=8832, ...}) = 0
mmap(NULL, 8832, PROT_READ, MAP_PRIVATE, 251, 0) = 0x7fc6fd5f7000
close(251)                              = 0
munmap(0x7fc6fd5f7000, 8832)            = 0
openat(AT_FDCWD, "/usr/local/share/fonts/Commercial/FONT-COMP-SET21/Fontstyles2/FontGraphic_Mac/UniversalWalk.otf", O_RDONLY) = 251
fstat(251, {st_mode=S_IFREG|0644, st_size=8832, ...}) = 0
mmap(NULL, 8832, PROT_READ, MAP_PRIVATE, 251, 0) = 0x7fc6fd5f7000
close(251)                              = 0
munmap(0x7fc6fd5f7000, 8832)            = 0
openat(AT_FDCWD, "/usr/local/share/fonts/Commercial/FONT-COMP-SET21/Fontstyles2/FontGraphic_Mac/UniversalWalk.otf", O_RDONLY) = 251
fstat(251, {st_mode=S_IFREG|0644, st_size=8832, ...}) = 0
mmap(NULL, 8832, PROT_READ, MAP_PRIVATE, 251, 0) = 0x7fc6fd5f7000
close(251)                              = 0
munmap(0x7fc6fd5f7000, 8832)            = 0
openat(AT_FDCWD, "/usr/local/share/fonts/Commercial/FONT-COMP-SET21/Fontstyles2/FontGraphic_Mac/UniversalWalk.otf", O_RDONLY) = 251
fstat(251, {st_mode=S_IFREG|0644, st_size=8832, ...}) = 0
mmap(NULL, 8832, PROT_READ, MAP_PRIVATE, 251, 0) = 0x7fc6fd5f7000
close(251)                              = 0
munmap(0x7fc6fd5f7000, 8832)            = 0
openat(AT_FDCWD, "/usr/local/share/fonts/Commercial/FONT-COMP-SET21/Fontstyles2/FontGraphic_Mac/UniversalWalk.otf", O_RDONLY) = 251
fstat(251, {st_mode=S_IFREG|0644, st_size=8832, ...}) = 0
mmap(NULL, 8832, PROT_READ, MAP_PRIVATE, 251, 0) = 0x7fc6fd5f7000
close(251)                              = 0
munmap(0x7fc6fd5f7000, 8832)            = 0
openat(AT_FDCWD, "/usr/local/share/fonts/Commercial/FONT-COMP-SET21/Fontstyles2/FontGraphic_Mac/UniversalWalk.otf", O_RDONLY) = 251
fstat(251, {st_mode=S_IFREG|0644, st_size=8832, ...}) = 0
mmap(NULL, 8832, PROT_READ, MAP_PRIVATE, 251, 0) = 0x7fc6fd5f7000
close(251)                              = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38d9095000, 8994816, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab8b000, 49152, MADV_DONTNEED) = 0
madvise(0x3a38d9095000, 8994816, MADV_DONTNEED) = 0
access("/usr/local/share/fonts/DeletedManjaro/UmePlus/umeplus-p-gothic.ttf", R_OK) = 0
madvise(0x3a38dab8b000, 385024, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab8b000, 49152, MADV_DONTNEED) = 0
madvise(0x3a38d9095000, 8994816, MADV_DONTNEED) = 0
access("/usr/share/fonts/TTF/DejaVuSans.ttf", R_OK) = 0
madvise(0x3a38dab8b000, 385024, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab8b000, 49152, MADV_DONTNEED) = 0
madvise(0x3a38d9095000, 8994816, MADV_DONTNEED) = 0
access("/usr/local/share/fonts/Monospace/font-bh-ttf-1.0.3/luxisr.ttf", R_OK) = 0
madvise(0x3a38dab8b000, 385024, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab8b000, 49152, MADV_DONTNEED) = 0
madvise(0x3a38d9095000, 8994816, MADV_DONTNEED) = 0
access("/usr/share/fonts/gsfonts/NimbusSans-Regular.otf", R_OK) = 0
madvise(0x3a38dab8b000, 385024, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab8b000, 49152, MADV_DONTNEED) = 0
madvise(0x3a38d9095000, 8994816, MADV_DONTNEED) = 0
access("/usr/share/fonts/TTF/MuktiNarrow.ttf", R_OK) = 0
madvise(0x3a38dab8b000, 385024, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab8b000, 49152, MADV_DONTNEED) = 0
madvise(0x3a38d9095000, 8994816, MADV_DONTNEED) = 0
access("/usr/share/fonts/TTF/malayalam.ttf", R_OK) = 0
madvise(0x3a38dab8b000, 385024, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab8b000, 49152, MADV_DONTNEED) = 0
madvise(0x3a38d9095000, 8994816, MADV_DONTNEED) = 0
access("/usr/share/fonts/TTF/Sampige.ttf", R_OK) = 0
madvise(0x3a38dab8b000, 385024, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab8b000, 49152, MADV_DONTNEED) = 0
madvise(0x3a38d9095000, 8994816, MADV_DONTNEED) = 0
access("/usr/share/fonts/TTF/padmaa-Medium-0.5.ttf", R_OK) = 0
madvise(0x3a38dab8b000, 385024, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab8b000, 49152, MADV_DONTNEED) = 0
madvise(0x3a38d9095000, 8994816, MADV_DONTNEED) = 0
access("/usr/share/fonts/TTF/VL-Gothic-Regular.ttf", R_OK) = 0
madvise(0x3a38dab8b000, 385024, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab8b000, 49152, MADV_DONTNEED) = 0
madvise(0x3a38d9095000, 8994816, MADV_DONTNEED) = 0
access("/usr/share/fonts/OTF/ipag.ttf", R_OK) = 0
madvise(0x3a38dab8b000, 385024, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab8b000, 49152, MADV_DONTNEED) = 0
madvise(0x3a38d9095000, 8994816, MADV_DONTNEED) = 0
access("/usr/share/fonts/TTF/TSCu_Paranar.ttf", R_OK) = 0
madvise(0x3a38dab8b000, 385024, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab8b000, 49152, MADV_DONTNEED) = 0
madvise(0x3a38d9095000, 8994816, MADV_DONTNEED) = 0
access("/usr/share/fonts/TTF/NanumGothic.ttf", R_OK) = 0
madvise(0x3a38dab8b000, 385024, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab8b000, 49152, MADV_DONTNEED) = 0
madvise(0x3a38d9095000, 8994816, MADV_DONTNEED) = 0
access("/usr/local/share/fonts/Korean/UnDotumBold.ttf", R_OK) = 0
madvise(0x3a38dab8b000, 385024, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab8b000, 49152, MADV_DONTNEED) = 0
madvise(0x3a38d9095000, 8994816, MADV_DONTNEED) = 0
access("/usr/local/share/fonts/Commercial/Unknown/CODE2000.ttf", R_OK) = 0
madvise(0x3a38dab8b000, 385024, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab8b000, 49152, MADV_DONTNEED) = 0
madvise(0x3a38d9095000, 8994816, MADV_DONTNEED) = 0
access("/usr/local/share/fonts/Morisawa/\343\203\222\343\203\251\343\202\256\343\203\216\344\270\270\343\202\264 Pr6N W4.otf", R_OK) = 0
madvise(0x3a38dab8b000, 385024, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab8b000, 49152, MADV_DONTNEED) = 0
madvise(0x3a38d9095000, 8994816, MADV_DONTNEED) = 0
access("/usr/local/share/fonts/Morisawa/\343\203\222\343\203\251\343\202\256\343\203\216\344\270\270\343\202\264 Upr W4.otf", R_OK) = 0
madvise(0x3a38dab8b000, 385024, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab8b000, 49152, MADV_DONTNEED) = 0
madvise(0x3a38d9095000, 8994816, MADV_DONTNEED) = 0
access("/usr/share/fonts/TTF/Mathematica6.ttf", R_OK) = 0
madvise(0x3a38dab8b000, 385024, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab8b000, 49152, MADV_DONTNEED) = 0
madvise(0x3a38d9095000, 8994816, MADV_DONTNEED) = 0
access("/usr/share/fonts/TTF/Mathematica7.ttf", R_OK) = 0
madvise(0x3a38dab8b000, 385024, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab8b000, 49152, MADV_DONTNEED) = 0
madvise(0x3a38d9095000, 8994816, MADV_DONTNEED) = 0
access("/usr/share/fonts/TTF/AndikaRegular.ttf", R_OK) = 0
madvise(0x3a38dab8b000, 385024, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab8b000, 49152, MADV_DONTNEED) = 0
madvise(0x3a38d9095000, 8994816, MADV_DONTNEED) = 0
access("/usr/local/share/fonts/Japanese/Tsuyuzora-bunko/XZBB.ttf", R_OK) = 0
madvise(0x3a38dab8b000, 385024, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab8b000, 49152, MADV_DONTNEED) = 0
madvise(0x3a38d9095000, 8994816, MADV_DONTNEED) = 0
access("/usr/local/share/fonts/Japanese/WadaLab/wlcmaru2004aribu4430/wlcmaru2004aribu.ttf", R_OK) = 0
madvise(0x3a38dab8b000, 385024, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab8b000, 49152, MADV_DONTNEED) = 0
madvise(0x3a38d9095000, 8994816, MADV_DONTNEED) = 0
access("/usr/share/fonts/OTF/FiraSans-Regular.otf", R_OK) = 0
madvise(0x3a38dab8b000, 385024, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab8b000, 49152, MADV_DONTNEED) = 0
madvise(0x3a38d9095000, 8994816, MADV_DONTNEED) = 0
access("/usr/local/share/fonts/Japanese/nukamiso/nukamiso_yamiyootf_beta07.otf", R_OK) = 0
madvise(0x3a38dab8b000, 385024, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab8b000, 49152, MADV_DONTNEED) = 0
madvise(0x3a38d9095000, 8994816, MADV_DONTNEED) = 0
access("/usr/share/fonts/OTF/Vollkorn-Regular.otf", R_OK) = 0
madvise(0x3a38dab8b000, 385024, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab8b000, 49152, MADV_DONTNEED) = 0
madvise(0x3a38d9095000, 8994816, MADV_DONTNEED) = 0
access("/usr/share/fonts/TTF/Ricty-Regular.ttf", R_OK) = 0
madvise(0x3a38dab8b000, 385024, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab8b000, 49152, MADV_DONTNEED) = 0
madvise(0x3a38d9095000, 8994816, MADV_DONTNEED) = 0
access("/usr/local/share/fonts/Commercial/Motoya/NFbc1kp.ttc", R_OK) = 0
madvise(0x3a38dab8b000, 385024, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab8b000, 49152, MADV_DONTNEED) = 0
madvise(0x3a38d9095000, 8994816, MADV_DONTNEED) = 0
access("/usr/local/share/fonts/Japanese/Motoya/MTLc3m.ttf", R_OK) = 0
madvise(0x3a38dab8b000, 385024, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab8b000, 49152, MADV_DONTNEED) = 0
madvise(0x3a38d9095000, 8994816, MADV_DONTNEED) = 0
access("/usr/local/share/fonts/Japanese/tfont/TGothic-GT01.ttc", R_OK) = 0
madvise(0x3a38dab8b000, 385024, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab69000, 57344, MADV_DONTNEED) = 0
madvise(0x3a38dab8b000, 49152, MADV_DONTNEED) = 0
madvise(0x3a38d9095000, 8994816, MADV_DONTNEED) = 0
access("/usr/local/share/fonts/Japanese/UchidaAkira/OradanoGSRR.ttf", R_OK) = 0
madvise(0x3a38dab8b000, 385024, MADV_DONTNEED) = 0

という感じで、フォントを片っ端から読んでいて、ものすごく時間がかかっている感じだ。 ちなみに、これはChromiumだと起動時に発生するため、フォント数が増えるとChromiumは起動が遅くなるのだが、Vivaldiではコンテキストメニューの表示がすさまじく遅くなる。 また、この問題はフォームをクリックしたときに発生するため、非常にストレスになっている。

もうひとつはページをロードしたときにロードの途中で異様に時間がかかる。 これはstraceを見ても止まるわけではないのだが、特徴的な要素は見つからず、コンソールで見るとただ単に飛んでいる。 これはChromiumでも発生するため、恐らくBlinkの問題だ。

Vivladi固有の問題のほうは時間があるときに報告するつもりだ。

現状では「Firefoxを使う」というのが解決策になりそうだ。 Chromiumは最近とにかく重くなっている。CPUの使い方がえぐいし、異様に処理に時間がかかるようになった。 フリーズしている、と感じるような処理時間で、原因がよくわからないケースが多い。 これがバージョン71から発生していることは認識しているのだが、そもそも「ウェブレンダリングを難しくしすぎている」というのが問題で、 「なんでもかんでもウェブでやろうとするのやめてくれないかなぁ」と心底思う。

だいたいこの流れや、レンダリングエンジンの複雑さがGoogleの胸先三寸になってしまっていることにはとても気持ち悪さを感じている。

Radeon RX580はどうだったか

なお、RTX2000シリーズは通常利用での暴走や出火などが問題視されていることからあまり完成度は高くないと見られており、 AMDは14nmプロセスでNvidiaより圧倒的に性能が低く、それでありながらライバルと位置づけるNvidia製品よりもずっと高い、という状況である。 しかもTSMCは7nmプロセスの新しいカードを用意しており、Radeon VIIという新製品は「RTX2080相当の性能で、価格的にも同等。Vega RX 64比では性能は1.8倍」とのたまっている。 TSMC、及びAMDは7nmで攻勢をかけるつもりのようで、とにかく時期が悪いのは確かだ。

だから、今買うならGTX1080かRTX2070あたりが妥当な判断で、RX580が4万円程度はするという点を考えると普通の(Windowsの、ゲーマーの)ユーザーには「迷わず買う人以外は買わないほうがいい」レベルの製品だろうとは思う。

Linuxにおける性能は、おおよそWindowsにおけるGeForceとの関係と同等。 つまり、NvidiaがWindowsと比べて半分程度の性能しか出せていない以上、AMDのドライバもWindows版と比べて半分程度、と考えれば良いのではないだろうか。 以前はもっともっと差が開いていたのでだいぶ健闘しているといって良さそうだ。現在はNvidiaのプロプライエタリドライバとAMDのオープンソースドライバ(AMDGPU)は同等の出来ということになる。 性能面では、だが

ゲーミング部分で言うと、ドライバの出来と、ゲームにおける最適化の結果として圧倒的にGeForce寄りであり、Radeonはその力を発揮できないという状態が続いている。 だから、ゲーム用途では何も考えずにGeForceでいいというレベルだし、多分それはRadeon VIIが出ても変わらない。

一方、Linuxのワークステーションユースで不満が出るという気はしなかった。 vdpauinfoでは

display: :0   screen: 0
API version: 1
Information string: G3DVL VDPAU Driver Shared Library version 1.0

Video surface:

name   width height types
-------------------------------------------
420    16384 16384  NV12 YV12 
422    16384 16384  UYVY YUYV 
444    16384 16384  Y8U8V8A8 V8U8Y8A8 

Decoder capabilities:

name                        level macbs width height
----------------------------------------------------
MPEG1                          --- not supported ---
MPEG2_SIMPLE                    3 65536  4096  4096
MPEG2_MAIN                      3 65536  4096  4096
H264_BASELINE                  52 65536  4096  4096
H264_MAIN                      52 65536  4096  4096
H264_HIGH                      52 65536  4096  4096
VC1_SIMPLE                      1 65536  4096  4096
VC1_MAIN                        2 65536  4096  4096
VC1_ADVANCED                    4 65536  4096  4096
MPEG4_PART2_SP                  3 65536  4096  4096
MPEG4_PART2_ASP                 5 65536  4096  4096
DIVX4_QMOBILE                  --- not supported ---
DIVX4_MOBILE                   --- not supported ---
DIVX4_HOME_THEATER             --- not supported ---
DIVX4_HD_1080P                 --- not supported ---
DIVX5_QMOBILE                  --- not supported ---
DIVX5_MOBILE                   --- not supported ---
DIVX5_HOME_THEATER             --- not supported ---
DIVX5_HD_1080P                 --- not supported ---
H264_CONSTRAINED_BASELINE       0 65536  4096  4096
H264_EXTENDED                  --- not supported ---
H264_PROGRESSIVE_HIGH          --- not supported ---
H264_CONSTRAINED_HIGH          --- not supported ---
H264_HIGH_444_PREDICTIVE       --- not supported ---
HEVC_MAIN                      186 65536  4096  4096
HEVC_MAIN_10                   186 65536  4096  4096
HEVC_MAIN_STILL                --- not supported ---
HEVC_MAIN_12                   --- not supported ---
HEVC_MAIN_444                  --- not supported ---

Output surface:

name              width height nat types
----------------------------------------------------
B8G8R8A8         16384 16384    y  NV12 YV12 UYVY YUYV Y8U8V8A8 V8U8Y8A8 A8I8 I8A8 
R8G8B8A8         16384 16384    y  NV12 YV12 UYVY YUYV Y8U8V8A8 V8U8Y8A8 A8I8 I8A8 
R10G10B10A2      16384 16384    y  NV12 YV12 UYVY YUYV Y8U8V8A8 V8U8Y8A8 A8I8 I8A8 
B10G10R10A2      16384 16384    y  NV12 YV12 UYVY YUYV Y8U8V8A8 V8U8Y8A8 A8I8 I8A8 

Bitmap surface:

name              width height
------------------------------
B8G8R8A8         16384 16384
R8G8B8A8         16384 16384
R10G10B10A2      16384 16384
B10G10R10A2      16384 16384
A8               16384 16384

Video mixer:

feature name                    sup
------------------------------------
DEINTERLACE_TEMPORAL             y
DEINTERLACE_TEMPORAL_SPATIAL     -
INVERSE_TELECINE                 -
NOISE_REDUCTION                  y
SHARPNESS                        y
LUMA_KEY                         y
HIGH QUALITY SCALING - L1        y
HIGH QUALITY SCALING - L2        -
HIGH QUALITY SCALING - L3        -
HIGH QUALITY SCALING - L4        -
HIGH QUALITY SCALING - L5        -
HIGH QUALITY SCALING - L6        -
HIGH QUALITY SCALING - L7        -
HIGH QUALITY SCALING - L8        -
HIGH QUALITY SCALING - L9        -

parameter name                  sup      min      max
-----------------------------------------------------
VIDEO_SURFACE_WIDTH              y        48     4096
VIDEO_SURFACE_HEIGHT             y        48     4096
CHROMA_TYPE                      y  
LAYERS                           y         0        4

attribute name                  sup      min      max
-----------------------------------------------------
BACKGROUND_COLOR                 y  
CSC_MATRIX                       y  
NOISE_REDUCTION_LEVEL            y      0.00     1.00
SHARPNESS_LEVEL                  y     -1.00     1.00
LUMA_KEY_MIN_LUMA                y  
LUMA_KEY_MAX_LUMA                y  

また、vainfoは

vainfo: VA-API version: 1.3 (libva 2.3.0)
vainfo: Driver version: Mesa Gallium driver 18.3.1 for Radeon RX 580 Series (POLARIS10, DRM 3.27.0, 4.20.1-1-MANJARO, LLVM 7.0.0)
vainfo: Supported profile and entrypoints
      VAProfileMPEG2Simple            : VAEntrypointVLD
      VAProfileMPEG2Main              : VAEntrypointVLD
      VAProfileVC1Simple              : VAEntrypointVLD
      VAProfileVC1Main                : VAEntrypointVLD
      VAProfileVC1Advanced            : VAEntrypointVLD
      VAProfileH264ConstrainedBaseline: VAEntrypointVLD
      VAProfileH264ConstrainedBaseline: VAEntrypointEncSlice
      VAProfileH264Main               : VAEntrypointVLD
      VAProfileH264Main               : VAEntrypointEncSlice
      VAProfileH264High               : VAEntrypointVLD
      VAProfileH264High               : VAEntrypointEncSlice
      VAProfileHEVCMain               : VAEntrypointVLD
      VAProfileHEVCMain               : VAEntrypointEncSlice
      VAProfileHEVCMain10             : VAEntrypointVLD
      VAProfileJPEGBaseline           : VAEntrypointVLD
      VAProfileNone                   : VAEntrypointVideoProc

と当初対応しておらず、重大な弱点であった「H.265の非対応」は解消されているようだ。 (ただし、VP8/9には対応していない)

実際に試してみたところ、hevc_vaapiでのエンコードは116fpsと、P400でのNVENCには劣るもののかなりの優秀さを見せた。これだけ速ければ十分に実用的だろう。 画質がNVENCだと実用には厳しいところがあったのだが、VCEの場合いくらか画質がいいためより実用しやすい。 それでも、利用できる場合は「普通は画質を少しでも良く保存したい」ために「速さ優先」とはなりづらく限定的だが。

さらにNvidiaと違い、Waylandのコンポジターがちゃんと動作するというのも大きなメリットだろう。

消費電力的にも、あまり電気を使わないプロセッサを使っているからという事情が前提になってしまってはいるものの、使いづらくなるほどではない。 気持ちとしては「もっと消費電力が少なかったらなぁ」というのと、「2万円台前半だったらなぁ」という気持ちはとてもしてしまうのだが、そうした点を除けば「入れておけばとりあえず安心できるカード」であると言えるだろう。 「とりあえず入れる」には巨大すぎて入れるケースを随分選ぶが。

DVI-Dがひとつ、HDMIとDPがふたつずつで計5出力というところも、使いやすく不満になりにくい。 このビデオカードは大きさ的にも電力的にもそう来やすく選べるものではないが、Linuxでのグラフィックにまつわる不満を感じているのなら、RX580と言わずとも(例えば560でも)Radeonにする価値はありそうだ。

将来的には

「ゲームをする事情」と「デスクトップユースとして普通のアプリを動かす事情」は似ているのだが、「計算力を求める事情」と「Linuxにおいて快適な仕様」とは大きな違いが出てきている。

だから、贅沢を言えば2種類の仕様を用意できると最善で、贅沢を言えば、 「Ryzen + GeForce (主にWindows及びゲーム向け)」と「Ryzen Threadripper + Radeon (Linux及び計算向け)」の2台で編成できたらなぁ、と思う。 Zen2でこれを構成するのはなかなかドリーミーだ。

とはいえ、現実的に1台に絞るとしたら、「Ryzen + Radeon」という構成で「現実的な計算力とLinuxで扱いやすいグラフィック」というのを取るだろう。

現状、P720はどうなのかというと、やはり4114に求めたものと諦めていたものというのが大きい。

「メニーコア」という性能は、それを発揮する場面というのは本当に少ない。 実際、私の普段の運用では4114ですら持て余し気味である。 ところが、普段遣いではあらゆるアプリで処理性能が足りずストレスフルである。 「普通の使い方でモバイルi3程度の快適性しか求められない」というのはわかっていたが、それでもこのマシンのクラスを考えるととても残念な感じがする。

対して、実際にメニーコアを求めるケースでは4114では全然足りないのだが、それでも処理性能はi7とは段違いであった。 「4114はフルコアを活用できたとしてもi7に劣る」と考えていたが、実際は第8世代Core i7よりもずっと高速に動作した。 シングルコア性能も諦めていたほどに低くはなく、「さすがにそれなりに性能はある」と感じることができる。 そもそも、20コア40スレッドであるから、「20スレッドスケールテスト」が手元でできるというのもかなりのメリットだった。 だから、ちゃんと求めたものは実現できているし、価格を考えれば完全に目的を達成できるほどではないというのはわかっていた。

だが、結局のところ現状P720の最大の魅力は「省電力」である。 48Wから90W程度でありながら非常に優れた処理性能を発揮する、というのはかなり魅力的だ。

だが、やっぱりコンピュータは「性能が足りるか否か」であり、エクスペリエンスが良いかと聞かれるとYESとは答えがたい。 部分的にボトルネックになるブラウジングが全体の作業の足を引っ張るという状況も痛い。

「エクスペリエンスは諦めて処理量を増やしたい」というのとは矛盾しているのだが、やはりエクスペリエンスを優先したい気持ちが湧いてくる。 今回RX580にしたことで飛躍的にエクスペリエンスが向上したことも大きな理由になっている。 というより、RX580にしたことでP720がとりあえず不満ないくらいの動作をしてくれるようになった。 だから、バランス的には今の状態は悪くないのかもしれない。

Erina/Surtrに関する研究が一区切りついて、あまりデータプロセッシングすることがなくなったというのも大きい。 圧倒的に重い処理であったことから、これのためにメニーコアを求めたし、それによって成果も挙げたのだが、これがなくなると相当頻繁に回されるタスクを考えても実際8コアもあればあまり支障はなく、16コアのRyzenが用意されるのであれば不満はなさそうに思える。

ただ、ゲームをすることに関していえばGeForce優位は揺るぎそうにもないし、かといってLinuxでは現状NvidiaもIntelもなかなかの惨状ということを考えればRadeon以外選択肢はないという状態であり、 これが2台構成を求める理由ともなっているが、1台を選ぶのであればLinuxエクスペリエンスを優先することになるだろう。

ただ、Zen2の世代ではまだP720は現役で、しかも「非常に高機能で並列処理能力は高いが、通常の使い方ではそれほど性能は高くなく、消費電力はやや少なめで、筐体はとても大きい」マシンをメイン以外で使うというのは非常に難しい。 今Godavariがそうであるように、「主にWindows環境(音楽制作)、必要なときは計算資源または分離された帯域としてのLinux」みたいな使い方になるだろうか。 実際、音楽制作では機材がIntelプロセッサを想定したドライバでAMDドライバだといまいちうまく動かないケースもあり、現在のP720のような構成は非常に好ましい。 多くのVSTプラグインを使う場合も4114はかなり良い働きをしてくれる。 それでも、なんとも微妙な話で、Zen2世代でメイン機の差し替えを行うかは悩ましいところではある。

やはり「それぞれの用途で最適化した理想の2台」なんて夢見がちな話をするに留めるとして、多分本当に多くの人にとって有益なのは現時点で性能的にやや微妙な立ち位置にあるRyzen Gが不満のない性能まで引き上げられること、 あるいはRX 580相当のRadeonがもっと安く、省電力でコンパクトなものとして出てくることだろう。それは、次の世代で実現するかもしれないし、Zen3の世代まで待たねばならないかもしれない。

一方、X11はいよいよ限界を迎えている感もあるが、一方でWaylandがよくなっているわけでもない。 IntelもNvidiaも不具合が出る状態が続けばかなり苦しいことになるだろう。


  1. 具体的にはFlower Knight Girlである。 なお、 18禁バージョンもあるため 検索される際にはくれぐれも留意願いたい。

H.264 vs H.265 vs VP8 vs VP9 vs AV1

実は先のビデオ関連の記事はMimir Yokohamaのほうにupしようかと思っていた。

こっちにしてよかった…Mimir Yokohamaのフォーマットで書いてたら絶対地獄を見た…

さて、先の記事の途中でAV1を試したが、実際AV1がどの程度使い物になるのか(いや、実際は強烈に遅いので全く使い物にならないのだが)試してみたくてちょっと検証してみた。

ソースビデオはコントラスト差、動きともに激しく、部分的にはほとんど更新されないドラムマニアのプレイ動画を使用した。 10MbpsほどのH.264ビデオである。

  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2avc1mp41
    encoder         : Lavf58.12.100
  Duration: 00:00:04.79, start: 0.308970, bitrate: 9998 kb/s
    Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, smpte170m/unknown/smpte170m), 1080x1920 [SAR 1:1 DAR 9:16], 9995 kb/s, 29.88 fps, 29.88 tbr, 15296 tbn, 59.75 tbc (default)
    Metadata:
      handler_name    : VideoHandler

libvpxはビットレートコントロールがうまくいかなかったことから、aomav1はそもそも変換できなかったことからこれらはrawvideoに変換し、それぞれvpxenc, aomencを使用して2パスで変換した。

メインビットレートはH.264で荒れる512kを選択。 VP8はあまりに小さいビットレートコントロールが困難だったため、512kについては200kを指定したCBRとした。

比較

ソース動画

Base H.264 @10Mbps

ソースは10Mbpsということもあり、暗い中非常にキレイに撮れている。 なお、撮影機材はZenfone Selfie(ZD511KL)である。

H.264

$ ffmepg -i base.mp4 -c:v libx264 -b:v 512k h264.mp4
H.264 @502kbps
H.264 @733kbps
H.264 @971kbps

そもそもH.264で荒れさせるのが基準だったため、512kでは動きのある部分は完全にブロックだし、パッド部分も相当粗い。

ビットレートが上がると順当にスムーズになっていき、素直な特性のようだ。

H.265

$ ffmepg -i base.mp4 -c:v libx265 -b:v 512k h265.mp4
H.265 @474kbps
H.265 @716kbs
H.265 @962kbps

現状最も有力なH.265。 さすがというか、静止画にすると打点のスティックが消えてしまっていて、VP9のほうが良さそうなのだが、 全体でみれば安定していてキレイ。動画では画質がよく感じられる。

全体的なざらつきがないので綺麗に見えるがこの静止画からわかるとおり動きの激しい部分でディティールがVP9よりも消えやすい。 ディティールにこだわる場合はビットレートに余裕を取るべきだと思うけれども、静止画に切り出す場合などはVP9のほうがうまくいく。

ビットレートが上がったときにも順当によくなっている。 H.264よりひとまわりいいといった感じで、ビットレートが上がると差は縮まり、ビットレートが非常に低いときはがんばっている感じだ。

H.265 (NVENC)

$ ffmpeg -i base.mp4 -c:v hevc_nvenc -b:v 512k h265-nvenc.mp4
H.265 (NVENC) @552kbps

NVENCは画質がよくないと言われているので、比較してみた。

テクスチャが雑で、なんか「下塗りです」といった感じ。 成る程、VP9 QSVのようにあからさまに目立つわけではないのだが、ディティールを見てしまうとなかなか厳しい。 利用できる状況は限られそうだ。

VP8

$ vpxenc --end-usage=cbr --bias-pct=0 --codec=vp8 --target-bitrate=200 --passes=2 -h 1920 -w 1080 -o vp8-cbr.webm raw.y4m
VP8 @586kbps

普及しなかったし残念なことになったVP8。768kならがんばってくれるが、512kはどうがんばっても到達せず、このセッティングでもちょっと大きめの586k。

画質は全体的にザラザラ。大きなブロックがないので静止画だとキレイっぽいけれど、常時こんな感じ(H.264なんかは部分的に、そしてちょいちょいブロック化してしまう感じである)なのでちょっとお話にならない。

何より目立つのは「色がおかしい」ことだが。

VP9

$ vpxenc --codec=vp9 --target-bitrate=512 --passes=2 -h 1920 -w 1080 -o vp9.webm raw.y4m 
VP9 @522kbps
VP9 @771kbps
VP9 @1020kbps

VP9は結構優秀で、H.264よりは良いし、H.265とどちらが良いかというと好みの問題と言えるくらいには仕上がっている。 ディティールを見ると損なわれ感があるのでやや厳しいが、ビットレートにある程度余裕を持たせればH.264よりも良い。

フリーコーデックに魅力を見ると感じるなら画質面ではアリだ。

だが、いかんせん遅い。x265の1/10くらいの速度である。 速度優先にしないと10fpsも夢のまた夢。

VP9もまともにマルチスレッドしないので、マルチスレッド化するだけでだいぶ実用になる気がするのだけど… (少なくともlibx265に負けない程度には)

ビットレートが上がるとH.265より良いように見える。 1Mbpsは完全に及第点だろう。

VP9 (QSV)

ffmpeg -init_hw_device vaapi=foo:/dev/dri/renderD128 -hwaccel vaapi -hwaccel_output_format vaapi -hwaccel_device foo -i invideo.mp4 -filter_hw_device foo -vf 'format=nv12|vaapi,hwupload' -c:v h264_vaapi -b:v 512k -c:a copy outvideo.mp4
VP9 (QSV) @555kbps

VP9を唯一実用する方法であるQSV。しかし、QSVのVP9は相当画質が悪い。 ビデオでの印象としてはVP8に近い。ちょっとこの品質ではよほど高ビットレートでない限り実用にならないという感じだ。 エンコードは100fpsほど出るのだが…

AV1

AV1はデフォルト設定では到底終わらないほどの時間がかかったため、次のようにした。

% aomenc --codec=av1 -t 40 --cpu-used=8 --target-bitrate=512 --passes=2 -h 1920 -w 1080 -o av1.mkv raw.y4m
Pass 1/2 frame  142/143    27456B    1546b/f   46186b/s   19657 ms (7.22 fps)
Pass 2/2 frame  142/142   298568B   16820b/f  502497b/s 2741931 ms (0.05 fps)

なお、どちらもスレッド数を指定しているが、AV1は完全にシングルスレッドで動作していた。

AV1 508kbps
AV1 @774kbps
AV1 @1032kbps

H.265よりもディティールが消え、のっぺりしている。 VP9とはほとんど見分けがつかないが、よく見ればなんとVP9のほうが良い。 VP9(512k)に対してAV1(512k)は

  • シャツの前のほうのシワが消滅
  • 打点部分のスティックが巨大なブロックによって消滅
  • シャツはのっぺりしてしまっている

と残念な結果に。

ビットレートがあがってもあまり改善していない。 速度優先の--cpu-usedのせいかもしれないがVP9の10倍は時間をかけた意味はどこへ…

追記: VP9/AV1 のマルチスレッド処理

テスト

コメントにてyusukeさんから

AV1がシングルスレッドでしか動かないのは–tile-columnsと–tile-rowsを指定していないからではないでしょうか

と情報頂いたので試してみた。

% aomenc --codec=av1 --cpu-used=8 --target-bitrate=512 --threads=16 --tile-columns=2 --tile-rows=2 --passes=2 -h 1920 -w 1080 -o av1-512-pararell.mkv raw.y4m

この場合、シングルスレッドで動作した。

% aomenc --codec=av1 --cpu-used=8 --target-bitrate=512 --threads=16 --tile-columns=6 --frame-parallel=1 --passes=2 -h 1920 -w 1080 -o av1-512-pararell.mkv raw.y4m

--tile-rowsをやめて、デコード用オプションである--frame-parallelを有効にしたところ、 マルチスレッドで動作した。 ただし、大部分はシングルスレッドで、ときどき6から10スレッド程度で動作するような挙動。

結果は

Pass 1/2 frame  142/143    27456B    1546b/f   46186b/s   19934 ms (7.12 fps)
Pass 2/2 frame  142/142   303279B   17086b/f  510444b/s 1562704 ms (0.09 fps)
aomenc --codec=av1 --cpu-used=8 --target-bitrate=512 --threads=16   --passes=  3502.70s user 67.02s system 224% cpu 26:29.29 total
マルチスレッドAV1 CPU利用率 (cpu-used=8)

CPUは200%越えてるけれど、速度的には2倍にはなっていない程度。

そして次の場合

% aomenc -w 1080 -h 1920 --tile-columns=6 --limit=48 -t 24 -b 8 --input-bit-depth=8 --end-usage=vbr --target-bitrate=512 -p 1 --webm --num-tile-groups=32 -o av1-512-parallel2.webm raw.y4m
Pass 1/1 frame  142/142   290129B   16345b/f  488306b/s 7850851 ms (0.02 fps)
aomenc -w 1080 -h 1920 --tile-columns=6 -t 24 -b 8 --input-bit-depth=8   -p 1  38460.66s user 114.83s system 491% cpu 2:10:55.73 total
マルチスレッドAV1 CPU利用率 (cpu-used=1)

ずっと激しく使われているのでなかなか効率はよさそう。 この違いは--cpu-usedにあるようだった。

--cpu-used=4の場合:

Pass 1/1 frame  142/142   295824B   16666b/f  497896b/s 1581372 ms (0.09 fps)
aomenc -w 1080 -h 1920 --cpu-used=$i --tile-columns=6 -t 24 -b 8    -p 1   -o  4379.28s user 54.32s system 279% cpu 26:26.07 total
マルチスレッドAV1 CPU利用率 (cpu-used=4)

--cpu-used=8より少し多めに動いている。

--cpu-used=2:

Pass 1/1 frame  142/142   297030B   16734b/f  499928b/s 3251395 ms (0.04 fps)
aomenc -w 1080 -h 1920 --cpu-used=$i --tile-columns=6 -t 24 -b 8    -p 1   -o  10423.02s user 70.17s system 322% cpu 54:16.15 total
マルチスレッドAV1 CPU利用率 (cpu-used=2)

結構動くようになった。

では待望の画質はというと

AV1 並列 cpu-used=1
AV1 並列 cpu-used=2
AV1 並列 cpu-used=4
AV1 並列 cpu-used=8

結構差は大きい。 cpu-used=8のAV1よりはcpu-used=1のVP9のほうが綺麗だけども、4だとディティールは潰れているけれどざらつきが減るため好みで済ませられるように思える。cpu-used=4より上であればH.265に対するアドバンテージは認められる。 のっぺりしているのはAV1のキャラクターのようだが、ノイズが消えるため感覚的には綺麗に見える。再変換したときに情報の欠落が気になりそうだが。

おまけ。同じセッティングでVP9を作ってみる(vpxencaomencはだいたいコマンド互換性がある)。 --num-tile-groupsは使えないので外し、--codec=vp9を追加する。

% vpxenc --codec=vp9 -w 1080 -h 1920 --cpu-used=8 --tile-columns=6 -t 24 -b 8 --input-bit-depth=8 --end-usage=vbr --target-bitrate=512 -p 1 --webm -o vp9-parallel.webm raw.y4m
Pass 1/1 frame  142/118   242873B 5835948 us 24.33 fps [ETA  0:00:01]    1125F   1298F  11937F    943F    792F    849F   1104F   1271F   1022F   1030F  24348F   1382F   1316F   1264F   2220F   1162F   1152F   1072F   1084F   1386F  13097FPass 1/1 frame  142/142   316309B   17820b/f  532379b/s 6950835 us (20.43 fps)
vpxenc --codec=vp9 -w 1080 -h 1920 --cpu-used=8 --tile-columns=6 -t 24 -b 8    16.91s user 0.73s system 235% cpu 7.478 total

おぉぉ、速いぞ!!! 実用になるぞ!!!よくみたらちょこっとだけ粗いけれど、全然いけるいける。

VP9 並列 cpu-used=8

ただ、--cpu-usedしないとさすがに厳しい。

% vpxenc --codec=vp9 -w 1080 -h 1920 --tile-columns=6 -t 24 -b 8 --input-bit-depth=8 --end-usage=vbr --target-bitrate=512 -p 1 --webm -o vp9-parallel-used1.webm raw.y4m     :(
Pass 1/1 frame  142/118   242579B   50719 ms 2.80 fps [ETA  0:00:10]    1121F   1252F  11933F    982F    752F    916F   1059F   1293F    973F   1027F  21951F   1641F   1210F   1324F   2162F   1095F   1044F   1052F   1099F   1382F  13774F Pass 1/1 frame  142/142   314260B   17704b/f  528930b/s   60777 ms (2.34 fps)
vpxenc --codec=vp9 -w 1080 -h 1920 --tile-columns=6 -t 24 -b 8    -p 1 --webm  143.78s user 1.13s system 236% cpu 1:01.31 total

所感

これをテストした上での感想としては

  • --cpu-used=1 はとても遅い。VP9でもかなり厳しい
  • --cpu-used=8 はあまり効果がなく、 --cpu-used=4 が軽量設定としてはよさそう
  • 確かに画質は良いが--cpu-used=8だと悪い。--cpu-used=1でx265並の速度が出れば革命的だけども…
  • マルチスレッドはVP9よりはAV1で改善されている
  • しかしAV1であっても対してCPUを活用できておらず、いまいちと言われているx265のほうがよっぽど計算リソースを有効活用する
  • だいたい活用できているのは8スレッドあたり。クロスしている部分を考慮しても12スレッド
  • AV1はいくらスレッド数を多く指定しても現実的な速度にならない。4114が遅いとしてもCOre i7であってもコアあたり8倍は速くないので、10FPSには到達しない感じ
  • スレッド数を増やしてもせいぜい2倍程度しか速くならないため、スレッド数よりも--cpu-usedのほうが影響が大きい
  • VP9の--cpu-used=4は速度的にも(うちでは30FPS出ないが)使えるが、H.265(libx265)との差は開いてしまい、よほど強い動機がないと厳しい (--cpu-used=2でも結構粗い)
  • AV1がハードウェア支援されたら使えるかというと、現状QSVのVP9がひどいという言葉では片付けられないくらいひどいので、全く期待できない

基本的には「向上するソース画質に対して可能な限り損なわないようにする」には「ソースサイズが大きくなったとき(あるいは画質が向上したときに)に同等ビットレートでソースの改善を反映できるように」動画コーデックは進化しているのであり、つまり情報の少ないソースであれば結果的により小さなサイズに圧縮できる、ということを反映意味する。

そのことを踏まえれば、「画質とサイズを妥協すれば新しいコーデックでも実用できる」というのは完全に本末転倒であり、全く価値がない。これは速度的にVP9の最高画質とAV1の最低画質が同ビットレートで逆転し、かつVP9のほうが速い、というのはまさにそれだ。

確かにAV1の画質は魅力的だが、それはあまりにも現実的ではないリソースをつぎ込めばという話である。 それをいくらか緩和しようとした時点でAV1の画質というメリットは損なわれてしまい、VP9のほうがまだマシという結果になる。

もちろん、一般で使われることは最初から投げ捨てて、配信者向けに作っているのでありユーザーには関係ない、というのであればわからなくはないが、現状のAV1はそれこそGoogleクラスでなければ実用できないようなものであり、ユーザーはデコードすらままならない。 そうすると単に「特殊で扱いにくいもの」になってしまい、そのようなものがどんな経過をたどり今残っていないのかということを完全に忘れ去ってしまっているように思う。

現状は、一般ユーザーにとってVP9であれAV1であれ利用を考慮する価値のないものであり、 フリーであることの価値を理解するのであればVP9は考えられるがAV1は存在自体忘れていても構わない。

ユーザーが使うならばH.265(あるいはH.264)が良い。 (特許問題など気持ち悪いとは思うが…)

画質、処理速度、コスト、処理の安定性などH.265(x265)の何が好まれていて、何を達成しなければならないのか、優位性を口にするくらいなら真剣に考えて欲しいと思う。

【まとめ特集記事】 ビデオカード * VDPAU / VA-API * ffmpeg

パッケージ名などはArch Linux/Manjaro Linux準拠である。

PRIME(異なるメーカーのビデオカード混合)の話はしていない。 (持っていないので) そのうちするかもしれない。

ffmpeg周りに関しては過去の記事には載せてなかった話も色々書いた大作になっている。 (特にAMD関連の情報やVDPAUなんかはドキュメントが少ないので有益なはず)

ビデオカードとドライバ

現在使用されているビデオカードは次の3メーカー。

  • Intel
  • Nvidia
  • AMD

Intelはコンシュマー向けIntel CPUに内蔵されているビデオカードである。 Intel CPUでもごく一部AMDビデオカードを内蔵したものもある。

NvidiaはGeForce/Quadro/Teslaビデオカード、AMDはRadeonビデオカード(AMD APU内蔵のものを含む)のことである。

ビデオカード ドライバー タイプ 現状
Intel intel free Supported
Nvidia nvidia non-free Supported
Nvidia nvidia-tesla non-free Supported
Nvidia nouveau free Supported
Nvidia nv free Deprected in 2010
AMD AMDGPU free Supported
AMD Catalyst non-free Legacy
AMD ATI/Radeon free Legacy
AMD radeonhd free Obsolated?
  • IntelとAMDのオープンソースドライバはメーカー協力のもと作られており、現状唯一の選択肢
  • AMDGPUは新しいドライバで新しいカードしかサポートしておらず、それ以前のものはATI及びRadeonドライバのサポート
  • プロプライエタリのCatalystドライバも更新されておらず、古いカード向け
  • nouveauドライバはメーカーサポートがないリバースエンジニアリングの賜物

ハードウェアビデオアクセラレーション

ハードウェア搭載機能

Intel

IntelはQSV(Quick Sync Video)という補助機能を搭載。 割とビデオが重かった時代から、ビデオを快適に再生できるようにビデオカードの力を借りて再生するものである。

そのため、QSVはビデオカードだけでなくCPUパワーも併用する。

NvidiaやAMDよりも非力だが、サポートしている形式が多く、意外と使いやすい。 また、画質がちょこっとだけいい。

Nvidia

Nvidiaはエンコード用のNVENCとデコード用のNVDECという2つの専用チップを搭載。 CUDAコアは利用していない。

IntelやNvidiaと比べ桁違いに高速。 GTX1080でFHD動画をH.264で1300FPS、H.265でも650FPSで処理できるという。

AMD

AMDはエンコード用のVCE(Video Coding Engine)、デコード用のUVD(Universal VideoDecorder)を搭載。 AMDも全然宣伝していなくて、情報がとにかく少ない。

VCEの速度的にはライバルNvidiaカードのNVENCの半分くらいが相場…らしい。 また、サポートしているフォーマットが結構少ない。あとからアップデートでサポートされたりもしているが。

Linux用のAPI

VDPAUはNvidia主導の、VA-APIはIntel主導のAPI。

VDPAUは再生のみ。VA-APIはエンコードもできる。

API エンコード デコード
VDPAU
VA-API

当然NvidiaはVDPAU、IntelはVA-APIをサポート。AMDはオープンソースドライバーでは両方サポート、CatalystはVA-APIのみ。

カード VDPAU VA-API
Intel
Nvidia
AMD non-free
AMD free

それぞれアダプタを使用してVDPAUをラップしてVA-APIで処理する方法や、VA-APIをラップしてVDPAUで処理する方法がある。 (libvdpau-va-gl及びlibva-vdpau-driver) これによってIntelでVDPAUを、NvidiaでVA-APIを処理できる。

VDPAUアダプタを使う場合、環境変数としてVDPAU_DRIVER=va_glする必要がある。

AMDの場合VA-APIとVDPAU両方をアダプタにすることが可能だが、それをするとエラーになる。 また、このVDPAUに対応させ、VA-APIをアダプタにするとエンコードはできなくなる。

nouveauドライバの注意点

nouveauドライバでVDPAUを使うにはプロプライエタリドライバのフォームウェアを流用したバージョンが必要で、 NVENCは利用することができない。

プレイヤーでデコード

VLC

ツール → 設定 → ビデオ → ディスプレイ → アウトプット → VDPAU出力 (もしくは自動)

ツール → 設定 → 入力 / コーデック → Hardware-accelerated decoding → VDPAUビデオエンコーダー or VA-APIビデオエンコーダー

SMPlayer

オプション → 環境設定 → 全般 → ビデオ → 出力ドライバー → vdpau or vaapi

GStreamer

gstreamer-vaapi (VA-API) 及び gst-plugins-bad (VDPAU) パッケージを導入

mpv

mpv --hwdec=vaapi --vo=gpu video

または

mpv --hwdec=vdpau video

mpvの場合NVDECを直接叩くこともできる。

mpv --hwdec=nvdec --vo=gpu video

さらにCUDAも使える。

mpv --hwdec=cuda --vo=gpu video

MPlayer

VDPAUの場合

mplayer -vo=vdpau -vc=ffh264vdpau,ffmpeg12vdpau,ffodivxvdpau,ffwmv3vdpau,ffvc1vdpau,ffhevcvdpau

VA-APIはフォークでサポート。mpvのほうがおすすめ

Xine

xine -V vdpau video

詳しくは

xine --list-plugins

Dragon Player

できないっぽい。

Kaffeine

多分できない。

もしVLCがコマンドラインでVDPAUあるいはVA-APIの使用を受け入れるならなんとかなる。

FFMpeg

基本編

マルチメディアフレームワークffmpeg。だいたい動画を操作するときはスイスナイフのように使える。

まずは基本

ffmpeg -i infile outfile

ffmpegは出力の拡張子を見る。なのでちゃんと指定することが必要。

ffmpeg -i infile outfile.mkv

オプション指定は順序が決まっている。

ffmpeg [global_options] {[input_file_options] -i input_url} ... {[output_file_options] output_url} ...

おおまかなグループで間違えなければ大丈夫そうだけれども、順番が問題になることは覚えておくといいかもしれない。

それでは古いreal mediaを今風にH.264+aacのmp4にしてみる。

ffmpeg -i 001.rm -c:v libx264 -c:a aac 001.mp4

-c:v = -vcodec (video codec)で、 -c:a = -acodec (audio codec)。

これでは品質指定ができないので、ビットレートを指定してみる。

ffmpeg -i 001.rm -c:v libx264 -b:v 5M -c:a aac -b:a 256k 001.mp4

H.264 (libx264) で色々する

H.264はだいたい標準的なビデオフォーマット。 標準のソフトウェアビデオコーデックはlibx264。

-c:vでビデオコーデック指定、-b:vでビデオビットレート指定、-*:aはそのオーディオ。

ffmpeg -i 001.rm -c:v libx264 -b:v 5M -c:a aac -b:a 256k 001.mp4

libx264はビットレートではなく品質で固定する-crfオプションが利用できる。

ffmpeg -i 001.rm -c:v libx264 -c:a aac -crf 23 001.mp4

-crfしていてもオーディオは固定することもできる。

ffmpeg -i 001.rm -c:v libx264 -crf 23 -c:a aac -b:a 256k 001.mp4

速度が問題になるケースでは-presetが有効。 選択肢はx264 --helpで確認可能。

ffmpeg -i 001.rm -c:v libx264 -crf 23 -preset ultrafast -c:a aac -b:a 256k 001.mp4

あまり使われないけれども有用なオプションとして-tuneがある。 主には実写用のfilmとアニメーション用のanimationを使うことになるだろう。 フィルムグレインを損なわないためにgrainを使うことも考えられる。

また配信用にはzerolatencyも有効だ。

ffmpeg -i 001.rm -c:v libx264 -crf 23 -preset ultrafast -tune film -c:a aac -b:a 256k 001.mp4

2-passエンコーディングで画質が〜と言っている人がいるが、基本的に2-passエンコーディングはファイルサイズをより正確にするためのものである。 詳しくはこの日本語訳あたりを。

x265もだいたい同じような感じで使える。

さらに色々する

動画から先頭4秒を切り出す

ffmpeg -i invideo.mp4 -t 4 -c:v copy -c:a copy out4sec.mp4

開始30秒のところから5秒切り出す

以前は-ss-iより後のほうがよかったらしい。 また、エンコードしないと不具合が出るので-c:v copyはできない。

ffmpeg -i invideo.mp4 -ss 30 -t 5 -c:v libx264 -crf 27 -c:a copy -t 4 out4sec.mp4

動画の開始10秒から10秒分を1秒あたり2枚で静止画に切り出す

ffmpeg -i invideo.mp4 -ss 10 -t 10 -r 2 image%d.jpg

動画をリサイズする

scaleはリサイズ先のサイズ。

ffmpeg -i invideo.mp4 -vf scale=1920:1080 -c:v libx264 -qp 24 -c:a copy outvideo.mp4

動画をクロップする

左上から200×200の座標を起点に、1600×900の動画で切り出す。

ffmpeg -i invideo.mp4 -vf crop=1600:900:200:200

連番動画からGIF動画を生成

フレームレートは5FPSで作ってみる。

ffmpeg -r -i image%d.jpg -r 5 outvideo.gif

音声を遅らせる(早める)

音ズレを解消する。

次の例では音声を1.5秒遅らせる。

ffmpeg -i invideo.mp4 -itsoffset 1.5 -i invideo.mp4 -map 0:0 -map 1:1 -c copy out.mp4

逆にビデオを1.5秒遅らせる

ffmpeg -i invideo.mp4 -itsoffset 1.5 -i invideo.mp4 -map 0:1 -map 1:0 -c copy out.mp4

これは理解が難しいので解説。

-itsoffset 1.5 でその入力ストリームを1.5秒遅らせている。 2つ指定している入力ストリームが両方同じファイルなので、同じファイルがソースになっているのだけど、

  • 入力0は1.5秒遅れたinvideo.mp4
  • 入力1はそのままのinvideo.mp4

になる。

この入力0, 1, 2, 3…はあくまで入力ソースなので、これ自体は特にその動画のなにを使うということに影響はない。

ffmpegは複数の指定した入力ストリームをマージする。 単純に複数の-iを並べた場合、どうなるかはいまいち制御できないようだ。確かなのは、オーディオチャンネルのないビデオと、オーディオを入力ストリームとした場合、確実にそのビデオとオーディオが合成される。

基本的にはffmpegは(というよりは一般的にビデオコンテナフォーマットは、かもしれない)#:0にビデオ、#:1にオーディオというファイルを作るようだ。 これは3つ以上のファイルをマージした場合でもである。

そして複数のビデオトラック、あるいはオーディオトラックを持たせるには-mapを使う。 例えば音声のないビデオinvideo.mp4とオーディオinaudio1.aac, inaudio2.aacがあったとして

ffmpeg -i invideo.mp4 -i inaudio1.aac -i inaudio2.aac -c copy outvideo.mp4

では単純にinvideo.mp4のビデオとinaudio1.aacのオーディオが合成され、inaudio2.aacは無視される。 invideo.mp4が音声を持っていた場合はinaudio1.aacも無視される。

ここで-mapを使い

  • 入力0のストリーム0
  • 入力1のストリーム0
  • 入力2のストリーム0

を合成させる

ffmpeg -i invideo.mp4 -i inaudio1.aac -i inaudio2.aac -c copy -map 0:0 -map 1:0 -map 2:0 outvideo.mp4

ここで-map 0:0 -map 0:1 -map 1:0として、オリジナルのビデオに追加のオーディオトラックを合成する、というようなことも可能だ。

ソースは複数のストリームを持てるので、何番のストリームに何が入っているかはffprobe fileとすることで知ることができる。

さて、元の話に戻ろう。#:0がビデオ、#:1がオーディオの一般的なビデオファイルであるならば、同じビデオファイルをソースとする「1.5秒遅れた入力0」と「そのままの入力1」を合成したとき、入力0のストリーム0と入力1のストリーム1を合成すればビデオが遅れるし、入力0のストリーム1と入力1のストリーム0を合成すれば音声が遅れるわけである。

コントラストを上げる

mpvで2を押すほうが簡単なのであまり使わないけど、暗いところで撮影した動画をupする場合などには少しコントラストを上げたほうが見やすい動画になる。

ffmpeg -i invideo.mp4 -vf eq=contrast=3 -c:v libx264 -crf 23 -c:a copy outvideo.mp4

さらにブライトネスもちょっと上げたいなと思ったらこんな感じ。

ffmpeg -i invideo.mp4 -vf eq=contrast=3:brightness=1 -c:v libx264 -crf 23 -c:a copy outvideo.mp4

お手軽にビデオ/オーディオをなしにする

ノイズを避ける場合や抽出したい場合に使える。

ビデオなしのオプションは-vn、オーディオなしのオプションは-an。 サブタイトルなしの-snもある。

VDPAU/VA-API/NVENC

再生支援

VDPAU

VDPAUの場合。これはあまり資料がない。単純には

ffmpeg -hwaccel vdpau -i invideo.mp4 -c:v libx264 -crf 24 -c:a copy outvideo.mp4

並列で複数のストリームを扱う場合は名前をつけよう。ここではvdpauストリームにfooという名前をつけて扱っている。

ffmpeg -init_hw_device vdpau=foo:$DISPLAY -hwaccel vdpau -hwaccel_device foo -i invideo.mp4 -c:v libx264 -crf 24 -c:a copy outvideo.mp4
VA-API

VA-APIの場合も同じ感じ。ただ、VA-APIデバイスの指定が必要。

ffmpeg -hwaccel vaapi -hwaccel_device /dev/dri/renderD128 -i invideo.mp4 -c:v libx264 -crf 24 -c:a copy outvideo.mp4

複数扱えるようにするには名前をつける。

ffmpeg -init_hw_dfevice vaapi=foo:/dev/dri/renderD128 -hwaccel vaapi -hwaccel_device foo -i invideo.mp4 -c:v libx264 -crf 24 -c:a copy outvideo.mp4
NVDEC

NVDECはVDPAUと同じ。-hwaccelだけでいい。

ffmpeg -hwaccel nvdec -i invideo.mp4 -c:v libx264 -crf 24 -c:a copy outvideo.mp4

エンコード支援

VA-API

VA-APIでは同じようにデバイスを指定し、ビデオフィルタでVA-APIにアップロードし、VA-APIハードウェアコーデックでエンコードする。

コーデックは「エンコードに何を使うか」なので、libx264を指定すればソフトウェアコーデックであるx264が使われる。 ここではVA-APIのハードウェアコーデックを使用する。

ffmpeg -vaapi_device /dev/dri/renderD128 -i invideo.mp4 -vf 'format=nv12,hwupload' -c:v h264_vaapi -qp 24 -c:a copy output.mp4

なお、A10-7870K (Radeon R7)をAMDGPUで使ったときは、-profile 578してあげないとうまくいかなかった。

ffmpeg -vaapi_device /dev/dri/renderD128 -i invideo.mp4 -vf 'format=nv12,hwupload' -c:v h264_vaapi -profile 578 -bf 0 -qp 24 -c:a copy output.mp4

VA-APIで利用できるコーデックはこんな感じ。もちろん、ハードウェアとドライバが対応していればの話。

フォーマット VA-APIコーデック
H.262 / MPEG-2 part 2 mpeg2_vaapi
H.264 / MPEG-4 part 10 (AVC) h264_vaapi
H.265 / MPEG-H part 2 (HEVC) hevc_vaapi
MJPEG / JPEG mjpeg_vaapi
VP8 vp8_vaapi
VP9 vp9_vaapi
NVENC

VDPAUはデコード専用でエンコードには使えない。 Nvidiaビデオカードの場合、ffmpegからNVENCが利用できる。ただし、nouveauドライバでは不可。

ffmpeg -i invideo.mp4 -c:v h264_nvenc -qp 23 -c:a copy outvideo.mp4

H.265(HEVC)の場合はhevc_nvench264_nvencとはオプションがちょっと違ったりする。

デコードもエンコードも支援

VA-API

VA-APIの場合は結構使うようだ。

最小で言えばVA-APIでデコードした出力を、-hwaccel_output_formatによってVA-APIで渡せば良いようだ。

ffmpeg -hwaccel vaapi -hwaccel_device /dev/dri/renderD128 -hwaccel_output_format vaapi -i invideo.mp4 -c:v h264_vaapi -qp 24 -c:a copy outvideo.mp4

ただし、私の環境(Intel Xeon Silver 4114, AMD Radeon RX580, Linux 5.3)ではこれをやるとかなりの確率でフリーズしてしまう。

VDPAU/NVDEC + NVENC (Nvidia)

NvidiaのVDPAU+NVENCはほとんど見かけないけれども、NVENCの使い方が単純にNVENCハードウェアコーデックを指定するだけなので、単純な組み合わせになる。

ffmpeg -hwaccel vdpau -i invideo.mp4 -c:v h264_nvenc -qp 24 -c:a copy outvideo.mp4

NVDECを使う場合もほとんど同じ。 CUVIDを使うこともできるけれど、多分使うべき理由はない。

ffmpeg -hwaccel nvdec -i invideo.mp4 -c:v h264_nvenc -qp 24 -c:a copy outvideo.mp4

他のコーデックを使う

コピー

copyはビデオ、オーディオともに利用でき、エンコードを行わず単純にストリームをコピーする。

エンコードを行わないので劣化が発生しない。 「ビデオだけ加工したい」といった場合に多用する。

ビデオ

H.265(HEVC)

H.264よりもファイルサイズあたりの品質がいい。 特許問題でものすごくドロドロしているけれども、今のところ主流である。

ソフトウェアコーデックとしてはx265があり、libx265として利用可能。 オプションはほぼlibx264と同じ。

主流だけあって最新のハードウェアなら3メーカーともサポートしており、hevc_vaapihevc_nvencが用意されている。

コンテナは主にはAACと組み合わせて.mp4。それ以外を使うなら.mkv

VP8

Googleが推進していた、全然流行らなかったコーデック。

ffmpeg -i invideo.mp4 -c:v libvpx -qmin 0 -qmax 50 -crf 5 -b:v 1M -c:a libvorbis outvideo.webm

コンテナはOgg Vorbisと組み合わせてWebM。 品質はあまりよくない。

VP9

Googleが推進するコーデック。 H.265がドロドロしすぎているので、配信なんかでは結構使われている。YouTubeでも使われている。

ffmpeg -i invideo.mp4 -c:v libvpx-vp9 -crf 30 -b:v 0 output.webm

指定方法がVP8と全然違う。 この方法だと変な品質のができるので

ffmpeg -i input.mp4 -c:v libvpx-vp9 -minrate 500k -b:v 2000k -maxrate 2500k -c:a opus output.webm

こっちのほうが安全。

画質はなぜか相当粗い。そしてサイズが非常に大きい。 あと、めちゃくちゃ遅い。なかなか思うようにコントロールできない。

コアあたりの速い16コアまでのCPU(具体的にはCore i7あたり)で、-thread 16 -speed 8とかやれば、耐えられないこともないかもしれない。

H.264のライバルらしいけれど、これをライバルと呼ぶのはちょっと無理がありすぎる。 特に低ビットレートになると差は歴然である。 高ビットレートなら意外といけるらしいが、今度は時間が耐え難い。

Intel QSVがVP9エンコーダを搭載しているのだけど、そっちを使うとさらにひどいことになる。

AV1

待望のH.265のライバルであるフリーなコーデック。

ffmpeg 4.0からついに投入されたのだけれど、私の手元では耐えるのは不可能な速度だったので、現実味はまったくなかった。 どうもlibx265と比べても時間は10倍ではきかない感じだ。 デコードも超重いらしい。

ffmpeg -i input.mp4 -c:v libaom-av1 -crf 30 -strict experimental av1_test.mkv

生ビデオにしてからaomencでやることはできた。 …といってもだ。

Pass 1/2 frame 3219/3220  618240B    1536b/f   23040b/s  207846 ms (15.49 fps)
Pass 2/2 frame   20/1      41244B  212969 ms 5.63 fpm [ETA 190:22:59] 1.771 40.510 45.055 49.142   41244F

このくっそ軽い動画で、5.63fpm(fpsではない。fpmである)。 190時間エンコードにかけるという。仮にも20コアXeonでだ。(aomencのマルチスレッドはゴミのようなものだが)

ふざけているのだろうか… libx265の10倍遅い、と言われているが、10倍どころではないだろう。だって、このマシンはlibx265でもだいたい30fpsくらい出るのだから。5fpmといったら、1/360のスピードである。

最終的には18fpm程度になり、3000フレームほどの動画を約4時間で済ませた(平均0.28fps)。

% aomenc --psnr --cpu-used=8 --threads=16 --webm --codec=av1 --profile=0 --end-usage=cq --cq-level=32 --target-bitrate=256 --bit-depth=8 -w 1920 -h 1080 -o testav1.webm pageraw.y4m 
Pass 1/2 frame 3219/3220  618240B    1536b/f   23040b/s  207846 ms (15.49 fps)
Pass 2/2 frame 3219/3219 3972143B    9871b/f  148065b/s 11605639 ms (0.28 fps)
Stream 0 PSNR (Overall/Avg/Y/U/V) 52.334 54.061 53.520 55.570 55.670  148076 bps 11605639 ms

画質は明らかに粗い。とはいえVP9よりはマシ。 今更これを出されても、しかもこんなに重いのでは話にならない…という気がする。 100倍速ければ使う、という感じ。(平均すれば30fps出る程度)

オーディオ

mp3

品質は高くないけれど便利なMP3。

192kbpsのmp3を作る場合

ffmpeg -i audio.wav -c:a libmp3lame -b:a 192k out.mp3

-q:aするとVBRになる。小さいほうが高品位。

ffmpeg -i audio.wav -c:a libmp3lame -q:a 2 out.mp3
Ogg Vorbis

高品位かつフリーなコーデックとして人気のOgg Vorbis。 サポートされていることも多いので有力。vorbisよりlibvorbisのほうが高品位。

-qファクターは大きいほうが高品位。これはoggenc-qにそのまま渡されるらしい。

ffmpeg -i audio.wav -c:a libvorbis -qa 7 out.ogg

ポータブルオーディオにはこれが良い。

Ogg FLAC

こちらもサポートされていることが多いロスレスのオーディオフォーマット。 ロスレスなので音質は損失しない。

CPUをたくさん使ってより圧縮することができる。 この圧縮レベルは音質には影響しないが、サイズの差は小さい。

ffmpeg -i audio.wav -c:a flac -compression_level 12 out.flac

容量に余裕があるなら使っていきたい。

Opus

SILK+CELTがベースになっていて低ビットレートではSILKのようにスピーチ用に可聴音域に特化し、高ビットレートではSILKベースのレイヤーを省いて高品位に再生するオーディオコーデック。

Opusは低ビットレートのHE-AAC、中ビットレートのAAC、高ビットレートのVorbis, AACと比べてより良い品質を提供する。 しかもフリーである。

素晴らしいのだけれど、動画では使いようがあるのに対して音声だと再生できるプレイヤーが割と少なくて困る。 WebMが標準でOpusをサポートしているのにAndroidがOpusをサポートしてないあたりもまた困る。

このため、Opusの出番は

  • ヴォイスレコーディング。 だいたい64kか92k。
  • もともと品質の高くないlossy audioの再変換。同ビットレートなら損失は微々たるもの
  • WebM。VP9との組み合わせが一般的。
  • H.264やH.265と組み合わせ、コンテナをMKVにする

H.265 + Opus の MKV は私の最近のお気に入り。 (ウェブカムのところを見て欲しい)

録音 with Pulse/ALSA

ffmpegがALSAに対応しているので簡単。

レコーディングするデバイスや調整はpavucontrolなどのPulseAudioミキサーでやると便利。

ffmpeg -f alsa -i pulse -c:a flac record.flac

ウェブカム録画

Video4Linux2を使ってウェブカムからの録画が可能。 次の例ではウェブカメラデバイス/dev/video0から録画している。

ffmpeg -f v4l2 -i /dev/video0 -c:v hevc_nvenc -qp 28 record.mp4

音声も録音したいなら組み合わせ

ffmpeg -f v4l2 -i /dev/video0 -c:v hevc_nvenc -qp 28 -f alsa -i pulse -c:a libopus -c:a 192k record.mkv

カメラの場合はカメラが撮れるフォーマットでしか撮れない。 まずは確認する。以下は定番のLogicool C270。

$ v4l2-ctl --list-formats
ioctl: VIDIOC_ENUM_FMT
        Index       : 0
        Type        : Video Capture
        Pixel Format: 'YUYV'
        Name        : YUYV 4:2:2

        Index       : 1
        Type        : Video Capture
        Pixel Format: 'MJPG' (compressed)
        Name        : Motion-JPEG
% v4l2-ctl --list-formats-ext
ioctl: VIDIOC_ENUM_FMT
        Index       : 0
        Type        : Video Capture
        Pixel Format: 'YUYV'
        Name        : YUYV 4:2:2
                Size: Discrete 640x480
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 160x120
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 176x144
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 320x176
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 320x240
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 352x288
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 432x240
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 544x288
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 640x360
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 752x416
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 800x448
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 800x600
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 864x480
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 960x544
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 960x720
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 1024x576
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 1184x656
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 1280x720
                        Interval: Discrete 0.133s (7.500 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 1280x960
                        Interval: Discrete 0.133s (7.500 fps)
                        Interval: Discrete 0.200s (5.000 fps)

        Index       : 1
        Type        : Video Capture
        Pixel Format: 'MJPG' (compressed)
        Name        : Motion-JPEG
                Size: Discrete 640x480
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 160x120
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 176x144
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 320x176
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 320x240
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 352x288
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 432x240
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 544x288
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 640x360
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 752x416
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 800x448
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 800x600
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 864x480
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 960x544
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 960x720
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 1024x576
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 1184x656
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 1280x720
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 1280x960
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)

センサー自体が4:3なので、一応仕様上は1280×720のカメラだと謳っているけれども、最大は1280×960。

画質をとってrawvideoの752×416

ffmpeg -f v4l2 -video_size 752x416 -framertate 25 -i /dev/video0 -c:v hevc_nvenc -profile:v main -qp 24 record.mp4

あるいは画質は劣悪だけれどもピクセル数重視でMotionJPEG。 もともとデータがMotionJPEGで送られてくるので再エンコードはいらない。

ffmpeg -f v4l2 -input_format mjpeg -video_size 1280x960 -framerate 30 -i /dev/video0 -c:v copy record.avi

音声も録音するならOpusでMKVかな

ffmpeg -f v4l2 -input_format mjpeg -video_size 1280x960 -framerate 30 -i /dev/video0 -c:v copy -f alsa -i pulse -c:a libopus -b:a 96k record.mkv

スクリーンキャスティング (X server)

XのAPIを使って画面の録画ができる。

ffmpeg -re -f x11grab -framerate 30 -i $DISPLAY -c:v h264_nvenc -qp 24 record.mp4

300×300のウィンドウを左上から200×200のオフセットで録画する場合

ffmpeg -re -f x11grab -video_size 300x300 -framerate 30 -i $DISPLAY+200,200 -c:v h264_nvenc -qp 24 record.mp4

さらに録画領域を表示する場合

ffmpeg -show_region 1 -re -f x11grab -video_size 300x300 -framerate 30 -i $DISPLAY+200,200 -c:v h264_nvenc -qp 24 record.mp4

クリックしたウィンドウを録画する(zshスクリプト)。 さらにマイク録音も加えた。

xwininfo=$(xwininfo -frame)
geo=$(perl -n -e '/geometry (\d+x\d+)/; print $1;' <<< "$xwininfo" | perl -n -e '/(\d+)(.)(\d+)/; print( $1 % 2 == 0 ? $1 : $1 - 1 ); print $2; print( $3 % 2 == 0 ? $3 : $3 - 1 )') 
corn=$(perl -n -e  '/Corners:\s+\+(\d+)\+(\d+)/ && print $1 . "," . $2;' <<< "$xwininfo") 
ffmpeg -show_region 1 -f x11grab -video_size $geo -framerate 60 -i "$DISPLAY+$corn" -f alsa -i pulse -c:v hevc_nvenc -profile:v main -preset:v default -qp 28 -c:a libopus -b:a 192k "record-$(date +"%y%m%d%H%M%S")".mkv

コンピュータの音とマイクの音両方を録音したい場合。 環境に依存する箇所が多いので注意。

まずは確認。

$ pacmd list-sources

あとはこんな感じ

$ pacmd load-module module-null-sink sink_name=mixmic
$ pacmd load-module module-loopback source=alsa_output.pci-0000_00_1f.3.analog-stereo.monitor sink=mixmic
$ pacmd load-module module-loopback source=alsa_input.usb-046d_0825_D457DB60-02.analog-mono sink=mixmic

ちなみに、WindowsでもDirectShowを使って

ffmpeg -f dshow -i video="screen-capture-recorder" outfile.mkv

みたいなことができるし、これよりはお勧めできる方法として

ffmpeg -f gdigrab -i desktop outfile.mkv

もできる。-offset_x, -offset_yも効くし、-video_sizeも効く。

Macの場合は

ffmpeg -f avfoundation -i "fooscreen:fooaudio" output.mkv

みたいにできる。 実際のデバイス名は

ffmpeg -f avfoundation -list_devices true -i ""

でリストできたり。

スクリーンキャスティングしている内容を仮想カメラにする (v4l2 loopback)

スクリーンキャスティング機能のないメッセンジャーで通話しているときにカメラとして使えることでスクリーンを写せるというメリットがある。

要v4l2loopback カーネルモジュール。

$ sudo modprobe v4l2 video_nr=1
$ ffmpeg -re -f x11grab -video_size hd1080 -i $DISPLAY -f v4l2 -r 60 -vcodec rawvideo -pix_fmt yuv420p /dev/video1

video_nrで作成するデバイス番号を指定している。 video_nr=1なので/dev/video1。4から6を作成したいなら video_nr=4,5,6

hd1080ってなんぞ、ということについては公式ドキュメント参照のこと

AMD APU (A10-7870K Godavari) * Radeon VCE * AMDGPU * VA-API * ffmpeg

理屈としては解説してきたものの、実際にVA-APIでVCEを叩いたことがなかったのでやってみた。 ついでなので、qsvやnvenc、あるいはlibx264などでも応用できるウェブカメラとスクリーンキャスティングの話もしておく。

基本的な手順は単純で、AMDGPU(事実上現在唯一となったAMDビデオドライバ)を選択した上で、 VA-APIを有効にし、VA-API経由でエンコーディングを行う。

注意点としては古くなったプロプライエタリドライバ(Catalyst)ではなく、AMDGPUドライバーを使用することと、 MESA VAドライバを使用することである。

RadeonはVA-API/VDPAUの両方をサポートしており、NvidiaのようにVDPAUドライバをインストールし、VA VDPAUアダプタを使用するという方法(libva-dvpau-driver)も成立してしまう。 しかし、この場合は動作しなくなるので、必ずMESA VAドライバ(libva-mesa-driver)を使用する必要がある。

その上で基本はこんな感じ。 (Arch/ManjaroのffmpegはVA-APIを含んでいるのでffmpeg云々の話はない)

$ ffmpeg -vaapi_device /dev/dri/renderD128 -i source.avi -vf 'format=nv12,hwupload' -c:v h264_vaapi -qp 24 -c:a copy outfile.mp4

ffmpeg上でのVA-APIは公式にドキュメントがある

ソースファイルがビデオアクセラレーションが効くのであればUVDをVA-API経由で叩いてデコードすることもできる。

$ ffmpeg -vaapi_device /dev/dri/renderD128 -hwaccel vaapi -hwaccel_output_format vaapi -i source.avi -vf 'format=nv12,hwupload' -c:v h264_vaapi -qp 24 -c:a copy outfile.mp4

ところがこれではうまくいかなかった。 一件成功しているように見えるのだが、フレームの全くないビデオファイルが出来上がってしまい再生できない。

多分、新しいRadeonだとそんなことはないのだろうと思うけれども、Godavari(2015年)のR7グラフィックスでは問題があったため、-profile 578を指定すると解決した。

$ ffmpeg -vaapi_device /dev/dri/renderD128 -i source.avi -vf 'format=nv12,hwupload' -c:v h264_vaapi -profile 578 -bf 0 -qp 24 -c:a copy outfile.mp4

ウェブカムからキャプチャする場合はエンコードのみ、入力はv4l2:

$ ffmpeg -vaapi_device /dev/dri/renderD128 -f v4l2 -i /dev/video0 -vf 'format=nv12,hwupload' -c:v h264_vaapi -profile 578 -qp 24 outfile.mp4

さらにマイクをPulseAudio経由で拾う場合。音声は192k AAC:

$ ffmpeg -vaapi_device /dev/dri/renderD128 -f v4l2 -i /dev/video0 -vf 'format=nv12,hwupload' -c:v h264_vaapi -profile 578 -qp 24 -f alsa -i pulse -c:a aac -b:a 192k outfile.mp4

X11のスクリーンキャスティング 音声つき。 A10-7870Kだとh264_vaapiは34fpsくらいなので、60fpsはフレーム落ちばかりになる。30fpsも無理で24fpsがドロップしない限界。 ultrafastにした場合は30fpsは可能だけれど60fpsは無理。

$ ffmpeg -vaapi_device /dev/dri/renderD128 -f x11grab -framerate 24 -video_size 1920x1080 -i $DISPLAY -vf 'format=nv12,hwupload' -c:v h264_vaapi -profile 578 -qp 24 -f alsa -i pulse -c:a aac -b:a 192k outfile.mp4

ultrafastで30fps:

$ ffmpeg -vaapi_device /dev/dri/renderD128 -f x11grab -framerate 30 -video_size 1920x1080 -i $DISPLAY -vf 'format=nv12,hwupload' -c:v h264_vaapi -profile 578 -preset ultrafast -qp 24 -f alsa -i pulse -c:a aac -b:a 192k outfile.mp4

なお、-video_size-iよりも先に指定することが必須である。基本的にffmpegはオプションは順番に厳しい。

300×300のウィンドウを左上から200×200のオフセットで録画する場合

$ ffmpeg -vaapi_device /dev/dri/renderD128 -f x11grab -framerate 30 -video_size 300x300 -i $DISPLAY+200,200 -vf 'format=nv12,hwupload' -c:v h264_vaapi -profile 578 -preset ultrafast -qp 24 -f alsa -i pulse -c:a aac -b:a 192k outfile.mp4

-video_sizeの指定方法は色々あって、公式ドキュメントで解説されている。 なので、-video_size 1920x1080ならば-video_size hd1080とも書ける。

録画領域を表示するには-show_region 1

$ ffmpeg -show_region 1 -vaapi_device /dev/dri/renderD128 -f x11grab -framerate 30 -video_size hd1080 -i $DISPLAY -vf 'format=nv12,hwupload' -c:v h264_vaapi -profile 578 -preset ultrafast -qp 24 -f alsa -i pulse -c:a aac -b:a 192k outfile.mp4

NVENCだとmkvにもできるので音声はFLACやOpusで撮ることもできるのだけど、AMDGPU VA-APIはmp4だけ

使ってみた感想としては、QSVと違ってCPUがあくのは良いけれど、R7の速度自体がCPUと大差ない(libx264でやったのと同程度)であるため、ちょっと微妙かもしれない。 A10でもスクリーンキャスティングしながら配信みたいなことができるというメリットはあるけれども。

Amazonのコンテンツ戦略とユーザーの問題

かつてのPrime

Amazonはいよいよ本格的にコンテンツ課金をはじめたようだ。

Amazonはプライムの価値を高めるため、Amazon Prime Music, Amazon Prime Photo, Amazon Prime Videoといったサービスをはじめた。 このサービス自体はアメリカ(.com)と同じものだが、.comと比べるとだいぶ安価な設定になっている。

そのためにプライムの価値は高かった。 当時プライムでなくても配送は無料だったし、お急ぎ便と変わらないスピードで届いていたのでプライムの価値は微妙だったけれど、こうしたコンテンツの充実によってプライムの価値を高めた。

Prime Musicはもとより微妙だった。 音楽大好きな私は大歓迎したのだけれど、とにかく収録曲数が少ない、というかラインナップが大変微妙。 しかもその微妙な音楽もどんどんPrimeから外されていくので実用性も微妙だった。

特殊なBGMをかけたいとき(ムードミュージックとか)でなければ使わなかった。

Prime Photoは現在も有効だけれど、写真をAmazonに渡すことを考えると…

そうしたことを踏まえてもAmazon PrimeのキラーコンテンツはAmazon Prime Videoだったと言っていい。

コンテンツ課金へ

付加コンテンツは微妙だが本国より圧倒的に安価なAmazon Primeはかなりの人気を集めた。

だが、Amazonはあまりユーザーのほうを向いていないようだ。

非Primeに対して送料有料にする、ということは無料自体が一時的なものだったからやむを得ないだろう。 また、梱包の質が落ちていることも、配送が遅れ気味であることも、Amazonのサービスの根幹的価値を落としている気がするが、かつての品質が非人道的労働によるものだとするならば、人はその品質低下は受け入れるべきだろう。

だが、問題は結局はPrimeに付加コンテンツを含めることをやめつつある、ということだ。

今後追加されると言っていたPrime Musicに関しては追加された楽曲にめぼしいものは少なく、主には(.comでライセンスされている)洋楽だった。むしろ追加より削除のほうが目立ったくらいで、人気アーティストの盤はライブや 結局、(私に限らず)Amazon Prime Musicは おまけのような存在を脱していなかったのだ1

そこへAmazon Music Unlimitedが追加された。Music Unlimitedサービスとしては標準的で、Primeサービスを拡張する感覚で使えるのがメリットだ。 だが、Amazonの付加コンテンツがただのお試し版であることが明らかになってしまったとも言える。 Primeの価値を高めるために追加されてきたコンテンツはあくまで他の有料サービスの体験版で、Primeの価値を高めるものではない(広告的存在である)と位置づけが変わってしまい、結果的にPrimeの価値はさらに下がった2

そしてPrime Videoもいまいちな状態となり3、早々にPrimeのみの表示だったトップページがPrimeをクリックしてもAmazonビデオのトップページとなり、さらに現在はPrimeのページにも購入の項目が並ぶようになっている。

そして有料チャンネルの追加だ。Prime VideoからJ-Sportが見られるようになった、というメリットはあるものの、これも本家で入ったほうが安く、オプションも豊富、見られる番組も多い。

とはいえこの時点では従来のPrime Videoが損なわれたわけではなく、「微妙な有料追加コンテンツが入った」というだけなのであまり見向きもされなかったのだが、一気に話題となったのがdアニメ for Amazon Primeの登場だろう。

Amazon Prime Videoはもとより比較的アニメに強かった。 だが、dアニメが圧倒的なラインナップを誇るためアニメ好きの選択肢というよりはアニメファンとしてはライト層の選択肢であったといっていいだろう。 ここにdアニメが加わったことは、単純に言えばAmazon Music Unlimitedのようなもので、コンテンツに幅が増えた、と言える。

だが、問題は、本家dアニメと比べて随分とラインナップが少ないこと、そして「Amazon Prime Videoを廃止してdアニメのみになった人気番組がある」ことだ。

ユーザーの絶望的リテラシー

もちろん、そのようなことは腹立たしいだろう。 私も「えー」と思った。

だが、大荒れのレビューは、ちょっとこんなにも愚かな人がこの世界にあふれているとはにわかには信じがたいものになっている。

まず、「元々お金をとっているのにさらに追加でお金をとるなんて詐欺だ」という主旨の発言。

Prime Video以外に選択肢がある、と理解しているのであればPrime経由でなくそちらでみればいい。 別に複数の課金コンテンツがあることはなんら問題ないだろう。 また、(その人はアニメのためにPrimeに加入しているのかもしれないが)Amazon PrimeはそもそもAmazonでの買い物のための優待であって、Prime Videoは付加コンテンツにすぎない。Amazon Primeが気に入らないのならPrimeを退会すれば良いし、なんならAmazonを使わなければ良い。 その自由はあるし、別にAmazon Primeをやめて他のところに加入するのも、Amazon Primeとは別に他のところに加入するのも自由だ。 Amazonにお金を払っているからといってすべてが手に入るわけではないのだから。

そして、「Primeのマークがあるのに途中からdアニメに課金させるなんて詐欺だ」という主旨の発言。

実際にそのような作品があった(それもかなり有名所であった)ため気持ちはわからないのではないのだが、元々Amazon Prime Videoの更新は不定期で、「毎週何曜日に更新」となっているものですら不定期だった。 対してdアニメのほうはきっちりやっているので時間差がある。

導入当初ならわかるのだが、既に大荒れコメントからの訂正というレビューが溢れているにもかかわらず放送回が更新されるたびにそんなレビューが追加されるのにはうんざりする。

多分、レビューが参考にならないといっている人はこのような人なのだと思う。 全く読まないか、もくしは読むとしても何かを読み取ろうとするのではなく自分の都合に合致するようにしか受け取らないのだ。 実際、このようなレビューは「他の人も言っている」とレビューしていたりするのだが、その人は訂正も入れているはずなのだが。

私はAmazonの対応よりも、自発的に何かを考えたり受け取ろうとしない愚かな人の多さによっぽど絶望している4


  1. AKBの楽曲があるので、AKBが好きな人なら満足したかもしれない。

  2. コンテンツ的にも削除が相次いで価値は少し下がったが、これは「PrimeはAmazonの特別なサービスを受けられる」から「PrimeはAmazonの他のサービスの体験版がついてくる」に位置づけとしてグレードダウンしたという話だ。

  3. これに関しては意見は様々だろうけれども、削除が目立ち、放送と連動したものも不定期にアップデートされ、みたいと思うような作品はなかなかPrime扱いにならないなど本屋の安売りワゴンのような様相を呈してきているように感じる。

  4. もちろんAmazonのやり方が適切だとも思わないが、それは「Primeの付加価値が低下し、存在価値が微妙になった」というだけのことで、サービスの質の低下についてとやかく言うことでもない。

今更だけど、mpvがビデオ再生に便利

mpv、ほんとになんでもできるようになってきていて笑いが止まらない。

mpvで自由自在にビデオを見る

mpvの定番の設定になっているようだけれども

ビデオを回転させる:

Alt+RIGHT add video-rotate 90
Alt+LEFT add video-rotate -90

ビデオをズーム/パンする。 これは既にデフォルトの設定として採用されている。

Alt+- add video-zoom -0.25
Alt+= add video-zoom 0.25

ズームしたビデオを移動する。

Alt+j add video-pan-x -0.05
Alt+l add video-pan-x 0.05
Alt+i add video-pan-y 0.05
Alt+k add video-pan-y -0.05

ズーム/パンの設定をリセットする。

Alt+BS set video-zoom 0; set video-pan-x 0; set video-pan-y 0

もちろん、こんなのはほんの一部で様々なことができる。

12はコントラストに割り当てられている。 全体的に画面が暗く、もやもやしてよく見えないときにはコントラストを上げると良い。 逆に色彩鮮やかすぎて目が痛い画面ではコントラストを下げると見やすくなる。 くらい室内の動画や夜間撮影の動画ではコントラスト上げが、明暗差がきつい晴天時のオンボード動画などではコントラスト下げが活躍する。

Ctrl++Ctrl+-はオーディオディレイに対応している。 定量的な音ズレを簡単に補正できる。

*/あるいは9, 0はボリュームコントロールに対応している。 複数のビデオを並行で再生するような環境では1音量を揃えるために活躍してくれる。セッションを越えて保存されないので、一時的な変更には最も手軽だ。

sでスナップショットを取る。非常に手軽だ。

3, 4でブライトネス、5, 6でガンマ、7, 8でサチュレーションを補正する。 私はあまり使わないが画質的に見づらい動画を補正できる。

iでビデオの詳細な情報を表示する。 詳細な上にみやすく、ビデオソースについて知る必要があるときには活躍する。

lでA-Bループになる。lを押すだけの簡単操作で正確なタイミングをつかみやすい。 Lでそのビデオをループする。

aはアスペクト比の強制を行う。 アスペクト比の間違ったビデオを再エンコードせずに視聴できる。

字幕も表示/非表示、タイミングの補正、位置の補正も可能だ。

mで一発ミュート。

[]は再生速度のコントロールになっている。 音楽の練習ではとても重宝する。

Ctrl+LEFTCtrl+RIGHTはちょっとめずらしい、字幕の早送り/巻き戻しに対応している。密度の高い字幕がある場合には結構便利だ。

PgUpPgDownがチャプターに対応しているが、Shift+PgUpShiftPgDownが10分巻に対応しているのも数時間あるようなビデオではポイント高い。

そして、実はXF86メディアキーでの操作も可能。

ほんとなんでもできる。ありとあらゆるビデオを快適に再生し、活用できるようになっている。

mpvについて

mpvはもとはMPlayer2と呼ばれていて、MPlayerからフォークしたものだ。 MPlayer2はあまり人気がなかった気がするけれども、mpvになってからはMPlayerに対する明らかなアドバンテージの数々(例えばVA-API/VDPAUのサポートなど)を武器に今や標準ツールとなりつつある。

MPlayerもそうなのだけど、GUIのないビデオプレイヤーの魅力って、ちょっと理解しにくい。 実際、私も昔はGMPlayer2ばかり使っていた。

ないよりはあったほうがいいじゃないか、と思うかもしれない。 だが、そうではないのだ。

ビデオの場合、視覚的なものである。 コントロールを表示すればその分表示領域が必要になる。 画面の外に表示すればビデオは小さくなるし、重ねれば邪魔になる。必ずしもフルスクリーンで見るわけでもない。フルスクリーンではないけれど取れる範囲で最大限のスペースを使いたいという希望は普通にあるだろう。

また、VLCやSMPlayerだとビデオを開くたびにセッションを開く。 再生が重いというのもあるが、ものすごく単純なこととして、「ファイルを開いたら単純にそのファイルを開いてほしい、それ以外にはなにもしないでほしい」というのがあったりする。

mpvは再生によって何かを保存したり記憶したりしない。 余計なものを開いたりもしない。ファイルブラウザでビデオを開くアプリケーションをmpvにしていれば、ただ単純にダブルクリックするとビデオが再生される。

だが、その場合でもちゃんと視聴に必要な機能は備わっていてほしいはずだ。 mpvには他のプレイヤーにはないような機能まできっちり備わっている。 何かにプレイヤーを内包するような機能はない3が、プレイヤーとしての機能はパーフェクトなはずだ。

写真で考えてみよう。

アルバムアプリを立ち上げ、写真フォルダを探しながら写真をみるときと、ファイルブラウザから写真をダブルクリックするときでは意識に大きな違いがあるはずだ。 そして、ファイルブラウザでダブルクリックしたとき、アルバムアプリが立ち上がり、写真フォルダ一覧が表示されるのはあなたが望むことではないだろう。ファイルブラウザで写真をダブルクリックしたら写真を表示してほしいはずだ。それ以外の余計なものは表示せずに。

mpvはそういうアプリケーションだ。 コントロールはキーボードで行う。一見複雑なようだが、考えてみてほしい。 複雑に様々なコントロールができるとしたら、専用のリモコン、あるいはコントローラがあったほうが便利だろう。

だが、GUIがあったほうが便利なこともある。 例えば全体がどれくらいで、今どれくらいの位置を再生しているのか知りたいときなどだ。 mpvはpseudo-gui/OSDと呼ばれる機能により、oキーと、マウスオーバーによってそれらの情報を表示できる。 しかも表示できるだけではない。なんて操作できる。ビデオスキャンのほか、タイトルクリックでのフルタイトル表示、プレイリストコントロールなどが可能だ。


  1. 多分そんなことをする人はあまりいないのだけれど、私は多用する。

  2. ソフトウェアとしてはMPlayerなのだけれど、gmplayerというコマンドを使用するとGUIつきで起動する。Arch LinuxではMPlayerはgmplayerなしでビルドされている。

  3. いや、実はyoutube-dlを介してURL再生できたりするのだが

Linux的ビデオのハードウェアエンコーディング

更新されたまとめた記事があります

ネットで検索するとかなりいい加減な情報が溢れているので、 そこまで分かっているわけではないけれどまとめてみた。

「エンコード」

まずencodeとdecodeがわからない記事がいくつか出てくるのでそこから。

  • データを映像/音声にするのがデコード
  • 映像/音声をデータにするのがエンコード

エンコードは動画編集をしているのでなければ、基本的に動画変換のお話。

ハードウェア

ハードウェアでやる、というのはCPUに頼らず、ハードウェア側に搭載された専用のチップを使用してエンコーディングする話をしている。

これにより

  • CPUにかかる負荷が低減できる
  • 速度が向上する(かもしれない)

というメリットがある。

遅いGPUと速いCPUの組み合わせだと速度向上には必ずしもつながらないが。 だが、GPUは非常に速いので高速化する可能性は高い。

最近の盛り上がり

動画処理というか、変換というかではなくて、 「ゲームしながらゲームを録画するため」 だと思う。

ゲームはリソースをいっぱい近く使うので、録画するのは難しい。 処理落ちなどの原因になる。 そんなことがあったら多分ガチなゲーマーは許さない。

録画時はそのまま映像データを収録しているとあまりに巨大ファイルになる。 ゲームのプレイ時間は長い可能性が高いし、これはこれできつい。 というわけで、これをハードウェアにオフロードしてCPUや描画用グラフィックスに負担をかけることなく録画/変換して保存しようということだと思う。

ただ、IntelのQSVは恐らく趣旨が違う。 というのは、こちらは「CPUやメモリにも負担をかける」からだ。 VP9エンコードにもKaby Lakeにも対応していたりするので、もしかしたら動画編集を意識しているのかもしれない。

VA-APIとVDPAU

VA-APIはIntelが、VDPAUはNvidiaが作ったLinux用のハードウェアビデオアクセラレーション用のAPIだ。

それぞれサポートされているのだが、そのサポートに注意がいる。

  • libva-vdpau-driverはVA-APIをラップしてVDPAUに投げる
  • libvdpau-va-glはVDPAUをラップしてVA-APIに投げる

このため

  • NVIDIAはVA-APIは使えるけれど実際はVDPAUを使用する
  • IntelはVDPAUは使えるけれど実際はVA-APIを使用する

ちなみに、AMDのオープンソースドライバ(ATIあるいはamdgpu)はVA-APIドライバとしてlibva-mesa-driver(とmesa)と、libva-vdpau-driverの2種類の方法がある。 前者であればVA-APIを直接取り扱う。後者であればVDPAUに流す。

そして、重要な点

  • VDPAUはハードウェアデコード用
  • VA-APIはハードウェアエンコード/デコード用

つまり

  • NvidiaのカードはVA-APIをサポートしていないのでこの方法でのエンコードは無理
  • AMDのカードはlibva-mesa-driverを使わないとハードウェアエンコードできない

ハードウェア側機能

IntelにはQSV, NvidiaにはNVEnc, AMDにはVCEがある。

QSV (Quick Sync Video)

デコードだけじゃなかったんだぁ…と思ってしまったけれど、 実はIntelのビデオアクセラレーションは割とLinuxに手厚い。

QSVの利用はIntel Media Server Studioを要求されるけれども、色々と条件が厳しいし、フリーではない(無料ではあるけれど)。

性能的には劣るもののVA-APIから叩けるらしい。

VCE (Video Coding Engine)

デコード用のUVD(Unified Video Decoder)とセットのAMDの機能。

VA-API経由で叩ける。

NVEnc

Nvidiaのエンコード用ビデオアクセラレーション。 Pascal世代になってとっても速くなったらしい。

Maxwell Gen2でもHEVC 720p高画質で300fpsとか言っているのでGPUすごい。

QSVのほうが速いとか言っている人がいるけれども、多分そんな環境まずない。

画質が割と腐っているけれど、H265がH264とほぼ同じ速度で変換できるので、H265にすればだいぶよろしくなる。 H265エンコードはMaxwellからのサポート。

エンコーダと画質のお話

ハードウェアエンコードを行う場合、実際のデータ変換処理を行う「エンコーダ」としてハードウェアへのアダプタを指定する。

つまり、NVEncを使う場合、libx264の代わりにnvenc_h264を使うことになる。 なのでエンコーダオプション(-crfとか)も変わる。

結果的に変換のされ方が変わる。 同一のクオリティを要求しても同じデータにはならない。

そして、ハードウェアエンコードを行った場合の画質、あまりよくない。 H.264でq=30くらいまで落とすとものすごくわかりやすいことになる。 q=28でも厳しい。

画質が悪いのだからできれば「保存したい」よりも「消すのはちょっと…」くらいのモチベーションの動画で使いたいところなのだが、 そういう動画こそサイズを小さくしたい。 ところが、ハードウェアエンコーダでサイズを小さくすると画質が目立って悪い。 だいぶ悩ましい話だ。

ffmpegでエンコード

Linuxの動画はffmpegで変換するものでしょう?

というわけで、QSVとVCEはVA-APIに対応しているのでVA-APIで。

ffmpeg -vaapi_device /dev/dri/renderD128 -i input.mp4 -vf 'format=nv12,hwupload' -c:v h264_vaapi output.mp4

エンコードもハードウェアでやればより軽い。

ffmpeg -init_hw_device vaapi=foo:/dev/dri/renderD128 -hwaccel vaapi -hwaccel_output_format vaapi -hwaccel_device foo -i input.mp4 -filter_hw_device foo -vf 'format=nv12|vaapi,hwupload' -c:v h264_vaapi output.mp4

-qオプションは指定できるみたい。

ffmpeg -init_hw_device vaapi=foo:/dev/dri/renderD128 -hwaccel vaapi -hwaccel_output_format vaapi -hwaccel_device foo -i input.mp4 -filter_hw_device foo -vf 'format=nv12|vaapi,hwupload' -c:v h264_vaapi -q 28 output.mp4

Nvidiaがひとり独自路線なのはちょっと気になるけれども、使いやすいのはnvencのほう。

ffmpeg -i input.mp4 -c:v nvenc_h264 -q 28 output.mp4

qの値など実際は探り探りやっていくしかない感じ。

あなたのビデオカード、眠ってませんか

GPUは基本的に積極的に働かせないと動かない子なので、 結構なリソースを眠らせている可能性は結構ある。

Linux環境だとCinnamonとKDE Plasmaがハードウェアアクセラレーションに対応しているため、 割と最近のIntel CPUやAMD APUを搭載しているコンピュータだとCPU的にはXFceやMATE、LXDEなんかよりよっぽど軽かったりもする。

そういうのがあればある程度は働いてくれるのだが、これもビデオカードの機能のごく一部を使っているだけ。 ちなみに、OpenGL用のアクセラレータを使っている。

この状態でもデコーダやエンコーダは遊んでいるので、せっかくのリソース活用してあげてください。

ハードウェアエンコーダの画質はちょっと微妙だけども。

ffmpegでスクリーンキャスト&ウェブカメラ撮影

更新されたまとめた記事があります

ほぼArch wikiの通りではあるけれども

スクリーンキャスト

スクリーンキャストはPCの画面を録画する。

recordMyDesktopやIstanbulを使うことが多いかもしれないが、処理が遅くて録画した後が大変だし、音声に自由度がない。

とりあえずFullHDでキャストしてみた。

$ ffmpeg -f x11grab -video_size 1920x1080 -i $DISPLAY -f alsa -i pulse -acodec aac -vcodec libx264 -preset ultrafast -qp 0 tmp/test.mp4

これで左上から1920×1080の領域が録画される。音声はpulse経由であり、マイク保存することもできるし、モニターを保存することもできるし、特定のアプリケーション出力を保存することもできる。

特に音声を記録しないなら

$ ffmpeg -f x11grab -video_size 1920x1080 -i $DISPLAY -acodec aac -vcodec libx264 -preset ultrafast -qp 0 tmp/test.mp4

ALSAでやりたいなら

$ ffmpeg -f x11grab -video_size 1920x1080 -i $DISPLAY -f alsa -i default -acodec aac -vcodec libx264 -preset ultrafast -qp 0 tmp/test.mp4

特定のウィンドウを記録するにはxwininfoを使えばいける。

Gist

使い方としては、-w(ウィンドウモード)、-m(マイク有効)オプションを受け付ける。

ウェブカム録画

$ ffmpeg -f alsa -i pulse -f v4l2 -s 1280x720 -i /dev/video0 -acodec flac -vcodec libx264 -preset ultrafast tmp/test.mkv

意外ときつい。解像度を落とせばいける。

ただし、guvcviewなどで録画するよりはずっと快適。

PulseAudio応用

マイクから録る

単純にpavucontrolから録音しているアプリケーションのマイクデバイスを選択すれば良い

モニターを録る

入力装置をAll Expect Mintorsではなく、All Input Devicesにすればモニターも見える。
あとは録音しているアプリケーションでモニターを選択すれば良い

特定のアプリケーションだけ録る

$ pacmd load-module module-null-sink sink_name=MySink
$ pacmd update-sink-proplist MySink device.description=MySink

といった感じでSinkを作成、これがスピーカーとして入るのでアプリケーションの出力先にする。
これだけでは追加されるのはモニターだけでマイクロフォンはないが、Monitor of Null 出力を選択すればそのアプリケーションだけ取れる。

もちろん複数のアプリケーションをまとめて録音することも可能。

エンコード

ultrafastで録画したデータは非常に大きいので、圧縮する。

圧縮がしやすいように用意した~/.zshrc.d/40-zaliasesは以下の通り

## Video Conversion ##

videocomps() {
  #WebM? H.264? H.265?
  case $1 in
  264)
    case $2 in
    best)
      ffmpeg -i "$3" -vcodec libx264 -preset veryslow -crf 18 -strict -2 _comped_"${3:r}".mp4
      ;;
    goodslow)
      ffmpeg -i "$3" -vcodec libx264 -preset slow -crf 18 -strict -2 _comped_"${3:r}".mp4
      ;;
    good)
      ffmpeg -i "$3" -vcodec libx264 -crf 18 -strict -2 _comped_"${3:r}".mp4
      ;;
    normal)
      ffmpeg -i "$3" -vcodec libx264 -crf 23 -strict -2 _comped_"${3:r}".mp4
      ;;
    light)
      ffmpeg -i "$3" -vcodec libx264 -crf 28 -strict -2 _comped_"${3:r}".mp4
      ;;
    mobile)
      ffmpeg -i "$3" -vcodec libx264 -crf 36 -strict -2 _comped_"${3:r}".mp4
      ;;
    esac
    ;;
  265)
    case $2 in
    best)
      ffmpeg -i "$3" -vcodec libx265 -preset veryslow -x265-params crf=18 -strict -2 _comped_"${3:r}".mp4
      ;;
    verygoodslow)
      ffmpeg -i "$3" -vcodec libx265 -preset slow -x265-params crf=18 -strict -2 _comped_"${3:r}".mp4
      ;;
    verygood)
      ffmpeg -i "$3" -vcodec libx265 -x265-params crf=18 -strict -2 _comped_"${3:r}".mp4
      ;;
    good)
      ffmpeg -i "$3" -vcodec libx265 -x265-params crf=23 -strict -2 _comped_"${3:r}".mp4
      ;;
    normal)
      ffmpeg -i "$3" -vcodec libx265 -x265-params crf=28 -strict -2 _comped_"${3:r}".mp4
      ;;
    light)
      ffmpeg -i "$3" -vcodec libx265 -x265-params crf=32 -strict -2 _comped_"${3:r}".mp4
      ;;
    mobile)
      ffmpeg -i "$3" -vcodec libx265 -x265-params crf=38 -strict -2 _comped_"${3:r}".mp4
      ;;
    esac
    ;;
  webm)
    case $2 in
    best)
      ffmpeg -i "$3" -c:v libvpx-vp9 -b:v 0 -threads 8 -crf 10 -c:a libopus -f webm _comped_"${3:r}".webm
      ;;
    verygood)
      ffmpeg -i "$3" -c:v libvpx-vp9 -b:v 0 -threads 8 -crf 18 -c:a libopus -f webm _comped_"${3:r}".webm
      ;;
    good)
      ffmpeg -i "$3" -c:v libvpx-vp9 -b:v 0 -threads 8 -crf 23 -c:a libopus -f webm _comped_"${3:r}".webm
      ;;
    normal)
      ffmpeg -i "$3" -c:v libvpx-vp9 -b:v 0 -threads 8 -crf 28 -c:a libopus -f webm _comped_"${3:r}".webm
      ;;
    light)
      ffmpeg -i "$3" -c:v libvpx-vp9 -b:v 0 -threads 8 -crf 33 -c:a libopus -f webm _comped_"${3:r}".webm
      ;;
    mobile)
      ffmpeg -i "$3" -c:v libvpx-vp9 -b:v 0 -threads 8 -crf 48 -c:a libopus -f webm _comped_"${3:r}".webm
      ;;
    esac
    ;;
  esac
}

CRF値はH.264以外はちゃんとデータを出していない。
参考までにVP9 CRF33でエンコードするとこんな感じだった。

$ ls -lh
合計 50M
-rw------- 1 aki users 3.1M  3月 14 16:50 _comped_purebuilder.webm
-rw------- 1 aki users  47M  3月 14 16:46 purebuilder.mp4

シンプルなスクリーンキャストとはいえ、mobileはさすがにきつい。