[FFmpeg-cvslog] ffserver_config: postpone codec context creation

Lukasz Marek git at videolan.org
Sat Nov 1 01:07:22 CET 2014


ffmpeg | branch: master | Lukasz Marek <lukasz.m.luki2 at gmail.com> | Sun Oct 19 21:29:40 2014 +0200| [ed1f8915daf6b84a940463dfe83c7b970f82383d] | committer: Lukasz Marek

ffserver_config: postpone codec context creation

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 is gathered.

Partially fixes #1275

> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=ed1f8915daf6b84a940463dfe83c7b970f82383d
---

 ffserver_config.c |  386 ++++++++++++++++++++++++++++++++++++++++-------------
 ffserver_config.h |    9 +-
 2 files changed, 297 insertions(+), 98 deletions(-)

diff --git a/ffserver_config.c b/ffserver_config.c
index e44cdf7..4c8740d 100644
--- a/ffserver_config.c
+++ b/ffserver_config.c
@@ -18,6 +18,7 @@
  * 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"
@@ -238,9 +239,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 +269,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 +287,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;
         }
     }
@@ -323,15 +325,78 @@ static AVOutputFormat *ffserver_guess_format(const char *short_name, const char
     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);
+    (*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);
-    av_log(NULL, log_level, "%s:%d: ", filename, line_num);
-    av_vlog(NULL, log_level, fmt, vl);
+    vreport_config_error(filename, line_num, log_level, errors, fmt, vl);
     va_end(vl);
+}
 
-    (*errors)++;
+static int ffserver_set_int_param(int *dest, const char *value, int factor, int min, int max,
+                                  FFServerConfig *config, int line_num, 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 (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, 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, int line_num, 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)
+        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, line_num, AV_LOG_ERROR, &config->errors, error_msg, vl);
+        va_end(vl);
+    }
+    return AVERROR(EINVAL);
 }
 
 #define ERROR(...)   report_config_error(config->filename, line_num, AV_LOG_ERROR,   &config->errors,   __VA_ARGS__)
@@ -502,6 +567,87 @@ 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;
+    int ret = 0;
+
+    /* Return values from ffserver_set_*_param are ignored.
+       Values are initially parsed and checked before inserting to AVDictionary. */
+
+    //video params
+    if ((e = av_dict_get(conf, "VideoBitRateRangeMin", NULL, 0)))
+        ffserver_set_int_param(&enc->rc_min_rate, e->value, 1000, INT_MIN, INT_MAX, NULL, 0, NULL);
+    if ((e = av_dict_get(conf, "VideoBitRateRangeMax", NULL, 0)))
+        ffserver_set_int_param(&enc->rc_max_rate, e->value, 1000, INT_MIN, INT_MAX, NULL, 0, NULL);
+    if ((e = av_dict_get(conf, "Debug", NULL, 0)))
+        ffserver_set_int_param(&enc->debug, e->value, 0, INT_MIN, INT_MAX, NULL, 0, NULL);
+    if ((e = av_dict_get(conf, "Strict", NULL, 0)))
+        ffserver_set_int_param(&enc->strict_std_compliance, e->value, 0, INT_MIN, INT_MAX, NULL, 0, NULL);
+    if ((e = av_dict_get(conf, "VideoBufferSize", NULL, 0)))
+        ffserver_set_int_param(&enc->rc_buffer_size, e->value, 8*1024, INT_MIN, INT_MAX, NULL, 0, NULL);
+    if ((e = av_dict_get(conf, "VideoBitRateTolerance", NULL, 0)))
+        ffserver_set_int_param(&enc->bit_rate_tolerance, e->value, 1000, INT_MIN, INT_MAX, NULL, 0, NULL);
+    if ((e = av_dict_get(conf, "VideoBitRate", NULL, 0)))
+        ffserver_set_int_param(&enc->bit_rate, e->value, 1000, INT_MIN, INT_MAX, NULL, 0, NULL);
+    if ((e = av_dict_get(conf, "VideoSizeWidth", NULL, 0)))
+        ffserver_set_int_param(&enc->width, e->value, 0, INT_MIN, INT_MAX, NULL, 0, NULL);
+    if ((e = av_dict_get(conf, "VideoSizeHeight", NULL, 0)))
+        ffserver_set_int_param(&enc->height, e->value, 0, INT_MIN, INT_MAX, NULL, 0, NULL);
+    if ((e = av_dict_get(conf, "PixelFormat", NULL, 0)))
+        ffserver_set_int_param(&enc->pix_fmt, e->value, 0, INT_MIN, INT_MAX, NULL, 0, NULL);
+    if ((e = av_dict_get(conf, "VideoGopSize", NULL, 0)))
+        ffserver_set_int_param(&enc->gop_size, e->value, 0, INT_MIN, INT_MAX, NULL, 0, NULL);
+    if ((e = av_dict_get(conf, "VideoFrameRateNum", NULL, 0)))
+        ffserver_set_int_param(&enc->time_base.num, e->value, 0, INT_MIN, INT_MAX, NULL, 0, NULL);
+    if ((e = av_dict_get(conf, "VideoFrameRateDen", NULL, 0)))
+        ffserver_set_int_param(&enc->time_base.den, e->value, 0, INT_MIN, INT_MAX, NULL, 0, NULL);
+    if ((e = av_dict_get(conf, "VideoQDiff", NULL, 0)))
+        ffserver_set_int_param(&enc->max_qdiff, e->value, 0, INT_MIN, INT_MAX, NULL, 0, NULL);
+    if ((e = av_dict_get(conf, "VideoQMax", NULL, 0)))
+        ffserver_set_int_param(&enc->qmax, e->value, 0, INT_MIN, INT_MAX, NULL, 0, NULL);
+    if ((e = av_dict_get(conf, "VideoQMin", NULL, 0)))
+        ffserver_set_int_param(&enc->qmin, e->value, 0, INT_MIN, INT_MAX, NULL, 0, NULL);
+    if ((e = av_dict_get(conf, "LumiMask", NULL, 0)))
+        ffserver_set_float_param(&enc->lumi_masking, e->value, 0, -FLT_MAX, FLT_MAX, NULL, 0, NULL);
+    if ((e = av_dict_get(conf, "DarkMask", NULL, 0)))
+        ffserver_set_float_param(&enc->dark_masking, e->value, 0, -FLT_MAX, FLT_MAX, NULL, 0, NULL);
+    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;
+        ffserver_set_int_param(&enc->global_quality, e->value, FF_QP2LAMBDA, INT_MIN, INT_MAX, NULL, 0, NULL);
+    }
+    if (av_dict_get(conf, "Video4MotionVector", NULL, 0)) {
+        enc->mb_decision = FF_MB_DECISION_BITS; //FIXME remove
+        enc->flags |= CODEC_FLAG_4MV;
+    }
+    //audio params
+    if ((e = av_dict_get(conf, "AudioChannels", NULL, 0)))
+        ffserver_set_int_param(&enc->channels, e->value, 0, INT_MIN, INT_MAX, NULL, 0, NULL);
+    if ((e = av_dict_get(conf, "AudioSampleRate", NULL, 0)))
+        ffserver_set_int_param(&enc->sample_rate, e->value, 0, INT_MIN, INT_MAX, NULL, 0, NULL);
+    if ((e = av_dict_get(conf, "AudioBitRate", NULL, 0)))
+        ffserver_set_int_param(&enc->bit_rate, e->value, 0, INT_MIN, INT_MAX, NULL, 0, NULL);
+
+    av_opt_set_dict2(enc, opts, AV_OPT_SEARCH_CHILDREN);
+    e = NULL;
+    while (e = av_dict_get(*opts, "", e, AV_DICT_IGNORE_SUFFIX)) {
+        av_log(NULL, AV_LOG_ERROR, "Provided AVOption '%s' doesn't match any existing option.\n", e->key);
+        ret = AVERROR(EINVAL);
+    }
+
+    return ret;
+}
+
 static int ffserver_parse_config_stream(FFServerConfig *config, const char *cmd, const char **p,
                                         int line_num, FFServerStream **pstream)
 {
@@ -528,14 +674,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;
@@ -587,23 +731,20 @@ static int ffserver_parse_config_stream(FFServerConfig *config, const char *cmd,
                !av_strcasecmp(cmd, "Copyright") ||
                !av_strcasecmp(cmd, "Title")) {
         char key[32];
-        int i, ret;
+        int i;
         ffserver_get_arg(arg, sizeof(arg), p);
         for (i = 0; i < strlen(cmd); i++)
             key[i] = av_tolower(cmd[i]);
         key[i] = 0;
         WARNING("'%s' option in configuration file is deprecated, "
                 "use 'Metadata %s VALUE' instead\n", cmd, key);
-        if ((ret = av_dict_set(&stream->metadata, key, arg, 0)) < 0)
-            ERROR("Could not set metadata '%s' to value '%s': %s\n", key, arg, av_err2str(ret));
+        if (av_dict_set(&stream->metadata, key, arg, 0) < 0)
+            goto nomem;
     } else if (!av_strcasecmp(cmd, "Metadata")) {
-        int ret;
         ffserver_get_arg(arg, sizeof(arg), p);
         ffserver_get_arg(arg2, sizeof(arg2), p);
-        if ((ret = av_dict_set(&stream->metadata, arg, arg2, 0)) < 0) {
-            ERROR("Could not set metadata '%s' to value '%s': %s\n",
-                  arg, arg2, av_err2str(ret));
-        }
+        if (av_dict_set(&stream->metadata, arg, arg2, 0) < 0)
+            goto nomem;
     } else if (!av_strcasecmp(cmd, "Preroll")) {
         ffserver_get_arg(arg, sizeof(arg), p);
         stream->prebuffer = atof(arg) * 1000;
@@ -624,136 +765,166 @@ 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);
+        float f;
+        ffserver_set_float_param(&f, arg, 1000, 0, FLT_MAX, config, line_num, "Invalid %s: %s\n", cmd, arg);
+        if (av_dict_set_int(&config->audio_conf, cmd, lrintf(f), 0) < 0)
+            goto nomem;
     } else if (!av_strcasecmp(cmd, "AudioChannels")) {
         ffserver_get_arg(arg, sizeof(arg), p);
-        config->audio_enc.channels = atoi(arg);
+        ffserver_set_int_param(NULL, arg, 0, 1, 8, config, line_num, "Invalid %s: %s, valid range is 1-8.", cmd, arg);
+        if (av_dict_set(&config->audio_conf, cmd, arg, 0) < 0)
+            goto nomem;
     } else if (!av_strcasecmp(cmd, "AudioSampleRate")) {
         ffserver_get_arg(arg, sizeof(arg), p);
-        config->audio_enc.sample_rate = atoi(arg);
+        ffserver_set_int_param(NULL, arg, 0, 0, INT_MAX, config, line_num, "Invalid %s: %s", cmd, arg);
+        if (av_dict_set(&config->audio_conf, cmd, arg, 0) < 0)
+            goto nomem;
     } 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;
+            if (av_dict_set_int(&config->video_conf, "VideoBitRateRangeMin", minrate, 0) < 0 ||
+                av_dict_set_int(&config->video_conf, "VideoBitRateRangeMax", maxrate, 0) < 0)
+                goto nomem;
         } 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);
+        ffserver_set_int_param(NULL, arg, 0, INT_MIN, INT_MAX, config, line_num, "Invalid %s: %s", cmd, arg);
+        if (av_dict_set(&config->video_conf, cmd, arg, 0) < 0)
+            goto nomem;
     } else if (!av_strcasecmp(cmd, "Strict")) {
         ffserver_get_arg(arg, sizeof(arg), p);
-        config->video_enc.strict_std_compliance = atoi(arg);
+        ffserver_set_int_param(NULL, arg, 0, INT_MIN, INT_MAX, config, line_num, "Invalid %s: %s", cmd, arg);
+        if (av_dict_set(&config->video_conf, cmd, arg, 0) < 0)
+            goto nomem;
     } else if (!av_strcasecmp(cmd, "VideoBufferSize")) {
         ffserver_get_arg(arg, sizeof(arg), p);
-        config->video_enc.rc_buffer_size = atoi(arg) * 8*1024;
+        ffserver_set_int_param(NULL, arg, 8*1024, 0, INT_MAX, config, line_num, "Invalid %s: %s", cmd, arg);
+        if (av_dict_set(&config->video_conf, cmd, arg, 0) < 0)
+            goto nomem;
     } else if (!av_strcasecmp(cmd, "VideoBitRateTolerance")) {
         ffserver_get_arg(arg, sizeof(arg), p);
-        config->video_enc.bit_rate_tolerance = atoi(arg) * 1000;
+        ffserver_set_int_param(NULL, arg, 1000, INT_MIN, INT_MAX, config, line_num, "Invalid %s: %s", cmd, arg);
+        if (av_dict_set(&config->video_conf, cmd, arg, 0) < 0)
+            goto nomem;
     } else if (!av_strcasecmp(cmd, "VideoBitRate")) {
         ffserver_get_arg(arg, sizeof(arg), p);
-        config->video_enc.bit_rate = atoi(arg) * 1000;
+        ffserver_set_int_param(NULL, arg, 1000, 0, INT_MAX, config, line_num, "Invalid %s: %s", cmd, arg);
+        if (av_dict_set(&config->video_conf, cmd, arg, 0) < 0)
+           goto nomem;
     } 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");
+        if (av_dict_set_int(&config->video_conf, "VideoSizeWidth", w, 0) < 0 ||
+            av_dict_set_int(&config->video_conf, "VideoSizeHeight", h, 0) < 0)
+            goto nomem;
     } 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;
+            if (av_dict_set_int(&config->video_conf, "VideoFrameRateNum", frame_rate.num, 0) < 0 ||
+                av_dict_set_int(&config->video_conf, "VideoFrameRateDen", frame_rate.den, 0) < 0)
+                goto nomem;
         }
     } 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);
+        if (av_dict_set_int(&config->video_conf, cmd, pix_fmt, 0) < 0)
+            goto nomem;
     } else if (!av_strcasecmp(cmd, "VideoGopSize")) {
         ffserver_get_arg(arg, sizeof(arg), p);
-        config->video_enc.gop_size = atoi(arg);
+        ffserver_set_int_param(NULL, arg, 0, INT_MIN, INT_MAX, config, line_num, "Invalid %s: %s", cmd, arg);
+        if (av_dict_set(&config->video_conf, cmd, arg, 0) < 0)
+            goto nomem;
     } else if (!av_strcasecmp(cmd, "VideoIntraOnly")) {
-        config->video_enc.gop_size = 1;
+        if (av_dict_set(&config->video_conf, cmd, "1", 0) < 0)
+            goto nomem;
     } else if (!av_strcasecmp(cmd, "VideoHighQuality")) {
-        config->video_enc.mb_decision = FF_MB_DECISION_BITS;
+        if (av_dict_set(&config->video_conf, cmd, "", 0) < 0)
+            goto nomem;
     } else if (!av_strcasecmp(cmd, "Video4MotionVector")) {
-        config->video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
-        config->video_enc.flags |= CODEC_FLAG_4MV;
+        if (av_dict_set(&config->video_conf, cmd, "", 0) < 0)
+            goto nomem;
     } 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;
+        if (av_dict_set(dict, arg, arg2, 0) < 0)
+            goto nomem;
     } 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]);
+        if (strlen(arg) == 4) {
+            if (av_dict_set(&config->video_conf, "VideoTag", "arg", 0) < 0)
+                goto nomem;
+        }
     } else if (!av_strcasecmp(cmd, "BitExact")) {
-        config->video_enc.flags |= CODEC_FLAG_BITEXACT;
+        if (av_dict_set(&config->video_conf, cmd, "", 0) < 0)
+            goto nomem;
     } else if (!av_strcasecmp(cmd, "DctFastint")) {
-        config->video_enc.dct_algo  = FF_DCT_FASTINT;
+        if (av_dict_set(&config->video_conf, cmd, "", 0) < 0)
+            goto nomem;
     } else if (!av_strcasecmp(cmd, "IdctSimple")) {
-        config->video_enc.idct_algo = FF_IDCT_SIMPLE;
+        if (av_dict_set(&config->video_conf, cmd, "", 0) < 0)
+            goto nomem;
     } 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);
+        if (av_dict_set(&config->video_conf, cmd, arg, 0) < 0)
+            goto nomem;
     } 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");
+        ffserver_set_int_param(NULL, arg, 0, 1, 31, config, line_num, "%s out of range\n", cmd);
+        if (av_dict_set(&config->video_conf, cmd, arg, 0) < 0)
+            goto nomem;
     } 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");
+        ffserver_set_int_param(NULL, arg, 0, 1, 31, config, line_num, "%s out of range\n", cmd);
+        if (av_dict_set(&config->video_conf, cmd, arg, 0) < 0)
+            goto nomem;
     } 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");
+        ffserver_set_int_param(NULL, arg, 0, 1, 31, config, line_num, "%s out of range\n", cmd);
+        if (av_dict_set(&config->video_conf, cmd, arg, 0) < 0)
+            goto nomem;
     } else if (!av_strcasecmp(cmd, "LumiMask")) {
         ffserver_get_arg(arg, sizeof(arg), p);
-        config->video_enc.lumi_masking = atof(arg);
+        ffserver_set_float_param(NULL, arg, 0, -FLT_MAX, FLT_MAX, config, line_num, "Invalid %s: %s", cmd, arg);
+        if (av_dict_set(&config->video_conf, cmd, arg, 0) < 0)
+            goto nomem;
     } else if (!av_strcasecmp(cmd, "DarkMask")) {
         ffserver_get_arg(arg, sizeof(arg), p);
-        config->video_enc.dark_masking = atof(arg);
+        ffserver_set_float_param(NULL, arg, 0, -FLT_MAX, FLT_MAX, config, line_num, "Invalid %s: %s", cmd, arg);
+        if (av_dict_set(&config->video_conf, cmd, arg, 0) < 0)
+            goto nomem;
     } else if (!av_strcasecmp(cmd, "NoVideo")) {
         config->video_id = AV_CODEC_ID_NONE;
     } else if (!av_strcasecmp(cmd, "NoAudio")) {
@@ -783,16 +954,32 @@ 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("Could not apply preset '%s'\n", arg);
+                if (ffserver_apply_stream_config(audio_enc, config->audio_conf, &config->audio_opts) < 0)
+                    config->errors++;
+                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("Could not apply preset '%s'\n", arg);
+                if (ffserver_apply_stream_config(video_enc, config->video_conf, &config->video_opts) < 0)
+                    config->errors++;
+                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);
+        av_freep(&config->video_preset);
+        av_freep(&config->audio_preset);
         *pstream = NULL;
     } else if (!av_strcasecmp(cmd, "File") || !av_strcasecmp(cmd, "ReadOnlyFile")) {
         ffserver_get_arg(stream->feed_filename, sizeof(stream->feed_filename), p);
@@ -800,6 +987,15 @@ static int ffserver_parse_config_stream(FFServerConfig *config, const char *cmd,
         ERROR("Invalid entry '%s' inside <Stream></Stream>\n", cmd);
     }
     return 0;
+  nomem:
+    av_log(NULL, AV_LOG_ERROR, "Out of memory. Aborting.\n");
+    av_dict_free(&config->video_opts);
+    av_dict_free(&config->video_conf);
+    av_dict_free(&config->audio_opts);
+    av_dict_free(&config->audio_conf);
+    av_freep(&config->video_preset);
+    av_freep(&config->audio_preset);
+    return AVERROR(ENOMEM);
 }
 
 static int ffserver_parse_config_redirect(FFServerConfig *config, const char *cmd, const char **p,
diff --git a/ffserver_config.h b/ffserver_config.h
index 36d61d0..ac75b06 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;     /* AVOptions for video encoder */
+    AVDictionary *video_conf;     /* Values stored in video AVCodecContext.fields */
+    AVDictionary *audio_opts;     /* AVOptions for audio encoder */
+    AVDictionary *audio_conf;     /* Values stored in audio AVCodecContext.fields */
+    char *video_preset;
+    char *audio_preset;
 } FFServerConfig;
 
 void ffserver_get_arg(char *buf, int buf_size, const char **pp);



More information about the ffmpeg-cvslog mailing list