diff --git a/webrtc/modules/include/module_common_types.h b/webrtc/modules/include/module_common_types.h index a2ab766ce5..8c7261769d 100644 --- a/webrtc/modules/include/module_common_types.h +++ b/webrtc/modules/include/module_common_types.h @@ -71,9 +71,10 @@ struct RTPVideoHeaderVP8 { }; enum TemporalStructureMode { - kTemporalStructureMode1, // 1 temporal layer structure - i.e., IPPP... - kTemporalStructureMode2, // 2 temporal layers 0-1-0-1... - kTemporalStructureMode3 // 3 temporal layers 0-2-1-2-0-2-1-2... + kTemporalStructureMode1, // 1 temporal layer structure - i.e., IPPP... + kTemporalStructureMode2, // 2 temporal layers 01... + kTemporalStructureMode3, // 3 temporal layers 0212... + kTemporalStructureMode4 // 3 temporal layers 02120212... }; struct GofInfoVP9 { @@ -121,6 +122,52 @@ struct GofInfoVP9 { pid_diff[3][0] = 1; pid_diff[3][1] = 2; break; + case kTemporalStructureMode4: + num_frames_in_gof = 8; + temporal_idx[0] = 0; + temporal_up_switch[0] = false; + num_ref_pics[0] = 1; + pid_diff[0][0] = 4; + + temporal_idx[1] = 2; + temporal_up_switch[1] = true; + num_ref_pics[1] = 1; + pid_diff[1][0] = 1; + + temporal_idx[2] = 1; + temporal_up_switch[2] = true; + num_ref_pics[2] = 1; + pid_diff[2][0] = 2; + + temporal_idx[3] = 2; + temporal_up_switch[3] = false; + num_ref_pics[3] = 2; + pid_diff[3][0] = 1; + pid_diff[3][1] = 2; + + temporal_idx[4] = 0; + temporal_up_switch[0] = false; + num_ref_pics[4] = 1; + pid_diff[4][0] = 4; + + temporal_idx[5] = 2; + temporal_up_switch[1] = false; + num_ref_pics[5] = 2; + pid_diff[5][0] = 1; + pid_diff[5][1] = 2; + + temporal_idx[6] = 1; + temporal_up_switch[2] = false; + num_ref_pics[6] = 2; + pid_diff[6][0] = 2; + pid_diff[6][1] = 4; + + temporal_idx[7] = 2; + temporal_up_switch[3] = false; + num_ref_pics[7] = 2; + pid_diff[7][0] = 1; + pid_diff[7][1] = 2; + break; default: assert(false); } @@ -143,6 +190,7 @@ struct GofInfoVP9 { bool temporal_up_switch[kMaxVp9FramesInGof]; uint8_t num_ref_pics[kMaxVp9FramesInGof]; uint8_t pid_diff[kMaxVp9FramesInGof][kMaxVp9RefPics]; + uint16_t pid_start; }; struct RTPVideoHeaderVP9 { diff --git a/webrtc/modules/video_coding/frame_object.cc b/webrtc/modules/video_coding/frame_object.cc index 7a05d28d56..ea7567c18e 100644 --- a/webrtc/modules/video_coding/frame_object.cc +++ b/webrtc/modules/video_coding/frame_object.cc @@ -15,6 +15,12 @@ namespace webrtc { namespace video_coding { +FrameObject::FrameObject() + : picture_id(0), + spatial_layer(0), + num_references(0), + inter_layer_predicted(false) {} + RtpFrameObject::RtpFrameObject(PacketBuffer* packet_buffer, uint16_t first_packet, uint16_t last_packet) diff --git a/webrtc/modules/video_coding/frame_object.h b/webrtc/modules/video_coding/frame_object.h index c5cdd6eb11..2b39f06fcd 100644 --- a/webrtc/modules/video_coding/frame_object.h +++ b/webrtc/modules/video_coding/frame_object.h @@ -23,13 +23,20 @@ class FrameObject { public: static const uint8_t kMaxFrameReferences = 5; + FrameObject(); + virtual bool GetBitstream(uint8_t* destination) const = 0; virtual ~FrameObject() {} + // The tuple (|picture_id|, |spatial_layer|) uniquely identifies a frame + // object. For codec types that don't necessarily have picture ids they + // have to be constructed from the header data relevant to that codec. uint16_t picture_id; + uint8_t spatial_layer; + size_t num_references; - std::array referencesr; uint16_t references[kMaxFrameReferences]; + bool inter_layer_predicted; }; class PacketBuffer; diff --git a/webrtc/modules/video_coding/packet_buffer.cc b/webrtc/modules/video_coding/packet_buffer.cc index d7b4f449e7..71ab3e57d8 100644 --- a/webrtc/modules/video_coding/packet_buffer.cc +++ b/webrtc/modules/video_coding/packet_buffer.cc @@ -14,6 +14,7 @@ #include #include "webrtc/base/checks.h" +#include "webrtc/base/logging.h" #include "webrtc/modules/video_coding/frame_object.h" namespace webrtc { @@ -31,7 +32,8 @@ PacketBuffer::PacketBuffer(size_t start_buffer_size, sequence_buffer_(start_buffer_size), frame_callback_(frame_callback), last_picture_id_(-1), - last_unwrap_(-1) { + last_unwrap_(-1), + current_ss_idx_(0) { RTC_DCHECK_LE(start_buffer_size, max_buffer_size); // Buffer size must always be a power of 2. RTC_DCHECK((start_buffer_size & (start_buffer_size - 1)) == 0); @@ -216,7 +218,7 @@ void PacketBuffer::ManageFrame(std::unique_ptr frame) { ManageFrameVp8(std::move(frame)); break; case kVideoCodecVP9: - // TODO(philipel): ManageFrameVp9(std::move(frame)); + ManageFrameVp9(std::move(frame)); break; case kVideoCodecH264: case kVideoCodecI420: @@ -316,7 +318,7 @@ void PacketBuffer::ManageFrameVp8(std::unique_ptr frame) { // Find if there has been a gap in fully received frames and save the picture // id of those frames in |not_yet_received_frames_|. - if (AheadOf(frame->picture_id, last_picture_id_)) { + if (AheadOf(frame->picture_id, last_picture_id_)) { last_picture_id_ = Add(last_picture_id_, 1); while (last_picture_id_ != frame->picture_id) { not_yet_received_frames_.insert(last_picture_id_); @@ -386,10 +388,10 @@ void PacketBuffer::ManageFrameVp8(std::unique_ptr frame) { auto not_received_frame_it = not_yet_received_frames_.upper_bound(layer_info_it->second[layer]); if (not_received_frame_it != not_yet_received_frames_.end() && - AheadOf(frame->picture_id, - *not_received_frame_it)) { - stashed_frames_.emplace(std::move(frame)); - return; + AheadOf(frame->picture_id, + *not_received_frame_it)) { + stashed_frames_.emplace(std::move(frame)); + return; } ++frame->num_references; @@ -425,8 +427,215 @@ void PacketBuffer::CompletedFrameVp8(std::unique_ptr frame) { } not_yet_received_frames_.erase(frame->picture_id); - for (size_t r = 0; r < frame->num_references; ++r) - frame->references[r] = UnwrapPictureId(frame->references[r]); + for (size_t i = 0; i < frame->num_references; ++i) + frame->references[i] = UnwrapPictureId(frame->references[i]); + frame->picture_id = UnwrapPictureId(frame->picture_id); + + frame_callback_->OnCompleteFrame(std::move(frame)); + RetryStashedFrames(); +} + +void PacketBuffer::ManageFrameVp9(std::unique_ptr frame) { + size_t index = frame->first_seq_num() % size_; + const VCMPacket& packet = data_buffer_[index]; + const RTPVideoHeaderVP9& codec_header = + packet.codecSpecificHeader.codecHeader.VP9; + + if (codec_header.picture_id == kNoPictureId) { + ManageFrameGeneric(std::move(frame)); + return; + } + + frame->spatial_layer = codec_header.spatial_idx; + frame->inter_layer_predicted = codec_header.inter_layer_predicted; + frame->picture_id = codec_header.picture_id % kPicIdLength; + + if (last_unwrap_ == -1) + last_unwrap_ = codec_header.picture_id; + + if (last_picture_id_ == -1) + last_picture_id_ = frame->picture_id; + + if (codec_header.flexible_mode) { + frame->num_references = codec_header.num_ref_pics; + for (size_t i = 0; i < frame->num_references; ++i) { + frame->references[i] = + Subtract<1 << 16>(frame->picture_id, codec_header.pid_diff[i]); + } + + CompletedFrameVp9(std::move(frame)); + return; + } + + if (codec_header.ss_data_available) { + // Scalability structures can only be sent with tl0 frames. + if (codec_header.temporal_idx != 0) { + LOG(LS_WARNING) << "Received scalability structure on a non base layer" + " frame. Scalability structure ignored."; + } else { + current_ss_idx_ = Add(current_ss_idx_, 1); + scalability_structures_[current_ss_idx_] = codec_header.gof; + scalability_structures_[current_ss_idx_].pid_start = frame->picture_id; + + auto pid_and_gof = std::make_pair( + frame->picture_id, &scalability_structures_[current_ss_idx_]); + gof_info_.insert(std::make_pair(codec_header.tl0_pic_idx, pid_and_gof)); + } + } + + // Clean up info for base layers that are too old. + uint8_t old_tl0_pic_idx = codec_header.tl0_pic_idx - kMaxGofSaved; + auto clean_gof_info_to = gof_info_.lower_bound(old_tl0_pic_idx); + gof_info_.erase(gof_info_.begin(), clean_gof_info_to); + + if (packet.frameType == kVideoFrameKey) { + // When using GOF all keyframes must include the scalability structure. + if (!codec_header.ss_data_available) + LOG(LS_WARNING) << "Received keyframe without scalability structure"; + + frame->num_references = 0; + GofInfoVP9* gof = gof_info_.find(codec_header.tl0_pic_idx)->second.second; + FrameReceivedVp9(frame->picture_id, *gof); + CompletedFrameVp9(std::move(frame)); + return; + } + + auto gof_info_it = gof_info_.find( + (codec_header.temporal_idx == 0 && !codec_header.ss_data_available) + ? codec_header.tl0_pic_idx - 1 + : codec_header.tl0_pic_idx); + + // Gof info for this frame is not available yet, stash this frame. + if (gof_info_it == gof_info_.end()) { + stashed_frames_.emplace(std::move(frame)); + return; + } + + GofInfoVP9* gof = gof_info_it->second.second; + uint16_t picture_id_tl0 = gof_info_it->second.first; + + FrameReceivedVp9(frame->picture_id, *gof); + + // Make sure we don't miss any frame that could potentially have the + // up switch flag set. + if (MissingRequiredFrameVp9(frame->picture_id, *gof)) { + stashed_frames_.emplace(std::move(frame)); + return; + } + + if (codec_header.temporal_up_switch) { + auto pid_tidx = + std::make_pair(frame->picture_id, codec_header.temporal_idx); + up_switch_.insert(pid_tidx); + } + + // If this is a base layer frame that contains a scalability structure + // then gof info has already been inserted earlier, so we only want to + // insert if we haven't done so already. + if (codec_header.temporal_idx == 0 && !codec_header.ss_data_available) { + auto pid_and_gof = std::make_pair(frame->picture_id, gof); + gof_info_.insert(std::make_pair(codec_header.tl0_pic_idx, pid_and_gof)); + } + + // Clean out old info about up switch frames. + uint16_t old_picture_id = Subtract(last_picture_id_, 50); + auto up_switch_erase_to = up_switch_.lower_bound(old_picture_id); + up_switch_.erase(up_switch_.begin(), up_switch_erase_to); + + RTC_DCHECK( + (AheadOrAt(frame->picture_id, picture_id_tl0))); + + size_t diff = + ForwardDiff(gof->pid_start, frame->picture_id); + size_t gof_idx = diff % gof->num_frames_in_gof; + + // Populate references according to the scalability structure. + frame->num_references = gof->num_ref_pics[gof_idx]; + for (size_t i = 0; i < frame->num_references; ++i) { + frame->references[i] = + Subtract(frame->picture_id, gof->pid_diff[gof_idx][i]); + + // If this is a reference to a frame earlier than the last up switch point, + // then ignore this reference. + if (UpSwitchInIntervalVp9(frame->picture_id, codec_header.temporal_idx, + frame->references[i])) { + --frame->num_references; + } + } + + CompletedFrameVp9(std::move(frame)); +} + +bool PacketBuffer::MissingRequiredFrameVp9(uint16_t picture_id, + const GofInfoVP9& gof) { + size_t diff = ForwardDiff(gof.pid_start, picture_id); + size_t gof_idx = diff % gof.num_frames_in_gof; + size_t temporal_idx = gof.temporal_idx[gof_idx]; + + // For every reference this frame has, check if there is a frame missing in + // the interval (|ref_pid|, |picture_id|) in any of the lower temporal + // layers. If so, we are missing a required frame. + uint8_t num_references = gof.num_ref_pics[gof_idx]; + for (size_t i = 0; i < num_references; ++i) { + uint16_t ref_pid = + Subtract(picture_id, gof.pid_diff[gof_idx][i]); + for (size_t l = 0; l < temporal_idx; ++l) { + auto missing_frame_it = missing_frames_for_layer_[l].lower_bound(ref_pid); + if (missing_frame_it != missing_frames_for_layer_[l].end() && + AheadOf(picture_id, *missing_frame_it)) { + return true; + } + } + } + return false; +} + +void PacketBuffer::FrameReceivedVp9(uint16_t picture_id, + const GofInfoVP9& gof) { + RTC_DCHECK_NE(-1, last_picture_id_); + + // If there is a gap, find which temporal layer the missing frames + // belong to and add the frame as missing for that temporal layer. + // Otherwise, remove this frame from the set of missing frames. + if (AheadOf(picture_id, last_picture_id_)) { + size_t diff = + ForwardDiff(gof.pid_start, last_picture_id_); + size_t gof_idx = diff % gof.num_frames_in_gof; + + last_picture_id_ = Add(last_picture_id_, 1); + while (last_picture_id_ != picture_id) { + ++gof_idx; + RTC_DCHECK_NE(0ul, gof_idx % gof.num_frames_in_gof); + size_t temporal_idx = gof.temporal_idx[gof_idx]; + missing_frames_for_layer_[temporal_idx].insert(last_picture_id_); + last_picture_id_ = Add(last_picture_id_, 1); + } + } else { + size_t diff = + ForwardDiff(gof.pid_start, picture_id); + size_t gof_idx = diff % gof.num_frames_in_gof; + size_t temporal_idx = gof.temporal_idx[gof_idx]; + missing_frames_for_layer_[temporal_idx].erase(picture_id); + } +} + +bool PacketBuffer::UpSwitchInIntervalVp9(uint16_t picture_id, + uint8_t temporal_idx, + uint16_t pid_ref) { + for (auto up_switch_it = up_switch_.upper_bound(pid_ref); + up_switch_it != up_switch_.end() && + AheadOf(picture_id, up_switch_it->first); + ++up_switch_it) { + if (up_switch_it->second < temporal_idx) + return true; + } + + return false; +} + +void PacketBuffer::CompletedFrameVp9(std::unique_ptr frame) { + for (size_t i = 0; i < frame->num_references; ++i) + frame->references[i] = UnwrapPictureId(frame->references[i]); frame->picture_id = UnwrapPictureId(frame->picture_id); frame_callback_->OnCompleteFrame(std::move(frame)); @@ -434,13 +643,12 @@ void PacketBuffer::CompletedFrameVp8(std::unique_ptr frame) { } uint16_t PacketBuffer::UnwrapPictureId(uint16_t picture_id) { - if (last_unwrap_ == -1) - last_unwrap_ = picture_id; + RTC_DCHECK_NE(-1, last_unwrap_); uint16_t unwrap_truncated = last_unwrap_ % kPicIdLength; - uint16_t diff = MinDiff(unwrap_truncated, picture_id); + uint16_t diff = MinDiff(unwrap_truncated, picture_id); - if (AheadOf(picture_id, unwrap_truncated)) + if (AheadOf(picture_id, unwrap_truncated)) last_unwrap_ = Add<1 << 16>(last_unwrap_, diff); else last_unwrap_ = Subtract<1 << 16>(last_unwrap_, diff); diff --git a/webrtc/modules/video_coding/packet_buffer.h b/webrtc/modules/video_coding/packet_buffer.h index 75049b33ba..8a1d7069f4 100644 --- a/webrtc/modules/video_coding/packet_buffer.h +++ b/webrtc/modules/video_coding/packet_buffer.h @@ -12,15 +12,17 @@ #define WEBRTC_MODULES_VIDEO_CODING_PACKET_BUFFER_H_ #include -#include #include #include -#include #include +#include +#include +#include #include "webrtc/base/criticalsection.h" #include "webrtc/base/scoped_ptr.h" #include "webrtc/base/thread_annotations.h" +#include "webrtc/modules/include/module_common_types.h" #include "webrtc/modules/video_coding/packet.h" #include "webrtc/modules/video_coding/sequence_number_util.h" @@ -49,10 +51,11 @@ class PacketBuffer { private: static const uint16_t kPicIdLength = 1 << 7; - static const uint8_t kMaxTemporalLayer = 5; + static const uint8_t kMaxTemporalLayers = 5; static const int kMaxStashedFrames = 10; static const int kMaxLayerInfo = 10; static const int kMaxNotYetReceivedFrames = 20; + static const int kMaxGofSaved = 15; friend RtpFrameObject; // Since we want the packet buffer to be as packet type agnostic @@ -116,6 +119,32 @@ class PacketBuffer { void CompletedFrameVp8(std::unique_ptr frame) EXCLUSIVE_LOCKS_REQUIRED(crit_); + // Find references for Vp9 frames + void ManageFrameVp9(std::unique_ptr frame) + EXCLUSIVE_LOCKS_REQUIRED(crit_); + + // Unwrap the picture id and the frame references and then call the + // |frame_callback| callback with the completed frame. + void CompletedFrameVp9(std::unique_ptr frame) + EXCLUSIVE_LOCKS_REQUIRED(crit_); + + // Check if we are missing a frame necessary to determine the references + // for this frame. + bool MissingRequiredFrameVp9(uint16_t picture_id, const GofInfoVP9& gof) + EXCLUSIVE_LOCKS_REQUIRED(crit_); + + // Updates which frames that have been received. If there is a gap, + // missing frames will be added to |missing_frames_for_layer_| or + // if this is an already missing frame then it will be removed. + void FrameReceivedVp9(uint16_t picture_id, const GofInfoVP9& gof) + EXCLUSIVE_LOCKS_REQUIRED(crit_); + + // Check if there is a frame with the up-switch flag set in the interval + // (|pid_ref|, |picture_id|) with temporal layer smaller than |temporal_idx|. + bool UpSwitchInIntervalVp9(uint16_t picture_id, + uint8_t temporal_idx, + uint16_t pid_ref) EXCLUSIVE_LOCKS_REQUIRED(crit_); + // All picture ids are unwrapped to 16 bits. uint16_t UnwrapPictureId(uint16_t picture_id) EXCLUSIVE_LOCKS_REQUIRED(crit_); @@ -161,8 +190,8 @@ class PacketBuffer { // Frames earlier than the last received frame that have not yet been // fully received. - std::set> - not_yet_received_frames_ GUARDED_BY(crit_); + std::set> + not_yet_received_frames_ GUARDED_BY(crit_); // Frames that have been fully received but didn't have all the information // needed to determine their references. @@ -171,8 +200,32 @@ class PacketBuffer { // Holds the information about the last completed frame for a given temporal // layer given a Tl0 picture index. std::map, - DescendingSeqNumComp> layer_info_ GUARDED_BY(crit_); + std::array, + DescendingSeqNumComp> + layer_info_ GUARDED_BY(crit_); + + // Where the current scalability structure is in the + // |scalability_structures_| array. + uint8_t current_ss_idx_; + + // Holds received scalability structures. + std::array scalability_structures_ + GUARDED_BY(crit_); + + // Holds the picture id and the Gof information for a given TL0 picture index. + std::map, + DescendingSeqNumComp> + gof_info_ GUARDED_BY(crit_); + + // Keep track of which picture id and which temporal layer that had the + // up switch flag set. + std::map up_switch_ GUARDED_BY(crit_); + + // For every temporal layer, keep a set of which frames that are missing. + std::array>, + kMaxTemporalLayers> + missing_frames_for_layer_ GUARDED_BY(crit_); }; } // namespace video_coding diff --git a/webrtc/modules/video_coding/packet_buffer_unittest.cc b/webrtc/modules/video_coding/packet_buffer_unittest.cc index eb0a03bf82..b7921e5c6d 100644 --- a/webrtc/modules/video_coding/packet_buffer_unittest.cc +++ b/webrtc/modules/video_coding/packet_buffer_unittest.cc @@ -11,6 +11,7 @@ #include #include #include +#include #include "webrtc/modules/video_coding/frame_object.h" #include "webrtc/modules/video_coding/packet_buffer.h" @@ -26,20 +27,23 @@ class TestPacketBuffer : public ::testing::Test, protected: TestPacketBuffer() : rand_(0x8739211), - packet_buffer_(new PacketBuffer(kStartSize, kMaxSize, this)) {} + packet_buffer_(new PacketBuffer(kStartSize, kMaxSize, this)), + frames_from_callback_(FrameComp()) {} uint16_t Rand() { return rand_.Rand(std::numeric_limits::max()); } void OnCompleteFrame(std::unique_ptr frame) override { uint16_t pid = frame->picture_id; - auto frame_it = frames_from_callback_.find(pid); + uint16_t sidx = frame->spatial_layer; + auto frame_it = frames_from_callback_.find(std::make_pair(pid, sidx)); if (frame_it != frames_from_callback_.end()) { - ADD_FAILURE() << "Already received frame with picture id: " << pid; + ADD_FAILURE() << "Already received frame with (pid:sidx): (" + << pid << ":" << sidx << ")"; return; } frames_from_callback_.insert( - make_pair(frame->picture_id, std::move(frame))); + std::make_pair(std::make_pair(pid, sidx), std::move(frame))); } void TearDown() override { @@ -49,6 +53,12 @@ class TestPacketBuffer : public ::testing::Test, frames_from_callback_.clear(); } + // Short version of true and false. + enum { + kT = true, + kF = false + }; + // Insert a generic packet into the packet buffer. void InsertGeneric(uint16_t seq_num, // packet sequence number bool keyframe, // is keyframe @@ -95,13 +105,85 @@ class TestPacketBuffer : public ::testing::Test, EXPECT_TRUE(packet_buffer_->InsertPacket(packet)); } - // Check if a frame with picture id |pid| has been delivered from the packet - // buffer, and if so, if it has the references specified by |refs|. + // Insert a Vp9 packet into the packet buffer. + void InsertVp9Gof(uint16_t seq_num, // packet sequence number + bool keyframe, // is keyframe + bool first, // is first packet of frame + bool last, // is last packet of frame + bool up = false, // frame is up-switch point + int32_t pid = kNoPictureId, // picture id + uint8_t sid = kNoSpatialIdx, // spatial id + uint8_t tid = kNoTemporalIdx, // temporal id + int32_t tl0 = kNoTl0PicIdx, // tl0 pic index + GofInfoVP9* ss = nullptr, // scalability structure + size_t data_size = 0, // size of data + uint8_t* data = nullptr) { // data pointer + VCMPacket packet; + packet.codec = kVideoCodecVP9; + packet.seqNum = seq_num; + packet.frameType = keyframe ? kVideoFrameKey : kVideoFrameDelta; + packet.isFirstPacket = first; + packet.markerBit = last; + packet.sizeBytes = data_size; + packet.dataPtr = data; + packet.codecSpecificHeader.codecHeader.VP9.flexible_mode = false; + packet.codecSpecificHeader.codecHeader.VP9.picture_id = pid % (1 << 15); + packet.codecSpecificHeader.codecHeader.VP9.temporal_idx = tid; + packet.codecSpecificHeader.codecHeader.VP9.spatial_idx = sid; + packet.codecSpecificHeader.codecHeader.VP9.tl0_pic_idx = tl0; + packet.codecSpecificHeader.codecHeader.VP9.temporal_up_switch = up; + if (ss != nullptr) { + packet.codecSpecificHeader.codecHeader.VP9.ss_data_available = true; + packet.codecSpecificHeader.codecHeader.VP9.gof = *ss; + } + + EXPECT_TRUE(packet_buffer_->InsertPacket(packet)); + } + + // Insert a Vp9 packet into the packet buffer. + void InsertVp9Flex(uint16_t seq_num, // packet sequence number + bool keyframe, // is keyframe + bool first, // is first packet of frame + bool last, // is last packet of frame + bool inter, // depends on S-1 layer + int32_t pid = kNoPictureId, // picture id + uint8_t sid = kNoSpatialIdx, // spatial id + uint8_t tid = kNoTemporalIdx, // temporal id + int32_t tl0 = kNoTl0PicIdx, // tl0 pic index + std::vector refs = + std::vector(), // frame references + size_t data_size = 0, // size of data + uint8_t* data = nullptr) { // data pointer + VCMPacket packet; + packet.codec = kVideoCodecVP9; + packet.seqNum = seq_num; + packet.frameType = keyframe ? kVideoFrameKey : kVideoFrameDelta; + packet.isFirstPacket = first; + packet.markerBit = last; + packet.sizeBytes = data_size; + packet.dataPtr = data; + packet.codecSpecificHeader.codecHeader.VP9.inter_layer_predicted = inter; + packet.codecSpecificHeader.codecHeader.VP9.flexible_mode = true; + packet.codecSpecificHeader.codecHeader.VP9.picture_id = pid % (1 << 15); + packet.codecSpecificHeader.codecHeader.VP9.temporal_idx = tid; + packet.codecSpecificHeader.codecHeader.VP9.spatial_idx = sid; + packet.codecSpecificHeader.codecHeader.VP9.tl0_pic_idx = tl0; + packet.codecSpecificHeader.codecHeader.VP9.num_ref_pics = refs.size(); + for (size_t i = 0; i < refs.size(); ++i) + packet.codecSpecificHeader.codecHeader.VP9.pid_diff[i] = refs[i]; + + EXPECT_TRUE(packet_buffer_->InsertPacket(packet)); + } + + // Check if a frame with picture id |pid| and spatial index |sidx| has been + // delivered from the packet buffer, and if so, if it has the references + // specified by |refs|. template - void CheckReferences(uint16_t pid, T... refs) const { - auto frame_it = frames_from_callback_.find(pid); + void CheckReferences(uint16_t pid, uint16_t sidx, T... refs) const { + auto frame_it = frames_from_callback_.find(std::make_pair(pid, sidx)); if (frame_it == frames_from_callback_.end()) { - ADD_FAILURE() << "Could not find frame with picture id " << pid; + ADD_FAILURE() << "Could not find frame with (pid:sidx): (" + << pid << ":" << sidx << ")"; return; } @@ -116,6 +198,21 @@ class TestPacketBuffer : public ::testing::Test, ASSERT_EQ(expected_refs, actual_refs); } + template + void CheckReferencesGeneric(uint16_t pid, T... refs) const { + CheckReferences(pid, 0, refs...); + } + + template + void CheckReferencesVp8(uint16_t pid, T... refs) const { + CheckReferences(pid, 0, refs...); + } + + template + void CheckReferencesVp9(uint16_t pid, uint8_t sidx, T... refs) const { + CheckReferences(pid, sidx, refs...); + } + template void RefsToSet(std::set* m, uint16_t ref, T... refs) const { m->insert(ref); @@ -129,7 +226,17 @@ class TestPacketBuffer : public ::testing::Test, Random rand_; std::unique_ptr packet_buffer_; - std::map> frames_from_callback_; + struct FrameComp { + bool operator()(const std::pair f1, + const std::pair f2) const { + if (f1.first == f2.first) + return f1.second < f2.second; + return f1.first < f2.first; + } + }; + std::map, + std::unique_ptr, + FrameComp> frames_from_callback_; }; TEST_F(TestPacketBuffer, InsertOnePacket) { @@ -161,8 +268,8 @@ TEST_F(TestPacketBuffer, ExpandBuffer) { uint16_t seq_num = Rand(); for (int i = 0; i < kStartSize + 1; ++i) { - // seq_num , keyframe, first, last - InsertGeneric(seq_num + i, true , true , true); + // seq_num , kf, frst, lst + InsertGeneric(seq_num + i, kT , kT, kT); } } @@ -170,8 +277,8 @@ TEST_F(TestPacketBuffer, ExpandBufferOverflow) { uint16_t seq_num = Rand(); for (int i = 0; i < kMaxSize; ++i) { - // seq_num , keyframe, first, last - InsertGeneric(seq_num + i, true , true , true); + // seq_num , kf, frst, lst + InsertGeneric(seq_num + i, kT, kT , kT); } VCMPacket packet; @@ -181,17 +288,17 @@ TEST_F(TestPacketBuffer, ExpandBufferOverflow) { } TEST_F(TestPacketBuffer, GenericOnePacketOneFrame) { - // seq_num, keyframe, first, last - InsertGeneric(Rand() , true , true , true); + // seq_num, kf, frst, lst + InsertGeneric(Rand() , kT, kT , kT); ASSERT_EQ(1UL, frames_from_callback_.size()); } TEST_F(TestPacketBuffer, GenericTwoPacketsTwoFrames) { uint16_t seq_num = Rand(); - // seq_num , keyframe, first, last - InsertGeneric(seq_num , true , true , true); - InsertGeneric(seq_num + 1, true , true , true); + // seq_num , kf, frst, lst + InsertGeneric(seq_num , kT, kT , kT); + InsertGeneric(seq_num + 1, kT, kT , kT); EXPECT_EQ(2UL, frames_from_callback_.size()); } @@ -199,9 +306,9 @@ TEST_F(TestPacketBuffer, GenericTwoPacketsTwoFrames) { TEST_F(TestPacketBuffer, GenericTwoPacketsOneFrames) { uint16_t seq_num = Rand(); - // seq_num , keyframe, first, last - InsertGeneric(seq_num , true , true , false); - InsertGeneric(seq_num + 1, true , false, true); + // seq_num , kf, frst, lst + InsertGeneric(seq_num , kT, kT , kF); + InsertGeneric(seq_num + 1, kT, kF , kT); EXPECT_EQ(1UL, frames_from_callback_.size()); } @@ -209,10 +316,10 @@ TEST_F(TestPacketBuffer, GenericTwoPacketsOneFrames) { TEST_F(TestPacketBuffer, GenericThreePacketReorderingOneFrame) { uint16_t seq_num = Rand(); - // seq_num , keyframe, first, last - InsertGeneric(seq_num , true , true , false); - InsertGeneric(seq_num + 2, true , false, true); - InsertGeneric(seq_num + 1, true , false, false); + // seq_num , kf, frst, lst + InsertGeneric(seq_num , kT, kT , kF); + InsertGeneric(seq_num + 2, kT, kF , kT); + InsertGeneric(seq_num + 1, kT, kF , kF); EXPECT_EQ(1UL, frames_from_callback_.size()); } @@ -270,10 +377,10 @@ TEST_F(TestPacketBuffer, GenericFrames) { InsertGeneric(seq_num + 3, false, true , true); ASSERT_EQ(4UL, frames_from_callback_.size()); - CheckReferences(seq_num); - CheckReferences(seq_num + 1, seq_num); - CheckReferences(seq_num + 2, seq_num + 1); - CheckReferences(seq_num + 3, seq_num + 2); + CheckReferencesGeneric(seq_num); + CheckReferencesGeneric(seq_num + 1, seq_num); + CheckReferencesGeneric(seq_num + 2, seq_num + 1); + CheckReferencesGeneric(seq_num + 3, seq_num + 2); } TEST_F(TestPacketBuffer, GenericFramesReordered) { @@ -286,10 +393,10 @@ TEST_F(TestPacketBuffer, GenericFramesReordered) { InsertGeneric(seq_num + 2, false, true , true); ASSERT_EQ(4UL, frames_from_callback_.size()); - CheckReferences(seq_num); - CheckReferences(seq_num + 1, seq_num); - CheckReferences(seq_num + 2, seq_num + 1); - CheckReferences(seq_num + 3, seq_num + 2); + CheckReferencesGeneric(seq_num); + CheckReferencesGeneric(seq_num + 1, seq_num); + CheckReferencesGeneric(seq_num + 2, seq_num + 1); + CheckReferencesGeneric(seq_num + 3, seq_num + 2); } TEST_F(TestPacketBuffer, GetBitstreamFromFrame) { @@ -304,15 +411,16 @@ TEST_F(TestPacketBuffer, GetBitstreamFromFrame) { uint16_t seq_num = Rand(); - // seq_num , keyf , first, last , data_size , data - InsertGeneric(seq_num , true , true , false, sizeof(many) , many); - InsertGeneric(seq_num + 1, false, false, false, sizeof(bitstream), bitstream); - InsertGeneric(seq_num + 2, false, false, false, sizeof(such) , such); - InsertGeneric(seq_num + 3, false, false, true , sizeof(data) , data); + // seq_num , kf, frst, lst, data_size , data + InsertGeneric(seq_num , kT, kT , kF , sizeof(many) , many); + InsertGeneric(seq_num + 1, kF, kF , kF , sizeof(bitstream), bitstream); + InsertGeneric(seq_num + 2, kF, kF , kF , sizeof(such) , such); + InsertGeneric(seq_num + 3, kF, kF , kT , sizeof(data) , data); ASSERT_EQ(1UL, frames_from_callback_.size()); - CheckReferences(seq_num + 3); - EXPECT_TRUE(frames_from_callback_[seq_num + 3]->GetBitstream(result)); + CheckReferencesVp8(seq_num + 3); + EXPECT_TRUE(frames_from_callback_[std::make_pair(seq_num + 3, 0)]-> + GetBitstream(result)); EXPECT_EQ(std::strcmp("many bitstream, such data", reinterpret_cast(result)), 0); @@ -321,36 +429,36 @@ TEST_F(TestPacketBuffer, GetBitstreamFromFrame) { TEST_F(TestPacketBuffer, FreeSlotsOnFrameDestruction) { uint16_t seq_num = Rand(); - // seq_num , keyf , first, last - InsertGeneric(seq_num , true , true , false); - InsertGeneric(seq_num + 1, false, false, false); - InsertGeneric(seq_num + 2, false, false, true); + // seq_num , kf, frst, lst + InsertGeneric(seq_num , kT, kT , kF); + InsertGeneric(seq_num + 1, kF, kF , kF); + InsertGeneric(seq_num + 2, kF, kF , kT); EXPECT_EQ(1UL, frames_from_callback_.size()); frames_from_callback_.clear(); - // seq_num , keyf , first, last - InsertGeneric(seq_num , true , true , false); - InsertGeneric(seq_num + 1, false, false, false); - InsertGeneric(seq_num + 2, false, false, true); + // seq_num , kf, frst, lst + InsertGeneric(seq_num , kT, kT , kF); + InsertGeneric(seq_num + 1, kF, kF , kF); + InsertGeneric(seq_num + 2, kF, kF , kT); EXPECT_EQ(1UL, frames_from_callback_.size()); } TEST_F(TestPacketBuffer, Flush) { uint16_t seq_num = Rand(); - // seq_num , keyf , first, last - InsertGeneric(seq_num , true , true , false); - InsertGeneric(seq_num + 1, false, false, false); - InsertGeneric(seq_num + 2, false, false, true); + // seq_num , kf, frst, lst + InsertGeneric(seq_num , kT, kT , kF); + InsertGeneric(seq_num + 1, kF, kF , kF); + InsertGeneric(seq_num + 2, kF, kF , kT); EXPECT_EQ(1UL, frames_from_callback_.size()); packet_buffer_->Flush(); - // seq_num , keyf , first, last - InsertGeneric(seq_num + kStartSize , true , true , false); - InsertGeneric(seq_num + kStartSize + 1, false, false, false); - InsertGeneric(seq_num + kStartSize + 2, false, false, true); + // seq_num , kf, frst, lst + InsertGeneric(seq_num + kStartSize , kT, kT , kF); + InsertGeneric(seq_num + kStartSize + 1, kF, kF , kF); + InsertGeneric(seq_num + kStartSize + 2, kF, kF , kT); EXPECT_EQ(2UL, frames_from_callback_.size()); } @@ -358,8 +466,8 @@ TEST_F(TestPacketBuffer, InvalidateFrameByFlushing) { VCMPacket packet; packet.codec = kVideoCodecGeneric; packet.frameType = kVideoFrameKey; - packet.isFirstPacket = true; - packet.markerBit = true; + packet.isFirstPacket = kT; + packet.markerBit = kT; packet.seqNum = Rand(); EXPECT_TRUE(packet_buffer_->InsertPacket(packet)); ASSERT_EQ(1UL, frames_from_callback_.size()); @@ -371,109 +479,109 @@ TEST_F(TestPacketBuffer, InvalidateFrameByFlushing) { TEST_F(TestPacketBuffer, Vp8NoPictureId) { uint16_t seq_num = Rand(); - // seq_num , keyf , first, last - InsertVp8(seq_num , true , true , false); - InsertVp8(seq_num + 1 , false, false, false); - InsertVp8(seq_num + 2 , false, false, true); + // seq_num , kf, frst, lst + InsertVp8(seq_num , kT, kT , kF); + InsertVp8(seq_num + 1 , kF, kF , kF); + InsertVp8(seq_num + 2 , kF, kF , kT); ASSERT_EQ(1UL, frames_from_callback_.size()); - InsertVp8(seq_num + 3 , false, true , false); - InsertVp8(seq_num + 4 , false, false, true); + InsertVp8(seq_num + 3 , kF, kT , kF); + InsertVp8(seq_num + 4 , kF, kF , kT); ASSERT_EQ(2UL, frames_from_callback_.size()); - InsertVp8(seq_num + 5 , false, true , false); - InsertVp8(seq_num + 6 , false, false, false); - InsertVp8(seq_num + 7 , false, false, false); - InsertVp8(seq_num + 8 , false, false, true); + InsertVp8(seq_num + 5 , kF, kT , kF); + InsertVp8(seq_num + 6 , kF, kF , kF); + InsertVp8(seq_num + 7 , kF, kF , kF); + InsertVp8(seq_num + 8 , kF, kF , kT); ASSERT_EQ(3UL, frames_from_callback_.size()); - InsertVp8(seq_num + 9 , false, true , true); + InsertVp8(seq_num + 9 , kF, kT , kT); ASSERT_EQ(4UL, frames_from_callback_.size()); - InsertVp8(seq_num + 10, false, true , false); - InsertVp8(seq_num + 11, false, false, true); + InsertVp8(seq_num + 10, kF, kT , kF); + InsertVp8(seq_num + 11, kF, kF , kT); ASSERT_EQ(5UL, frames_from_callback_.size()); - InsertVp8(seq_num + 12, true , true , true); + InsertVp8(seq_num + 12, kT, kT , kT); ASSERT_EQ(6UL, frames_from_callback_.size()); - InsertVp8(seq_num + 13, false, true , false); - InsertVp8(seq_num + 14, false, false, false); - InsertVp8(seq_num + 15, false, false, false); - InsertVp8(seq_num + 16, false, false, false); - InsertVp8(seq_num + 17, false, false, true); + InsertVp8(seq_num + 13, kF, kT , kF); + InsertVp8(seq_num + 14, kF, kF , kF); + InsertVp8(seq_num + 15, kF, kF , kF); + InsertVp8(seq_num + 16, kF, kF , kF); + InsertVp8(seq_num + 17, kF, kF , kT); ASSERT_EQ(7UL, frames_from_callback_.size()); - InsertVp8(seq_num + 18, false, true , true); + InsertVp8(seq_num + 18, kF, kT , kT); ASSERT_EQ(8UL, frames_from_callback_.size()); - InsertVp8(seq_num + 19, false, true , false); - InsertVp8(seq_num + 20, false, false, true); + InsertVp8(seq_num + 19, kF, kT , kF); + InsertVp8(seq_num + 20, kF, kF , kT); ASSERT_EQ(9UL, frames_from_callback_.size()); - InsertVp8(seq_num + 21, false, true , true); + InsertVp8(seq_num + 21, kF, kT , kT); ASSERT_EQ(10UL, frames_from_callback_.size()); - CheckReferences(seq_num + 2); - CheckReferences(seq_num + 4, seq_num + 2); - CheckReferences(seq_num + 8, seq_num + 4); - CheckReferences(seq_num + 9, seq_num + 8); - CheckReferences(seq_num + 11, seq_num + 9); - CheckReferences(seq_num + 12); - CheckReferences(seq_num + 17, seq_num + 12); - CheckReferences(seq_num + 18, seq_num + 17); - CheckReferences(seq_num + 20, seq_num + 18); - CheckReferences(seq_num + 21, seq_num + 20); + CheckReferencesVp8(seq_num + 2); + CheckReferencesVp8(seq_num + 4, seq_num + 2); + CheckReferencesVp8(seq_num + 8, seq_num + 4); + CheckReferencesVp8(seq_num + 9, seq_num + 8); + CheckReferencesVp8(seq_num + 11, seq_num + 9); + CheckReferencesVp8(seq_num + 12); + CheckReferencesVp8(seq_num + 17, seq_num + 12); + CheckReferencesVp8(seq_num + 18, seq_num + 17); + CheckReferencesVp8(seq_num + 20, seq_num + 18); + CheckReferencesVp8(seq_num + 21, seq_num + 20); } TEST_F(TestPacketBuffer, Vp8NoPictureIdReordered) { uint16_t seq_num = 0xfffa; - // seq_num , keyf , first, last - InsertVp8(seq_num + 1 , false, false, false); - InsertVp8(seq_num , true , true , false); - InsertVp8(seq_num + 2 , false, false, true); - InsertVp8(seq_num + 4 , false, false, true); - InsertVp8(seq_num + 6 , false, false, false); - InsertVp8(seq_num + 3 , false, true , false); - InsertVp8(seq_num + 7 , false, false, false); - InsertVp8(seq_num + 5 , false, true , false); - InsertVp8(seq_num + 9 , false, true , true); - InsertVp8(seq_num + 10, false, true , false); - InsertVp8(seq_num + 8 , false, false, true); - InsertVp8(seq_num + 13, false, true , false); - InsertVp8(seq_num + 14, false, false, false); - InsertVp8(seq_num + 12, true , true , true); - InsertVp8(seq_num + 11, false, false, true); - InsertVp8(seq_num + 16, false, false, false); - InsertVp8(seq_num + 19, false, true , false); - InsertVp8(seq_num + 15, false, false, false); - InsertVp8(seq_num + 17, false, false, true); - InsertVp8(seq_num + 20, false, false, true); - InsertVp8(seq_num + 21, false, true , true); - InsertVp8(seq_num + 18, false, true , true); + // seq_num , kf, frst, lst + InsertVp8(seq_num + 1 , kF, kF , kF); + InsertVp8(seq_num , kT, kT , kF); + InsertVp8(seq_num + 2 , kF, kF , kT); + InsertVp8(seq_num + 4 , kF, kF , kT); + InsertVp8(seq_num + 6 , kF, kF , kF); + InsertVp8(seq_num + 3 , kF, kT , kF); + InsertVp8(seq_num + 7 , kF, kF , kF); + InsertVp8(seq_num + 5 , kF, kT , kF); + InsertVp8(seq_num + 9 , kF, kT , kT); + InsertVp8(seq_num + 10, kF, kT , kF); + InsertVp8(seq_num + 8 , kF, kF , kT); + InsertVp8(seq_num + 13, kF, kT , kF); + InsertVp8(seq_num + 14, kF, kF , kF); + InsertVp8(seq_num + 12, kT, kT , kT); + InsertVp8(seq_num + 11, kF, kF , kT); + InsertVp8(seq_num + 16, kF, kF , kF); + InsertVp8(seq_num + 19, kF, kT , kF); + InsertVp8(seq_num + 15, kF, kF , kF); + InsertVp8(seq_num + 17, kF, kF , kT); + InsertVp8(seq_num + 20, kF, kF , kT); + InsertVp8(seq_num + 21, kF, kT , kT); + InsertVp8(seq_num + 18, kF, kT , kT); ASSERT_EQ(10UL, frames_from_callback_.size()); - CheckReferences(seq_num + 2); - CheckReferences(seq_num + 4, seq_num + 2); - CheckReferences(seq_num + 8, seq_num + 4); - CheckReferences(seq_num + 9, seq_num + 8); - CheckReferences(seq_num + 11, seq_num + 9); - CheckReferences(seq_num + 12); - CheckReferences(seq_num + 17, seq_num + 12); - CheckReferences(seq_num + 18, seq_num + 17); - CheckReferences(seq_num + 20, seq_num + 18); - CheckReferences(seq_num + 21, seq_num + 20); + CheckReferencesVp8(seq_num + 2); + CheckReferencesVp8(seq_num + 4, seq_num + 2); + CheckReferencesVp8(seq_num + 8, seq_num + 4); + CheckReferencesVp8(seq_num + 9, seq_num + 8); + CheckReferencesVp8(seq_num + 11, seq_num + 9); + CheckReferencesVp8(seq_num + 12); + CheckReferencesVp8(seq_num + 17, seq_num + 12); + CheckReferencesVp8(seq_num + 18, seq_num + 17); + CheckReferencesVp8(seq_num + 20, seq_num + 18); + CheckReferencesVp8(seq_num + 21, seq_num + 20); } TEST_F(TestPacketBuffer, Vp8KeyFrameReferences) { uint16_t pid = Rand(); - // seq_num, keyf, first, last, sync , pid, tid, tl0 - InsertVp8(Rand() , true, true , true, false, pid, 0 , 0); + // seq_num, kf, frst, lst, sync, pid, tid, tl0 + InsertVp8(Rand() , kT, kT , kT , kF , pid, 0 , 0); ASSERT_EQ(1UL, frames_from_callback_.size()); - CheckReferences(pid); + CheckReferencesVp8(pid); } // Test with 1 temporal layer. @@ -481,17 +589,17 @@ TEST_F(TestPacketBuffer, Vp8TemporalLayers_0) { uint16_t pid = Rand(); uint16_t seq_num = Rand(); - // seq_num , keyf , first, last, sync , pid , tid, tl0 - InsertVp8(seq_num , true , true , true, false, pid , 0 , 1); - InsertVp8(seq_num + 1, false, true , true, false, pid + 1, 0 , 2); - InsertVp8(seq_num + 2, false, true , true, false, pid + 2, 0 , 3); - InsertVp8(seq_num + 3, false, true , true, false, pid + 3, 0 , 4); + // seq_num , kf, frst, lst, sync, pid , tid, tl0 + InsertVp8(seq_num , kT, kT , kT , kF , pid , 0 , 1); + InsertVp8(seq_num + 1, kF, kT , kT , kF , pid + 1, 0 , 2); + InsertVp8(seq_num + 2, kF, kT , kT , kF , pid + 2, 0 , 3); + InsertVp8(seq_num + 3, kF, kT , kT , kF , pid + 3, 0 , 4); ASSERT_EQ(4UL, frames_from_callback_.size()); - CheckReferences(pid); - CheckReferences(pid + 1, pid); - CheckReferences(pid + 2, pid + 1); - CheckReferences(pid + 3, pid + 2); + CheckReferencesVp8(pid); + CheckReferencesVp8(pid + 1, pid); + CheckReferencesVp8(pid + 2, pid + 1); + CheckReferencesVp8(pid + 3, pid + 2); } // Test with 1 temporal layer. @@ -499,23 +607,23 @@ TEST_F(TestPacketBuffer, Vp8TemporalLayersReordering_0) { uint16_t pid = Rand(); uint16_t seq_num = Rand(); - // seq_num , keyf , first, last, sync , pid , tid, tl0 - InsertVp8(seq_num , true , true , true, false, pid , 0 , 1); - InsertVp8(seq_num + 1, false, true , true, false, pid + 1, 0 , 2); - InsertVp8(seq_num + 3, false, true , true, false, pid + 3, 0 , 4); - InsertVp8(seq_num + 2, false, true , true, false, pid + 2, 0 , 3); - InsertVp8(seq_num + 5, false, true , true, false, pid + 5, 0 , 6); - InsertVp8(seq_num + 6, false, true , true, false, pid + 6, 0 , 7); - InsertVp8(seq_num + 4, false, true , true, false, pid + 4, 0 , 5); + // seq_num , kf, frst, lst, sync, pid , tid, tl0 + InsertVp8(seq_num , kT, kT , kT , kF , pid , 0 , 1); + InsertVp8(seq_num + 1, kF, kT , kT , kF , pid + 1, 0 , 2); + InsertVp8(seq_num + 3, kF, kT , kT , kF , pid + 3, 0 , 4); + InsertVp8(seq_num + 2, kF, kT , kT , kF , pid + 2, 0 , 3); + InsertVp8(seq_num + 5, kF, kT , kT , kF , pid + 5, 0 , 6); + InsertVp8(seq_num + 6, kF, kT , kT , kF , pid + 6, 0 , 7); + InsertVp8(seq_num + 4, kF, kT , kT , kF , pid + 4, 0 , 5); ASSERT_EQ(7UL, frames_from_callback_.size()); - CheckReferences(pid); - CheckReferences(pid + 1, pid); - CheckReferences(pid + 2, pid + 1); - CheckReferences(pid + 3, pid + 2); - CheckReferences(pid + 4, pid + 3); - CheckReferences(pid + 5, pid + 4); - CheckReferences(pid + 6, pid + 5); + CheckReferencesVp8(pid); + CheckReferencesVp8(pid + 1, pid); + CheckReferencesVp8(pid + 2, pid + 1); + CheckReferencesVp8(pid + 3, pid + 2); + CheckReferencesVp8(pid + 4, pid + 3); + CheckReferencesVp8(pid + 5, pid + 4); + CheckReferencesVp8(pid + 6, pid + 5); } // Test with 2 temporal layers in a 01 pattern. @@ -523,17 +631,17 @@ TEST_F(TestPacketBuffer, Vp8TemporalLayers_01) { uint16_t pid = Rand(); uint16_t seq_num = Rand(); - // seq_num , keyf , first, last, sync , pid , tid, tl0 - InsertVp8(seq_num , true , true , true, false, pid , 0, 255); - InsertVp8(seq_num + 1, false, true , true, true , pid + 1, 1, 255); - InsertVp8(seq_num + 2, false, true , true, false, pid + 2, 0, 0); - InsertVp8(seq_num + 3, false, true , true, false, pid + 3, 1, 0); + // seq_num , kf, frst, lst, sync, pid , tid, tl0 + InsertVp8(seq_num , kT, kT , kT , kF , pid , 0, 255); + InsertVp8(seq_num + 1, kF, kT , kT , kT , pid + 1, 1, 255); + InsertVp8(seq_num + 2, kF, kT , kT , kF , pid + 2, 0, 0); + InsertVp8(seq_num + 3, kF, kT , kT , kF , pid + 3, 1, 0); ASSERT_EQ(4UL, frames_from_callback_.size()); - CheckReferences(pid); - CheckReferences(pid + 1, pid); - CheckReferences(pid + 2, pid); - CheckReferences(pid + 3, pid + 1, pid + 2); + CheckReferencesVp8(pid); + CheckReferencesVp8(pid + 1, pid); + CheckReferencesVp8(pid + 2, pid); + CheckReferencesVp8(pid + 3, pid + 1, pid + 2); } // Test with 2 temporal layers in a 01 pattern. @@ -541,25 +649,25 @@ TEST_F(TestPacketBuffer, Vp8TemporalLayersReordering_01) { uint16_t pid = Rand(); uint16_t seq_num = Rand(); - // seq_num , keyf , first, last, sync , pid , tid, tl0 - InsertVp8(seq_num + 1, false, true , true, true , pid + 1, 1 , 255); - InsertVp8(seq_num , true , true , true, false, pid , 0 , 255); - InsertVp8(seq_num + 3, false, true , true, false, pid + 3, 1 , 0); - InsertVp8(seq_num + 5, false, true , true, false, pid + 5, 1 , 1); - InsertVp8(seq_num + 2, false, true , true, false, pid + 2, 0 , 0); - InsertVp8(seq_num + 4, false, true , true, false, pid + 4, 0 , 1); - InsertVp8(seq_num + 6, false, true , true, false, pid + 6, 0 , 2); - InsertVp8(seq_num + 7, false, true , true, false, pid + 7, 1 , 2); + // seq_num , kf, frst, lst, sync, pid , tid, tl0 + InsertVp8(seq_num + 1, kF, kT , kT , kT , pid + 1, 1 , 255); + InsertVp8(seq_num , kT, kT , kT , kF , pid , 0 , 255); + InsertVp8(seq_num + 3, kF, kT , kT , kF , pid + 3, 1 , 0); + InsertVp8(seq_num + 5, kF, kT , kT , kF , pid + 5, 1 , 1); + InsertVp8(seq_num + 2, kF, kT , kT , kF , pid + 2, 0 , 0); + InsertVp8(seq_num + 4, kF, kT , kT , kF , pid + 4, 0 , 1); + InsertVp8(seq_num + 6, kF, kT , kT , kF , pid + 6, 0 , 2); + InsertVp8(seq_num + 7, kF, kT , kT , kF , pid + 7, 1 , 2); ASSERT_EQ(8UL, frames_from_callback_.size()); - CheckReferences(pid); - CheckReferences(pid + 1, pid); - CheckReferences(pid + 2, pid); - CheckReferences(pid + 3, pid + 1, pid + 2); - CheckReferences(pid + 4, pid + 2); - CheckReferences(pid + 5, pid + 3, pid + 4); - CheckReferences(pid + 6, pid + 4); - CheckReferences(pid + 7, pid + 5, pid + 6); + CheckReferencesVp8(pid); + CheckReferencesVp8(pid + 1, pid); + CheckReferencesVp8(pid + 2, pid); + CheckReferencesVp8(pid + 3, pid + 1, pid + 2); + CheckReferencesVp8(pid + 4, pid + 2); + CheckReferencesVp8(pid + 5, pid + 3, pid + 4); + CheckReferencesVp8(pid + 6, pid + 4); + CheckReferencesVp8(pid + 7, pid + 5, pid + 6); } // Test with 3 temporal layers in a 0212 pattern. @@ -567,33 +675,33 @@ TEST_F(TestPacketBuffer, Vp8TemporalLayers_0212) { uint16_t pid = Rand(); uint16_t seq_num = Rand(); - // seq_num , keyf , first, last, sync , pid , tid, tl0 - InsertVp8(seq_num , true , true , true , false, pid , 0 , 55); - InsertVp8(seq_num + 1 , false, true , true , true , pid + 1 , 2 , 55); - InsertVp8(seq_num + 2 , false, true , true , true , pid + 2 , 1 , 55); - InsertVp8(seq_num + 3 , false, true , true , false, pid + 3 , 2 , 55); - InsertVp8(seq_num + 4 , false, true , true , false, pid + 4 , 0 , 56); - InsertVp8(seq_num + 5 , false, true , true , false, pid + 5 , 2 , 56); - InsertVp8(seq_num + 6 , false, true , true , false, pid + 6 , 1 , 56); - InsertVp8(seq_num + 7 , false, true , true , false, pid + 7 , 2 , 56); - InsertVp8(seq_num + 8 , false, true , true , false, pid + 8 , 0 , 57); - InsertVp8(seq_num + 9 , false, true , true , true , pid + 9 , 2 , 57); - InsertVp8(seq_num + 10, false, true , true , true , pid + 10, 1 , 57); - InsertVp8(seq_num + 11, false, true , true , false, pid + 11, 2 , 57); + // seq_num , kf, frst, lst, sync, pid , tid, tl0 + InsertVp8(seq_num , kT, kT , kT , kF , pid , 0 , 55); + InsertVp8(seq_num + 1 , kF, kT , kT , kT , pid + 1 , 2 , 55); + InsertVp8(seq_num + 2 , kF, kT , kT , kT , pid + 2 , 1 , 55); + InsertVp8(seq_num + 3 , kF, kT , kT , kF , pid + 3 , 2 , 55); + InsertVp8(seq_num + 4 , kF, kT , kT , kF , pid + 4 , 0 , 56); + InsertVp8(seq_num + 5 , kF, kT , kT , kF , pid + 5 , 2 , 56); + InsertVp8(seq_num + 6 , kF, kT , kT , kF , pid + 6 , 1 , 56); + InsertVp8(seq_num + 7 , kF, kT , kT , kF , pid + 7 , 2 , 56); + InsertVp8(seq_num + 8 , kF, kT , kT , kF , pid + 8 , 0 , 57); + InsertVp8(seq_num + 9 , kF, kT , kT , kT , pid + 9 , 2 , 57); + InsertVp8(seq_num + 10, kF, kT , kT , kT , pid + 10, 1 , 57); + InsertVp8(seq_num + 11, kF, kT , kT , kF , pid + 11, 2 , 57); ASSERT_EQ(12UL, frames_from_callback_.size()); - CheckReferences(pid); - CheckReferences(pid + 1 , pid); - CheckReferences(pid + 2 , pid); - CheckReferences(pid + 3 , pid, pid + 1, pid + 2); - CheckReferences(pid + 4 , pid); - CheckReferences(pid + 5 , pid + 2, pid + 3, pid + 4); - CheckReferences(pid + 6 , pid + 2, pid + 4); - CheckReferences(pid + 7 , pid + 4, pid + 5, pid + 6); - CheckReferences(pid + 8 , pid + 4); - CheckReferences(pid + 9 , pid + 8); - CheckReferences(pid + 10, pid + 8); - CheckReferences(pid + 11, pid + 8, pid + 9, pid + 10); + CheckReferencesVp8(pid); + CheckReferencesVp8(pid + 1 , pid); + CheckReferencesVp8(pid + 2 , pid); + CheckReferencesVp8(pid + 3 , pid, pid + 1, pid + 2); + CheckReferencesVp8(pid + 4 , pid); + CheckReferencesVp8(pid + 5 , pid + 2, pid + 3, pid + 4); + CheckReferencesVp8(pid + 6 , pid + 2, pid + 4); + CheckReferencesVp8(pid + 7 , pid + 4, pid + 5, pid + 6); + CheckReferencesVp8(pid + 8 , pid + 4); + CheckReferencesVp8(pid + 9 , pid + 8); + CheckReferencesVp8(pid + 10, pid + 8); + CheckReferencesVp8(pid + 11, pid + 8, pid + 9, pid + 10); } // Test with 3 temporal layers in a 0212 pattern. @@ -601,33 +709,33 @@ TEST_F(TestPacketBuffer, Vp8TemporalLayersReordering_0212) { uint16_t pid = 126; uint16_t seq_num = Rand(); - // seq_num , keyf , first, last, sync , pid , tid, tl0 - InsertVp8(seq_num + 1 , false, true , true, true , pid + 1 , 2 , 55); - InsertVp8(seq_num , true , true , true, false, pid , 0 , 55); - InsertVp8(seq_num + 2 , false, true , true, true , pid + 2 , 1 , 55); - InsertVp8(seq_num + 4 , false, true , true, false, pid + 4 , 0 , 56); - InsertVp8(seq_num + 5 , false, true , true, false, pid + 5 , 2 , 56); - InsertVp8(seq_num + 3 , false, true , true, false, pid + 3 , 2 , 55); - InsertVp8(seq_num + 7 , false, true , true, false, pid + 7 , 2 , 56); - InsertVp8(seq_num + 9 , false, true , true, true , pid + 9 , 2 , 57); - InsertVp8(seq_num + 6 , false, true , true, false, pid + 6 , 1 , 56); - InsertVp8(seq_num + 8 , false, true , true, false, pid + 8 , 0 , 57); - InsertVp8(seq_num + 11, false, true , true, false, pid + 11, 2 , 57); - InsertVp8(seq_num + 10, false, true , true, true , pid + 10, 1 , 57); + // seq_num , kf, frst, lst, sync, pid , tid, tl0 + InsertVp8(seq_num + 1 , kF, kT , kT , kT , pid + 1 , 2 , 55); + InsertVp8(seq_num , kT, kT , kT , kF , pid , 0 , 55); + InsertVp8(seq_num + 2 , kF, kT , kT , kT , pid + 2 , 1 , 55); + InsertVp8(seq_num + 4 , kF, kT , kT , kF , pid + 4 , 0 , 56); + InsertVp8(seq_num + 5 , kF, kT , kT , kF , pid + 5 , 2 , 56); + InsertVp8(seq_num + 3 , kF, kT , kT , kF , pid + 3 , 2 , 55); + InsertVp8(seq_num + 7 , kF, kT , kT , kF , pid + 7 , 2 , 56); + InsertVp8(seq_num + 9 , kF, kT , kT , kT , pid + 9 , 2 , 57); + InsertVp8(seq_num + 6 , kF, kT , kT , kF , pid + 6 , 1 , 56); + InsertVp8(seq_num + 8 , kF, kT , kT , kF , pid + 8 , 0 , 57); + InsertVp8(seq_num + 11, kF, kT , kT , kF , pid + 11, 2 , 57); + InsertVp8(seq_num + 10, kF, kT , kT , kT , pid + 10, 1 , 57); ASSERT_EQ(12UL, frames_from_callback_.size()); - CheckReferences(pid); - CheckReferences(pid + 1 , pid); - CheckReferences(pid + 2 , pid); - CheckReferences(pid + 3 , pid, pid + 1, pid + 2); - CheckReferences(pid + 4 , pid); - CheckReferences(pid + 5 , pid + 2, pid + 3, pid + 4); - CheckReferences(pid + 6 , pid + 2, pid + 4); - CheckReferences(pid + 7 , pid + 4, pid + 5, pid + 6); - CheckReferences(pid + 8 , pid + 4); - CheckReferences(pid + 9 , pid + 8); - CheckReferences(pid + 10, pid + 8); - CheckReferences(pid + 11, pid + 8, pid + 9, pid + 10); + CheckReferencesVp8(pid); + CheckReferencesVp8(pid + 1 , pid); + CheckReferencesVp8(pid + 2 , pid); + CheckReferencesVp8(pid + 3 , pid, pid + 1, pid + 2); + CheckReferencesVp8(pid + 4 , pid); + CheckReferencesVp8(pid + 5 , pid + 2, pid + 3, pid + 4); + CheckReferencesVp8(pid + 6 , pid + 2, pid + 4); + CheckReferencesVp8(pid + 7 , pid + 4, pid + 5, pid + 6); + CheckReferencesVp8(pid + 8 , pid + 4); + CheckReferencesVp8(pid + 9 , pid + 8); + CheckReferencesVp8(pid + 10, pid + 8); + CheckReferencesVp8(pid + 11, pid + 8, pid + 9, pid + 10); } TEST_F(TestPacketBuffer, Vp8InsertManyFrames_0212) { @@ -639,15 +747,15 @@ TEST_F(TestPacketBuffer, Vp8InsertManyFrames_0212) { uint8_t tl0 = 128; for (int k = 0; k < keyframes_to_insert; ++k) { - // seq_num , keyf , first, last , sync , pid , tid, tl0 - InsertVp8(seq_num , true , true , true , false, pid , 0 , tl0); - InsertVp8(seq_num + 1, false, true , true , true , pid + 1, 2 , tl0); - InsertVp8(seq_num + 2, false, true , true , true , pid + 2, 1 , tl0); - InsertVp8(seq_num + 3, false, true , true , false, pid + 3, 2 , tl0); - CheckReferences(pid); - CheckReferences(pid + 1, pid); - CheckReferences(pid + 2, pid); - CheckReferences(pid + 3, pid, pid + 1, pid + 2); + // seq_num , keyf, frst, lst, sync, pid , tid, tl0 + InsertVp8(seq_num , kT , kT , kT , kF , pid , 0 , tl0); + InsertVp8(seq_num + 1, kF , kT , kT , kT , pid + 1, 2 , tl0); + InsertVp8(seq_num + 2, kF , kT , kT , kT , pid + 2, 1 , tl0); + InsertVp8(seq_num + 3, kF , kT , kT , kF , pid + 3, 2 , tl0); + CheckReferencesVp8(pid); + CheckReferencesVp8(pid + 1, pid); + CheckReferencesVp8(pid + 2, pid); + CheckReferencesVp8(pid + 3, pid, pid + 1, pid + 2); frames_from_callback_.clear(); ++tl0; @@ -655,15 +763,15 @@ TEST_F(TestPacketBuffer, Vp8InsertManyFrames_0212) { uint16_t sf = seq_num + f; uint16_t pidf = pid + f; - // seq_num, keyf , first, last, sync , pid , tid, tl0 - InsertVp8(sf , false, true , true, false, pidf , 0 , tl0); - InsertVp8(sf + 1 , false, true , true, false, pidf + 1, 2 , tl0); - InsertVp8(sf + 2 , false, true , true, false, pidf + 2, 1 , tl0); - InsertVp8(sf + 3 , false, true , true, false, pidf + 3, 2 , tl0); - CheckReferences(pidf, pidf - 4); - CheckReferences(pidf + 1, pidf, pidf - 1, pidf - 2); - CheckReferences(pidf + 2, pidf, pidf - 2); - CheckReferences(pidf + 3, pidf, pidf + 1, pidf + 2); + // seq_num, keyf, frst, lst, sync, pid , tid, tl0 + InsertVp8(sf , kF , kT , kT , kF , pidf , 0 , tl0); + InsertVp8(sf + 1 , kF , kT , kT , kF , pidf + 1, 2 , tl0); + InsertVp8(sf + 2 , kF , kT , kT , kF , pidf + 2, 1 , tl0); + InsertVp8(sf + 3 , kF , kT , kT , kF , pidf + 3, 2 , tl0); + CheckReferencesVp8(pidf, pidf - 4); + CheckReferencesVp8(pidf + 1, pidf, pidf - 1, pidf - 2); + CheckReferencesVp8(pidf + 2, pidf, pidf - 2); + CheckReferencesVp8(pidf + 3, pidf, pidf + 1, pidf + 2); frames_from_callback_.clear(); ++tl0; } @@ -677,25 +785,25 @@ TEST_F(TestPacketBuffer, Vp8LayerSync) { uint16_t pid = Rand(); uint16_t seq_num = Rand(); - // seq_num , keyf , first, last, sync , pid , tid, tl0 - InsertVp8(seq_num , true , true , true, false, pid , 0 , 0); - InsertVp8(seq_num + 1 , false, true , true, true , pid + 1 , 1 , 0); - InsertVp8(seq_num + 2 , false, true , true, false, pid + 2 , 0 , 1); + // seq_num , keyf, frst, lst, sync, pid , tid, tl0 + InsertVp8(seq_num , kT , kT , kT , kF , pid , 0 , 0); + InsertVp8(seq_num + 1 , kF , kT , kT , kT , pid + 1 , 1 , 0); + InsertVp8(seq_num + 2 , kF , kT , kT , kF , pid + 2 , 0 , 1); ASSERT_EQ(3UL, frames_from_callback_.size()); - InsertVp8(seq_num + 4 , false, true , true, false, pid + 4 , 0 , 2); - InsertVp8(seq_num + 5 , false, true , true, true , pid + 5 , 1 , 2); - InsertVp8(seq_num + 6 , false, true , true, false, pid + 6 , 0 , 3); - InsertVp8(seq_num + 7 , false, true , true, false, pid + 7 , 1 , 3); + InsertVp8(seq_num + 4 , kF , kT , kT , kF , pid + 4 , 0 , 2); + InsertVp8(seq_num + 5 , kF , kT , kT , kT , pid + 5 , 1 , 2); + InsertVp8(seq_num + 6 , kF , kT , kT , kF , pid + 6 , 0 , 3); + InsertVp8(seq_num + 7 , kF , kT , kT , kF , pid + 7 , 1 , 3); ASSERT_EQ(7UL, frames_from_callback_.size()); - CheckReferences(pid); - CheckReferences(pid + 1, pid); - CheckReferences(pid + 2, pid); - CheckReferences(pid + 4, pid + 2); - CheckReferences(pid + 5, pid + 4); - CheckReferences(pid + 6, pid + 4); - CheckReferences(pid + 7, pid + 6, pid + 5); + CheckReferencesVp8(pid); + CheckReferencesVp8(pid + 1, pid); + CheckReferencesVp8(pid + 2, pid); + CheckReferencesVp8(pid + 4, pid + 2); + CheckReferencesVp8(pid + 5, pid + 4); + CheckReferencesVp8(pid + 6, pid + 4); + CheckReferencesVp8(pid + 7, pid + 6, pid + 5); } TEST_F(TestPacketBuffer, Vp8InsertLargeFrames) { @@ -707,26 +815,591 @@ TEST_F(TestPacketBuffer, Vp8InsertLargeFrames) { uint16_t current = seq_num; uint16_t end = current + packets_per_frame; - // seq_num , keyf , first, last , sync , pid, tid, tl0 - InsertVp8(current++, true , true , false, false, pid, 0 , 0); + // seq_num , keyf, frst, lst, sync, pid, tid, tl0 + InsertVp8(current++, kT , kT , kF , kF , pid, 0 , 0); while (current != end) - InsertVp8(current++, false, false, false, false, pid, 0 , 0); - InsertVp8(current++, false, false, true , false, pid, 0 , 0); + InsertVp8(current++, kF , kF , kF , kF , pid, 0 , 0); + InsertVp8(current++, kF , kF , kT , kF , pid, 0 , 0); end = current + packets_per_frame; for (int f = 1; f < 4; ++f) { - InsertVp8(current++, false, true , false, false, pid + f, 0, f); + InsertVp8(current++, kF , kT , kF , kF , pid + f, 0, f); while (current != end) - InsertVp8(current++, false, false, false, false, pid + f, 0, f); - InsertVp8(current++, false, false, true , false, pid + f, 0, f); + InsertVp8(current++, kF , kF , kF , kF , pid + f, 0, f); + InsertVp8(current++, kF , kF , kT , kF , pid + f, 0, f); end = current + packets_per_frame; } ASSERT_EQ(4UL, frames_from_callback_.size()); - CheckReferences(pid); - CheckReferences(pid + 1, pid); - CheckReferences(pid + 2, pid + 1); - CheckReferences(pid + 3, pid + 2); + CheckReferencesVp8(pid); + CheckReferencesVp8(pid + 1, pid); + CheckReferencesVp8(pid + 2, pid + 1); + CheckReferencesVp8(pid + 3, pid + 2); +} + +TEST_F(TestPacketBuffer, Vp9GofInsertOneFrame) { + uint16_t pid = Rand(); + uint16_t seq_num = Rand(); + GofInfoVP9 ss; + ss.SetGofInfoVP9(kTemporalStructureMode1); + + // seq_num, keyf, frst, lst, up, pid, sid, tid, tl0, ss + InsertVp9Gof(seq_num, kT , kT , kT , kF, pid, 0 , 0 , 0 , &ss); + + CheckReferencesVp9(pid, 0); +} + +TEST_F(TestPacketBuffer, Vp9NoPictureIdReordered) { + uint16_t sn = 0xfffa; + + // sn , kf, frst, lst + InsertVp9Gof(sn + 1 , kF, kF , kF); + InsertVp9Gof(sn , kT, kT , kF); + InsertVp9Gof(sn + 2 , kF, kF , kT); + InsertVp9Gof(sn + 4 , kF, kF , kT); + InsertVp9Gof(sn + 6 , kF, kF , kF); + InsertVp9Gof(sn + 3 , kF, kT , kF); + InsertVp9Gof(sn + 7 , kF, kF , kF); + InsertVp9Gof(sn + 5 , kF, kT , kF); + InsertVp9Gof(sn + 9 , kF, kT , kT); + InsertVp9Gof(sn + 10, kF, kT , kF); + InsertVp9Gof(sn + 8 , kF, kF , kT); + InsertVp9Gof(sn + 13, kF, kT , kF); + InsertVp9Gof(sn + 14, kF, kF , kF); + InsertVp9Gof(sn + 12, kT, kT , kT); + InsertVp9Gof(sn + 11, kF, kF , kT); + InsertVp9Gof(sn + 16, kF, kF , kF); + InsertVp9Gof(sn + 19, kF, kT , kF); + InsertVp9Gof(sn + 15, kF, kF , kF); + InsertVp9Gof(sn + 17, kF, kF , kT); + InsertVp9Gof(sn + 20, kF, kF , kT); + InsertVp9Gof(sn + 21, kF, kT , kT); + InsertVp9Gof(sn + 18, kF, kT , kT); + + ASSERT_EQ(10UL, frames_from_callback_.size()); + CheckReferencesVp9(sn + 2 , 0); + CheckReferencesVp9(sn + 4 , 0, sn + 2); + CheckReferencesVp9(sn + 8 , 0, sn + 4); + CheckReferencesVp9(sn + 9 , 0, sn + 8); + CheckReferencesVp9(sn + 11, 0, sn + 9); + CheckReferencesVp9(sn + 12, 0); + CheckReferencesVp9(sn + 17, 0, sn + 12); + CheckReferencesVp9(sn + 18, 0, sn + 17); + CheckReferencesVp9(sn + 20, 0, sn + 18); + CheckReferencesVp9(sn + 21, 0, sn + 20); +} + +TEST_F(TestPacketBuffer, Vp9GofTemporalLayers_0) { + uint16_t pid = Rand(); + uint16_t sn = Rand(); + GofInfoVP9 ss; + ss.SetGofInfoVP9(kTemporalStructureMode1); // Only 1 spatial layer. + + // sn , kf, frst, lst, up, pid , sid, tid, tl0, ss + InsertVp9Gof(sn , kT, kT , kT , kF, pid , 0 , 0 , 0 , &ss); + InsertVp9Gof(sn + 1 , kF, kT , kT , kF, pid + 1 , 0 , 0 , 1); + InsertVp9Gof(sn + 2 , kF, kT , kT , kF, pid + 2 , 0 , 0 , 2); + InsertVp9Gof(sn + 3 , kF, kT , kT , kF, pid + 3 , 0 , 0 , 3); + InsertVp9Gof(sn + 4 , kF, kT , kT , kF, pid + 4 , 0 , 0 , 4); + InsertVp9Gof(sn + 5 , kF, kT , kT , kF, pid + 5 , 0 , 0 , 5); + InsertVp9Gof(sn + 6 , kF, kT , kT , kF, pid + 6 , 0 , 0 , 6); + InsertVp9Gof(sn + 7 , kF, kT , kT , kF, pid + 7 , 0 , 0 , 7); + InsertVp9Gof(sn + 8 , kF, kT , kT , kF, pid + 8 , 0 , 0 , 8); + InsertVp9Gof(sn + 9 , kF, kT , kT , kF, pid + 9 , 0 , 0 , 9); + InsertVp9Gof(sn + 10, kF, kT , kT , kF, pid + 10, 0 , 0 , 10); + InsertVp9Gof(sn + 11, kF, kT , kT , kF, pid + 11, 0 , 0 , 11); + InsertVp9Gof(sn + 12, kF, kT , kT , kF, pid + 12, 0 , 0 , 12); + InsertVp9Gof(sn + 13, kF, kT , kT , kF, pid + 13, 0 , 0 , 13); + InsertVp9Gof(sn + 14, kF, kT , kT , kF, pid + 14, 0 , 0 , 14); + InsertVp9Gof(sn + 15, kF, kT , kT , kF, pid + 15, 0 , 0 , 15); + InsertVp9Gof(sn + 16, kF, kT , kT , kF, pid + 16, 0 , 0 , 16); + InsertVp9Gof(sn + 17, kF, kT , kT , kF, pid + 17, 0 , 0 , 17); + InsertVp9Gof(sn + 18, kF, kT , kT , kF, pid + 18, 0 , 0 , 18); + InsertVp9Gof(sn + 19, kF, kT , kT , kF, pid + 19, 0 , 0 , 19); + + ASSERT_EQ(20UL, frames_from_callback_.size()); + CheckReferencesVp9(pid, 0); + CheckReferencesVp9(pid + 1 , 0, pid); + CheckReferencesVp9(pid + 2 , 0, pid + 1); + CheckReferencesVp9(pid + 3 , 0, pid + 2); + CheckReferencesVp9(pid + 4 , 0, pid + 3); + CheckReferencesVp9(pid + 5 , 0, pid + 4); + CheckReferencesVp9(pid + 6 , 0, pid + 5); + CheckReferencesVp9(pid + 7 , 0, pid + 6); + CheckReferencesVp9(pid + 8 , 0, pid + 7); + CheckReferencesVp9(pid + 9 , 0, pid + 8); + CheckReferencesVp9(pid + 10, 0, pid + 9); + CheckReferencesVp9(pid + 11, 0, pid + 10); + CheckReferencesVp9(pid + 12, 0, pid + 11); + CheckReferencesVp9(pid + 13, 0, pid + 12); + CheckReferencesVp9(pid + 14, 0, pid + 13); + CheckReferencesVp9(pid + 15, 0, pid + 14); + CheckReferencesVp9(pid + 16, 0, pid + 15); + CheckReferencesVp9(pid + 17, 0, pid + 16); + CheckReferencesVp9(pid + 18, 0, pid + 17); + CheckReferencesVp9(pid + 19, 0, pid + 18); +} + +TEST_F(TestPacketBuffer, Vp9GofTemporalLayersReordered_0) { + uint16_t pid = Rand(); + uint16_t sn = Rand(); + GofInfoVP9 ss; + ss.SetGofInfoVP9(kTemporalStructureMode1); // Only 1 spatial layer. + + // sn , kf, frst, lst, up, pid , sid, tid, tl0, ss + InsertVp9Gof(sn + 2 , kF, kT , kT , kF, pid + 2 , 0 , 0 , 2); + InsertVp9Gof(sn + 1 , kF, kT , kT , kF, pid + 1 , 0 , 0 , 1); + InsertVp9Gof(sn , kT, kT , kT , kF, pid , 0 , 0 , 0 , &ss); + InsertVp9Gof(sn + 4 , kF, kT , kT , kF, pid + 4 , 0 , 0 , 4); + InsertVp9Gof(sn + 3 , kF, kT , kT , kF, pid + 3 , 0 , 0 , 3); + InsertVp9Gof(sn + 5 , kF, kT , kT , kF, pid + 5 , 0 , 0 , 5); + InsertVp9Gof(sn + 7 , kF, kT , kT , kF, pid + 7 , 0 , 0 , 7); + InsertVp9Gof(sn + 6 , kF, kT , kT , kF, pid + 6 , 0 , 0 , 6); + InsertVp9Gof(sn + 8 , kF, kT , kT , kF, pid + 8 , 0 , 0 , 8); + InsertVp9Gof(sn + 10, kF, kT , kT , kF, pid + 10, 0 , 0 , 10); + InsertVp9Gof(sn + 13, kF, kT , kT , kF, pid + 13, 0 , 0 , 13); + InsertVp9Gof(sn + 11, kF, kT , kT , kF, pid + 11, 0 , 0 , 11); + InsertVp9Gof(sn + 9 , kF, kT , kT , kF, pid + 9 , 0 , 0 , 9); + InsertVp9Gof(sn + 16, kF, kT , kT , kF, pid + 16, 0 , 0 , 16); + InsertVp9Gof(sn + 14, kF, kT , kT , kF, pid + 14, 0 , 0 , 14); + InsertVp9Gof(sn + 15, kF, kT , kT , kF, pid + 15, 0 , 0 , 15); + InsertVp9Gof(sn + 12, kF, kT , kT , kF, pid + 12, 0 , 0 , 12); + InsertVp9Gof(sn + 17, kF, kT , kT , kF, pid + 17, 0 , 0 , 17); + InsertVp9Gof(sn + 19, kF, kT , kT , kF, pid + 19, 0 , 0 , 19); + InsertVp9Gof(sn + 18, kF, kT , kT , kF, pid + 18, 0 , 0 , 18); + + ASSERT_EQ(20UL, frames_from_callback_.size()); + CheckReferencesVp9(pid, 0); + CheckReferencesVp9(pid + 1 , 0, pid); + CheckReferencesVp9(pid + 2 , 0, pid + 1); + CheckReferencesVp9(pid + 3 , 0, pid + 2); + CheckReferencesVp9(pid + 4 , 0, pid + 3); + CheckReferencesVp9(pid + 5 , 0, pid + 4); + CheckReferencesVp9(pid + 6 , 0, pid + 5); + CheckReferencesVp9(pid + 7 , 0, pid + 6); + CheckReferencesVp9(pid + 8 , 0, pid + 7); + CheckReferencesVp9(pid + 9 , 0, pid + 8); + CheckReferencesVp9(pid + 10, 0, pid + 9); + CheckReferencesVp9(pid + 11, 0, pid + 10); + CheckReferencesVp9(pid + 12, 0, pid + 11); + CheckReferencesVp9(pid + 13, 0, pid + 12); + CheckReferencesVp9(pid + 14, 0, pid + 13); + CheckReferencesVp9(pid + 15, 0, pid + 14); + CheckReferencesVp9(pid + 16, 0, pid + 15); + CheckReferencesVp9(pid + 17, 0, pid + 16); + CheckReferencesVp9(pid + 18, 0, pid + 17); + CheckReferencesVp9(pid + 19, 0, pid + 18); +} + +TEST_F(TestPacketBuffer, Vp9GofTemporalLayers_01) { + uint16_t pid = Rand(); + uint16_t sn = Rand(); + GofInfoVP9 ss; + ss.SetGofInfoVP9(kTemporalStructureMode2); // 0101 pattern + + // sn , kf, frst, lst, up, pid , sid, tid, tl0, ss + InsertVp9Gof(sn , kT, kT , kT , kF, pid , 0 , 0 , 0 , &ss); + InsertVp9Gof(sn + 1 , kF, kT , kT , kF, pid + 1 , 0 , 1 , 0); + InsertVp9Gof(sn + 2 , kF, kT , kT , kF, pid + 2 , 0 , 0 , 1); + InsertVp9Gof(sn + 3 , kF, kT , kT , kF, pid + 3 , 0 , 1 , 1); + InsertVp9Gof(sn + 4 , kF, kT , kT , kF, pid + 4 , 0 , 0 , 2); + InsertVp9Gof(sn + 5 , kF, kT , kT , kF, pid + 5 , 0 , 1 , 2); + InsertVp9Gof(sn + 6 , kF, kT , kT , kF, pid + 6 , 0 , 0 , 3); + InsertVp9Gof(sn + 7 , kF, kT , kT , kF, pid + 7 , 0 , 1 , 3); + InsertVp9Gof(sn + 8 , kF, kT , kT , kF, pid + 8 , 0 , 0 , 4); + InsertVp9Gof(sn + 9 , kF, kT , kT , kF, pid + 9 , 0 , 1 , 4); + InsertVp9Gof(sn + 10, kF, kT , kT , kF, pid + 10, 0 , 0 , 5); + InsertVp9Gof(sn + 11, kF, kT , kT , kF, pid + 11, 0 , 1 , 5); + InsertVp9Gof(sn + 12, kF, kT , kT , kF, pid + 12, 0 , 0 , 6); + InsertVp9Gof(sn + 13, kF, kT , kT , kF, pid + 13, 0 , 1 , 6); + InsertVp9Gof(sn + 14, kF, kT , kT , kF, pid + 14, 0 , 0 , 7); + InsertVp9Gof(sn + 15, kF, kT , kT , kF, pid + 15, 0 , 1 , 7); + InsertVp9Gof(sn + 16, kF, kT , kT , kF, pid + 16, 0 , 0 , 8); + InsertVp9Gof(sn + 17, kF, kT , kT , kF, pid + 17, 0 , 1 , 8); + InsertVp9Gof(sn + 18, kF, kT , kT , kF, pid + 18, 0 , 0 , 9); + InsertVp9Gof(sn + 19, kF, kT , kT , kF, pid + 19, 0 , 1 , 9); + + ASSERT_EQ(20UL, frames_from_callback_.size()); + CheckReferencesVp9(pid, 0); + CheckReferencesVp9(pid + 1 , 0, pid); + CheckReferencesVp9(pid + 2 , 0, pid); + CheckReferencesVp9(pid + 3 , 0, pid + 2); + CheckReferencesVp9(pid + 4 , 0, pid + 2); + CheckReferencesVp9(pid + 5 , 0, pid + 4); + CheckReferencesVp9(pid + 6 , 0, pid + 4); + CheckReferencesVp9(pid + 7 , 0, pid + 6); + CheckReferencesVp9(pid + 8 , 0, pid + 6); + CheckReferencesVp9(pid + 9 , 0, pid + 8); + CheckReferencesVp9(pid + 10, 0, pid + 8); + CheckReferencesVp9(pid + 11, 0, pid + 10); + CheckReferencesVp9(pid + 12, 0, pid + 10); + CheckReferencesVp9(pid + 13, 0, pid + 12); + CheckReferencesVp9(pid + 14, 0, pid + 12); + CheckReferencesVp9(pid + 15, 0, pid + 14); + CheckReferencesVp9(pid + 16, 0, pid + 14); + CheckReferencesVp9(pid + 17, 0, pid + 16); + CheckReferencesVp9(pid + 18, 0, pid + 16); + CheckReferencesVp9(pid + 19, 0, pid + 18); +} + +TEST_F(TestPacketBuffer, Vp9GofTemporalLayersReordered_01) { + uint16_t pid = Rand(); + uint16_t sn = Rand(); + GofInfoVP9 ss; + ss.SetGofInfoVP9(kTemporalStructureMode2); // 01 pattern + + // sn , kf, frst, lst, up, pid , sid, tid, tl0, ss + InsertVp9Gof(sn + 1 , kF, kT , kT , kF, pid + 1 , 0 , 1 , 0); + InsertVp9Gof(sn , kT, kT , kT , kF, pid , 0 , 0 , 0 , &ss); + InsertVp9Gof(sn + 2 , kF, kT , kT , kF, pid + 2 , 0 , 0 , 1); + InsertVp9Gof(sn + 4 , kF, kT , kT , kF, pid + 4 , 0 , 0 , 2); + InsertVp9Gof(sn + 3 , kF, kT , kT , kF, pid + 3 , 0 , 1 , 1); + InsertVp9Gof(sn + 5 , kF, kT , kT , kF, pid + 5 , 0 , 1 , 2); + InsertVp9Gof(sn + 7 , kF, kT , kT , kF, pid + 7 , 0 , 1 , 3); + InsertVp9Gof(sn + 6 , kF, kT , kT , kF, pid + 6 , 0 , 0 , 3); + InsertVp9Gof(sn + 10, kF, kT , kT , kF, pid + 10, 0 , 0 , 5); + InsertVp9Gof(sn + 8 , kF, kT , kT , kF, pid + 8 , 0 , 0 , 4); + InsertVp9Gof(sn + 9 , kF, kT , kT , kF, pid + 9 , 0 , 1 , 4); + InsertVp9Gof(sn + 11, kF, kT , kT , kF, pid + 11, 0 , 1 , 5); + InsertVp9Gof(sn + 13, kF, kT , kT , kF, pid + 13, 0 , 1 , 6); + InsertVp9Gof(sn + 16, kF, kT , kT , kF, pid + 16, 0 , 0 , 8); + InsertVp9Gof(sn + 12, kF, kT , kT , kF, pid + 12, 0 , 0 , 6); + InsertVp9Gof(sn + 14, kF, kT , kT , kF, pid + 14, 0 , 0 , 7); + InsertVp9Gof(sn + 17, kF, kT , kT , kF, pid + 17, 0 , 1 , 8); + InsertVp9Gof(sn + 19, kF, kT , kT , kF, pid + 19, 0 , 1 , 9); + InsertVp9Gof(sn + 15, kF, kT , kT , kF, pid + 15, 0 , 1 , 7); + InsertVp9Gof(sn + 18, kF, kT , kT , kF, pid + 18, 0 , 0 , 9); + + ASSERT_EQ(20UL, frames_from_callback_.size()); + CheckReferencesVp9(pid, 0); + CheckReferencesVp9(pid + 1 , 0, pid); + CheckReferencesVp9(pid + 2 , 0, pid); + CheckReferencesVp9(pid + 3 , 0, pid + 2); + CheckReferencesVp9(pid + 4 , 0, pid + 2); + CheckReferencesVp9(pid + 5 , 0, pid + 4); + CheckReferencesVp9(pid + 6 , 0, pid + 4); + CheckReferencesVp9(pid + 7 , 0, pid + 6); + CheckReferencesVp9(pid + 8 , 0, pid + 6); + CheckReferencesVp9(pid + 9 , 0, pid + 8); + CheckReferencesVp9(pid + 10, 0, pid + 8); + CheckReferencesVp9(pid + 11, 0, pid + 10); + CheckReferencesVp9(pid + 12, 0, pid + 10); + CheckReferencesVp9(pid + 13, 0, pid + 12); + CheckReferencesVp9(pid + 14, 0, pid + 12); + CheckReferencesVp9(pid + 15, 0, pid + 14); + CheckReferencesVp9(pid + 16, 0, pid + 14); + CheckReferencesVp9(pid + 17, 0, pid + 16); + CheckReferencesVp9(pid + 18, 0, pid + 16); + CheckReferencesVp9(pid + 19, 0, pid + 18); +} + +TEST_F(TestPacketBuffer, Vp9GofTemporalLayers_0212) { + uint16_t pid = Rand(); + uint16_t sn = Rand(); + GofInfoVP9 ss; + ss.SetGofInfoVP9(kTemporalStructureMode3); // 0212 pattern + + // sn , kf, frst, lst, up, pid , sid, tid, tl0, ss + InsertVp9Gof(sn , kT, kT , kT , kF, pid , 0 , 0 , 0 , &ss); + InsertVp9Gof(sn + 1 , kF, kT , kT , kF, pid + 1 , 0 , 2 , 0); + InsertVp9Gof(sn + 2 , kF, kT , kT , kF, pid + 2 , 0 , 1 , 0); + InsertVp9Gof(sn + 3 , kF, kT , kT , kF, pid + 3 , 0 , 2 , 0); + InsertVp9Gof(sn + 4 , kF, kT , kT , kF, pid + 4 , 0 , 0 , 1); + InsertVp9Gof(sn + 5 , kF, kT , kT , kF, pid + 5 , 0 , 2 , 1); + InsertVp9Gof(sn + 6 , kF, kT , kT , kF, pid + 6 , 0 , 1 , 1); + InsertVp9Gof(sn + 7 , kF, kT , kT , kF, pid + 7 , 0 , 2 , 1); + InsertVp9Gof(sn + 8 , kF, kT , kT , kF, pid + 8 , 0 , 0 , 2); + InsertVp9Gof(sn + 9 , kF, kT , kT , kF, pid + 9 , 0 , 2 , 2); + InsertVp9Gof(sn + 10, kF, kT , kT , kF, pid + 10, 0 , 1 , 2); + InsertVp9Gof(sn + 11, kF, kT , kT , kF, pid + 11, 0 , 2 , 2); + InsertVp9Gof(sn + 12, kF, kT , kT , kF, pid + 12, 0 , 0 , 3); + InsertVp9Gof(sn + 13, kF, kT , kT , kF, pid + 13, 0 , 2 , 3); + InsertVp9Gof(sn + 14, kF, kT , kT , kF, pid + 14, 0 , 1 , 3); + InsertVp9Gof(sn + 15, kF, kT , kT , kF, pid + 15, 0 , 2 , 3); + InsertVp9Gof(sn + 16, kF, kT , kT , kF, pid + 16, 0 , 0 , 4); + InsertVp9Gof(sn + 17, kF, kT , kT , kF, pid + 17, 0 , 2 , 4); + InsertVp9Gof(sn + 18, kF, kT , kT , kF, pid + 18, 0 , 1 , 4); + InsertVp9Gof(sn + 19, kF, kT , kT , kF, pid + 19, 0 , 2 , 4); + + ASSERT_EQ(20UL, frames_from_callback_.size()); + CheckReferencesVp9(pid, 0); + CheckReferencesVp9(pid + 1 , 0, pid); + CheckReferencesVp9(pid + 2 , 0, pid); + CheckReferencesVp9(pid + 3 , 0, pid + 1, pid + 2); + CheckReferencesVp9(pid + 4 , 0, pid); + CheckReferencesVp9(pid + 5 , 0, pid + 4); + CheckReferencesVp9(pid + 6 , 0, pid + 4); + CheckReferencesVp9(pid + 7 , 0, pid + 5, pid + 6); + CheckReferencesVp9(pid + 8 , 0, pid + 4); + CheckReferencesVp9(pid + 9 , 0, pid + 8); + CheckReferencesVp9(pid + 10, 0, pid + 8); + CheckReferencesVp9(pid + 11, 0, pid + 9, pid + 10); + CheckReferencesVp9(pid + 12, 0, pid + 8); + CheckReferencesVp9(pid + 13, 0, pid + 12); + CheckReferencesVp9(pid + 14, 0, pid + 12); + CheckReferencesVp9(pid + 15, 0, pid + 13, pid + 14); + CheckReferencesVp9(pid + 16, 0, pid + 12); + CheckReferencesVp9(pid + 17, 0, pid + 16); + CheckReferencesVp9(pid + 18, 0, pid + 16); + CheckReferencesVp9(pid + 19, 0, pid + 17, pid + 18); +} + +TEST_F(TestPacketBuffer, Vp9GofTemporalLayersReordered_0212) { + uint16_t pid = Rand(); + uint16_t sn = Rand(); + GofInfoVP9 ss; + ss.SetGofInfoVP9(kTemporalStructureMode3); // 0212 pattern + + // sn , kf, frst, lst, up, pid , sid, tid, tl0, ss + InsertVp9Gof(sn + 2 , kF, kT , kT , kF, pid + 2 , 0 , 1 , 0); + InsertVp9Gof(sn + 1 , kF, kT , kT , kF, pid + 1 , 0 , 2 , 0); + InsertVp9Gof(sn , kT, kT , kT , kF, pid , 0 , 0 , 0 , &ss); + InsertVp9Gof(sn + 3 , kF, kT , kT , kF, pid + 3 , 0 , 2 , 0); + InsertVp9Gof(sn + 6 , kF, kT , kT , kF, pid + 6 , 0 , 1 , 1); + InsertVp9Gof(sn + 5 , kF, kT , kT , kF, pid + 5 , 0 , 2 , 1); + InsertVp9Gof(sn + 4 , kF, kT , kT , kF, pid + 4 , 0 , 0 , 1); + InsertVp9Gof(sn + 9 , kF, kT , kT , kF, pid + 9 , 0 , 2 , 2); + InsertVp9Gof(sn + 7 , kF, kT , kT , kF, pid + 7 , 0 , 2 , 1); + InsertVp9Gof(sn + 8 , kF, kT , kT , kF, pid + 8 , 0 , 0 , 2); + InsertVp9Gof(sn + 11, kF, kT , kT , kF, pid + 11, 0 , 2 , 2); + InsertVp9Gof(sn + 10, kF, kT , kT , kF, pid + 10, 0 , 1 , 2); + InsertVp9Gof(sn + 13, kF, kT , kT , kF, pid + 13, 0 , 2 , 3); + InsertVp9Gof(sn + 12, kF, kT , kT , kF, pid + 12, 0 , 0 , 3); + InsertVp9Gof(sn + 14, kF, kT , kT , kF, pid + 14, 0 , 1 , 3); + InsertVp9Gof(sn + 16, kF, kT , kT , kF, pid + 16, 0 , 0 , 4); + InsertVp9Gof(sn + 15, kF, kT , kT , kF, pid + 15, 0 , 2 , 3); + InsertVp9Gof(sn + 17, kF, kT , kT , kF, pid + 17, 0 , 2 , 4); + InsertVp9Gof(sn + 19, kF, kT , kT , kF, pid + 19, 0 , 2 , 4); + InsertVp9Gof(sn + 18, kF, kT , kT , kF, pid + 18, 0 , 1 , 4); + + ASSERT_EQ(20UL, frames_from_callback_.size()); + CheckReferencesVp9(pid, 0); + CheckReferencesVp9(pid + 1 , 0, pid); + CheckReferencesVp9(pid + 2 , 0, pid); + CheckReferencesVp9(pid + 3 , 0, pid + 1, pid + 2); + CheckReferencesVp9(pid + 4 , 0, pid); + CheckReferencesVp9(pid + 5 , 0, pid + 4); + CheckReferencesVp9(pid + 6 , 0, pid + 4); + CheckReferencesVp9(pid + 7 , 0, pid + 5, pid + 6); + CheckReferencesVp9(pid + 8 , 0, pid + 4); + CheckReferencesVp9(pid + 9 , 0, pid + 8); + CheckReferencesVp9(pid + 10, 0, pid + 8); + CheckReferencesVp9(pid + 11, 0, pid + 9, pid + 10); + CheckReferencesVp9(pid + 12, 0, pid + 8); + CheckReferencesVp9(pid + 13, 0, pid + 12); + CheckReferencesVp9(pid + 14, 0, pid + 12); + CheckReferencesVp9(pid + 15, 0, pid + 13, pid + 14); + CheckReferencesVp9(pid + 16, 0, pid + 12); + CheckReferencesVp9(pid + 17, 0, pid + 16); + CheckReferencesVp9(pid + 18, 0, pid + 16); + CheckReferencesVp9(pid + 19, 0, pid + 17, pid + 18); +} + +TEST_F(TestPacketBuffer, Vp9GofTemporalLayersUpSwitch_02120212) { + uint16_t pid = Rand(); + uint16_t sn = Rand(); + GofInfoVP9 ss; + ss.SetGofInfoVP9(kTemporalStructureMode4); // 02120212 pattern + + // sn , kf, frst, lst, up, pid , sid, tid, tl0, ss + InsertVp9Gof(sn , kT, kT , kT , kF, pid , 0 , 0 , 0 , &ss); + InsertVp9Gof(sn + 1 , kF, kT , kT , kF, pid + 1 , 0 , 2 , 0); + InsertVp9Gof(sn + 2 , kF, kT , kT , kF, pid + 2 , 0 , 1 , 0); + InsertVp9Gof(sn + 3 , kF, kT , kT , kF, pid + 3 , 0 , 2 , 0); + InsertVp9Gof(sn + 4 , kF, kT , kT , kF, pid + 4 , 0 , 0 , 1); + InsertVp9Gof(sn + 5 , kF, kT , kT , kF, pid + 5 , 0 , 2 , 1); + InsertVp9Gof(sn + 6 , kF, kT , kT , kT, pid + 6 , 0 , 1 , 1); + InsertVp9Gof(sn + 7 , kF, kT , kT , kF, pid + 7 , 0 , 2 , 1); + InsertVp9Gof(sn + 8 , kF, kT , kT , kT, pid + 8 , 0 , 0 , 2); + InsertVp9Gof(sn + 9 , kF, kT , kT , kF, pid + 9 , 0 , 2 , 2); + InsertVp9Gof(sn + 10, kF, kT , kT , kF, pid + 10, 0 , 1 , 2); + InsertVp9Gof(sn + 11, kF, kT , kT , kT, pid + 11, 0 , 2 , 2); + InsertVp9Gof(sn + 12, kF, kT , kT , kF, pid + 12, 0 , 0 , 3); + InsertVp9Gof(sn + 13, kF, kT , kT , kF, pid + 13, 0 , 2 , 3); + InsertVp9Gof(sn + 14, kF, kT , kT , kF, pid + 14, 0 , 1 , 3); + InsertVp9Gof(sn + 15, kF, kT , kT , kF, pid + 15, 0 , 2 , 3); + + ASSERT_EQ(16UL, frames_from_callback_.size()); + CheckReferencesVp9(pid, 0); + CheckReferencesVp9(pid + 1 , 0, pid); + CheckReferencesVp9(pid + 2 , 0, pid); + CheckReferencesVp9(pid + 3 , 0, pid + 1, pid + 2); + CheckReferencesVp9(pid + 4 , 0, pid); + CheckReferencesVp9(pid + 5 , 0, pid + 3, pid + 4); + CheckReferencesVp9(pid + 6 , 0, pid + 2, pid + 4); + CheckReferencesVp9(pid + 7 , 0, pid + 6); + CheckReferencesVp9(pid + 8 , 0, pid + 4); + CheckReferencesVp9(pid + 9 , 0, pid + 8); + CheckReferencesVp9(pid + 10, 0, pid + 8); + CheckReferencesVp9(pid + 11, 0, pid + 9, pid + 10); + CheckReferencesVp9(pid + 12, 0, pid + 8); + CheckReferencesVp9(pid + 13, 0, pid + 11, pid + 12); + CheckReferencesVp9(pid + 14, 0, pid + 10, pid + 12); + CheckReferencesVp9(pid + 15, 0, pid + 13, pid + 14); +} + +TEST_F(TestPacketBuffer, Vp9GofTemporalLayersUpSwitchReordered_02120212) { + uint16_t pid = Rand(); + uint16_t sn = Rand(); + GofInfoVP9 ss; + ss.SetGofInfoVP9(kTemporalStructureMode4); // 02120212 pattern + + // sn , kf, frst, lst, up, pid , sid, tid, tl0, ss + InsertVp9Gof(sn + 1 , kF, kT , kT , kF, pid + 1 , 0 , 2 , 0); + InsertVp9Gof(sn , kT, kT , kT , kF, pid , 0 , 0 , 0 , &ss); + InsertVp9Gof(sn + 4 , kF, kT , kT , kF, pid + 4 , 0 , 0 , 1); + InsertVp9Gof(sn + 2 , kF, kT , kT , kF, pid + 2 , 0 , 1 , 0); + InsertVp9Gof(sn + 5 , kF, kT , kT , kF, pid + 5 , 0 , 2 , 1); + InsertVp9Gof(sn + 3 , kF, kT , kT , kF, pid + 3 , 0 , 2 , 0); + InsertVp9Gof(sn + 7 , kF, kT , kT , kF, pid + 7 , 0 , 2 , 1); + InsertVp9Gof(sn + 9 , kF, kT , kT , kF, pid + 9 , 0 , 2 , 2); + InsertVp9Gof(sn + 6 , kF, kT , kT , kT, pid + 6 , 0 , 1 , 1); + InsertVp9Gof(sn + 12, kF, kT , kT , kF, pid + 12, 0 , 0 , 3); + InsertVp9Gof(sn + 10, kF, kT , kT , kF, pid + 10, 0 , 1 , 2); + InsertVp9Gof(sn + 8 , kF, kT , kT , kT, pid + 8 , 0 , 0 , 2); + InsertVp9Gof(sn + 11, kF, kT , kT , kT, pid + 11, 0 , 2 , 2); + InsertVp9Gof(sn + 13, kF, kT , kT , kF, pid + 13, 0 , 2 , 3); + InsertVp9Gof(sn + 15, kF, kT , kT , kF, pid + 15, 0 , 2 , 3); + InsertVp9Gof(sn + 14, kF, kT , kT , kF, pid + 14, 0 , 1 , 3); + + ASSERT_EQ(16UL, frames_from_callback_.size()); + CheckReferencesVp9(pid, 0); + CheckReferencesVp9(pid + 1 , 0, pid); + CheckReferencesVp9(pid + 2 , 0, pid); + CheckReferencesVp9(pid + 3 , 0, pid + 1, pid + 2); + CheckReferencesVp9(pid + 4 , 0, pid); + CheckReferencesVp9(pid + 5 , 0, pid + 3, pid + 4); + CheckReferencesVp9(pid + 6 , 0, pid + 2, pid + 4); + CheckReferencesVp9(pid + 7 , 0, pid + 6); + CheckReferencesVp9(pid + 8 , 0, pid + 4); + CheckReferencesVp9(pid + 9 , 0, pid + 8); + CheckReferencesVp9(pid + 10, 0, pid + 8); + CheckReferencesVp9(pid + 11, 0, pid + 9, pid + 10); + CheckReferencesVp9(pid + 12, 0, pid + 8); + CheckReferencesVp9(pid + 13, 0, pid + 11, pid + 12); + CheckReferencesVp9(pid + 14, 0, pid + 10, pid + 12); + CheckReferencesVp9(pid + 15, 0, pid + 13, pid + 14); +} + +TEST_F(TestPacketBuffer, Vp9GofTemporalLayersReordered_01_0212) { + uint16_t pid = Rand(); + uint16_t sn = Rand(); + GofInfoVP9 ss; + ss.SetGofInfoVP9(kTemporalStructureMode2); // 01 pattern + + // sn , kf, frst, lst, up, pid , sid, tid, tl0, ss + InsertVp9Gof(sn + 1 , kF, kT , kT , kF, pid + 1 , 0 , 1 , 0); + InsertVp9Gof(sn , kT, kT , kT , kF, pid , 0 , 0 , 0 , &ss); + InsertVp9Gof(sn + 3 , kF, kT , kT , kF, pid + 3 , 0 , 1 , 1); + InsertVp9Gof(sn + 6 , kF, kT , kT , kF, pid + 6 , 0 , 1 , 2); + ss.SetGofInfoVP9(kTemporalStructureMode3); // 0212 pattern + InsertVp9Gof(sn + 4 , kF, kT , kT , kF, pid + 4 , 0 , 0 , 2 , &ss); + InsertVp9Gof(sn + 2 , kF, kT , kT , kF, pid + 2 , 0 , 0 , 1); + InsertVp9Gof(sn + 5 , kF, kT , kT , kF, pid + 5 , 0 , 2 , 2); + InsertVp9Gof(sn + 8 , kF, kT , kT , kF, pid + 8 , 0 , 0 , 3); + InsertVp9Gof(sn + 10, kF, kT , kT , kF, pid + 10, 0 , 1 , 3); + InsertVp9Gof(sn + 7 , kF, kT , kT , kF, pid + 7 , 0 , 2 , 2); + InsertVp9Gof(sn + 11, kF, kT , kT , kF, pid + 11, 0 , 2 , 3); + InsertVp9Gof(sn + 9 , kF, kT , kT , kF, pid + 9 , 0 , 2 , 3); + + ASSERT_EQ(12UL, frames_from_callback_.size()); + CheckReferencesVp9(pid, 0); + CheckReferencesVp9(pid + 1 , 0, pid); + CheckReferencesVp9(pid + 2 , 0, pid); + CheckReferencesVp9(pid + 3 , 0, pid + 2); + CheckReferencesVp9(pid + 4 , 0, pid); + CheckReferencesVp9(pid + 5 , 0, pid + 4); + CheckReferencesVp9(pid + 6 , 0, pid + 4); + CheckReferencesVp9(pid + 7 , 0, pid + 5, pid + 6); + CheckReferencesVp9(pid + 8 , 0, pid + 4); + CheckReferencesVp9(pid + 9 , 0, pid + 8); + CheckReferencesVp9(pid + 10, 0, pid + 8); + CheckReferencesVp9(pid + 11, 0, pid + 9, pid + 10); +} + +TEST_F(TestPacketBuffer, Vp9FlexibleModeOneFrame) { + uint16_t pid = Rand(); + uint16_t sn = Rand(); + + // sn, kf, frst, lst, intr, pid, sid, tid, tl0 + InsertVp9Flex(sn, kT, kT , kT , kF , pid, 0 , 0 , 0); + + ASSERT_EQ(1UL, frames_from_callback_.size()); + CheckReferencesVp9(pid, 0); +} + +TEST_F(TestPacketBuffer, Vp9FlexibleModeTwoSpatialLayers) { + uint16_t pid = Rand(); + uint16_t sn = Rand(); + + // sn , kf, frst, lst, intr, pid , sid, tid, tl0, refs + InsertVp9Flex(sn , kT, kT , kT , kF , pid , 0 , 0 , 0); + InsertVp9Flex(sn + 1 , kT, kT , kT , kT , pid , 1 , 0 , 0); + InsertVp9Flex(sn + 2 , kF, kT , kT , kF , pid + 1, 1 , 0 , 0 , {1}); + InsertVp9Flex(sn + 3 , kF, kT , kT , kF , pid + 2, 0 , 0 , 1 , {2}); + InsertVp9Flex(sn + 4 , kF, kT , kT , kF , pid + 2, 1 , 0 , 1 , {1}); + InsertVp9Flex(sn + 5 , kF, kT , kT , kF , pid + 3, 1 , 0 , 1 , {1}); + InsertVp9Flex(sn + 6 , kF, kT , kT , kF , pid + 4, 0 , 0 , 2 , {2}); + InsertVp9Flex(sn + 7 , kF, kT , kT , kF , pid + 4, 1 , 0 , 2 , {1}); + InsertVp9Flex(sn + 8 , kF, kT , kT , kF , pid + 5, 1 , 0 , 2 , {1}); + InsertVp9Flex(sn + 9 , kF, kT , kT , kF , pid + 6, 0 , 0 , 3 , {2}); + InsertVp9Flex(sn + 10, kF, kT , kT , kF , pid + 6, 1 , 0 , 3 , {1}); + InsertVp9Flex(sn + 11, kF, kT , kT , kF , pid + 7, 1 , 0 , 3 , {1}); + InsertVp9Flex(sn + 12, kF, kT , kT , kF , pid + 8, 0 , 0 , 4 , {2}); + InsertVp9Flex(sn + 13, kF, kT , kT , kF , pid + 8, 1 , 0 , 4 , {1}); + + ASSERT_EQ(14UL, frames_from_callback_.size()); + CheckReferencesVp9(pid , 0); + CheckReferencesVp9(pid , 1); + CheckReferencesVp9(pid + 1, 1, pid); + CheckReferencesVp9(pid + 2, 0, pid); + CheckReferencesVp9(pid + 2, 1, pid + 1); + CheckReferencesVp9(pid + 3, 1, pid + 2); + CheckReferencesVp9(pid + 4, 0, pid + 2); + CheckReferencesVp9(pid + 4, 1, pid + 3); + CheckReferencesVp9(pid + 5, 1, pid + 4); + CheckReferencesVp9(pid + 6, 0, pid + 4); + CheckReferencesVp9(pid + 6, 1, pid + 5); + CheckReferencesVp9(pid + 7, 1, pid + 6); + CheckReferencesVp9(pid + 8, 0, pid + 6); + CheckReferencesVp9(pid + 8, 1, pid + 7); +} + +TEST_F(TestPacketBuffer, Vp9FlexibleModeTwoSpatialLayersReordered) { + uint16_t pid = Rand(); + uint16_t sn = Rand(); + + // sn , kf, frst, lst, intr, pid , sid, tid, tl0, refs + InsertVp9Flex(sn + 1 , kT, kT , kT , kT , pid , 1 , 0 , 0); + InsertVp9Flex(sn + 2 , kF, kT , kT , kF , pid + 1, 1 , 0 , 0 , {1}); + InsertVp9Flex(sn , kT, kT , kT , kF , pid , 0 , 0 , 0); + InsertVp9Flex(sn + 4 , kF, kT , kT , kF , pid + 2, 1 , 0 , 1 , {1}); + InsertVp9Flex(sn + 5 , kF, kT , kT , kF , pid + 3, 1 , 0 , 1 , {1}); + InsertVp9Flex(sn + 3 , kF, kT , kT , kF , pid + 2, 0 , 0 , 1 , {2}); + InsertVp9Flex(sn + 7 , kF, kT , kT , kF , pid + 4, 1 , 0 , 2 , {1}); + InsertVp9Flex(sn + 6 , kF, kT , kT , kF , pid + 4, 0 , 0 , 2 , {2}); + InsertVp9Flex(sn + 8 , kF, kT , kT , kF , pid + 5, 1 , 0 , 2 , {1}); + InsertVp9Flex(sn + 9 , kF, kT , kT , kF , pid + 6, 0 , 0 , 3 , {2}); + InsertVp9Flex(sn + 11, kF, kT , kT , kF , pid + 7, 1 , 0 , 3 , {1}); + InsertVp9Flex(sn + 10, kF, kT , kT , kF , pid + 6, 1 , 0 , 3 , {1}); + InsertVp9Flex(sn + 13, kF, kT , kT , kF , pid + 8, 1 , 0 , 4 , {1}); + InsertVp9Flex(sn + 12, kF, kT , kT , kF , pid + 8, 0 , 0 , 4 , {2}); + + ASSERT_EQ(14UL, frames_from_callback_.size()); + CheckReferencesVp9(pid , 0); + CheckReferencesVp9(pid , 1); + CheckReferencesVp9(pid + 1, 1, pid); + CheckReferencesVp9(pid + 2, 0, pid); + CheckReferencesVp9(pid + 2, 1, pid + 1); + CheckReferencesVp9(pid + 3, 1, pid + 2); + CheckReferencesVp9(pid + 4, 0, pid + 2); + CheckReferencesVp9(pid + 4, 1, pid + 3); + CheckReferencesVp9(pid + 5, 1, pid + 4); + CheckReferencesVp9(pid + 6, 0, pid + 4); + CheckReferencesVp9(pid + 6, 1, pid + 5); + CheckReferencesVp9(pid + 7, 1, pid + 6); + CheckReferencesVp9(pid + 8, 0, pid + 6); + CheckReferencesVp9(pid + 8, 1, pid + 7); } } // namespace video_coding