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>
This commit is contained in:
Lukasz Marek 2014-11-10 23:21:34 +01:00
parent 2657f00d3f
commit a38e06c1aa
4 changed files with 160 additions and 87 deletions

View File

@ -12,6 +12,7 @@ version <next>:
- UDP-Lite support (RFC 3828) - UDP-Lite support (RFC 3828)
- xBR scaling filter - xBR scaling filter
- AVFoundation screen capturing support - AVFoundation screen capturing support
- ffserver supports codec private options
version 2.4: version 2.4:
- Icecast protocol - Icecast protocol

View File

@ -589,8 +589,9 @@ Set sampling frequency for audio. When using low bitrates, you should
lower this frequency to 22050 or 11025. The supported frequencies lower this frequency to 22050 or 11025. The supported frequencies
depend on the selected audio codec. depend on the selected audio codec.
@item AVOptionAudio @var{option} @var{value} (@emph{encoding,audio}) @item AVOptionAudio [@var{codec}:]@var{option} @var{value} (@emph{encoding,audio})
Set generic option for audio stream. Set generic or private option for audio stream.
Private option must be prefixed with codec name or codec must be defined before.
@item AVPresetAudio @var{preset} (@emph{encoding,audio}) @item AVPresetAudio @var{preset} (@emph{encoding,audio})
Set preset for audio stream. Set preset for audio stream.
@ -667,8 +668,9 @@ Set video @option{qdiff} encoding option.
@item DarkMask @var{float} (@emph{encoding,video}) @item DarkMask @var{float} (@emph{encoding,video})
Set @option{lumi_mask}/@option{dark_mask} encoding options. Set @option{lumi_mask}/@option{dark_mask} encoding options.
@item AVOptionVideo @var{option} @var{value} (@emph{encoding,video}) @item AVOptionVideo [@var{codec}:]@var{option} @var{value} (@emph{encoding,video})
Set generic option for video stream. Set generic or private option for video stream.
Private option must be prefixed with codec name or codec must be defined before.
@item AVPresetVideo @var{preset} (@emph{encoding,video}) @item AVPresetVideo @var{preset} (@emph{encoding,video})
Set preset for video stream. Set preset for video stream.

View File

@ -31,6 +31,13 @@
#include "cmdutils.h" #include "cmdutils.h"
#include "ffserver_config.h" #include "ffserver_config.h"
static int ffserver_save_avoption(AVCodecContext *ctx, const char *opt, const char *arg,
AVDictionary **dict, int type, FFServerConfig *config, int line_num);
static void vreport_config_error(const char *filename, int line_num, int log_level,
int *errors, const char *fmt, va_list vl);
static void report_config_error(const char *filename, int line_num, int log_level,
int *errors, const char *fmt, ...);
/* FIXME: make ffserver work with IPv6 */ /* FIXME: make ffserver work with IPv6 */
/* resolve host with also IP address parsing */ /* resolve host with also IP address parsing */
static int resolve_host(struct in_addr *sin_addr, const char *hostname) static int resolve_host(struct in_addr *sin_addr, const char *hostname)
@ -246,40 +253,37 @@ static void add_codec(FFServerStream *stream, AVCodecContext *av)
stream->streams[stream->nb_streams++] = st; stream->streams[stream->nb_streams++] = st;
} }
static enum AVCodecID opt_codec(const char *name, enum AVMediaType type) static int ffserver_set_codec(AVCodecContext *ctx, const char *codec_name, FFServerConfig *config, int line_num)
{ {
AVCodec *codec = avcodec_find_encoder_by_name(name); int ret;
AVCodec *codec = avcodec_find_encoder_by_name(codec_name);
if (!codec || codec->type != type) if (!codec || codec->type != ctx->codec_type) {
return AV_CODEC_ID_NONE; report_config_error(config->filename, line_num, AV_LOG_ERROR,
return codec->id; &config->errors, "Invalid codec name: %s\n", codec_name);
return 0;
}
if (ctx->codec_id == AV_CODEC_ID_NONE && !ctx->priv_data) {
if ((ret = avcodec_get_context_defaults3(ctx, codec)) < 0)
return ret;
ctx->codec = codec;
}
if (ctx->codec_id != codec->id)
report_config_error(config->filename, line_num, AV_LOG_ERROR, &config->errors,
"Inconsistent configuration: trying to set %s codec option, but %s codec is used previously\n",
codec_name, avcodec_get_name(ctx->codec_id));
return 0;
} }
static int ffserver_opt_default(const char *opt, const char *arg, static int ffserver_opt_preset(const char *arg, AVCodecContext *avctx, FFServerConfig *config, int line_num)
AVCodecContext *avctx, int type)
{
int ret = 0;
const AVOption *o = av_opt_find(avctx, opt, NULL, type, 0);
if(o)
ret = av_opt_set(avctx, opt, arg, 0);
return ret;
}
static int ffserver_opt_preset(const char *arg,
AVCodecContext *avctx, int type,
enum AVCodecID *audio_id, enum AVCodecID *video_id)
{ {
FILE *f=NULL; FILE *f=NULL;
char filename[1000], tmp[1000], tmp2[1000], line[1000]; char filename[1000], tmp[1000], tmp2[1000], line[1000];
int ret = 0; int ret = 0;
AVCodec *codec = NULL; AVCodec *codec = avcodec_find_encoder(avctx->codec_id);
if (avctx)
codec = avcodec_find_encoder(avctx->codec_id);
if (!(f = get_preset_file(filename, sizeof(filename), arg, 0, if (!(f = get_preset_file(filename, sizeof(filename), arg, 0,
codec ? codec->name : NULL))) { codec ? codec->name : NULL))) {
fprintf(stderr, "File for preset '%s' not found\n", arg); av_log(NULL, AV_LOG_ERROR, "File for preset '%s' not found\n", arg);
return AVERROR(EINVAL); return AVERROR(EINVAL);
} }
@ -289,23 +293,42 @@ static int ffserver_opt_preset(const char *arg,
continue; continue;
e|= sscanf(line, "%999[^=]=%999[^\n]\n", tmp, tmp2) - 2; e|= sscanf(line, "%999[^=]=%999[^\n]\n", tmp, tmp2) - 2;
if(e){ if(e){
fprintf(stderr, "%s: Invalid syntax: '%s'\n", filename, line); av_log(NULL, AV_LOG_ERROR, "%s: Invalid syntax: '%s'\n", filename, line);
ret = AVERROR(EINVAL); ret = AVERROR(EINVAL);
break; break;
} }
if (audio_id && !strcmp(tmp, "acodec")) { if ((!strcmp(tmp, "acodec") && avctx->codec_type == AVMEDIA_TYPE_AUDIO) ||
*audio_id = opt_codec(tmp2, AVMEDIA_TYPE_AUDIO); !strcmp(tmp, "vcodec") && avctx->codec_type == AVMEDIA_TYPE_VIDEO)
} else if (video_id && !strcmp(tmp, "vcodec")){ {
*video_id = opt_codec(tmp2, AVMEDIA_TYPE_VIDEO); if (ffserver_set_codec(avctx, tmp2, config, line_num) < 0)
} else if(!strcmp(tmp, "scodec")) { break;
/* opt_subtitle_codec(tmp2); */ } else if (!strcmp(tmp, "scodec")) {
} else if (avctx && (ret = ffserver_opt_default(tmp, tmp2, avctx, type)) < 0) { av_log(NULL, AV_LOG_ERROR, "Subtitles preset found.\n");
fprintf(stderr, "%s: Invalid option or argument: '%s', parsed as " ret = AVERROR(EINVAL);
"'%s' = '%s'\n", filename, line, tmp, tmp2);
break; break;
} else {
int type;
AVDictionary **opts;
switch(avctx->codec_type) {
case AVMEDIA_TYPE_AUDIO:
type = AV_OPT_FLAG_AUDIO_PARAM;
opts = &config->audio_opts;
break;
case AVMEDIA_TYPE_VIDEO:
type = AV_OPT_FLAG_VIDEO_PARAM;
opts = &config->video_opts;
break;
default:
ret = AVERROR(EINVAL);
goto exit;
}
if (ffserver_save_avoption(avctx, tmp, tmp2, opts, type, config, line_num) < 0)
break;
} }
} }
exit:
fclose(f); fclose(f);
return ret; return ret;
@ -334,7 +357,8 @@ static void vreport_config_error(const char *filename, int line_num, int log_lev
{ {
av_log(NULL, log_level, "%s:%d: ", filename, line_num); av_log(NULL, log_level, "%s:%d: ", filename, line_num);
av_vlog(NULL, log_level, fmt, vl); av_vlog(NULL, log_level, fmt, vl);
(*errors)++; if (errors)
(*errors)++;
} }
static void report_config_error(const char *filename, int line_num, int log_level, int *errors, const char *fmt, ...) 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
return AVERROR(EINVAL); return AVERROR(EINVAL);
} }
static int ffserver_save_avoption(const char *opt, const char *arg, AVDictionary **dict, static int ffserver_save_avoption(AVCodecContext *ctx, const char *opt, const char *arg, AVDictionary **dict,
int type, FFServerConfig *config, int line_num) int type, FFServerConfig *config, int line_num)
{ {
static int hinted = 0;
int ret = 0; int ret = 0;
AVDictionaryEntry *e; AVDictionaryEntry *e;
const AVOption *o = av_opt_find(config->dummy_ctx, opt, NULL, type | AV_OPT_FLAG_ENCODING_PARAM, AV_OPT_SEARCH_CHILDREN); const AVOption *o = NULL;
const char *option = NULL;
const char *codec_name = NULL;
char buff[1024];
if (strchr(opt, ':')) {
//explicit private option
snprintf(buff, sizeof(buff), "%s", opt);
codec_name = buff;
option = strchr(buff, ':');
buff[option - buff] = '\0';
option++;
if ((ret = ffserver_set_codec(ctx, codec_name, config, line_num)) < 0)
return ret;
if (!ctx->codec || !ctx->priv_data)
return -1;
} else {
option = opt;
}
o = av_opt_find(ctx, option, NULL, type | AV_OPT_FLAG_ENCODING_PARAM, AV_OPT_SEARCH_CHILDREN);
if (!o) { if (!o) {
report_config_error(config->filename, line_num, AV_LOG_ERROR, report_config_error(config->filename, line_num, AV_LOG_ERROR,
&config->errors, "Option not found: %s\n", opt); &config->errors, "Option not found: %s\n", opt);
} else if ((ret = av_opt_set(config->dummy_ctx, opt, arg, AV_OPT_SEARCH_CHILDREN)) < 0) { if (!hinted && ctx->codec_id == AV_CODEC_ID_NONE) {
enum AVCodecID id;
hinted = 1;
switch(ctx->codec_type) {
case AVMEDIA_TYPE_AUDIO:
id = config->guessed_audio_codec_id != AV_CODEC_ID_NONE ? config->guessed_audio_codec_id : AV_CODEC_ID_AAC;
break;
case AVMEDIA_TYPE_VIDEO:
id = config->guessed_video_codec_id != AV_CODEC_ID_NONE ? config->guessed_video_codec_id : AV_CODEC_ID_H264;
break;
default:
break;
}
report_config_error(config->filename, line_num, AV_LOG_ERROR, NULL,
"If '%s' is a codec private option, then prefix it with codec name, "
"for example '%s:%s %s' or define codec earlier.\n",
opt, avcodec_get_name(id) ,opt, arg);
}
} else if ((ret = av_opt_set(ctx, option, arg, AV_OPT_SEARCH_CHILDREN)) < 0) {
report_config_error(config->filename, line_num, AV_LOG_ERROR, report_config_error(config->filename, line_num, AV_LOG_ERROR,
&config->errors, "Invalid value for option %s (%s): %s\n", opt, &config->errors, "Invalid value for option %s (%s): %s\n", opt,
arg, av_err2str(ret)); arg, av_err2str(ret));
} else if ((e = av_dict_get(*dict, opt, NULL, 0))) { } else if ((e = av_dict_get(*dict, option, NULL, 0))) {
if ((o->type == AV_OPT_TYPE_FLAGS) && arg && (arg[0] == '+' || arg[0] == '-')) if ((o->type == AV_OPT_TYPE_FLAGS) && arg && (arg[0] == '+' || arg[0] == '-'))
return av_dict_set(dict, opt, arg, AV_DICT_APPEND); return av_dict_set(dict, option, arg, AV_DICT_APPEND);
report_config_error(config->filename, line_num, AV_LOG_ERROR, report_config_error(config->filename, line_num, AV_LOG_ERROR,
&config->errors, &config->errors,
"Redeclaring value of the option %s, previous value: %s\n", "Redeclaring value of the option %s, previous value: %s\n",
opt, e->value); opt, e->value);
} else if (av_dict_set(dict, opt, arg, 0) < 0) { } else if (av_dict_set(dict, option, arg, 0) < 0) {
return AVERROR(ENOMEM); return AVERROR(ENOMEM);
} }
return 0; return 0;
@ -704,7 +768,11 @@ static void ffserver_apply_stream_config(AVCodecContext *enc, const AVDictionary
ffserver_set_int_param(&enc->bit_rate, e->value, 0, INT_MIN, INT_MAX, ffserver_set_int_param(&enc->bit_rate, e->value, 0, INT_MIN, INT_MAX,
NULL, 0, NULL); NULL, 0, NULL);
av_opt_set_dict2(enc->priv_data, opts, AV_OPT_SEARCH_CHILDREN);
av_opt_set_dict2(enc, opts, AV_OPT_SEARCH_CHILDREN); av_opt_set_dict2(enc, opts, AV_OPT_SEARCH_CHILDREN);
if (av_dict_count(*opts))
av_log(NULL, AV_LOG_ERROR, "Something went wrong, %d options not set!!!\n", av_dict_count(*opts));
} }
static int ffserver_parse_config_stream(FFServerConfig *config, const char *cmd, const char **p, 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,
stream = av_mallocz(sizeof(FFServerStream)); stream = av_mallocz(sizeof(FFServerStream));
if (!stream) if (!stream)
return AVERROR(ENOMEM); return AVERROR(ENOMEM);
config->dummy_ctx = avcodec_alloc_context3(NULL); config->dummy_actx = avcodec_alloc_context3(NULL);
if (!config->dummy_ctx) { config->dummy_vctx = avcodec_alloc_context3(NULL);
if (!config->dummy_vctx || !config->dummy_actx) {
av_free(stream); av_free(stream);
avcodec_free_context(&config->dummy_vctx);
avcodec_free_context(&config->dummy_actx);
return AVERROR(ENOMEM); return AVERROR(ENOMEM);
} }
config->dummy_actx->codec_type = AVMEDIA_TYPE_AUDIO;
config->dummy_vctx->codec_type = AVMEDIA_TYPE_VIDEO;
ffserver_get_arg(stream->filename, sizeof(stream->filename), p); ffserver_get_arg(stream->filename, sizeof(stream->filename), p);
q = strrchr(stream->filename, '>'); q = strrchr(stream->filename, '>');
if (q) if (q)
@ -740,11 +813,11 @@ static int ffserver_parse_config_stream(FFServerConfig *config, const char *cmd,
stream->fmt = ffserver_guess_format(NULL, stream->filename, NULL); stream->fmt = ffserver_guess_format(NULL, stream->filename, NULL);
if (stream->fmt) { if (stream->fmt) {
config->audio_id = stream->fmt->audio_codec; config->guessed_audio_codec_id = stream->fmt->audio_codec;
config->video_id = stream->fmt->video_codec; config->guessed_video_codec_id = stream->fmt->video_codec;
} else { } else {
config->audio_id = AV_CODEC_ID_NONE; config->guessed_audio_codec_id = AV_CODEC_ID_NONE;
config->video_id = AV_CODEC_ID_NONE; config->guessed_video_codec_id = AV_CODEC_ID_NONE;
} }
*pstream = stream; *pstream = stream;
return 0; return 0;
@ -779,8 +852,8 @@ static int ffserver_parse_config_stream(FFServerConfig *config, const char *cmd,
ERROR("Unknown Format: %s\n", arg); ERROR("Unknown Format: %s\n", arg);
} }
if (stream->fmt) { if (stream->fmt) {
config->audio_id = stream->fmt->audio_codec; config->guessed_audio_codec_id = stream->fmt->audio_codec;
config->video_id = stream->fmt->video_codec; config->guessed_video_codec_id = stream->fmt->video_codec;
} }
} else if (!av_strcasecmp(cmd, "InputFormat")) { } else if (!av_strcasecmp(cmd, "InputFormat")) {
ffserver_get_arg(arg, sizeof(arg), p); ffserver_get_arg(arg, sizeof(arg), p);
@ -819,14 +892,10 @@ static int ffserver_parse_config_stream(FFServerConfig *config, const char *cmd,
stream->send_on_key = 1; stream->send_on_key = 1;
} else if (!av_strcasecmp(cmd, "AudioCodec")) { } else if (!av_strcasecmp(cmd, "AudioCodec")) {
ffserver_get_arg(arg, sizeof(arg), p); ffserver_get_arg(arg, sizeof(arg), p);
config->audio_id = opt_codec(arg, AVMEDIA_TYPE_AUDIO); ffserver_set_codec(config->dummy_actx, arg, config, line_num);
if (config->audio_id == AV_CODEC_ID_NONE)
ERROR("Unknown AudioCodec: %s\n", arg);
} else if (!av_strcasecmp(cmd, "VideoCodec")) { } else if (!av_strcasecmp(cmd, "VideoCodec")) {
ffserver_get_arg(arg, sizeof(arg), p); ffserver_get_arg(arg, sizeof(arg), p);
config->video_id = opt_codec(arg, AVMEDIA_TYPE_VIDEO); ffserver_set_codec(config->dummy_vctx, arg, config, line_num);
if (config->video_id == AV_CODEC_ID_NONE)
ERROR("Unknown VideoCodec: %s\n", arg);
} else if (!av_strcasecmp(cmd, "MaxTime")) { } else if (!av_strcasecmp(cmd, "MaxTime")) {
ffserver_get_arg(arg, sizeof(arg), p); ffserver_get_arg(arg, sizeof(arg), p);
stream->max_time = atof(arg) * 1000; stream->max_time = atof(arg) * 1000;
@ -939,9 +1008,11 @@ static int ffserver_parse_config_stream(FFServerConfig *config, const char *cmd,
ffserver_get_arg(arg, sizeof(arg), p); ffserver_get_arg(arg, sizeof(arg), p);
ffserver_get_arg(arg2, sizeof(arg2), p); ffserver_get_arg(arg2, sizeof(arg2), p);
if (!av_strcasecmp(cmd, "AVOptionVideo")) if (!av_strcasecmp(cmd, "AVOptionVideo"))
ret = ffserver_save_avoption(arg, arg2, &config->video_opts, AV_OPT_FLAG_VIDEO_PARAM ,config, line_num); ret = ffserver_save_avoption(config->dummy_vctx, arg, arg2, &config->video_opts,
AV_OPT_FLAG_VIDEO_PARAM ,config, line_num);
else else
ret = ffserver_save_avoption(arg, arg2, &config->audio_opts, AV_OPT_FLAG_AUDIO_PARAM ,config, line_num); ret = ffserver_save_avoption(config->dummy_actx, arg, arg2, &config->audio_opts,
AV_OPT_FLAG_AUDIO_PARAM ,config, line_num);
if (ret < 0) if (ret < 0)
goto nomem; goto nomem;
} else if (!av_strcasecmp(cmd, "AVPresetVideo") || } else if (!av_strcasecmp(cmd, "AVPresetVideo") ||
@ -950,10 +1021,10 @@ static int ffserver_parse_config_stream(FFServerConfig *config, const char *cmd,
ffserver_get_arg(arg, sizeof(arg), p); ffserver_get_arg(arg, sizeof(arg), p);
if (!av_strcasecmp(cmd, "AVPresetVideo")) { if (!av_strcasecmp(cmd, "AVPresetVideo")) {
preset = &config->video_preset; preset = &config->video_preset;
ffserver_opt_preset(arg, NULL, 0, NULL, &config->video_id); ffserver_opt_preset(arg, config->dummy_vctx, config, line_num);
} else { } else {
preset = &config->audio_preset; preset = &config->audio_preset;
ffserver_opt_preset(arg, NULL, 0, &config->audio_id, NULL); ffserver_opt_preset(arg, config->dummy_actx, config, line_num);
} }
*preset = av_strdup(arg); *preset = av_strdup(arg);
if (!preset) if (!preset)
@ -1008,9 +1079,9 @@ static int ffserver_parse_config_stream(FFServerConfig *config, const char *cmd,
if (av_dict_set(&config->video_conf, cmd, arg, 0) < 0) if (av_dict_set(&config->video_conf, cmd, arg, 0) < 0)
goto nomem; goto nomem;
} else if (!av_strcasecmp(cmd, "NoVideo")) { } else if (!av_strcasecmp(cmd, "NoVideo")) {
config->video_id = AV_CODEC_ID_NONE; config->no_video = 1;
} else if (!av_strcasecmp(cmd, "NoAudio")) { } else if (!av_strcasecmp(cmd, "NoAudio")) {
config->audio_id = AV_CODEC_ID_NONE; config->no_audio = 1;
} else if (!av_strcasecmp(cmd, "ACL")) { } else if (!av_strcasecmp(cmd, "ACL")) {
ffserver_parse_acl_row(stream, NULL, NULL, *p, config->filename, ffserver_parse_acl_row(stream, NULL, NULL, *p, config->filename,
line_num); line_num);
@ -1040,24 +1111,18 @@ static int ffserver_parse_config_stream(FFServerConfig *config, const char *cmd,
stream->loop = 0; stream->loop = 0;
} else if (!av_strcasecmp(cmd, "</Stream>")) { } else if (!av_strcasecmp(cmd, "</Stream>")) {
if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm")) { if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm")) {
if (config->audio_id != AV_CODEC_ID_NONE) { if (config->dummy_actx->codec_id == AV_CODEC_ID_NONE)
AVCodecContext *audio_enc = avcodec_alloc_context3(avcodec_find_encoder(config->audio_id)); config->dummy_actx->codec_id = config->guessed_audio_codec_id;
if (config->audio_preset && if (!config->no_audio && config->dummy_actx->codec_id != AV_CODEC_ID_NONE) {
ffserver_opt_preset(arg, audio_enc, AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_ENCODING_PARAM, AVCodecContext *audio_enc = avcodec_alloc_context3(avcodec_find_encoder(config->dummy_actx->codec_id));
NULL, NULL) < 0) ffserver_apply_stream_config(audio_enc, config->audio_conf, &config->audio_opts);
ERROR("Could not apply preset '%s'\n", arg);
ffserver_apply_stream_config(audio_enc, config->audio_conf,
&config->audio_opts);
add_codec(stream, audio_enc); add_codec(stream, audio_enc);
} }
if (config->video_id != AV_CODEC_ID_NONE) { if (config->dummy_vctx->codec_id == AV_CODEC_ID_NONE)
AVCodecContext *video_enc = avcodec_alloc_context3(avcodec_find_encoder(config->video_id)); config->dummy_vctx->codec_id = config->guessed_video_codec_id;
if (config->video_preset && if (!config->no_video && config->dummy_vctx->codec_id != AV_CODEC_ID_NONE) {
ffserver_opt_preset(arg, video_enc, AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_ENCODING_PARAM, AVCodecContext *video_enc = avcodec_alloc_context3(avcodec_find_encoder(config->dummy_vctx->codec_id));
NULL, NULL) < 0) ffserver_apply_stream_config(video_enc, config->video_conf, &config->video_opts);
ERROR("Could not apply preset '%s'\n", arg);
ffserver_apply_stream_config(video_enc, config->video_conf,
&config->video_opts);
add_codec(stream, video_enc); add_codec(stream, video_enc);
} }
} }
@ -1067,7 +1132,8 @@ static int ffserver_parse_config_stream(FFServerConfig *config, const char *cmd,
av_dict_free(&config->audio_conf); av_dict_free(&config->audio_conf);
av_freep(&config->video_preset); av_freep(&config->video_preset);
av_freep(&config->audio_preset); av_freep(&config->audio_preset);
avcodec_free_context(&config->dummy_ctx); avcodec_free_context(&config->dummy_vctx);
avcodec_free_context(&config->dummy_actx);
*pstream = NULL; *pstream = NULL;
} else if (!av_strcasecmp(cmd, "File") || !av_strcasecmp(cmd, "ReadOnlyFile")) { } else if (!av_strcasecmp(cmd, "File") || !av_strcasecmp(cmd, "ReadOnlyFile")) {
ffserver_get_arg(stream->feed_filename, sizeof(stream->feed_filename), 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,
av_dict_free(&config->audio_conf); av_dict_free(&config->audio_conf);
av_freep(&config->video_preset); av_freep(&config->video_preset);
av_freep(&config->audio_preset); av_freep(&config->audio_preset);
avcodec_free_context(&config->dummy_ctx); avcodec_free_context(&config->dummy_vctx);
avcodec_free_context(&config->dummy_actx);
return AVERROR(ENOMEM); return AVERROR(ENOMEM);
} }

View File

@ -107,15 +107,18 @@ typedef struct FFServerConfig {
int errors; int errors;
int warnings; int warnings;
// Following variables MUST NOT be used outside configuration parsing code. // Following variables MUST NOT be used outside configuration parsing code.
enum AVCodecID audio_id; enum AVCodecID guessed_audio_codec_id;
enum AVCodecID video_id; enum AVCodecID guessed_video_codec_id;
AVDictionary *video_opts; /* AVOptions for video encoder */ AVDictionary *video_opts; /* AVOptions for video encoder */
AVDictionary *video_conf; /* Values stored in video AVCodecContext.fields */ AVDictionary *video_conf; /* Values stored in video AVCodecContext.fields */
AVDictionary *audio_opts; /* AVOptions for audio encoder */ AVDictionary *audio_opts; /* AVOptions for audio encoder */
AVDictionary *audio_conf; /* Values stored in audio AVCodecContext.fields */ AVDictionary *audio_conf; /* Values stored in audio AVCodecContext.fields */
char *video_preset; char *video_preset;
char *audio_preset; char *audio_preset;
AVCodecContext *dummy_ctx; /* Used internally to test AVOptions. Not to be used anywhere else */ AVCodecContext *dummy_actx; /* Used internally to test audio AVOptions. */
AVCodecContext *dummy_vctx; /* Used internally to test video AVOptions. */
int no_audio;
int no_video;
} FFServerConfig; } FFServerConfig;
void ffserver_get_arg(char *buf, int buf_size, const char **pp); void ffserver_get_arg(char *buf, int buf_size, const char **pp);