diff --git a/Readme.md b/Readme.md index 16a9533..4250177 100644 --- a/Readme.md +++ b/Readme.md @@ -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` 只控制框架内部 Logger(debug/info/warn/error); +> 若启用了 FFmpeg(例如 publish 的 HLS mux),建议通过节点 `debug.ffmpeg_log_level` 将 FFmpeg 内部日志降到 `error`, +> 避免出现大量类似 `hls ... Opening ...` 的 info 日志刷屏。 + - **优先方式**:使用 `templates + instances` 快速生成多路通道。 - **高级用法**:直接使用 `graphs` 写复杂拓扑(例如:一条流拆成多个完全不同的分支)。 diff --git a/plugins/ai_yolo/ai_yolo_node.cpp b/plugins/ai_yolo/ai_yolo_node.cpp index 091e668..fb0871b 100644 --- a/plugins/ai_yolo/ai_yolo_node.cpp +++ b/plugins/ai_yolo/ai_yolo_node.cpp @@ -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("model_h", 640); num_classes_ = config.ValueOr("num_classes", 80); + if (const SimpleJson* dbg = config.Find("debug"); dbg && dbg->IsObject()) { + stats_log_ = dbg->ValueOr("stats", stats_log_); + stats_interval_ = std::max( + 1, static_cast(dbg->ValueOr("stats_interval", static_cast(stats_interval_)))); + debug_det_ = dbg->ValueOr("detections", debug_det_); + } + // Optional inference throttle. 0 = run every frame. infer_interval_ms_ = std::max(0, static_cast(config.ValueOr("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(Clamp(static_cast(h / scale_h), 0, frame->height - static_cast(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>> 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; diff --git a/plugins/input_rtsp/input_rtsp_node.cpp b/plugins/input_rtsp/input_rtsp_node.cpp index 455029f..9be6ad7 100644 --- a/plugins/input_rtsp/input_rtsp_node.cpp +++ b/plugins/input_rtsp/input_rtsp_node.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -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("reconnect_sec", 5); reconnect_backoff_max_sec_ = config.ValueOr("reconnect_backoff_max_sec", 30); fallback_to_stub_on_fail_ = config.ValueOr("fallback_to_stub_on_fail", false); + + if (const SimpleJson* dbg = config.Find("debug"); dbg && dbg->IsObject()) { + stats_log_ = dbg->ValueOr("stats", stats_log_); + stats_interval_ = std::max( + 1, static_cast(dbg->ValueOr("stats_interval", static_cast(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(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(pkt->size))) { - if (pkt_count <= 10) { + if (stats_log_ && pkt_count <= 10) { int sc = GetAnnexBStartCodeSize(pkt->data, static_cast(pkt->size)); if (sc > 0 && static_cast(sc) < static_cast(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(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(b0))); } } handle_annexb(pkt->data, static_cast(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 cpu_affinity_; + + bool stats_log_ = false; + uint64_t stats_interval_ = 100; }; REGISTER_NODE(InputRtspNode, "input_rtsp"); diff --git a/plugins/osd/osd_node.cpp b/plugins/osd/osd_node.cpp index af33328..19baa86 100644 --- a/plugins/osd/osd_node.cpp +++ b/plugins/osd/osd_node.cpp @@ -9,6 +9,7 @@ #include #include "node.h" +#include "utils/logger.h" namespace rk3588 { @@ -288,12 +289,18 @@ public: line_width_ = config.ValueOr("line_width", 2); font_scale_ = config.ValueOr("font_scale", 1); + if (const SimpleJson* dbg = config.Find("debug"); dbg && dbg->IsObject()) { + stats_log_ = dbg->ValueOr("stats", stats_log_); + stats_interval_ = std::max( + 1, static_cast(dbg->ValueOr("stats_interval", static_cast(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> input_queue_; std::vector>> output_queues_; uint64_t processed_ = 0; + + bool stats_log_ = false; + uint64_t stats_interval_ = 100; }; REGISTER_NODE(OsdNode, "osd"); diff --git a/plugins/preprocess/preprocess_node.cpp b/plugins/preprocess/preprocess_node.cpp index 20ff609..604a21c 100644 --- a/plugins/preprocess/preprocess_node.cpp +++ b/plugins/preprocess/preprocess_node.cpp @@ -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("use_rga", true); use_rga_ = requested_use_rga; + if (const SimpleJson* dbg = config.Find("debug"); dbg && dbg->IsObject()) { + stats_log_ = dbg->ValueOr("stats", stats_log_); + stats_interval_ = std::max(1, static_cast(dbg->ValueOr("stats_interval", static_cast(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(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(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(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(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> input_queue_; std::vector>> output_queues_; uint64_t processed_ = 0; diff --git a/plugins/publish/publish_node.cpp b/plugins/publish/publish_node.cpp index 9b20afc..1842ab8 100644 --- a/plugins/publish/publish_node.cpp +++ b/plugins/publish/publish_node.cpp @@ -1,6 +1,8 @@ #include #include +#include #include +#include #include #include #include @@ -16,6 +18,8 @@ #include #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(std::tolower(static_cast(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 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("use_ffmpeg_mux", true); attach_encoded_meta_ = config.ValueOr("attach_encoded_meta", !output_queues_.empty()); + if (const SimpleJson* dbg = config.Find("debug"); dbg && dbg->IsObject()) { + stats_log_ = dbg->ValueOr("stats", stats_log_); + stats_interval_ = std::max( + 1, static_cast(dbg->ValueOr("stats_interval", static_cast(stats_interval_)))); +#if defined(RK3588_ENABLE_FFMPEG) + ffmpeg_log_level_ = dbg->ValueOr("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>> 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;