blob: 0a05baa16abca1e88f96176dc4126b84a2ae6e52 [file] [log] [blame]
philipelc707ab72016-04-01 02:01:54 -07001/*
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/checks.h"
17#include "webrtc/modules/video_coding/frame_object.h"
18#include "webrtc/modules/video_coding/sequence_number_util.h"
19
20namespace webrtc {
21namespace video_coding {
22
23PacketBuffer::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 last_seq_num_(0),
29 first_seq_num_(0),
30 initialized_(false),
31 data_buffer_(start_buffer_size),
32 sequence_buffer_(start_buffer_size),
33 frame_callback_(frame_callback) {
34 RTC_DCHECK_LE(start_buffer_size, max_buffer_size);
35 // Buffer size must always be a power of 2.
36 RTC_DCHECK((start_buffer_size & (start_buffer_size - 1)) == 0);
37 RTC_DCHECK((max_buffer_size & (max_buffer_size - 1)) == 0);
38}
39
40bool PacketBuffer::InsertPacket(const VCMPacket& packet) {
41 rtc::CritScope lock(&crit_);
42 uint16_t seq_num = packet.seqNum;
43 int index = seq_num % size_;
44
45 if (!initialized_) {
46 first_seq_num_ = seq_num - 1;
47 last_seq_num_ = seq_num;
48 initialized_ = true;
49 }
50
51 if (sequence_buffer_[index].used) {
52 // Duplicate packet, do nothing.
53 if (data_buffer_[index].seqNum == packet.seqNum)
54 return true;
55
56 // The packet buffer is full, try to expand the buffer.
57 while (ExpandBufferSize() && sequence_buffer_[seq_num % size_].used) {
58 }
59 index = seq_num % size_;
60
61 // Packet buffer is still full.
62 if (sequence_buffer_[index].used)
63 return false;
64 }
65
66 if (AheadOf(seq_num, last_seq_num_))
67 last_seq_num_ = seq_num;
68
69 sequence_buffer_[index].frame_begin = packet.isFirstPacket;
70 sequence_buffer_[index].frame_end = packet.markerBit;
71 sequence_buffer_[index].seq_num = packet.seqNum;
72 sequence_buffer_[index].continuous = false;
73 sequence_buffer_[index].used = true;
74 data_buffer_[index] = packet;
75
76 FindCompleteFrames(seq_num);
77 return true;
78}
79
80void PacketBuffer::ClearTo(uint16_t seq_num) {
81 rtc::CritScope lock(&crit_);
82 int index = first_seq_num_ % size_;
83 while (AheadOf<uint16_t>(seq_num, first_seq_num_ + 1)) {
84 index = (index + 1) % size_;
85 first_seq_num_ = Add<1 << 16>(first_seq_num_, 1);
86 sequence_buffer_[index].used = false;
87 }
88}
89
90bool PacketBuffer::ExpandBufferSize() {
91 if (size_ == max_size_)
92 return false;
93
94 size_t new_size = std::min(max_size_, 2 * size_);
95 std::vector<VCMPacket> new_data_buffer(new_size);
96 std::vector<ContinuityInfo> new_sequence_buffer(new_size);
97 for (size_t i = 0; i < size_; ++i) {
98 if (sequence_buffer_[i].used) {
99 int index = sequence_buffer_[i].seq_num % new_size;
100 new_sequence_buffer[index] = sequence_buffer_[i];
101 new_data_buffer[index] = data_buffer_[i];
102 }
103 }
104 size_ = new_size;
105 sequence_buffer_ = std::move(new_sequence_buffer);
106 data_buffer_ = std::move(new_data_buffer);
107 return true;
108}
109
110bool PacketBuffer::IsContinuous(uint16_t seq_num) const {
111 int index = seq_num % size_;
112 int prev_index = index > 0 ? index - 1 : size_ - 1;
113 if (!sequence_buffer_[index].used)
114 return false;
115 if (sequence_buffer_[index].frame_begin)
116 return true;
117 if (!sequence_buffer_[prev_index].used)
118 return false;
119 if (sequence_buffer_[prev_index].continuous)
120 return true;
121
122 return false;
123}
124
125void PacketBuffer::FindCompleteFrames(uint16_t seq_num) {
126 int index = seq_num % size_;
127 while (IsContinuous(seq_num)) {
128 sequence_buffer_[index].continuous = true;
129
130 // If the frame is complete, find the first packet of the frame and
131 // create a FrameObject.
132 if (sequence_buffer_[index].frame_end) {
133 int rindex = index;
134 uint16_t start_seq_num = seq_num;
135 while (!sequence_buffer_[rindex].frame_begin) {
136 rindex = rindex > 0 ? rindex - 1 : size_ - 1;
137 start_seq_num--;
138 }
139
140 std::unique_ptr<FrameObject> frame(
141 new RtpFrameObject(this, 1, start_seq_num, seq_num));
142 frame_callback_->OnCompleteFrame(std::move(frame));
143 }
144
145 index = (index + 1) % size_;
146 ++seq_num;
147 }
148}
149
150void PacketBuffer::ReturnFrame(RtpFrameObject* frame) {
151 rtc::CritScope lock(&crit_);
152 int index = frame->first_packet() % size_;
153 int end = (frame->last_packet() + 1) % size_;
154 uint16_t seq_num = frame->first_packet();
155 while (index != end) {
156 if (sequence_buffer_[index].seq_num == seq_num) {
157 sequence_buffer_[index].used = false;
158 sequence_buffer_[index].continuous = false;
159 }
160 index = (index + 1) % size_;
161 ++seq_num;
162 }
163
164 index = first_seq_num_ % size_;
165 while (AheadOf<uint16_t>(last_seq_num_, first_seq_num_) &&
166 !sequence_buffer_[index].used) {
167 ++first_seq_num_;
168 index = (index + 1) % size_;
169 }
170}
171
172bool PacketBuffer::GetBitstream(const RtpFrameObject& frame,
173 uint8_t* destination) {
174 rtc::CritScope lock(&crit_);
175
176 int index = frame.first_packet() % size_;
177 int end = (frame.last_packet() + 1) % size_;
178 uint16_t seq_num = frame.first_packet();
179 while (index != end) {
180 if (!sequence_buffer_[index].used ||
181 sequence_buffer_[index].seq_num != seq_num) {
182 return false;
183 }
184
185 const uint8_t* source = data_buffer_[index].dataPtr;
186 size_t length = data_buffer_[index].sizeBytes;
187 memcpy(destination, source, length);
188 destination += length;
189 index = (index + 1) % size_;
190 ++seq_num;
191 }
192 return true;
193}
194
195void PacketBuffer::Flush() {
196 rtc::CritScope lock(&crit_);
197 for (size_t i = 0; i < size_; ++i) {
198 sequence_buffer_[i].used = false;
199 sequence_buffer_[i].continuous = false;
200 }
201}
202
203} // namespace video_coding
204} // namespace webrtc