[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