From d1c44356c5d6d572ed660b91af683ed0b136c0cd Mon Sep 17 00:00:00 2001 From: glaznev Date: Thu, 23 Mar 2017 14:40:08 -0700 Subject: [PATCH] Add field trial to update quality scaler QP thresholds for Android HW encoder. BUG=b/36034878 Review-Url: https://codereview.webrtc.org/2764143002 Cr-Commit-Position: refs/heads/master@{#17367} --- .../video_coding/utility/quality_scaler.cc | 24 +++++----- .../src/jni/androidmediaencoder_jni.cc | 45 ++++++++++++++++--- 2 files changed, 51 insertions(+), 18 deletions(-) diff --git a/webrtc/modules/video_coding/utility/quality_scaler.cc b/webrtc/modules/video_coding/utility/quality_scaler.cc index 3dd3dde93a..ff22862bb5 100644 --- a/webrtc/modules/video_coding/utility/quality_scaler.cc +++ b/webrtc/modules/video_coding/utility/quality_scaler.cc @@ -112,6 +112,8 @@ QualityScaler::QualityScaler(AdaptationObserverInterface* observer, RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_); RTC_DCHECK(observer_ != nullptr); check_qp_task_ = new CheckQPTask(this); + LOG(LS_INFO) << "QP thresholds: low: " << thresholds_.low + << ", high: " << thresholds_.high; } QualityScaler::~QualityScaler() { @@ -140,7 +142,6 @@ void QualityScaler::CheckQP() { RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_); // Should be set through InitEncode -> Should be set by now. RTC_DCHECK_GE(thresholds_.low, 0); - LOG(LS_INFO) << "Checking if average QP exceeds threshold"; // Check if we should scale down due to high frame drop. const rtc::Optional drop_rate = framedrop_percent_.GetAverage(); if (drop_rate && *drop_rate >= kFramedropPercentThreshold) { @@ -150,27 +151,28 @@ void QualityScaler::CheckQP() { // Check if we should scale up or down based on QP. const rtc::Optional avg_qp = average_qp_.GetAverage(); - if (avg_qp && *avg_qp > thresholds_.high) { - ReportQPHigh(); - return; - } - if (avg_qp && *avg_qp <= thresholds_.low) { - // QP has been low. We want to try a higher resolution. - ReportQPLow(); - return; + if (avg_qp) { + LOG(LS_INFO) << "Checking average QP " << *avg_qp; + if (*avg_qp > thresholds_.high) { + ReportQPHigh(); + return; + } + if (*avg_qp <= thresholds_.low) { + // QP has been low. We want to try a higher resolution. + ReportQPLow(); + return; + } } } void QualityScaler::ReportQPLow() { RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_); - LOG(LS_INFO) << "QP has been low, asking for higher resolution."; ClearSamples(); observer_->AdaptUp(AdaptationObserverInterface::AdaptReason::kQuality); } void QualityScaler::ReportQPHigh() { RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_); - LOG(LS_INFO) << "QP has been high , asking for lower resolution."; ClearSamples(); observer_->AdaptDown(AdaptationObserverInterface::AdaptReason::kQuality); // If we've scaled down, wait longer before scaling up again. diff --git a/webrtc/sdk/android/src/jni/androidmediaencoder_jni.cc b/webrtc/sdk/android/src/jni/androidmediaencoder_jni.cc index 92406ec107..093966ee43 100644 --- a/webrtc/sdk/android/src/jni/androidmediaencoder_jni.cc +++ b/webrtc/sdk/android/src/jni/androidmediaencoder_jni.cc @@ -86,6 +86,7 @@ namespace { const size_t kFrameDiffThresholdMs = 350; const int kMinKeyFrameInterval = 6; const char kH264HighProfileFieldTrial[] = "WebRTC-H264HighProfile"; +const char kCustomQPThresholdsFieldTrial[] = "WebRTC-CustomQPThresholds"; } // namespace // MediaCodecVideoEncoder is a webrtc::VideoEncoder implementation that uses @@ -180,6 +181,8 @@ class MediaCodecVideoEncoder : public webrtc::VideoEncoder { // Displays encoder statistics. void LogStatistics(bool force_log); + VideoCodecType GetCodecType() const; + #if RTC_DCHECK_IS_ON // Mutex for protecting inited_. It is only used for correctness checking on // debug build. It is used for checking that encoder has been released in the @@ -384,8 +387,7 @@ int32_t MediaCodecVideoEncoder::InitEncode( return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; } // Factory should guard against other codecs being used with us. - const VideoCodecType codec_type = webrtc::PayloadNameToCodecType(codec_.name) - .value_or(webrtc::kVideoCodecUnknown); + const VideoCodecType codec_type = GetCodecType(); RTC_CHECK(codec_settings->codecType == codec_type) << "Unsupported codec " << codec_settings->codecType << " for " << codec_type; @@ -498,6 +500,11 @@ int32_t MediaCodecVideoEncoder::ProcessHWErrorOnEncode() { : WEBRTC_VIDEO_CODEC_ERROR; } +VideoCodecType MediaCodecVideoEncoder::GetCodecType() const { + return webrtc::PayloadNameToCodecType(codec_.name) + .value_or(webrtc::kVideoCodecUnknown); +} + int32_t MediaCodecVideoEncoder::InitEncodeInternal(int width, int height, int kbps, @@ -511,8 +518,7 @@ int32_t MediaCodecVideoEncoder::InitEncodeInternal(int width, JNIEnv* jni = AttachCurrentThreadIfNeeded(); ScopedLocalRefFrame local_ref_frame(jni); - const VideoCodecType codec_type = webrtc::PayloadNameToCodecType(codec_.name) - .value_or(webrtc::kVideoCodecUnknown); + const VideoCodecType codec_type = GetCodecType(); ALOGD << "InitEncodeInternal Type: " << (int)codec_type << ", " << width << " x " << height << ". Bitrate: " << kbps << " kbps. Fps: " << fps; if (kbps == 0) { @@ -1022,9 +1028,7 @@ bool MediaCodecVideoEncoder::DeliverPendingOutputs(JNIEnv* jni) { } // Callback - return encoded frame. - const VideoCodecType codec_type = - webrtc::PayloadNameToCodecType(codec_.name) - .value_or(webrtc::kVideoCodecUnknown); + const VideoCodecType codec_type = GetCodecType(); webrtc::EncodedImageCallback::Result callback_result( webrtc::EncodedImageCallback::Result::OK); if (callback_) { @@ -1186,6 +1190,33 @@ void MediaCodecVideoEncoder::LogStatistics(bool force_log) { webrtc::VideoEncoder::ScalingSettings MediaCodecVideoEncoder::GetScalingSettings() const { + if (webrtc::field_trial::IsEnabled(kCustomQPThresholdsFieldTrial)) { + const VideoCodecType codec_type = GetCodecType(); + std::string experiment_string = + webrtc::field_trial::FindFullName(kCustomQPThresholdsFieldTrial); + ALOGD << "QP custom thresholds: " << experiment_string << " for codec " + << codec_type; + int low_vp8_qp_threshold; + int high_vp8_qp_threshold; + int low_h264_qp_threshold; + int high_h264_qp_threshold; + int parsed_values = sscanf(experiment_string.c_str(), "Enabled-%u,%u,%u,%u", + &low_vp8_qp_threshold, &high_vp8_qp_threshold, + &low_h264_qp_threshold, &high_h264_qp_threshold); + if (parsed_values == 4) { + RTC_CHECK_GT(high_vp8_qp_threshold, low_vp8_qp_threshold); + RTC_CHECK_GT(low_vp8_qp_threshold, 0); + RTC_CHECK_GT(high_h264_qp_threshold, low_h264_qp_threshold); + RTC_CHECK_GT(low_h264_qp_threshold, 0); + if (codec_type == kVideoCodecVP8) { + return VideoEncoder::ScalingSettings(scale_, low_vp8_qp_threshold, + high_vp8_qp_threshold); + } else if (codec_type == kVideoCodecH264) { + return VideoEncoder::ScalingSettings(scale_, low_h264_qp_threshold, + high_h264_qp_threshold); + } + } + } return VideoEncoder::ScalingSettings(scale_); }