前幾天玩 panoramax 時不小心刪除了 Frigate NVR 的設定檔,實在是很難過,但想想或許正是時機改寫一下設定檔,畢竟從去年七月架設,frigate 經歷了多次更新,太多 breaking change 了。當時其中一個遺珠之憾就是不知道為什麼無法使用硬體加速解碼,就趁這次好好的研究了一下
目錄:
frigate 的設定怎麼了
深入研究
結論
Frigate 的設定怎麼了?
Frigate NVR 是一個開源的 NVR,他可以透過像是 Coral TPU 甚至是純 CPU 分析監視器影像的動作,並設定需要被注意的高風險事件,最重要的是,可以離線使用,資料不會通通丟到網路上。機器架在之前買的 Celeron J4105 準系統上。理論上來說作為一個 Gen 9 的 CPU,應該是支援硬體解碼 h264 的影像才對,但忘記什麼原因,當時 Driver 特別設定使用 i965 而不是 iHD。Intel 從第八代開始有 QSV 硬體解碼(Intel Quick Sync Video),需要使用 iHD 或是 Xe Driver 才可以使用,用了 i965 等於所有的影像解碼都會消耗比硬體解碼更高的 CPU。因此嘗試在設定檔中加入 hwaccel_args: preset-intel-qsv-h264
,果不其然,重新啟動後就炸掉了
[graph 0 input from stream 0:0 @ 0x7017e8001f80] Value 22.000000 for parameter 'colorspace' out of range [0 - 14]
[graph 0 input from stream 0:0 @ 0x7017e8001f80] Error setting option colorspace to value 22.
[graph 0 input from stream 0:0 @ 0x7017e8001f80] Error applying generic filter options.
[vf#0:0 @ 0x5e4a1a6be640] Error reinitializing filters!
[vf#0:0 @ 0x5e4a1a6be640] Task finished with error code: -34 (Numerical result out of range)
[vf#0:0 @ 0x5e4a1a6be640] Terminating thread with return code -34 (Numerical result out of range)
[vost#0:0/wrapped_avframe @ 0x5e4a1a68e480] Encoder thread received EOF
[vost#0:0/wrapped_avframe @ 0x5e4a1a68e480] Could not open encoder before EOF
[vost#0:0/wrapped_avframe @ 0x5e4a1a68e480] Task finished with error code: -22 (Invalid argument)
[vost#0:0/wrapped_avframe @ 0x5e4a1a68e480] Terminating thread with return code -22 (Invalid argument)
[vist#0:0/h264 @ 0x5e4a1aaa8780] [dec:h264_qsv @ 0x5e4a1a68be80] Decoder returned EOF, finishing
深入研究
首先我們要先確認 Frigate 在哪邊使用到 QSV 的技術,從原始碼可以看到 QSV 的技術主要是用在 ffmpeg 中加入 -hwaccel qsv
參數,第一個懷疑的是,會不會其實這顆 CPU 根本不支援
安裝 intel-gpu-tools 後輸入 intel_gpu_top
可以看到第一行就寫著Intel Geminilake (Gen9) @ /dev/dri/card0
可見 CPU 是有顯示晶片的
接著確認系統有沒有 QSV 硬體解碼的能力,可以透過 vainfo
確認 Driver 是否正確且支援 h264 硬體解碼
vainfo: Driver version: Intel iHD driver for Intel(R) Gen Graphics - 24.3.3 ()
vainfo: Supported profile and entrypoints
VAProfileNone : VAEntrypointVideoProc
VAProfileNone : VAEntrypointStats
VAProfileMPEG2Simple : VAEntrypointVLD
VAProfileMPEG2Main : VAEntrypointVLD
VAProfileH264Main : VAEntrypointVLD
VAProfileH264Main : VAEntrypointEncSlice
VAProfileH264Main : VAEntrypointFEI
VAProfileH264Main : VAEntrypointEncSliceLP
VAProfileH264High : VAEntrypointVLD
VAProfileH264High : VAEntrypointEncSlice
VAProfileH264High : VAEntrypointFEI
VAProfileH264High : VAEntrypointEncSliceLP
從輸出看到裡面有 VAProfileH264High
,所以至少 OS 的部分沒有問題。
那會不會是 FFmpeg 編譯時少了相關的支援呢?這時候就要查一下 FFmpeg 了,我使用的是 Frigate Docker,FFmpeg 放在 /usr/lib/ffmpeg/7.0/bin,輸入 ./ffmpeg -hide_banner -encoders|grep qsv
就可以確認
V..... av1_qsv AV1 (Intel Quick Sync Video acceleration) (codec av1)
V..... h264_qsv H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 (Intel Quick Sync Video acceleration) (codec h264)
V..... hevc_qsv HEVC (Intel Quick Sync Video acceleration) (codec hevc)
V..... mjpeg_qsv MJPEG (Intel Quick Sync Video acceleration) (codec mjpeg)
V..... mpeg2_qsv MPEG-2 video (Intel Quick Sync Video acceleration) (codec mpeg2video)
V..... vp9_qsv VP9 video (Intel Quick Sync Video acceleration) (codec vp9)
哇,支援好多種格式。可以看到 FFmpeg 的確支援 h264_qsv,那到底是什麼問題呢?想破頭實在沒有頭緒,問了一下 ChatGPT 後發現,有可能是影像本身的狀況!畢竟回到錯誤訊息本身, 「colorspace 超出範圍」怎麼聽都好像是跟來源影像有關,但這要怎麼確定呢?
首先先用 FFprobe 分析影像 metadata,輸入 ./ffprobe rtsp://admin:123456@10.13.0.11:554/mpeg4
,可以看到
Stream #0:0: Video: h264 (High), yuvj420p(pc, progressive), 3840x2160 [SAR 1:1 DAR 16:9], 20 fps, 20 tbr, 90k tbn
那個 yuvj420p 一臉可疑!研究下才這格式基本上與 yuv420p 相同,但是顏色空間表示方式不同,j 版本的顏色範圍更廣。顏色範圍… colorspace… 這兩個詞不能說是有點相似,只能說是一模一樣,我們似乎離真相越來越近了!
為了確認是不是這個原因,找了另一台監視器,輸出是 yuv420p,然後使用 FFmpeg 測試 ffmpeg -hide_banner -v verbose -hwaccel qsv -c:v h264_qsv -i rtsp://admin:XXX@10.13.0.12:554/mpeg4 -f null -
It works!
同樣的 FFmpeg 參數設定換成原本那台監視器就會出現一樣的錯誤了
太好了,是個無法解決的問題QQ
結論
雖然還是不能硬體解碼,但至少這次死得明明白白。而且我們發現 iHD Driver 在 CPU 的使用率似乎還是比 i965 好。能夠明白怎麼死的,也是很快樂,收工!