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