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

Side by Side Diff: webrtc/modules/video_coding/packet_buffer.cc

Issue 1903523003: Convert Vp9 Rtp headers to frame references. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Feedback fixes. Created 4 years, 7 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
1 /* 1 /*
2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. 2 * Copyright (c) 2016 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 10
11 #include "webrtc/modules/video_coding/packet_buffer.h" 11 #include "webrtc/modules/video_coding/packet_buffer.h"
12 12
13 #include <algorithm> 13 #include <algorithm>
14 #include <limits> 14 #include <limits>
15 15
16 #include "webrtc/base/checks.h" 16 #include "webrtc/base/checks.h"
17 #include "webrtc/base/logging.h"
17 #include "webrtc/modules/video_coding/frame_object.h" 18 #include "webrtc/modules/video_coding/frame_object.h"
18 19
19 namespace webrtc { 20 namespace webrtc {
20 namespace video_coding { 21 namespace video_coding {
21 22
22 PacketBuffer::PacketBuffer(size_t start_buffer_size, 23 PacketBuffer::PacketBuffer(size_t start_buffer_size,
23 size_t max_buffer_size, 24 size_t max_buffer_size,
24 OnCompleteFrameCallback* frame_callback) 25 OnCompleteFrameCallback* frame_callback)
25 : size_(start_buffer_size), 26 : size_(start_buffer_size),
26 max_size_(max_buffer_size), 27 max_size_(max_buffer_size),
27 first_seq_num_(0), 28 first_seq_num_(0),
28 last_seq_num_(0), 29 last_seq_num_(0),
29 first_packet_received_(false), 30 first_packet_received_(false),
30 data_buffer_(start_buffer_size), 31 data_buffer_(start_buffer_size),
31 sequence_buffer_(start_buffer_size), 32 sequence_buffer_(start_buffer_size),
32 frame_callback_(frame_callback), 33 frame_callback_(frame_callback),
33 last_picture_id_(-1), 34 last_picture_id_(-1),
34 last_unwrap_(-1) { 35 last_unwrap_(-1),
36 current_ss_idx_(0) {
35 RTC_DCHECK_LE(start_buffer_size, max_buffer_size); 37 RTC_DCHECK_LE(start_buffer_size, max_buffer_size);
36 // Buffer size must always be a power of 2. 38 // Buffer size must always be a power of 2.
37 RTC_DCHECK((start_buffer_size & (start_buffer_size - 1)) == 0); 39 RTC_DCHECK((start_buffer_size & (start_buffer_size - 1)) == 0);
38 RTC_DCHECK((max_buffer_size & (max_buffer_size - 1)) == 0); 40 RTC_DCHECK((max_buffer_size & (max_buffer_size - 1)) == 0);
39 } 41 }
40 42
41 bool PacketBuffer::InsertPacket(const VCMPacket& packet) { 43 bool PacketBuffer::InsertPacket(const VCMPacket& packet) {
42 rtc::CritScope lock(&crit_); 44 rtc::CritScope lock(&crit_);
43 uint16_t seq_num = packet.seqNum; 45 uint16_t seq_num = packet.seqNum;
44 size_t index = seq_num % size_; 46 size_t index = seq_num % size_;
(...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after
210 case kVideoCodecULPFEC : 212 case kVideoCodecULPFEC :
211 case kVideoCodecRED : 213 case kVideoCodecRED :
212 case kVideoCodecUnknown : { 214 case kVideoCodecUnknown : {
213 RTC_NOTREACHED(); 215 RTC_NOTREACHED();
214 } 216 }
215 case kVideoCodecVP8 : { 217 case kVideoCodecVP8 : {
216 ManageFrameVp8(std::move(frame)); 218 ManageFrameVp8(std::move(frame));
217 break; 219 break;
218 } 220 }
219 case kVideoCodecVP9 : { 221 case kVideoCodecVP9 : {
220 // TODO(philipel): ManageFrameVp9(std::move(frame)); 222 ManageFrameVp9(std::move(frame));
221 break; 223 break;
222 } 224 }
223 case kVideoCodecH264 : 225 case kVideoCodecH264 :
224 case kVideoCodecI420 : 226 case kVideoCodecI420 :
225 case kVideoCodecGeneric : 227 case kVideoCodecGeneric :
226 default : { 228 default : {
227 ManageFrameGeneric(std::move(frame)); 229 ManageFrameGeneric(std::move(frame));
228 } 230 }
229 } 231 }
230 } 232 }
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
312 frame->picture_id = codec_header.pictureId % kPicIdLength; 314 frame->picture_id = codec_header.pictureId % kPicIdLength;
313 315
314 if (last_unwrap_ == -1) 316 if (last_unwrap_ == -1)
315 last_unwrap_ = codec_header.pictureId; 317 last_unwrap_ = codec_header.pictureId;
316 318
317 if (last_picture_id_ == -1) 319 if (last_picture_id_ == -1)
318 last_picture_id_ = frame->picture_id; 320 last_picture_id_ = frame->picture_id;
319 321
320 // Find if there has been a gap in fully received frames and save the picture 322 // Find if there has been a gap in fully received frames and save the picture
321 // id of those frames in |not_yet_received_frames_|. 323 // id of those frames in |not_yet_received_frames_|.
322 if (AheadOf<uint8_t, kPicIdLength>(frame->picture_id, last_picture_id_)) { 324 if (AheadOf<uint16_t, kPicIdLength>(frame->picture_id, last_picture_id_)) {
323 last_picture_id_ = Add<kPicIdLength>(last_picture_id_, 1); 325 last_picture_id_ = Add<kPicIdLength>(last_picture_id_, 1);
324 while (last_picture_id_ != frame->picture_id) { 326 while (last_picture_id_ != frame->picture_id) {
325 not_yet_received_frames_.insert(last_picture_id_); 327 not_yet_received_frames_.insert(last_picture_id_);
326 last_picture_id_ = Add<kPicIdLength>(last_picture_id_, 1); 328 last_picture_id_ = Add<kPicIdLength>(last_picture_id_, 1);
327 } 329 }
328 } 330 }
329 331
330 // Clean up info for base layers that are too old. 332 // Clean up info for base layers that are too old.
331 uint8_t old_tl0_pic_idx = codec_header.tl0PicIdx - kMaxLayerInfo; 333 uint8_t old_tl0_pic_idx = codec_header.tl0PicIdx - kMaxLayerInfo;
332 auto clean_layer_info_to = layer_info_.lower_bound(old_tl0_pic_idx); 334 auto clean_layer_info_to = layer_info_.lower_bound(old_tl0_pic_idx);
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
382 // Find all references for this frame. 384 // Find all references for this frame.
383 frame->num_references = 0; 385 frame->num_references = 0;
384 for (uint8_t layer = 0; layer <= codec_header.temporalIdx; ++layer) { 386 for (uint8_t layer = 0; layer <= codec_header.temporalIdx; ++layer) {
385 RTC_DCHECK_NE(-1, layer_info_it->second[layer]); 387 RTC_DCHECK_NE(-1, layer_info_it->second[layer]);
386 388
387 // If we have not yet received a frame between this frame and the referenced 389 // If we have not yet received a frame between this frame and the referenced
388 // frame then we have to wait for that frame to be completed first. 390 // frame then we have to wait for that frame to be completed first.
389 auto not_received_frame_it = 391 auto not_received_frame_it =
390 not_yet_received_frames_.upper_bound(layer_info_it->second[layer]); 392 not_yet_received_frames_.upper_bound(layer_info_it->second[layer]);
391 if (not_received_frame_it != not_yet_received_frames_.end() && 393 if (not_received_frame_it != not_yet_received_frames_.end() &&
392 AheadOf<uint8_t, kPicIdLength>(frame->picture_id, 394 AheadOf<uint16_t, kPicIdLength>(frame->picture_id,
393 *not_received_frame_it)) { 395 *not_received_frame_it)) {
394 stashed_frames_.emplace(std::move(frame)); 396 stashed_frames_.emplace(std::move(frame));
395 return; 397 return;
396 } 398 }
397 399
398 ++frame->num_references; 400 ++frame->num_references;
399 frame->references[layer] = layer_info_it->second[layer]; 401 frame->references[layer] = layer_info_it->second[layer];
400 } 402 }
401 403
402 CompletedFrameVp8(std::move(frame)); 404 CompletedFrameVp8(std::move(frame));
(...skipping 18 matching lines...) Expand all
421 // update. 423 // update.
422 break; 424 break;
423 } 425 }
424 426
425 layer_info_it->second[codec_header.temporalIdx] = frame->picture_id; 427 layer_info_it->second[codec_header.temporalIdx] = frame->picture_id;
426 ++tl0_pic_idx; 428 ++tl0_pic_idx;
427 layer_info_it = layer_info_.find(tl0_pic_idx); 429 layer_info_it = layer_info_.find(tl0_pic_idx);
428 } 430 }
429 not_yet_received_frames_.erase(frame->picture_id); 431 not_yet_received_frames_.erase(frame->picture_id);
430 432
431 for (size_t r = 0; r < frame->num_references; ++r) 433 for (size_t i = 0; i < frame->num_references; ++i)
432 frame->references[r] = UnwrapPictureId(frame->references[r]); 434 frame->references[i] = UnwrapPictureId(frame->references[i]);
433 frame->picture_id = UnwrapPictureId(frame->picture_id); 435 frame->picture_id = UnwrapPictureId(frame->picture_id);
434 436
435 frame_callback_->OnCompleteFrame(std::move(frame)); 437 frame_callback_->OnCompleteFrame(std::move(frame));
436 RetryStashedFrames(); 438 RetryStashedFrames();
437 } 439 }
438 440
441 void PacketBuffer::ManageFrameVp9(std::unique_ptr<RtpFrameObject> frame) {
442 size_t index = frame->first_seq_num() % size_;
443 const VCMPacket& packet = data_buffer_[index];
444 const RTPVideoHeaderVP9& codec_header =
445 packet.codecSpecificHeader.codecHeader.VP9;
446
447 if (codec_header.picture_id == kNoPictureId) {
448 ManageFrameGeneric(std::move(frame));
449 return;
450 }
451
452 frame->spatial_layer = codec_header.spatial_idx;
453 frame->inter_layer_predicted = codec_header.inter_layer_predicted;
454 frame->picture_id = codec_header.picture_id % kPicIdLength;
455
456 if (last_unwrap_ == -1)
457 last_unwrap_ = codec_header.picture_id;
458
459 if (last_picture_id_ == -1)
460 last_picture_id_ = frame->picture_id;
461
462 if (codec_header.flexible_mode) {
463 frame->num_references = codec_header.num_ref_pics;
464 for (size_t i = 0; i < frame->num_references; ++i) {
465 frame->references[i] = Subtract<1 << 16>(frame->picture_id,
466 codec_header.pid_diff[i]);
467 }
468
469 CompletedFrameVp9(std::move(frame));
470 return;
471 }
472
473 if (codec_header.ss_data_available) {
474 // Scalability structures can only be sent with tl0 frames.
475 if (codec_header.temporal_idx != 0) {
476 LOG(LS_WARNING) << "Received scalability structure on a non base layer"
477 " frame. Scalability structure ignored.";
478 } else {
479 current_ss_idx_ = Add<kMaxGofSaved>(current_ss_idx_, 1);
480 scalability_structures_[current_ss_idx_] = codec_header.gof;
stefan-webrtc 2016/05/04 09:09:50 If you do auto inserted = scalability_structures_
philipel 2016/05/04 09:52:26 The member |scalability_structures_| is an std::ar
stefan-webrtc 2016/05/06 11:18:55 Ah, thanks
481 scalability_structures_[current_ss_idx_].pid_start = frame->picture_id;
482
483 auto pid_and_gof = std::make_pair(frame->picture_id,
484 &scalability_structures_[current_ss_idx_]);
stefan-webrtc 2016/05/04 09:09:50 git cl format
philipel 2016/05/04 09:52:26 Done.
485 gof_info_.insert(std::make_pair(codec_header.tl0_pic_idx, pid_and_gof));
486 }
487 }
488
489 // Clean up info for base layers that are too old.
490 uint8_t old_tl0_pic_idx = codec_header.tl0_pic_idx - kMaxGofSaved;
491 auto clean_gof_info_to = gof_info_.lower_bound(old_tl0_pic_idx);
492 gof_info_.erase(gof_info_.begin(), clean_gof_info_to);
493
494 if (packet.frameType == kVideoFrameKey) {
495 // When using GOF all keyframes must include the scalability structure.
496 if (!codec_header.ss_data_available)
497 LOG(LS_WARNING) << "Received keyframe without scalability structure";
498
499 frame->num_references = 0;
500 GofInfoVP9* gof = gof_info_.find(codec_header.tl0_pic_idx)->second.second;
stefan-webrtc 2016/05/04 09:09:50 It would be nice to clean this up and rename it Go
philipel 2016/05/04 09:52:26 Not sure what you mean.
stefan-webrtc 2016/05/06 11:18:55 I was refering to GofInfoVP9 -> GofInfoVp9. Feel
501 FrameReceivedVp9(frame->picture_id, *gof);
502 CompletedFrameVp9(std::move(frame));
503 return;
504 }
505
506 auto gof_info_it = gof_info_.find((codec_header.temporal_idx == 0 &&
507 !codec_header.ss_data_available)
508 ? codec_header.tl0_pic_idx - 1
509 : codec_header.tl0_pic_idx);
510
511 // Gof info for this frame is not available yet, stash this frame.
512 if (gof_info_it == gof_info_.end()) {
513 stashed_frames_.emplace(std::move(frame));
514 return;
515 }
516
517 GofInfoVP9* gof = gof_info_it->second.second;
518 uint16_t picture_id_tl0 = gof_info_it->second.first;
519
520 FrameReceivedVp9(frame->picture_id, *gof);
521
522 // Make sure we don't miss any frame that could potentially have the
523 // up switch flag set.
524 if (MissingRequiredFrameVp9(frame->picture_id, *gof)) {
525 stashed_frames_.emplace(std::move(frame));
526 return;
527 }
528
529 if (codec_header.temporal_up_switch) {
530 auto pid_tidx = std::make_pair(frame->picture_id,
531 codec_header.temporal_idx);
532 up_switch_.insert(pid_tidx);
533 }
534
535 // If this is a base layer frame that contains a scalability structure
536 // then gof info has already been inserted earlier, so we only want to
537 // insert if we haven't done so already.
538 if (codec_header.temporal_idx == 0 &&
539 !codec_header.ss_data_available) {
540 auto pid_and_gof = std::make_pair(frame->picture_id, gof);
541 gof_info_.insert(std::make_pair(codec_header.tl0_pic_idx, pid_and_gof));
542 }
543
544
stefan-webrtc 2016/05/04 09:09:50 Remove empty line
philipel 2016/05/04 09:52:26 Done.
545 // Clean out old info about up switch frames.
546 uint16_t old_picture_id = Subtract<kPicIdLength>(last_picture_id_, 50);
547 auto up_switch_erase_to = up_switch_.lower_bound(old_picture_id);
548 up_switch_.erase(up_switch_.begin(), up_switch_erase_to);
549
550 RTC_DCHECK((AheadOrAt<uint16_t, kPicIdLength>(frame->picture_id,
551 picture_id_tl0)));
552
553 uint8_t diff = ForwardDiff<uint16_t, kPicIdLength>(gof->pid_start,
stefan-webrtc 2016/05/04 09:09:50 This is a bit confusing to me. Why is the diff sto
philipel 2016/05/04 09:52:26 You are right that an uint8_t is to small, but the
554 frame->picture_id);
555 uint8_t gof_idx = diff % gof->num_frames_in_gof;
stefan-webrtc 2016/05/04 09:09:50 Can we make gof_idx a size_t? There's no point in
philipel 2016/05/04 09:52:26 Done.
556
557 // Populate references according to the scalability structure.
558 frame->num_references = gof->num_ref_pics[gof_idx];
559 for (size_t i = 0; i < frame->num_references; ++i) {
560 frame->references[i] = Subtract<kPicIdLength>(frame->picture_id,
561 gof->pid_diff[gof_idx][i]);
562
563 // If this is a reference to a frame earlier than the last up switch point,
564 // then ignore this reference.
565 if (UpSwitchInIntervalVp9(frame->picture_id,
566 codec_header.temporal_idx,
stefan-webrtc 2016/05/04 09:09:50 This doesn't look correctly formatted.
philipel 2016/05/04 09:52:26 Formated.
567 frame->references[i])) {
568 --frame->num_references;
569 }
570 }
571
572 CompletedFrameVp9(std::move(frame));
573 }
574
575 bool PacketBuffer::MissingRequiredFrameVp9(uint16_t picture_id,
576 const GofInfoVP9& gof) {
577 uint8_t diff = ForwardDiff<uint16_t, kPicIdLength>(gof.pid_start, picture_id);
578 uint8_t gof_idx = diff % gof.num_frames_in_gof;
579 uint8_t temporal_idx = gof.temporal_idx[gof_idx];
stefan-webrtc 2016/05/04 09:09:50 Should we use int for all of these instead? Just t
philipel 2016/05/04 09:52:26 Changed to size_t.
580
581 // For every reference this frame has, check if there is a frame missing in
582 // the intervall (|ref_pid|, |picture_id|) in any of the lower temporal
stefan-webrtc 2016/05/04 09:09:50 interval
philipel 2016/05/04 09:52:26 Done.
583 // layers. If so, we are missing a required frame.
584 uint8_t num_references = gof.num_ref_pics[gof_idx];
585 for (size_t i = 0; i < num_references; ++i) {
586 uint16_t ref_pid = Subtract<kPicIdLength>(picture_id,
587 gof.pid_diff[gof_idx][i]);
588 for (size_t l = 0; l < temporal_idx; ++l) {
589 auto missing_frame_it = missing_frames_for_layer_[l].lower_bound(ref_pid);
590 if (missing_frame_it != missing_frames_for_layer_[l].end() &&
591 AheadOf<uint16_t, kPicIdLength>(picture_id, *missing_frame_it)) {
592 return true;
593 }
594 }
595 }
596 return false;
597 }
598
599 void PacketBuffer::FrameReceivedVp9(uint16_t picture_id,
600 const GofInfoVP9& gof) {
601 RTC_DCHECK_NE(-1, last_picture_id_);
602
603 // If there is a gap, find which temporal layers the missing framess
stefan-webrtc 2016/05/04 09:09:50 frames
philipel 2016/05/04 09:52:26 Done.
604 // belongs to and add the frame as missing for that temporal layer.
stefan-webrtc 2016/05/04 09:09:50 belong to
philipel 2016/05/04 09:52:26 Done.
605 // Otherwise, remove this frame from the set of missing frames.
606 if (AheadOf<uint16_t, kPicIdLength>(picture_id, last_picture_id_)) {
607 uint8_t diff = ForwardDiff<uint16_t, kPicIdLength>(gof.pid_start,
608 last_picture_id_);
609 uint8_t gof_idx = diff % gof.num_frames_in_gof;
610
611 last_picture_id_ = Add<kPicIdLength>(last_picture_id_, 1);
612 while (last_picture_id_ != picture_id) {
613 ++gof_idx;
614 RTC_DCHECK_NE(0ul, gof_idx % gof.num_frames_in_gof);
615 uint8_t temporal_idx = gof.temporal_idx[gof_idx];
616 missing_frames_for_layer_[temporal_idx].insert(last_picture_id_);
617 last_picture_id_ = Add<kPicIdLength>(last_picture_id_, 1);
618 }
619 } else {
620 uint8_t diff = ForwardDiff<uint16_t, kPicIdLength>(gof.pid_start,
621 picture_id);
622 uint8_t gof_idx = diff % gof.num_frames_in_gof;
623 uint8_t temporal_idx = gof.temporal_idx[gof_idx];
624 missing_frames_for_layer_[temporal_idx].erase(picture_id);
625 }
626 }
627
628 bool PacketBuffer::UpSwitchInIntervalVp9(uint16_t picture_id,
629 uint8_t temporal_idx,
630 uint16_t pid_ref) {
631 auto up_switch_it = up_switch_.upper_bound(pid_ref);
632 while (up_switch_it != up_switch_.end() &&
stefan-webrtc 2016/05/04 09:09:50 I'd use a for loop here instead
philipel 2016/05/04 09:52:26 Done.
633 AheadOf<uint16_t, kPicIdLength>(picture_id, up_switch_it->first)) {
634 if (up_switch_it->second < temporal_idx)
635 return true;
636 ++up_switch_it;
637 }
638
639 return false;
640 }
641
642 void PacketBuffer::CompletedFrameVp9(std::unique_ptr<RtpFrameObject> frame) {
643 for (size_t i = 0; i < frame->num_references; ++i)
644 frame->references[i] = UnwrapPictureId(frame->references[i]);
645 frame->picture_id = UnwrapPictureId(frame->picture_id);
646
647 frame_callback_->OnCompleteFrame(std::move(frame));
648 RetryStashedFrames();
649 }
650
439 uint16_t PacketBuffer::UnwrapPictureId(uint16_t picture_id) { 651 uint16_t PacketBuffer::UnwrapPictureId(uint16_t picture_id) {
440 if (last_unwrap_ == -1) 652 RTC_DCHECK_NE(-1, last_unwrap_);
441 last_unwrap_ = picture_id;
442 653
443 uint16_t unwrap_truncated = last_unwrap_ % kPicIdLength; 654 uint16_t unwrap_truncated = last_unwrap_ % kPicIdLength;
444 uint16_t diff = MinDiff<uint8_t, kPicIdLength>(unwrap_truncated, picture_id); 655 uint16_t diff = MinDiff<uint16_t, kPicIdLength>(unwrap_truncated, picture_id);
445 656
446 if (AheadOf<uint8_t, kPicIdLength>(picture_id, unwrap_truncated)) 657 if (AheadOf<uint16_t, kPicIdLength>(picture_id, unwrap_truncated))
447 last_unwrap_ = Add<1 << 16>(last_unwrap_, diff); 658 last_unwrap_ = Add<1 << 16>(last_unwrap_, diff);
448 else 659 else
449 last_unwrap_ = Subtract<1 << 16>(last_unwrap_, diff); 660 last_unwrap_ = Subtract<1 << 16>(last_unwrap_, diff);
450 661
451 return last_unwrap_; 662 return last_unwrap_;
452 } 663 }
453 664
454 void PacketBuffer::Flush() { 665 void PacketBuffer::Flush() {
455 rtc::CritScope lock(&crit_); 666 rtc::CritScope lock(&crit_);
456 for (size_t i = 0; i < size_; ++i) 667 for (size_t i = 0; i < size_; ++i)
457 sequence_buffer_[i].used = false; 668 sequence_buffer_[i].used = false;
458 669
459 last_seq_num_gop_.clear(); 670 last_seq_num_gop_.clear();
460 while (!stashed_frames_.empty()) 671 while (!stashed_frames_.empty())
461 stashed_frames_.pop(); 672 stashed_frames_.pop();
462 not_yet_received_frames_.clear(); 673 not_yet_received_frames_.clear();
463 674
464 first_packet_received_ = false; 675 first_packet_received_ = false;
465 } 676 }
466 677
467 } // namespace video_coding 678 } // namespace video_coding
468 } // namespace webrtc 679 } // namespace webrtc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698