修复功能bug,对齐prd
This commit is contained in:
parent
7fe7b34f6c
commit
a12f91da63
5
.github/workflows/build.yml
vendored
5
.github/workflows/build.yml
vendored
@ -2,9 +2,10 @@ name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
branches: [ master, main ]
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
branches: [ master, main ]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
host-build:
|
||||
|
||||
@ -54,7 +54,7 @@ struct Frame {
|
||||
int stride = 0;
|
||||
|
||||
int dma_fd = -1;
|
||||
uint64_t pts = 0;
|
||||
uint64_t pts = 0; // microseconds
|
||||
uint64_t frame_id = 0;
|
||||
|
||||
uint8_t* data = nullptr; // base pointer if mapped to CPU
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
|
||||
#include <chrono>
|
||||
#include <cstddef>
|
||||
#include <cctype>
|
||||
#include <deque>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
@ -14,6 +15,37 @@ namespace rk3588 {
|
||||
|
||||
enum class LogLevel { Debug, Info, Warn, Error };
|
||||
|
||||
inline const char* LogLevelToString(LogLevel lvl) {
|
||||
switch (lvl) {
|
||||
case LogLevel::Debug: return "debug";
|
||||
case LogLevel::Info: return "info";
|
||||
case LogLevel::Warn: return "warn";
|
||||
case LogLevel::Error: return "error";
|
||||
}
|
||||
return "info";
|
||||
}
|
||||
|
||||
inline bool ParseLogLevel(std::string s, LogLevel& out) {
|
||||
for (char& c : s) c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
|
||||
if (s == "debug" || s == "d") {
|
||||
out = LogLevel::Debug;
|
||||
return true;
|
||||
}
|
||||
if (s == "info" || s == "i") {
|
||||
out = LogLevel::Info;
|
||||
return true;
|
||||
}
|
||||
if (s == "warn" || s == "warning" || s == "w") {
|
||||
out = LogLevel::Warn;
|
||||
return true;
|
||||
}
|
||||
if (s == "error" || s == "e") {
|
||||
out = LogLevel::Error;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
class Logger {
|
||||
public:
|
||||
static Logger& Instance() {
|
||||
@ -27,7 +59,21 @@ public:
|
||||
TrimLocked();
|
||||
}
|
||||
|
||||
void SetLevel(LogLevel lvl) {
|
||||
std::lock_guard<std::mutex> lock(mu_);
|
||||
min_level_ = lvl;
|
||||
}
|
||||
|
||||
LogLevel GetLevel() const {
|
||||
std::lock_guard<std::mutex> lock(mu_);
|
||||
return min_level_;
|
||||
}
|
||||
|
||||
void Log(LogLevel lvl, const std::string& msg) {
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mu_);
|
||||
if (static_cast<int>(lvl) < static_cast<int>(min_level_)) return;
|
||||
}
|
||||
const std::string line = FormatLine(lvl, msg);
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mu_);
|
||||
@ -89,6 +135,7 @@ private:
|
||||
mutable std::mutex mu_;
|
||||
std::deque<std::string> lines_;
|
||||
size_t max_lines_ = 2000;
|
||||
LogLevel min_level_ = LogLevel::Info;
|
||||
};
|
||||
|
||||
inline void LogDebug(const std::string& msg) { Logger::Instance().Log(LogLevel::Debug, msg); }
|
||||
|
||||
@ -3,8 +3,8 @@
|
||||
#include <chrono>
|
||||
#include <condition_variable>
|
||||
#include <cstddef>
|
||||
#include <deque>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
|
||||
namespace rk3588 {
|
||||
@ -28,14 +28,18 @@ public:
|
||||
};
|
||||
|
||||
SpscQueue(size_t capacity, QueueDropStrategy strategy)
|
||||
: capacity_(capacity), strategy_(strategy) {}
|
||||
: capacity_(capacity == 0 ? 1 : capacity), strategy_(strategy) {
|
||||
buf_.resize(capacity_);
|
||||
}
|
||||
|
||||
bool Push(T item) {
|
||||
std::unique_lock<std::mutex> lock(mu_);
|
||||
if (stop_) return false;
|
||||
if (queue_.size() >= capacity_) {
|
||||
if (size_ >= capacity_) {
|
||||
if (strategy_ == QueueDropStrategy::DropOldest) {
|
||||
queue_.pop_front();
|
||||
// Drop the oldest item.
|
||||
head_ = (head_ + 1) % capacity_;
|
||||
--size_;
|
||||
++dropped_;
|
||||
} else if (strategy_ == QueueDropStrategy::DropNewest) {
|
||||
// Drop the incoming item.
|
||||
@ -43,11 +47,13 @@ public:
|
||||
return true;
|
||||
} else {
|
||||
// Block until space is available
|
||||
space_cv_.wait(lock, [&] { return queue_.size() < capacity_ || stop_; });
|
||||
space_cv_.wait(lock, [&] { return size_ < capacity_ || stop_; });
|
||||
if (stop_) return false;
|
||||
}
|
||||
}
|
||||
queue_.push_back(std::move(item));
|
||||
buf_[tail_] = std::move(item);
|
||||
tail_ = (tail_ + 1) % capacity_;
|
||||
++size_;
|
||||
++pushed_;
|
||||
data_cv_.notify_one();
|
||||
return true;
|
||||
@ -55,12 +61,13 @@ public:
|
||||
|
||||
bool Pop(T& out, std::chrono::milliseconds timeout) {
|
||||
std::unique_lock<std::mutex> lock(mu_);
|
||||
if (!data_cv_.wait_for(lock, timeout, [&] { return !queue_.empty() || stop_; })) {
|
||||
if (!data_cv_.wait_for(lock, timeout, [&] { return size_ > 0 || stop_; })) {
|
||||
return false;
|
||||
}
|
||||
if (queue_.empty()) return false;
|
||||
out = std::move(queue_.front());
|
||||
queue_.pop_front();
|
||||
if (size_ == 0) return false;
|
||||
out = std::move(buf_[head_]);
|
||||
head_ = (head_ + 1) % capacity_;
|
||||
--size_;
|
||||
++popped_;
|
||||
space_cv_.notify_one();
|
||||
return true;
|
||||
@ -80,7 +87,7 @@ public:
|
||||
|
||||
size_t Size() const {
|
||||
std::lock_guard<std::mutex> lock(mu_);
|
||||
return queue_.size();
|
||||
return size_;
|
||||
}
|
||||
|
||||
size_t Capacity() const { return capacity_; }
|
||||
@ -103,7 +110,7 @@ public:
|
||||
Stats GetStats() const {
|
||||
std::lock_guard<std::mutex> lock(mu_);
|
||||
Stats s;
|
||||
s.size = queue_.size();
|
||||
s.size = size_;
|
||||
s.capacity = capacity_;
|
||||
s.dropped = dropped_;
|
||||
s.pushed = pushed_;
|
||||
@ -118,7 +125,10 @@ private:
|
||||
mutable std::mutex mu_;
|
||||
std::condition_variable data_cv_;
|
||||
std::condition_variable space_cv_;
|
||||
std::deque<T> queue_;
|
||||
std::vector<T> buf_;
|
||||
size_t head_ = 0;
|
||||
size_t tail_ = 0;
|
||||
size_t size_ = 0;
|
||||
bool stop_ = false;
|
||||
size_t dropped_ = 0;
|
||||
size_t pushed_ = 0;
|
||||
|
||||
@ -148,19 +148,55 @@ std::vector<uint8_t> SnapshotAction::EncodeJpeg(const std::shared_ptr<Frame>& fr
|
||||
uint8_t* src_data[4] = {nullptr};
|
||||
int src_linesize[4] = {0};
|
||||
|
||||
auto plane_ptr = [&](int idx) -> uint8_t* {
|
||||
if (idx < 0 || idx >= frame->plane_count) return nullptr;
|
||||
if (frame->planes[idx].data) return frame->planes[idx].data;
|
||||
if (!frame->data) return nullptr;
|
||||
const int off = frame->planes[idx].offset;
|
||||
if (off < 0 || static_cast<size_t>(off) >= frame->data_size) return nullptr;
|
||||
return frame->data + off;
|
||||
};
|
||||
auto plane_stride = [&](int idx, int fallback) -> int {
|
||||
if (idx >= 0 && idx < frame->plane_count && frame->planes[idx].stride > 0) {
|
||||
return frame->planes[idx].stride;
|
||||
}
|
||||
if (frame->stride > 0) return frame->stride;
|
||||
return fallback;
|
||||
};
|
||||
auto validate_bounds = [&](uint8_t* ptr, int stride, int h) -> bool {
|
||||
if (!frame->data || frame->data_size == 0) return true;
|
||||
if (!ptr || stride <= 0 || h <= 0) return false;
|
||||
const uint8_t* base = frame->data;
|
||||
const uint8_t* end = base + frame->data_size;
|
||||
if (ptr < base || ptr >= end) return true; // Unknown ownership; cannot validate.
|
||||
const size_t off = static_cast<size_t>(ptr - base);
|
||||
const size_t need = off + static_cast<size_t>(stride) * static_cast<size_t>(h);
|
||||
return need <= frame->data_size;
|
||||
};
|
||||
|
||||
if (frame->format == PixelFormat::RGB || frame->format == PixelFormat::BGR) {
|
||||
src_data[0] = frame->data;
|
||||
src_linesize[0] = frame->width * 3;
|
||||
src_data[0] = plane_ptr(0) ? plane_ptr(0) : frame->data;
|
||||
src_linesize[0] = plane_stride(0, frame->width * 3);
|
||||
if (!validate_bounds(src_data[0], src_linesize[0], frame->height)) {
|
||||
sws_freeContext(sws);
|
||||
av_frame_free(&av_frame);
|
||||
avcodec_free_context(&ctx);
|
||||
std::cerr << "[SnapshotAction] invalid RGB buffer size/stride (data_size=" << frame->data_size
|
||||
<< ", stride=" << src_linesize[0] << ", h=" << frame->height << ")\n";
|
||||
return output;
|
||||
}
|
||||
} else if (frame->format == PixelFormat::NV12) {
|
||||
src_data[0] = frame->planes[0].data ? frame->planes[0].data : frame->data;
|
||||
src_data[1] = frame->planes[1].data ? frame->planes[1].data
|
||||
: frame->data + frame->width * frame->height;
|
||||
src_data[0] = plane_ptr(0) ? plane_ptr(0) : frame->data;
|
||||
src_data[1] = plane_ptr(1);
|
||||
if (!src_data[1] && frame->data) {
|
||||
src_data[1] = frame->data + static_cast<size_t>(frame->width) * frame->height;
|
||||
}
|
||||
src_linesize[0] = frame->planes[0].stride > 0 ? frame->planes[0].stride : frame->width;
|
||||
src_linesize[1] = frame->planes[1].stride > 0 ? frame->planes[1].stride : frame->width;
|
||||
} else if (frame->format == PixelFormat::YUV420) {
|
||||
src_data[0] = frame->planes[0].data ? frame->planes[0].data : frame->data;
|
||||
src_data[1] = frame->planes[1].data;
|
||||
src_data[2] = frame->planes[2].data;
|
||||
src_data[0] = plane_ptr(0) ? plane_ptr(0) : frame->data;
|
||||
src_data[1] = plane_ptr(1);
|
||||
src_data[2] = plane_ptr(2);
|
||||
src_linesize[0] = frame->planes[0].stride > 0 ? frame->planes[0].stride : frame->width;
|
||||
src_linesize[1] = frame->planes[1].stride > 0 ? frame->planes[1].stride : frame->width / 2;
|
||||
src_linesize[2] = frame->planes[2].stride > 0 ? frame->planes[2].stride : frame->width / 2;
|
||||
|
||||
@ -160,7 +160,7 @@ private:
|
||||
static_cast<int>(y_size)};
|
||||
|
||||
frame->frame_id = ++frame_id_;
|
||||
frame->pts = duration_cast<milliseconds>(steady_clock::now().time_since_epoch()).count();
|
||||
frame->pts = duration_cast<microseconds>(steady_clock::now().time_since_epoch()).count();
|
||||
PushToDownstream(frame);
|
||||
|
||||
if (realtime_ && interval.count() > 0) {
|
||||
@ -263,7 +263,7 @@ private:
|
||||
const int64_t best_pts = f.pts;
|
||||
frame->pts = best_pts == AV_NOPTS_VALUE
|
||||
? 0
|
||||
: static_cast<uint64_t>(av_rescale_q(best_pts, time_base, {1, 1000}));
|
||||
: static_cast<uint64_t>(av_rescale_q(best_pts, time_base, {1, 1000000}));
|
||||
|
||||
if (fmt == PixelFormat::NV12 && plane_count == 2) {
|
||||
int y_size = width * height;
|
||||
@ -396,7 +396,7 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
bool Decode(const uint8_t* data, size_t size, bool eos, int64_t pts_ms,
|
||||
bool Decode(const uint8_t* data, size_t size, bool eos, int64_t pts_us,
|
||||
const std::function<void(MppFrame)>& on_frame) {
|
||||
if (!ctx || !mpi || !data || size == 0) return false;
|
||||
|
||||
@ -408,7 +408,7 @@ private:
|
||||
mpp_packet_set_size(packet, size);
|
||||
mpp_packet_set_pos(packet, pkt_data);
|
||||
mpp_packet_set_length(packet, size);
|
||||
mpp_packet_set_pts(packet, pts_ms);
|
||||
mpp_packet_set_pts(packet, pts_us);
|
||||
if (eos) mpp_packet_set_eos(packet);
|
||||
|
||||
bool pkt_done = false;
|
||||
@ -586,9 +586,9 @@ private:
|
||||
av_packet_unref(pkt);
|
||||
continue;
|
||||
}
|
||||
int64_t pts_ms = pkt->pts == AV_NOPTS_VALUE ? 0
|
||||
: av_rescale_q(pkt->pts, time_base, {1, 1000});
|
||||
dec.Decode(pkt->data, pkt->size, false, pts_ms,
|
||||
int64_t pts_us = pkt->pts == AV_NOPTS_VALUE ? 0
|
||||
: av_rescale_q(pkt->pts, time_base, {1, 1000000});
|
||||
dec.Decode(pkt->data, pkt->size, false, pts_us,
|
||||
[&](MppFrame frm) {
|
||||
PushFrameFromMpp(frm);
|
||||
if (realtime_ && interval.count() > 0) {
|
||||
|
||||
@ -130,7 +130,7 @@ private:
|
||||
frame->planes[0] = {nullptr, width_, width_ * height_, 0};
|
||||
frame->planes[1] = {nullptr, width_, width_ * height_ / 2, width_ * height_};
|
||||
frame->frame_id = ++frame_id_;
|
||||
frame->pts = duration_cast<milliseconds>(steady_clock::now().time_since_epoch()).count();
|
||||
frame->pts = duration_cast<microseconds>(steady_clock::now().time_since_epoch()).count();
|
||||
PushToDownstream(frame);
|
||||
|
||||
if (frame_id_ % 100 == 0) {
|
||||
@ -275,7 +275,7 @@ private:
|
||||
frame->frame_id = ++frame_id_;
|
||||
auto best_pts = f.pts; // av_frame_get_best_effort_timestamp is deprecated
|
||||
frame->pts = best_pts == AV_NOPTS_VALUE ? 0
|
||||
: static_cast<uint64_t>(av_rescale_q(best_pts, time_base, {1, 1000}));
|
||||
: static_cast<uint64_t>(av_rescale_q(best_pts, time_base, {1, 1000000}));
|
||||
frame->data_owner = buffer;
|
||||
|
||||
if (fmt == PixelFormat::NV12 && plane_count == 2) {
|
||||
@ -345,7 +345,7 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
bool Decode(const uint8_t* data, size_t size, bool eos, int64_t pts_ms,
|
||||
bool Decode(const uint8_t* data, size_t size, bool eos, int64_t pts_us,
|
||||
const std::function<void(MppFrame)>& on_frame) {
|
||||
if (!ctx || !mpi || !data || size == 0) return false;
|
||||
|
||||
@ -357,7 +357,7 @@ private:
|
||||
mpp_packet_set_size(packet, size);
|
||||
mpp_packet_set_pos(packet, pkt_data);
|
||||
mpp_packet_set_length(packet, size);
|
||||
mpp_packet_set_pts(packet, pts_ms);
|
||||
mpp_packet_set_pts(packet, pts_us);
|
||||
if (eos) mpp_packet_set_eos(packet);
|
||||
|
||||
bool pkt_done = false;
|
||||
@ -504,9 +504,9 @@ private:
|
||||
av_packet_unref(pkt);
|
||||
continue;
|
||||
}
|
||||
int64_t pts_ms = pkt->pts == AV_NOPTS_VALUE ? 0
|
||||
: av_rescale_q(pkt->pts, time_base, {1, 1000});
|
||||
dec.Decode(pkt->data, pkt->size, false, pts_ms,
|
||||
int64_t pts_us = pkt->pts == AV_NOPTS_VALUE ? 0
|
||||
: av_rescale_q(pkt->pts, time_base, {1, 1000000});
|
||||
dec.Decode(pkt->data, pkt->size, false, pts_us,
|
||||
[&](MppFrame frm) { PushFrameFromMpp(frm); });
|
||||
av_packet_unref(pkt);
|
||||
}
|
||||
|
||||
@ -518,8 +518,8 @@ public:
|
||||
}
|
||||
}
|
||||
int64_t mpp_pts = mpp_packet_get_pts(packet);
|
||||
// Use encoder's pts if valid, otherwise compute from frame count
|
||||
out.pts_ms = mpp_pts > 0 ? mpp_pts : static_cast<int64_t>(frame_count_ * 1000 / fps_);
|
||||
// Frame::pts is microseconds; ZLMediaKit/FFmpeg muxer paths use millisecond timestamps.
|
||||
out.pts_ms = mpp_pts > 0 ? (mpp_pts / 1000) : static_cast<int64_t>(frame_count_ * 1000 / fps_);
|
||||
++frame_count_;
|
||||
if (on_packet) on_packet(out);
|
||||
mpp_packet_deinit(&packet);
|
||||
|
||||
@ -2,7 +2,8 @@
|
||||
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
#include "utils/logger.h"
|
||||
|
||||
namespace rk3588 {
|
||||
|
||||
@ -12,7 +13,7 @@ AiScheduler& AiScheduler::Instance() {
|
||||
}
|
||||
|
||||
AiScheduler::AiScheduler() {
|
||||
std::cout << "[AiScheduler] initialized\n";
|
||||
LogInfo("[AiScheduler] initialized");
|
||||
}
|
||||
|
||||
AiScheduler::~AiScheduler() {
|
||||
@ -25,8 +26,8 @@ void AiScheduler::Shutdown() {
|
||||
std::lock_guard<std::mutex> lock(models_mutex_);
|
||||
models_.clear();
|
||||
}
|
||||
std::cout << "[AiScheduler] shutdown, total inferences: " << total_inferences_.load()
|
||||
<< ", errors: " << total_errors_.load() << "\n";
|
||||
LogInfo("[AiScheduler] shutdown, total inferences: " + std::to_string(total_inferences_.load()) +
|
||||
", errors: " + std::to_string(total_errors_.load()));
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -104,10 +105,11 @@ ModelHandle AiScheduler::LoadModel(const std::string& model_path, std::string& e
|
||||
models_[handle] = ctx;
|
||||
}
|
||||
|
||||
std::cout << "[AiScheduler] loaded model: " << model_path
|
||||
<< " (handle=" << handle << ", input=" << ctx->input_w
|
||||
<< "x" << ctx->input_h << "x" << ctx->input_c
|
||||
<< ", outputs=" << ctx->n_output << ")\n";
|
||||
LogInfo("[AiScheduler] loaded model: " + model_path +
|
||||
" (handle=" + std::to_string(handle) +
|
||||
", input=" + std::to_string(ctx->input_w) + "x" + std::to_string(ctx->input_h) +
|
||||
"x" + std::to_string(ctx->input_c) +
|
||||
", outputs=" + std::to_string(ctx->n_output) + ")");
|
||||
|
||||
return handle;
|
||||
#else
|
||||
@ -129,7 +131,7 @@ void AiScheduler::UnloadModel(ModelHandle handle) {
|
||||
}
|
||||
}
|
||||
if (erased) {
|
||||
std::cout << "[AiScheduler] unloaded model handle=" << handle << "\n";
|
||||
LogInfo("[AiScheduler] unloaded model handle=" + std::to_string(handle));
|
||||
}
|
||||
#else
|
||||
(void)handle;
|
||||
|
||||
@ -806,6 +806,14 @@ bool GraphManager::Build(const SimpleJson& root_cfg, std::string& err) {
|
||||
if (!plugin_path.empty()) {
|
||||
loader_.SetPluginDir(plugin_path);
|
||||
}
|
||||
|
||||
const std::string log_level = g->ValueOr<std::string>("log_level", "");
|
||||
if (!log_level.empty()) {
|
||||
LogLevel lvl;
|
||||
if (ParseLogLevel(log_level, lvl)) {
|
||||
Logger::Instance().SetLevel(lvl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(graphs_mu_);
|
||||
@ -928,6 +936,17 @@ bool GraphManager::ReloadFromFile(const std::string& path, std::string& err) {
|
||||
return "";
|
||||
}();
|
||||
|
||||
std::optional<LogLevel> new_log_level;
|
||||
if (const SimpleJson* g = expanded.Find("global")) {
|
||||
const std::string log_level = g->ValueOr<std::string>("log_level", "");
|
||||
if (!log_level.empty()) {
|
||||
LogLevel lvl;
|
||||
if (ParseLogLevel(log_level, lvl)) {
|
||||
new_log_level = lvl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(graphs_mu_);
|
||||
|
||||
const SimpleJson prev_last_good = last_good_root_;
|
||||
@ -1047,6 +1066,9 @@ bool GraphManager::ReloadFromFile(const std::string& path, std::string& err) {
|
||||
last_good_root_ = expanded;
|
||||
default_queue_size_ = new_default_queue_size;
|
||||
default_strategy_ = new_default_strategy;
|
||||
if (new_log_level) {
|
||||
Logger::Instance().SetLevel(*new_log_level);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1149,6 +1171,10 @@ bool GraphManager::ReloadFromFile(const std::string& path, std::string& err) {
|
||||
default_queue_size_ = new_default_queue_size;
|
||||
default_strategy_ = new_default_strategy;
|
||||
|
||||
if (new_log_level) {
|
||||
Logger::Instance().SetLevel(*new_log_level);
|
||||
}
|
||||
|
||||
if (!last_good_path_.empty()) {
|
||||
std::string werr;
|
||||
if (!WriteTextFileAtomic(last_good_path_, StringifySimpleJson(last_good_root_), werr)) {
|
||||
|
||||
@ -396,14 +396,14 @@ void HttpServer::Stop() {
|
||||
|
||||
void HttpServer::ServerLoop() {
|
||||
if (!InitSockets()) {
|
||||
std::cerr << "[HttpServer] socket init failed\n";
|
||||
LogError("[HttpServer] socket init failed");
|
||||
running_.store(false);
|
||||
return;
|
||||
}
|
||||
|
||||
Sock srv = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (srv == kInvalidSock) {
|
||||
std::cerr << "[HttpServer] socket() failed\n";
|
||||
LogError("[HttpServer] socket() failed");
|
||||
CleanupSockets();
|
||||
running_.store(false);
|
||||
return;
|
||||
@ -421,14 +421,14 @@ void HttpServer::ServerLoop() {
|
||||
addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
addr.sin_port = htons(static_cast<uint16_t>(port_));
|
||||
if (bind(srv, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) != 0) {
|
||||
std::cerr << "[HttpServer] bind failed on port " << port_ << "\n";
|
||||
LogError("[HttpServer] bind failed on port " + std::to_string(port_));
|
||||
CloseSock(srv);
|
||||
CleanupSockets();
|
||||
running_.store(false);
|
||||
return;
|
||||
}
|
||||
if (listen(srv, 16) != 0) {
|
||||
std::cerr << "[HttpServer] listen failed\n";
|
||||
LogError("[HttpServer] listen failed");
|
||||
CloseSock(srv);
|
||||
CleanupSockets();
|
||||
running_.store(false);
|
||||
@ -436,7 +436,7 @@ void HttpServer::ServerLoop() {
|
||||
}
|
||||
(void)SetNonBlocking(srv);
|
||||
listen_sock_.store(static_cast<int64_t>(srv));
|
||||
std::cout << "[HttpServer] listening on 0.0.0.0:" << port_ << " (web_root=" << web_root_ << ")\n";
|
||||
LogInfo("[HttpServer] listening on 0.0.0.0:" + std::to_string(port_) + " (web_root=" + web_root_ + ")");
|
||||
|
||||
while (running_.load()) {
|
||||
fd_set rfds;
|
||||
@ -527,6 +527,9 @@ void HttpServer::ServerLoop() {
|
||||
}
|
||||
oss << "]}";
|
||||
resp.body = oss.str();
|
||||
} else if (req.path == "/api/log/level") {
|
||||
const LogLevel lvl = Logger::Instance().GetLevel();
|
||||
resp.body = std::string("{\"level\":\"") + LogLevelToString(lvl) + "\"}";
|
||||
} else if (req.path.rfind("/api/nodes/", 0) == 0) {
|
||||
// /api/nodes/{id}/metrics
|
||||
const std::string prefix = "/api/nodes/";
|
||||
@ -577,6 +580,33 @@ void HttpServer::ServerLoop() {
|
||||
} else {
|
||||
resp.body = OkJson();
|
||||
}
|
||||
} else if (req.path == "/api/log/level") {
|
||||
if (req.body.empty()) {
|
||||
resp.status = 400;
|
||||
resp.body = ErrorJson("empty body");
|
||||
} else {
|
||||
SimpleJson body;
|
||||
std::string jerr;
|
||||
if (!ParseSimpleJson(req.body, body, jerr)) {
|
||||
resp.status = 400;
|
||||
resp.body = ErrorJson(jerr);
|
||||
} else {
|
||||
const std::string level = body.ValueOr<std::string>("level", "");
|
||||
if (level.empty()) {
|
||||
resp.status = 400;
|
||||
resp.body = ErrorJson("missing 'level'");
|
||||
} else {
|
||||
LogLevel lvl;
|
||||
if (!ParseLogLevel(level, lvl)) {
|
||||
resp.status = 400;
|
||||
resp.body = ErrorJson("invalid level; use debug|info|warn|error");
|
||||
} else {
|
||||
Logger::Instance().SetLevel(lvl);
|
||||
resp.body = OkJson();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (req.path.rfind("/api/nodes/", 0) == 0) {
|
||||
// /api/nodes/{id}/config
|
||||
const std::string prefix = "/api/nodes/";
|
||||
|
||||
@ -23,6 +23,7 @@ namespace fs = std::filesystem;
|
||||
|
||||
#include "graph_manager.h"
|
||||
#include "http_server.h"
|
||||
#include "utils/logger.h"
|
||||
#include "utils/simple_json.h"
|
||||
|
||||
namespace rk3588 {
|
||||
@ -53,7 +54,7 @@ std::string ResolvePluginDir() {
|
||||
|
||||
void HandleSignal(int) {
|
||||
if (g_manager) {
|
||||
std::cerr << "\n[MediaServerApp] Caught signal, stopping...\n";
|
||||
LogWarn("[MediaServerApp] Caught signal, stopping...");
|
||||
g_manager->RequestStop();
|
||||
}
|
||||
}
|
||||
@ -124,9 +125,9 @@ void InotifyWatchLoop(const std::string& path, std::atomic<bool>& stop_flag, Gra
|
||||
if (matched) {
|
||||
std::string err;
|
||||
if (!mgr.ReloadFromFile(path, err)) {
|
||||
std::cerr << "[MediaServerApp] hot reload failed: " << err << "\n";
|
||||
LogWarn("[MediaServerApp] hot reload failed: " + err);
|
||||
} else {
|
||||
std::cout << "[MediaServerApp] hot reload succeeded\n";
|
||||
LogInfo("[MediaServerApp] hot reload succeeded");
|
||||
}
|
||||
// Debounce burst events.
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(300));
|
||||
@ -158,9 +159,9 @@ void PollWatchLoop(const std::string& path, std::atomic<bool>& stop_flag, GraphM
|
||||
|
||||
std::string err;
|
||||
if (!mgr.ReloadFromFile(path, err)) {
|
||||
std::cerr << "[MediaServerApp] hot reload failed: " << err << "\n";
|
||||
LogWarn("[MediaServerApp] hot reload failed: " + err);
|
||||
} else {
|
||||
std::cout << "[MediaServerApp] hot reload succeeded\n";
|
||||
LogInfo("[MediaServerApp] hot reload succeeded");
|
||||
}
|
||||
#else
|
||||
(void)path;
|
||||
@ -178,7 +179,7 @@ int MediaServerApp::Start() {
|
||||
SimpleJson root_cfg;
|
||||
std::string err;
|
||||
if (!GraphManager::LoadConfigFile(config_path_, root_cfg, err)) {
|
||||
std::cerr << "[MediaServerApp] Failed to load config: " << err << "\n";
|
||||
LogError("[MediaServerApp] Failed to load config: " + err);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -190,7 +191,7 @@ int MediaServerApp::Start() {
|
||||
}
|
||||
|
||||
if (!graph_manager_.BuildFromFile(config_path_, err)) {
|
||||
std::cerr << "[MediaServerApp] Failed to build graphs: " << err << "\n";
|
||||
LogError("[MediaServerApp] Failed to build graphs: " + err);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -199,14 +200,14 @@ int MediaServerApp::Start() {
|
||||
signal(SIGTERM, HandleSignal);
|
||||
|
||||
if (!graph_manager_.StartAll()) {
|
||||
std::cerr << "[MediaServerApp] Failed to start graphs\n";
|
||||
LogError("[MediaServerApp] Failed to start graphs");
|
||||
return 1;
|
||||
}
|
||||
|
||||
HttpServer http(graph_manager_, metrics_port, web_root);
|
||||
(void)http.Start();
|
||||
|
||||
std::cout << "[MediaServerApp] Running. Press Ctrl+C to stop.\n";
|
||||
LogInfo("[MediaServerApp] Running. Press Ctrl+C to stop.");
|
||||
|
||||
std::atomic<bool> stop_watch{false};
|
||||
std::thread watcher;
|
||||
@ -220,7 +221,7 @@ int MediaServerApp::Start() {
|
||||
#else
|
||||
watcher = std::thread([&] { PollWatchLoop(config_path_, stop_watch, graph_manager_); });
|
||||
#endif
|
||||
std::cout << "[MediaServerApp] Hot reload enabled\n";
|
||||
LogInfo("[MediaServerApp] Hot reload enabled");
|
||||
}
|
||||
|
||||
graph_manager_.BlockUntilStop();
|
||||
@ -229,7 +230,7 @@ int MediaServerApp::Start() {
|
||||
|
||||
stop_watch.store(true);
|
||||
if (watcher.joinable()) watcher.join();
|
||||
std::cout << "[MediaServerApp] Shutdown complete.\n";
|
||||
LogInfo("[MediaServerApp] Shutdown complete.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user