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