[FFmpeg-devel] [PATCH 4/4] ffserver_config: postpone codec context creation
Stefano Sabatini
stefasab at gmail.com
Tue Oct 21 13:08:43 CEST 2014
On date Monday 2014-10-20 23:57:02 +0200, Lukasz Marek encoded:
> So far AVCodecContext was created without codec specified.
> This causes internal data to not be initialized to defaults.
>
> This commit postpone context creation until all information are gathered.
>
> Partially fixes #1275
> ---
> ffserver.c | 8 +-
> ffserver_config.c | 286 ++++++++++++++++++++++++++++++++----------------------
> ffserver_config.h | 9 +-
> 3 files changed, 183 insertions(+), 120 deletions(-)
>
> diff --git a/ffserver.c b/ffserver.c
> index 22560ce..8c65d12 100644
> --- a/ffserver.c
> +++ b/ffserver.c
> @@ -212,8 +212,12 @@ static FFServerConfig config = {
> .warnings = 0,
> .audio_id = AV_CODEC_ID_NONE,
> .video_id = AV_CODEC_ID_NONE,
> - .audio_enc = {0},
> - .video_enc = {0},
> + .video_opts = NULL,
> + .video_conf = NULL,
> + .audio_opts = NULL,
> + .audio_conf = NULL,
> + .video_preset = NULL,
> + .audio_preset = NULL,
> };
>
> static void new_connection(int server_fd, int is_rtsp);
> diff --git a/ffserver_config.c b/ffserver_config.c
> index 18b1e72..87c91cd 100644
> --- a/ffserver_config.c
> +++ b/ffserver_config.c
> @@ -238,9 +238,8 @@ static void add_codec(FFServerStream *stream, AVCodecContext *av)
> st = av_mallocz(sizeof(AVStream));
> if (!st)
> return;
> - st->codec = avcodec_alloc_context3(NULL);
> + st->codec = av;
> stream->streams[stream->nb_streams++] = st;
> - memcpy(st->codec, av, sizeof(AVCodecContext));
> }
>
> static enum AVCodecID opt_codec(const char *name, enum AVMediaType type)
> @@ -269,12 +268,15 @@ static int ffserver_opt_preset(const char *arg,
> FILE *f=NULL;
> char filename[1000], tmp[1000], tmp2[1000], line[1000];
> int ret = 0;
> - AVCodec *codec = avcodec_find_encoder(avctx->codec_id);
> + AVCodec *codec = NULL;
> +
> + if (avctx)
> + codec = avcodec_find_encoder(avctx->codec_id);
>
> if (!(f = get_preset_file(filename, sizeof(filename), arg, 0,
> codec ? codec->name : NULL))) {
> fprintf(stderr, "File for preset '%s' not found\n", arg);
> - return 1;
> + return AVERROR(EINVAL);
> }
>
> while(!feof(f)){
> @@ -284,18 +286,17 @@ static int ffserver_opt_preset(const char *arg,
> e|= sscanf(line, "%999[^=]=%999[^\n]\n", tmp, tmp2) - 2;
> if(e){
> fprintf(stderr, "%s: Invalid syntax: '%s'\n", filename, line);
> - ret = 1;
> + ret = AVERROR(EINVAL);
> break;
> }
> - if(!strcmp(tmp, "acodec")){
> + if (audio_id && !strcmp(tmp, "acodec")) {
> *audio_id = opt_codec(tmp2, AVMEDIA_TYPE_AUDIO);
> - }else if(!strcmp(tmp, "vcodec")){
> + } else if (video_id && !strcmp(tmp, "vcodec")){
> *video_id = opt_codec(tmp2, AVMEDIA_TYPE_VIDEO);
> - }else if(!strcmp(tmp, "scodec")){
> + } else if(!strcmp(tmp, "scodec")) {
> /* opt_subtitle_codec(tmp2); */
> - }else if(ffserver_opt_default(tmp, tmp2, avctx, type) < 0){
> + } else if (avctx && (ret = ffserver_opt_default(tmp, tmp2, avctx, type)) < 0) {
> fprintf(stderr, "%s: Invalid option or argument: '%s', parsed as '%s' = '%s'\n", filename, line, tmp, tmp2);
> - ret = 1;
> break;
> }
> }
> @@ -510,6 +511,83 @@ static int ffserver_parse_config_feed(FFServerConfig *config, const char *cmd, c
> return 0;
> }
>
> +static int ffserver_apply_stream_config(AVCodecContext *enc, const AVDictionary *conf, AVDictionary **opts)
> +{
> + AVDictionaryEntry *e;
> + char *eptr;
> +
> +#define SET_INT_PARAM(factor, param, key) \
> + if ((e = av_dict_get(conf, #key, NULL, 0))) { \
> + enc->param = strtol(e->value, &eptr, 0); \
> + if (factor) enc->param *= (factor); \
> + if (eptr[0] || errno) { \
> + av_log(NULL, AV_LOG_ERROR, "Cannot parse %s as number for %s parameter.\n", e->value, #param); \
> + return AVERROR(errno); \
> + } \
> + }
In case of empty string errno is not set, so you should do:
if (eptr[0]) ret = AVERROR(EINVAL);
same below. Also eptr is a bit confusing, I'd prefer tailp[tr] or simply
p[tr].
> +#define SET_DOUBLE_PARAM(factor, param, key) \
> + if ((e = av_dict_get(conf, #key, NULL, 0))) { \
> + enc->param = strtod(e->value, &eptr); \
> + if (factor) enc->param *= (factor); \
> + if (eptr[0] || errno) { \
> + av_log(NULL, AV_LOG_ERROR, "Cannot parse %s as number for %s parameter.\n", e->value, #param); \
> + return AVERROR(errno); \
> + } \
> + }
> +
> + errno = 0;
> + //video params
> + SET_INT_PARAM(0, rc_min_rate, VideoBitRateRangeMin)
> + SET_INT_PARAM(0, rc_max_rate, VideoBitRateRangeMax)
> + SET_INT_PARAM(0, debug, Debug)
> + SET_INT_PARAM(0, strict_std_compliance, Strict)
> + SET_INT_PARAM(8*1024, rc_buffer_size, VideoBufferSize)
> + SET_INT_PARAM(1000, bit_rate_tolerance, VideoBitRateTolerance)
> + SET_INT_PARAM(1000, bit_rate, VideoBitRate)
> + SET_INT_PARAM(0, width, VideoSizeWidth)
> + SET_INT_PARAM(0, height, VideoSizeHeight)
> + SET_INT_PARAM(0, pix_fmt, PixelFormat)
> + SET_INT_PARAM(0, gop_size, VideoGopSize)
> + SET_INT_PARAM(0, time_base.num, VideoFrameRateNum)
> + SET_INT_PARAM(0, time_base.den, VideoFrameRateDen)
> + SET_INT_PARAM(0, max_qdiff, VideoQDiff)
> + SET_INT_PARAM(0, qmax, VideoQMax)
> + SET_INT_PARAM(0, qmin, VideoQMin)
> + SET_DOUBLE_PARAM(0, lumi_masking, LumiMask)
> + SET_DOUBLE_PARAM(0, dark_masking, DarkMask)
> + if (av_dict_get(conf, "BitExact", NULL, 0))
> + enc->flags |= CODEC_FLAG_BITEXACT;
> + if (av_dict_get(conf, "DctFastint", NULL, 0))
> + enc->dct_algo = FF_DCT_FASTINT;
> + if (av_dict_get(conf, "IdctSimple", NULL, 0))
> + enc->idct_algo = FF_IDCT_SIMPLE;
> + if (av_dict_get(conf, "VideoHighQuality", NULL, 0))
> + enc->mb_decision = FF_MB_DECISION_BITS;
> + if ((e = av_dict_get(conf, "VideoTag", NULL, 0)))
> + enc->codec_tag = MKTAG(e->value[0], e->value[1], e->value[2], e->value[3]);
> + if (av_dict_get(conf, "Qscale", NULL, 0)) {
> + enc->flags |= CODEC_FLAG_QSCALE;
> + SET_INT_PARAM(FF_QP2LAMBDA, global_quality, "Qscale")
> + }
> + if (av_dict_get(conf, "Video4MotionVector", NULL, 0)) {
> + enc->mb_decision = FF_MB_DECISION_BITS; //FIXME remove
> + enc->flags |= CODEC_FLAG_4MV;
> + }
> + //audio params
> + SET_INT_PARAM(0, channels, AudioChannels)
> + SET_INT_PARAM(0, sample_rate, AudioSampleRate)
> + SET_INT_PARAM(0, bit_rate, AudioBitRate)
> +
> + av_opt_set_dict2(enc, opts, AV_OPT_SEARCH_CHILDREN);
Not sure, but looks like you're not moving the remaining options from
conf to opts.
> + e = NULL;
> + while (e = av_dict_get(*opts, "", e, AV_DICT_IGNORE_SUFFIX))
> + av_log(NULL, AV_LOG_WARNING, "Provided option '%s' doesn't match any existing option.\n", e->key);
> +
I'd prefer to exit in this case, after listening all the invalid
values, since otherwise the user will ignore the error.
> + return 0;
> +#undef SET_INT_PARAM
> +#undef SET_DOUBLE_PARAM
> +}
> +
> static int ffserver_parse_config_stream(FFServerConfig *config, const char *cmd, const char **p,
> int line_num, FFServerStream **pstream)
> {
> @@ -537,14 +615,12 @@ static int ffserver_parse_config_stream(FFServerConfig *config, const char *cmd,
> }
>
> stream->fmt = ffserver_guess_format(NULL, stream->filename, NULL);
> - avcodec_get_context_defaults3(&config->video_enc, NULL);
> - avcodec_get_context_defaults3(&config->audio_enc, NULL);
> -
> - config->audio_id = AV_CODEC_ID_NONE;
> - config->video_id = AV_CODEC_ID_NONE;
> if (stream->fmt) {
> config->audio_id = stream->fmt->audio_codec;
> config->video_id = stream->fmt->video_codec;
> + } else {
> + config->audio_id = AV_CODEC_ID_NONE;
> + config->video_id = AV_CODEC_ID_NONE;
> }
> *pstream = stream;
> return 0;
> @@ -638,136 +714,104 @@ static int ffserver_parse_config_stream(FFServerConfig *config, const char *cmd,
> stream->max_time = atof(arg) * 1000;
> } else if (!av_strcasecmp(cmd, "AudioBitRate")) {
> ffserver_get_arg(arg, sizeof(arg), p);
> - config->audio_enc.bit_rate = lrintf(atof(arg) * 1000);
> - } else if (!av_strcasecmp(cmd, "AudioChannels")) {
> - ffserver_get_arg(arg, sizeof(arg), p);
> - config->audio_enc.channels = atoi(arg);
> - } else if (!av_strcasecmp(cmd, "AudioSampleRate")) {
> + av_dict_set_int(&config->audio_conf, cmd, lrintf(atof(arg) * 1000), 0);
> + } else if (!av_strcasecmp(cmd, "AudioChannels") ||
> + !av_strcasecmp(cmd, "AudioSampleRate")) {
> ffserver_get_arg(arg, sizeof(arg), p);
> - config->audio_enc.sample_rate = atoi(arg);
> + av_dict_set(&config->audio_conf, cmd, arg, 0);
> } else if (!av_strcasecmp(cmd, "VideoBitRateRange")) {
> int minrate, maxrate;
> ffserver_get_arg(arg, sizeof(arg), p);
> if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
> - config->video_enc.rc_min_rate = minrate * 1000;
> - config->video_enc.rc_max_rate = maxrate * 1000;
> + av_dict_set_int(&config->video_conf, "VideoBitRateRangeMin", minrate * 1000, 0);
> + av_dict_set_int(&config->video_conf, "VideoBitRateRangeMax", maxrate * 1000, 0);
> } else
> ERROR("Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n", arg);
> - } else if (!av_strcasecmp(cmd, "Debug")) {
> - ffserver_get_arg(arg, sizeof(arg), p);
> - config->video_enc.debug = strtol(arg,0,0);
> - } else if (!av_strcasecmp(cmd, "Strict")) {
> - ffserver_get_arg(arg, sizeof(arg), p);
> - config->video_enc.strict_std_compliance = atoi(arg);
> - } else if (!av_strcasecmp(cmd, "VideoBufferSize")) {
> - ffserver_get_arg(arg, sizeof(arg), p);
> - config->video_enc.rc_buffer_size = atoi(arg) * 8*1024;
> - } else if (!av_strcasecmp(cmd, "VideoBitRateTolerance")) {
> - ffserver_get_arg(arg, sizeof(arg), p);
> - config->video_enc.bit_rate_tolerance = atoi(arg) * 1000;
> - } else if (!av_strcasecmp(cmd, "VideoBitRate")) {
> - ffserver_get_arg(arg, sizeof(arg), p);
> - config->video_enc.bit_rate = atoi(arg) * 1000;
> + } else if (!av_strcasecmp(cmd, "Debug") ||
> + !av_strcasecmp(cmd, "Strict") ||
> + !av_strcasecmp(cmd, "VideoBufferSize") ||
> + !av_strcasecmp(cmd, "VideoBitRateTolerance") ||
> + !av_strcasecmp(cmd, "VideoBitRate") ||
> + !av_strcasecmp(cmd, "VideoGopSize") ||
> + !av_strcasecmp(cmd, "Qscale") ||
> + !av_strcasecmp(cmd, "LumiMask") ||
> + !av_strcasecmp(cmd, "DarkMask")){
> + ffserver_get_arg(arg, sizeof(arg), p);
> + av_dict_set(&config->video_conf, cmd, arg, 0);
> } else if (!av_strcasecmp(cmd, "VideoSize")) {
> - int ret;
> + int ret, w, h;
> ffserver_get_arg(arg, sizeof(arg), p);
> - ret = av_parse_video_size(&config->video_enc.width, &config->video_enc.height, arg);
> + ret = av_parse_video_size(&w, &h, arg);
> if (ret < 0)
> ERROR("Invalid video size '%s'\n", arg);
> - else if ((config->video_enc.width % 16) != 0 || (config->video_enc.height % 16) != 0)
> + else if ((w % 16) || (h % 16))
> ERROR("Image size must be a multiple of 16\n");
Note: you can probably drop this check (but not in this patch).
> + av_dict_set_int(&config->video_conf, "VideoSizeWidth", w, 0);
> + av_dict_set_int(&config->video_conf, "VideoSizeHeight", h, 0);
> } else if (!av_strcasecmp(cmd, "VideoFrameRate")) {
> AVRational frame_rate;
> ffserver_get_arg(arg, sizeof(arg), p);
> if (av_parse_video_rate(&frame_rate, arg) < 0) {
> ERROR("Incorrect frame rate: %s\n", arg);
> } else {
> - config->video_enc.time_base.num = frame_rate.den;
> - config->video_enc.time_base.den = frame_rate.num;
> + av_dict_set_int(&config->video_conf, "VideoFrameRateNum", frame_rate.num, 0);
> + av_dict_set_int(&config->video_conf, "VideoFrameRateDen", frame_rate.den, 0);
> }
> } else if (!av_strcasecmp(cmd, "PixelFormat")) {
> + enum AVPixelFormat pix_fmt;
> ffserver_get_arg(arg, sizeof(arg), p);
> - config->video_enc.pix_fmt = av_get_pix_fmt(arg);
> - if (config->video_enc.pix_fmt == AV_PIX_FMT_NONE)
> + pix_fmt = av_get_pix_fmt(arg);
> + if (pix_fmt == AV_PIX_FMT_NONE)
> ERROR("Unknown pixel format: %s\n", arg);
> - } else if (!av_strcasecmp(cmd, "VideoGopSize")) {
> - ffserver_get_arg(arg, sizeof(arg), p);
> - config->video_enc.gop_size = atoi(arg);
> + av_dict_set_int(&config->video_conf, cmd, pix_fmt, 0);
> } else if (!av_strcasecmp(cmd, "VideoIntraOnly")) {
> - config->video_enc.gop_size = 1;
> - } else if (!av_strcasecmp(cmd, "VideoHighQuality")) {
> - config->video_enc.mb_decision = FF_MB_DECISION_BITS;
> - } else if (!av_strcasecmp(cmd, "Video4MotionVector")) {
> - config->video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
> - config->video_enc.flags |= CODEC_FLAG_4MV;
> + av_dict_set(&config->video_conf, "VideoGopSize", "1", 0);
> } else if (!av_strcasecmp(cmd, "AVOptionVideo") ||
> !av_strcasecmp(cmd, "AVOptionAudio")) {
> - AVCodecContext *avctx;
> - int type;
> + AVDictionary **dict;
> ffserver_get_arg(arg, sizeof(arg), p);
> ffserver_get_arg(arg2, sizeof(arg2), p);
> - if (!av_strcasecmp(cmd, "AVOptionVideo")) {
> - avctx = &config->video_enc;
> - type = AV_OPT_FLAG_VIDEO_PARAM;
> - } else {
> - avctx = &config->audio_enc;
> - type = AV_OPT_FLAG_AUDIO_PARAM;
> - }
> - if (ffserver_opt_default(arg, arg2, avctx, type|AV_OPT_FLAG_ENCODING_PARAM)) {
> - ERROR("Error setting %s option to %s %s\n", cmd, arg, arg2);
> - }
> + if (!av_strcasecmp(cmd, "AVOptionVideo"))
> + dict = &config->video_opts;
> + else
> + dict = &config->audio_opts;
> + av_dict_set(dict, arg, arg2, 0);
> } else if (!av_strcasecmp(cmd, "AVPresetVideo") ||
> !av_strcasecmp(cmd, "AVPresetAudio")) {
> - AVCodecContext *avctx;
> - int type;
> + char **preset = NULL;
> ffserver_get_arg(arg, sizeof(arg), p);
> if (!av_strcasecmp(cmd, "AVPresetVideo")) {
> - avctx = &config->video_enc;
> - config->video_enc.codec_id = config->video_id;
> - type = AV_OPT_FLAG_VIDEO_PARAM;
> + preset = &config->video_preset;
> + ffserver_opt_preset(arg, NULL, 0, NULL, &config->video_id);
> } else {
> - avctx = &config->audio_enc;
> - config->audio_enc.codec_id = config->audio_id;
> - type = AV_OPT_FLAG_AUDIO_PARAM;
> - }
> - if (ffserver_opt_preset(arg, avctx, type|AV_OPT_FLAG_ENCODING_PARAM, &config->audio_id, &config->video_id)) {
> - ERROR("AVPreset error: %s\n", arg);
> + preset = &config->audio_preset;
> + ffserver_opt_preset(arg, NULL, 0, &config->audio_id, NULL);
> }
> + *preset = av_strdup(arg);
> + if (!preset)
> + return AVERROR(ENOMEM);
> } else if (!av_strcasecmp(cmd, "VideoTag")) {
> ffserver_get_arg(arg, sizeof(arg), p);
> if (strlen(arg) == 4)
> - config->video_enc.codec_tag = MKTAG(arg[0], arg[1], arg[2], arg[3]);
> - } else if (!av_strcasecmp(cmd, "BitExact")) {
> - config->video_enc.flags |= CODEC_FLAG_BITEXACT;
> - } else if (!av_strcasecmp(cmd, "DctFastint")) {
> - config->video_enc.dct_algo = FF_DCT_FASTINT;
> - } else if (!av_strcasecmp(cmd, "IdctSimple")) {
> - config->video_enc.idct_algo = FF_IDCT_SIMPLE;
> - } else if (!av_strcasecmp(cmd, "Qscale")) {
> - ffserver_get_arg(arg, sizeof(arg), p);
> - config->video_enc.flags |= CODEC_FLAG_QSCALE;
> - config->video_enc.global_quality = FF_QP2LAMBDA * atoi(arg);
> - } else if (!av_strcasecmp(cmd, "VideoQDiff")) {
> - ffserver_get_arg(arg, sizeof(arg), p);
> - config->video_enc.max_qdiff = atoi(arg);
> - if (config->video_enc.max_qdiff < 1 || config->video_enc.max_qdiff > 31)
> - ERROR("VideoQDiff out of range\n");
> - } else if (!av_strcasecmp(cmd, "VideoQMax")) {
> - ffserver_get_arg(arg, sizeof(arg), p);
> - config->video_enc.qmax = atoi(arg);
> - if (config->video_enc.qmax < 1 || config->video_enc.qmax > 31)
> - ERROR("VideoQMax out of range\n");
> - } else if (!av_strcasecmp(cmd, "VideoQMin")) {
> - ffserver_get_arg(arg, sizeof(arg), p);
> - config->video_enc.qmin = atoi(arg);
> - if (config->video_enc.qmin < 1 || config->video_enc.qmin > 31)
> - ERROR("VideoQMin out of range\n");
> - } else if (!av_strcasecmp(cmd, "LumiMask")) {
> - ffserver_get_arg(arg, sizeof(arg), p);
> - config->video_enc.lumi_masking = atof(arg);
> - } else if (!av_strcasecmp(cmd, "DarkMask")) {
> - ffserver_get_arg(arg, sizeof(arg), p);
> - config->video_enc.dark_masking = atof(arg);
> + av_dict_set(&config->video_conf, "VideoTag", "arg", 0);
> + else
> + ERROR("Invalid VideoTag %s\n", arg);
> + } else if (!av_strcasecmp(cmd, "BitExact") ||
> + !av_strcasecmp(cmd, "DctFastint") ||
> + !av_strcasecmp(cmd, "IdctSimple") ||
> + !av_strcasecmp(cmd, "VideoHighQuality") ||
> + !av_strcasecmp(cmd, "Video4MotionVector")) {
> + av_dict_set(&config->video_conf, cmd, "", 0);
> + } else if (!av_strcasecmp(cmd, "VideoQDiff") ||
> + !av_strcasecmp(cmd, "VideoQMin") ||
> + !av_strcasecmp(cmd, "VideoQMax")) {
> + int val;
> + ffserver_get_arg(arg, sizeof(arg), p);
> + val = atoi(arg);
> + if (val < 1 || val > 31)
> + ERROR("%s out of range\n", cmd);
> + else
> + av_dict_set(&config->video_conf, cmd, arg, 0);
> } else if (!av_strcasecmp(cmd, "NoVideo")) {
> config->video_id = AV_CODEC_ID_NONE;
> } else if (!av_strcasecmp(cmd, "NoAudio")) {
> @@ -797,16 +841,28 @@ static int ffserver_parse_config_stream(FFServerConfig *config, const char *cmd,
> } else if (!av_strcasecmp(cmd, "</Stream>")) {
> if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
> if (config->audio_id != AV_CODEC_ID_NONE) {
> - config->audio_enc.codec_type = AVMEDIA_TYPE_AUDIO;
> - config->audio_enc.codec_id = config->audio_id;
> - add_codec(stream, &config->audio_enc);
> + AVCodecContext *audio_enc = avcodec_alloc_context3(avcodec_find_encoder(config->audio_id));
> + if (config->audio_preset &&
> + ffserver_opt_preset(arg, audio_enc, AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_ENCODING_PARAM,
> + NULL, NULL) < 0)
> + ERROR("AVPreset error: %s\n", arg);
Meaningful error message please, something like: "Could not apply
preset '%s'.
(Note: preset system is currently braindead and should be probably
removed altogether).
> + ffserver_apply_stream_config(audio_enc, config->audio_conf, &config->audio_opts);
> + add_codec(stream, audio_enc);
> }
> if (config->video_id != AV_CODEC_ID_NONE) {
> - config->video_enc.codec_type = AVMEDIA_TYPE_VIDEO;
> - config->video_enc.codec_id = config->video_id;
> - add_codec(stream, &config->video_enc);
> + AVCodecContext *video_enc = avcodec_alloc_context3(avcodec_find_encoder(config->video_id));
> + if (config->video_preset &&
> + ffserver_opt_preset(arg, video_enc, AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_ENCODING_PARAM,
> + NULL, NULL) < 0)
> + ERROR("AVPreset error: %s\n", arg);
> + ffserver_apply_stream_config(video_enc, config->video_conf, &config->video_opts);
> + add_codec(stream, video_enc);
> }
> }
> + av_dict_free(&config->video_opts);
> + av_dict_free(&config->video_conf);
> + av_dict_free(&config->audio_opts);
> + av_dict_free(&config->audio_conf);
> *pstream = NULL;
> } else if (!av_strcasecmp(cmd, "File") || !av_strcasecmp(cmd, "ReadOnlyFile")) {
> ffserver_get_arg(stream->feed_filename, sizeof(stream->feed_filename), p);
> diff --git a/ffserver_config.h b/ffserver_config.h
> index 36d61d0..234e91a 100644
> --- a/ffserver_config.h
> +++ b/ffserver_config.h
> @@ -107,11 +107,14 @@ typedef struct FFServerConfig {
> int errors;
> int warnings;
> // Following variables MUST NOT be used outside configuration parsing code.
> - AVCodecContext audio_enc;
> - AVCodecContext video_enc;
> enum AVCodecID audio_id;
> enum AVCodecID video_id;
> -
> + AVDictionary *video_opts;
> + AVDictionary *video_conf;
> + AVDictionary *audio_opts;
> + AVDictionary *audio_conf;
> + char *video_preset;
> + char *audio_preset;
please annotate what's the difference between options and
configuration, which is a bit confused/ing.
[...]
--
FFmpeg = Free and Foolish Magnificient Plastic Educated Gnome
More information about the ffmpeg-devel
mailing list