bonus-edge-proxy/streamer_Server.txt

346 lines
12 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

感谢您提供 `Dockerfile` 和 `docker-compose.yml` 文件。这是极其宝贵的信息,它让我能将之前的 C++ 架构蓝图,完美适配到您**已经高度定制化**的 RK3588 开发环境中。
[cite\_start]您提供的 `Dockerfile` 非常出色。它已经正确处理了最复杂的部分:通过 `PPA` [cite: 1, 2] [cite\_start]安装了特定于 Rockchip 的 GStreamer 插件 (`gstreamer1.0-rockchip` [cite: 2][cite\_start]) 以及 MPP/RGA 的**C++ 开发库** (`librockchip-mpp-dev`, `librga-dev` [cite: 2])。
您的 `docker-compose.yml` 也配置正确,通过 `devices` 和 `group_add` 将 NPU/VPU/RGA 硬件能力 成功映射到了容器内。
我们的架构决策保持不变:**将流媒体服务作为独立的 C++ 进程**。这可以确保它在崩溃时(例如 C++ 的段错误)**绝对不会**影响您现有的 Modbus/MQTT 核心服务。
基于您的环境,我为您制定了以下**高度定制**的开发计划。
-----
### A. 核心架构规划 (基于您的 Docker 环境)
1. **独立进程:** 我们将开发一个全新的 C++ 可执行文件(例如 `edge-streamer-cpp`)。
2. [cite\_start]**共享容器:** 这个新进程将与您现有的Modbus/MQTTC++ 服务**运行在同一个 `edge-proxy-dev` 容器中**。这允许它们共享所有硬件资源 和已安装的库 [cite: 2],同时保持进程级的故障隔离。
3. **开发工作流:** 您将在主机上编写代码(位于 `docker-compose.yml` 同级的目录中),代码会通过 `volumes` 自动同步到容器的 `/app` 目录。您将在容器内执行所有编译和运行操作。
4. **服务间通信 (IPC) 优化:**
* **控制C++ -\> C++** 您现有的服务Modbus将通过 **HTTP**(例如 `http://localhost:8001/api/start`)来控制新的流媒体服务。
* [cite\_start]**AI 结果C++ -\> MQTT** 新的流媒体服务在获得 AI 结果后,将使用 `paho.mqtt.cpp` 库(您的 `Dockerfile` 已经编译了它 [cite: 8])将 JSON 结果直接发布到 `docker-compose.yml` 中定义的 `mqtt-broker` 服务。这是最高效、最解耦的方案。
-----
### B. 关键发现:环境依赖检查 (RKNN)
[cite\_start]我发现了一个关键点:您的 `Dockerfile` 安装了 GStreamer 和 VPU/MPP 的开发库 (`librockchip-mpp-dev` [cite: 2]),这对于**视频编解码**是完美的。
但是,它**缺失了 AI 检测所需的 NPU (RKNN) C-API 开发库**(即 `rknn_api.h` 和 `librknnrt.so`)。
我的计划将基于您需要 NPU 加速 AI 检测的前提。因此,**我们的第一步必须是**将这些缺失的库添加到您的 Docker 镜像中。
-----
### C. 阶段一:完善您的 Docker 环境 (添加 RKNN, HTTP, JSON)
**目标:** 将缺失的 NPU C-API、C++ HTTP 库和 C++ JSON 库添加到您的 `edge-proxy-dev` 镜像中。
**步骤:**
1. **准备 RKNN SDK (在主机上)**
* 在您的主机项目目录(`docker-compose.yml` 所在的目录)下,创建一个新目录,例如 `docker/rknn_sdk/`。
* 从您的 RK3588 SDK 中,复制 `include/rknn_api.h` 到 `docker/rknn_sdk/include/rknn_api.h`。
* 复制 `lib/librknnrt.so` 到 `docker/rknn_sdk/lib/librknnrt.so`。
2. **修改您的 `docker/Dockerfile`**
* [cite\_start]找到构建 `paho.mqtt.cpp` [cite: 8] 的 `RUN` 指令块。
* [cite\_start]在 `cmake --build build --target install && \` [cite: 9] [cite\_start]之后,`rm -rf /tmp/build-context` [cite: 9] 之前,插入以下代码:
<!-- end list -->
```dockerfile
# ... (paho.mqtt.cpp 的 cmake install)
cmake --build build --target install && \
# --- 规划师建议:添加 RKNN, HTTP, JSON 库 ---
# 1. 复制 RKNN C-API (NPU 库) (假设已按步骤1放置)
# 注意COPY 指令的源路径是相对于 docker-compose.yml 的 context
COPY docker/rknn_sdk/include/rknn_api.h /usr/local/include/
COPY docker/rknn_sdk/lib/librknnrt.so /usr/local/lib/
# 2. 安装 C++ HTTP 和 JSON 的 header-only 库
# (需要先安装 curl)
apt-get update && apt-get install -y --no-install-recommends curl && \
# C++ HTTP Lib
curl -L https://raw.githubusercontent.com/yhirose/cpp-httplib/master/httplib.h -o /usr/local/include/httplib.h && \
# C++ JSON Lib
curl -L https://github.com/nlohmann/json/releases/latest/download/json.hpp -o /usr/local/include/json.hpp && \
# 3. 更新动态链接库缓存 (使系统找到 librknnrt.so)
ldconfig && \
# 4. 清理 apt 缓存
apt-get remove -y curl && \
apt-get autoremove -y && \
# (Dockerfile 原有的清理命令)
rm -rf /tmp/build-context
# (Dockerfile 的剩余部分)
RUN rm -rf /var/lib/apt/lists/*
# ...
```
3. **重建 Docker 镜像 (关键步骤)**
* 在主机的终端中执行:
<!-- end list -->
```bash
docker-compose build edge-proxy-dev
```
-----
### D. 阶段二:开发工作流程与项目设置
1. **启动开发环境:**
```bash
docker-compose up -d
```
* 这将启动 `edge-proxy-dev` 和 `mqtt-broker` 两个服务。
2. **创建新服务目录 (在主机上)**
* 在您的项目根目录(`docker-compose.yml` 所在位置)创建一个新目录:
<!-- end list -->
```bash
mkdir edge-streamer-cpp
```
3. **进入容器的开发 Shell**
```bash
docker-compose exec edge-proxy-dev /bin/bash
```
4. **在容器内初始化项目骨架:**
* **注意:** 以下所有命令均在 **容器内的 shell** (`/app` 目录) 中执行。
<!-- end list -->
```bash
# (容器内)
# /app 目录是您主机项目的挂载点
cd /app/edge-streamer-cpp
# 创建源码和构建目录
mkdir src include build
# 创建初始文件 (您将在主机上编辑它们)
touch src/main.cpp
touch src/StreamManager.cpp
touch include/StreamManager.h
touch CMakeLists.txt
```
5. **开始编码:**
* 现在,在您的**主机**上,使用您喜欢的 IDE (如 VS Code) 打开 `edge-streamer-cpp` 目录,开始编辑 `CMakeLists.txt` 和 `.cpp` / `.h` 文件。
-----
### E. 阶段三:配置 CMakeLists.txt
[cite\_start]**目标:** 配置 CMake使其能正确链接 GStreamer [cite: 2][cite\_start]、RKNN (阶段 C 添加的)、Paho MQTT [cite: 7, 8] 和 HTTP/JSON 库。
* 将以下内容粘贴到您在**主机**上打开的 `edge-streamer-cpp/CMakeLists.txt` 文件中:
```cmake
cmake_minimum_required(VERSION 3.10)
project(EdgeStreamer CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# [cite_start]--- 1. 查找 GStreamer (来自 Dockerfile) [cite: 2] ---
find_package(PkgConfig REQUIRED)
pkg_check_modules(GST REQUIRED gstreamer-1.0 gstreamer-app-1.0)
# [cite_start]--- 2. 查找 Paho MQTT (来自 Dockerfile) [cite: 7, 8] ---
# 您的 Dockerfile 编译并安装了它,我们可以直接 find_package
find_package(paho-mqttpp3 REQUIRED) # C++ 库
find_package(paho-mqtt-c REQUIRED) # C 库 (依赖)
# --- 3. 包含 RKNN, HTTP, JSON (来自 阶段C) ---
# 这些头文件已在 /usr/local/include会自动被 C++ 编译器找到
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/include
${GST_INCLUDE_DIRS}
/usr/local/include
)
# --- 4. 定义可执行文件 ---
add_executable(edge-streamer
src/main.cpp
src/StreamManager.cpp
)
# --- 5. 链接所有库 ---
target_link_libraries(edge-streamer
PRIVATE
# GStreamer
${GST_LIBRARIES}
# Paho MQTT (C++ 和 C)
paho-mqttpp3
paho-mqtt-c
# RKNN (来自 librknnrt.so)
rknnrt
# 线程 (GStreamer, httplib, Paho 都需要)
pthread
# [cite_start]Paho-MQTT SSL 依赖 [cite: 9] [cite_start](Dockerfile 有 libssl-dev [cite: 2])
ssl
crypto
)
```
-----
### F. 阶段四C++ 核心代码实现 (IPC 调整)
您在 `src/` 和 `include/` 中的代码逻辑与我上一个计划C++ 核心版)非常相似,但**IPC 部分将进行关键优化**
* **`main.cpp`**
* 完全不变。使用 `httplib.h` 在 `8001` 端口(或您选择的端口)启动一个 HTTP 服务,用于接收您现有 Modbus 服务的 "Start/Stop Stream" 命令。
* **`include/StreamManager.h`**
* 需要添加 `paho.mqtt.cpp` 的头文件和成员变量:
<!-- end list -->
```cpp
#include <mqtt/async_client.h> // Paho MQTT C++
// ...
class StreamManager {
// ...
private:
// ... (GstElement* 等)
// --- 新增 MQTT 客户端 ---
const std::string m_mqtt_server_address = "tcp://mqtt-broker:1883"; //
const std::string m_mqtt_client_id = "edge-streamer-ai";
mqtt::async_client m_mqtt_client;
};
```
* **`src/StreamManager.cpp` (关键的 AI 回调调整)**
* 在 `StreamManager` 的构造函数或初始化方法中,连接到 MQTT Broker。
* 在 GStreamer 的 `on_new_sample_from_sink` 回调函数中,当 RKNN 推理完成后:
<!-- end list -->
```cpp
// (伪代码)
// 静态 GStreamer 回调函数
static GstFlowReturn on_new_sample_from_sink(GstAppSink *sink, gpointer user_data) {
StreamManager *manager = static_cast<StreamManager*>(user_data);
// ... (1. 拉取 GstBuffer) ...
// ... (2. 调用 RKNN C-API 进行推理) ...
// rknn_outputs_get(ctx, 1, outputs, NULL);
// ... (3. (TODO) 将 'outputs' 格式化为 JSON 字符串) ...
// nlohmann::json ai_result;
// ai_result["stream_id"] = manager->get_stream_id();
// ai_result["object_count"] = ...;
// std::string payload = ai_result.dump();
// 4. (优化) 将 JSON 结果发布到内部 MQTT Broker
try {
std::string topic = "ai/results/" + manager->get_stream_id();
manager->get_mqtt_client().publish(topic, payload);
} catch (const mqtt::exception& exc) {
std::cerr << "Error publishing to MQTT: " << exc.what() << std::endl;
}
// ... (5. 释放 GstBuffer 和 RKNN outputs) ...
return GST_FLOW_OK;
}
```
-----
### G. 阶段五:编译与运行 (容器内)
在您**主机**上编写完代码后,回到您**容器内的 shell** (`docker-compose exec ...` 的那个)。
1. **编译项目 (在容器内)**
```bash
# (容器内)
cd /app/edge-streamer-cpp/build
# 运行 CMake (仅需一次)
cmake ..
# 编译 (每次代码变更后执行)
make -j$(nproc)
```
2. **运行新服务 (在容器内)**
```bash
# (容器内)
# 编译好的可执行文件位于 build/ 目录
./edge-streamer
# 您应该会看到 HTTP API 和 GStreamer 启动的日志
```
3. **测试 (在 *第二个* 容器 Shell 中)**
* 在**主机**上打开一个**新的**终端,再次 `exec` 进同一个容器:
<!-- end list -->
```bash
docker-compose exec edge-proxy-dev /bin/bash
```
* **A. 测试 API (控制)**
```bash
# (第二个容器内)
# (需要先 apt-get install curl
curl -X POST http://localhost:8001/api/v1/stream/start \
-d '{"stream_id":"cam1", "rtsp_url":"rtsp://..."}'
```
* **B. 监听 AI 结果 (MQTT)**
```bash
# (第二个容器内)
# (需要先 apt-get install mosquitto-clients)
mosquitto_sub -h mqtt-broker -t "ai/results/#" -v
```
* 您现在应该能在一个终端看到服务日志,在另一个终端看到 AI 推理结果。
-----
### H. 阶段六:生产部署 (可选)
您当前的 `docker-compose.yml` 使用 `command: sleep infinity`,这非常适合开发。
当您准备部署时,您需要一个进程管理器来同时启动和监控您的**两个 C++ 服务**Modbus服务 和 `edge-streamer`服务)。
**推荐方案:**
1. 修改 `Dockerfile` 以安装 `supervisor` (`apt-get install -y supervisor`)。
2. 创建一个 `supervisord.conf` 文件,配置 `[program:modbus_service]` 和 `[program:streamer_service]`。
3. 修改 `docker-compose.yml`,将 `command:` 更改为 `"/usr/bin/supervisord -c /etc/supervisor/supervisord.conf"`。
这将确保两个独立的服务都在容器启动时自动运行,并能在崩溃时自动重启。