Index: webrtc/media/base/videoadapter.cc |
diff --git a/webrtc/media/base/videoadapter.cc b/webrtc/media/base/videoadapter.cc |
index acb0e2c1a19888d758cd2d46893fca9e2b93a477..fe6c1683e241c4cc51c5db9300d6f711593c7fab 100644 |
--- a/webrtc/media/base/videoadapter.cc |
+++ b/webrtc/media/base/videoadapter.cc |
@@ -11,15 +11,19 @@ |
#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 { |
+const int kResolutionRequiredDivisor = 4; |
struct Fraction { |
int numerator; |
@@ -46,8 +50,32 @@ int roundUp(int valueToRound, int multiple, int maxValue) { |
} |
Fraction FindScaleLessThanOrEqual(int input_num_pixels, int target_num_pixels) { |
+ // Start searching from the last of the optimal fractions; |
+ Fraction best_scale = kScaleFractions[arraysize(kScaleFractions) - 1]; |
+ while (true) { |
+ const float scale = |
+ best_scale.numerator / static_cast<float>(best_scale.denominator); |
+ float test_num_pixels = input_num_pixels * scale * scale; |
+ float diff = target_num_pixels - test_num_pixels; |
+ if (diff < 0) { |
magjed_webrtc
2016/12/06 16:35:08
nit: I think this logic is cleaner:
if (test_num_p
kthelgason
2016/12/07 12:35:25
Acknowledged.
|
+ if (best_scale.numerator == 1) { |
+ best_scale.numerator = 3; |
+ best_scale.denominator *= 4; |
+ } else { |
+ best_scale.numerator = 1; |
+ best_scale.denominator /= 2; |
+ } |
+ } else { |
+ return best_scale; |
+ } |
+ } |
+} |
+ |
+rtc::Optional<Fraction> FindOptimizedScaleLessThanOrEqual( |
+ 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. |
+ rtc::Optional<Fraction> best_scale; |
for (const auto& fraction : kScaleFractions) { |
const float scale = |
fraction.numerator / static_cast<float>(fraction.denominator); |
@@ -58,7 +86,7 @@ Fraction FindScaleLessThanOrEqual(int input_num_pixels, int target_num_pixels) { |
} |
if (diff < best_distance) { |
best_distance = diff; |
- best_scale = fraction; |
+ best_scale = rtc::Optional<Fraction>(fraction); |
if (best_distance == 0) { // Found exact match. |
break; |
} |
@@ -67,9 +95,9 @@ Fraction FindScaleLessThanOrEqual(int input_num_pixels, int target_num_pixels) { |
return best_scale; |
} |
-Fraction FindScaleLargerThan(int input_num_pixels, |
- int target_num_pixels, |
- int* resulting_number_of_pixels) { |
+Fraction FindOptimizedScaleLargerThan(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. |
@@ -93,21 +121,30 @@ Fraction FindScaleLargerThan(int input_num_pixels, |
return best_scale; |
} |
-Fraction FindScale(int input_num_pixels, |
- int max_pixel_count_step_up, |
- int max_pixel_count) { |
+rtc::Optional<Fraction> FindOptimizedScale(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( |
+ const Fraction scale = FindOptimizedScaleLargerThan( |
input_num_pixels, max_pixel_count_step_up, &resulting_pixel_count); |
if (resulting_pixel_count <= max_pixel_count) |
- return scale; |
+ return rtc::Optional<Fraction>(scale); |
} |
// Return largest scale below |max_pixel_count|. |
- return FindScaleLessThanOrEqual(input_num_pixels, max_pixel_count); |
+ return FindOptimizedScaleLessThanOrEqual(input_num_pixels, max_pixel_count); |
} |
+Fraction FindScale(int input_num_pixels, |
+ int max_pixel_count_step_up, |
+ int max_pixel_count) { |
+ const rtc::Optional<Fraction> optimized_scale = FindOptimizedScale( |
+ input_num_pixels, max_pixel_count_step_up, max_pixel_count); |
+ if (optimized_scale) |
+ return *optimized_scale; |
+ return FindScaleLessThanOrEqual(input_num_pixels, max_pixel_count); |
+} |
} // namespace |
namespace cricket { |
@@ -211,23 +248,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); |
- |
// 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); |
- RTC_DCHECK_EQ(0, *cropped_width % scale.denominator); |
- RTC_DCHECK_EQ(0, *cropped_height % scale.denominator); |
+ // scale factor. Make sure the resulting dimensions are a multiple of 4 |
+ // to be nice to hardware encoders. |
+ *cropped_width = roundUp( |
+ *cropped_width, scale.denominator * kResolutionRequiredDivisor, in_width); |
+ *cropped_height = |
+ roundUp(*cropped_height, scale.denominator * kResolutionRequiredDivisor, |
+ in_height); |
+ RTC_DCHECK_EQ( |
+ 0, *cropped_width % scale.denominator * kResolutionRequiredDivisor); |
+ RTC_DCHECK_EQ( |
+ 0, *cropped_height % scale.denominator * kResolutionRequiredDivisor); |
// Calculate final output size. |
*out_width = *cropped_width / scale.denominator * scale.numerator; |
*out_height = *cropped_height / scale.denominator * scale.numerator; |
- |
++frames_out_; |
if (scale.numerator != scale.denominator) |
++frames_scaled_; |