WebRTC VideoEngine 本地Video数据处理-VideoCaptureInputTest
先从VideoCaptureInputTest分析VideoCaptureInput的用法,后续再分析具体实现。 VideoCaptureInputTest的实现,依赖google的gmock/gtest单元测试框架: gmock:http://code.google.com/p/googlemock/wiki/CheatSheet http://www.voidcn.com/article/p-xjdtroeq-bdg.html 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对象 #2表示想定义的那个方法名称。 #3表示#2方法的参数,只有调用#2方法,同时传递参数为#3时,才会用到ON_CALL的定义。 #4表示调用#2方法,同时传递参数为#3时,返回#4这个变量的值。 <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)。 gtesthttps://code.google.com/p/googletest/wiki/V1_7_Primer http://www.cnblogs.com/coderzh/archive/2009/04/06/1430364.html ASSERT_* 系列的断言,当检查点失败时,退出当前函数(注意:并非退出当前案例)。?EXPECT_* 系列的断言,当检查点失败时,继续往下执行。 TEST_F ?多个测试使用同样的配置,例如不同的测试用例都需要准备VideoFrame? VideoCaptureInputTest的实现:1.构造函数:<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> 2.SetUp<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)); }</span>? ? 1)通过EXPECT_CALL制定测试规则,当DeliverFrame(将数据发送给encoder)执行时,调用AddOutputFrame(输出video数据) ? ? 2)创建VideoCaptureInput对象 frame_callback_(frame_callback),获取video数据? ? 3)EncoderThreadFunction创建后,会通过capture_event_->Wait(kThreadWaitTimeMs)等待video数据, 3.AddInputFrame调用IncomingCapturedFrame,将video数据输入到VideoCaptureInput模块,通过执行DeliverFrame会将video数据发送到EncodeThread,与此同时4.AddOutputFrame将encode输出的数据push到output frame队列,同时调用output_frame_event_->Set(),发送输出数据到达的消息5.WaitOutputFrameEXPECT_EQ(kEventSignaled,output_frame_event_->Wait(FRAME_TIMEOUT_MS));通过output_frame_event_->Waite()等待output_frame,根据返回值是否等于kEventSignaled来判断,数据处理是否正常结束,进行测试 总结创建mock对象,设定测试规则:当DeliverFrame(将数据发送给encoder)执行时,调用AddOutputFrame(输出video数据),模拟一次数据输入编码输出过程,并通过EXPECT_EQ来判断处理是否正常 6.测试用例分析基于上述实现可以指定多种测试场景,代码中有多个TEST_F,以DropsFramesWithSameOrOldNtpTimestamp为例:<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> (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |