先从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的函数参数列表<span style="font-family:Arial;">ON_CALL(#1, #2(#3)).WillByDefault(Return(#4));</span>#1表示mock对象。定义了一个Mock类,那么就必须生成相应的mock对象
<span style="font-family:Arial;">EXPECT_CALL(mock_object, method(matchers)) .Times(cardinality) .WillOnce(action) .WillRepeatedly(action);</span>
第一个参数是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_* 系列的断言,当检查点失败时,退出当前函数(注意:并非退出当前案例)。
<span style="font-family:Arial;"> VideoCaptureInputTest() : mock_process_thread_(new NiceMock<MockProcessThread>), mock_frame_callback_(new NiceMock<MockVideoCaptureCallback>), output_frame_event_(EventWrapper::Create()), stats_proxy_(Clock::GetRealTimeClock(), webrtc::VideoSendStream::Config(nullptr)) {}</span>其中mock_process_thread_变量mock了ProcessThread对象,而mock_frame_callback_则mock了VideoCaptureCallback对象,目的就是对VideoCaptureInput的输入输出进行打桩,用于测试其处理逻辑,相关的定义如下,都是继承自现有类:
<span style="font-family:Arial;">class MockVideoCaptureCallback : public VideoCaptureCallback { public: MOCK_METHOD1(DeliverFrame, void(VideoFrame video_frame)); };</span>
<span style="font-family:Arial;">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<ProcessTask> task) override { PostTask(task.get()); } };</span>
<span style="font-family:Arial;"> 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)); }</span>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来判断处理是否正常
<span style="font-family:Arial;">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); }</span>