Files
platform-external-webrtc/webrtc/modules/video_coding/main/source/receiver_unittest.cc
Wan-Teh Chang 92d9489881 Miscellaneous cleanups in VCMReceiver and its unit tests.
The most important change is to prevent a potential buffer overflow in
NackList(). It cannot happen if the |size| argument passed to NackList()
is consistent with the |max_nack_list_size| argument passed to
SetNackSettings(), and there is an assertion to check that. But it is
good to defend against this in the release build because assert() is
compiled away in the release build.

Remove the unused |master| parameter to the VCMReceiver constructor.

Remove the unused State() getter method and the corresponding state_
member.

Remove the declarations for the nonexistent GenerateReceiverId()
method and the receiver_id_counter_ member.

Remove the unneeded data_buffer_ member of TestVCMReceiver. It was
assigned to packet.dataPtr and then immediately overwritten by
stream_generator_->GetPacket() or stream_generator_->PopPacket().

R=stefan@webrtc.org
BUG=none
TEST=none

Review URL: https://webrtc-codereview.appspot.com/51119004

Cr-Commit-Position: refs/heads/master@{#9318}
2015-05-28 20:36:22 +00:00

330 lines
13 KiB
C++

/* Copyright (c) 2013 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 <string.h>
#include <list>
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/modules/video_coding/main/source/packet.h"
#include "webrtc/modules/video_coding/main/source/receiver.h"
#include "webrtc/modules/video_coding/main/source/test/stream_generator.h"
#include "webrtc/modules/video_coding/main/source/timing.h"
#include "webrtc/modules/video_coding/main/test/test_util.h"
#include "webrtc/system_wrappers/interface/clock.h"
#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
namespace webrtc {
class TestVCMReceiver : public ::testing::Test {
protected:
enum { kWidth = 640 };
enum { kHeight = 480 };
TestVCMReceiver()
: clock_(new SimulatedClock(0)),
timing_(clock_.get()),
receiver_(&timing_, clock_.get(), &event_factory_) {
stream_generator_.reset(new
StreamGenerator(0, 0, clock_->TimeInMilliseconds()));
}
virtual void SetUp() {
receiver_.Reset();
}
int32_t InsertPacket(int index) {
VCMPacket packet;
bool packet_available = stream_generator_->GetPacket(&packet, index);
EXPECT_TRUE(packet_available);
if (!packet_available)
return kGeneralError; // Return here to avoid crashes below.
return receiver_.InsertPacket(packet, kWidth, kHeight);
}
int32_t InsertPacketAndPop(int index) {
VCMPacket packet;
bool packet_available = stream_generator_->PopPacket(&packet, index);
EXPECT_TRUE(packet_available);
if (!packet_available)
return kGeneralError; // Return here to avoid crashes below.
return receiver_.InsertPacket(packet, kWidth, kHeight);
}
int32_t InsertFrame(FrameType frame_type, bool complete) {
int num_of_packets = complete ? 1 : 2;
stream_generator_->GenerateFrame(
frame_type,
(frame_type != kFrameEmpty) ? num_of_packets : 0,
(frame_type == kFrameEmpty) ? 1 : 0,
clock_->TimeInMilliseconds());
int32_t ret = InsertPacketAndPop(0);
if (!complete) {
// Drop the second packet.
VCMPacket packet;
stream_generator_->PopPacket(&packet, 0);
}
clock_->AdvanceTimeMilliseconds(kDefaultFramePeriodMs);
return ret;
}
bool DecodeNextFrame() {
int64_t render_time_ms = 0;
VCMEncodedFrame* frame =
receiver_.FrameForDecoding(0, render_time_ms, false);
if (!frame)
return false;
receiver_.ReleaseFrame(frame);
return true;
}
rtc::scoped_ptr<SimulatedClock> clock_;
VCMTiming timing_;
NullEventFactory event_factory_;
VCMReceiver receiver_;
rtc::scoped_ptr<StreamGenerator> stream_generator_;
};
TEST_F(TestVCMReceiver, RenderBufferSize_AllComplete) {
EXPECT_EQ(0, receiver_.RenderBufferSizeMs());
EXPECT_GE(InsertFrame(kVideoFrameKey, true), kNoError);
int num_of_frames = 10;
for (int i = 0; i < num_of_frames; ++i) {
EXPECT_GE(InsertFrame(kVideoFrameDelta, true), kNoError);
}
EXPECT_EQ(num_of_frames * kDefaultFramePeriodMs,
receiver_.RenderBufferSizeMs());
}
TEST_F(TestVCMReceiver, RenderBufferSize_SkipToKeyFrame) {
EXPECT_EQ(0, receiver_.RenderBufferSizeMs());
const int kNumOfNonDecodableFrames = 2;
for (int i = 0; i < kNumOfNonDecodableFrames; ++i) {
EXPECT_GE(InsertFrame(kVideoFrameDelta, true), kNoError);
}
const int kNumOfFrames = 10;
EXPECT_GE(InsertFrame(kVideoFrameKey, true), kNoError);
for (int i = 0; i < kNumOfFrames - 1; ++i) {
EXPECT_GE(InsertFrame(kVideoFrameDelta, true), kNoError);
}
EXPECT_EQ((kNumOfFrames - 1) * kDefaultFramePeriodMs,
receiver_.RenderBufferSizeMs());
}
TEST_F(TestVCMReceiver, RenderBufferSize_NotAllComplete) {
EXPECT_EQ(0, receiver_.RenderBufferSizeMs());
EXPECT_GE(InsertFrame(kVideoFrameKey, true), kNoError);
int num_of_frames = 10;
for (int i = 0; i < num_of_frames; ++i) {
EXPECT_GE(InsertFrame(kVideoFrameDelta, true), kNoError);
}
num_of_frames++;
EXPECT_GE(InsertFrame(kVideoFrameDelta, false), kNoError);
for (int i = 0; i < num_of_frames; ++i) {
EXPECT_GE(InsertFrame(kVideoFrameDelta, true), kNoError);
}
EXPECT_EQ((num_of_frames - 1) * kDefaultFramePeriodMs,
receiver_.RenderBufferSizeMs());
}
TEST_F(TestVCMReceiver, RenderBufferSize_NoKeyFrame) {
EXPECT_EQ(0, receiver_.RenderBufferSizeMs());
int num_of_frames = 10;
for (int i = 0; i < num_of_frames; ++i) {
EXPECT_GE(InsertFrame(kVideoFrameDelta, true), kNoError);
}
int64_t next_render_time_ms = 0;
VCMEncodedFrame* frame = receiver_.FrameForDecoding(10, next_render_time_ms);
EXPECT_TRUE(frame == NULL);
receiver_.ReleaseFrame(frame);
EXPECT_GE(InsertFrame(kVideoFrameDelta, false), kNoError);
for (int i = 0; i < num_of_frames; ++i) {
EXPECT_GE(InsertFrame(kVideoFrameDelta, true), kNoError);
}
EXPECT_EQ(0, receiver_.RenderBufferSizeMs());
}
TEST_F(TestVCMReceiver, NonDecodableDuration_Empty) {
// Enable NACK and with no RTT thresholds for disabling retransmission delay.
receiver_.SetNackMode(kNack, -1, -1);
const size_t kMaxNackListSize = 1000;
const int kMaxPacketAgeToNack = 1000;
const int kMaxNonDecodableDuration = 500;
const int kMinDelayMs = 500;
receiver_.SetNackSettings(kMaxNackListSize, kMaxPacketAgeToNack,
kMaxNonDecodableDuration);
EXPECT_GE(InsertFrame(kVideoFrameKey, true), kNoError);
// Advance time until it's time to decode the key frame.
clock_->AdvanceTimeMilliseconds(kMinDelayMs);
EXPECT_TRUE(DecodeNextFrame());
uint16_t nack_list[kMaxNackListSize];
uint16_t nack_list_length = 0;
VCMNackStatus ret = receiver_.NackList(nack_list, kMaxNackListSize,
&nack_list_length);
EXPECT_EQ(kNackOk, ret);
}
TEST_F(TestVCMReceiver, NonDecodableDuration_NoKeyFrame) {
// Enable NACK and with no RTT thresholds for disabling retransmission delay.
receiver_.SetNackMode(kNack, -1, -1);
const size_t kMaxNackListSize = 1000;
const int kMaxPacketAgeToNack = 1000;
const int kMaxNonDecodableDuration = 500;
receiver_.SetNackSettings(kMaxNackListSize, kMaxPacketAgeToNack,
kMaxNonDecodableDuration);
const int kNumFrames = kDefaultFrameRate * kMaxNonDecodableDuration / 1000;
for (int i = 0; i < kNumFrames; ++i) {
EXPECT_GE(InsertFrame(kVideoFrameDelta, true), kNoError);
}
uint16_t nack_list[kMaxNackListSize];
uint16_t nack_list_length = 0;
VCMNackStatus ret = receiver_.NackList(nack_list, kMaxNackListSize,
&nack_list_length);
EXPECT_EQ(kNackKeyFrameRequest, ret);
}
TEST_F(TestVCMReceiver, NonDecodableDuration_OneIncomplete) {
// Enable NACK and with no RTT thresholds for disabling retransmission delay.
receiver_.SetNackMode(kNack, -1, -1);
const size_t kMaxNackListSize = 1000;
const int kMaxPacketAgeToNack = 1000;
const int kMaxNonDecodableDuration = 500;
const int kMaxNonDecodableDurationFrames = (kDefaultFrameRate *
kMaxNonDecodableDuration + 500) / 1000;
const int kMinDelayMs = 500;
receiver_.SetNackSettings(kMaxNackListSize, kMaxPacketAgeToNack,
kMaxNonDecodableDuration);
receiver_.SetMinReceiverDelay(kMinDelayMs);
int64_t key_frame_inserted = clock_->TimeInMilliseconds();
EXPECT_GE(InsertFrame(kVideoFrameKey, true), kNoError);
// Insert an incomplete frame.
EXPECT_GE(InsertFrame(kVideoFrameDelta, false), kNoError);
// Insert enough frames to have too long non-decodable sequence.
for (int i = 0; i < kMaxNonDecodableDurationFrames;
++i) {
EXPECT_GE(InsertFrame(kVideoFrameDelta, true), kNoError);
}
// Advance time until it's time to decode the key frame.
clock_->AdvanceTimeMilliseconds(kMinDelayMs - clock_->TimeInMilliseconds() -
key_frame_inserted);
EXPECT_TRUE(DecodeNextFrame());
// Make sure we get a key frame request.
uint16_t nack_list[kMaxNackListSize];
uint16_t nack_list_length = 0;
VCMNackStatus ret = receiver_.NackList(nack_list, kMaxNackListSize,
&nack_list_length);
EXPECT_EQ(kNackKeyFrameRequest, ret);
}
TEST_F(TestVCMReceiver, NonDecodableDuration_NoTrigger) {
// Enable NACK and with no RTT thresholds for disabling retransmission delay.
receiver_.SetNackMode(kNack, -1, -1);
const size_t kMaxNackListSize = 1000;
const int kMaxPacketAgeToNack = 1000;
const int kMaxNonDecodableDuration = 500;
const int kMaxNonDecodableDurationFrames = (kDefaultFrameRate *
kMaxNonDecodableDuration + 500) / 1000;
const int kMinDelayMs = 500;
receiver_.SetNackSettings(kMaxNackListSize, kMaxPacketAgeToNack,
kMaxNonDecodableDuration);
receiver_.SetMinReceiverDelay(kMinDelayMs);
int64_t key_frame_inserted = clock_->TimeInMilliseconds();
EXPECT_GE(InsertFrame(kVideoFrameKey, true), kNoError);
// Insert an incomplete frame.
EXPECT_GE(InsertFrame(kVideoFrameDelta, false), kNoError);
// Insert all but one frame to not trigger a key frame request due to
// too long duration of non-decodable frames.
for (int i = 0; i < kMaxNonDecodableDurationFrames - 1;
++i) {
EXPECT_GE(InsertFrame(kVideoFrameDelta, true), kNoError);
}
// Advance time until it's time to decode the key frame.
clock_->AdvanceTimeMilliseconds(kMinDelayMs - clock_->TimeInMilliseconds() -
key_frame_inserted);
EXPECT_TRUE(DecodeNextFrame());
// Make sure we don't get a key frame request since we haven't generated
// enough frames.
uint16_t nack_list[kMaxNackListSize];
uint16_t nack_list_length = 0;
VCMNackStatus ret = receiver_.NackList(nack_list, kMaxNackListSize,
&nack_list_length);
EXPECT_EQ(kNackOk, ret);
}
TEST_F(TestVCMReceiver, NonDecodableDuration_NoTrigger2) {
// Enable NACK and with no RTT thresholds for disabling retransmission delay.
receiver_.SetNackMode(kNack, -1, -1);
const size_t kMaxNackListSize = 1000;
const int kMaxPacketAgeToNack = 1000;
const int kMaxNonDecodableDuration = 500;
const int kMaxNonDecodableDurationFrames = (kDefaultFrameRate *
kMaxNonDecodableDuration + 500) / 1000;
const int kMinDelayMs = 500;
receiver_.SetNackSettings(kMaxNackListSize, kMaxPacketAgeToNack,
kMaxNonDecodableDuration);
receiver_.SetMinReceiverDelay(kMinDelayMs);
int64_t key_frame_inserted = clock_->TimeInMilliseconds();
EXPECT_GE(InsertFrame(kVideoFrameKey, true), kNoError);
// Insert enough frames to have too long non-decodable sequence, except that
// we don't have any losses.
for (int i = 0; i < kMaxNonDecodableDurationFrames;
++i) {
EXPECT_GE(InsertFrame(kVideoFrameDelta, true), kNoError);
}
// Insert an incomplete frame.
EXPECT_GE(InsertFrame(kVideoFrameDelta, false), kNoError);
// Advance time until it's time to decode the key frame.
clock_->AdvanceTimeMilliseconds(kMinDelayMs - clock_->TimeInMilliseconds() -
key_frame_inserted);
EXPECT_TRUE(DecodeNextFrame());
// Make sure we don't get a key frame request since the non-decodable duration
// is only one frame.
uint16_t nack_list[kMaxNackListSize];
uint16_t nack_list_length = 0;
VCMNackStatus ret = receiver_.NackList(nack_list, kMaxNackListSize,
&nack_list_length);
EXPECT_EQ(kNackOk, ret);
}
TEST_F(TestVCMReceiver, NonDecodableDuration_KeyFrameAfterIncompleteFrames) {
// Enable NACK and with no RTT thresholds for disabling retransmission delay.
receiver_.SetNackMode(kNack, -1, -1);
const size_t kMaxNackListSize = 1000;
const int kMaxPacketAgeToNack = 1000;
const int kMaxNonDecodableDuration = 500;
const int kMaxNonDecodableDurationFrames = (kDefaultFrameRate *
kMaxNonDecodableDuration + 500) / 1000;
const int kMinDelayMs = 500;
receiver_.SetNackSettings(kMaxNackListSize, kMaxPacketAgeToNack,
kMaxNonDecodableDuration);
receiver_.SetMinReceiverDelay(kMinDelayMs);
int64_t key_frame_inserted = clock_->TimeInMilliseconds();
EXPECT_GE(InsertFrame(kVideoFrameKey, true), kNoError);
// Insert an incomplete frame.
EXPECT_GE(InsertFrame(kVideoFrameDelta, false), kNoError);
// Insert enough frames to have too long non-decodable sequence.
for (int i = 0; i < kMaxNonDecodableDurationFrames;
++i) {
EXPECT_GE(InsertFrame(kVideoFrameDelta, true), kNoError);
}
EXPECT_GE(InsertFrame(kVideoFrameKey, true), kNoError);
// Advance time until it's time to decode the key frame.
clock_->AdvanceTimeMilliseconds(kMinDelayMs - clock_->TimeInMilliseconds() -
key_frame_inserted);
EXPECT_TRUE(DecodeNextFrame());
// Make sure we don't get a key frame request since we have a key frame
// in the list.
uint16_t nack_list[kMaxNackListSize];
uint16_t nack_list_length = 0;
VCMNackStatus ret = receiver_.NackList(nack_list, kMaxNackListSize,
&nack_list_length);
EXPECT_EQ(kNackOk, ret);
}
} // namespace webrtc