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

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

Issue 2988963002: Add support for a forced software encoder fallback. (Closed)
Patch Set: add max pixel limit 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/logging.h" 15 #include "webrtc/rtc_base/logging.h"
16 #include "webrtc/rtc_base/timeutils.h"
17 #include "webrtc/system_wrappers/include/field_trial.h"
16 18
17 namespace webrtc { 19 namespace webrtc {
20 namespace {
21 const char kVp8ForceFallbackEncoderFieldTrial[] =
22 "WebRTC-VP8-Forced-Fallback-Encoder";
23
24 bool EnableForcedFallback(const cricket::VideoCodec& codec) {
25 if (!webrtc::field_trial::IsEnabled(kVp8ForceFallbackEncoderFieldTrial))
26 return false;
27
28 return (PayloadNameToCodecType(codec.name).value_or(kVideoCodecUnknown) ==
29 kVideoCodecVP8);
30 }
31
32 void GetForcedFallbackParamsFromFieldTrialGroup(
33 VideoEncoderSoftwareFallbackWrapper::ForcedFallbackParams* params) {
brandtr 2017/08/04 11:16:23 RTC_DCHECK(params) ?
åsapersson 2017/08/08 10:40:53 Done.
34 std::string group =
35 webrtc::field_trial::FindFullName(kVp8ForceFallbackEncoderFieldTrial);
36 if (group.empty())
37 return;
38
39 int low_kbps;
40 int high_kbps;
41 int min_low_ms;
42 if (sscanf(group.c_str(), "Enabled-%d,%d,%d", &low_kbps, &high_kbps,
43 &min_low_ms) != 3) {
44 return;
sprang_webrtc 2017/08/07 08:59:12 Maybe log a warning if parsing fails?
åsapersson 2017/08/08 10:40:54 Done.
45 }
46
47 if (min_low_ms <= 0 || low_kbps <= 0 || high_kbps <= low_kbps)
48 return;
49
50 params->low_kbps = low_kbps;
51 params->high_kbps = high_kbps;
52 params->min_low_ms = min_low_ms;
53 }
54 } // namespace
18 55
19 VideoEncoderSoftwareFallbackWrapper::VideoEncoderSoftwareFallbackWrapper( 56 VideoEncoderSoftwareFallbackWrapper::VideoEncoderSoftwareFallbackWrapper(
20 const cricket::VideoCodec& codec, 57 const cricket::VideoCodec& codec,
21 webrtc::VideoEncoder* encoder) 58 webrtc::VideoEncoder* encoder)
22 : number_of_cores_(0), 59 : number_of_cores_(0),
23 max_payload_size_(0), 60 max_payload_size_(0),
24 rates_set_(false), 61 rates_set_(false),
25 framerate_(0), 62 framerate_(0),
26 channel_parameters_set_(false), 63 channel_parameters_set_(false),
27 packet_loss_(0), 64 packet_loss_(0),
28 rtt_(0), 65 rtt_(0),
29 codec_(codec), 66 codec_(codec),
30 encoder_(encoder), 67 encoder_(encoder),
31 callback_(nullptr) {} 68 callback_(nullptr),
69 forced_fallback_enabled_(EnableForcedFallback(codec)) {
70 if (forced_fallback_enabled_)
brandtr 2017/08/04 11:16:23 I'd add {} here, to make it a bit more readable.
åsapersson 2017/08/08 10:40:53 Done.
71 GetForcedFallbackParamsFromFieldTrialGroup(&forced_fallback_);
72 }
32 73
33 bool VideoEncoderSoftwareFallbackWrapper::InitFallbackEncoder() { 74 bool VideoEncoderSoftwareFallbackWrapper::InitFallbackEncoder() {
34 cricket::InternalEncoderFactory internal_factory; 75 cricket::InternalEncoderFactory internal_factory;
35 if (!FindMatchingCodec(internal_factory.supported_codecs(), codec_)) { 76 if (!FindMatchingCodec(internal_factory.supported_codecs(), codec_)) {
36 LOG(LS_WARNING) 77 LOG(LS_WARNING)
37 << "Encoder requesting fallback to codec not supported in software."; 78 << "Encoder requesting fallback to codec not supported in software.";
38 return false; 79 return false;
39 } 80 }
40 fallback_encoder_.reset(internal_factory.CreateVideoEncoder(codec_)); 81 fallback_encoder_.reset(internal_factory.CreateVideoEncoder(codec_));
41 if (fallback_encoder_->InitEncode(&codec_settings_, number_of_cores_, 82 if (fallback_encoder_->InitEncode(&codec_settings_, number_of_cores_,
(...skipping 27 matching lines...) Expand all
69 int32_t number_of_cores, 110 int32_t number_of_cores,
70 size_t max_payload_size) { 111 size_t max_payload_size) {
71 // Store settings, in case we need to dynamically switch to the fallback 112 // Store settings, in case we need to dynamically switch to the fallback
72 // encoder after a failed Encode call. 113 // encoder after a failed Encode call.
73 codec_settings_ = *codec_settings; 114 codec_settings_ = *codec_settings;
74 number_of_cores_ = number_of_cores; 115 number_of_cores_ = number_of_cores;
75 max_payload_size_ = max_payload_size; 116 max_payload_size_ = max_payload_size;
76 // Clear stored rate/channel parameters. 117 // Clear stored rate/channel parameters.
77 rates_set_ = false; 118 rates_set_ = false;
78 channel_parameters_set_ = false; 119 channel_parameters_set_ = false;
120 ValidateSettingsForForcedFallback();
121
122 if (TryReInitForcedFallbackEncoder()) {
123 return WEBRTC_VIDEO_CODEC_OK;
124 }
125 forced_fallback_.start_ms.reset();
79 126
80 int32_t ret = 127 int32_t ret =
81 encoder_->InitEncode(codec_settings, number_of_cores, max_payload_size); 128 encoder_->InitEncode(codec_settings, number_of_cores, max_payload_size);
82 if (ret == WEBRTC_VIDEO_CODEC_OK || codec_.name.empty()) { 129 if (ret == WEBRTC_VIDEO_CODEC_OK || codec_.name.empty()) {
83 if (fallback_encoder_) 130 if (fallback_encoder_)
84 fallback_encoder_->Release(); 131 fallback_encoder_->Release();
85 fallback_encoder_.reset(); 132 fallback_encoder_.reset();
86 if (callback_) 133 if (callback_)
87 encoder_->RegisterEncodeCompleteCallback(callback_); 134 encoder_->RegisterEncodeCompleteCallback(callback_);
88 return ret; 135 return ret;
(...skipping 21 matching lines...) Expand all
110 // need to Release() whichever one is active. 157 // need to Release() whichever one is active.
111 if (fallback_encoder_) 158 if (fallback_encoder_)
112 return fallback_encoder_->Release(); 159 return fallback_encoder_->Release();
113 return encoder_->Release(); 160 return encoder_->Release();
114 } 161 }
115 162
116 int32_t VideoEncoderSoftwareFallbackWrapper::Encode( 163 int32_t VideoEncoderSoftwareFallbackWrapper::Encode(
117 const VideoFrame& frame, 164 const VideoFrame& frame,
118 const CodecSpecificInfo* codec_specific_info, 165 const CodecSpecificInfo* codec_specific_info,
119 const std::vector<FrameType>* frame_types) { 166 const std::vector<FrameType>* frame_types) {
167 if (TryReleaseForcedFallbackEncoder() && encoder_->SupportsNativeHandle() &&
168 frame.video_frame_buffer()->type() != VideoFrameBuffer::Type::kNative) {
169 LOG(LS_WARNING) << "Encoder supports native frames, dropping one frame "
170 << "to avoid possible reconfig due to format change.";
171 return WEBRTC_VIDEO_CODEC_ERROR;
sprang_webrtc 2017/08/07 08:59:12 I know this code isn't new, but I'm not entirely s
åsapersson 2017/08/08 10:40:53 Done.
172 }
120 if (fallback_encoder_) 173 if (fallback_encoder_)
121 return fallback_encoder_->Encode(frame, codec_specific_info, frame_types); 174 return fallback_encoder_->Encode(frame, codec_specific_info, frame_types);
122 int32_t ret = encoder_->Encode(frame, codec_specific_info, frame_types); 175 int32_t ret = encoder_->Encode(frame, codec_specific_info, frame_types);
123 // If requested, try a software fallback. 176 // If requested, try a software fallback.
124 if (ret == WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE && InitFallbackEncoder()) { 177 if ((ret == WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE ||
178 (ret == WEBRTC_VIDEO_CODEC_OK && StartForcedFallback())) &&
brandtr 2017/08/04 11:16:23 These conditions are a bit complicated. Could it b
åsapersson 2017/08/08 10:40:54 Done.
179 InitFallbackEncoder()) {
180 if (ret == WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE)
181 forced_fallback_.start_ms.reset();
125 if (frame.video_frame_buffer()->type() == VideoFrameBuffer::Type::kNative && 182 if (frame.video_frame_buffer()->type() == VideoFrameBuffer::Type::kNative &&
126 !fallback_encoder_->SupportsNativeHandle()) { 183 !fallback_encoder_->SupportsNativeHandle()) {
127 LOG(LS_WARNING) << "Fallback encoder doesn't support native frames, " 184 LOG(LS_WARNING) << "Fallback encoder doesn't support native frames, "
128 << "dropping one frame."; 185 << "dropping one frame.";
129 return WEBRTC_VIDEO_CODEC_ERROR; 186 return WEBRTC_VIDEO_CODEC_ERROR;
130 } 187 }
131 188
132 // Fallback was successful, so start using it with this frame. 189 // Fallback was successful, so start using it with this frame.
133 return fallback_encoder_->Encode(frame, codec_specific_info, frame_types); 190 return fallback_encoder_->Encode(frame, codec_specific_info, frame_types);
134 } 191 }
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
169 VideoEncoderSoftwareFallbackWrapper::GetScalingSettings() const { 226 VideoEncoderSoftwareFallbackWrapper::GetScalingSettings() const {
170 return encoder_->GetScalingSettings(); 227 return encoder_->GetScalingSettings();
171 } 228 }
172 229
173 const char *VideoEncoderSoftwareFallbackWrapper::ImplementationName() const { 230 const char *VideoEncoderSoftwareFallbackWrapper::ImplementationName() const {
174 if (fallback_encoder_) 231 if (fallback_encoder_)
175 return fallback_encoder_->ImplementationName(); 232 return fallback_encoder_->ImplementationName();
176 return encoder_->ImplementationName(); 233 return encoder_->ImplementationName();
177 } 234 }
178 235
236 bool VideoEncoderSoftwareFallbackWrapper::StartForcedFallback() {
sprang_webrtc 2017/08/07 08:59:12 Maybe you can make this something liek a ShouldUse
åsapersson 2017/08/08 10:40:53 Changed the code a bit, ptal.
237 if (!forced_fallback_enabled_ || fallback_encoder_)
238 return false;
239
240 if (bitrate_allocation_.get_sum_kbps() > forced_fallback_.low_kbps ||
241 (codec_settings_.width * codec_settings_.height >
242 forced_fallback_.max_pixels)) {
243 forced_fallback_.start_ms.reset();
244 return false;
245 }
246 if (!forced_fallback_.start_ms) {
247 forced_fallback_.start_ms.emplace(rtc::TimeMillis());
248 return false;
249 }
250 if ((rtc::TimeMillis() - *forced_fallback_.start_ms) >=
251 forced_fallback_.min_low_ms) {
252 LOG(LS_INFO) << "Start forced sw-encoder fallback.";
253 return true;
254 }
255 return false;
256 }
257
258 bool VideoEncoderSoftwareFallbackWrapper::TryReleaseForcedFallbackEncoder() {
259 if (!forced_fallback_enabled_ || !fallback_encoder_ ||
260 !forced_fallback_.start_ms) {
261 return false;
262 }
263
264 if (bitrate_allocation_.get_sum_kbps() < forced_fallback_.high_kbps)
265 return false;
266
267 if (encoder_->InitEncode(&codec_settings_, number_of_cores_,
268 max_payload_size_) == WEBRTC_VIDEO_CODEC_OK) {
269 LOG(LS_INFO) << "Stop forced sw-encoder fallback, max bitrate exceeded.";
270 fallback_encoder_->Release();
271 fallback_encoder_.reset();
272 forced_fallback_.start_ms.reset();
273 if (callback_)
274 encoder_->RegisterEncodeCompleteCallback(callback_);
275 return true;
276 }
277 return false;
278 }
279
280 bool VideoEncoderSoftwareFallbackWrapper::TryReInitForcedFallbackEncoder() {
281 if (!forced_fallback_enabled_ || !fallback_encoder_ ||
282 !forced_fallback_.start_ms) {
brandtr 2017/08/04 11:16:23 Why do we need to check start_ms here?
åsapersson 2017/08/08 10:40:53 Checks if it is the forced fallback that is in use
283 return false;
284 }
285 if (codec_settings_.width * codec_settings_.height >
286 forced_fallback_.max_pixels) {
287 LOG(LS_INFO) << "Stop forced sw-encoder fallback, max pixels exceeded.";
288 return false;
289 }
290 if (fallback_encoder_->InitEncode(&codec_settings_, number_of_cores_,
291 max_payload_size_) !=
292 WEBRTC_VIDEO_CODEC_OK) {
293 LOG(LS_ERROR) << "Failed to re-init forced sw-encoder fallback.";
294 fallback_encoder_->Release();
295 fallback_encoder_.reset();
296 return false;
297 }
298 return true;
299 }
300
301 void VideoEncoderSoftwareFallbackWrapper::ValidateSettingsForForcedFallback() {
302 if (!forced_fallback_enabled_)
303 return;
304
305 bool valid = codec_settings_.codecType == kVideoCodecVP8 &&
306 codec_settings_.numberOfSimulcastStreams <= 1 &&
307 codec_settings_.VP8()->numberOfTemporalLayers == 1;
308
309 if (!valid) {
310 forced_fallback_enabled_ = false;
311 LOG(LS_INFO) << "Disable forced sw-encoder fallback due to settings.";
312 if (fallback_encoder_ && forced_fallback_.start_ms) {
313 fallback_encoder_->Release();
314 fallback_encoder_.reset();
315 }
316 }
317 }
318
179 } // namespace webrtc 319 } // namespace webrtc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698