ROCK 5BのHDMI Inを使って4Kキャプチャしよう

Rock 5BにはHDMI Inがついて来る。4K60 YUV420まではキャプチャできるようで、スペック上はなかなか優秀だ。

ということで、これを活用してみる。

いろいろ試行錯誤した結果、素のffmpegやobsではうまくキャプチャできなかったが、独自にv4l2のmulti planar APIに対応させたffmpeg改造版rkmppencを組み合わせることで、4K60 YUV420でキャプチャ & hwエンコードできるようになった。

rkmppenc_v4l2_hdmiin_rock5b_20230410_4k.jpg


まず、Radxa ROCK 5Bのキャプチャデバイスは、 /dev/video0 として認識される。


rigaya@rock-5b:~$ v4l2-ctl --device /dev/video0 --all
Driver Info:
Driver name : rk_hdmirx
Card type : rk_hdmirx
Bus info : fdee0000.hdmirx-controller
Driver version : 5.10.110
Capabilities : 0x84201000
Video Capture Multiplanar
Streaming
Extended Pix Format
Device Capabilities
Device Caps : 0x04201000
Video Capture Multiplanar
Streaming
Extended Pix Format
Priority: 2
DV timings:
Active width: 1920
Active height: 1080
Total width: 2200
Total height: 1125
Frame format: progressive
Polarities: -vsync -hsync
Pixelclock: 148348000 Hz (59.94 frames per second)
Horizontal frontporch: 84
Horizontal sync: 48
Horizontal backporch: 148
Vertical frontporch: 4
Vertical sync: 5
Vertical backporch: 36
Standards:
Flags:
DV timings capabilities:
Minimum Width: 640
Maximum Width: 4096
Minimum Height: 480
Maximum Height: 2160
Minimum PClock: 20000000
Maximum PClock: 600000000
Standards: CTA-861
Capabilities: Interlaced, Progressive
Format Video Capture Multiplanar:
Width/Height : 1920/1080
Pixel Format : 'NV24' (Y/CbCr 4:4:4)
Field : None
Number of planes : 1
Flags : premultiplied-alpha, 0x000000fe
Colorspace : Unknown (0x10098a48)
Transfer Function : Default
YCbCr/HSV Encoding: Unknown (0x000000ff)
Quantization : Default
Plane 0 :
Bytes per Line : 1920
Size Image : 6220800

Digital Video Controls

power_present 0x00a00964 (bitmask): max=0x00000001 default=0x00000000 value=0x00000001 flags=read-only


ここまではよさそうだが、いろいろな問題がある。まとめると、こんな感じ。

- Multiplanar formatを使っているが、ffmpegもOBSも対応していない
- ffmpegのv4l2読みがNV16/NV24に対応しない
- デバイスがffmpegの使用する一部の呼び出しに対応していない。
- VIDIOC_G_INPUT (読み込み状況の確認)
- VIDIOC_G_PARM (フレームレートの取得)



ffmpegとv4l2-ctlを使いながら、ひとつひとつ見てみよう。

まず、入力はRGB, YUV444(NV24), YUV422(NV16), YUV420(NV12)に対応するが、厄介なのは v4l2 multi-planar API を使用している点である。


rigaya@rock-5b:~$ v4l2-ctl --device /dev/video0 --list-formats
ioctl: VIDIOC_ENUM_FMT
Type: Video Capture Multiplanar

[0]: 'BGR3' (24-bit BGR 8-8-8)
[1]: 'NV24' (Y/CbCr 4:4:4)
[2]: 'NV16' (Y/CbCr 4:2:2)
[3]: 'NV12' (Y/CbCr 4:2:0)


OBSもffmpegもMultiplanar APIには非対応のようで、これが原因でエラーをはいてしまう。


ffmpeg -f v4l2 -i /dev/video0 -c:v libx264 ~/out.ts
[video4linux2,v4l2 @ 0x558b621f80] Not a video capture device.
/dev/video0: No such device


また、現行のffmpegのv4l2はNV16、NV24に対応していないので、ここもうまくいかない原因となってしまう。

さらに一部の呼び出しに対応していないようで、これはかなり困った点だ。

例えば、VIDIOC_G_INPUT 呼び出し(v4l2-ctl --get-input)にも応答しない。ffmpegは、VIDIOC_G_INPUT 呼び出しで入力があるかを判定しており、応答がないとエラー終了してし
しまう。ついでに、VIDIOC_S_INPUTにも反応しない。

rigaya@rock-5b:~$ v4l2-ctl --get-input
VIDIOC_G_INPUT: failed: Inappropriate ioctl for device


また、VIDIOC_G_PARM 呼び出し(v4l2-ctl --get-parm) にも応答しない。ffmpegは VIDIOC_G_PARM でフレームレートを取得しているが、これの応答がないため、フレームレートが取得されず、でたらめなフレームレートになってしまう。
また、下記のように --get-freq にも応答しない。


rigaya@rock-5b:~$ v4l2-ctl --get-parm
VIDIOC_G_PARM: failed: Inappropriate ioctl for device

rigaya@rock-5b:~$ v4l2-ctl --get-freq
VIDIOC_G_TUNER: failed: Inappropriate ioctl for device
VIDIOC_G_FREQUENCY: failed: Inappropriate ioctl for device


VIDIOC_G_DV_TIMINGS (v4l2-ctl --get-dv-timings) には対応しているため、これを使うと、フレームレートを取得できるようだ。

rigaya@rock-5b:~$ v4l2-ctl --get-dv-timings
DV timings:
Active width: 1920
Active height: 1080
Total width: 2200
Total height: 1125
Frame format: progressive
Polarities: -vsync -hsync
Pixelclock: 148348000 Hz (59.94 frames per second)
Horizontal frontporch: 84
Horizontal sync: 48
Horizontal backporch: 148
Vertical frontporch: 4
Vertical sync: 5
Vertical backporch: 36
Standards:
Flags:





このように、いろいろ問題があるので、とりあえずffmpegのv4l2読み部分を改造して、なんとか読み込めるようにしてみた。
https://github.com/rigaya/FFmpeg/tree/v4l2-multiplanar

1. v4l2 multi-planar APIへの対応
v4l2のドキュメントを参考に、multi-planar APIへの対応をざっと行った。それなりにコードの書き換えが必要だった。
https://github.com/rigaya/FFmpeg/commit/6ecd35e9d8e74da49a03e82b203c5fd6f1c084d8

2. NV16/NV24への対応
対応するといっても、これは単に定義を追加してあげるだけ。
https://github.com/rigaya/FFmpeg/commit/d7bf5fb1dcdd7ddbd173935ca026b17c219a2583

3. VIDIOC_G_INPUT/VIDIOC_S_INPUT に応答しない問題への対応
新たに ignore_input_error というオプションを追加する。 現状だと、VIDIOC_G_INPUT/VIDIOC_S_INPUTが常にエラーを返すので、ここで処理が止まってしまって先に進めない。そこで、"-ignore_input_error 1" とした場合には、ユーザーがchannelを指定した場合に限り、VIDIOC_S_INPUTがエラーを返してもエラー終了するのではなく、警告のみ表示して先に進むよう処理を変える。
https://github.com/rigaya/FFmpeg/commit/a91b4136cccf69954cef70e3f5fd3da3aabbc15a

4. VIDIOC_G_PARM がエラーを返し、フレームレートが設定されない問題への対応
VIDIOC_G_PARM がエラーを返した場合に、VIDIOC_G_DV_TIMINGS を使ってこちらからフレームレートを推定するようにする。

取得できるのは、毎秒のpixel数でフレームレートではないので、若干値がずれるが、多少であれば丸めてそれっぽいフレームレートにしてしまう。
https://github.com/rigaya/FFmpeg/commit/0d6e971afec7d5e997ef197a327e14d8b86443c2

ここまでやって、やっとffmpegでキャプチャできるようになる。



この改造版ffmpegを使って試しにキャプチャしてみる。

ffmpeg -f v4l2 -thread_queue_size 4096 -channel 0 -ignore_input_error 1 -i /dev/video0 -pix_fmt yuv420p -c:v libx264 -crf 20 -preset ultrafast ~/test.ts

1080p60なので、x264のultrafastを使ってもかなりCPU使用率は高め。それでも、現実的にエンコードできている。

ffmpeg_v4l2_hdmiin_rock5b_20230410.jpg



HDMI Inの音声



次に、音声も読み込んでみよう。音声の入力デバイスは "arecord -l" で確認可能。

ただ、最初は残念ながら音声がないと言われてしまった。

rigaya@rock-5b:~$ arecord -l
arecord: device_list:276: サウンドカードが見つかりません...


実際には、デバイスは見えていないだけで、存在はしている。

rigaya@rock-5b:~$ cat /proc/asound/cards
0 [rockchiphdmi0 ]: rockchip-hdmi0 - rockchip-hdmi0
rockchip-hdmi0
1 [rockchiphdmi1 ]: rockchip-hdmi1 - rockchip-hdmi1
rockchip-hdmi1
2 [rockchipdp0 ]: rockchip_dp0 - rockchip,dp0
rockchip,dp0
3 [rockchipes8316 ]: rockchip-es8316 - rockchip-es8316
rockchip-es8316
4 [rockchiphdmiin ]: rockchip_hdmiin - rockchip,hdmiin
rockchip,hdmiin


dmesgを見ても認識はされてそうだった。

dmesg | grep audio
[ 429.654609] rk_hdmirx fdee0000.hdmirx-controller: hdmirx_audio_interrupts_setup: 1
[ 429.817567] rk_hdmirx fdee0000.hdmirx-controller: hdmirx_delayed_work_audio: enable audio
[ 429.817577] rk_hdmirx fdee0000.hdmirx-controller: hdmirx_delayed_work_audio: restart audio fs(44100 -> 48000) ch(0 -> 2)
[ 429.817589] rk_hdmirx fdee0000.hdmirx-controller: hdmirx_audio_fifo_init
[ 478.615980] rk_hdmirx fdee0000.hdmirx-controller: hdmirx_audio_interrupts_setup: 1
[ 478.628920] rk_hdmirx fdee0000.hdmirx-controller: hdmirx_delayed_work_audio: enable audio
[ 478.628930] rk_hdmirx fdee0000.hdmirx-controller: hdmirx_delayed_work_audio: restart audio fs(44100 -> 48000) ch(0 -> 2)
[ 478.628941] rk_hdmirx fdee0000.hdmirx-controller: hdmirx_audio_fifo_init


原因は気づいてしまえば簡単で、権限の問題だった。ユーザーを "audio" groupに追加することで解決した。


sudo gpasswd -a ${USER} audio


これでshellを立ち上げなおすと、

rigaya@rock-5b:~$ arecord -l
**** ハードウェアデバイス CAPTURE のリスト ****
カード 3: rockchipes8316 [rockchip-es8316], デバイス 0: fe470000.i2s-ES8316 HiFi es8316.7-0011-0 [fe470000.i2s-ES8316 HiFi es8316.7-0011-0]
サブデバイス: 1/1
サブデバイス #0: subdevice #0
カード 4: rockchiphdmiin [rockchip,hdmiin], デバイス 0: fddf8000.i2s-dummy_codec hdmiin-dc-0 [fddf8000.i2s-dummy_codec hdmiin-dc-0]
サブデバイス: 1/1
サブデバイス #0: subdevice #0


hdmiinは "カード4" なので、これをffmpegで読み込むにはalsaを使って、

ffmpeg -f alsa -thread_queue_size 4096 -i hw:4 -f v4l2 -thread_queue_size 4096 -channel 0 -ignore_input_error 1 -i /dev/video0 -pix_fmt yuv420p -c:v libx264 -crf 20 -preset ultrafast ~/test.ts

とすればよかった。



キャプチャ映像をhwエンコード



先ほどはx264でswエンコードしていたので、CPU使用率が高かったが、hwエンコードすれば、CPU使用率を抑えられる。

前回作成したhwエンコーダのrkmppencを使ってみる。

まず、先ほど作成した改造版ffmpegのライブラリ(特にlibavdevice)をビルド・インストールして、さらにこれにリンクさせたrkmppencをビルドした。

リンク先がパッケージのlibavdeviceでなく、自分でビルドしたlibavdeviceであることを確認しよう。


rigaya@rock-5b:~/app/rkmppenc$ ldd rkmppenc | grep libavdevice
libavdevice.so.60 => /usr/local/lib/libavdevice.so.60 (0x0000007fb1f21000)


そのうえで、下記コマンドを実行。

rkmppenc --audio-source hw:4:format=alsa,codec=aac -i /dev/video0 --input-format v4l2 --input-option ignore_input_error:1 --input-option channel:0 --input-option ts:abs --cqp 20 --gop-len 120 -o ~/test.ts

無事hwエンコードでCPU使用率をかなり低く抑えながら、キャプチャできている。

下記はNintendo SwitchのHDMIをキャプチャしたとき。1080p RGBで問題なくキャプチャできている。

rkmppenc_v4l2_hdmiin_rock5b_20230410.jpg

今度はPC(RTX4080)の4K出力をキャプチャした場合。YUV420出力ではあるが、こちらも問題なくキャプチャできた。

rkmppenc_v4l2_hdmiin_rock5b_20230410_4k.jpg



いろいろと調整が必要だったものの、ROCK 5BのHDMI Inで4Kキャプチャができて、さらに強力なhwエンコーダのおかげで、これをリアルタイムエンコードできることも確認できた。

本当はキャプチャするならOBSでしたいところではあるけど、SBCでリアルタイムエンコードしながらHDMIの4Kキャプチャができるのはなかなか面白いと思う。
スポンサーサイト



コメントの投稿

非公開コメント

No title

このSBCの最初のほうでコメントした者ですがMultiplanarが解決できて素晴らしいですね。OBSが拾ってくれればなおよいのですが。4Kのキャプチャボードは高額なので単体でこの性能はすごいです。

No title

こちらの記事の内容でHDMI入力を試しているのですが、入力側のデバイスから音を出していない状態でキャプチャを行うと ALSA read error: Input/output error が発生し、正しく映像をキャプチャ出来ません。
音を出している状態だと正しくキャプチャされるのですが、音が止まると同じくエラーが出るようになります。
その後、再度音を出すとキャプチャが再開されるのですが、avout: Failed to get frame ID for pts ****, using ****. といった警告が出るようになります。
デバイスによっては無音状態でも音を出している状態になるようで、手持ちのデバイスだとiPad Airが該当しておりました。
音を出していない状態でもキャプチャすることはそもそも可能でしょうか。

Re: No title

私自身はSwitchとかPCの出力しかキャプチャしていないからなのか、すみません、「音を出していない状態」というのがちょっとよくわからないです。

いわゆる「無音」であっても、音声出力自体は生きているのではないかと思っていて、その場合、問題になることはないかと思います。

音声が本当に出力として入力されていないのなら、ALSA read errorになるのは、取得しようとする音声が来ないわけですから、それはごく自然な動作のように思います。音を扱わないのであれば、--audio-sourceオプションを削除していただくとよいと思います。

Re: Re: No title

ご回答ありがとうございます。

> 「音を出していない状態」というのがちょっとよくわからないです。

言葉足らずで申し訳ございません。スマホからHDMI出力を行って、それをキャプチャしておりました。その際に動画再生や音楽再生などで音を出していなかったことを示しておりました。

> いわゆる「無音」であっても、音声出力自体は生きているのではないかと思っていて、その場合、問題になることはないかと思います。
> 音声が本当に出力として入力されていないのなら、ALSA read errorになるのは、取得しようとする音声が来ないわけですから、それはごく自然な動作のように思います。

私も無音状態でも出力自体は生きていると考えており、そのためなぜエラーが出るのか分からない状況でした。ただ、無音状態でも音声出力自体を行っているかどうかはデバイスによって異なる気がするため、ROCK 5B側の問題では無い気がしました。
HDMI In機能メインで買ったわけではないので、こういうものなんだろうなぐらいで考えることにします。
プロフィール

rigaya

Author:rigaya
アニメとか見たり、エンコードしたり。
連絡先: rigaya34589@live.jp
github twitter

最新記事
最新コメント
カテゴリ
月別アーカイブ
カウンター
検索フォーム
いろいろ
公開中のAviutlプラグインとかのダウンロード

○Aviutl 出力プラグイン
x264guiEx 3.xx
- x264を使用したH264出力
- x264guiExの導入紹介動画>
- x264guiExの導入
- x264guiExのエラーと対処方法>
- x264.exeはこちら>

x265guiEx
- x265を使用したH.265/HEVC出力
- x265guiExの導入>
- x265.exeはこちら>

QSVEnc + QSVEncC
- QuickSyncVideoによるHWエンコード
- QSVEnc 導入/使用方法>
- QSVEncCオプション一覧>

NVEnc + NVEncC
- NVIDIAのNVEncによるHWエンコード
- NVEnc 導入/使用方法>
- NVEncCオプション一覧>

VCEEnc + VCEEncC
- AMDのVCE/VCNによるHWエンコード
- VCEEnc 導入/使用方法>
- VCEEncCオプション一覧>

svtAV1guiEx
- SVT-AV1によるAV1出力
- svtAV1guiExの導入>
- SVT-AV1単体はこちら>

VVenCguiEx
- VVenCによるVVC出力
- VVenCguiExの導入>

ffmpegOut
- ffmpegを使用した出力
- ffmpegOutの導入>


○Aviutl フィルタプラグイン
自動フィールドシフト (ミラー)
- SSE2~AVX512による高速化版
- オリジナル: aji様

clfilters 
- OpenCLベースの複数のGPUフィルタ集
- 対応フィルタの一覧等はこちら

エッジレベル調整MT (ミラー)
- エッジレベル調整の並列化/高速化
- SSE2~AVX512対応
- オリジナル: まじぽか太郎様

バンディング低減MT (ミラー)
- SSE2~AVX512による高速化版
- オリジナル: まじぽか太郎様

PMD_MT
- SSE2~AVX512による高速化版
- オリジナル: スレ48≫989氏

透過性ロゴ (ミラー)
- SSE2~FMA3によるSIMD版
- オリジナル: MakKi氏

AviutlColor (ミラー)
- BT.2020nc向け色変換プラグイン
- BT.709/BT.601向けも同梱

○その他
Amatsukaze改造版
- AmatsukazeのAV1対応版

rkmppenc
- Rockchip系SoCのhwエンコーダ

x264afs (ミラー)
- x264のafs対応版

aui_indexer (ミラー使い方>)
- lsmashinput.aui/m2v.auiの
 インデックス事前・一括生成

auc_export (ミラー使い方>)
- Aviutl Controlの
 エクスポートプラグイン版
 エクスポートをコマンドから

aup_reseter (ミラー)
- aupプロジェクトファイルの
 終了フラグを一括リセット

CheckBitrate (ミラー, 使い方, ソース)
- ビットレート分布の分析(HEVC対応)

チャプター変換 (使い方>)
- nero/appleチャプター形式変換

エッジレベル調整 (avisynth)
- Avisynth用エッジレベル調整

メモリ・キャッシュ速度測定
- スレッド数を変えて測定
- これまでの測定結果はこちら

○ビルドしたものとか
L-SMASH (ミラー)
x264 (ミラー)
x265 (ミラー)
SVT-AV1 (ミラー)

○その他
サンプル動画
その他

○読みもの (ミラー)
Aviutl/x264guiExの色変換
動画関連ダウンロードリンク集
簡易インストーラの概要

○更新停止・公開終了
改造版x264gui
x264guiEx 0.xx
RSSリンクの表示
リンク
QRコード
QR