| Index: webrtc/modules/video_coding/video_sender.cc
|
| diff --git a/webrtc/modules/video_coding/video_sender.cc b/webrtc/modules/video_coding/video_sender.cc
|
| index ac901f95b9e361055f826661a6be741429b6aca8..f14f8521148248507e3ff8048e8dadc708eb94cf 100644
|
| --- a/webrtc/modules/video_coding/video_sender.cc
|
| +++ b/webrtc/modules/video_coding/video_sender.cc
|
| @@ -32,7 +32,6 @@ VideoSender::VideoSender(Clock* clock,
|
| process_crit_sect_(CriticalSectionWrapper::CreateCriticalSection()),
|
| _encoder(nullptr),
|
| _encodedFrameCallback(post_encode_callback),
|
| - _nextFrameTypes(1, kVideoFrameDelta),
|
| _mediaOpt(clock_),
|
| _sendStatsCallback(nullptr),
|
| _codecDataBase(encoder_rate_observer, &_encodedFrameCallback),
|
| @@ -41,7 +40,9 @@ VideoSender::VideoSender(Clock* clock,
|
| current_codec_(),
|
| qm_settings_callback_(qm_settings_callback),
|
| protection_callback_(nullptr),
|
| - encoder_params_({0, 0, 0, 0}) {
|
| + encoder_params_({0, 0, 0, 0}),
|
| + encoder_has_internal_source_(false),
|
| + next_frame_types_(1, kVideoFrameDelta) {
|
| // Allow VideoSender to be created on one thread but used on another, post
|
| // construction. This is currently how this class is being used by at least
|
| // one external project (diffractor).
|
| @@ -66,7 +67,7 @@ int32_t VideoSender::Process() {
|
| }
|
|
|
| {
|
| - rtc::CritScope cs(¶ms_lock_);
|
| + rtc::CritScope cs(¶ms_crit_);
|
| // Force an encoder parameters update, so that incoming frame rate is
|
| // updated even if bandwidth hasn't changed.
|
| encoder_params_.input_frame_rate = _mediaOpt.InputFrameRate();
|
| @@ -84,7 +85,7 @@ int32_t VideoSender::RegisterSendCodec(const VideoCodec* sendCodec,
|
| uint32_t numberOfCores,
|
| uint32_t maxPayloadSize) {
|
| RTC_DCHECK(main_thread_.CalledOnValidThread());
|
| - rtc::CritScope lock(&send_crit_);
|
| + rtc::CritScope lock(&encoder_crit_);
|
| if (sendCodec == nullptr) {
|
| return VCM_PARAMETER_ERROR;
|
| }
|
| @@ -105,6 +106,9 @@ int32_t VideoSender::RegisterSendCodec(const VideoCodec* sendCodec,
|
| return VCM_CODEC_ERROR;
|
| }
|
|
|
| + // SetSendCodec succeeded, _encoder should be set.
|
| + RTC_DCHECK(_encoder);
|
| +
|
| int numLayers;
|
| if (sendCodec->codecType == kVideoCodecVP8) {
|
| numLayers = sendCodec->codecSpecific.VP8.numberOfTemporalLayers;
|
| @@ -122,9 +126,15 @@ int32_t VideoSender::RegisterSendCodec(const VideoCodec* sendCodec,
|
| } else if (frame_dropper_enabled_) {
|
| _mediaOpt.EnableFrameDropper(true);
|
| }
|
| - _nextFrameTypes.clear();
|
| - _nextFrameTypes.resize(VCM_MAX(sendCodec->numberOfSimulcastStreams, 1),
|
| - kVideoFrameDelta);
|
| + {
|
| + rtc::CritScope cs(¶ms_crit_);
|
| + next_frame_types_.clear();
|
| + next_frame_types_.resize(VCM_MAX(sendCodec->numberOfSimulcastStreams, 1),
|
| + kVideoFrameKey);
|
| + // Cache InternalSource() to have this available from IntraFrameRequest()
|
| + // without having to acquire encoder_crit_ (avoid blocking on encoder use).
|
| + encoder_has_internal_source_ = _encoder->InternalSource();
|
| + }
|
|
|
| _mediaOpt.SetEncodingData(sendCodec->codecType, sendCodec->maxBitrate * 1000,
|
| sendCodec->startBitrate * 1000, sendCodec->width,
|
| @@ -140,7 +150,7 @@ void VideoSender::RegisterExternalEncoder(VideoEncoder* externalEncoder,
|
| bool internalSource /*= false*/) {
|
| RTC_DCHECK(main_thread_.CalledOnValidThread());
|
|
|
| - rtc::CritScope lock(&send_crit_);
|
| + rtc::CritScope lock(&encoder_crit_);
|
|
|
| if (externalEncoder == nullptr) {
|
| bool wasSendCodec = false;
|
| @@ -148,7 +158,9 @@ void VideoSender::RegisterExternalEncoder(VideoEncoder* externalEncoder,
|
| _codecDataBase.DeregisterExternalEncoder(payloadType, &wasSendCodec));
|
| if (wasSendCodec) {
|
| // Make sure the VCM doesn't use the de-registered codec
|
| + rtc::CritScope params_lock(¶ms_crit_);
|
| _encoder = nullptr;
|
| + encoder_has_internal_source_ = false;
|
| }
|
| return;
|
| }
|
| @@ -190,7 +202,7 @@ int32_t VideoSender::SetChannelParameters(uint32_t target_bitrate,
|
|
|
| uint32_t input_frame_rate = _mediaOpt.InputFrameRate();
|
|
|
| - rtc::CritScope cs(¶ms_lock_);
|
| + rtc::CritScope cs(¶ms_crit_);
|
| encoder_params_ = {target_rate, lossRate, rtt, input_frame_rate};
|
|
|
| return VCM_OK;
|
| @@ -210,7 +222,7 @@ void VideoSender::SetEncoderParameters(EncoderParameters params) {
|
|
|
| int32_t VideoSender::RegisterTransportCallback(
|
| VCMPacketizationCallback* transport) {
|
| - rtc::CritScope lock(&send_crit_);
|
| + rtc::CritScope lock(&encoder_crit_);
|
| _encodedFrameCallback.SetMediaOpt(&_mediaOpt);
|
| _encodedFrameCallback.SetTransportCallback(transport);
|
| return VCM_OK;
|
| @@ -239,7 +251,7 @@ int32_t VideoSender::RegisterProtectionCallback(
|
|
|
| // Enable or disable a video protection method.
|
| void VideoSender::SetVideoProtection(VCMVideoProtection videoProtection) {
|
| - rtc::CritScope lock(&send_crit_);
|
| + rtc::CritScope lock(&encoder_crit_);
|
| switch (videoProtection) {
|
| case kProtectionNone:
|
| _mediaOpt.SetProtectionMethod(media_optimization::kNone);
|
| @@ -260,19 +272,16 @@ int32_t VideoSender::AddVideoFrame(const VideoFrame& videoFrame,
|
| const VideoContentMetrics* contentMetrics,
|
| const CodecSpecificInfo* codecSpecificInfo) {
|
| EncoderParameters encoder_params;
|
| + std::vector<FrameType> next_frame_types;
|
| {
|
| - rtc::CritScope lock(¶ms_lock_);
|
| + rtc::CritScope lock(¶ms_crit_);
|
| encoder_params = encoder_params_;
|
| + next_frame_types = next_frame_types_;
|
| }
|
| - rtc::CritScope lock(&send_crit_);
|
| + rtc::CritScope lock(&encoder_crit_);
|
| if (_encoder == nullptr)
|
| return VCM_UNINITIALIZED;
|
| SetEncoderParameters(encoder_params);
|
| - // TODO(holmer): Add support for dropping frames per stream. Currently we
|
| - // only have one frame dropper for all streams.
|
| - if (_nextFrameTypes[0] == kEmptyFrame) {
|
| - return VCM_OK;
|
| - }
|
| if (_mediaOpt.DropFrame()) {
|
| _encoder->OnDroppedFrame();
|
| return VCM_OK;
|
| @@ -294,13 +303,20 @@ int32_t VideoSender::AddVideoFrame(const VideoFrame& videoFrame,
|
| << "Frame conversion failed, won't be able to encode frame.";
|
| }
|
| int32_t ret =
|
| - _encoder->Encode(converted_frame, codecSpecificInfo, _nextFrameTypes);
|
| + _encoder->Encode(converted_frame, codecSpecificInfo, next_frame_types);
|
| if (ret < 0) {
|
| LOG(LS_ERROR) << "Failed to encode frame. Error code: " << ret;
|
| return ret;
|
| }
|
| - for (size_t i = 0; i < _nextFrameTypes.size(); ++i) {
|
| - _nextFrameTypes[i] = kVideoFrameDelta; // Default frame type.
|
| + {
|
| + // Change all keyframe requests to encode delta frames the next time.
|
| + rtc::CritScope lock(¶ms_crit_);
|
| + for (size_t i = 0; i < next_frame_types_.size(); ++i) {
|
| + // Check for equality (same requested as before encoding) to not
|
| + // accidentally drop a keyframe request while encoding.
|
| + if (next_frame_types[i] == next_frame_types_[i])
|
| + next_frame_types_[i] = kVideoFrameDelta;
|
| + }
|
| }
|
| if (qm_settings_callback_)
|
| qm_settings_callback_->SetTargetFramerate(_encoder->GetTargetFramerate());
|
| @@ -308,24 +324,38 @@ int32_t VideoSender::AddVideoFrame(const VideoFrame& videoFrame,
|
| }
|
|
|
| int32_t VideoSender::IntraFrameRequest(int stream_index) {
|
| - rtc::CritScope lock(&send_crit_);
|
| - if (stream_index < 0 ||
|
| - static_cast<unsigned int>(stream_index) >= _nextFrameTypes.size()) {
|
| - return -1;
|
| + {
|
| + rtc::CritScope lock(¶ms_crit_);
|
| + if (stream_index < 0 ||
|
| + static_cast<size_t>(stream_index) >= next_frame_types_.size()) {
|
| + return -1;
|
| + }
|
| + next_frame_types_[stream_index] = kVideoFrameKey;
|
| + if (!encoder_has_internal_source_)
|
| + return VCM_OK;
|
| }
|
| - _nextFrameTypes[stream_index] = kVideoFrameKey;
|
| + // TODO(pbos): Remove when InternalSource() is gone. Both locks have to be
|
| + // held here for internal consistency, since _encoder could be removed while
|
| + // not holding encoder_crit_. Checks have to be performed again since
|
| + // params_crit_ was dropped to not cause lock-order inversions with
|
| + // encoder_crit_.
|
| + rtc::CritScope lock(&encoder_crit_);
|
| + rtc::CritScope params_lock(¶ms_crit_);
|
| + if (static_cast<size_t>(stream_index) >= next_frame_types_.size())
|
| + return -1;
|
| if (_encoder != nullptr && _encoder->InternalSource()) {
|
| // Try to request the frame if we have an external encoder with
|
| // internal source since AddVideoFrame never will be called.
|
| - if (_encoder->RequestFrame(_nextFrameTypes) == WEBRTC_VIDEO_CODEC_OK) {
|
| - _nextFrameTypes[stream_index] = kVideoFrameDelta;
|
| + if (_encoder->RequestFrame(next_frame_types_) == WEBRTC_VIDEO_CODEC_OK) {
|
| + // Try to remove just-performed keyframe request, if stream still exists.
|
| + next_frame_types_[stream_index] = kVideoFrameDelta;
|
| }
|
| }
|
| return VCM_OK;
|
| }
|
|
|
| int32_t VideoSender::EnableFrameDropper(bool enable) {
|
| - rtc::CritScope lock(&send_crit_);
|
| + rtc::CritScope lock(&encoder_crit_);
|
| frame_dropper_enabled_ = enable;
|
| _mediaOpt.EnableFrameDropper(enable);
|
| return VCM_OK;
|
|
|