gapi_streaming_vpl_data_provider.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  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. #ifdef HAVE_ONEVPL
  7. #include <future>
  8. #include "../test_precomp.hpp"
  9. #include "../common/gapi_tests_common.hpp"
  10. #include "streaming/onevpl/data_provider_dispatcher.hpp"
  11. #include "streaming/onevpl/file_data_provider.hpp"
  12. #include "streaming/onevpl/demux/async_mfp_demux_data_provider.hpp"
  13. #include "streaming/onevpl/source_priv.hpp"
  14. namespace opencv_test
  15. {
  16. namespace
  17. {
  18. using source_t = std::string;
  19. using dd_valid_t = bool;
  20. using demux_valid_t = bool;
  21. using dec_valid_t = bool;
  22. using array_element_t =
  23. std::tuple<source_t, dd_valid_t, demux_valid_t, dec_valid_t>;
  24. array_element_t files[] = {
  25. array_element_t {"highgui/video/VID00003-20100701-2204.3GP",
  26. false, true, false},
  27. array_element_t {"highgui/video/VID00003-20100701-2204.avi",
  28. false, true, false},
  29. array_element_t {"highgui/video/VID00003-20100701-2204.mpg",
  30. false, true, false},
  31. array_element_t {"highgui/video/VID00003-20100701-2204.wmv",
  32. false, true, false},
  33. array_element_t {"highgui/video/sample_322x242_15frames.yuv420p.libaom-av1.mp4",
  34. true, true, true},
  35. array_element_t {"highgui/video/sample_322x242_15frames.yuv420p.libvpx-vp9.mp4",
  36. true, true, true},
  37. array_element_t {"highgui/video/sample_322x242_15frames.yuv420p.libx264.mp4",
  38. true, true, true},
  39. array_element_t {"highgui/video/sample_322x242_15frames.yuv420p.libx265.mp4",
  40. true, true, true},
  41. array_element_t {"highgui/video/sample_322x242_15frames.yuv420p.mjpeg.mp4",
  42. /* MFP cannot extract video MJPEG subtype from that */
  43. false, false, true},
  44. array_element_t {"highgui/video/big_buck_bunny.h264",
  45. false, false, false},
  46. array_element_t {"highgui/video/big_buck_bunny.h265",
  47. false, false, false}
  48. };
  49. class OneVPL_Source_MFPAsyncDispatcherTest : public ::testing::TestWithParam<array_element_t> {};
  50. TEST_P(OneVPL_Source_MFPAsyncDispatcherTest, open_and_decode_file)
  51. {
  52. using namespace cv::gapi::wip::onevpl;
  53. source_t path = findDataFile(std::get<0>(GetParam()));
  54. dd_valid_t dd_result = std::get<1>(GetParam());
  55. dec_valid_t dec_result = std::get<3>(GetParam());
  56. // open demux source & check format support
  57. std::unique_ptr<MFPAsyncDemuxDataProvider> provider_ptr;
  58. try {
  59. provider_ptr.reset(new MFPAsyncDemuxDataProvider(path));
  60. } catch (...) {
  61. EXPECT_FALSE(dd_result);
  62. GTEST_SUCCEED();
  63. return;
  64. }
  65. EXPECT_TRUE(dd_result);
  66. // initialize MFX
  67. mfxLoader mfx_handle = MFXLoad();
  68. mfxConfig cfg_inst_0 = MFXCreateConfig(mfx_handle);
  69. EXPECT_TRUE(cfg_inst_0);
  70. mfxVariant mfx_param_0;
  71. mfx_param_0.Type = MFX_VARIANT_TYPE_U32;
  72. mfx_param_0.Data.U32 = provider_ptr->get_mfx_codec_id();
  73. EXPECT_EQ(MFXSetConfigFilterProperty(cfg_inst_0,(mfxU8 *)CfgParam::decoder_id_name(),
  74. mfx_param_0), MFX_ERR_NONE);
  75. // create MFX session
  76. mfxSession mfx_session{};
  77. mfxStatus sts = MFXCreateSession(mfx_handle, 0, &mfx_session);
  78. EXPECT_EQ(MFX_ERR_NONE, sts);
  79. // create proper bitstream
  80. std::shared_ptr<IDataProvider::mfx_bitstream> bitstream{};
  81. // prepare dec params
  82. mfxVideoParam mfxDecParams {};
  83. mfxDecParams.mfx.CodecId = mfx_param_0.Data.U32;
  84. mfxDecParams.IOPattern = MFX_IOPATTERN_OUT_SYSTEM_MEMORY;
  85. do {
  86. bool fetched = provider_ptr->fetch_bitstream_data(bitstream);
  87. if (dec_result) {
  88. EXPECT_TRUE(fetched);
  89. }
  90. sts = MFXVideoDECODE_DecodeHeader(mfx_session, bitstream.get(), &mfxDecParams);
  91. EXPECT_TRUE(MFX_ERR_NONE == sts || MFX_ERR_MORE_DATA == sts);
  92. } while (sts == MFX_ERR_MORE_DATA && !provider_ptr->empty());
  93. if (dec_result) {
  94. EXPECT_EQ(MFX_ERR_NONE, sts);
  95. } else {
  96. EXPECT_FALSE(MFX_ERR_NONE == sts);
  97. }
  98. MFXVideoDECODE_Close(mfx_session);
  99. MFXClose(mfx_session);
  100. MFXUnload(mfx_handle);
  101. }
  102. TEST_P(OneVPL_Source_MFPAsyncDispatcherTest, choose_dmux_provider)
  103. {
  104. using namespace cv::gapi::wip::onevpl;
  105. source_t path = findDataFile(std::get<0>(GetParam()));
  106. dd_valid_t dd_result = std::get<1>(GetParam());
  107. std::shared_ptr<IDataProvider> provider_ptr;
  108. // choose demux provider for empty CfgParams
  109. try {
  110. provider_ptr = DataProviderDispatcher::create(path);
  111. } catch (...) {
  112. EXPECT_FALSE(dd_result);
  113. provider_ptr = DataProviderDispatcher::create(path,
  114. { CfgParam::create<std::string>(
  115. CfgParam::decoder_id_name(),
  116. "MFX_CODEC_HEVC") /* Doesn't matter what codec for RAW here*/});
  117. EXPECT_TRUE(std::dynamic_pointer_cast<FileDataProvider>(provider_ptr));
  118. GTEST_SUCCEED();
  119. return;
  120. }
  121. EXPECT_TRUE(dd_result);
  122. EXPECT_TRUE(std::dynamic_pointer_cast<MFPAsyncDemuxDataProvider>(provider_ptr));
  123. }
  124. INSTANTIATE_TEST_CASE_P(MFP_VPL_DecodeHeaderTests, OneVPL_Source_MFPAsyncDispatcherTest,
  125. testing::ValuesIn(files));
  126. namespace test {
  127. struct IntrusiveAsyncDemuxDataProvider :
  128. public cv::gapi::wip::onevpl::MFPAsyncDemuxDataProvider {
  129. using base_t = cv::gapi::wip::onevpl::MFPAsyncDemuxDataProvider;
  130. using base_t::base_t;
  131. ~IntrusiveAsyncDemuxDataProvider() {
  132. destroyed = true;
  133. }
  134. STDMETHODIMP OnReadSample(HRESULT status, DWORD stream_index,
  135. DWORD stream_flag, LONGLONG timestamp,
  136. IMFSample *sample_ptr) override {
  137. if (IntrusiveAsyncDemuxDataProvider::need_request_next) {
  138. return base_t::OnReadSample(status, stream_index, stream_flag,
  139. timestamp, sample_ptr);
  140. }
  141. return status;
  142. }
  143. // implementation methods
  144. size_t produce_worker_data(void *key,
  145. cv::gapi::wip::onevpl::ComPtrGuard<IMFMediaBuffer> &&buffer,
  146. std::shared_ptr<mfx_bitstream> &&staging_stream) override {
  147. return base_t::produce_worker_data(key, std::move(buffer),
  148. std::move(staging_stream));
  149. }
  150. static bool need_request_next;
  151. static bool destroyed;
  152. };
  153. bool IntrusiveAsyncDemuxDataProvider::need_request_next{};
  154. bool IntrusiveAsyncDemuxDataProvider::destroyed{};
  155. } // namespace test
  156. TEST(OneVPL_Source_MFPAsyncDemux, sync_flush) {
  157. using namespace cv::gapi::wip::onevpl;
  158. source_t path = findDataFile("highgui/video/sample_322x242_15frames.yuv420p.libx265.mp4");
  159. test::IntrusiveAsyncDemuxDataProvider::need_request_next = false;
  160. const size_t preprocessed_samples_count = 3;
  161. {
  162. test::IntrusiveAsyncDemuxDataProvider provider(path, preprocessed_samples_count);
  163. size_t produce_buffer_count = 199 * preprocessed_samples_count;
  164. std::thread producer([&provider, produce_buffer_count]() {
  165. size_t total_produced_count = 0;
  166. for (size_t i = 0; i < produce_buffer_count; i ++) {
  167. total_produced_count += provider.produce_worker_data(
  168. reinterpret_cast<void*>(i),
  169. createCOMPtrGuard<IMFMediaBuffer>(nullptr),
  170. {});
  171. }
  172. });
  173. producer.join();
  174. }
  175. EXPECT_EQ(test::IntrusiveAsyncDemuxDataProvider::destroyed, true);
  176. }
  177. TEST(OneVPL_Source_MFPAsyncDemux, async_flush) {
  178. using namespace cv::gapi::wip::onevpl;
  179. source_t path = findDataFile("highgui/video/sample_322x242_15frames.yuv420p.libx265.mp4");
  180. test::IntrusiveAsyncDemuxDataProvider::need_request_next = true;
  181. const size_t preprocessed_samples_count = 999;
  182. {
  183. std::shared_ptr<IDataProvider::mfx_bitstream> stream;
  184. test::IntrusiveAsyncDemuxDataProvider provider(path, preprocessed_samples_count);
  185. EXPECT_TRUE(provider.fetch_bitstream_data(stream));
  186. EXPECT_TRUE(stream);
  187. }
  188. EXPECT_EQ(test::IntrusiveAsyncDemuxDataProvider::destroyed, true);
  189. }
  190. TEST(OneVPL_Source_MFPAsyncDemux, eof_async_detection) {
  191. using namespace cv::gapi::wip::onevpl;
  192. source_t path = findDataFile("highgui/video/sample_322x242_15frames.yuv420p.libx265.mp4");
  193. test::IntrusiveAsyncDemuxDataProvider::need_request_next = false;
  194. const size_t preprocessed_samples_count = 0; // do not ask sample at start
  195. test::IntrusiveAsyncDemuxDataProvider provider(path, preprocessed_samples_count);
  196. std::promise<void> start_consume_data;
  197. std::future<void> wait_consume_data = start_consume_data.get_future();
  198. std::thread fetcher([&provider, &start_consume_data]() {
  199. std::shared_ptr<IDataProvider::mfx_bitstream> stream;
  200. start_consume_data.set_value();
  201. EXPECT_FALSE(provider.fetch_bitstream_data(stream));
  202. EXPECT_FALSE(stream);
  203. });
  204. wait_consume_data.wait();
  205. std::this_thread::sleep_for(std::chrono::seconds(2)); // hope fetched has slept on condition
  206. test::IntrusiveAsyncDemuxDataProvider::need_request_next = true;
  207. provider.OnReadSample(S_OK, 0, MF_SOURCE_READERF_ENDOFSTREAM, 0, nullptr);
  208. fetcher.join();
  209. }
  210. TEST(OneVPL_Source_MFPAsyncDemux, produce_consume) {
  211. using namespace cv::gapi::wip::onevpl;
  212. source_t path = findDataFile("highgui/video/sample_322x242_15frames.yuv420p.libx265.mp4");
  213. test::IntrusiveAsyncDemuxDataProvider::need_request_next = false;
  214. const size_t preprocessed_samples_count = 3;
  215. test::IntrusiveAsyncDemuxDataProvider provider(path, preprocessed_samples_count);
  216. std::promise<void> start_consume_data;
  217. std::future<void> wait_consume_data = start_consume_data.get_future();
  218. size_t produce_buffer_count = 199 * preprocessed_samples_count;
  219. std::thread producer([&provider, &wait_consume_data, produce_buffer_count]() {
  220. wait_consume_data.wait();
  221. size_t total_produced_count = 0;
  222. for (size_t i = 0; i < produce_buffer_count; i ++) {
  223. std::shared_ptr<IDataProvider::mfx_bitstream> dummy_stream =
  224. std::make_shared<IDataProvider::mfx_bitstream>();
  225. dummy_stream->DataLength = static_cast<mfxU32>(i); // control block
  226. dummy_stream->DataOffset = static_cast<mfxU32>(i); // control block
  227. dummy_stream->Data = reinterpret_cast<mfxU8*>(i);
  228. total_produced_count = provider.produce_worker_data(
  229. dummy_stream->Data,
  230. createCOMPtrGuard<IMFMediaBuffer>(nullptr),
  231. std::move(dummy_stream));
  232. EXPECT_TRUE(total_produced_count <= produce_buffer_count);
  233. }
  234. });
  235. std::thread consumer([&provider, &start_consume_data, produce_buffer_count]() {
  236. start_consume_data.set_value();
  237. size_t total_consumed_count = 0;
  238. std::shared_ptr<IDataProvider::mfx_bitstream> dummy_stream;
  239. size_t stream_idx = 0;
  240. do {
  241. EXPECT_TRUE(provider.fetch_bitstream_data(dummy_stream));
  242. EXPECT_TRUE(dummy_stream);
  243. EXPECT_EQ(dummy_stream->DataLength, stream_idx);
  244. stream_idx ++;
  245. total_consumed_count++;
  246. } while (total_consumed_count != produce_buffer_count);
  247. });
  248. producer.join();
  249. consumer.join();
  250. }
  251. }
  252. } // namespace opencv_test
  253. #endif // HAVE_ONEVPL