Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(9)

Side by Side Diff: webrtc/media/base/videoadapter.cc

Issue 2672793002: Change rtc::VideoSinkWants to have target and a max pixel count (Closed)
Patch Set: Clarified test Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « webrtc/media/base/videoadapter.h ('k') | webrtc/media/base/videoadapter_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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> 14 #include <cmath>
15 #include <cstdlib> 15 #include <cstdlib>
16 #include <limits> 16 #include <limits>
17 17
18 #include "webrtc/base/arraysize.h" 18 #include "webrtc/base/arraysize.h"
19 #include "webrtc/base/checks.h" 19 #include "webrtc/base/checks.h"
20 #include "webrtc/base/logging.h" 20 #include "webrtc/base/logging.h"
21 #include "webrtc/base/optional.h" 21 #include "webrtc/base/optional.h"
22 #include "webrtc/media/base/mediaconstants.h" 22 #include "webrtc/media/base/mediaconstants.h"
23 #include "webrtc/media/base/videocommon.h" 23 #include "webrtc/media/base/videocommon.h"
24 24
25 namespace { 25 namespace {
26 struct Fraction { 26 struct Fraction {
27 int numerator; 27 int numerator;
28 int denominator; 28 int denominator;
29
30 // Determines number of output pixels if both width and height of an input of
31 // |input_pixels| pixels is scaled with the fraction numerator / denominator.
32 int scale_pixel_count(int input_pixels) {
33 return (numerator * numerator * input_pixels) / (denominator * denominator);
34 }
29 }; 35 };
30 36
31 // Round |value_to_round| to a multiple of |multiple|. Prefer rounding upwards, 37 // Round |value_to_round| to a multiple of |multiple|. Prefer rounding upwards,
32 // but never more than |max_value|. 38 // but never more than |max_value|.
33 int roundUp(int value_to_round, int multiple, int max_value) { 39 int roundUp(int value_to_round, int multiple, int max_value) {
34 const int rounded_value = 40 const int rounded_value =
35 (value_to_round + multiple - 1) / multiple * multiple; 41 (value_to_round + multiple - 1) / multiple * multiple;
36 return rounded_value <= max_value ? rounded_value 42 return rounded_value <= max_value ? rounded_value
37 : (max_value / multiple * multiple); 43 : (max_value / multiple * multiple);
38 } 44 }
39 45
40 // Generates a scale factor that makes |input_num_pixels| smaller or 46 // Generates a scale factor that makes |input_pixels| close to |target_pixels|,
41 // larger than |target_num_pixels|, depending on the value of |step_up|. 47 // but no higher than |max_pixels|.
42 Fraction FindScale(int input_num_pixels, int target_num_pixels, bool step_up) { 48 Fraction FindScale(int input_pixels, int target_pixels, int max_pixels) {
43 // This function only makes sense for a positive target. 49 // This function only makes sense for a positive target.
44 RTC_DCHECK_GT(target_num_pixels, 0); 50 RTC_DCHECK_GT(target_pixels, 0);
51 RTC_DCHECK_GT(max_pixels, 0);
52 RTC_DCHECK_GE(max_pixels, target_pixels);
53
54 // Don't scale up original.
55 if (target_pixels >= input_pixels)
56 return Fraction{1, 1};
57
58 Fraction current_scale = Fraction{1, 1};
45 Fraction best_scale = Fraction{1, 1}; 59 Fraction best_scale = Fraction{1, 1};
46 Fraction last_scale = Fraction{1, 1}; 60 // The minimum (absolute) difference between the number of output pixels and
47 const float target_scale = 61 // the target pixel count.
48 sqrt(target_num_pixels / static_cast<float>(input_num_pixels)); 62 int min_pixel_diff = input_pixels;
magjed_webrtc 2017/02/07 15:02:40 Can you do this instead? int min_pixel_diff = nume
sprang_webrtc 2017/02/09 13:00:44 Sure. Won't change the behavior but might be more
49 while (best_scale.numerator > (target_scale * best_scale.denominator)) { 63 if (input_pixels < max_pixels) {
50 last_scale = best_scale; 64 // Start condition for 1/1 case, if it is less than max.
51 if (best_scale.numerator % 3 == 0 && best_scale.denominator % 2 == 0) { 65 min_pixel_diff = std::abs(input_pixels - target_pixels);
52 // Multiply by 2/3 66 }
53 best_scale.numerator /= 3; 67
54 best_scale.denominator /= 2; 68 // Alternately scale down by 2/3 and 3/4. This results in fractions which are
69 // effectively scalable. For instance, starting at 1280x720 will result in
70 // the series (3/4) => 960x540, (1/2) => 640x360, (3/8) => 480x270,
71 // (1/4) => 320x180, (3/16) => 240x125, (1/8) => 160x90.
72 while (current_scale.scale_pixel_count(input_pixels) > target_pixels) {
73 if (current_scale.numerator % 3 == 0 &&
74 current_scale.denominator % 2 == 0) {
75 // Multiply by 2/3.
76 current_scale.numerator /= 3;
77 current_scale.denominator /= 2;
55 } else { 78 } else {
56 // Multiply by 3/4 79 // Multiply by 3/4.
57 best_scale.numerator *= 3; 80 current_scale.numerator *= 3;
58 best_scale.denominator *= 4; 81 current_scale.denominator *= 4;
82 }
83
84 int output_pixels = current_scale.scale_pixel_count(input_pixels);
85 if (output_pixels <= max_pixels) {
86 int diff = std::abs(target_pixels - output_pixels);
87 if (diff < min_pixel_diff) {
88 min_pixel_diff = diff;
89 best_scale = current_scale;
90 }
59 } 91 }
60 } 92 }
61 if (step_up) 93
62 return last_scale;
63 return best_scale; 94 return best_scale;
64 } 95 }
65 } // namespace 96 } // namespace
66 97
67 namespace cricket { 98 namespace cricket {
68 99
69 VideoAdapter::VideoAdapter(int required_resolution_alignment) 100 VideoAdapter::VideoAdapter(int required_resolution_alignment)
70 : frames_in_(0), 101 : frames_in_(0),
71 frames_out_(0), 102 frames_out_(0),
72 frames_scaled_(0), 103 frames_scaled_(0),
73 adaption_changes_(0), 104 adaption_changes_(0),
74 previous_width_(0), 105 previous_width_(0),
75 previous_height_(0), 106 previous_height_(0),
76 required_resolution_alignment_(required_resolution_alignment), 107 required_resolution_alignment_(required_resolution_alignment),
77 resolution_request_max_pixel_count_(std::numeric_limits<int>::max()), 108 resolution_request_target_pixel_count_(std::numeric_limits<int>::max()),
78 step_up_(false) {} 109 resolution_request_max_pixel_count_(std::numeric_limits<int>::max()) {}
79 110
80 VideoAdapter::VideoAdapter() : VideoAdapter(1) {} 111 VideoAdapter::VideoAdapter() : VideoAdapter(1) {}
81 112
82 VideoAdapter::~VideoAdapter() {} 113 VideoAdapter::~VideoAdapter() {}
83 114
84 bool VideoAdapter::KeepFrame(int64_t in_timestamp_ns) { 115 bool VideoAdapter::KeepFrame(int64_t in_timestamp_ns) {
85 rtc::CritScope cs(&critical_section_); 116 rtc::CritScope cs(&critical_section_);
86 if (!requested_format_ || requested_format_->interval == 0) 117 if (!requested_format_ || requested_format_->interval == 0)
87 return true; 118 return true;
88 119
(...skipping 28 matching lines...) Expand all
117 int* cropped_height, 148 int* cropped_height,
118 int* out_width, 149 int* out_width,
119 int* out_height) { 150 int* out_height) {
120 rtc::CritScope cs(&critical_section_); 151 rtc::CritScope cs(&critical_section_);
121 ++frames_in_; 152 ++frames_in_;
122 153
123 // The max output pixel count is the minimum of the requests from 154 // The max output pixel count is the minimum of the requests from
124 // OnOutputFormatRequest and OnResolutionRequest. 155 // OnOutputFormatRequest and OnResolutionRequest.
125 int max_pixel_count = resolution_request_max_pixel_count_; 156 int max_pixel_count = resolution_request_max_pixel_count_;
126 if (requested_format_) { 157 if (requested_format_) {
127 // TODO(kthelgason): remove the - |step_up_| hack when we change how
128 // resolution is requested from VideoSourceProxy.
129 // This is required because we must not scale above the requested
130 // format so we subtract one when scaling up.
131 max_pixel_count = std::min( 158 max_pixel_count = std::min(
132 max_pixel_count, requested_format_->width * requested_format_->height - 159 max_pixel_count, requested_format_->width * requested_format_->height);
133 static_cast<int>(step_up_));
134 } 160 }
161 int target_pixel_count =
162 std::min(resolution_request_target_pixel_count_, max_pixel_count);
135 163
136 // Drop the input frame if necessary. 164 // Drop the input frame if necessary.
137 if (max_pixel_count <= 0 || !KeepFrame(in_timestamp_ns)) { 165 if (max_pixel_count <= 0 || !KeepFrame(in_timestamp_ns)) {
138 // Show VAdapt log every 90 frames dropped. (3 seconds) 166 // Show VAdapt log every 90 frames dropped. (3 seconds)
139 if ((frames_in_ - frames_out_) % 90 == 0) { 167 if ((frames_in_ - frames_out_) % 90 == 0) {
140 // TODO(fbarchard): Reduce to LS_VERBOSE when adapter info is not needed 168 // TODO(fbarchard): Reduce to LS_VERBOSE when adapter info is not needed
141 // in default calls. 169 // in default calls.
142 LOG(LS_INFO) << "VAdapt Drop Frame: scaled " << frames_scaled_ 170 LOG(LS_INFO) << "VAdapt Drop Frame: scaled " << frames_scaled_
143 << " / out " << frames_out_ 171 << " / out " << frames_out_
144 << " / in " << frames_in_ 172 << " / in " << frames_in_
(...skipping 21 matching lines...) Expand all
166 std::swap(requested_format_->width, requested_format_->height); 194 std::swap(requested_format_->width, requested_format_->height);
167 } 195 }
168 const float requested_aspect = 196 const float requested_aspect =
169 requested_format_->width / 197 requested_format_->width /
170 static_cast<float>(requested_format_->height); 198 static_cast<float>(requested_format_->height);
171 *cropped_width = 199 *cropped_width =
172 std::min(in_width, static_cast<int>(in_height * requested_aspect)); 200 std::min(in_width, static_cast<int>(in_height * requested_aspect));
173 *cropped_height = 201 *cropped_height =
174 std::min(in_height, static_cast<int>(in_width / requested_aspect)); 202 std::min(in_height, static_cast<int>(in_width / requested_aspect));
175 } 203 }
176 const Fraction scale = 204 const Fraction scale = FindScale((*cropped_width) * (*cropped_height),
177 FindScale(*cropped_width * *cropped_height, max_pixel_count, step_up_); 205 target_pixel_count, max_pixel_count);
178 // Adjust cropping slightly to get even integer output size and a perfect 206 // Adjust cropping slightly to get even integer output size and a perfect
179 // scale factor. Make sure the resulting dimensions are aligned correctly 207 // scale factor. Make sure the resulting dimensions are aligned correctly
180 // to be nice to hardware encoders. 208 // to be nice to hardware encoders.
181 *cropped_width = 209 *cropped_width =
182 roundUp(*cropped_width, 210 roundUp(*cropped_width,
183 scale.denominator * required_resolution_alignment_, in_width); 211 scale.denominator * required_resolution_alignment_, in_width);
184 *cropped_height = 212 *cropped_height =
185 roundUp(*cropped_height, 213 roundUp(*cropped_height,
186 scale.denominator * required_resolution_alignment_, in_height); 214 scale.denominator * required_resolution_alignment_, in_height);
187 RTC_DCHECK_EQ(0, *cropped_width % scale.denominator); 215 RTC_DCHECK_EQ(0, *cropped_width % scale.denominator);
(...skipping 27 matching lines...) Expand all
215 return true; 243 return true;
216 } 244 }
217 245
218 void VideoAdapter::OnOutputFormatRequest(const VideoFormat& format) { 246 void VideoAdapter::OnOutputFormatRequest(const VideoFormat& format) {
219 rtc::CritScope cs(&critical_section_); 247 rtc::CritScope cs(&critical_section_);
220 requested_format_ = rtc::Optional<VideoFormat>(format); 248 requested_format_ = rtc::Optional<VideoFormat>(format);
221 next_frame_timestamp_ns_ = rtc::Optional<int64_t>(); 249 next_frame_timestamp_ns_ = rtc::Optional<int64_t>();
222 } 250 }
223 251
224 void VideoAdapter::OnResolutionRequest( 252 void VideoAdapter::OnResolutionRequest(
225 rtc::Optional<int> max_pixel_count, 253 const rtc::Optional<int>& target_pixel_count,
226 rtc::Optional<int> max_pixel_count_step_up) { 254 const rtc::Optional<int>& max_pixel_count) {
227 rtc::CritScope cs(&critical_section_); 255 rtc::CritScope cs(&critical_section_);
228 resolution_request_max_pixel_count_ = max_pixel_count.value_or( 256 resolution_request_max_pixel_count_ =
229 max_pixel_count_step_up.value_or(std::numeric_limits<int>::max())); 257 max_pixel_count.value_or(std::numeric_limits<int>::max());
230 step_up_ = static_cast<bool>(max_pixel_count_step_up); 258 resolution_request_target_pixel_count_ =
259 target_pixel_count.value_or(resolution_request_target_pixel_count_);
231 } 260 }
232 261
233 } // namespace cricket 262 } // namespace cricket
OLDNEW
« no previous file with comments | « webrtc/media/base/videoadapter.h ('k') | webrtc/media/base/videoadapter_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698