/* * 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. Load more
/* * 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_VSYNC enum VideoSyncMethod video_sync_method = VSYNC_AUTO; #endif float 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 options typedef 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++; }