| Index: webrtc/media/base/videoadapter.cc
|
| diff --git a/webrtc/media/base/videoadapter.cc b/webrtc/media/base/videoadapter.cc
|
| index acb0e2c1a19888d758cd2d46893fca9e2b93a477..8f7288dc590290fe40213b998b6a383b5a3147bc 100644
|
| --- a/webrtc/media/base/videoadapter.cc
|
| +++ b/webrtc/media/base/videoadapter.cc
|
| @@ -11,116 +11,73 @@
|
| #include "webrtc/media/base/videoadapter.h"
|
|
|
| #include <algorithm>
|
| +#include <cmath>
|
| #include <cstdlib>
|
| #include <limits>
|
|
|
| +#include "webrtc/base/arraysize.h"
|
| #include "webrtc/base/checks.h"
|
| #include "webrtc/base/logging.h"
|
| +#include "webrtc/base/optional.h"
|
| #include "webrtc/media/base/mediaconstants.h"
|
| #include "webrtc/media/base/videocommon.h"
|
|
|
| namespace {
|
| -
|
| struct Fraction {
|
| int numerator;
|
| int denominator;
|
| };
|
|
|
| -// Scale factors optimized for in libYUV that we accept.
|
| -// Must be sorted in decreasing scale factors for FindScaleLargerThan to work.
|
| -const Fraction kScaleFractions[] = {
|
| - {1, 1},
|
| - {3, 4},
|
| - {1, 2},
|
| - {3, 8},
|
| - {1, 4},
|
| - {3, 16},
|
| -};
|
| -
|
| -// Round |valueToRound| to a multiple of |multiple|. Prefer rounding upwards,
|
| -// but never more than |maxValue|.
|
| -int roundUp(int valueToRound, int multiple, int maxValue) {
|
| - const int roundedValue = (valueToRound + multiple - 1) / multiple * multiple;
|
| - return roundedValue <= maxValue ? roundedValue
|
| - : (maxValue / multiple * multiple);
|
| -}
|
| -
|
| -Fraction FindScaleLessThanOrEqual(int input_num_pixels, int target_num_pixels) {
|
| - float best_distance = std::numeric_limits<float>::max();
|
| - Fraction best_scale = {0, 1}; // Default to 0 if nothing matches.
|
| - for (const auto& fraction : kScaleFractions) {
|
| - const float scale =
|
| - fraction.numerator / static_cast<float>(fraction.denominator);
|
| - float test_num_pixels = input_num_pixels * scale * scale;
|
| - float diff = target_num_pixels - test_num_pixels;
|
| - if (diff < 0) {
|
| - continue;
|
| - }
|
| - if (diff < best_distance) {
|
| - best_distance = diff;
|
| - best_scale = fraction;
|
| - if (best_distance == 0) { // Found exact match.
|
| - break;
|
| - }
|
| - }
|
| - }
|
| - return best_scale;
|
| +// Round |value_to_round| to a multiple of |multiple|. Prefer rounding upwards,
|
| +// but never more than |max_value|.
|
| +int roundUp(int value_to_round, int multiple, int max_value) {
|
| + const int rounded_value =
|
| + (value_to_round + multiple - 1) / multiple * multiple;
|
| + return rounded_value <= max_value ? rounded_value
|
| + : (max_value / multiple * multiple);
|
| }
|
|
|
| -Fraction FindScaleLargerThan(int input_num_pixels,
|
| - int target_num_pixels,
|
| - int* resulting_number_of_pixels) {
|
| - float best_distance = std::numeric_limits<float>::max();
|
| - Fraction best_scale = {1, 1}; // Default to unscaled if nothing matches.
|
| - // Default to input number of pixels.
|
| - float best_number_of_pixels = input_num_pixels;
|
| - for (const auto& fraction : kScaleFractions) {
|
| - const float scale =
|
| - fraction.numerator / static_cast<float>(fraction.denominator);
|
| - float test_num_pixels = input_num_pixels * scale * scale;
|
| - float diff = test_num_pixels - target_num_pixels;
|
| - if (diff <= 0) {
|
| - break;
|
| - }
|
| - if (diff < best_distance) {
|
| - best_distance = diff;
|
| - best_scale = fraction;
|
| - best_number_of_pixels = test_num_pixels;
|
| +// 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) {
|
| + // This function only makes sense for a positive target.
|
| + RTC_DCHECK_GT(target_num_pixels, 0);
|
| + 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;
|
| + } else {
|
| + // Multiply by 3/4
|
| + best_scale.numerator *= 3;
|
| + best_scale.denominator *= 4;
|
| }
|
| }
|
| -
|
| - *resulting_number_of_pixels = static_cast<int>(best_number_of_pixels + .5f);
|
| + if (step_up)
|
| + return last_scale;
|
| return best_scale;
|
| }
|
| -
|
| -Fraction FindScale(int input_num_pixels,
|
| - int max_pixel_count_step_up,
|
| - int max_pixel_count) {
|
| - // Try scale just above |max_pixel_count_step_up_|.
|
| - if (max_pixel_count_step_up > 0) {
|
| - int resulting_pixel_count;
|
| - const Fraction scale = FindScaleLargerThan(
|
| - input_num_pixels, max_pixel_count_step_up, &resulting_pixel_count);
|
| - if (resulting_pixel_count <= max_pixel_count)
|
| - return scale;
|
| - }
|
| - // Return largest scale below |max_pixel_count|.
|
| - return FindScaleLessThanOrEqual(input_num_pixels, max_pixel_count);
|
| -}
|
| -
|
| } // namespace
|
|
|
| namespace cricket {
|
|
|
| -VideoAdapter::VideoAdapter()
|
| +VideoAdapter::VideoAdapter(int required_resolution_alignment)
|
| : frames_in_(0),
|
| frames_out_(0),
|
| frames_scaled_(0),
|
| adaption_changes_(0),
|
| previous_width_(0),
|
| previous_height_(0),
|
| + required_resolution_alignment_(required_resolution_alignment),
|
| resolution_request_max_pixel_count_(std::numeric_limits<int>::max()),
|
| - resolution_request_max_pixel_count_step_up_(0) {}
|
| + step_up_(false) {}
|
| +
|
| +VideoAdapter::VideoAdapter() : VideoAdapter(1) {}
|
|
|
| VideoAdapter::~VideoAdapter() {}
|
|
|
| @@ -167,12 +124,17 @@ 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);
|
| + max_pixel_count, requested_format_->width * requested_format_->height -
|
| + static_cast<int>(step_up_));
|
| }
|
|
|
| // Drop the input frame if necessary.
|
| - if (max_pixel_count == 0 || !KeepFrame(in_timestamp_ns)) {
|
| + if (max_pixel_count <= 0 || !KeepFrame(in_timestamp_ns)) {
|
| // Show VAdapt log every 90 frames dropped. (3 seconds)
|
| if ((frames_in_ - frames_out_) % 90 == 0) {
|
| // TODO(fbarchard): Reduce to LS_VERBOSE when adapter info is not needed
|
| @@ -211,22 +173,25 @@ bool VideoAdapter::AdaptFrameResolution(int in_width,
|
| *cropped_height =
|
| std::min(in_height, static_cast<int>(in_width / requested_aspect));
|
| }
|
| -
|
| - // Find best scale factor.
|
| const Fraction scale =
|
| - FindScale(*cropped_width * *cropped_height,
|
| - resolution_request_max_pixel_count_step_up_, max_pixel_count);
|
| -
|
| + FindScale(*cropped_width * *cropped_height, max_pixel_count, step_up_);
|
| // Adjust cropping slightly to get even integer output size and a perfect
|
| - // scale factor.
|
| - *cropped_width = roundUp(*cropped_width, scale.denominator, in_width);
|
| - *cropped_height = roundUp(*cropped_height, scale.denominator, in_height);
|
| + // scale factor. Make sure the resulting dimensions are aligned correctly
|
| + // to be nice to hardware encoders.
|
| + *cropped_width =
|
| + roundUp(*cropped_width,
|
| + scale.denominator * required_resolution_alignment_, in_width);
|
| + *cropped_height =
|
| + roundUp(*cropped_height,
|
| + scale.denominator * required_resolution_alignment_, in_height);
|
| RTC_DCHECK_EQ(0, *cropped_width % scale.denominator);
|
| RTC_DCHECK_EQ(0, *cropped_height % scale.denominator);
|
|
|
| // Calculate final output size.
|
| *out_width = *cropped_width / scale.denominator * scale.numerator;
|
| *out_height = *cropped_height / scale.denominator * scale.numerator;
|
| + RTC_DCHECK_EQ(0, *out_height % required_resolution_alignment_);
|
| + RTC_DCHECK_EQ(0, *out_height % required_resolution_alignment_);
|
|
|
| ++frames_out_;
|
| if (scale.numerator != scale.denominator)
|
| @@ -260,10 +225,9 @@ void VideoAdapter::OnResolutionRequest(
|
| rtc::Optional<int> max_pixel_count,
|
| rtc::Optional<int> max_pixel_count_step_up) {
|
| rtc::CritScope cs(&critical_section_);
|
| - resolution_request_max_pixel_count_ =
|
| - max_pixel_count.value_or(std::numeric_limits<int>::max());
|
| - resolution_request_max_pixel_count_step_up_ =
|
| - max_pixel_count_step_up.value_or(0);
|
| + 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);
|
| }
|
|
|
| } // namespace cricket
|
|
|