update version to FFmpeg4.2

update version to FFmpeg4.2
pull/166/head
xufulong 5 years ago
parent 8a0ad6be65
commit 3dc207caa1
  1. 240
      app/src/main/cpp/ffmpeg/cmdutils.c
  2. 82
      app/src/main/cpp/ffmpeg/cmdutils.h
  3. 1392
      app/src/main/cpp/ffmpeg/config.h
  4. 2939
      app/src/main/cpp/ffmpeg/ffmpeg.c
  5. 147
      app/src/main/cpp/ffmpeg/ffmpeg.h
  6. 381
      app/src/main/cpp/ffmpeg/ffmpeg_filter.c
  7. 865
      app/src/main/cpp/ffmpeg/ffmpeg_opt.c
  8. 560
      app/src/main/cpp/ffmpeg/ffprobe.c

@ -33,8 +33,10 @@
#include "compat/va_copy.h" #include "compat/va_copy.h"
#include "libavformat/avformat.h" #include "libavformat/avformat.h"
#include "libavfilter/avfilter.h" #include "libavfilter/avfilter.h"
#include "libswresample/swresample.h"
#include "libswscale/swscale.h" #include "libswscale/swscale.h"
#include "libswresample/swresample.h"
#include "libpostproc/postprocess.h"
#include "libavutil/attributes.h"
#include "libavutil/avassert.h" #include "libavutil/avassert.h"
#include "libavutil/avstring.h" #include "libavutil/avstring.h"
#include "libavutil/bprint.h" #include "libavutil/bprint.h"
@ -48,6 +50,7 @@
#include "libavutil/dict.h" #include "libavutil/dict.h"
#include "libavutil/opt.h" #include "libavutil/opt.h"
#include "libavutil/cpu.h" #include "libavutil/cpu.h"
#include "libavutil/ffversion.h"
#include "libavutil/version.h" #include "libavutil/version.h"
#include "cmdutils.h" #include "cmdutils.h"
#if CONFIG_NETWORK #if CONFIG_NETWORK
@ -57,6 +60,9 @@
#include <sys/time.h> #include <sys/time.h>
#include <sys/resource.h> #include <sys/resource.h>
#endif #endif
#ifdef _WIN32
#include <windows.h>
#endif
#include <setjmp.h> #include <setjmp.h>
@ -72,6 +78,12 @@ static FILE *report_file;
static int report_file_level = AV_LOG_DEBUG; static int report_file_level = AV_LOG_DEBUG;
int hide_banner = 0; int hide_banner = 0;
enum show_muxdemuxers {
SHOW_DEFAULT,
SHOW_DEMUXERS,
SHOW_MUXERS,
};
void init_opts(void) void init_opts(void)
{ {
av_dict_set(&sws_dict, "flags", "bicubic", 0); av_dict_set(&sws_dict, "flags", "bicubic", 0);
@ -107,6 +119,15 @@ static void log_callback_report(void *ptr, int level, const char *fmt, va_list v
} }
} }
void init_dynload(void)
{
#ifdef _WIN32
/* Calling SetDllDirectory with the empty string (but not NULL) removes the
* current working directory from the DLL search path as a security pre-caution. */
SetDllDirectory("");
#endif
}
static void (*program_exit)(int ret); static void (*program_exit)(int ret);
void register_exit(void (*cb)(int ret)) void register_exit(void (*cb)(int ret))
@ -114,13 +135,12 @@ void register_exit(void (*cb)(int ret))
program_exit = cb; program_exit = cb;
} }
int exit_program(int ret) void exit_program(int ret)
{ {
if (program_exit) if (program_exit)
program_exit(ret); program_exit(ret);
longjmp(jump_buf, 1); longjmp(jump_buf, 1);
return ret;
} }
double parse_number_or_die(const char *context, const char *numstr, int type, double parse_number_or_die(const char *context, const char *numstr, int type,
@ -214,7 +234,6 @@ static const OptionDef *find_option(const OptionDef *po, const char *name)
* by default. HAVE_COMMANDLINETOARGVW is true on cygwin, while * by default. HAVE_COMMANDLINETOARGVW is true on cygwin, while
* it doesn't provide the actual command line via GetCommandLineW(). */ * it doesn't provide the actual command line via GetCommandLineW(). */
#if HAVE_COMMANDLINETOARGVW && defined(_WIN32) #if HAVE_COMMANDLINETOARGVW && defined(_WIN32)
#include <windows.h>
#include <shellapi.h> #include <shellapi.h>
/* Will be leaked on exit */ /* Will be leaked on exit */
static char** win32_argv_utf8 = NULL; static char** win32_argv_utf8 = NULL;
@ -864,28 +883,54 @@ int opt_loglevel(void *optctx, const char *opt, const char *arg)
{ "debug" , AV_LOG_DEBUG }, { "debug" , AV_LOG_DEBUG },
{ "trace" , AV_LOG_TRACE }, { "trace" , AV_LOG_TRACE },
}; };
const char *token;
char *tail; char *tail;
int level; int flags = av_log_get_flags();
int flags; int level = av_log_get_level();
int i; int cmd, i = 0;
flags = av_log_get_flags(); av_assert0(arg);
tail = strstr(arg, "repeat"); while (*arg) {
if (tail) token = arg;
flags &= ~AV_LOG_SKIP_REPEATED; if (*token == '+' || *token == '-') {
else cmd = *token++;
flags |= AV_LOG_SKIP_REPEATED; } else {
cmd = 0;
av_log_set_flags(flags); }
if (tail == arg) if (!i && !cmd) {
arg += 6 + (arg[6]=='+'); flags = 0; /* missing relative prefix, build absolute value */
if(tail && !*arg) }
return 0; if (!strncmp(token, "repeat", 6)) {
if (cmd == '-') {
flags |= AV_LOG_SKIP_REPEATED;
} else {
flags &= ~AV_LOG_SKIP_REPEATED;
}
arg = token + 6;
} else if (!strncmp(token, "level", 5)) {
if (cmd == '-') {
flags &= ~AV_LOG_PRINT_LEVEL;
} else {
flags |= AV_LOG_PRINT_LEVEL;
}
arg = token + 5;
} 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++) { for (i = 0; i < FF_ARRAY_ELEMS(log_levels); i++) {
if (!strcmp(log_levels[i].name, arg)) { if (!strcmp(log_levels[i].name, arg)) {
av_log_set_level(log_levels[i].level); level = log_levels[i].level;
return 0; goto end;
} }
} }
@ -897,6 +942,9 @@ int opt_loglevel(void *optctx, const char *opt, const char *arg)
av_log(NULL, AV_LOG_FATAL, "\"%s\"\n", log_levels[i].name); av_log(NULL, AV_LOG_FATAL, "\"%s\"\n", log_levels[i].name);
exit_program(1); exit_program(1);
} }
end:
av_log_set_flags(flags);
av_log_set_level(level); av_log_set_level(level);
return 0; return 0;
} }
@ -972,7 +1020,7 @@ static int init_report(const char *env)
av_free(key); av_free(key);
} }
av_bprint_init(&filename, 0, 1); av_bprint_init(&filename, 0, AV_BPRINT_SIZE_AUTOMATIC);
expand_filename_template(&filename, expand_filename_template(&filename,
av_x_if_null(filename_template, "%p-%t.log"), tm); av_x_if_null(filename_template, "%p-%t.log"), tm);
av_free(filename_template); av_free(filename_template);
@ -1086,15 +1134,21 @@ static void print_all_libs_info(int flags, int level)
PRINT_LIB_INFO(avfilter, AVFILTER, flags, level); PRINT_LIB_INFO(avfilter, AVFILTER, flags, level);
PRINT_LIB_INFO(swscale, SWSCALE, flags, level); PRINT_LIB_INFO(swscale, SWSCALE, flags, level);
PRINT_LIB_INFO(swresample, SWRESAMPLE, flags, level); PRINT_LIB_INFO(swresample, SWRESAMPLE, flags, level);
PRINT_LIB_INFO(postproc, POSTPROC, flags, level);
} }
static void print_program_info(int flags, int level) static void print_program_info(int flags, int level)
{ {
const char *indent = flags & INDENT? " " : ""; const char *indent = flags & INDENT? " " : "";
av_log(NULL, level, "%s version " FFMPEG_VERSION, program_name);
if (flags & SHOW_COPYRIGHT) 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, "\n");
av_log(NULL, level, FFMPEG_CONFIGURATION, indent); 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) static void print_buildconf(int flags, int level)
@ -1232,10 +1286,12 @@ static int is_device(const AVClass *avclass)
return AV_IS_INPUT_DEVICE(avclass->category) || AV_IS_OUTPUT_DEVICE(avclass->category); 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) static int show_formats_devices(void *optctx, const char *opt, const char *arg, int device_only, int muxdemuxers)
{ {
AVInputFormat *ifmt = NULL; void *ifmt_opaque = NULL;
AVOutputFormat *ofmt = NULL; const AVInputFormat *ifmt = NULL;
void *ofmt_opaque = NULL;
const AVOutputFormat *ofmt = NULL;
const char *last_name; const char *last_name;
int is_dev; int is_dev;
@ -1250,29 +1306,35 @@ static int show_formats_devices(void *optctx, const char *opt, const char *arg,
const char *name = NULL; const char *name = NULL;
const char *long_name = NULL; const char *long_name = NULL;
while ((ofmt = av_oformat_next(ofmt))) { if (muxdemuxers !=SHOW_DEMUXERS) {
is_dev = is_device(ofmt->priv_class); ofmt_opaque = NULL;
if (!is_dev && device_only) while ((ofmt = av_muxer_iterate(&ofmt_opaque))) {
continue; is_dev = is_device(ofmt->priv_class);
if ((!name || strcmp(ofmt->name, name) < 0) && if (!is_dev && device_only)
strcmp(ofmt->name, last_name) > 0) { continue;
name = ofmt->name; if ((!name || strcmp(ofmt->name, name) < 0) &&
long_name = ofmt->long_name; strcmp(ofmt->name, last_name) > 0) {
encode = 1; name = ofmt->name;
long_name = ofmt->long_name;
encode = 1;
}
} }
} }
while ((ifmt = av_iformat_next(ifmt))) { if (muxdemuxers != SHOW_MUXERS) {
is_dev = is_device(ifmt->priv_class); ifmt_opaque = NULL;
if (!is_dev && device_only) while ((ifmt = av_demuxer_iterate(&ifmt_opaque))) {
continue; is_dev = is_device(ifmt->priv_class);
if ((!name || strcmp(ifmt->name, name) < 0) && if (!is_dev && device_only)
strcmp(ifmt->name, last_name) > 0) { continue;
name = ifmt->name; if ((!name || strcmp(ifmt->name, name) < 0) &&
long_name = ifmt->long_name; strcmp(ifmt->name, last_name) > 0) {
encode = 0; name = ifmt->name;
long_name = ifmt->long_name;
encode = 0;
}
if (name && strcmp(ifmt->name, name) == 0)
decode = 1;
} }
if (name && strcmp(ifmt->name, name) == 0)
decode = 1;
} }
if (!name) if (!name)
break; break;
@ -1289,12 +1351,22 @@ static int show_formats_devices(void *optctx, const char *opt, const char *arg,
int show_formats(void *optctx, const char *opt, const char *arg) int show_formats(void *optctx, const char *opt, const char *arg)
{ {
return show_formats_devices(optctx, opt, arg, 0); 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) int show_devices(void *optctx, const char *opt, const char *arg)
{ {
return show_formats_devices(optctx, opt, arg, 1); return show_formats_devices(optctx, opt, arg, 1, SHOW_DEFAULT);
} }
#define PRINT_CODEC_SUPPORTED(codec, field, type, list_name, term, get_name) \ #define PRINT_CODEC_SUPPORTED(codec, field, type, list_name, term, get_name) \
@ -1342,6 +1414,16 @@ static void print_codec(const AVCodec *c)
AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_SLICE_THREADS |
AV_CODEC_CAP_AUTO_THREADS)) AV_CODEC_CAP_AUTO_THREADS))
printf("threads "); printf("threads ");
if (c->capabilities & AV_CODEC_CAP_AVOID_PROBING)
printf("avoidprobe ");
if (c->capabilities & AV_CODEC_CAP_INTRA_ONLY)
printf("intraonly ");
if (c->capabilities & AV_CODEC_CAP_LOSSLESS)
printf("lossless ");
if (c->capabilities & AV_CODEC_CAP_HARDWARE)
printf("hardware ");
if (c->capabilities & AV_CODEC_CAP_HYBRID)
printf("hybrid ");
if (!c->capabilities) if (!c->capabilities)
printf("none"); printf("none");
printf("\n"); printf("\n");
@ -1362,6 +1444,17 @@ static void print_codec(const AVCodec *c)
printf("\n"); printf("\n");
} }
if (avcodec_get_hw_config(c, 0)) {
printf(" Supported hardware devices: ");
for (int i = 0;; i++) {
const AVCodecHWConfig *config = avcodec_get_hw_config(c, i);
if (!config)
break;
printf("%s ", av_hwdevice_get_type_name(config->device_type));
}
printf("\n");
}
if (c->supported_framerates) { if (c->supported_framerates) {
const AVRational *fps = c->supported_framerates; const AVRational *fps = c->supported_framerates;
@ -1560,10 +1653,11 @@ int show_encoders(void *optctx, const char *opt, const char *arg)
int show_bsfs(void *optctx, const char *opt, const char *arg) int show_bsfs(void *optctx, const char *opt, const char *arg)
{ {
AVBitStreamFilter *bsf = NULL; const AVBitStreamFilter *bsf = NULL;
void *opaque = NULL;
printf("Bitstream filters:\n"); printf("Bitstream filters:\n");
while ((bsf = av_bitstream_filter_next(bsf))) while ((bsf = av_bsf_iterate(&opaque)))
printf("%s\n", bsf->name); printf("%s\n", bsf->name);
printf("\n"); printf("\n");
return 0; return 0;
@ -1589,6 +1683,7 @@ int show_filters(void *optctx, const char *opt, const char *arg)
#if CONFIG_AVFILTER #if CONFIG_AVFILTER
const AVFilter *filter = NULL; const AVFilter *filter = NULL;
char descr[64], *descr_cur; char descr[64], *descr_cur;
void *opaque = NULL;
int i, j; int i, j;
const AVFilterPad *pad; const AVFilterPad *pad;
@ -1600,7 +1695,7 @@ int show_filters(void *optctx, const char *opt, const char *arg)
" V = Video input/output\n" " V = Video input/output\n"
" N = Dynamic number and/or type of input/output\n" " N = Dynamic number and/or type of input/output\n"
" | = Source or sink filter\n"); " | = Source or sink filter\n");
while ((filter = avfilter_next(filter))) { while ((filter = av_filter_iterate(&opaque))) {
descr_cur = descr; descr_cur = descr;
for (i = 0; i < 2; i++) { for (i = 0; i < 2; i++) {
if (i) { if (i) {
@ -1663,7 +1758,7 @@ int show_pix_fmts(void *optctx, const char *opt, const char *arg)
#endif #endif
while ((pix_desc = av_pix_fmt_desc_next(pix_desc))) { while ((pix_desc = av_pix_fmt_desc_next(pix_desc))) {
enum AVPixelFormat pix_fmt = av_pix_fmt_desc_get_id(pix_desc); enum AVPixelFormat av_unused pix_fmt = av_pix_fmt_desc_get_id(pix_desc);
printf("%c%c%c%c%c %-16s %d %2d\n", printf("%c%c%c%c%c %-16s %d %2d\n",
sws_isSupportedInput (pix_fmt) ? 'I' : '.', sws_isSupportedInput (pix_fmt) ? 'I' : '.',
sws_isSupportedOutput(pix_fmt) ? 'O' : '.', sws_isSupportedOutput(pix_fmt) ? 'O' : '.',
@ -1857,6 +1952,25 @@ static void show_help_filter(const char *name)
} }
#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;
}
printf("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) int show_help(void *optctx, const char *opt, const char *arg)
{ {
char *topic, *par; char *topic, *par;
@ -1883,6 +1997,8 @@ int show_help(void *optctx, const char *opt, const char *arg)
} else if (!strcmp(topic, "filter")) { } else if (!strcmp(topic, "filter")) {
show_help_filter(par); show_help_filter(par);
#endif #endif
} else if (!strcmp(topic, "bsf")) {
show_help_bsf(par);
} else { } else {
show_help_default(topic, par); show_help_default(topic, par);
} }
@ -1974,7 +2090,7 @@ AVDictionary *filter_codec_opts(AVDictionary *opts, enum AVCodecID codec_id,
codec = s->oformat ? avcodec_find_encoder(codec_id) codec = s->oformat ? avcodec_find_encoder(codec_id)
: avcodec_find_decoder(codec_id); : avcodec_find_decoder(codec_id);
switch (st->codec->codec_type) { switch (st->codecpar->codec_type) {
case AVMEDIA_TYPE_VIDEO: case AVMEDIA_TYPE_VIDEO:
prefix = 'v'; prefix = 'v';
flags |= AV_OPT_FLAG_VIDEO_PARAM; flags |= AV_OPT_FLAG_VIDEO_PARAM;
@ -2032,7 +2148,7 @@ AVDictionary **setup_find_stream_info_opts(AVFormatContext *s,
return NULL; return NULL;
} }
for (i = 0; i < s->nb_streams; i++) for (i = 0; i < s->nb_streams; i++)
opts[i] = filter_codec_opts(codec_opts, s->streams[i]->codec->codec_id, opts[i] = filter_codec_opts(codec_opts, s->streams[i]->codecpar->codec_id,
s, s->streams[i], NULL); s, s->streams[i], NULL);
return opts; return opts;
} }
@ -2058,18 +2174,10 @@ void *grow_array(void *array, int elem_size, int *size, int new_size)
double get_rotation(AVStream *st) double get_rotation(AVStream *st)
{ {
AVDictionaryEntry *rotate_tag = av_dict_get(st->metadata, "rotate", NULL, 0);
uint8_t* displaymatrix = av_stream_get_side_data(st, uint8_t* displaymatrix = av_stream_get_side_data(st,
AV_PKT_DATA_DISPLAYMATRIX, NULL); AV_PKT_DATA_DISPLAYMATRIX, NULL);
double theta = 0; double theta = 0;
if (displaymatrix)
if (rotate_tag && *rotate_tag->value && strcmp(rotate_tag->value, "0")) {
char *tail;
theta = av_strtod(rotate_tag->value, &tail);
if (*tail)
theta = 0;
}
if (displaymatrix && !theta)
theta = -av_display_rotation_get((int32_t*) displaymatrix); theta = -av_display_rotation_get((int32_t*) displaymatrix);
theta -= 360*floor(theta/360 + 0.9/360); theta -= 360*floor(theta/360 + 0.9/360);
@ -2092,7 +2200,7 @@ static int print_device_sources(AVInputFormat *fmt, AVDictionary *opts)
if (!fmt || !fmt->priv_class || !AV_IS_INPUT_DEVICE(fmt->priv_class->category)) if (!fmt || !fmt->priv_class || !AV_IS_INPUT_DEVICE(fmt->priv_class->category))
return AVERROR(EINVAL); return AVERROR(EINVAL);
printf("Audo-detected sources for %s:\n", fmt->name); printf("Auto-detected sources for %s:\n", fmt->name);
if (!fmt->get_device_list) { if (!fmt->get_device_list) {
ret = AVERROR(ENOSYS); ret = AVERROR(ENOSYS);
printf("Cannot list sources. Not implemented.\n"); printf("Cannot list sources. Not implemented.\n");
@ -2122,7 +2230,7 @@ static int print_device_sinks(AVOutputFormat *fmt, AVDictionary *opts)
if (!fmt || !fmt->priv_class || !AV_IS_OUTPUT_DEVICE(fmt->priv_class->category)) if (!fmt || !fmt->priv_class || !AV_IS_OUTPUT_DEVICE(fmt->priv_class->category))
return AVERROR(EINVAL); return AVERROR(EINVAL);
printf("Audo-detected sinks for %s:\n", fmt->name); printf("Auto-detected sinks for %s:\n", fmt->name);
if (!fmt->get_device_list) { if (!fmt->get_device_list) {
ret = AVERROR(ENOSYS); ret = AVERROR(ENOSYS);
printf("Cannot list sinks. Not implemented.\n"); printf("Cannot list sinks. Not implemented.\n");

@ -19,8 +19,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#ifndef CMDUTILS_H #ifndef FFTOOLS_CMDUTILS_H
#define CMDUTILS_H #define FFTOOLS_CMDUTILS_H
#include <stdint.h> #include <stdint.h>
@ -59,7 +59,12 @@ void register_exit(void (*cb)(int ret));
/** /**
* Wraps exit with a program-specific cleanup routine. * Wraps exit with a program-specific cleanup routine.
*/ */
int exit_program(int ret); void exit_program(int ret) av_noreturn;
/**
* Initialize dynamic library loading
*/
void init_dynload(void);
/** /**
* Initialize the cmdutils option system, in particular * Initialize the cmdutils option system, in particular
@ -100,12 +105,6 @@ int opt_max_alloc(void *optctx, const char *opt, const char *arg);
int opt_codec_debug(void *optctx, const char *opt, const char *arg); int opt_codec_debug(void *optctx, const char *opt, const char *arg);
#if CONFIG_OPENCL
int opt_opencl(void *optctx, const char *opt, const char *arg);
int opt_opencl_bench(void *optctx, const char *opt, const char *arg);
#endif
/** /**
* Limit the execution time. * Limit the execution time.
*/ */
@ -150,6 +149,7 @@ typedef struct SpecifierOpt {
uint8_t *str; uint8_t *str;
int i; int i;
int64_t i64; int64_t i64;
uint64_t ui64;
float f; float f;
double dbl; double dbl;
} u; } u;
@ -201,6 +201,47 @@ typedef struct OptionDef {
void show_help_options(const OptionDef *options, const char *msg, int req_flags, void show_help_options(const OptionDef *options, const char *msg, int req_flags,
int rej_flags, int alt_flags); int rej_flags, int alt_flags);
#if CONFIG_AVDEVICE
#define CMDUTILS_COMMON_OPTIONS_AVDEVICE \
{ "sources" , OPT_EXIT | HAS_ARG, { .func_arg = show_sources }, \
"list sources of the input device", "device" }, \
{ "sinks" , OPT_EXIT | HAS_ARG, { .func_arg = show_sinks }, \
"list sinks of the output device", "device" }, \
#else
#define CMDUTILS_COMMON_OPTIONS_AVDEVICE
#endif
#define CMDUTILS_COMMON_OPTIONS \
{ "L", OPT_EXIT, { .func_arg = show_license }, "show license" }, \
{ "h", OPT_EXIT, { .func_arg = show_help }, "show help", "topic" }, \
{ "?", OPT_EXIT, { .func_arg = show_help }, "show help", "topic" }, \
{ "help", OPT_EXIT, { .func_arg = show_help }, "show help", "topic" }, \
{ "-help", OPT_EXIT, { .func_arg = show_help }, "show help", "topic" }, \
{ "version", OPT_EXIT, { .func_arg = show_version }, "show version" }, \
{ "buildconf", OPT_EXIT, { .func_arg = show_buildconf }, "show build configuration" }, \
{ "formats", OPT_EXIT, { .func_arg = show_formats }, "show available formats" }, \
{ "muxers", OPT_EXIT, { .func_arg = show_muxers }, "show available muxers" }, \
{ "demuxers", OPT_EXIT, { .func_arg = show_demuxers }, "show available demuxers" }, \
{ "devices", OPT_EXIT, { .func_arg = show_devices }, "show available devices" }, \
{ "codecs", OPT_EXIT, { .func_arg = show_codecs }, "show available codecs" }, \
{ "decoders", OPT_EXIT, { .func_arg = show_decoders }, "show available decoders" }, \
{ "encoders", OPT_EXIT, { .func_arg = show_encoders }, "show available encoders" }, \
{ "bsfs", OPT_EXIT, { .func_arg = show_bsfs }, "show available bit stream filters" }, \
{ "protocols", OPT_EXIT, { .func_arg = show_protocols }, "show available protocols" }, \
{ "filters", OPT_EXIT, { .func_arg = show_filters }, "show available filters" }, \
{ "pix_fmts", OPT_EXIT, { .func_arg = show_pix_fmts }, "show available pixel formats" }, \
{ "layouts", OPT_EXIT, { .func_arg = show_layouts }, "show standard channel layouts" }, \
{ "sample_fmts", OPT_EXIT, { .func_arg = show_sample_fmts }, "show available audio sample formats" }, \
{ "colors", OPT_EXIT, { .func_arg = show_colors }, "show available color names" }, \
{ "loglevel", HAS_ARG, { .func_arg = opt_loglevel }, "set logging level", "loglevel" }, \
{ "v", HAS_ARG, { .func_arg = opt_loglevel }, "set logging level", "loglevel" }, \
{ "report", 0, { (void*)opt_report }, "generate a report" }, \
{ "max_alloc", HAS_ARG, { .func_arg = opt_max_alloc }, "set maximum size of a single allocated block", "bytes" }, \
{ "cpuflags", HAS_ARG | OPT_EXPERT, { .func_arg = opt_cpuflags }, "force specific cpu flags", "flags" }, \
{ "hide_banner", OPT_BOOL | OPT_EXPERT, {&hide_banner}, "do not show program banner", "hide_banner" }, \
CMDUTILS_COMMON_OPTIONS_AVDEVICE \
/** /**
* Show help for all options with given flags in class and all its * Show help for all options with given flags in class and all its
* children. * children.
@ -436,6 +477,20 @@ int show_license(void *optctx, const char *opt, const char *arg);
*/ */
int show_formats(void *optctx, const char *opt, const char *arg); 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 * Print a listing containing all the devices supported by the
* program. * program.
@ -445,13 +500,13 @@ int show_devices(void *optctx, const char *opt, const char *arg);
#if CONFIG_AVDEVICE #if CONFIG_AVDEVICE
/** /**
* Print a listing containing audodetected sinks of the output device. * Print a listing containing autodetected sinks of the output device.
* Device name with options may be passed as an argument to limit results. * Device name with options may be passed as an argument to limit results.
*/ */
int show_sinks(void *optctx, const char *opt, const char *arg); int show_sinks(void *optctx, const char *opt, const char *arg);
/** /**
* Print a listing containing audodetected sources of the input device. * Print a listing containing autodetected sources of the input device.
* Device name with options may be passed as an argument to limit results. * Device name with options may be passed as an argument to limit results.
*/ */
int show_sources(void *optctx, const char *opt, const char *arg); int show_sources(void *optctx, const char *opt, const char *arg);
@ -570,6 +625,9 @@ void *grow_array(void *array, int elem_size, int *size, int new_size);
#define GET_PIX_FMT_NAME(pix_fmt)\ #define GET_PIX_FMT_NAME(pix_fmt)\
const char *name = av_get_pix_fmt_name(pix_fmt); const char *name = av_get_pix_fmt_name(pix_fmt);
#define GET_CODEC_NAME(id)\
const char *name = avcodec_descriptor_get(id)->name;
#define GET_SAMPLE_FMT_NAME(sample_fmt)\ #define GET_SAMPLE_FMT_NAME(sample_fmt)\
const char *name = av_get_sample_fmt_name(sample_fmt) const char *name = av_get_sample_fmt_name(sample_fmt)
@ -587,4 +645,4 @@ void *grow_array(void *array, int elem_size, int *size, int new_size);
double get_rotation(AVStream *st); double get_rotation(AVStream *st);
#endif /* CMDUTILS_H */ #endif /* FFTOOLS_CMDUTILS_H */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -16,8 +16,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#ifndef FFMPEG_H #ifndef FFTOOLS_FFMPEG_H
#define FFMPEG_H #define FFTOOLS_FFMPEG_H
#include "config.h" #include "config.h"
@ -25,10 +25,6 @@
#include <stdio.h> #include <stdio.h>
#include <signal.h> #include <signal.h>
#if HAVE_PTHREADS
#include <pthread.h>
#endif
#include "cmdutils.h" #include "cmdutils.h"
#include "libavformat/avformat.h" #include "libavformat/avformat.h"
@ -42,8 +38,10 @@
#include "libavutil/dict.h" #include "libavutil/dict.h"
#include "libavutil/eval.h" #include "libavutil/eval.h"
#include "libavutil/fifo.h" #include "libavutil/fifo.h"
#include "libavutil/hwcontext.h"
#include "libavutil/pixfmt.h" #include "libavutil/pixfmt.h"
#include "libavutil/rational.h" #include "libavutil/rational.h"
#include "libavutil/thread.h"
#include "libavutil/threadmessage.h" #include "libavutil/threadmessage.h"
#include "libswresample/swresample.h" #include "libswresample/swresample.h"
@ -60,11 +58,10 @@
enum HWAccelID { enum HWAccelID {
HWACCEL_NONE = 0, HWACCEL_NONE = 0,
HWACCEL_AUTO, HWACCEL_AUTO,
HWACCEL_VDPAU, HWACCEL_GENERIC,
HWACCEL_DXVA2,
HWACCEL_VDA,
HWACCEL_VIDEOTOOLBOX, HWACCEL_VIDEOTOOLBOX,
HWACCEL_QSV, HWACCEL_QSV,
HWACCEL_CUVID,
}; };
typedef struct HWAccel { typedef struct HWAccel {
@ -74,6 +71,12 @@ typedef struct HWAccel {
enum AVPixelFormat pix_fmt; enum AVPixelFormat pix_fmt;
} HWAccel; } HWAccel;
typedef struct HWDevice {
const char *name;
enum AVHWDeviceType type;
AVBufferRef *device_ref;
} HWDevice;
/* select an input stream for an output stream */ /* select an input stream for an output stream */
typedef struct StreamMap { typedef struct StreamMap {
int disabled; /* 1 is this mapping is disabled by a negative map */ int disabled; /* 1 is this mapping is disabled by a negative map */
@ -126,6 +129,8 @@ typedef struct OptionsContext {
int nb_hwaccels; int nb_hwaccels;
SpecifierOpt *hwaccel_devices; SpecifierOpt *hwaccel_devices;
int nb_hwaccel_devices; int nb_hwaccel_devices;
SpecifierOpt *hwaccel_output_formats;
int nb_hwaccel_output_formats;
SpecifierOpt *autorotate; SpecifierOpt *autorotate;
int nb_autorotate; int nb_autorotate;
@ -148,6 +153,7 @@ typedef struct OptionsContext {
float mux_preload; float mux_preload;
float mux_max_delay; float mux_max_delay;
int shortest; int shortest;
int bitexact;
int video_disable; int video_disable;
int audio_disable; int audio_disable;
@ -208,6 +214,8 @@ typedef struct OptionsContext {
int nb_pass; int nb_pass;
SpecifierOpt *passlogfiles; SpecifierOpt *passlogfiles;
int nb_passlogfiles; int nb_passlogfiles;
SpecifierOpt *max_muxing_queue_size;
int nb_max_muxing_queue_size;
SpecifierOpt *guess_layout_max; SpecifierOpt *guess_layout_max;
int nb_guess_layout_max; int nb_guess_layout_max;
SpecifierOpt *apad; SpecifierOpt *apad;
@ -218,6 +226,10 @@ typedef struct OptionsContext {
int nb_disposition; int nb_disposition;
SpecifierOpt *program; SpecifierOpt *program;
int nb_program; int nb_program;
SpecifierOpt *time_bases;
int nb_time_bases;
SpecifierOpt *enc_time_bases;
int nb_enc_time_bases;
} OptionsContext; } OptionsContext;
typedef struct InputFilter { typedef struct InputFilter {
@ -225,6 +237,23 @@ typedef struct InputFilter {
struct InputStream *ist; struct InputStream *ist;
struct FilterGraph *graph; struct FilterGraph *graph;
uint8_t *name; uint8_t *name;
enum AVMediaType type; // AVMEDIA_TYPE_SUBTITLE for sub2video
AVFifoBuffer *frame_queue;
// parameters configured for this input
int format;
int width, height;
AVRational sample_aspect_ratio;
int sample_rate;
int channels;
uint64_t channel_layout;
AVBufferRef *hw_frames_ctx;
int eof;
} InputFilter; } InputFilter;
typedef struct OutputFilter { typedef struct OutputFilter {
@ -236,6 +265,18 @@ typedef struct OutputFilter {
/* temporary storage until stream maps are processed */ /* temporary storage until stream maps are processed */
AVFilterInOut *out_tmp; AVFilterInOut *out_tmp;
enum AVMediaType type; enum AVMediaType type;
/* desired output stream properties */
int width, height;
AVRational frame_rate;
int format;
int sample_rate;
uint64_t channel_layout;
// those are only set if no format is specified and the encoder gives us multiple options
int *formats;
uint64_t *channel_layouts;
int *sample_rates;
} OutputFilter; } OutputFilter;
typedef struct FilterGraph { typedef struct FilterGraph {
@ -279,25 +320,21 @@ typedef struct InputStream {
int64_t min_pts; /* pts with the smallest value in a current stream */ int64_t min_pts; /* pts with the smallest value in a current stream */
int64_t max_pts; /* pts with the higher value in a current stream */ int64_t max_pts; /* pts with the higher value in a current stream */
// when forcing constant input framerate through -r,
// this contains the pts that will be given to the next decoded frame
int64_t cfr_next_pts;
int64_t nb_samples; /* number of samples in the last decoded audio frame before looping */ int64_t nb_samples; /* number of samples in the last decoded audio frame before looping */
double ts_scale; double ts_scale;
int saw_first_ts; int saw_first_ts;
int showed_multi_packet_warning;
AVDictionary *decoder_opts; AVDictionary *decoder_opts;
AVRational framerate; /* framerate forced with -r */ AVRational framerate; /* framerate forced with -r */
int top_field_first; int top_field_first;
int guess_layout_max; int guess_layout_max;
int autorotate; int autorotate;
int resample_height;
int resample_width;
int resample_pix_fmt;
int resample_sample_fmt;
int resample_sample_rate;
int resample_channels;
uint64_t resample_channel_layout;
int fix_sub_duration; int fix_sub_duration;
struct { /* previous decoded subtitle and related variables */ struct { /* previous decoded subtitle and related variables */
@ -309,6 +346,7 @@ typedef struct InputStream {
struct sub2video { struct sub2video {
int64_t last_pts; int64_t last_pts;
int64_t end_pts; int64_t end_pts;
AVFifoBuffer *sub_queue; ///< queue of AVSubtitle* before filter init
AVFrame *frame; AVFrame *frame;
int w, h; int w, h;
} sub2video; } sub2video;
@ -324,16 +362,18 @@ typedef struct InputStream {
/* hwaccel options */ /* hwaccel options */
enum HWAccelID hwaccel_id; enum HWAccelID hwaccel_id;
enum AVHWDeviceType hwaccel_device_type;
char *hwaccel_device; char *hwaccel_device;
enum AVPixelFormat hwaccel_output_format;
/* hwaccel context */ /* hwaccel context */
enum HWAccelID active_hwaccel_id;
void *hwaccel_ctx; void *hwaccel_ctx;
void (*hwaccel_uninit)(AVCodecContext *s); void (*hwaccel_uninit)(AVCodecContext *s);
int (*hwaccel_get_buffer)(AVCodecContext *s, AVFrame *frame, int flags); int (*hwaccel_get_buffer)(AVCodecContext *s, AVFrame *frame, int flags);
int (*hwaccel_retrieve_data)(AVCodecContext *s, AVFrame *frame); int (*hwaccel_retrieve_data)(AVCodecContext *s, AVFrame *frame);
enum AVPixelFormat hwaccel_pix_fmt; enum AVPixelFormat hwaccel_pix_fmt;
enum AVPixelFormat hwaccel_retrieved_pix_fmt; enum AVPixelFormat hwaccel_retrieved_pix_fmt;
AVBufferRef *hw_frames_ctx;
/* stats */ /* stats */
// combined size of all the packets read // combined size of all the packets read
@ -343,6 +383,11 @@ typedef struct InputStream {
// number of frames/samples retrieved from the decoder // number of frames/samples retrieved from the decoder
uint64_t frames_decoded; uint64_t frames_decoded;
uint64_t samples_decoded; uint64_t samples_decoded;
int64_t *dts_buffer;
int nb_dts_buffer;
int got_output;
} InputStream; } InputStream;
typedef struct InputFile { typedef struct InputFile {
@ -367,7 +412,7 @@ typedef struct InputFile {
int rate_emu; int rate_emu;
int accurate_seek; int accurate_seek;
#if HAVE_PTHREADS #if HAVE_THREADS
AVThreadMessageQueue *in_thread_queue; AVThreadMessageQueue *in_thread_queue;
pthread_t thread; /* thread reading from this file */ pthread_t thread; /* thread reading from this file */
int non_blocking; /* reading packets from the thread should not block */ int non_blocking; /* reading packets from the thread should not block */
@ -410,8 +455,15 @@ typedef struct OutputStream {
int64_t first_pts; int64_t first_pts;
/* dts of the last packet sent to the muxer */ /* dts of the last packet sent to the muxer */
int64_t last_mux_dts; int64_t last_mux_dts;
AVBitStreamFilterContext *bitstream_filters; // the timebase of the packets sent to the muxer
AVRational mux_timebase;
AVRational enc_timebase;
int nb_bitstream_filters;
AVBSFContext **bsf_ctx;
AVCodecContext *enc_ctx; AVCodecContext *enc_ctx;
AVCodecParameters *ref_par; /* associated input codec parameters with encoders options applied */
AVCodec *enc; AVCodec *enc;
int64_t max_frames; int64_t max_frames;
AVFrame *filtered_frame; AVFrame *filtered_frame;
@ -427,10 +479,12 @@ typedef struct OutputStream {
int force_fps; int force_fps;
int top_field_first; int top_field_first;
int rotate_overridden; int rotate_overridden;
double rotate_override_value;
AVRational frame_aspect_ratio; AVRational frame_aspect_ratio;
/* forced key frames */ /* forced key frames */
int64_t forced_kf_ref_pts;
int64_t *forced_kf_pts; int64_t *forced_kf_pts;
int forced_kf_count; int forced_kf_count;
int forced_kf_index; int forced_kf_index;
@ -458,6 +512,14 @@ typedef struct OutputStream {
OSTFinished finished; /* no more packets should be written for this stream */ OSTFinished finished; /* no more packets should be written for this stream */
int unavailable; /* true if the steram is unavailable (possibly temporarily) */ int unavailable; /* true if the steram is unavailable (possibly temporarily) */
int stream_copy; int stream_copy;
// init_output_stream() has been called for this stream
// The encoder and the bitstream filters have been initialized and the stream
// parameters are set in the AVStream.
int initialized;
int inputs_done;
const char *attachment_filename; const char *attachment_filename;
int copy_initial_nonkeyframes; int copy_initial_nonkeyframes;
int copy_prior_start; int copy_prior_start;
@ -465,8 +527,6 @@ typedef struct OutputStream {
int keep_pix_fmt; int keep_pix_fmt;
AVCodecParserContext *parser;
/* stats */ /* stats */
// combined size of all the packets written // combined size of all the packets written
uint64_t data_size; uint64_t data_size;
@ -479,6 +539,11 @@ typedef struct OutputStream {
/* packet quality factor */ /* packet quality factor */
int quality; int quality;
int max_muxing_queue_size;
/* the packets are buffered here until the muxer is ready to be initialized */
AVFifoBuffer *muxing_queue;
/* packet picture type */ /* packet picture type */
int pict_type; int pict_type;
@ -495,6 +560,8 @@ typedef struct OutputFile {
uint64_t limit_filesize; /* filesize limit expressed in bytes */ uint64_t limit_filesize; /* filesize limit expressed in bytes */
int shortest; int shortest;
int header_written;
} OutputFile; } OutputFile;
extern InputStream **input_streams; extern InputStream **input_streams;
@ -538,13 +605,21 @@ extern int stdin_interaction;
extern int frame_bits_per_raw_sample; extern int frame_bits_per_raw_sample;
extern AVIOContext *progress_avio; extern AVIOContext *progress_avio;
extern float max_error_rate; extern float max_error_rate;
extern int vdpau_api_ver;
extern char *videotoolbox_pixfmt; extern char *videotoolbox_pixfmt;
extern int filter_nbthreads;
extern int filter_complex_nbthreads;
extern int vstats_version;
extern const AVIOInterruptCB int_cb; extern const AVIOInterruptCB int_cb;
extern const OptionDef options[]; extern const OptionDef options[];
extern const HWAccel hwaccels[]; extern const HWAccel hwaccels[];
extern AVBufferRef *hw_device_ctx;
#if CONFIG_QSV
extern char *qsv_device;
#endif
extern HWDevice *filter_hw_device;
void term_init(void); void term_init(void);
@ -565,19 +640,31 @@ void choose_sample_fmt(AVStream *st, AVCodec *codec);
int configure_filtergraph(FilterGraph *fg); int configure_filtergraph(FilterGraph *fg);
int configure_output_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out); int configure_output_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out);
void check_filter_outputs(void);
int ist_in_filtergraph(FilterGraph *fg, InputStream *ist); int ist_in_filtergraph(FilterGraph *fg, InputStream *ist);
FilterGraph *init_simple_filtergraph(InputStream *ist, OutputStream *ost); int filtergraph_is_simple(FilterGraph *fg);
int init_simple_filtergraph(InputStream *ist, OutputStream *ost);
int init_complex_filtergraph(FilterGraph *fg); int init_complex_filtergraph(FilterGraph *fg);
void sub2video_update(InputStream *ist, AVSubtitle *sub);
int ifilter_parameters_from_frame(InputFilter *ifilter, const AVFrame *frame);
int ffmpeg_parse_options(int argc, char **argv); int ffmpeg_parse_options(int argc, char **argv);
int vdpau_init(AVCodecContext *s);
int dxva2_init(AVCodecContext *s);
int vda_init(AVCodecContext *s);
int videotoolbox_init(AVCodecContext *s); int videotoolbox_init(AVCodecContext *s);
int qsv_init(AVCodecContext *s); int qsv_init(AVCodecContext *s);
int qsv_transcode_init(OutputStream *ost); int cuvid_init(AVCodecContext *s);
HWDevice *hw_device_get_by_name(const char *name);
int hw_device_init_from_string(const char *arg, HWDevice **dev);
void hw_device_free_all(void);
int hw_device_setup_for_decode(InputStream *ist);
int hw_device_setup_for_encode(OutputStream *ost);
int hwaccel_decode_init(AVCodecContext *avctx);
int run(int argc, char **argv); int run(int argc, char **argv);
#endif /* FFMPEG_H */ #endif /* FFTOOLS_FFMPEG_H */

@ -20,10 +20,11 @@
#include <stdint.h> #include <stdint.h>
#include "ffmpeg/ffmpeg.h" #include "ffmpeg.h"
#include "libavfilter/avfilter.h" #include "libavfilter/avfilter.h"
#include "libavfilter/buffersink.h" #include "libavfilter/buffersink.h"
#include "libavfilter/buffersrc.h"
#include "libavutil/avassert.h" #include "libavutil/avassert.h"
#include "libavutil/avstring.h" #include "libavutil/avstring.h"
@ -36,7 +37,6 @@
#include "libavutil/imgutils.h" #include "libavutil/imgutils.h"
#include "libavutil/samplefmt.h" #include "libavutil/samplefmt.h"
static const enum AVPixelFormat *get_compliance_unofficial_pix_fmts(enum AVCodecID codec_id, const enum AVPixelFormat default_formats[]) static const enum AVPixelFormat *get_compliance_unofficial_pix_fmts(enum AVCodecID codec_id, const enum AVPixelFormat default_formats[])
{ {
static const enum AVPixelFormat mjpeg_formats[] = static const enum AVPixelFormat mjpeg_formats[] =
@ -63,6 +63,7 @@ enum AVPixelFormat choose_pixel_fmt(AVStream *st, AVCodecContext *enc_ctx, AVCod
if (codec && codec->pix_fmts) { if (codec && codec->pix_fmts) {
const enum AVPixelFormat *p = codec->pix_fmts; const enum AVPixelFormat *p = codec->pix_fmts;
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(target); const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(target);
//FIXME: This should check for AV_PIX_FMT_FLAG_ALPHA after PAL8 pixel format without alpha is implemented
int has_alpha = desc ? desc->nb_components % 2 == 0 : 0; int has_alpha = desc ? desc->nb_components % 2 == 0 : 0;
enum AVPixelFormat best= AV_PIX_FMT_NONE; enum AVPixelFormat best= AV_PIX_FMT_NONE;
@ -92,33 +93,33 @@ void choose_sample_fmt(AVStream *st, AVCodec *codec)
if (codec && codec->sample_fmts) { if (codec && codec->sample_fmts) {
const enum AVSampleFormat *p = codec->sample_fmts; const enum AVSampleFormat *p = codec->sample_fmts;
for (; *p != -1; p++) { for (; *p != -1; p++) {
if (*p == st->codec->sample_fmt) if (*p == st->codecpar->format)
break; break;
} }
if (*p == -1) { if (*p == -1) {
if((codec->capabilities & AV_CODEC_CAP_LOSSLESS) && av_get_sample_fmt_name(st->codec->sample_fmt) > av_get_sample_fmt_name(codec->sample_fmts[0])) if((codec->capabilities & AV_CODEC_CAP_LOSSLESS) && av_get_sample_fmt_name(st->codecpar->format) > av_get_sample_fmt_name(codec->sample_fmts[0]))
av_log(NULL, AV_LOG_ERROR, "Conversion will not be lossless.\n"); av_log(NULL, AV_LOG_ERROR, "Conversion will not be lossless.\n");
if(av_get_sample_fmt_name(st->codec->sample_fmt)) if(av_get_sample_fmt_name(st->codecpar->format))
av_log(NULL, AV_LOG_WARNING, av_log(NULL, AV_LOG_WARNING,
"Incompatible sample format '%s' for codec '%s', auto-selecting format '%s'\n", "Incompatible sample format '%s' for codec '%s', auto-selecting format '%s'\n",
av_get_sample_fmt_name(st->codec->sample_fmt), av_get_sample_fmt_name(st->codecpar->format),
codec->name, codec->name,
av_get_sample_fmt_name(codec->sample_fmts[0])); av_get_sample_fmt_name(codec->sample_fmts[0]));
st->codec->sample_fmt = codec->sample_fmts[0]; st->codecpar->format = codec->sample_fmts[0];
} }
} }
} }
static char *choose_pix_fmts(OutputStream *ost) static char *choose_pix_fmts(OutputFilter *ofilter)
{ {
OutputStream *ost = ofilter->ost;
AVDictionaryEntry *strict_dict = av_dict_get(ost->encoder_opts, "strict", NULL, 0); AVDictionaryEntry *strict_dict = av_dict_get(ost->encoder_opts, "strict", NULL, 0);
if (strict_dict) if (strict_dict)
// used by choose_pixel_fmt() and below // used by choose_pixel_fmt() and below
av_opt_set(ost->enc_ctx, "strict", strict_dict->value, 0); av_opt_set(ost->enc_ctx, "strict", strict_dict->value, 0);
if (ost->keep_pix_fmt) { if (ost->keep_pix_fmt) {
if (ost->filter) avfilter_graph_set_auto_convert(ofilter->graph->graph,
avfilter_graph_set_auto_convert(ost->filter->graph->graph,
AVFILTER_AUTO_CONVERT_NONE); AVFILTER_AUTO_CONVERT_NONE);
if (ost->enc_ctx->pix_fmt == AV_PIX_FMT_NONE) if (ost->enc_ctx->pix_fmt == AV_PIX_FMT_NONE)
return NULL; return NULL;
@ -153,13 +154,13 @@ static char *choose_pix_fmts(OutputStream *ost)
/* Define a function for building a string containing a list of /* Define a function for building a string containing a list of
* allowed formats. */ * allowed formats. */
#define DEF_CHOOSE_FORMAT(type, var, supported_list, none, get_name) \ #define DEF_CHOOSE_FORMAT(suffix, type, var, supported_list, none, get_name) \
static char *choose_ ## var ## s(OutputStream *ost) \ static char *choose_ ## suffix (OutputFilter *ofilter) \
{ \ { \
if (ost->enc_ctx->var != none) { \ if (ofilter->var != none) { \
get_name(ost->enc_ctx->var); \ get_name(ofilter->var); \
return av_strdup(name); \ return av_strdup(name); \
} else if (ost->enc && ost->enc->supported_list) { \ } else if (ofilter->supported_list) { \
const type *p; \ const type *p; \
AVIOContext *s = NULL; \ AVIOContext *s = NULL; \
uint8_t *ret; \ uint8_t *ret; \
@ -168,7 +169,7 @@ static char *choose_ ## var ## s(OutputStream *ost) \
if (avio_open_dyn_buf(&s) < 0) \ if (avio_open_dyn_buf(&s) < 0) \
exit_program(1); \ exit_program(1); \
\ \
for (p = ost->enc->supported_list; *p != none; p++) { \ for (p = ofilter->supported_list; *p != none; p++) { \
get_name(*p); \ get_name(*p); \
avio_printf(s, "%s|", name); \ avio_printf(s, "%s|", name); \
} \ } \
@ -179,19 +180,19 @@ static char *choose_ ## var ## s(OutputStream *ost) \
return NULL; \ return NULL; \
} }
// DEF_CHOOSE_FORMAT(enum AVPixelFormat, pix_fmt, pix_fmts, AV_PIX_FMT_NONE, //DEF_CHOOSE_FORMAT(pix_fmts, enum AVPixelFormat, format, formats, AV_PIX_FMT_NONE,
// GET_PIX_FMT_NAME) // GET_PIX_FMT_NAME)
DEF_CHOOSE_FORMAT(enum AVSampleFormat, sample_fmt, sample_fmts, DEF_CHOOSE_FORMAT(sample_fmts, enum AVSampleFormat, format, formats,
AV_SAMPLE_FMT_NONE, GET_SAMPLE_FMT_NAME) AV_SAMPLE_FMT_NONE, GET_SAMPLE_FMT_NAME)
DEF_CHOOSE_FORMAT(int, sample_rate, supported_samplerates, 0, DEF_CHOOSE_FORMAT(sample_rates, int, sample_rate, sample_rates, 0,
GET_SAMPLE_RATE_NAME) GET_SAMPLE_RATE_NAME)
DEF_CHOOSE_FORMAT(uint64_t, channel_layout, channel_layouts, 0, DEF_CHOOSE_FORMAT(channel_layouts, uint64_t, channel_layout, channel_layouts, 0,
GET_CH_LAYOUT_NAME) GET_CH_LAYOUT_NAME)
FilterGraph *init_simple_filtergraph(InputStream *ist, OutputStream *ost) int init_simple_filtergraph(InputStream *ist, OutputStream *ost)
{ {
FilterGraph *fg = av_mallocz(sizeof(*fg)); FilterGraph *fg = av_mallocz(sizeof(*fg));
@ -204,6 +205,7 @@ FilterGraph *init_simple_filtergraph(InputStream *ist, OutputStream *ost)
exit_program(1); exit_program(1);
fg->outputs[0]->ost = ost; fg->outputs[0]->ost = ost;
fg->outputs[0]->graph = fg; fg->outputs[0]->graph = fg;
fg->outputs[0]->format = -1;
ost->filter = fg->outputs[0]; ost->filter = fg->outputs[0];
@ -212,6 +214,11 @@ FilterGraph *init_simple_filtergraph(InputStream *ist, OutputStream *ost)
exit_program(1); exit_program(1);
fg->inputs[0]->ist = ist; fg->inputs[0]->ist = ist;
fg->inputs[0]->graph = fg; fg->inputs[0]->graph = fg;
fg->inputs[0]->format = -1;
fg->inputs[0]->frame_queue = av_fifo_alloc(8 * sizeof(AVFrame*));
if (!fg->inputs[0]->frame_queue)
exit_program(1);
GROW_ARRAY(ist->filters, ist->nb_filters); GROW_ARRAY(ist->filters, ist->nb_filters);
ist->filters[ist->nb_filters - 1] = fg->inputs[0]; ist->filters[ist->nb_filters - 1] = fg->inputs[0];
@ -219,7 +226,26 @@ FilterGraph *init_simple_filtergraph(InputStream *ist, OutputStream *ost)
GROW_ARRAY(filtergraphs, nb_filtergraphs); GROW_ARRAY(filtergraphs, nb_filtergraphs);
filtergraphs[nb_filtergraphs - 1] = fg; filtergraphs[nb_filtergraphs - 1] = fg;
return fg; return 0;
}
static char *describe_filter_link(FilterGraph *fg, AVFilterInOut *inout, int in)
{
AVFilterContext *ctx = inout->filter_ctx;
AVFilterPad *pads = in ? ctx->input_pads : ctx->output_pads;
int nb_pads = in ? ctx->nb_inputs : ctx->nb_outputs;
AVIOContext *pb;
uint8_t *res = NULL;
if (avio_open_dyn_buf(&pb) < 0)
exit_program(1);
avio_printf(pb, "%s", ctx->filter->name);
if (nb_pads > 1)
avio_printf(pb, ":%s", avfilter_pad_get_name(pads, inout->pad_idx));
avio_w8(pb, 0);
avio_close_dyn_buf(pb, &res);
return res;
} }
static void init_input_filter(FilterGraph *fg, AVFilterInOut *in) static void init_input_filter(FilterGraph *fg, AVFilterInOut *in)
@ -249,7 +275,7 @@ static void init_input_filter(FilterGraph *fg, AVFilterInOut *in)
s = input_files[file_idx]->ctx; s = input_files[file_idx]->ctx;
for (i = 0; i < s->nb_streams; i++) { for (i = 0; i < s->nb_streams; i++) {
enum AVMediaType stream_type = s->streams[i]->codec->codec_type; enum AVMediaType stream_type = s->streams[i]->codecpar->codec_type;
if (stream_type != type && if (stream_type != type &&
!(stream_type == AVMEDIA_TYPE_SUBTITLE && !(stream_type == AVMEDIA_TYPE_SUBTITLE &&
type == AVMEDIA_TYPE_VIDEO /* sub2video hack */)) type == AVMEDIA_TYPE_VIDEO /* sub2video hack */))
@ -265,10 +291,17 @@ static void init_input_filter(FilterGraph *fg, AVFilterInOut *in)
exit_program(1); exit_program(1);
} }
ist = input_streams[input_files[file_idx]->ist_index + st->index]; ist = input_streams[input_files[file_idx]->ist_index + st->index];
if (ist->user_set_discard == AVDISCARD_ALL) {
av_log(NULL, AV_LOG_FATAL, "Stream specifier '%s' in filtergraph description %s "
"matches a disabled input stream.\n", p, fg->graph_desc);
exit_program(1);
}
} else { } else {
/* find the first unused stream of corresponding type */ /* find the first unused stream of corresponding type */
for (i = 0; i < nb_input_streams; i++) { for (i = 0; i < nb_input_streams; i++) {
ist = input_streams[i]; ist = input_streams[i];
if (ist->user_set_discard == AVDISCARD_ALL)
continue;
if (ist->dec_ctx->codec_type == type && ist->discard) if (ist->dec_ctx->codec_type == type && ist->discard)
break; break;
} }
@ -290,6 +323,13 @@ static void init_input_filter(FilterGraph *fg, AVFilterInOut *in)
exit_program(1); exit_program(1);
fg->inputs[fg->nb_inputs - 1]->ist = ist; fg->inputs[fg->nb_inputs - 1]->ist = ist;
fg->inputs[fg->nb_inputs - 1]->graph = fg; fg->inputs[fg->nb_inputs - 1]->graph = fg;
fg->inputs[fg->nb_inputs - 1]->format = -1;
fg->inputs[fg->nb_inputs - 1]->type = ist->st->codecpar->codec_type;
fg->inputs[fg->nb_inputs - 1]->name = describe_filter_link(fg, in, 1);
fg->inputs[fg->nb_inputs - 1]->frame_queue = av_fifo_alloc(8 * sizeof(AVFrame*));
if (!fg->inputs[fg->nb_inputs - 1]->frame_queue)
exit_program(1);
GROW_ARRAY(ist->filters, ist->nb_filters); GROW_ARRAY(ist->filters, ist->nb_filters);
ist->filters[ist->nb_filters - 1] = fg->inputs[fg->nb_inputs - 1]; ist->filters[ist->nb_filters - 1] = fg->inputs[fg->nb_inputs - 1];
@ -306,6 +346,7 @@ int init_complex_filtergraph(FilterGraph *fg)
graph = avfilter_graph_alloc(); graph = avfilter_graph_alloc();
if (!graph) if (!graph)
return AVERROR(ENOMEM); return AVERROR(ENOMEM);
graph->nb_threads = 1;
ret = avfilter_graph_parse2(graph, fg->graph_desc, &inputs, &outputs); ret = avfilter_graph_parse2(graph, fg->graph_desc, &inputs, &outputs);
if (ret < 0) if (ret < 0)
@ -324,6 +365,7 @@ int init_complex_filtergraph(FilterGraph *fg)
fg->outputs[fg->nb_outputs - 1]->out_tmp = cur; fg->outputs[fg->nb_outputs - 1]->out_tmp = cur;
fg->outputs[fg->nb_outputs - 1]->type = avfilter_pad_get_type(cur->filter_ctx->output_pads, fg->outputs[fg->nb_outputs - 1]->type = avfilter_pad_get_type(cur->filter_ctx->output_pads,
cur->pad_idx); cur->pad_idx);
fg->outputs[fg->nb_outputs - 1]->name = describe_filter_link(fg, cur, 0);
cur = cur->next; cur = cur->next;
fg->outputs[fg->nb_outputs - 1]->out_tmp->next = NULL; fg->outputs[fg->nb_outputs - 1]->out_tmp->next = NULL;
} }
@ -412,13 +454,12 @@ static int configure_output_video_filter(FilterGraph *fg, OutputFilter *ofilter,
char *pix_fmts; char *pix_fmts;
OutputStream *ost = ofilter->ost; OutputStream *ost = ofilter->ost;
OutputFile *of = output_files[ost->file_index]; OutputFile *of = output_files[ost->file_index];
AVCodecContext *codec = ost->enc_ctx;
AVFilterContext *last_filter = out->filter_ctx; AVFilterContext *last_filter = out->filter_ctx;
int pad_idx = out->pad_idx; int pad_idx = out->pad_idx;
int ret; int ret;
char name[255]; char name[255];
snprintf(name, sizeof(name), "output stream %d:%d", ost->file_index, ost->index); snprintf(name, sizeof(name), "out_%d_%d", ost->file_index, ost->index);
ret = avfilter_graph_create_filter(&ofilter->filter, ret = avfilter_graph_create_filter(&ofilter->filter,
avfilter_get_by_name("buffersink"), avfilter_get_by_name("buffersink"),
name, NULL, NULL, fg->graph); name, NULL, NULL, fg->graph);
@ -426,21 +467,20 @@ static int configure_output_video_filter(FilterGraph *fg, OutputFilter *ofilter,
if (ret < 0) if (ret < 0)
return ret; return ret;
if (codec->width || codec->height) { if (ofilter->width || ofilter->height) {
char args[255]; char args[255];
AVFilterContext *filter; AVFilterContext *filter;
AVDictionaryEntry *e = NULL; AVDictionaryEntry *e = NULL;
snprintf(args, sizeof(args), "%d:%d", snprintf(args, sizeof(args), "%d:%d",
codec->width, ofilter->width, ofilter->height);
codec->height);
while ((e = av_dict_get(ost->sws_dict, "", e, while ((e = av_dict_get(ost->sws_dict, "", e,
AV_DICT_IGNORE_SUFFIX))) { AV_DICT_IGNORE_SUFFIX))) {
av_strlcatf(args, sizeof(args), ":%s=%s", e->key, e->value); av_strlcatf(args, sizeof(args), ":%s=%s", e->key, e->value);
} }
snprintf(name, sizeof(name), "scaler for output stream %d:%d", snprintf(name, sizeof(name), "scaler_out_%d_%d",
ost->file_index, ost->index); ost->file_index, ost->index);
if ((ret = avfilter_graph_create_filter(&filter, avfilter_get_by_name("scale"), if ((ret = avfilter_graph_create_filter(&filter, avfilter_get_by_name("scale"),
name, args, NULL, fg->graph)) < 0) name, args, NULL, fg->graph)) < 0)
@ -452,9 +492,9 @@ static int configure_output_video_filter(FilterGraph *fg, OutputFilter *ofilter,
pad_idx = 0; pad_idx = 0;
} }
if ((pix_fmts = choose_pix_fmts(ost))) { if ((pix_fmts = choose_pix_fmts(ofilter))) {
AVFilterContext *filter; AVFilterContext *filter;
snprintf(name, sizeof(name), "pixel format for output stream %d:%d", snprintf(name, sizeof(name), "format_out_%d_%d",
ost->file_index, ost->index); ost->file_index, ost->index);
ret = avfilter_graph_create_filter(&filter, ret = avfilter_graph_create_filter(&filter,
avfilter_get_by_name("format"), avfilter_get_by_name("format"),
@ -475,7 +515,7 @@ static int configure_output_video_filter(FilterGraph *fg, OutputFilter *ofilter,
snprintf(args, sizeof(args), "fps=%d/%d", ost->frame_rate.num, snprintf(args, sizeof(args), "fps=%d/%d", ost->frame_rate.num,
ost->frame_rate.den); ost->frame_rate.den);
snprintf(name, sizeof(name), "fps for output stream %d:%d", snprintf(name, sizeof(name), "fps_out_%d_%d",
ost->file_index, ost->index); ost->file_index, ost->index);
ret = avfilter_graph_create_filter(&fps, avfilter_get_by_name("fps"), ret = avfilter_graph_create_filter(&fps, avfilter_get_by_name("fps"),
name, args, NULL, fg->graph); name, args, NULL, fg->graph);
@ -489,7 +529,7 @@ static int configure_output_video_filter(FilterGraph *fg, OutputFilter *ofilter,
pad_idx = 0; pad_idx = 0;
} }
snprintf(name, sizeof(name), "trim for output stream %d:%d", snprintf(name, sizeof(name), "trim_out_%d_%d",
ost->file_index, ost->index); ost->file_index, ost->index);
ret = insert_trim(of->start_time, of->recording_time, ret = insert_trim(of->start_time, of->recording_time,
&last_filter, &pad_idx, name); &last_filter, &pad_idx, name);
@ -514,7 +554,7 @@ static int configure_output_audio_filter(FilterGraph *fg, OutputFilter *ofilter,
char name[255]; char name[255];
int ret; int ret;
snprintf(name, sizeof(name), "output stream %d:%d", ost->file_index, ost->index); snprintf(name, sizeof(name), "out_%d_%d", ost->file_index, ost->index);
ret = avfilter_graph_create_filter(&ofilter->filter, ret = avfilter_graph_create_filter(&ofilter->filter,
avfilter_get_by_name("abuffersink"), avfilter_get_by_name("abuffersink"),
name, NULL, NULL, fg->graph); name, NULL, NULL, fg->graph);
@ -559,9 +599,9 @@ static int configure_output_audio_filter(FilterGraph *fg, OutputFilter *ofilter,
if (codec->channels && !codec->channel_layout) if (codec->channels && !codec->channel_layout)
codec->channel_layout = av_get_default_channel_layout(codec->channels); codec->channel_layout = av_get_default_channel_layout(codec->channels);
sample_fmts = choose_sample_fmts(ost); sample_fmts = choose_sample_fmts(ofilter);
sample_rates = choose_sample_rates(ost); sample_rates = choose_sample_rates(ofilter);
channel_layouts = choose_channel_layouts(ost); channel_layouts = choose_channel_layouts(ofilter);
if (sample_fmts || sample_rates || channel_layouts) { if (sample_fmts || sample_rates || channel_layouts) {
AVFilterContext *format; AVFilterContext *format;
char args[256]; char args[256];
@ -581,7 +621,7 @@ static int configure_output_audio_filter(FilterGraph *fg, OutputFilter *ofilter,
av_freep(&sample_rates); av_freep(&sample_rates);
av_freep(&channel_layouts); av_freep(&channel_layouts);
snprintf(name, sizeof(name), "audio format for output stream %d:%d", snprintf(name, sizeof(name), "format_out_%d_%d",
ost->file_index, ost->index); ost->file_index, ost->index);
ret = avfilter_graph_create_filter(&format, ret = avfilter_graph_create_filter(&format,
avfilter_get_by_name("aformat"), avfilter_get_by_name("aformat"),
@ -609,7 +649,7 @@ static int configure_output_audio_filter(FilterGraph *fg, OutputFilter *ofilter,
int i; int i;
for (i=0; i<of->ctx->nb_streams; i++) for (i=0; i<of->ctx->nb_streams; i++)
if (of->ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) if (of->ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
break; break;
if (i<of->ctx->nb_streams) { if (i<of->ctx->nb_streams) {
@ -631,30 +671,10 @@ static int configure_output_audio_filter(FilterGraph *fg, OutputFilter *ofilter,
return 0; return 0;
} }
#define DESCRIBE_FILTER_LINK(f, inout, in) \
{ \
AVFilterContext *ctx = inout->filter_ctx; \
AVFilterPad *pads = in ? ctx->input_pads : ctx->output_pads; \
int nb_pads = in ? ctx->nb_inputs : ctx->nb_outputs; \
AVIOContext *pb; \
\
if (avio_open_dyn_buf(&pb) < 0) \
exit_program(1); \
\
avio_printf(pb, "%s", ctx->filter->name); \
if (nb_pads > 1) \
avio_printf(pb, ":%s", avfilter_pad_get_name(pads, inout->pad_idx));\
avio_w8(pb, 0); \
avio_close_dyn_buf(pb, &f->name); \
}
int configure_output_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out) int configure_output_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out)
{ {
av_freep(&ofilter->name);
DESCRIBE_FILTER_LINK(ofilter, out, 0);
if (!ofilter->ost) { if (!ofilter->ost) {
av_log(NULL, AV_LOG_FATAL, "Filter %s has a unconnected output\n", ofilter->name); av_log(NULL, AV_LOG_FATAL, "Filter %s has an unconnected output\n", ofilter->name);
exit_program(1); exit_program(1);
} }
@ -665,21 +685,36 @@ int configure_output_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOu
} }
} }
static int sub2video_prepare(InputStream *ist) void check_filter_outputs(void)
{
int i;
for (i = 0; i < nb_filtergraphs; i++) {
int n;
for (n = 0; n < filtergraphs[i]->nb_outputs; n++) {
OutputFilter *output = filtergraphs[i]->outputs[n];
if (!output->ost) {
av_log(NULL, AV_LOG_FATAL, "Filter %s has an unconnected output\n", output->name);
exit_program(1);
}
}
}
}
static int sub2video_prepare(InputStream *ist, InputFilter *ifilter)
{ {
AVFormatContext *avf = input_files[ist->file_index]->ctx; AVFormatContext *avf = input_files[ist->file_index]->ctx;
int i, w, h; int i, w, h;
/* Compute the size of the canvas for the subtitles stream. /* Compute the size of the canvas for the subtitles stream.
If the subtitles codec has set a size, use it. Otherwise use the If the subtitles codecpar has set a size, use it. Otherwise use the
maximum dimensions of the video streams in the same file. */ maximum dimensions of the video streams in the same file. */
w = ist->dec_ctx->width; w = ifilter->width;
h = ist->dec_ctx->height; h = ifilter->height;
if (!(w && h)) { if (!(w && h)) {
for (i = 0; i < avf->nb_streams; i++) { for (i = 0; i < avf->nb_streams; i++) {
if (avf->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) { if (avf->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
w = FFMAX(w, avf->streams[i]->codec->width); w = FFMAX(w, avf->streams[i]->codecpar->width);
h = FFMAX(h, avf->streams[i]->codec->height); h = FFMAX(h, avf->streams[i]->codecpar->height);
} }
} }
if (!(w && h)) { if (!(w && h)) {
@ -688,17 +723,21 @@ static int sub2video_prepare(InputStream *ist)
} }
av_log(avf, AV_LOG_INFO, "sub2video: using %dx%d canvas\n", w, h); av_log(avf, AV_LOG_INFO, "sub2video: using %dx%d canvas\n", w, h);
} }
ist->sub2video.w = ist->resample_width = w; ist->sub2video.w = ifilter->width = w;
ist->sub2video.h = ist->resample_height = h; ist->sub2video.h = ifilter->height = h;
ifilter->width = ist->dec_ctx->width ? ist->dec_ctx->width : ist->sub2video.w;
ifilter->height = ist->dec_ctx->height ? ist->dec_ctx->height : ist->sub2video.h;
/* rectangles are AV_PIX_FMT_PAL8, but we have no guarantee that the /* rectangles are AV_PIX_FMT_PAL8, but we have no guarantee that the
palettes for all rectangles are identical or compatible */ palettes for all rectangles are identical or compatible */
ist->resample_pix_fmt = ist->dec_ctx->pix_fmt = AV_PIX_FMT_RGB32; ifilter->format = AV_PIX_FMT_RGB32;
ist->sub2video.frame = av_frame_alloc(); ist->sub2video.frame = av_frame_alloc();
if (!ist->sub2video.frame) if (!ist->sub2video.frame)
return AVERROR(ENOMEM); return AVERROR(ENOMEM);
ist->sub2video.last_pts = INT64_MIN; ist->sub2video.last_pts = INT64_MIN;
ist->sub2video.end_pts = INT64_MIN;
return 0; return 0;
} }
@ -717,32 +756,36 @@ static int configure_input_video_filter(FilterGraph *fg, InputFilter *ifilter,
char name[255]; char name[255];
int ret, pad_idx = 0; int ret, pad_idx = 0;
int64_t tsoffset = 0; int64_t tsoffset = 0;
AVBufferSrcParameters *par = av_buffersrc_parameters_alloc();
if (!par)
return AVERROR(ENOMEM);
memset(par, 0, sizeof(*par));
par->format = AV_PIX_FMT_NONE;
if (ist->dec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) { if (ist->dec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) {
av_log(NULL, AV_LOG_ERROR, "Cannot connect video filter to audio input\n"); av_log(NULL, AV_LOG_ERROR, "Cannot connect video filter to audio input\n");
return AVERROR(EINVAL); ret = AVERROR(EINVAL);
goto fail;
} }
if (!fr.num) if (!fr.num)
fr = av_guess_frame_rate(input_files[ist->file_index]->ctx, ist->st, NULL); fr = av_guess_frame_rate(input_files[ist->file_index]->ctx, ist->st, NULL);
if (ist->dec_ctx->codec_type == AVMEDIA_TYPE_SUBTITLE) { if (ist->dec_ctx->codec_type == AVMEDIA_TYPE_SUBTITLE) {
ret = sub2video_prepare(ist); ret = sub2video_prepare(ist, ifilter);
if (ret < 0) if (ret < 0)
return ret; goto fail;
} }
sar = ist->st->sample_aspect_ratio.num ? sar = ifilter->sample_aspect_ratio;
ist->st->sample_aspect_ratio :
ist->dec_ctx->sample_aspect_ratio;
if(!sar.den) if(!sar.den)
sar = (AVRational){0,1}; sar = (AVRational){0,1};
av_bprint_init(&args, 0, 1); av_bprint_init(&args, 0, AV_BPRINT_SIZE_AUTOMATIC);
av_bprintf(&args, av_bprintf(&args,
"video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:" "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:"
"pixel_aspect=%d/%d:sws_param=flags=%d", ist->resample_width, "pixel_aspect=%d/%d:sws_param=flags=%d",
ist->resample_height, ifilter->width, ifilter->height, ifilter->format,
ist->hwaccel_retrieve_data ? ist->hwaccel_retrieved_pix_fmt : ist->resample_pix_fmt,
tb.num, tb.den, sar.num, sar.den, tb.num, tb.den, sar.num, sar.den,
SWS_BILINEAR + ((ist->dec_ctx->flags&AV_CODEC_FLAG_BITEXACT) ? SWS_BITEXACT:0)); SWS_BILINEAR + ((ist->dec_ctx->flags&AV_CODEC_FLAG_BITEXACT) ? SWS_BITEXACT:0));
if (fr.num && fr.den) if (fr.num && fr.den)
@ -750,9 +793,15 @@ static int configure_input_video_filter(FilterGraph *fg, InputFilter *ifilter,
snprintf(name, sizeof(name), "graph %d input from stream %d:%d", fg->index, snprintf(name, sizeof(name), "graph %d input from stream %d:%d", fg->index,
ist->file_index, ist->st->index); ist->file_index, ist->st->index);
if ((ret = avfilter_graph_create_filter(&ifilter->filter, buffer_filt, name, if ((ret = avfilter_graph_create_filter(&ifilter->filter, buffer_filt, name,
args.str, NULL, fg->graph)) < 0) args.str, NULL, fg->graph)) < 0)
return ret; goto fail;
par->hw_frames_ctx = ifilter->hw_frames_ctx;
ret = av_buffersrc_parameters_set(ifilter->filter, par);
if (ret < 0)
goto fail;
av_freep(&par);
last_filter = ifilter->filter; last_filter = ifilter->filter;
if (ist->autorotate) { if (ist->autorotate) {
@ -776,27 +825,10 @@ static int configure_input_video_filter(FilterGraph *fg, InputFilter *ifilter,
return ret; return ret;
} }
if (ist->framerate.num) {
AVFilterContext *setpts;
snprintf(name, sizeof(name), "force CFR for input from stream %d:%d",
ist->file_index, ist->st->index);
if ((ret = avfilter_graph_create_filter(&setpts,
avfilter_get_by_name("setpts"),
name, "N", NULL,
fg->graph)) < 0)
return ret;
if ((ret = avfilter_link(last_filter, 0, setpts, 0)) < 0)
return ret;
last_filter = setpts;
}
if (do_deinterlace) { if (do_deinterlace) {
AVFilterContext *yadif; AVFilterContext *yadif;
snprintf(name, sizeof(name), "deinterlace input from stream %d:%d", snprintf(name, sizeof(name), "deinterlace_in_%d_%d",
ist->file_index, ist->st->index); ist->file_index, ist->st->index);
if ((ret = avfilter_graph_create_filter(&yadif, if ((ret = avfilter_graph_create_filter(&yadif,
avfilter_get_by_name("yadif"), avfilter_get_by_name("yadif"),
@ -810,7 +842,7 @@ static int configure_input_video_filter(FilterGraph *fg, InputFilter *ifilter,
last_filter = yadif; last_filter = yadif;
} }
snprintf(name, sizeof(name), "trim for input stream %d:%d", snprintf(name, sizeof(name), "trim_in_%d_%d",
ist->file_index, ist->st->index); ist->file_index, ist->st->index);
if (copy_ts) { if (copy_ts) {
tsoffset = f->start_time == AV_NOPTS_VALUE ? 0 : f->start_time; tsoffset = f->start_time == AV_NOPTS_VALUE ? 0 : f->start_time;
@ -826,6 +858,10 @@ static int configure_input_video_filter(FilterGraph *fg, InputFilter *ifilter,
if ((ret = avfilter_link(last_filter, 0, in->filter_ctx, in->pad_idx)) < 0) if ((ret = avfilter_link(last_filter, 0, in->filter_ctx, in->pad_idx)) < 0)
return ret; return ret;
return 0; return 0;
fail:
av_freep(&par);
return ret;
} }
static int configure_input_audio_filter(FilterGraph *fg, InputFilter *ifilter, static int configure_input_audio_filter(FilterGraph *fg, InputFilter *ifilter,
@ -847,15 +883,15 @@ static int configure_input_audio_filter(FilterGraph *fg, InputFilter *ifilter,
av_bprint_init(&args, 0, AV_BPRINT_SIZE_AUTOMATIC); av_bprint_init(&args, 0, AV_BPRINT_SIZE_AUTOMATIC);
av_bprintf(&args, "time_base=%d/%d:sample_rate=%d:sample_fmt=%s", av_bprintf(&args, "time_base=%d/%d:sample_rate=%d:sample_fmt=%s",
1, ist->dec_ctx->sample_rate, 1, ifilter->sample_rate,
ist->dec_ctx->sample_rate, ifilter->sample_rate,
av_get_sample_fmt_name(ist->dec_ctx->sample_fmt)); av_get_sample_fmt_name(ifilter->format));
if (ist->dec_ctx->channel_layout) if (ifilter->channel_layout)
av_bprintf(&args, ":channel_layout=0x%"PRIx64, av_bprintf(&args, ":channel_layout=0x%"PRIx64,
ist->dec_ctx->channel_layout); ifilter->channel_layout);
else else
av_bprintf(&args, ":channels=%d", ist->dec_ctx->channels); av_bprintf(&args, ":channels=%d", ifilter->channels);
snprintf(name, sizeof(name), "graph %d input from stream %d:%d", fg->index, snprintf(name, sizeof(name), "graph_%d_in_%d_%d", fg->index,
ist->file_index, ist->st->index); ist->file_index, ist->st->index);
if ((ret = avfilter_graph_create_filter(&ifilter->filter, abuffer_filt, if ((ret = avfilter_graph_create_filter(&ifilter->filter, abuffer_filt,
@ -870,7 +906,7 @@ static int configure_input_audio_filter(FilterGraph *fg, InputFilter *ifilter,
av_log(NULL, AV_LOG_INFO, opt_name " is forwarded to lavfi " \ av_log(NULL, AV_LOG_INFO, opt_name " is forwarded to lavfi " \
"similarly to -af " filter_name "=%s.\n", arg); \ "similarly to -af " filter_name "=%s.\n", arg); \
\ \
snprintf(name, sizeof(name), "graph %d %s for input stream %d:%d", \ snprintf(name, sizeof(name), "graph_%d_%s_in_%d_%d", \
fg->index, filter_name, ist->file_index, ist->st->index); \ fg->index, filter_name, ist->file_index, ist->st->index); \
ret = avfilter_graph_create_filter(&filt_ctx, \ ret = avfilter_graph_create_filter(&filt_ctx, \
avfilter_get_by_name(filter_name), \ avfilter_get_by_name(filter_name), \
@ -941,9 +977,6 @@ static int configure_input_audio_filter(FilterGraph *fg, InputFilter *ifilter,
static int configure_input_filter(FilterGraph *fg, InputFilter *ifilter, static int configure_input_filter(FilterGraph *fg, InputFilter *ifilter,
AVFilterInOut *in) AVFilterInOut *in)
{ {
av_freep(&ifilter->name);
DESCRIBE_FILTER_LINK(ifilter, in, 1);
if (!ifilter->ist->dec) { if (!ifilter->ist->dec) {
av_log(NULL, AV_LOG_ERROR, av_log(NULL, AV_LOG_ERROR,
"No decoder for stream #%d:%d, filtering impossible\n", "No decoder for stream #%d:%d, filtering impossible\n",
@ -957,14 +990,24 @@ static int configure_input_filter(FilterGraph *fg, InputFilter *ifilter,
} }
} }
static void cleanup_filtergraph(FilterGraph *fg)
{
int i;
for (i = 0; i < fg->nb_outputs; i++)
fg->outputs[i]->filter = (AVFilterContext *)NULL;
for (i = 0; i < fg->nb_inputs; i++)
fg->inputs[i]->filter = (AVFilterContext *)NULL;
avfilter_graph_free(&fg->graph);
}
int configure_filtergraph(FilterGraph *fg) int configure_filtergraph(FilterGraph *fg)
{ {
AVFilterInOut *inputs, *outputs, *cur; AVFilterInOut *inputs, *outputs, *cur;
int ret, i, simple = !fg->graph_desc; int ret, i, simple = filtergraph_is_simple(fg);
const char *graph_desc = simple ? fg->outputs[0]->ost->avfilter : const char *graph_desc = simple ? fg->outputs[0]->ost->avfilter :
fg->graph_desc; fg->graph_desc;
avfilter_graph_free(&fg->graph); cleanup_filtergraph(fg);
if (!(fg->graph = avfilter_graph_alloc())) if (!(fg->graph = avfilter_graph_alloc()))
return AVERROR(ENOMEM); return AVERROR(ENOMEM);
@ -973,6 +1016,8 @@ int configure_filtergraph(FilterGraph *fg)
char args[512]; char args[512];
AVDictionaryEntry *e = NULL; AVDictionaryEntry *e = NULL;
fg->graph->nb_threads = filter_nbthreads;
args[0] = 0; args[0] = 0;
while ((e = av_dict_get(ost->sws_dict, "", e, while ((e = av_dict_get(ost->sws_dict, "", e,
AV_DICT_IGNORE_SUFFIX))) { AV_DICT_IGNORE_SUFFIX))) {
@ -998,15 +1043,28 @@ int configure_filtergraph(FilterGraph *fg)
} }
if (strlen(args)) if (strlen(args))
args[strlen(args) - 1] = '\0'; args[strlen(args) - 1] = '\0';
fg->graph->resample_lavr_opts = av_strdup(args);
e = av_dict_get(ost->encoder_opts, "threads", NULL, 0); e = av_dict_get(ost->encoder_opts, "threads", NULL, 0);
if (e) if (e)
av_opt_set(fg->graph, "threads", e->value, 0); av_opt_set(fg->graph, "threads", e->value, 0);
} else {
fg->graph->nb_threads = filter_complex_nbthreads;
} }
if ((ret = avfilter_graph_parse2(fg->graph, graph_desc, &inputs, &outputs)) < 0) if ((ret = avfilter_graph_parse2(fg->graph, graph_desc, &inputs, &outputs)) < 0)
return ret; goto fail;
if (filter_hw_device || hw_device_ctx) {
AVBufferRef *device = filter_hw_device ? filter_hw_device->device_ref
: hw_device_ctx;
for (i = 0; i < fg->graph->nb_filters; i++) {
fg->graph->filters[i]->hw_device_ctx = av_buffer_ref(device);
if (!fg->graph->filters[i]->hw_device_ctx) {
ret = AVERROR(ENOMEM);
goto fail;
}
}
}
if (simple && (!inputs || inputs->next || !outputs || outputs->next)) { if (simple && (!inputs || inputs->next || !outputs || outputs->next)) {
const char *num_inputs; const char *num_inputs;
@ -1030,14 +1088,15 @@ int configure_filtergraph(FilterGraph *fg)
" However, it had %s input(s) and %s output(s)." " However, it had %s input(s) and %s output(s)."
" Please adjust, or use a complex filtergraph (-filter_complex) instead.\n", " Please adjust, or use a complex filtergraph (-filter_complex) instead.\n",
graph_desc, num_inputs, num_outputs); graph_desc, num_inputs, num_outputs);
return AVERROR(EINVAL); ret = AVERROR(EINVAL);
goto fail;
} }
for (cur = inputs, i = 0; cur; cur = cur->next, i++) for (cur = inputs, i = 0; cur; cur = cur->next, i++)
if ((ret = configure_input_filter(fg, fg->inputs[i], cur)) < 0) { if ((ret = configure_input_filter(fg, fg->inputs[i], cur)) < 0) {
avfilter_inout_free(&inputs); avfilter_inout_free(&inputs);
avfilter_inout_free(&outputs); avfilter_inout_free(&outputs);
return ret; goto fail;
} }
avfilter_inout_free(&inputs); avfilter_inout_free(&inputs);
@ -1046,7 +1105,22 @@ int configure_filtergraph(FilterGraph *fg)
avfilter_inout_free(&outputs); avfilter_inout_free(&outputs);
if ((ret = avfilter_graph_config(fg->graph, NULL)) < 0) if ((ret = avfilter_graph_config(fg->graph, NULL)) < 0)
return ret; goto fail;
/* limit the lists of allowed formats to the ones selected, to
* make sure they stay the same if the filtergraph is reconfigured later */
for (i = 0; i < fg->nb_outputs; i++) {
OutputFilter *ofilter = fg->outputs[i];
AVFilterContext *sink = ofilter->filter;
ofilter->format = av_buffersink_get_format(sink);
ofilter->width = av_buffersink_get_w(sink);
ofilter->height = av_buffersink_get_h(sink);
ofilter->sample_rate = av_buffersink_get_sample_rate(sink);
ofilter->channel_layout = av_buffersink_get_channel_layout(sink);
}
fg->reconfiguration = 1; fg->reconfiguration = 1;
@ -1056,8 +1130,9 @@ int configure_filtergraph(FilterGraph *fg)
/* identical to the same check in ffmpeg.c, needed because /* identical to the same check in ffmpeg.c, needed because
complex filter graphs are initialized earlier */ complex filter graphs are initialized earlier */
av_log(NULL, AV_LOG_ERROR, "Encoder (codec %s) not found for output stream #%d:%d\n", av_log(NULL, AV_LOG_ERROR, "Encoder (codec %s) not found for output stream #%d:%d\n",
avcodec_get_name(ost->st->codec->codec_id), ost->file_index, ost->index); avcodec_get_name(ost->st->codecpar->codec_id), ost->file_index, ost->index);
return AVERROR(EINVAL); ret = AVERROR(EINVAL);
goto fail;
} }
if (ost->enc->type == AVMEDIA_TYPE_AUDIO && if (ost->enc->type == AVMEDIA_TYPE_AUDIO &&
!(ost->enc->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE)) !(ost->enc->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE))
@ -1065,6 +1140,66 @@ int configure_filtergraph(FilterGraph *fg)
ost->enc_ctx->frame_size); ost->enc_ctx->frame_size);
} }
for (i = 0; i < fg->nb_inputs; i++) {
while (av_fifo_size(fg->inputs[i]->frame_queue)) {
AVFrame *tmp;
av_fifo_generic_read(fg->inputs[i]->frame_queue, &tmp, sizeof(tmp), NULL);
ret = av_buffersrc_add_frame(fg->inputs[i]->filter, tmp);
av_frame_free(&tmp);
if (ret < 0)
goto fail;
}
}
/* send the EOFs for the finished inputs */
for (i = 0; i < fg->nb_inputs; i++) {
if (fg->inputs[i]->eof) {
ret = av_buffersrc_add_frame(fg->inputs[i]->filter, NULL);
if (ret < 0)
goto fail;
}
}
/* process queued up subtitle packets */
for (i = 0; i < fg->nb_inputs; i++) {
InputStream *ist = fg->inputs[i]->ist;
if (ist->sub2video.sub_queue && ist->sub2video.frame) {
while (av_fifo_size(ist->sub2video.sub_queue)) {
AVSubtitle tmp;
av_fifo_generic_read(ist->sub2video.sub_queue, &tmp, sizeof(tmp), NULL);
sub2video_update(ist, &tmp);
avsubtitle_free(&tmp);
}
}
}
return 0;
fail:
cleanup_filtergraph(fg);
return ret;
}
int ifilter_parameters_from_frame(InputFilter *ifilter, const AVFrame *frame)
{
av_buffer_unref(&ifilter->hw_frames_ctx);
ifilter->format = frame->format;
ifilter->width = frame->width;
ifilter->height = frame->height;
ifilter->sample_aspect_ratio = frame->sample_aspect_ratio;
ifilter->sample_rate = frame->sample_rate;
ifilter->channels = frame->channels;
ifilter->channel_layout = frame->channel_layout;
if (frame->hw_frames_ctx) {
ifilter->hw_frames_ctx = av_buffer_ref(frame->hw_frames_ctx);
if (!ifilter->hw_frames_ctx)
return AVERROR(ENOMEM);
}
return 0; return 0;
} }
@ -1077,3 +1212,7 @@ int ist_in_filtergraph(FilterGraph *fg, InputStream *ist)
return 0; return 0;
} }
int filtergraph_is_simple(FilterGraph *fg)
{
return !fg->graph_desc;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save