~noskcaj/ubuntu/saucy/sflphone/merge-1.2.3-2

« back to all changes in this revision

Viewing changes to daemon/libs/pjproject-2.0.1/pjsip-apps/src/samples/vid_streamutil.c

  • Committer: Jackson Doak
  • Date: 2013-07-10 21:04:46 UTC
  • mfrom: (20.1.3 sid)
  • Revision ID: noskcaj@ubuntu.com-20130710210446-y8f587vza807icr9
Properly merged from upstream.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: vid_streamutil.c 4084 2012-04-25 07:13:05Z ming $ */
 
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
 
 
48
static 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 */
 
108
static 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 */
 
112
int hex_string_to_octet_string(char *raw, char *hex, int len);
 
113
 
 
114
/*
 
115
 * Register all codecs.
 
116
 */
 
117
static 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
 */
 
135
static 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
 
 
142
static 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
 */
 
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,
 
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
 
 
271
typedef 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
 
 
285
static 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
                                          write_frame.size, &write_frame);
 
306
        if (status != PJ_SUCCESS)
 
307
            return;
 
308
    } else {
 
309
        write_frame = read_frame;
 
310
    }
 
311
 
 
312
    /* Display frame locally */
 
313
    if (play_file->renderer)
 
314
        pjmedia_port_put_frame(play_file->renderer, &write_frame);
 
315
 
 
316
    /* Send frame */
 
317
    pjmedia_port_put_frame(play_file->stream_port, &write_frame);
 
318
}
 
319
 
 
320
 
 
321
/*
 
322
 * usage()
 
323
 */
 
324
static void usage()
 
325
{
 
326
    puts(desc);
 
327
}
 
328
 
 
329
/*
 
330
 * main()
 
331
 */
 
332
int main(int argc, char *argv[])
 
333
{
 
334
    pj_caching_pool cp;
 
335
    pjmedia_endpt *med_endpt;
 
336
    pj_pool_t *pool;
 
337
    pjmedia_vid_stream *stream = NULL;
 
338
    pjmedia_port *enc_port, *dec_port;
 
339
    pj_status_t status;
 
340
 
 
341
    pjmedia_vid_port *capture=NULL, *renderer=NULL;
 
342
    pjmedia_vid_port_param vpp;
 
343
 
 
344
#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
 
345
    /* SRTP variables */
 
346
    pj_bool_t use_srtp = PJ_FALSE;
 
347
    char tmp_tx_key[64];
 
348
    char tmp_rx_key[64];
 
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};
 
352
    int tmp_key_len;
 
353
#endif
 
354
 
 
355
    /* Default values */
 
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;
 
364
 
 
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;
 
369
 
 
370
    enum {
 
371
        OPT_CODEC       = 'c',
 
372
        OPT_LOCAL_PORT  = 'p',
 
373
        OPT_REMOTE      = 'r',
 
374
        OPT_PLAY_FILE   = 'f',
 
375
        OPT_SEND_RECV   = 'b',
 
376
        OPT_SEND_ONLY   = 's',
 
377
        OPT_RECV_ONLY   = 'i',
 
378
        OPT_SEND_WIDTH  = 'W',
 
379
        OPT_SEND_HEIGHT = 'H',
 
380
        OPT_RECV_PT     = 't',
 
381
        OPT_SEND_PT     = 'T',
 
382
#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
 
383
        OPT_USE_SRTP    = 'S',
 
384
#endif
 
385
        OPT_SRTP_TX_KEY = 'x',
 
386
        OPT_SRTP_RX_KEY = 'y',
 
387
        OPT_HELP        = 'h',
 
388
    };
 
389
 
 
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 },
 
406
#endif
 
407
        { "help",           0, 0, OPT_HELP },
 
408
        { NULL, 0, 0, 0 },
 
409
    };
 
410
 
 
411
    int c;
 
412
    int option_index;
 
413
 
 
414
 
 
415
    pj_bzero(&remote_addr, sizeof(remote_addr));
 
416
 
 
417
 
 
418
    /* init PJLIB : */
 
419
    status = pj_init();
 
420
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
 
421
 
 
422
 
 
423
    /* Parse arguments */
 
424
    pj_optind = 0;
 
425
    while((c=pj_getopt_long(argc,argv, "h", long_options, &option_index))!=-1)
 
426
    {
 
427
        switch (c) {
 
428
        case OPT_CODEC:
 
429
            codec_id = pj_optarg;
 
430
            break;
 
431
 
 
432
        case OPT_LOCAL_PORT:
 
433
            local_port = (pj_uint16_t) atoi(pj_optarg);
 
434
            if (local_port < 1) {
 
435
                printf("Error: invalid local port %s\n", pj_optarg);
 
436
                return 1;
 
437
            }
 
438
            break;
 
439
 
 
440
        case OPT_REMOTE:
 
441
            {
 
442
                pj_str_t ip = pj_str(strtok(pj_optarg, ":"));
 
443
                pj_uint16_t port = (pj_uint16_t) atoi(strtok(NULL, ":"));
 
444
 
 
445
                status = pj_sockaddr_in_init(&remote_addr, &ip, port);
 
446
                if (status != PJ_SUCCESS) {
 
447
                    app_perror(THIS_FILE, "Invalid remote address", status);
 
448
                    return 1;
 
449
                }
 
450
            }
 
451
            break;
 
452
 
 
453
        case OPT_PLAY_FILE:
 
454
            play_file.file_name = pj_optarg;
 
455
            break;
 
456
 
 
457
        case OPT_SEND_RECV:
 
458
            dir = PJMEDIA_DIR_ENCODING_DECODING;
 
459
            break;
 
460
 
 
461
        case OPT_SEND_ONLY:
 
462
            dir = PJMEDIA_DIR_ENCODING;
 
463
            break;
 
464
 
 
465
        case OPT_RECV_ONLY:
 
466
            dir = PJMEDIA_DIR_DECODING;
 
467
            break;
 
468
 
 
469
        case OPT_SEND_WIDTH:
 
470
            tx_size.w = (unsigned)atoi(pj_optarg);
 
471
            break;
 
472
 
 
473
        case OPT_SEND_HEIGHT:
 
474
            tx_size.h = (unsigned)atoi(pj_optarg);
 
475
            break;
 
476
 
 
477
        case OPT_RECV_PT:
 
478
            rx_pt = (pj_int8_t)atoi(pj_optarg);
 
479
            break;
 
480
 
 
481
        case OPT_SEND_PT:
 
482
            tx_pt = (pj_int8_t)atoi(pj_optarg);
 
483
            break;
 
484
 
 
485
#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
 
486
        case OPT_USE_SRTP:
 
487
            use_srtp = PJ_TRUE;
 
488
            if (pj_optarg) {
 
489
                pj_strset(&srtp_crypto_suite, pj_optarg, strlen(pj_optarg));
 
490
            } else {
 
491
                srtp_crypto_suite = pj_str("AES_CM_128_HMAC_SHA1_80");
 
492
            }
 
493
            break;
 
494
 
 
495
        case OPT_SRTP_TX_KEY:
 
496
            tmp_key_len = hex_string_to_octet_string(tmp_tx_key, pj_optarg,
 
497
                                                     strlen(pj_optarg));
 
498
            pj_strset(&srtp_tx_key, tmp_tx_key, tmp_key_len/2);
 
499
            break;
 
500
 
 
501
        case OPT_SRTP_RX_KEY:
 
502
            tmp_key_len = hex_string_to_octet_string(tmp_rx_key, pj_optarg,
 
503
                                                     strlen(pj_optarg));
 
504
            pj_strset(&srtp_rx_key, tmp_rx_key, tmp_key_len/2);
 
505
            break;
 
506
#endif
 
507
 
 
508
        case OPT_HELP:
 
509
            usage();
 
510
            return 1;
 
511
 
 
512
        default:
 
513
            printf("Invalid options %s\n", argv[pj_optind]);
 
514
            return 1;
 
515
        }
 
516
 
 
517
    }
 
518
 
 
519
 
 
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");
 
524
            return 1;
 
525
        }
 
526
    }
 
527
 
 
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;
 
531
    }
 
532
 
 
533
#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
 
534
    /* SRTP validation */
 
535
    if (use_srtp) {
 
536
        if (!srtp_tx_key.slen || !srtp_rx_key.slen)
 
537
        {
 
538
            printf("Error: Key for each SRTP stream direction must be set\n");
 
539
            return 1;
 
540
        }
 
541
    }
 
542
#endif
 
543
 
 
544
    /* Must create a pool factory before we can allocate any memory. */
 
545
    pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0);
 
546
 
 
547
    /*
 
548
     * Initialize media endpoint.
 
549
     * This will implicitly initialize PJMEDIA too.
 
550
     */
 
551
    status = pjmedia_endpt_create(&cp.factory, NULL, 1, &med_endpt);
 
552
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
 
553
 
 
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    */
 
560
                           );
 
561
 
 
562
    /* Init video format manager */
 
563
    pjmedia_video_format_mgr_create(pool, 64, 0, NULL);
 
564
 
 
565
    /* Init video converter manager */
 
566
    pjmedia_converter_mgr_create(pool, NULL);
 
567
 
 
568
    /* Init event manager */
 
569
    pjmedia_event_mgr_create(pool, 0, NULL);
 
570
 
 
571
    /* Init video codec manager */
 
572
    pjmedia_vid_codec_mgr_create(pool, NULL);
 
573
 
 
574
    /* Init video subsystem */
 
575
    pjmedia_vid_dev_subsys_init(&cp.factory);
 
576
 
 
577
    /* Register all supported codecs */
 
578
    status = init_codecs(&cp.factory);
 
579
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
 
580
 
 
581
 
 
582
    /* Find which codec to use. */
 
583
    if (codec_id) {
 
584
        unsigned count = 1;
 
585
        pj_str_t str_codec_id = pj_str(codec_id);
 
586
 
 
587
        status = pjmedia_vid_codec_mgr_find_codecs_by_id(NULL,
 
588
                                                         &str_codec_id, &count,
 
589
                                                         &codec_info, NULL);
 
590
        if (status != PJ_SUCCESS) {
 
591
            printf("Error: unable to find codec %s\n", codec_id);
 
592
            return 1;
 
593
        }
 
594
    } else {
 
595
        static pjmedia_vid_codec_info info[1];
 
596
        unsigned count = PJ_ARRAY_SIZE(info);
 
597
 
 
598
        /* Default to first codec */
 
599
        pjmedia_vid_codec_mgr_enum_codecs(NULL, &count, info, NULL);
 
600
        codec_info = &info[0];
 
601
    }
 
602
 
 
603
    /* Get codec default param for info */
 
604
    status = pjmedia_vid_codec_mgr_get_default_param(NULL, codec_info,
 
605
                                                     &codec_param);
 
606
    pj_assert(status == PJ_SUCCESS);
 
607
 
 
608
    /* Set outgoing video size */
 
609
    if (tx_size.w && tx_size.h)
 
610
        codec_param.enc_fmt.det.vid.size = tx_size;
 
611
 
 
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;
 
618
#endif
 
619
 
 
620
    if (play_file.file_name) {
 
621
        pjmedia_video_format_detail *file_vfd;
 
622
        pjmedia_clock_param clock_param;
 
623
        char fmt_name[5];
 
624
 
 
625
        /* Create file player */
 
626
        status = create_file_player(pool, play_file.file_name, &play_port);
 
627
        if (status != PJ_SUCCESS)
 
628
            goto on_exit;
 
629
 
 
630
        /* Collect format info */
 
631
        file_vfd = pjmedia_format_get_video_format_detail(&play_port->info.fmt,
 
632
                                                          PJ_TRUE);
 
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)));
 
637
 
 
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);
 
641
 
 
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;
 
648
 
 
649
            /* Find decoder */
 
650
            status = pjmedia_vid_codec_mgr_get_codec_info2(NULL,
 
651
                                                           play_port->info.fmt.id,
 
652
                                                           &codec_info2);
 
653
            if (status != PJ_SUCCESS)
 
654
                goto on_exit;
 
655
 
 
656
            /* Init decoder */
 
657
            status = pjmedia_vid_codec_mgr_alloc_codec(NULL, codec_info2,
 
658
                                                       &play_decoder);
 
659
            if (status != PJ_SUCCESS)
 
660
                goto on_exit;
 
661
 
 
662
            status = play_decoder->op->init(play_decoder, pool);
 
663
            if (status != PJ_SUCCESS)
 
664
                goto on_exit;
 
665
 
 
666
            /* Open decoder */
 
667
            status = pjmedia_vid_codec_mgr_get_default_param(NULL, codec_info2,
 
668
                                                             &codec_param2);
 
669
            if (status != PJ_SUCCESS)
 
670
                goto on_exit;
 
671
 
 
672
            codec_param2.dir = PJMEDIA_DIR_DECODING;
 
673
            status = play_decoder->op->open(play_decoder, &codec_param2);
 
674
            if (status != PJ_SUCCESS)
 
675
                goto on_exit;
 
676
 
 
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) {
 
681
                status = PJ_ENOTSUP;
 
682
                goto on_exit;
 
683
            }
 
684
            dec_vafp.size = file_vfd->size;
 
685
            (*dec_vfi->apply_fmt)(dec_vfi, &dec_vafp);
 
686
 
 
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);
 
690
        }
 
691
 
 
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)
 
699
            goto on_exit;
 
700
 
 
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;
 
704
 
 
705
    } else {
 
706
        pjmedia_vid_port_param_default(&vpp);
 
707
 
 
708
        /* Set as active for all video devices */
 
709
        vpp.active = PJ_TRUE;
 
710
 
 
711
        /* Create video device port. */
 
712
        if (dir & PJMEDIA_DIR_ENCODING) {
 
713
            /* Create capture */
 
714
            status = pjmedia_vid_dev_default_param(
 
715
                                        pool,
 
716
                                        PJMEDIA_VID_DEFAULT_CAPTURE_DEV,
 
717
                                        &vpp.vidparam);
 
718
            if (status != PJ_SUCCESS)
 
719
                goto on_exit;
 
720
 
 
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;
 
724
 
 
725
            status = pjmedia_vid_port_create(pool, &vpp, &capture);
 
726
            if (status != PJ_SUCCESS)
 
727
                goto on_exit;
 
728
        }
 
729
 
 
730
        if (dir & PJMEDIA_DIR_DECODING) {
 
731
            /* Create renderer */
 
732
            status = pjmedia_vid_dev_default_param(
 
733
                                        pool,
 
734
                                        PJMEDIA_VID_DEFAULT_RENDER_DEV,
 
735
                                        &vpp.vidparam);
 
736
            if (status != PJ_SUCCESS)
 
737
                goto on_exit;
 
738
 
 
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;
 
745
 
 
746
            status = pjmedia_vid_port_create(pool, &vpp, &renderer);
 
747
            if (status != PJ_SUCCESS)
 
748
                goto on_exit;
 
749
        }
 
750
    }
 
751
 
 
752
    /* Set to ignore fmtp */
 
753
    codec_param.ignore_fmtp = PJ_TRUE;
 
754
 
 
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,
 
761
#endif
 
762
                           &stream);
 
763
    if (status != PJ_SUCCESS)
 
764
        goto on_exit;
 
765
 
 
766
    /* Get the port interface of the stream */
 
767
    status = pjmedia_vid_stream_get_port(stream, PJMEDIA_DIR_ENCODING,
 
768
                                         &enc_port);
 
769
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
 
770
 
 
771
    status = pjmedia_vid_stream_get_port(stream, PJMEDIA_DIR_DECODING,
 
772
                                         &dec_port);
 
773
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
 
774
 
 
775
    /* Start streaming */
 
776
    status = pjmedia_vid_stream_start(stream);
 
777
    if (status != PJ_SUCCESS)
 
778
        goto on_exit;
 
779
 
 
780
    /* Start renderer */
 
781
    if (renderer) {
 
782
        status = pjmedia_vid_port_connect(renderer, dec_port, PJ_FALSE);
 
783
        if (status != PJ_SUCCESS)
 
784
            goto on_exit;
 
785
        status = pjmedia_vid_port_start(renderer);
 
786
        if (status != PJ_SUCCESS)
 
787
            goto on_exit;
 
788
    }
 
789
 
 
790
    /* Start capture */
 
791
    if (capture) {
 
792
        status = pjmedia_vid_port_connect(capture, enc_port, PJ_FALSE);
 
793
        if (status != PJ_SUCCESS)
 
794
            goto on_exit;
 
795
        status = pjmedia_vid_port_start(capture);
 
796
        if (status != PJ_SUCCESS)
 
797
            goto on_exit;
 
798
    }
 
799
 
 
800
    /* Start playing file */
 
801
    if (play_file.file_name) {
 
802
 
 
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(
 
808
                                pool,
 
809
                                PJMEDIA_VID_DEFAULT_RENDER_DEV,
 
810
                                &vpp.vidparam);
 
811
        if (status != PJ_SUCCESS)
 
812
            goto on_exit;
 
813
 
 
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;
 
822
 
 
823
        status = pjmedia_vid_port_create(pool, &vpp, &renderer);
 
824
        if (status != PJ_SUCCESS)
 
825
            goto on_exit;
 
826
        status = pjmedia_vid_port_start(renderer);
 
827
        if (status != PJ_SUCCESS)
 
828
            goto on_exit;
 
829
#endif
 
830
 
 
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;
 
835
        if (renderer) {
 
836
            play_file.renderer = pjmedia_vid_port_get_passive_port(renderer);
 
837
        }
 
838
 
 
839
        status = pjmedia_clock_start(play_clock);
 
840
        if (status != PJ_SUCCESS)
 
841
            goto on_exit;
 
842
    }
 
843
 
 
844
    /* Done */
 
845
 
 
846
    if (dir == PJMEDIA_DIR_DECODING)
 
847
        printf("Stream is active, dir is recv-only, local port is %d\n",
 
848
               local_port);
 
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));
 
853
    else
 
854
        printf("Stream is active, send/recv, local port is %d, "
 
855
               "sending to %s:%d\n",
 
856
               local_port,
 
857
               pj_inet_ntoa(remote_addr.sin_addr),
 
858
               pj_ntohs(remote_addr.sin_port));
 
859
 
 
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)));
 
868
 
 
869
    for (;;) {
 
870
        char tmp[10];
 
871
 
 
872
        puts("");
 
873
        puts("Commands:");
 
874
        puts("  q     Quit");
 
875
        puts("");
 
876
 
 
877
        printf("Command: "); fflush(stdout);
 
878
 
 
879
        if (fgets(tmp, sizeof(tmp), stdin) == NULL) {
 
880
            puts("EOF while reading stdin, will quit now..");
 
881
            break;
 
882
        }
 
883
 
 
884
        if (tmp[0] == 'q')
 
885
            break;
 
886
 
 
887
    }
 
888
 
 
889
 
 
890
 
 
891
    /* Start deinitialization: */
 
892
on_exit:
 
893
 
 
894
    /* Stop video devices */
 
895
    if (capture)
 
896
        pjmedia_vid_port_stop(capture);
 
897
    if (renderer)
 
898
        pjmedia_vid_port_stop(renderer);
 
899
 
 
900
    /* Stop and destroy file clock */
 
901
    if (play_clock) {
 
902
        pjmedia_clock_stop(play_clock);
 
903
        pjmedia_clock_destroy(play_clock);
 
904
    }
 
905
 
 
906
    /* Destroy file reader/player */
 
907
    if (play_port)
 
908
        pjmedia_port_destroy(play_port);
 
909
 
 
910
    /* Destroy file decoder */
 
911
    if (play_decoder) {
 
912
        play_decoder->op->close(play_decoder);
 
913
        pjmedia_vid_codec_mgr_dealloc_codec(NULL, play_decoder);
 
914
    }
 
915
 
 
916
    /* Destroy video devices */
 
917
    if (capture)
 
918
        pjmedia_vid_port_destroy(capture);
 
919
    if (renderer)
 
920
        pjmedia_vid_port_destroy(renderer);
 
921
 
 
922
    /* Destroy stream */
 
923
    if (stream) {
 
924
        pjmedia_transport *tp;
 
925
 
 
926
        tp = pjmedia_vid_stream_get_transport(stream);
 
927
        pjmedia_vid_stream_destroy(stream);
 
928
 
 
929
        pjmedia_transport_close(tp);
 
930
    }
 
931
 
 
932
    /* Deinit codecs */
 
933
    deinit_codecs();
 
934
 
 
935
    /* Shutdown video subsystem */
 
936
    pjmedia_vid_dev_subsys_shutdown();
 
937
 
 
938
    /* Destroy event manager */
 
939
    pjmedia_event_mgr_destroy(NULL);
 
940
 
 
941
    /* Release application pool */
 
942
    pj_pool_release( pool );
 
943
 
 
944
    /* Destroy media endpoint. */
 
945
    pjmedia_endpt_destroy( med_endpt );
 
946
 
 
947
    /* Destroy pool factory */
 
948
    pj_caching_pool_destroy( &cp );
 
949
 
 
950
    /* Shutdown PJLIB */
 
951
    pj_shutdown();
 
952
 
 
953
    return (status == PJ_SUCCESS) ? 0 : 1;
 
954
}
 
955
 
 
956
 
 
957
#else
 
958
 
 
959
int main(int argc, char *argv[])
 
960
{
 
961
    PJ_UNUSED_ARG(argc);
 
962
    PJ_UNUSED_ARG(argv);
 
963
    puts("Error: this sample requires video capability (PJMEDIA_HAS_VIDEO == 1)");
 
964
    return -1;
 
965
}
 
966
 
 
967
#endif /* PJMEDIA_HAS_VIDEO */