| Index: webrtc/media/base/videoadapter.cc
|
| diff --git a/webrtc/media/base/videoadapter.cc b/webrtc/media/base/videoadapter.cc
|
| index 8f7288dc590290fe40213b998b6a383b5a3147bc..660df8ad673e8f40668d8f150722cb21082073ee 100644
|
| --- a/webrtc/media/base/videoadapter.cc
|
| +++ b/webrtc/media/base/videoadapter.cc
|
| @@ -26,6 +26,12 @@ namespace {
|
| struct Fraction {
|
| int numerator;
|
| int denominator;
|
| +
|
| + // Determines number of output pixels if both width and height of an input of
|
| + // |input_pixels| pixels is scaled with the fraction numerator / denominator.
|
| + int scale_pixel_count(int input_pixels) {
|
| + return (numerator * numerator * input_pixels) / (denominator * denominator);
|
| + }
|
| };
|
|
|
| // Round |value_to_round| to a multiple of |multiple|. Prefer rounding upwards,
|
| @@ -37,29 +43,54 @@ int roundUp(int value_to_round, int multiple, int max_value) {
|
| : (max_value / multiple * multiple);
|
| }
|
|
|
| -// Generates a scale factor that makes |input_num_pixels| smaller or
|
| -// larger than |target_num_pixels|, depending on the value of |step_up|.
|
| -Fraction FindScale(int input_num_pixels, int target_num_pixels, bool step_up) {
|
| +// Generates a scale factor that makes |input_pixels| close to |target_pixels|,
|
| +// but no higher than |max_pixels|.
|
| +Fraction FindScale(int input_pixels, int target_pixels, int max_pixels) {
|
| // This function only makes sense for a positive target.
|
| - RTC_DCHECK_GT(target_num_pixels, 0);
|
| + RTC_DCHECK_GT(target_pixels, 0);
|
| + RTC_DCHECK_GT(max_pixels, 0);
|
| + RTC_DCHECK_GE(max_pixels, target_pixels);
|
| +
|
| + // Don't scale up original.
|
| + if (target_pixels >= input_pixels)
|
| + return Fraction{1, 1};
|
| +
|
| + Fraction current_scale = Fraction{1, 1};
|
| Fraction best_scale = Fraction{1, 1};
|
| - Fraction last_scale = Fraction{1, 1};
|
| - const float target_scale =
|
| - sqrt(target_num_pixels / static_cast<float>(input_num_pixels));
|
| - while (best_scale.numerator > (target_scale * best_scale.denominator)) {
|
| - last_scale = best_scale;
|
| - if (best_scale.numerator % 3 == 0 && best_scale.denominator % 2 == 0) {
|
| - // Multiply by 2/3
|
| - best_scale.numerator /= 3;
|
| - best_scale.denominator /= 2;
|
| + // The minimum (absolute) difference between the number of output pixels and
|
| + // the target pixel count.
|
| + int min_pixel_diff = std::numeric_limits<int>::max();
|
| + if (input_pixels < max_pixels) {
|
| + // Start condition for 1/1 case, if it is less than max.
|
| + min_pixel_diff = std::abs(input_pixels - target_pixels);
|
| + }
|
| +
|
| + // Alternately scale down by 2/3 and 3/4. This results in fractions which are
|
| + // effectively scalable. For instance, starting at 1280x720 will result in
|
| + // the series (3/4) => 960x540, (1/2) => 640x360, (3/8) => 480x270,
|
| + // (1/4) => 320x180, (3/16) => 240x125, (1/8) => 160x90.
|
| + while (current_scale.scale_pixel_count(input_pixels) > target_pixels) {
|
| + if (current_scale.numerator % 3 == 0 &&
|
| + current_scale.denominator % 2 == 0) {
|
| + // Multiply by 2/3.
|
| + current_scale.numerator /= 3;
|
| + current_scale.denominator /= 2;
|
| } else {
|
| - // Multiply by 3/4
|
| - best_scale.numerator *= 3;
|
| - best_scale.denominator *= 4;
|
| + // Multiply by 3/4.
|
| + current_scale.numerator *= 3;
|
| + current_scale.denominator *= 4;
|
| + }
|
| +
|
| + int output_pixels = current_scale.scale_pixel_count(input_pixels);
|
| + if (output_pixels <= max_pixels) {
|
| + int diff = std::abs(target_pixels - output_pixels);
|
| + if (diff < min_pixel_diff) {
|
| + min_pixel_diff = diff;
|
| + best_scale = current_scale;
|
| + }
|
| }
|
| }
|
| - if (step_up)
|
| - return last_scale;
|
| +
|
| return best_scale;
|
| }
|
| } // namespace
|
| @@ -74,8 +105,8 @@ VideoAdapter::VideoAdapter(int required_resolution_alignment)
|
| previous_width_(0),
|
| previous_height_(0),
|
| required_resolution_alignment_(required_resolution_alignment),
|
| - resolution_request_max_pixel_count_(std::numeric_limits<int>::max()),
|
| - step_up_(false) {}
|
| + resolution_request_target_pixel_count_(std::numeric_limits<int>::max()),
|
| + resolution_request_max_pixel_count_(std::numeric_limits<int>::max()) {}
|
|
|
| VideoAdapter::VideoAdapter() : VideoAdapter(1) {}
|
|
|
| @@ -124,14 +155,11 @@ bool VideoAdapter::AdaptFrameResolution(int in_width,
|
| // OnOutputFormatRequest and OnResolutionRequest.
|
| int max_pixel_count = resolution_request_max_pixel_count_;
|
| if (requested_format_) {
|
| - // TODO(kthelgason): remove the - |step_up_| hack when we change how
|
| - // resolution is requested from VideoSourceProxy.
|
| - // This is required because we must not scale above the requested
|
| - // format so we subtract one when scaling up.
|
| max_pixel_count = std::min(
|
| - max_pixel_count, requested_format_->width * requested_format_->height -
|
| - static_cast<int>(step_up_));
|
| + max_pixel_count, requested_format_->width * requested_format_->height);
|
| }
|
| + int target_pixel_count =
|
| + std::min(resolution_request_target_pixel_count_, max_pixel_count);
|
|
|
| // Drop the input frame if necessary.
|
| if (max_pixel_count <= 0 || !KeepFrame(in_timestamp_ns)) {
|
| @@ -173,8 +201,8 @@ bool VideoAdapter::AdaptFrameResolution(int in_width,
|
| *cropped_height =
|
| std::min(in_height, static_cast<int>(in_width / requested_aspect));
|
| }
|
| - const Fraction scale =
|
| - FindScale(*cropped_width * *cropped_height, max_pixel_count, step_up_);
|
| + const Fraction scale = FindScale((*cropped_width) * (*cropped_height),
|
| + target_pixel_count, max_pixel_count);
|
| // Adjust cropping slightly to get even integer output size and a perfect
|
| // scale factor. Make sure the resulting dimensions are aligned correctly
|
| // to be nice to hardware encoders.
|
| @@ -222,12 +250,13 @@ void VideoAdapter::OnOutputFormatRequest(const VideoFormat& format) {
|
| }
|
|
|
| void VideoAdapter::OnResolutionRequest(
|
| - rtc::Optional<int> max_pixel_count,
|
| - rtc::Optional<int> max_pixel_count_step_up) {
|
| + const rtc::Optional<int>& target_pixel_count,
|
| + const rtc::Optional<int>& max_pixel_count) {
|
| rtc::CritScope cs(&critical_section_);
|
| - resolution_request_max_pixel_count_ = max_pixel_count.value_or(
|
| - max_pixel_count_step_up.value_or(std::numeric_limits<int>::max()));
|
| - step_up_ = static_cast<bool>(max_pixel_count_step_up);
|
| + resolution_request_max_pixel_count_ =
|
| + max_pixel_count.value_or(std::numeric_limits<int>::max());
|
| + resolution_request_target_pixel_count_ =
|
| + target_pixel_count.value_or(resolution_request_max_pixel_count_);
|
| }
|
|
|
| } // namespace cricket
|
|
|