Newer
Older
ffserver_get_arg(arg, sizeof(arg), p);
pix_fmt = av_get_pix_fmt(arg);
if (pix_fmt == AV_PIX_FMT_NONE)
ERROR("Unknown pixel format: '%s'\n", arg);
else if (ffserver_save_avoption("pixel_format", arg, AV_OPT_FLAG_VIDEO_PARAM, config) < 0)
} else if (!av_strcasecmp(cmd, "VideoGopSize")) {
ffserver_get_arg(arg, sizeof(arg), p);
if (ffserver_save_avoption("g", arg, AV_OPT_FLAG_VIDEO_PARAM, config) < 0)
} else if (!av_strcasecmp(cmd, "VideoIntraOnly")) {
if (ffserver_save_avoption("g", "1", AV_OPT_FLAG_VIDEO_PARAM, config) < 0)
} else if (!av_strcasecmp(cmd, "VideoHighQuality")) {
if (ffserver_save_avoption("mbd", "+bits", AV_OPT_FLAG_VIDEO_PARAM, config) < 0)
} else if (!av_strcasecmp(cmd, "Video4MotionVector")) {
if (ffserver_save_avoption("mbd", "+bits", AV_OPT_FLAG_VIDEO_PARAM, config) < 0 || //FIXME remove
ffserver_save_avoption("flags", "+mv4", AV_OPT_FLAG_VIDEO_PARAM, config) < 0)
} else if (!av_strcasecmp(cmd, "AVOptionVideo") ||
!av_strcasecmp(cmd, "AVOptionAudio")) {
ffserver_get_arg(arg, sizeof(arg), p);
ffserver_get_arg(arg2, sizeof(arg2), p);
if (!av_strcasecmp(cmd, "AVOptionVideo"))
ret = ffserver_save_avoption(arg, arg2, AV_OPT_FLAG_VIDEO_PARAM,
config);
ret = ffserver_save_avoption(arg, arg2, AV_OPT_FLAG_AUDIO_PARAM,
config);
} else if (!av_strcasecmp(cmd, "AVPresetVideo") ||
!av_strcasecmp(cmd, "AVPresetAudio")) {
ffserver_get_arg(arg, sizeof(arg), p);
if (!av_strcasecmp(cmd, "AVPresetVideo"))
ffserver_opt_preset(arg, AV_OPT_FLAG_VIDEO_PARAM, config);
ffserver_opt_preset(arg, AV_OPT_FLAG_AUDIO_PARAM, config);
} else if (!av_strcasecmp(cmd, "VideoTag")) {
ffserver_get_arg(arg, sizeof(arg), p);
if (strlen(arg) == 4 &&
ffserver_save_avoption_int("codec_tag",
MKTAG(arg[0], arg[1], arg[2], arg[3]),
AV_OPT_FLAG_VIDEO_PARAM, config) < 0)
goto nomem;
} else if (!av_strcasecmp(cmd, "BitExact")) {
if (ffserver_save_avoption("flags", "+bitexact", AV_OPT_FLAG_VIDEO_PARAM, config) < 0)
} else if (!av_strcasecmp(cmd, "DctFastint")) {
if (ffserver_save_avoption("dct", "fastint", AV_OPT_FLAG_VIDEO_PARAM, config) < 0)
} else if (!av_strcasecmp(cmd, "IdctSimple")) {
if (ffserver_save_avoption("idct", "simple", AV_OPT_FLAG_VIDEO_PARAM, config) < 0)
} else if (!av_strcasecmp(cmd, "Qscale")) {
ffserver_get_arg(arg, sizeof(arg), p);
ffserver_set_int_param(&val, arg, 0, INT_MIN, INT_MAX, config,
"Invalid Qscale: '%s'\n", arg);
if (ffserver_save_avoption("flags", "+qscale", AV_OPT_FLAG_VIDEO_PARAM, config) < 0 ||
ffserver_save_avoption_int("global_quality", FF_QP2LAMBDA * val,
AV_OPT_FLAG_VIDEO_PARAM, config) < 0)
} else if (!av_strcasecmp(cmd, "VideoQDiff")) {
ffserver_get_arg(arg, sizeof(arg), p);
if (ffserver_save_avoption("qdiff", arg, AV_OPT_FLAG_VIDEO_PARAM, config) < 0)
} else if (!av_strcasecmp(cmd, "VideoQMax")) {
ffserver_get_arg(arg, sizeof(arg), p);
if (ffserver_save_avoption("qmax", arg, AV_OPT_FLAG_VIDEO_PARAM, config) < 0)
} else if (!av_strcasecmp(cmd, "VideoQMin")) {
ffserver_get_arg(arg, sizeof(arg), p);
if (ffserver_save_avoption("qmin", arg, AV_OPT_FLAG_VIDEO_PARAM, config) < 0)
} else if (!av_strcasecmp(cmd, "LumiMask")) {
ffserver_get_arg(arg, sizeof(arg), p);
if (ffserver_save_avoption("lumi_mask", arg, AV_OPT_FLAG_VIDEO_PARAM, config) < 0)
} else if (!av_strcasecmp(cmd, "DarkMask")) {
ffserver_get_arg(arg, sizeof(arg), p);
if (ffserver_save_avoption("dark_mask", arg, AV_OPT_FLAG_VIDEO_PARAM, config) < 0)
} else if (!av_strcasecmp(cmd, "NoVideo")) {
} else if (!av_strcasecmp(cmd, "NoAudio")) {
} else if (!av_strcasecmp(cmd, "ACL")) {
ffserver_parse_acl_row(stream, NULL, NULL, *p, config->filename,
config->line_num);
} else if (!av_strcasecmp(cmd, "DynamicACL")) {
ffserver_get_arg(stream->dynamic_acl, sizeof(stream->dynamic_acl), p);
} else if (!av_strcasecmp(cmd, "RTSPOption")) {
ffserver_get_arg(arg, sizeof(arg), p);
av_freep(&stream->rtsp_option);
stream->rtsp_option = av_strdup(arg);
} else if (!av_strcasecmp(cmd, "MulticastAddress")) {
ffserver_get_arg(arg, sizeof(arg), p);
if (resolve_host(&stream->multicast_ip, arg))
ERROR("Invalid host/IP address: '%s'\n", arg);
stream->is_multicast = 1;
stream->loop = 1; /* default is looping */
} else if (!av_strcasecmp(cmd, "MulticastPort")) {
ffserver_get_arg(arg, sizeof(arg), p);
ffserver_set_int_param(&val, arg, 0, 1, 65535, config,
"Invalid MulticastPort: '%s'\n", arg);
} else if (!av_strcasecmp(cmd, "MulticastTTL")) {
ffserver_get_arg(arg, sizeof(arg), p);
ffserver_set_int_param(&val, arg, 0, INT_MIN, INT_MAX, config,
"Invalid MulticastTTL: '%s'\n", arg);
} else if (!av_strcasecmp(cmd, "NoLoop")) {
stream->loop = 0;
} else if (!av_strcasecmp(cmd, "</Stream>")) {
if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm")) {
if (config->dummy_actx->codec_id == AV_CODEC_ID_NONE)
config->dummy_actx->codec_id = config->guessed_audio_codec_id;
if (!config->no_audio &&
config->dummy_actx->codec_id != AV_CODEC_ID_NONE) {
AVCodecContext *audio_enc = avcodec_alloc_context3(avcodec_find_encoder(config->dummy_actx->codec_id));
add_codec(stream, audio_enc, config);
if (config->dummy_vctx->codec_id == AV_CODEC_ID_NONE)
config->dummy_vctx->codec_id = config->guessed_video_codec_id;
if (!config->no_video &&
config->dummy_vctx->codec_id != AV_CODEC_ID_NONE) {
AVCodecContext *video_enc = avcodec_alloc_context3(avcodec_find_encoder(config->dummy_vctx->codec_id));
add_codec(stream, video_enc, config);
av_dict_free(&config->video_opts);
av_dict_free(&config->audio_opts);
avcodec_free_context(&config->dummy_vctx);
avcodec_free_context(&config->dummy_actx);
} else if (!av_strcasecmp(cmd, "File") ||
!av_strcasecmp(cmd, "ReadOnlyFile")) {
ffserver_get_arg(stream->feed_filename, sizeof(stream->feed_filename),
p);
} else if (!av_strcasecmp(cmd, "UseDefaults")) {
if (config->stream_use_defaults > 1)
WARNING("Multiple UseDefaults/NoDefaults entries.\n");
config->stream_use_defaults = 3;
} else if (!av_strcasecmp(cmd, "NoDefaults")) {
if (config->stream_use_defaults > 1)
WARNING("Multiple UseDefaults/NoDefaults entries.\n");
config->stream_use_defaults = 2;
} else {
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->audio_opts);
avcodec_free_context(&config->dummy_vctx);
avcodec_free_context(&config->dummy_actx);
return AVERROR(ENOMEM);
static int ffserver_parse_config_redirect(FFServerConfig *config,
const char *cmd, const char **p,
FFServerStream **predirect)
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
{
FFServerStream *redirect;
av_assert0(predirect);
redirect = *predirect;
if (!av_strcasecmp(cmd, "<Redirect")) {
char *q;
redirect = av_mallocz(sizeof(FFServerStream));
if (!redirect)
return AVERROR(ENOMEM);
ffserver_get_arg(redirect->filename, sizeof(redirect->filename), p);
q = strrchr(redirect->filename, '>');
if (*q)
*q = '\0';
redirect->stream_type = STREAM_TYPE_REDIRECT;
*predirect = redirect;
return 0;
}
av_assert0(redirect);
if (!av_strcasecmp(cmd, "URL")) {
ffserver_get_arg(redirect->feed_filename,
sizeof(redirect->feed_filename), p);
} else if (!av_strcasecmp(cmd, "</Redirect>")) {
if (!redirect->feed_filename[0])
ERROR("No URL found for <Redirect>\n");
*predirect = NULL;
} else {
ERROR("Invalid entry '%s' inside <Redirect></Redirect>\n", cmd);
}
return 0;
}
int ffserver_parse_ffconfig(const char *filename, FFServerConfig *config)
{
FILE *f;
char line[1024];
char cmd[64];
const char *p;
FFServerStream **last_stream, *stream = NULL, *redirect = NULL;
FFServerStream **last_feed, *feed = NULL;
int ret = 0;
av_assert0(config);
f = fopen(filename, "r");
if (!f) {
ret = AVERROR(errno);
av_log(NULL, AV_LOG_ERROR,
"Could not open the configuration file '%s'\n", filename);
return ret;
}
config->first_stream = NULL;
config->first_feed = NULL;
config->errors = config->warnings = 0;
last_stream = &config->first_stream;
last_feed = &config->first_feed;
config->line_num = 0;
while (fgets(line, sizeof(line), f) != NULL) {
config->line_num++;
p = line;
while (av_isspace(*p))
p++;
if (*p == '\0' || *p == '#')
continue;
ffserver_get_arg(cmd, sizeof(cmd), &p);
if (feed || !av_strcasecmp(cmd, "<Feed")) {
int opening = !av_strcasecmp(cmd, "<Feed");
if (opening && (stream || feed || redirect)) {
ERROR("Already in a tag\n");
} else {
ret = ffserver_parse_config_feed(config, cmd, &p, &feed);
if (ret < 0)
/* add in stream & feed list */
*last_stream = feed;
*last_feed = feed;
last_stream = &feed->next;
last_feed = &feed->next_feed;
} else if (stream || !av_strcasecmp(cmd, "<Stream")) {
int opening = !av_strcasecmp(cmd, "<Stream");
if (opening && (stream || feed || redirect)) {
ERROR("Already in a tag\n");
} else {
ret = ffserver_parse_config_stream(config, cmd, &p, &stream);
if (ret < 0)
break;
if (opening) {
/* add in stream list */
*last_stream = stream;
last_stream = &stream->next;
} else if (redirect || !av_strcasecmp(cmd, "<Redirect")) {
int opening = !av_strcasecmp(cmd, "<Redirect");
if (opening && (stream || feed || redirect))
ERROR("Already in a tag\n");
ret = ffserver_parse_config_redirect(config, cmd, &p,
&redirect);
if (ret < 0)
break;
if (opening) {
/* add in stream list */
*last_stream = redirect;
last_stream = &redirect->next;
}
}
} else {
ffserver_parse_config_global(config, cmd, &p);
if (stream || feed || redirect)
ERROR("Missing closing </%s> tag\n",
stream ? "Stream" : (feed ? "Feed" : "Redirect"));
fclose(f);
if (ret < 0)
return ret;
if (config->errors)
return AVERROR(EINVAL);
else
return 0;
}
#undef ERROR
#undef WARNING
void ffserver_free_child_args(void *argsp)
{
int i;
char **args;
if (!argsp)
return;
args = *(char ***)argsp;
if (!args)
return;
for (i = 0; i < MAX_CHILD_ARGS; i++)
av_free(args[i]);
av_freep(argsp);
}