优化日志输出
Some checks are pending
CI / host-build (push) Waiting to run
CI / rk3588-cross-build (push) Waiting to run

This commit is contained in:
sladro 2026-01-06 18:16:35 +08:00
parent 266fbb040e
commit 116950d2bd
6 changed files with 212 additions and 106 deletions

View File

@ -174,6 +174,12 @@ struct Frame {
"size": 128,
"policy": "drop_oldest" // drop_oldest / drop_newest / block
},
"debug": { // 可选:调试/日志开关(生产默认建议关闭)
"stats": false, // 各节点的周期性统计日志processed/queue/drops 等)
"stats_interval": 100, // 统计日志间隔(帧数)
"detections": false, // 部分 AI 节点的前几帧检测框调试输出
"ffmpeg_log_level": "error" // FFmpeg 日志级别(影响 HLS/RTSP mux 的内部日志;默认 error
},
"...特定节点参数..."
}
```
@ -181,6 +187,11 @@ struct Frame {
- `enable = false`GraphMgr 构建图时可直接忽略该节点及相关 edges。
- `role` 主要用于配置校验source 不应有上游sink 不应有下游等)。
**日志/性能建议:**
- 生产环境建议:`global.log_level=warn`,并保持各节点 `debug.stats=false`,避免高频 stdout/stderr 造成 CPU 抖动。
- 需要定位丢帧/队列积压时,再对目标节点打开 `debug.stats=true`(并把 `stats_interval` 调大,如 500/1000
### 4.2 INode 接口(含 Drain
```cpp
@ -287,6 +298,10 @@ GraphMgr 负责:
}
```
> 说明:`global.log_level` 只控制框架内部 Loggerdebug/info/warn/error
> 若启用了 FFmpeg例如 publish 的 HLS mux建议通过节点 `debug.ffmpeg_log_level` 将 FFmpeg 内部日志降到 `error`
> 避免出现大量类似 `hls ... Opening ...` 的 info 日志刷屏。
- **优先方式**:使用 `templates + instances` 快速生成多路通道。
- **高级用法**:直接使用 `graphs` 写复杂拓扑(例如:一条流拆成多个完全不同的分支)。

View File

@ -11,6 +11,7 @@
#include "ai_scheduler.h"
#include "node.h"
#include "utils/logger.h"
#if defined(RK3588_ENABLE_RKNN)
#include "rknn_api.h"
@ -273,6 +274,13 @@ public:
model_input_h_ = config.ValueOr<int>("model_h", 640);
num_classes_ = config.ValueOr<int>("num_classes", 80);
if (const SimpleJson* dbg = config.Find("debug"); dbg && dbg->IsObject()) {
stats_log_ = dbg->ValueOr<bool>("stats", stats_log_);
stats_interval_ = std::max<uint64_t>(
1, static_cast<uint64_t>(dbg->ValueOr<int>("stats_interval", static_cast<int>(stats_interval_))));
debug_det_ = dbg->ValueOr<bool>("detections", debug_det_);
}
// Optional inference throttle. 0 = run every frame.
infer_interval_ms_ = std::max<int64_t>(0, static_cast<int64_t>(config.ValueOr<int>("infer_interval_ms", 0)));
if (infer_interval_ms_ <= 0) {
@ -338,17 +346,18 @@ public:
}
}
std::cout << "[ai_yolo] model loaded via AiScheduler: " << model_path_
<< " (handle=" << model_handle_ << ", version="
<< (yolo_version_ == YoloVersion::V5 ? "v5" : "v8") << ")\n";
LogInfo("[ai_yolo] model loaded via AiScheduler: " + model_path_ +
" (handle=" + std::to_string(model_handle_) + ", version=" +
(yolo_version_ == YoloVersion::V5 ? "v5" : "v8") + ")");
#else
std::cout << "[ai_yolo] RKNN disabled, will passthrough frames\n";
LogWarn("[ai_yolo] RKNN disabled, will passthrough frames");
#endif
return true;
}
bool Start() override {
std::cout << "[ai_yolo] started, conf=" << conf_thresh_ << " nms=" << nms_thresh_ << "\n";
LogInfo("[ai_yolo] start id=" + id_ + " conf=" + std::to_string(conf_thresh_) +
" nms=" + std::to_string(nms_thresh_));
return true;
}
@ -359,7 +368,7 @@ public:
model_handle_ = kInvalidModelHandle;
}
#endif
std::cout << "[ai_yolo] stopped\n";
LogInfo("[ai_yolo] stop id=" + id_);
}
NodeStatus Process(FramePtr frame) override {
@ -381,8 +390,8 @@ public:
PushToDownstream(frame);
++processed_;
if (processed_ % 100 == 0) {
std::cout << "[ai_yolo] processed " << processed_ << " frames\n";
if (stats_log_ && stats_interval_ > 0 && (processed_ % stats_interval_) == 0) {
LogInfo("[ai_yolo] processed=" + std::to_string(processed_) + " id=" + id_);
}
return NodeStatus::OK;
}
@ -551,11 +560,12 @@ private:
det.bbox.h = static_cast<float>(Clamp(static_cast<int>(h / scale_h), 0, frame->height - static_cast<int>(det.bbox.y)));
det.track_id = -1;
if (det_result->items.size() < 3 && processed_ < 10) {
std::cout << "[ai_yolo] det: raw(" << x1 << "," << y1 << "," << w << "," << h
<< ") -> bbox(" << det.bbox.x << "," << det.bbox.y << ","
<< det.bbox.w << "," << det.bbox.h << ") cls=" << cls_id
<< " score=" << det.score << "\n";
if (debug_det_ && det_result->items.size() < 3 && processed_ < 10) {
LogDebug("[ai_yolo] det: raw(" + std::to_string(x1) + "," + std::to_string(y1) + "," +
std::to_string(w) + "," + std::to_string(h) + ") -> bbox(" +
std::to_string(det.bbox.x) + "," + std::to_string(det.bbox.y) + "," +
std::to_string(det.bbox.w) + "," + std::to_string(det.bbox.h) + ") cls=" +
std::to_string(cls_id) + " score=" + std::to_string(det.score));
}
det_result->items.push_back(det);
@ -668,11 +678,12 @@ private:
det.track_id = -1;
// Debug output for first few detections
if (det_result->items.size() < 3 && processed_ < 10) {
std::cout << "[ai_yolo] det: raw(" << x1 << "," << y1 << "," << w << "," << h
<< ") -> bbox(" << det.bbox.x << "," << det.bbox.y << ","
<< det.bbox.w << "," << det.bbox.h << ") cls=" << cls_id
<< " score=" << det.score << "\n";
if (debug_det_ && det_result->items.size() < 3 && processed_ < 10) {
LogDebug("[ai_yolo] det: raw(" + std::to_string(x1) + "," + std::to_string(y1) + "," +
std::to_string(w) + "," + std::to_string(h) + ") -> bbox(" +
std::to_string(det.bbox.x) + "," + std::to_string(det.bbox.y) + "," +
std::to_string(det.bbox.w) + "," + std::to_string(det.bbox.h) + ") cls=" +
std::to_string(cls_id) + " score=" + std::to_string(det.score));
}
det_result->items.push_back(det);
@ -697,6 +708,10 @@ private:
std::vector<std::shared_ptr<SpscQueue<FramePtr>>> output_queues_;
uint64_t processed_ = 0;
bool stats_log_ = false;
uint64_t stats_interval_ = 100;
bool debug_det_ = false;
int64_t infer_interval_ms_ = 0;
int64_t last_infer_pts_ms_ = 0;

View File

@ -1,4 +1,5 @@
#include <atomic>
#include <algorithm>
#include <chrono>
#include <functional>
#include <iostream>
@ -12,6 +13,7 @@
#include "node.h"
#include "utils/thread_affinity.h"
#include "utils/logger.h"
#if defined(RK3588_ENABLE_MPP)
extern "C" {
@ -53,6 +55,12 @@ public:
reconnect_sec_ = config.ValueOr<int>("reconnect_sec", 5);
reconnect_backoff_max_sec_ = config.ValueOr<int>("reconnect_backoff_max_sec", 30);
fallback_to_stub_on_fail_ = config.ValueOr<bool>("fallback_to_stub_on_fail", false);
if (const SimpleJson* dbg = config.Find("debug"); dbg && dbg->IsObject()) {
stats_log_ = dbg->ValueOr<bool>("stats", stats_log_);
stats_interval_ = std::max<uint64_t>(
1, static_cast<uint64_t>(dbg->ValueOr<int>("stats_interval", static_cast<int>(stats_interval_))));
}
cpu_affinity_ = ParseCpuAffinity(config);
if (ctx.output_queues.empty()) {
std::cerr << "[input_rtsp] no downstream queue configured for node " << id_ << "\n";
@ -86,16 +94,16 @@ public:
worker_ = std::thread(&InputRtspNode::LoopStub, this);
#endif
std::cout << "[input_rtsp] start url=" << url_ << " fps=" << fps_;
std::string mode;
#if defined(RK3588_ENABLE_MPP)
if (use_mpp_) std::cout << " (ffmpeg demux + mpp decode)";
else if (use_ffmpeg_) std::cout << " (ffmpeg cpu decode" << (ffmpeg_force_tcp_ ? ", tcp" : ", udp") << ")";
else std::cout << " (stub)";
if (use_mpp_) mode = " (ffmpeg demux + mpp decode)";
else if (use_ffmpeg_) mode = std::string(" (ffmpeg cpu decode") + (ffmpeg_force_tcp_ ? ", tcp)" : ", udp)");
else mode = " (stub)";
#else
if (use_ffmpeg_) std::cout << " (ffmpeg cpu decode" << (ffmpeg_force_tcp_ ? ", tcp" : ", udp") << ")";
else std::cout << " (stub)";
if (use_ffmpeg_) mode = std::string(" (ffmpeg cpu decode") + (ffmpeg_force_tcp_ ? ", tcp)" : ", udp)");
else mode = " (stub)";
#endif
std::cout << "\n";
LogInfo("[input_rtsp] start id=" + id_ + " url=" + url_ + " fps=" + std::to_string(fps_) + mode);
return true;
}
@ -190,11 +198,10 @@ private:
frame->pts = duration_cast<microseconds>(steady_clock::now().time_since_epoch()).count();
PushToDownstream(frame);
if (frame_id_ % 100 == 0) {
std::cout << "[input_rtsp] generated frame " << frame_id_ << " queue="
<< (out_queues_.empty() ? 0 : out_queues_[0]->Size())
<< " drops=" << (out_queues_.empty() ? 0 : out_queues_[0]->DroppedCount())
<< "\n";
if (stats_log_ && stats_interval_ > 0 && (frame_id_ % stats_interval_) == 0) {
LogInfo("[input_rtsp] generated frame=" + std::to_string(frame_id_) +
" queue=" + std::to_string(out_queues_.empty() ? 0 : out_queues_[0]->Size()) +
" drops=" + std::to_string(out_queues_.empty() ? 0 : out_queues_[0]->DroppedCount()));
}
std::this_thread::sleep_for(frame_interval);
}
@ -354,11 +361,10 @@ private:
}
PushToDownstream(frame);
if (frame_id_ % 100 == 0) {
std::cout << "[input_rtsp] recv frame " << frame->frame_id
<< " queue=" << (out_queues_.empty() ? 0 : out_queues_[0]->Size())
<< " drops=" << (out_queues_.empty() ? 0 : out_queues_[0]->DroppedCount())
<< "\n";
if (stats_log_ && stats_interval_ > 0 && (frame_id_ % stats_interval_) == 0) {
LogInfo("[input_rtsp] recv frame=" + std::to_string(frame->frame_id) +
" queue=" + std::to_string(out_queues_.empty() ? 0 : out_queues_[0]->Size()) +
" drops=" + std::to_string(out_queues_.empty() ? 0 : out_queues_[0]->DroppedCount()));
}
}
@ -750,9 +756,10 @@ private:
}
if (extra && extra_size > 0) {
std::cout << "[input_rtsp] send extra_data size=" << extra_size
<< " annexb=" << (IsAnnexB(extra, extra_size) ? 1 : 0)
<< "\n";
if (stats_log_) {
LogInfo("[input_rtsp] send extra_data size=" + std::to_string(extra_size) +
" annexb=" + std::to_string(IsAnnexB(extra, extra_size) ? 1 : 0));
}
if (!dec.SendExtraData(extra, extra_size)) {
std::cerr << "[input_rtsp] send extra_data failed\n";
}
@ -776,8 +783,8 @@ private:
const bool is_idr = key_flag || ns.has_idr;
if (need_idr && !is_idr) {
++dropped_until_idr;
if (!announced_wait_idr || dropped_until_idr % 300 == 0) {
std::cout << "[input_rtsp] waiting for IDR/keyframe; dropped=" << dropped_until_idr << "\n";
if (stats_log_ && (!announced_wait_idr || dropped_until_idr % 300 == 0)) {
LogInfo("[input_rtsp] waiting for IDR/keyframe; dropped=" + std::to_string(dropped_until_idr));
announced_wait_idr = true;
}
return;
@ -826,32 +833,26 @@ private:
last_pts_us = pts_us;
have_last_pts = true;
if (pkt_count <= 3 || pkt_count % 300 == 0) {
std::cout << "[input_rtsp] recv pkt#" << pkt_count
<< " size=" << pkt->size
<< " pts=";
if (raw_pts == AV_NOPTS_VALUE) std::cout << "NOPTS";
else std::cout << raw_pts;
std::cout << " dts=";
if (raw_dts == AV_NOPTS_VALUE) std::cout << "NOPTS";
else std::cout << raw_dts;
std::cout << " pts_us=" << pts_us
<< " key=" << ((pkt->flags & AV_PKT_FLAG_KEY) ? 1 : 0)
<< "\n";
if (stats_log_ && (pkt_count <= 3 || pkt_count % 300 == 0)) {
LogInfo("[input_rtsp] recv pkt#" + std::to_string(pkt_count) +
" size=" + std::to_string(pkt->size) +
" pts=" + (raw_pts == AV_NOPTS_VALUE ? std::string("NOPTS") : std::to_string(raw_pts)) +
" dts=" + (raw_dts == AV_NOPTS_VALUE ? std::string("NOPTS") : std::to_string(raw_dts)) +
" pts_us=" + std::to_string(pts_us) +
" key=" + std::to_string((pkt->flags & AV_PKT_FLAG_KEY) ? 1 : 0));
}
if (IsAnnexB(pkt->data, static_cast<size_t>(pkt->size))) {
if (pkt_count <= 10) {
if (stats_log_ && pkt_count <= 10) {
int sc = GetAnnexBStartCodeSize(pkt->data, static_cast<size_t>(pkt->size));
if (sc > 0 && static_cast<size_t>(sc) < static_cast<size_t>(pkt->size)) {
uint8_t b0 = pkt->data[sc];
int h264_type = b0 & 0x1F;
int h265_type = (b0 >> 1) & 0x3F;
std::cout << "[input_rtsp] pkt#" << pkt_count
<< " nal(h264)=" << h264_type
<< " nal(h265)=" << h265_type
<< " first_byte=0x" << std::hex << static_cast<int>(b0) << std::dec
<< "\n";
LogInfo("[input_rtsp] pkt#" + std::to_string(pkt_count) +
" nal(h264)=" + std::to_string(h264_type) +
" nal(h265)=" + std::to_string(h265_type) +
" first_byte=" + std::to_string(static_cast<int>(b0)));
}
}
handle_annexb(pkt->data, static_cast<size_t>(pkt->size),
@ -942,11 +943,10 @@ private:
PushToDownstream(frame);
if (frame_id_ <= 3 || frame_id_ % 100 == 0) {
std::cout << "[input_rtsp] mpp frame " << frame->frame_id
<< " queue=" << (out_queues_.empty() ? 0 : out_queues_[0]->Size())
<< " drops=" << (out_queues_.empty() ? 0 : out_queues_[0]->DroppedCount())
<< "\n";
if (stats_log_ && (frame_id_ <= 3 || (stats_interval_ > 0 && (frame_id_ % stats_interval_) == 0))) {
LogInfo("[input_rtsp] mpp frame=" + std::to_string(frame->frame_id) +
" queue=" + std::to_string(out_queues_.empty() ? 0 : out_queues_[0]->Size()) +
" drops=" + std::to_string(out_queues_.empty() ? 0 : out_queues_[0]->DroppedCount()));
}
}
#endif
@ -968,6 +968,9 @@ private:
int reconnect_backoff_max_sec_ = 30;
bool fallback_to_stub_on_fail_ = false;
std::vector<int> cpu_affinity_;
bool stats_log_ = false;
uint64_t stats_interval_ = 100;
};
REGISTER_NODE(InputRtspNode, "input_rtsp");

View File

@ -9,6 +9,7 @@
#include <vector>
#include "node.h"
#include "utils/logger.h"
namespace rk3588 {
@ -288,12 +289,18 @@ public:
line_width_ = config.ValueOr<int>("line_width", 2);
font_scale_ = config.ValueOr<int>("font_scale", 1);
if (const SimpleJson* dbg = config.Find("debug"); dbg && dbg->IsObject()) {
stats_log_ = dbg->ValueOr<bool>("stats", stats_log_);
stats_interval_ = std::max<uint64_t>(
1, static_cast<uint64_t>(dbg->ValueOr<int>("stats_interval", static_cast<int>(stats_interval_))));
}
// Load custom labels from config
if (const SimpleJson* labels = config.Find("labels")) {
for (const auto& item : labels->AsArray()) {
labels_.push_back(item.AsString(""));
}
std::cout << "[osd] loaded " << labels_.size() << " custom labels\n";
LogInfo("[osd] loaded " + std::to_string(labels_.size()) + " custom labels");
}
input_queue_ = ctx.input_queue;
@ -310,12 +317,13 @@ public:
}
bool Start() override {
std::cout << "[osd] started, draw_bbox=" << draw_bbox_ << " draw_text=" << draw_text_ << "\n";
LogInfo(std::string("[osd] start id=") + id_ + " draw_bbox=" + (draw_bbox_ ? "true" : "false") +
" draw_text=" + (draw_text_ ? "true" : "false"));
return true;
}
void Stop() override {
std::cout << "[osd] stopped\n";
LogInfo("[osd] stop id=" + id_);
}
NodeStatus Process(FramePtr frame) override {
@ -332,8 +340,8 @@ public:
PushToDownstream(out);
++processed_;
if (processed_ % 100 == 0) {
std::cout << "[osd] processed " << processed_ << " frames\n";
if (stats_log_ && stats_interval_ > 0 && (processed_ % stats_interval_) == 0) {
LogInfo("[osd] processed=" + std::to_string(processed_) + " id=" + id_);
}
return NodeStatus::OK;
}
@ -437,6 +445,9 @@ private:
std::shared_ptr<SpscQueue<FramePtr>> input_queue_;
std::vector<std::shared_ptr<SpscQueue<FramePtr>>> output_queues_;
uint64_t processed_ = 0;
bool stats_log_ = false;
uint64_t stats_interval_ = 100;
};
REGISTER_NODE(OsdNode, "osd");

View File

@ -11,6 +11,7 @@
#include "node.h"
#include "utils/dma_alloc.h"
#include "utils/logger.h"
#if defined(RK3588_ENABLE_RGA)
#include "im2d.hpp"
@ -260,6 +261,11 @@ public:
const bool requested_use_rga = config.ValueOr<bool>("use_rga", true);
use_rga_ = requested_use_rga;
if (const SimpleJson* dbg = config.Find("debug"); dbg && dbg->IsObject()) {
stats_log_ = dbg->ValueOr<bool>("stats", stats_log_);
stats_interval_ = std::max<uint64_t>(1, static_cast<uint64_t>(dbg->ValueOr<int>("stats_interval", static_cast<int>(stats_interval_))));
}
input_queue_ = ctx.input_queue;
if (!input_queue_) {
std::cerr << "[preprocess] no input queue for node " << id_ << "\n";
@ -288,8 +294,8 @@ public:
}
bool Start() override {
std::cout << "[preprocess] start dst=" << dst_w_ << "x" << dst_h_
<< (use_rga_ ? " (rga)" : " (swscale)") << "\n";
LogInfo("[preprocess] start id=" + id_ + " dst=" + std::to_string(dst_w_) + "x" + std::to_string(dst_h_) +
(use_rga_ ? " (rga)" : " (swscale)"));
return true;
}
@ -331,8 +337,8 @@ private:
void ProcessPassthrough(FramePtr frame) {
PushToDownstream(frame);
++processed_;
if (processed_ % 100 == 0) {
std::cout << "[preprocess] passthrough frame " << frame->frame_id << "\n";
if (stats_log_ && stats_interval_ > 0 && (processed_ % stats_interval_) == 0) {
LogInfo("[preprocess] passthrough frame=" + std::to_string(frame->frame_id) + " id=" + id_);
}
}
@ -362,9 +368,10 @@ private:
if (!need_cvt && !need_resize) {
PushToDownstream(frame);
++processed_;
if (processed_ % 100 == 0) {
std::cout << "[preprocess] passthrough frame " << frame->frame_id
<< " " << frame->width << "x" << frame->height << " (no change)\n";
if (stats_log_ && stats_interval_ > 0 && (processed_ % stats_interval_) == 0) {
LogInfo("[preprocess] passthrough frame=" + std::to_string(frame->frame_id) +
" " + std::to_string(frame->width) + "x" + std::to_string(frame->height) + " (no change)" +
" id=" + id_);
}
return true;
}
@ -415,14 +422,19 @@ private:
return false;
}
if (processed_ < 3) {
std::cout << "[preprocess] src: " << frame->width << "x" << frame->height
<< " fmt=" << static_cast<int>(frame->format) << " rga_fmt=" << src_fmt_rga
<< " wstride=" << src_wstride << " hstride=" << src_hstride
<< " data_size=" << frame->data_size << "\n";
std::cout << "[preprocess] dst: " << out_w << "x" << out_h
<< " fmt=" << static_cast<int>(out_fmt) << " rga_fmt=" << dst_fmt_rga
<< " wstride=" << dst_wstride << " hstride=" << dst_hstride << "\n";
if (stats_log_ && processed_ < 3) {
LogInfo("[preprocess] src: " + std::to_string(frame->width) + "x" + std::to_string(frame->height) +
" fmt=" + std::to_string(static_cast<int>(frame->format)) +
" rga_fmt=" + std::to_string(src_fmt_rga) +
" wstride=" + std::to_string(src_wstride) +
" hstride=" + std::to_string(src_hstride) +
" data_size=" + std::to_string(frame->data_size));
LogInfo("[preprocess] dst: " + std::to_string(out_w) + "x" + std::to_string(out_h) +
" fmt=" + std::to_string(static_cast<int>(out_fmt)) +
" rga_fmt=" + std::to_string(dst_fmt_rga) +
" wstride=" + std::to_string(dst_wstride) +
" hstride=" + std::to_string(dst_hstride) +
" out_size=" + std::to_string(out_size));
}
rga_buffer_t src_buf{};
@ -568,10 +580,10 @@ private:
PushToDownstream(out_frame);
++processed_;
if (processed_ % 100 == 0) {
std::cout << "[preprocess] rga frame " << out_frame->frame_id
<< " " << frame->width << "x" << frame->height
<< " -> " << out_w << "x" << out_h << "\n";
if (stats_log_ && stats_interval_ > 0 && (processed_ % stats_interval_) == 0) {
LogInfo("[preprocess] rga frame=" + std::to_string(out_frame->frame_id) +
" " + std::to_string(frame->width) + "x" + std::to_string(frame->height) +
" -> " + std::to_string(out_w) + "x" + std::to_string(out_h));
}
return true;
@ -652,10 +664,11 @@ private:
PushToDownstream(out_frame);
++processed_;
if (processed_ % 100 == 0) {
std::cout << "[preprocess] swscale frame " << out_frame->frame_id
<< " " << frame->width << "x" << frame->height
<< " -> " << out_w << "x" << out_h << "\n";
if (stats_log_ && stats_interval_ > 0 && (processed_ % stats_interval_) == 0) {
LogInfo("[preprocess] swscale frame=" + std::to_string(out_frame->frame_id) +
" " + std::to_string(frame->width) + "x" + std::to_string(frame->height) +
" -> " + std::to_string(out_w) + "x" + std::to_string(out_h) +
" id=" + id_);
}
}
@ -770,6 +783,9 @@ private:
PixelFormat dst_fmt_ = PixelFormat::UNKNOWN;
bool use_rga_ = true;
bool stats_log_ = false;
uint64_t stats_interval_ = 100;
std::shared_ptr<SpscQueue<FramePtr>> input_queue_;
std::vector<std::shared_ptr<SpscQueue<FramePtr>>> output_queues_;
uint64_t processed_ = 0;

View File

@ -1,6 +1,8 @@
#include <algorithm>
#include <atomic>
#include <algorithm>
#include <chrono>
#include <cctype>
#include <cstring>
#include <filesystem>
#include <functional>
@ -16,6 +18,8 @@
#include <unordered_set>
#include "node.h"
#include "utils/logger.h"
#include "media/encoded_video_meta.h"
#if defined(RK3588_ENABLE_FFMPEG)
@ -43,6 +47,27 @@ namespace rk3588 {
namespace {
inline int Align16(int v) { return (v + 15) & ~15; }
#if defined(RK3588_ENABLE_FFMPEG)
static int FfmpegLogLevelFromString(std::string s) {
for (auto& c : s) c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
if (s == "quiet" || s == "0") return AV_LOG_QUIET;
if (s == "panic" || s == "1") return AV_LOG_PANIC;
if (s == "fatal" || s == "2") return AV_LOG_FATAL;
if (s == "error" || s == "3") return AV_LOG_ERROR;
if (s == "warning" || s == "warn" || s == "4") return AV_LOG_WARNING;
if (s == "info" || s == "5") return AV_LOG_INFO;
if (s == "verbose" || s == "6") return AV_LOG_VERBOSE;
if (s == "debug" || s == "7") return AV_LOG_DEBUG;
if (s == "trace" || s == "8") return AV_LOG_TRACE;
return AV_LOG_ERROR;
}
static void ApplyFfmpegLogLevel(const std::string& level) {
const int lv = FfmpegLogLevelFromString(level);
av_log_set_level(lv);
}
#endif
}
struct OutputConfig {
@ -87,7 +112,7 @@ public:
running_ = true;
monitor_thread_ = std::thread(&AvMuxer::MonitorLoop, this);
std::cout << "[publish] Muxer initialized async for " << url_ << "\n";
LogInfo("[publish] muxer init async for " + url_);
return true;
}
@ -148,7 +173,7 @@ private:
std::lock_guard<std::mutex> lock(mutex_);
ready_ = true;
warned_ = false;
std::cout << "[publish] Server ready: " << url_ << "\n";
LogInfo("[publish] muxer server ready: " + url_);
}
// Wait until error occurs or stop requested
@ -615,6 +640,20 @@ public:
use_ffmpeg_mux_ = config.ValueOr<bool>("use_ffmpeg_mux", true);
attach_encoded_meta_ = config.ValueOr<bool>("attach_encoded_meta", !output_queues_.empty());
if (const SimpleJson* dbg = config.Find("debug"); dbg && dbg->IsObject()) {
stats_log_ = dbg->ValueOr<bool>("stats", stats_log_);
stats_interval_ = std::max<uint64_t>(
1, static_cast<uint64_t>(dbg->ValueOr<int>("stats_interval", static_cast<int>(stats_interval_))));
#if defined(RK3588_ENABLE_FFMPEG)
ffmpeg_log_level_ = dbg->ValueOr<std::string>("ffmpeg_log_level", ffmpeg_log_level_);
#endif
}
#if defined(RK3588_ENABLE_FFMPEG)
// Reduce FFmpeg's internal info logs (e.g., HLS "Opening ...") unless explicitly enabled.
ApplyFfmpegLogLevel(ffmpeg_log_level_);
#endif
const SimpleJson* outputs = config.Find("outputs");
if (outputs && outputs->IsArray()) {
for (const auto& o : outputs->AsArray()) {
@ -656,9 +695,9 @@ public:
}
bool Start() override {
std::cout << "[publish] start codec=" << codec_ << " fps=" << fps_ << " gop=" << gop_
<< " bitrate=" << bitrate_kbps_ << "kbps"
<< (use_mpp_ ? " (mpp venc)" : " (stub)") << "\n";
LogInfo("[publish] start id=" + id_ + " codec=" + codec_ + " fps=" + std::to_string(fps_) +
" gop=" + std::to_string(gop_) + " bitrate=" + std::to_string(bitrate_kbps_) + "kbps" +
(use_mpp_ ? " (mpp venc)" : " (stub)"));
return true;
}
@ -864,7 +903,7 @@ private:
return false;
}
std::cout << "[publish] zlm rtsp server ready: rtsp://0.0.0.0:" << port_ << "/" << app_ << "/" << stream_ << "\n";
LogInfo("[publish] zlm rtsp server ready: rtsp://0.0.0.0:" + std::to_string(port_) + "/" + app_ + "/" + stream_);
return true;
}
@ -1106,7 +1145,7 @@ private:
}
if (is_cfg) {
self->seen_config_nal_ = true;
std::cout << "[publish] zlm saw config nal" << "\n";
LogDebug("[publish] zlm saw config nal");
}
}
}
@ -1172,10 +1211,10 @@ private:
void ProcessStub(FramePtr frame) {
++encoded_frames_;
if (encoded_frames_ % 100 == 0) {
std::cout << "[publish] stub frame " << frame->frame_id
<< " queue=" << input_queue_->Size()
<< " drops=" << input_queue_->DroppedCount() << "\n";
if (stats_log_ && stats_interval_ > 0 && (encoded_frames_ % stats_interval_) == 0) {
LogInfo("[publish] stub frame=" + std::to_string(frame->frame_id) +
" queue=" + std::to_string(input_queue_->Size()) +
" drops=" + std::to_string(input_queue_->DroppedCount()));
}
}
@ -1232,10 +1271,10 @@ private:
frame->user_meta = meta;
}
++encoded_frames_;
if (encoded_frames_ % 100 == 0) {
std::cout << "[publish] encoded frame " << encoded_frames_
<< " queue=" << input_queue_->Size()
<< " drops=" << input_queue_->DroppedCount() << "\n";
if (stats_log_ && stats_interval_ > 0 && (encoded_frames_ % stats_interval_) == 0) {
LogInfo("[publish] encoded frames=" + std::to_string(encoded_frames_) +
" queue=" + std::to_string(input_queue_->Size()) +
" drops=" + std::to_string(input_queue_->DroppedCount()));
}
#if defined(RK3588_ENABLE_FFMPEG)
if (use_ffmpeg_mux_ && mux_mgr_) mux_mgr_->Write(pkt);
@ -1267,6 +1306,13 @@ private:
std::vector<std::shared_ptr<SpscQueue<FramePtr>>> output_queues_;
uint64_t encoded_frames_ = 0;
bool stats_log_ = false;
uint64_t stats_interval_ = 100;
#if defined(RK3588_ENABLE_FFMPEG)
std::string ffmpeg_log_level_ = "error";
#endif
mutable std::mutex mu_;
bool attach_encoded_meta_ = false;