From bba2b626948a6c16aab41d016ee7909817baea8b Mon Sep 17 00:00:00 2001 From: Taner Sener Date: Mon, 5 Sep 2022 23:21:00 +0100 Subject: [PATCH] use ffmpeg n5.1.1 --- android.sh | 4 +- android/ffmpeg-kit-android-lib/Doxyfile | 2 +- android/ffmpeg-kit-android-lib/build.gradle | 8 +- .../src/main/cpp/ffmpegkit.c | 2 +- .../src/main/cpp/ffmpegkit.h | 2 +- .../src/main/cpp/ffprobekit.c | 3 +- .../src/main/cpp/fftools_cmdutils.c | 1561 ++-------------- .../src/main/cpp/fftools_cmdutils.h | 228 +-- .../src/main/cpp/fftools_ffmpeg.c | 1445 ++++++--------- .../src/main/cpp/fftools_ffmpeg.h | 142 +- .../src/main/cpp/fftools_ffmpeg_filter.c | 318 ++-- .../src/main/cpp/fftools_ffmpeg_hw.c | 61 +- .../src/main/cpp/fftools_ffmpeg_mux.c | 331 ++++ .../src/main/cpp/fftools_ffmpeg_opt.c | 701 +++++--- .../src/main/cpp/fftools_ffprobe.c | 588 +++++-- .../src/main/cpp/fftools_fopen_utf8.h | 79 + .../src/main/cpp/fftools_opt_common.c | 1492 ++++++++++++++++ .../src/main/cpp/fftools_opt_common.h | 202 +++ .../com/arthenica/ffmpegkit/NativeLoader.java | 2 +- android/jni/Android.mk | 2 +- apple.sh | 1 - apple/Doxyfile | 2 +- apple/configure.ac | 13 +- apple/src/FFmpegKitConfig.m | 4 +- apple/src/Makefile.am | 12 +- apple/src/Makefile.in | 88 +- apple/src/Packages.m | 3 - apple/src/fftools_cmdutils.c | 1560 ++-------------- apple/src/fftools_cmdutils.h | 228 +-- apple/src/fftools_ffmpeg.c | 1448 ++++++--------- apple/src/fftools_ffmpeg.h | 142 +- apple/src/fftools_ffmpeg_filter.c | 324 ++-- apple/src/fftools_ffmpeg_hw.c | 61 +- apple/src/fftools_ffmpeg_mux.c | 332 ++++ apple/src/fftools_ffmpeg_opt.c | 716 +++++--- apple/src/fftools_ffmpeg_videotoolbox.c | 177 -- apple/src/fftools_ffprobe.c | 588 +++++-- apple/src/fftools_fopen_utf8.h | 79 + apple/src/fftools_opt_common.c | 1492 ++++++++++++++++ apple/src/fftools_opt_common.h | 202 +++ ios.sh | 4 +- linux.sh | 4 +- linux/Doxyfile | 2 +- linux/configure.ac | 4 +- linux/src/FFmpegKitConfig.cpp | 2 +- linux/src/FFmpegKitConfig.h | 2 +- linux/src/Makefile.am | 8 +- linux/src/Makefile.in | 36 +- linux/src/fftools_cmdutils.c | 1568 ++--------------- linux/src/fftools_cmdutils.h | 228 +-- linux/src/fftools_ffmpeg.c | 1445 ++++++--------- linux/src/fftools_ffmpeg.h | 142 +- linux/src/fftools_ffmpeg_filter.c | 324 ++-- linux/src/fftools_ffmpeg_hw.c | 61 +- linux/src/fftools_ffmpeg_mux.c | 331 ++++ linux/src/fftools_ffmpeg_opt.c | 716 +++++--- linux/src/fftools_ffprobe.c | 588 +++++-- linux/src/fftools_fopen_utf8.h | 79 + linux/src/fftools_opt_common.c | 1492 ++++++++++++++++ linux/src/fftools_opt_common.h | 202 +++ macos.sh | 4 +- scripts/android/ffmpeg.sh | 8 +- scripts/apple/ffmpeg.sh | 9 +- scripts/function.sh | 31 +- scripts/linux/ffmpeg.sh | 6 +- scripts/source.sh | 8 +- tools/release/android/build.gradle | 8 +- tools/release/android/build.lts.gradle | 8 +- tvos.sh | 4 +- 69 files changed, 12075 insertions(+), 9894 deletions(-) create mode 100644 android/ffmpeg-kit-android-lib/src/main/cpp/fftools_ffmpeg_mux.c create mode 100644 android/ffmpeg-kit-android-lib/src/main/cpp/fftools_fopen_utf8.h create mode 100644 android/ffmpeg-kit-android-lib/src/main/cpp/fftools_opt_common.c create mode 100644 android/ffmpeg-kit-android-lib/src/main/cpp/fftools_opt_common.h create mode 100644 apple/src/fftools_ffmpeg_mux.c delete mode 100644 apple/src/fftools_ffmpeg_videotoolbox.c create mode 100644 apple/src/fftools_fopen_utf8.h create mode 100644 apple/src/fftools_opt_common.c create mode 100644 apple/src/fftools_opt_common.h create mode 100644 linux/src/fftools_ffmpeg_mux.c create mode 100644 linux/src/fftools_fopen_utf8.h create mode 100644 linux/src/fftools_opt_common.c create mode 100644 linux/src/fftools_opt_common.h diff --git a/android.sh b/android.sh index 2deaaa4..2790616 100755 --- a/android.sh +++ b/android.sh @@ -28,7 +28,7 @@ echo -e "\nINFO: Using Android NDK v${DETECTED_NDK_VERSION} provided at ${ANDROI echo -e "INFO: Build options: $*\n" 1>>"${BASEDIR}"/build.log 2>&1 # SET DEFAULT BUILD OPTIONS -GPL_ENABLED="no" +export GPL_ENABLED="no" DISPLAY_HELP="" BUILD_FULL="" BUILD_TYPE_ID="" @@ -105,7 +105,7 @@ while [ ! $# -eq 0 ]; do BUILD_FULL="1" ;; --enable-gpl) - GPL_ENABLED="yes" + export GPL_ENABLED="yes" ;; --enable-custom-library-*) CUSTOM_LIBRARY_OPTION_KEY=$(echo $1 | sed -e 's/^--enable-custom-//g;s/=.*$//g') diff --git a/android/ffmpeg-kit-android-lib/Doxyfile b/android/ffmpeg-kit-android-lib/Doxyfile index 9272c39..ad2f799 100644 --- a/android/ffmpeg-kit-android-lib/Doxyfile +++ b/android/ffmpeg-kit-android-lib/Doxyfile @@ -38,7 +38,7 @@ PROJECT_NAME = "FFmpegKit Android API" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 4.5.1 +PROJECT_NUMBER = 5.1 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/android/ffmpeg-kit-android-lib/build.gradle b/android/ffmpeg-kit-android-lib/build.gradle index e4d6233..4e59559 100644 --- a/android/ffmpeg-kit-android-lib/build.gradle +++ b/android/ffmpeg-kit-android-lib/build.gradle @@ -1,14 +1,14 @@ apply plugin: 'com.android.library' android { - compileSdkVersion 30 + compileSdkVersion 31 ndkVersion "22.1.7171670" defaultConfig { minSdkVersion 24 - targetSdkVersion 30 - versionCode 240451 - versionName "4.5.1" + targetSdkVersion 31 + versionCode 240510 + versionName "5.1" project.archivesBaseName = "ffmpeg-kit" consumerProguardFiles 'proguard-rules.pro' } diff --git a/android/ffmpeg-kit-android-lib/src/main/cpp/ffmpegkit.c b/android/ffmpeg-kit-android-lib/src/main/cpp/ffmpegkit.c index ae4588d..6722fa0 100644 --- a/android/ffmpeg-kit-android-lib/src/main/cpp/ffmpegkit.c +++ b/android/ffmpeg-kit-android-lib/src/main/cpp/ffmpegkit.c @@ -106,7 +106,7 @@ volatile int handleSIGXCPU = 1; volatile int handleSIGPIPE = 1; /** Holds the id of the current session */ -__thread volatile long globalSessionId = 0; +__thread long globalSessionId = 0; /** Holds the default log level */ int configuredLogLevel = AV_LOG_INFO; diff --git a/android/ffmpeg-kit-android-lib/src/main/cpp/ffmpegkit.h b/android/ffmpeg-kit-android-lib/src/main/cpp/ffmpegkit.h index dc1660d..eb7300c 100644 --- a/android/ffmpeg-kit-android-lib/src/main/cpp/ffmpegkit.h +++ b/android/ffmpeg-kit-android-lib/src/main/cpp/ffmpegkit.h @@ -27,7 +27,7 @@ #include "libavutil/ffversion.h" /** Library version string */ -#define FFMPEG_KIT_VERSION "4.5.1" +#define FFMPEG_KIT_VERSION "5.1" /** Defines tag used for Android logging. */ #define LIB_NAME "ffmpeg-kit" diff --git a/android/ffmpeg-kit-android-lib/src/main/cpp/ffprobekit.c b/android/ffmpeg-kit-android-lib/src/main/cpp/ffprobekit.c index d4a1103..089cefe 100644 --- a/android/ffmpeg-kit-android-lib/src/main/cpp/ffprobekit.c +++ b/android/ffmpeg-kit-android-lib/src/main/cpp/ffprobekit.c @@ -24,13 +24,14 @@ #include "config.h" #include "libavcodec/jni.h" #include "libavutil/bprint.h" +#include "libavutil/mem.h" #include "ffmpegkit.h" /** Forward declaration for function defined in fftools_ffprobe.c */ int ffprobe_execute(int argc, char **argv); extern int configuredLogLevel; -extern __thread volatile long globalSessionId; +extern __thread long globalSessionId; extern void addSession(long sessionId); extern void removeSession(long sessionId); extern void resetMessagesInTransmit(long sessionId); diff --git a/android/ffmpeg-kit-android-lib/src/main/cpp/fftools_cmdutils.c b/android/ffmpeg-kit-android-lib/src/main/cpp/fftools_cmdutils.c index 211ea07..5cd0dde 100644 --- a/android/ffmpeg-kit-android-lib/src/main/cpp/fftools_cmdutils.c +++ b/android/ffmpeg-kit-android-lib/src/main/cpp/fftools_cmdutils.c @@ -1,6 +1,7 @@ /* * Various utilities for command line tools * Copyright (c) 2000-2003 Fabrice Bellard + * copyright (c) 2018 Taner Sener ( tanersener gmail com ) * * This file is part of FFmpeg. * @@ -20,31 +21,42 @@ */ /* - * CHANGES 01.2021 - * - NDK r22 incompatibility issues regarding INT64_MAX fixed + * This file is the modified version of cmdutils.c file living in ffmpeg source code under the fftools folder. We + * manually update it each time we depend on a new ffmpeg version. Below you can see the list of changes applied + * by us to develop mobile-ffmpeg and later ffmpeg-kit libraries. * - * CHANGES 01.2020 - * - ffprobe support changes + * mobile-ffmpeg / ffmpeg-kit changes by Taner Sener + * + * 09.2022 + * -------------------------------------------------------- + * - Dropped the prototypes of init_report, ffmpegkit_log_callback_function and report_callback functions + * - volatile dropped from thread local variables + * + * 01.2020 + * -------------------------------------------------------- + * - ffprobe support added (variables used by ffprobe marked with "__thread" specifier, logs with AV_LOG_INFO level + * migrated to use AV_LOG_STDERR) * - (optindex < argc) validation in parse_options() method updated with (optindex >= argc) check * - * CHANGES 12.2019 - * - Concurrent execution support + * 12.2019 + * -------------------------------------------------------- + * - concurrent execution support ("__thread" specifier added to variables used by multiple threads) * - log_callback_report method re-added to fix -report option issues * - * CHANGES 08.2018 + * 08.2018 * -------------------------------------------------------- * - fftools_ prefix added to the file name and parent header * - * CHANGES 07.2018 + * 07.2018 * -------------------------------------------------------- - * - Unused headers removed - * - Parentheses placed around assignments in conditions to prevent -Wparentheses warning + * - unused headers removed + * - parentheses placed around assignments in conditions to prevent -Wparentheses warning * - exit_program updated with longjmp, disabling exit * - longjmp_value added to store exit code * - (optindex < argc) validation added before accessing argv[optindex] inside split_commandline() - * and parse_options() - * - All av_log_set_callback invocations updated to set ffmpegkit_log_callback_function from ffmpegkit.c. Unused - * log_callback_help and log_callback_help methods removed + * and parse_options() + * - all av_log_set_callback invocations updated to set ffmpegkit_log_callback_function from ffmpegkit.c + * - unused log_callback_help method removed * - (idx + 1 < argc) validation added in parse_loglevel() */ @@ -54,66 +66,44 @@ #include #include -#include "ffmpegkit_exception.h" - /* Include only the enabled headers since some compilers (namely, Sun Studio) will not omit unused inline functions and create undefined references to libraries that are not being built. */ #include "config.h" #include "libavformat/avformat.h" -#include "libavfilter/avfilter.h" -#include "libavdevice/avdevice.h" #include "libswscale/swscale.h" #include "libswresample/swresample.h" -#include "libavutil/attributes.h" #include "libavutil/avassert.h" #include "libavutil/avstring.h" -#include "libavutil/bprint.h" #include "libavutil/channel_layout.h" #include "libavutil/display.h" +#include "libavutil/getenv_utf8.h" #include "libavutil/mathematics.h" #include "libavutil/imgutils.h" #include "libavutil/libm.h" #include "libavutil/parseutils.h" -#include "libavutil/pixdesc.h" #include "libavutil/eval.h" #include "libavutil/dict.h" #include "libavutil/opt.h" -#include "libavutil/cpu.h" -#include "libavutil/ffversion.h" -#include "libavutil/version.h" -#include "libavcodec/bsf.h" #include "fftools_cmdutils.h" -#if HAVE_SYS_RESOURCE_H -#include -#include -#endif +#include "fftools_fopen_utf8.h" +#include "fftools_opt_common.h" +#include "ffmpegkit_exception.h" #ifdef _WIN32 #include +#include "compat/w32dlfcn.h" #endif -static int init_report(const char *env); -extern void ffmpegkit_log_callback_function(void *ptr, int level, const char* format, va_list vargs); -extern void (*report_callback)(int, float, float, int64_t, int, double, double); - __thread char *program_name; __thread int program_birth_year; __thread AVDictionary *sws_dict; __thread AVDictionary *swr_opts; -__thread AVDictionary *format_opts, *codec_opts, *resample_opts; +__thread AVDictionary *format_opts, *codec_opts; -FILE *report_file; -int report_file_level = AV_LOG_DEBUG; __thread int hide_banner = 0; -__thread volatile int longjmp_value = 0; - -enum show_muxdemuxers { - SHOW_DEFAULT, - SHOW_DEMUXERS, - SHOW_MUXERS, -}; +__thread int longjmp_value = 0; void uninit_opts(void) { @@ -121,27 +111,6 @@ void uninit_opts(void) av_dict_free(&sws_dict); av_dict_free(&format_opts); av_dict_free(&codec_opts); - av_dict_free(&resample_opts); -} - -void log_callback_report(void *ptr, int level, const char *fmt, va_list vl) -{ - va_list vl2; - char line[1024]; - static int print_prefix = 1; - - va_copy(vl2, vl); - if (report_callback == NULL) { - av_log_default_callback(ptr, level, fmt, vl); - } else { - ffmpegkit_log_callback_function(ptr, level, fmt, vl); - } - av_log_format_line(ptr, level, fmt, vl2, line, sizeof(line), &print_prefix); - va_end(vl2); - if (report_file_level >= level) { - fputs(line, report_file); - fflush(report_file); - } } void init_dynload(void) @@ -379,6 +348,12 @@ static int write_option(void *optctx, const OptionDef *po, const char *opt, int parse_option(void *optctx, const char *opt, const char *arg, const OptionDef *options) { + static const OptionDef opt_avoptions = { + .name = "AVOption passthrough", + .flags = HAS_ARG, + .u.func_arg = opt_default, + }; + const OptionDef *po; int ret; @@ -392,7 +367,7 @@ int parse_option(void *optctx, const char *opt, const char *arg, arg = "1"; if (!po->name) - po = find_option(options, "default"); + po = &opt_avoptions; if (!po->name) { av_log(NULL, AV_LOG_ERROR, "Unrecognized option '%s'\n", opt); return AVERROR(EINVAL); @@ -503,7 +478,7 @@ int locate_option(int argc, char **argv, const OptionDef *options, return 0; } -static void dump_argument(const char *a) +static void dump_argument(FILE *report_file, const char *a) { const unsigned char *p; @@ -539,7 +514,7 @@ static void check_options(const OptionDef *po) void parse_loglevel(int argc, char **argv, const OptionDef *options) { int idx = locate_option(argc, argv, options, "loglevel"); - const char *env; + char *env; check_options(options); @@ -548,18 +523,21 @@ void parse_loglevel(int argc, char **argv, const OptionDef *options) if (idx && (idx + 1 < argc) && argv[idx + 1]) opt_loglevel(NULL, "loglevel", argv[idx + 1]); idx = locate_option(argc, argv, options, "report"); - if ((env = getenv("FFREPORT")) || idx) { - init_report(env); + env = getenv_utf8("FFREPORT"); + if (env || idx) { + FILE *report_file = NULL; + init_report(env, &report_file); if (report_file) { int i; fprintf(report_file, "Command line:\n"); for (i = 0; i < argc; i++) { - dump_argument(argv[i]); + dump_argument(report_file, argv[i]); fputc(i < argc - 1 ? ' ' : '\n', report_file); } fflush(report_file); } } + freeenv_utf8(env); idx = locate_option(argc, argv, options, "hide_banner"); if (idx) hide_banner = 1; @@ -613,20 +591,12 @@ int opt_default(void *optctx, const char *opt, const char *arg) #if CONFIG_SWSCALE if (!consumed && (o = opt_find(&sc, opt, NULL, 0, AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ))) { - struct SwsContext *sws = sws_alloc_context(); - int ret = av_opt_set(sws, opt, arg, 0); - sws_freeContext(sws); if (!strcmp(opt, "srcw") || !strcmp(opt, "srch") || !strcmp(opt, "dstw") || !strcmp(opt, "dsth") || !strcmp(opt, "src_format") || !strcmp(opt, "dst_format")) { av_log(NULL, AV_LOG_ERROR, "Directly using swscale dimensions/format options is not supported, please use the -s or -pix_fmt options\n"); return AVERROR(EINVAL); } - if (ret < 0) { - av_log(NULL, AV_LOG_ERROR, "Error setting option %s.\n", opt); - return ret; - } - av_dict_set(&sws_dict, opt, arg, FLAGS); consumed = 1; @@ -640,13 +610,6 @@ int opt_default(void *optctx, const char *opt, const char *arg) #if CONFIG_SWRESAMPLE if (!consumed && (o=opt_find(&swr_class, opt, NULL, 0, AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ))) { - struct SwrContext *swr = swr_alloc(); - int ret = av_opt_set(swr, opt, arg, 0); - swr_free(&swr); - if (ret < 0) { - av_log(NULL, AV_LOG_ERROR, "Error setting option %s.\n", opt); - return ret; - } av_dict_set(&swr_opts, opt, arg, FLAGS); consumed = 1; } @@ -698,11 +661,9 @@ static void finish_group(OptionParseContext *octx, int group_idx, g->swr_opts = swr_opts; g->codec_opts = codec_opts; g->format_opts = format_opts; - g->resample_opts = resample_opts; codec_opts = NULL; format_opts = NULL; - resample_opts = NULL; sws_dict = NULL; swr_opts = NULL; @@ -733,7 +694,7 @@ static void init_parse_context(OptionParseContext *octx, memset(octx, 0, sizeof(*octx)); octx->nb_groups = nb_groups; - octx->groups = av_mallocz_array(octx->nb_groups, sizeof(*octx->groups)); + octx->groups = av_calloc(octx->nb_groups, sizeof(*octx->groups)); if (!octx->groups) exit_program(1); @@ -755,7 +716,6 @@ void uninit_parse_context(OptionParseContext *octx) av_freep(&l->groups[j].opts); av_dict_free(&l->groups[j].codec_opts); av_dict_free(&l->groups[j].format_opts); - av_dict_free(&l->groups[j].resample_opts); av_dict_free(&l->groups[j].sws_dict); av_dict_free(&l->groups[j].swr_opts); @@ -872,7 +832,7 @@ do { \ return AVERROR_OPTION_NOT_FOUND; } - if (octx->cur_group.nb_opts || codec_opts || format_opts || resample_opts) + if (octx->cur_group.nb_opts || codec_opts || format_opts) av_log(NULL, AV_LOG_WARNING, "Trailing option(s) found in the " "command: may be ignored.\n"); @@ -881,259 +841,6 @@ do { \ return 0; } -int opt_cpuflags(void *optctx, const char *opt, const char *arg) -{ - int ret; - unsigned flags = av_get_cpu_flags(); - - if ((ret = av_parse_cpu_caps(&flags, arg)) < 0) - return ret; - - av_force_cpu_flags(flags); - return 0; -} - -int opt_cpucount(void *optctx, const char *opt, const char *arg) -{ - int ret; - int count; - - static const AVOption opts[] = { - {"count", NULL, 0, AV_OPT_TYPE_INT, { .i64 = -1}, -1, INT_MAX, 0}, - {NULL}, - }; - static const AVClass class = { - .class_name = "cpucount", - .item_name = av_default_item_name, - .option = opts, - .version = LIBAVUTIL_VERSION_INT, - }; - const AVClass *pclass = &class; - - ret = av_opt_eval_int(&pclass, opts, arg, &count); - - if (!ret) { - av_cpu_force_count(count); - } - - return ret; -} - -int opt_loglevel(void *optctx, const char *opt, const char *arg) -{ - const struct { const char *name; int level; } log_levels[] = { - { "quiet" , AV_LOG_QUIET }, - { "panic" , AV_LOG_PANIC }, - { "fatal" , AV_LOG_FATAL }, - { "error" , AV_LOG_ERROR }, - { "warning", AV_LOG_WARNING }, - { "info" , AV_LOG_INFO }, - { "verbose", AV_LOG_VERBOSE }, - { "debug" , AV_LOG_DEBUG }, - { "trace" , AV_LOG_TRACE }, - }; - const char *token; - char *tail; - int flags = av_log_get_flags(); - int level = av_log_get_level(); - int cmd, i = 0; - - av_assert0(arg); - while (*arg) { - token = arg; - if (*token == '+' || *token == '-') { - cmd = *token++; - } else { - cmd = 0; - } - if (!i && !cmd) { - flags = 0; /* missing relative prefix, build absolute value */ - } - if (av_strstart(token, "repeat", &arg)) { - if (cmd == '-') { - flags |= AV_LOG_SKIP_REPEATED; - } else { - flags &= ~AV_LOG_SKIP_REPEATED; - } - } else if (av_strstart(token, "level", &arg)) { - if (cmd == '-') { - flags &= ~AV_LOG_PRINT_LEVEL; - } else { - flags |= AV_LOG_PRINT_LEVEL; - } - } else { - break; - } - i++; - } - if (!*arg) { - goto end; - } else if (*arg == '+') { - arg++; - } else if (!i) { - flags = av_log_get_flags(); /* level value without prefix, reset flags */ - } - - for (i = 0; i < FF_ARRAY_ELEMS(log_levels); i++) { - if (!strcmp(log_levels[i].name, arg)) { - level = log_levels[i].level; - goto end; - } - } - - level = strtol(arg, &tail, 10); - if (*tail) { - av_log(NULL, AV_LOG_FATAL, "Invalid loglevel \"%s\". " - "Possible levels are numbers or:\n", arg); - for (i = 0; i < FF_ARRAY_ELEMS(log_levels); i++) - av_log(NULL, AV_LOG_FATAL, "\"%s\"\n", log_levels[i].name); - exit_program(1); - } - -end: - av_log_set_flags(flags); - av_log_set_level(level); - return 0; -} - -static void expand_filename_template(AVBPrint *bp, const char *template, - struct tm *tm) -{ - int c; - - while ((c = *(template++))) { - if (c == '%') { - if (!(c = *(template++))) - break; - switch (c) { - case 'p': - av_bprintf(bp, "%s", program_name); - break; - case 't': - av_bprintf(bp, "%04d%02d%02d-%02d%02d%02d", - tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec); - break; - case '%': - av_bprint_chars(bp, c, 1); - break; - } - } else { - av_bprint_chars(bp, c, 1); - } - } -} - -static int init_report(const char *env) -{ - char *filename_template = NULL; - char *key, *val; - int ret, count = 0; - int prog_loglevel, envlevel = 0; - time_t now; - struct tm *tm; - AVBPrint filename; - - if (report_file) /* already opened */ - return 0; - time(&now); - tm = localtime(&now); - - while (env && *env) { - if ((ret = av_opt_get_key_value(&env, "=", ":", 0, &key, &val)) < 0) { - if (count) - av_log(NULL, AV_LOG_ERROR, - "Failed to parse FFREPORT environment variable: %s\n", - av_err2str(ret)); - break; - } - if (*env) - env++; - count++; - if (!strcmp(key, "file")) { - av_free(filename_template); - filename_template = val; - val = NULL; - } else if (!strcmp(key, "level")) { - char *tail; - report_file_level = strtol(val, &tail, 10); - if (*tail) { - av_log(NULL, AV_LOG_FATAL, "Invalid report file level\n"); - exit_program(1); - } - envlevel = 1; - } else { - av_log(NULL, AV_LOG_ERROR, "Unknown key '%s' in FFREPORT\n", key); - } - av_free(val); - av_free(key); - } - - av_bprint_init(&filename, 0, AV_BPRINT_SIZE_AUTOMATIC); - expand_filename_template(&filename, - av_x_if_null(filename_template, "%p-%t.log"), tm); - av_free(filename_template); - if (!av_bprint_is_complete(&filename)) { - av_log(NULL, AV_LOG_ERROR, "Out of memory building report file name\n"); - return AVERROR(ENOMEM); - } - - prog_loglevel = av_log_get_level(); - if (!envlevel) - report_file_level = FFMAX(report_file_level, prog_loglevel); - - report_file = fopen(filename.str, "w"); - if (!report_file) { - int ret = AVERROR(errno); - av_log(NULL, AV_LOG_ERROR, "Failed to open report \"%s\": %s\n", - filename.str, strerror(errno)); - return ret; - } - av_log_set_callback(log_callback_report); - av_log(NULL, AV_LOG_INFO, - "%s started on %04d-%02d-%02d at %02d:%02d:%02d\n" - "Report written to \"%s\"\n" - "Log level: %d\n", - program_name, - tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec, - filename.str, report_file_level); - av_bprint_finalize(&filename, NULL); - return 0; -} - -int opt_report(void *optctx, const char *opt, const char *arg) -{ - return init_report(NULL); -} - -int opt_max_alloc(void *optctx, const char *opt, const char *arg) -{ - char *tail; - size_t max; - - max = strtol(arg, &tail, 10); - if (*tail) { - av_log(NULL, AV_LOG_FATAL, "Invalid max_alloc \"%s\".\n", arg); - exit_program(1); - } - av_max_alloc(max); - return 0; -} - -int opt_timelimit(void *optctx, const char *opt, const char *arg) -{ -#if HAVE_SETRLIMIT - int lim = parse_number_or_die(opt, arg, OPT_INT64, 0, INT_MAX); - struct rlimit rl = { lim, lim + 1 }; - if (setrlimit(RLIMIT_CPU, &rl)) - perror("setrlimit"); -#else - av_log(NULL, AV_LOG_WARNING, "-%s not implemented on this OS\n", opt); -#endif - return 0; -} - void print_error(const char *filename, int err) { char errbuf[128]; @@ -1144,949 +851,6 @@ void print_error(const char *filename, int err) av_log(NULL, AV_LOG_ERROR, "%s: %s\n", filename, errbuf_ptr); } -__thread int warned_cfg = 0; - -#define INDENT 1 -#define SHOW_VERSION 2 -#define SHOW_CONFIG 4 -#define SHOW_COPYRIGHT 8 - -#define PRINT_LIB_INFO(libname, LIBNAME, flags, level) \ - if (CONFIG_##LIBNAME) { \ - const char *indent = flags & INDENT? " " : ""; \ - if (flags & SHOW_VERSION) { \ - unsigned int version = libname##_version(); \ - av_log(NULL, level, \ - "%slib%-11s %2d.%3d.%3d / %2d.%3d.%3d\n", \ - indent, #libname, \ - LIB##LIBNAME##_VERSION_MAJOR, \ - LIB##LIBNAME##_VERSION_MINOR, \ - LIB##LIBNAME##_VERSION_MICRO, \ - AV_VERSION_MAJOR(version), AV_VERSION_MINOR(version),\ - AV_VERSION_MICRO(version)); \ - } \ - if (flags & SHOW_CONFIG) { \ - const char *cfg = libname##_configuration(); \ - if (strcmp(FFMPEG_CONFIGURATION, cfg)) { \ - if (!warned_cfg) { \ - av_log(NULL, level, \ - "%sWARNING: library configuration mismatch\n", \ - indent); \ - warned_cfg = 1; \ - } \ - av_log(NULL, level, "%s%-11s configuration: %s\n", \ - indent, #libname, cfg); \ - } \ - } \ - } \ - -static void print_all_libs_info(int flags, int level) -{ - PRINT_LIB_INFO(avutil, AVUTIL, flags, level); - PRINT_LIB_INFO(avcodec, AVCODEC, flags, level); - PRINT_LIB_INFO(avformat, AVFORMAT, flags, level); - PRINT_LIB_INFO(avdevice, AVDEVICE, flags, level); - PRINT_LIB_INFO(avfilter, AVFILTER, flags, level); - PRINT_LIB_INFO(swscale, SWSCALE, flags, level); - PRINT_LIB_INFO(swresample, SWRESAMPLE, flags, level); -} - -static void print_program_info(int flags, int level) -{ - const char *indent = flags & INDENT? " " : ""; - - av_log(NULL, level, "%s version " FFMPEG_VERSION, program_name); - if (flags & SHOW_COPYRIGHT) - av_log(NULL, level, " Copyright (c) %d-%d the FFmpeg developers", - program_birth_year, CONFIG_THIS_YEAR); - av_log(NULL, level, "\n"); - av_log(NULL, level, "%sbuilt with %s\n", indent, CC_IDENT); - - av_log(NULL, level, "%sconfiguration: " FFMPEG_CONFIGURATION "\n", indent); -} - -static void print_buildconf(int flags, int level) -{ - const char *indent = flags & INDENT ? " " : ""; - char str[] = { FFMPEG_CONFIGURATION }; - char *conflist, *remove_tilde, *splitconf; - - // Change all the ' --' strings to '~--' so that - // they can be identified as tokens. - while ((conflist = strstr(str, " --")) != NULL) { - conflist[0] = '~'; - } - - // Compensate for the weirdness this would cause - // when passing 'pkg-config --static'. - while ((remove_tilde = strstr(str, "pkg-config~")) != NULL) { - remove_tilde[sizeof("pkg-config~") - 2] = ' '; - } - - splitconf = strtok(str, "~"); - av_log(NULL, level, "\n%sconfiguration:\n", indent); - while (splitconf != NULL) { - av_log(NULL, level, "%s%s%s\n", indent, indent, splitconf); - splitconf = strtok(NULL, "~"); - } -} - -void show_banner(int argc, char **argv, const OptionDef *options) -{ - int idx = locate_option(argc, argv, options, "version"); - if (hide_banner || idx) - return; - - print_program_info (INDENT|SHOW_COPYRIGHT, AV_LOG_INFO); - print_all_libs_info(INDENT|SHOW_CONFIG, AV_LOG_INFO); - print_all_libs_info(INDENT|SHOW_VERSION, AV_LOG_INFO); -} - -int show_version(void *optctx, const char *opt, const char *arg) -{ - print_program_info (SHOW_COPYRIGHT, AV_LOG_INFO); - print_all_libs_info(SHOW_VERSION, AV_LOG_INFO); - - return 0; -} - -int show_buildconf(void *optctx, const char *opt, const char *arg) -{ - print_buildconf (INDENT|0, AV_LOG_INFO); - - return 0; -} - -int show_license(void *optctx, const char *opt, const char *arg) -{ -#if CONFIG_NONFREE - av_log(NULL, AV_LOG_STDERR, - "This version of %s has nonfree parts compiled in.\n" - "Therefore it is not legally redistributable.\n", - program_name ); -#elif CONFIG_GPLV3 - av_log(NULL, AV_LOG_STDERR, - "%s is free software; you can redistribute it and/or modify\n" - "it under the terms of the GNU General Public License as published by\n" - "the Free Software Foundation; either version 3 of the License, or\n" - "(at your option) any later version.\n" - "\n" - "%s is distributed in the hope that it will be useful,\n" - "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" - "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" - "GNU General Public License for more details.\n" - "\n" - "You should have received a copy of the GNU General Public License\n" - "along with %s. If not, see .\n", - program_name, program_name, program_name ); -#elif CONFIG_GPL - av_log(NULL, AV_LOG_STDERR, - "%s is free software; you can redistribute it and/or modify\n" - "it under the terms of the GNU General Public License as published by\n" - "the Free Software Foundation; either version 2 of the License, or\n" - "(at your option) any later version.\n" - "\n" - "%s is distributed in the hope that it will be useful,\n" - "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" - "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" - "GNU General Public License for more details.\n" - "\n" - "You should have received a copy of the GNU General Public License\n" - "along with %s; if not, write to the Free Software\n" - "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n", - program_name, program_name, program_name ); -#elif CONFIG_LGPLV3 - av_log(NULL, AV_LOG_STDERR, - "%s is free software; you can redistribute it and/or modify\n" - "it under the terms of the GNU Lesser General Public License as published by\n" - "the Free Software Foundation; either version 3 of the License, or\n" - "(at your option) any later version.\n" - "\n" - "%s is distributed in the hope that it will be useful,\n" - "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" - "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" - "GNU Lesser General Public License for more details.\n" - "\n" - "You should have received a copy of the GNU Lesser General Public License\n" - "along with %s. If not, see .\n", - program_name, program_name, program_name ); -#else - av_log(NULL, AV_LOG_STDERR, - "%s is free software; you can redistribute it and/or\n" - "modify it under the terms of the GNU Lesser General Public\n" - "License as published by the Free Software Foundation; either\n" - "version 2.1 of the License, or (at your option) any later version.\n" - "\n" - "%s is distributed in the hope that it will be useful,\n" - "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" - "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n" - "Lesser General Public License for more details.\n" - "\n" - "You should have received a copy of the GNU Lesser General Public\n" - "License along with %s; if not, write to the Free Software\n" - "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n", - program_name, program_name, program_name ); -#endif - - return 0; -} - -static int is_device(const AVClass *avclass) -{ - if (!avclass) - return 0; - return AV_IS_INPUT_DEVICE(avclass->category) || AV_IS_OUTPUT_DEVICE(avclass->category); -} - -static int show_formats_devices(void *optctx, const char *opt, const char *arg, int device_only, int muxdemuxers) -{ - void *ifmt_opaque = NULL; - const AVInputFormat *ifmt = NULL; - void *ofmt_opaque = NULL; - const AVOutputFormat *ofmt = NULL; - const char *last_name; - int is_dev; - - av_log(NULL, AV_LOG_STDERR, "%s\n" - " D. = Demuxing supported\n" - " .E = Muxing supported\n" - " --\n", device_only ? "Devices:" : "File formats:"); - last_name = "000"; - for (;;) { - int decode = 0; - int encode = 0; - const char *name = NULL; - const char *long_name = NULL; - - if (muxdemuxers !=SHOW_DEMUXERS) { - ofmt_opaque = NULL; - while ((ofmt = av_muxer_iterate(&ofmt_opaque))) { - is_dev = is_device(ofmt->priv_class); - if (!is_dev && device_only) - continue; - if ((!name || strcmp(ofmt->name, name) < 0) && - strcmp(ofmt->name, last_name) > 0) { - name = ofmt->name; - long_name = ofmt->long_name; - encode = 1; - } - } - } - if (muxdemuxers != SHOW_MUXERS) { - ifmt_opaque = NULL; - while ((ifmt = av_demuxer_iterate(&ifmt_opaque))) { - is_dev = is_device(ifmt->priv_class); - if (!is_dev && device_only) - continue; - if ((!name || strcmp(ifmt->name, name) < 0) && - strcmp(ifmt->name, last_name) > 0) { - name = ifmt->name; - long_name = ifmt->long_name; - encode = 0; - } - if (name && strcmp(ifmt->name, name) == 0) - decode = 1; - } - } - if (!name) - break; - last_name = name; - - av_log(NULL, AV_LOG_STDERR, " %s%s %-15s %s\n", - decode ? "D" : " ", - encode ? "E" : " ", - name, - long_name ? long_name:" "); - } - return 0; -} - -int show_formats(void *optctx, const char *opt, const char *arg) -{ - return show_formats_devices(optctx, opt, arg, 0, SHOW_DEFAULT); -} - -int show_muxers(void *optctx, const char *opt, const char *arg) -{ - return show_formats_devices(optctx, opt, arg, 0, SHOW_MUXERS); -} - -int show_demuxers(void *optctx, const char *opt, const char *arg) -{ - return show_formats_devices(optctx, opt, arg, 0, SHOW_DEMUXERS); -} - -int show_devices(void *optctx, const char *opt, const char *arg) -{ - return show_formats_devices(optctx, opt, arg, 1, SHOW_DEFAULT); -} - -#define PRINT_CODEC_SUPPORTED(codec, field, type, list_name, term, get_name) \ - if (codec->field) { \ - const type *p = codec->field; \ - \ - av_log(NULL, AV_LOG_STDERR, " Supported " list_name ":"); \ - while (*p != term) { \ - get_name(*p); \ - av_log(NULL, AV_LOG_STDERR, " %s", name); \ - p++; \ - } \ - av_log(NULL, AV_LOG_STDERR, "\n"); \ - } \ - -static void print_codec(const AVCodec *c) -{ - int encoder = av_codec_is_encoder(c); - - av_log(NULL, AV_LOG_STDERR, "%s %s [%s]:\n", encoder ? "Encoder" : "Decoder", c->name, - c->long_name ? c->long_name : ""); - - av_log(NULL, AV_LOG_STDERR, " General capabilities: "); - if (c->capabilities & AV_CODEC_CAP_DRAW_HORIZ_BAND) - av_log(NULL, AV_LOG_STDERR, "horizband "); - if (c->capabilities & AV_CODEC_CAP_DR1) - av_log(NULL, AV_LOG_STDERR, "dr1 "); - if (c->capabilities & AV_CODEC_CAP_TRUNCATED) - av_log(NULL, AV_LOG_STDERR, "trunc "); - if (c->capabilities & AV_CODEC_CAP_DELAY) - av_log(NULL, AV_LOG_STDERR, "delay "); - if (c->capabilities & AV_CODEC_CAP_SMALL_LAST_FRAME) - av_log(NULL, AV_LOG_STDERR, "small "); - if (c->capabilities & AV_CODEC_CAP_SUBFRAMES) - av_log(NULL, AV_LOG_STDERR, "subframes "); - if (c->capabilities & AV_CODEC_CAP_EXPERIMENTAL) - av_log(NULL, AV_LOG_STDERR, "exp "); - if (c->capabilities & AV_CODEC_CAP_CHANNEL_CONF) - av_log(NULL, AV_LOG_STDERR, "chconf "); - if (c->capabilities & AV_CODEC_CAP_PARAM_CHANGE) - av_log(NULL, AV_LOG_STDERR, "paramchange "); - if (c->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE) - av_log(NULL, AV_LOG_STDERR, "variable "); - if (c->capabilities & (AV_CODEC_CAP_FRAME_THREADS | - AV_CODEC_CAP_SLICE_THREADS | - AV_CODEC_CAP_OTHER_THREADS)) - av_log(NULL, AV_LOG_STDERR, "threads "); - if (c->capabilities & AV_CODEC_CAP_AVOID_PROBING) - av_log(NULL, AV_LOG_STDERR, "avoidprobe "); - if (c->capabilities & AV_CODEC_CAP_HARDWARE) - av_log(NULL, AV_LOG_STDERR, "hardware "); - if (c->capabilities & AV_CODEC_CAP_HYBRID) - av_log(NULL, AV_LOG_STDERR, "hybrid "); - if (!c->capabilities) - av_log(NULL, AV_LOG_STDERR, "none"); - av_log(NULL, AV_LOG_STDERR, "\n"); - - if (c->type == AVMEDIA_TYPE_VIDEO || - c->type == AVMEDIA_TYPE_AUDIO) { - av_log(NULL, AV_LOG_STDERR, " Threading capabilities: "); - switch (c->capabilities & (AV_CODEC_CAP_FRAME_THREADS | - AV_CODEC_CAP_SLICE_THREADS | - AV_CODEC_CAP_OTHER_THREADS)) { - case AV_CODEC_CAP_FRAME_THREADS | - AV_CODEC_CAP_SLICE_THREADS: av_log(NULL, AV_LOG_STDERR, "frame and slice"); break; - case AV_CODEC_CAP_FRAME_THREADS: av_log(NULL, AV_LOG_STDERR, "frame"); break; - case AV_CODEC_CAP_SLICE_THREADS: av_log(NULL, AV_LOG_STDERR, "slice"); break; - case AV_CODEC_CAP_OTHER_THREADS : av_log(NULL, AV_LOG_STDERR, "other"); break; - default: av_log(NULL, AV_LOG_STDERR, "none"); break; - } - av_log(NULL, AV_LOG_STDERR, "\n"); - } - - if (avcodec_get_hw_config(c, 0)) { - av_log(NULL, AV_LOG_STDERR, " Supported hardware devices: "); - for (int i = 0;; i++) { - const AVCodecHWConfig *config = avcodec_get_hw_config(c, i); - if (!config) - break; - av_log(NULL, AV_LOG_STDERR, "%s ", av_hwdevice_get_type_name(config->device_type)); - } - av_log(NULL, AV_LOG_STDERR, "\n"); - } - - if (c->supported_framerates) { - const AVRational *fps = c->supported_framerates; - - av_log(NULL, AV_LOG_STDERR, " Supported framerates:"); - while (fps->num) { - av_log(NULL, AV_LOG_STDERR, " %d/%d", fps->num, fps->den); - fps++; - } - av_log(NULL, AV_LOG_STDERR, "\n"); - } - PRINT_CODEC_SUPPORTED(c, pix_fmts, enum AVPixelFormat, "pixel formats", - AV_PIX_FMT_NONE, GET_PIX_FMT_NAME); - PRINT_CODEC_SUPPORTED(c, supported_samplerates, int, "sample rates", 0, - GET_SAMPLE_RATE_NAME); - PRINT_CODEC_SUPPORTED(c, sample_fmts, enum AVSampleFormat, "sample formats", - AV_SAMPLE_FMT_NONE, GET_SAMPLE_FMT_NAME); - PRINT_CODEC_SUPPORTED(c, channel_layouts, uint64_t, "channel layouts", - 0, GET_CH_LAYOUT_DESC); - - if (c->priv_class) { - show_help_children(c->priv_class, - AV_OPT_FLAG_ENCODING_PARAM | - AV_OPT_FLAG_DECODING_PARAM); - } -} - -static char get_media_type_char(enum AVMediaType type) -{ - switch (type) { - case AVMEDIA_TYPE_VIDEO: return 'V'; - case AVMEDIA_TYPE_AUDIO: return 'A'; - case AVMEDIA_TYPE_DATA: return 'D'; - case AVMEDIA_TYPE_SUBTITLE: return 'S'; - case AVMEDIA_TYPE_ATTACHMENT:return 'T'; - default: return '?'; - } -} - -static const AVCodec *next_codec_for_id(enum AVCodecID id, void **iter, - int encoder) -{ - const AVCodec *c; - while ((c = av_codec_iterate(iter))) { - if (c->id == id && - (encoder ? av_codec_is_encoder(c) : av_codec_is_decoder(c))) - return c; - } - return NULL; -} - -static int compare_codec_desc(const void *a, const void *b) -{ - const AVCodecDescriptor * const *da = a; - const AVCodecDescriptor * const *db = b; - - return (*da)->type != (*db)->type ? FFDIFFSIGN((*da)->type, (*db)->type) : - strcmp((*da)->name, (*db)->name); -} - -static unsigned get_codecs_sorted(const AVCodecDescriptor ***rcodecs) -{ - const AVCodecDescriptor *desc = NULL; - const AVCodecDescriptor **codecs; - unsigned nb_codecs = 0, i = 0; - - while ((desc = avcodec_descriptor_next(desc))) - nb_codecs++; - if (!(codecs = av_calloc(nb_codecs, sizeof(*codecs)))) { - av_log(NULL, AV_LOG_ERROR, "Out of memory\n"); - exit_program(1); - } - desc = NULL; - while ((desc = avcodec_descriptor_next(desc))) - codecs[i++] = desc; - av_assert0(i == nb_codecs); - qsort(codecs, nb_codecs, sizeof(*codecs), compare_codec_desc); - *rcodecs = codecs; - return nb_codecs; -} - -static void print_codecs_for_id(enum AVCodecID id, int encoder) -{ - void *iter = NULL; - const AVCodec *codec; - - av_log(NULL, AV_LOG_STDERR, " (%s: ", encoder ? "encoders" : "decoders"); - - while ((codec = next_codec_for_id(id, &iter, encoder))) - av_log(NULL, AV_LOG_STDERR, "%s ", codec->name); - - av_log(NULL, AV_LOG_STDERR, ")"); -} - -int show_codecs(void *optctx, const char *opt, const char *arg) -{ - const AVCodecDescriptor **codecs; - unsigned i, nb_codecs = get_codecs_sorted(&codecs); - - av_log(NULL, AV_LOG_STDERR, "Codecs:\n" - " D..... = Decoding supported\n" - " .E.... = Encoding supported\n" - " ..V... = Video codec\n" - " ..A... = Audio codec\n" - " ..S... = Subtitle codec\n" - " ...I.. = Intra frame-only codec\n" - " ....L. = Lossy compression\n" - " .....S = Lossless compression\n" - " -------\n"); - for (i = 0; i < nb_codecs; i++) { - const AVCodecDescriptor *desc = codecs[i]; - const AVCodec *codec; - void *iter = NULL; - - if (strstr(desc->name, "_deprecated")) - continue; - - av_log(NULL, AV_LOG_STDERR, " "); - av_log(NULL, AV_LOG_STDERR, avcodec_find_decoder(desc->id) ? "D" : "."); - av_log(NULL, AV_LOG_STDERR, avcodec_find_encoder(desc->id) ? "E" : "."); - - av_log(NULL, AV_LOG_STDERR, "%c", get_media_type_char(desc->type)); - av_log(NULL, AV_LOG_STDERR, (desc->props & AV_CODEC_PROP_INTRA_ONLY) ? "I" : "."); - av_log(NULL, AV_LOG_STDERR, (desc->props & AV_CODEC_PROP_LOSSY) ? "L" : "."); - av_log(NULL, AV_LOG_STDERR, (desc->props & AV_CODEC_PROP_LOSSLESS) ? "S" : "."); - - av_log(NULL, AV_LOG_STDERR, " %-20s %s", desc->name, desc->long_name ? desc->long_name : ""); - - /* print decoders/encoders when there's more than one or their - * names are different from codec name */ - while ((codec = next_codec_for_id(desc->id, &iter, 0))) { - if (strcmp(codec->name, desc->name)) { - print_codecs_for_id(desc->id, 0); - break; - } - } - iter = NULL; - while ((codec = next_codec_for_id(desc->id, &iter, 1))) { - if (strcmp(codec->name, desc->name)) { - print_codecs_for_id(desc->id, 1); - break; - } - } - - av_log(NULL, AV_LOG_STDERR, "\n"); - } - av_free(codecs); - return 0; -} - -static void print_codecs(int encoder) -{ - const AVCodecDescriptor **codecs; - unsigned i, nb_codecs = get_codecs_sorted(&codecs); - - av_log(NULL, AV_LOG_STDERR, "%s:\n" - " V..... = Video\n" - " A..... = Audio\n" - " S..... = Subtitle\n" - " .F.... = Frame-level multithreading\n" - " ..S... = Slice-level multithreading\n" - " ...X.. = Codec is experimental\n" - " ....B. = Supports draw_horiz_band\n" - " .....D = Supports direct rendering method 1\n" - " ------\n", - encoder ? "Encoders" : "Decoders"); - for (i = 0; i < nb_codecs; i++) { - const AVCodecDescriptor *desc = codecs[i]; - const AVCodec *codec; - void *iter = NULL; - - while ((codec = next_codec_for_id(desc->id, &iter, encoder))) { - av_log(NULL, AV_LOG_STDERR, " %c", get_media_type_char(desc->type)); - av_log(NULL, AV_LOG_STDERR, (codec->capabilities & AV_CODEC_CAP_FRAME_THREADS) ? "F" : "."); - av_log(NULL, AV_LOG_STDERR, (codec->capabilities & AV_CODEC_CAP_SLICE_THREADS) ? "S" : "."); - av_log(NULL, AV_LOG_STDERR, (codec->capabilities & AV_CODEC_CAP_EXPERIMENTAL) ? "X" : "."); - av_log(NULL, AV_LOG_STDERR, (codec->capabilities & AV_CODEC_CAP_DRAW_HORIZ_BAND)?"B" : "."); - av_log(NULL, AV_LOG_STDERR, (codec->capabilities & AV_CODEC_CAP_DR1) ? "D" : "."); - - av_log(NULL, AV_LOG_STDERR, " %-20s %s", codec->name, codec->long_name ? codec->long_name : ""); - if (strcmp(codec->name, desc->name)) - av_log(NULL, AV_LOG_STDERR, " (codec %s)", desc->name); - - av_log(NULL, AV_LOG_STDERR, "\n"); - } - } - av_free(codecs); -} - -int show_decoders(void *optctx, const char *opt, const char *arg) -{ - print_codecs(0); - return 0; -} - -int show_encoders(void *optctx, const char *opt, const char *arg) -{ - print_codecs(1); - return 0; -} - -int show_bsfs(void *optctx, const char *opt, const char *arg) -{ - const AVBitStreamFilter *bsf = NULL; - void *opaque = NULL; - - av_log(NULL, AV_LOG_STDERR, "Bitstream filters:\n"); - while ((bsf = av_bsf_iterate(&opaque))) - av_log(NULL, AV_LOG_STDERR, "%s\n", bsf->name); - av_log(NULL, AV_LOG_STDERR, "\n"); - return 0; -} - -int show_protocols(void *optctx, const char *opt, const char *arg) -{ - void *opaque = NULL; - const char *name; - - av_log(NULL, AV_LOG_STDERR, "Supported file protocols:\n" - "Input:\n"); - while ((name = avio_enum_protocols(&opaque, 0))) - av_log(NULL, AV_LOG_STDERR, " %s\n", name); - av_log(NULL, AV_LOG_STDERR, "Output:\n"); - while ((name = avio_enum_protocols(&opaque, 1))) - av_log(NULL, AV_LOG_STDERR, " %s\n", name); - return 0; -} - -int show_filters(void *optctx, const char *opt, const char *arg) -{ -#if CONFIG_AVFILTER - const AVFilter *filter = NULL; - char descr[64], *descr_cur; - void *opaque = NULL; - int i, j; - const AVFilterPad *pad; - - av_log(NULL, AV_LOG_STDERR, "Filters:\n" - " T.. = Timeline support\n" - " .S. = Slice threading\n" - " ..C = Command support\n" - " A = Audio input/output\n" - " V = Video input/output\n" - " N = Dynamic number and/or type of input/output\n" - " | = Source or sink filter\n"); - while ((filter = av_filter_iterate(&opaque))) { - descr_cur = descr; - for (i = 0; i < 2; i++) { - if (i) { - *(descr_cur++) = '-'; - *(descr_cur++) = '>'; - } - pad = i ? filter->outputs : filter->inputs; - for (j = 0; pad && avfilter_pad_get_name(pad, j); j++) { - if (descr_cur >= descr + sizeof(descr) - 4) - break; - *(descr_cur++) = get_media_type_char(avfilter_pad_get_type(pad, j)); - } - if (!j) - *(descr_cur++) = ((!i && (filter->flags & AVFILTER_FLAG_DYNAMIC_INPUTS)) || - ( i && (filter->flags & AVFILTER_FLAG_DYNAMIC_OUTPUTS))) ? 'N' : '|'; - } - *descr_cur = 0; - av_log(NULL, AV_LOG_STDERR, " %c%c%c %-17s %-10s %s\n", - filter->flags & AVFILTER_FLAG_SUPPORT_TIMELINE ? 'T' : '.', - filter->flags & AVFILTER_FLAG_SLICE_THREADS ? 'S' : '.', - filter->process_command ? 'C' : '.', - filter->name, descr, filter->description); - } -#else - av_log(NULL, AV_LOG_STDERR, "No filters available: libavfilter disabled\n"); -#endif - return 0; -} - -int show_colors(void *optctx, const char *opt, const char *arg) -{ - const char *name; - const uint8_t *rgb; - int i; - - av_log(NULL, AV_LOG_STDERR, "%-32s #RRGGBB\n", "name"); - - for (i = 0; (name = av_get_known_color_name(i, &rgb)); i++) - av_log(NULL, AV_LOG_STDERR, "%-32s #%02x%02x%02x\n", name, rgb[0], rgb[1], rgb[2]); - - return 0; -} - -int show_pix_fmts(void *optctx, const char *opt, const char *arg) -{ - const AVPixFmtDescriptor *pix_desc = NULL; - - av_log(NULL, AV_LOG_STDERR, "Pixel formats:\n" - "I.... = Supported Input format for conversion\n" - ".O... = Supported Output format for conversion\n" - "..H.. = Hardware accelerated format\n" - "...P. = Paletted format\n" - "....B = Bitstream format\n" - "FLAGS NAME NB_COMPONENTS BITS_PER_PIXEL\n" - "-----\n"); - -#if !CONFIG_SWSCALE -# define sws_isSupportedInput(x) 0 -# define sws_isSupportedOutput(x) 0 -#endif - - while ((pix_desc = av_pix_fmt_desc_next(pix_desc))) { - enum AVPixelFormat av_unused pix_fmt = av_pix_fmt_desc_get_id(pix_desc); - av_log(NULL, AV_LOG_STDERR, "%c%c%c%c%c %-16s %d %2d\n", - sws_isSupportedInput (pix_fmt) ? 'I' : '.', - sws_isSupportedOutput(pix_fmt) ? 'O' : '.', - pix_desc->flags & AV_PIX_FMT_FLAG_HWACCEL ? 'H' : '.', - pix_desc->flags & AV_PIX_FMT_FLAG_PAL ? 'P' : '.', - pix_desc->flags & AV_PIX_FMT_FLAG_BITSTREAM ? 'B' : '.', - pix_desc->name, - pix_desc->nb_components, - av_get_bits_per_pixel(pix_desc)); - } - return 0; -} - -int show_layouts(void *optctx, const char *opt, const char *arg) -{ - int i = 0; - uint64_t layout, j; - const char *name, *descr; - - av_log(NULL, AV_LOG_STDERR, "Individual channels:\n" - "NAME DESCRIPTION\n"); - for (i = 0; i < 63; i++) { - name = av_get_channel_name((uint64_t)1 << i); - if (!name) - continue; - descr = av_get_channel_description((uint64_t)1 << i); - av_log(NULL, AV_LOG_STDERR, "%-14s %s\n", name, descr); - } - av_log(NULL, AV_LOG_STDERR, "\nStandard channel layouts:\n" - "NAME DECOMPOSITION\n"); - for (i = 0; !av_get_standard_channel_layout(i, &layout, &name); i++) { - if (name) { - av_log(NULL, AV_LOG_STDERR, "%-14s ", name); - for (j = 1; j; j <<= 1) - if ((layout & j)) - av_log(NULL, AV_LOG_STDERR, "%s%s", (layout & (j - 1)) ? "+" : "", av_get_channel_name(j)); - av_log(NULL, AV_LOG_STDERR, "\n"); - } - } - return 0; -} - -int show_sample_fmts(void *optctx, const char *opt, const char *arg) -{ - int i; - char fmt_str[128]; - for (i = -1; i < AV_SAMPLE_FMT_NB; i++) - av_log(NULL, AV_LOG_STDERR, "%s\n", av_get_sample_fmt_string(fmt_str, sizeof(fmt_str), i)); - return 0; -} - -static void show_help_codec(const char *name, int encoder) -{ - const AVCodecDescriptor *desc; - const AVCodec *codec; - - if (!name) { - av_log(NULL, AV_LOG_ERROR, "No codec name specified.\n"); - return; - } - - codec = encoder ? avcodec_find_encoder_by_name(name) : - avcodec_find_decoder_by_name(name); - - if (codec) - print_codec(codec); - else if ((desc = avcodec_descriptor_get_by_name(name))) { - void *iter = NULL; - int printed = 0; - - while ((codec = next_codec_for_id(desc->id, &iter, encoder))) { - printed = 1; - print_codec(codec); - } - - if (!printed) { - av_log(NULL, AV_LOG_ERROR, "Codec '%s' is known to FFmpeg, " - "but no %s for it are available. FFmpeg might need to be " - "recompiled with additional external libraries.\n", - name, encoder ? "encoders" : "decoders"); - } - } else { - av_log(NULL, AV_LOG_ERROR, "Codec '%s' is not recognized by FFmpeg.\n", - name); - } -} - -static void show_help_demuxer(const char *name) -{ - const AVInputFormat *fmt = av_find_input_format(name); - - if (!fmt) { - av_log(NULL, AV_LOG_ERROR, "Unknown format '%s'.\n", name); - return; - } - - av_log(NULL, AV_LOG_STDERR, "Demuxer %s [%s]:\n", fmt->name, fmt->long_name); - - if (fmt->extensions) - av_log(NULL, AV_LOG_STDERR, " Common extensions: %s.\n", fmt->extensions); - - if (fmt->priv_class) - show_help_children(fmt->priv_class, AV_OPT_FLAG_DECODING_PARAM); -} - -static void show_help_protocol(const char *name) -{ - const AVClass *proto_class; - - if (!name) { - av_log(NULL, AV_LOG_ERROR, "No protocol name specified.\n"); - return; - } - - proto_class = avio_protocol_get_class(name); - if (!proto_class) { - av_log(NULL, AV_LOG_ERROR, "Unknown protocol '%s'.\n", name); - return; - } - - show_help_children(proto_class, AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_ENCODING_PARAM); -} - -static void show_help_muxer(const char *name) -{ - const AVCodecDescriptor *desc; - const AVOutputFormat *fmt = av_guess_format(name, NULL, NULL); - - if (!fmt) { - av_log(NULL, AV_LOG_ERROR, "Unknown format '%s'.\n", name); - return; - } - - av_log(NULL, AV_LOG_STDERR, "Muxer %s [%s]:\n", fmt->name, fmt->long_name); - - if (fmt->extensions) - av_log(NULL, AV_LOG_STDERR, " Common extensions: %s.\n", fmt->extensions); - if (fmt->mime_type) - av_log(NULL, AV_LOG_STDERR, " Mime type: %s.\n", fmt->mime_type); - if (fmt->video_codec != AV_CODEC_ID_NONE && - (desc = avcodec_descriptor_get(fmt->video_codec))) { - av_log(NULL, AV_LOG_STDERR, " Default video codec: %s.\n", desc->name); - } - if (fmt->audio_codec != AV_CODEC_ID_NONE && - (desc = avcodec_descriptor_get(fmt->audio_codec))) { - av_log(NULL, AV_LOG_STDERR, " Default audio codec: %s.\n", desc->name); - } - if (fmt->subtitle_codec != AV_CODEC_ID_NONE && - (desc = avcodec_descriptor_get(fmt->subtitle_codec))) { - av_log(NULL, AV_LOG_STDERR, " Default subtitle codec: %s.\n", desc->name); - } - - if (fmt->priv_class) - show_help_children(fmt->priv_class, AV_OPT_FLAG_ENCODING_PARAM); -} - -#if CONFIG_AVFILTER -static void show_help_filter(const char *name) -{ -#if CONFIG_AVFILTER - const AVFilter *f = avfilter_get_by_name(name); - int i, count; - - if (!name) { - av_log(NULL, AV_LOG_ERROR, "No filter name specified.\n"); - return; - } else if (!f) { - av_log(NULL, AV_LOG_ERROR, "Unknown filter '%s'.\n", name); - return; - } - - av_log(NULL, AV_LOG_STDERR, "Filter %s\n", f->name); - if (f->description) - av_log(NULL, AV_LOG_STDERR, " %s\n", f->description); - - if (f->flags & AVFILTER_FLAG_SLICE_THREADS) - av_log(NULL, AV_LOG_STDERR, " slice threading supported\n"); - - av_log(NULL, AV_LOG_STDERR, " Inputs:\n"); - count = avfilter_pad_count(f->inputs); - for (i = 0; i < count; i++) { - av_log(NULL, AV_LOG_STDERR, " #%d: %s (%s)\n", i, avfilter_pad_get_name(f->inputs, i), - media_type_string(avfilter_pad_get_type(f->inputs, i))); - } - if (f->flags & AVFILTER_FLAG_DYNAMIC_INPUTS) - av_log(NULL, AV_LOG_STDERR, " dynamic (depending on the options)\n"); - else if (!count) - av_log(NULL, AV_LOG_STDERR, " none (source filter)\n"); - - av_log(NULL, AV_LOG_STDERR, " Outputs:\n"); - count = avfilter_pad_count(f->outputs); - for (i = 0; i < count; i++) { - av_log(NULL, AV_LOG_STDERR, " #%d: %s (%s)\n", i, avfilter_pad_get_name(f->outputs, i), - media_type_string(avfilter_pad_get_type(f->outputs, i))); - } - if (f->flags & AVFILTER_FLAG_DYNAMIC_OUTPUTS) - av_log(NULL, AV_LOG_STDERR, " dynamic (depending on the options)\n"); - else if (!count) - av_log(NULL, AV_LOG_STDERR, " none (sink filter)\n"); - - if (f->priv_class) - show_help_children(f->priv_class, AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM | - AV_OPT_FLAG_AUDIO_PARAM); - if (f->flags & AVFILTER_FLAG_SUPPORT_TIMELINE) - av_log(NULL, AV_LOG_STDERR, "This filter has support for timeline through the 'enable' option.\n"); -#else - av_log(NULL, AV_LOG_ERROR, "Build without libavfilter; " - "can not to satisfy request\n"); -#endif -} -#endif - -static void show_help_bsf(const char *name) -{ - const AVBitStreamFilter *bsf = av_bsf_get_by_name(name); - - if (!name) { - av_log(NULL, AV_LOG_ERROR, "No bitstream filter name specified.\n"); - return; - } else if (!bsf) { - av_log(NULL, AV_LOG_ERROR, "Unknown bit stream filter '%s'.\n", name); - return; - } - - av_log(NULL, AV_LOG_STDERR, "Bit stream filter %s\n", bsf->name); - PRINT_CODEC_SUPPORTED(bsf, codec_ids, enum AVCodecID, "codecs", - AV_CODEC_ID_NONE, GET_CODEC_NAME); - if (bsf->priv_class) - show_help_children(bsf->priv_class, AV_OPT_FLAG_BSF_PARAM); -} - -int show_help(void *optctx, const char *opt, const char *arg) -{ - char *topic, *par; - - topic = av_strdup(arg ? arg : ""); - if (!topic) - return AVERROR(ENOMEM); - par = strchr(topic, '='); - if (par) - *par++ = 0; - - if (!*topic) { - if (program_name && !strcmp(program_name, "ffmpeg")) { - show_help_default_ffmpeg(topic, par); - } else { - show_help_default_ffprobe(topic, par); - } - } else if (!strcmp(topic, "decoder")) { - show_help_codec(par, 0); - } else if (!strcmp(topic, "encoder")) { - show_help_codec(par, 1); - } else if (!strcmp(topic, "demuxer")) { - show_help_demuxer(par); - } else if (!strcmp(topic, "muxer")) { - show_help_muxer(par); - } else if (!strcmp(topic, "protocol")) { - show_help_protocol(par); -#if CONFIG_AVFILTER - } else if (!strcmp(topic, "filter")) { - show_help_filter(par); -#endif - } else if (!strcmp(topic, "bsf")) { - show_help_bsf(par); - } else { - if (program_name && !strcmp(program_name, "ffmpeg")) { - show_help_default_ffmpeg(topic, par); - } else { - show_help_default_ffprobe(topic, par); - } - } - - av_freep(&topic); - return 0; -} - int read_yesno(void) { int c = getchar(); @@ -2104,28 +868,45 @@ FILE *get_preset_file(char *filename, size_t filename_size, { FILE *f = NULL; int i; - const char *base[3] = { getenv("FFMPEG_DATADIR"), - getenv("HOME"), +#if HAVE_GETMODULEHANDLE && defined(_WIN32) + char *datadir = NULL; +#endif + char *env_home = getenv_utf8("HOME"); + char *env_ffmpeg_datadir = getenv_utf8("FFMPEG_DATADIR"); + const char *base[3] = { env_ffmpeg_datadir, + env_home, /* index=1(HOME) is special: search in a .ffmpeg subfolder */ FFMPEG_DATADIR, }; if (is_path) { av_strlcpy(filename, preset_name, filename_size); - f = fopen(filename, "r"); + f = fopen_utf8(filename, "r"); } else { #if HAVE_GETMODULEHANDLE && defined(_WIN32) - char datadir[MAX_PATH], *ls; + wchar_t *datadir_w = get_module_filename(NULL); base[2] = NULL; - if (GetModuleFileNameA(GetModuleHandleA(NULL), datadir, sizeof(datadir) - 1)) + if (wchartoutf8(datadir_w, &datadir)) + datadir = NULL; + av_free(datadir_w); + + if (datadir) { - for (ls = datadir; ls < datadir + strlen(datadir); ls++) + char *ls; + for (ls = datadir; *ls; ls++) if (*ls == '\\') *ls = '/'; if (ls = strrchr(datadir, '/')) { - *ls = 0; - strncat(datadir, "/ffpresets", sizeof(datadir) - 1 - strlen(datadir)); - base[2] = datadir; + ptrdiff_t datadir_len = ls - datadir; + size_t desired_size = datadir_len + strlen("/ffpresets") + 1; + char *new_datadir = av_realloc_array( + datadir, desired_size, sizeof *datadir); + if (new_datadir) { + datadir = new_datadir; + datadir[datadir_len] = 0; + strncat(datadir, "/ffpresets", desired_size - 1 - datadir_len); + base[2] = datadir; + } } } #endif @@ -2134,17 +915,22 @@ FILE *get_preset_file(char *filename, size_t filename_size, continue; snprintf(filename, filename_size, "%s%s/%s.ffpreset", base[i], i != 1 ? "" : "/.ffmpeg", preset_name); - f = fopen(filename, "r"); + f = fopen_utf8(filename, "r"); if (!f && codec_name) { snprintf(filename, filename_size, "%s%s/%s-%s.ffpreset", base[i], i != 1 ? "" : "/.ffmpeg", codec_name, preset_name); - f = fopen(filename, "r"); + f = fopen_utf8(filename, "r"); } } } +#if HAVE_GETMODULEHANDLE && defined(_WIN32) + av_free(datadir); +#endif + freeenv_utf8(env_ffmpeg_datadir); + freeenv_utf8(env_home); return f; } @@ -2160,7 +946,7 @@ AVDictionary *filter_codec_opts(AVDictionary *opts, enum AVCodecID codec_id, AVFormatContext *s, AVStream *st, const AVCodec *codec) { AVDictionary *ret = NULL; - AVDictionaryEntry *t = NULL; + const AVDictionaryEntry *t = NULL; int flags = s->oformat ? AV_OPT_FLAG_ENCODING_PARAM : AV_OPT_FLAG_DECODING_PARAM; char prefix = 0; @@ -2222,11 +1008,11 @@ AVDictionary **setup_find_stream_info_opts(AVFormatContext *s, if (!s->nb_streams) return NULL; - opts = av_mallocz_array(s->nb_streams, sizeof(*opts)); + opts = av_calloc(s->nb_streams, sizeof(*opts)); if (!opts) { av_log(NULL, AV_LOG_ERROR, "Could not alloc memory for stream options.\n"); - return NULL; + exit_program(1); } for (i = 0; i < s->nb_streams; i++) opts[i] = filter_codec_opts(codec_opts, s->streams[i]->codecpar->codec_id, @@ -2253,13 +1039,23 @@ void *grow_array(void *array, int elem_size, int *size, int new_size) return array; } -double get_rotation(AVStream *st) +void *allocate_array_elem(void *ptr, size_t elem_size, int *nb_elems) +{ + void *new_elem; + + if (!(new_elem = av_mallocz(elem_size)) || + av_dynarray_add_nofree(ptr, nb_elems, new_elem) < 0) { + av_log(NULL, AV_LOG_ERROR, "Could not alloc buffer.\n"); + exit_program(1); + } + return new_elem; +} + +double get_rotation(int32_t *displaymatrix) { - uint8_t* displaymatrix = av_stream_get_side_data(st, - AV_PKT_DATA_DISPLAYMATRIX, NULL); double theta = 0; if (displaymatrix) - theta = -av_display_rotation_get((int32_t*) displaymatrix); + theta = -round(av_display_rotation_get((int32_t*) displaymatrix)); theta -= 360*floor(theta/360 + 0.9/360); @@ -2271,162 +1067,3 @@ double get_rotation(AVStream *st) return theta; } - -#if CONFIG_AVDEVICE -static int print_device_sources(const AVInputFormat *fmt, AVDictionary *opts) -{ - int ret, i; - AVDeviceInfoList *device_list = NULL; - - if (!fmt || !fmt->priv_class || !AV_IS_INPUT_DEVICE(fmt->priv_class->category)) - return AVERROR(EINVAL); - - av_log(NULL, AV_LOG_STDERR, "Auto-detected sources for %s:\n", fmt->name); - if (!fmt->get_device_list) { - ret = AVERROR(ENOSYS); - av_log(NULL, AV_LOG_STDERR, "Cannot list sources. Not implemented.\n"); - goto fail; - } - - if ((ret = avdevice_list_input_sources(fmt, NULL, opts, &device_list)) < 0) { - av_log(NULL, AV_LOG_STDERR, "Cannot list sources.\n"); - goto fail; - } - - for (i = 0; i < device_list->nb_devices; i++) { - av_log(NULL, AV_LOG_STDERR, "%s %s [%s]\n", device_list->default_device == i ? "*" : " ", - device_list->devices[i]->device_name, device_list->devices[i]->device_description); - } - - fail: - avdevice_free_list_devices(&device_list); - return ret; -} - -static int print_device_sinks(const AVOutputFormat *fmt, AVDictionary *opts) -{ - int ret, i; - AVDeviceInfoList *device_list = NULL; - - if (!fmt || !fmt->priv_class || !AV_IS_OUTPUT_DEVICE(fmt->priv_class->category)) - return AVERROR(EINVAL); - - av_log(NULL, AV_LOG_STDERR, "Auto-detected sinks for %s:\n", fmt->name); - if (!fmt->get_device_list) { - ret = AVERROR(ENOSYS); - av_log(NULL, AV_LOG_STDERR, "Cannot list sinks. Not implemented.\n"); - goto fail; - } - - if ((ret = avdevice_list_output_sinks(fmt, NULL, opts, &device_list)) < 0) { - av_log(NULL, AV_LOG_STDERR, "Cannot list sinks.\n"); - goto fail; - } - - for (i = 0; i < device_list->nb_devices; i++) { - av_log(NULL, AV_LOG_STDERR, "%s %s [%s]\n", device_list->default_device == i ? "*" : " ", - device_list->devices[i]->device_name, device_list->devices[i]->device_description); - } - - fail: - avdevice_free_list_devices(&device_list); - return ret; -} - -static int show_sinks_sources_parse_arg(const char *arg, char **dev, AVDictionary **opts) -{ - int ret; - if (arg) { - char *opts_str = NULL; - av_assert0(dev && opts); - *dev = av_strdup(arg); - if (!*dev) - return AVERROR(ENOMEM); - if ((opts_str = strchr(*dev, ','))) { - *(opts_str++) = '\0'; - if (opts_str[0] && ((ret = av_dict_parse_string(opts, opts_str, "=", ":", 0)) < 0)) { - av_freep(dev); - return ret; - } - } - } else - av_log(NULL, AV_LOG_STDERR, "\nDevice name is not provided.\n" - "You can pass devicename[,opt1=val1[,opt2=val2...]] as an argument.\n\n"); - return 0; -} - -int show_sources(void *optctx, const char *opt, const char *arg) -{ - const AVInputFormat *fmt = NULL; - char *dev = NULL; - AVDictionary *opts = NULL; - int ret = 0; - int error_level = av_log_get_level(); - - av_log_set_level(AV_LOG_WARNING); - - if ((ret = show_sinks_sources_parse_arg(arg, &dev, &opts)) < 0) - goto fail; - - do { - fmt = av_input_audio_device_next(fmt); - if (fmt) { - if (!strcmp(fmt->name, "lavfi")) - continue; //it's pointless to probe lavfi - if (dev && !av_match_name(dev, fmt->name)) - continue; - print_device_sources(fmt, opts); - } - } while (fmt); - do { - fmt = av_input_video_device_next(fmt); - if (fmt) { - if (dev && !av_match_name(dev, fmt->name)) - continue; - print_device_sources(fmt, opts); - } - } while (fmt); - fail: - av_dict_free(&opts); - av_free(dev); - av_log_set_level(error_level); - return ret; -} - -int show_sinks(void *optctx, const char *opt, const char *arg) -{ - const AVOutputFormat *fmt = NULL; - char *dev = NULL; - AVDictionary *opts = NULL; - int ret = 0; - int error_level = av_log_get_level(); - - av_log_set_level(AV_LOG_WARNING); - - if ((ret = show_sinks_sources_parse_arg(arg, &dev, &opts)) < 0) - goto fail; - - do { - fmt = av_output_audio_device_next(fmt); - if (fmt) { - if (dev && !av_match_name(dev, fmt->name)) - continue; - print_device_sinks(fmt, opts); - } - } while (fmt); - do { - fmt = av_output_video_device_next(fmt); - if (fmt) { - if (dev && !av_match_name(dev, fmt->name)) - continue; - print_device_sinks(fmt, opts); - } - } while (fmt); - fail: - av_dict_free(&opts); - av_free(dev); - av_log_set_level(error_level); - return ret; -} - -#endif diff --git a/android/ffmpeg-kit-android-lib/src/main/cpp/fftools_cmdutils.h b/android/ffmpeg-kit-android-lib/src/main/cpp/fftools_cmdutils.h index e337ee7..d0b1e90 100644 --- a/android/ffmpeg-kit-android-lib/src/main/cpp/fftools_cmdutils.h +++ b/android/ffmpeg-kit-android-lib/src/main/cpp/fftools_cmdutils.h @@ -1,6 +1,7 @@ /* * Various utilities for command line tools * copyright (c) 2003 Fabrice Bellard + * copyright (c) 2018 Taner Sener ( tanersener gmail com ) * * This file is part of FFmpeg. * @@ -20,25 +21,37 @@ */ /* - * CHANGES 01.2020 - * - ffprobe support changes - * - AV_LOG_STDERR introduced + * This file is the modified version of cmdutils.h file living in ffmpeg source code under the fftools folder. We + * manually update it each time we depend on a new ffmpeg version. Below you can see the list of changes applied + * by us to develop mobile-ffmpeg and later ffmpeg-kit libraries. * - * CHANGES 12.2019 - * - Concurrent execution support + * mobile-ffmpeg / ffmpeg-kit changes by Taner Sener * - * CHANGES 03.2019 + * 09.2022 + * -------------------------------------------------------- + * - config.h include added back + * + * 01.2020 + * -------------------------------------------------------- + * - ffprobe support added (variables used by ffprobe marked with "__thread" specifier) + * - AV_LOG_STDERR log level added + * + * 12.2019 + * -------------------------------------------------------- + * - concurrent execution support ("__thread" specifier added to variables used by multiple threads) + * + * 03.2019 * -------------------------------------------------------- * - config.h include removed * - * CHANGES 08.2018 + * 08.2018 * -------------------------------------------------------- * - fftools_ prefix added to file name and include guards * - * CHANGES 07.2018 + * 07.2018 * -------------------------------------------------------- - * - Include guards renamed - * - Unused headers removed + * - include guards renamed + * - unused headers removed */ #ifndef FFTOOLS_CMDUTILS_H @@ -46,6 +59,7 @@ #include +#include "config.h" #include "libavcodec/avcodec.h" #include "libavfilter/avfilter.h" #include "libavformat/avformat.h" @@ -70,11 +84,9 @@ extern __thread char *program_name; */ extern __thread int program_birth_year; -extern __thread AVCodecContext *avcodec_opts[AVMEDIA_TYPE_NB]; -extern __thread AVFormatContext *avformat_opts; extern __thread AVDictionary *sws_dict; extern __thread AVDictionary *swr_opts; -extern __thread AVDictionary *format_opts, *codec_opts, *resample_opts; +extern __thread AVDictionary *format_opts, *codec_opts; extern __thread int hide_banner; extern __thread int find_stream_info; @@ -93,11 +105,6 @@ void exit_program(int ret) av_noreturn; */ void init_dynload(void); -/** - * Initialize the cmdutils option system, in particular - * allocate the *_opts contexts. - */ -void init_opts(void); /** * Uninitialize the cmdutils option system, in particular * free the *_opts contexts and their contents. @@ -110,33 +117,12 @@ void uninit_opts(void); */ void log_callback_help(void* ptr, int level, const char* fmt, va_list vl); -/** - * Override the cpuflags. - */ -int opt_cpuflags(void *optctx, const char *opt, const char *arg); - -/** - * Override the cpucount. - */ -int opt_cpucount(void *optctx, const char *opt, const char *arg); - /** * Fallback for options that are not explicitly handled, these will be * parsed through AVOptions. */ int opt_default(void *optctx, const char *opt, const char *arg); -/** - * Set the libav* libraries log level. - */ -int opt_loglevel(void *optctx, const char *opt, const char *arg); - -int opt_report(void *optctx, const char *opt, const char *arg); - -int opt_max_alloc(void *optctx, const char *opt, const char *arg); - -int opt_codec_debug(void *optctx, const char *opt, const char *arg); - /** * Limit the execution time. */ @@ -237,7 +223,7 @@ void show_help_options(const OptionDef *options, const char *msg, int req_flags, * Show help for all options with given flags in class and all its * children. */ -void show_help_children(const AVClass *class, int flags); +void show_help_children(const AVClass *clazz, int flags); /** * Per-fftool specific help handler. Implemented in each @@ -309,7 +295,6 @@ typedef struct OptionGroup { AVDictionary *codec_opts; AVDictionary *format_opts; - AVDictionary *resample_opts; AVDictionary *sws_dict; AVDictionary *swr_opts; } OptionGroup; @@ -417,8 +402,8 @@ AVDictionary *filter_codec_opts(AVDictionary *opts, enum AVCodecID codec_id, * Each dictionary will contain the options from codec_opts which can * be applied to the corresponding stream codec context. * - * @return pointer to the created array of dictionaries, NULL if it - * cannot be created + * @return pointer to the created array of dictionaries. + * Calls exit() on failure. */ AVDictionary **setup_find_stream_info_opts(AVFormatContext *s, AVDictionary *codec_opts); @@ -441,136 +426,6 @@ void print_error(const char *filename, int err); */ void show_banner(int argc, char **argv, const OptionDef *options); -/** - * Print the version of the program to stdout. The version message - * depends on the current versions of the repository and of the libav* - * libraries. - * This option processing function does not utilize the arguments. - */ -int show_version(void *optctx, const char *opt, const char *arg); - -/** - * Print the build configuration of the program to stdout. The contents - * depend on the definition of FFMPEG_CONFIGURATION. - * This option processing function does not utilize the arguments. - */ -int show_buildconf(void *optctx, const char *opt, const char *arg); - -/** - * Print the license of the program to stdout. The license depends on - * the license of the libraries compiled into the program. - * This option processing function does not utilize the arguments. - */ -int show_license(void *optctx, const char *opt, const char *arg); - -/** - * Print a listing containing all the formats supported by the - * program (including devices). - * This option processing function does not utilize the arguments. - */ -int show_formats(void *optctx, const char *opt, const char *arg); - -/** - * Print a listing containing all the muxers supported by the - * program (including devices). - * This option processing function does not utilize the arguments. - */ -int show_muxers(void *optctx, const char *opt, const char *arg); - -/** - * Print a listing containing all the demuxer supported by the - * program (including devices). - * This option processing function does not utilize the arguments. - */ -int show_demuxers(void *optctx, const char *opt, const char *arg); - -/** - * Print a listing containing all the devices supported by the - * program. - * This option processing function does not utilize the arguments. - */ -int show_devices(void *optctx, const char *opt, const char *arg); - -#if CONFIG_AVDEVICE -/** - * Print a listing containing autodetected sinks of the output device. - * Device name with options may be passed as an argument to limit results. - */ -int show_sinks(void *optctx, const char *opt, const char *arg); - -/** - * Print a listing containing autodetected sources of the input device. - * Device name with options may be passed as an argument to limit results. - */ -int show_sources(void *optctx, const char *opt, const char *arg); -#endif - -/** - * Print a listing containing all the codecs supported by the - * program. - * This option processing function does not utilize the arguments. - */ -int show_codecs(void *optctx, const char *opt, const char *arg); - -/** - * Print a listing containing all the decoders supported by the - * program. - */ -int show_decoders(void *optctx, const char *opt, const char *arg); - -/** - * Print a listing containing all the encoders supported by the - * program. - */ -int show_encoders(void *optctx, const char *opt, const char *arg); - -/** - * Print a listing containing all the filters supported by the - * program. - * This option processing function does not utilize the arguments. - */ -int show_filters(void *optctx, const char *opt, const char *arg); - -/** - * Print a listing containing all the bit stream filters supported by the - * program. - * This option processing function does not utilize the arguments. - */ -int show_bsfs(void *optctx, const char *opt, const char *arg); - -/** - * Print a listing containing all the protocols supported by the - * program. - * This option processing function does not utilize the arguments. - */ -int show_protocols(void *optctx, const char *opt, const char *arg); - -/** - * Print a listing containing all the pixel formats supported by the - * program. - * This option processing function does not utilize the arguments. - */ -int show_pix_fmts(void *optctx, const char *opt, const char *arg); - -/** - * Print a listing containing all the standard channel layouts supported by - * the program. - * This option processing function does not utilize the arguments. - */ -int show_layouts(void *optctx, const char *opt, const char *arg); - -/** - * Print a listing containing all the sample formats supported by the - * program. - */ -int show_sample_fmts(void *optctx, const char *opt, const char *arg); - -/** - * Print a listing containing all the color names and values recognized - * by the program. - */ -int show_colors(void *optctx, const char *opt, const char *arg); - /** * Return a positive value if a line read from standard input * starts with [yY], otherwise return 0. @@ -610,11 +465,26 @@ FILE *get_preset_file(char *filename, size_t filename_size, */ void *grow_array(void *array, int elem_size, int *size, int new_size); -#define media_type_string av_get_media_type_string +/** + * Atomically add a new element to an array of pointers, i.e. allocate + * a new entry, reallocate the array of pointers and make the new last + * member of this array point to the newly allocated buffer. + * Calls exit() on failure. + * + * @param array array of pointers to reallocate + * @param elem_size size of the new element to allocate + * @param nb_elems pointer to the number of elements of the array array; + * *nb_elems will be incremented by one by this function. + * @return pointer to the newly allocated entry + */ +void *allocate_array_elem(void *array, size_t elem_size, int *nb_elems); #define GROW_ARRAY(array, nb_elems)\ array = grow_array(array, sizeof(*array), &nb_elems, nb_elems + 1) +#define ALLOC_ARRAY_ELEM(array, nb_elems)\ + allocate_array_elem(&array, sizeof(*array[0]), &nb_elems) + #define GET_PIX_FMT_NAME(pix_fmt)\ const char *name = av_get_pix_fmt_name(pix_fmt); @@ -628,14 +498,6 @@ void *grow_array(void *array, int elem_size, int *size, int new_size); char name[16];\ snprintf(name, sizeof(name), "%d", rate); -#define GET_CH_LAYOUT_NAME(ch_layout)\ - char name[16];\ - snprintf(name, sizeof(name), "0x%"PRIx64, ch_layout); - -#define GET_CH_LAYOUT_DESC(ch_layout)\ - char name[128];\ - av_get_channel_layout_string(name, sizeof(name), 0, ch_layout); - -double get_rotation(AVStream *st); +double get_rotation(int32_t *displaymatrix); #endif /* FFTOOLS_CMDUTILS_H */ diff --git a/android/ffmpeg-kit-android-lib/src/main/cpp/fftools_ffmpeg.c b/android/ffmpeg-kit-android-lib/src/main/cpp/fftools_ffmpeg.c index 265f562..caaa00b 100644 --- a/android/ffmpeg-kit-android-lib/src/main/cpp/fftools_ffmpeg.c +++ b/android/ffmpeg-kit-android-lib/src/main/cpp/fftools_ffmpeg.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2000-2003 Fabrice Bellard + * Copyright (c) 2018 Taner Sener ( tanersener gmail com ) * * This file is part of FFmpeg. * @@ -24,35 +25,53 @@ */ /* - * CHANGES 01.2021 - * - NDK r22 incompatibility issues regarding INT64_MAX fixed + * This file is the modified version of ffmpeg.c file living in ffmpeg source code under the fftools folder. We + * manually update it each time we depend on a new ffmpeg version. Below you can see the list of changes applied + * by us to develop mobile-ffmpeg and later ffmpeg-kit libraries. * - * CHANGES 06.2020 + * mobile-ffmpeg / ffmpeg-kit changes by Taner Sener + * + * 09.2022 + * -------------------------------------------------------- + * - added opt_common.h include + * - volatile dropped from thread local variables + * + * 08.2020 + * -------------------------------------------------------- + * - OptionDef defines combined + * + * 06.2020 + * -------------------------------------------------------- * - ignoring signals implemented * - cancel_operation() method signature updated with id * - cancel by execution id implemented + * - volatile modifier added to critical variables * - * CHANGES 01.2020 - * - ffprobe support changes + * 01.2020 + * -------------------------------------------------------- + * - ffprobe support (added ffmpeg_ prefix to methods and variables defined for both ffmpeg and ffprobe) * - * CHANGES 12.2019 - * - concurrent execution support + * 12.2019 + * -------------------------------------------------------- + * - concurrent execution support ("__thread" specifier added to variables used by multiple threads, + * extern signatures of ffmpeg_opt.c methods called by both ffmpeg and ffprobe added, copied options from + * ffmpeg_opt.c and defined them as inline in execute method) * - * CHANGES 08.2018 + * 08.2018 * -------------------------------------------------------- * - fftools_ prefix added to file name and parent headers * - forward_report() method, report_callback function pointer and set_report_callback() setter - * method added to forward stats. + * method added to forward stats * - forward_report() call added from print_report() * - cancel_operation() method added to trigger sigterm_handler * - (!received_sigterm) validation added inside ifilter_send_eof() to complete cancellation * - * CHANGES 07.2018 + * 07.2018 * -------------------------------------------------------- - * - main() function renamed as ffmpeg_execute() + * - main() function renamed as execute() * - exit_program() implemented with setjmp * - extern longjmp_value added to access exit code stored in exit_program() - * - ffmpeg_var_cleanup() method added + * - cleanup() method added */ #include "config.h" @@ -66,6 +85,7 @@ #include #include "ffmpegkit_exception.h" +#include "fftools_opt_common.h" #if HAVE_IO_H #include @@ -157,15 +177,13 @@ typedef struct BenchmarkTimeStamps { int64_t sys_usec; } BenchmarkTimeStamps; -static void do_video_stats(OutputStream *ost, int frame_size); static BenchmarkTimeStamps get_benchmark_time_stamps(void); static int64_t getmaxrss(void); static int ifilter_has_all_input_formats(FilterGraph *fg); -__thread int run_as_daemon = 0; -__thread int nb_frames_dup = 0; -__thread unsigned dup_warning = 1000; -__thread int nb_frames_drop = 0; +__thread int64_t nb_frames_dup = 0; +__thread uint64_t dup_warning = 1000; +__thread int64_t nb_frames_drop = 0; __thread int64_t decode_error_stat[2]; __thread unsigned nb_output_dumped = 0; @@ -196,10 +214,6 @@ __thread int qp_histogram[52]; void (*report_callback)(int, float, float, int64_t, int, double, double) = NULL; -extern __thread int file_overwrite; -extern __thread int no_file_overwrite; -extern __thread int ignore_unknown_streams; -extern __thread int copy_unknown_streams; extern int opt_map(void *optctx, const char *opt, const char *arg); extern int opt_map_channel(void *optctx, const char *opt, const char *arg); extern int opt_recording_timestamp(void *optctx, const char *opt, const char *arg); @@ -215,11 +229,9 @@ extern int opt_filter_complex(void *optctx, const char *opt, const char *arg); extern int opt_filter_complex_script(void *optctx, const char *opt, const char *arg); extern int opt_attach(void *optctx, const char *opt, const char *arg); extern int opt_video_frames(void *optctx, const char *opt, const char *arg); -extern __thread int intra_only; extern int opt_video_codec(void *optctx, const char *opt, const char *arg); extern int opt_sameq(void *optctx, const char *opt, const char *arg); extern int opt_timecode(void *optctx, const char *opt, const char *arg); -extern __thread int do_psnr; extern int opt_vstats_file(void *optctx, const char *opt, const char *arg); extern int opt_vstats(void *optctx, const char *opt, const char *arg); extern int opt_video_frames(void *optctx, const char *opt, const char *arg); @@ -241,7 +253,14 @@ extern int opt_sdp_file(void *optctx, const char *opt, const char *arg); extern int opt_data_codec(void *optctx, const char *opt, const char *arg); extern int opt_init_hw_device(void *optctx, const char *opt, const char *arg); extern int opt_filter_hw_device(void *optctx, const char *opt, const char *arg); +extern int opt_filter_threads(void *optctx, const char *opt, const char *arg); extern __thread int input_sync; +extern __thread int file_overwrite; +extern __thread int no_file_overwrite; +extern __thread int do_psnr; +extern __thread int ignore_unknown_streams; +extern __thread int copy_unknown_streams; +extern __thread int recast_media; #if HAVE_TERMIOS_H @@ -260,7 +279,7 @@ extern volatile int handleSIGTERM; extern volatile int handleSIGXCPU; extern volatile int handleSIGPIPE; -extern __thread volatile long globalSessionId; +extern __thread long globalSessionId; extern void cancelSession(long sessionId); extern int cancelRequested(long sessionId); @@ -438,10 +457,10 @@ void term_exit(void) static volatile int received_sigterm = 0; static volatile int received_nb_signals = 0; __thread atomic_int transcode_init_done = ATOMIC_VAR_INIT(0); -__thread volatile int ffmpeg_exited = 0; -__thread volatile int main_ffmpeg_return_code = 0; +__thread int ffmpeg_exited = 0; +__thread int main_ffmpeg_return_code = 0; __thread int64_t copy_ts_first_pts = AV_NOPTS_VALUE; -extern __thread volatile int longjmp_value; +extern __thread int longjmp_value; static void sigterm_handler(int sig) @@ -513,7 +532,7 @@ void term_init(void) #endif #if HAVE_TERMIOS_H - if (!run_as_daemon && stdin_interaction) { + if (stdin_interaction) { struct termios tty; if (tcgetattr (0, &tty) == 0) { oldtty = tty; @@ -531,25 +550,25 @@ void term_init(void) tcsetattr (0, TCSANOW, &tty); } if (handleSIGQUIT == 1) { - signal(SIGQUIT, sigterm_handler); /* Quit (POSIX). */ + SIGNAL(SIGQUIT, sigterm_handler); /* Quit (POSIX). */ } } #endif if (handleSIGINT == 1) { - signal(SIGINT , sigterm_handler); /* Interrupt (ANSI). */ + SIGNAL(SIGINT , sigterm_handler); /* Interrupt (ANSI). */ } if (handleSIGTERM == 1) { - signal(SIGTERM, sigterm_handler); /* Termination (ANSI). */ + SIGNAL(SIGTERM, sigterm_handler); /* Termination (ANSI). */ } #ifdef SIGXCPU if (handleSIGXCPU == 1) { - signal(SIGXCPU, sigterm_handler); + SIGNAL(SIGXCPU, sigterm_handler); } #endif #ifdef SIGPIPE if (handleSIGPIPE == 1) { - signal(SIGPIPE, SIG_IGN); /* Broken pipe (POSIX). */ + SIGNAL(SIGPIPE, SIG_IGN); /* Broken pipe (POSIX). */ } #endif #if HAVE_SETCONSOLECTRLHANDLER @@ -634,21 +653,18 @@ static void ffmpeg_cleanup(int ret) InputFilter *ifilter = fg->inputs[j]; struct InputStream *ist = ifilter->ist; - while (av_fifo_size(ifilter->frame_queue)) { + if (ifilter->frame_queue) { AVFrame *frame; - av_fifo_generic_read(ifilter->frame_queue, &frame, - sizeof(frame), NULL); - av_frame_free(&frame); + while (av_fifo_read(ifilter->frame_queue, &frame, 1) >= 0) + av_frame_free(&frame); + av_fifo_freep2(&ifilter->frame_queue); } - av_fifo_freep(&ifilter->frame_queue); + av_freep(&ifilter->displaymatrix); if (ist->sub2video.sub_queue) { - while (av_fifo_size(ist->sub2video.sub_queue)) { - AVSubtitle sub; - av_fifo_generic_read(ist->sub2video.sub_queue, - &sub, sizeof(sub), NULL); + AVSubtitle sub; + while (av_fifo_read(ist->sub2video.sub_queue, &sub, 1) >= 0) avsubtitle_free(&sub); - } - av_fifo_freep(&ist->sub2video.sub_queue); + av_fifo_freep2(&ist->sub2video.sub_queue); } av_buffer_unref(&ifilter->hw_frames_ctx); av_freep(&ifilter->name); @@ -660,9 +676,7 @@ static void ffmpeg_cleanup(int ret) avfilter_inout_free(&ofilter->out_tmp); av_freep(&ofilter->name); - av_freep(&ofilter->formats); - av_freep(&ofilter->channel_layouts); - av_freep(&ofilter->sample_rates); + av_channel_layout_uninit(&ofilter->ch_layout); av_freep(&fg->outputs[j]); } av_freep(&fg->outputs); @@ -675,19 +689,9 @@ static void ffmpeg_cleanup(int ret) av_freep(&subtitle_out); /* close files */ - for (i = 0; i < nb_output_files; i++) { - OutputFile *of = output_files[i]; - AVFormatContext *s; - if (!of) - continue; - s = of->ctx; - if (s && s->oformat && !(s->oformat->flags & AVFMT_NOFILE)) - avio_closep(&s->pb); - avformat_free_context(s); - av_dict_free(&of->opts); + for (i = 0; i < nb_output_files; i++) + of_close(&output_files[i]); - av_freep(&output_files[i]); - } for (i = 0; i < nb_output_streams; i++) { OutputStream *ost = output_streams[i]; @@ -716,12 +720,10 @@ static void ffmpeg_cleanup(int ret) avcodec_parameters_free(&ost->ref_par); if (ost->muxing_queue) { - while (av_fifo_size(ost->muxing_queue)) { - AVPacket *pkt; - av_fifo_generic_read(ost->muxing_queue, &pkt, sizeof(pkt), NULL); + AVPacket *pkt; + while (av_fifo_read(ost->muxing_queue, &pkt, 1) >= 0) av_packet_free(&pkt); - } - av_fifo_freep(&ost->muxing_queue); + av_fifo_freep2(&ost->muxing_queue); } av_freep(&output_streams[i]); @@ -738,7 +740,6 @@ static void ffmpeg_cleanup(int ret) InputStream *ist = input_streams[i]; av_frame_free(&ist->decoded_frame); - av_frame_free(&ist->filter_frame); av_packet_free(&ist->pkt); av_dict_free(&ist->decoder_opts); avsubtitle_free(&ist->prev_sub.subtitle); @@ -759,6 +760,7 @@ static void ffmpeg_cleanup(int ret) av_err2str(AVERROR(errno))); } av_freep(&vstats_filename); + av_freep(&filter_nbthreads); av_freep(&input_streams); av_freep(&input_files); @@ -783,7 +785,7 @@ static void ffmpeg_cleanup(int ret) void remove_avoptions(AVDictionary **a, AVDictionary *b) { - AVDictionaryEntry *t = NULL; + const AVDictionaryEntry *t = NULL; while ((t = av_dict_get(b, "", t, AV_DICT_IGNORE_SUFFIX))) { av_dict_set(a, t->key, NULL, AV_DICT_MATCH_CASE); @@ -792,7 +794,7 @@ void remove_avoptions(AVDictionary **a, AVDictionary *b) void assert_avoptions(AVDictionary *m) { - AVDictionaryEntry *t; + const AVDictionaryEntry *t; if ((t = av_dict_get(m, "", NULL, AV_DICT_IGNORE_SUFFIX))) { av_log(NULL, AV_LOG_FATAL, "Option %s not found.\n", t->key); exit_program(1); @@ -825,168 +827,14 @@ static void update_benchmark(const char *fmt, ...) } } -static void close_all_output_streams(OutputStream *ost, OSTFinished this_stream, OSTFinished others) -{ - int i; - for (i = 0; i < nb_output_streams; i++) { - OutputStream *ost2 = output_streams[i]; - ost2->finished |= ost == ost2 ? this_stream : others; - } -} - -static void write_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost, int unqueue) -{ - AVFormatContext *s = of->ctx; - AVStream *st = ost->st; - int ret; - - /* - * Audio encoders may split the packets -- #frames in != #packets out. - * But there is no reordering, so we can limit the number of output packets - * by simply dropping them here. - * Counting encoded video frames needs to be done separately because of - * reordering, see do_video_out(). - * Do not count the packet when unqueued because it has been counted when queued. - */ - if (!(st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && ost->encoding_needed) && !unqueue) { - if (ost->frame_number >= ost->max_frames) { - av_packet_unref(pkt); - return; - } - ost->frame_number++; - } - - if (!of->header_written) { - AVPacket *tmp_pkt; - /* the muxer is not initialized yet, buffer the packet */ - if (!av_fifo_space(ost->muxing_queue)) { - unsigned int are_we_over_size = - (ost->muxing_queue_data_size + pkt->size) > ost->muxing_queue_data_threshold; - int new_size = are_we_over_size ? - FFMIN(2 * av_fifo_size(ost->muxing_queue), - ost->max_muxing_queue_size) : - 2 * av_fifo_size(ost->muxing_queue); - - if (new_size <= av_fifo_size(ost->muxing_queue)) { - av_log(NULL, AV_LOG_ERROR, - "Too many packets buffered for output stream %d:%d.\n", - ost->file_index, ost->st->index); - exit_program(1); - } - ret = av_fifo_realloc2(ost->muxing_queue, new_size); - if (ret < 0) - exit_program(1); - } - ret = av_packet_make_refcounted(pkt); - if (ret < 0) - exit_program(1); - tmp_pkt = av_packet_alloc(); - if (!tmp_pkt) - exit_program(1); - av_packet_move_ref(tmp_pkt, pkt); - ost->muxing_queue_data_size += tmp_pkt->size; - av_fifo_generic_write(ost->muxing_queue, &tmp_pkt, sizeof(tmp_pkt), NULL); - return; - } - - if ((st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && video_sync_method == VSYNC_DROP) || - (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && audio_sync_method < 0)) - pkt->pts = pkt->dts = AV_NOPTS_VALUE; - - if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { - int i; - uint8_t *sd = av_packet_get_side_data(pkt, AV_PKT_DATA_QUALITY_STATS, - NULL); - ost->quality = sd ? AV_RL32(sd) : -1; - ost->pict_type = sd ? sd[4] : AV_PICTURE_TYPE_NONE; - - for (i = 0; ierror); i++) { - if (sd && i < sd[5]) - ost->error[i] = AV_RL64(sd + 8 + 8*i); - else - ost->error[i] = -1; - } - - if (ost->frame_rate.num && ost->is_cfr) { - if (pkt->duration > 0) - av_log(NULL, AV_LOG_WARNING, "Overriding packet duration by frame rate, this should not happen\n"); - pkt->duration = av_rescale_q(1, av_inv_q(ost->frame_rate), - ost->mux_timebase); - } - } - - av_packet_rescale_ts(pkt, ost->mux_timebase, ost->st->time_base); - - if (!(s->oformat->flags & AVFMT_NOTIMESTAMPS)) { - if (pkt->dts != AV_NOPTS_VALUE && - pkt->pts != AV_NOPTS_VALUE && - pkt->dts > pkt->pts) { - av_log(s, AV_LOG_WARNING, "Invalid DTS: %"PRId64" PTS: %"PRId64" in output stream %d:%d, replacing by guess\n", - pkt->dts, pkt->pts, - ost->file_index, ost->st->index); - pkt->pts = - pkt->dts = pkt->pts + pkt->dts + ost->last_mux_dts + 1 - - FFMIN3(pkt->pts, pkt->dts, ost->last_mux_dts + 1) - - FFMAX3(pkt->pts, pkt->dts, ost->last_mux_dts + 1); - } - if ((st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO || st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO || st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) && - pkt->dts != AV_NOPTS_VALUE && - !(st->codecpar->codec_id == AV_CODEC_ID_VP9 && ost->stream_copy) && - ost->last_mux_dts != AV_NOPTS_VALUE) { - int64_t max = ost->last_mux_dts + !(s->oformat->flags & AVFMT_TS_NONSTRICT); - if (pkt->dts < max) { - int loglevel = max - pkt->dts > 2 || st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO ? AV_LOG_WARNING : AV_LOG_DEBUG; - if (exit_on_error) - loglevel = AV_LOG_ERROR; - av_log(s, loglevel, "Non-monotonous DTS in output stream " - "%d:%d; previous: %"PRId64", current: %"PRId64"; ", - ost->file_index, ost->st->index, ost->last_mux_dts, pkt->dts); - if (exit_on_error) { - av_log(NULL, AV_LOG_FATAL, "aborting.\n"); - exit_program(1); - } - av_log(s, loglevel, "changing to %"PRId64". This may result " - "in incorrect timestamps in the output file.\n", - max); - if (pkt->pts >= pkt->dts) - pkt->pts = FFMAX(pkt->pts, max); - pkt->dts = max; - } - } - } - ost->last_mux_dts = pkt->dts; - - ost->data_size += pkt->size; - ost->packets_written++; - - pkt->stream_index = ost->index; - - if (debug_ts) { - av_log(NULL, AV_LOG_INFO, "muxer <- type:%s " - "pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s size:%d\n", - av_get_media_type_string(ost->enc_ctx->codec_type), - av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &ost->st->time_base), - av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, &ost->st->time_base), - pkt->size - ); - } - - ret = av_interleaved_write_frame(s, pkt); - if (ret < 0) { - print_error("av_interleaved_write_frame()", ret); - main_ffmpeg_return_code = 1; - close_all_output_streams(ost, MUXER_FINISHED | ENCODER_FINISHED, ENCODER_FINISHED); - } - av_packet_unref(pkt); -} - static void close_output_stream(OutputStream *ost) { OutputFile *of = output_files[ost->file_index]; + AVRational time_base = ost->stream_copy ? ost->mux_timebase : ost->enc_ctx->time_base; ost->finished |= ENCODER_FINISHED; if (of->shortest) { - int64_t end = av_rescale_q(ost->sync_opts - ost->first_pts, ost->enc_ctx->time_base, AV_TIME_BASE_Q); + int64_t end = av_rescale_q(ost->sync_opts - ost->first_pts, time_base, AV_TIME_BASE_Q); of->recording_time = FFMIN(of->recording_time, end); } } @@ -1013,11 +861,11 @@ static void output_packet(OutputFile *of, AVPacket *pkt, if (ret < 0) goto finish; while ((ret = av_bsf_receive_packet(ost->bsf_ctx, pkt)) >= 0) - write_packet(of, pkt, ost, 0); + of_write_packet(of, pkt, ost, 0); if (ret == AVERROR(EAGAIN)) ret = 0; } else if (!eof) - write_packet(of, pkt, ost, 0); + of_write_packet(of, pkt, ost, 0); finish: if (ret < 0 && ret != AVERROR_EOF) { @@ -1041,7 +889,8 @@ static int check_recording_time(OutputStream *ost) return 1; } -static double adjust_frame_pts_to_encoder_tb(OutputFile *of, OutputStream *ost, AVFrame *frame) +static double adjust_frame_pts_to_encoder_tb(OutputFile *of, OutputStream *ost, + AVFrame *frame) { double float_pts = AV_NOPTS_VALUE; // this is identical to frame.pts but with higher precision AVCodecContext *enc = ost->enc_ctx; @@ -1084,9 +933,11 @@ early_exit: return float_pts; } -static int init_output_stream(OutputStream *ost, AVFrame *frame, char *error, int error_len); +static int init_output_stream(OutputStream *ost, AVFrame *frame, + char *error, int error_len); -static int init_output_stream_wrapper(OutputStream *ost, AVFrame *frame, unsigned int fatal) +static int init_output_stream_wrapper(OutputStream *ost, AVFrame *frame, + unsigned int fatal) { int ret = AVERROR_BUG; char error[1024] = {0}; @@ -1106,62 +957,166 @@ static int init_output_stream_wrapper(OutputStream *ost, AVFrame *frame, unsigne return ret; } -static void do_audio_out(OutputFile *of, OutputStream *ost, - AVFrame *frame) +static double psnr(double d) +{ + return -10.0 * log10(d); +} + +static void update_video_stats(OutputStream *ost, const AVPacket *pkt, int write_vstats) { + const uint8_t *sd = av_packet_get_side_data(pkt, AV_PKT_DATA_QUALITY_STATS, + NULL); AVCodecContext *enc = ost->enc_ctx; - AVPacket *pkt = ost->pkt; - int ret; + int64_t frame_number; + double ti1, bitrate, avg_bitrate; - adjust_frame_pts_to_encoder_tb(of, ost, frame); + ost->quality = sd ? AV_RL32(sd) : -1; + ost->pict_type = sd ? sd[4] : AV_PICTURE_TYPE_NONE; - if (!check_recording_time(ost)) + for (int i = 0; ierror); i++) { + if (sd && i < sd[5]) + ost->error[i] = AV_RL64(sd + 8 + 8*i); + else + ost->error[i] = -1; + } + + if (!write_vstats) return; - if (frame->pts == AV_NOPTS_VALUE || audio_sync_method < 0) - frame->pts = ost->sync_opts; - ost->sync_opts = frame->pts + frame->nb_samples; - ost->samples_encoded += frame->nb_samples; - ost->frames_encoded++; + /* this is executed just the first time update_video_stats is called */ + if (!vstats_file) { + vstats_file = fopen(vstats_filename, "w"); + if (!vstats_file) { + perror("fopen"); + exit_program(1); + } + } - update_benchmark(NULL); - if (debug_ts) { - av_log(NULL, AV_LOG_INFO, "encoder <- type:audio " - "frame_pts:%s frame_pts_time:%s time_base:%d/%d\n", - av_ts2str(frame->pts), av_ts2timestr(frame->pts, &enc->time_base), - enc->time_base.num, enc->time_base.den); + frame_number = ost->packets_encoded; + if (vstats_version <= 1) { + fprintf(vstats_file, "frame= %5"PRId64" q= %2.1f ", frame_number, + ost->quality / (float)FF_QP2LAMBDA); + } else { + fprintf(vstats_file, "out= %2d st= %2d frame= %5"PRId64" q= %2.1f ", ost->file_index, ost->index, frame_number, + ost->quality / (float)FF_QP2LAMBDA); } + if (ost->error[0]>=0 && (enc->flags & AV_CODEC_FLAG_PSNR)) + fprintf(vstats_file, "PSNR= %6.2f ", psnr(ost->error[0] / (enc->width * enc->height * 255.0 * 255.0))); + + fprintf(vstats_file,"f_size= %6d ", pkt->size); + /* compute pts value */ + ti1 = pkt->dts * av_q2d(ost->mux_timebase); + if (ti1 < 0.01) + ti1 = 0.01; + + bitrate = (pkt->size * 8) / av_q2d(enc->time_base) / 1000.0; + avg_bitrate = (double)(ost->data_size * 8) / ti1 / 1000.0; + fprintf(vstats_file, "s_size= %8.0fkB time= %0.3f br= %7.1fkbits/s avg_br= %7.1fkbits/s ", + (double)ost->data_size / 1024, ti1, bitrate, avg_bitrate); + fprintf(vstats_file, "type= %c\n", av_get_picture_type_char(ost->pict_type)); +} + +static int encode_frame(OutputFile *of, OutputStream *ost, AVFrame *frame) +{ + AVCodecContext *enc = ost->enc_ctx; + AVPacket *pkt = ost->pkt; + const char *type_desc = av_get_media_type_string(enc->codec_type); + const char *action = frame ? "encode" : "flush"; + int ret; + + if (frame) { + ost->frames_encoded++; + + if (debug_ts) { + av_log(NULL, AV_LOG_INFO, "encoder <- type:%s " + "frame_pts:%s frame_pts_time:%s time_base:%d/%d\n", + type_desc, + av_ts2str(frame->pts), av_ts2timestr(frame->pts, &enc->time_base), + enc->time_base.num, enc->time_base.den); + } + } + + update_benchmark(NULL); + ret = avcodec_send_frame(enc, frame); - if (ret < 0) - goto error; + if (ret < 0 && !(ret == AVERROR_EOF && !frame)) { + av_log(NULL, AV_LOG_ERROR, "Error submitting %s frame to the encoder\n", + type_desc); + return ret; + } while (1) { - av_packet_unref(pkt); ret = avcodec_receive_packet(enc, pkt); - if (ret == AVERROR(EAGAIN)) - break; - if (ret < 0) - goto error; + update_benchmark("%s_%s %d.%d", action, type_desc, + ost->file_index, ost->index); + + /* if two pass, output log on success and EOF */ + if ((ret >= 0 || ret == AVERROR_EOF) && ost->logfile && enc->stats_out) + fprintf(ost->logfile, "%s", enc->stats_out); + + if (ret == AVERROR(EAGAIN)) { + av_assert0(frame); // should never happen during flushing + return 0; + } else if (ret == AVERROR_EOF) { + output_packet(of, pkt, ost, 1); + return ret; + } else if (ret < 0) { + av_log(NULL, AV_LOG_ERROR, "%s encoding failed\n", type_desc); + return ret; + } - update_benchmark("encode_audio %d.%d", ost->file_index, ost->index); + if (debug_ts) { + av_log(NULL, AV_LOG_INFO, "encoder -> type:%s " + "pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s " + "duration:%s duration_time:%s\n", + type_desc, + av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &enc->time_base), + av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, &enc->time_base), + av_ts2str(pkt->duration), av_ts2timestr(pkt->duration, &enc->time_base)); + } av_packet_rescale_ts(pkt, enc->time_base, ost->mux_timebase); if (debug_ts) { - av_log(NULL, AV_LOG_INFO, "encoder -> type:audio " - "pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s\n", + av_log(NULL, AV_LOG_INFO, "encoder -> type:%s " + "pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s " + "duration:%s duration_time:%s\n", + type_desc, av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &enc->time_base), - av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, &enc->time_base)); + av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, &enc->time_base), + av_ts2str(pkt->duration), av_ts2timestr(pkt->duration, &enc->time_base)); } + if (enc->codec_type == AVMEDIA_TYPE_VIDEO) + update_video_stats(ost, pkt, !!vstats_filename); + + ost->packets_encoded++; + output_packet(of, pkt, ost, 0); } - return; -error: - av_log(NULL, AV_LOG_FATAL, "Audio encoding failed\n"); - exit_program(1); + av_assert0(0); +} + +static void do_audio_out(OutputFile *of, OutputStream *ost, + AVFrame *frame) +{ + int ret; + + adjust_frame_pts_to_encoder_tb(of, ost, frame); + + if (!check_recording_time(ost)) + return; + + if (frame->pts == AV_NOPTS_VALUE || audio_sync_method < 0) + frame->pts = ost->sync_opts; + ost->sync_opts = frame->pts + frame->nb_samples; + ost->samples_encoded += frame->nb_samples; + + ret = encode_frame(of, ost, frame); + if (ret < 0) + exit_program(1); } static void do_subtitle_out(OutputFile *of, @@ -1247,19 +1202,18 @@ static void do_subtitle_out(OutputFile *of, } } +/* May modify/reset next_picture */ static void do_video_out(OutputFile *of, OutputStream *ost, AVFrame *next_picture) { - int ret, format_video_sync; - AVPacket *pkt = ost->pkt; + int ret; AVCodecContext *enc = ost->enc_ctx; AVRational frame_rate; - int nb_frames, nb0_frames, i; + int64_t nb_frames, nb0_frames, i; double delta, delta0; double duration = 0; double sync_ipts = AV_NOPTS_VALUE; - int frame_size = 0; InputStream *ist = NULL; AVFilterContext *filter = ost->filter->filter; @@ -1298,28 +1252,10 @@ static void do_video_out(OutputFile *of, nb0_frames = 0; // tracks the number of times the PREVIOUS frame should be duplicated, mostly for variable framerate (VFR) nb_frames = 1; - format_video_sync = video_sync_method; - if (format_video_sync == VSYNC_AUTO) { - if(!strcmp(of->ctx->oformat->name, "avi")) { - format_video_sync = VSYNC_VFR; - } else - format_video_sync = (of->ctx->oformat->flags & AVFMT_VARIABLE_FPS) ? ((of->ctx->oformat->flags & AVFMT_NOTIMESTAMPS) ? VSYNC_PASSTHROUGH : VSYNC_VFR) : VSYNC_CFR; - if ( ist - && format_video_sync == VSYNC_CFR - && input_files[ist->file_index]->ctx->nb_streams == 1 - && input_files[ist->file_index]->input_ts_offset == 0) { - format_video_sync = VSYNC_VSCFR; - } - if (format_video_sync == VSYNC_CFR && copy_ts) { - format_video_sync = VSYNC_VSCFR; - } - } - ost->is_cfr = (format_video_sync == VSYNC_CFR || format_video_sync == VSYNC_VSCFR); - if (delta0 < 0 && delta > 0 && - format_video_sync != VSYNC_PASSTHROUGH && - format_video_sync != VSYNC_DROP) { + ost->vsync_method != VSYNC_PASSTHROUGH && + ost->vsync_method != VSYNC_DROP) { if (delta0 < -0.6) { av_log(NULL, AV_LOG_VERBOSE, "Past duration %f too large\n", -delta0); } else @@ -1329,7 +1265,7 @@ static void do_video_out(OutputFile *of, delta0 = 0; } - switch (format_video_sync) { + switch (ost->vsync_method) { case VSYNC_VSCFR: if (ost->frame_number == 0 && delta0 >= 0.5) { av_log(NULL, AV_LOG_DEBUG, "Not duplicating %d initial frames\n", (int)lrintf(delta0)); @@ -1344,7 +1280,7 @@ static void do_video_out(OutputFile *of, } else if (delta < -1.1) nb_frames = 0; else if (delta > 1.1) { - nb_frames = lrintf(delta); + nb_frames = llrintf(delta); if (delta0 > 1.1) nb0_frames = llrintf(delta0 - 0.6); } @@ -1364,6 +1300,11 @@ static void do_video_out(OutputFile *of, } } + /* + * For video, number of frames in == number of packets out. + * But there may be reordering, so we can't throw away frames on encoder + * flush, we need to limit them here, before they go into encoder. + */ nb_frames = FFMIN(nb_frames, ost->max_frames - ost->frame_number); nb0_frames = FFMIN(nb0_frames, nb_frames); @@ -1375,232 +1316,119 @@ static void do_video_out(OutputFile *of, if (nb0_frames == 0 && ost->last_dropped) { nb_frames_drop++; av_log(NULL, AV_LOG_VERBOSE, - "*** dropping frame %d from stream %d at ts %"PRId64"\n", + "*** dropping frame %"PRId64" from stream %d at ts %"PRId64"\n", ost->frame_number, ost->st->index, ost->last_frame->pts); } if (nb_frames > (nb0_frames && ost->last_dropped) + (nb_frames > nb0_frames)) { if (nb_frames > dts_error_threshold * 30) { - av_log(NULL, AV_LOG_ERROR, "%d frame duplication too large, skipping\n", nb_frames - 1); + av_log(NULL, AV_LOG_ERROR, "%"PRId64" frame duplication too large, skipping\n", nb_frames - 1); nb_frames_drop++; return; } nb_frames_dup += nb_frames - (nb0_frames && ost->last_dropped) - (nb_frames > nb0_frames); - av_log(NULL, AV_LOG_VERBOSE, "*** %d dup!\n", nb_frames - 1); + av_log(NULL, AV_LOG_VERBOSE, "*** %"PRId64" dup!\n", nb_frames - 1); if (nb_frames_dup > dup_warning) { - av_log(NULL, AV_LOG_WARNING, "More than %d frames duplicated\n", dup_warning); + av_log(NULL, AV_LOG_WARNING, "More than %"PRIu64" frames duplicated\n", dup_warning); dup_warning *= 10; } } ost->last_dropped = nb_frames == nb0_frames && next_picture; ost->dropped_keyframe = ost->last_dropped && next_picture && next_picture->key_frame; - /* duplicates frame if needed */ - for (i = 0; i < nb_frames; i++) { - AVFrame *in_picture; - int forced_keyframe = 0; - double pts_time; + /* duplicates frame if needed */ + for (i = 0; i < nb_frames; i++) { + AVFrame *in_picture; + int forced_keyframe = 0; + double pts_time; - if (i < nb0_frames && ost->last_frame) { - in_picture = ost->last_frame; - } else - in_picture = next_picture; + if (i < nb0_frames && ost->last_frame->buf[0]) { + in_picture = ost->last_frame; + } else + in_picture = next_picture; - if (!in_picture) - return; + if (!in_picture) + return; - in_picture->pts = ost->sync_opts; + in_picture->pts = ost->sync_opts; - if (!check_recording_time(ost)) - return; + if (!check_recording_time(ost)) + return; - in_picture->quality = enc->global_quality; - in_picture->pict_type = 0; - - if (ost->forced_kf_ref_pts == AV_NOPTS_VALUE && - in_picture->pts != AV_NOPTS_VALUE) - ost->forced_kf_ref_pts = in_picture->pts; - - pts_time = in_picture->pts != AV_NOPTS_VALUE ? - (in_picture->pts - ost->forced_kf_ref_pts) * av_q2d(enc->time_base) : NAN; - if (ost->forced_kf_index < ost->forced_kf_count && - in_picture->pts >= ost->forced_kf_pts[ost->forced_kf_index]) { - ost->forced_kf_index++; - forced_keyframe = 1; - } else if (ost->forced_keyframes_pexpr) { - double res; - ost->forced_keyframes_expr_const_values[FKF_T] = pts_time; - res = av_expr_eval(ost->forced_keyframes_pexpr, - ost->forced_keyframes_expr_const_values, NULL); - ff_dlog(NULL, "force_key_frame: n:%f n_forced:%f prev_forced_n:%f t:%f prev_forced_t:%f -> res:%f\n", - ost->forced_keyframes_expr_const_values[FKF_N], - ost->forced_keyframes_expr_const_values[FKF_N_FORCED], - ost->forced_keyframes_expr_const_values[FKF_PREV_FORCED_N], - ost->forced_keyframes_expr_const_values[FKF_T], - ost->forced_keyframes_expr_const_values[FKF_PREV_FORCED_T], - res); - if (res) { + in_picture->quality = enc->global_quality; + in_picture->pict_type = 0; + + if (ost->forced_kf_ref_pts == AV_NOPTS_VALUE && + in_picture->pts != AV_NOPTS_VALUE) + ost->forced_kf_ref_pts = in_picture->pts; + + pts_time = in_picture->pts != AV_NOPTS_VALUE ? + (in_picture->pts - ost->forced_kf_ref_pts) * av_q2d(enc->time_base) : NAN; + if (ost->forced_kf_index < ost->forced_kf_count && + in_picture->pts >= ost->forced_kf_pts[ost->forced_kf_index]) { + ost->forced_kf_index++; forced_keyframe = 1; - ost->forced_keyframes_expr_const_values[FKF_PREV_FORCED_N] = - ost->forced_keyframes_expr_const_values[FKF_N]; - ost->forced_keyframes_expr_const_values[FKF_PREV_FORCED_T] = - ost->forced_keyframes_expr_const_values[FKF_T]; - ost->forced_keyframes_expr_const_values[FKF_N_FORCED] += 1; - } + } else if (ost->forced_keyframes_pexpr) { + double res; + ost->forced_keyframes_expr_const_values[FKF_T] = pts_time; + res = av_expr_eval(ost->forced_keyframes_pexpr, + ost->forced_keyframes_expr_const_values, NULL); + ff_dlog(NULL, "force_key_frame: n:%f n_forced:%f prev_forced_n:%f t:%f prev_forced_t:%f -> res:%f\n", + ost->forced_keyframes_expr_const_values[FKF_N], + ost->forced_keyframes_expr_const_values[FKF_N_FORCED], + ost->forced_keyframes_expr_const_values[FKF_PREV_FORCED_N], + ost->forced_keyframes_expr_const_values[FKF_T], + ost->forced_keyframes_expr_const_values[FKF_PREV_FORCED_T], + res); + if (res) { + forced_keyframe = 1; + ost->forced_keyframes_expr_const_values[FKF_PREV_FORCED_N] = + ost->forced_keyframes_expr_const_values[FKF_N]; + ost->forced_keyframes_expr_const_values[FKF_PREV_FORCED_T] = + ost->forced_keyframes_expr_const_values[FKF_T]; + ost->forced_keyframes_expr_const_values[FKF_N_FORCED] += 1; + } - ost->forced_keyframes_expr_const_values[FKF_N] += 1; - } else if ( ost->forced_keyframes - && !strncmp(ost->forced_keyframes, "source", 6) + ost->forced_keyframes_expr_const_values[FKF_N] += 1; + } else if ( ost->forced_keyframes + && !strncmp(ost->forced_keyframes, "source", 6) && in_picture->key_frame==1 && !i) { - forced_keyframe = 1; + forced_keyframe = 1; } else if ( ost->forced_keyframes && !strncmp(ost->forced_keyframes, "source_no_drop", 14) && !i) { forced_keyframe = (in_picture->key_frame == 1) || ost->dropped_keyframe; ost->dropped_keyframe = 0; - } - - if (forced_keyframe) { - in_picture->pict_type = AV_PICTURE_TYPE_I; - av_log(NULL, AV_LOG_DEBUG, "Forced keyframe at time %f\n", pts_time); - } - - update_benchmark(NULL); - if (debug_ts) { - av_log(NULL, AV_LOG_INFO, "encoder <- type:video " - "frame_pts:%s frame_pts_time:%s time_base:%d/%d\n", - av_ts2str(in_picture->pts), av_ts2timestr(in_picture->pts, &enc->time_base), - enc->time_base.num, enc->time_base.den); - } - - ost->frames_encoded++; - - ret = avcodec_send_frame(enc, in_picture); - if (ret < 0) - goto error; - // Make sure Closed Captions will not be duplicated - av_frame_remove_side_data(in_picture, AV_FRAME_DATA_A53_CC); - - while (1) { - av_packet_unref(pkt); - ret = avcodec_receive_packet(enc, pkt); - update_benchmark("encode_video %d.%d", ost->file_index, ost->index); - if (ret == AVERROR(EAGAIN)) - break; - if (ret < 0) - goto error; - - if (debug_ts) { - av_log(NULL, AV_LOG_INFO, "encoder -> type:video " - "pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s\n", - av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &enc->time_base), - av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, &enc->time_base)); } - if (pkt->pts == AV_NOPTS_VALUE && !(enc->codec->capabilities & AV_CODEC_CAP_DELAY)) - pkt->pts = ost->sync_opts; - - av_packet_rescale_ts(pkt, enc->time_base, ost->mux_timebase); - - if (debug_ts) { - av_log(NULL, AV_LOG_INFO, "encoder -> type:video " - "pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s\n", - av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &ost->mux_timebase), - av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, &ost->mux_timebase)); + if (forced_keyframe) { + in_picture->pict_type = AV_PICTURE_TYPE_I; + av_log(NULL, AV_LOG_DEBUG, "Forced keyframe at time %f\n", pts_time); } - frame_size = pkt->size; - output_packet(of, pkt, ost, 0); + ret = encode_frame(of, ost, in_picture); + if (ret < 0) + exit_program(1); - /* if two pass, output log */ - if (ost->logfile && enc->stats_out) { - fprintf(ost->logfile, "%s", enc->stats_out); - } + ost->sync_opts++; + ost->frame_number++; } - ost->sync_opts++; - /* - * For video, number of frames in == number of packets out. - * But there may be reordering, so we can't throw away frames on encoder - * flush, we need to limit them here, before they go into encoder. - */ - ost->frame_number++; - - if (vstats_filename && frame_size) - do_video_stats(ost, frame_size); - } - if (!ost->last_frame) - ost->last_frame = av_frame_alloc(); av_frame_unref(ost->last_frame); - if (next_picture && ost->last_frame) - av_frame_ref(ost->last_frame, next_picture); - else - av_frame_free(&ost->last_frame); - - return; -error: - av_log(NULL, AV_LOG_FATAL, "Video encoding failed\n"); - exit_program(1); -} - -static double psnr(double d) -{ - return -10.0 * log10(d); -} - -static void do_video_stats(OutputStream *ost, int frame_size) -{ - AVCodecContext *enc; - int frame_number; - double ti1, bitrate, avg_bitrate; - - /* this is executed just the first time do_video_stats is called */ - if (!vstats_file) { - vstats_file = fopen(vstats_filename, "w"); - if (!vstats_file) { - perror("fopen"); - exit_program(1); - } - } - - enc = ost->enc_ctx; - if (enc->codec_type == AVMEDIA_TYPE_VIDEO) { - frame_number = ost->st->nb_frames; - if (vstats_version <= 1) { - fprintf(vstats_file, "frame= %5d q= %2.1f ", frame_number, - ost->quality / (float)FF_QP2LAMBDA); - } else { - fprintf(vstats_file, "out= %2d st= %2d frame= %5d q= %2.1f ", ost->file_index, ost->index, frame_number, - ost->quality / (float)FF_QP2LAMBDA); - } - - if (ost->error[0]>=0 && (enc->flags & AV_CODEC_FLAG_PSNR)) - fprintf(vstats_file, "PSNR= %6.2f ", psnr(ost->error[0] / (enc->width * enc->height * 255.0 * 255.0))); - - fprintf(vstats_file,"f_size= %6d ", frame_size); - /* compute pts value */ - ti1 = av_stream_get_end_pts(ost->st) * av_q2d(ost->st->time_base); - if (ti1 < 0.01) - ti1 = 0.01; - - bitrate = (frame_size * 8) / av_q2d(enc->time_base) / 1000.0; - avg_bitrate = (double)(ost->data_size * 8) / ti1 / 1000.0; - fprintf(vstats_file, "s_size= %8.0fkB time= %0.3f br= %7.1fkbits/s avg_br= %7.1fkbits/s ", - (double)ost->data_size / 1024, ti1, bitrate, avg_bitrate); - fprintf(vstats_file, "type= %c\n", av_get_picture_type_char(ost->pict_type)); - } + if (next_picture) + av_frame_move_ref(ost->last_frame, next_picture); } static void finish_output_stream(OutputStream *ost) { OutputFile *of = output_files[ost->file_index]; - int i; + AVRational time_base = ost->stream_copy ? ost->mux_timebase : ost->enc_ctx->time_base; ost->finished = ENCODER_FINISHED | MUXER_FINISHED; if (of->shortest) { - for (i = 0; i < of->ctx->nb_streams; i++) - output_streams[of->ost_index + i]->finished = ENCODER_FINISHED | MUXER_FINISHED; + int64_t end = av_rescale_q(ost->sync_opts - ost->first_pts, time_base, AV_TIME_BASE_Q); + of->recording_time = FFMIN(of->recording_time, end); } } @@ -1639,12 +1467,6 @@ static int reap_filters(int flush) if (av_buffersink_get_type(filter) == AVMEDIA_TYPE_AUDIO) init_output_stream_wrapper(ost, NULL, 1); - if (!ost->pkt && !(ost->pkt = av_packet_alloc())) { - return AVERROR(ENOMEM); - } - if (!ost->filtered_frame && !(ost->filtered_frame = av_frame_alloc())) { - return AVERROR(ENOMEM); - } filtered_frame = ost->filtered_frame; while (1) { @@ -1674,7 +1496,7 @@ static int reap_filters(int flush) break; case AVMEDIA_TYPE_AUDIO: if (!(enc->codec->capabilities & AV_CODEC_CAP_PARAM_CHANGE) && - enc->channels != filtered_frame->channels) { + enc->ch_layout.nb_channels != filtered_frame->ch_layout.nb_channels) { av_log(NULL, AV_LOG_ERROR, "Audio filter graph output is not normalized and encoder does not support parameter changes\n"); break; @@ -1748,7 +1570,7 @@ static void print_final_stats(int64_t total_size) total_packets += ist->nb_packets; av_log(NULL, AV_LOG_VERBOSE, " Input stream #%d:%d (%s): ", - i, j, media_type_string(type)); + i, j, av_get_media_type_string(type)); av_log(NULL, AV_LOG_VERBOSE, "%"PRIu64" packets read (%"PRIu64" bytes); ", ist->nb_packets, ist->data_size); @@ -1782,7 +1604,7 @@ static void print_final_stats(int64_t total_size) total_packets += ost->packets_written; av_log(NULL, AV_LOG_VERBOSE, " Output stream #%d:%d (%s): ", - i, j, media_type_string(type)); + i, j, av_get_media_type_string(type)); if (ost->encoding_needed) { av_log(NULL, AV_LOG_VERBOSE, "%"PRIu64" frames encoded", ost->frames_encoded); @@ -1818,7 +1640,7 @@ static void forward_report(int is_last_report, int64_t timer_start, int64_t cur_ int64_t pts = INT64_MIN + 1; int vid, i; - int frame_number = 0; + int64_t frame_number = 0; float fps = 0; float quality = 0; int64_t total_size = 0; @@ -1886,7 +1708,7 @@ static void print_report(int is_last_report, int64_t timer_start, int64_t cur_ti AVFormatContext *oc; int64_t total_size; AVCodecContext *enc; - int frame_number, vid, i; + int vid, i; double bitrate; double speed; int64_t pts = INT64_MIN + 1; @@ -1936,12 +1758,12 @@ static void print_report(int is_last_report, int64_t timer_start, int64_t cur_ti } if (!vid && enc->codec_type == AVMEDIA_TYPE_VIDEO) { float fps; + int64_t frame_number = ost->frame_number; - frame_number = ost->frame_number; fps = t > 1 ? frame_number / t : 0; - av_bprintf(&buf, "frame=%5d fps=%3.*f q=%3.1f ", + av_bprintf(&buf, "frame=%5"PRId64" fps=%3.*f q=%3.1f ", frame_number, fps < 9.95, fps, q); - av_bprintf(&buf_script, "frame=%d\n", frame_number); + av_bprintf(&buf_script, "frame=%"PRId64"\n", frame_number); av_bprintf(&buf_script, "fps=%.2f\n", fps); av_bprintf(&buf_script, "stream_%d_%d_q=%.1f\n", ost->file_index, ost->index, q); @@ -2045,9 +1867,9 @@ static void print_report(int is_last_report, int64_t timer_start, int64_t cur_ti } if (nb_frames_dup || nb_frames_drop) - av_bprintf(&buf, " dup=%d drop=%d", nb_frames_dup, nb_frames_drop); - av_bprintf(&buf_script, "dup_frames=%d\n", nb_frames_dup); - av_bprintf(&buf_script, "drop_frames=%d\n", nb_frames_drop); + av_bprintf(&buf, " dup=%"PRId64" drop=%"PRId64, nb_frames_dup, nb_frames_drop); + av_bprintf(&buf_script, "dup_frames=%"PRId64"\n", nb_frames_dup); + av_bprintf(&buf_script, "drop_frames=%"PRId64"\n", nb_frames_drop); if (speed < 0) { av_bprintf(&buf, " speed=N/A"); @@ -2060,11 +1882,11 @@ static void print_report(int is_last_report, int64_t timer_start, int64_t cur_ti if (print_stats || is_last_report) { const char end = is_last_report ? '\n' : '\r'; if (print_stats==1 && AV_LOG_INFO > av_log_get_level()) { - fprintf(stderr, "%s %c", buf.str, end); + av_log(NULL, AV_LOG_STDERR, "%s %c", buf.str, end); } else av_log(NULL, AV_LOG_INFO, "%s %c", buf.str, end); - fflush(stderr); + fflush(stderr); } av_bprint_finalize(&buf, NULL); @@ -2088,17 +1910,22 @@ static void print_report(int is_last_report, int64_t timer_start, int64_t cur_ti print_final_stats(total_size); } -static void ifilter_parameters_from_codecpar(InputFilter *ifilter, AVCodecParameters *par) +static int ifilter_parameters_from_codecpar(InputFilter *ifilter, AVCodecParameters *par) { + int ret; + // We never got any input. Set a fake format, which will // come from libavformat. ifilter->format = par->format; ifilter->sample_rate = par->sample_rate; - ifilter->channels = par->channels; - ifilter->channel_layout = par->channel_layout; ifilter->width = par->width; ifilter->height = par->height; ifilter->sample_aspect_ratio = par->sample_aspect_ratio; + ret = av_channel_layout_copy(&ifilter->ch_layout, &par->ch_layout); + if (ret < 0) + return ret; + + return 0; } static void flush_encoders(void) @@ -2126,8 +1953,11 @@ static void flush_encoders(void) int x; for (x = 0; x < fg->nb_inputs; x++) { InputFilter *ifilter = fg->inputs[x]; - if (ifilter->format < 0) - ifilter_parameters_from_codecpar(ifilter, ifilter->ist->st->codecpar); + if (ifilter->format < 0 && + ifilter_parameters_from_codecpar(ifilter, ifilter->ist->st->codecpar) < 0) { + av_log(NULL, AV_LOG_ERROR, "Error copying paramerets from input stream\n"); + exit_program(1); + } } if (!ifilter_has_all_input_formats(fg)) @@ -2143,65 +1973,14 @@ static void flush_encoders(void) } init_output_stream_wrapper(ost, NULL, 1); - } + } if (enc->codec_type != AVMEDIA_TYPE_VIDEO && enc->codec_type != AVMEDIA_TYPE_AUDIO) continue; - for (;;) { - const char *desc = NULL; - AVPacket *pkt = ost->pkt; - int pkt_size; - - switch (enc->codec_type) { - case AVMEDIA_TYPE_AUDIO: - desc = "audio"; - break; - case AVMEDIA_TYPE_VIDEO: - desc = "video"; - break; - default: - av_assert0(0); - } - - update_benchmark(NULL); - - av_packet_unref(pkt); - while ((ret = avcodec_receive_packet(enc, pkt)) == AVERROR(EAGAIN)) { - ret = avcodec_send_frame(enc, NULL); - if (ret < 0) { - av_log(NULL, AV_LOG_FATAL, "%s encoding failed: %s\n", - desc, - av_err2str(ret)); - exit_program(1); - } - } - - update_benchmark("flush_%s %d.%d", desc, ost->file_index, ost->index); - if (ret < 0 && ret != AVERROR_EOF) { - av_log(NULL, AV_LOG_FATAL, "%s encoding failed: %s\n", - desc, - av_err2str(ret)); - exit_program(1); - } - if (ost->logfile && enc->stats_out) { - fprintf(ost->logfile, "%s", enc->stats_out); - } - if (ret == AVERROR_EOF) { - output_packet(of, pkt, ost, 1); - break; - } - if (ost->finished & MUXER_FINISHED) { - av_packet_unref(pkt); - continue; - } - av_packet_rescale_ts(pkt, enc->time_base, ost->mux_timebase); - pkt_size = pkt->size; - output_packet(of, pkt, ost, 0); - if (ost->enc_ctx->codec_type == AVMEDIA_TYPE_VIDEO && vstats_filename) { - do_video_stats(ost, pkt_size); - } - } + ret = encode_frame(of, ost, NULL); + if (ret != AVERROR_EOF) + exit_program(1); } } @@ -2216,7 +1995,7 @@ static int check_output_constraints(InputStream *ist, OutputStream *ost) if (ost->source_index != ist_index) return 0; - if (ost->finished) + if (ost->finished & MUXER_FINISHED) return 0; if (of->start_time != AV_NOPTS_VALUE && ist->pts < of->start_time) @@ -2240,11 +2019,11 @@ static void do_streamcopy(InputStream *ist, OutputStream *ost, const AVPacket *p return; } - if ((!ost->frame_number && !(pkt->flags & AV_PKT_FLAG_KEY)) && + if (!ost->streamcopy_started && !(pkt->flags & AV_PKT_FLAG_KEY) && !ost->copy_initial_nonkeyframes) return; - if (!ost->frame_number && !ost->copy_prior_start) { + if (!ost->streamcopy_started && !ost->copy_prior_start) { int64_t comp_start = start_time; if (copy_ts && f->start_time != AV_NOPTS_VALUE) comp_start = FFMAX(start_time, f->start_time + f->ts_offset); @@ -2272,10 +2051,6 @@ static void do_streamcopy(InputStream *ist, OutputStream *ost, const AVPacket *p } } - /* force the input stream PTS */ - if (ost->enc_ctx->codec_type == AVMEDIA_TYPE_VIDEO) - ost->sync_opts++; - if (av_packet_ref(opkt, pkt) < 0) exit_program(1); @@ -2299,23 +2074,26 @@ static void do_streamcopy(InputStream *ist, OutputStream *ost, const AVPacket *p opkt->duration = av_rescale_q(pkt->duration, ist->st->time_base, ost->mux_timebase); + ost->sync_opts += opkt->duration; + output_packet(of, opkt, ost, 0); + + ost->streamcopy_started = 1; } int guess_input_channel_layout(InputStream *ist) { AVCodecContext *dec = ist->dec_ctx; - if (!dec->channel_layout) { + if (dec->ch_layout.order == AV_CHANNEL_ORDER_UNSPEC) { char layout_name[256]; - if (dec->channels > ist->guess_layout_max) + if (dec->ch_layout.nb_channels > ist->guess_layout_max) return 0; - dec->channel_layout = av_get_default_channel_layout(dec->channels); - if (!dec->channel_layout) + av_channel_layout_default(&dec->ch_layout, dec->ch_layout.nb_channels); + if (dec->ch_layout.order == AV_CHANNEL_ORDER_UNSPEC) return 0; - av_get_channel_layout_string(layout_name, sizeof(layout_name), - dec->channels, dec->channel_layout); + av_channel_layout_describe(&dec->ch_layout, layout_name, sizeof(layout_name)); av_log(NULL, AV_LOG_WARNING, "Guessed Channel Layout for Input Stream " "#%d.%d : %s\n", ist->file_index, ist->st->index, layout_name); } @@ -2352,10 +2130,15 @@ static int ifilter_has_all_input_formats(FilterGraph *fg) return 1; } -static int ifilter_send_frame(InputFilter *ifilter, AVFrame *frame) +static int ifilter_send_frame(InputFilter *ifilter, AVFrame *frame, int keep_reference) { FilterGraph *fg = ifilter->graph; - int need_reinit, ret, i; + AVFrameSideData *sd; + int need_reinit, ret; + int buffersrc_flags = AV_BUFFERSRC_FLAG_PUSH; + + if (keep_reference) + buffersrc_flags |= AV_BUFFERSRC_FLAG_KEEP_REF; /* determine if the parameters for this input changed */ need_reinit = ifilter->format != frame->format; @@ -2363,8 +2146,7 @@ static int ifilter_send_frame(InputFilter *ifilter, AVFrame *frame) switch (ifilter->ist->st->codecpar->codec_type) { case AVMEDIA_TYPE_AUDIO: need_reinit |= ifilter->sample_rate != frame->sample_rate || - ifilter->channels != frame->channels || - ifilter->channel_layout != frame->channel_layout; + av_channel_layout_compare(&ifilter->ch_layout, &frame->ch_layout); break; case AVMEDIA_TYPE_VIDEO: need_reinit |= ifilter->width != frame->width || @@ -2379,6 +2161,12 @@ static int ifilter_send_frame(InputFilter *ifilter, AVFrame *frame) (ifilter->hw_frames_ctx && ifilter->hw_frames_ctx->data != frame->hw_frames_ctx->data)) need_reinit = 1; + if ((sd = av_frame_get_side_data(frame, AV_FRAME_DATA_DISPLAYMATRIX))) { + if (!ifilter->displaymatrix || memcmp(sd->data, ifilter->displaymatrix, sizeof(int32_t) * 9)) + need_reinit = 1; + } else if (ifilter->displaymatrix) + need_reinit = 1; + if (need_reinit) { ret = ifilter_parameters_from_frame(ifilter, frame); if (ret < 0) @@ -2387,23 +2175,16 @@ static int ifilter_send_frame(InputFilter *ifilter, AVFrame *frame) /* (re)init the graph if possible, otherwise buffer the frame and return */ if (need_reinit || !fg->graph) { - for (i = 0; i < fg->nb_inputs; i++) { - if (!ifilter_has_all_input_formats(fg)) { - AVFrame *tmp = av_frame_clone(frame); - if (!tmp) - return AVERROR(ENOMEM); - av_frame_unref(frame); + if (!ifilter_has_all_input_formats(fg)) { + AVFrame *tmp = av_frame_clone(frame); + if (!tmp) + return AVERROR(ENOMEM); - if (!av_fifo_space(ifilter->frame_queue)) { - ret = av_fifo_realloc2(ifilter->frame_queue, 2 * av_fifo_size(ifilter->frame_queue)); - if (ret < 0) { - av_frame_free(&tmp); - return ret; - } - } - av_fifo_generic_write(ifilter->frame_queue, &tmp, sizeof(tmp), NULL); - return 0; - } + ret = av_fifo_write(ifilter->frame_queue, &tmp, 1); + if (ret < 0) + av_frame_free(&tmp); + + return ret; } ret = reap_filters(1); @@ -2419,7 +2200,7 @@ static int ifilter_send_frame(InputFilter *ifilter, AVFrame *frame) } } - ret = av_buffersrc_add_frame_flags(ifilter->filter, frame, AV_BUFFERSRC_FLAG_PUSH); + ret = av_buffersrc_add_frame_flags(ifilter->filter, frame, buffersrc_flags); if (ret < 0) { if (ret != AVERROR_EOF) av_log(NULL, AV_LOG_ERROR, "Error while filtering: %s\n", av_err2str(ret)); @@ -2445,8 +2226,11 @@ static int ifilter_send_eof(InputFilter *ifilter, int64_t pts) return ret; } else { // the filtergraph was never configured - if (ifilter->format < 0) - ifilter_parameters_from_codecpar(ifilter, ifilter->ist->st->codecpar); + if (ifilter->format < 0) { + ret = ifilter_parameters_from_codecpar(ifilter, ifilter->ist->st->codecpar); + if (ret < 0) + return ret; + } if (ifilter->format < 0 && (ifilter->type == AVMEDIA_TYPE_AUDIO || ifilter->type == AVMEDIA_TYPE_VIDEO)) { av_log(NULL, AV_LOG_ERROR, "Cannot determine format of input stream %d:%d after EOF\n", ifilter->ist->file_index, ifilter->ist->st->index); return AVERROR_INVALIDDATA; @@ -2486,18 +2270,10 @@ static int decode(AVCodecContext *avctx, AVFrame *frame, int *got_frame, AVPacke static int send_frame_to_filters(InputStream *ist, AVFrame *decoded_frame) { int i, ret; - AVFrame *f; av_assert1(ist->nb_filters > 0); /* ensure ret is initialized */ for (i = 0; i < ist->nb_filters; i++) { - if (i < ist->nb_filters - 1) { - f = ist->filter_frame; - ret = av_frame_ref(f, decoded_frame); - if (ret < 0) - break; - } else - f = decoded_frame; - ret = ifilter_send_frame(ist->filters[i], f); + ret = ifilter_send_frame(ist->filters[i], decoded_frame, i < ist->nb_filters - 1); if (ret == AVERROR_EOF) ret = 0; /* ignore */ if (ret < 0) { @@ -2512,17 +2288,11 @@ static int send_frame_to_filters(InputStream *ist, AVFrame *decoded_frame) static int decode_audio(InputStream *ist, AVPacket *pkt, int *got_output, int *decode_failed) { - AVFrame *decoded_frame; + AVFrame *decoded_frame = ist->decoded_frame; AVCodecContext *avctx = ist->dec_ctx; int ret, err = 0; AVRational decoded_frame_tb; - if (!ist->decoded_frame && !(ist->decoded_frame = av_frame_alloc())) - return AVERROR(ENOMEM); - if (!ist->filter_frame && !(ist->filter_frame = av_frame_alloc())) - return AVERROR(ENOMEM); - decoded_frame = ist->decoded_frame; - update_benchmark(NULL); ret = decode(avctx, decoded_frame, got_output, pkt); update_benchmark("decode_audio %d.%d", ist->file_index, ist->st->index); @@ -2559,6 +2329,11 @@ static int decode_audio(InputStream *ist, AVPacket *pkt, int *got_output, decoded_frame->pts = ist->dts; decoded_frame_tb = AV_TIME_BASE_Q; } + if (pkt && pkt->duration && ist->prev_pkt_pts != AV_NOPTS_VALUE && + pkt->pts != AV_NOPTS_VALUE && pkt->pts - ist->prev_pkt_pts > pkt->duration) + ist->filter_in_rescale_delta_last = AV_NOPTS_VALUE; + if (pkt) + ist->prev_pkt_pts = pkt->pts; if (decoded_frame->pts != AV_NOPTS_VALUE) decoded_frame->pts = av_rescale_delta(decoded_frame_tb, decoded_frame->pts, (AVRational){1, avctx->sample_rate}, decoded_frame->nb_samples, &ist->filter_in_rescale_delta_last, @@ -2566,7 +2341,6 @@ static int decode_audio(InputStream *ist, AVPacket *pkt, int *got_output, ist->nb_samples = decoded_frame->nb_samples; err = send_frame_to_filters(ist, decoded_frame); - av_frame_unref(ist->filter_frame); av_frame_unref(decoded_frame); return err < 0 ? err : ret; } @@ -2574,7 +2348,7 @@ static int decode_audio(InputStream *ist, AVPacket *pkt, int *got_output, static int decode_video(InputStream *ist, AVPacket *pkt, int *got_output, int64_t *duration_pts, int eof, int *decode_failed) { - AVFrame *decoded_frame; + AVFrame *decoded_frame = ist->decoded_frame; int i, ret = 0, err = 0; int64_t best_effort_timestamp; int64_t dts = AV_NOPTS_VALUE; @@ -2585,11 +2359,6 @@ static int decode_video(InputStream *ist, AVPacket *pkt, int *got_output, int64_ if (!eof && pkt && pkt->size == 0) return 0; - if (!ist->decoded_frame && !(ist->decoded_frame = av_frame_alloc())) - return AVERROR(ENOMEM); - if (!ist->filter_frame && !(ist->filter_frame = av_frame_alloc())) - return AVERROR(ENOMEM); - decoded_frame = ist->decoded_frame; if (ist->dts != AV_NOPTS_VALUE) dts = av_rescale_q(ist->dts, AV_TIME_BASE_Q, ist->st->time_base); if (pkt) { @@ -2697,7 +2466,6 @@ static int decode_video(InputStream *ist, AVPacket *pkt, int *got_output, int64_ err = send_frame_to_filters(ist, decoded_frame); fail: - av_frame_unref(ist->filter_frame); av_frame_unref(decoded_frame); return err < 0 ? err : ret; } @@ -2746,15 +2514,13 @@ static int transcode_subtitles(InputStream *ist, AVPacket *pkt, int *got_output, sub2video_update(ist, INT64_MIN, &subtitle); } else if (ist->nb_filters) { if (!ist->sub2video.sub_queue) - ist->sub2video.sub_queue = av_fifo_alloc(8 * sizeof(AVSubtitle)); + ist->sub2video.sub_queue = av_fifo_alloc2(8, sizeof(AVSubtitle), AV_FIFO_FLAG_AUTO_GROW); if (!ist->sub2video.sub_queue) exit_program(1); - if (!av_fifo_space(ist->sub2video.sub_queue)) { - ret = av_fifo_realloc2(ist->sub2video.sub_queue, 2 * av_fifo_size(ist->sub2video.sub_queue)); - if (ret < 0) - exit_program(1); - } - av_fifo_generic_write(ist->sub2video.sub_queue, &subtitle, sizeof(subtitle), NULL); + + ret = av_fifo_write(ist->sub2video.sub_queue, &subtitle, 1); + if (ret < 0) + exit_program(1); free_sub = 0; } @@ -2766,8 +2532,6 @@ static int transcode_subtitles(InputStream *ist, AVPacket *pkt, int *got_output, for (i = 0; i < nb_output_streams; i++) { OutputStream *ost = output_streams[i]; - if (!ost->pkt && !(ost->pkt = av_packet_alloc())) - exit_program(1); if (!check_output_constraints(ist, ost) || !ost->encoding_needed || ost->enc->type != AVMEDIA_TYPE_SUBTITLE) continue; @@ -2803,11 +2567,7 @@ static int process_input_packet(InputStream *ist, const AVPacket *pkt, int no_eo int repeating = 0; int eof_reached = 0; - AVPacket *avpkt; - - if (!ist->pkt && !(ist->pkt = av_packet_alloc())) - return AVERROR(ENOMEM); - avpkt = ist->pkt; + AVPacket *avpkt = ist->pkt; if (!ist->saw_first_ts) { ist->first_dts = @@ -2974,12 +2734,12 @@ static int process_input_packet(InputStream *ist, const AVPacket *pkt, int no_eo } ist->pts = ist->dts; ist->next_pts = ist->next_dts; - } + } else if (!ist->decoding_needed) + eof_reached = 1; + for (i = 0; i < nb_output_streams; i++) { OutputStream *ost = output_streams[i]; - if (!ost->pkt && !(ost->pkt = av_packet_alloc())) - exit_program(1); if (!check_output_constraints(ist, ost) || ost->encoding_needed) continue; @@ -2989,51 +2749,6 @@ static int process_input_packet(InputStream *ist, const AVPacket *pkt, int no_eo return !eof_reached; } -static void print_sdp(void) -{ - char sdp[16384]; - int i; - int j; - AVIOContext *sdp_pb; - AVFormatContext **avc; - - for (i = 0; i < nb_output_files; i++) { - if (!output_files[i]->header_written) - return; - } - - avc = av_malloc_array(nb_output_files, sizeof(*avc)); - if (!avc) - exit_program(1); - for (i = 0, j = 0; i < nb_output_files; i++) { - if (!strcmp(output_files[i]->ctx->oformat->name, "rtp")) { - avc[j] = output_files[i]->ctx; - j++; - } - } - - if (!j) - goto fail; - - av_sdp_create(avc, j, sdp, sizeof(sdp)); - - if (!sdp_filename) { - av_log(NULL, AV_LOG_STDERR, "SDP:\n%s\n", sdp); - fflush(stdout); - } else { - if (avio_open2(&sdp_pb, sdp_filename, AVIO_FLAG_WRITE, &int_cb, NULL) < 0) { - av_log(NULL, AV_LOG_ERROR, "Failed to open sdp file '%s'\n", sdp_filename); - } else { - avio_print(sdp_pb, sdp); - avio_closep(&sdp_pb); - av_freep(&sdp_filename); - } - } - -fail: - av_freep(&avc); -} - static enum AVPixelFormat get_format(AVCodecContext *s, const enum AVPixelFormat *pix_fmts) { InputStream *ist = s->opaque; @@ -3061,12 +2776,7 @@ static enum AVPixelFormat get_format(AVCodecContext *s, const enum AVPixelFormat break; } } - if (config) { - if (config->device_type != ist->hwaccel_device_type) { - // Different hwaccel offered, ignore. - continue; - } - + if (config && config->device_type == ist->hwaccel_device_type) { ret = hwaccel_decode_init(s); if (ret < 0) { if (ist->hwaccel_id == HWACCEL_GENERIC) { @@ -3079,57 +2789,15 @@ static enum AVPixelFormat get_format(AVCodecContext *s, const enum AVPixelFormat } continue; } - } else { - const HWAccel *hwaccel = NULL; - int i; - for (i = 0; hwaccels[i].name; i++) { - if (hwaccels[i].pix_fmt == *p) { - hwaccel = &hwaccels[i]; - break; - } - } - if (!hwaccel) { - // No hwaccel supporting this pixfmt. - continue; - } - if (hwaccel->id != ist->hwaccel_id) { - // Does not match requested hwaccel. - continue; - } - ret = hwaccel->init(s); - if (ret < 0) { - av_log(NULL, AV_LOG_FATAL, - "%s hwaccel requested for input stream #%d:%d, " - "but cannot be initialized.\n", hwaccel->name, - ist->file_index, ist->st->index); - return AV_PIX_FMT_NONE; - } - } - - if (ist->hw_frames_ctx) { - s->hw_frames_ctx = av_buffer_ref(ist->hw_frames_ctx); - if (!s->hw_frames_ctx) - return AV_PIX_FMT_NONE; + ist->hwaccel_pix_fmt = *p; + break; } - - ist->hwaccel_pix_fmt = *p; - break; } return *p; } -static int get_buffer(AVCodecContext *s, AVFrame *frame, int flags) -{ - InputStream *ist = s->opaque; - - if (ist->hwaccel_get_buffer && frame->format == ist->hwaccel_pix_fmt) - return ist->hwaccel_get_buffer(s, frame, flags); - - return avcodec_default_get_buffer2(s, frame, flags); -} - static int init_input_stream(int ist_index, char *error, int error_len) { int ret; @@ -3145,11 +2813,10 @@ static int init_input_stream(int ist_index, char *error, int error_len) ist->dec_ctx->opaque = ist; ist->dec_ctx->get_format = get_format; - ist->dec_ctx->get_buffer2 = get_buffer; #if LIBAVCODEC_VERSION_MAJOR < 60 -FF_DISABLE_DEPRECATION_WARNINGS + AV_NOWARN_DEPRECATED({ ist->dec_ctx->thread_safe_callbacks = 1; -FF_ENABLE_DEPRECATION_WARNINGS + }) #endif if (ist->dec_ctx->codec_id == AV_CODEC_ID_DVB_SUBTITLE && @@ -3159,8 +2826,6 @@ FF_ENABLE_DEPRECATION_WARNINGS av_log(NULL, AV_LOG_WARNING, "Warning using DVB subtitles for filtering and output at the same time is not fully supported, also see -compute_edt [0|1]\n"); } - av_dict_set(&ist->decoder_opts, "sub_text_format", "ass", AV_DICT_DONT_OVERWRITE); - /* Useful for subtitles retiming by lavf (FIXME), skipping samples in * audio, and video decoders such as cuvid or mediacodec */ ist->dec_ctx->pkt_timebase = ist->st->time_base; @@ -3210,56 +2875,6 @@ static int compare_int64(const void *a, const void *b) return FFDIFFSIGN(*(const int64_t *)a, *(const int64_t *)b); } -/* open the muxer when all the streams are initialized */ -static int check_init_output_file(OutputFile *of, int file_index) -{ - int ret, i; - - for (i = 0; i < of->ctx->nb_streams; i++) { - OutputStream *ost = output_streams[of->ost_index + i]; - if (!ost->initialized) - return 0; - } - - of->ctx->interrupt_callback = int_cb; - - ret = avformat_write_header(of->ctx, &of->opts); - if (ret < 0) { - av_log(NULL, AV_LOG_ERROR, - "Could not write header for output file #%d " - "(incorrect codec parameters ?): %s\n", - file_index, av_err2str(ret)); - return ret; - } - //assert_avoptions(of->opts); - of->header_written = 1; - - av_dump_format(of->ctx, file_index, of->ctx->url, 1); - nb_output_dumped++; - - if (sdp_filename || want_sdp) - print_sdp(); - - /* flush the muxing queues */ - for (i = 0; i < of->ctx->nb_streams; i++) { - OutputStream *ost = output_streams[of->ost_index + i]; - - /* try to improve muxing time_base (only possible if nothing has been written yet) */ - if (!av_fifo_size(ost->muxing_queue)) - ost->mux_timebase = ost->st->time_base; - - while (av_fifo_size(ost->muxing_queue)) { - AVPacket *pkt; - av_fifo_generic_read(ost->muxing_queue, &pkt, sizeof(pkt), NULL); - ost->muxing_queue_data_size -= pkt->size; - write_packet(of, pkt, ost, 1); - av_packet_free(&pkt); - } - } - - return 0; -} - static int init_output_bsfs(OutputStream *ost) { AVBSFContext *ctx = ost->bsf_ctx; @@ -3269,22 +2884,21 @@ static int init_output_bsfs(OutputStream *ost) return 0; ret = avcodec_parameters_copy(ctx->par_in, ost->st->codecpar); - if (ret < 0) - return ret; + if (ret < 0) + return ret; ctx->time_base_in = ost->st->time_base; - ret = av_bsf_init(ctx); - if (ret < 0) { - av_log(NULL, AV_LOG_ERROR, "Error initializing bitstream filter: %s\n", + ret = av_bsf_init(ctx); + if (ret < 0) { + av_log(NULL, AV_LOG_ERROR, "Error initializing bitstream filter: %s\n", ctx->filter->name); - return ret; - } + return ret; + } ret = avcodec_parameters_copy(ost->st->codecpar, ctx->par_out); if (ret < 0) return ret; - ost->st->time_base = ctx->time_base_out; return 0; @@ -3320,9 +2934,9 @@ static int init_output_stream_streamcopy(OutputStream *ost) if (!codec_tag) { unsigned int codec_tag_tmp; - if (!of->ctx->oformat->codec_tag || - av_codec_get_id (of->ctx->oformat->codec_tag, par_src->codec_tag) == par_src->codec_id || - !av_codec_get_tag2(of->ctx->oformat->codec_tag, par_src->codec_id, &codec_tag_tmp)) + if (!of->format->codec_tag || + av_codec_get_id (of->format->codec_tag, par_src->codec_tag) == par_src->codec_id || + !av_codec_get_tag2(of->format->codec_tag, par_src->codec_id, &codec_tag_tmp)) codec_tag = par_src->codec_tag; } @@ -3340,7 +2954,7 @@ static int init_output_stream_streamcopy(OutputStream *ost) else ost->st->avg_frame_rate = ist->st->avg_frame_rate; - ret = avformat_transfer_internal_stream_timing_info(of->ctx->oformat, ost->st, ist->st, copy_tb); + ret = avformat_transfer_internal_stream_timing_info(of->format, ost->st, ist->st, copy_tb); if (ret < 0) return ret; @@ -3356,9 +2970,6 @@ static int init_output_stream_streamcopy(OutputStream *ost) if (ost->st->duration <= 0 && ist->st->duration > 0) ost->st->duration = av_rescale_q(ist->st->duration, ist->st->time_base, ost->st->time_base); - // copy disposition - ost->st->disposition = ist->st->disposition; - if (ist->st->nb_side_data) { for (i = 0; i < ist->st->nb_side_data; i++) { const AVPacketSideData *sd_src = &ist->st->side_data[i]; @@ -3414,7 +3025,7 @@ static int init_output_stream_streamcopy(OutputStream *ost) static void set_encoder_id(OutputFile *of, OutputStream *ost) { - AVDictionaryEntry *e; + const AVDictionaryEntry *e; uint8_t *encoder_string; int encoder_string_len; @@ -3545,41 +3156,19 @@ static int init_output_stream_encode(OutputStream *ost, AVFrame *frame) InputStream *ist = get_input_stream(ost); AVCodecContext *enc_ctx = ost->enc_ctx; AVCodecContext *dec_ctx = NULL; - AVFormatContext *oc = output_files[ost->file_index]->ctx; - int j, ret; + OutputFile *of = output_files[ost->file_index]; + AVFormatContext *oc = of->ctx; + int ret; set_encoder_id(output_files[ost->file_index], ost); - // Muxers use AV_PKT_DATA_DISPLAYMATRIX to signal rotation. On the other - // hand, the legacy API makes demuxers set "rotate" metadata entries, - // which have to be filtered out to prevent leaking them to output files. - av_dict_set(&ost->st->metadata, "rotate", NULL, 0); - if (ist) { - ost->st->disposition = ist->st->disposition; - dec_ctx = ist->dec_ctx; - - enc_ctx->chroma_sample_location = dec_ctx->chroma_sample_location; - } else { - for (j = 0; j < oc->nb_streams; j++) { - AVStream *st = oc->streams[j]; - if (st != ost->st && st->codecpar->codec_type == ost->st->codecpar->codec_type) - break; - } - if (j == oc->nb_streams) - if (ost->st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO || - ost->st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) - ost->st->disposition = AV_DISPOSITION_DEFAULT; } if (enc_ctx->codec_type == AVMEDIA_TYPE_VIDEO) { if (!ost->frame_rate.num) ost->frame_rate = av_buffersink_get_frame_rate(ost->filter->filter); - if (ist && !ost->frame_rate.num) - ost->frame_rate = ist->framerate; - if (ist && !ost->frame_rate.num) - ost->frame_rate = ist->st->r_frame_rate; if (ist && !ost->frame_rate.num && !ost->max_frame_rate.num) { ost->frame_rate = (AVRational){25, 1}; av_log(NULL, AV_LOG_WARNING, @@ -3609,12 +3198,16 @@ static int init_output_stream_encode(OutputStream *ost, AVFrame *frame) switch (enc_ctx->codec_type) { case AVMEDIA_TYPE_AUDIO: enc_ctx->sample_fmt = av_buffersink_get_format(ost->filter->filter); - if (dec_ctx) + enc_ctx->sample_rate = av_buffersink_get_sample_rate(ost->filter->filter); + ret = av_buffersink_get_ch_layout(ost->filter->filter, &enc_ctx->ch_layout); + if (ret < 0) + return ret; + + if (ost->bits_per_raw_sample) + enc_ctx->bits_per_raw_sample = ost->bits_per_raw_sample; + else if (dec_ctx && ost->filter->graph->is_meta) enc_ctx->bits_per_raw_sample = FFMIN(dec_ctx->bits_per_raw_sample, av_get_bytes_per_sample(enc_ctx->sample_fmt) << 3); - enc_ctx->sample_rate = av_buffersink_get_sample_rate(ost->filter->filter); - enc_ctx->channel_layout = av_buffersink_get_channel_layout(ost->filter->filter); - enc_ctx->channels = av_buffersink_get_channels(ost->filter->filter); init_encoder_time_base(ost, av_make_q(1, enc_ctx->sample_rate)); break; @@ -3624,10 +3217,12 @@ static int init_output_stream_encode(OutputStream *ost, AVFrame *frame) if (!(enc_ctx->time_base.num && enc_ctx->time_base.den)) enc_ctx->time_base = av_buffersink_get_time_base(ost->filter->filter); - if ( av_q2d(enc_ctx->time_base) < 0.001 && video_sync_method != VSYNC_PASSTHROUGH - && (video_sync_method == VSYNC_CFR || video_sync_method == VSYNC_VSCFR || (video_sync_method == VSYNC_AUTO && !(oc->oformat->flags & AVFMT_VARIABLE_FPS)))){ + if ( av_q2d(enc_ctx->time_base) < 0.001 && ost->vsync_method != VSYNC_PASSTHROUGH + && (ost->vsync_method == VSYNC_CFR || ost->vsync_method == VSYNC_VSCFR || + (ost->vsync_method == VSYNC_AUTO && !(of->format->flags & AVFMT_VARIABLE_FPS)))){ av_log(oc, AV_LOG_WARNING, "Frame rate very high for a muxer not efficiently supporting it.\n" - "Please consider specifying a lower framerate, a different muxer or -vsync 2\n"); + "Please consider specifying a lower framerate, a different muxer or " + "setting vsync/fps_mode to vfr\n"); } enc_ctx->width = av_buffersink_get_w(ost->filter->filter); @@ -3638,7 +3233,10 @@ static int init_output_stream_encode(OutputStream *ost, AVFrame *frame) av_buffersink_get_sample_aspect_ratio(ost->filter->filter); enc_ctx->pix_fmt = av_buffersink_get_format(ost->filter->filter); - if (dec_ctx) + + if (ost->bits_per_raw_sample) + enc_ctx->bits_per_raw_sample = ost->bits_per_raw_sample; + else if (dec_ctx && ost->filter->graph->is_meta) enc_ctx->bits_per_raw_sample = FFMIN(dec_ctx->bits_per_raw_sample, av_pix_fmt_desc_get(enc_ctx->pix_fmt)->comp[0].depth); @@ -3654,13 +3252,6 @@ static int init_output_stream_encode(OutputStream *ost, AVFrame *frame) ost->st->avg_frame_rate = ost->frame_rate; - if (!dec_ctx || - enc_ctx->width != dec_ctx->width || - enc_ctx->height != dec_ctx->height || - enc_ctx->pix_fmt != dec_ctx->pix_fmt) { - enc_ctx->bits_per_raw_sample = frame_bits_per_raw_sample; - } - // Field order: autodetection if (frame) { if (enc_ctx->flags & (AV_CODEC_FLAG_INTERLACED_DCT | AV_CODEC_FLAG_INTERLACED_ME) && @@ -3697,8 +3288,8 @@ static int init_output_stream_encode(OutputStream *ost, AVFrame *frame) ost->forced_keyframes_expr_const_values[FKF_PREV_FORCED_N] = NAN; ost->forced_keyframes_expr_const_values[FKF_PREV_FORCED_T] = NAN; - // Don't parse the 'forced_keyframes' in case of 'keep-source-keyframes', - // parse it only for static kf timings + // Don't parse the 'forced_keyframes' in case of 'keep-source-keyframes', + // parse it only for static kf timings } else if(strncmp(ost->forced_keyframes, "source", 6)) { parse_forced_key_frames(ost->forced_keyframes, ost, ost->enc_ctx); } @@ -3723,7 +3314,8 @@ static int init_output_stream_encode(OutputStream *ost, AVFrame *frame) return 0; } -static int init_output_stream(OutputStream *ost, AVFrame *frame, char *error, int error_len) +static int init_output_stream(OutputStream *ost, AVFrame *frame, + char *error, int error_len) { int ret = 0; @@ -3748,17 +3340,12 @@ static int init_output_stream(OutputStream *ost, AVFrame *frame, char *error, in } if (!av_dict_get(ost->encoder_opts, "threads", NULL, 0)) av_dict_set(&ost->encoder_opts, "threads", "auto", 0); - if (ost->enc->type == AVMEDIA_TYPE_AUDIO && - !codec->defaults && - !av_dict_get(ost->encoder_opts, "b", NULL, 0) && - !av_dict_get(ost->encoder_opts, "ab", NULL, 0)) - av_dict_set(&ost->encoder_opts, "b", "128000", 0); ret = hw_device_setup_for_encode(ost); if (ret < 0) { snprintf(error, error_len, "Device setup failed for " "encoder on output stream #%d:%d : %s", - ost->file_index, ost->index, av_err2str(ret)); + ost->file_index, ost->index, av_err2str(ret)); return ret; } @@ -3855,40 +3442,6 @@ static int init_output_stream(OutputStream *ost, AVFrame *frame, char *error, in return ret; } - // parse user provided disposition, and update stream values - if (ost->disposition) { - static const AVOption opts[] = { - { "disposition" , NULL, 0, AV_OPT_TYPE_FLAGS, { .i64 = 0 }, INT64_MIN, (double)INT64_MAX, .unit = "flags" }, - { "default" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_DEFAULT }, .unit = "flags" }, - { "dub" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_DUB }, .unit = "flags" }, - { "original" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_ORIGINAL }, .unit = "flags" }, - { "comment" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_COMMENT }, .unit = "flags" }, - { "lyrics" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_LYRICS }, .unit = "flags" }, - { "karaoke" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_KARAOKE }, .unit = "flags" }, - { "forced" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_FORCED }, .unit = "flags" }, - { "hearing_impaired" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_HEARING_IMPAIRED }, .unit = "flags" }, - { "visual_impaired" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_VISUAL_IMPAIRED }, .unit = "flags" }, - { "clean_effects" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_CLEAN_EFFECTS }, .unit = "flags" }, - { "attached_pic" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_ATTACHED_PIC }, .unit = "flags" }, - { "captions" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_CAPTIONS }, .unit = "flags" }, - { "descriptions" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_DESCRIPTIONS }, .unit = "flags" }, - { "dependent" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_DEPENDENT }, .unit = "flags" }, - { "metadata" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_METADATA }, .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; - - ret = av_opt_eval_flags(&pclass, &opts[0], ost->disposition, &ost->st->disposition); - if (ret < 0) - return ret; - } - /* initialize bitstream filters for the output stream * needs to be done here, because the codec id for streamcopy is not * known until now */ @@ -3898,7 +3451,7 @@ static int init_output_stream(OutputStream *ost, AVFrame *frame, char *error, in ost->initialized = 1; - ret = check_init_output_file(output_files[ost->file_index], ost->file_index); + ret = of_check_init(output_files[ost->file_index]); if (ret < 0) return ret; @@ -4000,8 +3553,8 @@ static int transcode_init(void) /* write headers for files with no streams */ for (i = 0; i < nb_output_files; i++) { oc = output_files[i]->ctx; - if (oc->oformat->flags & AVFMT_NOSTREAMS && oc->nb_streams == 0) { - ret = check_init_output_file(output_files[i], i); + if (output_files[i]->format->flags & AVFMT_NOSTREAMS && oc->nb_streams == 0) { + ret = of_check_init(output_files[i]); if (ret < 0) goto dump_format; } @@ -4177,13 +3730,15 @@ static int check_keyboard_interaction(int64_t cur_time) if (received_nb_signals) return AVERROR_EXIT; /* read_key() returns 0 on EOF */ - if(cur_time - keyboard_last_time >= 100000 && !run_as_daemon){ + if(cur_time - keyboard_last_time >= 100000){ key = read_key(); keyboard_last_time = cur_time; }else key = -1; - if (key == 'q') + if (key == 'q') { + av_log(NULL, AV_LOG_INFO, "\n\n[q] command received. Exiting.\n\n"); return AVERROR_EXIT; + } if (key == '+') av_log_set_level(av_log_get_level()+10); if (key == '-') av_log_set_level(av_log_get_level()-10); if (key == 's') qp_hist ^= 1; @@ -4200,7 +3755,7 @@ static int check_keyboard_interaction(int64_t cur_time) char buf[4096], target[64], command[256], arg[256] = {0}; double time; int k, n = 0; - fprintf(stderr, "\nEnter command: |all