Skip to content
Snippets Groups Projects
ffserver_config.c 49.9 KiB
Newer Older
  • Learn to ignore specific revisions
  •         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")) {
    
            config->no_video = 1;
    
        } else if (!av_strcasecmp(cmd, "NoAudio")) {
    
            config->no_audio = 1;
    
        } else if (!av_strcasecmp(cmd, "ACL")) {
    
            ffserver_parse_acl_row(stream, NULL, NULL, *p, config->filename,
    
        } 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);
    
            stream->multicast_port = val;
    
        } 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);
    
            stream->multicast_ttl = val;
    
        } else if (!av_strcasecmp(cmd, "NoLoop")) {
            stream->loop = 0;
        } else if (!av_strcasecmp(cmd, "</Stream>")) {
    
            config->stream_use_defaults &= 1;
    
            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)
    
    {
        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) {
    
            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;
    
                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;
    
            return AVERROR(EINVAL);
        else
            return 0;
    }
    
    
    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);
    }