From df8878af00e9758ef51c4ed945a74da88f7a1c19 Mon Sep 17 00:00:00 2001 From: Mamadou DIOP Date: Thu, 10 Mar 2016 01:31:45 +0100 Subject: Add support for resolution change based on network congestion (enabled on 'tch' build only) --- tinyDAV/src/video/tdav_session_video.c | 165 +++++++++++++++++++++------------ 1 file changed, 107 insertions(+), 58 deletions(-) (limited to 'tinyDAV') diff --git a/tinyDAV/src/video/tdav_session_video.c b/tinyDAV/src/video/tdav_session_video.c index 920d005..d0d65f2 100755 --- a/tinyDAV/src/video/tdav_session_video.c +++ b/tinyDAV/src/video/tdav_session_video.c @@ -755,6 +755,9 @@ static int _tdav_session_video_codec_set_int32(tdav_session_video_t* self, const ret = tmedia_producer_set(base->producer, param); } else { + if (tsk_strniequals(key, "out-size", 8)) { + self->encoder.size_changed = tsk_true; + } ret = tmedia_codec_set((tmedia_codec_t*)(self)->encoder.codec, param); } } @@ -1430,7 +1433,7 @@ static int _tdav_session_video_timer_cb(const void* arg, tsk_timer_id_t timer_id uint64_t bw_est_kbps; tsk_bool_t cavgneg, update_qavg = tsk_false, update_size = tsk_false; unsigned enc_avg_time; - int32_t bw_up_base_kbps, bw_up_ref_kbps; + int32_t bw_up_base_kbps, bw_up_ref_kbps, bw_up_new_kbps; tsk_mutex_lock(video->h_mutex_qos); q1 = video->q1_n ? session->qos_metrics.q1 : 1.f; @@ -1469,60 +1472,6 @@ static int _tdav_session_video_timer_cb(const void* arg, tsk_timer_id_t timer_id session->qos_metrics.last_update_time = tsk_time_now(); tsk_mutex_unlock(video->h_mutex_qos); -#if BUILD_TYPE_TCH - { - unsigned best_enc_time; - float vs_weight; - - // Check if encoding time is too high or low - best_enc_time = 1000 / (codec->out.fps); - if (enc_avg_time > (best_enc_time + (best_enc_time >> 2))) { /* Too slow */ - if (++video->num_enc_avg_time_high >= 2) { - update_size = tsk_true; - vs_weight = ((best_enc_time + (best_enc_time >> 2)) / (float)enc_avg_time); - TSK_DEBUG_INFO("_tdav_session_video_timer_cb: upsample the video size: %f", vs_weight); - video->num_enc_avg_time_high = 0; - } - } - else { /* Too fast */ - if (enc_avg_time < (best_enc_time - (best_enc_time >> 1))) { - if (--video->num_enc_avg_time_high <= -2) { - if (enc_avg_time != 0.f && (codec->out.width * codec->out.height) < (video->neg_width * video->neg_height)) { // video size downsampled in the past? - update_size = tsk_true; - vs_weight = ((best_enc_time - (best_enc_time >> 1)) / (float)enc_avg_time); - TSK_DEBUG_INFO("_tdav_session_video_timer_cb: downsample the video size: %f", vs_weight); - } - video->num_enc_avg_time_high = 0; - } - } - } - - // Update video size - if (update_size) { - unsigned new_w, new_h, new_s; - char size[128] = {'\0'}; - tmedia_param_t* param; - new_w = (((unsigned)(codec->out.width * vs_weight)) + 16) & -16; // +16 instead of +15 to make sure the size will be >= 16 - new_h = (((unsigned)(codec->out.height * vs_weight)) + 16) & -16; - new_s = (new_w & 0xFFFF) | (new_h << 16); - TSK_DEBUG_INFO("_tdav_session_video_timer_cb: new video size: (%u, %u), neg size: (%u, %u)", new_w, new_h, video->neg_width, video->neg_height); - param = tmedia_param_create(tmedia_pat_set, - tmedia_video, - tmedia_ppt_codec, - tmedia_pvt_int32, - "out-size", - (void*)&new_s); - if (param) { - tsk_mutex_lock(video->encoder.h_mutex); - tmedia_codec_set(TMEDIA_CODEC(codec), param); - video->encoder.size_changed = tsk_true; - tsk_mutex_unlock(video->encoder.h_mutex); - TSK_OBJECT_SAFE_FREE(param); - } - } - } -#endif - // Compute the new qvag value qavg = q1 * 0.1f + q2 * 0.4f + q3 * 0.1f + q4 * 0.0f + q5 * 0.4f; cavg = (qavg - session->qos_metrics.qvag); @@ -1549,11 +1498,14 @@ static int _tdav_session_video_timer_cb(const void* arg, tsk_timer_id_t timer_id update_qavg = (cavg > 0.1f); } - bw_up_base_kbps = tmedia_get_video_bandwidth_kbps_2(codec->out.width, codec->out.height, codec->out.fps); + // Do not use "codec->out.width" and "codec->out.height" to compute "bw_up_base_kbps" as these values could be changed when + // adapt. resolution is enabled + bw_up_base_kbps = tmedia_get_video_bandwidth_kbps_2(video->neg_width, video->neg_height, codec->out.fps); bw_up_ref_kbps = TMEDIA_CODEC(codec)->bandwidth_max_upload; if (bw_up_ref_kbps < 0 || bw_up_ref_kbps == INT_MAX) { - bw_up_ref_kbps = tmedia_get_video_bandwidth_kbps_2(codec->out.width, codec->out.height, codec->out.fps); + bw_up_ref_kbps = bw_up_base_kbps; } + bw_up_new_kbps = bw_up_ref_kbps; // default value will be update depending on qavg // Unconditionally decrease the bandwidth when the quality is < 90% // bandwidth will decrease regardless qavg value as the ref. value is recursive @@ -1563,7 +1515,7 @@ static int _tdav_session_video_timer_cb(const void* arg, tsk_timer_id_t timer_id if (update_qavg) { // Update the upload bandwidth - int32_t bw_up_new_kbps, bw_up_max_kbps = base->bandwidth_max_upload_kbps; // user-defined maximum + int32_t bw_up_max_kbps = base->bandwidth_max_upload_kbps; // user-defined maximum // When the qavg is within ]90-100]% we increase the ref. bw if (qavg > 0.9f) { @@ -1580,6 +1532,103 @@ static int _tdav_session_video_timer_cb(const void* arg, tsk_timer_id_t timer_id session->qos_metrics.qvag = qavg; } //!\ update qavg only if condition "c" is true + + + /* Update size depending on bw */ +#if BUILD_TYPE_TCH + { + // A video quality is defined by MR (Motion Rank) like this: + // MR(#1)->poor, #2->acceptable, #4->good, #6->excellent .... + // Higher the MR is higher is the bandwidth and the quality + // The algorithm to change the video size depending on the bandwidth is straightforward: + // 1/ Compute the right bandwidth (bw_up_new_kbps) using Qavg as done above + // 2/ From the current video resolution (width, height), framerate(fps) and bandwidth(bw_up_new_kbps) compute the MR (a.k.a quality) + // 3/ If the computed MR is <=#1(poor) then, downsample the resolution to have MR=#2(acceptable) + // 4/ If the computed MR is >=#4 and the current resolution is lower than what was negotiated then, upsample the resolution to have MR=#2 (at most) + // In short: we want MR to stay within [2, %[ + int32_t mr = tmedia_get_video_motion_rank(codec->out.width, codec->out.height, codec->out.fps, bw_up_new_kbps); + int32_t mr_diff = 0; + update_size = ((mr <= 1) || (mr >= 4 && (codec->out.width * codec->out.height) < (video->neg_width * video->neg_height))); + if (update_size) { + mr_diff = (mr - 2); + } + if (mr_diff != 0) { + unsigned new_w, new_h, min_w, min_h, max_w, max_h; + if (mr_diff > 0) { + new_w = ((codec->out.width << mr_diff) + 15) & -16; + new_h = ((codec->out.height << mr_diff) + 15) & -16; + } + else { + new_w = ((codec->out.width >> (-mr_diff)) + 15) & -16; + new_h = ((codec->out.height >> (-mr_diff)) + 15) & -16; + } + min_w = 16; + min_h = 16; + max_w = video->neg_width; + max_h = video->neg_height; + if (tmedia_defaults_get_adapt_video_size_range_enabled()) { + tmedia_pref_video_size_t min, max; + if (tmedia_defaults_get_pref_video_size_range(&min, &max) == 0) { + tmedia_video_get_size(min, &min_w, &min_h); + tmedia_video_get_size(max, &max_w, &max_h); + } + } + new_w = TSK_CLAMP(min_w, new_w, max_w); + new_h = TSK_CLAMP(min_h, new_h, max_h); + if ((new_w * new_h) < (codec->out.width * codec->out.height)) { // make sure we'll set lower resolution after clipping + TSK_DEBUG_INFO("_tdav_session_video_timer_cb: [[size change based on bandwidth]] new video size: (%u, %u), neg size: (%u, %u)", new_w, new_h, video->neg_width, video->neg_height); + tsk_mutex_lock(video->encoder.h_mutex); + _tdav_session_video_codec_set_int32(video, "out-size", (int32_t)((new_w & 0xFFFF) | (new_h << 16))); + tsk_mutex_unlock(video->encoder.h_mutex); + } + } + } +#endif /* BUILD_TYPE_TCH */ + + /* Update size depending cpu usage */ +#if BUILD_TYPE_TCH + if (!update_size) { + unsigned best_enc_time; + float vs_weight; + + // Check if encoding time is too high or low + best_enc_time = 1000 / (codec->out.fps); + if (enc_avg_time > (best_enc_time + (best_enc_time >> 2))) { /* Too slow */ + if (++video->num_enc_avg_time_high >= 2) { + update_size = tsk_true; + vs_weight = ((best_enc_time + (best_enc_time >> 2)) / (float)enc_avg_time); + TSK_DEBUG_INFO("_tdav_session_video_timer_cb: upsample the video size: %f", vs_weight); + video->num_enc_avg_time_high = 0; + } + } + else { /* Too fast */ + if (enc_avg_time < (best_enc_time - (best_enc_time >> 1))) { + if (--video->num_enc_avg_time_high <= -2) { + if (enc_avg_time != 0.f && (codec->out.width * codec->out.height) < (video->neg_width * video->neg_height)) { // video size downsampled in the past? + update_size = tsk_true; + vs_weight = ((best_enc_time - (best_enc_time >> 1)) / (float)enc_avg_time); + TSK_DEBUG_INFO("_tdav_session_video_timer_cb: downsample the video size: %f", vs_weight); + } + video->num_enc_avg_time_high = 0; + } + } + } + + // Update video size + if (update_size) { + unsigned new_w, new_h, new_s; + char size[128] = {'\0'}; + new_w = (((unsigned)(codec->out.width * vs_weight)) + 16) & -16; // +16 instead of +15 to make sure the size will be >= 16 + new_h = (((unsigned)(codec->out.height * vs_weight)) + 16) & -16; + new_s = (new_w & 0xFFFF) | (new_h << 16); + TSK_DEBUG_INFO("_tdav_session_video_timer_cb: [[size change based on cpu]] new video size: (%u, %u), neg size: (%u, %u)", new_w, new_h, video->neg_width, video->neg_height); + tsk_mutex_lock(video->encoder.h_mutex); + _tdav_session_video_codec_set_int32(video, "out-size", (int32_t)new_s); + video->encoder.size_changed = tsk_true; + tsk_mutex_unlock(video->encoder.h_mutex); + } + } +#endif /* BUILD_TYPE_TCH */ } tsk_object_unref(TSK_OBJECT(codec)); } -- cgit v1.1