OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 #include "webrtc/modules/video_coding/main/source/jitter_buffer.h" | 10 #include "webrtc/modules/video_coding/main/source/jitter_buffer.h" |
(...skipping 15 matching lines...) Expand all Loading... | |
26 #include "webrtc/system_wrappers/interface/event_wrapper.h" | 26 #include "webrtc/system_wrappers/interface/event_wrapper.h" |
27 #include "webrtc/system_wrappers/interface/logging.h" | 27 #include "webrtc/system_wrappers/interface/logging.h" |
28 #include "webrtc/system_wrappers/interface/metrics.h" | 28 #include "webrtc/system_wrappers/interface/metrics.h" |
29 #include "webrtc/system_wrappers/interface/trace_event.h" | 29 #include "webrtc/system_wrappers/interface/trace_event.h" |
30 | 30 |
31 namespace webrtc { | 31 namespace webrtc { |
32 | 32 |
33 // Use this rtt if no value has been reported. | 33 // Use this rtt if no value has been reported. |
34 static const int64_t kDefaultRtt = 200; | 34 static const int64_t kDefaultRtt = 200; |
35 | 35 |
36 // Request a keyframe if no continuous frame has been received for this | |
37 // number of milliseconds and NACKs are disabled. | |
38 static const int64_t kMaxDiscontinuousFramesTime = 10000; | |
joachim
2015/09/03 00:05:01
I based the timeout on the behaviour of "EndToEndT
stefan-webrtc
2015/09/18 14:22:41
Acknowledged.
| |
39 | |
36 typedef std::pair<uint32_t, VCMFrameBuffer*> FrameListPair; | 40 typedef std::pair<uint32_t, VCMFrameBuffer*> FrameListPair; |
37 | 41 |
38 bool IsKeyFrame(FrameListPair pair) { | 42 bool IsKeyFrame(FrameListPair pair) { |
39 return pair.second->FrameType() == kVideoFrameKey; | 43 return pair.second->FrameType() == kVideoFrameKey; |
40 } | 44 } |
41 | 45 |
42 bool HasNonEmptyState(FrameListPair pair) { | 46 bool HasNonEmptyState(FrameListPair pair) { |
43 return pair.second->GetState() != kStateEmpty; | 47 return pair.second->GetState() != kStateEmpty; |
44 } | 48 } |
45 | 49 |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
130 stats_callback_(NULL), | 134 stats_callback_(NULL), |
131 incoming_frame_rate_(0), | 135 incoming_frame_rate_(0), |
132 incoming_frame_count_(0), | 136 incoming_frame_count_(0), |
133 time_last_incoming_frame_count_(0), | 137 time_last_incoming_frame_count_(0), |
134 incoming_bit_count_(0), | 138 incoming_bit_count_(0), |
135 incoming_bit_rate_(0), | 139 incoming_bit_rate_(0), |
136 num_consecutive_old_packets_(0), | 140 num_consecutive_old_packets_(0), |
137 num_packets_(0), | 141 num_packets_(0), |
138 num_duplicated_packets_(0), | 142 num_duplicated_packets_(0), |
139 num_discarded_packets_(0), | 143 num_discarded_packets_(0), |
144 time_last_decodable_frame_(-1), | |
140 time_first_packet_ms_(0), | 145 time_first_packet_ms_(0), |
141 jitter_estimate_(clock), | 146 jitter_estimate_(clock), |
142 inter_frame_delay_(clock_->TimeInMilliseconds()), | 147 inter_frame_delay_(clock_->TimeInMilliseconds()), |
143 rtt_ms_(kDefaultRtt), | 148 rtt_ms_(kDefaultRtt), |
144 nack_mode_(kNoNack), | 149 nack_mode_(kNoNack), |
145 low_rtt_nack_threshold_ms_(-1), | 150 low_rtt_nack_threshold_ms_(-1), |
146 high_rtt_nack_threshold_ms_(-1), | 151 high_rtt_nack_threshold_ms_(-1), |
147 missing_sequence_numbers_(SequenceNumberLessThan()), | 152 missing_sequence_numbers_(SequenceNumberLessThan()), |
148 max_nack_list_size_(0), | 153 max_nack_list_size_(0), |
149 max_packet_age_to_nack_(0), | 154 max_packet_age_to_nack_(0), |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
206 incoming_frame_rate_ = 0; | 211 incoming_frame_rate_ = 0; |
207 incoming_bit_count_ = 0; | 212 incoming_bit_count_ = 0; |
208 incoming_bit_rate_ = 0; | 213 incoming_bit_rate_ = 0; |
209 time_last_incoming_frame_count_ = clock_->TimeInMilliseconds(); | 214 time_last_incoming_frame_count_ = clock_->TimeInMilliseconds(); |
210 receive_statistics_ = FrameCounts(); | 215 receive_statistics_ = FrameCounts(); |
211 | 216 |
212 num_consecutive_old_packets_ = 0; | 217 num_consecutive_old_packets_ = 0; |
213 num_packets_ = 0; | 218 num_packets_ = 0; |
214 num_duplicated_packets_ = 0; | 219 num_duplicated_packets_ = 0; |
215 num_discarded_packets_ = 0; | 220 num_discarded_packets_ = 0; |
221 time_last_decodable_frame_ = -1; | |
216 time_first_packet_ms_ = 0; | 222 time_first_packet_ms_ = 0; |
217 | 223 |
218 // Start in a non-signaled state. | 224 // Start in a non-signaled state. |
219 waiting_for_completion_.frame_size = 0; | 225 waiting_for_completion_.frame_size = 0; |
220 waiting_for_completion_.timestamp = 0; | 226 waiting_for_completion_.timestamp = 0; |
221 waiting_for_completion_.latest_packet_time = -1; | 227 waiting_for_completion_.latest_packet_time = -1; |
222 first_packet_since_reset_ = true; | 228 first_packet_since_reset_ = true; |
223 rtt_ms_ = kDefaultRtt; | 229 rtt_ms_ = kDefaultRtt; |
224 last_decoded_state_.Reset(); | 230 last_decoded_state_.Reset(); |
225 last_gof_valid_ = false; | 231 last_gof_valid_ = false; |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
257 return running_; | 263 return running_; |
258 } | 264 } |
259 | 265 |
260 void VCMJitterBuffer::Flush() { | 266 void VCMJitterBuffer::Flush() { |
261 CriticalSectionScoped cs(crit_sect_); | 267 CriticalSectionScoped cs(crit_sect_); |
262 decodable_frames_.Reset(&free_frames_); | 268 decodable_frames_.Reset(&free_frames_); |
263 incomplete_frames_.Reset(&free_frames_); | 269 incomplete_frames_.Reset(&free_frames_); |
264 last_decoded_state_.Reset(); // TODO(mikhal): sync reset. | 270 last_decoded_state_.Reset(); // TODO(mikhal): sync reset. |
265 last_gof_valid_ = false; | 271 last_gof_valid_ = false; |
266 num_consecutive_old_packets_ = 0; | 272 num_consecutive_old_packets_ = 0; |
273 time_last_decodable_frame_ = -1; | |
267 // Also reset the jitter and delay estimates | 274 // Also reset the jitter and delay estimates |
268 jitter_estimate_.Reset(); | 275 jitter_estimate_.Reset(); |
269 inter_frame_delay_.Reset(clock_->TimeInMilliseconds()); | 276 inter_frame_delay_.Reset(clock_->TimeInMilliseconds()); |
270 waiting_for_completion_.frame_size = 0; | 277 waiting_for_completion_.frame_size = 0; |
271 waiting_for_completion_.timestamp = 0; | 278 waiting_for_completion_.timestamp = 0; |
272 waiting_for_completion_.latest_packet_time = -1; | 279 waiting_for_completion_.latest_packet_time = -1; |
273 first_packet_since_reset_ = true; | 280 first_packet_since_reset_ = true; |
274 missing_sequence_numbers_.clear(); | 281 missing_sequence_numbers_.clear(); |
275 } | 282 } |
276 | 283 |
(...skipping 409 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
686 buffer_state = kFlushIndicator; | 693 buffer_state = kFlushIndicator; |
687 } | 694 } |
688 | 695 |
689 latest_received_sequence_number_ = LatestSequenceNumber( | 696 latest_received_sequence_number_ = LatestSequenceNumber( |
690 latest_received_sequence_number_, packet.seqNum); | 697 latest_received_sequence_number_, packet.seqNum); |
691 } | 698 } |
692 } | 699 } |
693 | 700 |
694 // Is the frame already in the decodable list? | 701 // Is the frame already in the decodable list? |
695 bool continuous = IsContinuous(*frame); | 702 bool continuous = IsContinuous(*frame); |
703 bool continuous_for_decoding; | |
704 if (continuous && | |
705 (decode_error_mode_ != kWithErrors || nack_mode_ != kNoNack)) { | |
stefan-webrtc
2015/09/18 14:22:41
Can you comment on this if-statement? Especially I
joachim
2015/09/18 20:23:47
If "IsContinuous" returns true and decode_error_mo
| |
706 continuous_for_decoding = true; | |
707 time_last_decodable_frame_ = now_ms; | |
708 } else { | |
709 continuous_for_decoding = IsContinuousForDecoding(*frame); | |
710 if (continuous_for_decoding) { | |
711 time_last_decodable_frame_ = now_ms; | |
712 } | |
713 } | |
696 switch (buffer_state) { | 714 switch (buffer_state) { |
697 case kGeneralError: | 715 case kGeneralError: |
698 case kTimeStampError: | 716 case kTimeStampError: |
699 case kSizeError: { | 717 case kSizeError: { |
700 free_frames_.push_back(frame); | 718 free_frames_.push_back(frame); |
701 break; | 719 break; |
702 } | 720 } |
703 case kCompleteSession: { | 721 case kCompleteSession: { |
704 if (previous_state != kStateDecodable && | 722 if (previous_state != kStateDecodable && |
705 previous_state != kStateComplete) { | 723 previous_state != kStateComplete) { |
706 CountFrame(*frame); | 724 CountFrame(*frame); |
707 if (continuous) { | 725 if (continuous) { |
708 // Signal that we have a complete session. | 726 // Signal that we have a complete session. |
709 frame_event_->Set(); | 727 frame_event_->Set(); |
710 } | 728 } |
711 } | 729 } |
712 FALLTHROUGH(); | 730 FALLTHROUGH(); |
713 } | 731 } |
714 // Note: There is no break here - continuing to kDecodableSession. | 732 // Note: There is no break here - continuing to kDecodableSession. |
715 case kDecodableSession: { | 733 case kDecodableSession: { |
716 *retransmitted = (frame->GetNackCount() > 0); | 734 *retransmitted = (frame->GetNackCount() > 0); |
717 if (continuous) { | 735 if (continuous) { |
718 decodable_frames_.InsertFrame(frame); | 736 decodable_frames_.InsertFrame(frame); |
719 FindAndInsertContinuousFrames(*frame); | 737 FindAndInsertContinuousFrames(*frame); |
720 } else { | 738 } else { |
721 incomplete_frames_.InsertFrame(frame); | 739 incomplete_frames_.InsertFrame(frame); |
722 } | 740 } |
741 if (nack_mode_ == kNoNack && continuous && !continuous_for_decoding) { | |
stefan-webrtc
2015/09/18 14:22:42
Why do you want to do this only for kDecodableSess
joachim
2015/09/18 20:23:47
Right, added there too.
| |
742 // If we didn't receive a continuous decodable frame for too long and | |
743 // can't report through NACKs to the sender, request a keyframe. | |
744 if (time_last_decodable_frame_ >= 0 && | |
745 now_ms - time_last_decodable_frame_ > kMaxDiscontinuousFramesTime) { | |
746 // Update to current time so we don't request keyframes too often. | |
747 time_last_decodable_frame_ = now_ms; | |
748 return kFlushIndicator; | |
749 } | |
750 } | |
723 break; | 751 break; |
724 } | 752 } |
725 case kIncomplete: { | 753 case kIncomplete: { |
726 if (frame->GetState() == kStateEmpty && | 754 if (frame->GetState() == kStateEmpty && |
727 last_decoded_state_.UpdateEmptyFrame(frame)) { | 755 last_decoded_state_.UpdateEmptyFrame(frame)) { |
728 free_frames_.push_back(frame); | 756 free_frames_.push_back(frame); |
729 return kNoError; | 757 return kNoError; |
730 } else { | 758 } else { |
731 incomplete_frames_.InsertFrame(frame); | 759 incomplete_frames_.InsertFrame(frame); |
732 } | 760 } |
(...skipping 12 matching lines...) Expand all Loading... | |
745 break; | 773 break; |
746 } | 774 } |
747 case kFlushIndicator: | 775 case kFlushIndicator: |
748 free_frames_.push_back(frame); | 776 free_frames_.push_back(frame); |
749 return kFlushIndicator; | 777 return kFlushIndicator; |
750 default: assert(false); | 778 default: assert(false); |
751 } | 779 } |
752 return buffer_state; | 780 return buffer_state; |
753 } | 781 } |
754 | 782 |
755 bool VCMJitterBuffer::IsContinuousInState(const VCMFrameBuffer& frame, | 783 bool VCMJitterBuffer::IsContinuousInState(const VCMFrameBuffer& frame, |
stefan-webrtc
2015/09/18 14:22:42
Should this method have a different name? I'd say
joachim
2015/09/18 20:23:47
As the functionality of "IsContinuousInState" is t
| |
756 const VCMDecodingState& decoding_state) const { | 784 const VCMDecodingState& decoding_state) const { |
757 if (decode_error_mode_ == kWithErrors) | 785 if (decode_error_mode_ == kWithErrors) { |
758 return true; | 786 return true; |
787 } | |
788 return IsContinuousInStateForDecoding(frame, decoding_state); | |
stefan-webrtc
2015/09/18 14:22:41
return decode_error_mode_ == kWithErrors || IsCont
joachim
2015/09/18 20:23:47
Refactored, so that doesn't apply any more.
| |
789 } | |
790 | |
791 bool VCMJitterBuffer::IsContinuousInStateForDecoding( | |
792 const VCMFrameBuffer& frame, const VCMDecodingState& decoding_state) const { | |
759 // Is this frame (complete or decodable) and continuous? | 793 // Is this frame (complete or decodable) and continuous? |
760 // kStateDecodable will never be set when decode_error_mode_ is false | 794 // kStateDecodable will never be set when decode_error_mode_ is false |
761 // as SessionInfo determines this state based on the error mode (and frame | 795 // as SessionInfo determines this state based on the error mode (and frame |
762 // completeness). | 796 // completeness). |
763 return (frame.GetState() == kStateComplete || | 797 return (frame.GetState() == kStateComplete || |
764 frame.GetState() == kStateDecodable) && | 798 frame.GetState() == kStateDecodable) && |
765 decoding_state.ContinuousFrame(&frame); | 799 decoding_state.ContinuousFrame(&frame); |
766 } | 800 } |
767 | 801 |
768 bool VCMJitterBuffer::IsContinuous(const VCMFrameBuffer& frame) const { | 802 bool VCMJitterBuffer::IsContinuous(const VCMFrameBuffer& frame) const { |
769 if (IsContinuousInState(frame, last_decoded_state_)) { | 803 if (IsContinuousInState(frame, last_decoded_state_)) { |
770 return true; | 804 return true; |
771 } | 805 } |
772 VCMDecodingState decoding_state; | 806 VCMDecodingState decoding_state; |
773 decoding_state.CopyFrom(last_decoded_state_); | 807 decoding_state.CopyFrom(last_decoded_state_); |
774 for (FrameList::const_iterator it = decodable_frames_.begin(); | 808 for (FrameList::const_iterator it = decodable_frames_.begin(); |
775 it != decodable_frames_.end(); ++it) { | 809 it != decodable_frames_.end(); ++it) { |
776 VCMFrameBuffer* decodable_frame = it->second; | 810 VCMFrameBuffer* decodable_frame = it->second; |
777 if (IsNewerTimestamp(decodable_frame->TimeStamp(), frame.TimeStamp())) { | 811 if (IsNewerTimestamp(decodable_frame->TimeStamp(), frame.TimeStamp())) { |
778 break; | 812 break; |
779 } | 813 } |
780 decoding_state.SetState(decodable_frame); | 814 decoding_state.SetState(decodable_frame); |
781 if (IsContinuousInState(frame, decoding_state)) { | 815 if (IsContinuousInState(frame, decoding_state)) { |
782 return true; | 816 return true; |
783 } | 817 } |
784 } | 818 } |
785 return false; | 819 return false; |
786 } | 820 } |
787 | 821 |
822 bool VCMJitterBuffer::IsContinuousForDecoding( | |
stefan-webrtc
2015/09/18 14:22:41
I don't like how this duplicates the code of IsCon
joachim
2015/09/18 20:23:47
Updated to take a parameter for the two modes.
| |
823 const VCMFrameBuffer& frame) const { | |
824 if (IsContinuousInStateForDecoding(frame, last_decoded_state_)) { | |
825 return true; | |
826 } | |
827 VCMDecodingState decoding_state; | |
828 decoding_state.CopyFrom(last_decoded_state_); | |
829 for (FrameList::const_iterator it = decodable_frames_.begin(); | |
830 it != decodable_frames_.end(); ++it) { | |
831 VCMFrameBuffer* decodable_frame = it->second; | |
832 if (IsNewerTimestamp(decodable_frame->TimeStamp(), frame.TimeStamp())) { | |
833 break; | |
834 } | |
835 decoding_state.SetState(decodable_frame); | |
836 if (IsContinuousInStateForDecoding(frame, decoding_state)) { | |
837 return true; | |
838 } | |
839 } | |
840 return false; | |
841 } | |
842 | |
788 void VCMJitterBuffer::FindAndInsertContinuousFrames( | 843 void VCMJitterBuffer::FindAndInsertContinuousFrames( |
789 const VCMFrameBuffer& new_frame) { | 844 const VCMFrameBuffer& new_frame) { |
790 VCMDecodingState decoding_state; | 845 VCMDecodingState decoding_state; |
791 decoding_state.CopyFrom(last_decoded_state_); | 846 decoding_state.CopyFrom(last_decoded_state_); |
792 decoding_state.SetState(&new_frame); | 847 decoding_state.SetState(&new_frame); |
793 FindAndInsertContinuousFramesWithState(decoding_state); | 848 FindAndInsertContinuousFramesWithState(decoding_state); |
794 } | 849 } |
795 | 850 |
796 void VCMJitterBuffer::FindAndInsertContinuousFramesWithState( | 851 void VCMJitterBuffer::FindAndInsertContinuousFramesWithState( |
797 const VCMDecodingState& original_decoded_state) { | 852 const VCMDecodingState& original_decoded_state) { |
(...skipping 455 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1253 } | 1308 } |
1254 // Evaluate if the RTT is higher than |high_rtt_nack_threshold_ms_|, and in | 1309 // Evaluate if the RTT is higher than |high_rtt_nack_threshold_ms_|, and in |
1255 // that case we don't wait for retransmissions. | 1310 // that case we don't wait for retransmissions. |
1256 if (high_rtt_nack_threshold_ms_ >= 0 && | 1311 if (high_rtt_nack_threshold_ms_ >= 0 && |
1257 rtt_ms_ >= high_rtt_nack_threshold_ms_) { | 1312 rtt_ms_ >= high_rtt_nack_threshold_ms_) { |
1258 return false; | 1313 return false; |
1259 } | 1314 } |
1260 return true; | 1315 return true; |
1261 } | 1316 } |
1262 } // namespace webrtc | 1317 } // namespace webrtc |
OLD | NEW |