| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
| 5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
| 6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
| 7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
| 8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
| 9 */ | 9 */ |
| 10 #include "webrtc/modules/video_coding/utility/quality_scaler.h" | 10 #include "webrtc/modules/video_coding/utility/quality_scaler.h" |
| (...skipping 12 matching lines...) Expand all Loading... |
| 23 static const int kMinDownscaleDimension = 140; | 23 static const int kMinDownscaleDimension = 140; |
| 24 // Initial resolutions corresponding to a bitrate. Aa bit above their actual | 24 // Initial resolutions corresponding to a bitrate. Aa bit above their actual |
| 25 // values to permit near-VGA and near-QVGA resolutions to use the same | 25 // values to permit near-VGA and near-QVGA resolutions to use the same |
| 26 // mechanism. | 26 // mechanism. |
| 27 static const int kVgaBitrateThresholdKbps = 500; | 27 static const int kVgaBitrateThresholdKbps = 500; |
| 28 static const int kVgaNumPixels = 700 * 500; // 640x480 | 28 static const int kVgaNumPixels = 700 * 500; // 640x480 |
| 29 static const int kQvgaBitrateThresholdKbps = 250; | 29 static const int kQvgaBitrateThresholdKbps = 250; |
| 30 static const int kQvgaNumPixels = 400 * 300; // 320x240 | 30 static const int kQvgaNumPixels = 400 * 300; // 320x240 |
| 31 } // namespace | 31 } // namespace |
| 32 | 32 |
| 33 QualityScaler::QualityScaler() | 33 QualityScaler::QualityScaler() : low_qp_threshold_(-1) {} |
| 34 : low_qp_threshold_(-1), framerate_down_(false) {} | |
| 35 | 34 |
| 36 void QualityScaler::Init(int low_qp_threshold, | 35 void QualityScaler::Init(int low_qp_threshold, |
| 37 int high_qp_threshold, | 36 int high_qp_threshold, |
| 38 bool use_framerate_reduction, | |
| 39 int initial_bitrate_kbps, | 37 int initial_bitrate_kbps, |
| 40 int width, | 38 int width, |
| 41 int height, | 39 int height, |
| 42 int fps) { | 40 int fps) { |
| 43 ClearSamples(); | 41 ClearSamples(); |
| 44 low_qp_threshold_ = low_qp_threshold; | 42 low_qp_threshold_ = low_qp_threshold; |
| 45 high_qp_threshold_ = high_qp_threshold; | 43 high_qp_threshold_ = high_qp_threshold; |
| 46 use_framerate_reduction_ = use_framerate_reduction; | |
| 47 downscale_shift_ = 0; | 44 downscale_shift_ = 0; |
| 48 // Use a faster window for upscaling initially (but be more graceful later). | 45 // Use a faster window for upscaling initially (but be more graceful later). |
| 49 // This enables faster initial rampups without risking strong up-down | 46 // This enables faster initial rampups without risking strong up-down |
| 50 // behavior later. | 47 // behavior later. |
| 51 measure_seconds_upscale_ = kMeasureSecondsFastUpscale; | 48 measure_seconds_upscale_ = kMeasureSecondsFastUpscale; |
| 52 const int init_width = width; | 49 const int init_width = width; |
| 53 const int init_height = height; | 50 const int init_height = height; |
| 54 if (initial_bitrate_kbps > 0) { | 51 if (initial_bitrate_kbps > 0) { |
| 55 int init_num_pixels = width * height; | 52 int init_num_pixels = width * height; |
| 56 if (initial_bitrate_kbps < kVgaBitrateThresholdKbps) | 53 if (initial_bitrate_kbps < kVgaBitrateThresholdKbps) |
| 57 init_num_pixels = kVgaNumPixels; | 54 init_num_pixels = kVgaNumPixels; |
| 58 if (initial_bitrate_kbps < kQvgaBitrateThresholdKbps) | 55 if (initial_bitrate_kbps < kQvgaBitrateThresholdKbps) |
| 59 init_num_pixels = kQvgaNumPixels; | 56 init_num_pixels = kQvgaNumPixels; |
| 60 while (width * height > init_num_pixels) { | 57 while (width * height > init_num_pixels) { |
| 61 ++downscale_shift_; | 58 ++downscale_shift_; |
| 62 width /= 2; | 59 width /= 2; |
| 63 height /= 2; | 60 height /= 2; |
| 64 } | 61 } |
| 65 } | 62 } |
| 66 UpdateTargetResolution(init_width, init_height); | 63 UpdateTargetResolution(init_width, init_height); |
| 67 ReportFramerate(fps); | 64 ReportFramerate(fps); |
| 68 target_framerate_ = -1; | |
| 69 } | 65 } |
| 70 | 66 |
| 71 // Report framerate(fps) to estimate # of samples. | 67 // Report framerate(fps) to estimate # of samples. |
| 72 void QualityScaler::ReportFramerate(int framerate) { | 68 void QualityScaler::ReportFramerate(int framerate) { |
| 73 framerate_ = framerate; | 69 framerate_ = framerate; |
| 74 UpdateSampleCounts(); | 70 UpdateSampleCounts(); |
| 75 } | 71 } |
| 76 | 72 |
| 77 void QualityScaler::ReportQP(int qp) { | 73 void QualityScaler::ReportQP(int qp) { |
| 78 framedrop_percent_.AddSample(0); | 74 framedrop_percent_.AddSample(0); |
| 79 average_qp_downscale_.AddSample(qp); | 75 average_qp_downscale_.AddSample(qp); |
| 80 average_qp_upscale_.AddSample(qp); | 76 average_qp_upscale_.AddSample(qp); |
| 81 } | 77 } |
| 82 | 78 |
| 83 void QualityScaler::ReportDroppedFrame() { | 79 void QualityScaler::ReportDroppedFrame() { |
| 84 framedrop_percent_.AddSample(100); | 80 framedrop_percent_.AddSample(100); |
| 85 } | 81 } |
| 86 | 82 |
| 87 void QualityScaler::OnEncodeFrame(const VideoFrame& frame) { | 83 void QualityScaler::OnEncodeFrame(const VideoFrame& frame) { |
| 88 // Should be set through InitEncode -> Should be set by now. | 84 // Should be set through InitEncode -> Should be set by now. |
| 89 assert(low_qp_threshold_ >= 0); | 85 assert(low_qp_threshold_ >= 0); |
| 90 assert(num_samples_upscale_ > 0); | 86 assert(num_samples_upscale_ > 0); |
| 91 assert(num_samples_downscale_ > 0); | 87 assert(num_samples_downscale_ > 0); |
| 92 | 88 |
| 93 // Update scale factor. | 89 // Update scale factor. |
| 94 int avg_drop = 0; | 90 int avg_drop = 0; |
| 95 int avg_qp = 0; | 91 int avg_qp = 0; |
| 96 | 92 |
| 97 // When encoder consistently overshoots, framerate reduction and spatial | |
| 98 // resizing will be triggered to get a smoother video. | |
| 99 if ((framedrop_percent_.GetAverage(num_samples_downscale_, &avg_drop) && | 93 if ((framedrop_percent_.GetAverage(num_samples_downscale_, &avg_drop) && |
| 100 avg_drop >= kFramedropPercentThreshold) || | 94 avg_drop >= kFramedropPercentThreshold) || |
| 101 (average_qp_downscale_.GetAverage(num_samples_downscale_, &avg_qp) && | 95 (average_qp_downscale_.GetAverage(num_samples_downscale_, &avg_qp) && |
| 102 avg_qp > high_qp_threshold_)) { | 96 avg_qp > high_qp_threshold_)) { |
| 103 // Reducing frame rate before spatial resolution change. | 97 AdjustScale(false); |
| 104 // Reduce frame rate only when it is above a certain number. | |
| 105 // Only one reduction is allowed for now. | |
| 106 // TODO(jackychen): Allow more than one framerate reduction. | |
| 107 if (use_framerate_reduction_ && !framerate_down_ && framerate_ >= 20) { | |
| 108 target_framerate_ = framerate_ / 2; | |
| 109 framerate_down_ = true; | |
| 110 // If frame rate has been updated, clear the buffer. We don't want | |
| 111 // spatial resolution to change right after frame rate change. | |
| 112 ClearSamples(); | |
| 113 } else { | |
| 114 AdjustScale(false); | |
| 115 } | |
| 116 } else if (average_qp_upscale_.GetAverage(num_samples_upscale_, &avg_qp) && | 98 } else if (average_qp_upscale_.GetAverage(num_samples_upscale_, &avg_qp) && |
| 117 avg_qp <= low_qp_threshold_) { | 99 avg_qp <= low_qp_threshold_) { |
| 118 if (use_framerate_reduction_ && framerate_down_) { | 100 AdjustScale(true); |
| 119 target_framerate_ = -1; | |
| 120 framerate_down_ = false; | |
| 121 ClearSamples(); | |
| 122 } else { | |
| 123 AdjustScale(true); | |
| 124 } | |
| 125 } | 101 } |
| 126 UpdateTargetResolution(frame.width(), frame.height()); | 102 UpdateTargetResolution(frame.width(), frame.height()); |
| 127 } | 103 } |
| 128 | 104 |
| 129 QualityScaler::Resolution QualityScaler::GetScaledResolution() const { | 105 QualityScaler::Resolution QualityScaler::GetScaledResolution() const { |
| 130 return res_; | 106 return res_; |
| 131 } | 107 } |
| 132 | 108 |
| 133 int QualityScaler::GetTargetFramerate() const { | |
| 134 return target_framerate_; | |
| 135 } | |
| 136 | |
| 137 const VideoFrame& QualityScaler::GetScaledFrame(const VideoFrame& frame) { | 109 const VideoFrame& QualityScaler::GetScaledFrame(const VideoFrame& frame) { |
| 138 Resolution res = GetScaledResolution(); | 110 Resolution res = GetScaledResolution(); |
| 139 if (res.width == frame.width()) | 111 if (res.width == frame.width()) |
| 140 return frame; | 112 return frame; |
| 141 | 113 |
| 142 scaler_.Set(frame.width(), frame.height(), res.width, res.height, kI420, | 114 scaler_.Set(frame.width(), frame.height(), res.width, res.height, kI420, |
| 143 kI420, kScaleBox); | 115 kI420, kScaleBox); |
| 144 if (scaler_.Scale(frame, &scaled_frame_) != 0) | 116 if (scaler_.Scale(frame, &scaled_frame_) != 0) |
| 145 return frame; | 117 return frame; |
| 146 | 118 |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 189 downscale_shift_ = 0; | 161 downscale_shift_ = 0; |
| 190 if (!up) { | 162 if (!up) { |
| 191 // Hit first downscale, start using a slower threshold for going up. | 163 // Hit first downscale, start using a slower threshold for going up. |
| 192 measure_seconds_upscale_ = kMeasureSecondsUpscale; | 164 measure_seconds_upscale_ = kMeasureSecondsUpscale; |
| 193 UpdateSampleCounts(); | 165 UpdateSampleCounts(); |
| 194 } | 166 } |
| 195 ClearSamples(); | 167 ClearSamples(); |
| 196 } | 168 } |
| 197 | 169 |
| 198 } // namespace webrtc | 170 } // namespace webrtc |
| OLD | NEW |