video_stats.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  1. #include "precompile.h"
  2. #include "gettimeofday.h"
  3. #include "video_statics/video_stats.h"
  4. #include "videoutil.h"
  5. #define BW_GAMMA 0.5f
  6. static VideoStats *g_stats = NULL;
  7. static void* video_stats_loop_event(void* arg);
  8. static void ex_video_stats_log(int level, const char* file, int line, const char *fmt, ...)
  9. {
  10. va_list vl;
  11. if (g_stats != NULL && g_stats->log_callback.log_fn != NULL) {
  12. va_start(vl, fmt);
  13. g_stats->log_callback.log_fn(g_stats->log_callback.userdata, level, file, line, fmt, vl);
  14. va_end(vl);
  15. }
  16. }
  17. static void video_stats_setup_log(VideoStatsLogCallBack *log_func)
  18. {
  19. if (log_func && g_stats != NULL) {
  20. g_stats->log_callback.log_fn = log_func->log_fn;
  21. g_stats->log_callback.userdata = log_func->userdata;
  22. }
  23. }
  24. #define video_stats_debug(...) ex_video_stats_log(0, __FILE__, __LINE__, __VA_ARGS__)
  25. #define video_stats_info(...) ex_video_stats_log(1, __FILE__, __LINE__, __VA_ARGS__)
  26. #define video_stats_warn(...) ex_video_stats_log(2, __FILE__, __LINE__, __VA_ARGS__)
  27. #define video_stats_error(...) ex_video_stats_log(3, __FILE__, __LINE__, __VA_ARGS__)
  28. static float compute_bw(struct timeval *orig, unsigned int *bytes, const struct timeval *current){
  29. float bw;
  30. float time;
  31. time=(float)((double)(current->tv_sec - orig->tv_sec) +
  32. ((double)(current->tv_usec - orig->tv_usec)*1e-6));
  33. bw=((float)*bytes)*8/(time+0.0001f);
  34. /*+0.0001 avoids a division by zero without changing the results significatively*/
  35. *orig=*current;
  36. return bw;
  37. }
  38. static void compute_recv_bandwidth(StreamBandwidthStats *stats, const struct timeval *current) {
  39. stats->download_bw = compute_bw(&stats->recv_bw_start, &stats->recv_bytes, current);
  40. stats->recv_bytes = 0;
  41. stats->average_download_bw = (stats->average_download_bw==0) ?
  42. stats->download_bw :
  43. (1 - BW_GAMMA) * stats->average_download_bw + BW_GAMMA * stats->download_bw;
  44. }
  45. static void compute_send_bandwidth(StreamBandwidthStats *stats, const struct timeval *current) {
  46. stats->upload_bw = compute_bw(&stats->send_bw_start, &stats->sent_bytes, current);
  47. stats->sent_bytes = 0;
  48. stats->average_upload_bw = (stats->average_upload_bw==0) ?
  49. stats->upload_bw :
  50. (1 - BW_GAMMA) * stats->average_upload_bw + BW_GAMMA * stats->upload_bw;
  51. }
  52. void video_stats_init(VideoStatsLogCallBack *log_func){
  53. if (g_stats == NULL){
  54. g_stats = (VideoStats *)malloc(sizeof(VideoStats));
  55. memset(g_stats, 0, sizeof(VideoStats));
  56. video_stats_setup_log(log_func);
  57. g_stats->run = 1;
  58. g_stats->thr = su_create_thread(NULL, video_stats_loop_event, g_stats);
  59. }
  60. }
  61. void video_stats_uninit(){
  62. if (g_stats != NULL){
  63. g_stats->run = 0;
  64. while (g_stats->run == 0){
  65. su_sleep(0, 10000);
  66. }
  67. free(g_stats);
  68. g_stats = NULL;
  69. }
  70. }
  71. float video_stats_bandwidth_compute_loss_rate(rtcp_statistics *rtcp_stat){
  72. unsigned int cur_loss;
  73. unsigned int cur_seq;
  74. unsigned int expected;
  75. float loss_percent;
  76. if (g_stats != NULL) {
  77. cur_loss= rtcp_stat->total_packet_lost;
  78. cur_seq = ((unsigned int)rtcp_stat->seq_circles << 16 | (unsigned int)rtcp_stat->last_seq);
  79. expected = cur_seq - g_stats->rtcp_stats.seq_begin;
  80. if (expected == 0) return 0;
  81. g_stats->rtcp_stats.last_loss_percent = 100.0f*(float)(cur_loss - g_stats->rtcp_stats.loss_begin) / (float)expected;
  82. g_stats->rtcp_stats.seq_begin = cur_seq;
  83. g_stats->rtcp_stats.loss_begin = cur_loss;
  84. return g_stats->rtcp_stats.last_loss_percent;
  85. }
  86. return -1;
  87. }
  88. static float video_stats_bandwidth_compute_recv_bandwidth(){
  89. struct timeval current;
  90. gettimeofday(&current,NULL);
  91. if (g_stats != NULL) {
  92. compute_recv_bandwidth(&g_stats->rtp_stats, &current);
  93. compute_recv_bandwidth(&g_stats->rtcp_stats, &current);
  94. return g_stats->rtp_stats.download_bw + g_stats->rtcp_stats.download_bw;
  95. }
  96. return -1;
  97. }
  98. static float video_stats_bandwidth_compute_send_bandwidth(){
  99. struct timeval current;
  100. gettimeofday(&current,NULL);
  101. if (g_stats != NULL) {
  102. compute_send_bandwidth(&g_stats->rtp_stats, &current);
  103. compute_send_bandwidth(&g_stats->rtcp_stats, &current);
  104. return g_stats->rtp_stats.download_bw + g_stats->rtcp_stats.download_bw;
  105. }
  106. return -1;
  107. }
  108. //huchen comment, immediately bandwidth
  109. static float video_stats_bandwidth_get_recv_bandwidth(){
  110. if (g_stats != NULL) {
  111. return g_stats->rtp_stats.download_bw + g_stats->rtcp_stats.download_bw;
  112. }
  113. return -1;
  114. }
  115. static float video_stats_bandwidth_get_send_bandwidth(){
  116. if (g_stats != NULL) {
  117. return g_stats->rtp_stats.upload_bw + g_stats->rtcp_stats.upload_bw;
  118. }
  119. return -1;
  120. }
  121. //huchen comment, mean smooth bandwidth
  122. static float video_stats_bandwidth_get_recv_bandwidth_smooth(){
  123. if (g_stats != NULL) {
  124. return g_stats->rtp_stats.average_download_bw + g_stats->rtcp_stats.average_download_bw;
  125. }
  126. return -1;
  127. }
  128. static float video_stats_bandwidth_get_send_bandwidth_smooth(){
  129. if (g_stats != NULL) {
  130. return g_stats->rtp_stats.average_upload_bw + g_stats->rtcp_stats.average_upload_bw;
  131. }
  132. return -1;
  133. }
  134. void video_stats_bandwidth_update_recv_rtp_bytes(size_t nbytes){
  135. if (g_stats != NULL) {
  136. if ((g_stats->rtp_stats.recv_bytes == 0) && (g_stats->rtp_stats.recv_bw_start.tv_sec == 0) && (g_stats->rtp_stats.recv_bw_start.tv_usec == 0)) {
  137. gettimeofday(&g_stats->rtp_stats.recv_bw_start, NULL);
  138. }
  139. g_stats->rtp_stats.recv_bytes += (unsigned int)(nbytes + IP_UDP_HEADER_SIZE + RTP_HEADER_SIZE);
  140. }
  141. }
  142. void video_stats_bandwidth_update_recv_rtcp_bytes(size_t nbytes){
  143. if (g_stats != NULL) {
  144. if ((g_stats->rtcp_stats.recv_bytes == 0) && (g_stats->rtcp_stats.recv_bw_start.tv_sec == 0) && (g_stats->rtcp_stats.recv_bw_start.tv_usec == 0)) {
  145. gettimeofday(&g_stats->rtcp_stats.recv_bw_start, NULL);
  146. }
  147. g_stats->rtcp_stats.recv_bytes += (unsigned int)(nbytes + IP_UDP_HEADER_SIZE + RTP_HEADER_SIZE);
  148. }
  149. }
  150. void video_stats_bandwidth_update_send_rtp_bytes(int nbytes){
  151. if (g_stats != NULL) {
  152. if ((g_stats->rtp_stats.sent_bytes == 0) && (g_stats->rtp_stats.send_bw_start.tv_sec == 0) && (g_stats->rtp_stats.send_bw_start.tv_usec == 0)) {
  153. /* Initialize bandwidth computing time when has not been started yet. */
  154. gettimeofday(&g_stats->rtp_stats.send_bw_start, NULL);
  155. }
  156. g_stats->rtp_stats.sent_bytes += nbytes + IP_UDP_HEADER_SIZE + RTP_HEADER_SIZE;
  157. }
  158. }
  159. void video_stats_bandwidth_update_send_rtcp_bytes(int nbytes){
  160. if (g_stats != NULL) {
  161. if ((g_stats->rtcp_stats.sent_bytes == 0) && (g_stats->rtcp_stats.send_bw_start.tv_sec == 0) && (g_stats->rtcp_stats.send_bw_start.tv_usec == 0)) {
  162. /* Initialize bandwidth computing time when has not been started yet. */
  163. gettimeofday(&g_stats->rtcp_stats.send_bw_start, NULL);
  164. }
  165. g_stats->rtcp_stats.sent_bytes += nbytes + IP_UDP_HEADER_SIZE + RTP_HEADER_SIZE;
  166. }
  167. }
  168. //接收相关统计
  169. ReceiverStats *video_stats_receiver_get_stats(){
  170. if (g_stats != NULL) {
  171. return &g_stats->receiver_stats;
  172. }
  173. return NULL;
  174. }
  175. void video_stats_receiver_on_started(int64_t start_ms, ReceiverConfigStats *config){
  176. if (g_stats != NULL) {
  177. g_stats->receiver_stats.start_ms_ = start_ms;
  178. memcpy(&g_stats->receiver_stats.config_stats, config, sizeof(ReceiverConfigStats));
  179. }
  180. }
  181. void video_stats_receiver_on_stopped(int64_t stop_ms){
  182. if (g_stats != NULL) {
  183. g_stats->receiver_stats.stop_ms_ = stop_ms;
  184. }
  185. }
  186. void video_stats_receiver_on_incoming_packet(int64_t recv_time_ms){
  187. if (g_stats != NULL) {
  188. if (g_stats->receiver_stats.first_frame_received_time_ms_ == 0){
  189. g_stats->receiver_stats.first_frame_received_time_ms_ = recv_time_ms;
  190. }
  191. g_stats->receiver_stats.last_frame_received_time_ms_ = recv_time_ms;
  192. g_stats->receiver_stats.received_packet_counts++;
  193. }
  194. }
  195. void video_stats_receiver_on_decoded_frame(int64_t decoded_time_ms, int64_t decode_duration_ms, int is_key){
  196. if (g_stats != NULL) {
  197. if (g_stats->receiver_stats.first_decoded_frame_time_ms_ == 0){
  198. g_stats->receiver_stats.first_decoded_frame_time_ms_ = decoded_time_ms;
  199. }
  200. g_stats->receiver_stats.last_decoded_frame_time_ms_ = decoded_time_ms;
  201. g_stats->receiver_stats.last_decode_duration_ms = decode_duration_ms;
  202. if (is_key) {
  203. g_stats->receiver_stats.key_frames_counts++;
  204. }else {
  205. g_stats->receiver_stats.delta_frames_counts++;
  206. }
  207. g_stats->receiver_stats.decoded_frame_counts++;
  208. }
  209. }
  210. void video_stats_receiver_on_rendered_frame(int64_t render_time_ms, int64_t render_duration_ms){
  211. if (g_stats != NULL) {
  212. if (g_stats->receiver_stats.first_render_frame_time_ms_ == 0){
  213. g_stats->receiver_stats.first_render_frame_time_ms_ = render_time_ms;
  214. }
  215. g_stats->receiver_stats.last_render_frame_time_ms_ = render_time_ms;
  216. g_stats->receiver_stats.last_render_duration_ms = render_duration_ms;
  217. g_stats->receiver_stats.render_frame_counts++;
  218. }
  219. }
  220. void video_stats_receiver_on_report_cc_bitrate(int bitrate){
  221. if (g_stats != NULL) {
  222. g_stats->receiver_stats.last_report_cc_bitrate = bitrate;
  223. }
  224. }
  225. //发送相关统计
  226. SenderStats *video_stats_sender_get_stats(){
  227. if (g_stats != NULL) {
  228. return &g_stats->sender_stats;
  229. }
  230. return NULL;
  231. }
  232. void video_stats_sender_on_started(int64_t start_ms, SenderConfigStats *config){
  233. if (g_stats != NULL) {
  234. g_stats->sender_stats.start_ms_ = start_ms;
  235. memcpy(&g_stats->sender_stats.config_stats, config, sizeof(SenderConfigStats));
  236. }
  237. }
  238. void video_stats_sender_on_stopped(int64_t stop_ms){
  239. if (g_stats != NULL) {
  240. g_stats->sender_stats.stop_ms_ = stop_ms;
  241. }
  242. }
  243. void video_stats_sender_on_sent_packet(int64_t sent_time_ms){
  244. if (g_stats != NULL) {
  245. if (g_stats->sender_stats.first_frame_sent_time_ms_ == 0){
  246. g_stats->sender_stats.first_frame_sent_time_ms_ = sent_time_ms;
  247. }
  248. g_stats->sender_stats.last_frame_sent_time_ms_ = sent_time_ms;
  249. g_stats->sender_stats.sent_packet_counts++;
  250. }
  251. }
  252. void video_stats_sender_on_encoded_frame(int64_t encoded_time_ms, int64_t encode_duration_ms, int is_key){
  253. if (g_stats != NULL) {
  254. if (g_stats->sender_stats.first_encoded_frame_time_ms_ == 0){
  255. g_stats->sender_stats.first_encoded_frame_time_ms_ = encoded_time_ms;
  256. }
  257. g_stats->sender_stats.last_encoded_frame_time_ms_ = encoded_time_ms;
  258. g_stats->sender_stats.last_encode_duration_ms = encode_duration_ms;
  259. if (is_key) {
  260. g_stats->sender_stats.key_frames_counts++;
  261. }else {
  262. g_stats->sender_stats.delta_frames_counts++;
  263. }
  264. g_stats->sender_stats.encoded_frame_counts++;
  265. }
  266. }
  267. void video_stats_sender_on_encoder_rate_changed(int allocation_fps, int allocation_bitrate){
  268. if (g_stats != NULL) {
  269. g_stats->sender_stats.last_allocation_bitrate = allocation_bitrate;
  270. g_stats->sender_stats.last_allocation_fps = allocation_fps;
  271. }
  272. }
  273. void video_stats_sender_on_frame_dropped(int cap_drop, int framedropper_drop){
  274. if (g_stats != NULL) {
  275. g_stats->sender_stats.cap_drop_frames_counts += cap_drop;
  276. g_stats->sender_stats.framedropper_drop_frames_counts += framedropper_drop;
  277. }
  278. }
  279. static void video_stats_heartbeat(VideoStats* s, int64_t now_ts)
  280. {
  281. uint32_t delay;
  282. if (s->stat_ts + 20*1000 < now_ts){
  283. delay = (uint32_t)(now_ts - s->stat_ts);
  284. s->stat_ts = now_ts;
  285. video_stats_bandwidth_compute_recv_bandwidth();
  286. video_stats_bandwidth_compute_send_bandwidth();
  287. //print stats
  288. //sender
  289. video_stats_debug("video_stats: ******************************sender_stats: \r\n");
  290. video_stats_debug("video_stats: send start_ms = %I64d stop_ms = %I64d. \r\n",
  291. g_stats->sender_stats.start_ms_, g_stats->sender_stats.stop_ms_);
  292. video_stats_debug("video_stats: send config: local_pt = %u remote_ip = %lu remote_port = %d mtu = %d. \r\n",
  293. g_stats->sender_stats.config_stats.local_pt, g_stats->sender_stats.config_stats.remote_ip,
  294. g_stats->sender_stats.config_stats.remote_rtp_port, g_stats->sender_stats.config_stats.mtu);
  295. video_stats_debug("video_stats: send config: tx = %d x %d capture = %d x %d. \r\n",
  296. g_stats->sender_stats.config_stats.tx_width, g_stats->sender_stats.config_stats.tx_height,
  297. g_stats->sender_stats.config_stats.capture_width, g_stats->sender_stats.config_stats.capture_height);
  298. video_stats_debug("video_stats: send config: fps_den = %d fps_num = %d bit_rate = %d. \r\n",
  299. g_stats->sender_stats.config_stats.fps_den, g_stats->sender_stats.config_stats.fps_num,
  300. g_stats->sender_stats.config_stats.bit_rate);
  301. video_stats_debug("video_stats: first_frame_sent_time_ms = %I64d last_frame_sent_time_ms = %I64d. \r\n",
  302. g_stats->sender_stats.first_frame_sent_time_ms_, g_stats->sender_stats.last_frame_sent_time_ms_);
  303. video_stats_debug("video_stats: first_encoded_frame_time_ms = %I64d last_encoded_frame_time_ms = %I64d. \r\n",
  304. g_stats->sender_stats.first_encoded_frame_time_ms_, g_stats->sender_stats.last_encoded_frame_time_ms_);
  305. video_stats_debug("video_stats: last_encoded_key_frame_time_ms = %I64d last_encode_duration_ms = %I64d. \r\n",
  306. g_stats->sender_stats.last_encoded_key_frame_time_ms_, g_stats->sender_stats.last_encode_duration_ms);
  307. video_stats_debug("video_stats: sent_packet_counts = %I64d encoded_frame_counts = %I64d. \r\n",
  308. g_stats->sender_stats.sent_packet_counts, g_stats->sender_stats.encoded_frame_counts);
  309. video_stats_debug("video_stats: last_allocation_fps = %d last_allocation_bitrate = %d. \r\n",
  310. g_stats->sender_stats.last_allocation_fps, g_stats->sender_stats.last_allocation_bitrate);
  311. video_stats_debug("video_stats: send key_frames_counts = %d delta_frames_counts = %d. \r\n",
  312. g_stats->sender_stats.key_frames_counts, g_stats->sender_stats.delta_frames_counts);
  313. video_stats_debug("video_stats: send cap_drop_frames_counts = %d framedropper_drop_frames_counts = %d. \r\n",
  314. g_stats->sender_stats.cap_drop_frames_counts, g_stats->sender_stats.framedropper_drop_frames_counts);
  315. video_stats_debug("video_stats: send bandwidth_smooth = %f kbits/s, send bandwidth = %f kbits/s \r\n",
  316. video_stats_bandwidth_get_send_bandwidth_smooth()/1000,
  317. video_stats_bandwidth_get_send_bandwidth()/1000);
  318. //receiver
  319. video_stats_debug("video_stats: ******************************receiver_stats: \r\n");
  320. video_stats_debug("video_stats: recv start_ms = %I64d stop_ms = %I64d. \r\n",
  321. g_stats->receiver_stats.start_ms_, g_stats->receiver_stats.stop_ms_);
  322. video_stats_debug("video_stats: recv config: remote_pt = %u local_ip = %lu local_port = %d bit_rate = %d. \r\n",
  323. g_stats->receiver_stats.config_stats.remote_pt, g_stats->receiver_stats.config_stats.local_ip,
  324. g_stats->receiver_stats.config_stats.local_rtp_port, g_stats->receiver_stats.config_stats.bit_rate);
  325. video_stats_debug("video_stats: recv config: rx = %d x %d. \r\n",
  326. g_stats->receiver_stats.config_stats.rx_width, g_stats->receiver_stats.config_stats.rx_height);
  327. video_stats_debug("video_stats: first_frame_received_time_ms = %I64d last_frame_received_time_ms = %I64d. \r\n",
  328. g_stats->receiver_stats.first_frame_received_time_ms_, g_stats->receiver_stats.last_frame_received_time_ms_);
  329. video_stats_debug("video_stats: first_decoded_frame_time_ms = %I64d last_decoded_frame_time_ms = %I64d. \r\n",
  330. g_stats->receiver_stats.first_decoded_frame_time_ms_, g_stats->receiver_stats.last_decoded_frame_time_ms_);
  331. video_stats_debug("video_stats: last_decoded_key_frame_time_ms = %I64d. \r\n",
  332. g_stats->receiver_stats.last_decoded_key_frame_time_ms_);
  333. video_stats_debug("video_stats: received_packet_counts = %I64d decoded_frame_counts = %I64d. \r\n",
  334. g_stats->receiver_stats.received_packet_counts, g_stats->receiver_stats.decoded_frame_counts);
  335. video_stats_debug("video_stats: recv key_frames_counts = %d delta_frames_counts = %d. \r\n",
  336. g_stats->receiver_stats.key_frames_counts, g_stats->receiver_stats.delta_frames_counts);
  337. video_stats_debug("video_stats: recv last_report_cc_bitrate = %d. \r\n",
  338. g_stats->receiver_stats.last_report_cc_bitrate);
  339. video_stats_debug("video_stats: first_render_frame_time_ms = %I64d last_render_frame_time_ms = %I64d. \r\n",
  340. g_stats->receiver_stats.first_render_frame_time_ms_, g_stats->receiver_stats.last_render_frame_time_ms_);
  341. video_stats_debug("video_stats: last_render_duration_ms = %I64d render_frame_counts = %I64d. \r\n",
  342. g_stats->receiver_stats.last_render_duration_ms, g_stats->receiver_stats.render_frame_counts);
  343. video_stats_debug("video_stats: recv bandwidth_smooth = %f kbits/s, recv bandwidth = %f kbits/s \r\n",
  344. video_stats_bandwidth_get_recv_bandwidth_smooth()/1000,
  345. video_stats_bandwidth_get_recv_bandwidth()/1000);
  346. video_stats_debug("video_stats: last_loss_percent = %f. \r\n",
  347. g_stats->rtcp_stats.last_loss_percent);
  348. video_stats_debug("video_stats: ******************************receiver_stats end. \r\n");
  349. }
  350. }
  351. static void* video_stats_loop_event(void* arg)
  352. {
  353. VideoStats* s = (VideoStats*)arg;
  354. int64_t now_ts = 0, prev_ts = 0;
  355. prev_ts = now_ts = GET_SYS_MS();
  356. while (s->run == 1){
  357. now_ts = GET_SYS_MS();
  358. if (now_ts >= prev_ts + 5){
  359. video_stats_heartbeat(s, now_ts);
  360. prev_ts = now_ts;
  361. }
  362. Sleep(5);
  363. }
  364. s->run = -1;
  365. return NULL;
  366. }