示例#1
0
文件: pj_vpx.c 项目: iTeach/SipClient
 */PJ_DEF(pj_status_t) pjmedia_codec_vpx_init(pjmedia_vid_codec_mgr *mgr,
        pj_pool_factory *pf) {
    pj_pool_t *pool;
    pj_status_t status;
    unsigned i;

    PJ_LOG(4, (THIS_FILE, "Init px codec"));

    if (vpx_factory.pool != NULL ) {
        /* Already initialized. */
        return PJ_SUCCESS;
    }

    if (!mgr)
        mgr = pjmedia_vid_codec_mgr_instance();
    PJ_ASSERT_RETURN(mgr, PJ_EINVAL);

    /* Create VPX codec factory. */
    vpx_factory.base.op = &vpx_factory_op;
    vpx_factory.base.factory_data = NULL;
    vpx_factory.mgr = mgr;
    vpx_factory.pf = pf;

    pool = pj_pool_create(pf, "vpx codec factory", 256, 256, NULL );
    if (!pool)
        return PJ_ENOMEM;

    /* Create mutex. */
    status = pj_mutex_create_simple(pool, "vpx codec factory",
            &vpx_factory.mutex);
    if (status != PJ_SUCCESS)
        goto on_error;

    /* Register codec factory to codec manager. */
    status = pjmedia_vid_codec_mgr_register_factory(mgr, &vpx_factory.base);
    if (status != PJ_SUCCESS)
        goto on_error;

    vpx_factory.pool = pool;

    /* Done. */
    return PJ_SUCCESS;

    on_error: pj_pool_release(pool);
    return status;
}
示例#2
0
//Wrap start & stop
PJ_DECL(pj_status_t) csipsimple_init(pjsua_config *ua_cfg,
		pjsua_logging_config *log_cfg, pjsua_media_config *media_cfg,
		csipsimple_config *css_cfg, jobject context) {
	pj_status_t result;
	unsigned i;

	/* Create memory pool for application. */
	if(css_var.pool == NULL){
		css_var.pool = pjsua_pool_create("css", 1000, 1000);
		PJ_ASSERT_RETURN(css_var.pool, PJ_ENOMEM);
	}
	// Finalize configuration
	log_cfg->cb = &pj_android_log_msg;

	// Static cfg
	extern pj_bool_t pjsip_use_compact_form;
	extern pj_bool_t pjsip_include_allow_hdr_in_dlg;
	extern pj_bool_t pjmedia_add_rtpmap_for_static_pt;
	extern pj_bool_t pjmedia_add_bandwidth_tias_in_sdp;
	extern pj_bool_t pjsua_no_update;
	extern pj_bool_t pjmedia_webrtc_use_ns;

	pjsua_no_update = css_cfg->use_no_update ? PJ_TRUE : PJ_FALSE;

	pjsip_use_compact_form =
			css_cfg->use_compact_form_headers ? PJ_TRUE : PJ_FALSE;
	/* do not transmit Allow header */
	pjsip_include_allow_hdr_in_dlg =
			css_cfg->use_compact_form_headers ? PJ_FALSE : PJ_TRUE;
	/* Do not include rtpmap for static payload types (<96) */
	pjmedia_add_rtpmap_for_static_pt =
			css_cfg->use_compact_form_sdp ? PJ_FALSE : PJ_TRUE;
	/* Do not enable bandwidth information inclusion in sdp */
	pjmedia_add_bandwidth_tias_in_sdp =
			css_cfg->add_bandwidth_tias_in_sdp ? PJ_TRUE : PJ_FALSE;
	/* Use noise suppressor ? */
	pjmedia_webrtc_use_ns =
			css_cfg->use_noise_suppressor ? PJ_TRUE : PJ_FALSE;

	css_tcp_keep_alive_interval = css_cfg->tcp_keep_alive_interval;
	css_tls_keep_alive_interval = css_cfg->tls_keep_alive_interval;

	// Transaction timeouts
	pjsip_sip_cfg_var.tsx.t1 = css_cfg->tsx_t1_timeout;
	pjsip_sip_cfg_var.tsx.t2 = css_cfg->tsx_t2_timeout;
	pjsip_sip_cfg_var.tsx.t4 = css_cfg->tsx_t4_timeout;
	pjsip_sip_cfg_var.tsx.td = css_cfg->tsx_td_timeout;
	pjsip_sip_cfg_var.endpt.disable_tcp_switch = css_cfg->disable_tcp_switch;
    pjsip_sip_cfg_var.endpt.disable_rport = css_cfg->disable_rport;

	// Audio codec cfg
	css_var.extra_aud_codecs_cnt = css_cfg->extra_aud_codecs_cnt;
	for (i = 0; i < css_cfg->extra_aud_codecs_cnt; i++) {
		dynamic_factory *css_codec = &css_var.extra_aud_codecs[i];
		dynamic_factory *cfg_codec = &css_cfg->extra_aud_codecs[i];

		pj_strdup_with_null(css_var.pool, &css_codec->shared_lib_path,
				&cfg_codec->shared_lib_path);
		pj_strdup_with_null(css_var.pool, &css_codec->init_factory_name,
				&cfg_codec->init_factory_name);
	}

	// Video codec cfg -- For now only destroy is useful but for future
	// hopefully vid codec mgr will behaves as audio does
	// Also in this case destroy will become obsolete
	css_var.extra_vid_codecs_cnt = css_cfg->extra_vid_codecs_cnt;
	for (i = 0; i < css_cfg->extra_vid_codecs_cnt; i++) {
		dynamic_factory *css_codec = &css_var.extra_vid_codecs[i];
		dynamic_factory *cfg_codec = &css_cfg->extra_vid_codecs[i];

		pj_strdup_with_null(css_var.pool, &css_codec->shared_lib_path,
				&cfg_codec->shared_lib_path);
		pj_strdup_with_null(css_var.pool, &css_codec->init_factory_name,
				&cfg_codec->init_factory_name);


		css_codec = &css_var.extra_vid_codecs_destroy[i];
		cfg_codec = &css_cfg->extra_vid_codecs_destroy[i];

		pj_strdup_with_null(css_var.pool, &css_codec->shared_lib_path,
				&cfg_codec->shared_lib_path);
		pj_strdup_with_null(css_var.pool, &css_codec->init_factory_name,
				&cfg_codec->init_factory_name);

	}

	// ZRTP cfg
	css_var.default_use_zrtp = css_cfg->use_zrtp;
	ua_cfg->cb.on_create_media_transport = &on_transport_created_wrapper;

#if defined(PJMEDIA_HAS_ZRTP) && PJMEDIA_HAS_ZRTP!=0
	pj_ansi_snprintf(css_var.zid_file, sizeof(css_var.zid_file),
			"%.*s/simple.zid", css_cfg->storage_folder.slen,
			css_cfg->storage_folder.ptr);
#endif

	JNIEnv *jni_env = 0;
	ATTACH_JVM(jni_env);
	css_var.context = (*jni_env)->NewGlobalRef(jni_env, context);
	DETACH_JVM(jni_env);

	result = (pj_status_t) pjsua_init(ua_cfg, log_cfg, media_cfg);
	if (result == PJ_SUCCESS) {
		/* Ringback tone */
	    init_ringback_tone();

		/* Init audio device */
		pj_status_t added_audio = PJ_ENOTFOUND;
		if (css_cfg->audio_implementation.init_factory_name.slen > 0) {
			pjmedia_aud_dev_factory* (*init_factory)(
					pj_pool_factory *pf) = get_library_factory(&css_cfg->audio_implementation);
			if(init_factory != NULL) {
				pjmedia_aud_register_factory(init_factory);
				added_audio = PJ_SUCCESS;
				PJ_LOG(4, (THIS_FILE, "Loaded audio dev"));
			}
		}

		// Fallback to default audio dev if no one found
		if (added_audio != PJ_SUCCESS) {
			pjmedia_aud_register_factory(&pjmedia_android_factory);
		}

		// Init video device
#if PJMEDIA_HAS_VIDEO
		// load renderer
		if (css_cfg->video_render_implementation.init_factory_name.slen > 0) {
			pjmedia_vid_dev_factory* (*init_factory)(
					pj_pool_factory *pf) = get_library_factory(&css_cfg->video_render_implementation);
			if(init_factory != NULL) {
				pjmedia_vid_register_factory(init_factory, NULL);
				PJ_LOG(4, (THIS_FILE, "Loaded video render dev"));
			}
		}
		// load capture
		if (css_cfg->video_capture_implementation.init_factory_name.slen > 0) {
			pjmedia_vid_dev_factory* (*init_factory)(
								pj_pool_factory *pf) = get_library_factory(&css_cfg->video_capture_implementation);
			if(init_factory != NULL) {
				pjmedia_vid_register_factory(init_factory, NULL);
				PJ_LOG(4, (THIS_FILE, "Loaded video capture dev"));
			}
		}

		// Load ffmpeg converter
		pjmedia_converter_mgr* cvrt_mgr = pjmedia_converter_mgr_instance();
		if(css_cfg->vid_converter.init_factory_name.slen > 0){
			pj_status_t (*init_factory)(pjmedia_converter_mgr* cvrt_mgr) = get_library_factory(&css_cfg->vid_converter);
			if(init_factory != NULL) {
				init_factory(cvrt_mgr);
				PJ_LOG(4, (THIS_FILE, "Loaded video converter"));
			}
		}


		// Load video codecs
		pjmedia_vid_codec_mgr* vid_mgr = pjmedia_vid_codec_mgr_instance();

		for (i = 0; i < css_var.extra_vid_codecs_cnt; i++) {
			dynamic_factory *codec = &css_var.extra_vid_codecs[i];
			pj_status_t (*init_factory)(pjmedia_vid_codec_mgr *mgr,
                    pj_pool_factory *pf) = get_library_factory(codec);
			if(init_factory != NULL){
				pj_status_t status = init_factory(vid_mgr, &pjsua_var.cp.factory);
				if(status != PJ_SUCCESS) {
					PJ_LOG(2, (THIS_FILE,"Error loading dynamic codec plugin"));
				}
	    	}
		}

#endif
		}

	return result;
}
示例#3
0
static int main_func(int argc, char *argv[])
{
    pj_caching_pool cp;
    pj_pool_t *pool;
    int rc = 0;
    pj_status_t status = PJ_SUCCESS;

    if (argc != 2) {
        puts("Error: filename required");
        puts(desc);
        return 1;
    }


    /* Must init PJLIB first: */
    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);

    /* Create memory pool for our file player */
    pool = pj_pool_create( &cp.factory,	    /* pool factory	    */
                           "AVI",	    /* pool name.	    */
                           4000,	    /* init size	    */
                           4000,	    /* increment size	    */
                           NULL		    /* callback on error    */
                         );

    pjmedia_video_format_mgr_create(pool, 64, 0, NULL);
    pjmedia_converter_mgr_create(pool, NULL);
    pjmedia_event_mgr_create(pool, 0, NULL);
    pjmedia_vid_codec_mgr_create(pool, NULL);

    status = pjmedia_vid_dev_subsys_init(&cp.factory);
    if (status != PJ_SUCCESS)
        goto on_return;

    status = pjmedia_aud_subsys_init(&cp.factory);
    if (status != PJ_SUCCESS) {
        goto on_return;
    }

#if PJMEDIA_HAS_FFMPEG_VID_CODEC
    status = pjmedia_codec_ffmpeg_vid_init(NULL, &cp.factory);
    if (status != PJ_SUCCESS)
        goto on_return;
#endif

    rc = aviplay(pool, argv[1]);

    /*
     * File should be playing and looping now
     */

    /* Without this sleep, Windows/DirectSound will repeteadly
     * play the last frame during destroy.
     */
    pj_thread_sleep(100);

on_return:
#if PJMEDIA_HAS_FFMPEG_VID_CODEC
    pjmedia_codec_ffmpeg_vid_deinit();
#endif
    pjmedia_aud_subsys_shutdown();
    pjmedia_vid_dev_subsys_shutdown();

    pjmedia_video_format_mgr_destroy(pjmedia_video_format_mgr_instance());
    pjmedia_converter_mgr_destroy(pjmedia_converter_mgr_instance());
    pjmedia_event_mgr_destroy(pjmedia_event_mgr_instance());
    pjmedia_vid_codec_mgr_destroy(pjmedia_vid_codec_mgr_instance());

    /* Release application pool */
    pj_pool_release( pool );

    /* Destroy pool factory */
    pj_caching_pool_destroy( &cp );

    /* Shutdown PJLIB */
    pj_shutdown();

    /* Done. */
    return 0;
}
示例#4
0
/* Create m=video SDP media line */
PJ_DEF(pj_status_t) pjmedia_endpt_create_video_sdp(pjmedia_endpt *endpt,
																									 pj_pool_t *pool,
																									 const pjmedia_sock_info *si,
																									 unsigned options,
																									 pjmedia_sdp_media **p_m)
{


	const pj_str_t STR_VIDEO = { "video", 5 };
	pjmedia_sdp_media *m;
	pjmedia_vid_codec_info codec_info[PJMEDIA_VID_CODEC_MGR_MAX_CODECS];
	unsigned codec_prio[PJMEDIA_VID_CODEC_MGR_MAX_CODECS];
	pjmedia_sdp_attr *attr;
	unsigned cnt, i;
	unsigned max_bitrate = 0;
	pj_status_t status;

	PJ_UNUSED_ARG(options);

	/* Make sure video codec manager is instantiated */
	if (!pjmedia_vid_codec_mgr_instance())
		pjmedia_vid_codec_mgr_create(endpt->pool, NULL);

	/* Create and init basic SDP media */
	m = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_media);
	status = init_sdp_media(m, pool, &STR_VIDEO, si);
	if (status != PJ_SUCCESS)
		return status;

	cnt = PJ_ARRAY_SIZE(codec_info);
	status = pjmedia_vid_codec_mgr_enum_codecs(NULL, &cnt, 
		codec_info, codec_prio);

	/* Check that there are not too many codecs */
	PJ_ASSERT_RETURN(0 <= PJMEDIA_MAX_SDP_FMT,
		PJ_ETOOMANY);

	/* Add format, rtpmap, and fmtp (when applicable) for each codec */
	for (i=0; i<cnt; ++i) {
		pjmedia_sdp_rtpmap rtpmap;
		pjmedia_vid_codec_param codec_param;
		pj_str_t *fmt;
		pjmedia_video_format_detail *vfd;

		pj_bzero(&rtpmap, sizeof(rtpmap));

		if (codec_prio[i] == PJMEDIA_CODEC_PRIO_DISABLED)
			break;

		if (i > PJMEDIA_MAX_SDP_FMT) {
			/* Too many codecs, perhaps it is better to tell application by
			* returning appropriate status code.
			*/
			PJ_PERROR(3,(THIS_FILE, PJ_ETOOMANY,
				"Skipping some video codecs"));
			break;
		}

		/* Must support RTP packetization and bidirectional */
		if ((codec_info[i].packings & PJMEDIA_VID_PACKING_PACKETS) == 0 ||
			codec_info[i].dir != PJMEDIA_DIR_ENCODING_DECODING)
		{
			continue;
		}

		pjmedia_vid_codec_mgr_get_default_param(NULL, &codec_info[i],
			&codec_param);

		fmt = &m->desc.fmt[m->desc.fmt_count++];
		fmt->ptr = (char*) pj_pool_alloc(pool, 8);
		fmt->slen = pj_utoa(codec_info[i].pt, fmt->ptr);
		rtpmap.pt = *fmt;

		/* Encoding name */
		rtpmap.enc_name = codec_info[i].encoding_name;

		/* Clock rate */
		rtpmap.clock_rate = codec_info[i].clock_rate;

		if (codec_info[i].pt >= 96 || pjmedia_add_rtpmap_for_static_pt) {
			pjmedia_sdp_rtpmap_to_attr(pool, &rtpmap, &attr);
			m->attr[m->attr_count++] = attr;
		}

		/* Add fmtp params */
		if (codec_param.dec_fmtp.cnt > 0) {
			enum { MAX_FMTP_STR_LEN = 160 };
			char buf[MAX_FMTP_STR_LEN];
			unsigned buf_len = 0, j;
			pjmedia_codec_fmtp *dec_fmtp = &codec_param.dec_fmtp;

			/* Print codec PT */
			buf_len += pj_ansi_snprintf(buf, 
				MAX_FMTP_STR_LEN - buf_len, 
				"%d", 
				codec_info[i].pt);

			for (j = 0; j < dec_fmtp->cnt; ++j) {
				unsigned test_len = 2;

				/* Check if buf still available */
				test_len = dec_fmtp->param[j].val.slen + 
					dec_fmtp->param[j].name.slen;
				if (test_len + buf_len >= MAX_FMTP_STR_LEN)
					return PJ_ETOOBIG;

				/* Print delimiter */
				buf_len += pj_ansi_snprintf(&buf[buf_len], 
					MAX_FMTP_STR_LEN - buf_len,
					(j == 0?" ":";"));

				/* Print an fmtp param */
				if (dec_fmtp->param[j].name.slen)
					buf_len += pj_ansi_snprintf(
					&buf[buf_len],
					MAX_FMTP_STR_LEN - buf_len,
					"%.*s=%.*s",
					(int)dec_fmtp->param[j].name.slen,
					dec_fmtp->param[j].name.ptr,
					(int)dec_fmtp->param[j].val.slen,
					dec_fmtp->param[j].val.ptr);
				else
					buf_len += pj_ansi_snprintf(&buf[buf_len], 
					MAX_FMTP_STR_LEN - buf_len,
					"%.*s", 
					(int)dec_fmtp->param[j].val.slen,
					dec_fmtp->param[j].val.ptr);
			}

			attr = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_attr);

			attr->name = pj_str("fmtp");
			attr->value = pj_strdup3(pool, buf);
			m->attr[m->attr_count++] = attr;
		}

		/* Find maximum bitrate in this media */
		vfd = pjmedia_format_get_video_format_detail(&codec_param.enc_fmt,
			PJ_TRUE);
		if (vfd && max_bitrate < vfd->max_bps)
			max_bitrate = vfd->max_bps;
	}

	/* Put bandwidth info in media level using bandwidth modifier "TIAS"
	* (RFC3890).
	*/
	if (max_bitrate) {
		const pj_str_t STR_BANDW_MODIFIER = { "TIAS", 4 };
		pjmedia_sdp_bandw *b;

		b = PJ_POOL_ALLOC_T(pool, pjmedia_sdp_bandw);
		b->modifier = STR_BANDW_MODIFIER;
		b->value = max_bitrate;
		m->bandw[m->bandw_count++] = b;
	}

	*p_m = m;
	return PJ_SUCCESS;
}
示例#5
0
/*
 * Initialize and register openh264 codec factory to pjmedia endpoint.
 */
PJ_DEF(pj_status_t) pjmedia_codec_openh264_vid_init(pjmedia_vid_codec_mgr *mgr,
                                                  pj_pool_factory *pf)
{
    pj_pool_t *pool;
    pj_status_t status;
	openh264_codec_desc *desc = &codec_desc[0];

    if (openh264_factory.pool != NULL) {
		/* Already initialized. */
		return PJ_SUCCESS;
    }

    if (!mgr)
		mgr = pjmedia_vid_codec_mgr_instance();

    PJ_ASSERT_RETURN(mgr, PJ_EINVAL);

    /* Create openh264 codec factory. */
    openh264_factory.base.op = &openh264_factory_op;
    openh264_factory.base.factory_data = NULL;
    openh264_factory.mgr = mgr;
    openh264_factory.pf = pf;

    pool = pj_pool_create(pf, "openh264 codec factory", 256, 256, NULL);
    if (!pool)
		return PJ_ENOMEM;

    /* Create mutex. */
    status = pj_mutex_create_simple(pool, "openh264 codec factory", 
				    &openh264_factory.mutex);
    if (status != PJ_SUCCESS)
		goto on_error;

	desc->info.dec_fmt_id[0] = PJMEDIA_FORMAT_I420;
	desc->info.dec_fmt_id_cnt = 1;
    desc->info.dir |= PJMEDIA_DIR_ENCODING;
    desc->info.dir |= PJMEDIA_DIR_DECODING;
	desc->enabled = PJ_TRUE;

	if (desc->info.clock_rate == 0)
	    desc->info.clock_rate = 90000;

	desc->info.packings |= PJMEDIA_VID_PACKING_WHOLE;
	if (desc->packetize && desc->unpacketize)
	    desc->info.packings |= PJMEDIA_VID_PACKING_PACKETS;

	/* Registering format match for SDP negotiation */
	if (desc->sdp_fmt_match) {
		status = pjmedia_sdp_neg_register_fmt_match_cb(
			&desc->info.encoding_name,
			desc->sdp_fmt_match);
		pj_assert(status == PJ_SUCCESS);
	}

    /* Register codec factory to codec manager. */
    status = pjmedia_vid_codec_mgr_register_factory(mgr, 
						    &openh264_factory.base);
    if (status != PJ_SUCCESS)
		goto on_error;

    openh264_factory.pool = pool;

    /* Done. */
    return PJ_SUCCESS;

on_error:
    pj_pool_release(pool);
    return status;
}
示例#6
0
int test_main(void)
{
    int rc = 0;
    pj_caching_pool caching_pool;
    pj_pool_t *pool;

    pj_init();
    pj_caching_pool_init(&caching_pool, &pj_pool_factory_default_policy, 0);
    pool = pj_pool_create(&caching_pool.factory, "test", 1000, 512, NULL);

    pj_log_set_decor(PJ_LOG_HAS_NEWLINE);
    pj_log_set_level(3);

    mem = &caching_pool.factory;

#if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
    pjmedia_video_format_mgr_create(pool, 64, 0, NULL);
    pjmedia_converter_mgr_create(pool, NULL);
    pjmedia_event_mgr_create(pool, 0, NULL);
    pjmedia_vid_codec_mgr_create(pool, NULL);
#endif

#if HAS_VID_PORT_TEST
    DO_TEST(vid_port_test());
#endif

#if HAS_VID_DEV_TEST
    DO_TEST(vid_dev_test());
#endif

#if HAS_VID_CODEC_TEST
    DO_TEST(vid_codec_test());
#endif

#if HAS_SDP_NEG_TEST
    DO_TEST(sdp_neg_test());
#endif
    //DO_TEST(sdp_test (&caching_pool.factory));
    //DO_TEST(rtp_test(&caching_pool.factory));
    //DO_TEST(session_test (&caching_pool.factory));
#if HAS_JBUF_TEST
    DO_TEST(jbuf_main());
#endif
#if HAS_MIPS_TEST
    DO_TEST(mips_test());
#endif
#if HAS_CODEC_VECTOR_TEST
    DO_TEST(codec_test_vectors());
#endif

    PJ_LOG(3,(THIS_FILE," "));

on_return:
    if (rc != 0) {
	PJ_LOG(3,(THIS_FILE,"Test completed with error(s)!"));
    } else {
	PJ_LOG(3,(THIS_FILE,"Looks like everything is okay!"));
    }

#if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
    pjmedia_video_format_mgr_destroy(pjmedia_video_format_mgr_instance());
    pjmedia_converter_mgr_destroy(pjmedia_converter_mgr_instance());
    pjmedia_event_mgr_destroy(pjmedia_event_mgr_instance());
    pjmedia_vid_codec_mgr_destroy(pjmedia_vid_codec_mgr_instance());
#endif

    pj_pool_release(pool);
    pj_caching_pool_destroy(&caching_pool);

    return rc;
}
示例#7
0
/*
 * Initialize and register FFMPEG codec factory to pjmedia endpoint.
 */
PJ_DEF(pj_status_t) pjmedia_codec_ffmpeg_init(pjmedia_vid_codec_mgr *mgr,
                                              pj_pool_factory *pf)
{
    pj_pool_t *pool;
    AVCodec *c;
    pj_status_t status;
    unsigned i;

    if (ffmpeg_factory.pool != NULL) {
	/* Already initialized. */
	return PJ_SUCCESS;
    }

    if (!mgr) mgr = pjmedia_vid_codec_mgr_instance();
    PJ_ASSERT_RETURN(mgr, PJ_EINVAL);

    /* Create FFMPEG codec factory. */
    ffmpeg_factory.base.op = &ffmpeg_factory_op;
    ffmpeg_factory.base.factory_data = NULL;
    ffmpeg_factory.mgr = mgr;
    ffmpeg_factory.pf = pf;

    pool = pj_pool_create(pf, "ffmpeg codec factory", 256, 256, NULL);
    if (!pool)
	return PJ_ENOMEM;

    /* Create mutex. */
    status = pj_mutex_create_simple(pool, "ffmpeg codec factory", 
				    &ffmpeg_factory.mutex);
    if (status != PJ_SUCCESS)
	goto on_error;

    avcodec_init();
    avcodec_register_all();
    av_log_set_level(AV_LOG_ERROR);

    /* Enum FFMPEG codecs */
    for (c=av_codec_next(NULL); c; c=av_codec_next(c)) {
        ffmpeg_codec_desc *desc;
	pjmedia_format_id fmt_id;
	int codec_info_idx;
        
#if LIBAVCODEC_VERSION_MAJOR <= 52
#   define AVMEDIA_TYPE_VIDEO	CODEC_TYPE_VIDEO
#endif
        if (c->type != AVMEDIA_TYPE_VIDEO)
            continue;

        /* Video encoder and decoder are usually implemented in separate
         * AVCodec instances. While the codec attributes (e.g: raw formats,
	 * supported fps) are in the encoder.
         */

	//PJ_LOG(3, (THIS_FILE, "%s", c->name));
	status = CodecID_to_pjmedia_format_id(c->id, &fmt_id);
	/* Skip if format ID is unknown */
	if (status != PJ_SUCCESS)
	    continue;

	codec_info_idx = find_codec_idx_by_fmt_id(fmt_id);
	/* Skip if codec is unwanted by this wrapper (not listed in 
	 * the codec info array)
	 */
	if (codec_info_idx < 0)
	    continue;

	desc = &codec_desc[codec_info_idx];

	/* Skip duplicated codec implementation */
	if ((c->encode && (desc->info.dir & PJMEDIA_DIR_ENCODING)) ||
	    (c->decode && (desc->info.dir & PJMEDIA_DIR_DECODING)))
	{
	    continue;
	}

	/* Get raw/decoded format ids in the encoder */
	if (c->pix_fmts && c->encode) {
	    pjmedia_format_id raw_fmt[PJMEDIA_VID_CODEC_MAX_DEC_FMT_CNT];
	    unsigned raw_fmt_cnt = 0;
	    unsigned raw_fmt_cnt_should_be = 0;
	    const enum PixelFormat *p = c->pix_fmts;

	    for(;(p && *p != -1) &&
		 (raw_fmt_cnt < PJMEDIA_VID_CODEC_MAX_DEC_FMT_CNT);
		 ++p)
	    {
		pjmedia_format_id fmt_id;

		raw_fmt_cnt_should_be++;
		status = PixelFormat_to_pjmedia_format_id(*p, &fmt_id);
		if (status != PJ_SUCCESS) {
		    PJ_LOG(6, (THIS_FILE, "Unrecognized ffmpeg pixel "
			       "format %d", *p));
		    continue;
		}
		
		//raw_fmt[raw_fmt_cnt++] = fmt_id;
		/* Disable some formats due to H.264 error:
		 * x264 [error]: baseline profile doesn't support 4:4:4
		 */
		if (desc->info.pt != PJMEDIA_RTP_PT_H264 ||
		    fmt_id != PJMEDIA_FORMAT_RGB24)
		{
		    raw_fmt[raw_fmt_cnt++] = fmt_id;
		}
	    }

	    if (raw_fmt_cnt == 0) {
		PJ_LOG(5, (THIS_FILE, "No recognized raw format "
				      "for codec [%s/%s], codec ignored",
				      c->name, c->long_name));
		/* Skip this encoder */
		continue;
	    }

	    if (raw_fmt_cnt < raw_fmt_cnt_should_be) {
		PJ_LOG(6, (THIS_FILE, "Codec [%s/%s] have %d raw formats, "
				      "recognized only %d raw formats",
				      c->name, c->long_name,
				      raw_fmt_cnt_should_be, raw_fmt_cnt));
	    }

	    desc->info.dec_fmt_id_cnt = raw_fmt_cnt;
	    pj_memcpy(desc->info.dec_fmt_id, raw_fmt, 
		      sizeof(raw_fmt[0])*raw_fmt_cnt);
	}

	/* Get supported framerates */
	if (c->supported_framerates) {
	    const AVRational *fr = c->supported_framerates;
	    while ((fr->num != 0 || fr->den != 0) && 
		   desc->info.fps_cnt < PJMEDIA_VID_CODEC_MAX_FPS_CNT)
	    {
		desc->info.fps[desc->info.fps_cnt].num = fr->num;
		desc->info.fps[desc->info.fps_cnt].denum = fr->den;
		++desc->info.fps_cnt;
		++fr;
	    }
	}

	/* Get ffmpeg encoder instance */
        if (c->encode && !desc->enc) {
            desc->info.dir |= PJMEDIA_DIR_ENCODING;
            desc->enc = c;
        }
	
	/* Get ffmpeg decoder instance */
        if (c->decode && !desc->dec) {
            desc->info.dir |= PJMEDIA_DIR_DECODING;
            desc->dec = c;
        }

	/* Enable this codec when any ffmpeg codec instance are recognized
	 * and the supported raw formats info has been collected.
	 */
	if ((desc->dec || desc->enc) && desc->info.dec_fmt_id_cnt)
	{
	    desc->enabled = PJ_TRUE;
	}

	/* Normalize default value of clock rate */
	if (desc->info.clock_rate == 0)
	    desc->info.clock_rate = 90000;

	/* Set supported packings */
	desc->info.packings |= PJMEDIA_VID_PACKING_WHOLE;
	if (desc->packetize && desc->unpacketize)
	    desc->info.packings |= PJMEDIA_VID_PACKING_PACKETS;

    }

    /* Review all codecs for applying base format, registering format match for
     * SDP negotiation, etc.
     */
    for (i = 0; i < PJ_ARRAY_SIZE(codec_desc); ++i) {
	ffmpeg_codec_desc *desc = &codec_desc[i];

	/* Init encoder/decoder description from base format */
	if (desc->base_fmt_id && (!desc->dec || !desc->enc)) {
	    ffmpeg_codec_desc *base_desc = NULL;
	    int base_desc_idx;
	    pjmedia_dir copied_dir = PJMEDIA_DIR_NONE;

	    base_desc_idx = find_codec_idx_by_fmt_id(desc->base_fmt_id);
	    if (base_desc_idx != -1)
		base_desc = &codec_desc[base_desc_idx];
	    if (!base_desc || !base_desc->enabled)
		continue;

	    /* Copy description from base codec */
	    if (!desc->info.dec_fmt_id_cnt) {
		desc->info.dec_fmt_id_cnt = base_desc->info.dec_fmt_id_cnt;
		pj_memcpy(desc->info.dec_fmt_id, base_desc->info.dec_fmt_id, 
			  sizeof(pjmedia_format_id)*desc->info.dec_fmt_id_cnt);
	    }
	    if (!desc->info.fps_cnt) {
		desc->info.fps_cnt = base_desc->info.fps_cnt;
		pj_memcpy(desc->info.fps, base_desc->info.fps, 
			  sizeof(desc->info.fps[0])*desc->info.fps_cnt);
	    }
	    if (!desc->info.clock_rate) {
		desc->info.clock_rate = base_desc->info.clock_rate;
	    }
	    if (!desc->dec && base_desc->dec) {
		copied_dir |= PJMEDIA_DIR_DECODING;
		desc->dec = base_desc->dec;
	    }
	    if (!desc->enc && base_desc->enc) {
		copied_dir |= PJMEDIA_DIR_ENCODING;
		desc->enc = base_desc->enc;
	    }

	    desc->info.dir |= copied_dir;
	    desc->enabled = (desc->info.dir != PJMEDIA_DIR_NONE);

	    /* Set supported packings */
	    desc->info.packings |= PJMEDIA_VID_PACKING_WHOLE;
	    if (desc->packetize && desc->unpacketize)
		desc->info.packings |= PJMEDIA_VID_PACKING_PACKETS;

	    if (copied_dir != PJMEDIA_DIR_NONE) {
		const char *dir_name[] = {NULL, "encoder", "decoder", "codec"};
		PJ_LOG(5, (THIS_FILE, "The %.*s %s is using base codec (%.*s)",
			   desc->info.encoding_name.slen,
			   desc->info.encoding_name.ptr,
			   dir_name[copied_dir],
			   base_desc->info.encoding_name.slen,
			   base_desc->info.encoding_name.ptr));
	    }
        }

	/* Registering format match for SDP negotiation */
	if (desc->sdp_fmt_match) {
	    status = pjmedia_sdp_neg_register_fmt_match_cb(
						&desc->info.encoding_name,
						desc->sdp_fmt_match);
	    pj_assert(status == PJ_SUCCESS);
	}

	/* Print warning about missing encoder/decoder */
	if (!desc->enc) {
	    PJ_LOG(4, (THIS_FILE, "Cannot find %.*s encoder in ffmpeg library",
		       desc->info.encoding_name.slen,
		       desc->info.encoding_name.ptr));
	}
	if (!desc->dec) {
	    PJ_LOG(4, (THIS_FILE, "Cannot find %.*s decoder in ffmpeg library",
		       desc->info.encoding_name.slen,
		       desc->info.encoding_name.ptr));
	}
    }

    /* Register codec factory to codec manager. */
    status = pjmedia_vid_codec_mgr_register_factory(mgr, 
						    &ffmpeg_factory.base);
    if (status != PJ_SUCCESS)
	goto on_error;

    ffmpeg_factory.pool = pool;

    /* Done. */
    return PJ_SUCCESS;

on_error:
    pj_pool_release(pool);
    return status;
}