1
/* $Id: vid_streamutil.c 4084 2012-04-25 07:13:05Z ming $ */
3
* Copyright (C) 2011 Teluu Inc. (http://www.teluu.com)
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.
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.
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
22
* \page page_pjmedia_samples_vid_streamutil_c Samples: Video Streaming
24
* This example mainly demonstrates how to stream video to remote
27
* This file is pjsip-apps/src/samples/vid_streamutil.c
29
* \includelineno vid_streamutil.c
33
#include <pjlib-util.h>
35
#include <pjmedia-codec.h>
36
#include <pjmedia/transport_srtp.h>
39
#if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
42
#include <stdlib.h> /* atoi() */
48
static const char *desc =
52
" Demonstrate how to use pjmedia video stream component to \n"
53
" transmit/receive RTP packets to/from video device/file. \n"
57
" vid_streamutil [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"
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"
77
" --send-pt Payload type for sending \n"
78
" --recv-pt Payload type for receiving \n"
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"
93
#define THIS_FILE "vid_streamutil.c"
96
/* If set, local renderer will be created to play original file */
97
#define HAS_LOCAL_RENDERER_FOR_PLAY_FILE 1
100
/* Default width and height for the renderer, better be set to maximum
103
#define DEF_RENDERER_WIDTH 640
104
#define DEF_RENDERER_HEIGHT 480
108
static void print_stream_stat(pjmedia_vid_stream *stream,
109
const pjmedia_vid_codec_param *codec_param);
111
/* Prototype for LIBSRTP utility in file datatypes.c */
112
int hex_string_to_octet_string(char *raw, char *hex, int len);
115
* Register all codecs.
117
static pj_status_t init_codecs(pj_pool_factory *pf)
121
/* To suppress warning about unused var when all codecs are disabled */
122
PJ_UNUSED_ARG(status);
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);
133
* Register all codecs.
135
static void deinit_codecs()
137
#if defined(PJMEDIA_HAS_FFMPEG_VID_CODEC) && PJMEDIA_HAS_FFMPEG_VID_CODEC != 0
138
pjmedia_codec_ffmpeg_vid_deinit();
142
static pj_status_t create_file_player( pj_pool_t *pool,
143
const char *file_name,
144
pjmedia_port **p_play_port)
146
pjmedia_avi_streams *avi_streams;
147
pjmedia_avi_stream *vid_stream;
148
pjmedia_port *play_port;
151
status = pjmedia_avi_player_create_streams(pool, file_name, 0, &avi_streams);
152
if (status != PJ_SUCCESS)
155
vid_stream = pjmedia_avi_streams_get_stream_by_media(avi_streams,
161
play_port = pjmedia_avi_stream_get_port(vid_stream);
162
pj_assert(play_port);
164
*p_play_port = play_port;
170
* Create stream based on the codec, dir, remote address, etc.
172
static 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,
179
pj_uint16_t local_port,
180
const pj_sockaddr_in *rem_addr,
181
#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
183
const pj_str_t *crypto_suite,
184
const pj_str_t *srtp_tx_key,
185
const pj_str_t *srtp_rx_key,
187
pjmedia_vid_stream **p_stream )
189
pjmedia_vid_stream_info info;
190
pjmedia_transport *transport = NULL;
192
#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
193
pjmedia_transport *srtp_tp = NULL;
196
/* Reset stream info. */
197
pj_bzero(&info, sizeof(info));
199
/* Initialize stream info formats */
200
info.type = PJMEDIA_TYPE_VIDEO;
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();
207
info.codec_param = codec_param;
209
/* Copy remote address */
210
pj_memcpy(&info.rem_addr, rem_addr, sizeof(pj_sockaddr_in));
212
/* If remote address is not set, set to an arbitrary address
213
* (otherwise stream will assert).
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);
220
/* Create media transport */
221
status = pjmedia_transport_udp_create(med_endpt, NULL, local_port,
223
if (status != PJ_SUCCESS)
226
#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
227
/* Check if SRTP enabled */
229
pjmedia_srtp_crypto tx_plc, rx_plc;
231
status = pjmedia_transport_srtp_create(med_endpt, transport,
233
if (status != PJ_SUCCESS)
236
pj_bzero(&tx_plc, sizeof(pjmedia_srtp_crypto));
237
pj_bzero(&rx_plc, sizeof(pjmedia_srtp_crypto));
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;
244
status = pjmedia_transport_srtp_start(srtp_tp, &tx_plc, &rx_plc);
245
if (status != PJ_SUCCESS)
252
/* Now that the stream info is initialized, we can create the
256
status = pjmedia_vid_stream_create( med_endpt, pool, &info,
260
if (status != PJ_SUCCESS) {
261
app_perror(THIS_FILE, "Error creating stream", status);
262
pjmedia_transport_close(transport);
271
typedef struct play_file_data
273
const char *file_name;
274
pjmedia_port *play_port;
275
pjmedia_port *stream_port;
276
pjmedia_vid_codec *decoder;
277
pjmedia_port *renderer;
279
pj_size_t read_buf_size;
281
pj_size_t dec_buf_size;
285
static void clock_cb(const pj_timestamp *ts, void *user_data)
287
play_file_data *play_file = (play_file_data*)user_data;
288
pjmedia_frame read_frame, write_frame;
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);
298
/* Decode frame, if needed */
299
if (play_file->decoder) {
300
pjmedia_vid_codec *decoder = play_file->decoder;
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
write_frame.size, &write_frame);
306
if (status != PJ_SUCCESS)
309
write_frame = read_frame;
312
/* Display frame locally */
313
if (play_file->renderer)
314
pjmedia_port_put_frame(play_file->renderer, &write_frame);
317
pjmedia_port_put_frame(play_file->stream_port, &write_frame);
332
int main(int argc, char *argv[])
335
pjmedia_endpt *med_endpt;
337
pjmedia_vid_stream *stream = NULL;
338
pjmedia_port *enc_port, *dec_port;
341
pjmedia_vid_port *capture=NULL, *renderer=NULL;
342
pjmedia_vid_port_param vpp;
344
#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
346
pj_bool_t use_srtp = PJ_FALSE;
349
pj_str_t srtp_tx_key = {NULL, 0};
350
pj_str_t srtp_rx_key = {NULL, 0};
351
pj_str_t srtp_crypto_suite = {NULL, 0};
356
const pjmedia_vid_codec_info *codec_info;
357
pjmedia_vid_codec_param codec_param;
358
pjmedia_dir dir = PJMEDIA_DIR_DECODING;
359
pj_sockaddr_in remote_addr;
360
pj_uint16_t local_port = 4000;
361
char *codec_id = NULL;
362
pjmedia_rect_size tx_size = {0};
363
pj_int8_t rx_pt = -1, tx_pt = -1;
365
play_file_data play_file = { NULL };
366
pjmedia_port *play_port = NULL;
367
pjmedia_vid_codec *play_decoder = NULL;
368
pjmedia_clock *play_clock = NULL;
372
OPT_LOCAL_PORT = 'p',
378
OPT_SEND_WIDTH = 'W',
379
OPT_SEND_HEIGHT = 'H',
382
#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
385
OPT_SRTP_TX_KEY = 'x',
386
OPT_SRTP_RX_KEY = 'y',
390
struct pj_getopt_option long_options[] = {
391
{ "codec", 1, 0, OPT_CODEC },
392
{ "local-port", 1, 0, OPT_LOCAL_PORT },
393
{ "remote", 1, 0, OPT_REMOTE },
394
{ "play-file", 1, 0, OPT_PLAY_FILE },
395
{ "send-recv", 0, 0, OPT_SEND_RECV },
396
{ "send-only", 0, 0, OPT_SEND_ONLY },
397
{ "recv-only", 0, 0, OPT_RECV_ONLY },
398
{ "send-width", 1, 0, OPT_SEND_WIDTH },
399
{ "send-height", 1, 0, OPT_SEND_HEIGHT },
400
{ "recv-pt", 1, 0, OPT_RECV_PT },
401
{ "send-pt", 1, 0, OPT_SEND_PT },
402
#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
403
{ "use-srtp", 2, 0, OPT_USE_SRTP },
404
{ "srtp-tx-key", 1, 0, OPT_SRTP_TX_KEY },
405
{ "srtp-rx-key", 1, 0, OPT_SRTP_RX_KEY },
407
{ "help", 0, 0, OPT_HELP },
415
pj_bzero(&remote_addr, sizeof(remote_addr));
420
PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
423
/* Parse arguments */
425
while((c=pj_getopt_long(argc,argv, "h", long_options, &option_index))!=-1)
429
codec_id = pj_optarg;
433
local_port = (pj_uint16_t) atoi(pj_optarg);
434
if (local_port < 1) {
435
printf("Error: invalid local port %s\n", pj_optarg);
442
pj_str_t ip = pj_str(strtok(pj_optarg, ":"));
443
pj_uint16_t port = (pj_uint16_t) atoi(strtok(NULL, ":"));
445
status = pj_sockaddr_in_init(&remote_addr, &ip, port);
446
if (status != PJ_SUCCESS) {
447
app_perror(THIS_FILE, "Invalid remote address", status);
454
play_file.file_name = pj_optarg;
458
dir = PJMEDIA_DIR_ENCODING_DECODING;
462
dir = PJMEDIA_DIR_ENCODING;
466
dir = PJMEDIA_DIR_DECODING;
470
tx_size.w = (unsigned)atoi(pj_optarg);
473
case OPT_SEND_HEIGHT:
474
tx_size.h = (unsigned)atoi(pj_optarg);
478
rx_pt = (pj_int8_t)atoi(pj_optarg);
482
tx_pt = (pj_int8_t)atoi(pj_optarg);
485
#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
489
pj_strset(&srtp_crypto_suite, pj_optarg, strlen(pj_optarg));
491
srtp_crypto_suite = pj_str("AES_CM_128_HMAC_SHA1_80");
495
case OPT_SRTP_TX_KEY:
496
tmp_key_len = hex_string_to_octet_string(tmp_tx_key, pj_optarg,
498
pj_strset(&srtp_tx_key, tmp_tx_key, tmp_key_len/2);
501
case OPT_SRTP_RX_KEY:
502
tmp_key_len = hex_string_to_octet_string(tmp_rx_key, pj_optarg,
504
pj_strset(&srtp_rx_key, tmp_rx_key, tmp_key_len/2);
513
printf("Invalid options %s\n", argv[pj_optind]);
520
/* Verify arguments. */
521
if (dir & PJMEDIA_DIR_ENCODING) {
522
if (remote_addr.sin_addr.s_addr == 0) {
523
printf("Error: remote address must be set\n");
528
if (play_file.file_name != NULL && dir != PJMEDIA_DIR_ENCODING) {
529
printf("Direction is set to --send-only because of --play-file\n");
530
dir = PJMEDIA_DIR_ENCODING;
533
#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
534
/* SRTP validation */
536
if (!srtp_tx_key.slen || !srtp_rx_key.slen)
538
printf("Error: Key for each SRTP stream direction must be set\n");
544
/* Must create a pool factory before we can allocate any memory. */
545
pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0);
548
* Initialize media endpoint.
549
* This will implicitly initialize PJMEDIA too.
551
status = pjmedia_endpt_create(&cp.factory, NULL, 1, &med_endpt);
552
PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
554
/* Create memory pool for application purpose */
555
pool = pj_pool_create( &cp.factory, /* pool factory */
556
"app", /* pool name. */
557
4000, /* init size */
558
4000, /* increment size */
559
NULL /* callback on error */
562
/* Init video format manager */
563
pjmedia_video_format_mgr_create(pool, 64, 0, NULL);
565
/* Init video converter manager */
566
pjmedia_converter_mgr_create(pool, NULL);
568
/* Init event manager */
569
pjmedia_event_mgr_create(pool, 0, NULL);
571
/* Init video codec manager */
572
pjmedia_vid_codec_mgr_create(pool, NULL);
574
/* Init video subsystem */
575
pjmedia_vid_dev_subsys_init(&cp.factory);
577
/* Register all supported codecs */
578
status = init_codecs(&cp.factory);
579
PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
582
/* Find which codec to use. */
585
pj_str_t str_codec_id = pj_str(codec_id);
587
status = pjmedia_vid_codec_mgr_find_codecs_by_id(NULL,
588
&str_codec_id, &count,
590
if (status != PJ_SUCCESS) {
591
printf("Error: unable to find codec %s\n", codec_id);
595
static pjmedia_vid_codec_info info[1];
596
unsigned count = PJ_ARRAY_SIZE(info);
598
/* Default to first codec */
599
pjmedia_vid_codec_mgr_enum_codecs(NULL, &count, info, NULL);
600
codec_info = &info[0];
603
/* Get codec default param for info */
604
status = pjmedia_vid_codec_mgr_get_default_param(NULL, codec_info,
606
pj_assert(status == PJ_SUCCESS);
608
/* Set outgoing video size */
609
if (tx_size.w && tx_size.h)
610
codec_param.enc_fmt.det.vid.size = tx_size;
612
#if DEF_RENDERER_WIDTH && DEF_RENDERER_HEIGHT
613
/* Set incoming video size */
614
if (DEF_RENDERER_WIDTH > codec_param.dec_fmt.det.vid.size.w)
615
codec_param.dec_fmt.det.vid.size.w = DEF_RENDERER_WIDTH;
616
if (DEF_RENDERER_HEIGHT > codec_param.dec_fmt.det.vid.size.h)
617
codec_param.dec_fmt.det.vid.size.h = DEF_RENDERER_HEIGHT;
620
if (play_file.file_name) {
621
pjmedia_video_format_detail *file_vfd;
622
pjmedia_clock_param clock_param;
625
/* Create file player */
626
status = create_file_player(pool, play_file.file_name, &play_port);
627
if (status != PJ_SUCCESS)
630
/* Collect format info */
631
file_vfd = pjmedia_format_get_video_format_detail(&play_port->info.fmt,
633
PJ_LOG(2, (THIS_FILE, "Reading video stream %dx%d %s @%.2ffps",
634
file_vfd->size.w, file_vfd->size.h,
635
pjmedia_fourcc_name(play_port->info.fmt.id, fmt_name),
636
(1.0*file_vfd->fps.num/file_vfd->fps.denum)));
638
/* Allocate file read buffer */
639
play_file.read_buf_size = PJMEDIA_MAX_VIDEO_ENC_FRAME_SIZE;
640
play_file.read_buf = pj_pool_zalloc(pool, play_file.read_buf_size);
642
/* Create decoder, if the file and the stream uses different codec */
643
if (codec_info->fmt_id != (pjmedia_format_id)play_port->info.fmt.id) {
644
const pjmedia_video_format_info *dec_vfi;
645
pjmedia_video_apply_fmt_param dec_vafp = {0};
646
const pjmedia_vid_codec_info *codec_info2;
647
pjmedia_vid_codec_param codec_param2;
650
status = pjmedia_vid_codec_mgr_get_codec_info2(NULL,
651
play_port->info.fmt.id,
653
if (status != PJ_SUCCESS)
657
status = pjmedia_vid_codec_mgr_alloc_codec(NULL, codec_info2,
659
if (status != PJ_SUCCESS)
662
status = play_decoder->op->init(play_decoder, pool);
663
if (status != PJ_SUCCESS)
667
status = pjmedia_vid_codec_mgr_get_default_param(NULL, codec_info2,
669
if (status != PJ_SUCCESS)
672
codec_param2.dir = PJMEDIA_DIR_DECODING;
673
status = play_decoder->op->open(play_decoder, &codec_param2);
674
if (status != PJ_SUCCESS)
677
/* Get decoder format info and apply param */
678
dec_vfi = pjmedia_get_video_format_info(NULL,
679
codec_info2->dec_fmt_id[0]);
680
if (!dec_vfi || !dec_vfi->apply_fmt) {
684
dec_vafp.size = file_vfd->size;
685
(*dec_vfi->apply_fmt)(dec_vfi, &dec_vafp);
687
/* Allocate buffer to receive decoder output */
688
play_file.dec_buf_size = dec_vafp.framebytes;
689
play_file.dec_buf = pj_pool_zalloc(pool, play_file.dec_buf_size);
692
/* Create player clock */
693
clock_param.usec_interval = PJMEDIA_PTIME(&file_vfd->fps);
694
clock_param.clock_rate = codec_info->clock_rate;
695
status = pjmedia_clock_create2(pool, &clock_param,
696
PJMEDIA_CLOCK_NO_HIGHEST_PRIO,
697
&clock_cb, &play_file, &play_clock);
698
if (status != PJ_SUCCESS)
701
/* Override stream codec param for encoding direction */
702
codec_param.enc_fmt.det.vid.size = file_vfd->size;
703
codec_param.enc_fmt.det.vid.fps = file_vfd->fps;
706
pjmedia_vid_port_param_default(&vpp);
708
/* Set as active for all video devices */
709
vpp.active = PJ_TRUE;
711
/* Create video device port. */
712
if (dir & PJMEDIA_DIR_ENCODING) {
714
status = pjmedia_vid_dev_default_param(
716
PJMEDIA_VID_DEFAULT_CAPTURE_DEV,
718
if (status != PJ_SUCCESS)
721
pjmedia_format_copy(&vpp.vidparam.fmt, &codec_param.enc_fmt);
722
vpp.vidparam.fmt.id = codec_param.dec_fmt.id;
723
vpp.vidparam.dir = PJMEDIA_DIR_CAPTURE;
725
status = pjmedia_vid_port_create(pool, &vpp, &capture);
726
if (status != PJ_SUCCESS)
730
if (dir & PJMEDIA_DIR_DECODING) {
731
/* Create renderer */
732
status = pjmedia_vid_dev_default_param(
734
PJMEDIA_VID_DEFAULT_RENDER_DEV,
736
if (status != PJ_SUCCESS)
739
pjmedia_format_copy(&vpp.vidparam.fmt, &codec_param.dec_fmt);
740
vpp.vidparam.dir = PJMEDIA_DIR_RENDER;
741
vpp.vidparam.disp_size = vpp.vidparam.fmt.det.vid.size;
742
vpp.vidparam.flags |= PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW_FLAGS;
743
vpp.vidparam.window_flags = PJMEDIA_VID_DEV_WND_BORDER |
744
PJMEDIA_VID_DEV_WND_RESIZABLE;
746
status = pjmedia_vid_port_create(pool, &vpp, &renderer);
747
if (status != PJ_SUCCESS)
752
/* Set to ignore fmtp */
753
codec_param.ignore_fmtp = PJ_TRUE;
755
/* Create stream based on program arguments */
756
status = create_stream(pool, med_endpt, codec_info, &codec_param,
757
dir, rx_pt, tx_pt, local_port, &remote_addr,
758
#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
759
use_srtp, &srtp_crypto_suite,
760
&srtp_tx_key, &srtp_rx_key,
763
if (status != PJ_SUCCESS)
766
/* Get the port interface of the stream */
767
status = pjmedia_vid_stream_get_port(stream, PJMEDIA_DIR_ENCODING,
769
PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
771
status = pjmedia_vid_stream_get_port(stream, PJMEDIA_DIR_DECODING,
773
PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
775
/* Start streaming */
776
status = pjmedia_vid_stream_start(stream);
777
if (status != PJ_SUCCESS)
782
status = pjmedia_vid_port_connect(renderer, dec_port, PJ_FALSE);
783
if (status != PJ_SUCCESS)
785
status = pjmedia_vid_port_start(renderer);
786
if (status != PJ_SUCCESS)
792
status = pjmedia_vid_port_connect(capture, enc_port, PJ_FALSE);
793
if (status != PJ_SUCCESS)
795
status = pjmedia_vid_port_start(capture);
796
if (status != PJ_SUCCESS)
800
/* Start playing file */
801
if (play_file.file_name) {
803
#if HAS_LOCAL_RENDERER_FOR_PLAY_FILE
804
/* Create local renderer */
805
pjmedia_vid_port_param_default(&vpp);
806
vpp.active = PJ_FALSE;
807
status = pjmedia_vid_dev_default_param(
809
PJMEDIA_VID_DEFAULT_RENDER_DEV,
811
if (status != PJ_SUCCESS)
814
vpp.vidparam.dir = PJMEDIA_DIR_RENDER;
815
pjmedia_format_copy(&vpp.vidparam.fmt, &codec_param.dec_fmt);
816
vpp.vidparam.fmt.det.vid.size = play_port->info.fmt.det.vid.size;
817
vpp.vidparam.fmt.det.vid.fps = play_port->info.fmt.det.vid.fps;
818
vpp.vidparam.disp_size = vpp.vidparam.fmt.det.vid.size;
819
vpp.vidparam.flags |= PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW_FLAGS;
820
vpp.vidparam.window_flags = PJMEDIA_VID_DEV_WND_BORDER |
821
PJMEDIA_VID_DEV_WND_RESIZABLE;
823
status = pjmedia_vid_port_create(pool, &vpp, &renderer);
824
if (status != PJ_SUCCESS)
826
status = pjmedia_vid_port_start(renderer);
827
if (status != PJ_SUCCESS)
831
/* Init play file data */
832
play_file.play_port = play_port;
833
play_file.stream_port = enc_port;
834
play_file.decoder = play_decoder;
836
play_file.renderer = pjmedia_vid_port_get_passive_port(renderer);
839
status = pjmedia_clock_start(play_clock);
840
if (status != PJ_SUCCESS)
846
if (dir == PJMEDIA_DIR_DECODING)
847
printf("Stream is active, dir is recv-only, local port is %d\n",
849
else if (dir == PJMEDIA_DIR_ENCODING)
850
printf("Stream is active, dir is send-only, sending to %s:%d\n",
851
pj_inet_ntoa(remote_addr.sin_addr),
852
pj_ntohs(remote_addr.sin_port));
854
printf("Stream is active, send/recv, local port is %d, "
855
"sending to %s:%d\n",
857
pj_inet_ntoa(remote_addr.sin_addr),
858
pj_ntohs(remote_addr.sin_port));
860
if (dir & PJMEDIA_DIR_ENCODING)
861
PJ_LOG(2, (THIS_FILE, "Sending %dx%d %.*s @%.2ffps",
862
codec_param.enc_fmt.det.vid.size.w,
863
codec_param.enc_fmt.det.vid.size.h,
864
codec_info->encoding_name.slen,
865
codec_info->encoding_name.ptr,
866
(1.0*codec_param.enc_fmt.det.vid.fps.num/
867
codec_param.enc_fmt.det.vid.fps.denum)));
877
printf("Command: "); fflush(stdout);
879
if (fgets(tmp, sizeof(tmp), stdin) == NULL) {
880
puts("EOF while reading stdin, will quit now..");
891
/* Start deinitialization: */
894
/* Stop video devices */
896
pjmedia_vid_port_stop(capture);
898
pjmedia_vid_port_stop(renderer);
900
/* Stop and destroy file clock */
902
pjmedia_clock_stop(play_clock);
903
pjmedia_clock_destroy(play_clock);
906
/* Destroy file reader/player */
908
pjmedia_port_destroy(play_port);
910
/* Destroy file decoder */
912
play_decoder->op->close(play_decoder);
913
pjmedia_vid_codec_mgr_dealloc_codec(NULL, play_decoder);
916
/* Destroy video devices */
918
pjmedia_vid_port_destroy(capture);
920
pjmedia_vid_port_destroy(renderer);
924
pjmedia_transport *tp;
926
tp = pjmedia_vid_stream_get_transport(stream);
927
pjmedia_vid_stream_destroy(stream);
929
pjmedia_transport_close(tp);
935
/* Shutdown video subsystem */
936
pjmedia_vid_dev_subsys_shutdown();
938
/* Destroy event manager */
939
pjmedia_event_mgr_destroy(NULL);
941
/* Release application pool */
942
pj_pool_release( pool );
944
/* Destroy media endpoint. */
945
pjmedia_endpt_destroy( med_endpt );
947
/* Destroy pool factory */
948
pj_caching_pool_destroy( &cp );
953
return (status == PJ_SUCCESS) ? 0 : 1;
959
int main(int argc, char *argv[])
963
puts("Error: this sample requires video capability (PJMEDIA_HAS_VIDEO == 1)");
967
#endif /* PJMEDIA_HAS_VIDEO */