1325 lines · 50.0 KB · C
RawDownload
/* * Copyright (c) 2000, 2001, 2002 Fabrice Bellard * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include <float.h>#include "libavutil/opt.h"#include "libavutil/parseutils.h"#include "libavutil/avstring.h"#include "libavutil/pixdesc.h"#include "libavutil/avassert.h" #include "cmdutils.h"#include "ffserver_config.h" #define MAX_CHILD_ARGS 64 static int ffserver_save_avoption(const char *opt, const char *arg, int type,                                  FFServerConfig *config);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,                                ...); #define ERROR(...) report_config_error(config->filename, config->line_num,\                                       AV_LOG_ERROR, &config->errors, __VA_ARGS__)#define WARNING(...) report_config_error(config->filename, config->line_num,\                                         AV_LOG_WARNING, &config->warnings, __VA_ARGS__) /* FIXME: make ffserver work with IPv6 *//* resolve host with also IP address parsing */static int resolve_host(struct in_addr *sin_addr, const char *hostname){     if (!ff_inet_aton(hostname, sin_addr)) {#if HAVE_GETADDRINFO        struct addrinfo *ai, *cur;        struct addrinfo hints = { 0 };        hints.ai_family = AF_INET;        if (getaddrinfo(hostname, NULL, &hints, &ai))            return -1;        /* getaddrinfo returns a linked list of addrinfo structs.         * Even if we set ai_family = AF_INET above, make sure         * that the returned one actually is of the correct type. */        for (cur = ai; cur; cur = cur->ai_next) {            if (cur->ai_family == AF_INET) {                *sin_addr = ((struct sockaddr_in *)cur->ai_addr)->sin_addr;                freeaddrinfo(ai);                return 0;            }        }        freeaddrinfo(ai);        return -1;#else        struct hostent *hp;        hp = gethostbyname(hostname);        if (!hp)            return -1;        memcpy(sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));#endif    }    return 0;} void ffserver_get_arg(char *buf, int buf_size, const char **pp){    const char *p;    char *q;    int quote = 0;     p = *pp;    q = buf;     while (av_isspace(*p)) p++;     if (*p == '\"' || *p == '\'')        quote = *p++;     while (*p != '\0') {        if (quote && *p == quote || !quote && av_isspace(*p))            break;        if ((q - buf) < buf_size - 1)            *q++ = *p;        p++;    }     *q = '\0';    if (quote && *p == quote)        p++;    *pp = p;} void ffserver_parse_acl_row(FFServerStream *stream, FFServerStream* feed,                            FFServerIPAddressACL *ext_acl,                            const char *p, const char *filename, int line_num){    char arg[1024];    FFServerIPAddressACL acl;    FFServerIPAddressACL *nacl;    FFServerIPAddressACL **naclp;     ffserver_get_arg(arg, sizeof(arg), &p);    if (av_strcasecmp(arg, "allow") == 0)        acl.action = IP_ALLOW;    else if (av_strcasecmp(arg, "deny") == 0)        acl.action = IP_DENY;    else {        fprintf(stderr, "%s:%d: ACL action '%s' should be ALLOW or DENY.\n",                filename, line_num, arg);        goto bail;    }     ffserver_get_arg(arg, sizeof(arg), &p);     if (resolve_host(&acl.first, arg)) {        fprintf(stderr,                "%s:%d: ACL refers to invalid host or IP address '%s'\n",                filename, line_num, arg);        goto bail;    }     acl.last = acl.first;     ffserver_get_arg(arg, sizeof(arg), &p);     if (arg[0]) {        if (resolve_host(&acl.last, arg)) {            fprintf(stderr,                    "%s:%d: ACL refers to invalid host or IP address '%s'\n",                    filename, line_num, arg);            goto bail;        }    }     nacl = av_mallocz(sizeof(*nacl));    if (!nacl) {        fprintf(stderr, "Failed to allocate FFServerIPAddressACL\n");        goto bail;    }     naclp = 0;     acl.next = 0;    *nacl = acl;     if (stream)        naclp = &stream->acl;    else if (feed)        naclp = &feed->acl;    else if (ext_acl)        naclp = &ext_acl;    else        fprintf(stderr, "%s:%d: ACL found not in <Stream> or <Feed>\n",                filename, line_num);     if (naclp) {        while (*naclp)            naclp = &(*naclp)->next;         *naclp = nacl;    } else        av_free(nacl); bail:  return; } /* add a codec and set the default parameters */static void add_codec(FFServerStream *stream, AVCodecContext *av,                      FFServerConfig *config){    LayeredAVStream *st;    AVDictionary **opts, *recommended = NULL;    char *enc_config;     if(stream->nb_streams >= FF_ARRAY_ELEMS(stream->streams))        return;     opts = av->codec_type == AVMEDIA_TYPE_AUDIO ?           &config->audio_opts : &config->video_opts;    av_dict_copy(&recommended, *opts, 0);    av_opt_set_dict2(av->priv_data, opts, AV_OPT_SEARCH_CHILDREN);    av_opt_set_dict2(av, opts, AV_OPT_SEARCH_CHILDREN);     if (av_dict_count(*opts))        av_log(NULL, AV_LOG_WARNING,               "Something is wrong, %d options are not set!\n",               av_dict_count(*opts));     if (!config->stream_use_defaults) {        switch(av->codec_type) {        case AVMEDIA_TYPE_AUDIO:            if (av->bit_rate == 0)                report_config_error(config->filename, config->line_num,                                    AV_LOG_ERROR, &config->errors,                                    "audio bit rate is not set\n");            if (av->sample_rate == 0)                report_config_error(config->filename, config->line_num,                                    AV_LOG_ERROR, &config->errors,                                    "audio sample rate is not set\n");            break;        case AVMEDIA_TYPE_VIDEO:            if (av->width == 0 || av->height == 0)                report_config_error(config->filename, config->line_num,                                    AV_LOG_ERROR, &config->errors,                                    "video size is not set\n");            break;        default:            av_assert0(0);        }        goto done;    }     /* stream_use_defaults = true */     /* compute default parameters */    switch(av->codec_type) {    case AVMEDIA_TYPE_AUDIO:        if (!av_dict_get(recommended, "b", NULL, 0)) {            av->bit_rate = 64000;            av_dict_set_int(&recommended, "b", av->bit_rate, 0);            WARNING("Setting default value for audio bit rate = %d. "                    "Use NoDefaults to disable it.\n",                    av->bit_rate);        }        if (!av_dict_get(recommended, "ar", NULL, 0)) {            av->sample_rate = 22050;            av_dict_set_int(&recommended, "ar", av->sample_rate, 0);            WARNING("Setting default value for audio sample rate = %d. "                    "Use NoDefaults to disable it.\n",                    av->sample_rate);        }        if (!av_dict_get(recommended, "ac", NULL, 0)) {            av->channels = 1;            av_dict_set_int(&recommended, "ac", av->channels, 0);            WARNING("Setting default value for audio channel count = %d. "                    "Use NoDefaults to disable it.\n",                    av->channels);        }        break;    case AVMEDIA_TYPE_VIDEO:        if (!av_dict_get(recommended, "b", NULL, 0)) {            av->bit_rate = 64000;            av_dict_set_int(&recommended, "b", av->bit_rate, 0);            WARNING("Setting default value for video bit rate = %d. "                    "Use NoDefaults to disable it.\n",                    av->bit_rate);        }        if (!av_dict_get(recommended, "time_base", NULL, 0)){            av->time_base.den = 5;            av->time_base.num = 1;            av_dict_set(&recommended, "time_base", "1/5", 0);            WARNING("Setting default value for video frame rate = %d. "                    "Use NoDefaults to disable it.\n",                    av->time_base.den);        }        if (!av_dict_get(recommended, "video_size", NULL, 0)) {            av->width = 160;            av->height = 128;            av_dict_set(&recommended, "video_size", "160x128", 0);            WARNING("Setting default value for video size = %dx%d. "                    "Use NoDefaults to disable it.\n",                    av->width, av->height);        }        /* Bitrate tolerance is less for streaming */        if (!av_dict_get(recommended, "bt", NULL, 0)) {            av->bit_rate_tolerance = FFMAX(av->bit_rate / 4,                      (int64_t)av->bit_rate*av->time_base.num/av->time_base.den);            av_dict_set_int(&recommended, "bt", av->bit_rate_tolerance, 0);            WARNING("Setting default value for video bit rate tolerance = %d. "                    "Use NoDefaults to disable it.\n",                    av->bit_rate_tolerance);        }         if (!av_dict_get(recommended, "rc_eq", NULL, 0)) {            av->rc_eq = av_strdup("tex^qComp");            av_dict_set(&recommended, "rc_eq", "tex^qComp", 0);            WARNING("Setting default value for video rate control equation = "                    "%s. Use NoDefaults to disable it.\n",                    av->rc_eq);        }        if (!av_dict_get(recommended, "maxrate", NULL, 0)) {            av->rc_max_rate = av->bit_rate * 2;            av_dict_set_int(&recommended, "maxrate", av->rc_max_rate, 0);            WARNING("Setting default value for video max rate = %d. "                    "Use NoDefaults to disable it.\n",                    av->rc_max_rate);        }         if (av->rc_max_rate && !av_dict_get(recommended, "bufsize", NULL, 0)) {            av->rc_buffer_size = av->rc_max_rate;            av_dict_set_int(&recommended, "bufsize", av->rc_buffer_size, 0);            WARNING("Setting default value for video buffer size = %d. "                    "Use NoDefaults to disable it.\n",                    av->rc_buffer_size);        }        break;    default:        abort();    } done:    st = av_mallocz(sizeof(*st));    if (!st)        return;    av_dict_get_string(recommended, &enc_config, '=', ',');    av_dict_free(&recommended);    st->recommended_encoder_configuration = enc_config;    st->codec = av;    st->codecpar = avcodec_parameters_alloc();    avcodec_parameters_from_context(st->codecpar, av);    stream->streams[stream->nb_streams++] = st;} static int ffserver_set_codec(AVCodecContext *ctx, const char *codec_name,                              FFServerConfig *config){    int ret;    AVCodec *codec = avcodec_find_encoder_by_name(codec_name);    if (!codec || codec->type != ctx->codec_type) {        report_config_error(config->filename, config->line_num, AV_LOG_ERROR,                            &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, config->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_preset(const char *arg, int type, FFServerConfig *config){    FILE *f=NULL;    char filename[1000], tmp[1000], tmp2[1000], line[1000];    int ret = 0;    AVCodecContext *avctx;    const AVCodec *codec;     switch(type) {    case AV_OPT_FLAG_AUDIO_PARAM:        avctx = config->dummy_actx;        break;    case AV_OPT_FLAG_VIDEO_PARAM:        avctx = config->dummy_vctx;        break;    default:        av_assert0(0);    }    codec = avcodec_find_encoder(avctx->codec_id);     if (!(f = get_preset_file(filename, sizeof(filename), arg, 0,                              codec ? codec->name : NULL))) {        av_log(NULL, AV_LOG_ERROR, "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){            av_log(NULL, AV_LOG_ERROR, "%s: Invalid syntax: '%s'\n", filename,                   line);            ret = AVERROR(EINVAL);            break;        }        if (!strcmp(tmp, "acodec") && avctx->codec_type == AVMEDIA_TYPE_AUDIO ||            !strcmp(tmp, "vcodec") && avctx->codec_type == AVMEDIA_TYPE_VIDEO)        {            if (ffserver_set_codec(avctx, tmp2, config) < 0)                break;        } else if (!strcmp(tmp, "scodec")) {            av_log(NULL, AV_LOG_ERROR, "Subtitles preset found.\n");            ret = AVERROR(EINVAL);            break;        } else if (ffserver_save_avoption(tmp, tmp2, type, config) < 0)            break;    }     fclose(f);     return ret;} static AVOutputFormat *ffserver_guess_format(const char *short_name,                                             const char *filename,                                             const char *mime_type){    AVOutputFormat *fmt = av_guess_format(short_name, filename, mime_type);     if (fmt) {        AVOutputFormat *stream_fmt;        char stream_format_name[64];         snprintf(stream_format_name, sizeof(stream_format_name), "%s_stream",                fmt->name);        stream_fmt = av_guess_format(stream_format_name, NULL, NULL);         if (stream_fmt)            fmt = stream_fmt;    }     return fmt;} static void vreport_config_error(const char *filename, int line_num,                                 int log_level, int *errors, const char *fmt,                                 va_list vl){    av_log(NULL, log_level, "%s:%d: ", filename, line_num);    av_vlog(NULL, log_level, fmt, vl);    if (errors)        (*errors)++;} static void report_config_error(const char *filename, int line_num,                                int log_level, int *errors,                                const char *fmt, ...){    va_list vl;    va_start(vl, fmt);    vreport_config_error(filename, line_num, log_level, errors, fmt, vl);    va_end(vl);} static int ffserver_set_int_param(int *dest, const char *value, int factor,                                  int min, int max, FFServerConfig *config,                                  const char *error_msg, ...){    int tmp;    char *tailp;    if (!value || !value[0])        goto error;    errno = 0;    tmp = strtol(value, &tailp, 0);    if (tmp < min || tmp > max)        goto error;    if (factor) {        if (tmp == INT_MIN || FFABS(tmp) > INT_MAX / FFABS(factor))            goto error;        tmp *= factor;    }    if (tailp[0] || errno)        goto error;    if (dest)        *dest = tmp;    return 0;  error:    if (config) {        va_list vl;        va_start(vl, error_msg);        vreport_config_error(config->filename, config->line_num, AV_LOG_ERROR,                &config->errors, error_msg, vl);        va_end(vl);    }    return AVERROR(EINVAL);} static int ffserver_set_float_param(float *dest, const char *value,                                    float factor, float min, float max,                                    FFServerConfig *config,                                    const char *error_msg, ...){    double tmp;    char *tailp;    if (!value || !value[0])        goto error;    errno = 0;    tmp = strtod(value, &tailp);    if (tmp < min || tmp > max)        goto error;    if (factor)

Lines 1–500 of 1325.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t