blob: b9c5ea547a40865cc18e1eb49c657504c22c31cc [file] [log] [blame]
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +00001/*
2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
3 *
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
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +000011
henrik.lundin@webrtc.org1a3a6e52013-10-28 10:16:14 +000012#include <algorithm> // std::max
13
tommi@webrtc.orge07710c2015-02-19 17:43:25 +000014#include "webrtc/base/checks.h"
pbos854e84c2015-11-16 16:39:06 -080015#include "webrtc/base/logging.h"
philipel5908c712015-12-21 08:23:20 -080016#include "webrtc/common_types.h"
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +000017#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
Henrik Kjellander2557b862015-11-18 22:00:21 +010018#include "webrtc/modules/video_coding/include/video_codec_interface.h"
19#include "webrtc/modules/video_coding/encoded_frame.h"
kjellander@webrtc.orgb7ce9642015-11-18 23:04:10 +010020#include "webrtc/modules/video_coding/utility/quality_scaler.h"
Henrik Kjellander2557b862015-11-18 22:00:21 +010021#include "webrtc/modules/video_coding/video_coding_impl.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010022#include "webrtc/system_wrappers/include/clock.h"
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +000023
24namespace webrtc {
25namespace vcm {
26
stefan@webrtc.org34c5da62014-04-11 14:08:35 +000027VideoSender::VideoSender(Clock* clock,
pbos@webrtc.org891d4832015-02-26 13:15:22 +000028 EncodedImageCallback* post_encode_callback,
mflodmanfcf54bd2015-04-14 21:28:08 +020029 VideoEncoderRateObserver* encoder_rate_observer,
perkj376b1922016-05-02 11:35:24 -070030 VCMSendStatisticsCallback* send_stats_callback)
stefan@webrtc.org34c5da62014-04-11 14:08:35 +000031 : clock_(clock),
Peter Boström9dbbcfb2015-04-21 15:55:11 +020032 _encoder(nullptr),
stefan@webrtc.org34c5da62014-04-11 14:08:35 +000033 _mediaOpt(clock_),
perkj376b1922016-05-02 11:35:24 -070034 _encodedFrameCallback(post_encode_callback, &_mediaOpt),
35 send_stats_callback_(send_stats_callback),
Peter Boström4f5db112015-10-29 16:53:59 +010036 _codecDataBase(encoder_rate_observer, &_encodedFrameCallback),
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +000037 frame_dropper_enabled_(true),
andresp@webrtc.orge682aa52013-12-19 10:59:48 +000038 _sendStatsTimer(1000, clock_),
tommi@webrtc.orge07710c2015-02-19 17:43:25 +000039 current_codec_(),
Peter Boström233bfd22016-01-18 20:23:40 +010040 encoder_params_({0, 0, 0, 0}),
41 encoder_has_internal_source_(false),
42 next_frame_types_(1, kVideoFrameDelta) {
Peter Boströmad6fc5a2016-05-12 03:01:31 +020043 _mediaOpt.Reset();
tommi@webrtc.org658d2012015-03-05 12:21:54 +000044 // Allow VideoSender to be created on one thread but used on another, post
45 // construction. This is currently how this class is being used by at least
46 // one external project (diffractor).
47 main_thread_.DetachFromThread();
tommi@webrtc.orge07710c2015-02-19 17:43:25 +000048}
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +000049
Peter Boströmdcb89982015-09-15 14:43:47 +020050VideoSender::~VideoSender() {}
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +000051
pbosa26ac922016-02-25 04:50:01 -080052void VideoSender::Process() {
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +000053 if (_sendStatsTimer.TimeUntilProcess() == 0) {
perkj376b1922016-05-02 11:35:24 -070054 // |_sendStatsTimer.Processed()| must be called. Otherwise
55 // VideoSender::Process() will be called in an infinite loop.
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +000056 _sendStatsTimer.Processed();
perkj376b1922016-05-02 11:35:24 -070057 if (send_stats_callback_) {
tommi@webrtc.orge07710c2015-02-19 17:43:25 +000058 uint32_t bitRate = _mediaOpt.SentBitRate();
59 uint32_t frameRate = _mediaOpt.SentFrameRate();
perkj376b1922016-05-02 11:35:24 -070060 std::string encoder_name;
61 {
62 rtc::CritScope cs(&params_crit_);
63 // Copy the string here so that we don't hold |params_crit_| in the CB.
64 encoder_name = encoder_name_;
65 }
66 send_stats_callback_->SendStatistics(bitRate, frameRate, encoder_name);
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +000067 }
68 }
69
Erik Språng66a641a2015-06-11 14:20:07 +020070 {
Peter Boström233bfd22016-01-18 20:23:40 +010071 rtc::CritScope cs(&params_crit_);
Erik Språng66a641a2015-06-11 14:20:07 +020072 // Force an encoder parameters update, so that incoming frame rate is
73 // updated even if bandwidth hasn't changed.
74 encoder_params_.input_frame_rate = _mediaOpt.InputFrameRate();
Erik Språng66a641a2015-06-11 14:20:07 +020075 }
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +000076}
77
pkasting@chromium.org0b1534c2014-12-15 22:09:40 +000078int64_t VideoSender::TimeUntilNextProcess() {
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +000079 return _sendStatsTimer.TimeUntilProcess();
80}
81
82// Register the send codec to be used.
83int32_t VideoSender::RegisterSendCodec(const VideoCodec* sendCodec,
84 uint32_t numberOfCores,
85 uint32_t maxPayloadSize) {
henrikg91d6ede2015-09-17 00:24:34 -070086 RTC_DCHECK(main_thread_.CalledOnValidThread());
Peter Boström233bfd22016-01-18 20:23:40 +010087 rtc::CritScope lock(&encoder_crit_);
mflodmanfcf54bd2015-04-14 21:28:08 +020088 if (sendCodec == nullptr) {
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +000089 return VCM_PARAMETER_ERROR;
90 }
91
Peter Boström4f5db112015-10-29 16:53:59 +010092 bool ret =
93 _codecDataBase.SetSendCodec(sendCodec, numberOfCores, maxPayloadSize);
pbos@webrtc.orgda2c4ce2013-09-17 09:38:41 +000094
95 // Update encoder regardless of result to make sure that we're not holding on
96 // to a deleted instance.
97 _encoder = _codecDataBase.GetEncoder();
tommi@webrtc.orge07710c2015-02-19 17:43:25 +000098 // Cache the current codec here so they can be fetched from this thread
99 // without requiring the _sendCritSect lock.
100 current_codec_ = *sendCodec;
pbos@webrtc.orgda2c4ce2013-09-17 09:38:41 +0000101
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000102 if (!ret) {
pbos@webrtc.org0b52ceb2015-03-24 11:20:54 +0000103 LOG(LS_ERROR) << "Failed to initialize set encoder with payload name '"
104 << sendCodec->plName << "'.";
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000105 return VCM_CODEC_ERROR;
106 }
107
Peter Boström233bfd22016-01-18 20:23:40 +0100108 // SetSendCodec succeeded, _encoder should be set.
109 RTC_DCHECK(_encoder);
110
ivicac7199c22015-10-07 06:43:33 -0700111 int numLayers;
112 if (sendCodec->codecType == kVideoCodecVP8) {
113 numLayers = sendCodec->codecSpecific.VP8.numberOfTemporalLayers;
114 } else if (sendCodec->codecType == kVideoCodecVP9) {
115 numLayers = sendCodec->codecSpecific.VP9.numberOfTemporalLayers;
116 } else {
117 numLayers = 1;
118 }
119
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000120 // If we have screensharing and we have layers, we disable frame dropper.
121 bool disable_frame_dropper =
122 numLayers > 1 && sendCodec->mode == kScreensharing;
123 if (disable_frame_dropper) {
124 _mediaOpt.EnableFrameDropper(false);
125 } else if (frame_dropper_enabled_) {
126 _mediaOpt.EnableFrameDropper(true);
127 }
Peter Boström233bfd22016-01-18 20:23:40 +0100128 {
129 rtc::CritScope cs(&params_crit_);
130 next_frame_types_.clear();
131 next_frame_types_.resize(VCM_MAX(sendCodec->numberOfSimulcastStreams, 1),
132 kVideoFrameKey);
133 // Cache InternalSource() to have this available from IntraFrameRequest()
134 // without having to acquire encoder_crit_ (avoid blocking on encoder use).
135 encoder_has_internal_source_ = _encoder->InternalSource();
136 }
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000137
isheriff7620be82016-03-06 23:22:33 -0800138 LOG(LS_VERBOSE) << " max bitrate " << sendCodec->maxBitrate
139 << " start bitrate " << sendCodec->startBitrate
140 << " max frame rate " << sendCodec->maxFramerate
141 << " max payload size " << maxPayloadSize;
Per69b332d2016-06-02 15:45:42 +0200142 _mediaOpt.SetEncodingData(sendCodec->maxBitrate * 1000,
philipel5908c712015-12-21 08:23:20 -0800143 sendCodec->startBitrate * 1000, sendCodec->width,
144 sendCodec->height, sendCodec->maxFramerate,
145 numLayers, maxPayloadSize);
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000146 return VCM_OK;
147}
148
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000149// Register an external decoder object.
150// This can not be used together with external decoder callbacks.
Peter Boström795dbe42015-11-27 14:09:07 +0100151void VideoSender::RegisterExternalEncoder(VideoEncoder* externalEncoder,
philipel5908c712015-12-21 08:23:20 -0800152 uint8_t payloadType,
153 bool internalSource /*= false*/) {
henrikg91d6ede2015-09-17 00:24:34 -0700154 RTC_DCHECK(main_thread_.CalledOnValidThread());
tommi@webrtc.org558dc402015-03-07 20:55:56 +0000155
Peter Boström233bfd22016-01-18 20:23:40 +0100156 rtc::CritScope lock(&encoder_crit_);
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000157
mflodmanfcf54bd2015-04-14 21:28:08 +0200158 if (externalEncoder == nullptr) {
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000159 bool wasSendCodec = false;
Peter Boström795dbe42015-11-27 14:09:07 +0100160 RTC_CHECK(
161 _codecDataBase.DeregisterExternalEncoder(payloadType, &wasSendCodec));
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000162 if (wasSendCodec) {
163 // Make sure the VCM doesn't use the de-registered codec
Peter Boström233bfd22016-01-18 20:23:40 +0100164 rtc::CritScope params_lock(&params_crit_);
mflodmanfcf54bd2015-04-14 21:28:08 +0200165 _encoder = nullptr;
Peter Boström233bfd22016-01-18 20:23:40 +0100166 encoder_has_internal_source_ = false;
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000167 }
Peter Boström795dbe42015-11-27 14:09:07 +0100168 return;
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000169 }
philipel5908c712015-12-21 08:23:20 -0800170 _codecDataBase.RegisterExternalEncoder(externalEncoder, payloadType,
171 internalSource);
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000172}
173
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000174// Get encode bitrate
175int VideoSender::Bitrate(unsigned int* bitrate) const {
henrikg91d6ede2015-09-17 00:24:34 -0700176 RTC_DCHECK(main_thread_.CalledOnValidThread());
tommi@webrtc.org558dc402015-03-07 20:55:56 +0000177 // Since we're running on the thread that's the only thread known to modify
178 // the value of _encoder, we don't need to grab the lock here.
179
Peter Boström69ccb332015-10-29 16:30:23 +0100180 if (!_encoder)
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000181 return VCM_UNINITIALIZED;
Peter Boström69ccb332015-10-29 16:30:23 +0100182 *bitrate = _encoder->GetEncoderParameters().target_bitrate;
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000183 return 0;
184}
185
186// Get encode frame rate
187int VideoSender::FrameRate(unsigned int* framerate) const {
henrikg91d6ede2015-09-17 00:24:34 -0700188 RTC_DCHECK(main_thread_.CalledOnValidThread());
tommi@webrtc.org558dc402015-03-07 20:55:56 +0000189 // Since we're running on the thread that's the only thread known to modify
190 // the value of _encoder, we don't need to grab the lock here.
191
Peter Boström69ccb332015-10-29 16:30:23 +0100192 if (!_encoder)
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000193 return VCM_UNINITIALIZED;
Peter Boström69ccb332015-10-29 16:30:23 +0100194
195 *framerate = _encoder->GetEncoderParameters().input_frame_rate;
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000196 return 0;
197}
198
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000199int32_t VideoSender::SetChannelParameters(uint32_t target_bitrate,
200 uint8_t lossRate,
pkasting@chromium.org16825b12015-01-12 21:51:21 +0000201 int64_t rtt) {
Per69b332d2016-06-02 15:45:42 +0200202 uint32_t target_rate =
203 _mediaOpt.SetTargetRates(target_bitrate, lossRate, rtt);
tommi@webrtc.org558dc402015-03-07 20:55:56 +0000204
tommi@webrtc.org558dc402015-03-07 20:55:56 +0000205 uint32_t input_frame_rate = _mediaOpt.InputFrameRate();
206
noahricd4badbc2016-04-13 14:59:48 -0700207 EncoderParameters encoder_params = {target_rate, lossRate, rtt,
208 input_frame_rate};
209 bool encoder_has_internal_source;
210 {
211 rtc::CritScope cs(&params_crit_);
212 encoder_params_ = encoder_params;
213 encoder_has_internal_source = encoder_has_internal_source_;
214 }
215
216 // For encoders with internal sources, we need to tell the encoder directly,
217 // instead of waiting for an AddVideoFrame that will never come (internal
218 // source encoders don't get input frames).
219 if (encoder_has_internal_source) {
220 rtc::CritScope cs(&encoder_crit_);
221 if (_encoder) {
222 SetEncoderParameters(encoder_params);
223 }
224 }
Erik Språng66a641a2015-06-11 14:20:07 +0200225
226 return VCM_OK;
227}
228
Peter Boströmdcb89982015-09-15 14:43:47 +0200229void VideoSender::SetEncoderParameters(EncoderParameters params) {
perkjfea93092016-05-14 00:58:48 -0700230 // |target_bitrate == 0 | means that the network is down or the send pacer is
231 // full.
232 // TODO(perkj): Consider setting |target_bitrate| == 0 to the encoders.
233 // Especially if |encoder_has_internal_source_ | == true.
Peter Boström69ccb332015-10-29 16:30:23 +0100234 if (params.target_bitrate == 0)
Peter Boströmdcb89982015-09-15 14:43:47 +0200235 return;
tommi@webrtc.org558dc402015-03-07 20:55:56 +0000236
Erik Språng66a641a2015-06-11 14:20:07 +0200237 if (params.input_frame_rate == 0) {
238 // No frame rate estimate available, use default.
239 params.input_frame_rate = current_codec_.maxFramerate;
240 }
Peter Boström69ccb332015-10-29 16:30:23 +0100241 if (_encoder != nullptr)
242 _encoder->SetEncoderParameters(params);
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000243}
244
Per69b332d2016-06-02 15:45:42 +0200245// Deprecated:
246// TODO(perkj): Remove once no projects call this method. It currently do
247// nothing.
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000248int32_t VideoSender::RegisterProtectionCallback(
andresp@webrtc.orge682aa52013-12-19 10:59:48 +0000249 VCMProtectionCallback* protection_callback) {
Per69b332d2016-06-02 15:45:42 +0200250 // Deprecated:
251 // TODO(perkj): Remove once no projects call this method. It currently do
252 // nothing.
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000253 return VCM_OK;
254}
255
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000256// Add one raw video frame to the encoder, blocking.
Miguel Casas-Sanchez47650702015-05-29 17:21:40 -0700257int32_t VideoSender::AddVideoFrame(const VideoFrame& videoFrame,
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000258 const CodecSpecificInfo* codecSpecificInfo) {
Peter Boströmdcb89982015-09-15 14:43:47 +0200259 EncoderParameters encoder_params;
Peter Boström233bfd22016-01-18 20:23:40 +0100260 std::vector<FrameType> next_frame_types;
Peter Boströmdcb89982015-09-15 14:43:47 +0200261 {
Peter Boström233bfd22016-01-18 20:23:40 +0100262 rtc::CritScope lock(&params_crit_);
Peter Boströmdcb89982015-09-15 14:43:47 +0200263 encoder_params = encoder_params_;
Peter Boström233bfd22016-01-18 20:23:40 +0100264 next_frame_types = next_frame_types_;
Peter Boströmdcb89982015-09-15 14:43:47 +0200265 }
Peter Boström233bfd22016-01-18 20:23:40 +0100266 rtc::CritScope lock(&encoder_crit_);
Peter Boström69ccb332015-10-29 16:30:23 +0100267 if (_encoder == nullptr)
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000268 return VCM_UNINITIALIZED;
Peter Boström69ccb332015-10-29 16:30:23 +0100269 SetEncoderParameters(encoder_params);
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000270 if (_mediaOpt.DropFrame()) {
isheriff7620be82016-03-06 23:22:33 -0800271 LOG(LS_VERBOSE) << "Drop Frame "
272 << "target bitrate " << encoder_params.target_bitrate
273 << " loss rate " << encoder_params.loss_rate << " rtt "
274 << encoder_params.rtt << " input frame rate "
275 << encoder_params.input_frame_rate;
jackychen61b4d512015-04-21 15:30:11 -0700276 _encoder->OnDroppedFrame();
stefan@webrtc.org34c5da62014-04-11 14:08:35 +0000277 return VCM_OK;
278 }
pbos@webrtc.org67a9e402015-03-05 13:57:37 +0000279 // TODO(pbos): Make sure setting send codec is synchronized with video
280 // processing so frame size always matches.
281 if (!_codecDataBase.MatchesCurrentResolution(videoFrame.width(),
282 videoFrame.height())) {
283 LOG(LS_ERROR) << "Incoming frame doesn't match set resolution. Dropping.";
284 return VCM_PARAMETER_ERROR;
285 }
Peter Boströmeb66e802015-06-05 11:08:03 +0200286 VideoFrame converted_frame = videoFrame;
nisse26acec42016-04-15 03:43:39 -0700287 if (converted_frame.video_frame_buffer()->native_handle() &&
288 !_encoder->SupportsNativeHandle()) {
Peter Boströmeb66e802015-06-05 11:08:03 +0200289 // This module only supports software encoding.
290 // TODO(pbos): Offload conversion from the encoder thread.
nisse72e735d2016-06-17 02:55:14 -0700291 converted_frame = converted_frame.ConvertNativeToI420Frame();
292 RTC_CHECK(!converted_frame.IsZeroSize())
293 << "Frame conversion failed, won't be able to encode frame.";
Peter Boströmeb66e802015-06-05 11:08:03 +0200294 }
stefan@webrtc.org34c5da62014-04-11 14:08:35 +0000295 int32_t ret =
Peter Boström233bfd22016-01-18 20:23:40 +0100296 _encoder->Encode(converted_frame, codecSpecificInfo, next_frame_types);
stefan@webrtc.org34c5da62014-04-11 14:08:35 +0000297 if (ret < 0) {
298 LOG(LS_ERROR) << "Failed to encode frame. Error code: " << ret;
299 return ret;
300 }
perkj376b1922016-05-02 11:35:24 -0700301
Peter Boström233bfd22016-01-18 20:23:40 +0100302 {
Peter Boström233bfd22016-01-18 20:23:40 +0100303 rtc::CritScope lock(&params_crit_);
perkj376b1922016-05-02 11:35:24 -0700304 encoder_name_ = _encoder->ImplementationName();
305
306 // Change all keyframe requests to encode delta frames the next time.
Peter Boström233bfd22016-01-18 20:23:40 +0100307 for (size_t i = 0; i < next_frame_types_.size(); ++i) {
308 // Check for equality (same requested as before encoding) to not
309 // accidentally drop a keyframe request while encoding.
310 if (next_frame_types[i] == next_frame_types_[i])
311 next_frame_types_[i] = kVideoFrameDelta;
312 }
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000313 }
314 return VCM_OK;
315}
316
perkj600246e2016-05-04 11:26:51 -0700317int32_t VideoSender::IntraFrameRequest(size_t stream_index) {
Peter Boström233bfd22016-01-18 20:23:40 +0100318 {
319 rtc::CritScope lock(&params_crit_);
perkj600246e2016-05-04 11:26:51 -0700320 if (stream_index >= next_frame_types_.size()) {
Peter Boström233bfd22016-01-18 20:23:40 +0100321 return -1;
322 }
323 next_frame_types_[stream_index] = kVideoFrameKey;
324 if (!encoder_has_internal_source_)
325 return VCM_OK;
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000326 }
Peter Boström233bfd22016-01-18 20:23:40 +0100327 // TODO(pbos): Remove when InternalSource() is gone. Both locks have to be
328 // held here for internal consistency, since _encoder could be removed while
329 // not holding encoder_crit_. Checks have to be performed again since
330 // params_crit_ was dropped to not cause lock-order inversions with
331 // encoder_crit_.
332 rtc::CritScope lock(&encoder_crit_);
333 rtc::CritScope params_lock(&params_crit_);
perkj600246e2016-05-04 11:26:51 -0700334 if (stream_index >= next_frame_types_.size())
Peter Boström233bfd22016-01-18 20:23:40 +0100335 return -1;
mflodmanfcf54bd2015-04-14 21:28:08 +0200336 if (_encoder != nullptr && _encoder->InternalSource()) {
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000337 // Try to request the frame if we have an external encoder with
338 // internal source since AddVideoFrame never will be called.
Peter Boström233bfd22016-01-18 20:23:40 +0100339 if (_encoder->RequestFrame(next_frame_types_) == WEBRTC_VIDEO_CODEC_OK) {
340 // Try to remove just-performed keyframe request, if stream still exists.
341 next_frame_types_[stream_index] = kVideoFrameDelta;
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000342 }
343 }
344 return VCM_OK;
345}
346
347int32_t VideoSender::EnableFrameDropper(bool enable) {
Peter Boström233bfd22016-01-18 20:23:40 +0100348 rtc::CritScope lock(&encoder_crit_);
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000349 frame_dropper_enabled_ = enable;
350 _mediaOpt.EnableFrameDropper(enable);
351 return VCM_OK;
352}
353
henrik.lundin@webrtc.orgce8e0932013-11-18 12:18:43 +0000354void VideoSender::SuspendBelowMinBitrate() {
henrikg91d6ede2015-09-17 00:24:34 -0700355 RTC_DCHECK(main_thread_.CalledOnValidThread());
henrik.lundin@webrtc.org1a3a6e52013-10-28 10:16:14 +0000356 int threshold_bps;
tommi@webrtc.orge07710c2015-02-19 17:43:25 +0000357 if (current_codec_.numberOfSimulcastStreams == 0) {
358 threshold_bps = current_codec_.minBitrate * 1000;
henrik.lundin@webrtc.org1a3a6e52013-10-28 10:16:14 +0000359 } else {
tommi@webrtc.orge07710c2015-02-19 17:43:25 +0000360 threshold_bps = current_codec_.simulcastStream[0].minBitrate * 1000;
henrik.lundin@webrtc.org1a3a6e52013-10-28 10:16:14 +0000361 }
362 // Set the hysteresis window to be at 10% of the threshold, but at least
363 // 10 kbps.
364 int window_bps = std::max(threshold_bps / 10, 10000);
henrik.lundin@webrtc.orgce8e0932013-11-18 12:18:43 +0000365 _mediaOpt.SuspendBelowMinBitrate(threshold_bps, window_bps);
henrik.lundin@webrtc.org572699d2013-09-30 12:16:08 +0000366}
367
henrik.lundin@webrtc.orgce8e0932013-11-18 12:18:43 +0000368bool VideoSender::VideoSuspended() const {
andresp@webrtc.orge682aa52013-12-19 10:59:48 +0000369 return _mediaOpt.IsVideoSuspended();
henrik.lundin@webrtc.org572699d2013-09-30 12:16:08 +0000370}
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000371} // namespace vcm
372} // namespace webrtc