/* * Copyright (c) 2000, 2001, 2002 Fabrice Bellard * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include <float.h>#include "libavutil/opt.h"#include "libavutil/parseutils.h"#include "libavutil/avstring.h"#include "libavutil/pixdesc.h"#include "libavutil/avassert.h" #include "cmdutils.h"#include "ffserver_config.h" #define MAX_CHILD_ARGS 64 static int ffserver_save_avoption(const char *opt, const char *arg, int type, FFServerConfig *config);static void vreport_config_error(const char *filename, int line_num, int log_level, int *errors, const char *fmt, va_list vl);static void report_config_error(const char *filename, int line_num, int log_level, int *errors, const char *fmt, ...); #define ERROR(...) report_config_error(config->filename, config->line_num,\ AV_LOG_ERROR, &config->errors, __VA_ARGS__)#define WARNING(...) report_config_error(config->filename, config->line_num,\ AV_LOG_WARNING, &config->warnings, __VA_ARGS__) /* FIXME: make ffserver work with IPv6 *//* resolve host with also IP address parsing */static int resolve_host(struct in_addr *sin_addr, const char *hostname){ if (!ff_inet_aton(hostname, sin_addr)) {#if HAVE_GETADDRINFO struct addrinfo *ai, *cur; struct addrinfo hints = { 0 }; hints.ai_family = AF_INET; if (getaddrinfo(hostname, NULL, &hints, &ai)) return -1; /* getaddrinfo returns a linked list of addrinfo structs. * Even if we set ai_family = AF_INET above, make sure * that the returned one actually is of the correct type. */ for (cur = ai; cur; cur = cur->ai_next) { if (cur->ai_family == AF_INET) { *sin_addr = ((struct sockaddr_in *)cur->ai_addr)->sin_addr; freeaddrinfo(ai); return 0; } } freeaddrinfo(ai); return -1;#else struct hostent *hp; hp = gethostbyname(hostname); if (!hp) return -1; memcpy(sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));#endif } return 0;} void ffserver_get_arg(char *buf, int buf_size, const char **pp){ const char *p; char *q; int quote = 0; p = *pp; q = buf; while (av_isspace(*p)) p++; if (*p == '\"' || *p == '\'') quote = *p++; while (*p != '\0') { if (quote && *p == quote || !quote && av_isspace(*p)) break; if ((q - buf) < buf_size - 1) *q++ = *p; p++; } *q = '\0'; if (quote && *p == quote) p++; *pp = p;} void ffserver_parse_acl_row(FFServerStream *stream, FFServerStream* feed, FFServerIPAddressACL *ext_acl, const char *p, const char *filename, int line_num){ char arg[1024]; FFServerIPAddressACL acl; FFServerIPAddressACL *nacl; FFServerIPAddressACL **naclp; ffserver_get_arg(arg, sizeof(arg), &p); if (av_strcasecmp(arg, "allow") == 0) acl.action = IP_ALLOW; else if (av_strcasecmp(arg, "deny") == 0) acl.action = IP_DENY; else { fprintf(stderr, "%s:%d: ACL action '%s' should be ALLOW or DENY.\n", filename, line_num, arg); goto bail; } ffserver_get_arg(arg, sizeof(arg), &p); if (resolve_host(&acl.first, arg)) { fprintf(stderr, "%s:%d: ACL refers to invalid host or IP address '%s'\n", filename, line_num, arg); goto bail; } acl.last = acl.first; ffserver_get_arg(arg, sizeof(arg), &p); if (arg[0]) { if (resolve_host(&acl.last, arg)) { fprintf(stderr, "%s:%d: ACL refers to invalid host or IP address '%s'\n", filename, line_num, arg); goto bail; } } nacl = av_mallocz(sizeof(*nacl)); if (!nacl) { fprintf(stderr, "Failed to allocate FFServerIPAddressACL\n"); goto bail; } naclp = 0; acl.next = 0; *nacl = acl; if (stream) naclp = &stream->acl; else if (feed) naclp = &feed->acl; else if (ext_acl) naclp = &ext_acl; else fprintf(stderr, "%s:%d: ACL found not in <Stream> or <Feed>\n", filename, line_num); if (naclp) { while (*naclp) naclp = &(*naclp)->next; *naclp = nacl; } else av_free(nacl); bail: return; } /* add a codec and set the default parameters */static void add_codec(FFServerStream *stream, AVCodecContext *av, FFServerConfig *config){ LayeredAVStream *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(*st)); if (!st) return; av_dict_get_string(recommended, &enc_config, '=', ','); av_dict_free(&recommended); st->recommended_encoder_configuration = enc_config; st->codec = av; st->codecpar = avcodec_parameters_alloc(); avcodec_parameters_from_context(st->codecpar, av); stream->streams[stream->nb_streams++] = st;} 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 int ffserver_opt_preset(const char *arg, int type, FFServerConfig *config){ FILE *f=NULL; char filename[1000], tmp[1000], tmp2[1000], line[1000]; int ret = 0; AVCodecContext *avctx; const AVCodec *codec; switch(type) { case AV_OPT_FLAG_AUDIO_PARAM: avctx = config->dummy_actx; break; case AV_OPT_FLAG_VIDEO_PARAM: avctx = config->dummy_vctx; break; default: av_assert0(0); } codec = avcodec_find_encoder(avctx->codec_id); if (!(f = get_preset_file(filename, sizeof(filename), arg, 0, codec ? codec->name : NULL))) { av_log(NULL, AV_LOG_ERROR, "File for preset '%s' not found\n", arg); return AVERROR(EINVAL); } while(!feof(f)){ int e= fscanf(f, "%999[^\n]\n", line) - 1; if(line[0] == '#' && !e) continue; e|= sscanf(line, "%999[^=]=%999[^\n]\n", tmp, tmp2) - 2; if(e){ av_log(NULL, AV_LOG_ERROR, "%s: Invalid syntax: '%s'\n", filename, line); ret = AVERROR(EINVAL); break; } if (!strcmp(tmp, "acodec") && avctx->codec_type == AVMEDIA_TYPE_AUDIO || !strcmp(tmp, "vcodec") && avctx->codec_type == AVMEDIA_TYPE_VIDEO) { if (ffserver_set_codec(avctx, tmp2, config) < 0) break; } else if (!strcmp(tmp, "scodec")) { av_log(NULL, AV_LOG_ERROR, "Subtitles preset found.\n"); ret = AVERROR(EINVAL); break; } else if (ffserver_save_avoption(tmp, tmp2, type, config) < 0) break; } fclose(f); return ret;} static AVOutputFormat *ffserver_guess_format(const char *short_name, const char *filename, const char *mime_type){ AVOutputFormat *fmt = av_guess_format(short_name, filename, mime_type); if (fmt) { AVOutputFormat *stream_fmt; char stream_format_name[64]; snprintf(stream_format_name, sizeof(stream_format_name), "%s_stream", fmt->name); stream_fmt = av_guess_format(stream_format_name, NULL, NULL); if (stream_fmt) fmt = stream_fmt; } return fmt;} static void vreport_config_error(const char *filename, int line_num, int log_level, int *errors, const char *fmt, va_list vl){ av_log(NULL, log_level, "%s:%d: ", filename, line_num); av_vlog(NULL, log_level, fmt, vl); if (errors) (*errors)++;} static void report_config_error(const char *filename, int line_num, int log_level, int *errors, const char *fmt, ...){ va_list vl; va_start(vl, fmt); vreport_config_error(filename, line_num, log_level, errors, fmt, vl); va_end(vl);} static int ffserver_set_int_param(int *dest, const char *value, int factor, int min, int max, FFServerConfig *config, const char *error_msg, ...){ int tmp; char *tailp; if (!value || !value[0]) goto error; errno = 0; tmp = strtol(value, &tailp, 0); if (tmp < min || tmp > max) goto error; if (factor) { if (tmp == INT_MIN || FFABS(tmp) > INT_MAX / FFABS(factor)) goto error; tmp *= factor; } if (tailp[0] || errno) goto error; if (dest) *dest = tmp; return 0; error: if (config) { va_list vl; va_start(vl, error_msg); vreport_config_error(config->filename, config->line_num, AV_LOG_ERROR, &config->errors, error_msg, vl); va_end(vl); } return AVERROR(EINVAL);} static int ffserver_set_float_param(float *dest, const char *value, float factor, float min, float max, FFServerConfig *config, const char *error_msg, ...){ double tmp; char *tailp; if (!value || !value[0]) goto error; errno = 0; tmp = strtod(value, &tailp); if (tmp < min || tmp > max) goto error; if (factor)Lines 1–500 of 1325. Load more
/* * Copyright (c) 2000, 2001, 2002 Fabrice Bellard * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include <float.h> #include "libavutil/opt.h" #include "libavutil/parseutils.h" #include "libavutil/avstring.h" #include "libavutil/pixdesc.h" #include "libavutil/avassert.h" #include "cmdutils.h" #include "ffserver_config.h" #define MAX_CHILD_ARGS 64 static int ffserver_save_avoption(const char *opt, const char *arg, int type, FFServerConfig *config); static void vreport_config_error(const char *filename, int line_num, int log_level, int *errors, const char *fmt, va_list vl); static void report_config_error(const char *filename, int line_num, int log_level, int *errors, const char *fmt, ...); #define ERROR(...) report_config_error(config->filename, config->line_num,\ AV_LOG_ERROR, &config->errors, __VA_ARGS__) #define WARNING(...) report_config_error(config->filename, config->line_num,\ AV_LOG_WARNING, &config->warnings, __VA_ARGS__) /* FIXME: make ffserver work with IPv6 */ /* resolve host with also IP address parsing */ static int resolve_host(struct in_addr *sin_addr, const char *hostname) { if (!ff_inet_aton(hostname, sin_addr)) { #if HAVE_GETADDRINFO struct addrinfo *ai, *cur; struct addrinfo hints = { 0 }; hints.ai_family = AF_INET; if (getaddrinfo(hostname, NULL, &hints, &ai)) return -1; /* getaddrinfo returns a linked list of addrinfo structs. * Even if we set ai_family = AF_INET above, make sure * that the returned one actually is of the correct type. */ for (cur = ai; cur; cur = cur->ai_next) { if (cur->ai_family == AF_INET) { *sin_addr = ((struct sockaddr_in *)cur->ai_addr)->sin_addr; freeaddrinfo(ai); return 0; } } freeaddrinfo(ai); return -1; #else struct hostent *hp; hp = gethostbyname(hostname); if (!hp) return -1; memcpy(sin_addr, hp->h_addr_list[0], sizeof(struct in_addr)); #endif } return 0; } void ffserver_get_arg(char *buf, int buf_size, const char **pp) { const char *p; char *q; int quote = 0; p = *pp; q = buf; while (av_isspace(*p)) p++; if (*p == '\"' || *p == '\'') quote = *p++; while (*p != '\0') { if (quote && *p == quote || !quote && av_isspace(*p)) break; if ((q - buf) < buf_size - 1) *q++ = *p; p++; } *q = '\0'; if (quote && *p == quote) p++; *pp = p; } void ffserver_parse_acl_row(FFServerStream *stream, FFServerStream* feed, FFServerIPAddressACL *ext_acl, const char *p, const char *filename, int line_num) { char arg[1024]; FFServerIPAddressACL acl; FFServerIPAddressACL *nacl; FFServerIPAddressACL **naclp; ffserver_get_arg(arg, sizeof(arg), &p); if (av_strcasecmp(arg, "allow") == 0) acl.action = IP_ALLOW; else if (av_strcasecmp(arg, "deny") == 0) acl.action = IP_DENY; else { fprintf(stderr, "%s:%d: ACL action '%s' should be ALLOW or DENY.\n", filename, line_num, arg); goto bail; } ffserver_get_arg(arg, sizeof(arg), &p); if (resolve_host(&acl.first, arg)) { fprintf(stderr, "%s:%d: ACL refers to invalid host or IP address '%s'\n", filename, line_num, arg); goto bail; } acl.last = acl.first; ffserver_get_arg(arg, sizeof(arg), &p); if (arg[0]) { if (resolve_host(&acl.last, arg)) { fprintf(stderr, "%s:%d: ACL refers to invalid host or IP address '%s'\n", filename, line_num, arg); goto bail; } } nacl = av_mallocz(sizeof(*nacl)); if (!nacl) { fprintf(stderr, "Failed to allocate FFServerIPAddressACL\n"); goto bail; } naclp = 0; acl.next = 0; *nacl = acl; if (stream) naclp = &stream->acl; else if (feed) naclp = &feed->acl; else if (ext_acl) naclp = &ext_acl; else fprintf(stderr, "%s:%d: ACL found not in <Stream> or <Feed>\n", filename, line_num); if (naclp) { while (*naclp) naclp = &(*naclp)->next; *naclp = nacl; } else av_free(nacl); bail: return; } /* add a codec and set the default parameters */ static void add_codec(FFServerStream *stream, AVCodecContext *av, FFServerConfig *config) { LayeredAVStream *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(*st)); if (!st) return; av_dict_get_string(recommended, &enc_config, '=', ','); av_dict_free(&recommended); st->recommended_encoder_configuration = enc_config; st->codec = av; st->codecpar = avcodec_parameters_alloc(); avcodec_parameters_from_context(st->codecpar, av); stream->streams[stream->nb_streams++] = st; } 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 int ffserver_opt_preset(const char *arg, int type, FFServerConfig *config) { FILE *f=NULL; char filename[1000], tmp[1000], tmp2[1000], line[1000]; int ret = 0; AVCodecContext *avctx; const AVCodec *codec; switch(type) { case AV_OPT_FLAG_AUDIO_PARAM: avctx = config->dummy_actx; break; case AV_OPT_FLAG_VIDEO_PARAM: avctx = config->dummy_vctx; break; default: av_assert0(0); } codec = avcodec_find_encoder(avctx->codec_id); if (!(f = get_preset_file(filename, sizeof(filename), arg, 0, codec ? codec->name : NULL))) { av_log(NULL, AV_LOG_ERROR, "File for preset '%s' not found\n", arg); return AVERROR(EINVAL); } while(!feof(f)){ int e= fscanf(f, "%999[^\n]\n", line) - 1; if(line[0] == '#' && !e) continue; e|= sscanf(line, "%999[^=]=%999[^\n]\n", tmp, tmp2) - 2; if(e){ av_log(NULL, AV_LOG_ERROR, "%s: Invalid syntax: '%s'\n", filename, line); ret = AVERROR(EINVAL); break; } if (!strcmp(tmp, "acodec") && avctx->codec_type == AVMEDIA_TYPE_AUDIO || !strcmp(tmp, "vcodec") && avctx->codec_type == AVMEDIA_TYPE_VIDEO) { if (ffserver_set_codec(avctx, tmp2, config) < 0) break; } else if (!strcmp(tmp, "scodec")) { av_log(NULL, AV_LOG_ERROR, "Subtitles preset found.\n"); ret = AVERROR(EINVAL); break; } else if (ffserver_save_avoption(tmp, tmp2, type, config) < 0) break; } fclose(f); return ret; } static AVOutputFormat *ffserver_guess_format(const char *short_name, const char *filename, const char *mime_type) { AVOutputFormat *fmt = av_guess_format(short_name, filename, mime_type); if (fmt) { AVOutputFormat *stream_fmt; char stream_format_name[64]; snprintf(stream_format_name, sizeof(stream_format_name), "%s_stream", fmt->name); stream_fmt = av_guess_format(stream_format_name, NULL, NULL); if (stream_fmt) fmt = stream_fmt; } return fmt; } static void vreport_config_error(const char *filename, int line_num, int log_level, int *errors, const char *fmt, va_list vl) { av_log(NULL, log_level, "%s:%d: ", filename, line_num); av_vlog(NULL, log_level, fmt, vl); if (errors) (*errors)++; } static void report_config_error(const char *filename, int line_num, int log_level, int *errors, const char *fmt, ...) { va_list vl; va_start(vl, fmt); vreport_config_error(filename, line_num, log_level, errors, fmt, vl); va_end(vl); } static int ffserver_set_int_param(int *dest, const char *value, int factor, int min, int max, FFServerConfig *config, const char *error_msg, ...) { int tmp; char *tailp; if (!value || !value[0]) goto error; errno = 0; tmp = strtol(value, &tailp, 0); if (tmp < min || tmp > max) goto error; if (factor) { if (tmp == INT_MIN || FFABS(tmp) > INT_MAX / FFABS(factor)) goto error; tmp *= factor; } if (tailp[0] || errno) goto error; if (dest) *dest = tmp; return 0; error: if (config) { va_list vl; va_start(vl, error_msg); vreport_config_error(config->filename, config->line_num, AV_LOG_ERROR, &config->errors, error_msg, vl); va_end(vl); } return AVERROR(EINVAL); } static int ffserver_set_float_param(float *dest, const char *value, float factor, float min, float max, FFServerConfig *config, const char *error_msg, ...) { double tmp; char *tailp; if (!value || !value[0]) goto error; errno = 0; tmp = strtod(value, &tailp); if (tmp < min || tmp > max) goto error; if (factor)