New VCM robustness API
This CL defines and starts to implement a new robustness API for video coding module. The API is partly implemented. Some of the modes and methods are still TBD. Also including a new unittest with mocking of decoder and callbacks, and faking of system clock. Review URL: http://webrtc-codereview.appspot.com/333006 git-svn-id: http://webrtc.googlecode.com/svn/trunk@1276 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
parent
697bc43b67
commit
4a19030131
@ -14,6 +14,7 @@
|
||||
#include <string>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "modules/video_coding/codecs/interface/video_codec_interface.h"
|
||||
#include "typedefs.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) 2011 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_MAIN_INTERFACE_MOCK_MOCK_VCM_CALLBACKS_H_
|
||||
#define WEBRTC_MODULES_VIDEO_CODING_MAIN_INTERFACE_MOCK_MOCK_VCM_CALLBACKS_H_
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "typedefs.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class MockVCMFrameTypeCallback : public VCMFrameTypeCallback {
|
||||
public:
|
||||
MOCK_METHOD1(FrameTypeRequest, int32_t(const FrameType frameType));
|
||||
MOCK_METHOD1(SliceLossIndicationRequest,
|
||||
WebRtc_Word32(const WebRtc_UWord64 pictureId));
|
||||
};
|
||||
|
||||
class MockPacketRequestCallback : public VCMPacketRequestCallback {
|
||||
public:
|
||||
MOCK_METHOD2(ResendPackets, int32_t(const uint16_t* sequenceNumbers,
|
||||
uint16_t length));
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_VIDEO_CODING_MAIN_INTERFACE_MOCK_MOCK_VCM_CALLBACKS_H_
|
@ -26,6 +26,25 @@ struct CodecSpecificInfo;
|
||||
class VideoCodingModule : public Module
|
||||
{
|
||||
public:
|
||||
enum SenderNackMode {
|
||||
kNackNone,
|
||||
kNackAll,
|
||||
kNackSelective
|
||||
};
|
||||
|
||||
enum ReceiverRobustness {
|
||||
kNone,
|
||||
kHardNack,
|
||||
kSoftNack,
|
||||
kDualDecoder,
|
||||
kReferenceSelection
|
||||
};
|
||||
|
||||
enum DecodeErrors {
|
||||
kNoDecodeErrors,
|
||||
kAllowDecodeErrors
|
||||
};
|
||||
|
||||
static VideoCodingModule* Create(const WebRtc_Word32 id);
|
||||
|
||||
static VideoCodingModule* Create(const WebRtc_Word32 id,
|
||||
@ -501,6 +520,57 @@ public:
|
||||
// frame was sent to the decoder. Therefore packets which were prematurely
|
||||
// NACKed will be counted.
|
||||
virtual WebRtc_UWord32 DiscardedPackets() const = 0;
|
||||
|
||||
|
||||
// Robustness APIs
|
||||
|
||||
// Set the sender RTX/NACK mode.
|
||||
// Input:
|
||||
// - mode : the selected NACK mode.
|
||||
//
|
||||
// Return value : VCM_OK, on success;
|
||||
// < 0, on error.
|
||||
virtual int SetSenderNackMode(SenderNackMode mode) = 0;
|
||||
|
||||
// Set the sender reference picture selection (RPS) mode.
|
||||
// Input:
|
||||
// - enable : true or false, for enable and disable, respectively.
|
||||
//
|
||||
// Return value : VCM_OK, on success;
|
||||
// < 0, on error.
|
||||
virtual int SetSenderReferenceSelection(bool enable) = 0;
|
||||
|
||||
// Set the sender forward error correction (FEC) mode.
|
||||
// Input:
|
||||
// - enable : true or false, for enable and disable, respectively.
|
||||
//
|
||||
// Return value : VCM_OK, on success;
|
||||
// < 0, on error.
|
||||
virtual int SetSenderFEC(bool enable) = 0;
|
||||
|
||||
// Set the key frame period, or disable periodic key frames (I-frames).
|
||||
// Input:
|
||||
// - periodMs : period in ms; <= 0 to disable periodic key frames.
|
||||
//
|
||||
// Return value : VCM_OK, on success;
|
||||
// < 0, on error.
|
||||
virtual int SetSenderKeyFramePeriod(int periodMs) = 0;
|
||||
|
||||
// Set the receiver robustness mode. The mode decides how the receiver
|
||||
// responds to losses in the stream. The type of counter-measure (soft or
|
||||
// hard NACK, dual decoder, RPS, etc.) is selected through the
|
||||
// robustnessMode parameter. The errorMode parameter decides if it is
|
||||
// allowed to display frames corrupted by losses. Note that not all
|
||||
// combinations of the two parameters are feasible. An error will be
|
||||
// returned for invalid combinations.
|
||||
// Input:
|
||||
// - robustnessMode : selected robustness mode.
|
||||
// - errorMode : selected error mode.
|
||||
//
|
||||
// Return value : VCM_OK, on success;
|
||||
// < 0, on error.
|
||||
virtual int SetReceiverRobustnessMode(ReceiverRobustness robustnessMode,
|
||||
DecodeErrors errorMode) = 0;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
@ -1578,4 +1578,85 @@ WebRtc_UWord32 VideoCodingModuleImpl::DiscardedPackets() const {
|
||||
return _receiver.DiscardedPackets();
|
||||
}
|
||||
|
||||
int VideoCodingModuleImpl::SetSenderNackMode(SenderNackMode mode) {
|
||||
CriticalSectionScoped cs(_sendCritSect);
|
||||
|
||||
switch (mode) {
|
||||
case kNackNone:
|
||||
_mediaOpt.EnableProtectionMethod(false, kNack);
|
||||
break;
|
||||
case kNackAll:
|
||||
_mediaOpt.EnableProtectionMethod(true, kNack);
|
||||
break;
|
||||
case kNackSelective:
|
||||
return VCM_NOT_IMPLEMENTED;
|
||||
break;
|
||||
}
|
||||
return VCM_OK;
|
||||
}
|
||||
|
||||
int VideoCodingModuleImpl::SetSenderReferenceSelection(bool enable) {
|
||||
return VCM_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
int VideoCodingModuleImpl::SetSenderFEC(bool enable) {
|
||||
CriticalSectionScoped cs(_sendCritSect);
|
||||
_mediaOpt.EnableProtectionMethod(enable, kFec);
|
||||
return VCM_OK;
|
||||
}
|
||||
|
||||
int VideoCodingModuleImpl::SetSenderKeyFramePeriod(int periodMs) {
|
||||
return VCM_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
int VideoCodingModuleImpl::SetReceiverRobustnessMode(
|
||||
ReceiverRobustness robustnessMode,
|
||||
DecodeErrors errorMode) {
|
||||
CriticalSectionScoped cs(_receiveCritSect);
|
||||
switch (robustnessMode) {
|
||||
case kNone:
|
||||
_receiver.SetNackMode(kNoNack);
|
||||
_dualReceiver.SetNackMode(kNoNack);
|
||||
if (errorMode == kNoDecodeErrors) {
|
||||
_keyRequestMode = kKeyOnLoss;
|
||||
} else {
|
||||
_keyRequestMode = kKeyOnError;
|
||||
}
|
||||
break;
|
||||
case kHardNack:
|
||||
if (errorMode == kAllowDecodeErrors) {
|
||||
return VCM_PARAMETER_ERROR;
|
||||
}
|
||||
_receiver.SetNackMode(kNackInfinite);
|
||||
_dualReceiver.SetNackMode(kNoNack);
|
||||
_keyRequestMode = kKeyOnError; // TODO(hlundin): On long NACK list?
|
||||
break;
|
||||
case kSoftNack:
|
||||
assert(false); // TODO(hlundin): Not completed.
|
||||
return VCM_NOT_IMPLEMENTED;
|
||||
_receiver.SetNackMode(kNackHybrid);
|
||||
_dualReceiver.SetNackMode(kNoNack);
|
||||
_keyRequestMode = kKeyOnError;
|
||||
break;
|
||||
case kDualDecoder:
|
||||
if (errorMode == kNoDecodeErrors) {
|
||||
return VCM_PARAMETER_ERROR;
|
||||
}
|
||||
_receiver.SetNackMode(kNoNack);
|
||||
_dualReceiver.SetNackMode(kNackInfinite);
|
||||
_keyRequestMode = kKeyOnError;
|
||||
break;
|
||||
case kReferenceSelection:
|
||||
assert(false); // TODO(hlundin): Not completed.
|
||||
return VCM_NOT_IMPLEMENTED;
|
||||
if (errorMode == kNoDecodeErrors) {
|
||||
return VCM_PARAMETER_ERROR;
|
||||
}
|
||||
_receiver.SetNackMode(kNoNack);
|
||||
_dualReceiver.SetNackMode(kNoNack);
|
||||
break;
|
||||
}
|
||||
return VCM_OK;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
@ -256,6 +256,25 @@ public:
|
||||
// Returns the number of packets discarded by the jitter buffer.
|
||||
virtual WebRtc_UWord32 DiscardedPackets() const;
|
||||
|
||||
|
||||
// Robustness APIs
|
||||
|
||||
// Set the sender RTX/NACK mode.
|
||||
virtual int SetSenderNackMode(SenderNackMode mode);
|
||||
|
||||
// Set the sender reference picture selection (RPS) mode.
|
||||
virtual int SetSenderReferenceSelection(bool enable);
|
||||
|
||||
// Set the sender forward error correction (FEC) mode.
|
||||
virtual int SetSenderFEC(bool enable);
|
||||
|
||||
// Set the key frame period, or disable periodic key frames (I-frames).
|
||||
virtual int SetSenderKeyFramePeriod(int periodMs);
|
||||
|
||||
// Set the receiver robustness mode.
|
||||
virtual int SetReceiverRobustnessMode(ReceiverRobustness robustnessMode,
|
||||
DecodeErrors errorMode);
|
||||
|
||||
protected:
|
||||
WebRtc_Word32 Decode(const webrtc::VCMEncodedFrame& frame);
|
||||
WebRtc_Word32 RequestKeyFrame();
|
||||
|
@ -0,0 +1,373 @@
|
||||
/*
|
||||
* Copyright (c) 2011 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 "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "modules/video_coding/codecs/interface/mock/mock_video_codec_interface.h"
|
||||
#include "modules/video_coding/main/interface/video_coding.h"
|
||||
#include "modules/video_coding/main/interface/mock/mock_vcm_callbacks.h"
|
||||
#include "modules/video_coding/main/source/mock/fake_tick_time.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
using ::testing::Return;
|
||||
using ::testing::_;
|
||||
using ::testing::ElementsAre;
|
||||
using ::testing::AllOf;
|
||||
using ::testing::Args;
|
||||
using ::testing::Field;
|
||||
using ::testing::Pointee;
|
||||
using ::testing::NiceMock;
|
||||
using ::testing::Sequence;
|
||||
|
||||
class VCMRobustnessTest : public ::testing::Test {
|
||||
protected:
|
||||
static const size_t kPayloadLen = 10;
|
||||
|
||||
virtual void SetUp() {
|
||||
clock_ = new FakeTickTime(0);
|
||||
ASSERT_TRUE(clock_ != NULL);
|
||||
vcm_ = VideoCodingModule::Create(0, clock_);
|
||||
ASSERT_TRUE(vcm_ != NULL);
|
||||
ASSERT_EQ(0, vcm_->InitializeReceiver());
|
||||
ASSERT_EQ(0, vcm_->RegisterFrameTypeCallback(&frame_type_callback_));
|
||||
ASSERT_EQ(0, vcm_->RegisterPacketRequestCallback(&request_callback_));
|
||||
ASSERT_EQ(VCM_OK, vcm_->Codec(kVideoCodecVP8, &video_codec_));
|
||||
ASSERT_EQ(VCM_OK, vcm_->RegisterReceiveCodec(&video_codec_, 1));
|
||||
ASSERT_EQ(VCM_OK, vcm_->RegisterExternalDecoder(&decoder_,
|
||||
video_codec_.plType,
|
||||
true));
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
VideoCodingModule::Destroy(vcm_);
|
||||
delete clock_;
|
||||
}
|
||||
|
||||
void InsertPacket(uint32_t timestamp,
|
||||
uint16_t seq_no,
|
||||
bool first,
|
||||
bool marker_bit,
|
||||
FrameType frame_type) {
|
||||
const uint8_t payload[kPayloadLen] = {0};
|
||||
WebRtcRTPHeader rtp_info;
|
||||
memset(&rtp_info, 0, sizeof(rtp_info));
|
||||
rtp_info.frameType = frame_type;
|
||||
rtp_info.header.timestamp = timestamp;
|
||||
rtp_info.header.sequenceNumber = seq_no;
|
||||
rtp_info.header.markerBit = marker_bit;
|
||||
rtp_info.header.payloadType = video_codec_.plType;
|
||||
rtp_info.type.Video.codec = kRTPVideoVP8;
|
||||
rtp_info.type.Video.codecHeader.VP8.InitRTPVideoHeaderVP8();
|
||||
rtp_info.type.Video.isFirstPacket = first;
|
||||
|
||||
ASSERT_EQ(VCM_OK, vcm_->IncomingPacket(payload, kPayloadLen, rtp_info));
|
||||
}
|
||||
|
||||
VideoCodingModule* vcm_;
|
||||
VideoCodec video_codec_;
|
||||
MockVCMFrameTypeCallback frame_type_callback_;
|
||||
MockPacketRequestCallback request_callback_;
|
||||
NiceMock<MockVideoDecoder> decoder_;
|
||||
NiceMock<MockVideoDecoder> decoderCopy_;
|
||||
FakeTickTime* clock_;
|
||||
};
|
||||
|
||||
TEST_F(VCMRobustnessTest, TestHardNack) {
|
||||
Sequence s;
|
||||
EXPECT_CALL(request_callback_, ResendPackets(_, 2))
|
||||
.With(Args<0, 1>(ElementsAre(6, 7)))
|
||||
.Times(1);
|
||||
for (int ts = 0; ts <= 6000; ts += 3000) {
|
||||
EXPECT_CALL(decoder_, Decode(AllOf(Field(&EncodedImage::_timeStamp, ts),
|
||||
Field(&EncodedImage::_length,
|
||||
kPayloadLen * 3),
|
||||
Field(&EncodedImage::_completeFrame,
|
||||
true)),
|
||||
false, _, _, _))
|
||||
.Times(1)
|
||||
.InSequence(s);
|
||||
}
|
||||
|
||||
ASSERT_EQ(VCM_OK, vcm_->SetReceiverRobustnessMode(
|
||||
VideoCodingModule::kHardNack,
|
||||
VideoCodingModule::kNoDecodeErrors));
|
||||
|
||||
InsertPacket(0, 0, true, false, kVideoFrameKey);
|
||||
InsertPacket(0, 1, false, false, kVideoFrameKey);
|
||||
InsertPacket(0, 2, false, true, kVideoFrameKey);
|
||||
|
||||
InsertPacket(3000, 3, true, false, kVideoFrameDelta);
|
||||
InsertPacket(3000, 4, false, false, kVideoFrameDelta);
|
||||
InsertPacket(3000, 5, false, true, kVideoFrameDelta);
|
||||
|
||||
ASSERT_EQ(VCM_OK, vcm_->Decode(0));
|
||||
ASSERT_EQ(VCM_OK, vcm_->Decode(0));
|
||||
ASSERT_EQ(VCM_FRAME_NOT_READY, vcm_->Decode(0));
|
||||
|
||||
clock_->IncrementDebugClock(10);
|
||||
|
||||
ASSERT_EQ(VCM_OK, vcm_->Process());
|
||||
|
||||
ASSERT_EQ(VCM_FRAME_NOT_READY, vcm_->Decode(0));
|
||||
|
||||
InsertPacket(6000, 8, false, true, kVideoFrameDelta);
|
||||
clock_->IncrementDebugClock(10);
|
||||
ASSERT_EQ(VCM_OK, vcm_->Process());
|
||||
|
||||
ASSERT_EQ(VCM_FRAME_NOT_READY, vcm_->Decode(0));
|
||||
|
||||
InsertPacket(6000, 6, true, false, kVideoFrameDelta);
|
||||
InsertPacket(6000, 7, false, false, kVideoFrameDelta);
|
||||
clock_->IncrementDebugClock(10);
|
||||
ASSERT_EQ(VCM_OK, vcm_->Process());
|
||||
|
||||
ASSERT_EQ(VCM_OK, vcm_->Decode(0));
|
||||
}
|
||||
|
||||
TEST_F(VCMRobustnessTest, TestDualDecoder) {
|
||||
Sequence s1, s2;
|
||||
EXPECT_CALL(request_callback_, ResendPackets(_, 1))
|
||||
.With(Args<0, 1>(ElementsAre(4)))
|
||||
.Times(1);
|
||||
|
||||
EXPECT_CALL(decoder_, Copy())
|
||||
.Times(1)
|
||||
.WillOnce(Return(&decoderCopy_));
|
||||
EXPECT_CALL(decoderCopy_, Copy())
|
||||
.Times(1)
|
||||
.WillOnce(Return(&decoder_));
|
||||
|
||||
// Decode operations
|
||||
EXPECT_CALL(decoder_, Decode(AllOf(Field(&EncodedImage::_timeStamp, 0),
|
||||
Field(&EncodedImage::_completeFrame,
|
||||
true)),
|
||||
false, _, _, _))
|
||||
.Times(1)
|
||||
.InSequence(s1);
|
||||
EXPECT_CALL(decoder_, Decode(AllOf(Field(&EncodedImage::_timeStamp, 3000),
|
||||
Field(&EncodedImage::_completeFrame,
|
||||
false)),
|
||||
false, _, _, _))
|
||||
.Times(1)
|
||||
.InSequence(s1);
|
||||
EXPECT_CALL(decoder_, Decode(AllOf(Field(&EncodedImage::_timeStamp, 6000),
|
||||
Field(&EncodedImage::_completeFrame,
|
||||
true)),
|
||||
false, _, _, _))
|
||||
.Times(1)
|
||||
.InSequence(s1);
|
||||
EXPECT_CALL(decoder_, Decode(AllOf(Field(&EncodedImage::_timeStamp, 9000),
|
||||
Field(&EncodedImage::_completeFrame,
|
||||
true)),
|
||||
false, _, _, _))
|
||||
.Times(1)
|
||||
.InSequence(s1);
|
||||
|
||||
EXPECT_CALL(decoderCopy_, Decode(AllOf(Field(&EncodedImage::_timeStamp, 3000),
|
||||
Field(&EncodedImage::_completeFrame,
|
||||
true)),
|
||||
false, _, _, _))
|
||||
.Times(1)
|
||||
.InSequence(s2);
|
||||
EXPECT_CALL(decoderCopy_, Decode(AllOf(Field(&EncodedImage::_timeStamp, 6000),
|
||||
Field(&EncodedImage::_completeFrame,
|
||||
true)),
|
||||
false, _, _, _))
|
||||
.Times(1)
|
||||
.InSequence(s2);
|
||||
|
||||
|
||||
ASSERT_EQ(VCM_OK, vcm_->SetReceiverRobustnessMode(
|
||||
VideoCodingModule::kDualDecoder,
|
||||
VideoCodingModule::kAllowDecodeErrors));
|
||||
|
||||
InsertPacket(0, 0, true, false, kVideoFrameKey);
|
||||
InsertPacket(0, 1, false, false, kVideoFrameKey);
|
||||
InsertPacket(0, 2, false, true, kVideoFrameKey);
|
||||
EXPECT_EQ(VCM_OK, vcm_->Decode(0)); // Decode timestamp 0.
|
||||
|
||||
clock_->IncrementDebugClock(33);
|
||||
InsertPacket(3000, 3, true, false, kVideoFrameDelta);
|
||||
// Packet 4 missing
|
||||
InsertPacket(3000, 5, false, true, kVideoFrameDelta);
|
||||
EXPECT_EQ(VCM_FRAME_NOT_READY, vcm_->Decode(0));
|
||||
|
||||
clock_->IncrementDebugClock(33);
|
||||
InsertPacket(6000, 6, true, false, kVideoFrameDelta);
|
||||
InsertPacket(6000, 7, false, false, kVideoFrameDelta);
|
||||
InsertPacket(6000, 8, false, true, kVideoFrameDelta);
|
||||
|
||||
EXPECT_EQ(VCM_OK, vcm_->Decode(0)); // Decode timestamp 3000 incomplete.
|
||||
// Spawn a decoder copy.
|
||||
EXPECT_EQ(0, vcm_->DecodeDualFrame(0)); // Expect no dual decoder action.
|
||||
|
||||
clock_->IncrementDebugClock(10);
|
||||
EXPECT_EQ(VCM_OK, vcm_->Process()); // Generate NACK list.
|
||||
|
||||
EXPECT_EQ(VCM_OK, vcm_->Decode(0)); // Decode timestamp 6000 complete.
|
||||
EXPECT_EQ(0, vcm_->DecodeDualFrame(0)); // Expect no dual decoder action.
|
||||
|
||||
InsertPacket(3000, 4, false, false, kVideoFrameDelta);
|
||||
EXPECT_EQ(1, vcm_->DecodeDualFrame(0)); // Dual decode of timestamp 3000.
|
||||
EXPECT_EQ(1, vcm_->DecodeDualFrame(0)); // Dual decode of timestamp 6000.
|
||||
EXPECT_EQ(0, vcm_->DecodeDualFrame(0)); // No more frames.
|
||||
|
||||
InsertPacket(9000, 9, true, false, kVideoFrameDelta);
|
||||
InsertPacket(9000, 10, false, false, kVideoFrameDelta);
|
||||
InsertPacket(9000, 11, false, true, kVideoFrameDelta);
|
||||
EXPECT_EQ(VCM_OK, vcm_->Decode(0)); // Decode timestamp 9000 complete.
|
||||
EXPECT_EQ(0, vcm_->DecodeDualFrame(0)); // Expect no dual decoder action.
|
||||
}
|
||||
|
||||
TEST_F(VCMRobustnessTest, TestModeNoneWithErrors) {
|
||||
EXPECT_CALL(decoder_, InitDecode(_, _)).Times(1);
|
||||
EXPECT_CALL(decoder_, Release()).Times(1);
|
||||
Sequence s1;
|
||||
EXPECT_CALL(request_callback_, ResendPackets(_, 1))
|
||||
.With(Args<0, 1>(ElementsAre(4)))
|
||||
.Times(0);
|
||||
|
||||
EXPECT_CALL(decoder_, Copy())
|
||||
.Times(0);
|
||||
EXPECT_CALL(decoderCopy_, Copy())
|
||||
.Times(0);
|
||||
|
||||
// Decode operations
|
||||
EXPECT_CALL(decoder_, Decode(AllOf(Field(&EncodedImage::_timeStamp, 0),
|
||||
Field(&EncodedImage::_completeFrame,
|
||||
true)),
|
||||
false, _, _, _))
|
||||
.Times(1)
|
||||
.InSequence(s1);
|
||||
EXPECT_CALL(decoder_, Decode(AllOf(Field(&EncodedImage::_timeStamp, 3000),
|
||||
Field(&EncodedImage::_completeFrame,
|
||||
false)),
|
||||
false, _, _, _))
|
||||
.Times(1)
|
||||
.InSequence(s1);
|
||||
EXPECT_CALL(decoder_, Decode(AllOf(Field(&EncodedImage::_timeStamp, 6000),
|
||||
Field(&EncodedImage::_completeFrame,
|
||||
true)),
|
||||
false, _, _, _))
|
||||
.Times(1)
|
||||
.InSequence(s1);
|
||||
EXPECT_CALL(decoder_, Decode(AllOf(Field(&EncodedImage::_timeStamp, 9000),
|
||||
Field(&EncodedImage::_completeFrame,
|
||||
true)),
|
||||
false, _, _, _))
|
||||
.Times(1)
|
||||
.InSequence(s1);
|
||||
|
||||
ASSERT_EQ(VCM_OK, vcm_->SetReceiverRobustnessMode(
|
||||
VideoCodingModule::kNone,
|
||||
VideoCodingModule::kAllowDecodeErrors));
|
||||
|
||||
InsertPacket(0, 0, true, false, kVideoFrameKey);
|
||||
InsertPacket(0, 1, false, false, kVideoFrameKey);
|
||||
InsertPacket(0, 2, false, true, kVideoFrameKey);
|
||||
EXPECT_EQ(VCM_OK, vcm_->Decode(0)); // Decode timestamp 0.
|
||||
EXPECT_EQ(VCM_OK, vcm_->Process()); // Expect no NACK list.
|
||||
|
||||
clock_->IncrementDebugClock(33);
|
||||
InsertPacket(3000, 3, true, false, kVideoFrameDelta);
|
||||
// Packet 4 missing
|
||||
InsertPacket(3000, 5, false, true, kVideoFrameDelta);
|
||||
EXPECT_EQ(VCM_FRAME_NOT_READY, vcm_->Decode(0));
|
||||
EXPECT_EQ(VCM_OK, vcm_->Process()); // Expect no NACK list.
|
||||
|
||||
clock_->IncrementDebugClock(33);
|
||||
InsertPacket(6000, 6, true, false, kVideoFrameDelta);
|
||||
InsertPacket(6000, 7, false, false, kVideoFrameDelta);
|
||||
InsertPacket(6000, 8, false, true, kVideoFrameDelta);
|
||||
EXPECT_EQ(VCM_OK, vcm_->Decode(0)); // Decode timestamp 3000 incomplete.
|
||||
EXPECT_EQ(VCM_OK, vcm_->Process()); // Expect no NACK list.
|
||||
|
||||
clock_->IncrementDebugClock(10);
|
||||
EXPECT_EQ(VCM_OK, vcm_->Decode(0)); // Decode timestamp 6000 complete.
|
||||
EXPECT_EQ(VCM_OK, vcm_->Process()); // Expect no NACK list.
|
||||
|
||||
clock_->IncrementDebugClock(23);
|
||||
InsertPacket(3000, 4, false, false, kVideoFrameDelta);
|
||||
|
||||
InsertPacket(9000, 9, true, false, kVideoFrameDelta);
|
||||
InsertPacket(9000, 10, false, false, kVideoFrameDelta);
|
||||
InsertPacket(9000, 11, false, true, kVideoFrameDelta);
|
||||
EXPECT_EQ(VCM_OK, vcm_->Decode(0)); // Decode timestamp 9000 complete.
|
||||
}
|
||||
|
||||
TEST_F(VCMRobustnessTest, TestModeNoneWithoutErrors) {
|
||||
Sequence s1;
|
||||
EXPECT_CALL(decoder_, InitDecode(_, _)).Times(1);
|
||||
EXPECT_CALL(decoder_, Release()).Times(1);
|
||||
EXPECT_CALL(request_callback_, ResendPackets(_, 1))
|
||||
.With(Args<0, 1>(ElementsAre(4)))
|
||||
.Times(0);
|
||||
|
||||
EXPECT_CALL(decoder_, Copy())
|
||||
.Times(0);
|
||||
EXPECT_CALL(decoderCopy_, Copy())
|
||||
.Times(0);
|
||||
|
||||
// Decode operations
|
||||
EXPECT_CALL(decoder_, Decode(AllOf(Field(&EncodedImage::_timeStamp, 0),
|
||||
Field(&EncodedImage::_completeFrame,
|
||||
true)),
|
||||
false, _, _, _))
|
||||
.Times(1)
|
||||
.InSequence(s1);
|
||||
EXPECT_CALL(decoder_, Decode(AllOf(Field(&EncodedImage::_timeStamp, 3000),
|
||||
Field(&EncodedImage::_completeFrame,
|
||||
false)),
|
||||
false, _, _, _))
|
||||
.Times(1)
|
||||
.InSequence(s1);
|
||||
EXPECT_CALL(decoder_, Decode(AllOf(Field(&EncodedImage::_timeStamp, 6000),
|
||||
Field(&EncodedImage::_completeFrame,
|
||||
true)),
|
||||
false, _, _, _))
|
||||
.Times(1)
|
||||
.InSequence(s1);
|
||||
EXPECT_CALL(frame_type_callback_, FrameTypeRequest(kVideoFrameKey))
|
||||
.Times(1);
|
||||
|
||||
ASSERT_EQ(VCM_OK, vcm_->SetReceiverRobustnessMode(
|
||||
VideoCodingModule::kNone,
|
||||
VideoCodingModule::kNoDecodeErrors));
|
||||
|
||||
InsertPacket(0, 0, true, false, kVideoFrameKey);
|
||||
InsertPacket(0, 1, false, false, kVideoFrameKey);
|
||||
InsertPacket(0, 2, false, true, kVideoFrameKey);
|
||||
EXPECT_EQ(VCM_OK, vcm_->Decode(0)); // Decode timestamp 0.
|
||||
EXPECT_EQ(VCM_OK, vcm_->Process()); // Expect no NACK list.
|
||||
|
||||
clock_->IncrementDebugClock(33);
|
||||
InsertPacket(3000, 3, true, false, kVideoFrameDelta);
|
||||
// Packet 4 missing
|
||||
InsertPacket(3000, 5, false, true, kVideoFrameDelta);
|
||||
EXPECT_EQ(VCM_FRAME_NOT_READY, vcm_->Decode(0));
|
||||
EXPECT_EQ(VCM_OK, vcm_->Process()); // Expect no NACK list.
|
||||
|
||||
clock_->IncrementDebugClock(33);
|
||||
InsertPacket(6000, 6, true, false, kVideoFrameDelta);
|
||||
InsertPacket(6000, 7, false, false, kVideoFrameDelta);
|
||||
InsertPacket(6000, 8, false, true, kVideoFrameDelta);
|
||||
EXPECT_EQ(VCM_OK, vcm_->Decode(0)); // Decode timestamp 3000 incomplete.
|
||||
// Schedule key frame request.
|
||||
EXPECT_EQ(VCM_OK, vcm_->Process()); // Expect no NACK list.
|
||||
|
||||
clock_->IncrementDebugClock(10);
|
||||
EXPECT_EQ(VCM_OK, vcm_->Decode(0)); // Decode timestamp 6000 complete.
|
||||
EXPECT_EQ(VCM_OK, vcm_->Process()); // Expect no NACK list.
|
||||
|
||||
clock_->IncrementDebugClock(500); // Wait for the key request timer to set.
|
||||
EXPECT_EQ(VCM_OK, vcm_->Process()); // Expect key frame request.
|
||||
}
|
||||
} // namespace webrtc
|
@ -69,13 +69,17 @@
|
||||
'webrtc_video_coding',
|
||||
'<(webrtc_root)/../test/test.gyp:test_support_main',
|
||||
'<(webrtc_root)/../testing/gtest.gyp:gtest',
|
||||
'<(webrtc_root)/../testing/gmock.gyp:gmock',
|
||||
'<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:system_wrappers',
|
||||
],
|
||||
'include_dirs': [
|
||||
'../../../interface',
|
||||
'../../codecs/interface',
|
||||
],
|
||||
'sources': [
|
||||
'../interface/mock/mock_vcm_callbacks.h',
|
||||
'session_info_unittest.cc',
|
||||
'video_coding_robustness_unittest.cc',
|
||||
],
|
||||
},
|
||||
],
|
||||
|
Loading…
x
Reference in New Issue
Block a user