Пример #1
0
static int aviplay(pj_pool_t *pool, const char *fname)
{
    pjmedia_vid_port *renderer=NULL;
    pjmedia_vid_port_param param;
    const pjmedia_video_format_info *vfi;
    pjmedia_video_format_detail *vfd;
    pjmedia_snd_port *snd_port = NULL;
    pj_status_t status;
    int rc = 0;
    pjmedia_avi_streams *avi_streams;
    pjmedia_avi_stream *vid_stream, *aud_stream;
    pjmedia_port *vid_port = NULL, *aud_port = NULL;
    pjmedia_vid_codec *codec=NULL;
    avi_port_t avi_port;

    pj_bzero(&avi_port, sizeof(avi_port));

    status = pjmedia_avi_player_create_streams(pool, fname, 0, &avi_streams);
    if (status != PJ_SUCCESS) {
        PJ_PERROR(2,("", status, "    Error playing %s", fname));
        rc = 210;
        goto on_return;
    }

    vid_stream = pjmedia_avi_streams_get_stream_by_media(avi_streams,
                 0,
                 PJMEDIA_TYPE_VIDEO);
    vid_port = pjmedia_avi_stream_get_port(vid_stream);

    if (vid_port) {
        pjmedia_vid_port_param_default(&param);

        status = pjmedia_vid_dev_default_param(pool,
                                               PJMEDIA_VID_DEFAULT_RENDER_DEV,
                                               &param.vidparam);
        if (status != PJ_SUCCESS) {
            rc = 220;
            goto on_return;
        }

        /* Create renderer, set it to active  */
        param.active = PJ_TRUE;
        param.vidparam.dir = PJMEDIA_DIR_RENDER;
        vfd = pjmedia_format_get_video_format_detail(&vid_port->info.fmt,
                PJ_TRUE);
        pjmedia_format_init_video(&param.vidparam.fmt,
                                  vid_port->info.fmt.id,
                                  vfd->size.w, vfd->size.h,
                                  vfd->fps.num, vfd->fps.denum);

        vfi = pjmedia_get_video_format_info(
                  pjmedia_video_format_mgr_instance(),
                  vid_port->info.fmt.id);
        /* Check whether the frame is encoded */
        if (!vfi || vfi->bpp == 0) {
            /* Yes, prepare codec */
            pj_str_t codec_id_st;
            unsigned info_cnt = 1, i, k;
            const pjmedia_vid_codec_info *codec_info;
            pj_str_t port_name = {"codec", 5};
            pj_uint8_t *enc_buf = NULL;
            pj_size_t enc_buf_size = 0;
            pjmedia_vid_dev_info rdr_info;
            pjmedia_port codec_port;
            codec_port_data_t codec_port_data;
            pjmedia_vid_codec_param codec_param;
            struct codec_fmt *codecp = NULL;

            /* Lookup codec */
            for (i = 0; i < sizeof(codec_fmts)/sizeof(codec_fmts[0]); i++) {
                if (vid_port->info.fmt.id == codec_fmts[i].pjmedia_id) {
                    codecp = &codec_fmts[i];
                    break;
                }
            }
            if (!codecp) {
                rc = 242;
                goto on_return;
            }
            pj_cstr(&codec_id_st, codecp->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;
            }

            pjmedia_format_copy(&codec_param.enc_fmt, &param.vidparam.fmt);

            pjmedia_vid_dev_get_info(param.vidparam.rend_id, &rdr_info);
            for (i=0; i<codec_info->dec_fmt_id_cnt; ++i) {
                for (k=0; k<rdr_info.fmt_cnt; ++k) {
                    if (codec_info->dec_fmt_id[i]==(int)rdr_info.fmt[k].id)
                    {
                        param.vidparam.fmt.id = codec_info->dec_fmt_id[i];
                        i = codec_info->dec_fmt_id_cnt;
                        break;
                    }
                }
            }

            /* 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;
            }

            pjmedia_format_copy(&codec_param.dec_fmt, &param.vidparam.fmt);
            codec_param.dir = PJMEDIA_DIR_DECODING;
            codec_param.packing = PJMEDIA_VID_PACKING_WHOLE;
            status = pjmedia_vid_codec_open(codec, &codec_param);
            if (status != PJ_SUCCESS) {
                rc = 252;
                goto on_return;
            }

            /* Alloc encoding buffer */
            enc_buf_size =  codec_param.dec_fmt.det.vid.size.w *
                            codec_param.dec_fmt.det.vid.size.h * 4
                            + 16; /*< padding, just in case */
            enc_buf = pj_pool_alloc(pool,enc_buf_size);

            /* 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;
            }
            pj_bzero(&codec_port_data, sizeof(codec_port_data));
            codec_port_data.codec = codec;
            codec_port_data.src_port = vid_port;
            codec_port_data.enc_buf = enc_buf;
            codec_port_data.enc_buf_size = enc_buf_size;

            codec_port.get_frame = &codec_get_frame;
            codec_port.port_data.pdata = &codec_port_data;

            /* Check whether we need to convert the decoded frame */
            if (codecp->need_conversion) {
                pjmedia_conversion_param conv_param;

                pjmedia_format_copy(&conv_param.src, &param.vidparam.fmt);
                pjmedia_format_copy(&conv_param.dst, &param.vidparam.fmt);
                conv_param.dst.id = codecp->dst_fmt;
                param.vidparam.fmt.id = conv_param.dst.id;

                status = pjmedia_converter_create(NULL, pool, &conv_param,
                                                  &codec_port_data.conv);
                if (status != PJ_SUCCESS) {
                    rc = 270;
                    goto on_return;
                }
            }

            status = pjmedia_vid_port_create(pool, &param, &renderer);
            if (status != PJ_SUCCESS) {
                rc = 230;
                goto on_return;
            }

            status = pjmedia_vid_port_connect(renderer, &codec_port,
                                              PJ_FALSE);
        } else {
            status = pjmedia_vid_port_create(pool, &param, &renderer);
            if (status != PJ_SUCCESS) {
                rc = 230;
                goto on_return;
            }

            /* Connect avi port to renderer */
            status = pjmedia_vid_port_connect(renderer, vid_port,
                                              PJ_FALSE);
        }

        if (status != PJ_SUCCESS) {
            rc = 240;
            goto on_return;
        }
    }

    aud_stream = pjmedia_avi_streams_get_stream_by_media(avi_streams,
                 0,
                 PJMEDIA_TYPE_AUDIO);
    aud_port = pjmedia_avi_stream_get_port(aud_stream);

    if (aud_port) {
        /* Create sound player port. */
        status = pjmedia_snd_port_create_player(
                     pool,				    /* pool		    */
                     -1,				    /* use default dev.	    */
                     PJMEDIA_PIA_SRATE(&aud_port->info),/* clock rate.	    */
                     PJMEDIA_PIA_CCNT(&aud_port->info), /* # of channels.	    */
                     PJMEDIA_PIA_SPF(&aud_port->info),  /* samples per frame.   */
                     PJMEDIA_PIA_BITS(&aud_port->info), /* bits per sample.	    */
                     0,				    /* options		    */
                     &snd_port			    /* returned port	    */
                 );
        if (status != PJ_SUCCESS) {
            rc = 310;
            goto on_return;
        }

        /* Connect file port to the sound player.
         * Stream playing will commence immediately.
         */
        status = pjmedia_snd_port_connect(snd_port, aud_port);
        if (status != PJ_SUCCESS) {
            rc = 330;
            goto on_return;
        }
    }

    if (vid_port) {
        pjmedia_vid_dev_cb cb;

        pj_bzero(&cb, sizeof(cb));
        avi_port.snd_port = snd_port;
        avi_port.vid_port = renderer;
        avi_port.is_running = PJ_TRUE;
        pjmedia_vid_port_set_cb(renderer, &cb, &avi_port);

        /* subscribe events */
        pjmedia_event_subscribe(NULL, &avi_event_cb, &avi_port,
                                renderer);

        if (snd_port) {
            /* Synchronize video rendering and audio playback */
            pjmedia_vid_port_set_clock_src(
                renderer,
                pjmedia_snd_port_get_clock_src(
                    snd_port, PJMEDIA_DIR_PLAYBACK));
        }


        /* Start video streaming.. */
        status = pjmedia_vid_port_start(renderer);
        if (status != PJ_SUCCESS) {
            rc = 270;
            goto on_return;
        }
    }

    while (!avi_port.is_quitting) {
        pj_thread_sleep(100);
    }

on_return:
    if (snd_port) {
        pjmedia_snd_port_disconnect(snd_port);
        /* Without this sleep, Windows/DirectSound will repeteadly
         * play the last frame during destroy.
         */
        pj_thread_sleep(100);
        pjmedia_snd_port_destroy(snd_port);
    }
    if (renderer) {
        pjmedia_event_unsubscribe(NULL, &avi_event_cb, &avi_port,
                                  renderer);
        pjmedia_vid_port_destroy(renderer);
    }
    if (aud_port)
        pjmedia_port_destroy(aud_port);
    if (vid_port)
        pjmedia_port_destroy(vid_port);
    if (codec) {
        pjmedia_vid_codec_close(codec);
        pjmedia_vid_codec_mgr_dealloc_codec(NULL, codec);
    }

    return rc;
}
Пример #2
0
/*
 * main()
 */
int main(int argc, char *argv[])
{
    pj_caching_pool cp;
    pjmedia_endpt *med_endpt;
    pj_pool_t *pool;
    pj_status_t status; 

    /* Codec */
    char *codec_id = (char*)"H264";
    const pjmedia_vid_codec_info *codec_info;
    pjmedia_vid_codec_param codec_param;
    pjmedia_vid_codec *codec = NULL;

    //const char *save_filename =
    //	"/home/bennylp/Desktop/opt/src/openh264-svn/testbin/test.264";
    const char *save_filename = NULL;

    /* File */
    enum
    {
	WIDTH = 320,
	HEIGHT = 192,
	FPS = 12,
	YUV_SIZE = WIDTH * HEIGHT * 3 >> 1,
	YUV_BUF_SIZE = YUV_SIZE + WIDTH,
	MAX_FRAMES = 32,
	MTU = 1500
    };
    FILE *fyuv = NULL;
    FILE *f264 = NULL;
    typedef pj_uint8_t enc_buf_type[MTU];
    pj_uint8_t yuv_frame[YUV_BUF_SIZE];
    enc_buf_type enc_buf[MAX_FRAMES];
    unsigned read_cnt = 0,
	     pkt_cnt = 0,
	     dec_cnt = 0,
	     enc_cnt;

    if (0) {
	diff_file();
	return 1;
    }

    /* init PJLIB : */
    status = pj_init();
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);

    /* 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. */
    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);

    /* Register all supported codecs */
    status = init_codecs(&cp.factory);
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);

    /* Open YUV file */
    fyuv = fopen("pjsip-apps/bin/CiscoVT2people_320x192_12fps.yuv", "rb");
    if (!fyuv) {
	puts("Unable to open ../CiscoVT2people_320x192_12fps.yuv");
	status = -1;
	goto on_exit;
    }

    /* Write 264 file if wanted */
    if (save_filename) {
	f264 = fopen(save_filename, "wb");
    }

    /* 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);
    
    /* Alloc encoder */
    status = pjmedia_vid_codec_mgr_alloc_codec(NULL, codec_info, &codec);
    if (status != PJ_SUCCESS) {
	PJ_PERROR(3,(THIS_FILE, status, "Error allocating codec"));
	goto on_exit;
    }

    codec_param.dir = PJMEDIA_DIR_ENCODING_DECODING;
    codec_param.packing = PJMEDIA_VID_PACKING_PACKETS;
    codec_param.enc_mtu = MTU;
    codec_param.enc_fmt.det.vid.size.w = WIDTH;
    codec_param.enc_fmt.det.vid.size.h = HEIGHT;
    codec_param.enc_fmt.det.vid.fps.num = FPS;
    codec_param.enc_fmt.det.vid.avg_bps = WIDTH * HEIGHT * FPS;

    status = pjmedia_vid_codec_init(codec, pool);
    if (status != PJ_SUCCESS) {
	PJ_PERROR(3,(THIS_FILE, status, "Error initializing codec"));
	goto on_exit;
    }

    status = pjmedia_vid_codec_open(codec, &codec_param);
    if (status != PJ_SUCCESS) {
	PJ_PERROR(3,(THIS_FILE, status, "Error opening codec"));
	goto on_exit;
    }

    while (fread(yuv_frame, 1, YUV_SIZE, fyuv) == YUV_SIZE) {
	pjmedia_frame frm_yuv, frm_enc[MAX_FRAMES];
	pj_bool_t has_more = PJ_FALSE;
	const pj_uint8_t start_nal[] = { 0, 0, 1 };
	unsigned i;

	++ read_cnt;

	pj_bzero(&frm_enc, sizeof(frm_enc));
	pj_bzero(&frm_yuv, sizeof(frm_yuv));

	frm_yuv.buf = yuv_frame;
	frm_yuv.size = YUV_SIZE;

	enc_cnt = 0;
	frm_enc[enc_cnt].buf = enc_buf[enc_cnt];
	frm_enc[enc_cnt].size = MTU;

	status = pjmedia_vid_codec_encode_begin(codec, NULL, &frm_yuv,
	                                        MTU, &frm_enc[enc_cnt],
	                                        &has_more);
	if (status != PJ_SUCCESS) {
	    PJ_PERROR(3,(THIS_FILE, status, "Codec encode error"));
	    goto on_exit;
	}
	if (frm_enc[enc_cnt].size) {
	    if (f264) {
		fwrite(start_nal, 1, sizeof(start_nal), f264);
		fwrite(frm_enc[enc_cnt].buf, 1, frm_enc[enc_cnt].size, f264);
	    }
	    ++pkt_cnt;
	    ++enc_cnt;
	}

	while (has_more) {

	    if (enc_cnt >= MAX_FRAMES) {
		status = -1;
		puts("Error: too many encoded frames");
		goto on_exit;
	    }

	    has_more = PJ_FALSE;
	    frm_enc[enc_cnt].buf = enc_buf[enc_cnt];
	    frm_enc[enc_cnt].size = MTU;

	    status = pjmedia_vid_codec_encode_more(codec, MTU,
	                                           &frm_enc[enc_cnt],
	                                           &has_more);
	    if (status != PJ_SUCCESS) {
		PJ_PERROR(3,(THIS_FILE, status, "Codec encode error"));
		goto on_exit;
	    }

	    if (frm_enc[enc_cnt].size) {
		if (f264) {
		    fwrite(start_nal, 1, sizeof(start_nal), f264);
		    fwrite(frm_enc[enc_cnt].buf, 1, frm_enc[enc_cnt].size,
		           f264);
		}
		++pkt_cnt;
		++enc_cnt;
	    }
	}

	if (enc_cnt) {
	    frm_yuv.buf = yuv_frame;
	    frm_yuv.size = YUV_BUF_SIZE;
	    status = pjmedia_vid_codec_decode(codec, enc_cnt,
					      frm_enc,
					      YUV_BUF_SIZE,
					      &frm_yuv);
	    if (status != PJ_SUCCESS) {
		PJ_PERROR(3,(THIS_FILE, status, "Codec decode error"));
		goto on_exit;
	    }

	    if (frm_yuv.size != 0) {
		++dec_cnt;
	    }
	}
    }

    printf("Done.\n"
	   " Read YUV frames:    %d\n"
	   " Encoded packets:    %d\n"
	   " Decoded YUV frames: %d\n",
	   read_cnt, pkt_cnt, dec_cnt);

    /* Start deinitialization: */
on_exit:
    if (codec) {
	pjmedia_vid_codec_close(codec);
	pjmedia_vid_codec_mgr_dealloc_codec(NULL, codec);
    }

    if (f264)
	fclose(f264);

    if (fyuv)
	fclose(fyuv);

    /* Deinit codecs */
    deinit_codecs();

    /* 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;
}


#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;
}
Пример #3
0
/*
 * 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, 
						     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,
						     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;

	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 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;
}
Пример #4
0
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;
}
/*
 * Internal function for collecting codec info and param from the SDP media.
 */
static pj_status_t get_video_codec_info_param(pjmedia_vid_stream_info *si,
					      pj_pool_t *pool,
					      pjmedia_vid_codec_mgr *mgr,
					      const pjmedia_sdp_media *local_m,
					      const pjmedia_sdp_media *rem_m)
{
    unsigned pt = 0;
    const pjmedia_vid_codec_info *p_info;
    pj_status_t status;

    pt = pj_strtoul(&local_m->desc.fmt[0]);

    /* Get payload type for receiving direction */
    si->rx_pt = pt;

    /* Get codec info and payload type for transmitting direction. */
    if (pt < 96) {
	/* For static payload types, get the codec info from codec manager. */
	status = pjmedia_vid_codec_mgr_get_codec_info(mgr, pt, &p_info);
	if (status != PJ_SUCCESS)
	    return status;

	si->codec_info = *p_info;

	/* Get payload type for transmitting direction.
	 * For static payload type, pt's are symetric.
	 */
	si->tx_pt = pt;
    } else {
	const pjmedia_sdp_attr *attr;
	pjmedia_sdp_rtpmap *rtpmap;
	pjmedia_codec_id codec_id;
	pj_str_t codec_id_st;
	unsigned i;

	/* Determine payload type for outgoing channel, by finding
	 * dynamic payload type in remote SDP that matches the answer.
	 */
	si->tx_pt = 0xFFFF;
	for (i=0; i<rem_m->desc.fmt_count; ++i) {
	    if (pjmedia_sdp_neg_fmt_match(NULL,
					  (pjmedia_sdp_media*)local_m, 0,
					  (pjmedia_sdp_media*)rem_m, i, 0) ==
		PJ_SUCCESS)
	    {
		/* Found matched codec. */
		si->tx_pt = pj_strtoul(&rem_m->desc.fmt[i]);
		break;
	    }
	}

	if (si->tx_pt == 0xFFFF)
	    return PJMEDIA_EMISSINGRTPMAP;

	/* For dynamic payload types, get codec name from the rtpmap */
	attr = pjmedia_sdp_media_find_attr(local_m, &ID_RTPMAP,
					   &local_m->desc.fmt[0]);
	if (attr == NULL)
	    return PJMEDIA_EMISSINGRTPMAP;

	status = pjmedia_sdp_attr_to_rtpmap(pool, attr, &rtpmap);
	if (status != PJ_SUCCESS)
	    return status;

	/* Then get the codec info from the codec manager */
	pj_ansi_snprintf(codec_id, sizeof(codec_id), "%.*s/",
			 (int)rtpmap->enc_name.slen, rtpmap->enc_name.ptr);
	codec_id_st = pj_str(codec_id);
	i = 1;
	status = pjmedia_vid_codec_mgr_find_codecs_by_id(mgr, &codec_id_st,
							 &i, &p_info, NULL);
	if (status != PJ_SUCCESS)
	    return status;

	si->codec_info = *p_info;
    }


    /* Request for codec with the correct packing for streaming */
    si->codec_info.packings = PJMEDIA_VID_PACKING_PACKETS;

    /* Now that we have codec info, get the codec param. */
    si->codec_param = PJ_POOL_ALLOC_T(pool, pjmedia_vid_codec_param);
    status = pjmedia_vid_codec_mgr_get_default_param(mgr,
						     &si->codec_info,
						     si->codec_param);

    /* Adjust encoding bitrate, if higher than remote preference. The remote
     * bitrate preference is read from SDP "b=TIAS" line in media level.
     */
    if ((si->dir & PJMEDIA_DIR_ENCODING) && rem_m->bandw_count) {
	unsigned i, bandw = 0;

	for (i = 0; i < rem_m->bandw_count; ++i) {
	    const pj_str_t STR_BANDW_MODIFIER_TIAS = { "TIAS", 4 };
	    if (!pj_stricmp(&rem_m->bandw[i]->modifier,
		&STR_BANDW_MODIFIER_TIAS))
	    {
		bandw = rem_m->bandw[i]->value;
		break;
	    }
	}

	if (bandw) {
	    pjmedia_video_format_detail *enc_vfd;
	    enc_vfd = pjmedia_format_get_video_format_detail(
					&si->codec_param->enc_fmt, PJ_TRUE);
	    if (!enc_vfd->avg_bps || enc_vfd->avg_bps > bandw)
		enc_vfd->avg_bps = bandw * 3 / 4;
	    if (!enc_vfd->max_bps || enc_vfd->max_bps > bandw)
		enc_vfd->max_bps = bandw;
	}
    }

    /* Get remote fmtp for our encoder. */
    pjmedia_stream_info_parse_fmtp(pool, rem_m, si->tx_pt,
				   &si->codec_param->enc_fmtp);

    /* Get local fmtp for our decoder. */
    pjmedia_stream_info_parse_fmtp(pool, local_m, si->rx_pt,
				   &si->codec_param->dec_fmtp);

    /* When direction is NONE (it means SDP negotiation has failed) we don't
     * need to return a failure here, as returning failure will cause
     * the whole SDP to be rejected. See ticket #:
     *	http://
     *
     * Thanks Alain Totouom
     */
    if (status != PJ_SUCCESS && si->dir != PJMEDIA_DIR_NONE)
	return status;

    return PJ_SUCCESS;
}