性能优化5
This commit is contained in:
parent
6f1e1f3f03
commit
5c72a489a5
@ -5,7 +5,6 @@
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <numeric>
|
||||
@ -424,29 +423,31 @@ public:
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mu_);
|
||||
cfg_ = std::move(snap);
|
||||
#if defined(RK3588_ENABLE_RKNN)
|
||||
priors_cache_ = {};
|
||||
#endif
|
||||
}
|
||||
|
||||
input_queue_ = ctx.input_queue;
|
||||
output_queues_ = ctx.output_queues;
|
||||
if (!input_queue_) {
|
||||
std::cerr << "[ai_face_det] no input queue for node " << id_ << "\n";
|
||||
LogError("[ai_face_det] no input queue for node " + id_);
|
||||
return false;
|
||||
}
|
||||
if (output_queues_.empty()) {
|
||||
std::cerr << "[ai_face_det] no output queue for node " << id_ << "\n";
|
||||
LogError("[ai_face_det] no output queue for node " + id_);
|
||||
return false;
|
||||
}
|
||||
|
||||
#if defined(RK3588_ENABLE_RKNN)
|
||||
if (model_path_.empty()) {
|
||||
std::cerr << "[ai_face_det] model_path is required\n";
|
||||
LogError("[ai_face_det] model_path is required");
|
||||
return false;
|
||||
}
|
||||
std::string err;
|
||||
model_handle_ = AiScheduler::Instance().LoadModel(model_path_, err);
|
||||
if (model_handle_ == kInvalidModelHandle) {
|
||||
std::cerr << "[ai_face_det] failed to load model: " << err << "\n";
|
||||
LogError("[ai_face_det] failed to load model: " + err);
|
||||
return false;
|
||||
}
|
||||
ModelInfo info;
|
||||
@ -498,7 +499,9 @@ public:
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mu_);
|
||||
cfg_ = std::move(snap);
|
||||
#if defined(RK3588_ENABLE_RKNN)
|
||||
priors_cache_ = {};
|
||||
#endif
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -532,7 +535,7 @@ private:
|
||||
void Run(FramePtr frame) {
|
||||
if (!frame->data || frame->data_size == 0) return;
|
||||
if (frame->format != PixelFormat::RGB && frame->format != PixelFormat::BGR) {
|
||||
std::cerr << "[ai_face_det] input must be RGB/BGR\n";
|
||||
LogWarn("[ai_face_det] input must be RGB/BGR");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -614,7 +617,7 @@ private:
|
||||
|
||||
auto r = AiScheduler::Instance().InferBorrowed(model_handle_, input);
|
||||
if (!r.success) {
|
||||
std::cerr << "[ai_face_det] inference failed: " << r.error << "\n";
|
||||
LogWarn("[ai_face_det] inference failed: " + r.error);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -733,7 +736,8 @@ private:
|
||||
const std::vector<Prior>& priors = priors_ptr ? *priors_ptr : empty_priors;
|
||||
if (!priors.empty() && static_cast<int>(priors.size()) != n) {
|
||||
// Mismatch: can't reliably decode.
|
||||
std::cerr << "[ai_face_det] prior mismatch: priors=" << priors.size() << " n=" << n << "\n";
|
||||
LogWarn("[ai_face_det] prior mismatch: priors=" + std::to_string(priors.size()) +
|
||||
" n=" + std::to_string(n));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -838,7 +842,9 @@ private:
|
||||
|
||||
mutable std::mutex mu_;
|
||||
std::shared_ptr<const FaceDetConfigSnapshot> cfg_;
|
||||
#if defined(RK3588_ENABLE_RKNN)
|
||||
PriorsCache priors_cache_;
|
||||
#endif
|
||||
|
||||
std::shared_ptr<SpscQueue<FramePtr>> input_queue_;
|
||||
std::vector<std::shared_ptr<SpscQueue<FramePtr>>> output_queues_;
|
||||
|
||||
@ -5,7 +5,6 @@
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
@ -655,23 +654,23 @@ public:
|
||||
input_queue_ = ctx.input_queue;
|
||||
output_queues_ = ctx.output_queues;
|
||||
if (!input_queue_) {
|
||||
std::cerr << "[ai_face_recog] no input queue for node " << id_ << "\n";
|
||||
LogError("[ai_face_recog] no input queue for node " + id_);
|
||||
return false;
|
||||
}
|
||||
if (output_queues_.empty()) {
|
||||
std::cerr << "[ai_face_recog] no output queue for node " << id_ << "\n";
|
||||
LogError("[ai_face_recog] no output queue for node " + id_);
|
||||
return false;
|
||||
}
|
||||
|
||||
#if defined(RK3588_ENABLE_RKNN)
|
||||
if (model_path_.empty()) {
|
||||
std::cerr << "[ai_face_recog] model_path is required\n";
|
||||
LogError("[ai_face_recog] model_path is required");
|
||||
return false;
|
||||
}
|
||||
std::string err;
|
||||
model_handle_ = AiScheduler::Instance().LoadModel(model_path_, err);
|
||||
if (model_handle_ == kInvalidModelHandle) {
|
||||
std::cerr << "[ai_face_recog] failed to load model: " << err << "\n";
|
||||
LogError("[ai_face_recog] failed to load model: " + err);
|
||||
return false;
|
||||
}
|
||||
ModelInfo info;
|
||||
@ -804,7 +803,7 @@ private:
|
||||
if (!frame->face_det || frame->face_det->faces.empty()) return;
|
||||
if (!frame->data || frame->data_size == 0) return;
|
||||
if (frame->format != PixelFormat::RGB && frame->format != PixelFormat::BGR) {
|
||||
std::cerr << "[ai_face_recog] input must be RGB/BGR\n";
|
||||
LogWarn("[ai_face_recog] input must be RGB/BGR");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -892,7 +891,7 @@ private:
|
||||
|
||||
auto r = AiScheduler::Instance().InferBorrowed(model_handle_, in);
|
||||
if (!r.success || r.outputs.empty()) {
|
||||
std::cerr << "[ai_face_recog] inference failed: " << (r.error.empty() ? "unknown" : r.error) << "\n";
|
||||
LogWarn(std::string("[ai_face_recog] inference failed: ") + (r.error.empty() ? "unknown" : r.error));
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@ -4,7 +4,6 @@
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <thread>
|
||||
@ -310,25 +309,25 @@ public:
|
||||
|
||||
input_queue_ = ctx.input_queue;
|
||||
if (!input_queue_) {
|
||||
std::cerr << "[ai_yolo] no input queue for node " << id_ << "\n";
|
||||
LogError("[ai_yolo] no input queue for node " + id_);
|
||||
return false;
|
||||
}
|
||||
if (ctx.output_queues.empty()) {
|
||||
std::cerr << "[ai_yolo] no output queue for node " << id_ << "\n";
|
||||
LogError("[ai_yolo] no output queue for node " + id_);
|
||||
return false;
|
||||
}
|
||||
output_queues_ = ctx.output_queues;
|
||||
|
||||
#if defined(RK3588_ENABLE_RKNN)
|
||||
if (model_path_.empty()) {
|
||||
std::cerr << "[ai_yolo] model_path is required\n";
|
||||
LogError("[ai_yolo] model_path is required");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string err;
|
||||
model_handle_ = AiScheduler::Instance().LoadModel(model_path_, err);
|
||||
if (model_handle_ == kInvalidModelHandle) {
|
||||
std::cerr << "[ai_yolo] failed to load model: " << err << "\n";
|
||||
LogError("[ai_yolo] failed to load model: " + err);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -410,7 +409,7 @@ private:
|
||||
|
||||
bool is_rgb = (frame->format == PixelFormat::RGB || frame->format == PixelFormat::BGR);
|
||||
if (!is_rgb) {
|
||||
std::cerr << "[ai_yolo] input must be RGB/BGR, got other format\n";
|
||||
LogWarn("[ai_yolo] input must be RGB/BGR, got other format");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -439,8 +438,9 @@ private:
|
||||
}
|
||||
} else {
|
||||
if (frame->data_size < static_cast<size_t>(src_stride) * static_cast<size_t>(h)) {
|
||||
std::cerr << "[ai_yolo] invalid RGB buffer size/stride (data_size=" << frame->data_size
|
||||
<< ", stride=" << src_stride << ", h=" << h << ")\n";
|
||||
LogWarn("[ai_yolo] invalid RGB buffer size/stride (data_size=" + std::to_string(frame->data_size) +
|
||||
", stride=" + std::to_string(src_stride) +
|
||||
", h=" + std::to_string(h) + ")");
|
||||
return;
|
||||
}
|
||||
rgb_tmp_.resize(packed_size);
|
||||
@ -458,7 +458,7 @@ private:
|
||||
|
||||
auto result = AiScheduler::Instance().InferBorrowed(model_handle_, input);
|
||||
if (!result.success) {
|
||||
std::cerr << "[ai_yolo] inference failed: " << result.error << "\n";
|
||||
LogWarn("[ai_yolo] inference failed: " + result.error);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@ -7,10 +7,12 @@
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <mutex>
|
||||
#include <sstream>
|
||||
#include <thread>
|
||||
|
||||
#include "utils/logger.h"
|
||||
|
||||
#if defined(RK3588_ENABLE_FFMPEG)
|
||||
extern "C" {
|
||||
#include <libavcodec/avcodec.h>
|
||||
@ -26,6 +28,21 @@ namespace rk3588 {
|
||||
|
||||
namespace {
|
||||
|
||||
bool SafeLocalTime(std::time_t t, std::tm& out) {
|
||||
#if defined(_WIN32)
|
||||
return localtime_s(&out, &t) == 0;
|
||||
#elif defined(__unix__) || defined(__APPLE__)
|
||||
return localtime_r(&t, &out) != nullptr;
|
||||
#else
|
||||
static std::mutex mu;
|
||||
std::lock_guard<std::mutex> lock(mu);
|
||||
std::tm* p = std::localtime(&t);
|
||||
if (!p) return false;
|
||||
out = *p;
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool HasAnnexBStartCode(const uint8_t* d, size_t n) {
|
||||
if (!d || n < 4) return false;
|
||||
for (size_t i = 0; i + 3 < n; ++i) {
|
||||
@ -145,7 +162,7 @@ bool ClipAction::Init(const SimpleJson& config) {
|
||||
if (const SimpleJson* upload_cfg = config.Find("upload")) {
|
||||
uploader_ = CreateUploader(*upload_cfg);
|
||||
if (!uploader_) {
|
||||
std::cerr << "[ClipAction] failed to create uploader\n";
|
||||
LogError("[ClipAction] failed to create uploader");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
@ -153,21 +170,22 @@ bool ClipAction::Init(const SimpleJson& config) {
|
||||
uploader_ = CreateUploader(default_cfg);
|
||||
}
|
||||
|
||||
std::cout << "[ClipAction] initialized, pre=" << pre_sec_ << "s post=" << post_sec_
|
||||
<< "s format=" << format_ << "\n";
|
||||
LogInfo("[ClipAction] initialized, pre=" + std::to_string(pre_sec_) +
|
||||
"s post=" + std::to_string(post_sec_) +
|
||||
"s format=" + format_);
|
||||
return true;
|
||||
}
|
||||
|
||||
void ClipAction::Execute(AlarmEvent& event, std::shared_ptr<Frame> frame) {
|
||||
if (!packet_buffer_) {
|
||||
std::cerr << "[ClipAction] packet buffer not set\n";
|
||||
LogError("[ClipAction] packet buffer not set");
|
||||
return;
|
||||
}
|
||||
if (!frame) return;
|
||||
|
||||
const int64_t trigger_pts_ms = frame->pts > 0 ? static_cast<int64_t>(frame->pts / 1000ULL) : 0;
|
||||
if (trigger_pts_ms <= 0) {
|
||||
std::cerr << "[ClipAction] invalid trigger pts\n";
|
||||
LogWarn("[ClipAction] invalid trigger pts");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -192,14 +210,14 @@ void ClipAction::Execute(AlarmEvent& event, std::shared_ptr<Frame> frame) {
|
||||
metas = packet_buffer_->GetPacketsInRange(trigger_pts_ms, end_pts);
|
||||
}
|
||||
if (metas.empty()) {
|
||||
std::cerr << "[ClipAction] no packets in range\n";
|
||||
LogWarn("[ClipAction] no packets in range");
|
||||
return;
|
||||
}
|
||||
|
||||
std::string url = ProcessClipFromPackets(metas, event);
|
||||
if (!url.empty()) {
|
||||
event.clip_url = url;
|
||||
std::cout << "[ClipAction] clip uploaded: " << url << "\n";
|
||||
LogInfo("[ClipAction] clip uploaded: " + url);
|
||||
}
|
||||
}
|
||||
|
||||
@ -220,14 +238,14 @@ std::string ClipAction::ProcessClipFromPackets(const std::vector<std::shared_ptr
|
||||
if (codec == VideoCodec::H264) cid = AV_CODEC_ID_H264;
|
||||
else if (codec == VideoCodec::H265) cid = AV_CODEC_ID_HEVC;
|
||||
else {
|
||||
std::cerr << "[ClipAction] unsupported codec\n";
|
||||
LogError("[ClipAction] unsupported codec");
|
||||
return "";
|
||||
}
|
||||
|
||||
const int width = first->codec->width;
|
||||
const int height = first->codec->height;
|
||||
if (width <= 0 || height <= 0) {
|
||||
std::cerr << "[ClipAction] invalid codec size\n";
|
||||
LogError("[ClipAction] invalid codec size");
|
||||
return "";
|
||||
}
|
||||
|
||||
@ -235,13 +253,14 @@ std::string ClipAction::ProcessClipFromPackets(const std::vector<std::shared_ptr
|
||||
try {
|
||||
tmp_dir = std::filesystem::temp_directory_path();
|
||||
} catch (...) {
|
||||
LogWarn("[ClipAction] temp_directory_path failed; falling back to current directory");
|
||||
tmp_dir = ".";
|
||||
}
|
||||
std::filesystem::path tmp_path = tmp_dir / ("clip_" + std::to_string(event.timestamp_ms) + "." + format_);
|
||||
|
||||
AVFormatContext* fmt_ctx = nullptr;
|
||||
if (avformat_alloc_output_context2(&fmt_ctx, nullptr, format_.c_str(), tmp_path.string().c_str()) < 0 || !fmt_ctx) {
|
||||
std::cerr << "[ClipAction] failed to create output context\n";
|
||||
LogError("[ClipAction] failed to create output context");
|
||||
return "";
|
||||
}
|
||||
|
||||
@ -271,7 +290,7 @@ std::string ClipAction::ProcessClipFromPackets(const std::vector<std::shared_ptr
|
||||
mp4_extradata = ex; // AVCC
|
||||
} else if (HasAnnexBStartCode(ex.data(), ex.size())) {
|
||||
if (!BuildAvccFromAnnexB(ex, mp4_extradata)) {
|
||||
std::cerr << "[ClipAction] failed to build AVCC from AnnexB extradata\n";
|
||||
LogWarn("[ClipAction] failed to build AVCC from AnnexB extradata");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -356,7 +375,7 @@ std::string ClipAction::ProcessClipFromPackets(const std::vector<std::shared_ptr
|
||||
|
||||
std::ifstream file(tmp_path, std::ios::binary | std::ios::ate);
|
||||
if (!file) {
|
||||
std::cerr << "[ClipAction] failed to read temp file\n";
|
||||
LogError("[ClipAction] failed to read temp file");
|
||||
return "";
|
||||
}
|
||||
const size_t file_size = static_cast<size_t>(file.tellg());
|
||||
@ -372,12 +391,12 @@ std::string ClipAction::ProcessClipFromPackets(const std::vector<std::shared_ptr
|
||||
std::filesystem::remove(tmp_path, ec);
|
||||
|
||||
if (result.success) return result.url;
|
||||
std::cerr << "[ClipAction] upload failed: " << result.error << "\n";
|
||||
LogWarn("[ClipAction] upload failed: " + result.error);
|
||||
return "";
|
||||
#else
|
||||
(void)metas;
|
||||
(void)event;
|
||||
std::cerr << "[ClipAction] FFmpeg not enabled\n";
|
||||
LogError("[ClipAction] FFmpeg not enabled");
|
||||
return "";
|
||||
#endif
|
||||
}
|
||||
@ -385,12 +404,13 @@ std::string ClipAction::ProcessClipFromPackets(const std::vector<std::shared_ptr
|
||||
std::string ClipAction::GenerateKey(const AlarmEvent& event) {
|
||||
auto now = std::chrono::system_clock::now();
|
||||
auto time_t_now = std::chrono::system_clock::to_time_t(now);
|
||||
std::tm* tm = std::localtime(&time_t_now);
|
||||
std::tm tm{};
|
||||
(void)SafeLocalTime(time_t_now, tm);
|
||||
|
||||
std::ostringstream oss;
|
||||
oss << std::put_time(tm, "%Y%m%d") << "/"
|
||||
oss << std::put_time(&tm, "%Y%m%d") << "/"
|
||||
<< event.node_id << "_"
|
||||
<< std::put_time(tm, "%H%M%S") << "_"
|
||||
<< std::put_time(&tm, "%H%M%S") << "_"
|
||||
<< event.frame_id << "." << format_;
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
@ -2,14 +2,16 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <cstdlib>
|
||||
#include <iomanip>
|
||||
#include <ctime>
|
||||
#include <iostream>
|
||||
#include <mutex>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
#include "utils/simple_json.h"
|
||||
#include "utils/simple_json_writer.h"
|
||||
#include "utils/logger.h"
|
||||
|
||||
#if __has_include(<curl/curl.h>)
|
||||
#include <curl/curl.h>
|
||||
@ -21,7 +23,31 @@
|
||||
namespace rk3588 {
|
||||
namespace {
|
||||
|
||||
bool SafeLocalTime(std::time_t t, std::tm& out) {
|
||||
#if defined(_WIN32)
|
||||
return localtime_s(&out, &t) == 0;
|
||||
#elif defined(__unix__) || defined(__APPLE__)
|
||||
return localtime_r(&t, &out) != nullptr;
|
||||
#else
|
||||
static std::mutex mu;
|
||||
std::lock_guard<std::mutex> lock(mu);
|
||||
std::tm* p = std::localtime(&t);
|
||||
if (!p) return false;
|
||||
out = *p;
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if HAS_CURL
|
||||
|
||||
void EnsureCurlGlobalInitOnce() {
|
||||
static std::once_flag once;
|
||||
std::call_once(once, []() {
|
||||
curl_global_init(CURL_GLOBAL_DEFAULT);
|
||||
std::atexit([]() { curl_global_cleanup(); });
|
||||
});
|
||||
}
|
||||
|
||||
size_t CurlWriteCb(char* ptr, size_t size, size_t nmemb, void* userdata) {
|
||||
if (!userdata) return 0;
|
||||
auto* out = static_cast<std::string*>(userdata);
|
||||
@ -122,30 +148,29 @@ bool ExternalApiAction::Init(const SimpleJson& config) {
|
||||
retry_backoff_ms_ = std::max(0, config.ValueOr<int>("retry_backoff_ms", 200));
|
||||
|
||||
if (get_token_url_.empty()) {
|
||||
std::cerr << "[ExternalApiAction] getTokenUrl is required\n";
|
||||
LogError("[ExternalApiAction] getTokenUrl is required");
|
||||
return false;
|
||||
}
|
||||
if (put_message_url_.empty()) {
|
||||
std::cerr << "[ExternalApiAction] putMessageUrl is required\n";
|
||||
LogError("[ExternalApiAction] putMessageUrl is required");
|
||||
return false;
|
||||
}
|
||||
if (tenant_code_.empty()) {
|
||||
std::cerr << "[ExternalApiAction] tenantCode is required\n";
|
||||
LogError("[ExternalApiAction] tenantCode is required");
|
||||
return false;
|
||||
}
|
||||
if (channel_no_.empty()) {
|
||||
std::cerr << "[ExternalApiAction] channelNo is required\n";
|
||||
LogError("[ExternalApiAction] channelNo is required");
|
||||
return false;
|
||||
}
|
||||
|
||||
#if HAS_CURL
|
||||
curl_global_init(CURL_GLOBAL_DEFAULT);
|
||||
EnsureCurlGlobalInitOnce();
|
||||
#endif
|
||||
|
||||
running_.store(true);
|
||||
worker_ = std::thread(&ExternalApiAction::WorkerLoop, this);
|
||||
std::cout << "[ExternalApiAction] initialized, token_url=" << get_token_url_
|
||||
<< " msg_url=" << put_message_url_ << "\n";
|
||||
LogInfo("[ExternalApiAction] initialized, token_url=" + get_token_url_ + " msg_url=" + put_message_url_);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -214,7 +239,7 @@ void ExternalApiAction::WorkerLoop() {
|
||||
|
||||
std::string err;
|
||||
if (!EnsureToken(err)) {
|
||||
std::cerr << "[ExternalApiAction] ensure token failed: " << err << "\n";
|
||||
LogWarn("[ExternalApiAction] ensure token failed: " + err);
|
||||
} else {
|
||||
std::string token;
|
||||
{
|
||||
@ -247,10 +272,10 @@ void ExternalApiAction::WorkerLoop() {
|
||||
token = token_;
|
||||
continue;
|
||||
}
|
||||
std::cerr << "[ExternalApiAction] refresh token failed: " << terr << "\n";
|
||||
LogWarn("[ExternalApiAction] refresh token failed: " + terr);
|
||||
}
|
||||
|
||||
std::cerr << "[ExternalApiAction] send failed: " << send_err << " (http=" << http_code << ")\n";
|
||||
LogWarn("[ExternalApiAction] send failed: " + send_err + " (http=" + std::to_string(http_code) + ")");
|
||||
}
|
||||
}
|
||||
|
||||
@ -362,17 +387,17 @@ bool ExternalApiAction::SendMessageWithToken(const Job& job, const std::string&
|
||||
#else
|
||||
(void)job;
|
||||
(void)token;
|
||||
std::cout << "[ExternalApiAction] curl not available; would POST to " << put_message_url_ << "\n";
|
||||
LogInfo("[ExternalApiAction] curl not available; would POST to " + put_message_url_);
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string ExternalApiAction::FormatAlarmTime(uint64_t timestamp_ms) const {
|
||||
const std::time_t t = static_cast<std::time_t>(timestamp_ms / 1000ULL);
|
||||
std::tm* tm = std::localtime(&t);
|
||||
if (!tm) return "";
|
||||
std::tm tm{};
|
||||
if (!SafeLocalTime(t, tm)) return "";
|
||||
std::ostringstream oss;
|
||||
oss << std::put_time(tm, "%Y-%m-%d %H:%M:%S");
|
||||
oss << std::put_time(&tm, "%Y-%m-%d %H:%M:%S");
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
|
||||
@ -2,9 +2,14 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <cctype>
|
||||
#include <cstdlib>
|
||||
#include <ctime>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include "utils/logger.h"
|
||||
|
||||
#if __has_include(<curl/curl.h>)
|
||||
#include <curl/curl.h>
|
||||
@ -15,6 +20,43 @@
|
||||
|
||||
namespace rk3588 {
|
||||
|
||||
namespace {
|
||||
|
||||
std::string ToLower(std::string s) {
|
||||
for (char& c : s) c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
|
||||
return s;
|
||||
}
|
||||
|
||||
std::string JsonEscape(std::string_view s) {
|
||||
std::string out;
|
||||
out.reserve(s.size() + 8);
|
||||
for (char c : s) {
|
||||
switch (c) {
|
||||
case '\\': out += "\\\\"; break;
|
||||
case '"': out += "\\\""; break;
|
||||
case '\n': out += "\\n"; break;
|
||||
case '\r': out += "\\r"; break;
|
||||
case '\t': out += "\\t"; break;
|
||||
default:
|
||||
if (static_cast<unsigned char>(c) < 0x20) out += "?";
|
||||
else out.push_back(c);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
#if HAS_CURL
|
||||
void EnsureCurlGlobalInitOnce() {
|
||||
static std::once_flag once;
|
||||
std::call_once(once, []() {
|
||||
curl_global_init(CURL_GLOBAL_DEFAULT);
|
||||
std::atexit([]() { curl_global_cleanup(); });
|
||||
});
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace
|
||||
|
||||
HttpAction::~HttpAction() {
|
||||
Drain();
|
||||
Stop();
|
||||
@ -32,17 +74,17 @@ bool HttpAction::Init(const SimpleJson& config) {
|
||||
else queue_policy_ = QueuePolicy::DropOldest;
|
||||
|
||||
if (url_.empty()) {
|
||||
std::cerr << "[HttpAction] url is required\n";
|
||||
LogError("[HttpAction] url is required");
|
||||
return false;
|
||||
}
|
||||
|
||||
#if HAS_CURL
|
||||
curl_global_init(CURL_GLOBAL_DEFAULT);
|
||||
EnsureCurlGlobalInitOnce();
|
||||
#endif
|
||||
|
||||
running_.store(true);
|
||||
worker_ = std::thread(&HttpAction::WorkerLoop, this);
|
||||
std::cout << "[HttpAction] initialized, url=" << url_ << "\n";
|
||||
LogInfo("[HttpAction] initialized, url=" + url_ + ", method=" + method_);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -50,17 +92,17 @@ void HttpAction::Execute(AlarmEvent& event, std::shared_ptr<Frame> /*frame*/) {
|
||||
// Build JSON body
|
||||
std::ostringstream oss;
|
||||
oss << "{";
|
||||
oss << "\"node_id\":\"" << event.node_id << "\",";
|
||||
oss << "\"rule_name\":\"" << event.rule_name << "\",";
|
||||
oss << "\"node_id\":\"" << JsonEscape(event.node_id) << "\",";
|
||||
oss << "\"rule_name\":\"" << JsonEscape(event.rule_name) << "\",";
|
||||
oss << "\"timestamp\":" << event.timestamp_ms << ",";
|
||||
oss << "\"frame_id\":" << event.frame_id << ",";
|
||||
|
||||
if (include_media_url_) {
|
||||
if (!event.snapshot_url.empty()) {
|
||||
oss << "\"snapshot_url\":\"" << event.snapshot_url << "\",";
|
||||
oss << "\"snapshot_url\":\"" << JsonEscape(event.snapshot_url) << "\",";
|
||||
}
|
||||
if (!event.clip_url.empty()) {
|
||||
oss << "\"clip_url\":\"" << event.clip_url << "\",";
|
||||
oss << "\"clip_url\":\"" << JsonEscape(event.clip_url) << "\",";
|
||||
}
|
||||
}
|
||||
|
||||
@ -142,7 +184,7 @@ bool HttpAction::SendRequest(const std::string& json_body) {
|
||||
#if HAS_CURL
|
||||
CURL* curl = curl_easy_init();
|
||||
if (!curl) {
|
||||
std::cerr << "[HttpAction] curl_easy_init failed\n";
|
||||
LogError("[HttpAction] curl_easy_init failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -151,13 +193,26 @@ bool HttpAction::SendRequest(const std::string& json_body) {
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_URL, url_.c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json_body.c_str());
|
||||
|
||||
const std::string method_lc = ToLower(method_);
|
||||
if (method_lc == "post") {
|
||||
curl_easy_setopt(curl, CURLOPT_POST, 1L);
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json_body.c_str());
|
||||
} else if (method_lc == "put" || method_lc == "patch") {
|
||||
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, method_.c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json_body.c_str());
|
||||
} else {
|
||||
LogWarn("[HttpAction] unsupported method='" + method_ + "', falling back to POST");
|
||||
curl_easy_setopt(curl, CURLOPT_POST, 1L);
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json_body.c_str());
|
||||
}
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, timeout_ms_);
|
||||
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT_MS, timeout_ms_ / 2);
|
||||
|
||||
CURLcode res = curl_easy_perform(curl);
|
||||
if (res != CURLE_OK) {
|
||||
std::cerr << "[HttpAction] request failed: " << curl_easy_strerror(res) << "\n";
|
||||
LogWarn(std::string("[HttpAction] request failed: ") + curl_easy_strerror(res));
|
||||
}
|
||||
|
||||
curl_slist_free_all(headers);
|
||||
@ -165,8 +220,7 @@ bool HttpAction::SendRequest(const std::string& json_body) {
|
||||
return res == CURLE_OK;
|
||||
#else
|
||||
// Stub implementation for Windows without curl
|
||||
std::cout << "[HttpAction] HTTP POST to " << url_ << "\n"
|
||||
<< " Body: " << json_body << "\n";
|
||||
LogInfo("[HttpAction] (stub) method=" + method_ + " url=" + url_ + " body=" + json_body);
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -3,26 +3,54 @@
|
||||
#include <chrono>
|
||||
#include <ctime>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <mutex>
|
||||
#include <sstream>
|
||||
|
||||
#include "utils/logger.h"
|
||||
|
||||
namespace rk3588 {
|
||||
|
||||
namespace {
|
||||
|
||||
bool SafeLocalTime(std::time_t t, std::tm& out) {
|
||||
#if defined(_WIN32)
|
||||
return localtime_s(&out, &t) == 0;
|
||||
#elif defined(__unix__) || defined(__APPLE__)
|
||||
return localtime_r(&t, &out) != nullptr;
|
||||
#else
|
||||
static std::mutex mu;
|
||||
std::lock_guard<std::mutex> lock(mu);
|
||||
std::tm* p = std::localtime(&t);
|
||||
if (!p) return false;
|
||||
out = *p;
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
LogLevel LogLevelFromStringOrInfo(const std::string& s) {
|
||||
LogLevel lvl = LogLevel::Info;
|
||||
(void)ParseLogLevel(s, lvl);
|
||||
return lvl;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool LogAction::Init(const SimpleJson& config) {
|
||||
level_ = config.ValueOr<std::string>("level", "info");
|
||||
include_detections_ = config.ValueOr<bool>("include_detections", true);
|
||||
std::cout << "[LogAction] initialized, level=" << level_ << "\n";
|
||||
LogInfo("[LogAction] initialized, level=" + level_);
|
||||
return true;
|
||||
}
|
||||
|
||||
void LogAction::Execute(AlarmEvent& event, std::shared_ptr<Frame> /*frame*/) {
|
||||
auto now = std::chrono::system_clock::now();
|
||||
auto time_t_now = std::chrono::system_clock::to_time_t(now);
|
||||
std::tm* tm_now = std::localtime(&time_t_now);
|
||||
std::tm tm_now{};
|
||||
(void)SafeLocalTime(time_t_now, tm_now);
|
||||
|
||||
std::ostringstream oss;
|
||||
oss << "[ALARM][" << level_ << "] "
|
||||
<< std::put_time(tm_now, "%Y-%m-%d %H:%M:%S")
|
||||
<< std::put_time(&tm_now, "%Y-%m-%d %H:%M:%S")
|
||||
<< " node=" << event.node_id
|
||||
<< " rule=" << event.rule_name
|
||||
<< " frame=" << event.frame_id;
|
||||
@ -49,7 +77,7 @@ void LogAction::Execute(AlarmEvent& event, std::shared_ptr<Frame> /*frame*/) {
|
||||
oss << " clip=" << event.clip_url;
|
||||
}
|
||||
|
||||
std::cout << oss.str() << "\n";
|
||||
Logger::Instance().Log(LogLevelFromStringOrInfo(level_), oss.str());
|
||||
}
|
||||
|
||||
} // namespace rk3588
|
||||
|
||||
@ -5,10 +5,11 @@
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <mutex>
|
||||
#include <sstream>
|
||||
|
||||
#include "utils/dma_alloc.h"
|
||||
#include "utils/logger.h"
|
||||
|
||||
#if defined(RK3588_ENABLE_FFMPEG)
|
||||
extern "C" {
|
||||
@ -25,6 +26,21 @@ namespace rk3588 {
|
||||
|
||||
namespace {
|
||||
|
||||
bool SafeLocalTime(std::time_t t, std::tm& out) {
|
||||
#if defined(_WIN32)
|
||||
return localtime_s(&out, &t) == 0;
|
||||
#elif defined(__unix__) || defined(__APPLE__)
|
||||
return localtime_r(&t, &out) != nullptr;
|
||||
#else
|
||||
static std::mutex mu;
|
||||
std::lock_guard<std::mutex> lock(mu);
|
||||
std::tm* p = std::localtime(&t);
|
||||
if (!p) return false;
|
||||
out = *p;
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline uint8_t ClipU8(int v) {
|
||||
if (v < 0) return 0;
|
||||
if (v > 255) return 255;
|
||||
@ -46,6 +62,7 @@ inline int PlaneStride(const Frame& f, int idx, int fallback) {
|
||||
return fallback;
|
||||
}
|
||||
|
||||
#if HAS_FFMPEG
|
||||
bool FillYuv420pFromFrame(const Frame& src, AVFrame* dst) {
|
||||
if (!dst) return false;
|
||||
if (dst->format != AV_PIX_FMT_YUV420P && dst->format != AV_PIX_FMT_YUVJ420P) return false;
|
||||
@ -179,6 +196,7 @@ bool FillYuv420pFromFrame(const Frame& src, AVFrame* dst) {
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace
|
||||
|
||||
@ -189,7 +207,7 @@ bool SnapshotAction::Init(const SimpleJson& config) {
|
||||
if (const SimpleJson* upload_cfg = config.Find("upload")) {
|
||||
uploader_ = CreateUploader(*upload_cfg);
|
||||
if (!uploader_) {
|
||||
std::cerr << "[SnapshotAction] failed to create uploader\n";
|
||||
LogError("[SnapshotAction] failed to create uploader");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
@ -198,14 +216,13 @@ bool SnapshotAction::Init(const SimpleJson& config) {
|
||||
uploader_ = CreateUploader(default_cfg);
|
||||
}
|
||||
|
||||
std::cout << "[SnapshotAction] initialized, format=" << format_
|
||||
<< " quality=" << quality_ << "\n";
|
||||
LogInfo("[SnapshotAction] initialized, format=" + format_ + " quality=" + std::to_string(quality_));
|
||||
return true;
|
||||
}
|
||||
|
||||
void SnapshotAction::Execute(AlarmEvent& event, std::shared_ptr<Frame> frame) {
|
||||
if (!frame || !frame->data) {
|
||||
std::cerr << "[SnapshotAction] no frame data\n";
|
||||
LogWarn("[SnapshotAction] no frame data");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -214,7 +231,7 @@ void SnapshotAction::Execute(AlarmEvent& event, std::shared_ptr<Frame> frame) {
|
||||
auto jpeg_data = EncodeJpeg(frame);
|
||||
if (dma_fd >= 0) DmaSyncEndFd(dma_fd);
|
||||
if (jpeg_data.empty()) {
|
||||
std::cerr << "[SnapshotAction] failed to encode JPEG\n";
|
||||
LogWarn("[SnapshotAction] failed to encode JPEG");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -223,21 +240,22 @@ void SnapshotAction::Execute(AlarmEvent& event, std::shared_ptr<Frame> frame) {
|
||||
|
||||
if (result.success) {
|
||||
event.snapshot_url = result.url;
|
||||
std::cout << "[SnapshotAction] uploaded: " << result.url << "\n";
|
||||
LogInfo("[SnapshotAction] uploaded: " + result.url);
|
||||
} else {
|
||||
std::cerr << "[SnapshotAction] upload failed: " << result.error << "\n";
|
||||
LogWarn("[SnapshotAction] upload failed: " + result.error);
|
||||
}
|
||||
}
|
||||
|
||||
std::string SnapshotAction::GenerateKey(const AlarmEvent& event) {
|
||||
auto now = std::chrono::system_clock::now();
|
||||
auto time_t_now = std::chrono::system_clock::to_time_t(now);
|
||||
std::tm* tm = std::localtime(&time_t_now);
|
||||
std::tm tm{};
|
||||
(void)SafeLocalTime(time_t_now, tm);
|
||||
|
||||
std::ostringstream oss;
|
||||
oss << std::put_time(tm, "%Y%m%d") << "/"
|
||||
oss << std::put_time(&tm, "%Y%m%d") << "/"
|
||||
<< event.node_id << "_"
|
||||
<< std::put_time(tm, "%H%M%S") << "_"
|
||||
<< std::put_time(&tm, "%H%M%S") << "_"
|
||||
<< event.frame_id << "." << format_;
|
||||
return oss.str();
|
||||
}
|
||||
@ -248,7 +266,7 @@ std::vector<uint8_t> SnapshotAction::EncodeJpeg(const std::shared_ptr<Frame>& fr
|
||||
#if HAS_FFMPEG
|
||||
const AVCodec* codec = avcodec_find_encoder(AV_CODEC_ID_MJPEG);
|
||||
if (!codec) {
|
||||
std::cerr << "[SnapshotAction] MJPEG encoder not found\n";
|
||||
LogError("[SnapshotAction] MJPEG encoder not found");
|
||||
return output;
|
||||
}
|
||||
|
||||
@ -304,7 +322,7 @@ std::vector<uint8_t> SnapshotAction::EncodeJpeg(const std::shared_ptr<Frame>& fr
|
||||
avcodec_free_context(&ctx);
|
||||
#else
|
||||
// Stub: just create a minimal valid JPEG header for testing
|
||||
std::cerr << "[SnapshotAction] FFmpeg not enabled, cannot encode JPEG\n";
|
||||
LogError("[SnapshotAction] FFmpeg not enabled, cannot encode JPEG");
|
||||
#endif
|
||||
|
||||
return output;
|
||||
|
||||
@ -4,7 +4,6 @@
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
@ -12,6 +11,8 @@
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include "utils/logger.h"
|
||||
|
||||
#include "face/face_result.h"
|
||||
#include "node.h"
|
||||
#include "rule_engine.h"
|
||||
@ -51,11 +52,16 @@ public:
|
||||
|
||||
const uint64_t now = NowEpochMs();
|
||||
uint64_t last = last_exec_ms_.load(std::memory_order_relaxed);
|
||||
if (last != 0 && now > last && (now - last) < min_interval_ms_) {
|
||||
return;
|
||||
while (true) {
|
||||
if (last != 0 && now > last && (now - last) < min_interval_ms_) {
|
||||
return;
|
||||
}
|
||||
// Best-effort: only one thread should win the update.
|
||||
if (last_exec_ms_.compare_exchange_weak(last, now, std::memory_order_relaxed)) {
|
||||
break;
|
||||
}
|
||||
// last is updated by compare_exchange_weak; loop and re-check.
|
||||
}
|
||||
// Best-effort: only one thread should update; compare-exchange avoids lost updates.
|
||||
last_exec_ms_.store(now, std::memory_order_relaxed);
|
||||
inner_->Execute(event, std::move(frame));
|
||||
}
|
||||
|
||||
@ -131,7 +137,7 @@ public:
|
||||
// Initialize rule engine
|
||||
if (const SimpleJson* rules_cfg = config.Find("rules")) {
|
||||
if (!rule_engine_.Init(*rules_cfg, labels_)) {
|
||||
std::cerr << "[alarm] failed to init rule engine\n";
|
||||
LogError("[alarm] failed to init rule engine");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -229,18 +235,18 @@ public:
|
||||
|
||||
input_queue_ = ctx.input_queue;
|
||||
if (!input_queue_) {
|
||||
std::cerr << "[alarm] no input queue for node " << id_ << "\n";
|
||||
LogError("[alarm] no input queue for node " + id_);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::cout << "[alarm] initialized with " << actions_.size() << " actions\n";
|
||||
LogInfo("[alarm] initialized with " + std::to_string(actions_.size()) + " actions");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Start() override {
|
||||
worker_running_.store(true);
|
||||
worker_ = std::thread(&AlarmNode::WorkerLoop, this);
|
||||
std::cout << "[alarm] started\n";
|
||||
LogInfo("[alarm] started");
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -253,8 +259,8 @@ public:
|
||||
for (auto& action : actions_) action->Drain();
|
||||
for (auto& action : actions_) action->Stop();
|
||||
|
||||
std::cout << "[alarm] stopped, processed " << processed_frames_
|
||||
<< " frames, triggered " << alarm_count_ << " alarms\n";
|
||||
LogInfo("[alarm] stopped, processed " + std::to_string(processed_frames_) +
|
||||
" frames, triggered " + std::to_string(alarm_count_) + " alarms");
|
||||
}
|
||||
|
||||
void Drain() override {
|
||||
|
||||
@ -1,12 +1,34 @@
|
||||
#include "rule_engine.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdio>
|
||||
#include <ctime>
|
||||
#include <iostream>
|
||||
#include <mutex>
|
||||
#include <sstream>
|
||||
|
||||
#include "utils/logger.h"
|
||||
|
||||
namespace rk3588 {
|
||||
|
||||
namespace {
|
||||
|
||||
bool SafeLocalTime(std::time_t t, std::tm& out) {
|
||||
#if defined(_WIN32)
|
||||
return localtime_s(&out, &t) == 0;
|
||||
#elif defined(__unix__) || defined(__APPLE__)
|
||||
return localtime_r(&t, &out) != nullptr;
|
||||
#else
|
||||
static std::mutex mu;
|
||||
std::lock_guard<std::mutex> lock(mu);
|
||||
std::tm* p = std::localtime(&t);
|
||||
if (!p) return false;
|
||||
out = *p;
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool RuleEngine::Init(const SimpleJson& rules_config, const std::vector<std::string>& labels) {
|
||||
labels_ = labels;
|
||||
rules_.clear();
|
||||
@ -14,7 +36,7 @@ bool RuleEngine::Init(const SimpleJson& rules_config, const std::vector<std::str
|
||||
last_trigger_.clear();
|
||||
|
||||
if (!rules_config.IsArray()) {
|
||||
std::cerr << "[RuleEngine] rules must be an array\n";
|
||||
LogError("[RuleEngine] rules must be an array");
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -54,12 +76,15 @@ bool RuleEngine::Init(const SimpleJson& rules_config, const std::vector<std::str
|
||||
}
|
||||
|
||||
rules_.push_back(rule);
|
||||
std::cout << "[RuleEngine] loaded rule: " << rule.name
|
||||
<< " class_ids=" << rule.class_ids.size()
|
||||
<< " roi=(" << rule.roi.x << "," << rule.roi.y << ","
|
||||
<< rule.roi.w << "," << rule.roi.h << ")"
|
||||
<< " min_duration=" << rule.min_duration_ms << "ms"
|
||||
<< " cooldown=" << rule.cooldown_ms << "ms\n";
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "[RuleEngine] loaded rule: " << rule.name
|
||||
<< " class_ids=" << rule.class_ids.size()
|
||||
<< " roi=(" << rule.roi.x << "," << rule.roi.y << "," << rule.roi.w << "," << rule.roi.h << ")"
|
||||
<< " min_duration=" << rule.min_duration_ms << "ms"
|
||||
<< " cooldown=" << rule.cooldown_ms << "ms";
|
||||
LogInfo(oss.str());
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -140,11 +165,14 @@ bool RuleEngine::IsInSchedule(const std::string& schedule) const {
|
||||
}
|
||||
|
||||
int start_h = 0, start_m = 0, end_h = 0, end_m = 0;
|
||||
std::sscanf(schedule.c_str(), "%d:%d-%d:%d", &start_h, &start_m, &end_h, &end_m);
|
||||
(void)std::sscanf(schedule.c_str(), "%d:%d-%d:%d", &start_h, &start_m, &end_h, &end_m);
|
||||
|
||||
std::time_t now = std::time(nullptr);
|
||||
std::tm* local = std::localtime(&now);
|
||||
int curr_min = local->tm_hour * 60 + local->tm_min;
|
||||
std::tm local{};
|
||||
if (!SafeLocalTime(now, local)) {
|
||||
return true;
|
||||
}
|
||||
int curr_min = local.tm_hour * 60 + local.tm_min;
|
||||
int start_min = start_h * 60 + start_m;
|
||||
int end_min = end_h * 60 + end_m;
|
||||
|
||||
|
||||
@ -2,7 +2,8 @@
|
||||
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
#include "utils/logger.h"
|
||||
|
||||
namespace rk3588 {
|
||||
|
||||
@ -13,11 +14,11 @@ bool LocalUploader::Init(const SimpleJson& config) {
|
||||
try {
|
||||
std::filesystem::create_directories(base_path_);
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "[LocalUploader] failed to create directory: " << e.what() << "\n";
|
||||
LogError(std::string("[LocalUploader] failed to create directory: ") + e.what());
|
||||
return false;
|
||||
}
|
||||
|
||||
std::cout << "[LocalUploader] initialized, path=" << base_path_ << "\n";
|
||||
LogInfo("[LocalUploader] initialized, path=" + base_path_);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -6,12 +6,12 @@
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <mutex>
|
||||
#include <sstream>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include "utils/logger.h"
|
||||
#include "utils/simple_json_writer.h"
|
||||
|
||||
#if __has_include(<curl/curl.h>)
|
||||
@ -325,15 +325,17 @@ bool MinioUploader::Init(const SimpleJson& config) {
|
||||
|
||||
#if HAS_CURL
|
||||
static std::once_flag curl_once;
|
||||
std::call_once(curl_once, [] { curl_global_init(CURL_GLOBAL_DEFAULT); });
|
||||
std::call_once(curl_once, [] {
|
||||
curl_global_init(CURL_GLOBAL_DEFAULT);
|
||||
std::atexit([]() { curl_global_cleanup(); });
|
||||
});
|
||||
#endif
|
||||
|
||||
if (presign_endpoint_.empty() && (access_key_.empty() || secret_key_.empty())) {
|
||||
std::cerr << "[MinioUploader] warning: access_key/secret_key not set; recommended to set presign_endpoint\n";
|
||||
LogWarn("[MinioUploader] access_key/secret_key not set; recommended to set presign_endpoint");
|
||||
}
|
||||
|
||||
std::cout << "[MinioUploader] initialized, endpoint=" << endpoint_
|
||||
<< " bucket=" << bucket_ << "\n";
|
||||
LogInfo("[MinioUploader] initialized, endpoint=" + endpoint_ + " bucket=" + bucket_);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -471,8 +473,8 @@ UploadResult MinioUploader::Upload(const std::string& key,
|
||||
return result;
|
||||
#else
|
||||
// Stub for Windows
|
||||
std::cout << "[MinioUploader] would upload " << size << " bytes as key=" << key
|
||||
<< " (configure presign_endpoint to enable real upload)\n";
|
||||
LogInfo("[MinioUploader] would upload " + std::to_string(size) + " bytes as key=" + key +
|
||||
" (configure presign_endpoint to enable real upload)");
|
||||
result.success = true;
|
||||
result.url = endpoint_ + "/" + bucket_ + "/" + key;
|
||||
#endif
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
#include "local_uploader.h"
|
||||
#include "minio_uploader.h"
|
||||
|
||||
#include <iostream>
|
||||
#include "utils/logger.h"
|
||||
|
||||
namespace rk3588 {
|
||||
|
||||
@ -17,7 +17,7 @@ std::unique_ptr<IUploader> CreateUploader(const SimpleJson& config) {
|
||||
}
|
||||
|
||||
if (uploader && !uploader->Init(config)) {
|
||||
std::cerr << "[CreateUploader] failed to init uploader type=" << type << "\n";
|
||||
LogError("[CreateUploader] failed to init uploader type=" + type);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
@ -4,7 +4,6 @@
|
||||
#include <cstdint>
|
||||
#include <cmath>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <random>
|
||||
@ -14,6 +13,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "node.h"
|
||||
#include "utils/logger.h"
|
||||
|
||||
namespace rk3588 {
|
||||
|
||||
@ -694,18 +694,18 @@ public:
|
||||
std::shared_ptr<const ConfigSnapshot> snap;
|
||||
std::string err;
|
||||
if (!BuildConfigSnapshot(config, snap, err)) {
|
||||
std::cerr << "[det_post] invalid config: " << err << "\n";
|
||||
LogError("[det_post] invalid config: " + err);
|
||||
return false;
|
||||
}
|
||||
id_ = snap->id;
|
||||
|
||||
input_queue_ = ctx.input_queue;
|
||||
if (!input_queue_) {
|
||||
std::cerr << "[det_post] no input queue for node " << id_ << "\n";
|
||||
LogError("[det_post] no input queue for node " + id_);
|
||||
return false;
|
||||
}
|
||||
if (ctx.output_queues.empty()) {
|
||||
std::cerr << "[det_post] no output queue for node " << id_ << "\n";
|
||||
LogError("[det_post] no output queue for node " + id_);
|
||||
return false;
|
||||
}
|
||||
output_queues_ = ctx.output_queues;
|
||||
@ -718,19 +718,19 @@ public:
|
||||
}
|
||||
|
||||
bool Start() override {
|
||||
std::cout << "[det_post] started\n";
|
||||
LogInfo("[det_post] started");
|
||||
return true;
|
||||
}
|
||||
|
||||
void Stop() override {
|
||||
std::cout << "[det_post] stopped\n";
|
||||
LogInfo("[det_post] stopped");
|
||||
}
|
||||
|
||||
bool UpdateConfig(const SimpleJson& new_config) override {
|
||||
std::shared_ptr<const ConfigSnapshot> snap;
|
||||
std::string err;
|
||||
if (!BuildConfigSnapshot(new_config, snap, err)) {
|
||||
std::cerr << "[det_post] UpdateConfig rejected: " << err << "\n";
|
||||
LogWarn("[det_post] UpdateConfig rejected: " + err);
|
||||
return false;
|
||||
}
|
||||
if (!id_.empty() && !snap->id.empty() && snap->id != id_) {
|
||||
|
||||
@ -2,7 +2,6 @@
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
@ -10,6 +9,7 @@
|
||||
|
||||
#include "node.h"
|
||||
#include "utils/thread_affinity.h"
|
||||
#include "utils/logger.h"
|
||||
|
||||
#if defined(RK3588_ENABLE_MPP)
|
||||
extern "C" {
|
||||
@ -50,13 +50,13 @@ public:
|
||||
cpu_affinity_ = ParseCpuAffinity(config);
|
||||
|
||||
if (ctx.output_queues.empty()) {
|
||||
std::cerr << "[input_file] no downstream queue configured for node " << id_ << "\n";
|
||||
LogError("[input_file] no downstream queue configured for node " + id_);
|
||||
return false;
|
||||
}
|
||||
out_queues_ = ctx.output_queues;
|
||||
|
||||
if (path_.empty() && !fallback_to_stub_on_fail_) {
|
||||
std::cerr << "[input_file] path is required\n";
|
||||
LogError("[input_file] path is required");
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -83,23 +83,26 @@ public:
|
||||
}
|
||||
#else
|
||||
if (use_ffmpeg_ || use_mpp_) {
|
||||
std::cerr << "[input_file] requested ffmpeg/mpp but not enabled at build time\n";
|
||||
LogError("[input_file] requested ffmpeg/mpp but not enabled at build time");
|
||||
}
|
||||
worker_ = std::thread(&InputFileNode::LoopStub, this);
|
||||
#endif
|
||||
|
||||
std::cout << "[input_file] start path=" << path_ << " loop=" << (loop_ ? "true" : "false")
|
||||
<< " realtime=" << (realtime_ ? "true" : "false")
|
||||
<< " fps=" << fps_;
|
||||
std::string mode;
|
||||
#if defined(RK3588_ENABLE_MPP)
|
||||
if (use_ffmpeg_ && use_mpp_) std::cout << " (ffmpeg demux + mpp decode)";
|
||||
else if (use_ffmpeg_) std::cout << " (ffmpeg cpu decode)";
|
||||
else std::cout << " (stub)";
|
||||
if (use_ffmpeg_ && use_mpp_) mode = "ffmpeg demux + mpp decode";
|
||||
else if (use_ffmpeg_) mode = "ffmpeg cpu decode";
|
||||
else mode = "stub";
|
||||
#else
|
||||
if (use_ffmpeg_) std::cout << " (ffmpeg cpu decode)";
|
||||
else std::cout << " (stub)";
|
||||
if (use_ffmpeg_) mode = "ffmpeg cpu decode";
|
||||
else mode = "stub";
|
||||
#endif
|
||||
std::cout << "\n";
|
||||
|
||||
LogInfo("[input_file] start path=" + path_ +
|
||||
" loop=" + (loop_ ? std::string("true") : std::string("false")) +
|
||||
" realtime=" + (realtime_ ? std::string("true") : std::string("false")) +
|
||||
" fps=" + std::to_string(fps_) +
|
||||
" (" + mode + ")");
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -107,7 +110,7 @@ public:
|
||||
running_.store(false);
|
||||
for (auto& q : out_queues_) q->Stop();
|
||||
if (worker_.joinable()) worker_.join();
|
||||
std::cout << "[input_file] stopped\n";
|
||||
LogInfo("[input_file] stopped");
|
||||
}
|
||||
|
||||
void Drain() override {
|
||||
@ -119,7 +122,7 @@ private:
|
||||
if (cpu_affinity_.empty()) return;
|
||||
std::string aerr;
|
||||
if (!SetCurrentThreadAffinity(cpu_affinity_, aerr)) {
|
||||
std::cerr << "[input_file] SetCurrentThreadAffinity failed: " << aerr << "\n";
|
||||
LogWarn("[input_file] SetCurrentThreadAffinity failed: " + aerr);
|
||||
}
|
||||
}
|
||||
|
||||
@ -297,7 +300,7 @@ private:
|
||||
|
||||
std::string oerr;
|
||||
if (!OpenFile(fmt_ctx, video_stream, time_base, fps_out, oerr)) {
|
||||
std::cerr << "[input_file] open failed: " << oerr << " path=" << path_ << "\n";
|
||||
LogError("[input_file] open failed: " + oerr + " path=" + path_);
|
||||
Cleanup(fmt_ctx, codec_ctx, pkt, frm);
|
||||
if (fallback_to_stub_on_fail_) {
|
||||
LoopStub();
|
||||
@ -309,7 +312,7 @@ private:
|
||||
|
||||
const AVCodec* codec = avcodec_find_decoder(fmt_ctx->streams[video_stream]->codecpar->codec_id);
|
||||
if (!codec) {
|
||||
std::cerr << "[input_file] decoder not found\n";
|
||||
LogError("[input_file] decoder not found");
|
||||
Cleanup(fmt_ctx, codec_ctx, pkt, frm);
|
||||
running_.store(false);
|
||||
break;
|
||||
@ -317,7 +320,7 @@ private:
|
||||
codec_ctx = avcodec_alloc_context3(codec);
|
||||
avcodec_parameters_to_context(codec_ctx, fmt_ctx->streams[video_stream]->codecpar);
|
||||
if (avcodec_open2(codec_ctx, codec, nullptr) < 0) {
|
||||
std::cerr << "[input_file] avcodec_open2 failed\n";
|
||||
LogError("[input_file] avcodec_open2 failed");
|
||||
Cleanup(fmt_ctx, codec_ctx, pkt, frm);
|
||||
running_.store(false);
|
||||
break;
|
||||
@ -546,7 +549,7 @@ private:
|
||||
|
||||
std::string oerr;
|
||||
if (!OpenFile(fmt_ctx, video_stream, time_base, fps_out, oerr)) {
|
||||
std::cerr << "[input_file] open failed: " << oerr << " path=" << path_ << "\n";
|
||||
LogError("[input_file] open failed: " + oerr + " path=" + path_);
|
||||
Cleanup(fmt_ctx, nullptr, pkt, nullptr);
|
||||
if (fallback_to_stub_on_fail_) {
|
||||
LoopStub();
|
||||
@ -561,7 +564,7 @@ private:
|
||||
if (codec_id == AV_CODEC_ID_H264) coding = MPP_VIDEO_CodingAVC;
|
||||
else if (codec_id == AV_CODEC_ID_HEVC) coding = MPP_VIDEO_CodingHEVC;
|
||||
else {
|
||||
std::cerr << "[input_file] unsupported codec for mpp\n";
|
||||
LogError("[input_file] unsupported codec for mpp");
|
||||
Cleanup(fmt_ctx, nullptr, pkt, nullptr);
|
||||
running_.store(false);
|
||||
break;
|
||||
@ -569,7 +572,7 @@ private:
|
||||
|
||||
MppDecoderWrapper dec;
|
||||
if (!dec.Init(coding)) {
|
||||
std::cerr << "[input_file] mpp init failed\n";
|
||||
LogError("[input_file] mpp init failed");
|
||||
Cleanup(fmt_ctx, nullptr, pkt, nullptr);
|
||||
running_.store(false);
|
||||
break;
|
||||
|
||||
@ -2,7 +2,6 @@
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <cctype>
|
||||
@ -63,7 +62,7 @@ public:
|
||||
}
|
||||
cpu_affinity_ = ParseCpuAffinity(config);
|
||||
if (ctx.output_queues.empty()) {
|
||||
std::cerr << "[input_rtsp] no downstream queue configured for node " << id_ << "\n";
|
||||
LogError("[input_rtsp] no downstream queue configured for node " + id_);
|
||||
return false;
|
||||
}
|
||||
out_queues_ = ctx.output_queues;
|
||||
@ -89,7 +88,7 @@ public:
|
||||
}
|
||||
#else
|
||||
if (use_ffmpeg_ || use_mpp_) {
|
||||
std::cerr << "[input_rtsp] requested ffmpeg/mpp but not enabled at build time" << "\n";
|
||||
LogError("[input_rtsp] requested ffmpeg/mpp but not enabled at build time");
|
||||
}
|
||||
worker_ = std::thread(&InputRtspNode::LoopStub, this);
|
||||
#endif
|
||||
@ -172,7 +171,7 @@ private:
|
||||
if (cpu_affinity_.empty()) return;
|
||||
std::string aerr;
|
||||
if (!SetCurrentThreadAffinity(cpu_affinity_, aerr)) {
|
||||
std::cerr << "[input_rtsp] SetCurrentThreadAffinity failed: " << aerr << "\n";
|
||||
LogWarn("[input_rtsp] SetCurrentThreadAffinity failed: " + aerr);
|
||||
}
|
||||
}
|
||||
|
||||
@ -232,7 +231,7 @@ private:
|
||||
av_dict_set(&opts, "fflags", "nobuffer", 0);
|
||||
av_dict_set(&opts, "flags", "low_delay", 0);
|
||||
if (avformat_open_input(&fmt_ctx, url_.c_str(), nullptr, &opts) < 0) {
|
||||
std::cerr << "[input_rtsp] avformat_open_input failed: " << url_ << "\n";
|
||||
LogError("[input_rtsp] avformat_open_input failed: " + url_);
|
||||
av_dict_free(&opts);
|
||||
Cleanup(fmt_ctx, codec_ctx, pkt, frm);
|
||||
if (fallback_to_stub_on_fail_) {
|
||||
@ -246,7 +245,7 @@ private:
|
||||
av_dict_free(&opts);
|
||||
if (avformat_find_stream_info(fmt_ctx, nullptr) < 0) {
|
||||
// For RTSP, codec parameters are often available from SDP already; keep going.
|
||||
std::cerr << "[input_rtsp] avformat_find_stream_info failed (continuing)\n";
|
||||
LogWarn("[input_rtsp] avformat_find_stream_info failed (continuing)");
|
||||
}
|
||||
for (unsigned i = 0; i < fmt_ctx->nb_streams; ++i) {
|
||||
if (fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
|
||||
@ -256,7 +255,7 @@ private:
|
||||
}
|
||||
}
|
||||
if (video_stream < 0) {
|
||||
std::cerr << "[input_rtsp] no video stream\n";
|
||||
LogError("[input_rtsp] no video stream");
|
||||
Cleanup(fmt_ctx, codec_ctx, pkt, frm);
|
||||
std::this_thread::sleep_for(seconds(backoff));
|
||||
backoff = std::min(backoff_max, backoff * 2);
|
||||
@ -265,7 +264,7 @@ private:
|
||||
|
||||
const AVCodec* codec = avcodec_find_decoder(fmt_ctx->streams[video_stream]->codecpar->codec_id);
|
||||
if (!codec) {
|
||||
std::cerr << "[input_rtsp] decoder not found\n";
|
||||
LogError("[input_rtsp] decoder not found");
|
||||
Cleanup(fmt_ctx, codec_ctx, pkt, frm);
|
||||
std::this_thread::sleep_for(seconds(backoff));
|
||||
backoff = std::min(backoff_max, backoff * 2);
|
||||
@ -274,7 +273,7 @@ private:
|
||||
codec_ctx = avcodec_alloc_context3(codec);
|
||||
avcodec_parameters_to_context(codec_ctx, fmt_ctx->streams[video_stream]->codecpar);
|
||||
if (avcodec_open2(codec_ctx, codec, nullptr) < 0) {
|
||||
std::cerr << "[input_rtsp] avcodec_open2 failed\n";
|
||||
LogError("[input_rtsp] avcodec_open2 failed");
|
||||
Cleanup(fmt_ctx, codec_ctx, pkt, frm);
|
||||
std::this_thread::sleep_for(seconds(backoff));
|
||||
backoff = std::min(backoff_max, backoff * 2);
|
||||
@ -477,7 +476,8 @@ private:
|
||||
MPP_RET ret = mpp_packet_init(&src, const_cast<uint8_t*>(data), size);
|
||||
if (ret != MPP_OK || !src) {
|
||||
if (++fail_copy_init_ <= 3 || fail_copy_init_ % 200 == 0) {
|
||||
std::cerr << "[input_rtsp] mpp_packet_init failed ret=" << ret << " size=" << size << "\n";
|
||||
LogWarn("[input_rtsp] mpp_packet_init failed ret=" + std::to_string(ret) +
|
||||
" size=" + std::to_string(size));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -487,7 +487,8 @@ private:
|
||||
mpp_packet_deinit(&src);
|
||||
if (ret != MPP_OK || !packet) {
|
||||
if (++fail_copy_init_ <= 3 || fail_copy_init_ % 200 == 0) {
|
||||
std::cerr << "[input_rtsp] mpp_packet_copy_init failed ret=" << ret << " size=" << size << "\n";
|
||||
LogWarn("[input_rtsp] mpp_packet_copy_init failed ret=" + std::to_string(ret) +
|
||||
" size=" + std::to_string(size));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -504,7 +505,7 @@ private:
|
||||
if (gr == MPP_ERR_TIMEOUT) return;
|
||||
if (gr != MPP_OK) {
|
||||
if (++fail_get_frame_ <= 3 || fail_get_frame_ % 200 == 0) {
|
||||
std::cerr << "[input_rtsp] decode_get_frame ret=" << gr << "\n";
|
||||
LogWarn("[input_rtsp] decode_get_frame ret=" + std::to_string(gr));
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -543,7 +544,7 @@ private:
|
||||
// Treat as packet drop to keep pipeline progressing; caller can decide to wait for next IDR.
|
||||
if (last_put != MPP_ERR_BUFFER_FULL) {
|
||||
if (++fail_put_packet_ <= 3 || fail_put_packet_ % 200 == 0) {
|
||||
std::cerr << "[input_rtsp] decode_put_packet failed ret=" << last_put << "\n";
|
||||
LogWarn("[input_rtsp] decode_put_packet failed ret=" + std::to_string(last_put));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -553,7 +554,7 @@ private:
|
||||
bool SendExtraData(const uint8_t* data, size_t size) {
|
||||
if (!ctx || !mpi || !data || size == 0) return false;
|
||||
if (!IsAnnexB(data, size)) {
|
||||
std::cerr << "[input_rtsp] extra_data is not AnnexB; mpp may ignore it\n";
|
||||
LogWarn("[input_rtsp] extra_data is not AnnexB; mpp may ignore it");
|
||||
}
|
||||
|
||||
MppPacket src = nullptr;
|
||||
@ -590,7 +591,7 @@ private:
|
||||
usleep(2000);
|
||||
}
|
||||
|
||||
std::cerr << "[input_rtsp] extra_data decode_put_packet timeout\n";
|
||||
LogWarn("[input_rtsp] extra_data decode_put_packet timeout");
|
||||
mpp_packet_deinit(&pkt);
|
||||
return false;
|
||||
}
|
||||
@ -612,7 +613,7 @@ private:
|
||||
!try_group(static_cast<MppBufferType>(MPP_BUFFER_TYPE_DRM)) &&
|
||||
!try_group(static_cast<MppBufferType>(MPP_BUFFER_TYPE_ION | MPP_BUFFER_FLAGS_CACHABLE)) &&
|
||||
!try_group(static_cast<MppBufferType>(MPP_BUFFER_TYPE_ION))) {
|
||||
std::cerr << "[input_rtsp] mpp info_change: failed to alloc frame buffer group\n";
|
||||
LogError("[input_rtsp] mpp info_change: failed to alloc frame buffer group");
|
||||
return;
|
||||
}
|
||||
frame_group = group;
|
||||
@ -658,7 +659,7 @@ private:
|
||||
av_dict_set(&opts, "fflags", "nobuffer", 0);
|
||||
av_dict_set(&opts, "flags", "low_delay", 0);
|
||||
if (avformat_open_input(&fmt_ctx, url_.c_str(), nullptr, &opts) < 0) {
|
||||
std::cerr << "[input_rtsp] avformat_open_input failed: " << url_ << "\n";
|
||||
LogError("[input_rtsp] avformat_open_input failed: " + url_);
|
||||
av_dict_free(&opts);
|
||||
if (bsf_ctx) av_bsf_free(&bsf_ctx);
|
||||
if (filt_pkt) av_packet_free(&filt_pkt);
|
||||
@ -674,7 +675,7 @@ private:
|
||||
av_dict_free(&opts);
|
||||
if (avformat_find_stream_info(fmt_ctx, nullptr) < 0) {
|
||||
// For RTSP, codec parameters are often available from SDP already; keep going.
|
||||
std::cerr << "[input_rtsp] avformat_find_stream_info failed (continuing)\n";
|
||||
LogWarn("[input_rtsp] avformat_find_stream_info failed (continuing)");
|
||||
}
|
||||
for (unsigned i = 0; i < fmt_ctx->nb_streams; ++i) {
|
||||
if (fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
|
||||
@ -684,7 +685,7 @@ private:
|
||||
}
|
||||
}
|
||||
if (video_stream < 0) {
|
||||
std::cerr << "[input_rtsp] no video stream\n";
|
||||
LogError("[input_rtsp] no video stream");
|
||||
if (bsf_ctx) av_bsf_free(&bsf_ctx);
|
||||
if (filt_pkt) av_packet_free(&filt_pkt);
|
||||
Cleanup(fmt_ctx, nullptr, pkt, nullptr);
|
||||
@ -698,7 +699,7 @@ private:
|
||||
if (codec_id == AV_CODEC_ID_H264) coding = MPP_VIDEO_CodingAVC;
|
||||
else if (codec_id == AV_CODEC_ID_HEVC) coding = MPP_VIDEO_CodingHEVC;
|
||||
else {
|
||||
std::cerr << "[input_rtsp] unsupported codec for mpp\n";
|
||||
LogError("[input_rtsp] unsupported codec for mpp");
|
||||
if (bsf_ctx) av_bsf_free(&bsf_ctx);
|
||||
if (filt_pkt) av_packet_free(&filt_pkt);
|
||||
Cleanup(fmt_ctx, nullptr, pkt, nullptr);
|
||||
@ -709,7 +710,7 @@ private:
|
||||
|
||||
MppDecoderWrapper dec;
|
||||
if (!dec.Init(coding)) {
|
||||
std::cerr << "[input_rtsp] mpp init failed\n";
|
||||
LogError("[input_rtsp] mpp init failed");
|
||||
if (bsf_ctx) av_bsf_free(&bsf_ctx);
|
||||
if (filt_pkt) av_packet_free(&filt_pkt);
|
||||
Cleanup(fmt_ctx, nullptr, pkt, nullptr);
|
||||
@ -761,7 +762,7 @@ private:
|
||||
" 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";
|
||||
LogWarn("[input_rtsp] send extra_data failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -800,7 +801,7 @@ private:
|
||||
if (!need_idr && ++decode_fail >= 3) {
|
||||
need_idr = true;
|
||||
announced_wait_idr = false;
|
||||
std::cerr << "[input_rtsp] decoder desync/backpressure; re-sync on next IDR\n";
|
||||
LogWarn("[input_rtsp] decoder desync/backpressure; re-sync on next IDR");
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -866,7 +867,7 @@ private:
|
||||
}
|
||||
}
|
||||
} else {
|
||||
std::cerr << "[input_rtsp] non-AnnexB bitstream but bsf init failed; mpp decode may produce no frames\n";
|
||||
LogWarn("[input_rtsp] non-AnnexB bitstream but bsf init failed; mpp decode may produce no frames");
|
||||
}
|
||||
|
||||
av_packet_unref(pkt);
|
||||
|
||||
@ -3,7 +3,6 @@
|
||||
#include <cstddef>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
@ -371,11 +370,11 @@ public:
|
||||
|
||||
input_queue_ = ctx.input_queue;
|
||||
if (!input_queue_) {
|
||||
std::cerr << "[osd] no input queue for node " << id_ << "\n";
|
||||
LogError("[osd] no input queue for node " + id_);
|
||||
return false;
|
||||
}
|
||||
if (ctx.output_queues.empty()) {
|
||||
std::cerr << "[osd] no output queue for node " << id_ << "\n";
|
||||
LogError("[osd] no output queue for node " + id_);
|
||||
return false;
|
||||
}
|
||||
output_queues_ = ctx.output_queues;
|
||||
|
||||
@ -4,7 +4,6 @@
|
||||
#include <condition_variable>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
@ -59,6 +58,7 @@ int GlobalRgaMaxInflight() {
|
||||
int v = std::stoi(s);
|
||||
if (v > 0 && v <= 32) GlobalRgaMaxInflightRef().store(v);
|
||||
} catch (...) {
|
||||
LogWarn(std::string("[preprocess] invalid RK3588_RGA_MAX_INFLIGHT='") + s + "'");
|
||||
}
|
||||
});
|
||||
int v = GlobalRgaMaxInflightRef().load();
|
||||
@ -148,7 +148,7 @@ void EnsureRgaInitializedOnce() {
|
||||
std::call_once(once, []() {
|
||||
const IM_STATUS st = imcheckHeader();
|
||||
if (st != IM_STATUS_NOERROR && st != IM_STATUS_SUCCESS) {
|
||||
std::cerr << "[preprocess] imcheckHeader failed: " << imStrError(st) << "\n";
|
||||
LogWarn(std::string("[preprocess] imcheckHeader failed: ") + imStrError(st));
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -344,25 +344,25 @@ public:
|
||||
|
||||
input_queue_ = ctx.input_queue;
|
||||
if (!input_queue_) {
|
||||
std::cerr << "[preprocess] no input queue for node " << id_ << "\n";
|
||||
LogError("[preprocess] no input queue for node " + id_);
|
||||
return false;
|
||||
}
|
||||
if (ctx.output_queues.empty()) {
|
||||
std::cerr << "[preprocess] no output queue for node " << id_ << "\n";
|
||||
LogError("[preprocess] no output queue for node " + id_);
|
||||
return false;
|
||||
}
|
||||
output_queues_ = ctx.output_queues;
|
||||
|
||||
#if !defined(RK3588_ENABLE_RGA)
|
||||
if (requested_use_rga) {
|
||||
std::cerr << "[preprocess] use_rga=true but RGA not enabled at build time\n";
|
||||
LogError("[preprocess] use_rga=true but RGA not enabled at build time");
|
||||
return false;
|
||||
}
|
||||
use_rga_ = false;
|
||||
#endif
|
||||
#if !defined(RK3588_ENABLE_FFMPEG)
|
||||
if (!use_rga_) {
|
||||
std::cerr << "[preprocess] neither RGA nor FFmpeg enabled\n";
|
||||
LogError("[preprocess] neither RGA nor FFmpeg enabled");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
@ -507,20 +507,20 @@ private:
|
||||
int dst_hstride = Align16(out_h);
|
||||
|
||||
if (src_fmt_rga == RK_FORMAT_UNKNOWN || dst_fmt_rga == RK_FORMAT_UNKNOWN) {
|
||||
std::cerr << "[preprocess] unsupported format for RGA\n";
|
||||
LogError("[preprocess] unsupported format for RGA");
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t out_size = CalcImageSizeStrided(dst_wstride, dst_hstride, out_fmt);
|
||||
if (out_size == 0) {
|
||||
std::cerr << "[preprocess] invalid output size for RGA\n";
|
||||
LogError("[preprocess] invalid output size for RGA");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Use DMA-BUF allocation to avoid >4GB address issue with RGA
|
||||
auto dma_buf = DmaAlloc(out_size);
|
||||
if (!dma_buf || !dma_buf->valid()) {
|
||||
std::cerr << "[preprocess] DMA alloc failed\n";
|
||||
LogError("[preprocess] DMA alloc failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -588,7 +588,7 @@ private:
|
||||
// If there's no DMA fd, we must allocate/copy into a DMA-BUF for RGA.
|
||||
if (frame->dma_fd < 0) {
|
||||
if (!CopySrcToDmaIfPossible()) {
|
||||
std::cerr << "[preprocess] no dma_fd and src copy failed\n";
|
||||
LogError("[preprocess] no dma_fd and src copy failed");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -674,7 +674,7 @@ private:
|
||||
|
||||
const int src_fd = (src_dma_buf && src_dma_buf->valid()) ? src_dma_buf->fd : frame->dma_fd;
|
||||
if (src_fd < 0 || !RunRgaOnce(src_fd, rga_err)) {
|
||||
std::cerr << "[preprocess] " << (rga_err.empty() ? "RGA failed" : rga_err) << "\n";
|
||||
LogError(std::string("[preprocess] ") + (rga_err.empty() ? "RGA failed" : rga_err));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@ -6,7 +6,6 @@
|
||||
#include <cstring>
|
||||
#include <filesystem>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
@ -194,7 +193,7 @@ private:
|
||||
if (!warned_) {
|
||||
char errbuf[128];
|
||||
av_strerror(ret, errbuf, sizeof(errbuf));
|
||||
std::cerr << "[publish] write failed for " << url_ << ": " << errbuf << ", resetting...\n";
|
||||
LogWarn(std::string("[publish] write failed for ") + url_ + ": " + errbuf + ", resetting...");
|
||||
warned_ = true;
|
||||
}
|
||||
return false;
|
||||
@ -216,7 +215,7 @@ private:
|
||||
AVFormatContext* fmt = nullptr;
|
||||
const char* fmt_name = proto_ == "hls" ? "hls" : "rtsp";
|
||||
if (avformat_alloc_output_context2(&fmt, nullptr, fmt_name, url_.c_str()) < 0 || !fmt) {
|
||||
std::cerr << "[publish] alloc context failed " << url_ << "\n";
|
||||
LogError("[publish] alloc context failed " + url_);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -370,7 +369,7 @@ public:
|
||||
} else if (src.format == PixelFormat::YUV420) {
|
||||
mpp_fmt_ = MPP_FMT_YUV420P;
|
||||
} else {
|
||||
std::cerr << "[publish] unsupported pixel format for mpp encoder\n";
|
||||
LogError("[publish] unsupported pixel format for mpp encoder");
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -381,20 +380,20 @@ public:
|
||||
}
|
||||
|
||||
if (mpp_create(&ctx_, &mpi_) != MPP_OK) {
|
||||
std::cerr << "[publish] mpp_create failed\n";
|
||||
LogError("[publish] mpp_create failed");
|
||||
return false;
|
||||
}
|
||||
if (mpp_init(ctx_, MPP_CTX_ENC, coding_) != MPP_OK) {
|
||||
std::cerr << "[publish] mpp_init enc failed\n";
|
||||
LogError("[publish] mpp_init enc failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mpp_enc_cfg_init(&cfg_) != MPP_OK) {
|
||||
std::cerr << "[publish] mpp_enc_cfg_init failed\n";
|
||||
LogError("[publish] mpp_enc_cfg_init failed");
|
||||
return false;
|
||||
}
|
||||
if (mpi_->control(ctx_, MPP_ENC_GET_CFG, cfg_) != MPP_OK) {
|
||||
std::cerr << "[publish] MPP_ENC_GET_CFG failed\n";
|
||||
LogError("[publish] MPP_ENC_GET_CFG failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -416,7 +415,7 @@ public:
|
||||
mpp_enc_cfg_set_s32(cfg_, "codec:type", coding_);
|
||||
|
||||
if (mpi_->control(ctx_, MPP_ENC_SET_CFG, cfg_) != MPP_OK) {
|
||||
std::cerr << "[publish] MPP_ENC_SET_CFG failed\n";
|
||||
LogError("[publish] MPP_ENC_SET_CFG failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -424,7 +423,7 @@ public:
|
||||
if (coding_ == MPP_VIDEO_CodingAVC || coding_ == MPP_VIDEO_CodingHEVC) {
|
||||
MppEncHeaderMode header_mode = MPP_ENC_HEADER_MODE_EACH_IDR;
|
||||
if (mpi_->control(ctx_, MPP_ENC_SET_HEADER_MODE, &header_mode) != MPP_OK) {
|
||||
std::cerr << "[publish] MPP_ENC_SET_HEADER_MODE failed\n";
|
||||
LogWarn("[publish] MPP_ENC_SET_HEADER_MODE failed");
|
||||
}
|
||||
}
|
||||
|
||||
@ -441,7 +440,7 @@ public:
|
||||
|
||||
if (mpp_buffer_group_get_internal(&frm_grp_, MPP_BUFFER_TYPE_DRM, NULL) != MPP_OK) {
|
||||
if (mpp_buffer_group_get_internal(&frm_grp_, MPP_BUFFER_TYPE_NORMAL, NULL) != MPP_OK) {
|
||||
std::cerr << "[publish] mpp_buffer_group_get_internal failed\n";
|
||||
LogError("[publish] mpp_buffer_group_get_internal failed");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -685,7 +684,7 @@ public:
|
||||
#endif
|
||||
|
||||
if (!input_queue_) {
|
||||
std::cerr << "[publish] no input queue for node " << id_ << "\n";
|
||||
LogError("[publish] no input queue for node " + id_);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -874,7 +873,7 @@ private:
|
||||
EnsureZlmEnv();
|
||||
|
||||
if (!StartRtspServerOnce(port)) {
|
||||
std::cerr << "[publish] zlm rtsp server start failed on port " << port << "\n";
|
||||
LogError("[publish] zlm rtsp server start failed on port " + std::to_string(port));
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -887,13 +886,13 @@ private:
|
||||
|
||||
media_ = mk_media_create("__defaultVhost__", app_.c_str(), stream_.c_str(), 0, 0, 0);
|
||||
if (!media_) {
|
||||
std::cerr << "[publish] zlm mk_media_create failed app=" << app_ << " stream=" << stream_ << "\n";
|
||||
LogError("[publish] zlm mk_media_create failed app=" + app_ + " stream=" + stream_);
|
||||
return false;
|
||||
}
|
||||
|
||||
int ok = mk_media_init_video(media_, codec_id, width, height, static_cast<float>(fps), bitrate_kbps * 1000);
|
||||
if (!ok) {
|
||||
std::cerr << "[publish] zlm mk_media_init_video failed" << "\n";
|
||||
LogError("[publish] zlm mk_media_init_video failed");
|
||||
mk_media_release(media_);
|
||||
media_ = nullptr;
|
||||
return false;
|
||||
@ -903,7 +902,7 @@ private:
|
||||
is_h265_ = (codec_id == 1);
|
||||
splitter_ = mk_h264_splitter_create(&OnSplitFrame, this);
|
||||
if (!splitter_) {
|
||||
std::cerr << "[publish] zlm mk_h264_splitter_create failed" << "\n";
|
||||
LogError("[publish] zlm mk_h264_splitter_create failed");
|
||||
mk_media_release(media_);
|
||||
media_ = nullptr;
|
||||
return false;
|
||||
@ -1232,7 +1231,7 @@ private:
|
||||
|
||||
if (!encoder_ready_) {
|
||||
if (!mpp_encoder_->InitFromFrame(*frame, codec_, fps_, gop_, bitrate_kbps_)) {
|
||||
std::cerr << "[publish] encoder init failed, fallback to stub\n";
|
||||
LogWarn("[publish] encoder init failed, fallback to stub");
|
||||
use_mpp_ = false;
|
||||
ProcessStub(frame);
|
||||
return;
|
||||
|
||||
@ -6,12 +6,13 @@
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
|
||||
#include "utils/logger.h"
|
||||
|
||||
#include "node.h"
|
||||
#include "media/encoded_video_meta.h"
|
||||
|
||||
@ -156,22 +157,40 @@ static std::vector<uint8_t> AnnexBToLengthPrefixed(const uint8_t* d, size_t n) {
|
||||
}
|
||||
#endif
|
||||
|
||||
bool SafeLocalTime(std::time_t t, std::tm& out) {
|
||||
#if defined(_WIN32)
|
||||
return localtime_s(&out, &t) == 0;
|
||||
#elif defined(__unix__) || defined(__APPLE__)
|
||||
return localtime_r(&t, &out) != nullptr;
|
||||
#else
|
||||
static std::mutex mu;
|
||||
std::lock_guard<std::mutex> lock(mu);
|
||||
std::tm* p = std::localtime(&t);
|
||||
if (!p) return false;
|
||||
out = *p;
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string FormatTime(const std::string& pattern) {
|
||||
auto now = std::chrono::system_clock::now();
|
||||
auto time_t_now = std::chrono::system_clock::to_time_t(now);
|
||||
std::tm* tm = std::localtime(&time_t_now);
|
||||
std::tm tm{};
|
||||
if (!SafeLocalTime(time_t_now, tm)) {
|
||||
LogWarn("[storage] localtime failed while formatting filename");
|
||||
}
|
||||
|
||||
std::ostringstream oss;
|
||||
for (size_t i = 0; i < pattern.size(); ++i) {
|
||||
if (pattern[i] == '%' && i + 1 < pattern.size()) {
|
||||
char spec = pattern[++i];
|
||||
switch (spec) {
|
||||
case 'Y': oss << std::put_time(tm, "%Y"); break;
|
||||
case 'm': oss << std::put_time(tm, "%m"); break;
|
||||
case 'd': oss << std::put_time(tm, "%d"); break;
|
||||
case 'H': oss << std::put_time(tm, "%H"); break;
|
||||
case 'M': oss << std::put_time(tm, "%M"); break;
|
||||
case 'S': oss << std::put_time(tm, "%S"); break;
|
||||
case 'Y': oss << std::put_time(&tm, "%Y"); break;
|
||||
case 'm': oss << std::put_time(&tm, "%m"); break;
|
||||
case 'd': oss << std::put_time(&tm, "%d"); break;
|
||||
case 'H': oss << std::put_time(&tm, "%H"); break;
|
||||
case 'M': oss << std::put_time(&tm, "%M"); break;
|
||||
case 'S': oss << std::put_time(&tm, "%S"); break;
|
||||
default: oss << '%' << spec; break;
|
||||
}
|
||||
} else {
|
||||
@ -201,7 +220,7 @@ public:
|
||||
} else if (fmt == PixelFormat::YUV420) {
|
||||
mpp_fmt_ = MPP_FMT_YUV420P;
|
||||
} else {
|
||||
std::cerr << "[storage] unsupported pixel format for MPP encoder\n";
|
||||
LogError("[storage] unsupported pixel format for MPP encoder");
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -382,31 +401,32 @@ public:
|
||||
|
||||
input_queue_ = ctx.input_queue;
|
||||
if (!input_queue_) {
|
||||
std::cerr << "[storage] no input queue\n";
|
||||
LogError("[storage] no input queue");
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
std::filesystem::create_directories(base_path_);
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "[storage] failed to create directory: " << e.what() << "\n";
|
||||
LogError(std::string("[storage] failed to create directory: ") + e.what());
|
||||
return false;
|
||||
}
|
||||
|
||||
std::cout << "[storage] initialized, path=" << base_path_
|
||||
<< " segment=" << segment_sec_ << "s format=" << format_ << "\n";
|
||||
LogInfo("[storage] initialized, path=" + base_path_ +
|
||||
" segment=" + std::to_string(segment_sec_) +
|
||||
"s format=" + format_);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Start() override {
|
||||
std::cout << "[storage] started\n";
|
||||
LogInfo("[storage] started");
|
||||
return true;
|
||||
}
|
||||
|
||||
void Stop() override {
|
||||
if (input_queue_) input_queue_->Stop();
|
||||
CloseCurrentFile();
|
||||
std::cout << "[storage] stopped, recorded " << total_frames_ << " frames\n";
|
||||
LogInfo("[storage] stopped, recorded " + std::to_string(total_frames_) + " frames");
|
||||
}
|
||||
|
||||
void Drain() override {
|
||||
@ -442,7 +462,11 @@ public:
|
||||
|
||||
try {
|
||||
std::filesystem::create_directories(base_path_);
|
||||
} catch (const std::exception& e) {
|
||||
LogWarn(std::string("[storage] create_directories failed during UpdateConfig: ") + e.what());
|
||||
return false;
|
||||
} catch (...) {
|
||||
LogWarn("[storage] create_directories failed during UpdateConfig: unknown error");
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -501,12 +525,16 @@ private:
|
||||
if (p.has_parent_path()) {
|
||||
std::filesystem::create_directories(p.parent_path());
|
||||
}
|
||||
} catch (...) {}
|
||||
} catch (const std::exception& e) {
|
||||
LogWarn(std::string("[storage] failed to create directories for segment: ") + e.what());
|
||||
} catch (...) {
|
||||
LogWarn("[storage] failed to create directories for segment: unknown error");
|
||||
}
|
||||
|
||||
const char* fmt_name = format_ == "ts" ? "mpegts" : "mp4";
|
||||
if (avformat_alloc_output_context2(&fmt_ctx_, nullptr, fmt_name,
|
||||
current_path_.c_str()) < 0) {
|
||||
std::cerr << "[storage] failed to create output context\n";
|
||||
LogError("[storage] failed to create output context");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -600,9 +628,9 @@ private:
|
||||
file_open_ = true;
|
||||
segment_start_ = std::chrono::steady_clock::now();
|
||||
segment_frames_ = 0;
|
||||
std::cout << "[storage] opened: " << current_path_ << "\n";
|
||||
LogInfo("[storage] opened: " + current_path_);
|
||||
#else
|
||||
std::cerr << "[storage] FFmpeg not enabled\n";
|
||||
LogError("[storage] FFmpeg not enabled");
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -700,8 +728,7 @@ private:
|
||||
segment_base_pts_ms_ = 0;
|
||||
last_pts90k_ = -1;
|
||||
|
||||
std::cout << "[storage] closed: " << current_path_
|
||||
<< " (" << segment_frames_ << " frames)\n";
|
||||
LogInfo("[storage] closed: " + current_path_ + " (" + std::to_string(segment_frames_) + " frames)");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@ -3,11 +3,11 @@
|
||||
#include <cctype>
|
||||
#include <cstring>
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
|
||||
#include "node.h"
|
||||
#include "utils/logger.h"
|
||||
|
||||
#if defined(RK3588_ENABLE_ZLMEDIAKIT)
|
||||
extern "C" {
|
||||
@ -189,7 +189,7 @@ public:
|
||||
|
||||
#if !defined(RK3588_ENABLE_ZLMEDIAKIT)
|
||||
(void)config;
|
||||
std::cerr << "[zlm_http] RK3588_ENABLE_ZLMEDIAKIT is OFF at build time\n";
|
||||
LogError("[zlm_http] RK3588_ENABLE_ZLMEDIAKIT is OFF at build time");
|
||||
return false;
|
||||
#else
|
||||
root_ = config.ValueOr<std::string>("root", "");
|
||||
@ -199,7 +199,7 @@ public:
|
||||
ssl_ = config.ValueOr<bool>("ssl", false);
|
||||
|
||||
if (root_.empty()) {
|
||||
std::cerr << "[zlm_http] missing config: root (or path)\n";
|
||||
LogError("[zlm_http] missing config: root (or path)");
|
||||
return false;
|
||||
}
|
||||
if (prefix_.empty()) prefix_ = "/";
|
||||
@ -224,11 +224,11 @@ public:
|
||||
|
||||
auto actual = StartHttpServerOnce(port_, ssl_);
|
||||
if (actual == 0) {
|
||||
std::cerr << "[zlm_http] failed to start HTTP server on port " << port_ << "\n";
|
||||
LogError("[zlm_http] failed to start HTTP server on port " + std::to_string(port_));
|
||||
return false;
|
||||
}
|
||||
std::cout << "[zlm_http] http file server started, port=" << actual
|
||||
<< " root=" << root_ << " prefix=" << prefix_ << "\n";
|
||||
LogInfo("[zlm_http] http file server started, port=" + std::to_string(actual) +
|
||||
" root=" + root_ + " prefix=" + prefix_);
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user