[FFmpeg-devel] [PATCH 4/4] ffserver_config: postpone codec context creation

Lukasz Marek lukasz.m.luki2 at gmail.com
Mon Oct 20 23:57:02 CEST 2014


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);                          \
+        }                                                   \
+    }
+#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);
+    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);
+
+    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");
+        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);
+                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;
 } FFServerConfig;
 
 void ffserver_get_arg(char *buf, int buf_size, const char **pp);
-- 
1.9.1



More information about the ffmpeg-devel mailing list