Packet buffer for the new jitter buffer.

BUG=webrtc:5514
R=stefan@webrtc.org, mflodman@webrtc.org

Review URL: https://codereview.webrtc.org/1772383002

Cr-Commit-Position: refs/heads/master@{#12194}
This commit is contained in:
philipel
2016-04-01 02:01:54 -07:00
committed by Commit bot
parent fcc640f8f6
commit c707ab7cb0
8 changed files with 696 additions and 0 deletions

View File

@ -370,6 +370,7 @@
'video_coding/jitter_estimator_tests.cc', 'video_coding/jitter_estimator_tests.cc',
'video_coding/media_optimization_unittest.cc', 'video_coding/media_optimization_unittest.cc',
'video_coding/nack_module_unittest.cc', 'video_coding/nack_module_unittest.cc',
'video_coding/packet_buffer_unittest.cc',
'video_coding/percentile_filter_unittest.cc', 'video_coding/percentile_filter_unittest.cc',
'video_coding/receiver_unittest.cc', 'video_coding/receiver_unittest.cc',
'video_coding/session_info_unittest.cc', 'video_coding/session_info_unittest.cc',

View File

@ -25,6 +25,8 @@ source_set("video_coding") {
"fec_tables_xor.h", "fec_tables_xor.h",
"frame_buffer.cc", "frame_buffer.cc",
"frame_buffer.h", "frame_buffer.h",
"frame_object.cc",
"frame_object.h",
"generic_decoder.cc", "generic_decoder.cc",
"generic_decoder.h", "generic_decoder.h",
"generic_encoder.cc", "generic_encoder.cc",
@ -50,6 +52,8 @@ source_set("video_coding") {
"nack_module.h", "nack_module.h",
"packet.cc", "packet.cc",
"packet.h", "packet.h",
"packet_buffer.cc",
"packet_buffer.h",
"percentile_filter.cc", "percentile_filter.cc",
"percentile_filter.h", "percentile_filter.h",
"qm_select.cc", "qm_select.cc",

View File

@ -0,0 +1,47 @@
/*
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/modules/video_coding/frame_object.h"
#include "webrtc/base/criticalsection.h"
#include "webrtc/modules/video_coding/packet_buffer.h"
namespace webrtc {
namespace video_coding {
RtpFrameObject::RtpFrameObject(PacketBuffer* packet_buffer,
uint16_t picture_id,
uint16_t first_packet,
uint16_t last_packet)
: packet_buffer_(packet_buffer),
first_packet_(first_packet),
last_packet_(last_packet) {}
RtpFrameObject::~RtpFrameObject() {
packet_buffer_->ReturnFrame(this);
}
uint16_t RtpFrameObject::first_packet() const {
return first_packet_;
}
uint16_t RtpFrameObject::last_packet() const {
return last_packet_;
}
uint16_t RtpFrameObject::picture_id() const {
return picture_id_;
}
bool RtpFrameObject::GetBitstream(uint8_t* destination) const {
return packet_buffer_->GetBitstream(*this, destination);
}
} // namespace video_coding
} // namespace webrtc

View File

@ -0,0 +1,50 @@
/*
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_MODULES_VIDEO_CODING_FRAME_OBJECT_H_
#define WEBRTC_MODULES_VIDEO_CODING_FRAME_OBJECT_H_
#include "webrtc/modules/video_coding/packet.h"
namespace webrtc {
namespace video_coding {
class FrameObject {
public:
virtual uint16_t picture_id() const = 0;
virtual bool GetBitstream(uint8_t* destination) const = 0;
virtual ~FrameObject() {}
};
class PacketBuffer;
class RtpFrameObject : public FrameObject {
public:
RtpFrameObject(PacketBuffer* packet_buffer,
uint16_t picture_id,
uint16_t first_packet,
uint16_t last_packet);
~RtpFrameObject();
uint16_t first_packet() const;
uint16_t last_packet() const;
uint16_t picture_id() const override;
bool GetBitstream(uint8_t* destination) const override;
private:
PacketBuffer* packet_buffer_;
uint16_t picture_id_;
uint16_t first_packet_;
uint16_t last_packet_;
};
} // namespace video_coding
} // namespace webrtc
#endif // WEBRTC_MODULES_VIDEO_CODING_FRAME_OBJECT_H_

View File

@ -0,0 +1,204 @@
/*
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/modules/video_coding/packet_buffer.h"
#include <algorithm>
#include <limits>
#include "webrtc/base/checks.h"
#include "webrtc/modules/video_coding/frame_object.h"
#include "webrtc/modules/video_coding/sequence_number_util.h"
namespace webrtc {
namespace video_coding {
PacketBuffer::PacketBuffer(size_t start_buffer_size,
size_t max_buffer_size,
OnCompleteFrameCallback* frame_callback)
: size_(start_buffer_size),
max_size_(max_buffer_size),
last_seq_num_(0),
first_seq_num_(0),
initialized_(false),
data_buffer_(start_buffer_size),
sequence_buffer_(start_buffer_size),
frame_callback_(frame_callback) {
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);
RTC_DCHECK((max_buffer_size & (max_buffer_size - 1)) == 0);
}
bool PacketBuffer::InsertPacket(const VCMPacket& packet) {
rtc::CritScope lock(&crit_);
uint16_t seq_num = packet.seqNum;
int index = seq_num % size_;
if (!initialized_) {
first_seq_num_ = seq_num - 1;
last_seq_num_ = seq_num;
initialized_ = true;
}
if (sequence_buffer_[index].used) {
// Duplicate packet, do nothing.
if (data_buffer_[index].seqNum == packet.seqNum)
return true;
// The packet buffer is full, try to expand the buffer.
while (ExpandBufferSize() && sequence_buffer_[seq_num % size_].used) {
}
index = seq_num % size_;
// Packet buffer is still full.
if (sequence_buffer_[index].used)
return false;
}
if (AheadOf(seq_num, last_seq_num_))
last_seq_num_ = seq_num;
sequence_buffer_[index].frame_begin = packet.isFirstPacket;
sequence_buffer_[index].frame_end = packet.markerBit;
sequence_buffer_[index].seq_num = packet.seqNum;
sequence_buffer_[index].continuous = false;
sequence_buffer_[index].used = true;
data_buffer_[index] = packet;
FindCompleteFrames(seq_num);
return true;
}
void PacketBuffer::ClearTo(uint16_t seq_num) {
rtc::CritScope lock(&crit_);
int index = first_seq_num_ % size_;
while (AheadOf<uint16_t>(seq_num, first_seq_num_ + 1)) {
index = (index + 1) % size_;
first_seq_num_ = Add<1 << 16>(first_seq_num_, 1);
sequence_buffer_[index].used = false;
}
}
bool PacketBuffer::ExpandBufferSize() {
if (size_ == max_size_)
return false;
size_t new_size = std::min(max_size_, 2 * size_);
std::vector<VCMPacket> new_data_buffer(new_size);
std::vector<ContinuityInfo> new_sequence_buffer(new_size);
for (size_t i = 0; i < size_; ++i) {
if (sequence_buffer_[i].used) {
int index = sequence_buffer_[i].seq_num % new_size;
new_sequence_buffer[index] = sequence_buffer_[i];
new_data_buffer[index] = data_buffer_[i];
}
}
size_ = new_size;
sequence_buffer_ = std::move(new_sequence_buffer);
data_buffer_ = std::move(new_data_buffer);
return true;
}
bool PacketBuffer::IsContinuous(uint16_t seq_num) const {
int index = seq_num % size_;
int prev_index = index > 0 ? index - 1 : size_ - 1;
if (!sequence_buffer_[index].used)
return false;
if (sequence_buffer_[index].frame_begin)
return true;
if (!sequence_buffer_[prev_index].used)
return false;
if (sequence_buffer_[prev_index].continuous)
return true;
return false;
}
void PacketBuffer::FindCompleteFrames(uint16_t seq_num) {
int index = seq_num % size_;
while (IsContinuous(seq_num)) {
sequence_buffer_[index].continuous = true;
// If the frame is complete, find the first packet of the frame and
// create a FrameObject.
if (sequence_buffer_[index].frame_end) {
int rindex = index;
uint16_t start_seq_num = seq_num;
while (!sequence_buffer_[rindex].frame_begin) {
rindex = rindex > 0 ? rindex - 1 : size_ - 1;
start_seq_num--;
}
std::unique_ptr<FrameObject> frame(
new RtpFrameObject(this, 1, start_seq_num, seq_num));
frame_callback_->OnCompleteFrame(std::move(frame));
}
index = (index + 1) % size_;
++seq_num;
}
}
void PacketBuffer::ReturnFrame(RtpFrameObject* frame) {
rtc::CritScope lock(&crit_);
int index = frame->first_packet() % size_;
int end = (frame->last_packet() + 1) % size_;
uint16_t seq_num = frame->first_packet();
while (index != end) {
if (sequence_buffer_[index].seq_num == seq_num) {
sequence_buffer_[index].used = false;
sequence_buffer_[index].continuous = false;
}
index = (index + 1) % size_;
++seq_num;
}
index = first_seq_num_ % size_;
while (AheadOf<uint16_t>(last_seq_num_, first_seq_num_) &&
!sequence_buffer_[index].used) {
++first_seq_num_;
index = (index + 1) % size_;
}
}
bool PacketBuffer::GetBitstream(const RtpFrameObject& frame,
uint8_t* destination) {
rtc::CritScope lock(&crit_);
int index = frame.first_packet() % size_;
int end = (frame.last_packet() + 1) % size_;
uint16_t seq_num = frame.first_packet();
while (index != end) {
if (!sequence_buffer_[index].used ||
sequence_buffer_[index].seq_num != seq_num) {
return false;
}
const uint8_t* source = data_buffer_[index].dataPtr;
size_t length = data_buffer_[index].sizeBytes;
memcpy(destination, source, length);
destination += length;
index = (index + 1) % size_;
++seq_num;
}
return true;
}
void PacketBuffer::Flush() {
rtc::CritScope lock(&crit_);
for (size_t i = 0; i < size_; ++i) {
sequence_buffer_[i].used = false;
sequence_buffer_[i].continuous = false;
}
}
} // namespace video_coding
} // namespace webrtc

View File

@ -0,0 +1,81 @@
/*
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_MODULES_VIDEO_CODING_PACKET_BUFFER_H_
#define WEBRTC_MODULES_VIDEO_CODING_PACKET_BUFFER_H_
#include <vector>
#include "webrtc/base/criticalsection.h"
#include "webrtc/base/scoped_ptr.h"
#include "webrtc/base/thread_annotations.h"
#include "webrtc/modules/video_coding/packet.h"
namespace webrtc {
namespace video_coding {
class FrameObject;
class RtpFrameObject;
class OnCompleteFrameCallback {
public:
virtual ~OnCompleteFrameCallback() {}
virtual void OnCompleteFrame(std::unique_ptr<FrameObject> frame) = 0;
};
class PacketBuffer {
public:
// Both |start_buffer_size| and |max_buffer_size| must be a power of 2.
PacketBuffer(size_t start_buffer_size,
size_t max_buffer_size,
OnCompleteFrameCallback* frame_callback);
bool InsertPacket(const VCMPacket& packet);
void ClearTo(uint16_t seq_num);
void Flush();
private:
friend RtpFrameObject;
// Since we want the packet buffer to be as packet type agnostic
// as possible we extract only the information needed in order
// to determin whether a sequence of packets is continuous or not.
struct ContinuityInfo {
uint16_t seq_num = 0;
bool frame_begin = false;
bool frame_end = false;
bool used = false;
bool continuous = false;
};
bool ExpandBufferSize() EXCLUSIVE_LOCKS_REQUIRED(crit_);
bool IsContinuous(uint16_t seq_num) const EXCLUSIVE_LOCKS_REQUIRED(crit_);
void FindCompleteFrames(uint16_t seq_num) EXCLUSIVE_LOCKS_REQUIRED(crit_);
bool GetBitstream(const RtpFrameObject& frame, uint8_t* destination);
void ReturnFrame(RtpFrameObject* frame);
rtc::CriticalSection crit_;
// Buffer size_ and max_size_ must always be a power of two.
size_t size_ GUARDED_BY(crit_);
const size_t max_size_;
uint16_t last_seq_num_ GUARDED_BY(crit_);
uint16_t first_seq_num_ GUARDED_BY(crit_);
bool initialized_ GUARDED_BY(crit_);
std::vector<VCMPacket> data_buffer_ GUARDED_BY(crit_);
std::vector<ContinuityInfo> sequence_buffer_ GUARDED_BY(crit_);
OnCompleteFrameCallback* const frame_callback_;
};
} // namespace video_coding
} // namespace webrtc
#endif // WEBRTC_MODULES_VIDEO_CODING_PACKET_BUFFER_H_

View File

@ -0,0 +1,305 @@
/*
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <cstring>
#include <limits>
#include "webrtc/modules/video_coding/frame_object.h"
#include "webrtc/modules/video_coding/packet_buffer.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/base/random.h"
namespace webrtc {
namespace video_coding {
class TestPacketBuffer : public ::testing::Test,
public OnCompleteFrameCallback {
protected:
TestPacketBuffer()
: rand_(0x8739211), packet_buffer_(kStartSize, kMaxSize, this) {}
uint16_t Rand() { return rand_.Rand(std::numeric_limits<uint16_t>::max()); }
void OnCompleteFrame(std::unique_ptr<FrameObject> frame) override {
frames_from_callback_.emplace_back(std::move(frame));
}
void TearDown() override {
// All FrameObjects must be destroyed before the PacketBuffer since
// a FrameObject will try to remove itself from the packet buffer
// upon destruction.
frames_from_callback_.clear();
}
const int kStartSize = 16;
const int kMaxSize = 64;
Random rand_;
PacketBuffer packet_buffer_;
std::vector<std::unique_ptr<FrameObject>> frames_from_callback_;
};
TEST_F(TestPacketBuffer, InsertOnePacket) {
VCMPacket packet;
packet.seqNum = Rand();
EXPECT_TRUE(packet_buffer_.InsertPacket(packet));
}
TEST_F(TestPacketBuffer, InsertMultiplePackets) {
VCMPacket packet;
packet.seqNum = Rand();
EXPECT_TRUE(packet_buffer_.InsertPacket(packet));
++packet.seqNum;
EXPECT_TRUE(packet_buffer_.InsertPacket(packet));
++packet.seqNum;
EXPECT_TRUE(packet_buffer_.InsertPacket(packet));
}
TEST_F(TestPacketBuffer, InsertDuplicatePacket) {
VCMPacket packet;
packet.seqNum = Rand();
EXPECT_TRUE(packet_buffer_.InsertPacket(packet));
++packet.seqNum;
EXPECT_TRUE(packet_buffer_.InsertPacket(packet));
EXPECT_TRUE(packet_buffer_.InsertPacket(packet));
++packet.seqNum;
EXPECT_TRUE(packet_buffer_.InsertPacket(packet));
}
TEST_F(TestPacketBuffer, ExpandBuffer) {
VCMPacket packet;
packet.seqNum = Rand();
for (int i = 0; i < kStartSize + 1; ++i) {
EXPECT_TRUE(packet_buffer_.InsertPacket(packet));
++packet.seqNum;
}
}
TEST_F(TestPacketBuffer, ExpandBufferOverflow) {
VCMPacket packet;
packet.seqNum = Rand();
for (int i = 0; i < kMaxSize; ++i) {
EXPECT_TRUE(packet_buffer_.InsertPacket(packet));
++packet.seqNum;
}
EXPECT_FALSE(packet_buffer_.InsertPacket(packet));
}
TEST_F(TestPacketBuffer, OnePacketOneFrame) {
VCMPacket packet;
packet.isFirstPacket = true;
packet.markerBit = true;
packet.seqNum = Rand();
EXPECT_TRUE(packet_buffer_.InsertPacket(packet));
EXPECT_EQ(1UL, frames_from_callback_.size());
}
TEST_F(TestPacketBuffer, TwoPacketsTwoFrames) {
VCMPacket packet;
packet.isFirstPacket = true;
packet.markerBit = true;
packet.seqNum = Rand();
EXPECT_TRUE(packet_buffer_.InsertPacket(packet));
++packet.seqNum;
EXPECT_TRUE(packet_buffer_.InsertPacket(packet));
EXPECT_EQ(2UL, frames_from_callback_.size());
}
TEST_F(TestPacketBuffer, TwoPacketsOneFrames) {
VCMPacket packet;
packet.isFirstPacket = true;
packet.seqNum = Rand();
EXPECT_TRUE(packet_buffer_.InsertPacket(packet));
packet.markerBit = true;
++packet.seqNum;
EXPECT_TRUE(packet_buffer_.InsertPacket(packet));
EXPECT_EQ(1UL, frames_from_callback_.size());
}
TEST_F(TestPacketBuffer, ThreePacketReorderingOneFrame) {
VCMPacket packet;
packet.isFirstPacket = true;
packet.seqNum = Rand();
EXPECT_TRUE(packet_buffer_.InsertPacket(packet));
EXPECT_EQ(0UL, frames_from_callback_.size());
packet.isFirstPacket = false;
packet.markerBit = true;
packet.seqNum += 2;
EXPECT_TRUE(packet_buffer_.InsertPacket(packet));
EXPECT_EQ(0UL, frames_from_callback_.size());
packet.markerBit = false;
packet.seqNum -= 1;
EXPECT_TRUE(packet_buffer_.InsertPacket(packet));
EXPECT_EQ(1UL, frames_from_callback_.size());
}
TEST_F(TestPacketBuffer, IndexWrapOneFrame) {
VCMPacket packet;
packet.isFirstPacket = true;
packet.seqNum = kStartSize - 1;
EXPECT_TRUE(packet_buffer_.InsertPacket(packet));
EXPECT_EQ(0UL, frames_from_callback_.size());
packet.isFirstPacket = false;
++packet.seqNum;
EXPECT_TRUE(packet_buffer_.InsertPacket(packet));
EXPECT_EQ(0UL, frames_from_callback_.size());
++packet.seqNum;
EXPECT_TRUE(packet_buffer_.InsertPacket(packet));
EXPECT_EQ(0UL, frames_from_callback_.size());
packet.markerBit = true;
++packet.seqNum;
EXPECT_TRUE(packet_buffer_.InsertPacket(packet));
EXPECT_EQ(1UL, frames_from_callback_.size());
}
TEST_F(TestPacketBuffer, DiscardOldPacket) {
uint16_t seq_num = Rand();
VCMPacket packet;
packet.seqNum = Rand();
EXPECT_TRUE(packet_buffer_.InsertPacket(packet));
packet.seqNum += 2;
EXPECT_TRUE(packet_buffer_.InsertPacket(packet));
for (int i = 3; i < kMaxSize; ++i) {
++packet.seqNum;
EXPECT_TRUE(packet_buffer_.InsertPacket(packet));
}
++packet.seqNum;
EXPECT_FALSE(packet_buffer_.InsertPacket(packet));
packet_buffer_.ClearTo(seq_num + 1);
EXPECT_TRUE(packet_buffer_.InsertPacket(packet));
}
TEST_F(TestPacketBuffer, DiscardMultipleOldPackets) {
uint16_t seq_num = Rand();
VCMPacket packet;
packet.seqNum = seq_num;
EXPECT_TRUE(packet_buffer_.InsertPacket(packet));
packet.seqNum += 2;
EXPECT_TRUE(packet_buffer_.InsertPacket(packet));
for (int i = 3; i < kMaxSize; ++i) {
++packet.seqNum;
EXPECT_TRUE(packet_buffer_.InsertPacket(packet));
}
packet_buffer_.ClearTo(seq_num + 15);
for (int i = 0; i < 15; ++i) {
++packet.seqNum;
EXPECT_TRUE(packet_buffer_.InsertPacket(packet));
}
for (int i = 15; i < kMaxSize; ++i) {
++packet.seqNum;
EXPECT_FALSE(packet_buffer_.InsertPacket(packet));
}
}
TEST_F(TestPacketBuffer, GetBitstreamFromFrame) {
// "many bitstream, such data" with null termination.
uint8_t many[] = {0x6d, 0x61, 0x6e, 0x79, 0x20};
uint8_t bitstream[] = {0x62, 0x69, 0x74, 0x73, 0x74, 0x72,
0x65, 0x61, 0x6d, 0x2c, 0x20};
uint8_t such[] = {0x73, 0x75, 0x63, 0x68, 0x20};
uint8_t data[] = {0x64, 0x61, 0x74, 0x61, 0x0};
uint8_t
result[sizeof(many) + sizeof(bitstream) + sizeof(such) + sizeof(data)];
VCMPacket packet;
packet.isFirstPacket = true;
packet.seqNum = 0xfffe;
packet.dataPtr = many;
packet.sizeBytes = sizeof(many);
EXPECT_TRUE(packet_buffer_.InsertPacket(packet));
packet.isFirstPacket = false;
++packet.seqNum;
packet.dataPtr = bitstream;
packet.sizeBytes = sizeof(bitstream);
EXPECT_TRUE(packet_buffer_.InsertPacket(packet));
++packet.seqNum;
packet.dataPtr = such;
packet.sizeBytes = sizeof(such);
EXPECT_TRUE(packet_buffer_.InsertPacket(packet));
packet.markerBit = true;
++packet.seqNum;
packet.dataPtr = data;
packet.sizeBytes = sizeof(data);
EXPECT_EQ(0UL, frames_from_callback_.size());
EXPECT_TRUE(packet_buffer_.InsertPacket(packet));
ASSERT_EQ(1UL, frames_from_callback_.size());
EXPECT_TRUE(frames_from_callback_[0]->GetBitstream(result));
EXPECT_EQ(
std::strcmp("many bitstream, such data", reinterpret_cast<char*>(result)),
0);
}
TEST_F(TestPacketBuffer, FreeSlotsOnFrameDestruction) {
VCMPacket packet;
packet.isFirstPacket = true;
packet.seqNum = Rand();
EXPECT_TRUE(packet_buffer_.InsertPacket(packet));
EXPECT_EQ(0UL, frames_from_callback_.size());
packet.isFirstPacket = false;
++packet.seqNum;
EXPECT_TRUE(packet_buffer_.InsertPacket(packet));
EXPECT_EQ(0UL, frames_from_callback_.size());
++packet.seqNum;
packet.markerBit = true;
EXPECT_TRUE(packet_buffer_.InsertPacket(packet));
EXPECT_EQ(1UL, frames_from_callback_.size());
frames_from_callback_.clear();
packet.isFirstPacket = true;
packet.markerBit = false;
packet.seqNum = Rand();
EXPECT_TRUE(packet_buffer_.InsertPacket(packet));
EXPECT_EQ(0UL, frames_from_callback_.size());
packet.isFirstPacket = false;
++packet.seqNum;
EXPECT_TRUE(packet_buffer_.InsertPacket(packet));
EXPECT_EQ(0UL, frames_from_callback_.size());
++packet.seqNum;
packet.markerBit = true;
EXPECT_TRUE(packet_buffer_.InsertPacket(packet));
EXPECT_EQ(1UL, frames_from_callback_.size());
}
TEST_F(TestPacketBuffer, Flush) {
VCMPacket packet;
packet.isFirstPacket = true;
packet.markerBit = true;
packet.seqNum = Rand();
EXPECT_TRUE(packet_buffer_.InsertPacket(packet));
EXPECT_TRUE(packet_buffer_.InsertPacket(packet));
packet_buffer_.Flush();
EXPECT_TRUE(packet_buffer_.InsertPacket(packet));
EXPECT_EQ(2UL, frames_from_callback_.size());
}
TEST_F(TestPacketBuffer, InvalidateFrameByFlushing) {
VCMPacket packet;
packet.isFirstPacket = true;
packet.markerBit = true;
packet.seqNum = Rand();
EXPECT_TRUE(packet_buffer_.InsertPacket(packet));
ASSERT_EQ(1UL, frames_from_callback_.size());
packet_buffer_.Flush();
EXPECT_FALSE(frames_from_callback_[0]->GetBitstream(nullptr));
}
} // namespace video_coding
} // namespace webrtc

View File

@ -34,6 +34,7 @@
'encoded_frame.h', 'encoded_frame.h',
'fec_tables_xor.h', 'fec_tables_xor.h',
'frame_buffer.h', 'frame_buffer.h',
'frame_object.h',
'generic_decoder.h', 'generic_decoder.h',
'generic_encoder.h', 'generic_encoder.h',
'histogram.h', 'histogram.h',
@ -47,6 +48,7 @@
'nack_fec_tables.h', 'nack_fec_tables.h',
'nack_module.h', 'nack_module.h',
'packet.h', 'packet.h',
'packet_buffer.h',
'percentile_filter.h', 'percentile_filter.h',
'qm_select_data.h', 'qm_select_data.h',
'qm_select.h', 'qm_select.h',
@ -65,6 +67,7 @@
'decoding_state.cc', 'decoding_state.cc',
'encoded_frame.cc', 'encoded_frame.cc',
'frame_buffer.cc', 'frame_buffer.cc',
'frame_object.cc',
'generic_decoder.cc', 'generic_decoder.cc',
'generic_encoder.cc', 'generic_encoder.cc',
'inter_frame_delay.cc', 'inter_frame_delay.cc',
@ -75,6 +78,7 @@
'media_optimization.cc', 'media_optimization.cc',
'nack_module.cc', 'nack_module.cc',
'packet.cc', 'packet.cc',
'packet_buffer.cc',
'percentile_filter.cc', 'percentile_filter.cc',
'qm_select.cc', 'qm_select.cc',
'receiver.cc', 'receiver.cc',