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

Side by Side Diff: webrtc/media/engine/videoencodersoftwarefallbackwrapper.cc

Issue 2988963002: Add support for a forced software encoder fallback. (Closed)
Patch Set: address comments Created 3 years, 4 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
OLDNEW
1 /* 1 /*
2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. 2 * Copyright (c) 2016 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/engine/videoencodersoftwarefallbackwrapper.h" 11 #include "webrtc/media/engine/videoencodersoftwarefallbackwrapper.h"
12 12
13 #include "webrtc/media/engine/internalencoderfactory.h" 13 #include "webrtc/media/engine/internalencoderfactory.h"
14 #include "webrtc/modules/video_coding/include/video_error_codes.h" 14 #include "webrtc/modules/video_coding/include/video_error_codes.h"
15 #include "webrtc/rtc_base/checks.h"
15 #include "webrtc/rtc_base/logging.h" 16 #include "webrtc/rtc_base/logging.h"
17 #include "webrtc/rtc_base/timeutils.h"
18 #include "webrtc/system_wrappers/include/field_trial.h"
16 19
17 namespace webrtc { 20 namespace webrtc {
21 namespace {
22 const char kVp8ForceFallbackEncoderFieldTrial[] =
23 "WebRTC-VP8-Forced-Fallback-Encoder";
24
25 bool EnableForcedFallback(const cricket::VideoCodec& codec) {
26 if (!webrtc::field_trial::IsEnabled(kVp8ForceFallbackEncoderFieldTrial))
27 return false;
28
29 return (PayloadNameToCodecType(codec.name).value_or(kVideoCodecUnknown) ==
30 kVideoCodecVP8);
31 }
32
33 bool IsForcedFallbackPossible(const VideoCodec& codec_settings) {
34 return codec_settings.codecType == kVideoCodecVP8 &&
35 codec_settings.numberOfSimulcastStreams <= 1 &&
36 codec_settings.VP8().numberOfTemporalLayers == 1;
37 }
38
39 void GetForcedFallbackParamsFromFieldTrialGroup(uint32_t* param_low_kbps,
40 uint32_t* param_high_kbps,
41 int64_t* param_min_low_ms) {
42 RTC_DCHECK(param_low_kbps);
43 RTC_DCHECK(param_high_kbps);
44 RTC_DCHECK(param_min_low_ms);
45 std::string group =
46 webrtc::field_trial::FindFullName(kVp8ForceFallbackEncoderFieldTrial);
47 if (group.empty())
48 return;
49
50 int low_kbps;
51 int high_kbps;
52 int min_low_ms;
53 if (sscanf(group.c_str(), "Enabled-%d,%d,%d", &low_kbps, &high_kbps,
54 &min_low_ms) != 3) {
55 LOG(LS_WARNING) << "Invalid number of forced fallback parameters provided.";
56 return;
57 }
58 if (min_low_ms <= 0 || low_kbps <= 0 || high_kbps <= low_kbps) {
59 LOG(LS_WARNING) << "Invalid forced fallback parameter value provided.";
60 return;
61 }
62 *param_low_kbps = low_kbps;
63 *param_high_kbps = high_kbps;
64 *param_min_low_ms = min_low_ms;
65 }
66 } // namespace
18 67
19 VideoEncoderSoftwareFallbackWrapper::VideoEncoderSoftwareFallbackWrapper( 68 VideoEncoderSoftwareFallbackWrapper::VideoEncoderSoftwareFallbackWrapper(
20 const cricket::VideoCodec& codec, 69 const cricket::VideoCodec& codec,
21 webrtc::VideoEncoder* encoder) 70 webrtc::VideoEncoder* encoder)
22 : number_of_cores_(0), 71 : number_of_cores_(0),
23 max_payload_size_(0), 72 max_payload_size_(0),
24 rates_set_(false), 73 rates_set_(false),
25 framerate_(0), 74 framerate_(0),
26 channel_parameters_set_(false), 75 channel_parameters_set_(false),
27 packet_loss_(0), 76 packet_loss_(0),
28 rtt_(0), 77 rtt_(0),
29 codec_(codec), 78 codec_(codec),
30 encoder_(encoder), 79 encoder_(encoder),
31 callback_(nullptr) {} 80 callback_(nullptr),
81 forced_fallback_possible_(EnableForcedFallback(codec)) {
82 if (forced_fallback_possible_) {
83 GetForcedFallbackParamsFromFieldTrialGroup(&forced_fallback_.low_kbps,
84 &forced_fallback_.high_kbps,
85 &forced_fallback_.min_low_ms);
86 }
87 }
32 88
33 bool VideoEncoderSoftwareFallbackWrapper::InitFallbackEncoder() { 89 bool VideoEncoderSoftwareFallbackWrapper::InitFallbackEncoder() {
34 cricket::InternalEncoderFactory internal_factory; 90 cricket::InternalEncoderFactory internal_factory;
35 if (!FindMatchingCodec(internal_factory.supported_codecs(), codec_)) { 91 if (!FindMatchingCodec(internal_factory.supported_codecs(), codec_)) {
36 LOG(LS_WARNING) 92 LOG(LS_WARNING)
37 << "Encoder requesting fallback to codec not supported in software."; 93 << "Encoder requesting fallback to codec not supported in software.";
38 return false; 94 return false;
39 } 95 }
40 fallback_encoder_.reset(internal_factory.CreateVideoEncoder(codec_)); 96 fallback_encoder_.reset(internal_factory.CreateVideoEncoder(codec_));
41 if (fallback_encoder_->InitEncode(&codec_settings_, number_of_cores_, 97 if (fallback_encoder_->InitEncode(&codec_settings_, number_of_cores_,
(...skipping 27 matching lines...) Expand all
69 int32_t number_of_cores, 125 int32_t number_of_cores,
70 size_t max_payload_size) { 126 size_t max_payload_size) {
71 // Store settings, in case we need to dynamically switch to the fallback 127 // Store settings, in case we need to dynamically switch to the fallback
72 // encoder after a failed Encode call. 128 // encoder after a failed Encode call.
73 codec_settings_ = *codec_settings; 129 codec_settings_ = *codec_settings;
74 number_of_cores_ = number_of_cores; 130 number_of_cores_ = number_of_cores;
75 max_payload_size_ = max_payload_size; 131 max_payload_size_ = max_payload_size;
76 // Clear stored rate/channel parameters. 132 // Clear stored rate/channel parameters.
77 rates_set_ = false; 133 rates_set_ = false;
78 channel_parameters_set_ = false; 134 channel_parameters_set_ = false;
135 ValidateSettingsForForcedFallback();
136
137 // Try to reinit forced software codec if it is in use.
138 if (TryReInitForcedFallbackEncoder()) {
139 return WEBRTC_VIDEO_CODEC_OK;
140 }
141 forced_fallback_.Reset();
79 142
80 int32_t ret = 143 int32_t ret =
81 encoder_->InitEncode(codec_settings, number_of_cores, max_payload_size); 144 encoder_->InitEncode(codec_settings, number_of_cores, max_payload_size);
82 if (ret == WEBRTC_VIDEO_CODEC_OK || codec_.name.empty()) { 145 if (ret == WEBRTC_VIDEO_CODEC_OK || codec_.name.empty()) {
83 if (fallback_encoder_) 146 if (fallback_encoder_)
84 fallback_encoder_->Release(); 147 fallback_encoder_->Release();
85 fallback_encoder_.reset(); 148 fallback_encoder_.reset();
86 if (callback_) 149 if (callback_)
87 encoder_->RegisterEncodeCompleteCallback(callback_); 150 encoder_->RegisterEncodeCompleteCallback(callback_);
88 return ret; 151 return ret;
(...skipping 21 matching lines...) Expand all
110 // need to Release() whichever one is active. 173 // need to Release() whichever one is active.
111 if (fallback_encoder_) 174 if (fallback_encoder_)
112 return fallback_encoder_->Release(); 175 return fallback_encoder_->Release();
113 return encoder_->Release(); 176 return encoder_->Release();
114 } 177 }
115 178
116 int32_t VideoEncoderSoftwareFallbackWrapper::Encode( 179 int32_t VideoEncoderSoftwareFallbackWrapper::Encode(
117 const VideoFrame& frame, 180 const VideoFrame& frame,
118 const CodecSpecificInfo* codec_specific_info, 181 const CodecSpecificInfo* codec_specific_info,
119 const std::vector<FrameType>* frame_types) { 182 const std::vector<FrameType>* frame_types) {
183 if (TryReleaseForcedFallbackEncoder()) {
184 // Frame may have been converted from kNative to kI420 during fallback.
185 if (encoder_->SupportsNativeHandle() &&
186 frame.video_frame_buffer()->type() != VideoFrameBuffer::Type::kNative) {
187 LOG(LS_WARNING) << "Encoder supports native frames, dropping one frame "
188 << "to avoid possible reconfig due to format change.";
189 return WEBRTC_VIDEO_CODEC_ERROR;
190 }
191 }
120 if (fallback_encoder_) 192 if (fallback_encoder_)
121 return fallback_encoder_->Encode(frame, codec_specific_info, frame_types); 193 return fallback_encoder_->Encode(frame, codec_specific_info, frame_types);
122 int32_t ret = encoder_->Encode(frame, codec_specific_info, frame_types); 194 int32_t ret = encoder_->Encode(frame, codec_specific_info, frame_types);
123 // If requested, try a software fallback. 195 // If requested, try a software fallback.
124 if (ret == WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE && InitFallbackEncoder()) { 196 bool fallback_requested =
197 (ret == WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE) ||
198 (ret == WEBRTC_VIDEO_CODEC_OK && RequestForcedFallback());
199 if (fallback_requested && InitFallbackEncoder()) {
200 // Fallback was successful.
201 if (ret == WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE)
202 forced_fallback_.Reset(); // Not a forced fallback.
125 if (frame.video_frame_buffer()->type() == VideoFrameBuffer::Type::kNative && 203 if (frame.video_frame_buffer()->type() == VideoFrameBuffer::Type::kNative &&
126 !fallback_encoder_->SupportsNativeHandle()) { 204 !fallback_encoder_->SupportsNativeHandle()) {
127 LOG(LS_WARNING) << "Fallback encoder doesn't support native frames, " 205 LOG(LS_WARNING) << "Fallback encoder doesn't support native frames, "
128 << "dropping one frame."; 206 << "dropping one frame.";
129 return WEBRTC_VIDEO_CODEC_ERROR; 207 return WEBRTC_VIDEO_CODEC_ERROR;
130 } 208 }
131 209
132 // Fallback was successful, so start using it with this frame. 210 // Start using the fallback with this frame.
133 return fallback_encoder_->Encode(frame, codec_specific_info, frame_types); 211 return fallback_encoder_->Encode(frame, codec_specific_info, frame_types);
134 } 212 }
135 return ret; 213 return ret;
136 } 214 }
137 215
138 int32_t VideoEncoderSoftwareFallbackWrapper::SetChannelParameters( 216 int32_t VideoEncoderSoftwareFallbackWrapper::SetChannelParameters(
139 uint32_t packet_loss, 217 uint32_t packet_loss,
140 int64_t rtt) { 218 int64_t rtt) {
141 channel_parameters_set_ = true; 219 channel_parameters_set_ = true;
142 packet_loss_ = packet_loss; 220 packet_loss_ = packet_loss;
(...skipping 26 matching lines...) Expand all
169 VideoEncoderSoftwareFallbackWrapper::GetScalingSettings() const { 247 VideoEncoderSoftwareFallbackWrapper::GetScalingSettings() const {
170 return encoder_->GetScalingSettings(); 248 return encoder_->GetScalingSettings();
171 } 249 }
172 250
173 const char *VideoEncoderSoftwareFallbackWrapper::ImplementationName() const { 251 const char *VideoEncoderSoftwareFallbackWrapper::ImplementationName() const {
174 if (fallback_encoder_) 252 if (fallback_encoder_)
175 return fallback_encoder_->ImplementationName(); 253 return fallback_encoder_->ImplementationName();
176 return encoder_->ImplementationName(); 254 return encoder_->ImplementationName();
177 } 255 }
178 256
257 bool VideoEncoderSoftwareFallbackWrapper::IsForcedFallbackActive() const {
258 return (forced_fallback_possible_ && fallback_encoder_ &&
259 forced_fallback_.start_ms);
260 }
261
262 bool VideoEncoderSoftwareFallbackWrapper::RequestForcedFallback() {
263 if (!forced_fallback_possible_ || fallback_encoder_ || !rates_set_)
264 return false;
265
266 // No fallback encoder.
267 if (forced_fallback_.Start(bitrate_allocation_.get_sum_kbps(),
268 codec_settings_)) {
269 LOG(LS_INFO) << "Request forced SW encoder fallback.";
270 return true;
271 }
272 return false;
273 }
274
275 bool VideoEncoderSoftwareFallbackWrapper::TryReleaseForcedFallbackEncoder() {
276 if (!IsForcedFallbackActive())
277 return false;
278
279 if (!forced_fallback_.Stop(bitrate_allocation_.get_sum_kbps()))
280 return false;
281
282 // Release the forced fallback encoder.
283 if (encoder_->InitEncode(&codec_settings_, number_of_cores_,
284 max_payload_size_) == WEBRTC_VIDEO_CODEC_OK) {
285 LOG(LS_INFO) << "Stop forced SW encoder fallback, max bitrate exceeded.";
286 fallback_encoder_->Release();
287 fallback_encoder_.reset();
288 forced_fallback_.Reset();
289 return true;
290 }
291 return false;
292 }
293
294 bool VideoEncoderSoftwareFallbackWrapper::TryReInitForcedFallbackEncoder() {
295 if (!IsForcedFallbackActive())
296 return false;
297
298 // Encoder reconfigured.
299 if (!forced_fallback_.IsValid(codec_settings_)) {
300 LOG(LS_INFO) << "Stop forced SW encoder fallback, max pixels exceeded.";
301 return false;
302 }
303 // Settings valid, reinitialize the forced fallback encoder.
304 if (fallback_encoder_->InitEncode(&codec_settings_, number_of_cores_,
305 max_payload_size_) !=
306 WEBRTC_VIDEO_CODEC_OK) {
307 LOG(LS_ERROR) << "Failed to init forced SW encoder fallback.";
308 return false;
309 }
310 return true;
311 }
312
313 void VideoEncoderSoftwareFallbackWrapper::ValidateSettingsForForcedFallback() {
314 if (!forced_fallback_possible_)
315 return;
316
317 if (!IsForcedFallbackPossible(codec_settings_)) {
318 if (IsForcedFallbackActive()) {
319 fallback_encoder_->Release();
320 fallback_encoder_.reset();
321 }
322 LOG(LS_INFO) << "Disable forced_fallback_possible_ due to settings.";
323 forced_fallback_possible_ = false;
324 }
325 }
326
327 bool VideoEncoderSoftwareFallbackWrapper::ForcedFallbackParams::Start(
328 uint32_t kbps,
brandtr 2017/08/09 09:05:02 bitrate_kbps?
åsapersson 2017/08/09 09:50:36 Done.
329 const VideoCodec& codec) {
330 if (kbps > low_kbps || !IsValid(codec)) {
331 start_ms.reset();
332 return false;
333 }
334 // Has bitrate been below |low_kbps| for long enough duration.
335 if (!start_ms)
336 start_ms.emplace(rtc::TimeMillis());
337 return (rtc::TimeMillis() - *start_ms) >= min_low_ms;
sprang_webrtc 2017/08/09 08:38:07 nit: call rtc::TimeMillis() just once and reuse th
åsapersson 2017/08/09 09:50:36 Done.
338 }
339
179 } // namespace webrtc 340 } // namespace webrtc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698