瀏覽代碼

add: rtmp,继续优化统计信息,优化日志输出

Wendal Chen 3 月之前
父節點
當前提交
ca69c0f32d
共有 2 個文件被更改,包括 115 次插入22 次删除
  1. 31 8
      components/rtmp/include/luat_rtmp_push.h
  2. 84 14
      components/rtmp/src/luat_rtmp_push.c

+ 31 - 8
components/rtmp/include/luat_rtmp_push.h

@@ -138,7 +138,7 @@ typedef struct {
  * 用于查询RTMP连接的实时统计数据
  */
 typedef struct {
-    uint32_t bytes_sent;            /**< 已发送的字节数 */
+    uint64_t bytes_sent;            /**< 已发送的字节数 */
     uint32_t video_frames_sent;     /**< 已发送的视频帧数 */
     uint32_t audio_frames_sent;     /**< 已发送的音频帧数 */
     uint32_t connection_time;       /**< 连接持续时间(毫秒) */
@@ -149,11 +149,11 @@ typedef struct {
     /* 细分统计 */
     uint32_t i_frames;              /**< 发送的I帧数量 */
     uint32_t p_frames;              /**< 发送的P帧数量 */
-    uint32_t i_bytes;               /**< 发送的I帧字节数(NAL数据长度累加) */
-    uint32_t p_bytes;               /**< 发送的P帧字节数(NAL数据长度累加) */
+    uint64_t i_bytes;               /**< 发送的I帧字节数(NAL数据长度累加) */
+    uint64_t p_bytes;               /**< 发送的P帧字节数(NAL数据长度累加) */
 
     uint32_t dropped_frames;        /**< 被丢弃的帧数量 */
-    uint32_t dropped_bytes;         /**< 被丢弃的帧字节数 */
+    uint64_t dropped_bytes;         /**< 被丢弃的帧字节数 */
 } rtmp_stats_t;
 
 /**
@@ -203,17 +203,22 @@ typedef struct {
     
     /** ============ 统计信息 ============ */
     uint32_t packets_sent;          /**< 已发送的包数 */
-    uint32_t bytes_sent;            /**< 已发送的字节数 */
+    uint64_t bytes_sent;            /**< 已发送的字节数 */
     uint32_t command_id;            /**< 当前命令ID */
 
     /* 帧统计 */
     uint32_t i_frames;              /**< 发送的I帧数量 */
     uint32_t p_frames;              /**< 发送的P帧数量 */
-    uint32_t i_bytes;               /**< 发送的I帧字节数 */
-    uint32_t p_bytes;               /**< 发送的P帧字节数 */
+    uint64_t i_bytes;               /**< 发送的I帧字节数 */
+    uint64_t p_bytes;               /**< 发送的P帧字节数 */
     uint32_t dropped_frames;        /**< 被丢弃的帧数量 */
-    uint32_t dropped_bytes;         /**< 被丢弃的帧字节数 */
+    uint64_t dropped_bytes;         /**< 被丢弃的帧字节数 */
     uint32_t last_stats_log_ms;     /**< 上次统计日志输出时间 */
+    uint64_t last_stats_bytes;      /**< 上次统计日志输出时的总字节数 */
+    uint32_t stats_interval_ms;     /**< 统计输出间隔(毫秒),默认10000 */
+    uint32_t stats_window_ms;       /**< 统计窗口长度(毫秒),默认与间隔相同 */
+    uint32_t last_window_ms;        /**< 上次窗口采样时间戳(ms) */
+    uint64_t last_window_bytes;     /**< 上次窗口采样时的总字节数 */
     
     /** ============ 用户数据 ============ */
     void *user_data;                /**< 用户自定义数据指针 */
@@ -379,6 +384,24 @@ void* rtmp_get_user_data(rtmp_ctx_t *ctx);
  */
 int rtmp_get_stats(rtmp_ctx_t *ctx, rtmp_stats_t *stats);
 
+/**
+ * 设置统计输出间隔
+ * 
+ * @param ctx RTMP上下文指针
+ * @param interval_ms 间隔毫秒数(例如10000表示10秒)
+ * @return RTMP_OK表示成功
+ */
+int rtmp_set_stats_interval(rtmp_ctx_t *ctx, uint32_t interval_ms);
+
+/**
+ * 设置统计窗口长度
+ * 
+ * @param ctx RTMP上下文指针
+ * @param window_ms 窗口毫秒数(例如10000表示10秒)
+ * @return RTMP_OK表示成功
+ */
+int rtmp_set_stats_window(rtmp_ctx_t *ctx, uint32_t window_ms);
+
 /* ======================== 回调函数定义 ======================== */
 
 /**

+ 84 - 14
components/rtmp/src/luat_rtmp_push.c

@@ -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;
     }