2078 lines · 82.1 KB · C
RawDownload
/* * ffmpeg option parsing * * 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 "config.h" #include <stdint.h> #if HAVE_SYS_RESOURCE_H#include <sys/time.h>#include <sys/resource.h>#endif #include "ffmpeg.h"#include "ffmpeg_sched.h"#include "cmdutils.h"#include "opt_common.h" #include "libavformat/avformat.h" #include "libavcodec/avcodec.h"#include "libavcodec/bsf.h" #include "libavfilter/avfilter.h" #include "libavutil/avassert.h"#include "libavutil/avstring.h"#include "libavutil/avutil.h"#include "libavutil/mathematics.h"#include "libavutil/mem.h"#include "libavutil/opt.h"#include "libavutil/parseutils.h"#include "libavutil/stereo3d.h" HWDevice *filter_hw_device; char *vstats_filename; float dts_delta_threshold   = 10;float dts_error_threshold   = 3600*30; #if FFMPEG_OPT_VSYNCenum VideoSyncMethod video_sync_method = VSYNC_AUTO;#endiffloat frame_drop_threshold = 0;int do_benchmark      = 0;int do_benchmark_all  = 0;int do_hex_dump       = 0;int do_pkt_dump       = 0;int copy_ts           = 0;int start_at_zero     = 0;int copy_tb           = -1;int debug_ts          = 0;int exit_on_error     = 0;int abort_on_flags    = 0;int print_stats       = -1;int stdin_interaction = 1;float max_error_rate  = 2.0/3;char *filter_nbthreads;int filter_complex_nbthreads = 0;int vstats_version = 2;int auto_conversion_filters = 1;int64_t stats_period = 500000;  static int file_overwrite     = 0;static int no_file_overwrite  = 0;int ignore_unknown_streams = 0;int copy_unknown_streams = 0;int recast_media = 0; // this struct is passed as the optctx argument// to func_arg() for global optionstypedef struct GlobalOptionsContext {    Scheduler      *sch;     char          **filtergraphs;    int          nb_filtergraphs;} GlobalOptionsContext; static void uninit_options(OptionsContext *o){    /* all OPT_SPEC and OPT_TYPE_STRING can be freed in generic way */    for (const OptionDef *po = options; po->name; po++) {        void *dst;         if (!(po->flags & OPT_FLAG_OFFSET))            continue;         dst = (uint8_t*)o + po->u.off;        if (po->flags & OPT_FLAG_SPEC) {            SpecifierOptList *so = dst;            for (int i = 0; i < so->nb_opt; i++) {                av_freep(&so->opt[i].specifier);                if (po->flags & OPT_FLAG_PERSTREAM)                    stream_specifier_uninit(&so->opt[i].stream_spec);                if (po->type == OPT_TYPE_STRING)                    av_freep(&so->opt[i].u.str);            }            av_freep(&so->opt);            so->nb_opt = 0;        } else if (po->type == OPT_TYPE_STRING)            av_freep(dst);    }     for (int i = 0; i < o->nb_stream_maps; i++)        av_freep(&o->stream_maps[i].linklabel);    av_freep(&o->stream_maps);     for (int i = 0; i < o->nb_attachments; i++)        av_freep(&o->attachments[i]);    av_freep(&o->attachments);     av_dict_free(&o->streamid);} static void init_options(OptionsContext *o){    memset(o, 0, sizeof(*o));     o->stop_time = INT64_MAX;    o->mux_max_delay  = 0.7;    o->start_time     = AV_NOPTS_VALUE;    o->start_time_eof = AV_NOPTS_VALUE;    o->recording_time = INT64_MAX;    o->limit_filesize = INT64_MAX;    o->chapters_input_file = INT_MAX;    o->accurate_seek  = 1;    o->thread_queue_size = 0;    o->input_sync_ref = -1;    o->find_stream_info = 1;    o->shortest_buf_duration = 10.f;} static int show_hwaccels(void *optctx, const char *opt, const char *arg){    enum AVHWDeviceType type = AV_HWDEVICE_TYPE_NONE;     printf("Hardware acceleration methods:\n");    while ((type = av_hwdevice_iterate_types(type)) !=           AV_HWDEVICE_TYPE_NONE)        printf("%s\n", av_hwdevice_get_type_name(type));    printf("\n");    return 0;} const char *opt_match_per_type_str(const SpecifierOptList *sol,                                   char mediatype){    av_assert0(!sol->nb_opt || sol->type == OPT_TYPE_STRING);     for (int i = 0; i < sol->nb_opt; i++) {        const char *spec = sol->opt[i].specifier;        if (spec[0] == mediatype && !spec[1])            return sol->opt[i].u.str;    }    return NULL;} static unsigned opt_match_per_stream(void *logctx, enum OptionType type,                                     const SpecifierOptList *sol,                                     AVFormatContext *fc, AVStream *st){    int matches = 0, match_idx = -1;     av_assert0((type == sol->type) || !sol->nb_opt);     for (int i = 0; i < sol->nb_opt; i++) {        const StreamSpecifier *ss = &sol->opt[i].stream_spec;         if (stream_specifier_match(ss, fc, st, logctx)) {            match_idx = i;            matches++;        }    }     if (matches > 1 && sol->opt_canon) {        const SpecifierOpt *so = &sol->opt[match_idx];        const char *spec = so->specifier && so->specifier[0] ? so->specifier : "";         char namestr[128] = "";        char optval_buf[32];        const char *optval = optval_buf;         snprintf(namestr, sizeof(namestr), "-%s", sol->opt_canon->name);        if (sol->opt_canon->flags & OPT_HAS_ALT) {            const char * const *names_alt = sol->opt_canon->u1.names_alt;            for (int i = 0; names_alt[i]; i++)                av_strlcatf(namestr, sizeof(namestr), "/-%s", names_alt[i]);        }         switch (sol->type) {        case OPT_TYPE_STRING: optval = so->u.str;                                             break;        case OPT_TYPE_INT:    snprintf(optval_buf, sizeof(optval_buf), "%d", so->u.i);        break;        case OPT_TYPE_INT64:  snprintf(optval_buf, sizeof(optval_buf), "%"PRId64, so->u.i64); break;        case OPT_TYPE_FLOAT:  snprintf(optval_buf, sizeof(optval_buf), "%f", so->u.f);        break;        case OPT_TYPE_DOUBLE: snprintf(optval_buf, sizeof(optval_buf), "%f", so->u.dbl);      break;        default: av_assert0(0);        }         av_log(logctx, AV_LOG_WARNING, "Multiple %s options specified for "               "stream %d, only the last option '-%s%s%s %s' will be used.\n",               namestr, st->index, sol->opt_canon->name, spec[0] ? ":" : "",               spec, optval);    }     return match_idx + 1;} #define OPT_MATCH_PER_STREAM(name, type, opt_type, m)                                   \void opt_match_per_stream_ ## name(void *logctx, const SpecifierOptList *sol,           \                                   AVFormatContext *fc, AVStream *st, type *out)        \{                                                                                       \    unsigned ret = opt_match_per_stream(logctx, opt_type, sol, fc, st);                 \    if (ret > 0)                                                                        \        *out = sol->opt[ret - 1].u.m;                                                   \} OPT_MATCH_PER_STREAM(str,   const char *, OPT_TYPE_STRING, str);OPT_MATCH_PER_STREAM(int,   int,          OPT_TYPE_INT,    i);OPT_MATCH_PER_STREAM(int64, int64_t,      OPT_TYPE_INT64,  i64);OPT_MATCH_PER_STREAM(dbl,   double,       OPT_TYPE_DOUBLE, dbl); int view_specifier_parse(const char **pspec, ViewSpecifier *vs){    const char *spec = *pspec;    char *endptr;     vs->type = VIEW_SPECIFIER_TYPE_NONE;     if (!strncmp(spec, "view:", 5)) {        spec += 5;         if (!strncmp(spec, "all", 3)) {            spec += 3;            vs->type = VIEW_SPECIFIER_TYPE_ALL;        } else {            vs->type = VIEW_SPECIFIER_TYPE_ID;            vs->val  = strtoul(spec, &endptr, 0);            if (endptr == spec) {                av_log(NULL, AV_LOG_ERROR, "Invalid view ID: %s\n", spec);                return AVERROR(EINVAL);            }            spec = endptr;        }    } else if (!strncmp(spec, "vidx:", 5)) {        spec += 5;        vs->type = VIEW_SPECIFIER_TYPE_IDX;        vs->val  = strtoul(spec, &endptr, 0);        if (endptr == spec) {            av_log(NULL, AV_LOG_ERROR, "Invalid view index: %s\n", spec);            return AVERROR(EINVAL);        }        spec = endptr;    } else if (!strncmp(spec, "vpos:", 5)) {        spec += 5;        vs->type = VIEW_SPECIFIER_TYPE_POS;         if (!strncmp(spec, "left", 4) && !cmdutils_isalnum(spec[4])) {            spec += 4;            vs->val = AV_STEREO3D_VIEW_LEFT;        } else if (!strncmp(spec, "right", 5) && !cmdutils_isalnum(spec[5])) {            spec += 5;            vs->val = AV_STEREO3D_VIEW_RIGHT;        } else {            av_log(NULL, AV_LOG_ERROR, "Invalid view position: %s\n", spec);            return AVERROR(EINVAL);        }    } else        return 0;     *pspec = spec;     return 0;} int parse_and_set_vsync(const char *arg, int *vsync_var, int file_idx, int st_idx, int is_global){    if      (!av_strcasecmp(arg, "cfr"))         *vsync_var = VSYNC_CFR;    else if (!av_strcasecmp(arg, "vfr"))         *vsync_var = VSYNC_VFR;    else if (!av_strcasecmp(arg, "passthrough")) *vsync_var = VSYNC_PASSTHROUGH;#if FFMPEG_OPT_VSYNC_DROP    else if (!av_strcasecmp(arg, "drop")) {        av_log(NULL, AV_LOG_WARNING, "-vsync/fps_mode drop is deprecated\n");        *vsync_var = VSYNC_DROP;    }#endif    else if (!is_global && !av_strcasecmp(arg, "auto"))  *vsync_var = VSYNC_AUTO;    else if (!is_global) {        av_log(NULL, AV_LOG_FATAL, "Invalid value %s specified for fps_mode of #%d:%d.\n", arg, file_idx, st_idx);        return AVERROR(EINVAL);    } #if FFMPEG_OPT_VSYNC    if (is_global && *vsync_var == VSYNC_AUTO) {        int ret;        double num;         ret = parse_number("vsync", arg, OPT_TYPE_INT, VSYNC_AUTO, VSYNC_VFR, &num);        if (ret < 0)            return ret;         video_sync_method = num;        av_log(NULL, AV_LOG_WARNING, "Passing a number to -vsync is deprecated,"               " use a string argument as described in the manual.\n");    }#endif     return 0;} /* Correct input file start times based on enabled streams */static void correct_input_start_times(void){    for (int i = 0; i < nb_input_files; i++) {        InputFile       *ifile = input_files[i];        AVFormatContext    *is = ifile->ctx;        int64_t new_start_time = INT64_MAX, diff, abs_start_seek;         ifile->start_time_effective = is->start_time;         if (is->start_time == AV_NOPTS_VALUE ||            !(is->iformat->flags & AVFMT_TS_DISCONT))            continue;         for (int j = 0; j < is->nb_streams; j++) {            AVStream *st = is->streams[j];            if(st->discard == AVDISCARD_ALL || st->start_time == AV_NOPTS_VALUE)                continue;            new_start_time = FFMIN(new_start_time, av_rescale_q(st->start_time, st->time_base, AV_TIME_BASE_Q));        }         diff = new_start_time - is->start_time;        if (diff) {            av_log(NULL, AV_LOG_VERBOSE, "Correcting start time of Input #%d by %"PRId64" us.\n", i, diff);            ifile->start_time_effective = new_start_time;            if (copy_ts && start_at_zero)                ifile->ts_offset = -new_start_time;            else if (!copy_ts) {                abs_start_seek = is->start_time + ((ifile->start_time != AV_NOPTS_VALUE) ? ifile->start_time : 0);                ifile->ts_offset = abs_start_seek > new_start_time ? -abs_start_seek : -new_start_time;            } else if (copy_ts)                ifile->ts_offset = 0;             ifile->ts_offset += ifile->input_ts_offset;        }    }} static int apply_sync_offsets(void){    for (int i = 0; i < nb_input_files; i++) {        InputFile *ref, *self = input_files[i];        int64_t adjustment;        int64_t self_start_time, ref_start_time, self_seek_start, ref_seek_start;        int start_times_set = 1;         if (self->input_sync_ref == -1 || self->input_sync_ref == i) continue;        if (self->input_sync_ref >= nb_input_files || self->input_sync_ref < -1) {            av_log(NULL, AV_LOG_FATAL, "-isync for input %d references non-existent input %d.\n", i, self->input_sync_ref);            return AVERROR(EINVAL);        }         if (copy_ts && !start_at_zero) {            av_log(NULL, AV_LOG_FATAL, "Use of -isync requires that start_at_zero be set if copyts is set.\n");            return AVERROR(EINVAL);        }         ref = input_files[self->input_sync_ref];        if (ref->input_sync_ref != -1 && ref->input_sync_ref != self->input_sync_ref) {            av_log(NULL, AV_LOG_ERROR, "-isync for input %d references a resynced input %d. Sync not set.\n", i, self->input_sync_ref);            continue;        }         if (self->ctx->start_time_realtime != AV_NOPTS_VALUE && ref->ctx->start_time_realtime != AV_NOPTS_VALUE) {            self_start_time = self->ctx->start_time_realtime;            ref_start_time  =  ref->ctx->start_time_realtime;        } else if (self->start_time_effective != AV_NOPTS_VALUE && ref->start_time_effective != AV_NOPTS_VALUE) {            self_start_time = self->start_time_effective;            ref_start_time  =  ref->start_time_effective;        } else {            start_times_set = 0;        }         if (start_times_set) {            self_seek_start = self->start_time == AV_NOPTS_VALUE ? 0 : self->start_time;            ref_seek_start  =  ref->start_time == AV_NOPTS_VALUE ? 0 :  ref->start_time;             adjustment = (self_start_time - ref_start_time) + !copy_ts*(self_seek_start - ref_seek_start) + ref->input_ts_offset;             self->ts_offset += adjustment;             av_log(NULL, AV_LOG_INFO, "Adjusted ts offset for Input #%d by %"PRId64" us to sync with Input #%d.\n", i, adjustment, self->input_sync_ref);        } else {            av_log(NULL, AV_LOG_INFO, "Unable to identify start times for Inputs #%d and %d both. No sync adjustment made.\n", i, self->input_sync_ref);        }    }     return 0;} static int opt_filter_threads(void *optctx, const char *opt, const char *arg){    av_free(filter_nbthreads);    filter_nbthreads = av_strdup(arg);    return 0;} static int opt_abort_on(void *optctx, const char *opt, const char *arg){    static const AVOption opts[] = {        { "abort_on"           , NULL, 0, AV_OPT_TYPE_FLAGS, { .i64 = 0 }, INT64_MIN, (double)INT64_MAX,   .unit = "flags" },        { "empty_output"       , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = ABORT_ON_FLAG_EMPTY_OUTPUT        }, .unit = "flags" },        { "empty_output_stream", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = ABORT_ON_FLAG_EMPTY_OUTPUT_STREAM }, .unit = "flags" },        { NULL },    };    static const AVClass class = {        .class_name = "",        .item_name  = av_default_item_name,        .option     = opts,        .version    = LIBAVUTIL_VERSION_INT,    };    const AVClass *pclass = &class;     return av_opt_eval_flags(&pclass, &opts[0], arg, &abort_on_flags);} static int opt_stats_period(void *optctx, const char *opt, const char *arg){    int64_t user_stats_period;    int ret = av_parse_time(&user_stats_period, arg, 1);    if (ret < 0)        return ret;     if (user_stats_period <= 0) {        av_log(NULL, AV_LOG_ERROR, "stats_period %s must be positive.\n", arg);        return AVERROR(EINVAL);    }     stats_period = user_stats_period;    av_log(NULL, AV_LOG_INFO, "ffmpeg stats and -progress period set to %s.\n", arg);     return 0;} static int opt_audio_codec(void *optctx, const char *opt, const char *arg){    OptionsContext *o = optctx;    return parse_option(o, "codec:a", arg, options);} static int opt_video_codec(void *optctx, const char *opt, const char *arg){    OptionsContext *o = optctx;    return parse_option(o, "codec:v", arg, options);} static int opt_subtitle_codec(void *optctx, const char *opt, const char *arg){    OptionsContext *o = optctx;    return parse_option(o, "codec:s", arg, options);} static int opt_data_codec(void *optctx, const char *opt, const char *arg){    OptionsContext *o = optctx;    return parse_option(o, "codec:d", arg, options);} static int opt_map(void *optctx, const char *opt, const char *arg){    OptionsContext *o = optctx;    StreamMap *m = NULL;    StreamSpecifier ss;    int i, negative = 0, file_idx, disabled = 0;    int ret, allow_unused = 0;     memset(&ss, 0, sizeof(ss));     if (*arg == '-') {        negative = 1;        arg++;    } 

Lines 1–500 of 2078.

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