Fix deadlock in video_receiver.cc.
In webrtc::vcm::VideoReceiver::ResetDecoder(), the lock order is: 1. take _receiveCritSect, 2. take process_crit_sect_ This conflicts with the follow code path: 1. webrtc::vcm::VideoReceiver::Process(), take process_crit_sect_ call -> webrtc::vcm::VideoReceiver::NackList(), 2. with nackStats=kNackKeyFrameRequest, take _receiveCritSect BUG=2861 TEST=trybots R=sprang@webrtc.org Review URL: https://webrtc-codereview.appspot.com/7749004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@5456 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
@ -121,8 +121,12 @@ int32_t VideoReceiver::Process() {
|
|||||||
// Key frame requests
|
// Key frame requests
|
||||||
if (_keyRequestTimer.TimeUntilProcess() == 0) {
|
if (_keyRequestTimer.TimeUntilProcess() == 0) {
|
||||||
_keyRequestTimer.Processed();
|
_keyRequestTimer.Processed();
|
||||||
|
bool request_key_frame = false;
|
||||||
|
{
|
||||||
CriticalSectionScoped cs(process_crit_sect_.get());
|
CriticalSectionScoped cs(process_crit_sect_.get());
|
||||||
if (_scheduleKeyRequest && _frameTypeCallback != NULL) {
|
request_key_frame = _scheduleKeyRequest && _frameTypeCallback != NULL;
|
||||||
|
}
|
||||||
|
if (request_key_frame) {
|
||||||
const int32_t ret = RequestKeyFrame();
|
const int32_t ret = RequestKeyFrame();
|
||||||
if (ret != VCM_OK && returnValue == VCM_OK) {
|
if (ret != VCM_OK && returnValue == VCM_OK) {
|
||||||
returnValue = ret;
|
returnValue = ret;
|
||||||
@ -135,19 +139,27 @@ int32_t VideoReceiver::Process() {
|
|||||||
// disabled when NACK is off.
|
// disabled when NACK is off.
|
||||||
if (_retransmissionTimer.TimeUntilProcess() == 0) {
|
if (_retransmissionTimer.TimeUntilProcess() == 0) {
|
||||||
_retransmissionTimer.Processed();
|
_retransmissionTimer.Processed();
|
||||||
|
bool callback_registered = false;
|
||||||
|
uint16_t length;
|
||||||
|
{
|
||||||
CriticalSectionScoped cs(process_crit_sect_.get());
|
CriticalSectionScoped cs(process_crit_sect_.get());
|
||||||
if (_packetRequestCallback != NULL) {
|
length = max_nack_list_size_;
|
||||||
uint16_t length = max_nack_list_size_;
|
callback_registered = _packetRequestCallback != NULL;
|
||||||
|
}
|
||||||
|
if (callback_registered && length > 0) {
|
||||||
std::vector<uint16_t> nackList(length);
|
std::vector<uint16_t> nackList(length);
|
||||||
const int32_t ret = NackList(&nackList[0], &length);
|
const int32_t ret = NackList(&nackList[0], &length);
|
||||||
if (ret != VCM_OK && returnValue == VCM_OK) {
|
if (ret != VCM_OK && returnValue == VCM_OK) {
|
||||||
returnValue = ret;
|
returnValue = ret;
|
||||||
}
|
}
|
||||||
if (length > 0) {
|
if (ret == VCM_OK && length > 0) {
|
||||||
|
CriticalSectionScoped cs(process_crit_sect_.get());
|
||||||
|
if (_packetRequestCallback != NULL) {
|
||||||
_packetRequestCallback->ResendPackets(&nackList[0], length);
|
_packetRequestCallback->ResendPackets(&nackList[0], length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return returnValue;
|
return returnValue;
|
||||||
}
|
}
|
||||||
@ -452,7 +464,7 @@ int32_t VideoReceiver::RequestSliceLossIndication(
|
|||||||
|
|
||||||
int32_t VideoReceiver::RequestKeyFrame() {
|
int32_t VideoReceiver::RequestKeyFrame() {
|
||||||
TRACE_EVENT0("webrtc", "RequestKeyFrame");
|
TRACE_EVENT0("webrtc", "RequestKeyFrame");
|
||||||
CriticalSectionScoped cs(process_crit_sect_.get());
|
CriticalSectionScoped process_cs(process_crit_sect_.get());
|
||||||
if (_frameTypeCallback != NULL) {
|
if (_frameTypeCallback != NULL) {
|
||||||
const int32_t ret = _frameTypeCallback->RequestKeyFrame();
|
const int32_t ret = _frameTypeCallback->RequestKeyFrame();
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
@ -547,6 +559,7 @@ int32_t VideoReceiver::Decode(const VCMEncodedFrame& frame) {
|
|||||||
int32_t ret = _decoder->Decode(frame, clock_->TimeInMilliseconds());
|
int32_t ret = _decoder->Decode(frame, clock_->TimeInMilliseconds());
|
||||||
|
|
||||||
// Check for failed decoding, run frame type request callback if needed.
|
// Check for failed decoding, run frame type request callback if needed.
|
||||||
|
bool request_key_frame = false;
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
if (ret == VCM_ERROR_REQUEST_SLI) {
|
if (ret == VCM_ERROR_REQUEST_SLI) {
|
||||||
return RequestSliceLossIndication(
|
return RequestSliceLossIndication(
|
||||||
@ -557,44 +570,46 @@ int32_t VideoReceiver::Decode(const VCMEncodedFrame& frame) {
|
|||||||
VCMId(_id),
|
VCMId(_id),
|
||||||
"Failed to decode frame %u, requesting key frame",
|
"Failed to decode frame %u, requesting key frame",
|
||||||
frame.TimeStamp());
|
frame.TimeStamp());
|
||||||
ret = RequestKeyFrame();
|
request_key_frame = true;
|
||||||
}
|
}
|
||||||
} else if (ret == VCM_REQUEST_SLI) {
|
} else if (ret == VCM_REQUEST_SLI) {
|
||||||
ret = RequestSliceLossIndication(
|
ret = RequestSliceLossIndication(
|
||||||
_decodedFrameCallback.LastReceivedPictureID() + 1);
|
_decodedFrameCallback.LastReceivedPictureID() + 1);
|
||||||
}
|
}
|
||||||
if (!frame.Complete() || frame.MissingFrame()) {
|
if (!frame.Complete() || frame.MissingFrame()) {
|
||||||
CriticalSectionScoped cs(process_crit_sect_.get());
|
|
||||||
switch (_keyRequestMode) {
|
switch (_keyRequestMode) {
|
||||||
case kKeyOnKeyLoss: {
|
case kKeyOnKeyLoss: {
|
||||||
if (frame.FrameType() == kVideoFrameKey) {
|
if (frame.FrameType() == kVideoFrameKey) {
|
||||||
_scheduleKeyRequest = true;
|
request_key_frame = true;
|
||||||
return VCM_OK;
|
ret = VCM_OK;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case kKeyOnLoss: {
|
case kKeyOnLoss: {
|
||||||
_scheduleKeyRequest = true;
|
request_key_frame = true;
|
||||||
return VCM_OK;
|
ret = VCM_OK;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (request_key_frame) {
|
||||||
|
CriticalSectionScoped cs(process_crit_sect_.get());
|
||||||
|
_scheduleKeyRequest = true;
|
||||||
|
}
|
||||||
TRACE_EVENT_ASYNC_END0("webrtc", "Video", frame.TimeStamp());
|
TRACE_EVENT_ASYNC_END0("webrtc", "Video", frame.TimeStamp());
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset the decoder state
|
// Reset the decoder state
|
||||||
int32_t VideoReceiver::ResetDecoder() {
|
int32_t VideoReceiver::ResetDecoder() {
|
||||||
|
bool reset_key_request = false;
|
||||||
|
{
|
||||||
CriticalSectionScoped cs(_receiveCritSect);
|
CriticalSectionScoped cs(_receiveCritSect);
|
||||||
if (_decoder != NULL) {
|
if (_decoder != NULL) {
|
||||||
_receiver.Initialize();
|
_receiver.Initialize();
|
||||||
_timing.Reset();
|
_timing.Reset();
|
||||||
{
|
reset_key_request = true;
|
||||||
CriticalSectionScoped cs(process_crit_sect_.get());
|
|
||||||
_scheduleKeyRequest = false;
|
|
||||||
}
|
|
||||||
_decoder->Reset();
|
_decoder->Reset();
|
||||||
}
|
}
|
||||||
if (_dualReceiver.State() != kPassive) {
|
if (_dualReceiver.State() != kPassive) {
|
||||||
@ -604,6 +619,11 @@ int32_t VideoReceiver::ResetDecoder() {
|
|||||||
_codecDataBase.ReleaseDecoder(_dualDecoder);
|
_codecDataBase.ReleaseDecoder(_dualDecoder);
|
||||||
_dualDecoder = NULL;
|
_dualDecoder = NULL;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (reset_key_request) {
|
||||||
|
CriticalSectionScoped cs(process_crit_sect_.get());
|
||||||
|
_scheduleKeyRequest = false;
|
||||||
|
}
|
||||||
return VCM_OK;
|
return VCM_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -720,7 +740,6 @@ int32_t VideoReceiver::NackList(uint16_t* nackList, uint16_t* size) {
|
|||||||
return VCM_MEMORY;
|
return VCM_MEMORY;
|
||||||
}
|
}
|
||||||
case kNackKeyFrameRequest: {
|
case kNackKeyFrameRequest: {
|
||||||
CriticalSectionScoped cs(_receiveCritSect);
|
|
||||||
WEBRTC_TRACE(webrtc::kTraceWarning,
|
WEBRTC_TRACE(webrtc::kTraceWarning,
|
||||||
webrtc::kTraceVideoCoding,
|
webrtc::kTraceVideoCoding,
|
||||||
VCMId(_id),
|
VCMId(_id),
|
||||||
|
Reference in New Issue
Block a user