test_source.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  1. /*************************************************************************
  2. * Copyright (C) [2019] by Cambricon, Inc. All rights reserved
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * The above copyright notice and this permission notice shall be included in
  11. * all copies or substantial portions of the Software.
  12. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  13. * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  14. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  15. * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  16. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  17. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  18. * THE SOFTWARE.
  19. *************************************************************************/
  20. #include <gtest/gtest.h>
  21. #include <chrono>
  22. #include <memory>
  23. #include <string>
  24. #include <thread>
  25. #include <vector>
  26. #include "cnstream_module.hpp"
  27. #include "data_handler_file.hpp"
  28. #include "data_handler_mem.hpp"
  29. #include "data_handler_rtsp.hpp"
  30. #include "data_source.hpp"
  31. #include "device/mlu_context.h"
  32. #include "test_base.hpp"
  33. namespace cnstream {
  34. static constexpr const char *gname = "source";
  35. static constexpr const char *gvideo_path = "../../data/videos/cars.mp4";
  36. static constexpr const char *gimage_path = "../../data/images/%d.jpg";
  37. void ResetParam(ModuleParamSet &param) { // NOLINT
  38. param["output_type"] = "mlu";
  39. param["device_id"] = "0";
  40. param["interval"] = "1";
  41. param["decoder_type"] = "mlu";
  42. param["reuse_cndec_buf"] = "true";
  43. param["input_buf_number"] = "100";
  44. param["output_buf_number"] = "100";
  45. }
  46. TEST(Source, Construct) {
  47. std::shared_ptr<Module> src = std::make_shared<DataSource>(gname);
  48. EXPECT_STREQ(src->GetName().c_str(), gname);
  49. }
  50. TEST(Source, OpenClose) {
  51. std::shared_ptr<Module> src = std::make_shared<DataSource>(gname);
  52. ModuleParamSet param;
  53. ResetParam(param);
  54. EXPECT_TRUE(src->CheckParamSet(param));
  55. EXPECT_TRUE(src->Open(param));
  56. // invalid output_type type
  57. param["output_type"] = "foo";
  58. EXPECT_FALSE(src->Open(param));
  59. ResetParam(param);
  60. // invalid output type
  61. param["output_type"] = "bar";
  62. EXPECT_FALSE(src->Open(param));
  63. ResetParam(param);
  64. // mlu output with invalid device id
  65. param.erase("device_id");
  66. ResetParam(param);
  67. // negative interval
  68. param["interval"] = "-1";
  69. EXPECT_FALSE(src->Open(param));
  70. ResetParam(param);
  71. // invalid decode type
  72. param["decoder_type"] = "blabla";
  73. EXPECT_FALSE(src->Open(param));
  74. ResetParam(param);
  75. // mlu decoder with invalid device id
  76. param.erase("device_id");
  77. ResetParam(param);
  78. // reuse cndecoder buffer
  79. param["reuse_cndex_buf"] = "false";
  80. ResetParam(param);
  81. // proper params
  82. // ffmpeg
  83. param["output_type"] = "mlu";
  84. param["decoder_type"] = "mlu";
  85. param["device_id"] = "0";
  86. EXPECT_TRUE(src->CheckParamSet(param));
  87. EXPECT_TRUE(src->Open(param));
  88. param.clear();
  89. src->Close();
  90. param["output_type"] = "mlu";
  91. param["decoder_type"] = "mlu";
  92. param["reuse_cndec_buf"] = "true";
  93. param["device_id"] = "0";
  94. EXPECT_TRUE(src->Open(param));
  95. param.clear();
  96. src->Close();
  97. param["output_type"] = "cpu";
  98. param["decoder_type"] = "cpu";
  99. EXPECT_TRUE(src->Open(param));
  100. param.clear();
  101. src->Close();
  102. param["output_type"] = "mlu";
  103. param["decoder_type"] = "mlu";
  104. param["reuse_cndec_buf"] = "true";
  105. param["device_id"] = "0";
  106. EXPECT_TRUE(src->Open(param));
  107. param.clear();
  108. src->Close();
  109. // DataSource module should not invoke Process()
  110. std::shared_ptr<CNFrameInfo> data = nullptr;
  111. EXPECT_FALSE(src->Process(data));
  112. }
  113. TEST(Source, AddSource) {
  114. auto src = std::make_shared<DataSource>(gname);
  115. std::string stream_id1 = "1";
  116. std::string stream_id2 = "2";
  117. std::string stream_id3 = "3";
  118. std::string stream_id4 = "4";
  119. std::string video_path = GetExePath() + gvideo_path;
  120. std::string rtsp_path = "rtsp://test";
  121. ModuleParamSet param;
  122. param["output_type"] = "mlu";
  123. param["decoder_type"] = "mlu";
  124. param["device_id"] = "0";
  125. ASSERT_TRUE(src->Open(param));
  126. auto handler1 = FileHandler::Create(src.get(), stream_id1, video_path, 24, true);
  127. auto handler2 = FileHandler::Create(src.get(), stream_id2, video_path, 24, false);
  128. auto handler3 = FileHandler::Create(src.get(), stream_id3, video_path, 24, false);
  129. // auto handler4 = RtspHandler::Create(src.get(), stream_id4, rtsp_path);
  130. // successfully add video source
  131. EXPECT_EQ(src->AddSource(handler1), 0);
  132. EXPECT_EQ(src->AddSource(handler2), 0);
  133. EXPECT_EQ(src->AddSource(handler3), 0);
  134. // EXPECT_EQ(src->AddSource(handler4), 0);
  135. // repeadly add video source, wrong!
  136. EXPECT_EQ(src->AddSource(handler1), -1);
  137. EXPECT_EQ(src->AddSource(handler2), -1);
  138. std::this_thread::sleep_for(std::chrono::milliseconds(500));
  139. src->Close();
  140. // filename.empty(), return -1
  141. auto handler_error = FileHandler::Create(src.get(), std::to_string(5), "", 24, false);
  142. EXPECT_EQ(handler_error, nullptr);
  143. // filename valid, return 0
  144. const uint32_t max_test_stream_num = 64;
  145. for (uint32_t i = 0; i < max_test_stream_num; i++) {
  146. auto handler = FileHandler::Create(src.get(), std::to_string(i), video_path, 24, false);
  147. EXPECT_EQ(src->AddSource(handler), 0);
  148. std::this_thread::sleep_for(std::chrono::milliseconds(100));
  149. }
  150. // open source failed, return -1, TODO(LMX): test max stream size, (MLU270 , video_path can not create 128 streams.)
  151. // auto handler = FileHandler::Create(src.get(), std::to_string(GetMaxStreamNumber()), video_path, 24, false);
  152. // EXPECT_EQ(src->AddSource(handler), -1);
  153. std::this_thread::sleep_for(std::chrono::milliseconds(500));
  154. src->Close();
  155. }
  156. TEST(Source, RemoveSource) {
  157. std::string video_path = GetExePath() + gvideo_path;
  158. auto src = std::make_shared<DataSource>(gname);
  159. std::string stream_id1 = "1";
  160. std::string stream_id2 = "2";
  161. std::string stream_id3 = "3";
  162. std::string stream_id4 = "4";
  163. ModuleParamSet param;
  164. param["output_type"] = "mlu";
  165. param["decoder_type"] = "mlu";
  166. param["device_id"] = "0";
  167. ASSERT_TRUE(src->Open(param));
  168. // successfully add video source
  169. for (int i = 0; i < 10; i++) {
  170. auto handler = FileHandler::Create(src.get(), std::to_string(i), video_path, 24, false);
  171. EXPECT_EQ(src->AddSource(handler), 0);
  172. std::this_thread::sleep_for(std::chrono::milliseconds(100));
  173. }
  174. // remove source
  175. for (int i = 0; i < 10; i++) {
  176. EXPECT_EQ(src->RemoveSource(std::to_string(i)), 0);
  177. }
  178. // source not exist, log warning
  179. EXPECT_EQ(src->RemoveSource(std::to_string(0)), 0);
  180. EXPECT_EQ(src->RemoveSource(std::to_string(4)), 0);
  181. // remove all sources
  182. src->Close();
  183. // source not exist, log warning
  184. EXPECT_EQ(src->RemoveSource(std::to_string(3)), 0);
  185. EXPECT_EQ(src->RemoveSource(std::to_string(9)), 0);
  186. }
  187. TEST(Source, FFMpegMLU) {
  188. auto src = std::make_shared<DataSource>(gname);
  189. std::string video_path = GetExePath() + gvideo_path;
  190. std::string image_path = GetExePath() + gimage_path;
  191. std::string stream_id1 = "1";
  192. std::string stream_id2 = "2";
  193. std::string stream_id3 = "3";
  194. std::string stream_id4 = "4";
  195. ModuleParamSet param;
  196. param["output_type"] = "mlu";
  197. param["decoder_type"] = "mlu";
  198. param["device_id"] = "0";
  199. ASSERT_TRUE(src->Open(param));
  200. // add source
  201. auto handler1 = FileHandler::Create(src.get(), stream_id1, video_path, 24, false);
  202. EXPECT_EQ(src->AddSource(handler1), 0);
  203. auto handler2 = FileHandler::Create(src.get(), stream_id2, video_path, 24, true);
  204. EXPECT_EQ(src->AddSource(handler2), 0);
  205. auto handler3 = FileHandler::Create(src.get(), stream_id3, video_path, 24, false);
  206. EXPECT_EQ(src->AddSource(handler3), 0);
  207. auto handler4 = FileHandler::Create(src.get(), stream_id4, image_path, 24, false);
  208. EXPECT_EQ(src->AddSource(handler4), 0);
  209. EXPECT_NE(src->AddSource(handler3), 0);
  210. EXPECT_NE(src->AddSource(handler4), 0);
  211. std::this_thread::sleep_for(std::chrono::milliseconds(500));
  212. EXPECT_EQ(src->RemoveSource(handler1), 0);
  213. EXPECT_EQ(src->RemoveSource(handler2), 0);
  214. EXPECT_EQ(src->AddSource(handler1), 0);
  215. EXPECT_EQ(src->AddSource(handler2), 0);
  216. std::this_thread::sleep_for(std::chrono::milliseconds(500));
  217. src->Close();
  218. // reuse codec buffer
  219. param["reuse_cndec_buf"] = "true";
  220. ASSERT_TRUE(src->Open(param));
  221. auto handler = FileHandler::Create(src.get(), stream_id1, video_path, 24, false);
  222. EXPECT_EQ(src->AddSource(handler), 0);
  223. std::this_thread::sleep_for(std::chrono::milliseconds(500));
  224. src->Close();
  225. }
  226. TEST(Source, FFMpegCPU) {
  227. auto src = std::make_shared<DataSource>(gname);
  228. std::string video_path = GetExePath() + gvideo_path;
  229. std::string stream_id1 = "1";
  230. std::string stream_id2 = "2";
  231. std::string stream_id3 = "3";
  232. ModuleParamSet param;
  233. param["output_type"] = "cpu";
  234. param["decoder_type"] = "cpu";
  235. ASSERT_TRUE(src->Open(param));
  236. // add source
  237. auto handler1 = FileHandler::Create(src.get(), stream_id1, video_path, 23, false);
  238. EXPECT_EQ(src->AddSource(handler1), 0);
  239. auto handler2 = FileHandler::Create(src.get(), stream_id2, video_path, 24, true);
  240. EXPECT_EQ(src->AddSource(handler2), 0);
  241. auto handler3 = FileHandler::Create(src.get(), stream_id3, video_path, 25, false);
  242. EXPECT_EQ(src->AddSource(handler3), 0);
  243. EXPECT_NE(src->AddSource(handler3), 0);
  244. std::this_thread::sleep_for(std::chrono::milliseconds(500));
  245. EXPECT_EQ(src->RemoveSource(stream_id3), 0);
  246. EXPECT_EQ(src->RemoveSource(stream_id1), 0);
  247. EXPECT_EQ(src->RemoveSource(stream_id2), 0);
  248. param["output_type"] = "mlu";
  249. param["device_id"] = "0";
  250. ASSERT_TRUE(src->Open(param));
  251. auto handler4 = FileHandler::Create(src.get(), stream_id1, video_path, 22, false);
  252. EXPECT_EQ(src->AddSource(handler4), 0);
  253. auto handler5 = FileHandler::Create(src.get(), stream_id2, video_path, 21, false);
  254. EXPECT_EQ(src->AddSource(handler5), 0);
  255. std::this_thread::sleep_for(std::chrono::milliseconds(500));
  256. src->Close();
  257. }
  258. TEST(Source, MemMLU) {
  259. std::string h264_path = GetExePath() + "../../modules/unitest/source/data/raw.h264";
  260. auto src = std::make_shared<DataSource>(gname);
  261. std::string stream_id0 = "0";
  262. std::string stream_id1 = "1";
  263. std::string stream_id2 = "2";
  264. std::string stream_id3 = "3";
  265. ModuleParamSet param;
  266. param["output_type"] = "mlu";
  267. param["decoder_type"] = "mlu";
  268. param["device_id"] = "0";
  269. ASSERT_TRUE(src->Open(param));
  270. std::vector<std::shared_ptr<SourceHandler>> vec_handlers;
  271. std::vector<std::thread> vec_threads_mem;
  272. // add source
  273. auto handler0 = ESMemHandler::Create(src.get(), stream_id0);
  274. EXPECT_EQ(src->AddSource(handler0), 0);
  275. vec_handlers.push_back(handler0);
  276. auto handler1 = ESMemHandler::Create(src.get(), stream_id1);
  277. EXPECT_EQ(src->AddSource(handler1), 0);
  278. vec_handlers.push_back(handler1);
  279. auto handler2 = ESMemHandler::Create(src.get(), stream_id2);
  280. EXPECT_EQ(src->AddSource(handler2), 0);
  281. vec_handlers.push_back(handler2);
  282. auto handler3 = ESMemHandler::Create(src.get(), stream_id3);
  283. EXPECT_EQ(src->AddSource(handler3), 0);
  284. vec_handlers.push_back(handler3);
  285. EXPECT_NE(src->AddSource(handler3), 0);
  286. for (auto &handler : vec_handlers) {
  287. vec_threads_mem.push_back(std::thread([&]() {
  288. FILE *fp = fopen(h264_path.c_str(), "rb");
  289. if (fp) {
  290. auto memHandler = std::dynamic_pointer_cast<cnstream::ESMemHandler>(handler);
  291. unsigned char buf[4096];
  292. int read_cnt = 0;
  293. while (!feof(fp) && read_cnt < 10) {
  294. int size = fread(buf, 1, 4096, fp);
  295. memHandler->Write(buf, size);
  296. read_cnt++;
  297. }
  298. memHandler->Write(NULL, 0);
  299. fclose(fp);
  300. }
  301. }));
  302. }
  303. std::this_thread::sleep_for(std::chrono::milliseconds(500));
  304. src->Close();
  305. for (auto &thread_id : vec_threads_mem) {
  306. if (thread_id.joinable()) thread_id.join();
  307. }
  308. vec_threads_mem.clear();
  309. vec_handlers.clear();
  310. // reuse codec buffer
  311. param["reuse_cndec_buf"] = "true";
  312. ASSERT_TRUE(src->Open(param));
  313. handler0 = ESMemHandler::Create(src.get(), stream_id1);
  314. EXPECT_EQ(src->AddSource(handler0), 0);
  315. vec_handlers.push_back(handler0);
  316. handler1 = ESMemHandler::Create(src.get(), stream_id2);
  317. EXPECT_EQ(src->AddSource(handler1), 0);
  318. vec_handlers.push_back(handler1);
  319. for (auto &handler : vec_handlers) {
  320. vec_threads_mem.push_back(std::thread([&]() {
  321. FILE *fp = fopen(h264_path.c_str(), "rb");
  322. if (fp) {
  323. auto memHandler = std::dynamic_pointer_cast<cnstream::ESMemHandler>(handler);
  324. unsigned char buf[4096];
  325. int read_cnt = 0;
  326. while (!feof(fp) && read_cnt < 10) {
  327. int size = fread(buf, 1, 4096, fp);
  328. memHandler->Write(buf, size);
  329. read_cnt++;
  330. }
  331. memHandler->Write(NULL, 0);
  332. fclose(fp);
  333. }
  334. }));
  335. }
  336. std::this_thread::sleep_for(std::chrono::milliseconds(500));
  337. src->Close();
  338. for (auto &thread_id : vec_threads_mem) {
  339. if (thread_id.joinable()) thread_id.join();
  340. }
  341. vec_threads_mem.clear();
  342. vec_handlers.clear();
  343. }
  344. } // namespace cnstream