Browse code

ffserver_config: handle codec private options

This commit allows to set codec's private option.
As side effect, it also improves preset support.

Signed-off-by: Lukasz Marek <lukasz.m.luki2@gmail.com>

Lukasz Marek authored on 2014/11/11 07:21:34
Showing 4 changed files
... ...
@@ -12,6 +12,7 @@ version <next>:
12 12
 - UDP-Lite support (RFC 3828)
13 13
 - xBR scaling filter
14 14
 - AVFoundation screen capturing support
15
+- ffserver supports codec private options
15 16
 
16 17
 version 2.4:
17 18
 - Icecast protocol
... ...
@@ -589,8 +589,9 @@ Set sampling frequency for audio. When using low bitrates, you should
589 589
 lower this frequency to 22050 or 11025. The supported frequencies
590 590
 depend on the selected audio codec.
591 591
 
592
-@item AVOptionAudio @var{option} @var{value} (@emph{encoding,audio})
593
-Set generic option for audio stream.
592
+@item AVOptionAudio [@var{codec}:]@var{option} @var{value} (@emph{encoding,audio})
593
+Set generic or private option for audio stream.
594
+Private option must be prefixed with codec name or codec must be defined before.
594 595
 
595 596
 @item AVPresetAudio @var{preset} (@emph{encoding,audio})
596 597
 Set preset for audio stream.
... ...
@@ -667,8 +668,9 @@ Set video @option{qdiff} encoding option.
667 667
 @item DarkMask @var{float} (@emph{encoding,video})
668 668
 Set @option{lumi_mask}/@option{dark_mask} encoding options.
669 669
 
670
-@item AVOptionVideo @var{option} @var{value} (@emph{encoding,video})
671
-Set generic option for video stream.
670
+@item AVOptionVideo [@var{codec}:]@var{option} @var{value} (@emph{encoding,video})
671
+Set generic or private option for video stream.
672
+Private option must be prefixed with codec name or codec must be defined before.
672 673
 
673 674
 @item AVPresetVideo @var{preset} (@emph{encoding,video})
674 675
 Set preset for video stream.
... ...
@@ -31,6 +31,13 @@
31 31
 #include "cmdutils.h"
32 32
 #include "ffserver_config.h"
33 33
 
34
+static int ffserver_save_avoption(AVCodecContext *ctx, const char *opt, const char *arg,
35
+                                  AVDictionary **dict, int type, FFServerConfig *config, int line_num);
36
+static void vreport_config_error(const char *filename, int line_num, int log_level,
37
+                                 int *errors, const char *fmt, va_list vl);
38
+static void report_config_error(const char *filename, int line_num, int log_level,
39
+                                int *errors, const char *fmt, ...);
40
+
34 41
 /* FIXME: make ffserver work with IPv6 */
35 42
 /* resolve host with also IP address parsing */
36 43
 static int resolve_host(struct in_addr *sin_addr, const char *hostname)
... ...
@@ -246,40 +253,37 @@ static void add_codec(FFServerStream *stream, AVCodecContext *av)
246 246
     stream->streams[stream->nb_streams++] = st;
247 247
 }
248 248
 
249
-static enum AVCodecID opt_codec(const char *name, enum AVMediaType type)
250
-{
251
-    AVCodec *codec = avcodec_find_encoder_by_name(name);
252
-
253
-    if (!codec || codec->type != type)
254
-        return AV_CODEC_ID_NONE;
255
-    return codec->id;
256
-}
257
-
258
-static int ffserver_opt_default(const char *opt, const char *arg,
259
-                       AVCodecContext *avctx, int type)
249
+static int ffserver_set_codec(AVCodecContext *ctx, const char *codec_name, FFServerConfig *config, int line_num)
260 250
 {
261
-    int ret = 0;
262
-    const AVOption *o = av_opt_find(avctx, opt, NULL, type, 0);
263
-    if(o)
264
-        ret = av_opt_set(avctx, opt, arg, 0);
265
-    return ret;
251
+    int ret;
252
+    AVCodec *codec = avcodec_find_encoder_by_name(codec_name);
253
+    if (!codec || codec->type != ctx->codec_type) {
254
+        report_config_error(config->filename, line_num, AV_LOG_ERROR,
255
+                            &config->errors, "Invalid codec name: %s\n", codec_name);
256
+        return 0;
257
+    }
258
+    if (ctx->codec_id == AV_CODEC_ID_NONE && !ctx->priv_data) {
259
+        if ((ret = avcodec_get_context_defaults3(ctx, codec)) < 0)
260
+            return ret;
261
+        ctx->codec = codec;
262
+    }
263
+    if (ctx->codec_id != codec->id)
264
+        report_config_error(config->filename, line_num, AV_LOG_ERROR, &config->errors,
265
+                            "Inconsistent configuration: trying to set %s codec option, but %s codec is used previously\n",
266
+                            codec_name, avcodec_get_name(ctx->codec_id));
267
+    return 0;
266 268
 }
267 269
 
268
-static int ffserver_opt_preset(const char *arg,
269
-                       AVCodecContext *avctx, int type,
270
-                       enum AVCodecID *audio_id, enum AVCodecID *video_id)
270
+static int ffserver_opt_preset(const char *arg, AVCodecContext *avctx, FFServerConfig *config, int line_num)
271 271
 {
272 272
     FILE *f=NULL;
273 273
     char filename[1000], tmp[1000], tmp2[1000], line[1000];
274 274
     int ret = 0;
275
-    AVCodec *codec = NULL;
276
-
277
-    if (avctx)
278
-        codec = avcodec_find_encoder(avctx->codec_id);
275
+    AVCodec *codec = avcodec_find_encoder(avctx->codec_id);
279 276
 
280 277
     if (!(f = get_preset_file(filename, sizeof(filename), arg, 0,
281 278
                               codec ? codec->name : NULL))) {
282
-        fprintf(stderr, "File for preset '%s' not found\n", arg);
279
+        av_log(NULL, AV_LOG_ERROR, "File for preset '%s' not found\n", arg);
283 280
         return AVERROR(EINVAL);
284 281
     }
285 282
 
... ...
@@ -289,23 +293,42 @@ static int ffserver_opt_preset(const char *arg,
289 289
             continue;
290 290
         e|= sscanf(line, "%999[^=]=%999[^\n]\n", tmp, tmp2) - 2;
291 291
         if(e){
292
-            fprintf(stderr, "%s: Invalid syntax: '%s'\n", filename, line);
292
+            av_log(NULL, AV_LOG_ERROR, "%s: Invalid syntax: '%s'\n", filename, line);
293 293
             ret = AVERROR(EINVAL);
294 294
             break;
295 295
         }
296
-        if (audio_id && !strcmp(tmp, "acodec")) {
297
-            *audio_id = opt_codec(tmp2, AVMEDIA_TYPE_AUDIO);
298
-        } else if (video_id && !strcmp(tmp, "vcodec")){
299
-            *video_id = opt_codec(tmp2, AVMEDIA_TYPE_VIDEO);
300
-        } else if(!strcmp(tmp, "scodec")) {
301
-            /* opt_subtitle_codec(tmp2); */
302
-        } else if (avctx && (ret = ffserver_opt_default(tmp, tmp2, avctx, type)) < 0) {
303
-            fprintf(stderr, "%s: Invalid option or argument: '%s', parsed as "
304
-                    "'%s' = '%s'\n", filename, line, tmp, tmp2);
296
+        if ((!strcmp(tmp, "acodec") && avctx->codec_type == AVMEDIA_TYPE_AUDIO) ||
297
+             !strcmp(tmp, "vcodec") && avctx->codec_type == AVMEDIA_TYPE_VIDEO)
298
+        {
299
+            if (ffserver_set_codec(avctx, tmp2, config, line_num) < 0)
300
+                break;
301
+        } else if (!strcmp(tmp, "scodec")) {
302
+            av_log(NULL, AV_LOG_ERROR, "Subtitles preset found.\n");
303
+            ret = AVERROR(EINVAL);
305 304
             break;
305
+        } else {
306
+            int type;
307
+            AVDictionary **opts;
308
+
309
+            switch(avctx->codec_type) {
310
+            case AVMEDIA_TYPE_AUDIO:
311
+                type = AV_OPT_FLAG_AUDIO_PARAM;
312
+                opts = &config->audio_opts;
313
+                break;
314
+            case AVMEDIA_TYPE_VIDEO:
315
+                type = AV_OPT_FLAG_VIDEO_PARAM;
316
+                opts = &config->video_opts;
317
+                break;
318
+            default:
319
+                ret = AVERROR(EINVAL);
320
+                goto exit;
321
+            }
322
+            if (ffserver_save_avoption(avctx, tmp, tmp2, opts, type, config, line_num) < 0)
323
+                break;
306 324
         }
307 325
     }
308 326
 
327
+  exit:
309 328
     fclose(f);
310 329
 
311 330
     return ret;
... ...
@@ -334,7 +357,8 @@ static void vreport_config_error(const char *filename, int line_num, int log_lev
334 334
 {
335 335
     av_log(NULL, log_level, "%s:%d: ", filename, line_num);
336 336
     av_vlog(NULL, log_level, fmt, vl);
337
-    (*errors)++;
337
+    if (errors)
338
+        (*errors)++;
338 339
 }
339 340
 
340 341
 static void report_config_error(const char *filename, int line_num, int log_level, int *errors, const char *fmt, ...)
... ...
@@ -406,27 +430,67 @@ static int ffserver_set_float_param(float *dest, const char *value, float factor
406 406
     return AVERROR(EINVAL);
407 407
 }
408 408
 
409
-static int ffserver_save_avoption(const char *opt, const char *arg, AVDictionary **dict,
409
+static int ffserver_save_avoption(AVCodecContext *ctx, const char *opt, const char *arg, AVDictionary **dict,
410 410
                                   int type, FFServerConfig *config, int line_num)
411 411
 {
412
+    static int hinted = 0;
412 413
     int ret = 0;
413 414
     AVDictionaryEntry *e;
414
-    const AVOption *o = av_opt_find(config->dummy_ctx, opt, NULL, type | AV_OPT_FLAG_ENCODING_PARAM, AV_OPT_SEARCH_CHILDREN);
415
+    const AVOption *o = NULL;
416
+    const char *option = NULL;
417
+    const char *codec_name = NULL;
418
+    char buff[1024];
419
+
420
+    if (strchr(opt, ':')) {
421
+        //explicit private option
422
+        snprintf(buff, sizeof(buff), "%s", opt);
423
+        codec_name = buff;
424
+        option = strchr(buff, ':');
425
+        buff[option - buff] = '\0';
426
+        option++;
427
+        if ((ret = ffserver_set_codec(ctx, codec_name, config, line_num)) < 0)
428
+            return ret;
429
+        if (!ctx->codec || !ctx->priv_data)
430
+            return -1;
431
+    } else {
432
+        option = opt;
433
+    }
434
+
435
+    o = av_opt_find(ctx, option, NULL, type | AV_OPT_FLAG_ENCODING_PARAM, AV_OPT_SEARCH_CHILDREN);
415 436
     if (!o) {
416 437
         report_config_error(config->filename, line_num, AV_LOG_ERROR,
417
-                &config->errors, "Option not found: %s\n", opt);
418
-    } else if ((ret = av_opt_set(config->dummy_ctx, opt, arg, AV_OPT_SEARCH_CHILDREN)) < 0) {
438
+                            &config->errors, "Option not found: %s\n", opt);
439
+        if (!hinted && ctx->codec_id == AV_CODEC_ID_NONE) {
440
+            enum AVCodecID id;
441
+            hinted = 1;
442
+            switch(ctx->codec_type) {
443
+            case AVMEDIA_TYPE_AUDIO:
444
+                id = config->guessed_audio_codec_id != AV_CODEC_ID_NONE ? config->guessed_audio_codec_id : AV_CODEC_ID_AAC;
445
+                break;
446
+            case AVMEDIA_TYPE_VIDEO:
447
+                id = config->guessed_video_codec_id != AV_CODEC_ID_NONE ? config->guessed_video_codec_id : AV_CODEC_ID_H264;
448
+                break;
449
+            default:
450
+                break;
451
+            }
452
+            report_config_error(config->filename, line_num, AV_LOG_ERROR, NULL,
453
+                                "If '%s' is a codec private option, then prefix it with codec name, "
454
+                                "for example '%s:%s %s' or define codec earlier.\n",
455
+                                opt, avcodec_get_name(id) ,opt, arg);
456
+
457
+        }
458
+    } else if ((ret = av_opt_set(ctx, option, arg, AV_OPT_SEARCH_CHILDREN)) < 0) {
419 459
         report_config_error(config->filename, line_num, AV_LOG_ERROR,
420 460
                 &config->errors, "Invalid value for option %s (%s): %s\n", opt,
421 461
                 arg, av_err2str(ret));
422
-    } else if ((e = av_dict_get(*dict, opt, NULL, 0))) {
462
+    } else if ((e = av_dict_get(*dict, option, NULL, 0))) {
423 463
         if ((o->type == AV_OPT_TYPE_FLAGS) && arg && (arg[0] == '+' || arg[0] == '-'))
424
-            return av_dict_set(dict, opt, arg, AV_DICT_APPEND);
464
+            return av_dict_set(dict, option, arg, AV_DICT_APPEND);
425 465
         report_config_error(config->filename, line_num, AV_LOG_ERROR,
426 466
                 &config->errors,
427 467
                 "Redeclaring value of the option %s, previous value: %s\n",
428 468
                 opt, e->value);
429
-    } else if (av_dict_set(dict, opt, arg, 0) < 0) {
469
+    } else if (av_dict_set(dict, option, arg, 0) < 0) {
430 470
         return AVERROR(ENOMEM);
431 471
     }
432 472
     return 0;
... ...
@@ -704,7 +768,11 @@ static void ffserver_apply_stream_config(AVCodecContext *enc, const AVDictionary
704 704
         ffserver_set_int_param(&enc->bit_rate, e->value, 0, INT_MIN, INT_MAX,
705 705
                 NULL, 0, NULL);
706 706
 
707
+    av_opt_set_dict2(enc->priv_data, opts, AV_OPT_SEARCH_CHILDREN);
707 708
     av_opt_set_dict2(enc, opts, AV_OPT_SEARCH_CHILDREN);
709
+
710
+    if (av_dict_count(*opts))
711
+        av_log(NULL, AV_LOG_ERROR, "Something went wrong, %d options not set!!!\n", av_dict_count(*opts));
708 712
 }
709 713
 
710 714
 static int ffserver_parse_config_stream(FFServerConfig *config, const char *cmd, const char **p,
... ...
@@ -723,11 +791,16 @@ static int ffserver_parse_config_stream(FFServerConfig *config, const char *cmd,
723 723
         stream = av_mallocz(sizeof(FFServerStream));
724 724
         if (!stream)
725 725
             return AVERROR(ENOMEM);
726
-        config->dummy_ctx = avcodec_alloc_context3(NULL);
727
-        if (!config->dummy_ctx) {
726
+        config->dummy_actx = avcodec_alloc_context3(NULL);
727
+        config->dummy_vctx = avcodec_alloc_context3(NULL);
728
+        if (!config->dummy_vctx || !config->dummy_actx) {
728 729
             av_free(stream);
730
+            avcodec_free_context(&config->dummy_vctx);
731
+            avcodec_free_context(&config->dummy_actx);
729 732
             return AVERROR(ENOMEM);
730 733
         }
734
+        config->dummy_actx->codec_type = AVMEDIA_TYPE_AUDIO;
735
+        config->dummy_vctx->codec_type = AVMEDIA_TYPE_VIDEO;
731 736
         ffserver_get_arg(stream->filename, sizeof(stream->filename), p);
732 737
         q = strrchr(stream->filename, '>');
733 738
         if (q)
... ...
@@ -740,11 +813,11 @@ static int ffserver_parse_config_stream(FFServerConfig *config, const char *cmd,
740 740
 
741 741
         stream->fmt = ffserver_guess_format(NULL, stream->filename, NULL);
742 742
         if (stream->fmt) {
743
-            config->audio_id = stream->fmt->audio_codec;
744
-            config->video_id = stream->fmt->video_codec;
743
+            config->guessed_audio_codec_id = stream->fmt->audio_codec;
744
+            config->guessed_video_codec_id = stream->fmt->video_codec;
745 745
         } else {
746
-            config->audio_id = AV_CODEC_ID_NONE;
747
-            config->video_id = AV_CODEC_ID_NONE;
746
+            config->guessed_audio_codec_id = AV_CODEC_ID_NONE;
747
+            config->guessed_video_codec_id = AV_CODEC_ID_NONE;
748 748
         }
749 749
         *pstream = stream;
750 750
         return 0;
... ...
@@ -779,8 +852,8 @@ static int ffserver_parse_config_stream(FFServerConfig *config, const char *cmd,
779 779
                 ERROR("Unknown Format: %s\n", arg);
780 780
         }
781 781
         if (stream->fmt) {
782
-            config->audio_id = stream->fmt->audio_codec;
783
-            config->video_id = stream->fmt->video_codec;
782
+            config->guessed_audio_codec_id = stream->fmt->audio_codec;
783
+            config->guessed_video_codec_id = stream->fmt->video_codec;
784 784
         }
785 785
     } else if (!av_strcasecmp(cmd, "InputFormat")) {
786 786
         ffserver_get_arg(arg, sizeof(arg), p);
... ...
@@ -819,14 +892,10 @@ static int ffserver_parse_config_stream(FFServerConfig *config, const char *cmd,
819 819
         stream->send_on_key = 1;
820 820
     } else if (!av_strcasecmp(cmd, "AudioCodec")) {
821 821
         ffserver_get_arg(arg, sizeof(arg), p);
822
-        config->audio_id = opt_codec(arg, AVMEDIA_TYPE_AUDIO);
823
-        if (config->audio_id == AV_CODEC_ID_NONE)
824
-            ERROR("Unknown AudioCodec: %s\n", arg);
822
+        ffserver_set_codec(config->dummy_actx, arg, config, line_num);
825 823
     } else if (!av_strcasecmp(cmd, "VideoCodec")) {
826 824
         ffserver_get_arg(arg, sizeof(arg), p);
827
-        config->video_id = opt_codec(arg, AVMEDIA_TYPE_VIDEO);
828
-        if (config->video_id == AV_CODEC_ID_NONE)
829
-            ERROR("Unknown VideoCodec: %s\n", arg);
825
+        ffserver_set_codec(config->dummy_vctx, arg, config, line_num);
830 826
     } else if (!av_strcasecmp(cmd, "MaxTime")) {
831 827
         ffserver_get_arg(arg, sizeof(arg), p);
832 828
         stream->max_time = atof(arg) * 1000;
... ...
@@ -939,9 +1008,11 @@ static int ffserver_parse_config_stream(FFServerConfig *config, const char *cmd,
939 939
         ffserver_get_arg(arg, sizeof(arg), p);
940 940
         ffserver_get_arg(arg2, sizeof(arg2), p);
941 941
         if (!av_strcasecmp(cmd, "AVOptionVideo"))
942
-            ret = ffserver_save_avoption(arg, arg2, &config->video_opts, AV_OPT_FLAG_VIDEO_PARAM ,config, line_num);
942
+            ret = ffserver_save_avoption(config->dummy_vctx, arg, arg2, &config->video_opts,
943
+                                         AV_OPT_FLAG_VIDEO_PARAM ,config, line_num);
943 944
         else
944
-            ret = ffserver_save_avoption(arg, arg2, &config->audio_opts, AV_OPT_FLAG_AUDIO_PARAM ,config, line_num);
945
+            ret = ffserver_save_avoption(config->dummy_actx, arg, arg2, &config->audio_opts,
946
+                                         AV_OPT_FLAG_AUDIO_PARAM ,config, line_num);
945 947
         if (ret < 0)
946 948
             goto nomem;
947 949
     } else if (!av_strcasecmp(cmd, "AVPresetVideo") ||
... ...
@@ -950,10 +1021,10 @@ static int ffserver_parse_config_stream(FFServerConfig *config, const char *cmd,
950 950
         ffserver_get_arg(arg, sizeof(arg), p);
951 951
         if (!av_strcasecmp(cmd, "AVPresetVideo")) {
952 952
             preset = &config->video_preset;
953
-            ffserver_opt_preset(arg, NULL, 0, NULL, &config->video_id);
953
+            ffserver_opt_preset(arg, config->dummy_vctx, config, line_num);
954 954
         } else {
955 955
             preset = &config->audio_preset;
956
-            ffserver_opt_preset(arg, NULL, 0, &config->audio_id, NULL);
956
+            ffserver_opt_preset(arg, config->dummy_actx, config, line_num);
957 957
         }
958 958
         *preset = av_strdup(arg);
959 959
         if (!preset)
... ...
@@ -1008,9 +1079,9 @@ static int ffserver_parse_config_stream(FFServerConfig *config, const char *cmd,
1008 1008
         if (av_dict_set(&config->video_conf, cmd, arg, 0) < 0)
1009 1009
             goto nomem;
1010 1010
     } else if (!av_strcasecmp(cmd, "NoVideo")) {
1011
-        config->video_id = AV_CODEC_ID_NONE;
1011
+        config->no_video = 1;
1012 1012
     } else if (!av_strcasecmp(cmd, "NoAudio")) {
1013
-        config->audio_id = AV_CODEC_ID_NONE;
1013
+        config->no_audio = 1;
1014 1014
     } else if (!av_strcasecmp(cmd, "ACL")) {
1015 1015
         ffserver_parse_acl_row(stream, NULL, NULL, *p, config->filename,
1016 1016
                 line_num);
... ...
@@ -1040,24 +1111,18 @@ static int ffserver_parse_config_stream(FFServerConfig *config, const char *cmd,
1040 1040
         stream->loop = 0;
1041 1041
     } else if (!av_strcasecmp(cmd, "</Stream>")) {
1042 1042
         if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm")) {
1043
-            if (config->audio_id != AV_CODEC_ID_NONE) {
1044
-                AVCodecContext *audio_enc = avcodec_alloc_context3(avcodec_find_encoder(config->audio_id));
1045
-                if (config->audio_preset &&
1046
-                    ffserver_opt_preset(arg, audio_enc, AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_ENCODING_PARAM,
1047
-                                        NULL, NULL) < 0)
1048
-                    ERROR("Could not apply preset '%s'\n", arg);
1049
-                ffserver_apply_stream_config(audio_enc, config->audio_conf,
1050
-                        &config->audio_opts);
1043
+            if (config->dummy_actx->codec_id == AV_CODEC_ID_NONE)
1044
+                config->dummy_actx->codec_id = config->guessed_audio_codec_id;
1045
+            if (!config->no_audio && config->dummy_actx->codec_id != AV_CODEC_ID_NONE) {
1046
+                AVCodecContext *audio_enc = avcodec_alloc_context3(avcodec_find_encoder(config->dummy_actx->codec_id));
1047
+                ffserver_apply_stream_config(audio_enc, config->audio_conf, &config->audio_opts);
1051 1048
                 add_codec(stream, audio_enc);
1052 1049
             }
1053
-            if (config->video_id != AV_CODEC_ID_NONE) {
1054
-                AVCodecContext *video_enc = avcodec_alloc_context3(avcodec_find_encoder(config->video_id));
1055
-                if (config->video_preset &&
1056
-                    ffserver_opt_preset(arg, video_enc, AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_ENCODING_PARAM,
1057
-                                        NULL, NULL) < 0)
1058
-                    ERROR("Could not apply preset '%s'\n", arg);
1059
-                ffserver_apply_stream_config(video_enc, config->video_conf,
1060
-                        &config->video_opts);
1050
+            if (config->dummy_vctx->codec_id == AV_CODEC_ID_NONE)
1051
+                config->dummy_vctx->codec_id = config->guessed_video_codec_id;
1052
+            if (!config->no_video && config->dummy_vctx->codec_id != AV_CODEC_ID_NONE) {
1053
+                AVCodecContext *video_enc = avcodec_alloc_context3(avcodec_find_encoder(config->dummy_vctx->codec_id));
1054
+                ffserver_apply_stream_config(video_enc, config->video_conf, &config->video_opts);
1061 1055
                 add_codec(stream, video_enc);
1062 1056
             }
1063 1057
         }
... ...
@@ -1067,7 +1132,8 @@ static int ffserver_parse_config_stream(FFServerConfig *config, const char *cmd,
1067 1067
         av_dict_free(&config->audio_conf);
1068 1068
         av_freep(&config->video_preset);
1069 1069
         av_freep(&config->audio_preset);
1070
-        avcodec_free_context(&config->dummy_ctx);
1070
+        avcodec_free_context(&config->dummy_vctx);
1071
+        avcodec_free_context(&config->dummy_actx);
1071 1072
         *pstream = NULL;
1072 1073
     } else if (!av_strcasecmp(cmd, "File") || !av_strcasecmp(cmd, "ReadOnlyFile")) {
1073 1074
         ffserver_get_arg(stream->feed_filename, sizeof(stream->feed_filename),
... ...
@@ -1084,7 +1150,8 @@ static int ffserver_parse_config_stream(FFServerConfig *config, const char *cmd,
1084 1084
     av_dict_free(&config->audio_conf);
1085 1085
     av_freep(&config->video_preset);
1086 1086
     av_freep(&config->audio_preset);
1087
-    avcodec_free_context(&config->dummy_ctx);
1087
+    avcodec_free_context(&config->dummy_vctx);
1088
+    avcodec_free_context(&config->dummy_actx);
1088 1089
     return AVERROR(ENOMEM);
1089 1090
 }
1090 1091
 
... ...
@@ -107,15 +107,18 @@ typedef struct FFServerConfig {
107 107
     int errors;
108 108
     int warnings;
109 109
     // Following variables MUST NOT be used outside configuration parsing code.
110
-    enum AVCodecID audio_id;
111
-    enum AVCodecID video_id;
110
+    enum AVCodecID guessed_audio_codec_id;
111
+    enum AVCodecID guessed_video_codec_id;
112 112
     AVDictionary *video_opts;     /* AVOptions for video encoder */
113 113
     AVDictionary *video_conf;     /* Values stored in video AVCodecContext.fields */
114 114
     AVDictionary *audio_opts;     /* AVOptions for audio encoder */
115 115
     AVDictionary *audio_conf;     /* Values stored in audio AVCodecContext.fields */
116 116
     char *video_preset;
117 117
     char *audio_preset;
118
-    AVCodecContext *dummy_ctx;    /* Used internally to test AVOptions. Not to be used anywhere else */
118
+    AVCodecContext *dummy_actx;   /* Used internally to test audio AVOptions. */
119
+    AVCodecContext *dummy_vctx;   /* Used internally to test video AVOptions. */
120
+    int no_audio;
121
+    int no_video;
119 122
 } FFServerConfig;
120 123
 
121 124
 void ffserver_get_arg(char *buf, int buf_size, const char **pp);