Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(196)

Side by Side Diff: webrtc/modules/rtp_rtcp/source/rtcp_packet/feedback_packet.cc

Issue 1175263002: Add packetization and coding/decoding of feedback message format. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Fixed rounding of negative deltas Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * Copyright (c) 2015 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/rtp_rtcp/source/rtcp_packet/feedback_packet.h"
12
13 #include "webrtc/base/checks.h"
14 #include "webrtc/base/logging.h"
15 #include "webrtc/modules/rtp_rtcp/source/byte_io.h"
16
17 namespace webrtc {
18 namespace rtcp {
19
20 class FeedbackPacket::PacketStatusChunk {
21 public:
22 virtual ~PacketStatusChunk() {}
23 virtual uint16_t NumSymbols() const = 0;
24 virtual void AppendSymbolsTo(
25 std::vector<FeedbackPacket::StatusSymbol>* vec) const = 0;
26 virtual void WriteTo(uint8_t* buffer) const = 0;
27 };
28
29 uint8_t EncodeSymbol(FeedbackPacket::StatusSymbol symbol) {
30 switch (symbol) {
31 case FeedbackPacket::StatusSymbol::kNotReceived:
32 return 0;
33 case FeedbackPacket::StatusSymbol::kReceivedSmallDelta:
34 return 1;
35 case FeedbackPacket::StatusSymbol::kReceivedLargeDelta:
36 return 2;
37 case FeedbackPacket::StatusSymbol::kReceivedUntimed:
38 return 3;
39 default:
40 abort();
41 }
42 }
43
44 FeedbackPacket::StatusSymbol DecodeSymbol(uint8_t value) {
45 switch (value) {
46 case 0:
47 return FeedbackPacket::StatusSymbol::kNotReceived;
48 case 1:
49 return FeedbackPacket::StatusSymbol::kReceivedSmallDelta;
50 case 2:
51 return FeedbackPacket::StatusSymbol::kReceivedLargeDelta;
52 case 3:
53 return FeedbackPacket::StatusSymbol::kReceivedUntimed;
54 default:
55 RTC_NOTREACHED();
56 return FeedbackPacket::StatusSymbol::kNotReceived;
57 }
58 }
59
60 FeedbackPacket::FeedbackPacket()
61 : base_seq_(-1),
62 base_delta_(-1),
63 feedback_seq_(0),
64 last_seq_(-1),
65 last_timestamp_(-1),
66 first_symbol_cardinality_(0),
67 vec_needs_two_bit_symbols_(false),
68 size_bytes_(8) {
69 }
70
71 FeedbackPacket::~FeedbackPacket() {
72 for (PacketStatusChunk* chunk : status_chunks_)
73 delete chunk;
74 }
75
76 class OneBitVectorChunk : public FeedbackPacket::PacketStatusChunk {
77 public:
78 explicit OneBitVectorChunk(
79 std::deque<FeedbackPacket::StatusSymbol>* symbols) {
80 size_t input_size = symbols->size();
81 for (size_t i = 0; i < 14; ++i) {
stefan-webrtc 2015/06/16 08:29:13 What is 14 here? I think it's worth naming it and
sprang_webrtc 2015/06/22 12:20:10 Done.
82 if (i < input_size) {
83 symbols_[i] = symbols->front();
84 symbols->pop_front();
85 } else {
86 symbols_[i] = FeedbackPacket::StatusSymbol::kNotReceived;
87 }
88 }
89 }
90
91 virtual ~OneBitVectorChunk() {}
92
93 uint16_t NumSymbols() const override { return 14; }
94
95 void AppendSymbolsTo(
96 std::vector<FeedbackPacket::StatusSymbol>* vec) const override {
97 vec->insert(vec->end(), &symbols_[0], &symbols_[14]);
98 }
99
100 void WriteTo(uint8_t* buffer) const override {
101 buffer[0] = 0x80;
102 buffer[0] |= EncodeSymbol(symbols_[0]) << 5;
103 buffer[0] |= EncodeSymbol(symbols_[1]) << 4;
104 buffer[0] |= EncodeSymbol(symbols_[2]) << 3;
105 buffer[0] |= EncodeSymbol(symbols_[3]) << 2;
106 buffer[0] |= EncodeSymbol(symbols_[4]) << 1;
107 buffer[0] |= EncodeSymbol(symbols_[5]);
108 buffer[1] = EncodeSymbol(symbols_[6]) << 7;
109 buffer[1] |= EncodeSymbol(symbols_[7]) << 6;
110 buffer[1] |= EncodeSymbol(symbols_[8]) << 5;
111 buffer[1] |= EncodeSymbol(symbols_[9]) << 4;
112 buffer[1] |= EncodeSymbol(symbols_[10]) << 3;
113 buffer[1] |= EncodeSymbol(symbols_[11]) << 2;
114 buffer[1] |= EncodeSymbol(symbols_[12]) << 1;
115 buffer[1] |= EncodeSymbol(symbols_[13]);
116 }
117
118 static OneBitVectorChunk* ParseFrom(const uint8_t* data) {
119 OneBitVectorChunk* chunk = new OneBitVectorChunk();
120
121 size_t index = 0;
122 for (int i = 5; i >= 0; --i)
123 chunk->symbols_[index++] = DecodeSymbol((data[0] >> i) & 0x01);
124 for (int i = 7; i >= 0; --i)
125 chunk->symbols_[index++] = DecodeSymbol((data[1] >> i) & 0x01);
stefan-webrtc 2015/06/16 08:29:13 Probably worth mentioning why this is done in two
sprang_webrtc 2015/06/22 12:20:10 Done.
126
127 return chunk;
128 }
129
130 private:
131 OneBitVectorChunk() {}
132
133 FeedbackPacket::StatusSymbol symbols_[14];
134 };
135
136 class TwoBitVectorChunk : public FeedbackPacket::PacketStatusChunk {
137 public:
138 explicit TwoBitVectorChunk(
139 std::deque<FeedbackPacket::StatusSymbol>* symbols) {
140 size_t input_size = symbols->size();
141 for (size_t i = 0; i < 7; ++i) {
142 if (i < input_size) {
143 symbols_[i] = symbols->front();
144 symbols->pop_front();
145 } else {
146 symbols_[i] = FeedbackPacket::StatusSymbol::kNotReceived;
147 }
148 }
149 }
150
151 virtual ~TwoBitVectorChunk() {}
152
153 uint16_t NumSymbols() const override { return 7; }
154
155 void AppendSymbolsTo(
156 std::vector<FeedbackPacket::StatusSymbol>* vec) const override {
157 vec->insert(vec->end(), &symbols_[0], &symbols_[7]);
158 }
159
160 void WriteTo(uint8_t* buffer) const override {
161 buffer[0] = 0xC0;
162 buffer[0] |= EncodeSymbol(symbols_[0]) << 4;
163 buffer[0] |= EncodeSymbol(symbols_[1]) << 2;
164 buffer[0] |= EncodeSymbol(symbols_[2]);
165 buffer[1] = EncodeSymbol(symbols_[3]) << 6;
166 buffer[1] |= EncodeSymbol(symbols_[4]) << 4;
167 buffer[1] |= EncodeSymbol(symbols_[5]) << 2;
168 buffer[1] |= EncodeSymbol(symbols_[6]);
169 }
170
171 static TwoBitVectorChunk* ParseFrom(const uint8_t* buffer) {
172 TwoBitVectorChunk* chunk = new TwoBitVectorChunk();
173
174 chunk->symbols_[0] = DecodeSymbol((buffer[0] >> 4) & 0x03);
175 chunk->symbols_[1] = DecodeSymbol((buffer[0] >> 2) & 0x03);
176 chunk->symbols_[2] = DecodeSymbol(buffer[0] & 0x03);
177 chunk->symbols_[3] = DecodeSymbol((buffer[1] >> 6) & 0x03);
178 chunk->symbols_[4] = DecodeSymbol((buffer[1] >> 4) & 0x03);
179 chunk->symbols_[5] = DecodeSymbol((buffer[1] >> 2) & 0x03);
180 chunk->symbols_[6] = DecodeSymbol(buffer[1] & 0x03);
181
182 return chunk;
183 }
184
185 private:
186 TwoBitVectorChunk() {}
187
188 FeedbackPacket::StatusSymbol symbols_[7];
stefan-webrtc 2015/06/16 08:29:13 Why 7? Name the constant and explain.
sprang_webrtc 2015/06/22 12:20:10 Done.
189 };
190
191 class RunLengthChunk : public FeedbackPacket::PacketStatusChunk {
192 public:
193 RunLengthChunk(FeedbackPacket::StatusSymbol symbol, size_t size)
194 : symbol_(symbol), size_(size) {
195 DCHECK_LE(size, 0x1FFFu);
196 }
197
198 virtual ~RunLengthChunk() {}
199
200 uint16_t NumSymbols() const override { return size_; }
201
202 void AppendSymbolsTo(
203 std::vector<FeedbackPacket::StatusSymbol>* vec) const override {
204 vec->insert(vec->end(), size_, symbol_);
205 }
206
207 void WriteTo(uint8_t* buffer) const override {
stefan-webrtc 2015/06/16 08:29:13 I find this method complicated enough to deserve a
sprang_webrtc 2015/06/22 12:20:10 Done.
208 buffer[0] = EncodeSymbol(symbol_) << 5;
209 buffer[0] |= (size_ >> 8) & 0x1F;
210 buffer[1] = size_ & 0xFF;
211 }
212
213 static RunLengthChunk* ParseFrom(const uint8_t* buffer) {
stefan-webrtc 2015/06/16 08:29:13 Same with this.
sprang_webrtc 2015/06/22 12:20:10 Should be ok with changes above?
stefan-webrtc 2015/07/14 12:14:54 Yes
sprang_webrtc 2015/07/16 11:12:10 Acknowledged.
214 FeedbackPacket::StatusSymbol symbol = DecodeSymbol((buffer[0] >> 5) & 0x03);
215 uint16_t count = ((buffer[0] & 0x1F) << 8) | buffer[1];
216
217 return new RunLengthChunk(symbol, count);
218 }
219
220 private:
221 const FeedbackPacket::StatusSymbol symbol_;
222 const size_t size_;
223 };
224
225 int64_t FeedbackPacket::Unwrap(uint16_t sequence_number) {
226 if (last_seq_ == -1)
227 return sequence_number;
228
229 int64_t delta = sequence_number - (last_seq_ & 0xFFFF);
230 if (delta <= -0x8FFF) {
stefan-webrtc 2015/06/16 08:29:13 Shouldn't this be -0x7FFF? I wonder if we could r
sprang_webrtc 2015/06/22 12:20:10 Done.
231 // Wrap forward.
232 delta += (1 << 16);
233 } else if (delta > 0x8FFF) {
234 // Wrap backwards.
235 delta -= (1 << 16);
236 }
237
238 return last_seq_ + delta;
239 }
240
241 void FeedbackPacket::WithBase(uint16_t base_sequence,
242 int64_t prev_timestamp_us,
243 int64_t ref_timestamp_us) {
stefan-webrtc 2015/06/16 08:29:13 Would base_timestamp_us be better? Or is that not
sprang_webrtc 2015/06/22 12:20:10 Changed to use absolute ref time, as per discussio
244 DCHECK_EQ(-1, base_seq_);
245 DCHECK_NE(-1, ref_timestamp_us);
246 base_seq_ = base_sequence;
247 last_seq_ = base_sequence;
248 if (prev_timestamp_us != -1) {
249 base_delta_ = (ref_timestamp_us - prev_timestamp_us) / kBaseScaleFactor;
250 DCHECK_EQ(base_delta_, static_cast<int16_t>(base_delta_));
251
252 // Include precision loss in order to avoid drift.
stefan-webrtc 2015/07/14 12:14:54 Keep this comment, I found it really helpful.
253 last_timestamp_ = prev_timestamp_us + (base_delta_ * kBaseScaleFactor);
254 } else {
255 base_delta_ = 0;
256 last_timestamp_ = ref_timestamp_us;
257 }
258 }
259
260 void FeedbackPacket::WithFeedbackSequenceNumber(uint8_t feedback_sequence) {
261 feedback_seq_ = feedback_sequence;
262 }
263
264 bool FeedbackPacket::WithUntimedPacket(uint16_t sequence_number) {
265 DCHECK_NE(-1, base_seq_);
266 int64_t seq = Unwrap(sequence_number);
267 DCHECK_GE(seq, last_seq_);
268 return AddSymbol(StatusSymbol::kReceivedUntimed, sequence_number);
269 }
270
271 bool FeedbackPacket::WithReceivedPacket(uint16_t sequence_number,
272 int64_t timestamp) {
273 DCHECK_NE(-1, base_seq_);
274 int64_t seq = Unwrap(sequence_number);
275 if (seq != base_seq_) {
276 if (seq <= last_seq_)
277 return false;
278 }
279
280 // Convert to ticks and round.
281 int64_t delta_full = timestamp - last_timestamp_;
282 delta_full +=
283 delta_full < 0 ? -(kDeltaScaleFactor / 2) : kDeltaScaleFactor / 2;
284 delta_full /= kDeltaScaleFactor;
285
286 int16_t delta = static_cast<int16_t>(delta_full);
287 // If larger than 16bit signed, we can't represent it - need new fb packet.
288 if (delta != delta_full) {
289 LOG(LS_WARNING) << "Delta value too large ( >= 2^16 ticks )";
290 return false;
291 }
292
293 StatusSymbol symbol;
294 if (delta >= 0 && delta <= 0xFF) {
295 symbol = StatusSymbol::kReceivedSmallDelta;
296 } else {
297 symbol = StatusSymbol::kReceivedLargeDelta;
298 }
299
300 if (!AddSymbol(symbol, seq))
301 return false;
302
303 receive_deltas_.push_back(delta);
304 last_timestamp_ += delta * kDeltaScaleFactor;
305 return true;
306 }
307
308 bool FeedbackPacket::AddSymbol(StatusSymbol symbol, int64_t seq) {
309 while (last_seq_ < seq - 1) {
310 if (!Encode(StatusSymbol::kNotReceived))
311 return false;
312 ++last_seq_;
313 }
314
315 if (!Encode(symbol))
316 return false;
317
318 last_seq_ = seq;
319 return true;
320 }
321
322 bool FeedbackPacket::Encode(StatusSymbol symbol) {
323 if (last_seq_ - base_seq_ + 1 > 0xFFFF) {
324 LOG(LS_WARNING) << "Packet status count too large ( >= 2^16 )";
325 return false;
326 }
327
328 bool is_two_bit = (symbol == StatusSymbol::kReceivedLargeDelta ||
329 symbol == StatusSymbol::kReceivedUntimed);
330 int delta_size;
331 switch (symbol) {
332 case StatusSymbol::kReceivedSmallDelta:
333 delta_size = 1;
334 break;
335 case StatusSymbol::kReceivedLargeDelta:
336 delta_size = 2;
337 break;
338 default:
339 delta_size = 0;
340 }
341
342 if (symbol_vec_.empty()) {
343 if (size_bytes_ + delta_size + 2 > kMaxSizeBytes)
344 return false;
345
346 symbol_vec_.push_back(symbol);
347 vec_needs_two_bit_symbols_ = is_two_bit;
348 first_symbol_cardinality_ = 1;
349 size_bytes_ += delta_size + 2;
350 return true;
351 }
352 if (size_bytes_ + delta_size > kMaxSizeBytes)
353 return false;
354
355 size_t capacity = vec_needs_two_bit_symbols_ ? kTwoBitVectorCapacity
356 : kOneBitVectorCapacity;
357 bool rle_candidate = symbol_vec_.size() == first_symbol_cardinality_ ||
358 first_symbol_cardinality_ > capacity;
359 if (rle_candidate) {
360 if (symbol_vec_.back() == symbol) {
361 ++first_symbol_cardinality_;
362 if (first_symbol_cardinality_ <= capacity) {
363 symbol_vec_.push_back(symbol);
364 } else if (first_symbol_cardinality_ == kRunLengthCapacity) {
365 EmitRunLengthChunk();
366 }
367 size_bytes_ += delta_size;
368 return true;
369 } else if (first_symbol_cardinality_ > capacity) {
370 // Convert from run length to vector.
371 EmitRunLengthChunk();
372 return Encode(symbol);
373 }
374 }
375
376 if (is_two_bit && !vec_needs_two_bit_symbols_) {
377 if (symbol_vec_.size() >= kTwoBitVectorCapacity) {
378 if (size_bytes_ + delta_size + 2 > kMaxSizeBytes)
379 return false;
380 EmitVectorChunk();
381 return Encode(symbol);
382 }
383 vec_needs_two_bit_symbols_ = true;
384 capacity = kTwoBitVectorCapacity;
385 }
386
387 symbol_vec_.push_back(symbol);
388 size_t symbol_vec_size = symbol_vec_.size();
389 if (symbol_vec_size == capacity)
390 EmitVectorChunk();
391
392 size_bytes_ += delta_size;
393 return true;
394 }
395
396 void FeedbackPacket::EmitRemaining() {
397 if (symbol_vec_.empty())
398 return;
399
400 size_t capacity = vec_needs_two_bit_symbols_ ? kTwoBitVectorCapacity
401 : kOneBitVectorCapacity;
402 if (first_symbol_cardinality_ > capacity) {
403 EmitRunLengthChunk();
404 } else {
405 EmitVectorChunk();
406 }
407 }
408
409 void FeedbackPacket::EmitVectorChunk() {
410 if (vec_needs_two_bit_symbols_) {
411 status_chunks_.push_back(new TwoBitVectorChunk(&symbol_vec_));
412 } else {
413 status_chunks_.push_back(new OneBitVectorChunk(&symbol_vec_));
414 }
415 }
416
417 uint16_t FeedbackPacket::GetBaseSequence() const {
418 return base_seq_;
419 }
420
421 int16_t FeedbackPacket::GetBaseDelta() const {
422 return base_delta_;
423 }
424
425 int64_t FeedbackPacket::GetBaseDeltaUs() const {
426 return base_delta_ * kBaseScaleFactor;
427 }
428
429 std::vector<FeedbackPacket::StatusSymbol> FeedbackPacket::GetStatusVector()
430 const {
431 std::vector<FeedbackPacket::StatusSymbol> symbols;
432 for (PacketStatusChunk* chunk : status_chunks_)
433 chunk->AppendSymbolsTo(&symbols);
434 int64_t status_count = last_seq_ - base_seq_ + 1;
435 symbols.erase(symbols.begin() + status_count, symbols.end());
436 return symbols;
437 }
438
439 std::vector<int16_t> FeedbackPacket::GetReceiveDeltas() const {
440 return receive_deltas_;
441 }
442
443 std::vector<int64_t> FeedbackPacket::GetReceiveDeltasUs() const {
444 std::vector<int64_t> us_deltas;
445 if (receive_deltas_.empty()) {
446 us_deltas.push_back(base_delta_ * kBaseScaleFactor);
447 return us_deltas;
448 }
449
450 for (int16_t delta : receive_deltas_)
451 us_deltas.push_back(static_cast<int64_t>(delta) * kDeltaScaleFactor);
452 us_deltas[0] += base_delta_ * kBaseScaleFactor;
453
454 return us_deltas;
455 }
456
457 void FeedbackPacket::EmitRunLengthChunk() {
458 status_chunks_.push_back(
459 new RunLengthChunk(symbol_vec_.front(), first_symbol_cardinality_));
460 symbol_vec_.clear();
461 }
462
463 bool FeedbackPacket::Create(uint8_t* packet,
464 size_t* position,
465 size_t max_length,
466 PacketReadyCallback* callback) const {
467 if (base_seq_ == -1)
468 return false;
469
470 while (*position + size_bytes_ > max_length) {
471 if (!OnBufferFull(packet, position, callback))
472 return false;
473 }
474
475 DCHECK_LE(base_seq_, 0xFFFF);
476 ByteWriter<uint16_t>::WriteBigEndian(&packet[*position], base_seq_);
477 *position += 2;
478
479 int64_t status_count = last_seq_ - base_seq_ + 1;
480 DCHECK_LE(status_count, 0xFFFF);
481 ByteWriter<uint16_t>::WriteBigEndian(&packet[*position], status_count);
482 *position += 2;
483
484 DCHECK_LE(base_delta_, 0xFFFF);
485 ByteWriter<int16_t>::WriteBigEndian(&packet[*position], base_delta_);
486 *position += 2;
487
488 packet[(*position)++] = feedback_seq_;
489
490 uint16_t size_words = (size_bytes_ + 3) / 4;
491 size_words -= 2; // Excluding header.
492 DCHECK_LE(size_words, 0xFF);
493 packet[(*position)++] = size_words;
494
495 // TODO(sprang): Get rid of this cast.
496 const_cast<FeedbackPacket*>(this)->EmitRemaining();
497 for (PacketStatusChunk* chunk : status_chunks_) {
498 chunk->WriteTo(&packet[*position]);
499 *position += 2;
500 }
501
502 for (int16_t delta : receive_deltas_) {
503 if (delta >= 0 && delta <= 0xFF) {
504 packet[(*position)++] = delta;
505 } else {
506 ByteWriter<int16_t>::WriteBigEndian(&packet[*position], delta);
507 *position += 2;
508 }
509 }
510
511 while ((*position % 4) != 0)
512 packet[(*position)++] = 0;
513
514 return true;
515 }
516
517 rtc::scoped_ptr<FeedbackPacket> FeedbackPacket::ParseFrom(const uint8_t* buffer,
518 size_t length) {
519 rtc::scoped_ptr<FeedbackPacket> packet(new FeedbackPacket());
520
521 size_t packet_size_words = 0;
522 if (length < kMinSizeBytes ||
523 length < (packet_size_words = buffer[7] * 4) + 8) {
524 LOG(LS_WARNING) << "Buffer too small (" << length
525 << " bytes) to parse feedback packet of "
526 << (packet_size_words * 4 + 8) << "bytes.";
527 return nullptr;
528 }
529
530 packet->base_seq_ = ByteReader<uint16_t>::ReadBigEndian(&buffer[0]);
531 uint16_t num_packets = ByteReader<uint16_t>::ReadBigEndian(&buffer[2]);
532 packet->base_delta_ = ByteReader<int16_t>::ReadBigEndian(&buffer[4]);
533 packet->feedback_seq_ = buffer[6];
534 size_t index = 8;
535
536 if (num_packets == 0) {
537 LOG(LS_WARNING) << "Empty feedback messages not allowed.";
538 return nullptr;
539 }
540 packet->last_seq_ = packet->base_seq_ + num_packets - 1;
541
542 size_t packets_read = 0;
543 while (packets_read < num_packets) {
544 if (index + 2 > length) {
545 LOG(LS_WARNING) << "Buffer overflow while parsing packet.";
546 return nullptr;
547 }
548
549 PacketStatusChunk* chunk =
550 ParseChunk(&buffer[index], num_packets - packets_read);
551 if (chunk == nullptr)
552 return nullptr;
553
554 index += 2;
555 packet->status_chunks_.push_back(chunk);
556 packets_read += chunk->NumSymbols();
557 }
558
559 std::vector<StatusSymbol> symbols = packet->GetStatusVector();
560
561 DCHECK_EQ(num_packets, symbols.size());
562
563 for (StatusSymbol symbol : symbols) {
564 switch (symbol) {
565 case StatusSymbol::kReceivedSmallDelta:
566 if (index + 1 > length) {
567 LOG(LS_WARNING) << "Buffer overflow while parsing packet.";
568 return nullptr;
569 }
570 packet->receive_deltas_.push_back(buffer[index]);
571 ++index;
572 break;
573 case StatusSymbol::kReceivedLargeDelta:
574 if (index + 2 > length) {
575 LOG(LS_WARNING) << "Buffer overflow while parsing packet.";
576 return nullptr;
577 }
578 packet->receive_deltas_.push_back(
579 ByteReader<int16_t>::ReadBigEndian(&buffer[index]));
580 index += 2;
581 break;
582 default:
583 continue;
584 }
585 }
586
587 DCHECK_GE(index, length - 3);
588 DCHECK_LE(index, length);
589
590 return packet;
591 }
592
593 FeedbackPacket::PacketStatusChunk* FeedbackPacket::ParseChunk(
594 const uint8_t* buffer,
595 size_t max_size) {
596 if (buffer[0] & 0x80) {
597 // First bit set => vector chunk.
598 std::deque<StatusSymbol> symbols;
599 if (buffer[0] & 0x40) {
600 // Second bit set => two bits per symbol vector.
601 return TwoBitVectorChunk::ParseFrom(buffer);
602 }
603
604 // Second bit not set => one bit per symbol vector.
605 return OneBitVectorChunk::ParseFrom(buffer);
606 }
607
608 // First bit not set => RLE chunk.
609 RunLengthChunk* rle_chunk = RunLengthChunk::ParseFrom(buffer);
610 if (rle_chunk->NumSymbols() > max_size) {
611 LOG(LS_WARNING) << "Header/body mismatch. "
612 "RLE block of size "
613 << rle_chunk->NumSymbols() << " but only " << max_size
614 << " left to read.";
615 delete rle_chunk;
616 return nullptr;
617 }
618 return rle_chunk;
619 }
620
621 } // namespace rtcp
622 } // namespace webrtc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698