gapi_streaming_sync_tests.cpp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. // This file is part of OpenCV project.
  2. // It is subject to the license terms in the LICENSE file found in the top-level directory
  3. // of this distribution and at http://opencv.org/license.html.
  4. //
  5. // Copyright (C) 2021 Intel Corporation
  6. #include "../test_precomp.hpp"
  7. #include <opencv2/gapi/streaming/cap.hpp>
  8. #include <opencv2/gapi/core.hpp>
  9. #include <opencv2/gapi/fluid/imgproc.hpp>
  10. #include <opencv2/gapi/streaming/cap.hpp>
  11. #include <opencv2/gapi/streaming/sync.hpp>
  12. namespace opencv_test {
  13. namespace {
  14. using ts_t = int64_t;
  15. using ts_vec = std::vector<ts_t>;
  16. using cv::gapi::streaming::sync_policy;
  17. ts_t calcLeastCommonMultiple(const ts_vec& values) {
  18. ts_t res = *std::max_element(values.begin(), values.end());
  19. auto isDivisor = [&](ts_t v) { return res % v == 0; };
  20. while(!std::all_of(values.begin(), values.end(), isDivisor)) {
  21. res++;
  22. }
  23. return res;
  24. }
  25. struct TimestampGenerationParams {
  26. const ts_vec frame_times;
  27. sync_policy policy;
  28. ts_t end_time;
  29. TimestampGenerationParams(const ts_vec& ft, sync_policy sp, ts_t et = 25)
  30. : frame_times(ft), policy(sp), end_time(et) {
  31. }
  32. };
  33. class MultiFrameSource {
  34. class SingleSource : public cv::gapi::wip::IStreamSource {
  35. MultiFrameSource& m_source;
  36. std::size_t m_idx;
  37. public:
  38. SingleSource(MultiFrameSource& s, std::size_t idx)
  39. : m_source(s)
  40. , m_idx(idx)
  41. {}
  42. virtual bool pull(cv::gapi::wip::Data& data) {
  43. return m_source.pull(data, m_idx);
  44. }
  45. virtual GMetaArg descr_of() const { return GMetaArg{m_source.desc()}; }
  46. };
  47. TimestampGenerationParams p;
  48. ts_vec m_current_times;
  49. cv::Mat m_mat;
  50. public:
  51. MultiFrameSource(const TimestampGenerationParams& params)
  52. : p(params)
  53. , m_current_times(p.frame_times.size(), 0u)
  54. , m_mat(8, 8, CV_8UC1) {
  55. }
  56. bool pull(cv::gapi::wip::Data& data, std::size_t idx) {
  57. cv::randn(m_mat, 127, 32);
  58. GAPI_Assert(idx < p.frame_times.size());
  59. m_current_times[idx] += p.frame_times[idx];
  60. if (m_current_times[idx] >= p.end_time) {
  61. return false;
  62. }
  63. data = m_mat.clone();
  64. data.meta[cv::gapi::streaming::meta_tag::timestamp] = m_current_times[idx];
  65. return true;
  66. }
  67. cv::gapi::wip::IStreamSource::Ptr getSource(std::size_t idx) {
  68. return cv::gapi::wip::IStreamSource::Ptr{new SingleSource(*this, idx)};
  69. }
  70. GMatDesc desc() const { return cv::descr_of(m_mat); }
  71. };
  72. class TimestampChecker {
  73. TimestampGenerationParams p;
  74. ts_t m_synced_time = 0u;
  75. ts_t m_synced_frame_time = 0u;
  76. public:
  77. TimestampChecker(const TimestampGenerationParams& params)
  78. : p(params)
  79. , m_synced_frame_time(calcLeastCommonMultiple(p.frame_times)) {
  80. }
  81. void checkNext(const ts_vec& timestamps) {
  82. if (p.policy == sync_policy::dont_sync) {
  83. // don't check timestamps if the policy is dont_sync
  84. return;
  85. }
  86. m_synced_time += m_synced_frame_time;
  87. for (const auto& ts : timestamps) {
  88. EXPECT_EQ(m_synced_time, ts);
  89. }
  90. }
  91. std::size_t nFrames() const {
  92. auto frame_time = p.policy == sync_policy::dont_sync
  93. ? *std::max_element(p.frame_times.begin(), p.frame_times.end())
  94. : m_synced_frame_time;
  95. auto n_frames = p.end_time / frame_time;
  96. GAPI_Assert(n_frames > 0u);
  97. return (std::size_t)n_frames;
  98. }
  99. };
  100. struct TimestampSyncTest : public ::testing::TestWithParam<sync_policy> {
  101. void run(cv::GProtoInputArgs&& ins, cv::GProtoOutputArgs&& outs,
  102. const ts_vec& frame_times) {
  103. auto video_in_n = frame_times.size();
  104. GAPI_Assert(video_in_n <= ins.m_args.size());
  105. // Assume that all remaining inputs are const
  106. auto const_in_n = ins.m_args.size() - video_in_n;
  107. auto out_n = outs.m_args.size();
  108. auto policy = GetParam();
  109. TimestampGenerationParams ts_params(frame_times, policy);
  110. MultiFrameSource source(ts_params);
  111. GRunArgs gins;
  112. for (std::size_t i = 0; i < video_in_n; i++) {
  113. gins += cv::gin(source.getSource(i));
  114. }
  115. auto desc = source.desc();
  116. cv::Mat const_mat = cv::Mat::eye(desc.size.height,
  117. desc.size.width,
  118. CV_MAKE_TYPE(desc.depth, desc.chan));
  119. for (std::size_t i = 0; i < const_in_n; i++) {
  120. gins += cv::gin(const_mat);
  121. }
  122. ts_vec out_timestamps(out_n);
  123. cv::GRunArgsP gouts{};
  124. for (auto& t : out_timestamps) {
  125. gouts += cv::gout(t);
  126. }
  127. auto pipe = cv::GComputation(std::move(ins), std::move(outs))
  128. .compileStreaming(cv::compile_args(policy));
  129. pipe.setSource(std::move(gins));
  130. pipe.start();
  131. std::size_t frames = 0u;
  132. TimestampChecker checker(ts_params);
  133. while(pipe.pull(std::move(gouts))) {
  134. checker.checkNext(out_timestamps);
  135. frames++;
  136. }
  137. EXPECT_EQ(checker.nFrames(), frames);
  138. }
  139. };
  140. } // anonymous namespace
  141. TEST_P(TimestampSyncTest, Basic)
  142. {
  143. cv::GMat in1, in2;
  144. auto out = cv::gapi::add(in1, in2);
  145. auto ts = cv::gapi::streaming::timestamp(out);
  146. run(cv::GIn(in1, in2), cv::GOut(ts), {1,2});
  147. }
  148. TEST_P(TimestampSyncTest, ThreeInputs)
  149. {
  150. cv::GMat in1, in2, in3;
  151. auto tmp = cv::gapi::add(in1, in2);
  152. auto out = cv::gapi::add(tmp, in3);
  153. auto ts = cv::gapi::streaming::timestamp(out);
  154. run(cv::GIn(in1, in2, in3), cv::GOut(ts), {2,4,3});
  155. }
  156. TEST_P(TimestampSyncTest, TwoOutputs)
  157. {
  158. cv::GMat in1, in2, in3;
  159. auto out1 = cv::gapi::add(in1, in3);
  160. auto out2 = cv::gapi::add(in2, in3);
  161. auto ts1 = cv::gapi::streaming::timestamp(out1);
  162. auto ts2 = cv::gapi::streaming::timestamp(out2);
  163. run(cv::GIn(in1, in2, in3), cv::GOut(ts1, ts2), {1,4,2});
  164. }
  165. TEST_P(TimestampSyncTest, ConstInput)
  166. {
  167. cv::GMat in1, in2, in3;
  168. auto out1 = cv::gapi::add(in1, in3);
  169. auto out2 = cv::gapi::add(in2, in3);
  170. auto ts1 = cv::gapi::streaming::timestamp(out1);
  171. auto ts2 = cv::gapi::streaming::timestamp(out2);
  172. run(cv::GIn(in1, in2, in3), cv::GOut(ts1, ts2), {1,2});
  173. }
  174. TEST_P(TimestampSyncTest, ChangeSource)
  175. {
  176. cv::GMat in1, in2, in3;
  177. auto out1 = cv::gapi::add(in1, in3);
  178. auto out2 = cv::gapi::add(in2, in3);
  179. auto ts1 = cv::gapi::streaming::timestamp(out1);
  180. auto ts2 = cv::gapi::streaming::timestamp(out2);
  181. run(cv::GIn(in1, in2, in3), cv::GOut(ts1, ts2), {1,2});
  182. run(cv::GIn(in1, in2, in3), cv::GOut(ts1, ts2), {1,2});
  183. }
  184. INSTANTIATE_TEST_CASE_P(InputSynchronization, TimestampSyncTest,
  185. Values(sync_policy::dont_sync,
  186. sync_policy::drop));
  187. } // namespace opencv_test