blob: 7d8e97b58d63c0f10f87326aed7a26d067bb1db0 [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
11#include "webrtc/common_types.h"
12
henrik.lundin@webrtc.org1a3a6e52013-10-28 10:16:14 +000013#include <algorithm> // std::max
14
tommi@webrtc.orge07710c2015-02-19 17:43:25 +000015#include "webrtc/base/checks.h"
pbos854e84c2015-11-16 16:39:06 -080016#include "webrtc/base/logging.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,
30 VCMQMSettingsCallback* qm_settings_callback)
stefan@webrtc.org34c5da62014-04-11 14:08:35 +000031 : clock_(clock),
stefan@webrtc.org8db81c52013-09-18 11:57:34 +000032 process_crit_sect_(CriticalSectionWrapper::CreateCriticalSection()),
Peter Boström9dbbcfb2015-04-21 15:55:11 +020033 _encoder(nullptr),
andresp@webrtc.org1df9dc32014-01-09 08:01:57 +000034 _encodedFrameCallback(post_encode_callback),
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +000035 _nextFrameTypes(1, kVideoFrameDelta),
stefan@webrtc.org34c5da62014-04-11 14:08:35 +000036 _mediaOpt(clock_),
mflodmanfcf54bd2015-04-14 21:28:08 +020037 _sendStatsCallback(nullptr),
Peter Boström4f5db112015-10-29 16:53:59 +010038 _codecDataBase(encoder_rate_observer, &_encodedFrameCallback),
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +000039 frame_dropper_enabled_(true),
andresp@webrtc.orge682aa52013-12-19 10:59:48 +000040 _sendStatsTimer(1000, clock_),
tommi@webrtc.orge07710c2015-02-19 17:43:25 +000041 current_codec_(),
mflodmanfcf54bd2015-04-14 21:28:08 +020042 qm_settings_callback_(qm_settings_callback),
Peter Boström69ccb332015-10-29 16:30:23 +010043 protection_callback_(nullptr),
44 encoder_params_({0, 0, 0, 0}) {
tommi@webrtc.org658d2012015-03-05 12:21:54 +000045 // Allow VideoSender to be created on one thread but used on another, post
46 // construction. This is currently how this class is being used by at least
47 // one external project (diffractor).
mflodmanfcf54bd2015-04-14 21:28:08 +020048 _mediaOpt.EnableQM(qm_settings_callback_ != nullptr);
Peter Boström9dbbcfb2015-04-21 15:55:11 +020049 _mediaOpt.Reset();
tommi@webrtc.org658d2012015-03-05 12:21:54 +000050 main_thread_.DetachFromThread();
tommi@webrtc.orge07710c2015-02-19 17:43:25 +000051}
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +000052
Peter Boströmdcb89982015-09-15 14:43:47 +020053VideoSender::~VideoSender() {}
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +000054
55int32_t VideoSender::Process() {
56 int32_t returnValue = VCM_OK;
57
58 if (_sendStatsTimer.TimeUntilProcess() == 0) {
59 _sendStatsTimer.Processed();
stefan@webrtc.org8db81c52013-09-18 11:57:34 +000060 CriticalSectionScoped cs(process_crit_sect_.get());
mflodmanfcf54bd2015-04-14 21:28:08 +020061 if (_sendStatsCallback != nullptr) {
tommi@webrtc.orge07710c2015-02-19 17:43:25 +000062 uint32_t bitRate = _mediaOpt.SentBitRate();
63 uint32_t frameRate = _mediaOpt.SentFrameRate();
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +000064 _sendStatsCallback->SendStatistics(bitRate, frameRate);
65 }
66 }
67
Erik Språng66a641a2015-06-11 14:20:07 +020068 {
69 rtc::CritScope cs(&params_lock_);
70 // Force an encoder parameters update, so that incoming frame rate is
71 // updated even if bandwidth hasn't changed.
72 encoder_params_.input_frame_rate = _mediaOpt.InputFrameRate();
Erik Språng66a641a2015-06-11 14:20:07 +020073 }
74
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +000075 return returnValue;
76}
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ömdcb89982015-09-15 14:43:47 +020087 rtc::CritScope lock(&send_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
ivicac7199c22015-10-07 06:43:33 -0700108 int numLayers;
109 if (sendCodec->codecType == kVideoCodecVP8) {
110 numLayers = sendCodec->codecSpecific.VP8.numberOfTemporalLayers;
111 } else if (sendCodec->codecType == kVideoCodecVP9) {
112 numLayers = sendCodec->codecSpecific.VP9.numberOfTemporalLayers;
113 } else {
114 numLayers = 1;
115 }
116
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000117 // If we have screensharing and we have layers, we disable frame dropper.
118 bool disable_frame_dropper =
119 numLayers > 1 && sendCodec->mode == kScreensharing;
120 if (disable_frame_dropper) {
121 _mediaOpt.EnableFrameDropper(false);
122 } else if (frame_dropper_enabled_) {
123 _mediaOpt.EnableFrameDropper(true);
124 }
125 _nextFrameTypes.clear();
126 _nextFrameTypes.resize(VCM_MAX(sendCodec->numberOfSimulcastStreams, 1),
127 kVideoFrameDelta);
128
pbos@webrtc.org32d640e2013-09-17 10:36:30 +0000129 _mediaOpt.SetEncodingData(sendCodec->codecType,
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000130 sendCodec->maxBitrate * 1000,
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000131 sendCodec->startBitrate * 1000,
132 sendCodec->width,
133 sendCodec->height,
Peter Boströmdf664532015-05-12 12:22:14 +0200134 sendCodec->maxFramerate,
andresp@webrtc.orge682aa52013-12-19 10:59:48 +0000135 numLayers,
136 maxPayloadSize);
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000137 return VCM_OK;
138}
139
tommi@webrtc.orge07710c2015-02-19 17:43:25 +0000140const VideoCodec& VideoSender::GetSendCodec() const {
henrikg91d6ede2015-09-17 00:24:34 -0700141 RTC_DCHECK(main_thread_.CalledOnValidThread());
tommi@webrtc.orge07710c2015-02-19 17:43:25 +0000142 return current_codec_;
143}
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000144
tommi@webrtc.orge07710c2015-02-19 17:43:25 +0000145int32_t VideoSender::SendCodecBlocking(VideoCodec* currentSendCodec) const {
Peter Boströmdcb89982015-09-15 14:43:47 +0200146 rtc::CritScope lock(&send_crit_);
mflodmanfcf54bd2015-04-14 21:28:08 +0200147 if (currentSendCodec == nullptr) {
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000148 return VCM_PARAMETER_ERROR;
149 }
150 return _codecDataBase.SendCodec(currentSendCodec) ? 0 : -1;
151}
152
tommi@webrtc.orge07710c2015-02-19 17:43:25 +0000153VideoCodecType VideoSender::SendCodecBlocking() const {
Peter Boströmdcb89982015-09-15 14:43:47 +0200154 rtc::CritScope lock(&send_crit_);
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000155 return _codecDataBase.SendCodec();
156}
157
158// Register an external decoder object.
159// This can not be used together with external decoder callbacks.
Peter Boström795dbe42015-11-27 14:09:07 +0100160void VideoSender::RegisterExternalEncoder(VideoEncoder* externalEncoder,
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000161 uint8_t payloadType,
162 bool internalSource /*= false*/) {
henrikg91d6ede2015-09-17 00:24:34 -0700163 RTC_DCHECK(main_thread_.CalledOnValidThread());
tommi@webrtc.org558dc402015-03-07 20:55:56 +0000164
Peter Boströmdcb89982015-09-15 14:43:47 +0200165 rtc::CritScope lock(&send_crit_);
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000166
mflodmanfcf54bd2015-04-14 21:28:08 +0200167 if (externalEncoder == nullptr) {
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000168 bool wasSendCodec = false;
Peter Boström795dbe42015-11-27 14:09:07 +0100169 RTC_CHECK(
170 _codecDataBase.DeregisterExternalEncoder(payloadType, &wasSendCodec));
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000171 if (wasSendCodec) {
172 // Make sure the VCM doesn't use the de-registered codec
mflodmanfcf54bd2015-04-14 21:28:08 +0200173 _encoder = nullptr;
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000174 }
Peter Boström795dbe42015-11-27 14:09:07 +0100175 return;
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000176 }
177 _codecDataBase.RegisterExternalEncoder(
178 externalEncoder, payloadType, internalSource);
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000179}
180
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000181// Get encode bitrate
182int VideoSender::Bitrate(unsigned int* bitrate) const {
henrikg91d6ede2015-09-17 00:24:34 -0700183 RTC_DCHECK(main_thread_.CalledOnValidThread());
tommi@webrtc.org558dc402015-03-07 20:55:56 +0000184 // Since we're running on the thread that's the only thread known to modify
185 // the value of _encoder, we don't need to grab the lock here.
186
Peter Boström69ccb332015-10-29 16:30:23 +0100187 if (!_encoder)
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000188 return VCM_UNINITIALIZED;
Peter Boström69ccb332015-10-29 16:30:23 +0100189 *bitrate = _encoder->GetEncoderParameters().target_bitrate;
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000190 return 0;
191}
192
193// Get encode frame rate
194int VideoSender::FrameRate(unsigned int* framerate) const {
henrikg91d6ede2015-09-17 00:24:34 -0700195 RTC_DCHECK(main_thread_.CalledOnValidThread());
tommi@webrtc.org558dc402015-03-07 20:55:56 +0000196 // Since we're running on the thread that's the only thread known to modify
197 // the value of _encoder, we don't need to grab the lock here.
198
Peter Boström69ccb332015-10-29 16:30:23 +0100199 if (!_encoder)
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000200 return VCM_UNINITIALIZED;
Peter Boström69ccb332015-10-29 16:30:23 +0100201
202 *framerate = _encoder->GetEncoderParameters().input_frame_rate;
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000203 return 0;
204}
205
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000206int32_t VideoSender::SetChannelParameters(uint32_t target_bitrate,
207 uint8_t lossRate,
pkasting@chromium.org16825b12015-01-12 21:51:21 +0000208 int64_t rtt) {
Erik Språng66a641a2015-06-11 14:20:07 +0200209 uint32_t target_rate =
210 _mediaOpt.SetTargetRates(target_bitrate, lossRate, rtt,
211 protection_callback_, qm_settings_callback_);
tommi@webrtc.org558dc402015-03-07 20:55:56 +0000212
tommi@webrtc.org558dc402015-03-07 20:55:56 +0000213 uint32_t input_frame_rate = _mediaOpt.InputFrameRate();
214
Erik Språng66a641a2015-06-11 14:20:07 +0200215 rtc::CritScope cs(&params_lock_);
Peter Boström69ccb332015-10-29 16:30:23 +0100216 encoder_params_ = {target_rate, lossRate, rtt, input_frame_rate};
Erik Språng66a641a2015-06-11 14:20:07 +0200217
218 return VCM_OK;
219}
220
Peter Boströmdcb89982015-09-15 14:43:47 +0200221void VideoSender::SetEncoderParameters(EncoderParameters params) {
Peter Boström69ccb332015-10-29 16:30:23 +0100222 if (params.target_bitrate == 0)
Peter Boströmdcb89982015-09-15 14:43:47 +0200223 return;
tommi@webrtc.org558dc402015-03-07 20:55:56 +0000224
Erik Språng66a641a2015-06-11 14:20:07 +0200225 if (params.input_frame_rate == 0) {
226 // No frame rate estimate available, use default.
227 params.input_frame_rate = current_codec_.maxFramerate;
228 }
Peter Boström69ccb332015-10-29 16:30:23 +0100229 if (_encoder != nullptr)
230 _encoder->SetEncoderParameters(params);
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000231}
232
233int32_t VideoSender::RegisterTransportCallback(
234 VCMPacketizationCallback* transport) {
Peter Boströmdcb89982015-09-15 14:43:47 +0200235 rtc::CritScope lock(&send_crit_);
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000236 _encodedFrameCallback.SetMediaOpt(&_mediaOpt);
237 _encodedFrameCallback.SetTransportCallback(transport);
238 return VCM_OK;
239}
240
241// Register video output information callback which will be called to deliver
242// information about the video stream produced by the encoder, for instance the
243// average frame rate and bit rate.
244int32_t VideoSender::RegisterSendStatisticsCallback(
245 VCMSendStatisticsCallback* sendStats) {
stefan@webrtc.org8db81c52013-09-18 11:57:34 +0000246 CriticalSectionScoped cs(process_crit_sect_.get());
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000247 _sendStatsCallback = sendStats;
248 return VCM_OK;
249}
250
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000251// Register a video protection callback which will be called to deliver the
252// requested FEC rate and NACK status (on/off).
mflodmanfcf54bd2015-04-14 21:28:08 +0200253// Note: this callback is assumed to only be registered once and before it is
254// used in this class.
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000255int32_t VideoSender::RegisterProtectionCallback(
andresp@webrtc.orge682aa52013-12-19 10:59:48 +0000256 VCMProtectionCallback* protection_callback) {
henrikg91d6ede2015-09-17 00:24:34 -0700257 RTC_DCHECK(protection_callback == nullptr || protection_callback_ == nullptr);
andresp@webrtc.orge682aa52013-12-19 10:59:48 +0000258 protection_callback_ = protection_callback;
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000259 return VCM_OK;
260}
261
262// Enable or disable a video protection method.
pbosba8c15b2015-07-14 09:36:34 -0700263void VideoSender::SetVideoProtection(VCMVideoProtection videoProtection) {
Peter Boströmdcb89982015-09-15 14:43:47 +0200264 rtc::CritScope lock(&send_crit_);
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000265 switch (videoProtection) {
pbos@webrtc.orgcade82c2015-03-12 10:39:24 +0000266 case kProtectionNone:
pbosba8c15b2015-07-14 09:36:34 -0700267 _mediaOpt.SetProtectionMethod(media_optimization::kNone);
pbos@webrtc.orgcade82c2015-03-12 10:39:24 +0000268 break;
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000269 case kProtectionNack:
pbosba8c15b2015-07-14 09:36:34 -0700270 _mediaOpt.SetProtectionMethod(media_optimization::kNack);
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000271 break;
pbos@webrtc.orgcade82c2015-03-12 10:39:24 +0000272 case kProtectionNackFEC:
pbosba8c15b2015-07-14 09:36:34 -0700273 _mediaOpt.SetProtectionMethod(media_optimization::kNackFec);
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000274 break;
pbos@webrtc.orgcade82c2015-03-12 10:39:24 +0000275 case kProtectionFEC:
pbosba8c15b2015-07-14 09:36:34 -0700276 _mediaOpt.SetProtectionMethod(media_optimization::kFec);
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000277 break;
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000278 }
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000279}
280// Add one raw video frame to the encoder, blocking.
Miguel Casas-Sanchez47650702015-05-29 17:21:40 -0700281int32_t VideoSender::AddVideoFrame(const VideoFrame& videoFrame,
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000282 const VideoContentMetrics* contentMetrics,
283 const CodecSpecificInfo* codecSpecificInfo) {
Peter Boströmdcb89982015-09-15 14:43:47 +0200284 EncoderParameters encoder_params;
285 {
286 rtc::CritScope lock(&params_lock_);
287 encoder_params = encoder_params_;
Peter Boströmdcb89982015-09-15 14:43:47 +0200288 }
289 rtc::CritScope lock(&send_crit_);
Peter Boström69ccb332015-10-29 16:30:23 +0100290 if (_encoder == nullptr)
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000291 return VCM_UNINITIALIZED;
Peter Boström69ccb332015-10-29 16:30:23 +0100292 SetEncoderParameters(encoder_params);
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000293 // TODO(holmer): Add support for dropping frames per stream. Currently we
294 // only have one frame dropper for all streams.
pbos22993e12015-10-19 02:39:06 -0700295 if (_nextFrameTypes[0] == kEmptyFrame) {
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000296 return VCM_OK;
297 }
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000298 if (_mediaOpt.DropFrame()) {
jackychen61b4d512015-04-21 15:30:11 -0700299 _encoder->OnDroppedFrame();
stefan@webrtc.org34c5da62014-04-11 14:08:35 +0000300 return VCM_OK;
301 }
302 _mediaOpt.UpdateContentData(contentMetrics);
pbos@webrtc.org67a9e402015-03-05 13:57:37 +0000303 // TODO(pbos): Make sure setting send codec is synchronized with video
304 // processing so frame size always matches.
305 if (!_codecDataBase.MatchesCurrentResolution(videoFrame.width(),
306 videoFrame.height())) {
307 LOG(LS_ERROR) << "Incoming frame doesn't match set resolution. Dropping.";
308 return VCM_PARAMETER_ERROR;
309 }
Peter Boströmeb66e802015-06-05 11:08:03 +0200310 VideoFrame converted_frame = videoFrame;
311 if (converted_frame.native_handle() && !_encoder->SupportsNativeHandle()) {
312 // This module only supports software encoding.
313 // TODO(pbos): Offload conversion from the encoder thread.
314 converted_frame = converted_frame.ConvertNativeToI420Frame();
henrikg91d6ede2015-09-17 00:24:34 -0700315 RTC_CHECK(!converted_frame.IsZeroSize())
Peter Boströmeb66e802015-06-05 11:08:03 +0200316 << "Frame conversion failed, won't be able to encode frame.";
317 }
stefan@webrtc.org34c5da62014-04-11 14:08:35 +0000318 int32_t ret =
Peter Boströmeb66e802015-06-05 11:08:03 +0200319 _encoder->Encode(converted_frame, codecSpecificInfo, _nextFrameTypes);
stefan@webrtc.org34c5da62014-04-11 14:08:35 +0000320 if (ret < 0) {
321 LOG(LS_ERROR) << "Failed to encode frame. Error code: " << ret;
322 return ret;
323 }
324 for (size_t i = 0; i < _nextFrameTypes.size(); ++i) {
325 _nextFrameTypes[i] = kVideoFrameDelta; // Default frame type.
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000326 }
jackychen6e2ce6e2015-07-13 16:26:33 -0700327 if (qm_settings_callback_)
328 qm_settings_callback_->SetTargetFramerate(_encoder->GetTargetFramerate());
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000329 return VCM_OK;
330}
331
332int32_t VideoSender::IntraFrameRequest(int stream_index) {
Peter Boströmdcb89982015-09-15 14:43:47 +0200333 rtc::CritScope lock(&send_crit_);
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000334 if (stream_index < 0 ||
335 static_cast<unsigned int>(stream_index) >= _nextFrameTypes.size()) {
336 return -1;
337 }
338 _nextFrameTypes[stream_index] = kVideoFrameKey;
mflodmanfcf54bd2015-04-14 21:28:08 +0200339 if (_encoder != nullptr && _encoder->InternalSource()) {
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000340 // Try to request the frame if we have an external encoder with
341 // internal source since AddVideoFrame never will be called.
342 if (_encoder->RequestFrame(_nextFrameTypes) == WEBRTC_VIDEO_CODEC_OK) {
343 _nextFrameTypes[stream_index] = kVideoFrameDelta;
344 }
345 }
346 return VCM_OK;
347}
348
349int32_t VideoSender::EnableFrameDropper(bool enable) {
Peter Boströmdcb89982015-09-15 14:43:47 +0200350 rtc::CritScope lock(&send_crit_);
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000351 frame_dropper_enabled_ = enable;
352 _mediaOpt.EnableFrameDropper(enable);
353 return VCM_OK;
354}
355
henrik.lundin@webrtc.orgce8e0932013-11-18 12:18:43 +0000356void VideoSender::SuspendBelowMinBitrate() {
henrikg91d6ede2015-09-17 00:24:34 -0700357 RTC_DCHECK(main_thread_.CalledOnValidThread());
henrik.lundin@webrtc.org1a3a6e52013-10-28 10:16:14 +0000358 int threshold_bps;
tommi@webrtc.orge07710c2015-02-19 17:43:25 +0000359 if (current_codec_.numberOfSimulcastStreams == 0) {
360 threshold_bps = current_codec_.minBitrate * 1000;
henrik.lundin@webrtc.org1a3a6e52013-10-28 10:16:14 +0000361 } else {
tommi@webrtc.orge07710c2015-02-19 17:43:25 +0000362 threshold_bps = current_codec_.simulcastStream[0].minBitrate * 1000;
henrik.lundin@webrtc.org1a3a6e52013-10-28 10:16:14 +0000363 }
364 // Set the hysteresis window to be at 10% of the threshold, but at least
365 // 10 kbps.
366 int window_bps = std::max(threshold_bps / 10, 10000);
henrik.lundin@webrtc.orgce8e0932013-11-18 12:18:43 +0000367 _mediaOpt.SuspendBelowMinBitrate(threshold_bps, window_bps);
henrik.lundin@webrtc.org572699d2013-09-30 12:16:08 +0000368}
369
henrik.lundin@webrtc.orgce8e0932013-11-18 12:18:43 +0000370bool VideoSender::VideoSuspended() const {
andresp@webrtc.orge682aa52013-12-19 10:59:48 +0000371 return _mediaOpt.IsVideoSuspended();
henrik.lundin@webrtc.org572699d2013-09-30 12:16:08 +0000372}
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000373} // namespace vcm
374} // namespace webrtc