Reland 8631 "Speculative revert of 8631 "Remove lock from Bitrat..."
> Speculative revert of 8631 "Remove lock from Bitrate() and FrameRate() in Video..."
>
> We ran into the alignment problem on Mac 10.9 debug again. This is the only CL I see in the range that adds an rtc::CriticalSection, so I'm trying out reverting it before attempting another roll.
>
> > Remove lock from Bitrate() and FrameRate() in VideoSender.
> > These methods are called on the VideoSender's construction thread, which is the same thread as modifies the value of _encoder. It's therefore safe to not require a lock to access _encoder on this thread.
> >
> > I'm making access to the rate variables from VCMGenericEncoder, thread safe, by using a lock that's not associated with the encoder. There should be little to no contention there. While modifying VCMGenericEncoder, I noticed that a couple of member variables weren't needed, so I removed them.
> >
> > The reason for this change is that getStats is currently contending with the encoder when Bitrate() is called. On my machine, this means that getStats can take about 25-30ms instead of ~1ms.
> >
> > Also adding some documentation for other methods and a suggestion for how we could avoid contention between the encoder and the network thread.
> >
> > BUG=2822
> > R=mflodman@webrtc.org
> >
> > Review URL: https://webrtc-codereview.appspot.com/43479004
>
> TBR=tommi@webrtc.org
>
> Review URL: https://webrtc-codereview.appspot.com/45529004
TBR=tommi@webrtc.org
Review URL: https://webrtc-codereview.appspot.com/46519004
Cr-Commit-Position: refs/heads/master@{#8645}
git-svn-id: http://webrtc.googlecode.com/svn/trunk@8645 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/webrtc/modules/video_coding/main/source/generic_encoder.cc b/webrtc/modules/video_coding/main/source/generic_encoder.cc
index 208f925..dcddf2f 100644
--- a/webrtc/modules/video_coding/main/source/generic_encoder.cc
+++ b/webrtc/modules/video_coding/main/source/generic_encoder.cc
@@ -60,11 +60,9 @@
bool internalSource)
: encoder_(encoder),
rate_observer_(rate_observer),
- _codecType(kVideoCodecUnknown),
- _VCMencodedFrameCallback(NULL),
- _bitRate(0),
- _frameRate(0),
- _internalSource(internalSource) {
+ bit_rate_(0),
+ frame_rate_(0),
+ internal_source_(internalSource) {
}
VCMGenericEncoder::~VCMGenericEncoder()
@@ -73,9 +71,12 @@
int32_t VCMGenericEncoder::Release()
{
- _bitRate = 0;
- _frameRate = 0;
- _VCMencodedFrameCallback = NULL;
+ {
+ rtc::CritScope lock(&rates_lock_);
+ bit_rate_ = 0;
+ frame_rate_ = 0;
+ }
+
return encoder_->Release();
}
@@ -84,9 +85,12 @@
int32_t numberOfCores,
size_t maxPayloadSize)
{
- _bitRate = settings->startBitrate * 1000;
- _frameRate = settings->maxFramerate;
- _codecType = settings->codecType;
+ {
+ rtc::CritScope lock(&rates_lock_);
+ bit_rate_ = settings->startBitrate * 1000;
+ frame_rate_ = settings->maxFramerate;
+ }
+
if (encoder_->InitEncode(settings, numberOfCores, maxPayloadSize) != 0) {
LOG(LS_ERROR) << "Failed to initialize the encoder associated with "
"payload name: " << settings->plName;
@@ -120,8 +124,13 @@
{
return ret;
}
- _bitRate = newBitRate;
- _frameRate = frameRate;
+
+ {
+ rtc::CritScope lock(&rates_lock_);
+ bit_rate_ = newBitRate;
+ frame_rate_ = frameRate;
+ }
+
if (rate_observer_ != nullptr)
rate_observer_->OnSetRates(newBitRate, frameRate);
return VCM_OK;
@@ -140,12 +149,14 @@
uint32_t VCMGenericEncoder::BitRate() const
{
- return _bitRate;
+ rtc::CritScope lock(&rates_lock_);
+ return bit_rate_;
}
uint32_t VCMGenericEncoder::FrameRate() const
{
- return _frameRate;
+ rtc::CritScope lock(&rates_lock_);
+ return frame_rate_;
}
int32_t
@@ -166,15 +177,14 @@
int32_t
VCMGenericEncoder::RegisterEncodeCallback(VCMEncodedFrameCallback* VCMencodedFrameCallback)
{
- _VCMencodedFrameCallback = VCMencodedFrameCallback;
- _VCMencodedFrameCallback->SetInternalSource(_internalSource);
- return encoder_->RegisterEncodeCompleteCallback(_VCMencodedFrameCallback);
+ VCMencodedFrameCallback->SetInternalSource(internal_source_);
+ return encoder_->RegisterEncodeCompleteCallback(VCMencodedFrameCallback);
}
bool
VCMGenericEncoder::InternalSource() const
{
- return _internalSource;
+ return internal_source_;
}
/***************************
diff --git a/webrtc/modules/video_coding/main/source/generic_encoder.h b/webrtc/modules/video_coding/main/source/generic_encoder.h
index 1fefc40..eba7715 100644
--- a/webrtc/modules/video_coding/main/source/generic_encoder.h
+++ b/webrtc/modules/video_coding/main/source/generic_encoder.h
@@ -16,6 +16,7 @@
#include <stdio.h>
+#include "webrtc/base/criticalsection.h"
#include "webrtc/base/scoped_ptr.h"
namespace webrtc {
@@ -74,9 +75,9 @@
{
friend class VCMCodecDataBase;
public:
- VCMGenericEncoder(VideoEncoder* encoder,
- VideoEncoderRateObserver* rate_observer,
- bool internalSource);
+ VCMGenericEncoder(VideoEncoder* encoder,
+ VideoEncoderRateObserver* rate_observer,
+ bool internalSource);
~VCMGenericEncoder();
/**
* Free encoder memory
@@ -102,6 +103,9 @@
* Set new target bitrate (bits/s) and framerate.
* Return Value: new bit rate if OK, otherwise <0s.
*/
+ // TODO(tommi): We could replace BitRate and FrameRate below with a GetRates
+ // method that matches SetRates. For fetching current rates, we'd then only
+ // grab the lock once instead of twice.
int32_t SetRates(uint32_t target_bitrate, uint32_t frameRate);
/**
* Set a new packet loss rate and a new round-trip time in milliseconds.
@@ -132,11 +136,10 @@
private:
VideoEncoder* const encoder_;
VideoEncoderRateObserver* const rate_observer_;
- VideoCodecType _codecType;
- VCMEncodedFrameCallback* _VCMencodedFrameCallback;
- uint32_t _bitRate;
- uint32_t _frameRate;
- bool _internalSource;
+ uint32_t bit_rate_;
+ uint32_t frame_rate_;
+ const bool internal_source_;
+ mutable rtc::CriticalSection rates_lock_;
}; // end of VCMGenericEncoder class
} // namespace webrtc
diff --git a/webrtc/modules/video_coding/main/source/video_sender.cc b/webrtc/modules/video_coding/main/source/video_sender.cc
index 5a4ed1f..032dab7 100644
--- a/webrtc/modules/video_coding/main/source/video_sender.cc
+++ b/webrtc/modules/video_coding/main/source/video_sender.cc
@@ -193,6 +193,8 @@
int32_t VideoSender::RegisterExternalEncoder(VideoEncoder* externalEncoder,
uint8_t payloadType,
bool internalSource /*= false*/) {
+ DCHECK(main_thread_.CalledOnValidThread());
+
CriticalSectionScoped cs(_sendCritSect);
if (externalEncoder == NULL) {
@@ -229,7 +231,10 @@
// Get encode bitrate
int VideoSender::Bitrate(unsigned int* bitrate) const {
- CriticalSectionScoped cs(_sendCritSect);
+ DCHECK(main_thread_.CalledOnValidThread());
+ // Since we're running on the thread that's the only thread known to modify
+ // the value of _encoder, we don't need to grab the lock here.
+
// return the bit rate which the encoder is set to
if (!_encoder) {
return VCM_UNINITIALIZED;
@@ -240,7 +245,10 @@
// Get encode frame rate
int VideoSender::FrameRate(unsigned int* framerate) const {
- CriticalSectionScoped cs(_sendCritSect);
+ DCHECK(main_thread_.CalledOnValidThread());
+ // Since we're running on the thread that's the only thread known to modify
+ // the value of _encoder, we don't need to grab the lock here.
+
// input frame rate, not compensated
if (!_encoder) {
return VCM_UNINITIALIZED;
@@ -249,32 +257,33 @@
return 0;
}
-// Set channel parameters
int32_t VideoSender::SetChannelParameters(uint32_t target_bitrate,
uint8_t lossRate,
int64_t rtt) {
- int32_t ret = 0;
- {
- CriticalSectionScoped sendCs(_sendCritSect);
- uint32_t targetRate = _mediaOpt.SetTargetRates(target_bitrate,
- lossRate,
- rtt,
- protection_callback_,
- qm_settings_callback_);
- if (_encoder != NULL) {
- ret = _encoder->SetChannelParameters(lossRate, rtt);
- if (ret < 0) {
- return ret;
- }
- ret = (int32_t)_encoder->SetRates(targetRate, _mediaOpt.InputFrameRate());
- if (ret < 0) {
- return ret;
- }
- } else {
- return VCM_UNINITIALIZED;
- } // encoder
- } // send side
- return VCM_OK;
+ // TODO(tommi,mflodman): This method is called on the network thread via the
+ // OnNetworkChanged event (ViEEncoder::OnNetworkChanged). Could we instead
+ // post the updated information to the encoding thread and not grab a lock
+ // here? This effectively means that the network thread will be blocked for
+ // as much as frame encoding period.
+
+ CriticalSectionScoped sendCs(_sendCritSect);
+ uint32_t target_rate = _mediaOpt.SetTargetRates(target_bitrate,
+ lossRate,
+ rtt,
+ protection_callback_,
+ qm_settings_callback_);
+ uint32_t input_frame_rate = _mediaOpt.InputFrameRate();
+
+ int32_t ret = VCM_UNINITIALIZED;
+ static_assert(VCM_UNINITIALIZED < 0, "VCM_UNINITIALIZED must be negative.");
+
+ if (_encoder != NULL) {
+ ret = _encoder->SetChannelParameters(lossRate, rtt);
+ if (ret >= 0) {
+ ret = _encoder->SetRates(target_rate, input_frame_rate);
+ }
+ }
+ return ret;
}
int32_t VideoSender::RegisterTransportCallback(
@@ -300,6 +309,9 @@
int32_t VideoSender::RegisterVideoQMCallback(
VCMQMSettingsCallback* qm_settings_callback) {
CriticalSectionScoped cs(_sendCritSect);
+ DCHECK(qm_settings_callback_ == qm_settings_callback ||
+ !qm_settings_callback_ ||
+ !qm_settings_callback) << "Overwriting the previous callback?";
qm_settings_callback_ = qm_settings_callback;
_mediaOpt.EnableQM(qm_settings_callback_ != NULL);
return VCM_OK;
@@ -310,6 +322,9 @@
int32_t VideoSender::RegisterProtectionCallback(
VCMProtectionCallback* protection_callback) {
CriticalSectionScoped cs(_sendCritSect);
+ DCHECK(protection_callback_ == protection_callback ||
+ !protection_callback_ ||
+ !protection_callback) << "Overwriting the previous callback?";
protection_callback_ = protection_callback;
return VCM_OK;
}