加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

WebRTC VideoEngine 本地Video数据处理-VideoCaptureInputTest

发布时间:2020-12-14 02:13:46 所属栏目:大数据 来源:网络整理
导读:先从VideoCaptureInputTest分析VideoCaptureInput的用法,后续再分析具体实现。 VideoCaptureInputTest的实现,依赖google的gmock/gtest单元测试框架: gmock: http://code.google.com/p/googlemock/wiki/CheatSheet http://www.voidcn.com/article/p-xjdtr

先从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)。


gtest

https://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数据
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数据送入编码器,
? ? 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.WaitOutputFrame

EXPECT_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>

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读