vid_codec_test.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555
  1. /*
  2. * Copyright (C) 2011 Teluu Inc. (http://www.teluu.com)
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  17. */
  18. #include "test.h"
  19. #include <pjmedia-codec.h>
  20. #include <pjmedia-videodev/videodev.h>
  21. #include <pjmedia/vid_codec.h>
  22. #include <pjmedia/port.h>
  23. #if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
  24. #define THIS_FILE "vid_codec.c"
  25. /*
  26. * Capture device setting:
  27. * -1 = colorbar,
  28. * -2 = any non-colorbar capture device (first found)
  29. * x = specified capture device id
  30. */
  31. #define CAPTURE_DEV -1
  32. typedef struct codec_port_data_t
  33. {
  34. pjmedia_vid_codec *codec;
  35. pjmedia_vid_port *rdr_port;
  36. pj_uint8_t *enc_buf;
  37. pj_size_t enc_buf_size;
  38. pj_uint8_t *pack_buf;
  39. pj_size_t pack_buf_size;
  40. } codec_port_data_t;
  41. static pj_status_t codec_on_event(pjmedia_event *event,
  42. void *user_data)
  43. {
  44. codec_port_data_t *port_data = (codec_port_data_t*)user_data;
  45. if (event->type == PJMEDIA_EVENT_FMT_CHANGED) {
  46. pjmedia_vid_codec *codec = port_data->codec;
  47. pjmedia_vid_codec_param codec_param;
  48. pj_status_t status;
  49. status = pjmedia_vid_codec_get_param(codec, &codec_param);
  50. if (status != PJ_SUCCESS)
  51. return status;
  52. status = pjmedia_vid_dev_stream_set_cap(
  53. pjmedia_vid_port_get_stream(port_data->rdr_port),
  54. PJMEDIA_VID_DEV_CAP_FORMAT,
  55. &codec_param.dec_fmt);
  56. if (status != PJ_SUCCESS)
  57. return status;
  58. }
  59. return PJ_SUCCESS;
  60. }
  61. static pj_status_t codec_put_frame(pjmedia_port *port,
  62. pjmedia_frame *frame)
  63. {
  64. enum { MAX_PACKETS = 50 };
  65. codec_port_data_t *port_data = (codec_port_data_t*)port->port_data.pdata;
  66. pj_status_t status;
  67. pjmedia_vid_codec *codec = port_data->codec;
  68. unsigned enc_cnt = 0;
  69. pj_uint8_t *enc_buf;
  70. unsigned enc_size_left;
  71. pjmedia_frame enc_frames[MAX_PACKETS];
  72. pj_bool_t has_more = PJ_FALSE;
  73. enc_buf = port_data->enc_buf;
  74. enc_size_left = (unsigned)port_data->enc_buf_size;
  75. /*
  76. * Encode
  77. */
  78. enc_frames[enc_cnt].buf = enc_buf;
  79. enc_frames[enc_cnt].size = enc_size_left;
  80. status = pjmedia_vid_codec_encode_begin(codec, NULL, frame, enc_size_left,
  81. &enc_frames[enc_cnt], &has_more);
  82. if (status != PJ_SUCCESS) goto on_error;
  83. enc_buf += enc_frames[enc_cnt].size;
  84. enc_size_left -= (unsigned)enc_frames[enc_cnt].size;
  85. ++enc_cnt;
  86. while (has_more) {
  87. enc_frames[enc_cnt].buf = enc_buf;
  88. enc_frames[enc_cnt].size = enc_size_left;
  89. status = pjmedia_vid_codec_encode_more(codec, enc_size_left,
  90. &enc_frames[enc_cnt],
  91. &has_more);
  92. if (status != PJ_SUCCESS)
  93. break;
  94. enc_buf += enc_frames[enc_cnt].size;
  95. enc_size_left -= (unsigned)enc_frames[enc_cnt].size;
  96. ++enc_cnt;
  97. if (enc_cnt >= MAX_PACKETS) {
  98. assert(!"Too many packets!");
  99. break;
  100. }
  101. }
  102. /*
  103. * Decode
  104. */
  105. status = pjmedia_vid_codec_decode(codec, enc_cnt, enc_frames,
  106. (unsigned)frame->size, frame);
  107. if (status != PJ_SUCCESS) goto on_error;
  108. /* Display */
  109. status = pjmedia_port_put_frame(
  110. pjmedia_vid_port_get_passive_port(port_data->rdr_port),
  111. frame);
  112. if (status != PJ_SUCCESS) goto on_error;
  113. return PJ_SUCCESS;
  114. on_error:
  115. pj_perror(3, THIS_FILE, status, "codec_put_frame() error");
  116. return status;
  117. }
  118. static const char* dump_codec_info(const pjmedia_vid_codec_info *info)
  119. {
  120. static char str[80];
  121. unsigned i;
  122. char *p = str;
  123. /* Raw format ids */
  124. for (i=0; (i<info->dec_fmt_id_cnt) && (p-str+5<(int)sizeof(str)); ++i) {
  125. pj_memcpy(p, &info->dec_fmt_id[i], 4);
  126. p += 4;
  127. *p++ = ' ';
  128. }
  129. *p = '\0';
  130. return str;
  131. }
  132. static int enum_codecs()
  133. {
  134. unsigned i, cnt;
  135. pjmedia_vid_codec_info info[PJMEDIA_CODEC_MGR_MAX_CODECS];
  136. pj_status_t status;
  137. PJ_LOG(3, (THIS_FILE, " codec enums"));
  138. cnt = PJ_ARRAY_SIZE(info);
  139. status = pjmedia_vid_codec_mgr_enum_codecs(NULL, &cnt, info, NULL);
  140. if (status != PJ_SUCCESS)
  141. return 100;
  142. for (i = 0; i < cnt; ++i) {
  143. PJ_LOG(3, (THIS_FILE, " %-16.*s %c%c %s",
  144. (int)info[i].encoding_name.slen, info[i].encoding_name.ptr,
  145. (info[i].dir & PJMEDIA_DIR_ENCODING? 'E' : ' '),
  146. (info[i].dir & PJMEDIA_DIR_DECODING? 'D' : ' '),
  147. dump_codec_info(&info[i])));
  148. }
  149. return PJ_SUCCESS;
  150. }
  151. static int encode_decode_test(pj_pool_t *pool, const char *codec_id,
  152. pjmedia_vid_packing packing)
  153. {
  154. const pj_str_t port_name = {"codec", 5};
  155. pjmedia_vid_codec *codec=NULL;
  156. pjmedia_port codec_port;
  157. codec_port_data_t codec_port_data;
  158. pjmedia_vid_codec_param codec_param;
  159. const pjmedia_vid_codec_info *codec_info;
  160. const char *packing_name;
  161. pjmedia_vid_dev_index cap_idx, rdr_idx;
  162. pjmedia_vid_port *capture=NULL, *renderer=NULL;
  163. pjmedia_vid_port_param vport_param;
  164. pjmedia_video_format_detail *vfd;
  165. char codec_name[5];
  166. pj_status_t status;
  167. int rc = 0;
  168. switch (packing) {
  169. case PJMEDIA_VID_PACKING_PACKETS:
  170. packing_name = "framed";
  171. break;
  172. case PJMEDIA_VID_PACKING_WHOLE:
  173. packing_name = "whole";
  174. break;
  175. default:
  176. packing_name = "unknown";
  177. break;
  178. }
  179. PJ_LOG(3, (THIS_FILE, " encode decode test: codec=%s, packing=%s",
  180. codec_id, packing_name));
  181. /* Lookup codec */
  182. {
  183. pj_str_t codec_id_st;
  184. unsigned info_cnt = 1;
  185. /* Lookup codec */
  186. pj_cstr(&codec_id_st, codec_id);
  187. status = pjmedia_vid_codec_mgr_find_codecs_by_id(NULL, &codec_id_st,
  188. &info_cnt,
  189. &codec_info, NULL);
  190. if (status != PJ_SUCCESS) {
  191. rc = 205; goto on_return;
  192. }
  193. }
  194. #if CAPTURE_DEV == -1
  195. /* Lookup colorbar source */
  196. status = pjmedia_vid_dev_lookup("Colorbar", "Colorbar generator", &cap_idx);
  197. if (status != PJ_SUCCESS) {
  198. rc = 206; goto on_return;
  199. }
  200. #elif CAPTURE_DEV == -2
  201. /* Lookup any first non-colorbar source */
  202. {
  203. unsigned i, cnt;
  204. pjmedia_vid_dev_info info;
  205. cap_idx = -1;
  206. cnt = pjmedia_vid_dev_count();
  207. for (i = 0; i < cnt; ++i) {
  208. status = pjmedia_vid_dev_get_info(i, &info);
  209. if (status != PJ_SUCCESS) {
  210. rc = 206; goto on_return;
  211. }
  212. if (info.dir & PJMEDIA_DIR_CAPTURE &&
  213. pj_ansi_stricmp(info.driver, "Colorbar"))
  214. {
  215. cap_idx = i;
  216. break;
  217. }
  218. }
  219. if (cap_idx == -1) {
  220. status = PJ_ENOTFOUND;
  221. rc = 206; goto on_return;
  222. }
  223. }
  224. #else
  225. cap_idx = CAPTURE_DEV;
  226. #endif
  227. /* Lookup SDL renderer */
  228. status = pjmedia_vid_dev_lookup("SDL", "SDL renderer", &rdr_idx);
  229. if (status != PJ_SUCCESS) {
  230. rc = 207; goto on_return;
  231. }
  232. /* Prepare codec */
  233. {
  234. pj_str_t codec_id_st;
  235. unsigned info_cnt = 1;
  236. /* Lookup codec */
  237. pj_cstr(&codec_id_st, codec_id);
  238. status = pjmedia_vid_codec_mgr_find_codecs_by_id(NULL, &codec_id_st,
  239. &info_cnt,
  240. &codec_info, NULL);
  241. if (status != PJ_SUCCESS) {
  242. rc = 245; goto on_return;
  243. }
  244. status = pjmedia_vid_codec_mgr_get_default_param(NULL, codec_info,
  245. &codec_param);
  246. if (status != PJ_SUCCESS) {
  247. rc = 246; goto on_return;
  248. }
  249. codec_param.packing = packing;
  250. /* Don't apply SDP fmtp */
  251. codec_param.ignore_fmtp = PJ_TRUE;
  252. /* Open codec */
  253. status = pjmedia_vid_codec_mgr_alloc_codec(NULL, codec_info,
  254. &codec);
  255. if (status != PJ_SUCCESS) {
  256. rc = 250; goto on_return;
  257. }
  258. status = pjmedia_vid_codec_init(codec, pool);
  259. if (status != PJ_SUCCESS) {
  260. rc = 251; goto on_return;
  261. }
  262. status = pjmedia_vid_codec_open(codec, &codec_param);
  263. if (status != PJ_SUCCESS) {
  264. rc = 252; goto on_return;
  265. }
  266. /* After opened, codec will update the param, let's sync encoder &
  267. * decoder format detail.
  268. */
  269. codec_param.dec_fmt.det = codec_param.enc_fmt.det;
  270. /* Subscribe to codec events */
  271. pjmedia_event_subscribe(NULL, &codec_on_event, &codec_port_data,
  272. codec);
  273. }
  274. pjmedia_vid_port_param_default(&vport_param);
  275. /* Create capture, set it to active (master) */
  276. status = pjmedia_vid_dev_default_param(pool, cap_idx,
  277. &vport_param.vidparam);
  278. if (status != PJ_SUCCESS) {
  279. rc = 220; goto on_return;
  280. }
  281. pjmedia_format_copy(&vport_param.vidparam.fmt, &codec_param.dec_fmt);
  282. vport_param.vidparam.dir = PJMEDIA_DIR_CAPTURE;
  283. vport_param.active = PJ_TRUE;
  284. if (vport_param.vidparam.fmt.detail_type != PJMEDIA_FORMAT_DETAIL_VIDEO) {
  285. rc = 221; goto on_return;
  286. }
  287. vfd = pjmedia_format_get_video_format_detail(&vport_param.vidparam.fmt,
  288. PJ_TRUE);
  289. if (vfd == NULL) {
  290. rc = 225; goto on_return;
  291. }
  292. status = pjmedia_vid_port_create(pool, &vport_param, &capture);
  293. if (status != PJ_SUCCESS) {
  294. rc = 226; goto on_return;
  295. }
  296. /* Create renderer, set it to passive (slave) */
  297. vport_param.active = PJ_FALSE;
  298. vport_param.vidparam.dir = PJMEDIA_DIR_RENDER;
  299. vport_param.vidparam.rend_id = rdr_idx;
  300. vport_param.vidparam.disp_size = vfd->size;
  301. status = pjmedia_vid_port_create(pool, &vport_param, &renderer);
  302. if (status != PJ_SUCCESS) {
  303. rc = 230; goto on_return;
  304. }
  305. /* Init codec port */
  306. pj_bzero(&codec_port, sizeof(codec_port));
  307. status = pjmedia_port_info_init2(&codec_port.info, &port_name, 0x1234,
  308. PJMEDIA_DIR_ENCODING,
  309. &codec_param.dec_fmt);
  310. if (status != PJ_SUCCESS) {
  311. rc = 260; goto on_return;
  312. }
  313. codec_port_data.codec = codec;
  314. codec_port_data.rdr_port = renderer;
  315. codec_port_data.enc_buf_size = codec_param.dec_fmt.det.vid.size.w *
  316. codec_param.dec_fmt.det.vid.size.h * 4;
  317. codec_port_data.enc_buf = pj_pool_alloc(pool,
  318. codec_port_data.enc_buf_size);
  319. codec_port_data.pack_buf_size = codec_port_data.enc_buf_size;
  320. codec_port_data.pack_buf = pj_pool_alloc(pool,
  321. codec_port_data.pack_buf_size);
  322. codec_port.put_frame = &codec_put_frame;
  323. codec_port.port_data.pdata = &codec_port_data;
  324. /* Connect capture to codec port */
  325. status = pjmedia_vid_port_connect(capture,
  326. &codec_port,
  327. PJ_FALSE);
  328. if (status != PJ_SUCCESS) {
  329. rc = 270; goto on_return;
  330. }
  331. PJ_LOG(3, (THIS_FILE, " starting codec test: %s<->%.*s %dx%d",
  332. pjmedia_fourcc_name(codec_param.dec_fmt.id, codec_name),
  333. (int)codec_info->encoding_name.slen,
  334. codec_info->encoding_name.ptr,
  335. codec_param.dec_fmt.det.vid.size.w,
  336. codec_param.dec_fmt.det.vid.size.h
  337. ));
  338. /* Start streaming.. */
  339. status = pjmedia_vid_port_start(renderer);
  340. if (status != PJ_SUCCESS) {
  341. rc = 275; goto on_return;
  342. }
  343. status = pjmedia_vid_port_start(capture);
  344. if (status != PJ_SUCCESS) {
  345. rc = 280; goto on_return;
  346. }
  347. /* Sleep while the video is being displayed... */
  348. pj_thread_sleep(10000);
  349. on_return:
  350. if (status != PJ_SUCCESS) {
  351. PJ_PERROR(3, (THIS_FILE, status, " error"));
  352. }
  353. if (capture)
  354. pjmedia_vid_port_stop(capture);
  355. if (renderer)
  356. pjmedia_vid_port_stop(renderer);
  357. if (capture)
  358. pjmedia_vid_port_destroy(capture);
  359. if (renderer)
  360. pjmedia_vid_port_destroy(renderer);
  361. if (codec) {
  362. pjmedia_event_unsubscribe(NULL, &codec_on_event, &codec_port_data,
  363. codec);
  364. pjmedia_vid_codec_close(codec);
  365. pjmedia_vid_codec_mgr_dealloc_codec(NULL, codec);
  366. }
  367. return rc;
  368. }
  369. int vid_codec_test(void)
  370. {
  371. pj_pool_t *pool;
  372. int rc = 0;
  373. pj_status_t status;
  374. int orig_log_level;
  375. orig_log_level = pj_log_get_level();
  376. pj_log_set_level(3);
  377. PJ_LOG(3, (THIS_FILE, "Performing video codec tests.."));
  378. pool = pj_pool_create(mem, "Vid codec test", 256, 256, 0);
  379. status = pjmedia_vid_dev_subsys_init(mem);
  380. if (status != PJ_SUCCESS)
  381. return -10;
  382. #if PJMEDIA_HAS_VIDEO && PJMEDIA_HAS_OPENH264_CODEC
  383. status = pjmedia_codec_openh264_vid_init(NULL, mem);
  384. if (status != PJ_SUCCESS) {
  385. return -22;
  386. }
  387. #endif
  388. #if PJMEDIA_HAS_VIDEO && PJMEDIA_HAS_VID_TOOLBOX_CODEC
  389. status = pjmedia_codec_vid_toolbox_init(NULL, mem);
  390. if (status != PJ_SUCCESS) {
  391. return -23;
  392. }
  393. #endif
  394. #if PJMEDIA_HAS_VIDEO && PJMEDIA_HAS_VPX_CODEC
  395. status = pjmedia_codec_vpx_vid_init(NULL, mem);
  396. if (status != PJ_SUCCESS) {
  397. return -22;
  398. }
  399. #endif
  400. #if PJMEDIA_HAS_FFMPEG_VID_CODEC
  401. status = pjmedia_codec_ffmpeg_vid_init(NULL, mem);
  402. if (status != PJ_SUCCESS)
  403. return -20;
  404. #endif
  405. rc = enum_codecs();
  406. if (rc != 0)
  407. goto on_return;
  408. #if PJMEDIA_HAS_FFMPEG_VID_CODEC
  409. rc = encode_decode_test(pool, "h263-1998", PJMEDIA_VID_PACKING_WHOLE);
  410. if (rc != 0)
  411. goto on_return;
  412. rc = encode_decode_test(pool, "h263-1998", PJMEDIA_VID_PACKING_PACKETS);
  413. if (rc != 0)
  414. goto on_return;
  415. #endif
  416. #if PJMEDIA_HAS_FFMPEG_VID_CODEC || PJMEDIA_HAS_OPENH264_CODEC || \
  417. PJMEDIA_HAS_VID_TOOLBOX_CODEC
  418. rc = encode_decode_test(pool, "h264", PJMEDIA_VID_PACKING_WHOLE);
  419. if (rc != 0)
  420. goto on_return;
  421. rc = encode_decode_test(pool, "h264", PJMEDIA_VID_PACKING_PACKETS);
  422. if (rc != 0)
  423. goto on_return;
  424. #endif
  425. #if PJMEDIA_HAS_VPX_CODEC && PJMEDIA_HAS_VPX_CODEC_VP8
  426. rc = encode_decode_test(pool, "vp8", PJMEDIA_VID_PACKING_WHOLE);
  427. if (rc != 0)
  428. goto on_return;
  429. rc = encode_decode_test(pool, "vp8", PJMEDIA_VID_PACKING_PACKETS);
  430. if (rc != 0)
  431. goto on_return;
  432. #endif
  433. #if PJMEDIA_HAS_VPX_CODEC && PJMEDIA_HAS_VPX_CODEC_VP9
  434. rc = encode_decode_test(pool, "vp9", PJMEDIA_VID_PACKING_WHOLE);
  435. if (rc != 0)
  436. goto on_return;
  437. rc = encode_decode_test(pool, "vp9", PJMEDIA_VID_PACKING_PACKETS);
  438. if (rc != 0)
  439. goto on_return;
  440. #endif
  441. on_return:
  442. #if PJMEDIA_HAS_FFMPEG_VID_CODEC
  443. pjmedia_codec_ffmpeg_vid_deinit();
  444. #endif
  445. #if defined(PJMEDIA_HAS_OPENH264_CODEC) && PJMEDIA_HAS_OPENH264_CODEC != 0
  446. pjmedia_codec_openh264_vid_deinit();
  447. #endif
  448. #if PJMEDIA_HAS_VIDEO && PJMEDIA_HAS_VID_TOOLBOX_CODEC
  449. pjmedia_codec_vid_toolbox_deinit();
  450. #endif
  451. #if defined(PJMEDIA_HAS_VPX_CODEC) && PJMEDIA_HAS_VPX_CODEC != 0
  452. pjmedia_codec_vpx_vid_deinit();
  453. #endif
  454. pjmedia_vid_dev_subsys_shutdown();
  455. pj_pool_release(pool);
  456. pj_log_set_level(orig_log_level);
  457. /* Avoid compile warning */
  458. PJ_UNUSED_ARG(encode_decode_test);
  459. return rc;
  460. }
  461. #endif /* PJMEDIA_HAS_VIDEO */