static int ffserver_save_avoption(const char *opt, const char *arg, AVDictionary **dict, int type, FFServerConfig *config, int line_num) { int ret = 0; AVDictionaryEntry *e; const AVOption *o = av_opt_find(config->dummy_ctx, opt, NULL, type | AV_OPT_FLAG_ENCODING_PARAM, AV_OPT_SEARCH_CHILDREN); if (!o) { report_config_error(config->filename, line_num, AV_LOG_ERROR, &config->errors, "Option not found: %s\n", opt); } else if ((ret = av_opt_set(config->dummy_ctx, opt, arg, AV_OPT_SEARCH_CHILDREN)) < 0) { report_config_error(config->filename, line_num, AV_LOG_ERROR, &config->errors, "Invalid value for option %s (%s): %s\n", opt, arg, av_err2str(ret)); } else if ((e = av_dict_get(*dict, opt, NULL, 0))) { if ((o->type == AV_OPT_TYPE_FLAGS) && arg && (arg[0] == '+' || arg[0] == '-')) return av_dict_set(dict, opt, arg, AV_DICT_APPEND); report_config_error(config->filename, line_num, AV_LOG_ERROR, &config->errors, "Redeclaring value of the option %s, previous value: %s\n", opt, e->value); } else if (av_dict_set(dict, opt, arg, 0) < 0) { return AVERROR(ENOMEM); } return 0; }
static void bfd_nbrip_handler(vector_t *strvec) { bfd_t *bfd; struct sockaddr_storage nbr_addr; assert(strvec); assert(bfd_data); bfd = LIST_TAIL_DATA(bfd_data->bfd); assert(bfd); if (!strcmp(vector_slot(strvec, 1), "neighbour_ip")) neighbor_str = "neighbour"; if (inet_stosockaddr(strvec_slot(strvec, 1), BFD_CONTROL_PORT, &nbr_addr)) { report_config_error(CONFIG_GENERAL_ERROR, "Configuration error: BFD instance %s has" " malformed %s address %s, ignoring instance", bfd->iname, neighbor_str, FMT_STR_VSLOT(strvec, 1)); list_del(bfd_data->bfd, bfd); skip_block(false); return; } else if (find_bfd_by_addr(&nbr_addr)) { report_config_error(CONFIG_GENERAL_ERROR, "Configuration error: BFD instance %s has" " duplicate %s address %s, ignoring instance", bfd->iname, neighbor_str, FMT_STR_VSLOT(strvec, 1)); list_del(bfd_data->bfd, bfd); skip_block(false); return; } else bfd->nbr_addr = nbr_addr; }
static void bfd_idletx_handler(vector_t *strvec) { bfd_t *bfd; unsigned value; assert(strvec); assert(bfd_data); bfd = LIST_TAIL_DATA(bfd_data->bfd); assert(bfd); if (!read_unsigned_strvec(strvec, 1, &value,BFD_IDLETX_MIN, BFD_IDLETX_MAX, false)) report_config_error(CONFIG_GENERAL_ERROR, "Configuration error: BFD instance %s" " idle_tx value %s is not valid (must be in range" " [%u-%u]), ignoring", bfd->iname, FMT_STR_VSLOT(strvec, 1), BFD_IDLETX_MIN, BFD_IDLETX_MAX); else bfd->local_idle_tx_intv = value * 1000U; if (value > BFD_IDLETX_MAX_SENSIBLE) log_message(LOG_INFO, "Configuration warning: BFD instance %s" " idle_tx value %u is larger than max sensible (%u)", bfd->iname, value, BFD_IDLETX_MAX_SENSIBLE); }
static bool check_new_bfd(const char *name) { if (strlen(name) >= BFD_INAME_MAX) { report_config_error(CONFIG_GENERAL_ERROR, "Configuration error: BFD instance %s" " name too long (maximum length is %i" " characters) - ignoring", name, BFD_INAME_MAX - 1); return false; } if (find_bfd_by_name(name)) { report_config_error(CONFIG_GENERAL_ERROR, "Configuration error: BFD instance %s" " already configured - ignoring", name); return false; } return true; }
static void smtpto_handler(vector_t *strvec) { unsigned timeout; /* The min value should be 1, but allow 0 to maintain backward compatibility * with pre v2.0.7 */ if (!read_unsigned_strvec(strvec, 1, &timeout, 0, UINT_MAX / TIMER_HZ, true)) { report_config_error(CONFIG_GENERAL_ERROR, "smtp_connect_timeout '%s' must be in [0, %d] - ignoring", FMT_STR_VSLOT(strvec, 1), UINT_MAX / TIMER_HZ); return; } if (timeout == 0) { report_config_error(CONFIG_GENERAL_ERROR, "smtp_conect_timeout must be greater than 0, setting to 1"); timeout = 1; } global_data->smtp_connection_to = timeout * TIMER_HZ; }
static int ffserver_set_codec(AVCodecContext *ctx, const char *codec_name, FFServerConfig *config) { int ret; AVCodec *codec = avcodec_find_encoder_by_name(codec_name); if (!codec || codec->type != ctx->codec_type) { report_config_error(config->filename, config->line_num, AV_LOG_ERROR, &config->errors, "Invalid codec name: '%s'\n", codec_name); return 0; } if (ctx->codec_id == AV_CODEC_ID_NONE && !ctx->priv_data) { if ((ret = avcodec_get_context_defaults3(ctx, codec)) < 0) return ret; ctx->codec = codec; } if (ctx->codec_id != codec->id) report_config_error(config->filename, config->line_num, AV_LOG_ERROR, &config->errors, "Inconsistent configuration: trying to set '%s' " "codec option, but '%s' codec is used previously\n", codec_name, avcodec_get_name(ctx->codec_id)); return 0; }
static void dynamic_interfaces_handler(vector_t *strvec) { char *str; global_data->dynamic_interfaces = true; if (vector_size(strvec) >= 2) { str = strvec_slot(strvec, 1); if (!strcmp(str, "allow_if_changes")) global_data->allow_if_changes = true; else report_config_error(CONFIG_GENERAL_ERROR, "Unknown dynamic_interfaces option '%s'",str); } }
static void bfd_multiplier_handler(vector_t *strvec) { bfd_t *bfd; unsigned value; assert(strvec); assert(bfd_data); bfd = LIST_TAIL_DATA(bfd_data->bfd); assert(bfd); if (!read_unsigned_strvec(strvec, 1, &value, BFD_MULTIPLIER_MIN, BFD_MULTIPLIER_MAX, false)) report_config_error(CONFIG_GENERAL_ERROR, "Configuration error: BFD instance %s" " multiplier value %s not valid (must be in range" " [%u-%u]), ignoring", bfd->iname, FMT_STR_VSLOT(strvec, 1), BFD_MULTIPLIER_MIN, BFD_MULTIPLIER_MAX); else bfd->local_detect_mult = value; }
static void bfd_srcip_handler(vector_t *strvec) { bfd_t *bfd; struct sockaddr_storage src_addr; assert(strvec); assert(bfd_data); bfd = LIST_TAIL_DATA(bfd_data->bfd); assert(bfd); if (inet_stosockaddr(strvec_slot(strvec, 1), NULL, &src_addr)) { report_config_error(CONFIG_GENERAL_ERROR, "Configuration error: BFD instance %s has" " malformed source address %s, ignoring", bfd->iname, FMT_STR_VSLOT(strvec, 1)); } else bfd->src_addr = src_addr; }
static int ffserver_save_avoption(const char *opt, const char *arg, int type, FFServerConfig *config) { static int hinted = 0; int ret = 0; AVDictionaryEntry *e; const AVOption *o = NULL; const char *option = NULL; const char *codec_name = NULL; char buff[1024]; AVCodecContext *ctx; AVDictionary **dict; enum AVCodecID guessed_codec_id; switch (type) { case AV_OPT_FLAG_VIDEO_PARAM: ctx = config->dummy_vctx; dict = &config->video_opts; guessed_codec_id = config->guessed_video_codec_id != AV_CODEC_ID_NONE ? config->guessed_video_codec_id : AV_CODEC_ID_H264; break; case AV_OPT_FLAG_AUDIO_PARAM: ctx = config->dummy_actx; dict = &config->audio_opts; guessed_codec_id = config->guessed_audio_codec_id != AV_CODEC_ID_NONE ? config->guessed_audio_codec_id : AV_CODEC_ID_AAC; break; default: av_assert0(0); } if (strchr(opt, ':')) { //explicit private option snprintf(buff, sizeof(buff), "%s", opt); codec_name = buff; if(!(option = strchr(buff, ':'))) { report_config_error(config->filename, config->line_num, AV_LOG_ERROR, &config->errors, "Syntax error. Unmatched ':'\n"); return -1; } buff[option - buff] = '\0'; option++; if ((ret = ffserver_set_codec(ctx, codec_name, config)) < 0) return ret; if (!ctx->codec || !ctx->priv_data) return -1; } else { option = opt; } o = av_opt_find(ctx, option, NULL, type | AV_OPT_FLAG_ENCODING_PARAM, AV_OPT_SEARCH_CHILDREN); if (!o && (!strcmp(option, "time_base") || !strcmp(option, "pixel_format") || !strcmp(option, "video_size") || !strcmp(option, "codec_tag"))) o = av_opt_find(ctx, option, NULL, 0, 0); if (!o) { report_config_error(config->filename, config->line_num, AV_LOG_ERROR, &config->errors, "Option not found: '%s'\n", opt); if (!hinted && ctx->codec_id == AV_CODEC_ID_NONE) { hinted = 1; report_config_error(config->filename, config->line_num, AV_LOG_ERROR, NULL, "If '%s' is a codec private" "option, then prefix it with codec name, for " "example '%s:%s %s' or define codec earlier.\n", opt, avcodec_get_name(guessed_codec_id) ,opt, arg); } } else if ((ret = av_opt_set(ctx, option, arg, AV_OPT_SEARCH_CHILDREN)) < 0) { report_config_error(config->filename, config->line_num, AV_LOG_ERROR, &config->errors, "Invalid value for option %s (%s): %s\n", opt, arg, av_err2str(ret)); } else if ((e = av_dict_get(*dict, option, NULL, 0))) { if ((o->type == AV_OPT_TYPE_FLAGS) && arg && (arg[0] == '+' || arg[0] == '-')) return av_dict_set(dict, option, arg, AV_DICT_APPEND); report_config_error(config->filename, config->line_num, AV_LOG_ERROR, &config->errors, "Redeclaring value of option '%s'." "Previous value was: '%s'.\n", opt, e->value); } else if (av_dict_set(dict, option, arg, 0) < 0) { return AVERROR(ENOMEM); } return 0; }
/* add a codec and set the default parameters */ static void add_codec(FFServerStream *stream, AVCodecContext *av, FFServerConfig *config) { AVStream *st; AVDictionary **opts, *recommended = NULL; char *enc_config; if(stream->nb_streams >= FF_ARRAY_ELEMS(stream->streams)) return; opts = av->codec_type == AVMEDIA_TYPE_AUDIO ? &config->audio_opts : &config->video_opts; av_dict_copy(&recommended, *opts, 0); av_opt_set_dict2(av->priv_data, opts, AV_OPT_SEARCH_CHILDREN); av_opt_set_dict2(av, opts, AV_OPT_SEARCH_CHILDREN); if (av_dict_count(*opts)) av_log(NULL, AV_LOG_WARNING, "Something is wrong, %d options are not set!\n", av_dict_count(*opts)); if (!config->stream_use_defaults) { switch(av->codec_type) { case AVMEDIA_TYPE_AUDIO: if (av->bit_rate == 0) report_config_error(config->filename, config->line_num, AV_LOG_ERROR, &config->errors, "audio bit rate is not set\n"); if (av->sample_rate == 0) report_config_error(config->filename, config->line_num, AV_LOG_ERROR, &config->errors, "audio sample rate is not set\n"); break; case AVMEDIA_TYPE_VIDEO: if (av->width == 0 || av->height == 0) report_config_error(config->filename, config->line_num, AV_LOG_ERROR, &config->errors, "video size is not set\n"); break; default: av_assert0(0); } goto done; } /* stream_use_defaults = true */ /* compute default parameters */ switch(av->codec_type) { case AVMEDIA_TYPE_AUDIO: if (!av_dict_get(recommended, "b", NULL, 0)) { av->bit_rate = 64000; av_dict_set_int(&recommended, "b", av->bit_rate, 0); WARNING("Setting default value for audio bit rate = %d. " "Use NoDefaults to disable it.\n", av->bit_rate); } if (!av_dict_get(recommended, "ar", NULL, 0)) { av->sample_rate = 22050; av_dict_set_int(&recommended, "ar", av->sample_rate, 0); WARNING("Setting default value for audio sample rate = %d. " "Use NoDefaults to disable it.\n", av->sample_rate); } if (!av_dict_get(recommended, "ac", NULL, 0)) { av->channels = 1; av_dict_set_int(&recommended, "ac", av->channels, 0); WARNING("Setting default value for audio channel count = %d. " "Use NoDefaults to disable it.\n", av->channels); } break; case AVMEDIA_TYPE_VIDEO: if (!av_dict_get(recommended, "b", NULL, 0)) { av->bit_rate = 64000; av_dict_set_int(&recommended, "b", av->bit_rate, 0); WARNING("Setting default value for video bit rate = %d. " "Use NoDefaults to disable it.\n", av->bit_rate); } if (!av_dict_get(recommended, "time_base", NULL, 0)) { av->time_base.den = 5; av->time_base.num = 1; av_dict_set(&recommended, "time_base", "1/5", 0); WARNING("Setting default value for video frame rate = %d. " "Use NoDefaults to disable it.\n", av->time_base.den); } if (!av_dict_get(recommended, "video_size", NULL, 0)) { av->width = 160; av->height = 128; av_dict_set(&recommended, "video_size", "160x128", 0); WARNING("Setting default value for video size = %dx%d. " "Use NoDefaults to disable it.\n", av->width, av->height); } /* Bitrate tolerance is less for streaming */ if (!av_dict_get(recommended, "bt", NULL, 0)) { av->bit_rate_tolerance = FFMAX(av->bit_rate / 4, (int64_t)av->bit_rate*av->time_base.num/av->time_base.den); av_dict_set_int(&recommended, "bt", av->bit_rate_tolerance, 0); WARNING("Setting default value for video bit rate tolerance = %d. " "Use NoDefaults to disable it.\n", av->bit_rate_tolerance); } if (!av_dict_get(recommended, "rc_eq", NULL, 0)) { av->rc_eq = av_strdup("tex^qComp"); av_dict_set(&recommended, "rc_eq", "tex^qComp", 0); WARNING("Setting default value for video rate control equation = " "%s. Use NoDefaults to disable it.\n", av->rc_eq); } if (!av_dict_get(recommended, "maxrate", NULL, 0)) { av->rc_max_rate = av->bit_rate * 2; av_dict_set_int(&recommended, "maxrate", av->rc_max_rate, 0); WARNING("Setting default value for video max rate = %d. " "Use NoDefaults to disable it.\n", av->rc_max_rate); } if (av->rc_max_rate && !av_dict_get(recommended, "bufsize", NULL, 0)) { av->rc_buffer_size = av->rc_max_rate; av_dict_set_int(&recommended, "bufsize", av->rc_buffer_size, 0); WARNING("Setting default value for video buffer size = %d. " "Use NoDefaults to disable it.\n", av->rc_buffer_size); } break; default: abort(); } done: st = av_mallocz(sizeof(AVStream)); if (!st) return; av_dict_get_string(recommended, &enc_config, '=', ','); av_dict_free(&recommended); av_stream_set_recommended_encoder_configuration(st, enc_config); st->codec = av; stream->streams[stream->nb_streams++] = st; }