前言

隨着邊緣計算的興起,瑞芯微(Rockchip)、NVIDIA Jetson、飛騰、鯤鵬等 ARM64 架構的嵌入式設備,已經廣泛出現在安防監控、工業自動化、無人機圖傳、機器人視覺等場景裏。

在這些場景中,有兩個指標幾乎是“生死線”級別的:

  • 低延遲:操控類業務必須做到 100–200ms 量級,否則雲台轉動、無人機飛行會出現明顯“拖影感”。
  • 穩定性:7×24 小時持續運行不能頻繁重啓,更不能內存泄漏、句柄泄露導致系統崩潰。

本文基於大牛直播 SDK(SmartPlayerSDK)在 Linux ARM64 平台的 Demo 源碼,結合實際的 C++ 封裝與 X11 窗口管理代碼,系統拆解如何在 Linux ARM64 環境下,實現一個支持多路並行、毫秒級延遲的 RTSP/RTMP 播放器

深度硬核:在 Linux ARM64 架構下打造極致低延遲 RTSP/RTMP 播放器_linux rtmp播放器


一、整體架構:從 C 風格 SDK 到工程化播放器

大牛直播 SDK 在 Linux 下的核心入口是一個純 C 風格的結構體 SmartPlayerSDKAPI,裏面是一組函數指針:Init/UnInit/Open/Close/SetURL/StartPlay/...

在此之上,這套 Demo 做了三層清晰的分層:

  1. SDK API 層(C 接口)
  • 負責 RTSP/RTMP 拉流、解碼、渲染、事件回調等。
  1. 句柄封裝層:NT_SDK_HandleWrapper
  • 負責 NT_HANDLE 的創建、關閉、參數配置,以及 SDK 事件分發。
  1. 播放器封裝層:NT_PlayerSDKWrapper
  • 負責與 X11 窗口綁定、播放控制、截圖、窗口 resize、靜音等業務邏輯。
  1. 應用層:multi_player_demo.cpp
  • 初始化 SDK & X11,創建主窗口 + 子窗口,實現多畫面佈局與事件循環。

這套架構的核心思路是:把 C 風格的“裸 SDK”包成 C++ RAII 對象,讓它適合 7×24 小時運行的工程環境


二、句柄生命週期管理:NT_SDK_HandleWrapper 與 RAII

2.1 RAII 思路

SDK 底層通過 Open 返回一個 NT_HANDLE,用户需要顯式 Close。如果在複雜業務裏手動管理,很容易出現:

  • 異常路徑忘記 Close
  • 多線程場景重複 Close
  • 資源在對象析構時仍被佔用

於是 C++ 層引入 NT_SDK_HandleWrapper,採用 RAII:

NT_SDK_HandleWrapper::~NT_SDK_HandleWrapper() {
    Close();    // 析構自動釋放 SDK 句柄
}

生命週期與 C++ 對象深度綁定,徹底避免了資源泄漏。


2.2 Open:統一配置播放參數

Open 方法除了創建句柄,還會順便把一系列“低延遲 + 穩定性”相關參數一次性配置好:

sdk_api_->SetBuffer(handle, buffer);
sdk_api_->SetRtspAutoSwitchTcpUdp(handle, 1);
sdk_api_->SetRtspTimeout(handle, 15);
sdk_api_->SetReportDownloadSpeed(handle, 1, 5);
sdk_api_->SetURL(handle, url.c_str());

其中:

  • SetBuffer(0) → 極小緩存,降低延遲
  • TCP/UDP 自動切換 → 弱網情況下提升成功率
  • 超時 15s → 避免卡死
  • 下載速度上報 → 幫助上層動態監控鏈路狀態

這是典型的“工程化初始化”,讓上層應用不必關心這些參數。


2.3 事件分發機制

SDK 原生的事件回調是 C 風格的函數,你通過 NT_SDK_HandleWrapper 將其轉換為 C++ 的多觀察者模式:

handler->OnEventHandler(handle, event_id, param1, ...);

這樣多個業務模塊(UI、日誌、統計、AI)可以同時接收:

  • 連接成功 / 失敗
  • 緩衝開始 / 停止
  • 下載速率
  • RTSP 401 鑑權錯誤

這為構建一個完整的監控客户端奠定基礎。


三、播放器封裝:NT_PlayerSDKWrapper 的職責邊界

NT_PlayerSDKWrapper 相當於真正“對業務友好”的那層,封裝了:

  • 窗口綁定
  • 參數設置
  • Start / Stop
  • 截圖
  • 縮放模式
  • 事件處理

3.1 與 X11 子窗口綁定

播放器被創建後,會被注入:

  • Display* display_
  • int screen_
  • Window window_

Start 時執行:

player_api_->SetRenderXWindow(handle_->Handle(), window_);
player_api_->SetRenderScaleMode(handle_->Handle(), render_scale_mode);
player_api_->SetRenderTextureScaleFilterMode(handle_->Handle(), 3);

SDK 內部使用 OpenGL 或 XVideo 完成渲染,你無需自己處理像素格式轉換。


3.2 音頻處理與靜音

player_api_->SetMute(handle_->Handle(), is_mute ? 1 : 0);
player_api_->SetIsOutputAudioDevice(handle_->Handle(), 1);
player_api_->SetAudioOutputLayer(handle_->Handle(), 0);

Demo 中做了一個非常實用的處理:

多路播放時,只有第一路開聲,其餘默認靜音。

避免了“所有窗口一起叫”的噪音問題。


3.3 解碼策略:只解碼關鍵幀模式

player_api_->SetOnlyDecodeVideoKeyFrame(handle, is_only_dec_key_frame ? 1 : 0);

它適合:

  • 極低性能的 ARM 開發板
  • 多畫面預覽(畫質要求不高)

如果要追求最低延遲 + 流暢度,不建議開啓。


四、如何做到“極致低延遲”:核心策略拆解

低延遲是一套系統工程,不是調一個參數那麼簡單。這裏總結實際有效的策略:


4.1 極小緩衝區:SetBuffer(0)

sdk_api->SetBuffer(handle, 0);

直接減少排隊時間,是降低延遲的第一步。

注意:弱網抖動時可能會更容易卡頓,需要配合其他策略。


4.2 RTSP 智能 TCP/UDP 自動切換

sdk_api->SetRtspAutoSwitchTcpUdp(handle, 1);

策略:

  • 先嚐試 UDP(低延遲)
  • 網絡不佳時自動切換 TCP(穩定)

這比固定 UDP 或固定 TCP 更適合工程落地。


4.3 快速首幀:Fast Startup

適合:

  • 監控輪巡
  • 頻繁切換通道
  • 預覽牆系統

讓畫面能“點開即看”,不需要等 I 幀阻塞。


4.4 低延遲播放模式:SetLowLatencyMode

開啓後會減少內部隊列長度,調整同步策略,使渲染儘可能貼近解碼結果。

常用於:

  • 雲台控制
  • 無人機圖傳
  • 遠程巡檢

五、X11 渲染與多窗口布局

multi_player_demo.cpp 展示瞭如何構建一個多路實時播放的界面。


5.1 主窗口 & 子窗口的創建綁定

主流程:

  1. 調用 XOpenDisplay 獲取 X server
  2. 創建主窗口 XCreateSimpleWindow
  3. 按播放路數動態計算子窗口布局
  4. 使用 XCreateWindow 創建子窗口
  5. 將子窗口的 Window ID bind 到播放器

這比 Qt/GTK 更輕量,更適合 ARM64 工控設備。


5.2 響應窗口大小改變(Resize)

收到 ConfigureNotify 事件後:

  1. 重新計算佈局
  2. 調 XMoveResizeWindow 調整子窗口
  3. 通知 SDK:
player_api->OnWindowSize(handle, width, height);

SDK 會自動重新計算顯示區域,你不需要自己做矩陣變換或視口調整。


六、高效事件循環:poll + X11 的組合模型

為了避免主循環一直佔滿 CPU,Demo 引入了:

poll(ConnectionNumber(display), ...)

流程:

  • 若 X11 有事件 → 立即處理
  • 若無事件 → 在 poll 的超時週期內休眠

優點:

  • 不阻塞 UI
  • 低 CPU 佔用
  • 延遲響應毫秒級

特別適合:

  • ARM64 工控板
  • 多路渲染
  • 資源緊張場景

七、ARM64 場景化調優建議

7.1 無人機 / 雲台

  • 建議使用 RTSP over UDP
  • 參數組合:
  • SetBuffer(0)
  • SetLowLatencyMode(1)
  • SetFastStartup(1)
  • 如需更高穩定性可 fallback 到 TCP

7.2 工控監控 / NVR 預覽牆

  • 多路佈局用 SubWindowsLayout
  • 每路可以設置 0–200ms buffer,提升穩定性
  • 開啓下載速率上報用於監控鏈路質量

7.3 AI 視覺前處理

  • SetVideoFrameCallBack 取 I420 幀餵給 AI 模型
  • 播放器仍然可以同步渲染,做到“可算可視”
  • 若模型要求統一分辨率,可用 V2 接口自動縮放

八、完整啓動流程(串起來)

簡化後的主流程:

// 1. SDK 初始化
player_api.Init();

// 2. X11 初始化
Display* display = XOpenDisplay(nullptr);

// 3. 創建 X11 子窗口
Window sub_win = XCreateWindow(...);

// 4. 播放器實例
auto player = std::make_shared<NT_PlayerSDKWrapper>(&player_api);
player->SetDisplay(display);
player->SetScreen(screen);
player->SetWindow(sub_win);
player->SetURL("rtsp://xxx");

// 5. 啓動播放(低延遲模式)
player->Start(0, false, 1, false);

// 6. Event Loop(poll + X11)
while (true) {
    if (pending_x_event()) {
        XNextEvent(...);
    }
}


九、總結:從 Demo 到工程落地

這套 Linux ARM64 多路播放器 Demo 展示了一條完整、可落地的行業級鏈路:

  • SDK 層:跨 RTSP/RTMP 協議、解碼、同步、OpenGL 渲染
  • 句柄管理層:RAII + 事件分發 + 低延遲參數注入
  • 播放器封裝層:播放控制、窗口綁定、截圖、Resize
  • X11 應用層:多路佈局、事件循環、資源管理

它不是一個“只為了展示功能”的 Demo,而是一套可以直接在實際項目中複用的框架。

如果你準備開發:

  • 工控機 / NVR
  • 機器人 AI 視頻節點
  • 無人機圖傳地面站
  • 多路實時監控客户端

這套架構可以直接作為項目骨架,稍加業務化即可生產可用版本。