diff --git a/src/mod/applications/mod_av/avcodec.c b/src/mod/applications/mod_av/avcodec.c index 627c8a2402..ff7c50ad66 100644 --- a/src/mod/applications/mod_av/avcodec.c +++ b/src/mod/applications/mod_av/avcodec.c @@ -413,6 +413,7 @@ typedef struct avcodec_profile_s { int decoder_thread_count; AVCodecContext ctx; switch_event_t *options; + switch_event_t *codecs; } avcodec_profile_t; struct avcodec_globals { @@ -440,6 +441,36 @@ const char *get_profile_name(int codec_id) return "NONE"; } +static void parse_profile(avcodec_profile_t *aprofile, switch_xml_t profile); + +static void parse_codec_specific_profile(avcodec_profile_t *aprofile, const char *codec_name) +{ + switch_xml_t cfg = NULL; + switch_xml_t xml = switch_xml_open_cfg("avcodec.conf", &cfg, NULL); + switch_xml_t profiles = cfg ? switch_xml_child(cfg, "profiles") : NULL; + + // open config and find the profile to parse + if (profiles) { + switch_event_header_t *hp; + + for (hp = aprofile->codecs->headers; hp; hp = hp->next) { + // switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s: %s\n", hp->name, hp->value); + if (!strcmp(hp->name, codec_name)) { + switch_xml_t profile; + for (profile = switch_xml_child(profiles, "profile"); profile; profile = profile->next) { + const char *name = switch_xml_attr(profile, "name"); + + if (!strcmp(hp->value, name)) { + parse_profile(aprofile, profile); + } + } + } + } + } + + if (xml) switch_xml_free(xml); +} + static void init_profile(avcodec_profile_t *aprofile, const char *name); static avcodec_profile_t *find_profile(const char *name, switch_bool_t reconfig) @@ -1183,7 +1214,7 @@ static void set_h264_private_data(h264_codec_context_t *context, avcodec_profile static switch_status_t open_encoder(h264_codec_context_t *context, uint32_t width, uint32_t height) { int fps = 15; - avcodec_profile_t *profile = NULL; + avcodec_profile_t *aprofile = NULL; char codec_string[1024]; if (!context->encoder) { @@ -1212,16 +1243,20 @@ static switch_status_t open_encoder(h264_codec_context_t *context, uint32_t widt } if (!zstr(context->codec_settings.video.config_profile_name)) { - profile = find_profile(context->codec_settings.video.config_profile_name, SWITCH_FALSE); + aprofile = find_profile(context->codec_settings.video.config_profile_name, SWITCH_FALSE); } - if (!profile) { - profile = find_profile(get_profile_name(context->av_codec_id), SWITCH_FALSE); + if (!aprofile) { + aprofile = find_profile(get_profile_name(context->av_codec_id), SWITCH_FALSE); } - if (!profile) return SWITCH_STATUS_FALSE; + if (!aprofile) return SWITCH_STATUS_FALSE; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Using config profile: [%s]\n", profile->name); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Using config profile: [%s]\n", aprofile->name); + + if (aprofile->codecs) { + parse_codec_specific_profile(aprofile, get_profile_name(context->av_codec_id)); + } if (context->encoder_ctx) { if (avcodec_is_open(context->encoder_ctx)) { @@ -1281,9 +1316,9 @@ static switch_status_t open_encoder(h264_codec_context_t *context, uint32_t widt context->encoder_ctx->width = context->codec_settings.video.width; context->encoder_ctx->height = context->codec_settings.video.height; context->encoder_ctx->time_base = (AVRational){1, 90}; - context->encoder_ctx->max_b_frames = profile->ctx.max_b_frames; + context->encoder_ctx->max_b_frames = aprofile->ctx.max_b_frames; context->encoder_ctx->pix_fmt = AV_PIX_FMT_YUV420P; - context->encoder_ctx->thread_count = profile->ctx.thread_count; + context->encoder_ctx->thread_count = aprofile->ctx.thread_count; if (context->av_codec_id == AV_CODEC_ID_H263 || context->av_codec_id == AV_CODEC_ID_H263P) { #ifndef H263_MODE_B @@ -1304,10 +1339,10 @@ FF_ENABLE_DEPRECATION_WARNINGS context->encoder_ctx->opaque = context; av_opt_set_int(context->encoder_ctx->priv_data, "mb_info", SLICE_SIZE - 8, 0); } else if (context->av_codec_id == AV_CODEC_ID_H264) { - context->encoder_ctx->profile = profile->ctx.profile; - context->encoder_ctx->level = profile->ctx.level; + context->encoder_ctx->profile = aprofile->ctx.profile; + context->encoder_ctx->level = aprofile->ctx.level; - set_h264_private_data(context, profile); + set_h264_private_data(context, aprofile); } GCC_DIAG_OFF(deprecated-declarations) @@ -1919,23 +1954,15 @@ void show_codecs(switch_stream_handle_t *stream) av_free(codecs); } -static void parse_profile(switch_xml_t profile) +static void parse_profile(avcodec_profile_t *aprofile, switch_xml_t profile) { switch_xml_t options = switch_xml_child(profile, "options"); switch_xml_t param = NULL; const char *profile_name = switch_xml_attr(profile, "name"); - avcodec_profile_t *aprofile = NULL; AVCodecContext *ctx = NULL; if (zstr(profile_name)) return; - aprofile = find_profile(profile_name, SWITCH_TRUE); - - if (!aprofile) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "cannot find profile %s\n", profile_name); - return; - } - ctx = &aprofile->ctx; if (!ctx) return; @@ -2142,6 +2169,36 @@ static void parse_profile(switch_xml_t profile) } // for options } +static void parse_codecs(avcodec_profile_t *aprofile, switch_xml_t codecs) +{ + switch_xml_t codec = NULL; + + if (!codecs) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "no codecs in %s\n", aprofile->name); + return; + } + + codec = switch_xml_child(codecs, "codec"); + + if (aprofile->codecs) { + switch_event_destroy(&aprofile->codecs); + } + + switch_event_create(&aprofile->codecs, SWITCH_EVENT_CLONE); + + for (; codec; codec = codec->next) { + const char *codec_name = switch_xml_attr(codec, "name"); + const char *profile_name = switch_xml_attr(codec, "profile"); + + if (zstr(codec_name) || zstr(profile_name)) continue; + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "codec: %s, profile: %s\n", codec_name, profile_name); + + switch_event_add_header_string(aprofile->codecs, SWITCH_STACK_BOTTOM, codec_name, profile_name); + } +} + + static void load_config() { switch_xml_t cfg = NULL, xml = NULL; @@ -2186,7 +2243,21 @@ static void load_config() switch_xml_t profile = switch_xml_child(profiles, "profile"); for (; profile; profile = profile->next) { - parse_profile(profile); + switch_xml_t codecs = switch_xml_child(profile, "codecs"); + const char *profile_name = switch_xml_attr(profile, "name"); + avcodec_profile_t *aprofile = NULL; + + if (zstr(profile_name)) continue; + + aprofile = find_profile(profile_name, SWITCH_TRUE); + + if (!aprofile) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "cannot find profile %s\n", profile_name); + continue; + } + + parse_profile(aprofile, profile); + parse_codecs(aprofile, codecs); } // for profile } // profiles @@ -2250,6 +2321,10 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_avcodec_shutdown) switch_event_destroy(&profile->options); } + if (profile->codecs) { + switch_event_destroy(&profile->codecs); + } + free(profile); }