vid_streamutil.c 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017
  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. /**
  19. * \page page_pjmedia_samples_vid_streamutil_c Samples: Video Streaming
  20. *
  21. * This example mainly demonstrates how to stream video to remote
  22. * peer using RTP.
  23. *
  24. * This file is pjsip-apps/src/samples/vid_streamutil.c
  25. *
  26. * \includelineno vid_streamutil.c
  27. */
  28. #include <pjlib.h>
  29. #include <pjlib-util.h>
  30. #include <pjmedia.h>
  31. #include <pjmedia-codec.h>
  32. #include <pjmedia/transport_srtp.h>
  33. #if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
  34. #include <stdlib.h> /* atoi() */
  35. #include <stdio.h>
  36. #include "util.h"
  37. static const char *desc =
  38. " vid_streamutil \n"
  39. "\n"
  40. " PURPOSE: \n"
  41. " Demonstrate how to use pjmedia video stream component to \n"
  42. " transmit/receive RTP packets to/from video device/file. \n"
  43. "\n"
  44. "\n"
  45. " USAGE: \n"
  46. " vid_streamutil [options] \n"
  47. "\n"
  48. "\n"
  49. " Options: \n"
  50. " --codec=CODEC Set the codec name. \n"
  51. " --local-port=PORT Set local RTP port (default=4000) \n"
  52. " --remote=IP:PORT Set the remote peer. If this option is set, \n"
  53. " the program will transmit RTP audio to the \n"
  54. " specified address. (default: recv only) \n"
  55. " --play-file=AVI Send video from the AVI file instead of from \n"
  56. " the video device. \n"
  57. " --send-recv Set stream direction to bidirectional. \n"
  58. " --send-only Set stream direction to send only \n"
  59. " --recv-only Set stream direction to recv only (default) \n"
  60. " --send-width Video width to be sent \n"
  61. " --send-height Video height to be sent \n"
  62. " --send-width and --send-height not applicable \n"
  63. " for file streaming (see --play-file) \n"
  64. " --send-pt Payload type for sending \n"
  65. " --recv-pt Payload type for receiving \n"
  66. #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
  67. " --use-srtp[=NAME] Enable SRTP with crypto suite NAME \n"
  68. " e.g: AES_CM_128_HMAC_SHA1_80 (default), \n"
  69. " AES_CM_128_HMAC_SHA1_32 \n"
  70. " Use this option along with the TX & RX keys, \n"
  71. " formated of 60 hex digits (e.g: E148DA..) \n"
  72. " --srtp-tx-key SRTP key for transmiting \n"
  73. " --srtp-rx-key SRTP key for receiving \n"
  74. #endif
  75. "\n"
  76. ;
  77. #define THIS_FILE "vid_streamutil.c"
  78. /* If set, local renderer will be created to play original file */
  79. #define HAS_LOCAL_RENDERER_FOR_PLAY_FILE 1
  80. /* Default width and height for the renderer, better be set to maximum
  81. * acceptable size.
  82. */
  83. #define DEF_RENDERER_WIDTH 640
  84. #define DEF_RENDERER_HEIGHT 480
  85. /* Hexa string to octet array */
  86. int my_hex_string_to_octet_string(char *raw, char *hex, int len)
  87. {
  88. int i;
  89. for (i = 0; i < len; i+=2) {
  90. int tmp;
  91. if (i+1 >= len || !pj_isxdigit(hex[i]) || !pj_isxdigit(hex[i+1]))
  92. return i;
  93. tmp = pj_hex_digit_to_val((unsigned char)hex[i]) << 4;
  94. tmp |= pj_hex_digit_to_val((unsigned char)hex[i+1]);
  95. raw[i/2] = (char)(tmp & 0xFF);
  96. }
  97. return len;
  98. }
  99. /*
  100. * Register all codecs.
  101. */
  102. static pj_status_t init_codecs(pj_pool_factory *pf)
  103. {
  104. pj_status_t status;
  105. /* To suppress warning about unused var when all codecs are disabled */
  106. PJ_UNUSED_ARG(status);
  107. PJ_UNUSED_ARG(pf);
  108. #if defined(PJMEDIA_HAS_OPENH264_CODEC) && PJMEDIA_HAS_OPENH264_CODEC != 0
  109. status = pjmedia_codec_openh264_vid_init(NULL, pf);
  110. PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
  111. #endif
  112. #if defined(PJMEDIA_HAS_VID_TOOLBOX_CODEC) && \
  113. PJMEDIA_HAS_VID_TOOLBOX_CODEC != 0
  114. status = pjmedia_codec_vid_toolbox_init(NULL, pf);
  115. PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
  116. #endif
  117. #if defined(PJMEDIA_HAS_VPX_CODEC) && PJMEDIA_HAS_VPX_CODEC != 0
  118. status = pjmedia_codec_vpx_vid_init(NULL, pf);
  119. PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
  120. #endif
  121. #if defined(PJMEDIA_HAS_FFMPEG_VID_CODEC) && PJMEDIA_HAS_FFMPEG_VID_CODEC != 0
  122. status = pjmedia_codec_ffmpeg_vid_init(NULL, pf);
  123. PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
  124. #endif
  125. return PJ_SUCCESS;
  126. }
  127. /*
  128. * Register all codecs.
  129. */
  130. static void deinit_codecs()
  131. {
  132. #if defined(PJMEDIA_HAS_FFMPEG_VID_CODEC) && PJMEDIA_HAS_FFMPEG_VID_CODEC != 0
  133. pjmedia_codec_ffmpeg_vid_deinit();
  134. #endif
  135. #if defined(PJMEDIA_HAS_OPENH264_CODEC) && PJMEDIA_HAS_OPENH264_CODEC != 0
  136. pjmedia_codec_openh264_vid_deinit();
  137. #endif
  138. #if defined(PJMEDIA_HAS_VID_TOOLBOX_CODEC) && \
  139. PJMEDIA_HAS_VID_TOOLBOX_CODEC != 0
  140. pjmedia_codec_vid_toolbox_deinit();
  141. #endif
  142. #if defined(PJMEDIA_HAS_VPX_CODEC) && PJMEDIA_HAS_VPX_CODEC != 0
  143. pjmedia_codec_vpx_vid_deinit();
  144. #endif
  145. }
  146. static pj_status_t create_file_player( pj_pool_t *pool,
  147. const char *file_name,
  148. pjmedia_port **p_play_port)
  149. {
  150. pjmedia_avi_streams *avi_streams;
  151. pjmedia_avi_stream *vid_stream;
  152. pjmedia_port *play_port;
  153. pj_status_t status;
  154. status = pjmedia_avi_player_create_streams(pool, file_name, 0, &avi_streams);
  155. if (status != PJ_SUCCESS)
  156. return status;
  157. vid_stream = pjmedia_avi_streams_get_stream_by_media(avi_streams,
  158. 0,
  159. PJMEDIA_TYPE_VIDEO);
  160. if (!vid_stream)
  161. return PJ_ENOTFOUND;
  162. play_port = pjmedia_avi_stream_get_port(vid_stream);
  163. pj_assert(play_port);
  164. *p_play_port = play_port;
  165. return PJ_SUCCESS;
  166. }
  167. /*
  168. * Create stream based on the codec, dir, remote address, etc.
  169. */
  170. static pj_status_t create_stream( pj_pool_t *pool,
  171. pjmedia_endpt *med_endpt,
  172. const pjmedia_vid_codec_info *codec_info,
  173. pjmedia_vid_codec_param *codec_param,
  174. pjmedia_dir dir,
  175. pj_int8_t rx_pt,
  176. pj_int8_t tx_pt,
  177. pj_uint16_t local_port,
  178. const pj_sockaddr_in *rem_addr,
  179. #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
  180. pj_bool_t use_srtp,
  181. const pj_str_t *crypto_suite,
  182. const pj_str_t *srtp_tx_key,
  183. const pj_str_t *srtp_rx_key,
  184. #endif
  185. pjmedia_vid_stream **p_stream )
  186. {
  187. pjmedia_vid_stream_info info;
  188. pjmedia_transport *transport = NULL;
  189. pj_status_t status;
  190. #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
  191. pjmedia_transport *srtp_tp = NULL;
  192. #endif
  193. /* Reset stream info. */
  194. pj_bzero(&info, sizeof(info));
  195. /* Initialize stream info formats */
  196. info.type = PJMEDIA_TYPE_VIDEO;
  197. info.dir = dir;
  198. info.codec_info = *codec_info;
  199. info.tx_pt = (tx_pt == -1)? (pj_uint8_t)codec_info->pt : tx_pt;
  200. info.rx_pt = (rx_pt == -1)? (pj_uint8_t)codec_info->pt : rx_pt;
  201. info.ssrc = pj_rand();
  202. if (codec_param)
  203. info.codec_param = codec_param;
  204. /* Copy remote address */
  205. pj_memcpy(&info.rem_addr, rem_addr, sizeof(pj_sockaddr_in));
  206. /* If remote address is not set, set to an arbitrary address
  207. * (otherwise stream will assert).
  208. */
  209. if (info.rem_addr.addr.sa_family == 0) {
  210. const pj_str_t addr = pj_str("127.0.0.1");
  211. pj_sockaddr_in_init(&info.rem_addr.ipv4, &addr, 0);
  212. }
  213. /* Create media transport */
  214. status = pjmedia_transport_udp_create(med_endpt, NULL, local_port,
  215. 0, &transport);
  216. if (status != PJ_SUCCESS)
  217. return status;
  218. #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
  219. /* Check if SRTP enabled */
  220. if (use_srtp) {
  221. pjmedia_srtp_crypto tx_plc, rx_plc;
  222. status = pjmedia_transport_srtp_create(med_endpt, transport,
  223. NULL, &srtp_tp);
  224. if (status != PJ_SUCCESS)
  225. return status;
  226. pj_bzero(&tx_plc, sizeof(pjmedia_srtp_crypto));
  227. pj_bzero(&rx_plc, sizeof(pjmedia_srtp_crypto));
  228. tx_plc.key = *srtp_tx_key;
  229. tx_plc.name = *crypto_suite;
  230. rx_plc.key = *srtp_rx_key;
  231. rx_plc.name = *crypto_suite;
  232. status = pjmedia_transport_srtp_start(srtp_tp, &tx_plc, &rx_plc);
  233. if (status != PJ_SUCCESS)
  234. return status;
  235. transport = srtp_tp;
  236. }
  237. #endif
  238. /* Now that the stream info is initialized, we can create the
  239. * stream.
  240. */
  241. status = pjmedia_vid_stream_create( med_endpt, pool, &info,
  242. transport,
  243. NULL, p_stream);
  244. if (status != PJ_SUCCESS) {
  245. app_perror(THIS_FILE, "Error creating stream", status);
  246. pjmedia_transport_close(transport);
  247. return status;
  248. }
  249. /* Start media transport */
  250. pjmedia_transport_media_start(transport, 0, 0, 0, 0);
  251. return PJ_SUCCESS;
  252. }
  253. typedef struct play_file_data
  254. {
  255. const char *file_name;
  256. pjmedia_port *play_port;
  257. pjmedia_port *stream_port;
  258. pjmedia_vid_codec *decoder;
  259. pjmedia_port *renderer;
  260. void *read_buf;
  261. pj_size_t read_buf_size;
  262. void *dec_buf;
  263. pj_size_t dec_buf_size;
  264. } play_file_data;
  265. static void clock_cb(const pj_timestamp *ts, void *user_data)
  266. {
  267. play_file_data *play_file = (play_file_data*)user_data;
  268. pjmedia_frame read_frame, write_frame;
  269. pj_status_t status;
  270. PJ_UNUSED_ARG(ts);
  271. /* Read frame from file */
  272. read_frame.buf = play_file->read_buf;
  273. read_frame.size = play_file->read_buf_size;
  274. pjmedia_port_get_frame(play_file->play_port, &read_frame);
  275. /* Decode frame, if needed */
  276. if (play_file->decoder) {
  277. pjmedia_vid_codec *decoder = play_file->decoder;
  278. write_frame.buf = play_file->dec_buf;
  279. write_frame.size = play_file->dec_buf_size;
  280. status = pjmedia_vid_codec_decode(decoder, 1, &read_frame,
  281. (unsigned)write_frame.size,
  282. &write_frame);
  283. if (status != PJ_SUCCESS)
  284. return;
  285. } else {
  286. write_frame = read_frame;
  287. }
  288. /* Display frame locally */
  289. if (play_file->renderer)
  290. pjmedia_port_put_frame(play_file->renderer, &write_frame);
  291. /* Send frame */
  292. pjmedia_port_put_frame(play_file->stream_port, &write_frame);
  293. }
  294. /*
  295. * usage()
  296. */
  297. static void usage()
  298. {
  299. puts(desc);
  300. }
  301. /*
  302. * main()
  303. */
  304. static int main_func(int argc, char *argv[])
  305. {
  306. pj_caching_pool cp;
  307. pjmedia_endpt *med_endpt;
  308. pj_pool_t *pool;
  309. pjmedia_vid_stream *stream = NULL;
  310. pjmedia_port *enc_port, *dec_port;
  311. char addr[PJ_INET_ADDRSTRLEN];
  312. pj_status_t status;
  313. pjmedia_vid_port *capture=NULL, *renderer=NULL;
  314. pjmedia_vid_port_param vpp;
  315. #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
  316. /* SRTP variables */
  317. pj_bool_t use_srtp = PJ_FALSE;
  318. char tmp_tx_key[64];
  319. char tmp_rx_key[64];
  320. pj_str_t srtp_tx_key = {NULL, 0};
  321. pj_str_t srtp_rx_key = {NULL, 0};
  322. pj_str_t srtp_crypto_suite = {NULL, 0};
  323. int tmp_key_len;
  324. #endif
  325. /* Default values */
  326. const pjmedia_vid_codec_info *codec_info;
  327. pjmedia_vid_codec_param codec_param;
  328. pjmedia_dir dir = PJMEDIA_DIR_DECODING;
  329. pj_sockaddr_in remote_addr;
  330. pj_uint16_t local_port = 4000;
  331. char *codec_id = NULL;
  332. pjmedia_rect_size tx_size = {0};
  333. pj_int8_t rx_pt = -1, tx_pt = -1;
  334. play_file_data play_file = { NULL };
  335. pjmedia_port *play_port = NULL;
  336. pjmedia_vid_codec *play_decoder = NULL;
  337. pjmedia_clock *play_clock = NULL;
  338. enum {
  339. OPT_CODEC = 'c',
  340. OPT_LOCAL_PORT = 'p',
  341. OPT_REMOTE = 'r',
  342. OPT_PLAY_FILE = 'f',
  343. OPT_SEND_RECV = 'b',
  344. OPT_SEND_ONLY = 's',
  345. OPT_RECV_ONLY = 'i',
  346. OPT_SEND_WIDTH = 'W',
  347. OPT_SEND_HEIGHT = 'H',
  348. OPT_RECV_PT = 't',
  349. OPT_SEND_PT = 'T',
  350. #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
  351. OPT_USE_SRTP = 'S',
  352. #endif
  353. OPT_SRTP_TX_KEY = 'x',
  354. OPT_SRTP_RX_KEY = 'y',
  355. OPT_HELP = 'h',
  356. };
  357. struct pj_getopt_option long_options[] = {
  358. { "codec", 1, 0, OPT_CODEC },
  359. { "local-port", 1, 0, OPT_LOCAL_PORT },
  360. { "remote", 1, 0, OPT_REMOTE },
  361. { "play-file", 1, 0, OPT_PLAY_FILE },
  362. { "send-recv", 0, 0, OPT_SEND_RECV },
  363. { "send-only", 0, 0, OPT_SEND_ONLY },
  364. { "recv-only", 0, 0, OPT_RECV_ONLY },
  365. { "send-width", 1, 0, OPT_SEND_WIDTH },
  366. { "send-height", 1, 0, OPT_SEND_HEIGHT },
  367. { "recv-pt", 1, 0, OPT_RECV_PT },
  368. { "send-pt", 1, 0, OPT_SEND_PT },
  369. #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
  370. { "use-srtp", 2, 0, OPT_USE_SRTP },
  371. { "srtp-tx-key", 1, 0, OPT_SRTP_TX_KEY },
  372. { "srtp-rx-key", 1, 0, OPT_SRTP_RX_KEY },
  373. #endif
  374. { "help", 0, 0, OPT_HELP },
  375. { NULL, 0, 0, 0 },
  376. };
  377. int c;
  378. int option_index;
  379. pj_bzero(&remote_addr, sizeof(remote_addr));
  380. /* init PJLIB : */
  381. status = pj_init();
  382. PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
  383. /* Parse arguments */
  384. pj_optind = 0;
  385. while((c=pj_getopt_long(argc,argv, "h", long_options, &option_index))!=-1)
  386. {
  387. switch (c) {
  388. case OPT_CODEC:
  389. codec_id = pj_optarg;
  390. break;
  391. case OPT_LOCAL_PORT:
  392. local_port = (pj_uint16_t) atoi(pj_optarg);
  393. if (local_port < 1) {
  394. printf("Error: invalid local port %s\n", pj_optarg);
  395. return 1;
  396. }
  397. break;
  398. case OPT_REMOTE:
  399. {
  400. pj_str_t ip = pj_str(strtok(pj_optarg, ":"));
  401. pj_uint16_t port = (pj_uint16_t) atoi(strtok(NULL, ":"));
  402. status = pj_sockaddr_in_init(&remote_addr, &ip, port);
  403. if (status != PJ_SUCCESS) {
  404. app_perror(THIS_FILE, "Invalid remote address", status);
  405. return 1;
  406. }
  407. }
  408. break;
  409. case OPT_PLAY_FILE:
  410. play_file.file_name = pj_optarg;
  411. break;
  412. case OPT_SEND_RECV:
  413. dir = PJMEDIA_DIR_ENCODING_DECODING;
  414. break;
  415. case OPT_SEND_ONLY:
  416. dir = PJMEDIA_DIR_ENCODING;
  417. break;
  418. case OPT_RECV_ONLY:
  419. dir = PJMEDIA_DIR_DECODING;
  420. break;
  421. case OPT_SEND_WIDTH:
  422. tx_size.w = (unsigned)atoi(pj_optarg);
  423. break;
  424. case OPT_SEND_HEIGHT:
  425. tx_size.h = (unsigned)atoi(pj_optarg);
  426. break;
  427. case OPT_RECV_PT:
  428. rx_pt = (pj_int8_t)atoi(pj_optarg);
  429. break;
  430. case OPT_SEND_PT:
  431. tx_pt = (pj_int8_t)atoi(pj_optarg);
  432. break;
  433. #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
  434. case OPT_USE_SRTP:
  435. use_srtp = PJ_TRUE;
  436. if (pj_optarg) {
  437. pj_strset(&srtp_crypto_suite, pj_optarg, strlen(pj_optarg));
  438. } else {
  439. srtp_crypto_suite = pj_str("AES_CM_128_HMAC_SHA1_80");
  440. }
  441. break;
  442. case OPT_SRTP_TX_KEY:
  443. tmp_key_len = my_hex_string_to_octet_string(tmp_tx_key, pj_optarg,
  444. (int)strlen(pj_optarg));
  445. pj_strset(&srtp_tx_key, tmp_tx_key, tmp_key_len/2);
  446. break;
  447. case OPT_SRTP_RX_KEY:
  448. tmp_key_len = my_hex_string_to_octet_string(tmp_rx_key, pj_optarg,
  449. (int)strlen(pj_optarg));
  450. pj_strset(&srtp_rx_key, tmp_rx_key, tmp_key_len/2);
  451. break;
  452. #endif
  453. case OPT_HELP:
  454. usage();
  455. return 1;
  456. default:
  457. printf("Invalid options %s\n", argv[pj_optind]);
  458. return 1;
  459. }
  460. }
  461. /* Verify arguments. */
  462. if (dir & PJMEDIA_DIR_ENCODING) {
  463. if (remote_addr.sin_addr.s_addr == 0) {
  464. printf("Error: remote address must be set\n");
  465. return 1;
  466. }
  467. }
  468. if (play_file.file_name != NULL && dir != PJMEDIA_DIR_ENCODING) {
  469. printf("Direction is set to --send-only because of --play-file\n");
  470. dir = PJMEDIA_DIR_ENCODING;
  471. }
  472. #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
  473. /* SRTP validation */
  474. if (use_srtp) {
  475. if (!srtp_tx_key.slen || !srtp_rx_key.slen)
  476. {
  477. printf("Error: Key for each SRTP stream direction must be set\n");
  478. return 1;
  479. }
  480. }
  481. #endif
  482. /* Must create a pool factory before we can allocate any memory. */
  483. pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0);
  484. /*
  485. * Initialize media endpoint.
  486. * This will implicitly initialize PJMEDIA too.
  487. */
  488. status = pjmedia_endpt_create(&cp.factory, NULL, 1, &med_endpt);
  489. PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
  490. /* Create memory pool for application purpose */
  491. pool = pj_pool_create( &cp.factory, /* pool factory */
  492. "app", /* pool name. */
  493. 4000, /* init size */
  494. 4000, /* increment size */
  495. NULL /* callback on error */
  496. );
  497. /* Init video format manager */
  498. pjmedia_video_format_mgr_create(pool, 64, 0, NULL);
  499. /* Init video converter manager */
  500. pjmedia_converter_mgr_create(pool, NULL);
  501. /* Init event manager */
  502. pjmedia_event_mgr_create(pool, 0, NULL);
  503. /* Init video codec manager */
  504. pjmedia_vid_codec_mgr_create(pool, NULL);
  505. /* Init video subsystem */
  506. pjmedia_vid_dev_subsys_init(&cp.factory);
  507. /* Register all supported codecs */
  508. status = init_codecs(&cp.factory);
  509. PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
  510. /* Find which codec to use. */
  511. if (codec_id) {
  512. unsigned count = 1;
  513. pj_str_t str_codec_id = pj_str(codec_id);
  514. status = pjmedia_vid_codec_mgr_find_codecs_by_id(NULL,
  515. &str_codec_id, &count,
  516. &codec_info, NULL);
  517. if (status != PJ_SUCCESS) {
  518. printf("Error: unable to find codec %s\n", codec_id);
  519. return 1;
  520. }
  521. } else {
  522. static pjmedia_vid_codec_info info[1];
  523. unsigned count = PJ_ARRAY_SIZE(info);
  524. /* Default to first codec */
  525. pjmedia_vid_codec_mgr_enum_codecs(NULL, &count, info, NULL);
  526. codec_info = &info[0];
  527. }
  528. /* Get codec default param for info */
  529. status = pjmedia_vid_codec_mgr_get_default_param(NULL, codec_info,
  530. &codec_param);
  531. pj_assert(status == PJ_SUCCESS);
  532. /* Set outgoing video size */
  533. if (tx_size.w && tx_size.h)
  534. codec_param.enc_fmt.det.vid.size = tx_size;
  535. #if DEF_RENDERER_WIDTH && DEF_RENDERER_HEIGHT
  536. /* Set incoming video size */
  537. if (DEF_RENDERER_WIDTH > codec_param.dec_fmt.det.vid.size.w)
  538. codec_param.dec_fmt.det.vid.size.w = DEF_RENDERER_WIDTH;
  539. if (DEF_RENDERER_HEIGHT > codec_param.dec_fmt.det.vid.size.h)
  540. codec_param.dec_fmt.det.vid.size.h = DEF_RENDERER_HEIGHT;
  541. #endif
  542. if (play_file.file_name) {
  543. pjmedia_video_format_detail *file_vfd;
  544. pjmedia_clock_param clock_param;
  545. char fmt_name[5];
  546. /* Create file player */
  547. status = create_file_player(pool, play_file.file_name, &play_port);
  548. if (status != PJ_SUCCESS)
  549. goto on_exit;
  550. /* Collect format info */
  551. file_vfd = pjmedia_format_get_video_format_detail(&play_port->info.fmt,
  552. PJ_TRUE);
  553. PJ_LOG(2, (THIS_FILE, "Reading video stream %dx%d %s @%.2ffps",
  554. file_vfd->size.w, file_vfd->size.h,
  555. pjmedia_fourcc_name(play_port->info.fmt.id, fmt_name),
  556. (1.0*file_vfd->fps.num/file_vfd->fps.denum)));
  557. /* Allocate file read buffer */
  558. play_file.read_buf_size = PJMEDIA_MAX_VIDEO_ENC_FRAME_SIZE;
  559. play_file.read_buf = pj_pool_zalloc(pool, play_file.read_buf_size);
  560. /* Create decoder, if the file and the stream uses different codec */
  561. if (codec_info->fmt_id != (pjmedia_format_id)play_port->info.fmt.id) {
  562. const pjmedia_video_format_info *dec_vfi;
  563. pjmedia_video_apply_fmt_param dec_vafp = {0};
  564. const pjmedia_vid_codec_info *codec_info2;
  565. pjmedia_vid_codec_param codec_param2;
  566. /* Find decoder */
  567. status = pjmedia_vid_codec_mgr_get_codec_info2(NULL,
  568. play_port->info.fmt.id,
  569. &codec_info2);
  570. if (status != PJ_SUCCESS)
  571. goto on_exit;
  572. /* Init decoder */
  573. status = pjmedia_vid_codec_mgr_alloc_codec(NULL, codec_info2,
  574. &play_decoder);
  575. if (status != PJ_SUCCESS)
  576. goto on_exit;
  577. status = play_decoder->op->init(play_decoder, pool);
  578. if (status != PJ_SUCCESS)
  579. goto on_exit;
  580. /* Open decoder */
  581. status = pjmedia_vid_codec_mgr_get_default_param(NULL, codec_info2,
  582. &codec_param2);
  583. if (status != PJ_SUCCESS)
  584. goto on_exit;
  585. codec_param2.dir = PJMEDIA_DIR_DECODING;
  586. status = play_decoder->op->open(play_decoder, &codec_param2);
  587. if (status != PJ_SUCCESS)
  588. goto on_exit;
  589. /* Get decoder format info and apply param */
  590. dec_vfi = pjmedia_get_video_format_info(NULL,
  591. codec_info2->dec_fmt_id[0]);
  592. if (!dec_vfi || !dec_vfi->apply_fmt) {
  593. status = PJ_ENOTSUP;
  594. goto on_exit;
  595. }
  596. dec_vafp.size = file_vfd->size;
  597. (*dec_vfi->apply_fmt)(dec_vfi, &dec_vafp);
  598. /* Allocate buffer to receive decoder output */
  599. play_file.dec_buf_size = dec_vafp.framebytes;
  600. play_file.dec_buf = pj_pool_zalloc(pool, play_file.dec_buf_size);
  601. }
  602. /* Create player clock */
  603. clock_param.usec_interval = PJMEDIA_PTIME(&file_vfd->fps);
  604. clock_param.clock_rate = codec_info->clock_rate;
  605. status = pjmedia_clock_create2(pool, &clock_param,
  606. PJMEDIA_CLOCK_NO_HIGHEST_PRIO,
  607. &clock_cb, &play_file, &play_clock);
  608. if (status != PJ_SUCCESS)
  609. goto on_exit;
  610. /* Override stream codec param for encoding direction */
  611. codec_param.enc_fmt.det.vid.size = file_vfd->size;
  612. codec_param.enc_fmt.det.vid.fps = file_vfd->fps;
  613. } else {
  614. pjmedia_vid_port_param_default(&vpp);
  615. /* Set as active for all video devices */
  616. vpp.active = PJ_TRUE;
  617. /* Create video device port. */
  618. if (dir & PJMEDIA_DIR_ENCODING) {
  619. /* Create capture */
  620. status = pjmedia_vid_dev_default_param(
  621. pool,
  622. PJMEDIA_VID_DEFAULT_CAPTURE_DEV,
  623. &vpp.vidparam);
  624. if (status != PJ_SUCCESS)
  625. goto on_exit;
  626. pjmedia_format_copy(&vpp.vidparam.fmt, &codec_param.enc_fmt);
  627. vpp.vidparam.fmt.id = codec_param.dec_fmt.id;
  628. vpp.vidparam.dir = PJMEDIA_DIR_CAPTURE;
  629. status = pjmedia_vid_port_create(pool, &vpp, &capture);
  630. if (status != PJ_SUCCESS)
  631. goto on_exit;
  632. }
  633. if (dir & PJMEDIA_DIR_DECODING) {
  634. /* Create renderer */
  635. status = pjmedia_vid_dev_default_param(
  636. pool,
  637. PJMEDIA_VID_DEFAULT_RENDER_DEV,
  638. &vpp.vidparam);
  639. if (status != PJ_SUCCESS)
  640. goto on_exit;
  641. pjmedia_format_copy(&vpp.vidparam.fmt, &codec_param.dec_fmt);
  642. vpp.vidparam.dir = PJMEDIA_DIR_RENDER;
  643. vpp.vidparam.disp_size = vpp.vidparam.fmt.det.vid.size;
  644. vpp.vidparam.flags |= PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW_FLAGS;
  645. vpp.vidparam.window_flags = PJMEDIA_VID_DEV_WND_BORDER |
  646. PJMEDIA_VID_DEV_WND_RESIZABLE;
  647. status = pjmedia_vid_port_create(pool, &vpp, &renderer);
  648. if (status != PJ_SUCCESS)
  649. goto on_exit;
  650. }
  651. }
  652. /* Set to ignore fmtp */
  653. codec_param.ignore_fmtp = PJ_TRUE;
  654. /* Create stream based on program arguments */
  655. status = create_stream(pool, med_endpt, codec_info, &codec_param,
  656. dir, rx_pt, tx_pt, local_port, &remote_addr,
  657. #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
  658. use_srtp, &srtp_crypto_suite,
  659. &srtp_tx_key, &srtp_rx_key,
  660. #endif
  661. &stream);
  662. if (status != PJ_SUCCESS)
  663. goto on_exit;
  664. /* Get the port interface of the stream */
  665. status = pjmedia_vid_stream_get_port(stream, PJMEDIA_DIR_ENCODING,
  666. &enc_port);
  667. PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
  668. status = pjmedia_vid_stream_get_port(stream, PJMEDIA_DIR_DECODING,
  669. &dec_port);
  670. PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
  671. /* Start streaming */
  672. status = pjmedia_vid_stream_start(stream);
  673. if (status != PJ_SUCCESS)
  674. goto on_exit;
  675. /* Start renderer */
  676. if (renderer) {
  677. status = pjmedia_vid_port_connect(renderer, dec_port, PJ_FALSE);
  678. if (status != PJ_SUCCESS)
  679. goto on_exit;
  680. status = pjmedia_vid_port_start(renderer);
  681. if (status != PJ_SUCCESS)
  682. goto on_exit;
  683. }
  684. /* Start capture */
  685. if (capture) {
  686. status = pjmedia_vid_port_connect(capture, enc_port, PJ_FALSE);
  687. if (status != PJ_SUCCESS)
  688. goto on_exit;
  689. status = pjmedia_vid_port_start(capture);
  690. if (status != PJ_SUCCESS)
  691. goto on_exit;
  692. }
  693. /* Start playing file */
  694. if (play_file.file_name) {
  695. #if HAS_LOCAL_RENDERER_FOR_PLAY_FILE
  696. /* Create local renderer */
  697. pjmedia_vid_port_param_default(&vpp);
  698. vpp.active = PJ_FALSE;
  699. status = pjmedia_vid_dev_default_param(
  700. pool,
  701. PJMEDIA_VID_DEFAULT_RENDER_DEV,
  702. &vpp.vidparam);
  703. if (status != PJ_SUCCESS)
  704. goto on_exit;
  705. vpp.vidparam.dir = PJMEDIA_DIR_RENDER;
  706. pjmedia_format_copy(&vpp.vidparam.fmt, &codec_param.dec_fmt);
  707. vpp.vidparam.fmt.det.vid.size = play_port->info.fmt.det.vid.size;
  708. vpp.vidparam.fmt.det.vid.fps = play_port->info.fmt.det.vid.fps;
  709. vpp.vidparam.disp_size = vpp.vidparam.fmt.det.vid.size;
  710. vpp.vidparam.flags |= PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW_FLAGS;
  711. vpp.vidparam.window_flags = PJMEDIA_VID_DEV_WND_BORDER |
  712. PJMEDIA_VID_DEV_WND_RESIZABLE;
  713. status = pjmedia_vid_port_create(pool, &vpp, &renderer);
  714. if (status != PJ_SUCCESS)
  715. goto on_exit;
  716. status = pjmedia_vid_port_start(renderer);
  717. if (status != PJ_SUCCESS)
  718. goto on_exit;
  719. #endif
  720. /* Init play file data */
  721. play_file.play_port = play_port;
  722. play_file.stream_port = enc_port;
  723. play_file.decoder = play_decoder;
  724. if (renderer) {
  725. play_file.renderer = pjmedia_vid_port_get_passive_port(renderer);
  726. }
  727. status = pjmedia_clock_start(play_clock);
  728. if (status != PJ_SUCCESS)
  729. goto on_exit;
  730. }
  731. /* Done */
  732. if (dir == PJMEDIA_DIR_DECODING)
  733. printf("Stream is active, dir is recv-only, local port is %d\n",
  734. local_port);
  735. else if (dir == PJMEDIA_DIR_ENCODING)
  736. printf("Stream is active, dir is send-only, sending to %s:%d\n",
  737. pj_inet_ntop2(pj_AF_INET(), &remote_addr.sin_addr, addr,
  738. sizeof(addr)),
  739. pj_ntohs(remote_addr.sin_port));
  740. else
  741. printf("Stream is active, send/recv, local port is %d, "
  742. "sending to %s:%d\n",
  743. local_port,
  744. pj_inet_ntop2(pj_AF_INET(), &remote_addr.sin_addr, addr,
  745. sizeof(addr)),
  746. pj_ntohs(remote_addr.sin_port));
  747. if (dir & PJMEDIA_DIR_ENCODING)
  748. PJ_LOG(2, (THIS_FILE, "Sending %dx%d %.*s @%.2ffps",
  749. codec_param.enc_fmt.det.vid.size.w,
  750. codec_param.enc_fmt.det.vid.size.h,
  751. (int)codec_info->encoding_name.slen,
  752. codec_info->encoding_name.ptr,
  753. (1.0*codec_param.enc_fmt.det.vid.fps.num/
  754. codec_param.enc_fmt.det.vid.fps.denum)));
  755. for (;;) {
  756. char tmp[10];
  757. puts("");
  758. puts("Commands:");
  759. puts(" q Quit");
  760. puts("");
  761. printf("Command: "); fflush(stdout);
  762. if (fgets(tmp, sizeof(tmp), stdin) == NULL) {
  763. puts("EOF while reading stdin, will quit now..");
  764. break;
  765. }
  766. if (tmp[0] == 'q')
  767. break;
  768. }
  769. /* Start deinitialization: */
  770. on_exit:
  771. /* Stop video devices */
  772. if (capture)
  773. pjmedia_vid_port_stop(capture);
  774. if (renderer)
  775. pjmedia_vid_port_stop(renderer);
  776. /* Stop and destroy file clock */
  777. if (play_clock) {
  778. pjmedia_clock_stop(play_clock);
  779. pjmedia_clock_destroy(play_clock);
  780. }
  781. /* Destroy file reader/player */
  782. if (play_port)
  783. pjmedia_port_destroy(play_port);
  784. /* Destroy file decoder */
  785. if (play_decoder) {
  786. play_decoder->op->close(play_decoder);
  787. pjmedia_vid_codec_mgr_dealloc_codec(NULL, play_decoder);
  788. }
  789. /* Destroy video devices */
  790. if (capture)
  791. pjmedia_vid_port_destroy(capture);
  792. if (renderer)
  793. pjmedia_vid_port_destroy(renderer);
  794. /* Destroy stream */
  795. if (stream) {
  796. pjmedia_transport *tp;
  797. tp = pjmedia_vid_stream_get_transport(stream);
  798. pjmedia_vid_stream_destroy(stream);
  799. pjmedia_transport_media_stop(tp);
  800. pjmedia_transport_close(tp);
  801. }
  802. /* Deinit codecs */
  803. deinit_codecs();
  804. /* Shutdown video subsystem */
  805. pjmedia_vid_dev_subsys_shutdown();
  806. /* Destroy event manager */
  807. pjmedia_event_mgr_destroy(NULL);
  808. /* Release application pool */
  809. pj_pool_release( pool );
  810. /* Destroy media endpoint. */
  811. pjmedia_endpt_destroy( med_endpt );
  812. /* Destroy pool factory */
  813. pj_caching_pool_destroy( &cp );
  814. /* Shutdown PJLIB */
  815. pj_shutdown();
  816. return (status == PJ_SUCCESS) ? 0 : 1;
  817. }
  818. int main(int argc, char *argv[])
  819. {
  820. return pj_run_app(&main_func, argc, argv, 0);
  821. }
  822. #else
  823. int main(int argc, char *argv[])
  824. {
  825. PJ_UNUSED_ARG(argc);
  826. PJ_UNUSED_ARG(argv);
  827. puts("Error: this sample requires video capability (PJMEDIA_HAS_VIDEO == 1)");
  828. return -1;
  829. }
  830. #endif /* PJMEDIA_HAS_VIDEO */