123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447 |
- #include "precompile.h"
- #include "gettimeofday.h"
- #include "video_statics/video_stats.h"
- #include "videoutil.h"
- #define BW_GAMMA 0.5f
- static VideoStats *g_stats = NULL;
- static void* video_stats_loop_event(void* arg);
- static void ex_video_stats_log(int level, const char* file, int line, const char *fmt, ...)
- {
- va_list vl;
- if (g_stats != NULL && g_stats->log_callback.log_fn != NULL) {
- va_start(vl, fmt);
- g_stats->log_callback.log_fn(g_stats->log_callback.userdata, level, file, line, fmt, vl);
- va_end(vl);
- }
- }
- static void video_stats_setup_log(VideoStatsLogCallBack *log_func)
- {
- if (log_func && g_stats != NULL) {
- g_stats->log_callback.log_fn = log_func->log_fn;
- g_stats->log_callback.userdata = log_func->userdata;
- }
- }
- #define video_stats_debug(...) ex_video_stats_log(0, __FILE__, __LINE__, __VA_ARGS__)
- #define video_stats_info(...) ex_video_stats_log(1, __FILE__, __LINE__, __VA_ARGS__)
- #define video_stats_warn(...) ex_video_stats_log(2, __FILE__, __LINE__, __VA_ARGS__)
- #define video_stats_error(...) ex_video_stats_log(3, __FILE__, __LINE__, __VA_ARGS__)
- static float compute_bw(struct timeval *orig, unsigned int *bytes, const struct timeval *current){
- float bw;
- float time;
- time=(float)((double)(current->tv_sec - orig->tv_sec) +
- ((double)(current->tv_usec - orig->tv_usec)*1e-6));
- bw=((float)*bytes)*8/(time+0.0001f);
- /*+0.0001 avoids a division by zero without changing the results significatively*/
- *orig=*current;
- return bw;
- }
- static void compute_recv_bandwidth(StreamBandwidthStats *stats, const struct timeval *current) {
- stats->download_bw = compute_bw(&stats->recv_bw_start, &stats->recv_bytes, current);
- stats->recv_bytes = 0;
- stats->average_download_bw = (stats->average_download_bw==0) ?
- stats->download_bw :
- (1 - BW_GAMMA) * stats->average_download_bw + BW_GAMMA * stats->download_bw;
- }
- static void compute_send_bandwidth(StreamBandwidthStats *stats, const struct timeval *current) {
- stats->upload_bw = compute_bw(&stats->send_bw_start, &stats->sent_bytes, current);
- stats->sent_bytes = 0;
- stats->average_upload_bw = (stats->average_upload_bw==0) ?
- stats->upload_bw :
- (1 - BW_GAMMA) * stats->average_upload_bw + BW_GAMMA * stats->upload_bw;
- }
- void video_stats_init(VideoStatsLogCallBack *log_func){
- if (g_stats == NULL){
- g_stats = (VideoStats *)malloc(sizeof(VideoStats));
- memset(g_stats, 0, sizeof(VideoStats));
- video_stats_setup_log(log_func);
- g_stats->run = 1;
- g_stats->thr = su_create_thread(NULL, video_stats_loop_event, g_stats);
- }
- }
- void video_stats_uninit(){
- if (g_stats != NULL){
- g_stats->run = 0;
- while (g_stats->run == 0){
- su_sleep(0, 10000);
- }
-
- free(g_stats);
- g_stats = NULL;
- }
- }
- float video_stats_bandwidth_compute_loss_rate(rtcp_statistics *rtcp_stat){
- unsigned int cur_loss;
- unsigned int cur_seq;
- unsigned int expected;
- float loss_percent;
- if (g_stats != NULL) {
- cur_loss= rtcp_stat->total_packet_lost;
- cur_seq = ((unsigned int)rtcp_stat->seq_circles << 16 | (unsigned int)rtcp_stat->last_seq);
- expected = cur_seq - g_stats->rtcp_stats.seq_begin;
- if (expected == 0) return 0;
- g_stats->rtcp_stats.last_loss_percent = 100.0f*(float)(cur_loss - g_stats->rtcp_stats.loss_begin) / (float)expected;
- g_stats->rtcp_stats.seq_begin = cur_seq;
- g_stats->rtcp_stats.loss_begin = cur_loss;
- return g_stats->rtcp_stats.last_loss_percent;
- }
- return -1;
- }
- static float video_stats_bandwidth_compute_recv_bandwidth(){
- struct timeval current;
- gettimeofday(¤t,NULL);
- if (g_stats != NULL) {
- compute_recv_bandwidth(&g_stats->rtp_stats, ¤t);
- compute_recv_bandwidth(&g_stats->rtcp_stats, ¤t);
- return g_stats->rtp_stats.download_bw + g_stats->rtcp_stats.download_bw;
- }
- return -1;
- }
- static float video_stats_bandwidth_compute_send_bandwidth(){
- struct timeval current;
- gettimeofday(¤t,NULL);
- if (g_stats != NULL) {
- compute_send_bandwidth(&g_stats->rtp_stats, ¤t);
- compute_send_bandwidth(&g_stats->rtcp_stats, ¤t);
- return g_stats->rtp_stats.download_bw + g_stats->rtcp_stats.download_bw;
- }
- return -1;
- }
- //huchen comment, immediately bandwidth
- static float video_stats_bandwidth_get_recv_bandwidth(){
- if (g_stats != NULL) {
- return g_stats->rtp_stats.download_bw + g_stats->rtcp_stats.download_bw;
- }
- return -1;
- }
- static float video_stats_bandwidth_get_send_bandwidth(){
- if (g_stats != NULL) {
- return g_stats->rtp_stats.upload_bw + g_stats->rtcp_stats.upload_bw;
- }
- return -1;
- }
- //huchen comment, mean smooth bandwidth
- static float video_stats_bandwidth_get_recv_bandwidth_smooth(){
- if (g_stats != NULL) {
- return g_stats->rtp_stats.average_download_bw + g_stats->rtcp_stats.average_download_bw;
- }
- return -1;
- }
- static float video_stats_bandwidth_get_send_bandwidth_smooth(){
- if (g_stats != NULL) {
- return g_stats->rtp_stats.average_upload_bw + g_stats->rtcp_stats.average_upload_bw;
- }
- return -1;
- }
- void video_stats_bandwidth_update_recv_rtp_bytes(size_t nbytes){
- if (g_stats != NULL) {
- 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)) {
- gettimeofday(&g_stats->rtp_stats.recv_bw_start, NULL);
- }
- g_stats->rtp_stats.recv_bytes += (unsigned int)(nbytes + IP_UDP_HEADER_SIZE + RTP_HEADER_SIZE);
- }
- }
- void video_stats_bandwidth_update_recv_rtcp_bytes(size_t nbytes){
- if (g_stats != NULL) {
- 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)) {
- gettimeofday(&g_stats->rtcp_stats.recv_bw_start, NULL);
- }
- g_stats->rtcp_stats.recv_bytes += (unsigned int)(nbytes + IP_UDP_HEADER_SIZE + RTP_HEADER_SIZE);
- }
- }
- void video_stats_bandwidth_update_send_rtp_bytes(int nbytes){
- if (g_stats != NULL) {
- 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)) {
- /* Initialize bandwidth computing time when has not been started yet. */
- gettimeofday(&g_stats->rtp_stats.send_bw_start, NULL);
- }
- g_stats->rtp_stats.sent_bytes += nbytes + IP_UDP_HEADER_SIZE + RTP_HEADER_SIZE;
- }
- }
- void video_stats_bandwidth_update_send_rtcp_bytes(int nbytes){
- if (g_stats != NULL) {
- 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)) {
- /* Initialize bandwidth computing time when has not been started yet. */
- gettimeofday(&g_stats->rtcp_stats.send_bw_start, NULL);
- }
- g_stats->rtcp_stats.sent_bytes += nbytes + IP_UDP_HEADER_SIZE + RTP_HEADER_SIZE;
- }
- }
- //接收相关统计
- ReceiverStats *video_stats_receiver_get_stats(){
- if (g_stats != NULL) {
- return &g_stats->receiver_stats;
- }
- return NULL;
- }
- void video_stats_receiver_on_started(int64_t start_ms, ReceiverConfigStats *config){
- if (g_stats != NULL) {
- g_stats->receiver_stats.start_ms_ = start_ms;
-
- memcpy(&g_stats->receiver_stats.config_stats, config, sizeof(ReceiverConfigStats));
- }
- }
- void video_stats_receiver_on_stopped(int64_t stop_ms){
- if (g_stats != NULL) {
- g_stats->receiver_stats.stop_ms_ = stop_ms;
- }
- }
- void video_stats_receiver_on_incoming_packet(int64_t recv_time_ms){
- if (g_stats != NULL) {
- if (g_stats->receiver_stats.first_frame_received_time_ms_ == 0){
- g_stats->receiver_stats.first_frame_received_time_ms_ = recv_time_ms;
- }
- g_stats->receiver_stats.last_frame_received_time_ms_ = recv_time_ms;
- g_stats->receiver_stats.received_packet_counts++;
- }
- }
- void video_stats_receiver_on_decoded_frame(int64_t decoded_time_ms, int64_t decode_duration_ms, int is_key){
- if (g_stats != NULL) {
- if (g_stats->receiver_stats.first_decoded_frame_time_ms_ == 0){
- g_stats->receiver_stats.first_decoded_frame_time_ms_ = decoded_time_ms;
- }
- g_stats->receiver_stats.last_decoded_frame_time_ms_ = decoded_time_ms;
- g_stats->receiver_stats.last_decode_duration_ms = decode_duration_ms;
- if (is_key) {
- g_stats->receiver_stats.key_frames_counts++;
- }else {
- g_stats->receiver_stats.delta_frames_counts++;
- }
- g_stats->receiver_stats.decoded_frame_counts++;
- }
- }
- void video_stats_receiver_on_rendered_frame(int64_t render_time_ms, int64_t render_duration_ms){
- if (g_stats != NULL) {
- if (g_stats->receiver_stats.first_render_frame_time_ms_ == 0){
- g_stats->receiver_stats.first_render_frame_time_ms_ = render_time_ms;
- }
- g_stats->receiver_stats.last_render_frame_time_ms_ = render_time_ms;
- g_stats->receiver_stats.last_render_duration_ms = render_duration_ms;
-
- g_stats->receiver_stats.render_frame_counts++;
- }
- }
- void video_stats_receiver_on_report_cc_bitrate(int bitrate){
- if (g_stats != NULL) {
- g_stats->receiver_stats.last_report_cc_bitrate = bitrate;
- }
- }
- //发送相关统计
- SenderStats *video_stats_sender_get_stats(){
- if (g_stats != NULL) {
- return &g_stats->sender_stats;
- }
- return NULL;
- }
- void video_stats_sender_on_started(int64_t start_ms, SenderConfigStats *config){
- if (g_stats != NULL) {
- g_stats->sender_stats.start_ms_ = start_ms;
-
- memcpy(&g_stats->sender_stats.config_stats, config, sizeof(SenderConfigStats));
- }
- }
- void video_stats_sender_on_stopped(int64_t stop_ms){
- if (g_stats != NULL) {
- g_stats->sender_stats.stop_ms_ = stop_ms;
- }
- }
- void video_stats_sender_on_sent_packet(int64_t sent_time_ms){
- if (g_stats != NULL) {
- if (g_stats->sender_stats.first_frame_sent_time_ms_ == 0){
- g_stats->sender_stats.first_frame_sent_time_ms_ = sent_time_ms;
- }
- g_stats->sender_stats.last_frame_sent_time_ms_ = sent_time_ms;
- g_stats->sender_stats.sent_packet_counts++;
- }
- }
- void video_stats_sender_on_encoded_frame(int64_t encoded_time_ms, int64_t encode_duration_ms, int is_key){
- if (g_stats != NULL) {
- if (g_stats->sender_stats.first_encoded_frame_time_ms_ == 0){
- g_stats->sender_stats.first_encoded_frame_time_ms_ = encoded_time_ms;
- }
- g_stats->sender_stats.last_encoded_frame_time_ms_ = encoded_time_ms;
- g_stats->sender_stats.last_encode_duration_ms = encode_duration_ms;
- if (is_key) {
- g_stats->sender_stats.key_frames_counts++;
- }else {
- g_stats->sender_stats.delta_frames_counts++;
- }
- g_stats->sender_stats.encoded_frame_counts++;
- }
- }
- void video_stats_sender_on_encoder_rate_changed(int allocation_fps, int allocation_bitrate){
- if (g_stats != NULL) {
- g_stats->sender_stats.last_allocation_bitrate = allocation_bitrate;
- g_stats->sender_stats.last_allocation_fps = allocation_fps;
- }
- }
- void video_stats_sender_on_frame_dropped(int cap_drop, int framedropper_drop){
- if (g_stats != NULL) {
- g_stats->sender_stats.cap_drop_frames_counts += cap_drop;
- g_stats->sender_stats.framedropper_drop_frames_counts += framedropper_drop;
- }
- }
- static void video_stats_heartbeat(VideoStats* s, int64_t now_ts)
- {
- uint32_t delay;
- if (s->stat_ts + 20*1000 < now_ts){
- delay = (uint32_t)(now_ts - s->stat_ts);
- s->stat_ts = now_ts;
- video_stats_bandwidth_compute_recv_bandwidth();
- video_stats_bandwidth_compute_send_bandwidth();
- //print stats
- //sender
- video_stats_debug("video_stats: ******************************sender_stats: \r\n");
- video_stats_debug("video_stats: send start_ms = %I64d stop_ms = %I64d. \r\n",
- g_stats->sender_stats.start_ms_, g_stats->sender_stats.stop_ms_);
- video_stats_debug("video_stats: send config: local_pt = %u remote_ip = %lu remote_port = %d mtu = %d. \r\n",
- g_stats->sender_stats.config_stats.local_pt, g_stats->sender_stats.config_stats.remote_ip,
- g_stats->sender_stats.config_stats.remote_rtp_port, g_stats->sender_stats.config_stats.mtu);
- video_stats_debug("video_stats: send config: tx = %d x %d capture = %d x %d. \r\n",
- g_stats->sender_stats.config_stats.tx_width, g_stats->sender_stats.config_stats.tx_height,
- g_stats->sender_stats.config_stats.capture_width, g_stats->sender_stats.config_stats.capture_height);
- video_stats_debug("video_stats: send config: fps_den = %d fps_num = %d bit_rate = %d. \r\n",
- g_stats->sender_stats.config_stats.fps_den, g_stats->sender_stats.config_stats.fps_num,
- g_stats->sender_stats.config_stats.bit_rate);
-
- video_stats_debug("video_stats: first_frame_sent_time_ms = %I64d last_frame_sent_time_ms = %I64d. \r\n",
- g_stats->sender_stats.first_frame_sent_time_ms_, g_stats->sender_stats.last_frame_sent_time_ms_);
- video_stats_debug("video_stats: first_encoded_frame_time_ms = %I64d last_encoded_frame_time_ms = %I64d. \r\n",
- g_stats->sender_stats.first_encoded_frame_time_ms_, g_stats->sender_stats.last_encoded_frame_time_ms_);
- video_stats_debug("video_stats: last_encoded_key_frame_time_ms = %I64d last_encode_duration_ms = %I64d. \r\n",
- g_stats->sender_stats.last_encoded_key_frame_time_ms_, g_stats->sender_stats.last_encode_duration_ms);
-
- video_stats_debug("video_stats: sent_packet_counts = %I64d encoded_frame_counts = %I64d. \r\n",
- g_stats->sender_stats.sent_packet_counts, g_stats->sender_stats.encoded_frame_counts);
- video_stats_debug("video_stats: last_allocation_fps = %d last_allocation_bitrate = %d. \r\n",
- g_stats->sender_stats.last_allocation_fps, g_stats->sender_stats.last_allocation_bitrate);
- video_stats_debug("video_stats: send key_frames_counts = %d delta_frames_counts = %d. \r\n",
- g_stats->sender_stats.key_frames_counts, g_stats->sender_stats.delta_frames_counts);
- video_stats_debug("video_stats: send cap_drop_frames_counts = %d framedropper_drop_frames_counts = %d. \r\n",
- g_stats->sender_stats.cap_drop_frames_counts, g_stats->sender_stats.framedropper_drop_frames_counts);
- video_stats_debug("video_stats: send bandwidth_smooth = %f kbits/s, send bandwidth = %f kbits/s \r\n",
- video_stats_bandwidth_get_send_bandwidth_smooth()/1000,
- video_stats_bandwidth_get_send_bandwidth()/1000);
- //receiver
- video_stats_debug("video_stats: ******************************receiver_stats: \r\n");
- video_stats_debug("video_stats: recv start_ms = %I64d stop_ms = %I64d. \r\n",
- g_stats->receiver_stats.start_ms_, g_stats->receiver_stats.stop_ms_);
- video_stats_debug("video_stats: recv config: remote_pt = %u local_ip = %lu local_port = %d bit_rate = %d. \r\n",
- g_stats->receiver_stats.config_stats.remote_pt, g_stats->receiver_stats.config_stats.local_ip,
- g_stats->receiver_stats.config_stats.local_rtp_port, g_stats->receiver_stats.config_stats.bit_rate);
- video_stats_debug("video_stats: recv config: rx = %d x %d. \r\n",
- g_stats->receiver_stats.config_stats.rx_width, g_stats->receiver_stats.config_stats.rx_height);
-
- video_stats_debug("video_stats: first_frame_received_time_ms = %I64d last_frame_received_time_ms = %I64d. \r\n",
- g_stats->receiver_stats.first_frame_received_time_ms_, g_stats->receiver_stats.last_frame_received_time_ms_);
- video_stats_debug("video_stats: first_decoded_frame_time_ms = %I64d last_decoded_frame_time_ms = %I64d. \r\n",
- g_stats->receiver_stats.first_decoded_frame_time_ms_, g_stats->receiver_stats.last_decoded_frame_time_ms_);
- video_stats_debug("video_stats: last_decoded_key_frame_time_ms = %I64d. \r\n",
- g_stats->receiver_stats.last_decoded_key_frame_time_ms_);
- video_stats_debug("video_stats: received_packet_counts = %I64d decoded_frame_counts = %I64d. \r\n",
- g_stats->receiver_stats.received_packet_counts, g_stats->receiver_stats.decoded_frame_counts);
- video_stats_debug("video_stats: recv key_frames_counts = %d delta_frames_counts = %d. \r\n",
- g_stats->receiver_stats.key_frames_counts, g_stats->receiver_stats.delta_frames_counts);
- video_stats_debug("video_stats: recv last_report_cc_bitrate = %d. \r\n",
- g_stats->receiver_stats.last_report_cc_bitrate);
- video_stats_debug("video_stats: first_render_frame_time_ms = %I64d last_render_frame_time_ms = %I64d. \r\n",
- g_stats->receiver_stats.first_render_frame_time_ms_, g_stats->receiver_stats.last_render_frame_time_ms_);
- video_stats_debug("video_stats: last_render_duration_ms = %I64d render_frame_counts = %I64d. \r\n",
- g_stats->receiver_stats.last_render_duration_ms, g_stats->receiver_stats.render_frame_counts);
-
- video_stats_debug("video_stats: recv bandwidth_smooth = %f kbits/s, recv bandwidth = %f kbits/s \r\n",
- video_stats_bandwidth_get_recv_bandwidth_smooth()/1000,
- video_stats_bandwidth_get_recv_bandwidth()/1000);
- video_stats_debug("video_stats: last_loss_percent = %f. \r\n",
- g_stats->rtcp_stats.last_loss_percent);
- video_stats_debug("video_stats: ******************************receiver_stats end. \r\n");
- }
- }
- static void* video_stats_loop_event(void* arg)
- {
- VideoStats* s = (VideoStats*)arg;
- int64_t now_ts = 0, prev_ts = 0;
- prev_ts = now_ts = GET_SYS_MS();
- while (s->run == 1){
- now_ts = GET_SYS_MS();
- if (now_ts >= prev_ts + 5){
- video_stats_heartbeat(s, now_ts);
- prev_ts = now_ts;
- }
- Sleep(5);
- }
- s->run = -1;
- return NULL;
- }
|