Esempio n. 1
0
static int ffserver_opt_preset(const char *arg,
                       AVCodecContext *avctx, int type,
                       enum AVCodecID *audio_id, enum AVCodecID *video_id)
{
    FILE *f=NULL;
    char filename[1000], tmp[1000], tmp2[1000], line[1000];
    int ret = 0;
    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 AVERROR(EINVAL);
    }

    while(!feof(f)){
        int e= fscanf(f, "%999[^\n]\n", line) - 1;
        if(line[0] == '#' && !e)
            continue;
        e|= sscanf(line, "%999[^=]=%999[^\n]\n", tmp, tmp2) - 2;
        if(e){
            fprintf(stderr, "%s: Invalid syntax: '%s'\n", filename, line);
            ret = AVERROR(EINVAL);
            break;
        }
        if (audio_id && !strcmp(tmp, "acodec")) {
            *audio_id = opt_codec(tmp2, AVMEDIA_TYPE_AUDIO);
        } else if (video_id && !strcmp(tmp, "vcodec")){
            *video_id = opt_codec(tmp2, AVMEDIA_TYPE_VIDEO);
        } else if(!strcmp(tmp, "scodec")) {
            /* opt_subtitle_codec(tmp2); */
        } 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);
            break;
        }
    }

    fclose(f);

    return ret;
}
Esempio n. 2
0
static int ffserver_parse_config_stream(FFServerConfig *config, const char *cmd, const char **p,
                                        int line_num, FFServerStream **pstream)
{
    char arg[1024], arg2[1024];
    FFServerStream *stream;

    av_assert0(pstream);
    stream = *pstream;

    if (!av_strcasecmp(cmd, "<Stream")) {
        char *q;
        FFServerStream *s;
        stream = av_mallocz(sizeof(FFServerStream));
        if (!stream)
            return AVERROR(ENOMEM);
        ffserver_get_arg(stream->filename, sizeof(stream->filename), p);
        q = strrchr(stream->filename, '>');
        if (q)
            *q = '\0';

        for (s = config->first_stream; s; s = s->next) {
            if (!strcmp(stream->filename, s->filename))
                ERROR("Stream '%s' already registered\n", s->filename);
        }

        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;
        }
        *pstream = stream;
        return 0;
    }
    av_assert0(stream);
    if (!av_strcasecmp(cmd, "Feed")) {
        FFServerStream *sfeed;
        ffserver_get_arg(arg, sizeof(arg), p);
        sfeed = config->first_feed;
        while (sfeed) {
            if (!strcmp(sfeed->filename, arg))
                break;
            sfeed = sfeed->next_feed;
        }
        if (!sfeed)
            ERROR("Feed with name '%s' for stream '%s' is not defined\n", arg, stream->filename);
        else
            stream->feed = sfeed;
    } else if (!av_strcasecmp(cmd, "Format")) {
        ffserver_get_arg(arg, sizeof(arg), p);
        if (!strcmp(arg, "status")) {
            stream->stream_type = STREAM_TYPE_STATUS;
            stream->fmt = NULL;
        } else {
            stream->stream_type = STREAM_TYPE_LIVE;
            /* JPEG cannot be used here, so use single frame MJPEG */
            if (!strcmp(arg, "jpeg"))
                strcpy(arg, "mjpeg");
            stream->fmt = ffserver_guess_format(arg, NULL, NULL);
            if (!stream->fmt)
                ERROR("Unknown Format: %s\n", arg);
        }
        if (stream->fmt) {
            config->audio_id = stream->fmt->audio_codec;
            config->video_id = stream->fmt->video_codec;
        }
    } else if (!av_strcasecmp(cmd, "InputFormat")) {
        ffserver_get_arg(arg, sizeof(arg), p);
        stream->ifmt = av_find_input_format(arg);
        if (!stream->ifmt)
            ERROR("Unknown input format: %s\n", arg);
    } else if (!av_strcasecmp(cmd, "FaviconURL")) {
        if (stream->stream_type == STREAM_TYPE_STATUS)
            ffserver_get_arg(stream->feed_filename, sizeof(stream->feed_filename), p);
        else
            ERROR("FaviconURL only permitted for status streams\n");
    } else if (!av_strcasecmp(cmd, "Author")    ||
               !av_strcasecmp(cmd, "Comment")   ||
               !av_strcasecmp(cmd, "Copyright") ||
               !av_strcasecmp(cmd, "Title")) {
        char key[32];
        int i, ret;
        ffserver_get_arg(arg, sizeof(arg), p);
        for (i = 0; i < strlen(cmd); i++)
            key[i] = av_tolower(cmd[i]);
        key[i] = 0;
        WARNING("'%s' option in configuration file is deprecated, "
                "use 'Metadata %s VALUE' instead\n", cmd, key);
        if ((ret = av_dict_set(&stream->metadata, key, arg, 0)) < 0)
            ERROR("Could not set metadata '%s' to value '%s': %s\n", key, arg, av_err2str(ret));
    } else if (!av_strcasecmp(cmd, "Metadata")) {
        int ret;
        ffserver_get_arg(arg, sizeof(arg), p);
        ffserver_get_arg(arg2, sizeof(arg2), p);
        if ((ret = av_dict_set(&stream->metadata, arg, arg2, 0)) < 0) {
            ERROR("Could not set metadata '%s' to value '%s': %s\n",
                  arg, arg2, av_err2str(ret));
        }
    } else if (!av_strcasecmp(cmd, "Preroll")) {
        ffserver_get_arg(arg, sizeof(arg), p);
        stream->prebuffer = atof(arg) * 1000;
    } else if (!av_strcasecmp(cmd, "StartSendOnKey")) {
        stream->send_on_key = 1;
    } else if (!av_strcasecmp(cmd, "AudioCodec")) {
        ffserver_get_arg(arg, sizeof(arg), p);
        config->audio_id = opt_codec(arg, AVMEDIA_TYPE_AUDIO);
        if (config->audio_id == AV_CODEC_ID_NONE)
            ERROR("Unknown AudioCodec: %s\n", arg);
    } else if (!av_strcasecmp(cmd, "VideoCodec")) {
        ffserver_get_arg(arg, sizeof(arg), p);
        config->video_id = opt_codec(arg, AVMEDIA_TYPE_VIDEO);
        if (config->video_id == AV_CODEC_ID_NONE)
            ERROR("Unknown VideoCodec: %s\n", arg);
    } else if (!av_strcasecmp(cmd, "MaxTime")) {
        ffserver_get_arg(arg, sizeof(arg), p);
        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")) {
        ffserver_get_arg(arg, sizeof(arg), p);
        config->audio_enc.sample_rate = atoi(arg);
    } 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;
        } 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, "VideoSize")) {
        int ret;
        ffserver_get_arg(arg, sizeof(arg), p);
        ret = av_parse_video_size(&config->video_enc.width, &config->video_enc.height, 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)
            ERROR("Image size must be a multiple of 16\n");
    } 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;
        }
    } else if (!av_strcasecmp(cmd, "PixelFormat")) {
        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)
            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);
    } 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;
    } else if (!av_strcasecmp(cmd, "AVOptionVideo") ||
               !av_strcasecmp(cmd, "AVOptionAudio")) {
        AVCodecContext *avctx;
        int type;
        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);
        }
    } else if (!av_strcasecmp(cmd, "AVPresetVideo") ||
               !av_strcasecmp(cmd, "AVPresetAudio")) {
        AVCodecContext *avctx;
        int type;
        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;
        } 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);
        }
    } 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);
    } else if (!av_strcasecmp(cmd, "NoVideo")) {
        config->video_id = AV_CODEC_ID_NONE;
    } else if (!av_strcasecmp(cmd, "NoAudio")) {
        config->audio_id = AV_CODEC_ID_NONE;
    } else if (!av_strcasecmp(cmd, "ACL")) {
        ffserver_parse_acl_row(stream, NULL, NULL, *p, config->filename, 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) != 0)
            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);
        stream->multicast_port = atoi(arg);
    } else if (!av_strcasecmp(cmd, "MulticastTTL")) {
        ffserver_get_arg(arg, sizeof(arg), p);
        stream->multicast_ttl = atoi(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") != 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);
            }
            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);
            }
        }
        *pstream = NULL;
    } else if (!av_strcasecmp(cmd, "File") || !av_strcasecmp(cmd, "ReadOnlyFile")) {
        ffserver_get_arg(stream->feed_filename, sizeof(stream->feed_filename), p);
    } else {
        ERROR("Invalid entry '%s' inside <Stream></Stream>\n", cmd);
    }
    return 0;
}