blob: bbf6480c030baa09f7e9c732a5de17cd97590f07 [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,
30 VCMQMSettingsCallback* qm_settings_callback)
stefan@webrtc.org34c5da62014-04-11 14:08:35 +000031 : clock_(clock),
Peter Boström9dbbcfb2015-04-21 15:55:11 +020032 _encoder(nullptr),
andresp@webrtc.org1df9dc32014-01-09 08:01:57 +000033 _encodedFrameCallback(post_encode_callback),
stefan@webrtc.org34c5da62014-04-11 14:08:35 +000034 _mediaOpt(clock_),
mflodmanfcf54bd2015-04-14 21:28:08 +020035 _sendStatsCallback(nullptr),
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_(),
mflodmanfcf54bd2015-04-14 21:28:08 +020040 qm_settings_callback_(qm_settings_callback),
Peter Boström69ccb332015-10-29 16:30:23 +010041 protection_callback_(nullptr),
Peter Boström233bfd22016-01-18 20:23:40 +010042 encoder_params_({0, 0, 0, 0}),
43 encoder_has_internal_source_(false),
44 next_frame_types_(1, kVideoFrameDelta) {
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
pbosa26ac922016-02-25 04:50:01 -080055void VideoSender::Process() {
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +000056 if (_sendStatsTimer.TimeUntilProcess() == 0) {
57 _sendStatsTimer.Processed();
sprang3911c262016-04-15 01:24:14 -070058 rtc::CritScope cs(&process_crit_);
mflodmanfcf54bd2015-04-14 21:28:08 +020059 if (_sendStatsCallback != nullptr) {
tommi@webrtc.orge07710c2015-02-19 17:43:25 +000060 uint32_t bitRate = _mediaOpt.SentBitRate();
61 uint32_t frameRate = _mediaOpt.SentFrameRate();
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +000062 _sendStatsCallback->SendStatistics(bitRate, frameRate);
63 }
64 }
65
Erik Språng66a641a2015-06-11 14:20:07 +020066 {
Peter Boström233bfd22016-01-18 20:23:40 +010067 rtc::CritScope cs(&params_crit_);
Erik Språng66a641a2015-06-11 14:20:07 +020068 // Force an encoder parameters update, so that incoming frame rate is
69 // updated even if bandwidth hasn't changed.
70 encoder_params_.input_frame_rate = _mediaOpt.InputFrameRate();
Erik Språng66a641a2015-06-11 14:20:07 +020071 }
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +000072}
73
pkasting@chromium.org0b1534c2014-12-15 22:09:40 +000074int64_t VideoSender::TimeUntilNextProcess() {
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +000075 return _sendStatsTimer.TimeUntilProcess();
76}
77
78// Register the send codec to be used.
79int32_t VideoSender::RegisterSendCodec(const VideoCodec* sendCodec,
80 uint32_t numberOfCores,
81 uint32_t maxPayloadSize) {
henrikg91d6ede2015-09-17 00:24:34 -070082 RTC_DCHECK(main_thread_.CalledOnValidThread());
Peter Boström233bfd22016-01-18 20:23:40 +010083 rtc::CritScope lock(&encoder_crit_);
mflodmanfcf54bd2015-04-14 21:28:08 +020084 if (sendCodec == nullptr) {
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +000085 return VCM_PARAMETER_ERROR;
86 }
87
Peter Boström4f5db112015-10-29 16:53:59 +010088 bool ret =
89 _codecDataBase.SetSendCodec(sendCodec, numberOfCores, maxPayloadSize);
pbos@webrtc.orgda2c4ce2013-09-17 09:38:41 +000090
91 // Update encoder regardless of result to make sure that we're not holding on
92 // to a deleted instance.
93 _encoder = _codecDataBase.GetEncoder();
tommi@webrtc.orge07710c2015-02-19 17:43:25 +000094 // Cache the current codec here so they can be fetched from this thread
95 // without requiring the _sendCritSect lock.
96 current_codec_ = *sendCodec;
pbos@webrtc.orgda2c4ce2013-09-17 09:38:41 +000097
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +000098 if (!ret) {
pbos@webrtc.org0b52ceb2015-03-24 11:20:54 +000099 LOG(LS_ERROR) << "Failed to initialize set encoder with payload name '"
100 << sendCodec->plName << "'.";
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000101 return VCM_CODEC_ERROR;
102 }
103
Peter Boström233bfd22016-01-18 20:23:40 +0100104 // SetSendCodec succeeded, _encoder should be set.
105 RTC_DCHECK(_encoder);
106
ivicac7199c22015-10-07 06:43:33 -0700107 int numLayers;
108 if (sendCodec->codecType == kVideoCodecVP8) {
109 numLayers = sendCodec->codecSpecific.VP8.numberOfTemporalLayers;
110 } else if (sendCodec->codecType == kVideoCodecVP9) {
111 numLayers = sendCodec->codecSpecific.VP9.numberOfTemporalLayers;
112 } else {
113 numLayers = 1;
114 }
115
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000116 // If we have screensharing and we have layers, we disable frame dropper.
117 bool disable_frame_dropper =
118 numLayers > 1 && sendCodec->mode == kScreensharing;
119 if (disable_frame_dropper) {
120 _mediaOpt.EnableFrameDropper(false);
121 } else if (frame_dropper_enabled_) {
122 _mediaOpt.EnableFrameDropper(true);
123 }
Peter Boström233bfd22016-01-18 20:23:40 +0100124 {
125 rtc::CritScope cs(&params_crit_);
126 next_frame_types_.clear();
127 next_frame_types_.resize(VCM_MAX(sendCodec->numberOfSimulcastStreams, 1),
128 kVideoFrameKey);
129 // Cache InternalSource() to have this available from IntraFrameRequest()
130 // without having to acquire encoder_crit_ (avoid blocking on encoder use).
131 encoder_has_internal_source_ = _encoder->InternalSource();
132 }
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000133
isheriff7620be82016-03-06 23:22:33 -0800134 LOG(LS_VERBOSE) << " max bitrate " << sendCodec->maxBitrate
135 << " start bitrate " << sendCodec->startBitrate
136 << " max frame rate " << sendCodec->maxFramerate
137 << " max payload size " << maxPayloadSize;
philipel5908c712015-12-21 08:23:20 -0800138 _mediaOpt.SetEncodingData(sendCodec->codecType, sendCodec->maxBitrate * 1000,
139 sendCodec->startBitrate * 1000, sendCodec->width,
140 sendCodec->height, sendCodec->maxFramerate,
141 numLayers, maxPayloadSize);
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000142 return VCM_OK;
143}
144
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000145// Register an external decoder object.
146// This can not be used together with external decoder callbacks.
Peter Boström795dbe42015-11-27 14:09:07 +0100147void VideoSender::RegisterExternalEncoder(VideoEncoder* externalEncoder,
philipel5908c712015-12-21 08:23:20 -0800148 uint8_t payloadType,
149 bool internalSource /*= false*/) {
henrikg91d6ede2015-09-17 00:24:34 -0700150 RTC_DCHECK(main_thread_.CalledOnValidThread());
tommi@webrtc.org558dc402015-03-07 20:55:56 +0000151
Peter Boström233bfd22016-01-18 20:23:40 +0100152 rtc::CritScope lock(&encoder_crit_);
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000153
mflodmanfcf54bd2015-04-14 21:28:08 +0200154 if (externalEncoder == nullptr) {
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000155 bool wasSendCodec = false;
Peter Boström795dbe42015-11-27 14:09:07 +0100156 RTC_CHECK(
157 _codecDataBase.DeregisterExternalEncoder(payloadType, &wasSendCodec));
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000158 if (wasSendCodec) {
159 // Make sure the VCM doesn't use the de-registered codec
Peter Boström233bfd22016-01-18 20:23:40 +0100160 rtc::CritScope params_lock(&params_crit_);
mflodmanfcf54bd2015-04-14 21:28:08 +0200161 _encoder = nullptr;
Peter Boström233bfd22016-01-18 20:23:40 +0100162 encoder_has_internal_source_ = false;
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000163 }
Peter Boström795dbe42015-11-27 14:09:07 +0100164 return;
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000165 }
philipel5908c712015-12-21 08:23:20 -0800166 _codecDataBase.RegisterExternalEncoder(externalEncoder, payloadType,
167 internalSource);
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000168}
169
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000170// Get encode bitrate
171int VideoSender::Bitrate(unsigned int* bitrate) const {
henrikg91d6ede2015-09-17 00:24:34 -0700172 RTC_DCHECK(main_thread_.CalledOnValidThread());
tommi@webrtc.org558dc402015-03-07 20:55:56 +0000173 // Since we're running on the thread that's the only thread known to modify
174 // the value of _encoder, we don't need to grab the lock here.
175
Peter Boström69ccb332015-10-29 16:30:23 +0100176 if (!_encoder)
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000177 return VCM_UNINITIALIZED;
Peter Boström69ccb332015-10-29 16:30:23 +0100178 *bitrate = _encoder->GetEncoderParameters().target_bitrate;
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000179 return 0;
180}
181
182// Get encode frame rate
183int VideoSender::FrameRate(unsigned int* framerate) const {
henrikg91d6ede2015-09-17 00:24:34 -0700184 RTC_DCHECK(main_thread_.CalledOnValidThread());
tommi@webrtc.org558dc402015-03-07 20:55:56 +0000185 // Since we're running on the thread that's the only thread known to modify
186 // the value of _encoder, we don't need to grab the lock here.
187
Peter Boström69ccb332015-10-29 16:30:23 +0100188 if (!_encoder)
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000189 return VCM_UNINITIALIZED;
Peter Boström69ccb332015-10-29 16:30:23 +0100190
191 *framerate = _encoder->GetEncoderParameters().input_frame_rate;
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000192 return 0;
193}
194
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000195int32_t VideoSender::SetChannelParameters(uint32_t target_bitrate,
196 uint8_t lossRate,
pkasting@chromium.org16825b12015-01-12 21:51:21 +0000197 int64_t rtt) {
Erik Språng66a641a2015-06-11 14:20:07 +0200198 uint32_t target_rate =
199 _mediaOpt.SetTargetRates(target_bitrate, lossRate, rtt,
200 protection_callback_, qm_settings_callback_);
tommi@webrtc.org558dc402015-03-07 20:55:56 +0000201
tommi@webrtc.org558dc402015-03-07 20:55:56 +0000202 uint32_t input_frame_rate = _mediaOpt.InputFrameRate();
203
noahricd4badbc2016-04-13 14:59:48 -0700204 EncoderParameters encoder_params = {target_rate, lossRate, rtt,
205 input_frame_rate};
206 bool encoder_has_internal_source;
207 {
208 rtc::CritScope cs(&params_crit_);
209 encoder_params_ = encoder_params;
210 encoder_has_internal_source = encoder_has_internal_source_;
211 }
212
213 // For encoders with internal sources, we need to tell the encoder directly,
214 // instead of waiting for an AddVideoFrame that will never come (internal
215 // source encoders don't get input frames).
216 if (encoder_has_internal_source) {
217 rtc::CritScope cs(&encoder_crit_);
218 if (_encoder) {
219 SetEncoderParameters(encoder_params);
220 }
221 }
Erik Språng66a641a2015-06-11 14:20:07 +0200222
223 return VCM_OK;
224}
225
Peter Boströmdcb89982015-09-15 14:43:47 +0200226void VideoSender::SetEncoderParameters(EncoderParameters params) {
Peter Boström69ccb332015-10-29 16:30:23 +0100227 if (params.target_bitrate == 0)
Peter Boströmdcb89982015-09-15 14:43:47 +0200228 return;
tommi@webrtc.org558dc402015-03-07 20:55:56 +0000229
Erik Språng66a641a2015-06-11 14:20:07 +0200230 if (params.input_frame_rate == 0) {
231 // No frame rate estimate available, use default.
232 params.input_frame_rate = current_codec_.maxFramerate;
233 }
Peter Boström69ccb332015-10-29 16:30:23 +0100234 if (_encoder != nullptr)
235 _encoder->SetEncoderParameters(params);
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000236}
237
238int32_t VideoSender::RegisterTransportCallback(
239 VCMPacketizationCallback* transport) {
Peter Boström233bfd22016-01-18 20:23:40 +0100240 rtc::CritScope lock(&encoder_crit_);
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000241 _encodedFrameCallback.SetMediaOpt(&_mediaOpt);
242 _encodedFrameCallback.SetTransportCallback(transport);
243 return VCM_OK;
244}
245
246// Register video output information callback which will be called to deliver
247// information about the video stream produced by the encoder, for instance the
248// average frame rate and bit rate.
249int32_t VideoSender::RegisterSendStatisticsCallback(
250 VCMSendStatisticsCallback* sendStats) {
sprang3911c262016-04-15 01:24:14 -0700251 rtc::CritScope cs(&process_crit_);
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000252 _sendStatsCallback = sendStats;
253 return VCM_OK;
254}
255
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000256// Register a video protection callback which will be called to deliver the
257// requested FEC rate and NACK status (on/off).
mflodmanfcf54bd2015-04-14 21:28:08 +0200258// Note: this callback is assumed to only be registered once and before it is
259// used in this class.
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000260int32_t VideoSender::RegisterProtectionCallback(
andresp@webrtc.orge682aa52013-12-19 10:59:48 +0000261 VCMProtectionCallback* protection_callback) {
henrikg91d6ede2015-09-17 00:24:34 -0700262 RTC_DCHECK(protection_callback == nullptr || protection_callback_ == nullptr);
andresp@webrtc.orge682aa52013-12-19 10:59:48 +0000263 protection_callback_ = protection_callback;
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000264 return VCM_OK;
265}
266
267// Enable or disable a video protection method.
pbosba8c15b2015-07-14 09:36:34 -0700268void VideoSender::SetVideoProtection(VCMVideoProtection videoProtection) {
Peter Boström233bfd22016-01-18 20:23:40 +0100269 rtc::CritScope lock(&encoder_crit_);
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000270 switch (videoProtection) {
pbos@webrtc.orgcade82c2015-03-12 10:39:24 +0000271 case kProtectionNone:
pbosba8c15b2015-07-14 09:36:34 -0700272 _mediaOpt.SetProtectionMethod(media_optimization::kNone);
pbos@webrtc.orgcade82c2015-03-12 10:39:24 +0000273 break;
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000274 case kProtectionNack:
pbosba8c15b2015-07-14 09:36:34 -0700275 _mediaOpt.SetProtectionMethod(media_optimization::kNack);
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000276 break;
pbos@webrtc.orgcade82c2015-03-12 10:39:24 +0000277 case kProtectionNackFEC:
pbosba8c15b2015-07-14 09:36:34 -0700278 _mediaOpt.SetProtectionMethod(media_optimization::kNackFec);
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000279 break;
pbos@webrtc.orgcade82c2015-03-12 10:39:24 +0000280 case kProtectionFEC:
pbosba8c15b2015-07-14 09:36:34 -0700281 _mediaOpt.SetProtectionMethod(media_optimization::kFec);
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000282 break;
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000283 }
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000284}
285// Add one raw video frame to the encoder, blocking.
Miguel Casas-Sanchez47650702015-05-29 17:21:40 -0700286int32_t VideoSender::AddVideoFrame(const VideoFrame& videoFrame,
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000287 const VideoContentMetrics* contentMetrics,
288 const CodecSpecificInfo* codecSpecificInfo) {
Peter Boströmdcb89982015-09-15 14:43:47 +0200289 EncoderParameters encoder_params;
Peter Boström233bfd22016-01-18 20:23:40 +0100290 std::vector<FrameType> next_frame_types;
Peter Boströmdcb89982015-09-15 14:43:47 +0200291 {
Peter Boström233bfd22016-01-18 20:23:40 +0100292 rtc::CritScope lock(&params_crit_);
Peter Boströmdcb89982015-09-15 14:43:47 +0200293 encoder_params = encoder_params_;
Peter Boström233bfd22016-01-18 20:23:40 +0100294 next_frame_types = next_frame_types_;
Peter Boströmdcb89982015-09-15 14:43:47 +0200295 }
Peter Boström233bfd22016-01-18 20:23:40 +0100296 rtc::CritScope lock(&encoder_crit_);
Peter Boström69ccb332015-10-29 16:30:23 +0100297 if (_encoder == nullptr)
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000298 return VCM_UNINITIALIZED;
Peter Boström69ccb332015-10-29 16:30:23 +0100299 SetEncoderParameters(encoder_params);
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000300 if (_mediaOpt.DropFrame()) {
isheriff7620be82016-03-06 23:22:33 -0800301 LOG(LS_VERBOSE) << "Drop Frame "
302 << "target bitrate " << encoder_params.target_bitrate
303 << " loss rate " << encoder_params.loss_rate << " rtt "
304 << encoder_params.rtt << " input frame rate "
305 << encoder_params.input_frame_rate;
jackychen61b4d512015-04-21 15:30:11 -0700306 _encoder->OnDroppedFrame();
stefan@webrtc.org34c5da62014-04-11 14:08:35 +0000307 return VCM_OK;
308 }
309 _mediaOpt.UpdateContentData(contentMetrics);
pbos@webrtc.org67a9e402015-03-05 13:57:37 +0000310 // TODO(pbos): Make sure setting send codec is synchronized with video
311 // processing so frame size always matches.
312 if (!_codecDataBase.MatchesCurrentResolution(videoFrame.width(),
313 videoFrame.height())) {
314 LOG(LS_ERROR) << "Incoming frame doesn't match set resolution. Dropping.";
315 return VCM_PARAMETER_ERROR;
316 }
Peter Boströmeb66e802015-06-05 11:08:03 +0200317 VideoFrame converted_frame = videoFrame;
318 if (converted_frame.native_handle() && !_encoder->SupportsNativeHandle()) {
319 // This module only supports software encoding.
320 // TODO(pbos): Offload conversion from the encoder thread.
321 converted_frame = converted_frame.ConvertNativeToI420Frame();
henrikg91d6ede2015-09-17 00:24:34 -0700322 RTC_CHECK(!converted_frame.IsZeroSize())
Peter Boströmeb66e802015-06-05 11:08:03 +0200323 << "Frame conversion failed, won't be able to encode frame.";
324 }
stefan@webrtc.org34c5da62014-04-11 14:08:35 +0000325 int32_t ret =
Peter Boström233bfd22016-01-18 20:23:40 +0100326 _encoder->Encode(converted_frame, codecSpecificInfo, next_frame_types);
stefan@webrtc.org34c5da62014-04-11 14:08:35 +0000327 if (ret < 0) {
328 LOG(LS_ERROR) << "Failed to encode frame. Error code: " << ret;
329 return ret;
330 }
Peter Boström233bfd22016-01-18 20:23:40 +0100331 {
332 // Change all keyframe requests to encode delta frames the next time.
333 rtc::CritScope lock(&params_crit_);
334 for (size_t i = 0; i < next_frame_types_.size(); ++i) {
335 // Check for equality (same requested as before encoding) to not
336 // accidentally drop a keyframe request while encoding.
337 if (next_frame_types[i] == next_frame_types_[i])
338 next_frame_types_[i] = kVideoFrameDelta;
339 }
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000340 }
jackychen6e2ce6e2015-07-13 16:26:33 -0700341 if (qm_settings_callback_)
342 qm_settings_callback_->SetTargetFramerate(_encoder->GetTargetFramerate());
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000343 return VCM_OK;
344}
345
346int32_t VideoSender::IntraFrameRequest(int stream_index) {
Peter Boström233bfd22016-01-18 20:23:40 +0100347 {
348 rtc::CritScope lock(&params_crit_);
349 if (stream_index < 0 ||
350 static_cast<size_t>(stream_index) >= next_frame_types_.size()) {
351 return -1;
352 }
353 next_frame_types_[stream_index] = kVideoFrameKey;
354 if (!encoder_has_internal_source_)
355 return VCM_OK;
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000356 }
Peter Boström233bfd22016-01-18 20:23:40 +0100357 // TODO(pbos): Remove when InternalSource() is gone. Both locks have to be
358 // held here for internal consistency, since _encoder could be removed while
359 // not holding encoder_crit_. Checks have to be performed again since
360 // params_crit_ was dropped to not cause lock-order inversions with
361 // encoder_crit_.
362 rtc::CritScope lock(&encoder_crit_);
363 rtc::CritScope params_lock(&params_crit_);
364 if (static_cast<size_t>(stream_index) >= next_frame_types_.size())
365 return -1;
mflodmanfcf54bd2015-04-14 21:28:08 +0200366 if (_encoder != nullptr && _encoder->InternalSource()) {
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000367 // Try to request the frame if we have an external encoder with
368 // internal source since AddVideoFrame never will be called.
Peter Boström233bfd22016-01-18 20:23:40 +0100369 if (_encoder->RequestFrame(next_frame_types_) == WEBRTC_VIDEO_CODEC_OK) {
370 // Try to remove just-performed keyframe request, if stream still exists.
371 next_frame_types_[stream_index] = kVideoFrameDelta;
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000372 }
373 }
374 return VCM_OK;
375}
376
377int32_t VideoSender::EnableFrameDropper(bool enable) {
Peter Boström233bfd22016-01-18 20:23:40 +0100378 rtc::CritScope lock(&encoder_crit_);
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000379 frame_dropper_enabled_ = enable;
380 _mediaOpt.EnableFrameDropper(enable);
381 return VCM_OK;
382}
383
henrik.lundin@webrtc.orgce8e0932013-11-18 12:18:43 +0000384void VideoSender::SuspendBelowMinBitrate() {
henrikg91d6ede2015-09-17 00:24:34 -0700385 RTC_DCHECK(main_thread_.CalledOnValidThread());
henrik.lundin@webrtc.org1a3a6e52013-10-28 10:16:14 +0000386 int threshold_bps;
tommi@webrtc.orge07710c2015-02-19 17:43:25 +0000387 if (current_codec_.numberOfSimulcastStreams == 0) {
388 threshold_bps = current_codec_.minBitrate * 1000;
henrik.lundin@webrtc.org1a3a6e52013-10-28 10:16:14 +0000389 } else {
tommi@webrtc.orge07710c2015-02-19 17:43:25 +0000390 threshold_bps = current_codec_.simulcastStream[0].minBitrate * 1000;
henrik.lundin@webrtc.org1a3a6e52013-10-28 10:16:14 +0000391 }
392 // Set the hysteresis window to be at 10% of the threshold, but at least
393 // 10 kbps.
394 int window_bps = std::max(threshold_bps / 10, 10000);
henrik.lundin@webrtc.orgce8e0932013-11-18 12:18:43 +0000395 _mediaOpt.SuspendBelowMinBitrate(threshold_bps, window_bps);
henrik.lundin@webrtc.org572699d2013-09-30 12:16:08 +0000396}
397
henrik.lundin@webrtc.orgce8e0932013-11-18 12:18:43 +0000398bool VideoSender::VideoSuspended() const {
andresp@webrtc.orge682aa52013-12-19 10:59:48 +0000399 return _mediaOpt.IsVideoSuspended();
henrik.lundin@webrtc.org572699d2013-09-30 12:16:08 +0000400}
andresp@webrtc.orgf7eb75b2013-09-14 00:25:28 +0000401} // namespace vcm
402} // namespace webrtc