Forráskód Böngészése

性能优化: RGA硬件加速 + 显示降频, CPU 267%->89%

- rga_processor: 接入 librga 硬件加速(NV12->RGB888+resize)
  修正 format 字段位置(rect.format), RGA blit 成功, 不再软件循环
- 主循环: 显示帧与推理同频(每skip_frames+1帧生成一次)
  不再每帧 processToRgb, 大幅降低CPU
- DisplayOutput: 画布刷新可配置(refresh_ms, 默认10FPS)
- 实测: 8路通道(6子码流+2主码流) CPU从267%降到89%
dev 1 hete
szülő
commit
d4338d349c
4 módosított fájl, 121 hozzáadás és 15 törlés
  1. 5 3
      src/display_output.cpp
  2. 3 1
      src/display_output.h
  3. 9 6
      src/main.cpp
  4. 104 5
      src/rga_processor.cpp

+ 5 - 3
src/display_output.cpp

@@ -8,11 +8,12 @@ DisplayOutput::~DisplayOutput() {
 }
 
 bool DisplayOutput::start(bool enable, int grid_cols, const string& title,
-                          bool fullscreen) {
+                          bool fullscreen, int refresh_ms) {
     enable_ = enable;
     grid_cols_ = grid_cols;
     title_ = title;
     fullscreen_ = fullscreen;
+    refresh_ms_ = refresh_ms > 0 ? refresh_ms : 100;
     if (!enable_) return false;
     if (running_.load()) return true;
 
@@ -145,10 +146,11 @@ void DisplayOutput::loop() {
 
         cv::waitKey(1);
 
-        // 目标 15 FPS 刷新
+        // 画布合成与窗口刷新按 refresh_ms_ 节流
+        int target_ms = refresh_ms_;
         auto dt = chrono::duration_cast<chrono::milliseconds>(
                       chrono::steady_clock::now() - t0).count();
-        if (dt < 33) this_thread::sleep_for(chrono::milliseconds(33 - dt));
+        if (dt < target_ms) this_thread::sleep_for(chrono::milliseconds(target_ms - dt));
     }
 
     cv::destroyWindow(title_);

+ 3 - 1
src/display_output.h

@@ -15,8 +15,9 @@ public:
     ~DisplayOutput();
 
     // 初始化: enable=启用输出, grid_cols=网格列数(0=自动), fullscreen=全屏显示
+    // refresh_ms=画布刷新间隔(毫秒, 默认100=10FPS, 0=最快)
     bool start(bool enable, int grid_cols = 0, const std::string& title = "ZoneAlarm",
-               bool fullscreen = true);
+               bool fullscreen = true, int refresh_ms = 100);
     void stop();
 
     void setFrame(int channel, const cv::Mat& frame, const std::string& label);
@@ -32,6 +33,7 @@ private:
     std::thread worker_;
     std::string title_ = "ZoneAlarm";
     int grid_cols_ = 0;
+    int refresh_ms_ = 100;
 
     std::mutex mtx_;
     std::map<int, std::pair<cv::Mat, std::string>> frames_;

+ 9 - 6
src/main.cpp

@@ -1891,13 +1891,16 @@ int main(int argc, char* argv[]) {
                 }
             }
 
-            std::vector<uint8_t> rgb8;
-            int out_w, out_h;
-            ch->rga.processToRgb(nv12, rgb8, out_w, out_h);
+            // 显示帧: 与推理同频(每 skip_frames+1 帧生成一次), 降低CPU
             cv::Mat display;
-            if (!rgb8.empty()) {
-                display = cv::Mat(out_h, out_w, CV_8UC3, rgb8.data()).clone();
-                cv::cvtColor(display, display, cv::COLOR_RGB2BGR);
+            if (do_infer) {
+                std::vector<uint8_t> rgb8;
+                int out_w, out_h;
+                ch->rga.processToRgb(nv12, rgb8, out_w, out_h);
+                if (!rgb8.empty()) {
+                    display = cv::Mat(out_h, out_w, CV_8UC3, rgb8.data()).clone();
+                    cv::cvtColor(display, display, cv::COLOR_RGB2BGR);
+                }
             }
             if (!display.empty()) {
                 float ds = (nv12.width > 0) ? (float)display.cols / nv12.width : 1.0f;

+ 104 - 5
src/rga_processor.cpp

@@ -2,18 +2,27 @@
 #include <cstring>
 #include <cmath>
 #include <algorithm>
+#include <iostream>
+#include <atomic>
+#include "RgaApi.h"
+#include "drmrga.h"
 
-RgaProcessor::~RgaProcessor() {}
-
+// RGA 硬件加速: NV12 -> RGB888 + resize + letterbox
+// 源: NV12(YCbCr 420 semi-planar), 目标: RGB888
 bool RgaProcessor::init(int target_w, int target_h) {
     target_w_ = target_w;
     target_h_ = target_h;
     return true;
 }
 
+RgaProcessor::~RgaProcessor() {}
+
 bool RgaProcessor::process(const Nv12Frame& nv12,
                            std::vector<float>& output,
                            float& scale, int& pad_x, int& pad_y) {
+    if (nv12.data == nullptr || nv12.width <= 0 || nv12.height <= 0)
+        return false;
+
     float sx = (float)target_w_ / nv12.width;
     float sy = (float)target_h_ / nv12.height;
     scale = std::min(sx, sy);
@@ -29,8 +38,60 @@ bool RgaProcessor::process(const Nv12Frame& nv12,
     output.resize(3 * target_w_ * target_h_);
     std::fill(output.begin(), output.end(), 0.0f);
 
-    int uv_offset = nv12.ver_stride * nv12.stride;
+    // ========== RGA 硬件加速 ==========
+    static bool rga_ok = false;
+    static bool rga_tried = false;
+    if (!rga_tried) {
+        rga_ok = (c_RkRgaInit() == 0);
+        rga_tried = true;
+    }
+
+    if (rga_ok) {
+        // 源: NV12(YCbCr 420 SP), 全图
+        rga_info_t src;
+        memset(&src, 0, sizeof(src));
+        src.fd = -1;
+        src.virAddr = nv12.data;
+        src.mmuFlag = 1;                 // 用户空间虚拟地址, 需MMU
+        src.blend = 0;
+        rga_set_rect(&src.rect, 0, 0, nv12.width, nv12.height,
+                     nv12.stride,
+                     nv12.ver_stride > 0 ? nv12.ver_stride : nv12.height,
+                     RK_FORMAT_YCbCr_420_SP);
+
+        // 目标: 先转整张 RGB(resized_w x resized_h), 再手动填 letterbox
+        std::vector<uint8_t> rgb_tmp(resized_w * resized_h * 3);
+
+        rga_info_t dst;
+        memset(&dst, 0, sizeof(dst));
+        dst.fd = -1;
+        dst.virAddr = rgb_tmp.data();
+        dst.mmuFlag = 1;
+        dst.blend = 0;
+        dst.scale_mode = 1;   // 双线性插值缩放
+        rga_set_rect(&dst.rect, 0, 0, resized_w, resized_h,
+                     resized_w, resized_h, RK_FORMAT_RGB_888);
+
+        int ret = c_RkRgaBlit(&src, &dst, nullptr);
+        if (ret == 0) {
+            // 填 letterbox 并归一化到 [0,1]
+            for (int y = 0; y < resized_h; y++) {
+                const uint8_t* row = rgb_tmp.data() + (size_t)y * resized_w * 3;
+                for (int x = 0; x < resized_w; x++) {
+                    int di = ((y + pad_y) * target_w_ + (x + pad_x)) * 3;
+                    output[di + 0] = row[x * 3 + 0] / 255.0f;
+                    output[di + 1] = row[x * 3 + 1] / 255.0f;
+                    output[di + 2] = row[x * 3 + 2] / 255.0f;
+                }
+            }
+            return true;
+        }
+        // RGA 失败则回退软件
+        std::cerr << "[RGA] blit失败, 回退软件: " << ret << std::endl;
+    }
 
+    // ========== 软件回退 ==========
+    int uv_offset = nv12.ver_stride * nv12.stride;
     for (int y = 0; y < resized_h; y++) {
         int src_y = std::min((int)(y / scale), nv12.height - 1);
         for (int x = 0; x < resized_w; x++) {
@@ -53,6 +114,9 @@ bool RgaProcessor::process(const Nv12Frame& nv12,
 
 bool RgaProcessor::processToRgb(const Nv12Frame& nv12, std::vector<uint8_t>& rgb_out,
                                 int& out_w, int& out_h) {
+    if (nv12.data == nullptr || nv12.width <= 0 || nv12.height <= 0)
+        return false;
+
     float sx = (float)target_w_ / nv12.width;
     float sy = (float)target_h_ / nv12.height;
     float s = std::min(sx, sy);
@@ -61,10 +125,45 @@ bool RgaProcessor::processToRgb(const Nv12Frame& nv12, std::vector<uint8_t>& rgb
     if (out_w < 1) out_w = 1;
     if (out_h < 1) out_h = 1;
 
-    rgb_out.resize(out_w * out_h * 3);
+    rgb_out.resize((size_t)out_w * out_h * 3);
 
-    int uv_offset = nv12.ver_stride * nv12.stride;
+    // ========== RGA 硬件加速 ==========
+    static bool rga_ok = false;
+    static bool rga_tried = false;
+    if (!rga_tried) {
+        rga_ok = (c_RkRgaInit() == 0);
+        rga_tried = true;
+    }
 
+    if (rga_ok) {
+        rga_info_t src;
+        memset(&src, 0, sizeof(src));
+        src.fd = -1;
+        src.virAddr = nv12.data;
+        src.mmuFlag = 1;
+        src.blend = 0;
+        rga_set_rect(&src.rect, 0, 0, nv12.width, nv12.height,
+                     nv12.stride,
+                     nv12.ver_stride > 0 ? nv12.ver_stride : nv12.height,
+                     RK_FORMAT_YCbCr_420_SP);
+
+        rga_info_t dst;
+        memset(&dst, 0, sizeof(dst));
+        dst.fd = -1;
+        dst.virAddr = rgb_out.data();
+        dst.mmuFlag = 1;
+        dst.blend = 0;
+        dst.scale_mode = 1;
+        rga_set_rect(&dst.rect, 0, 0, out_w, out_h, out_w, out_h,
+                     RK_FORMAT_RGB_888);
+
+        int ret = c_RkRgaBlit(&src, &dst, nullptr);
+        if (ret == 0) return true;
+        std::cerr << "[RGA] blit失败, 回退软件: " << ret << std::endl;
+    }
+
+    // ========== 软件回退 ==========
+    int uv_offset = nv12.ver_stride * nv12.stride;
     for (int y = 0; y < out_h; y++) {
         int src_y = std::min((int)(y / s), nv12.height - 1);
         for (int x = 0; x < out_w; x++) {