| OLD | NEW | 
|---|
| 1 /* | 1 /* | 
| 2  *  Copyright (c) 2010 The WebRTC project authors. All Rights Reserved. | 2  *  Copyright (c) 2010 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 | 10 | 
| 11 #include "webrtc/media/base/videoadapter.h" | 11 #include "webrtc/media/base/videoadapter.h" | 
| 12 | 12 | 
| 13 #include <algorithm> | 13 #include <algorithm> | 
| 14 #include <cmath> |  | 
| 15 #include <cstdlib> | 14 #include <cstdlib> | 
| 16 #include <limits> | 15 #include <limits> | 
| 17 | 16 | 
| 18 #include "webrtc/base/arraysize.h" |  | 
| 19 #include "webrtc/base/checks.h" | 17 #include "webrtc/base/checks.h" | 
| 20 #include "webrtc/base/logging.h" | 18 #include "webrtc/base/logging.h" | 
| 21 #include "webrtc/base/optional.h" |  | 
| 22 #include "webrtc/media/base/mediaconstants.h" | 19 #include "webrtc/media/base/mediaconstants.h" | 
| 23 #include "webrtc/media/base/videocommon.h" | 20 #include "webrtc/media/base/videocommon.h" | 
| 24 | 21 | 
| 25 namespace { | 22 namespace { | 
|  | 23 | 
| 26 struct Fraction { | 24 struct Fraction { | 
| 27   int numerator; | 25   int numerator; | 
| 28   int denominator; | 26   int denominator; | 
| 29 }; | 27 }; | 
| 30 | 28 | 
| 31 // Scale factors optimized for in libYUV that we accept. | 29 // Scale factors optimized for in libYUV that we accept. | 
| 32 // Must be sorted in decreasing scale factors for FindScaleLargerThan to work. | 30 // Must be sorted in decreasing scale factors for FindScaleLargerThan to work. | 
| 33 const Fraction kScaleFractions[] = { | 31 const Fraction kScaleFractions[] = { | 
| 34   {1, 1}, | 32   {1, 1}, | 
| 35   {3, 4}, | 33   {3, 4}, | 
| 36   {1, 2}, | 34   {1, 2}, | 
| 37   {3, 8}, | 35   {3, 8}, | 
| 38   {1, 4}, | 36   {1, 4}, | 
| 39   {3, 16}, | 37   {3, 16}, | 
| 40 }; | 38 }; | 
| 41 | 39 | 
| 42 // Round |value_to_round| to a multiple of |multiple|. Prefer rounding upwards, | 40 // Round |valueToRound| to a multiple of |multiple|. Prefer rounding upwards, | 
| 43 // but never more than |max_value|. | 41 // but never more than |maxValue|. | 
| 44 int roundUp(int value_to_round, int multiple, int max_value) { | 42 int roundUp(int valueToRound, int multiple, int maxValue) { | 
| 45   const int rounded_value = | 43   const int roundedValue = (valueToRound + multiple - 1) / multiple * multiple; | 
| 46       (value_to_round + multiple - 1) / multiple * multiple; | 44   return roundedValue <= maxValue ? roundedValue | 
| 47   return rounded_value <= max_value ? rounded_value | 45                                   : (maxValue / multiple * multiple); | 
| 48                                     : (max_value / multiple * multiple); |  | 
| 49 } | 46 } | 
| 50 | 47 | 
| 51 // Generates a scale factor that makes |input_num_pixels| smaller than |  | 
| 52 // |target_num_pixels|. This should only be used after making sure none |  | 
| 53 // of the optimized factors are small enough. |  | 
| 54 Fraction FindScaleLessThanOrEqual(int input_num_pixels, int target_num_pixels) { | 48 Fraction FindScaleLessThanOrEqual(int input_num_pixels, int target_num_pixels) { | 
| 55   // Start searching from the last of the optimal fractions; |  | 
| 56   Fraction best_scale = kScaleFractions[arraysize(kScaleFractions) - 1]; |  | 
| 57   const float target_scale = |  | 
| 58       sqrt(target_num_pixels / static_cast<float>(input_num_pixels)); |  | 
| 59   do { |  | 
| 60     if (best_scale.numerator % 3 == 0 && best_scale.denominator % 2 == 0) { |  | 
| 61       // Multiply by 2/3 |  | 
| 62       best_scale.numerator /= 3; |  | 
| 63       best_scale.denominator /= 2; |  | 
| 64     } else { |  | 
| 65       // Multiply by 3/4 |  | 
| 66       best_scale.numerator *= 3; |  | 
| 67       best_scale.denominator *= 4; |  | 
| 68     } |  | 
| 69   } while (best_scale.numerator > (target_scale * best_scale.denominator)); |  | 
| 70   return best_scale; |  | 
| 71 } |  | 
| 72 |  | 
| 73 rtc::Optional<Fraction> FindOptimizedScaleLessThanOrEqual( |  | 
| 74     int input_num_pixels, |  | 
| 75     int target_num_pixels) { |  | 
| 76   float best_distance = std::numeric_limits<float>::max(); | 49   float best_distance = std::numeric_limits<float>::max(); | 
| 77   rtc::Optional<Fraction> best_scale; | 50   Fraction best_scale = {0, 1};  // Default to 0 if nothing matches. | 
| 78   for (const auto& fraction : kScaleFractions) { | 51   for (const auto& fraction : kScaleFractions) { | 
| 79     const float scale = | 52     const float scale = | 
| 80         fraction.numerator / static_cast<float>(fraction.denominator); | 53         fraction.numerator / static_cast<float>(fraction.denominator); | 
| 81     float test_num_pixels = input_num_pixels * scale * scale; | 54     float test_num_pixels = input_num_pixels * scale * scale; | 
| 82     float diff = target_num_pixels - test_num_pixels; | 55     float diff = target_num_pixels - test_num_pixels; | 
| 83     if (diff < 0) { | 56     if (diff < 0) { | 
| 84       continue; | 57       continue; | 
| 85     } | 58     } | 
| 86     if (diff < best_distance) { | 59     if (diff < best_distance) { | 
| 87       best_distance = diff; | 60       best_distance = diff; | 
| 88       best_scale = rtc::Optional<Fraction>(fraction); | 61       best_scale = fraction; | 
| 89       if (best_distance == 0) {  // Found exact match. | 62       if (best_distance == 0) {  // Found exact match. | 
| 90         break; | 63         break; | 
| 91       } | 64       } | 
| 92     } | 65     } | 
| 93   } | 66   } | 
| 94   return best_scale; | 67   return best_scale; | 
| 95 } | 68 } | 
| 96 | 69 | 
| 97 Fraction FindOptimizedScaleLargerThan(int input_num_pixels, | 70 Fraction FindScaleLargerThan(int input_num_pixels, | 
| 98                                       int target_num_pixels, | 71                              int target_num_pixels, | 
| 99                                       int* resulting_number_of_pixels) { | 72                              int* resulting_number_of_pixels) { | 
| 100   float best_distance = std::numeric_limits<float>::max(); | 73   float best_distance = std::numeric_limits<float>::max(); | 
| 101   Fraction best_scale = {1, 1};  // Default to unscaled if nothing matches. | 74   Fraction best_scale = {1, 1};  // Default to unscaled if nothing matches. | 
| 102   // Default to input number of pixels. | 75   // Default to input number of pixels. | 
| 103   float best_number_of_pixels = input_num_pixels; | 76   float best_number_of_pixels = input_num_pixels; | 
| 104   for (const auto& fraction : kScaleFractions) { | 77   for (const auto& fraction : kScaleFractions) { | 
| 105     const float scale = | 78     const float scale = | 
| 106         fraction.numerator / static_cast<float>(fraction.denominator); | 79         fraction.numerator / static_cast<float>(fraction.denominator); | 
| 107     float test_num_pixels = input_num_pixels * scale * scale; | 80     float test_num_pixels = input_num_pixels * scale * scale; | 
| 108     float diff = test_num_pixels - target_num_pixels; | 81     float diff = test_num_pixels - target_num_pixels; | 
| 109     if (diff <= 0) { | 82     if (diff <= 0) { | 
| 110       break; | 83       break; | 
| 111     } | 84     } | 
| 112     if (diff < best_distance) { | 85     if (diff < best_distance) { | 
| 113       best_distance = diff; | 86       best_distance = diff; | 
| 114       best_scale = fraction; | 87       best_scale = fraction; | 
| 115       best_number_of_pixels = test_num_pixels; | 88       best_number_of_pixels = test_num_pixels; | 
| 116     } | 89     } | 
| 117   } | 90   } | 
| 118 | 91 | 
| 119   *resulting_number_of_pixels = static_cast<int>(best_number_of_pixels + .5f); | 92   *resulting_number_of_pixels = static_cast<int>(best_number_of_pixels + .5f); | 
| 120   return best_scale; | 93   return best_scale; | 
| 121 } | 94 } | 
| 122 | 95 | 
| 123 rtc::Optional<Fraction> FindOptimizedScale(int input_num_pixels, |  | 
| 124                                            int max_pixel_count_step_up, |  | 
| 125                                            int max_pixel_count) { |  | 
| 126   // Try scale just above |max_pixel_count_step_up_|. |  | 
| 127   if (max_pixel_count_step_up > 0) { |  | 
| 128     int resulting_pixel_count; |  | 
| 129     const Fraction scale = FindOptimizedScaleLargerThan( |  | 
| 130         input_num_pixels, max_pixel_count_step_up, &resulting_pixel_count); |  | 
| 131     if (resulting_pixel_count <= max_pixel_count) |  | 
| 132       return rtc::Optional<Fraction>(scale); |  | 
| 133   } |  | 
| 134   // Return largest scale below |max_pixel_count|. |  | 
| 135   return FindOptimizedScaleLessThanOrEqual(input_num_pixels, max_pixel_count); |  | 
| 136 } |  | 
| 137 |  | 
| 138 Fraction FindScale(int input_num_pixels, | 96 Fraction FindScale(int input_num_pixels, | 
| 139                    int max_pixel_count_step_up, | 97                    int max_pixel_count_step_up, | 
| 140                    int max_pixel_count) { | 98                    int max_pixel_count) { | 
| 141   const rtc::Optional<Fraction> optimized_scale = FindOptimizedScale( | 99   // Try scale just above |max_pixel_count_step_up_|. | 
| 142       input_num_pixels, max_pixel_count_step_up, max_pixel_count); | 100   if (max_pixel_count_step_up > 0) { | 
| 143   if (optimized_scale) | 101     int resulting_pixel_count; | 
| 144     return *optimized_scale; | 102     const Fraction scale = FindScaleLargerThan( | 
|  | 103         input_num_pixels, max_pixel_count_step_up, &resulting_pixel_count); | 
|  | 104     if (resulting_pixel_count <= max_pixel_count) | 
|  | 105       return scale; | 
|  | 106   } | 
|  | 107   // Return largest scale below |max_pixel_count|. | 
| 145   return FindScaleLessThanOrEqual(input_num_pixels, max_pixel_count); | 108   return FindScaleLessThanOrEqual(input_num_pixels, max_pixel_count); | 
| 146 } | 109 } | 
|  | 110 | 
| 147 }  // namespace | 111 }  // namespace | 
| 148 | 112 | 
| 149 namespace cricket { | 113 namespace cricket { | 
| 150 | 114 | 
| 151 VideoAdapter::VideoAdapter(int required_resolution_alignment) | 115 VideoAdapter::VideoAdapter() | 
| 152     : frames_in_(0), | 116     : frames_in_(0), | 
| 153       frames_out_(0), | 117       frames_out_(0), | 
| 154       frames_scaled_(0), | 118       frames_scaled_(0), | 
| 155       adaption_changes_(0), | 119       adaption_changes_(0), | 
| 156       previous_width_(0), | 120       previous_width_(0), | 
| 157       previous_height_(0), | 121       previous_height_(0), | 
| 158       required_resolution_alignment_(required_resolution_alignment), |  | 
| 159       resolution_request_max_pixel_count_(std::numeric_limits<int>::max()), | 122       resolution_request_max_pixel_count_(std::numeric_limits<int>::max()), | 
| 160       resolution_request_max_pixel_count_step_up_(0) {} | 123       resolution_request_max_pixel_count_step_up_(0) {} | 
| 161 | 124 | 
| 162 VideoAdapter::VideoAdapter() : VideoAdapter(1) {} |  | 
| 163 |  | 
| 164 VideoAdapter::~VideoAdapter() {} | 125 VideoAdapter::~VideoAdapter() {} | 
| 165 | 126 | 
| 166 bool VideoAdapter::KeepFrame(int64_t in_timestamp_ns) { | 127 bool VideoAdapter::KeepFrame(int64_t in_timestamp_ns) { | 
| 167   rtc::CritScope cs(&critical_section_); | 128   rtc::CritScope cs(&critical_section_); | 
| 168   if (!requested_format_ || requested_format_->interval == 0) | 129   if (!requested_format_ || requested_format_->interval == 0) | 
| 169     return true; | 130     return true; | 
| 170 | 131 | 
| 171   if (next_frame_timestamp_ns_) { | 132   if (next_frame_timestamp_ns_) { | 
| 172     // Time until next frame should be outputted. | 133     // Time until next frame should be outputted. | 
| 173     const int64_t time_until_next_frame_ns = | 134     const int64_t time_until_next_frame_ns = | 
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 243       std::swap(requested_format_->width, requested_format_->height); | 204       std::swap(requested_format_->width, requested_format_->height); | 
| 244     } | 205     } | 
| 245     const float requested_aspect = | 206     const float requested_aspect = | 
| 246         requested_format_->width / | 207         requested_format_->width / | 
| 247         static_cast<float>(requested_format_->height); | 208         static_cast<float>(requested_format_->height); | 
| 248     *cropped_width = | 209     *cropped_width = | 
| 249         std::min(in_width, static_cast<int>(in_height * requested_aspect)); | 210         std::min(in_width, static_cast<int>(in_height * requested_aspect)); | 
| 250     *cropped_height = | 211     *cropped_height = | 
| 251         std::min(in_height, static_cast<int>(in_width / requested_aspect)); | 212         std::min(in_height, static_cast<int>(in_width / requested_aspect)); | 
| 252   } | 213   } | 
|  | 214 | 
|  | 215   // Find best scale factor. | 
| 253   const Fraction scale = | 216   const Fraction scale = | 
| 254       FindScale(*cropped_width * *cropped_height, | 217       FindScale(*cropped_width * *cropped_height, | 
| 255                 resolution_request_max_pixel_count_step_up_, max_pixel_count); | 218                 resolution_request_max_pixel_count_step_up_, max_pixel_count); | 
|  | 219 | 
| 256   // Adjust cropping slightly to get even integer output size and a perfect | 220   // Adjust cropping slightly to get even integer output size and a perfect | 
| 257   // scale factor. Make sure the resulting dimensions are aligned correctly | 221   // scale factor. | 
| 258   // to be nice to hardware encoders. | 222   *cropped_width = roundUp(*cropped_width, scale.denominator, in_width); | 
| 259   *cropped_width = | 223   *cropped_height = roundUp(*cropped_height, scale.denominator, in_height); | 
| 260       roundUp(*cropped_width, |  | 
| 261               scale.denominator * required_resolution_alignment_, in_width); |  | 
| 262   *cropped_height = |  | 
| 263       roundUp(*cropped_height, |  | 
| 264               scale.denominator * required_resolution_alignment_, in_height); |  | 
| 265   RTC_DCHECK_EQ(0, *cropped_width % scale.denominator); | 224   RTC_DCHECK_EQ(0, *cropped_width % scale.denominator); | 
| 266   RTC_DCHECK_EQ(0, *cropped_height % scale.denominator); | 225   RTC_DCHECK_EQ(0, *cropped_height % scale.denominator); | 
| 267 | 226 | 
| 268   // Calculate final output size. | 227   // Calculate final output size. | 
| 269   *out_width = *cropped_width / scale.denominator * scale.numerator; | 228   *out_width = *cropped_width / scale.denominator * scale.numerator; | 
| 270   *out_height = *cropped_height / scale.denominator * scale.numerator; | 229   *out_height = *cropped_height / scale.denominator * scale.numerator; | 
| 271   RTC_DCHECK_EQ(0, *out_height % required_resolution_alignment_); |  | 
| 272   RTC_DCHECK_EQ(0, *out_height % required_resolution_alignment_); |  | 
| 273 | 230 | 
| 274   ++frames_out_; | 231   ++frames_out_; | 
| 275   if (scale.numerator != scale.denominator) | 232   if (scale.numerator != scale.denominator) | 
| 276     ++frames_scaled_; | 233     ++frames_scaled_; | 
| 277 | 234 | 
| 278   if (previous_width_ && (previous_width_ != *out_width || | 235   if (previous_width_ && (previous_width_ != *out_width || | 
| 279                           previous_height_ != *out_height)) { | 236                           previous_height_ != *out_height)) { | 
| 280     ++adaption_changes_; | 237     ++adaption_changes_; | 
| 281     LOG(LS_INFO) << "Frame size changed: scaled " << frames_scaled_ << " / out " | 238     LOG(LS_INFO) << "Frame size changed: scaled " << frames_scaled_ << " / out " | 
| 282                  << frames_out_ << " / in " << frames_in_ | 239                  << frames_out_ << " / in " << frames_in_ | 
| (...skipping 20 matching lines...) Expand all  Loading... | 
| 303     rtc::Optional<int> max_pixel_count, | 260     rtc::Optional<int> max_pixel_count, | 
| 304     rtc::Optional<int> max_pixel_count_step_up) { | 261     rtc::Optional<int> max_pixel_count_step_up) { | 
| 305   rtc::CritScope cs(&critical_section_); | 262   rtc::CritScope cs(&critical_section_); | 
| 306   resolution_request_max_pixel_count_ = | 263   resolution_request_max_pixel_count_ = | 
| 307       max_pixel_count.value_or(std::numeric_limits<int>::max()); | 264       max_pixel_count.value_or(std::numeric_limits<int>::max()); | 
| 308   resolution_request_max_pixel_count_step_up_ = | 265   resolution_request_max_pixel_count_step_up_ = | 
| 309       max_pixel_count_step_up.value_or(0); | 266       max_pixel_count_step_up.value_or(0); | 
| 310 } | 267 } | 
| 311 | 268 | 
| 312 }  // namespace cricket | 269 }  // namespace cricket | 
| OLD | NEW | 
|---|