123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017 |
- /*
- * Copyright (C) 2011 Teluu Inc. (http://www.teluu.com)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
- /**
- * \page page_pjmedia_samples_vid_streamutil_c Samples: Video Streaming
- *
- * This example mainly demonstrates how to stream video to remote
- * peer using RTP.
- *
- * This file is pjsip-apps/src/samples/vid_streamutil.c
- *
- * \includelineno vid_streamutil.c
- */
- #include <pjlib.h>
- #include <pjlib-util.h>
- #include <pjmedia.h>
- #include <pjmedia-codec.h>
- #include <pjmedia/transport_srtp.h>
- #if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
- #include <stdlib.h> /* atoi() */
- #include <stdio.h>
- #include "util.h"
- static const char *desc =
- " vid_streamutil \n"
- "\n"
- " PURPOSE: \n"
- " Demonstrate how to use pjmedia video stream component to \n"
- " transmit/receive RTP packets to/from video device/file. \n"
- "\n"
- "\n"
- " USAGE: \n"
- " vid_streamutil [options] \n"
- "\n"
- "\n"
- " Options: \n"
- " --codec=CODEC Set the codec name. \n"
- " --local-port=PORT Set local RTP port (default=4000) \n"
- " --remote=IP:PORT Set the remote peer. If this option is set, \n"
- " the program will transmit RTP audio to the \n"
- " specified address. (default: recv only) \n"
- " --play-file=AVI Send video from the AVI file instead of from \n"
- " the video device. \n"
- " --send-recv Set stream direction to bidirectional. \n"
- " --send-only Set stream direction to send only \n"
- " --recv-only Set stream direction to recv only (default) \n"
-
- " --send-width Video width to be sent \n"
- " --send-height Video height to be sent \n"
- " --send-width and --send-height not applicable \n"
- " for file streaming (see --play-file) \n"
- " --send-pt Payload type for sending \n"
- " --recv-pt Payload type for receiving \n"
- #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
- " --use-srtp[=NAME] Enable SRTP with crypto suite NAME \n"
- " e.g: AES_CM_128_HMAC_SHA1_80 (default), \n"
- " AES_CM_128_HMAC_SHA1_32 \n"
- " Use this option along with the TX & RX keys, \n"
- " formated of 60 hex digits (e.g: E148DA..) \n"
- " --srtp-tx-key SRTP key for transmiting \n"
- " --srtp-rx-key SRTP key for receiving \n"
- #endif
- "\n"
- ;
- #define THIS_FILE "vid_streamutil.c"
- /* If set, local renderer will be created to play original file */
- #define HAS_LOCAL_RENDERER_FOR_PLAY_FILE 1
- /* Default width and height for the renderer, better be set to maximum
- * acceptable size.
- */
- #define DEF_RENDERER_WIDTH 640
- #define DEF_RENDERER_HEIGHT 480
- /* Hexa string to octet array */
- int my_hex_string_to_octet_string(char *raw, char *hex, int len)
- {
- int i;
- for (i = 0; i < len; i+=2) {
- int tmp;
- if (i+1 >= len || !pj_isxdigit(hex[i]) || !pj_isxdigit(hex[i+1]))
- return i;
- tmp = pj_hex_digit_to_val((unsigned char)hex[i]) << 4;
- tmp |= pj_hex_digit_to_val((unsigned char)hex[i+1]);
- raw[i/2] = (char)(tmp & 0xFF);
- }
- return len;
- }
- /*
- * Register all codecs.
- */
- static pj_status_t init_codecs(pj_pool_factory *pf)
- {
- pj_status_t status;
- /* To suppress warning about unused var when all codecs are disabled */
- PJ_UNUSED_ARG(status);
- PJ_UNUSED_ARG(pf);
- #if defined(PJMEDIA_HAS_OPENH264_CODEC) && PJMEDIA_HAS_OPENH264_CODEC != 0
- status = pjmedia_codec_openh264_vid_init(NULL, pf);
- PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
- #endif
- #if defined(PJMEDIA_HAS_VID_TOOLBOX_CODEC) && \
- PJMEDIA_HAS_VID_TOOLBOX_CODEC != 0
- status = pjmedia_codec_vid_toolbox_init(NULL, pf);
- PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
- #endif
- #if defined(PJMEDIA_HAS_VPX_CODEC) && PJMEDIA_HAS_VPX_CODEC != 0
- status = pjmedia_codec_vpx_vid_init(NULL, pf);
- PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
- #endif
- #if defined(PJMEDIA_HAS_FFMPEG_VID_CODEC) && PJMEDIA_HAS_FFMPEG_VID_CODEC != 0
- status = pjmedia_codec_ffmpeg_vid_init(NULL, pf);
- PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
- #endif
- return PJ_SUCCESS;
- }
- /*
- * Register all codecs.
- */
- static void deinit_codecs()
- {
- #if defined(PJMEDIA_HAS_FFMPEG_VID_CODEC) && PJMEDIA_HAS_FFMPEG_VID_CODEC != 0
- pjmedia_codec_ffmpeg_vid_deinit();
- #endif
- #if defined(PJMEDIA_HAS_OPENH264_CODEC) && PJMEDIA_HAS_OPENH264_CODEC != 0
- pjmedia_codec_openh264_vid_deinit();
- #endif
- #if defined(PJMEDIA_HAS_VID_TOOLBOX_CODEC) && \
- PJMEDIA_HAS_VID_TOOLBOX_CODEC != 0
- pjmedia_codec_vid_toolbox_deinit();
- #endif
- #if defined(PJMEDIA_HAS_VPX_CODEC) && PJMEDIA_HAS_VPX_CODEC != 0
- pjmedia_codec_vpx_vid_deinit();
- #endif
- }
- static pj_status_t create_file_player( pj_pool_t *pool,
- const char *file_name,
- pjmedia_port **p_play_port)
- {
- pjmedia_avi_streams *avi_streams;
- pjmedia_avi_stream *vid_stream;
- pjmedia_port *play_port;
- pj_status_t status;
- status = pjmedia_avi_player_create_streams(pool, file_name, 0, &avi_streams);
- if (status != PJ_SUCCESS)
- return status;
- vid_stream = pjmedia_avi_streams_get_stream_by_media(avi_streams,
- 0,
- PJMEDIA_TYPE_VIDEO);
- if (!vid_stream)
- return PJ_ENOTFOUND;
- play_port = pjmedia_avi_stream_get_port(vid_stream);
- pj_assert(play_port);
- *p_play_port = play_port;
- return PJ_SUCCESS;
- }
- /*
- * Create stream based on the codec, dir, remote address, etc.
- */
- static pj_status_t create_stream( pj_pool_t *pool,
- pjmedia_endpt *med_endpt,
- const pjmedia_vid_codec_info *codec_info,
- pjmedia_vid_codec_param *codec_param,
- pjmedia_dir dir,
- pj_int8_t rx_pt,
- pj_int8_t tx_pt,
- pj_uint16_t local_port,
- const pj_sockaddr_in *rem_addr,
- #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
- pj_bool_t use_srtp,
- const pj_str_t *crypto_suite,
- const pj_str_t *srtp_tx_key,
- const pj_str_t *srtp_rx_key,
- #endif
- pjmedia_vid_stream **p_stream )
- {
- pjmedia_vid_stream_info info;
- pjmedia_transport *transport = NULL;
- pj_status_t status;
- #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
- pjmedia_transport *srtp_tp = NULL;
- #endif
- /* Reset stream info. */
- pj_bzero(&info, sizeof(info));
- /* Initialize stream info formats */
- info.type = PJMEDIA_TYPE_VIDEO;
- info.dir = dir;
- info.codec_info = *codec_info;
- info.tx_pt = (tx_pt == -1)? (pj_uint8_t)codec_info->pt : tx_pt;
- info.rx_pt = (rx_pt == -1)? (pj_uint8_t)codec_info->pt : rx_pt;
- info.ssrc = pj_rand();
- if (codec_param)
- info.codec_param = codec_param;
-
- /* Copy remote address */
- pj_memcpy(&info.rem_addr, rem_addr, sizeof(pj_sockaddr_in));
- /* If remote address is not set, set to an arbitrary address
- * (otherwise stream will assert).
- */
- if (info.rem_addr.addr.sa_family == 0) {
- const pj_str_t addr = pj_str("127.0.0.1");
- pj_sockaddr_in_init(&info.rem_addr.ipv4, &addr, 0);
- }
- /* Create media transport */
- status = pjmedia_transport_udp_create(med_endpt, NULL, local_port,
- 0, &transport);
- if (status != PJ_SUCCESS)
- return status;
- #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
- /* Check if SRTP enabled */
- if (use_srtp) {
- pjmedia_srtp_crypto tx_plc, rx_plc;
- status = pjmedia_transport_srtp_create(med_endpt, transport,
- NULL, &srtp_tp);
- if (status != PJ_SUCCESS)
- return status;
- pj_bzero(&tx_plc, sizeof(pjmedia_srtp_crypto));
- pj_bzero(&rx_plc, sizeof(pjmedia_srtp_crypto));
- tx_plc.key = *srtp_tx_key;
- tx_plc.name = *crypto_suite;
- rx_plc.key = *srtp_rx_key;
- rx_plc.name = *crypto_suite;
-
- status = pjmedia_transport_srtp_start(srtp_tp, &tx_plc, &rx_plc);
- if (status != PJ_SUCCESS)
- return status;
- transport = srtp_tp;
- }
- #endif
- /* Now that the stream info is initialized, we can create the
- * stream.
- */
- status = pjmedia_vid_stream_create( med_endpt, pool, &info,
- transport,
- NULL, p_stream);
- if (status != PJ_SUCCESS) {
- app_perror(THIS_FILE, "Error creating stream", status);
- pjmedia_transport_close(transport);
- return status;
- }
- /* Start media transport */
- pjmedia_transport_media_start(transport, 0, 0, 0, 0);
- return PJ_SUCCESS;
- }
- typedef struct play_file_data
- {
- const char *file_name;
- pjmedia_port *play_port;
- pjmedia_port *stream_port;
- pjmedia_vid_codec *decoder;
- pjmedia_port *renderer;
- void *read_buf;
- pj_size_t read_buf_size;
- void *dec_buf;
- pj_size_t dec_buf_size;
- } play_file_data;
- static void clock_cb(const pj_timestamp *ts, void *user_data)
- {
- play_file_data *play_file = (play_file_data*)user_data;
- pjmedia_frame read_frame, write_frame;
- pj_status_t status;
- PJ_UNUSED_ARG(ts);
- /* Read frame from file */
- read_frame.buf = play_file->read_buf;
- read_frame.size = play_file->read_buf_size;
- pjmedia_port_get_frame(play_file->play_port, &read_frame);
- /* Decode frame, if needed */
- if (play_file->decoder) {
- pjmedia_vid_codec *decoder = play_file->decoder;
- write_frame.buf = play_file->dec_buf;
- write_frame.size = play_file->dec_buf_size;
- status = pjmedia_vid_codec_decode(decoder, 1, &read_frame,
- (unsigned)write_frame.size,
- &write_frame);
- if (status != PJ_SUCCESS)
- return;
- } else {
- write_frame = read_frame;
- }
- /* Display frame locally */
- if (play_file->renderer)
- pjmedia_port_put_frame(play_file->renderer, &write_frame);
- /* Send frame */
- pjmedia_port_put_frame(play_file->stream_port, &write_frame);
- }
- /*
- * usage()
- */
- static void usage()
- {
- puts(desc);
- }
- /*
- * main()
- */
- static int main_func(int argc, char *argv[])
- {
- pj_caching_pool cp;
- pjmedia_endpt *med_endpt;
- pj_pool_t *pool;
- pjmedia_vid_stream *stream = NULL;
- pjmedia_port *enc_port, *dec_port;
- char addr[PJ_INET_ADDRSTRLEN];
- pj_status_t status;
- pjmedia_vid_port *capture=NULL, *renderer=NULL;
- pjmedia_vid_port_param vpp;
- #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
- /* SRTP variables */
- pj_bool_t use_srtp = PJ_FALSE;
- char tmp_tx_key[64];
- char tmp_rx_key[64];
- pj_str_t srtp_tx_key = {NULL, 0};
- pj_str_t srtp_rx_key = {NULL, 0};
- pj_str_t srtp_crypto_suite = {NULL, 0};
- int tmp_key_len;
- #endif
- /* Default values */
- const pjmedia_vid_codec_info *codec_info;
- pjmedia_vid_codec_param codec_param;
- pjmedia_dir dir = PJMEDIA_DIR_DECODING;
- pj_sockaddr_in remote_addr;
- pj_uint16_t local_port = 4000;
- char *codec_id = NULL;
- pjmedia_rect_size tx_size = {0};
- pj_int8_t rx_pt = -1, tx_pt = -1;
- play_file_data play_file = { NULL };
- pjmedia_port *play_port = NULL;
- pjmedia_vid_codec *play_decoder = NULL;
- pjmedia_clock *play_clock = NULL;
- enum {
- OPT_CODEC = 'c',
- OPT_LOCAL_PORT = 'p',
- OPT_REMOTE = 'r',
- OPT_PLAY_FILE = 'f',
- OPT_SEND_RECV = 'b',
- OPT_SEND_ONLY = 's',
- OPT_RECV_ONLY = 'i',
- OPT_SEND_WIDTH = 'W',
- OPT_SEND_HEIGHT = 'H',
- OPT_RECV_PT = 't',
- OPT_SEND_PT = 'T',
- #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
- OPT_USE_SRTP = 'S',
- #endif
- OPT_SRTP_TX_KEY = 'x',
- OPT_SRTP_RX_KEY = 'y',
- OPT_HELP = 'h',
- };
- struct pj_getopt_option long_options[] = {
- { "codec", 1, 0, OPT_CODEC },
- { "local-port", 1, 0, OPT_LOCAL_PORT },
- { "remote", 1, 0, OPT_REMOTE },
- { "play-file", 1, 0, OPT_PLAY_FILE },
- { "send-recv", 0, 0, OPT_SEND_RECV },
- { "send-only", 0, 0, OPT_SEND_ONLY },
- { "recv-only", 0, 0, OPT_RECV_ONLY },
- { "send-width", 1, 0, OPT_SEND_WIDTH },
- { "send-height", 1, 0, OPT_SEND_HEIGHT },
- { "recv-pt", 1, 0, OPT_RECV_PT },
- { "send-pt", 1, 0, OPT_SEND_PT },
- #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
- { "use-srtp", 2, 0, OPT_USE_SRTP },
- { "srtp-tx-key", 1, 0, OPT_SRTP_TX_KEY },
- { "srtp-rx-key", 1, 0, OPT_SRTP_RX_KEY },
- #endif
- { "help", 0, 0, OPT_HELP },
- { NULL, 0, 0, 0 },
- };
- int c;
- int option_index;
- pj_bzero(&remote_addr, sizeof(remote_addr));
- /* init PJLIB : */
- status = pj_init();
- PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
- /* Parse arguments */
- pj_optind = 0;
- while((c=pj_getopt_long(argc,argv, "h", long_options, &option_index))!=-1)
- {
- switch (c) {
- case OPT_CODEC:
- codec_id = pj_optarg;
- break;
- case OPT_LOCAL_PORT:
- local_port = (pj_uint16_t) atoi(pj_optarg);
- if (local_port < 1) {
- printf("Error: invalid local port %s\n", pj_optarg);
- return 1;
- }
- break;
- case OPT_REMOTE:
- {
- pj_str_t ip = pj_str(strtok(pj_optarg, ":"));
- pj_uint16_t port = (pj_uint16_t) atoi(strtok(NULL, ":"));
- status = pj_sockaddr_in_init(&remote_addr, &ip, port);
- if (status != PJ_SUCCESS) {
- app_perror(THIS_FILE, "Invalid remote address", status);
- return 1;
- }
- }
- break;
- case OPT_PLAY_FILE:
- play_file.file_name = pj_optarg;
- break;
- case OPT_SEND_RECV:
- dir = PJMEDIA_DIR_ENCODING_DECODING;
- break;
- case OPT_SEND_ONLY:
- dir = PJMEDIA_DIR_ENCODING;
- break;
- case OPT_RECV_ONLY:
- dir = PJMEDIA_DIR_DECODING;
- break;
- case OPT_SEND_WIDTH:
- tx_size.w = (unsigned)atoi(pj_optarg);
- break;
- case OPT_SEND_HEIGHT:
- tx_size.h = (unsigned)atoi(pj_optarg);
- break;
- case OPT_RECV_PT:
- rx_pt = (pj_int8_t)atoi(pj_optarg);
- break;
- case OPT_SEND_PT:
- tx_pt = (pj_int8_t)atoi(pj_optarg);
- break;
- #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
- case OPT_USE_SRTP:
- use_srtp = PJ_TRUE;
- if (pj_optarg) {
- pj_strset(&srtp_crypto_suite, pj_optarg, strlen(pj_optarg));
- } else {
- srtp_crypto_suite = pj_str("AES_CM_128_HMAC_SHA1_80");
- }
- break;
- case OPT_SRTP_TX_KEY:
- tmp_key_len = my_hex_string_to_octet_string(tmp_tx_key, pj_optarg,
- (int)strlen(pj_optarg));
- pj_strset(&srtp_tx_key, tmp_tx_key, tmp_key_len/2);
- break;
- case OPT_SRTP_RX_KEY:
- tmp_key_len = my_hex_string_to_octet_string(tmp_rx_key, pj_optarg,
- (int)strlen(pj_optarg));
- pj_strset(&srtp_rx_key, tmp_rx_key, tmp_key_len/2);
- break;
- #endif
- case OPT_HELP:
- usage();
- return 1;
- default:
- printf("Invalid options %s\n", argv[pj_optind]);
- return 1;
- }
- }
- /* Verify arguments. */
- if (dir & PJMEDIA_DIR_ENCODING) {
- if (remote_addr.sin_addr.s_addr == 0) {
- printf("Error: remote address must be set\n");
- return 1;
- }
- }
- if (play_file.file_name != NULL && dir != PJMEDIA_DIR_ENCODING) {
- printf("Direction is set to --send-only because of --play-file\n");
- dir = PJMEDIA_DIR_ENCODING;
- }
- #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
- /* SRTP validation */
- if (use_srtp) {
- if (!srtp_tx_key.slen || !srtp_rx_key.slen)
- {
- printf("Error: Key for each SRTP stream direction must be set\n");
- return 1;
- }
- }
- #endif
- /* Must create a pool factory before we can allocate any memory. */
- pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0);
- /*
- * Initialize media endpoint.
- * This will implicitly initialize PJMEDIA too.
- */
- status = pjmedia_endpt_create(&cp.factory, NULL, 1, &med_endpt);
- PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
- /* Create memory pool for application purpose */
- pool = pj_pool_create( &cp.factory, /* pool factory */
- "app", /* pool name. */
- 4000, /* init size */
- 4000, /* increment size */
- NULL /* callback on error */
- );
- /* Init video format manager */
- pjmedia_video_format_mgr_create(pool, 64, 0, NULL);
- /* Init video converter manager */
- pjmedia_converter_mgr_create(pool, NULL);
- /* Init event manager */
- pjmedia_event_mgr_create(pool, 0, NULL);
- /* Init video codec manager */
- pjmedia_vid_codec_mgr_create(pool, NULL);
- /* Init video subsystem */
- pjmedia_vid_dev_subsys_init(&cp.factory);
- /* Register all supported codecs */
- status = init_codecs(&cp.factory);
- PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
- /* Find which codec to use. */
- if (codec_id) {
- unsigned count = 1;
- pj_str_t str_codec_id = pj_str(codec_id);
- status = pjmedia_vid_codec_mgr_find_codecs_by_id(NULL,
- &str_codec_id, &count,
- &codec_info, NULL);
- if (status != PJ_SUCCESS) {
- printf("Error: unable to find codec %s\n", codec_id);
- return 1;
- }
- } else {
- static pjmedia_vid_codec_info info[1];
- unsigned count = PJ_ARRAY_SIZE(info);
- /* Default to first codec */
- pjmedia_vid_codec_mgr_enum_codecs(NULL, &count, info, NULL);
- codec_info = &info[0];
- }
- /* Get codec default param for info */
- status = pjmedia_vid_codec_mgr_get_default_param(NULL, codec_info,
- &codec_param);
- pj_assert(status == PJ_SUCCESS);
-
- /* Set outgoing video size */
- if (tx_size.w && tx_size.h)
- codec_param.enc_fmt.det.vid.size = tx_size;
- #if DEF_RENDERER_WIDTH && DEF_RENDERER_HEIGHT
- /* Set incoming video size */
- if (DEF_RENDERER_WIDTH > codec_param.dec_fmt.det.vid.size.w)
- codec_param.dec_fmt.det.vid.size.w = DEF_RENDERER_WIDTH;
- if (DEF_RENDERER_HEIGHT > codec_param.dec_fmt.det.vid.size.h)
- codec_param.dec_fmt.det.vid.size.h = DEF_RENDERER_HEIGHT;
- #endif
- if (play_file.file_name) {
- pjmedia_video_format_detail *file_vfd;
- pjmedia_clock_param clock_param;
- char fmt_name[5];
- /* Create file player */
- status = create_file_player(pool, play_file.file_name, &play_port);
- if (status != PJ_SUCCESS)
- goto on_exit;
- /* Collect format info */
- file_vfd = pjmedia_format_get_video_format_detail(&play_port->info.fmt,
- PJ_TRUE);
- PJ_LOG(2, (THIS_FILE, "Reading video stream %dx%d %s @%.2ffps",
- file_vfd->size.w, file_vfd->size.h,
- pjmedia_fourcc_name(play_port->info.fmt.id, fmt_name),
- (1.0*file_vfd->fps.num/file_vfd->fps.denum)));
- /* Allocate file read buffer */
- play_file.read_buf_size = PJMEDIA_MAX_VIDEO_ENC_FRAME_SIZE;
- play_file.read_buf = pj_pool_zalloc(pool, play_file.read_buf_size);
- /* Create decoder, if the file and the stream uses different codec */
- if (codec_info->fmt_id != (pjmedia_format_id)play_port->info.fmt.id) {
- const pjmedia_video_format_info *dec_vfi;
- pjmedia_video_apply_fmt_param dec_vafp = {0};
- const pjmedia_vid_codec_info *codec_info2;
- pjmedia_vid_codec_param codec_param2;
- /* Find decoder */
- status = pjmedia_vid_codec_mgr_get_codec_info2(NULL,
- play_port->info.fmt.id,
- &codec_info2);
- if (status != PJ_SUCCESS)
- goto on_exit;
- /* Init decoder */
- status = pjmedia_vid_codec_mgr_alloc_codec(NULL, codec_info2,
- &play_decoder);
- if (status != PJ_SUCCESS)
- goto on_exit;
- status = play_decoder->op->init(play_decoder, pool);
- if (status != PJ_SUCCESS)
- goto on_exit;
- /* Open decoder */
- status = pjmedia_vid_codec_mgr_get_default_param(NULL, codec_info2,
- &codec_param2);
- if (status != PJ_SUCCESS)
- goto on_exit;
- codec_param2.dir = PJMEDIA_DIR_DECODING;
- status = play_decoder->op->open(play_decoder, &codec_param2);
- if (status != PJ_SUCCESS)
- goto on_exit;
- /* Get decoder format info and apply param */
- dec_vfi = pjmedia_get_video_format_info(NULL,
- codec_info2->dec_fmt_id[0]);
- if (!dec_vfi || !dec_vfi->apply_fmt) {
- status = PJ_ENOTSUP;
- goto on_exit;
- }
- dec_vafp.size = file_vfd->size;
- (*dec_vfi->apply_fmt)(dec_vfi, &dec_vafp);
- /* Allocate buffer to receive decoder output */
- play_file.dec_buf_size = dec_vafp.framebytes;
- play_file.dec_buf = pj_pool_zalloc(pool, play_file.dec_buf_size);
- }
- /* Create player clock */
- clock_param.usec_interval = PJMEDIA_PTIME(&file_vfd->fps);
- clock_param.clock_rate = codec_info->clock_rate;
- status = pjmedia_clock_create2(pool, &clock_param,
- PJMEDIA_CLOCK_NO_HIGHEST_PRIO,
- &clock_cb, &play_file, &play_clock);
- if (status != PJ_SUCCESS)
- goto on_exit;
- /* Override stream codec param for encoding direction */
- codec_param.enc_fmt.det.vid.size = file_vfd->size;
- codec_param.enc_fmt.det.vid.fps = file_vfd->fps;
- } else {
- pjmedia_vid_port_param_default(&vpp);
- /* Set as active for all video devices */
- vpp.active = PJ_TRUE;
- /* Create video device port. */
- if (dir & PJMEDIA_DIR_ENCODING) {
- /* Create capture */
- status = pjmedia_vid_dev_default_param(
- pool,
- PJMEDIA_VID_DEFAULT_CAPTURE_DEV,
- &vpp.vidparam);
- if (status != PJ_SUCCESS)
- goto on_exit;
- pjmedia_format_copy(&vpp.vidparam.fmt, &codec_param.enc_fmt);
- vpp.vidparam.fmt.id = codec_param.dec_fmt.id;
- vpp.vidparam.dir = PJMEDIA_DIR_CAPTURE;
-
- status = pjmedia_vid_port_create(pool, &vpp, &capture);
- if (status != PJ_SUCCESS)
- goto on_exit;
- }
-
- if (dir & PJMEDIA_DIR_DECODING) {
- /* Create renderer */
- status = pjmedia_vid_dev_default_param(
- pool,
- PJMEDIA_VID_DEFAULT_RENDER_DEV,
- &vpp.vidparam);
- if (status != PJ_SUCCESS)
- goto on_exit;
- pjmedia_format_copy(&vpp.vidparam.fmt, &codec_param.dec_fmt);
- vpp.vidparam.dir = PJMEDIA_DIR_RENDER;
- vpp.vidparam.disp_size = vpp.vidparam.fmt.det.vid.size;
- vpp.vidparam.flags |= PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW_FLAGS;
- vpp.vidparam.window_flags = PJMEDIA_VID_DEV_WND_BORDER |
- PJMEDIA_VID_DEV_WND_RESIZABLE;
- status = pjmedia_vid_port_create(pool, &vpp, &renderer);
- if (status != PJ_SUCCESS)
- goto on_exit;
- }
- }
- /* Set to ignore fmtp */
- codec_param.ignore_fmtp = PJ_TRUE;
- /* Create stream based on program arguments */
- status = create_stream(pool, med_endpt, codec_info, &codec_param,
- dir, rx_pt, tx_pt, local_port, &remote_addr,
- #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
- use_srtp, &srtp_crypto_suite,
- &srtp_tx_key, &srtp_rx_key,
- #endif
- &stream);
- if (status != PJ_SUCCESS)
- goto on_exit;
- /* Get the port interface of the stream */
- status = pjmedia_vid_stream_get_port(stream, PJMEDIA_DIR_ENCODING,
- &enc_port);
- PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
- status = pjmedia_vid_stream_get_port(stream, PJMEDIA_DIR_DECODING,
- &dec_port);
- PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
- /* Start streaming */
- status = pjmedia_vid_stream_start(stream);
- if (status != PJ_SUCCESS)
- goto on_exit;
- /* Start renderer */
- if (renderer) {
- status = pjmedia_vid_port_connect(renderer, dec_port, PJ_FALSE);
- if (status != PJ_SUCCESS)
- goto on_exit;
- status = pjmedia_vid_port_start(renderer);
- if (status != PJ_SUCCESS)
- goto on_exit;
- }
- /* Start capture */
- if (capture) {
- status = pjmedia_vid_port_connect(capture, enc_port, PJ_FALSE);
- if (status != PJ_SUCCESS)
- goto on_exit;
- status = pjmedia_vid_port_start(capture);
- if (status != PJ_SUCCESS)
- goto on_exit;
- }
- /* Start playing file */
- if (play_file.file_name) {
- #if HAS_LOCAL_RENDERER_FOR_PLAY_FILE
- /* Create local renderer */
- pjmedia_vid_port_param_default(&vpp);
- vpp.active = PJ_FALSE;
- status = pjmedia_vid_dev_default_param(
- pool,
- PJMEDIA_VID_DEFAULT_RENDER_DEV,
- &vpp.vidparam);
- if (status != PJ_SUCCESS)
- goto on_exit;
- vpp.vidparam.dir = PJMEDIA_DIR_RENDER;
- pjmedia_format_copy(&vpp.vidparam.fmt, &codec_param.dec_fmt);
- vpp.vidparam.fmt.det.vid.size = play_port->info.fmt.det.vid.size;
- vpp.vidparam.fmt.det.vid.fps = play_port->info.fmt.det.vid.fps;
- vpp.vidparam.disp_size = vpp.vidparam.fmt.det.vid.size;
- vpp.vidparam.flags |= PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW_FLAGS;
- vpp.vidparam.window_flags = PJMEDIA_VID_DEV_WND_BORDER |
- PJMEDIA_VID_DEV_WND_RESIZABLE;
- status = pjmedia_vid_port_create(pool, &vpp, &renderer);
- if (status != PJ_SUCCESS)
- goto on_exit;
- status = pjmedia_vid_port_start(renderer);
- if (status != PJ_SUCCESS)
- goto on_exit;
- #endif
- /* Init play file data */
- play_file.play_port = play_port;
- play_file.stream_port = enc_port;
- play_file.decoder = play_decoder;
- if (renderer) {
- play_file.renderer = pjmedia_vid_port_get_passive_port(renderer);
- }
- status = pjmedia_clock_start(play_clock);
- if (status != PJ_SUCCESS)
- goto on_exit;
- }
- /* Done */
- if (dir == PJMEDIA_DIR_DECODING)
- printf("Stream is active, dir is recv-only, local port is %d\n",
- local_port);
- else if (dir == PJMEDIA_DIR_ENCODING)
- printf("Stream is active, dir is send-only, sending to %s:%d\n",
- pj_inet_ntop2(pj_AF_INET(), &remote_addr.sin_addr, addr,
- sizeof(addr)),
- pj_ntohs(remote_addr.sin_port));
- else
- printf("Stream is active, send/recv, local port is %d, "
- "sending to %s:%d\n",
- local_port,
- pj_inet_ntop2(pj_AF_INET(), &remote_addr.sin_addr, addr,
- sizeof(addr)),
- pj_ntohs(remote_addr.sin_port));
- if (dir & PJMEDIA_DIR_ENCODING)
- PJ_LOG(2, (THIS_FILE, "Sending %dx%d %.*s @%.2ffps",
- codec_param.enc_fmt.det.vid.size.w,
- codec_param.enc_fmt.det.vid.size.h,
- (int)codec_info->encoding_name.slen,
- codec_info->encoding_name.ptr,
- (1.0*codec_param.enc_fmt.det.vid.fps.num/
- codec_param.enc_fmt.det.vid.fps.denum)));
- for (;;) {
- char tmp[10];
- puts("");
- puts("Commands:");
- puts(" q Quit");
- puts("");
- printf("Command: "); fflush(stdout);
- if (fgets(tmp, sizeof(tmp), stdin) == NULL) {
- puts("EOF while reading stdin, will quit now..");
- break;
- }
- if (tmp[0] == 'q')
- break;
- }
- /* Start deinitialization: */
- on_exit:
- /* Stop video devices */
- if (capture)
- pjmedia_vid_port_stop(capture);
- if (renderer)
- pjmedia_vid_port_stop(renderer);
- /* Stop and destroy file clock */
- if (play_clock) {
- pjmedia_clock_stop(play_clock);
- pjmedia_clock_destroy(play_clock);
- }
- /* Destroy file reader/player */
- if (play_port)
- pjmedia_port_destroy(play_port);
- /* Destroy file decoder */
- if (play_decoder) {
- play_decoder->op->close(play_decoder);
- pjmedia_vid_codec_mgr_dealloc_codec(NULL, play_decoder);
- }
- /* Destroy video devices */
- if (capture)
- pjmedia_vid_port_destroy(capture);
- if (renderer)
- pjmedia_vid_port_destroy(renderer);
- /* Destroy stream */
- if (stream) {
- pjmedia_transport *tp;
- tp = pjmedia_vid_stream_get_transport(stream);
- pjmedia_vid_stream_destroy(stream);
-
- pjmedia_transport_media_stop(tp);
- pjmedia_transport_close(tp);
- }
- /* Deinit codecs */
- deinit_codecs();
- /* Shutdown video subsystem */
- pjmedia_vid_dev_subsys_shutdown();
- /* Destroy event manager */
- pjmedia_event_mgr_destroy(NULL);
- /* Release application pool */
- pj_pool_release( pool );
- /* Destroy media endpoint. */
- pjmedia_endpt_destroy( med_endpt );
- /* Destroy pool factory */
- pj_caching_pool_destroy( &cp );
- /* Shutdown PJLIB */
- pj_shutdown();
- return (status == PJ_SUCCESS) ? 0 : 1;
- }
- int main(int argc, char *argv[])
- {
- return pj_run_app(&main_func, argc, argv, 0);
- }
- #else
- int main(int argc, char *argv[])
- {
- PJ_UNUSED_ARG(argc);
- PJ_UNUSED_ARG(argv);
- puts("Error: this sample requires video capability (PJMEDIA_HAS_VIDEO == 1)");
- return -1;
- }
- #endif /* PJMEDIA_HAS_VIDEO */
|