OLD | NEW |
---|---|
(Empty) | |
1 /* | |
2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. | |
3 * | |
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 | |
6 * tree. An additional intellectual property rights grant can be found | |
7 * in the file PATENTS. All contributing project authors may | |
8 * be found in the AUTHORS file in the root of the source tree. | |
9 */ | |
10 | |
11 #include "webrtc/modules/video_coding/packet_buffer.h" | |
12 | |
13 #include <algorithm> | |
14 #include <limits> | |
15 | |
16 #include "webrtc/base/mod_ops.h" | |
17 #include "webrtc/base/checks.h" | |
18 #include "webrtc/modules/video_coding/frame_object.h" | |
19 | |
20 namespace webrtc { | |
21 namespace video_coding { | |
22 | |
23 PacketBuffer::PacketBuffer(size_t start_buffer_size, | |
24 size_t max_buffer_size, | |
25 OnCompleteFrameCallback* frame_callback) | |
26 : size_(start_buffer_size), | |
27 max_size_(max_buffer_size), | |
28 clear_up_to_(0), | |
29 initialized_(false), | |
30 data_buffer_(start_buffer_size), | |
31 sequence_buffer_(start_buffer_size), | |
32 frame_callback_(frame_callback) { | |
33 RTC_DCHECK_LE(start_buffer_size, max_buffer_size); | |
34 // Buffer size must always be a power of 2. | |
35 RTC_DCHECK((start_buffer_size & start_buffer_size - 1) == 0); | |
36 RTC_DCHECK((max_buffer_size & max_buffer_size - 1) == 0); | |
37 } | |
38 | |
39 bool PacketBuffer::InsertPacket(const VCMPacket& packet) { | |
40 rtc::CritScope lock(&crit_); | |
41 uint16_t seq_num = packet.seqNum; | |
42 int index = seq_num % size_; | |
43 | |
44 if (!initialized_) { | |
45 clear_up_to_ = seq_num; | |
46 initialized_ = true; | |
47 } | |
48 | |
49 if (sequence_buffer_[index].used) { | |
50 // Duplicate packet, do nothing. | |
51 if (data_buffer_[index].seqNum == packet.seqNum) | |
52 return false; | |
53 | |
54 // The packet buffer is full, try to expand the buffer. | |
55 while (ExpandBufferSize() && sequence_buffer_[seq_num % size_].used) {} | |
56 index = seq_num % size_; | |
57 // If still full, test if the old packet can be discarded (overwritten | |
58 // later in the code), if not, return false. | |
59 if (sequence_buffer_[index].used && | |
60 AheadOrAt(sequence_buffer_[index].seq_num, clear_up_to_)) | |
61 return false; | |
62 } | |
63 | |
64 sequence_buffer_[index].frame_begin = packet.isFirstPacket; | |
65 sequence_buffer_[index].frame_end = packet.markerBit; | |
66 sequence_buffer_[index].seq_num = packet.seqNum; | |
67 sequence_buffer_[index].continuous = false; | |
68 sequence_buffer_[index].used = true; | |
69 data_buffer_[index] = packet; | |
70 | |
71 FindCompleteFrames(seq_num); | |
72 return true; | |
73 } | |
74 | |
75 void PacketBuffer::ClearUpTo(uint16_t seq_num) { | |
76 rtc::CritScope lock(&crit_); | |
77 clear_up_to_ = seq_num; | |
stefan-webrtc
2016/03/30 11:59:32
Why doesn't this simply clear the packet_buffer_ i
philipel
2016/03/30 12:40:11
Since both the |data_buffer_| and the |sequence_bu
stefan-webrtc
2016/03/30 12:56:20
Change as discussed offline
| |
78 } | |
79 | |
80 bool PacketBuffer::ExpandBufferSize() { | |
81 if (size_ == max_size_) { | |
82 return false; | |
83 } | |
84 | |
85 size_t new_size = std::min(max_size_, 2 * size_); | |
86 std::vector<VCMPacket> new_data_buffer(new_size); | |
87 std::vector<ContinuityInfo> new_sequence_buffer(new_size); | |
88 for (size_t i = 0; i < size_; ++i) { | |
89 if (sequence_buffer_[i].used) { | |
90 int index = sequence_buffer_[i].seq_num % new_size; | |
91 new_sequence_buffer[index] = sequence_buffer_[i]; | |
92 new_data_buffer[index] = data_buffer_[i]; | |
93 } | |
94 } | |
95 size_ = new_size; | |
96 sequence_buffer_ = std::move(new_sequence_buffer); | |
97 data_buffer_ = std::move(new_data_buffer); | |
98 return true; | |
99 } | |
100 | |
101 bool PacketBuffer::IsContinuous(uint16_t seq_num) const { | |
102 int index = seq_num % size_; | |
103 int prev_index = index > 0 ? index - 1 : size_ - 1; | |
104 if (!sequence_buffer_[index].used) | |
stefan-webrtc
2016/03/30 11:59:31
We should be able to DCHECK on this, right? We sho
philipel
2016/03/30 12:40:11
We are guaranteed to check sequence numbers that h
stefan-webrtc
2016/03/30 12:56:20
Ah, yes, my mistake.
| |
105 return false; | |
106 if (sequence_buffer_[index].frame_begin) | |
107 return true; | |
108 if (!sequence_buffer_[prev_index].used) | |
109 return false; | |
110 if (sequence_buffer_[prev_index].continuous) | |
111 return true; | |
112 | |
113 return false; | |
stefan-webrtc
2016/03/30 11:59:31
Can we rewrite this method so that we have a singl
philipel
2016/03/30 12:40:11
Hmm... Negating the condition on line 106 and 110
stefan-webrtc
2016/03/30 12:56:20
That's right, maybe it gets more complicated.
| |
114 } | |
115 | |
116 void PacketBuffer::FindCompleteFrames(uint16_t seq_num) { | |
117 int index = seq_num % size_; | |
118 while (IsContinuous(seq_num)) { | |
119 sequence_buffer_[index].continuous = true; | |
120 | |
121 // If the frame is complete, find the first packet of the frame and | |
stefan-webrtc
2016/03/30 11:59:31
Should this say "If the frame has the last packet,
philipel
2016/03/30 12:40:11
No, if we have reached a packet that is marked wit
stefan-webrtc
2016/03/30 12:56:20
Maybe change the comment to what you just wrote in
| |
122 // create a FrameObject. | |
123 if (sequence_buffer_[index].frame_end) { | |
124 int rindex = index; | |
125 uint16_t start_seq_num = seq_num; | |
126 while (!sequence_buffer_[rindex].frame_begin) { | |
127 rindex = rindex > 0 ? rindex - 1 : size_ - 1; | |
128 start_seq_num--; | |
129 } | |
stefan-webrtc
2016/03/30 11:59:31
Can we DCHECK on that we actually found the first
philipel
2016/03/30 12:40:11
I guess, but then we have to save the capture time
stefan-webrtc
2016/03/30 12:56:20
Can we add a check on picture id instead then?
| |
130 | |
131 std::unique_ptr<FrameObject> frame( | |
132 new RtpFrameObject(this, 1, start_seq_num, seq_num)); | |
133 frame_callback_->OnCompleteFrame(std::move(frame)); | |
134 } | |
135 | |
136 index = (index + 1) % size_; | |
137 ++seq_num; | |
138 } | |
139 } | |
140 | |
141 void PacketBuffer::ReturnFrame(RtpFrameObject* frame) { | |
142 rtc::CritScope lock(&crit_); | |
143 int index = frame->first_packet() % size_; | |
144 int end = (frame->last_packet() + 1) % size_; | |
145 uint16_t seq_num = frame->first_packet(); | |
146 while (index != end) { | |
147 if (sequence_buffer_[index].seq_num == seq_num) { | |
148 sequence_buffer_[index].used = false; | |
149 sequence_buffer_[index].continuous = false; | |
150 } | |
151 index = (index + 1) % size_; | |
152 ++seq_num; | |
153 } | |
154 } | |
155 | |
156 bool PacketBuffer::GetBitstream(const RtpFrameObject& frame, | |
157 uint8_t* destination) { | |
stefan-webrtc
2016/03/30 11:59:31
Is it up to the caller to ensure this buffer is la
philipel
2016/03/30 12:40:11
It's up to the caller, I guess we could (shoud?) a
stefan-webrtc
2016/03/30 12:56:20
I think that'd be good, otherwise I suspect it'd b
| |
158 rtc::CritScope lock(&crit_); | |
159 | |
160 int index = frame.first_packet() % size_; | |
161 int end = (frame.last_packet() + 1) % size_; | |
162 uint16_t seq_num = frame.first_packet(); | |
163 while (index != end) { | |
164 if (!sequence_buffer_[index].used || | |
165 sequence_buffer_[index].seq_num != seq_num) | |
stefan-webrtc
2016/03/30 11:59:31
{} since this if statement is > 2 lines.
philipel
2016/03/30 12:40:11
Done.
| |
166 return false; | |
167 | |
168 const uint8_t* source = data_buffer_[index].dataPtr; | |
169 size_t length = data_buffer_[index].sizeBytes; | |
170 memcpy(destination, source, length); | |
171 destination += length; | |
172 index = (index + 1) % size_; | |
173 ++seq_num; | |
174 } | |
175 return true; | |
176 } | |
177 | |
178 void PacketBuffer::Flush() { | |
179 rtc::CritScope lock(&crit_); | |
180 for (size_t i = 0; i < size_; ++i) { | |
181 sequence_buffer_[i].used = false; | |
182 sequence_buffer_[i].continuous = false; | |
183 } | |
184 } | |
185 | |
186 } // namespace video_coding | |
187 } // namespace webrtc | |
OLD | NEW |