|
|
@@ -541,6 +541,11 @@ rtmp_ctx_t* rtmp_create(void) {
|
|
|
|
|
|
/* 统计初始化 */
|
|
|
ctx->last_stats_log_ms = (uint32_t)luat_mcu_tick64_ms();
|
|
|
+ ctx->last_stats_bytes = 0;
|
|
|
+ ctx->stats_interval_ms = 10000;
|
|
|
+ ctx->stats_window_ms = 10000;
|
|
|
+ ctx->last_window_ms = ctx->last_stats_log_ms;
|
|
|
+ ctx->last_window_bytes = 0;
|
|
|
|
|
|
RTMP_LOGV("RTMP: Context created successfully");
|
|
|
g_rtmp_ctx = ctx;
|
|
|
@@ -1001,7 +1006,7 @@ static int rtmp_send_single_nalu(rtmp_ctx_t *ctx, const uint8_t *nalu_data,
|
|
|
/* 更新统计 */
|
|
|
ctx->video_timestamp = timestamp;
|
|
|
ctx->packets_sent++;
|
|
|
- ctx->bytes_sent += nalu_len;
|
|
|
+ ctx->bytes_sent += (uint64_t)nalu_len;
|
|
|
if (is_key_frame) {
|
|
|
ctx->i_frames++;
|
|
|
ctx->i_bytes += nalu_len;
|
|
|
@@ -1086,18 +1091,54 @@ int rtmp_poll(rtmp_ctx_t *ctx) {
|
|
|
|
|
|
/* 周期性打印统计信息(每10秒) */
|
|
|
uint32_t now_ms = (uint32_t)luat_mcu_tick64_ms();
|
|
|
- if (now_ms - ctx->last_stats_log_ms >= 10000) {
|
|
|
- ctx->last_stats_log_ms = now_ms;
|
|
|
- LLOGI("RTMP stats: bytes=%u packets=%u I=%u (%uB) P=%u (%uB) dropped=%u (%uB) queue=%u",
|
|
|
- ctx->bytes_sent,
|
|
|
+ /* 独立刷新窗口采样 */
|
|
|
+ if (now_ms - ctx->last_window_ms >= ctx->stats_window_ms) {
|
|
|
+ ctx->last_window_ms = now_ms;
|
|
|
+ ctx->last_window_bytes = ctx->bytes_sent;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (now_ms - ctx->last_stats_log_ms >= ctx->stats_interval_ms) {
|
|
|
+ uint32_t elapsed_ms = 0;
|
|
|
+ if (ctx->base_timestamp > 0 && now_ms > ctx->base_timestamp) {
|
|
|
+ elapsed_ms = now_ms - ctx->base_timestamp;
|
|
|
+ }
|
|
|
+ /* 平均码率(单位kbps): 总比特 / 秒 / 1000 */
|
|
|
+ uint32_t avg_kbps = 0;
|
|
|
+ if (elapsed_ms > 0) {
|
|
|
+ double kbps = ((double)ctx->bytes_sent * 8.0) / ((double)elapsed_ms / 1000.0) / 1000.0;
|
|
|
+ avg_kbps = (uint32_t)(kbps + 0.5);
|
|
|
+ }
|
|
|
+ /* 区间平均码率(最近10秒) */
|
|
|
+ uint32_t win_kbps = 0;
|
|
|
+ /* 统计窗口以 stats_window_ms 为准;若比实际间隔更长,则按实际间隔计算 */
|
|
|
+ uint32_t win_ms = (now_ms >= ctx->last_window_ms) ? (now_ms - ctx->last_window_ms) : 0;
|
|
|
+ uint64_t win_bytes = (ctx->bytes_sent >= ctx->last_window_bytes) ? (ctx->bytes_sent - ctx->last_window_bytes) : 0;
|
|
|
+ if (win_ms > 0 && win_bytes > 0) {
|
|
|
+ double wkbps = ((double)win_bytes * 8.0) / ((double)win_ms / 1000.0) / 1000.0;
|
|
|
+ win_kbps = (uint32_t)(wkbps + 0.5);
|
|
|
+ }
|
|
|
+ /* 以kB为单位显示总字节和各类字节(四舍五入) */
|
|
|
+ uint64_t total_kB = ctx->bytes_sent / 1024ULL;
|
|
|
+ uint64_t i_kB = ctx->i_bytes / 1024ULL;
|
|
|
+ uint64_t p_kB = ctx->p_bytes / 1024ULL;
|
|
|
+ uint64_t drop_kB = ctx->dropped_bytes / 1024ULL;
|
|
|
+
|
|
|
+ LLOGI("RTMP stats: total=%llu kB packets=%u I=%u (%llukB) P=%u (%llukB) dropped=%u (%llukB) queue=%u avg=%u kbps win=%u kbps",
|
|
|
+ (unsigned long long)total_kB,
|
|
|
ctx->packets_sent,
|
|
|
ctx->i_frames,
|
|
|
- ctx->i_bytes,
|
|
|
+ (unsigned long long)i_kB,
|
|
|
ctx->p_frames,
|
|
|
- ctx->p_bytes,
|
|
|
+ (unsigned long long)p_kB,
|
|
|
ctx->dropped_frames,
|
|
|
- ctx->dropped_bytes,
|
|
|
- ctx->frame_queue_bytes);
|
|
|
+ (unsigned long long)drop_kB,
|
|
|
+ ctx->frame_queue_bytes,
|
|
|
+ avg_kbps,
|
|
|
+ win_kbps);
|
|
|
+
|
|
|
+ /* 更新日志基准 */
|
|
|
+ ctx->last_stats_log_ms = now_ms;
|
|
|
+ ctx->last_stats_bytes = ctx->bytes_sent;
|
|
|
}
|
|
|
|
|
|
return RTMP_OK;
|
|
|
@@ -1172,6 +1213,35 @@ int rtmp_set_state_callback(rtmp_ctx_t *ctx, rtmp_state_callback callback) {
|
|
|
return RTMP_OK;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * 设置统计输出间隔
|
|
|
+ */
|
|
|
+int rtmp_set_stats_interval(rtmp_ctx_t *ctx, uint32_t interval_ms) {
|
|
|
+ if (!ctx) {
|
|
|
+ return RTMP_ERR_INVALID_PARAM;
|
|
|
+ }
|
|
|
+ if (interval_ms == 0) {
|
|
|
+ /* 防止除零/过于频繁,设定最小1000ms */
|
|
|
+ interval_ms = 1000;
|
|
|
+ }
|
|
|
+ ctx->stats_interval_ms = interval_ms;
|
|
|
+ return RTMP_OK;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 设置统计窗口长度
|
|
|
+ */
|
|
|
+int rtmp_set_stats_window(rtmp_ctx_t *ctx, uint32_t window_ms) {
|
|
|
+ if (!ctx) {
|
|
|
+ return RTMP_ERR_INVALID_PARAM;
|
|
|
+ }
|
|
|
+ if (window_ms == 0) {
|
|
|
+ window_ms = 1000;
|
|
|
+ }
|
|
|
+ ctx->stats_window_ms = window_ms;
|
|
|
+ return RTMP_OK;
|
|
|
+}
|
|
|
+
|
|
|
/* ======================== 内部函数实现 ======================== */
|
|
|
|
|
|
/**
|
|
|
@@ -1441,7 +1511,7 @@ static err_t rtmp_tcp_sent_callback(void *arg, struct tcp_pcb *pcb, u16_t len) {
|
|
|
total_sent += len;
|
|
|
//LLOGD("RTMP: TCP sent callback, len=%d, total_sent=%llu", len, total_sent);
|
|
|
if (ctx) {
|
|
|
- ctx->bytes_sent += len;
|
|
|
+ ctx->bytes_sent += (uint64_t)len;
|
|
|
/* 继续发送队列中的数据 */
|
|
|
rtmp_try_send_queue(ctx);
|
|
|
}
|
|
|
@@ -1779,7 +1849,7 @@ static int rtmp_queue_frame(rtmp_ctx_t *ctx, rtmp_frame_node_t *node) {
|
|
|
if (to_free == ctx->frame_tail) ctx->frame_tail = prev;
|
|
|
ctx->frame_queue_bytes -= to_free->len;
|
|
|
ctx->dropped_frames++;
|
|
|
- ctx->dropped_bytes += to_free->len;
|
|
|
+ ctx->dropped_bytes += (uint64_t)to_free->len;
|
|
|
rtmp_free_frame_node(to_free);
|
|
|
continue;
|
|
|
}
|
|
|
@@ -1800,7 +1870,7 @@ static int rtmp_queue_frame(rtmp_ctx_t *ctx, rtmp_frame_node_t *node) {
|
|
|
if (to_free == ctx->frame_tail) ctx->frame_tail = prev;
|
|
|
ctx->frame_queue_bytes -= to_free->len;
|
|
|
ctx->dropped_frames++;
|
|
|
- ctx->dropped_bytes += to_free->len;
|
|
|
+ ctx->dropped_bytes += (uint64_t)to_free->len;
|
|
|
rtmp_free_frame_node(to_free);
|
|
|
continue;
|
|
|
}
|
|
|
@@ -1818,7 +1888,7 @@ static int rtmp_queue_frame(rtmp_ctx_t *ctx, rtmp_frame_node_t *node) {
|
|
|
if (to_free == ctx->frame_tail) ctx->frame_tail = prev;
|
|
|
ctx->frame_queue_bytes -= to_free->len;
|
|
|
ctx->dropped_frames++;
|
|
|
- ctx->dropped_bytes += to_free->len;
|
|
|
+ ctx->dropped_bytes += (uint64_t)to_free->len;
|
|
|
rtmp_free_frame_node(to_free);
|
|
|
continue;
|
|
|
}
|
|
|
@@ -1830,7 +1900,7 @@ static int rtmp_queue_frame(rtmp_ctx_t *ctx, rtmp_frame_node_t *node) {
|
|
|
if (ctx->frame_queue_bytes + need_bytes > RTMP_MAX_QUEUE_BYTES) {
|
|
|
LLOGE("RTMP: Drop frame, queue bytes %u exceed max %u", ctx->frame_queue_bytes + need_bytes, RTMP_MAX_QUEUE_BYTES);
|
|
|
ctx->dropped_frames++;
|
|
|
- ctx->dropped_bytes += node->len;
|
|
|
+ ctx->dropped_bytes += (uint64_t)node->len;
|
|
|
return RTMP_ERR_BUFFER_OVERFLOW;
|
|
|
}
|
|
|
|