2026年6月28日

IPCAMM NVR - 開發現況

前言:

上一篇提到在開發NVR,到今天2026-06-28,目前推測進度在85%~90%之間,這篇就把目前的開發進展貼出來展示。

近況:

Server端大致上都差不多了,但目前根據前端還會修改。
最近主要在處理Playback和Video Decoder/Rendering的部份,這兩塊比較難處理,Playback部份可能還會改到後端Recorder和Gateway的CMD模式。
目前前端特色是,我實際上實做了Linux/MacOS/Windows的硬體解碼器操作以及各平台的Rendering。
Linux硬體解碼器使用VA-API,Rendering實做3種:

  • vasurface: VA-API的Surface直出,從解碼器-螢幕成像直通,CPU和GPU使用率最低,但會有穩定性問題
  • glrender: 解碼器用VA-API解碼,顯示的部份使用UNO Platform的OpenGL元件,中間是切開的,會有CPU操作,但解碼和成像都是GPU。處理是直接YUV處理。
    skiarender: 解碼器用VA-API解碼,顯示的部份直接是UNO Platform的SkCanvas元件,解碼是GPU,其他都是CPU。處理是RGB(VA-API轉出RGB)。

MacOS硬體解碼器使用Video ToolBox,Rendering實做2種:

  • glrender: 解碼器用Video ToolBox,顯示的部份使用UNO Platform的OpenGL元件,同Linux的glrender,不同的是,MacOS的OpenGL使用OpenGL ES 3.0。處理是直接RGB處理。
  • nsviewrender: 解碼器用Video ToolBox,顯示的部份使用MacOS的原生NSView,NSView上面疊CGImage顯示。處理是直接RGB處理。
這裡可能疑惑,為何MacOS的Rendering都用RGB處理,因為MacOS的Video ToolBox解出後直接是RGB,特殊的是,它讓你指定RGB大小,所以實際上它幫你把YUV->RGB和Resize都處理了,nsviewrender有透過反射方式,直接把畫面大小指定給Decoder API,讓Video ToolBox直接根據視窗大小resize。glrender沒這問題,它本來就是GPU處理,所以原始尺寸給它自己resize。

Windows硬體解碼器使用DXVA2(D3D11),Rendering目前實做1種:

  • glrender: 解碼器用D3D11,顯示部份使用UNO Platform的OpenGL元件,同Linux的glrender。處理是直接YUV處理。

我手上這台Windows的電腦太舊了,Microsoft Media Foundation(後面簡稱MF)沒有硬體解碼器的驅動程式,只有DXVA2(D3D11)的硬體解碼器驅動程式。Windows的硬體解碼器最新的是MF,前一代是D3D11,D3D11前一代是DXVA2,DVXA2前一代是DXVA。目前DXVA已經廢棄,D3D11一般也會叫做DXVA2或DXVA。目前Windows實做有MF和D3D11版本,但MF無法測試,D3D11版本 + glrender正常顯示。至於像是vasurface或是nsviewrender這樣的直出,目前還沒時間處理。

Browser版本,目前有點難產,Browser的硬體解碼器挑硬體,不一定會有,我手邊的電腦Chrome都無法正常驅動WebCodecs的軟解和硬解。我目前找到H265的軟體解碼器可以解,但要Rendering是另一個麻煩點,因為UNO Platform是單一個WebGL Canvas整塊成像,它有自己實做MediaPlayerElement,但原理是專門針對MediaPlayerElement挖空讓<video>顯示,這部份還在嘗試突破。

AI功能,目前AI功能已經實做了,可以參考主要功能Demo影片,目前實做了一個AI對話框,能夠直接跟AI對話,架構設計上,AI串接在後端LLM Gateway Service,LLM Gateway裡面設定要使用的AI Model和OpenAI EndPoint以及API Key,API Key設定在後端,不用擔心前端偷走。
前端應用程式在程式中定義了能夠使用的function calling,包括2種,一種是把function calling當成system prompt,這種專門適用於Gemma Model,另一種是標準的function calling呼叫。
流程上,前端會發送API把具備的function calling註冊到LLM Gateway,之後在AI對話框對話時,AI就能知道有哪些function calling能夠使用,並能呼叫工具操作。
目前NvrApp(前端)包括Camera的列出、放置到LiveView、最大化、頁籤切換、目前有哪些Event,計畫中但還沒完成的,把Camera放置到Playback、跳到指定日期時間、播放。
其中Event(已經完成)比較特別,AI的Event function calling包括2種,一種是目前NvrApp收到的Event,另一種則是NvrApp透過後端API查詢資料庫中的歷史Event。
API Model主要用智譜的GLM-4.7測試,但它的API主要相容Claude的Anthropic API協定,包括有所謂的深度思考,目前實做和測試都OK。

License的設定頁面目前是假資料,其他都是真實能運作的。


Demo影片:

主要功能Demo(Linux平台應用程式):


Linux各Rendering效能比較:


Browser WASM現況:


MacOS Rendering Demo:

Windows Rendering Demo:


開發與測試環境:

開發電腦: 

CPU: AMD Ryzen 5 7530U
GPU: AMD Ryzen 5內顯,4GB VRAM,VA-API支援
GPU硬體編解碼器: MPEG2, VC1, H264, HEVC(H265), JPEG, VP9(不支援AV1)
Memory: DDR4 32GB
作業系統: Debian 13 + MATE Desktop + X-Window + .NET 10(目前到10.0.301)

Linux測試環境(NVR Server):

CPU: Intel Celeron J4105 CPU
GPU: Intel Celeron J4105內顯,VRAM未知
GPU硬體編解碼器: MPEG2, H264, HEVC(H265), JPEG, VP8, VP9(不支援AV1)
Memory: DDR4 4GB
Disk: NVMe 128GB (錄影儲存目前也在這裡面)
作業系統: Debian 13

MacOS測試和編譯環境:

硬體: Mac mini M1 8GB RAM
作業系統: macOS Sequoia 15.7.2

Windows測試和編譯環境:

CPU: Intel Core m7-6Y75 (第六代Intel Core m處理器)
GPU: 
Intel Core m7-6Y75內顯,Intel HD Graphics 515
GPU硬體編解碼器: H264, H265有硬體解碼器(D3D11)
Memory: DDR3 16GB
作業系統: Windows 10


2026年6月1日

IPCAMM NVR - 前導篇

前言:

前面在寫ONVIF Client Lab時提到,在開發ONVIF相關的Side Project,其實就是NVR。
我回看PRD日期,最早大概從2026-03-21開始,也就是3月底左右,到現在2026-06-01,約2個多月的時間,有空閒就開發它,目前推測進度大概70%左右。
因為好一段時間了,雖然還沒有成果,但我想可以先把目前的規劃、實做進行描述。
因為架構比預期大,之後打算用Gitlab Page或Wiki讓AI撰寫系統架構、設計、Models之類的。

發想:

首先,這個NVR預計會是雙授權型式,AGPL與Commercial。
對的,AGPL開源與商用雙授權。
AGPL允許在不改程式碼的情況下,或者開源的情況下可以修改與使用,甚至以安裝方式提供商用服務,唯一要求就是開源。
Commercial,提供商用,但我還沒想清楚到底怎麼商用法。
會特別提的原因是,程式碼是開源的,但上面包括License設計和實做,對的,你沒看錯,程式碼開源還包括License設計與實做在裡面 😆,這在看到時可能覺得疑惑,怎麼要註冊,但是又有程式碼,授權又是AGPL。

我第一份工作就是NVR,負責Linux平台和整合,對NVR有設計的遺憾。
我原本以為自從中國成為監控大國之後,監控產業大概都趴了,在上幾份工作時寫停車場系統才發現,NVR對於公司竟然還是香噴噴的,因此,AI開發計畫中,就有NVR在裡面。

NVR完成後不會是這個Side Project的結束,後面會延續進一步推進Analysis Service以及GIS Service,最終目標是做出Dashboard,能像之前美國國防部記者會時的操作界面,有個地圖(戰場/非戰場)會有圖釘標示哪裡有攻擊(事件),滑鼠移動過去後點擊,會出現當時的影片片段。

當然,無人機這麼熱,不湊熱度說不過去,對吧。

設計規劃:

這次實做花很多時間的原因是,設計的架構比預期大和複雜。

後端系統以微服務設計,分為4部份:

  • Streammer: 接Camera串流、分發串流
  • Recorder: 錄影寫檔案
  • Manager: CRUD服務,REST API和資料管理
  • Gateway: 前端應用程式的對接口,後端接Streammer、Recorder、Manager

微服務的底層設計邏輯是,各自處理各自的事務,所有事務獨立,體現在幾個點:
調Record、查Record Status、Disk Status,都由Recorder處理
Camera介接、串流,都由Streammer處理
DB設定更新、CRUD API,都由Manager處理
和Client對接,Client的Protocol轉換,StreamBus -> WebSocket、gRPC <-> WebSocket、Manager反向代理,都由Gateway處理

主要設計邏輯和核心協定:

微服務(Streammer、Recorder、Manager、Gateway)間透過3個主要協定通訊:

  • gRPC: REST API與WebSocket類的API,Playback的串流都透過gRPC傳輸
  • 自定義的StreamBus Protocol: RTSP串流的訂閱轉發通訊協定
  • MQTT Protocol (EventBus): Event的訂閱轉發協定使用MQTT為基底

各個微服務設計特點:

Streammer:

Streammer主要功能是轉發,包括串流和Event(事件),串流轉發使用StreamBus,Event轉發使用EventBus。
Streammer串流轉發的設計受到Publish/Subscribe設計和mediamtx影響,當然還有AI的建議,Streammer內部使用c#的Channels實做,但額外設計3種對外接口,分別是Named Pipeline、TCP、UDP,Streammer內的串流擴展可直接在內部透過StreamBus實做模塊擴展,Streammer外可以透過TCP、UDP、Named Pipeline串接,Gateway與Recorder就是用外部串接方式和Streammer對接。
Streammer Event轉發使用MQTT為基底,設計上,本身是MQTT Server,也可以用外部MQTT Server,Event則透過MQTT推送到MQTT Server上。
Streammer有gRPC Service服務,主要用於傳入CMD,例如:ReloadCamera,gRPC有Event Trigger API,但Event Trigger透過MQTT注入更方便,兩種都有設計,主要透過MQTT。

Recorder:

Recorder主要功能是錄影寫檔案。
但因為以前整合時吃了太多磁碟IO的虧,Recorder核心設計包括IndexCache、RecCache以及IOWorker。
Recorder包括3個Cache,Playback用的錄影檔案Cache,Index讀寫的LRU Cache,預錄影的RingBuffer Cache。
Recorder在Cache下層寫入磁碟時,會透過IOWorker Pool,IOWorker能在appsettings.json內設定同時的Read IOWorker數量、Write IOWorker數量,所有IO都透過IOWorker Pool動作。
Recorder設定時指定多個實體路徑寫入,透過Consistent Hashing(一致性哈希)平均分散資料到實體路徑內。
保留軟體RAID(Erasure Code)實做設計。

Manager:

Manager提供CRUD,Camera的增/刪/查/找,使用者登入認證都在這裡。前端應用程式的API,主要都是對Manager。有個比較特殊的,ONVIF Discovery是在Manager觸發和搜尋。
目前設定都透過DB儲存,原則上至少支援SQLite和PostgreSQL,Microsoft SQL Server有支援,但問題在於,c# SQL Server的SQLClient目前不完全支援AoT。

Gateway:

Gateway顧名思義,是入口。Client端連入會是透過Gateway,Web版的網站程式也會放在Gateway。
Gateway對Client就2個協定,WebSocket和REST API,REST API主要是反向代理到Manager,其他都透過WebSocket,像是Streammer的StreamBus,StreamBus -> WebSocket,Recorder的gRPC API,WebSocket <-> Recorder gRPC API。

認證有2組:

使用者的認證以及微服務間的認證。
使用者認證就是透過Manager的Auth API進行認證後拿到JWT,然後後續不論是WebSocket或是其他REST API都透過這組JWT。
微服務間的認證,在每個服務的appsettings.json內會有個Internal API Key,要填入相同的密碼,服務間的gRPC會用Internal API Key加密Timestamp後送出,另一端會用Internal API Key解密,並判斷Timestamp是否在一段時間內(是的,每個服務所在的電腦,要對時,我記得會查30秒內吧)。

License設計:

License會以線上登錄序號的方式,登錄註冊後提供license.lic檔案,放入系統中作用。
目前這段細節我還沒想清楚,目前考慮鎖在Streammer就好,但考慮到叢集多電腦微服務運作,我還沒完全想清楚授權怎麼處理。
License預設會有2種,一種是已經完成的license.lic,另一種是USB License Key的形式,不論哪種,核心加密都使用AES + ECDSA簽章。

使用者和群組設計:

DB中,包括幾個跟User有關的Table,包括users, groups, permissions這3個主要的Table以及用於Mapping group和permission的group_permissions Mapping Table。
權限可以概略分2類,1類是NVR操作的使用者權限,一類是MQTT的服務權限。
包括NVR類的:nvr_admin, nvr_power_user, nvr_user, nvr_viewer
以及MQTT類的:mqtt_admin, mqtt_rw, mqtt_ro

權限會對應到group,因此Group包括:
admins, power_users, users, operators, mqtt_services, mqtt_clients

每個使用者都屬於特定1個群組,但群組可以包括多種權限。
直接的體現是,admin這個使用者是admins群組,admins群組的帳號可以同時登入MQTT Server和NVR Client,同樣的道理,
mqtt_services群組的成員,只能登入MQTT Server,NVR Client是不能登入的。

Client設計:

Client應用程式預計為跨平台,會先提供Linux版和網頁版,使用UNO Platform開發。

AI規劃:

設計階段就在想,既然是全新開發NVR,那有沒有什麼新的想法能夠引入?
尤其是AI,既然AI這麼熱門,到底使用者對於AI的想像是什麼? 如何引入?
在和AI討論後,目前想定的設計分2塊,NVR階段的以及Dashboard(中控)階段的。
我對AI之於應用程式的想像是這樣,我要如何如何時,直接跟AI說或對話,AI直接幫我處理,以及AI能夠跟我說發生了什麼事情。
也就是說,延續監控產業的一脈路線,什麼是監控產業的一脈路線?
從最傳統的能錄影 -> 能根據時間調出錄像 -> 有Event -> 能智能的根據Event主動通知

那麼,當進入AI時代後,我對這一脈路線的想定是,Event的通知對象不再是人,而是AI,由AI主動分析Event,並提供給人狀況、建議行為。

因此,我把AI規劃分為低階跟高階,高階放在Dashboard(中控),低階下放在NVR內。
NVR內放的AI,能夠根據文字窗口給與指示,
例如:
給我看第三支Camera目前畫面。
播放第2支Camera昨天下午3:00的錄像。
幫我看看,這兩天有哪些Camera斷線過?

而高階的,則能夠根據Event進行細部推斷,
例如:
目前分析系統偵測到大廳有多人聚集,或者大廳人數眾多。

而兩者差異體現在2塊,1個是AI的智能程度,NVR原則上用的就指令遵循型,能夠提供Live、Playback的自動化操作,而Dashboard(中控)的,就可能需串接雲端,提供目前過往的Event資訊,或者觸發Event時打到雲端AI,讓雲端AI能有完整的Event進行判斷。

我們更白話的說,AI的判斷能力,取決於我們給哪些Event + AI的智能程度,低階的做單純的UI操作,不具備分析,高階的能獲得更多Event訊息,並能深入分析。

目前NVR階段,已能在UNO Platform上面透過按鈕觸發特定連續頁面操作。

Client實做進展:

目前已實做和串接部份,錄影進度條已經能正常顯示,Event能正常顯示,Device清單能正常顯示,錄影狀態串接中。
Device Search功能正常,但UI還需優化,Schedule UI和設定正常。
PTZ能夠功能正常,UI還需優化。
影像部份,Linux版本Live有畫面,但穩定性還有問題。

Client截圖: