Chromium Code Reviews| Index: webrtc/media/base/videoadapter.cc |
| diff --git a/webrtc/media/base/videoadapter.cc b/webrtc/media/base/videoadapter.cc |
| index acb0e2c1a19888d758cd2d46893fca9e2b93a477..16d23193549e3e4aff9956cd0c234b7ef4bc1ae7 100644 |
| --- a/webrtc/media/base/videoadapter.cc |
| +++ b/webrtc/media/base/videoadapter.cc |
| @@ -11,117 +11,72 @@ |
| #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) { |
| + 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) {} |
| +VideoAdapter::VideoAdapter() : VideoAdapter(1) {} |
| + |
| VideoAdapter::~VideoAdapter() {} |
| bool VideoAdapter::KeepFrame(int64_t in_timestamp_ns) { |
| @@ -165,10 +120,14 @@ bool VideoAdapter::AdaptFrameResolution(int in_width, |
| // The max output pixel count is the minimum of the requests from |
| // OnOutputFormatRequest and OnResolutionRequest. |
| + const bool step_up = resolution_request_max_pixel_count_step_up_; |
| int max_pixel_count = resolution_request_max_pixel_count_; |
| if (requested_format_) { |
| + // TODO(kthelgason): remove the - |step_up| hack when we change how |
|
magjed_webrtc
2016/12/08 13:45:32
Explain also how this logic works, i.e. we are not
|
| + // resolution is requested from VideoSourceProxy. |
| max_pixel_count = std::min( |
| - max_pixel_count, requested_format_->width * requested_format_->height); |
| + max_pixel_count, |
| + requested_format_->width * requested_format_->height - step_up); |
| } |
| // Drop the input frame if necessary. |
| @@ -211,22 +170,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,8 +222,8 @@ 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_ = max_pixel_count.value_or( |
| + max_pixel_count_step_up.value_or(std::numeric_limits<int>::max())); |
| resolution_request_max_pixel_count_step_up_ = |
|
magjed_webrtc
2016/12/08 13:45:32
Store |scale_up| instead of |resolution_request_ma
|
| max_pixel_count_step_up.value_or(0); |
| } |