【まとめ特集記事】 ビデオカード * 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 x o
VA-API o o

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

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

それぞれアダプタを使用して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の場合NVDECを直接叩くこともできる。

さらにCUDAも使える。

MPlayer

VDPAUの場合

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

Xine

詳しくは

Dragon Player

できないっぽい。

Kaffeine

多分できない。

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

FFMpeg

基本編

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

まずは基本

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

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

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

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

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

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

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

H.264で色々する

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

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

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

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

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

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

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

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

さらに色々する

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

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

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

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

動画をリサイズする

動画をクロップする

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

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

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

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

音ズレを解消する。

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

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

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

-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があったとして

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

ここで-mapを使い

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

を合成させる

ここで-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する場合などには少しコントラストを上げたほうが見やすい動画になる。

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

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

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

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

VDPAU/VA-API/NVENC

再生支援

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

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

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

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

エンコード支援

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

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

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

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

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

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

再生もエンコードも支援

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

基本的には組み合わせなのだけれど、出力フォーマットにvaapiを指定する必要があり、項目は2つ増えている。これはちょっと複雑。

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

他のコーデックを使う

コピー

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

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

ビデオ

H.265(HEVC)

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

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

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

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

VP8

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

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

VP9

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

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

こっちのほうが安全。

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

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

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

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

AV1

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

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

生ビデオにしてから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)。

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

オーディオ

mp3

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

192kbpsのmp3を作る場合

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

Ogg Vorbis

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

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

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

Ogg FLAC

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

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

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

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ミキサーでやると便利。

ウェブカム録画

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

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

カメラの場合はカメラが撮れるフォーマットでしか撮れない。 まずは確認する。以下は定番の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

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

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

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

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

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

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

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

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

まずは確認。

$ 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

スクリーンキャスティングしている内容を仮想カメラにする (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でもスクリーンキャスティングしながら配信みたいなことができるというメリットはあるけれども。

ffmpeg * V4L2 と Logicool C270 で HD 30FPS 撮りたい

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

まずffmpeg * V4L2 でウェブカム撮影する方法は次の通り。

デバイスは適宜読み替えること。

NVENCでG.265に変換して変換して保存する場合は

QSVやVCEでVA-APIを使う場合は

さらにPulseを使って音も入れる場合は

HEVC+Opus MKVが最近のお気に入り。

そしてビデオサイズを指定する場合は

しかしLogicool C270だとこれで5FPSになってしまう。かっくかくやでぇ。 そこでフレームレートを指定する。

けれどこれでも7.5FPSになってしまう。 v4l2-ctlを用いて確認してみる。

YUVU以外にMotionJPEGもサポートしている、と。 で、詳しく見てみると…

% 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)

YUVUだと720Pは5/7.5FPSしか選択肢がない。 一方、MotionJPEGであれば30FPSでもとれるらしい。 720Pのカメラ、とあるのだが、何気に1280×960などというフォーマットもあるのは、センサー自体が4:3だからということだろうか。

というわけでmotionJPEGを指定する。

しかし、大量のエラーメッセージが出る

[video4linux2,v4l2 @ 0x5600641ec760] Thread message queue blocking; consider raising the thread_queue_size option (current value: 8)
[mjpeg @ 0x5600641eea00] unable to decode APP fields: Invalid data found when processing input

しかも、画質は非常に悪い。 確かにHDで30FPSを取るという目的は達成できたけども、画質を考えると普通に640×480で取るのと大差ないという悲しさよ。

MotionJPEGで高画素で取るのなら一旦はMotionJPEGのままでもよさそう。

調べた限り、USB3.0接続のウェブカムというのはなさそうで、 H.264でFHD 30fpsの出るウェブカムというのはあるにはあるけれども、UVC1.5に対応していないとなかなか面倒なことになる…と

手頃にH.264が取れるウェブカムとしては、ELPのカメラモジュールがあったりするのだけれど、 ウェブカムに色々求めてはいけないということなのだろうか…

Intel QSV * Linux * FFmpeg * (H.265|VP9)

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

Intel QSVによる動画エンコーディングを試してみた。

LinuxにおいてIntel QSVはVA-APIを通して利用することができる。 そのため、FFmpegのVA-API機能を使用してエンコードしてみる。

VP9 WebM。

おおよそ基本的なフォーマットに従っているけれども、注意点は-vfオプションだろう。

これはビデオフィルタを指定するのだが、この中でscale_vaapiは動画の画像サイズ(よく解像度と言われるもの)を変更している。 これは、ソフトウェアエンコーディングのものと比べ柔軟性が劣るため、スクリプトで連続処理する場合はよく考えて設定する必要がある。 特にアスペクト比が一定でない場合は注意が必要。

VP9でconstant qualityエンコーディングしたいと考えたのだけど、結局まともな結果は得られなかった。 -qだろうが-qpだろうが、設定は基本的に無視される(もちろん、-b:v 0しているのだけど)。

H.265の動画を作る。

そして、-qp 32のH.265なMP4と、-b:v 2.5MのVP9なWebMの比較が次の通り。

-rw-r--r-- 1 aki aki  43215798  1月 24 14:27 _comp_fuwa.mp4
-rw-r--r-- 1 aki aki  43365795  1月 24 14:30 _comp_fuwa.webm

VP9は非常に荒れている
VP9 2.5Mbps キャプチャ

H.265は良好な画質
H.265 2.5Mbps (qp=32)

VP9のほうは、とても見られたものではない。 オリジナルは171484771バイトのH.264 MP4であるが、

encoder         : Lavf57.25.100
  Duration: 00:02:14.08, start: 0.000000, bitrate: 10231 kb/s
    Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, smpte170m/unknown/smpte170m), 1080x1920 [SAR 1:1 DAR 9:16], 9942 kb/s, 29.88 fps, 29.88 tbr, 15296 tbn, 59.75 tbc (default)

H.265のほうがなんら問題なく見られるのに対して、VP9のほうはちょっと実用に耐えない。 フリーのコーデックを使いたいという気持ちは強いので、何度も実験しているのだけれども、今のところ「高圧縮のH.265並の圧縮度を求めるとひどい結果になる」という結論しか得られていない。

そもそも(VP10が合流した)AV1が「HEVCに迫る」なんて言っている状況を鑑みればそんなものなのかもしれない。 AV1はまだavcodecには載っていないので、WebM勢は遅れが目立ち、このままではWeb配信のみのフォーマットになってしまいそうだ。

WebPが後発のHEIFに飲み込まれそうな情勢を考えても、世界はライセンス問題という頭痛の種をなんとかしようという方向には進まないらしい。

個人的に所蔵するデータについては、恐らくおとなしくH.265/MP4にするのが無難だろう。 公開・配布する場合はVP9も選択肢に入るだろうし、その場合はIntel QSVでエンコードできるのは非常に嬉しいだろう。1

先日のNVENCを使用する方法(Nvidia版, H.264)は次のようなものだった。 どちらかといえばVA-APIにして欲しいなぁ…


  1. 自分で所蔵する(オリジナルになる)特別な動画データなら時間をかけても構わないが、一時的な自分ではあまり使わないデータであれば瞬間で終わってほしいと思うのが人情だろう。

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はさすがにきつい。

Linuxにおけるビデオフォーマットの取り扱い(H.264/H.265/VP9 WebM)

ビデオのファイルフォーマットについて

ビデオのファイルフォーマットは、

  • 動画部分
  • 音声部分
  • それをまとめる部分

の3パートからなる。
今回は

  • H.264+AACのMPEG-4 Part14(mp4)
  • H.265+AACのMPEG-4 Part14(mp4)
  • VP9+OpusのWebM

の3種類についての検討となる。

検討すべき点

画質とファイルサイズ

画質面では基本的に非圧縮が最良である、と考えて良い。
しかし、それではあまり巨大なデータになってしまうので、圧縮することになる。
非可逆圧縮を行えば画質は劣化する。これは、音声と同じ理屈である。可逆圧縮も存在するが、やはりサイズが大きく、現実的ではないとみなされている。

そもそもの話として、そんな巨大すぎるデータを扱うことは難しいため、動画素材が出力される時点でなんらかの圧縮がされているというのが普通だ。
それは、例えば録画ソフトだったり、ビデオカメラだったりだ。録画の場合、録画時に圧縮されるだけでなく、録画ソースがデジタル動画なら、その動画自体が既に圧縮されていて、2回目の圧縮をかけることになる。

いずれにせよ、非圧縮の映像ソースが手に入らないのであれば、映像ソースの状態が最良である。画質向上のための加工をすれば改善する可能性はあるが、それは普通ではない。

そこからさらにファイルサイズを小さくするために変換するか、あるいは取り扱いやすさのために変換するか、ということになる。
場合によっては、カメラから出力されるデータの圧縮形式を選べる、という場合もある。

つまりここで問題になるのは、ファイルサイズに対して画質の劣化がどれくらい抑えられるか、である。

速度

エンコード時に時間がかかるコーデックは、動画を変換してファイルとして出力する際に時間がかかる。

デコード時に時間がかかるコーデックは、再生が間に合わず飛んでしまうかもしれない。

ただ、実感としては、デコード時の所要時間の問題というよりは、ビットレートが高い動画は飛びやすい、という印象だ。
ただし、動画再生の重さには関係する。

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

デコードが重いコーデックであっても、ビデオカードがそのデコードを担うことができるのであれば、それは問題にならない。

これは、プロセッサ、ドライバ、そしてアクセラレーションの仕組みの全てがサポートしていなければ利用できない。

フォーマット

H.264

H.264(≈MPEG-4 AVC)は2003年に勧告された新しいフォーマットで、現在の主流といっていい。
MPEG-1から続く基本的な動画圧縮アルゴリズムを改良したもので、かなりの高圧縮でも目立った劣化が少ないことから主流となった。

高機能・高圧縮・高画質とメリットは大きいが、H.264を「使わない理由」といえば、エンコードに時間がかかりすぎるため、というのが一般的だ。

一般的なので、とりあえず迷ったらH.264で良いと思う。
LinuxではVDPAU/VA-APIにおいて、nVidiaグラフィックスにオープンソースまたはプロプライエタリのドライバ、さらにAMDグラフィックスにRadeonまたはCatalystドライバでH.264アクセラレーションがサポートされるというのは大きなメリットだろう。
どうもAMD APUでうまく動作してくれていないが。

nVidia Quadro 2000グラフィックスにLinux 4.3 + nvidia 1:352.53-1という構成のvdpauinfoはこのようになっている。

H264_BASELINE                  --- not supported ---
H264_MAIN                      41  8192  2048  2048
H264_HIGH                      41  8192  2048  2048
H264_CONSTRAINED_BASELINE      --- not supported ---
H264_EXTENDED                  --- not supported ---
H264_PROGRESSIVE_HIGH          --- not supported ---
H264_CONSTRAINED_HIGH          --- not supported ---
H264_HIGH_444_PREDICTIVE       --- not supported ---

Quadro 2000はFeature set Cなのでこうなっているのだろう。

非常に扱いやすい、お勧めできるフォーマットだ。
可搬性からいえば、MPEG-4のほうが上かもしれない。ちなみに、MPEG-4 Part2は、H.263がベースで、H.264と比べると劣っている。

H.265/HEVC

承認されたのが2013年という非常に新しいコーデックで、携帯向け映像配信から8kビデオまで幅広くターゲットにしている。
dアニメストアがH.265を採用していることで知られている。

同等の画質でH.264の半分の容量、という触れ込みだ。
非常に優れたフォーマットだが、新しすぎて結構厳しい。ハードウェア支援が追いついておらず、それでいて処理は非常に重い、というのが辛い部分でもある。
将来的には、H.265を置き換えていくのだろう。

H.265をサポートするFeature set FはGTX950/960のみで、TITANも含まない。QuadroシリーズはM6000まで含めて最大でもEまでだ。H.265が新しいフォーマットであることもあり、対応はまだまだ進んでいない、最新のカードでようやく対応がはじまったということなのだろう。

ちなみに、エンコード速度の差はあまりなかった。
というよりも、私の環境ではH.264の高品位エンコードが結構遅いので、H.265を若干軽い設定にしたこともあってか、2.1fpsでどちらも同じだった。

VP9 (WebM)

H.264はかなり複雑な特許関係になっているし、H.265はMPEG LAが特許を保有している。
こうしたことを嫌う人は、かなりいる。

Mozilla Firefoxは、以前mp4系ではなく、Ogg Theoraをサポートしていくことを表明したことがある。

Ogg Theoraについてはちょっと説明が必要だろう。Oggというのは、そもそもコンテナフォーマットで、任意の数の対応したコーデックを格納できる。一番有名なのは非可逆圧縮音声コーデックのVorbisで、OggコンテナフォーマットにVorbisを格納したものがOgg Vorbisだ。

そして、可逆圧縮音声コーデックのFLACを格納したものがOgg FLAC(FLACはOggに格納しないほうが普通)、動画コーデックのTheoraを格納したものがOgg Theoraだ(音声はSpeex, Vorbis, CELT, Opus, FLAC, OggPCMのどれか)。

このあたりは、Xiph.orgが開発したロイヤリティフリーコーデック/フォーマットで、OSSの一翼を担うと自負するMozillaなりのプライドだったのだろう。
しかし、そもそもOn2のVP3をベースにしたTheoraはあまり品質の良いものではなく、結局普及もしないままだ。オープンなのは良いことだが、Ogg Theoraをサポートしているプレイヤーも少なく、最初から影の薄い存在だ。

動機は似ているが、よりアグレッシヴに、技術的な主導権を握ろうとしたのがChromeの開発を行うGoogleだ。GoogleはChromeへの搭載とYouTubeでの採用の両面から働きかけている。

GoogleはコンテナフォーマットWebMを開発し、VPコーデックを開発してきたOn2を買収してその最新コーデックであるVP8を採用、音声フォーマットはVorbisをメインに採用してきた。
VP8に関しては特許問題があったが、最初から利用者に対する開放という方針は貫かれている。その後特許問題をライセンス契約締結によって解決し、自由に使えるようにした。

主導権を得るために、かなり献身的な振る舞いをしていると言ってもいい。品質面に問題があるTheoraに対して、VP8を採用するWebMは品質面でもH.264+AACのmp4に対抗できる存在だった。
現在においてもこの試み、つまりオープンソースによってデファクトスタンダードを塗替え、フォーマットを統一してリーダーボードを握るというのは依然として野心的だが、挑戦は続いているし、かつ悪くない話でもあり失敗もしていない。

そして、WebMの第二世代ともいうべきサポートが、VP9ビデオコーデックとOpusオーディオコーデックの採用だ。

VP9は、VP8に対して同一画質でビットレートを半分にする、ということなので、その目標はH.264に対するH.265と等しい。仕様がH.265と比べてもシンプルで、YUV444, 12bit色深度, アルファチャンネル, 深度チャンネル, 8kと機能はむしろ勝ってさえいる。
2011年にスタートしたプロジェクトで、後追いだったVP8とは違い、H.265に対して一歩前をいく状況で始まっている。

さらに、音声コーデックのOpusは、スピーチ向き音声フォーマットのSpeex、あるいは音楽向けコーデックのVorbisを越える存在として登場している。
IETFによって開発され、RFCで標準化され、リファレンス実装がBSDライセンスでリリースされている。Xiph.orgが手動するVorbisやFLACよりも、さらに文句なしにフリーだ。
音質がいいだけでなく、低レイテンシも実現している。ビットレートによって(場合によってはシームレスに)モードが切り替わり複数の仕様が混在するのは美しいとは言えないように思うが、実際に品質は素晴らしいのだから文句のつけようがない。
政治的紛争と無縁というわけではないのだが、Vorbisの次を叶えるコーデックではあるだろう。

つまり、完全に特許と制約に基づいたH.265+AACに対して、課題はあれども利用者としては自由に使うことが約束されているVP9+Opusでは、まずそこで魅力がかなり異なる。
しかも品質面でも優れている。

だが、決定的なディスアドバンテージもある。LinuxのVDPAUにおいてどころか、WindowsのPureVideoでさえ、VP9はもちろん、VP8もハードウェアアクセラレーションがサポートされていない。
VP8がサポートされていないということは、将来的にも大きな状況の変化がない限りはVP9も含め、WebMでのハードウェアアクセラレーションはサポートされないのだろう。
H.265のサポートはもう見えている。これは決定的だ。

比較

実際に比較してみた。

エンコーディングはだいたい同じくらいの時間がかかった。VP9+OpusのWebMが3.0fps出ていて1.5倍ちかく速かったが、それでもとても遅いのであまり意味はない。

サイズを見てみよう。

-rw------- 1 aki users 194571866 12月 10 10:59 moto-mad-01.h264.mp4
-rw------- 1 aki users 153719824 12月 10 17:14 moto-mad-01.h265-crf20.mp4
-rw------- 1 aki users  96287262 12月 10 09:13 moto-mad-01.h265.mp4
-rw-r--r-- 1 aki users 492912031  4月 16  2015 moto-mad-01.mov
-rw------- 1 aki users 215367319 12月 10 11:50 moto-mad-01.webm

H.264はCRF18、h265-crf20とWebMはCRF20、h265はCRF24だ。
ちなみに、元のMOVファイルはH.264+AC3である。

CRFが同一基準にならないようにしか見えないので、それぞれのコーデックで画質と容量の関係を探らなければ意味がなさそうだ。
実際、FFmpeg公式で、x265については

default CRF of 28. The CRF of 28 should visually correspond to libx264 video at CRF 23, but result in about half the file size.

と言っていたりする。色々やってみなければ分からないのだが、実際H.265の「劣化が少ない」は納得できる。H.264と比べてもそこは結構違う。H.264でCRFを上げていくとかなり乱れるので、ケータイ向けに用意したりするとはっきりと違ってくるのだ。

ちなみに、この生成物の感覚的な画質の比較でいうと

  • H.264は若干粗い。滑らかさが足りない
  • H.265は綺麗。CRF20かCRF24かの違いはほとんど分からない
  • WebM(VP9)はなめらかに見えるが、動きが激しいところではざらついて見える

結論

  • 今のところはH.264を使うのが可搬性を考えてもまとも
  • どうしてもファイルサイズを落としたい場合、H.265は結構いい
  • とりあえずVP9を使うメリットは、OSS派以外にはなさそう。エンドユーザーから見るとこだわりがない限り動機としてはかなり弱い
  • 将来的にはH.265に移っていくと考えて良いと思う
  • WebMがもっと普及して、ハードウェアアクセラレーションも対応してくれると嬉しい
  • そもそも、現在大抵の動画はH.264になってるし、普通の人がコーデックを選ぶ機会があまりないと思う
  • 昔のWMVやRM抱えてる人はWebMにしちゃうのもいいかもよ

Linux Tips

YouTubeのプレイリストからタイトルを抽出する

結局使わなかったのだが、ワンライナーで書いた。 比較的素直なHTMLなので解析は簡単。行指向ではないので、PerlでなくRubyにした。

$ curl 'https://www.youtube.com/playlist?list=<playlistid>' | ruby -e "s = STDIN.read" -e 's.scan(/<a class="[^"]*pl-video-title-link[^"]*"[^>]*>(.*?)</m) {puts $1.strip }' | grep -v 動画は削除されました

ffmpegでh.264/aacな360pのmp4を

元動画は1080pのmovまたはmp4。 オーディオはいじらず、元々aac(ac3)。

$ ffmpeg -i <infile> -vcodec libx264 -s 640x360 -crf 34 -strict -2 <outfile>.mp4

ちなみに480p(16:9)は720×280。 -crfの値は18-28が推奨されている(小さいほど高ビットレート)が、今回はモバイル向けなので34を指定。

なお、6の増減でビットレートはおよそ1:2の変動となる。

ffmpegでCowon M2向けの動画を作る

COWON M2はXVidとmp3のAVI動画で、解像度は320×240またはWMVをサポートするとある。

WMVだと結構サイズが大きいので、AVIで作る。 ソースは前回と同じくh.264*ac3のMOVまたはh.264*m4aのmp4。

$ ffmpeg -i <infile> -vcodec libxvid -acodec libmp3lame -b:v 372k -b:a 128k -s 320x240 <outfile>.avi

随分としょぼい解像度の上にアスペクト比も壊れる(プレイヤー側で調整することは可能)が、案外見られる。 ただし、360pでも細部は潰れてしまっているのでよく分からない部分は出てしまう。

XineのUIの文字化けを直す

fontにHerveticaを要求しているので、フォントエイリアスを設定すれば良い。

VHS変換用スクリプト

結局Windowsで記録するようにしたため、MPEGファイルをH.265形式に変換するためのスクリプト。

INDIR/SUBDIR/FILE.mpgファイルをOUTDIR/SUBDIR/SUBDIDR-NN.mkvに変換する。

ちょっと工夫をいれることでだいぶ楽にした。

#!/usr/bin/zsh

# Put your videos on a subdirectory under $WORKER_DIR.
WORKER_DIR=$HOME/mov/usr/vhs_converted/worker
# Videos will be put on a subdirectory under $DEST_DIR.
DEST_DIR=$HOME/mov/usr/vhs_converted/recorded/${dir:t}
# if $1 given, use as bitrate value.
bitrate={$1:512k}

for dir in $WORKER_DIR/*
do

typeset -i index=1

if [[ ! -e $DEST_DIR/${dir:t} ]]
then
mkdir $DEST_DIR/${dir:t}
fi

for i in $dir/*
do
ffmpeg -i "$i" -vcodec hevc -b:v $bitrate -aspect 720:480 $DEST_DIR/${dir:t}/${dir:t}-$(printf "%02d" $index).mkv
(( index++ ))
done
done

EasyCap(USBコンポジットビデオキャプチャ)をLinuxで使いたい

安価なUSBキャプチャデバイス、EasyCapを購入した。コンポジットとSビデオを備える。目的はVHSのデジタル記録だ。だが、これが茨の道となった。

Linuxで動作するかは確認しなかった。最悪、Windowsでキャプチャすればいいという考え方からだ。動作自体は以外と簡単で、V4L2ドライバで動くらしい。

ffmpeg -f alsa -i pulse -f v4l2 -s 1280x640 -i /dev/video1 -f mpeg - | vlc -

これで一応は表示できる(USBカメラがあるため、video1となっている。音声はPulseAudioを使用。同様に例えば

ffmpeg -f v4l2 -framerate 25 -video_size 640x360 -i /dev/video1 out.mkv

のように録画することもできる。

H.265で高品質圧縮を狙ったが、

ffmpeg -f alsa -i pulse -f v4l2 -s 640x480 -i /dev/video1 -vcodec hevc -b:v 256k -aspect 640:480 ~/tmp/test.mkv

音は記録できるが、映像はコマ落ち、変色、コマが混ざるなど見られたものではない。

Linuxでのさらなる方法として、VLCを使うという方法がある。ビデオデバイスは「キャプチャーデバイスを開く」で簡単にできるものの、オーディオデバイスはどうすればいいのか悩んでしまった。PulseAudio経由で取得したい場合、pacmd list-sourcesにあるName項目を見て、pulse://Name とすれば取得できる。

これはレイテンシもわずかで非常に快適な視聴が可能。しかし、変換/保存から保存しようとすると、コマ落ちなどが激しい。

他に様々なアプリを試したが、満足な品質にはならなかった。

そこで、ラップトップのWindowsでトライ。純正ソフトであるHoneSteach TVRを使う。だが、まず録画設定に適切なものがない。MPEG-1、MPEG-2とも320×240しかないのだ。DVDを選択することで720×480が選択可能。これで正常に録画できるが、プレビューでは問題のないものの、録画するとかなりコマ落ちが発生する。これはVLCと同様と言ってもいいが、VLCの場合のほうが常にスムーズに録画できないため、こちらのほうがマシだとも言える。

恐らく本当に重要なビデオは2回録画したほうがいいだろう。結構な頻度で発生するため、編集前提にしたほうが良いと思う。

仕方がないのでデスクトップでトライしようとした。DTM用なので余計なソフトウェア(特にデバイスドライバ)は入れたくないのだが、仕方がない…と考えたのだが、Autorunからインストールしようとするとフリーズした挙句、Version mismatchと言われて終了してしまう。ディスクから直接にインストーラを起動すればインストールできるが、起動すると(こちらではMPEG-2で720×480が選べる)、録画を開始した途端に「ディスク容量不足です」と表示され録画が止まってしまう。他に適当な、動作するキャプチャソフトはみつけられなかった。

フラストレーションのたまる結果だ。Lowlatency Kernelならできるといったことがあるのだろうか。