先从VideoCaptureInputTest分析VideoCaptureInput的用法,后续再分析具体实现。
VideoCaptureInputTest的实现,依赖google的gmock/gtest单元测试框架:
http://code.google.com/p/googlemock/wiki/CheatSheet
http://blog.csdn.net/russell_tao/article/details/7344739
http://www.2cto.com/kf/201406/307020.html
MOCK_METHOD#1(#2, #3(#4) )
#1表示被mock的函数参数个数,#2表示被mock的函数名称,#3表示被mock的函数返回值,#4表示被mock的函数参数列表ON_CALL(#1, #2(#3)).WillByDefault(Return(#4));
#1表示mock对象。定义了一个Mock类,那么就必须生成相应的mock对象EXPECT_CALL(mock_object, method(matchers))
.Times(cardinality)
.WillOnce(action)
.WillRepeatedly(action);
第一个参数是mock对象,第二个参数是mock函数名及其参数。二者中间是以逗号;宏后面还可以紧跟若干语句,以提供对mock函数调用的预期结果的更多信息,Times表示执行次数,WillOnce代表执行1次,WillRepeatedly代表重复执行,action代表预期行为,如果没有指定,系统将会为其指派默认行为(什么都不做,返回0),并且在屏幕上打印WARNING这种风格的语法被一些人称作是“特定领域语言”(Domain-Specific Language,DSL)。
https://code.google.com/p/googletest/wiki/V1_7_Primer
http://www.cnblogs.com/coderzh/archive/2009/04/06/1430364.html
ASSERT_* 系列的断言,当检查点失败时,退出当前函数(注意:并非退出当前案例)。 VideoCaptureInputTest()
: mock_process_thread_(new NiceMock),
mock_frame_callback_(new NiceMock),
output_frame_event_(EventWrapper::Create()),
stats_proxy_(Clock::GetRealTimeClock(),
webrtc::VideoSendStream::Config(nullptr)) {}
其中mock_process_thread_变量mock了ProcessThread对象,而mock_frame_callback_则mock了VideoCaptureCallback对象,目的就是对VideoCaptureInput的输入输出进行打桩,用于测试其处理逻辑,相关的定义如下,都是继承自现有类:class MockVideoCaptureCallback : public VideoCaptureCallback {
public:
MOCK_METHOD1(DeliverFrame, void(VideoFrame video_frame));
};
class MockProcessThread : public ProcessThread {
public:
MOCK_METHOD0(Start, void());
MOCK_METHOD0(Stop, void());
MOCK_METHOD1(WakeUp, void(Module* module));
MOCK_METHOD1(PostTask, void(ProcessTask* task));
MOCK_METHOD1(RegisterModule, void(Module* module));
MOCK_METHOD1(DeRegisterModule, void(Module* module));
// MOCK_METHOD1 gets confused with mocking this method, so we work around it
// by overriding the method from the interface and forwarding the call to a
// mocked, simpler method.
void PostTask(rtc::scoped_ptr task) override {
PostTask(task.get());
}
};
virtual void SetUp() {
/*方法DeliverFrame可以被mock_frame_callback_调用任意次,且对参数没有要求(参数为"_"),
*当其被调用后,mock_frame_callback_会执行Invoke来调用AddOutputFrame方法
*/
EXPECT_CALL(*mock_frame_callback_, DeliverFrame(_))
.WillRepeatedly(
WithArg<0>(Invoke(this, &VideoCaptureInputTest::AddOutputFrame)));
Config config;
//创建VideoCaptureInput对象,使用mock的对象
input_.reset(new internal::VideoCaptureInput(
mock_process_thread_.get(), mock_frame_callback_.get(), nullptr,
&stats_proxy_, nullptr, nullptr));
}
1)通过EXPECT_CALL制定测试规则,当DeliverFrame(将数据发送给encoder)执行时,调用AddOutputFrame(输出video数据)frame_callback_(frame_callback),获取video数据3)EncoderThreadFunction创建后,会通过capture_event_->Wait(kThreadWaitTimeMs)等待video数据,
stats_proxy_(stats_proxy),跟新本地发送数据的信息(biterate,frame account,rtcp account .etc)
capture_event_(EventWrapper::Create()),控制encode线程的执行
overuse_detector_,根据发送端对video数据处理时间,来判断系统资源使用情况,
module_process_thread_->RegisterModule(overuse_detector_.get()),监听上述信息
创建EncoderThreadFunction线程并开始,主要作用是将本地Video数据送入编码器,
创建mock对象,设定测试规则:当DeliverFrame(将数据发送给encoder)执行时,调用AddOutputFrame(输出video数据),模拟一次数据输入编码输出过程,并通过EXPECT_EQ来判断处理是否正常
TEST_F(VideoCaptureInputTest, DropsFramesWithSameOrOldNtpTimestamp) {
input_frames_.push_back(CreateVideoFrame(0));//本地构造一帧图像,放入input_frame队列
input_frames_[0]->set_ntp_time_ms(17);//设置ts
AddInputFrame(input_frames_[0]);//调用AddInputFrame,输入到VideoCaptureInput模块
WaitOutputFrame();//当DeliverFrame执行时,会调用AddOutputFrame,解锁Wait
EXPECT_EQ(output_frames_[0]->timestamp(),//判断timestamp在处理前后是否相等,如不相等,说明处理逻辑有问题
input_frames_[0]->ntp_time_ms() * 90);
// Repeat frame with the same NTP timestamp should drop.
AddInputFrame(input_frames_[0]);//再将上一帧重复输入到VideoCaptureInput
EXPECT_EQ(kEventTimeout, output_frame_event_->Wait(FRAME_TIMEOUT_MS));//此时会返回ERROR
// As should frames with a decreased NTP timestamp.
input_frames_[0]->set_ntp_time_ms(input_frames_[0]->ntp_time_ms() - 1);//将时间减去1,模拟后接收到的帧,ts小于之前收到帧的ts
AddInputFrame(input_frames_[0]);
EXPECT_EQ(kEventTimeout, output_frame_event_->Wait(FRAME_TIMEOUT_MS));//此时也会返回ERROR
// But delivering with an increased NTP timestamp should succeed.
//如果后传入的帧ts大于之前的frame,则处理正常
input_frames_[0]->set_ntp_time_ms(4711);
AddInputFrame(input_frames_[0]);
WaitOutputFrame();
EXPECT_EQ(output_frames_[1]->timestamp(),
input_frames_[0]->ntp_time_ms() * 90);
}