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