Avoid race in VideoReceiveStream shutdown

The decode thread should be stopped before triggering shutdown of the
video receiver, so that the decoder doesn't try to insert a new frame
while the jitter buffer is being shut down.

BUG=webrtc:6102

Review-Url: https://codereview.webrtc.org/2146883002
Cr-Commit-Position: refs/heads/master@{#13467}
This commit is contained in:
sprang
2016-07-13 10:57:07 -07:00
committed by Commit bot
parent 6f06cca96f
commit 22691e0d32
3 changed files with 26 additions and 31 deletions

View File

@ -229,7 +229,7 @@ VCMJitterBuffer::VCMJitterBuffer(Clock* clock,
incomplete_frames_(),
last_decoded_state_(),
first_packet_since_reset_(true),
stats_callback_(NULL),
stats_callback_(nullptr),
incoming_frame_rate_(0),
incoming_frame_count_(0),
time_last_incoming_frame_count_(0),
@ -247,6 +247,7 @@ VCMJitterBuffer::VCMJitterBuffer(Clock* clock,
low_rtt_nack_threshold_ms_(-1),
high_rtt_nack_threshold_ms_(-1),
missing_sequence_numbers_(SequenceNumberLessThan()),
latest_received_sequence_number_(0),
max_nack_list_size_(0),
max_packet_age_to_nack_(0),
max_incomplete_time_ms_(0),
@ -325,30 +326,17 @@ void VCMJitterBuffer::Start() {
first_packet_since_reset_ = true;
rtt_ms_ = kDefaultRtt;
last_decoded_state_.Reset();
decodable_frames_.Reset(&free_frames_);
incomplete_frames_.Reset(&free_frames_);
}
void VCMJitterBuffer::Stop() {
crit_sect_->Enter();
CriticalSectionScoped cs(crit_sect_);
UpdateHistograms();
running_ = false;
last_decoded_state_.Reset();
// Make sure all frames are free and reset.
for (FrameList::iterator it = decodable_frames_.begin();
it != decodable_frames_.end(); ++it) {
free_frames_.push_back(it->second);
}
for (FrameList::iterator it = incomplete_frames_.begin();
it != incomplete_frames_.end(); ++it) {
free_frames_.push_back(it->second);
}
for (UnorderedFrameList::iterator it = free_frames_.begin();
it != free_frames_.end(); ++it) {
(*it)->Reset();
}
decodable_frames_.clear();
incomplete_frames_.clear();
crit_sect_->Leave();
// Make sure we wake up any threads waiting on these events.
frame_event_->Set();
}
@ -594,11 +582,10 @@ VCMEncodedFrame* VCMJitterBuffer::ExtractAndSetDecode(uint32_t timestamp) {
// Release frame when done with decoding. Should never be used to release
// frames from within the jitter buffer.
void VCMJitterBuffer::ReleaseFrame(VCMEncodedFrame* frame) {
RTC_CHECK(frame != nullptr);
CriticalSectionScoped cs(crit_sect_);
VCMFrameBuffer* frame_buffer = static_cast<VCMFrameBuffer*>(frame);
if (frame_buffer) {
free_frames_.push_back(frame_buffer);
}
RecycleFrameBuffer(frame_buffer);
}
// Gets frame to use for this timestamp. If no match, get empty frame.
@ -624,9 +611,9 @@ VCMFrameBufferEnum VCMJitterBuffer::GetFrame(const VCMPacket& packet,
LOG(LS_WARNING) << "Unable to get empty frame; Recycling.";
bool found_key_frame = RecycleFramesUntilKeyFrame();
*frame = GetEmptyFrame();
assert(*frame);
RTC_CHECK(*frame);
if (!found_key_frame) {
free_frames_.push_back(*frame);
RecycleFrameBuffer(*frame);
return kFlushIndicator;
}
}
@ -753,7 +740,7 @@ VCMFrameBufferEnum VCMJitterBuffer::InsertPacket(const VCMPacket& packet,
case kGeneralError:
case kTimeStampError:
case kSizeError: {
free_frames_.push_back(frame);
RecycleFrameBuffer(frame);
break;
}
case kCompleteSession: {
@ -787,7 +774,7 @@ VCMFrameBufferEnum VCMJitterBuffer::InsertPacket(const VCMPacket& packet,
case kIncomplete: {
if (frame->GetState() == kStateEmpty &&
last_decoded_state_.UpdateEmptyFrame(frame)) {
free_frames_.push_back(frame);
RecycleFrameBuffer(frame);
return kNoError;
} else {
incomplete_frames_.InsertFrame(frame);
@ -807,13 +794,13 @@ VCMFrameBufferEnum VCMJitterBuffer::InsertPacket(const VCMPacket& packet,
if (frame_list != NULL) {
frame_list->InsertFrame(frame);
} else {
free_frames_.push_back(frame);
RecycleFrameBuffer(frame);
}
++num_duplicated_packets_;
break;
}
case kFlushIndicator:
free_frames_.push_back(frame);
RecycleFrameBuffer(frame);
return kFlushIndicator;
default:
assert(false);
@ -1315,4 +1302,9 @@ bool VCMJitterBuffer::WaitForRetransmissions() {
return true;
}
void VCMJitterBuffer::RecycleFrameBuffer(VCMFrameBuffer* frame) {
frame->Reset();
free_frames_.push_back(frame);
}
} // namespace webrtc

View File

@ -261,8 +261,6 @@ class VCMJitterBuffer {
// Drops all packets in the NACK list up until |last_decoded_sequence_number|.
void DropPacketsFromNackList(uint16_t last_decoded_sequence_number);
void ReleaseFrameIfNotDecoding(VCMFrameBuffer* frame);
// Gets an empty frame, creating a new frame if necessary (i.e. increases
// jitter buffer size).
VCMFrameBuffer* GetEmptyFrame() EXCLUSIVE_LOCKS_REQUIRED(crit_sect_);
@ -310,6 +308,10 @@ class VCMJitterBuffer {
void UpdateHistograms() EXCLUSIVE_LOCKS_REQUIRED(crit_sect_);
// Reset frame buffer and return it to free_frames_.
void RecycleFrameBuffer(VCMFrameBuffer* frame)
EXCLUSIVE_LOCKS_REQUIRED(crit_sect_);
Clock* clock_;
// If we are running (have started) or not.
bool running_;
@ -334,8 +336,6 @@ class VCMJitterBuffer {
int64_t time_last_incoming_frame_count_;
unsigned int incoming_bit_count_;
unsigned int incoming_bit_rate_;
// Number of frames in a row that have been too old.
int num_consecutive_old_frames_;
// Number of packets in a row that have been too old.
int num_consecutive_old_packets_;
// Number of packets received.