static pj_status_t avi_event_cb(pjmedia_event *event, void *user_data) { avi_port_t *ap = (avi_port_t *)user_data; switch (event->type) { case PJMEDIA_EVENT_WND_CLOSED: ap->is_quitting = PJ_TRUE; break; case PJMEDIA_EVENT_MOUSE_BTN_DOWN: if (ap->is_running) { pjmedia_vid_port_stop(ap->vid_port); if (ap->snd_port) pjmedia_aud_stream_stop( pjmedia_snd_port_get_snd_stream(ap->snd_port)); } else { pjmedia_vid_port_start(ap->vid_port); if (ap->snd_port) pjmedia_aud_stream_start( pjmedia_snd_port_get_snd_stream(ap->snd_port)); } ap->is_running = !ap->is_running; break; default: return PJ_SUCCESS; } /* We handled the event on our own, so return non-PJ_SUCCESS here */ return -1; }
PJ_DEF(pj_status_t) pjmedia_vid_port_start(pjmedia_vid_port *vp) { pj_status_t status; PJ_ASSERT_RETURN(vp, PJ_EINVAL); status = pjmedia_vid_dev_stream_start(vp->strm); if (status != PJ_SUCCESS) goto on_error; if (vp->clock) { status = pjmedia_clock_start(vp->clock); if (status != PJ_SUCCESS) goto on_error; } return PJ_SUCCESS; on_error: pjmedia_vid_port_stop(vp); return status; }
static int encode_decode_test(pj_pool_t *pool, const char *codec_id, pjmedia_vid_packing packing) { const pj_str_t port_name = {"codec", 5}; pjmedia_vid_codec *codec=NULL; pjmedia_port codec_port; codec_port_data_t codec_port_data; pjmedia_vid_codec_param codec_param; const pjmedia_vid_codec_info *codec_info; const char *packing_name; pjmedia_vid_dev_index cap_idx, rdr_idx; pjmedia_vid_port *capture=NULL, *renderer=NULL; pjmedia_vid_port_param vport_param; pjmedia_video_format_detail *vfd; char codec_name[5]; pj_status_t status; int rc = 0; switch (packing) { case PJMEDIA_VID_PACKING_PACKETS: packing_name = "framed"; break; case PJMEDIA_VID_PACKING_WHOLE: packing_name = "whole"; break; default: packing_name = "unknown"; break; } PJ_LOG(3, (THIS_FILE, " encode decode test: codec=%s, packing=%s", codec_id, packing_name)); /* Lookup codec */ { pj_str_t codec_id_st; unsigned info_cnt = 1; /* Lookup codec */ pj_cstr(&codec_id_st, codec_id); status = pjmedia_vid_codec_mgr_find_codecs_by_id(NULL, &codec_id_st, &info_cnt, &codec_info, NULL); if (status != PJ_SUCCESS) { rc = 205; goto on_return; } } #if CAPTURE_DEV == -1 /* Lookup colorbar source */ status = pjmedia_vid_dev_lookup("Colorbar", "Colorbar generator", &cap_idx); if (status != PJ_SUCCESS) { rc = 206; goto on_return; } #elif CAPTURE_DEV == -2 /* Lookup any first non-colorbar source */ { unsigned i, cnt; pjmedia_vid_dev_info info; cap_idx = -1; cnt = pjmedia_vid_dev_count(); for (i = 0; i < cnt; ++i) { status = pjmedia_vid_dev_get_info(i, &info); if (status != PJ_SUCCESS) { rc = 206; goto on_return; } if (info.dir & PJMEDIA_DIR_CAPTURE && pj_ansi_stricmp(info.driver, "Colorbar")) { cap_idx = i; break; } } if (cap_idx == -1) { status = PJ_ENOTFOUND; rc = 206; goto on_return; } } #else cap_idx = CAPTURE_DEV; #endif /* Lookup SDL renderer */ status = pjmedia_vid_dev_lookup("SDL", "SDL renderer", &rdr_idx); if (status != PJ_SUCCESS) { rc = 207; goto on_return; } /* Prepare codec */ { pj_str_t codec_id_st; unsigned info_cnt = 1; const pjmedia_vid_codec_info *codec_info; /* Lookup codec */ pj_cstr(&codec_id_st, codec_id); status = pjmedia_vid_codec_mgr_find_codecs_by_id(NULL, &codec_id_st, &info_cnt, &codec_info, NULL); if (status != PJ_SUCCESS) { rc = 245; goto on_return; } status = pjmedia_vid_codec_mgr_get_default_param(NULL, codec_info, &codec_param); if (status != PJ_SUCCESS) { rc = 246; goto on_return; } codec_param.packing = packing; /* Open codec */ status = pjmedia_vid_codec_mgr_alloc_codec(NULL, codec_info, &codec); if (status != PJ_SUCCESS) { rc = 250; goto on_return; } status = pjmedia_vid_codec_init(codec, pool); if (status != PJ_SUCCESS) { rc = 251; goto on_return; } status = pjmedia_vid_codec_open(codec, &codec_param); if (status != PJ_SUCCESS) { rc = 252; goto on_return; } /* After opened, codec will update the param, let's sync encoder & * decoder format detail. */ codec_param.dec_fmt.det = codec_param.enc_fmt.det; /* Subscribe to codec events */ pjmedia_event_subscribe(NULL, &codec_on_event, &codec_port_data, codec); } pjmedia_vid_port_param_default(&vport_param); /* Create capture, set it to active (master) */ status = pjmedia_vid_dev_default_param(pool, cap_idx, &vport_param.vidparam); if (status != PJ_SUCCESS) { rc = 220; goto on_return; } pjmedia_format_copy(&vport_param.vidparam.fmt, &codec_param.dec_fmt); vport_param.vidparam.dir = PJMEDIA_DIR_CAPTURE; vport_param.active = PJ_TRUE; if (vport_param.vidparam.fmt.detail_type != PJMEDIA_FORMAT_DETAIL_VIDEO) { rc = 221; goto on_return; } vfd = pjmedia_format_get_video_format_detail(&vport_param.vidparam.fmt, PJ_TRUE); if (vfd == NULL) { rc = 225; goto on_return; } status = pjmedia_vid_port_create(pool, &vport_param, &capture); if (status != PJ_SUCCESS) { rc = 226; goto on_return; } /* Create renderer, set it to passive (slave) */ vport_param.active = PJ_FALSE; vport_param.vidparam.dir = PJMEDIA_DIR_RENDER; vport_param.vidparam.rend_id = rdr_idx; vport_param.vidparam.disp_size = vfd->size; status = pjmedia_vid_port_create(pool, &vport_param, &renderer); if (status != PJ_SUCCESS) { rc = 230; goto on_return; } /* Init codec port */ pj_bzero(&codec_port, sizeof(codec_port)); status = pjmedia_port_info_init2(&codec_port.info, &port_name, 0x1234, PJMEDIA_DIR_ENCODING, &codec_param.dec_fmt); if (status != PJ_SUCCESS) { rc = 260; goto on_return; } codec_port_data.codec = codec; codec_port_data.rdr_port = renderer; codec_port_data.enc_buf_size = codec_param.dec_fmt.det.vid.size.w * codec_param.dec_fmt.det.vid.size.h * 4; codec_port_data.enc_buf = pj_pool_alloc(pool, codec_port_data.enc_buf_size); codec_port_data.pack_buf_size = codec_port_data.enc_buf_size; codec_port_data.pack_buf = pj_pool_alloc(pool, codec_port_data.pack_buf_size); codec_port.put_frame = &codec_put_frame; codec_port.port_data.pdata = &codec_port_data; /* Connect capture to codec port */ status = pjmedia_vid_port_connect(capture, &codec_port, PJ_FALSE); if (status != PJ_SUCCESS) { rc = 270; goto on_return; } PJ_LOG(3, (THIS_FILE, " starting codec test: %s<->%.*s %dx%d", pjmedia_fourcc_name(codec_param.dec_fmt.id, codec_name), codec_info->encoding_name.slen, codec_info->encoding_name.ptr, codec_param.dec_fmt.det.vid.size.w, codec_param.dec_fmt.det.vid.size.h )); /* Start streaming.. */ status = pjmedia_vid_port_start(renderer); if (status != PJ_SUCCESS) { rc = 275; goto on_return; } status = pjmedia_vid_port_start(capture); if (status != PJ_SUCCESS) { rc = 280; goto on_return; } /* Sleep while the video is being displayed... */ pj_thread_sleep(10000); on_return: if (status != PJ_SUCCESS) { PJ_PERROR(3, (THIS_FILE, status, " error")); } if (capture) pjmedia_vid_port_stop(capture); if (renderer) pjmedia_vid_port_stop(renderer); if (capture) pjmedia_vid_port_destroy(capture); if (renderer) pjmedia_vid_port_destroy(renderer); if (codec) { pjmedia_event_unsubscribe(NULL, &codec_on_event, &codec_port_data, codec); pjmedia_vid_codec_close(codec); pjmedia_vid_codec_mgr_dealloc_codec(NULL, codec); } return rc; }
static int capture_render_loopback(pj_bool_t active, int cap_dev_id, int rend_dev_id, const pjmedia_format *fmt) { pj_pool_t *pool; pjmedia_vid_port *capture=NULL, *renderer=NULL; pjmedia_vid_dev_info cdi, rdi; pjmedia_vid_port_param param; pjmedia_video_format_detail *vfd; pj_status_t status; int rc = 0, i; pool = pj_pool_create(mem, "vidportloop", 1000, 1000, NULL); status = pjmedia_vid_dev_get_info(cap_dev_id, &cdi); if (status != PJ_SUCCESS) goto on_return; status = pjmedia_vid_dev_get_info(rend_dev_id, &rdi); if (status != PJ_SUCCESS) goto on_return; PJ_LOG(3,(THIS_FILE, " %s (%s) ===> %s (%s)\t%s\t%dx%d\t@%d:%d fps", cdi.name, cdi.driver, rdi.name, rdi.driver, pjmedia_get_video_format_info(NULL, fmt->id)->name, fmt->det.vid.size.w, fmt->det.vid.size.h, fmt->det.vid.fps.num, fmt->det.vid.fps.denum)); pjmedia_vid_port_param_default(¶m); /* Create capture, set it to active (master) */ status = pjmedia_vid_dev_default_param(pool, cap_dev_id, ¶m.vidparam); if (status != PJ_SUCCESS) { rc = 100; goto on_return; } param.vidparam.dir = PJMEDIA_DIR_CAPTURE; param.vidparam.fmt = *fmt; param.active = (active? PJ_TRUE: PJ_FALSE); if (param.vidparam.fmt.detail_type != PJMEDIA_FORMAT_DETAIL_VIDEO) { rc = 103; goto on_return; } vfd = pjmedia_format_get_video_format_detail(¶m.vidparam.fmt, PJ_TRUE); if (vfd == NULL) { rc = 105; goto on_return; } status = pjmedia_vid_port_create(pool, ¶m, &capture); if (status != PJ_SUCCESS) { rc = 110; goto on_return; } /* Create renderer, set it to passive (slave) */ status = pjmedia_vid_dev_default_param(pool, rend_dev_id, ¶m.vidparam); if (status != PJ_SUCCESS) { rc = 120; goto on_return; } param.active = (active? PJ_FALSE: PJ_TRUE); param.vidparam.dir = PJMEDIA_DIR_RENDER; param.vidparam.rend_id = rend_dev_id; param.vidparam.fmt = *fmt; param.vidparam.disp_size = vfd->size; status = pjmedia_vid_port_create(pool, ¶m, &renderer); if (status != PJ_SUCCESS) { rc = 130; goto on_return; } /* Set event handler */ pjmedia_event_subscribe(NULL, &vid_event_cb, NULL, renderer); /* Connect capture to renderer */ status = pjmedia_vid_port_connect( (active? capture: renderer), pjmedia_vid_port_get_passive_port(active? renderer: capture), PJ_FALSE); if (status != PJ_SUCCESS) { rc = 140; goto on_return; } /* Start streaming.. */ status = pjmedia_vid_port_start(renderer); if (status != PJ_SUCCESS) { rc = 150; goto on_return; } status = pjmedia_vid_port_start(capture); if (status != PJ_SUCCESS) { rc = 160; goto on_return; } /* Sleep while the webcam is being displayed... */ for (i = 0; i < LOOP_DURATION*10 && (!is_quitting); i++) { pj_thread_sleep(100); } on_return: if (status != PJ_SUCCESS) PJ_PERROR(3, (THIS_FILE, status, " error")); if (capture) pjmedia_vid_port_stop(capture); if (renderer) pjmedia_vid_port_stop(renderer); if (capture) pjmedia_vid_port_destroy(capture); if (renderer) { pjmedia_event_unsubscribe(NULL, &vid_event_cb, NULL, renderer); pjmedia_vid_port_destroy(renderer); } pj_pool_release(pool); return rc; }
/* * main() */ int main(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; 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 = 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 = 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_ntoa(remote_addr.sin_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_ntoa(remote_addr.sin_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, 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_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; }