#include "libavcodec/avcodec.h"
#include "libavfilter/avfilter.h"
-#include "libavfilter/avfiltergraph.h"
#include "libavutil/avassert.h"
#include "libavutil/avstring.h"
#include "libavutil/pixdesc.h"
#include "libavutil/pixfmt.h"
+#define DEFAULT_PASS_LOGFILENAME_PREFIX "av2pass"
+
#define MATCH_PER_STREAM_OPT(name, type, outvar, fmtctx, st)\
{\
int i, ret;\
if ((ret = check_stream_specifier(fmtctx, st, spec)) > 0)\
outvar = o->name[i].u.type;\
else if (ret < 0)\
- exit(1);\
+ exit_program(1);\
}\
}
+const HWAccel hwaccels[] = {
+#if HAVE_VDPAU_X11
+ { "vdpau", vdpau_init, HWACCEL_VDPAU, AV_PIX_FMT_VDPAU },
+#endif
+#if HAVE_DXVA2_LIB
+ { "dxva2", dxva2_init, HWACCEL_DXVA2, AV_PIX_FMT_DXVA2_VLD },
+#endif
+#if CONFIG_VDA
+ { "vda", vda_init, HWACCEL_VDA, AV_PIX_FMT_VDA },
+#endif
+#if CONFIG_LIBMFX
+ { "qsv", qsv_init, HWACCEL_QSV, AV_PIX_FMT_QSV },
+#endif
+#if CONFIG_VAAPI
+ { "vaapi", vaapi_decode_init, HWACCEL_VAAPI, AV_PIX_FMT_VAAPI },
+#endif
+ { 0 },
+};
+int hwaccel_lax_profile_check = 0;
+AVBufferRef *hw_device_ctx;
+
char *vstats_filename;
float audio_drift_threshold = 0.1;
int audio_volume = 256;
int audio_sync_method = 0;
int video_sync_method = VSYNC_AUTO;
-int do_deinterlace = 0;
int do_benchmark = 0;
int do_hex_dump = 0;
int do_pkt_dump = 0;
int qp_hist = 0;
static int file_overwrite = 0;
+static int file_skip = 0;
static int video_discard = 0;
static int intra_dc_precision = 8;
static int using_stdin = 0;
memset(o, 0, sizeof(*o));
o->mux_max_delay = 0.7;
+ o->start_time = AV_NOPTS_VALUE;
o->recording_time = INT64_MAX;
o->limit_filesize = UINT64_MAX;
o->chapters_input_file = INT_MAX;
+ o->accurate_seek = 1;
}
/* return a copy of the input with the stream specifiers removed from the keys */
if (!ar) {
av_log(NULL, AV_LOG_FATAL, "Incorrect aspect ratio specification.\n");
- exit(1);
+ exit_program(1);
}
return ar;
}
+static int show_hwaccels(void *optctx, const char *opt, const char *arg)
+{
+ int i;
+
+ printf("Supported hardware acceleration:\n");
+ for (i = 0; hwaccels[i].name; i++) {
+ printf("%s\n", hwaccels[i].name);
+ }
+ printf("\n");
+ return 0;
+}
+
static int opt_audio_codec(void *optctx, const char *opt, const char *arg)
{
OptionsContext *o = optctx;
arg++;
}
map = av_strdup(arg);
+ if (!map)
+ return AVERROR(ENOMEM);
/* parse sync stream first, just pick first matching stream */
if (sync = strchr(map, ',')) {
sync_file_idx = strtol(sync + 1, &sync, 0);
if (sync_file_idx >= nb_input_files || sync_file_idx < 0) {
av_log(NULL, AV_LOG_FATAL, "Invalid sync file index: %d.\n", sync_file_idx);
- exit(1);
+ exit_program(1);
}
if (*sync)
sync++;
if (i == input_files[sync_file_idx]->nb_streams) {
av_log(NULL, AV_LOG_FATAL, "Sync stream specification in map %s does not "
"match any streams.\n", arg);
- exit(1);
+ exit_program(1);
}
}
m->linklabel = av_get_token(&c, "]");
if (!m->linklabel) {
av_log(NULL, AV_LOG_ERROR, "Invalid output link label: %s.\n", map);
- exit(1);
+ exit_program(1);
}
} else {
file_idx = strtol(map, &p, 0);
if (file_idx >= nb_input_files || file_idx < 0) {
av_log(NULL, AV_LOG_FATAL, "Invalid input file index: %d.\n", file_idx);
- exit(1);
+ exit_program(1);
}
if (negative)
/* disable some already defined maps */
if (!m) {
av_log(NULL, AV_LOG_FATAL, "Stream map '%s' matches no streams.\n", arg);
- exit(1);
+ exit_program(1);
}
av_freep(&map);
return 0;
}
+#if CONFIG_VAAPI
+static int opt_vaapi_device(void *optctx, const char *opt, const char *arg)
+{
+ int err;
+ err = vaapi_device_init(arg);
+ if (err < 0)
+ exit_program(1);
+ return 0;
+}
+#endif
+
/**
* Parse a metadata specifier passed as 'arg' parameter.
* @param arg metadata string to parse
case 's':
if (*(++arg) && *arg != ':') {
av_log(NULL, AV_LOG_FATAL, "Invalid metadata specifier %s.\n", arg);
- exit(1);
+ exit_program(1);
}
*stream_spec = *arg == ':' ? arg + 1 : "";
break;
break;
default:
av_log(NULL, AV_LOG_FATAL, "Invalid metadata type %c.\n", *arg);
- exit(1);
+ exit_program(1);
}
} else
*type = 'g';
if ((index) < 0 || (index) >= (nb_elems)) {\
av_log(NULL, AV_LOG_FATAL, "Invalid %s index %d while processing metadata maps.\n",\
(desc), (index));\
- exit(1);\
+ exit_program(1);\
}
#define SET_DICT(type, meta, context, index)\
meta_in = &ic->streams[i]->metadata;
break;
} else if (ret < 0)
- exit(1);
+ exit_program(1);
}
if (!meta_in) {
av_log(NULL, AV_LOG_FATAL, "Stream specifier %s does not match any streams.\n", istream_spec);
- exit(1);
+ exit_program(1);
}
}
meta_out = &oc->streams[i]->metadata;
av_dict_copy(meta_out, *meta_in, AV_DICT_DONT_OVERWRITE);
} else if (ret < 0)
- exit(1);
+ exit_program(1);
}
} else
av_dict_copy(meta_out, *meta_in, AV_DICT_DONT_OVERWRITE);
if (!codec) {
av_log(NULL, AV_LOG_FATAL, "Unknown %s '%s'\n", codec_string, name);
- exit(1);
+ exit_program(1);
}
if (codec->type != type) {
av_log(NULL, AV_LOG_FATAL, "Invalid %s type '%s'\n", codec_string, name);
- exit(1);
+ exit_program(1);
}
return codec;
}
MATCH_PER_STREAM_OPT(codec_names, str, codec_name, s, st);
if (codec_name) {
- AVCodec *codec = find_codec_or_die(codec_name, st->codec->codec_type, 0);
- st->codec->codec_id = codec->id;
+ AVCodec *codec = find_codec_or_die(codec_name, st->codecpar->codec_type, 0);
+ st->codecpar->codec_id = codec->id;
return codec;
} else
- return avcodec_find_decoder(st->codec->codec_id);
+ return avcodec_find_decoder(st->codecpar->codec_id);
}
/* Add all the streams from the given input file to the global
* list of input streams. */
static void add_input_streams(OptionsContext *o, AVFormatContext *ic)
{
- int i;
+ int i, ret;
for (i = 0; i < ic->nb_streams; i++) {
AVStream *st = ic->streams[i];
- AVCodecContext *dec = st->codec;
+ AVCodecParameters *par = st->codecpar;
InputStream *ist = av_mallocz(sizeof(*ist));
- char *framerate = NULL;
+ char *framerate = NULL, *hwaccel = NULL, *hwaccel_device = NULL;
+ char *hwaccel_output_format = NULL;
+ char *codec_tag = NULL;
+ char *next;
if (!ist)
- exit(1);
+ exit_program(1);
GROW_ARRAY(input_streams, nb_input_streams);
input_streams[nb_input_streams - 1] = ist;
ist->file_index = nb_input_files;
ist->discard = 1;
st->discard = AVDISCARD_ALL;
+ ist->nb_samples = 0;
+ ist->min_pts = INT64_MAX;
+ ist->max_pts = INT64_MIN;
ist->ts_scale = 1.0;
MATCH_PER_STREAM_OPT(ts_scale, dbl, ist->ts_scale, ic, st);
+ ist->autorotate = 1;
+ MATCH_PER_STREAM_OPT(autorotate, i, ist->autorotate, ic, st);
+
+ MATCH_PER_STREAM_OPT(codec_tags, str, codec_tag, ic, st);
+ if (codec_tag) {
+ uint32_t tag = strtol(codec_tag, &next, 0);
+ if (*next)
+ tag = AV_RL32(codec_tag);
+ st->codecpar->codec_tag = tag;
+ }
+
ist->dec = choose_decoder(o, ic, st);
- ist->opts = filter_codec_opts(o->g->codec_opts, ist->st->codec->codec_id, ic, st, ist->dec);
+ ist->decoder_opts = filter_codec_opts(o->g->codec_opts, par->codec_id, ic, st, ist->dec);
- switch (dec->codec_type) {
- case AVMEDIA_TYPE_VIDEO:
- ist->resample_height = dec->height;
- ist->resample_width = dec->width;
- ist->resample_pix_fmt = dec->pix_fmt;
+ ist->dec_ctx = avcodec_alloc_context3(ist->dec);
+ if (!ist->dec_ctx) {
+ av_log(NULL, AV_LOG_ERROR, "Error allocating the decoder context.\n");
+ exit_program(1);
+ }
+
+ ret = avcodec_parameters_to_context(ist->dec_ctx, par);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Error initializing the decoder context.\n");
+ exit_program(1);
+ }
+ switch (par->codec_type) {
+ case AVMEDIA_TYPE_VIDEO:
MATCH_PER_STREAM_OPT(frame_rates, str, framerate, ic, st);
if (framerate && av_parse_video_rate(&ist->framerate,
framerate) < 0) {
av_log(NULL, AV_LOG_ERROR, "Error parsing framerate %s.\n",
framerate);
- exit(1);
+ exit_program(1);
}
+ MATCH_PER_STREAM_OPT(hwaccels, str, hwaccel, ic, st);
+ if (hwaccel) {
+ if (!strcmp(hwaccel, "none"))
+ ist->hwaccel_id = HWACCEL_NONE;
+ else if (!strcmp(hwaccel, "auto"))
+ ist->hwaccel_id = HWACCEL_AUTO;
+ else {
+ int i;
+ for (i = 0; hwaccels[i].name; i++) {
+ if (!strcmp(hwaccels[i].name, hwaccel)) {
+ ist->hwaccel_id = hwaccels[i].id;
+ break;
+ }
+ }
+
+ if (!ist->hwaccel_id) {
+ av_log(NULL, AV_LOG_FATAL, "Unrecognized hwaccel: %s.\n",
+ hwaccel);
+ av_log(NULL, AV_LOG_FATAL, "Supported hwaccels: ");
+ for (i = 0; hwaccels[i].name; i++)
+ av_log(NULL, AV_LOG_FATAL, "%s ", hwaccels[i].name);
+ av_log(NULL, AV_LOG_FATAL, "\n");
+ exit_program(1);
+ }
+ }
+ }
+
+ MATCH_PER_STREAM_OPT(hwaccel_devices, str, hwaccel_device, ic, st);
+ if (hwaccel_device) {
+ ist->hwaccel_device = av_strdup(hwaccel_device);
+ if (!ist->hwaccel_device)
+ exit_program(1);
+ }
+
+ MATCH_PER_STREAM_OPT(hwaccel_output_formats, str,
+ hwaccel_output_format, ic, st);
+ if (hwaccel_output_format) {
+ ist->hwaccel_output_format = av_get_pix_fmt(hwaccel_output_format);
+ if (ist->hwaccel_output_format == AV_PIX_FMT_NONE) {
+ av_log(NULL, AV_LOG_FATAL, "Unrecognised hwaccel output "
+ "format: %s", hwaccel_output_format);
+ }
+ } else {
+ ist->hwaccel_output_format = AV_PIX_FMT_NONE;
+ }
+
+ ist->hwaccel_pix_fmt = AV_PIX_FMT_NONE;
+
break;
case AVMEDIA_TYPE_AUDIO:
guess_input_channel_layout(ist);
-
- ist->resample_sample_fmt = dec->sample_fmt;
- ist->resample_sample_rate = dec->sample_rate;
- ist->resample_channels = dec->channels;
- ist->resample_channel_layout = dec->channel_layout;
-
break;
case AVMEDIA_TYPE_DATA:
case AVMEDIA_TYPE_SUBTITLE:
static void assert_file_overwrite(const char *filename)
{
+ if (file_overwrite && file_skip) {
+ fprintf(stderr, "Error, both -y and -n supplied. Exiting.\n");
+ exit_program(1);
+ }
+
if (!file_overwrite &&
- (strchr(filename, ':') == NULL || filename[1] == ':' ||
+ (!strchr(filename, ':') || filename[1] == ':' ||
av_strstart(filename, "file:", NULL))) {
if (avio_check(filename, 0) == 0) {
- if (!using_stdin) {
+ if (!using_stdin && !file_skip) {
fprintf(stderr,"File '%s' already exists. Overwrite ? [y/N] ", filename);
fflush(stderr);
if (!read_yesno()) {
fprintf(stderr, "Not overwriting - exiting\n");
- exit(1);
+ exit_program(1);
}
}
else {
fprintf(stderr,"File '%s' already exists. Exiting.\n", filename);
- exit(1);
+ exit_program(1);
}
}
}
AVIOContext *out = NULL;
AVDictionaryEntry *e;
- if (!st->codec->extradata_size) {
+ if (!st->codecpar->extradata_size) {
av_log(NULL, AV_LOG_WARNING, "No extradata to dump in stream #%d:%d.\n",
nb_input_files - 1, st->index);
return;
if (!*filename) {
av_log(NULL, AV_LOG_FATAL, "No filename specified and no 'filename' tag"
"in stream #%d:%d.\n", nb_input_files - 1, st->index);
- exit(1);
+ exit_program(1);
}
assert_file_overwrite(filename);
if ((ret = avio_open2(&out, filename, AVIO_FLAG_WRITE, &int_cb, NULL)) < 0) {
av_log(NULL, AV_LOG_FATAL, "Could not open file %s for writing.\n",
filename);
- exit(1);
+ exit_program(1);
}
- avio_write(out, st->codec->extradata, st->codec->extradata_size);
+ avio_write(out, st->codecpar->extradata, st->codecpar->extradata_size);
avio_flush(out);
avio_close(out);
}
if (o->format) {
if (!(file_iformat = av_find_input_format(o->format))) {
av_log(NULL, AV_LOG_FATAL, "Unknown input format: '%s'\n", o->format);
- exit(1);
+ exit_program(1);
}
}
ic = avformat_alloc_context();
if (!ic) {
print_error(filename, AVERROR(ENOMEM));
- exit(1);
+ exit_program(1);
}
if (o->nb_audio_sample_rate) {
snprintf(buf, sizeof(buf), "%d", o->audio_sample_rate[o->nb_audio_sample_rate - 1].u.i);
ic->flags |= AVFMT_FLAG_NONBLOCK;
ic->interrupt_callback = int_cb;
- /* open the input file with generic libav function */
+ /* open the input file with generic Libav function */
err = avformat_open_input(&ic, filename, file_iformat, &o->g->format_opts);
if (err < 0) {
print_error(filename, err);
- exit(1);
+ exit_program(1);
}
assert_avoptions(o->g->format_opts);
if (ret < 0) {
av_log(NULL, AV_LOG_FATAL, "%s: could not find codec parameters\n", filename);
avformat_close_input(&ic);
- exit(1);
+ exit_program(1);
}
- timestamp = o->start_time;
+ timestamp = (o->start_time == AV_NOPTS_VALUE) ? 0 : o->start_time;
/* add the stream start time */
if (ic->start_time != AV_NOPTS_VALUE)
timestamp += ic->start_time;
/* if seeking requested, we execute it */
- if (o->start_time != 0) {
+ if (o->start_time != AV_NOPTS_VALUE) {
ret = av_seek_frame(ic, -1, timestamp, AVSEEK_FLAG_BACKWARD);
if (ret < 0) {
av_log(NULL, AV_LOG_WARNING, "%s: could not seek to position %0.3f\n",
GROW_ARRAY(input_files, nb_input_files);
f = av_mallocz(sizeof(*f));
if (!f)
- exit(1);
+ exit_program(1);
input_files[nb_input_files - 1] = f;
f->ctx = ic;
f->ist_index = nb_input_streams - ic->nb_streams;
+ f->start_time = o->start_time;
+ f->recording_time = o->recording_time;
f->ts_offset = o->input_ts_offset - (copy_ts ? 0 : timestamp);
f->nb_streams = ic->nb_streams;
f->rate_emu = o->rate_emu;
+ f->accurate_seek = o->accurate_seek;
+ f->loop = o->loop;
+ f->duration = 0;
+ f->time_base = (AVRational){ 1, 1 };
/* check if all codec options have been used */
unused_opts = strip_specifiers(o->g->codec_opts);
for (i = f->ist_index; i < nb_input_streams; i++) {
e = NULL;
- while ((e = av_dict_get(input_streams[i]->opts, "", e,
+ while ((e = av_dict_get(input_streams[i]->decoder_opts, "", e,
AV_DICT_IGNORE_SUFFIX)))
av_dict_set(&unused_opts, e->key, NULL, 0);
}
"input file #%d (%s) is not a decoding option.\n", e->key,
option->help ? option->help : "", nb_input_files - 1,
filename);
- exit(1);
+ exit_program(1);
}
av_log(NULL, AV_LOG_WARNING, "Codec AVOption %s (%s) specified for "
if (avio_open_dyn_buf(&line) < 0) {
av_log(NULL, AV_LOG_FATAL, "Could not alloc buffer for reading preset.\n");
- exit(1);
+ exit_program(1);
}
while ((c = avio_r8(s)) && c != '\n')
static int get_preset_file_2(const char *preset_name, const char *codec_name, AVIOContext **s)
{
- int i, ret = 1;
+ int i, ret = -1;
char filename[1000];
const char *base[3] = { getenv("AVCONV_DATADIR"),
getenv("HOME"),
AVCONV_DATADIR,
};
- for (i = 0; i < FF_ARRAY_ELEMS(base) && ret; i++) {
+ for (i = 0; i < FF_ARRAY_ELEMS(base) && ret < 0; i++) {
if (!base[i])
continue;
if (codec_name) {
i != 1 ? "" : "/.avconv", codec_name, preset_name);
ret = avio_open2(s, filename, AVIO_FLAG_READ, &int_cb, NULL);
}
- if (ret) {
+ if (ret < 0) {
snprintf(filename, sizeof(filename), "%s%s/%s.avpreset", base[i],
i != 1 ? "" : "/.avconv", preset_name);
ret = avio_open2(s, filename, AVIO_FLAG_READ, &int_cb, NULL);
return ret;
}
-static void choose_encoder(OptionsContext *o, AVFormatContext *s, OutputStream *ost)
+static int choose_encoder(OptionsContext *o, AVFormatContext *s, OutputStream *ost)
{
+ enum AVMediaType type = ost->st->codecpar->codec_type;
char *codec_name = NULL;
- MATCH_PER_STREAM_OPT(codec_names, str, codec_name, s, ost->st);
- if (!codec_name) {
- ost->st->codec->codec_id = av_guess_codec(s->oformat, NULL, s->filename,
- NULL, ost->st->codec->codec_type);
- ost->enc = avcodec_find_encoder(ost->st->codec->codec_id);
- } else if (!strcmp(codec_name, "copy"))
- ost->stream_copy = 1;
- else {
- ost->enc = find_codec_or_die(codec_name, ost->st->codec->codec_type, 1);
- ost->st->codec->codec_id = ost->enc->id;
+ if (type == AVMEDIA_TYPE_VIDEO || type == AVMEDIA_TYPE_AUDIO || type == AVMEDIA_TYPE_SUBTITLE) {
+ MATCH_PER_STREAM_OPT(codec_names, str, codec_name, s, ost->st);
+ if (!codec_name) {
+ ost->st->codecpar->codec_id = av_guess_codec(s->oformat, NULL, s->filename,
+ NULL, ost->st->codecpar->codec_type);
+ ost->enc = avcodec_find_encoder(ost->st->codecpar->codec_id);
+ if (!ost->enc) {
+ av_log(NULL, AV_LOG_FATAL, "Automatic encoder selection failed for "
+ "output stream #%d:%d. Default encoder for format %s is "
+ "probably disabled. Please choose an encoder manually.\n",
+ ost->file_index, ost->index, s->oformat->name);
+ return AVERROR_ENCODER_NOT_FOUND;
+ }
+ } else if (!strcmp(codec_name, "copy"))
+ ost->stream_copy = 1;
+ else {
+ ost->enc = find_codec_or_die(codec_name, ost->st->codecpar->codec_type, 1);
+ ost->st->codecpar->codec_id = ost->enc->id;
+ }
+
+ ost->encoding_needed = !ost->stream_copy;
+ } else {
+ /* no encoding supported for other media types */
+ ost->stream_copy = 1;
+ ost->encoding_needed = 0;
}
+
+ return 0;
}
static OutputStream *new_output_stream(OptionsContext *o, AVFormatContext *oc, enum AVMediaType type)
OutputStream *ost;
AVStream *st = avformat_new_stream(oc, NULL);
int idx = oc->nb_streams - 1, ret = 0;
- char *bsf = NULL, *next, *codec_tag = NULL;
- AVBitStreamFilterContext *bsfc, *bsfc_prev = NULL;
+ const char *bsfs = NULL;
+ char *next, *codec_tag = NULL;
double qscale = -1;
if (!st) {
av_log(NULL, AV_LOG_FATAL, "Could not alloc stream.\n");
- exit(1);
+ exit_program(1);
}
if (oc->nb_streams - 1 < o->nb_streamid_map)
GROW_ARRAY(output_streams, nb_output_streams);
if (!(ost = av_mallocz(sizeof(*ost))))
- exit(1);
+ exit_program(1);
output_streams[nb_output_streams - 1] = ost;
- ost->file_index = nb_output_files;
+ ost->file_index = nb_output_files - 1;
ost->index = idx;
ost->st = st;
- st->codec->codec_type = type;
- choose_encoder(o, oc, ost);
+ st->codecpar->codec_type = type;
+
+ ret = choose_encoder(o, oc, ost);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_FATAL, "Error selecting an encoder for stream "
+ "%d:%d\n", ost->file_index, ost->index);
+ exit_program(1);
+ }
+
+ ost->enc_ctx = avcodec_alloc_context3(ost->enc);
+ if (!ost->enc_ctx) {
+ av_log(NULL, AV_LOG_ERROR, "Error allocating the encoding context.\n");
+ exit_program(1);
+ }
+ ost->enc_ctx->codec_type = type;
+
if (ost->enc) {
AVIOContext *s = NULL;
char *buf = NULL, *arg = NULL, *preset = NULL;
- ost->opts = filter_codec_opts(o->g->codec_opts, ost->enc->id, oc, st, ost->enc);
+ ost->encoder_opts = filter_codec_opts(o->g->codec_opts, ost->enc->id, oc, st, ost->enc);
MATCH_PER_STREAM_OPT(presets, str, preset, oc, st);
if (preset && (!(ret = get_preset_file_2(preset, ost->enc->name, &s)))) {
}
if (!(arg = strchr(buf, '='))) {
av_log(NULL, AV_LOG_FATAL, "Invalid line found in the preset file.\n");
- exit(1);
+ exit_program(1);
}
*arg++ = 0;
- av_dict_set(&ost->opts, buf, arg, AV_DICT_DONT_OVERWRITE);
+ av_dict_set(&ost->encoder_opts, buf, arg, AV_DICT_DONT_OVERWRITE);
av_free(buf);
} while (!s->eof_reached);
avio_close(s);
av_log(NULL, AV_LOG_FATAL,
"Preset %s specified for stream %d:%d, but could not be opened.\n",
preset, ost->file_index, ost->index);
- exit(1);
+ exit_program(1);
}
} else {
- ost->opts = filter_codec_opts(o->g->codec_opts, AV_CODEC_ID_NONE, oc, st, NULL);
+ ost->encoder_opts = filter_codec_opts(o->g->codec_opts, AV_CODEC_ID_NONE, oc, st, NULL);
}
- avcodec_get_context_defaults3(st->codec, ost->enc);
- st->codec->codec_type = type; // XXX hack, avcodec_get_context_defaults2() sets type to unknown for stream copy
-
ost->max_frames = INT64_MAX;
MATCH_PER_STREAM_OPT(max_frames, i64, ost->max_frames, oc, st);
- MATCH_PER_STREAM_OPT(bitstream_filters, str, bsf, oc, st);
- while (bsf) {
- if (next = strchr(bsf, ','))
- *next++ = 0;
- if (!(bsfc = av_bitstream_filter_init(bsf))) {
- av_log(NULL, AV_LOG_FATAL, "Unknown bitstream filter %s\n", bsf);
- exit(1);
+ MATCH_PER_STREAM_OPT(bitstream_filters, str, bsfs, oc, st);
+ while (bsfs && *bsfs) {
+ const AVBitStreamFilter *filter;
+ const char *bsf, *bsf_options_str, *bsf_name;
+ AVDictionary *bsf_options = NULL;
+
+ bsf = bsf_options_str = av_get_token(&bsfs, ",");
+ if (!bsf)
+ exit_program(1);
+ bsf_name = av_get_token(&bsf_options_str, "=");
+ if (!bsf_name)
+ exit_program(1);
+
+ filter = av_bsf_get_by_name(bsf_name);
+ if (!filter) {
+ av_log(NULL, AV_LOG_FATAL, "Unknown bitstream filter %s\n", bsf_name);
+ exit_program(1);
}
- if (bsfc_prev)
- bsfc_prev->next = bsfc;
- else
- ost->bitstream_filters = bsfc;
+ if (*bsf_options_str++) {
+ ret = av_dict_parse_string(&bsf_options, bsf_options_str, "=", ":", 0);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Error parsing options for bitstream filter %s\n", bsf_name);
+ exit_program(1);
+ }
+ }
+ av_freep(&bsf);
+
+ ost->bsf_ctx = av_realloc_array(ost->bsf_ctx,
+ ost->nb_bitstream_filters + 1,
+ sizeof(*ost->bsf_ctx));
+ if (!ost->bsf_ctx)
+ exit_program(1);
+
+ ret = av_bsf_alloc(filter, &ost->bsf_ctx[ost->nb_bitstream_filters]);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Error allocating a bistream filter context\n");
+ exit_program(1);
+ }
+ ost->nb_bitstream_filters++;
+
+ if (bsf_options) {
+ ret = av_opt_set_dict(ost->bsf_ctx[ost->nb_bitstream_filters-1]->priv_data, &bsf_options);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Error setting options for bitstream filter %s\n", bsf_name);
+ exit_program(1);
+ }
+ assert_avoptions(bsf_options);
+ av_dict_free(&bsf_options);
+ }
+ av_freep(&bsf_name);
- bsfc_prev = bsfc;
- bsf = next;
+ if (*bsfs)
+ bsfs++;
}
MATCH_PER_STREAM_OPT(codec_tags, str, codec_tag, oc, st);
uint32_t tag = strtol(codec_tag, &next, 0);
if (*next)
tag = AV_RL32(codec_tag);
- st->codec->codec_tag = tag;
+ ost->enc_ctx->codec_tag = tag;
}
MATCH_PER_STREAM_OPT(qscale, dbl, qscale, oc, st);
if (qscale >= 0) {
- st->codec->flags |= CODEC_FLAG_QSCALE;
- st->codec->global_quality = FF_QP2LAMBDA * qscale;
+ ost->enc_ctx->flags |= AV_CODEC_FLAG_QSCALE;
+ ost->enc_ctx->global_quality = FF_QP2LAMBDA * qscale;
}
+ ost->max_muxing_queue_size = 128;
+ MATCH_PER_STREAM_OPT(max_muxing_queue_size, i, ost->max_muxing_queue_size, oc, st);
+ ost->max_muxing_queue_size *= sizeof(AVPacket);
+
if (oc->oformat->flags & AVFMT_GLOBALHEADER)
- st->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
+ ost->enc_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
av_opt_get_int(o->g->sws_opts, "sws_flags", 0, &ost->sws_flags);
av_dict_copy(&ost->resample_opts, o->g->resample_opts, 0);
ost->pix_fmts[0] = ost->pix_fmts[1] = AV_PIX_FMT_NONE;
+ ost->last_mux_dts = AV_NOPTS_VALUE;
+
+ ost->muxing_queue = av_fifo_alloc(8 * sizeof(AVPacket));
+ if (!ost->muxing_queue)
+ exit_program(1);
return ost;
}
p = strchr(p, ',');
if (!p) {
av_log(NULL, AV_LOG_FATAL, "Syntax error in matrix \"%s\" at coeff %d\n", str, i);
- exit(1);
+ exit_program(1);
}
p++;
}
}
+/* read file contents into a string */
+static uint8_t *read_file(const char *filename)
+{
+ AVIOContext *pb = NULL;
+ AVIOContext *dyn_buf = NULL;
+ int ret = avio_open(&pb, filename, AVIO_FLAG_READ);
+ uint8_t buf[1024], *str;
+
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Error opening file %s.\n", filename);
+ return NULL;
+ }
+
+ ret = avio_open_dyn_buf(&dyn_buf);
+ if (ret < 0) {
+ avio_closep(&pb);
+ return NULL;
+ }
+ while ((ret = avio_read(pb, buf, sizeof(buf))) > 0)
+ avio_write(dyn_buf, buf, ret);
+ avio_w8(dyn_buf, 0);
+ avio_closep(&pb);
+
+ ret = avio_close_dyn_buf(dyn_buf, &str);
+ if (ret < 0)
+ return NULL;
+ return str;
+}
+
+static char *get_ost_filters(OptionsContext *o, AVFormatContext *oc,
+ OutputStream *ost)
+{
+ AVStream *st = ost->st;
+ char *filter = NULL, *filter_script = NULL;
+
+ MATCH_PER_STREAM_OPT(filter_scripts, str, filter_script, oc, st);
+ MATCH_PER_STREAM_OPT(filters, str, filter, oc, st);
+
+ if (filter_script && filter) {
+ av_log(NULL, AV_LOG_ERROR, "Both -filter and -filter_script set for "
+ "output stream #%d:%d.\n", nb_output_files, st->index);
+ exit_program(1);
+ }
+
+ if (filter_script)
+ return read_file(filter_script);
+ else if (filter)
+ return av_strdup(filter);
+
+ return av_strdup(st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO ?
+ "null" : "anull");
+}
+
static OutputStream *new_video_stream(OptionsContext *o, AVFormatContext *oc)
{
AVStream *st;
OutputStream *ost;
AVCodecContext *video_enc;
+ char *frame_aspect_ratio = NULL;
ost = new_output_stream(o, oc, AVMEDIA_TYPE_VIDEO);
st = ost->st;
- video_enc = st->codec;
+ video_enc = ost->enc_ctx;
+
+ MATCH_PER_STREAM_OPT(frame_aspect_ratios, str, frame_aspect_ratio, oc, st);
+ if (frame_aspect_ratio)
+ ost->frame_aspect_ratio = parse_frame_aspect_ratio(frame_aspect_ratio);
if (!ost->stream_copy) {
const char *p = NULL;
char *frame_rate = NULL, *frame_size = NULL;
- char *frame_aspect_ratio = NULL, *frame_pix_fmt = NULL;
+ char *frame_pix_fmt = NULL;
char *intra_matrix = NULL, *inter_matrix = NULL;
- const char *filters = "null";
int do_pass = 0;
int i;
MATCH_PER_STREAM_OPT(frame_rates, str, frame_rate, oc, st);
if (frame_rate && av_parse_video_rate(&ost->frame_rate, frame_rate) < 0) {
av_log(NULL, AV_LOG_FATAL, "Invalid framerate value: %s\n", frame_rate);
- exit(1);
+ exit_program(1);
}
MATCH_PER_STREAM_OPT(frame_sizes, str, frame_size, oc, st);
if (frame_size && av_parse_video_size(&video_enc->width, &video_enc->height, frame_size) < 0) {
av_log(NULL, AV_LOG_FATAL, "Invalid frame size: %s.\n", frame_size);
- exit(1);
+ exit_program(1);
}
- MATCH_PER_STREAM_OPT(frame_aspect_ratios, str, frame_aspect_ratio, oc, st);
- if (frame_aspect_ratio)
- ost->frame_aspect_ratio = parse_frame_aspect_ratio(frame_aspect_ratio);
-
MATCH_PER_STREAM_OPT(frame_pix_fmts, str, frame_pix_fmt, oc, st);
if (frame_pix_fmt && (video_enc->pix_fmt = av_get_pix_fmt(frame_pix_fmt)) == AV_PIX_FMT_NONE) {
av_log(NULL, AV_LOG_FATAL, "Unknown pixel format requested: %s.\n", frame_pix_fmt);
- exit(1);
+ exit_program(1);
}
st->sample_aspect_ratio = video_enc->sample_aspect_ratio;
if (intra_matrix) {
if (!(video_enc->intra_matrix = av_mallocz(sizeof(*video_enc->intra_matrix) * 64))) {
av_log(NULL, AV_LOG_FATAL, "Could not allocate memory for intra matrix.\n");
- exit(1);
+ exit_program(1);
}
parse_matrix_coeffs(video_enc->intra_matrix, intra_matrix);
}
if (inter_matrix) {
if (!(video_enc->inter_matrix = av_mallocz(sizeof(*video_enc->inter_matrix) * 64))) {
av_log(NULL, AV_LOG_FATAL, "Could not allocate memory for inter matrix.\n");
- exit(1);
+ exit_program(1);
}
parse_matrix_coeffs(video_enc->inter_matrix, inter_matrix);
}
int e = sscanf(p, "%d,%d,%d", &start, &end, &q);
if (e != 3) {
av_log(NULL, AV_LOG_FATAL, "error parsing rc_override\n");
- exit(1);
+ exit_program(1);
}
video_enc->rc_override =
av_realloc(video_enc->rc_override,
sizeof(RcOverride) * (i + 1));
+ if (!video_enc->rc_override) {
+ av_log(NULL, AV_LOG_FATAL, "Could not (re)allocate memory for rc_override.\n");
+ exit_program(1);
+ }
video_enc->rc_override[i].start_frame = start;
video_enc->rc_override[i].end_frame = end;
if (q > 0) {
MATCH_PER_STREAM_OPT(pass, i, do_pass, oc, st);
if (do_pass) {
if (do_pass == 1) {
- video_enc->flags |= CODEC_FLAG_PASS1;
+ video_enc->flags |= AV_CODEC_FLAG_PASS1;
} else {
- video_enc->flags |= CODEC_FLAG_PASS2;
+ video_enc->flags |= AV_CODEC_FLAG_PASS2;
}
}
MATCH_PER_STREAM_OPT(passlogfiles, str, ost->logfile_prefix, oc, st);
if (ost->logfile_prefix &&
!(ost->logfile_prefix = av_strdup(ost->logfile_prefix)))
- exit(1);
+ exit_program(1);
+
+ if (do_pass) {
+ char logfilename[1024];
+ FILE *f;
+
+ snprintf(logfilename, sizeof(logfilename), "%s-%d.log",
+ ost->logfile_prefix ? ost->logfile_prefix :
+ DEFAULT_PASS_LOGFILENAME_PREFIX,
+ i);
+ if (!strcmp(ost->enc->name, "libx264")) {
+ av_dict_set(&ost->encoder_opts, "stats", logfilename, AV_DICT_DONT_OVERWRITE);
+ } else {
+ if (video_enc->flags & AV_CODEC_FLAG_PASS1) {
+ f = fopen(logfilename, "wb");
+ if (!f) {
+ av_log(NULL, AV_LOG_FATAL, "Cannot write log file '%s' for pass-1 encoding: %s\n",
+ logfilename, strerror(errno));
+ exit_program(1);
+ }
+ ost->logfile = f;
+ } else {
+ char *logbuffer = read_file(logfilename);
+
+ if (!logbuffer) {
+ av_log(NULL, AV_LOG_FATAL, "Error reading log file '%s' for pass-2 encoding\n",
+ logfilename);
+ exit_program(1);
+ }
+ video_enc->stats_in = logbuffer;
+ }
+ }
+ }
MATCH_PER_STREAM_OPT(forced_key_frames, str, ost->forced_keyframes, oc, st);
if (ost->forced_keyframes)
ost->top_field_first = -1;
MATCH_PER_STREAM_OPT(top_field_first, i, ost->top_field_first, oc, st);
- MATCH_PER_STREAM_OPT(filters, str, filters, oc, st);
- ost->avfilter = av_strdup(filters);
+
+ ost->avfilter = get_ost_filters(o, oc, ost);
+ if (!ost->avfilter)
+ exit_program(1);
} else {
MATCH_PER_STREAM_OPT(copy_initial_nonkeyframes, i, ost->copy_initial_nonkeyframes, oc ,st);
}
ost = new_output_stream(o, oc, AVMEDIA_TYPE_AUDIO);
st = ost->st;
- audio_enc = st->codec;
+ audio_enc = ost->enc_ctx;
audio_enc->codec_type = AVMEDIA_TYPE_AUDIO;
if (!ost->stream_copy) {
char *sample_fmt = NULL;
- const char *filters = "anull";
MATCH_PER_STREAM_OPT(audio_channels, i, audio_enc->channels, oc, st);
if (sample_fmt &&
(audio_enc->sample_fmt = av_get_sample_fmt(sample_fmt)) == AV_SAMPLE_FMT_NONE) {
av_log(NULL, AV_LOG_FATAL, "Invalid sample format '%s'\n", sample_fmt);
- exit(1);
+ exit_program(1);
}
MATCH_PER_STREAM_OPT(audio_sample_rate, i, audio_enc->sample_rate, oc, st);
- MATCH_PER_STREAM_OPT(filters, str, filters, oc, st);
- ost->avfilter = av_strdup(filters);
+ ost->avfilter = get_ost_filters(o, oc, ost);
+ if (!ost->avfilter)
+ exit_program(1);
}
return ost;
ost = new_output_stream(o, oc, AVMEDIA_TYPE_DATA);
if (!ost->stream_copy) {
av_log(NULL, AV_LOG_FATAL, "Data stream encoding not supported yet (only streamcopy)\n");
- exit(1);
+ exit_program(1);
}
return ost;
{
OutputStream *ost = new_output_stream(o, oc, AVMEDIA_TYPE_ATTACHMENT);
ost->stream_copy = 1;
+ ost->finished = 1;
return ost;
}
static OutputStream *new_subtitle_stream(OptionsContext *o, AVFormatContext *oc)
{
- AVStream *st;
OutputStream *ost;
AVCodecContext *subtitle_enc;
ost = new_output_stream(o, oc, AVMEDIA_TYPE_SUBTITLE);
- st = ost->st;
- subtitle_enc = st->codec;
+ subtitle_enc = ost->enc_ctx;
subtitle_enc->codec_type = AVMEDIA_TYPE_SUBTITLE;
av_log(NULL, AV_LOG_FATAL,
"Invalid value '%s' for option '%s', required syntax is 'index:value'\n",
arg, opt);
- exit(1);
+ exit_program(1);
}
*p++ = '\0';
idx = parse_number_or_die(opt, idx_str, OPT_INT, 0, INT_MAX);
for (i = 0; i < is->nb_chapters; i++) {
AVChapter *in_ch = is->chapters[i], *out_ch;
- int64_t ts_off = av_rescale_q(ofile->start_time - ifile->ts_offset,
+ int64_t start_time = (ofile->start_time == AV_NOPTS_VALUE) ? 0 : ofile->start_time;
+ int64_t ts_off = av_rescale_q(start_time - ifile->ts_offset,
AV_TIME_BASE_Q, in_ch->time_base);
int64_t rt = (ofile->recording_time == INT64_MAX) ? INT64_MAX :
av_rescale_q(ofile->recording_time, AV_TIME_BASE_Q, in_ch->time_base);
{
OutputStream *ost;
- switch (avfilter_pad_get_type(ofilter->out_tmp->filter_ctx->output_pads,
- ofilter->out_tmp->pad_idx)) {
+ switch (ofilter->type) {
case AVMEDIA_TYPE_VIDEO: ost = new_video_stream(o, oc); break;
case AVMEDIA_TYPE_AUDIO: ost = new_audio_stream(o, oc); break;
default:
av_log(NULL, AV_LOG_FATAL, "Only video and audio filters are supported "
"currently.\n");
- exit(1);
+ exit_program(1);
}
ost->source_index = -1;
ost->filter = ofilter;
ofilter->ost = ost;
+ ofilter->format = -1;
if (ost->stream_copy) {
av_log(NULL, AV_LOG_ERROR, "Streamcopy requested for output stream %d:%d, "
"which is fed from a complex filtergraph. Filtering and streamcopy "
"cannot be used together.\n", ost->file_index, ost->index);
- exit(1);
+ exit_program(1);
}
- if (configure_output_filter(ofilter->graph, ofilter, ofilter->out_tmp) < 0) {
- av_log(NULL, AV_LOG_FATAL, "Error configuring filter.\n");
- exit(1);
- }
avfilter_inout_free(&ofilter->out_tmp);
}
-static int configure_complex_filters(void)
+static int init_complex_filters(void)
{
int i, ret = 0;
- for (i = 0; i < nb_filtergraphs; i++)
- if (!filtergraphs[i]->graph &&
- (ret = configure_filtergraph(filtergraphs[i])) < 0)
+ for (i = 0; i < nb_filtergraphs; i++) {
+ ret = init_complex_filtergraph(filtergraphs[i]);
+ if (ret < 0)
return ret;
+ }
return 0;
}
AVDictionary *unused_opts = NULL;
AVDictionaryEntry *e = NULL;
- if (configure_complex_filters() < 0) {
- av_log(NULL, AV_LOG_FATAL, "Error configuring filters.\n");
- exit(1);
- }
+ GROW_ARRAY(output_files, nb_output_files);
+ of = av_mallocz(sizeof(*of));
+ if (!of)
+ exit_program(1);
+ output_files[nb_output_files - 1] = of;
+
+ of->ost_index = nb_output_streams;
+ of->recording_time = o->recording_time;
+ of->start_time = o->start_time;
+ of->limit_filesize = o->limit_filesize;
+ of->shortest = o->shortest;
+ av_dict_copy(&of->opts, o->g->format_opts, 0);
if (!strcmp(filename, "-"))
filename = "pipe:";
oc = avformat_alloc_context();
if (!oc) {
print_error(filename, AVERROR(ENOMEM));
- exit(1);
+ exit_program(1);
}
+ of->ctx = oc;
+ if (o->recording_time != INT64_MAX)
+ oc->duration = o->recording_time;
if (o->format) {
file_oformat = av_guess_format(o->format, NULL, NULL);
if (!file_oformat) {
av_log(NULL, AV_LOG_FATAL, "Requested output format '%s' is not a suitable output format\n", o->format);
- exit(1);
+ exit_program(1);
}
} else {
file_oformat = av_guess_format(NULL, filename, NULL);
if (!file_oformat) {
av_log(NULL, AV_LOG_FATAL, "Unable to find a suitable output format for '%s'\n",
filename);
- exit(1);
+ exit_program(1);
}
}
if (!ofilter->out_tmp || ofilter->out_tmp->name)
continue;
- switch (avfilter_pad_get_type(ofilter->out_tmp->filter_ctx->output_pads,
- ofilter->out_tmp->pad_idx)) {
+ switch (ofilter->type) {
case AVMEDIA_TYPE_VIDEO: o->video_disable = 1; break;
case AVMEDIA_TYPE_AUDIO: o->audio_disable = 1; break;
case AVMEDIA_TYPE_SUBTITLE: o->subtitle_disable = 1; break;
int area = 0, idx = -1;
for (i = 0; i < nb_input_streams; i++) {
ist = input_streams[i];
- if (ist->st->codec->codec_type == AVMEDIA_TYPE_VIDEO &&
- ist->st->codec->width * ist->st->codec->height > area) {
- area = ist->st->codec->width * ist->st->codec->height;
+ if (ist->st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO &&
+ ist->st->codecpar->width * ist->st->codecpar->height > area) {
+ area = ist->st->codecpar->width * ist->st->codecpar->height;
idx = i;
}
}
int channels = 0, idx = -1;
for (i = 0; i < nb_input_streams; i++) {
ist = input_streams[i];
- if (ist->st->codec->codec_type == AVMEDIA_TYPE_AUDIO &&
- ist->st->codec->channels > channels) {
- channels = ist->st->codec->channels;
+ if (ist->st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&
+ ist->st->codecpar->channels > channels) {
+ channels = ist->st->codecpar->channels;
idx = i;
}
}
/* subtitles: pick first */
if (!o->subtitle_disable && oc->oformat->subtitle_codec != AV_CODEC_ID_NONE) {
for (i = 0; i < nb_input_streams; i++)
- if (input_streams[i]->st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE) {
+ if (input_streams[i]->st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) {
NEW_STREAM(subtitle, i);
break;
}
if (!ofilter) {
av_log(NULL, AV_LOG_FATAL, "Output with label '%s' does not exist "
"in any defined filter graph.\n", map->linklabel);
- exit(1);
+ exit_program(1);
}
init_output_filter(ofilter, o, oc);
} else {
ist = input_streams[input_files[map->file_index]->ist_index + map->stream_index];
- switch (ist->st->codec->codec_type) {
+ switch (ist->st->codecpar->codec_type) {
case AVMEDIA_TYPE_VIDEO: ost = new_video_stream(o, oc); break;
case AVMEDIA_TYPE_AUDIO: ost = new_audio_stream(o, oc); break;
case AVMEDIA_TYPE_SUBTITLE: ost = new_subtitle_stream(o, oc); break;
default:
av_log(NULL, AV_LOG_FATAL, "Cannot map stream #%d:%d - unsupported type.\n",
map->file_index, map->stream_index);
- exit(1);
+ exit_program(1);
}
ost->source_index = input_files[map->file_index]->ist_index + map->stream_index;
if ((err = avio_open2(&pb, o->attachments[i], AVIO_FLAG_READ, &int_cb, NULL)) < 0) {
av_log(NULL, AV_LOG_FATAL, "Could not open attachment file %s.\n",
o->attachments[i]);
- exit(1);
+ exit_program(1);
}
if ((len = avio_size(pb)) <= 0) {
av_log(NULL, AV_LOG_FATAL, "Could not get size of the attachment %s.\n",
o->attachments[i]);
- exit(1);
+ exit_program(1);
}
if (!(attachment = av_malloc(len))) {
av_log(NULL, AV_LOG_FATAL, "Attachment %s too large to fit into memory.\n",
o->attachments[i]);
- exit(1);
+ exit_program(1);
}
avio_read(pb, attachment, len);
ost->stream_copy = 0;
ost->source_index = -1;
ost->attachment_filename = o->attachments[i];
- ost->st->codec->extradata = attachment;
- ost->st->codec->extradata_size = len;
+ ost->st->codecpar->extradata = attachment;
+ ost->st->codecpar->extradata_size = len;
p = strrchr(o->attachments[i], '/');
av_dict_set(&ost->st->metadata, "filename", (p && *p) ? p + 1 : o->attachments[i], AV_DICT_DONT_OVERWRITE);
avio_close(pb);
}
- GROW_ARRAY(output_files, nb_output_files);
- of = av_mallocz(sizeof(*of));
- if (!of)
- exit(1);
- output_files[nb_output_files - 1] = of;
-
- of->ctx = oc;
- of->ost_index = nb_output_streams - oc->nb_streams;
- of->recording_time = o->recording_time;
- if (o->recording_time != INT64_MAX)
- oc->duration = o->recording_time;
- of->start_time = o->start_time;
- of->limit_filesize = o->limit_filesize;
- of->shortest = o->shortest;
- av_dict_copy(&of->opts, o->g->format_opts, 0);
-
+ if (!oc->nb_streams && !(oc->oformat->flags & AVFMT_NOSTREAMS)) {
+ av_dump_format(oc, nb_output_files - 1, oc->filename, 1);
+ av_log(NULL, AV_LOG_ERROR, "Output file #%d does not contain any stream\n", nb_output_files - 1);
+ exit_program(1);
+ }
/* check if all codec options have been used */
unused_opts = strip_specifiers(o->g->codec_opts);
for (i = of->ost_index; i < nb_output_streams; i++) {
e = NULL;
- while ((e = av_dict_get(output_streams[i]->opts, "", e,
+ while ((e = av_dict_get(output_streams[i]->encoder_opts, "", e,
AV_DICT_IGNORE_SUFFIX)))
av_dict_set(&unused_opts, e->key, NULL, 0);
}
"output file #%d (%s) is not an encoding option.\n", e->key,
option->help ? option->help : "", nb_output_files - 1,
filename);
- exit(1);
+ exit_program(1);
}
av_log(NULL, AV_LOG_WARNING, "Codec AVOption %s (%s) specified for "
}
av_dict_free(&unused_opts);
+ /* set the decoding_needed flags and create simple filtergraphs */
+ for (i = of->ost_index; i < nb_output_streams; i++) {
+ OutputStream *ost = output_streams[i];
+
+ if (ost->encoding_needed && ost->source_index >= 0) {
+ InputStream *ist = input_streams[ost->source_index];
+ ist->decoding_needed = 1;
+
+ if (ost->st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO ||
+ ost->st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
+ err = init_simple_filtergraph(ist, ost);
+ if (err < 0) {
+ av_log(NULL, AV_LOG_ERROR,
+ "Error initializing a simple filtergraph between streams "
+ "%d:%d->%d:%d\n", ist->file_index, ost->source_index,
+ nb_output_files - 1, ost->st->index);
+ exit_program(1);
+ }
+ }
+ }
+
+ /*
+ * We want CFR output if and only if one of those is true:
+ * 1) user specified output framerate with -r
+ * 2) user specified -vsync cfr
+ * 3) output format is CFR and the user didn't force vsync to
+ * something else than CFR
+ *
+ * in such a case, set ost->frame_rate
+ */
+ if (ost->encoding_needed && ost->enc_ctx->codec_type == AVMEDIA_TYPE_VIDEO) {
+ int format_cfr = !(oc->oformat->flags & (AVFMT_NOTIMESTAMPS | AVFMT_VARIABLE_FPS));
+ int need_cfr = !!ost->frame_rate.num;
+
+ if (video_sync_method == VSYNC_CFR ||
+ (video_sync_method == VSYNC_AUTO && format_cfr))
+ need_cfr = 1;
+
+ if (need_cfr && !ost->frame_rate.num) {
+ InputStream *ist = ost->source_index >= 0 ? input_streams[ost->source_index] : NULL;
+
+ if (ist && ist->framerate.num)
+ ost->frame_rate = ist->framerate;
+ else if (ist && ist->st->avg_frame_rate.num)
+ ost->frame_rate = ist->st->avg_frame_rate;
+ else {
+ av_log(NULL, AV_LOG_WARNING, "Constant framerate requested "
+ "for the output stream #%d:%d, but no information "
+ "about the input framerate is available. Falling "
+ "back to a default value of 25fps. Use the -r option "
+ "if you want a different framerate.\n",
+ ost->file_index, ost->index);
+ ost->frame_rate = (AVRational){ 25, 1 };
+ }
+ }
+
+ if (need_cfr && ost->enc->supported_framerates && !ost->force_fps) {
+ int idx = av_find_nearest_q_idx(ost->frame_rate, ost->enc->supported_framerates);
+ ost->frame_rate = ost->enc->supported_framerates[idx];
+ }
+ }
+
+ /* set the filter output constraints */
+ if (ost->filter) {
+ OutputFilter *f = ost->filter;
+ int count;
+ switch (ost->enc_ctx->codec_type) {
+ case AVMEDIA_TYPE_VIDEO:
+ f->frame_rate = ost->frame_rate;
+ f->width = ost->enc_ctx->width;
+ f->height = ost->enc_ctx->height;
+ if (ost->enc_ctx->pix_fmt != AV_PIX_FMT_NONE) {
+ f->format = ost->enc_ctx->pix_fmt;
+ } else if (ost->enc->pix_fmts) {
+ count = 0;
+ while (ost->enc->pix_fmts[count] != AV_PIX_FMT_NONE)
+ count++;
+ f->formats = av_mallocz_array(count + 1, sizeof(*f->formats));
+ if (!f->formats)
+ exit_program(1);
+ memcpy(f->formats, ost->enc->pix_fmts, (count + 1) * sizeof(*f->formats));
+ }
+ break;
+ case AVMEDIA_TYPE_AUDIO:
+ if (ost->enc_ctx->sample_fmt != AV_SAMPLE_FMT_NONE) {
+ f->format = ost->enc_ctx->sample_fmt;
+ } else if (ost->enc->sample_fmts) {
+ count = 0;
+ while (ost->enc->sample_fmts[count] != AV_SAMPLE_FMT_NONE)
+ count++;
+ f->formats = av_mallocz_array(count + 1, sizeof(*f->formats));
+ if (!f->formats)
+ exit_program(1);
+ memcpy(f->formats, ost->enc->sample_fmts, (count + 1) * sizeof(*f->formats));
+ }
+ if (ost->enc_ctx->sample_rate) {
+ f->sample_rate = ost->enc_ctx->sample_rate;
+ } else if (ost->enc->supported_samplerates) {
+ count = 0;
+ while (ost->enc->supported_samplerates[count])
+ count++;
+ f->sample_rates = av_mallocz_array(count + 1, sizeof(*f->sample_rates));
+ if (!f->sample_rates)
+ exit_program(1);
+ memcpy(f->sample_rates, ost->enc->supported_samplerates,
+ (count + 1) * sizeof(*f->sample_rates));
+ }
+ if (ost->enc_ctx->channels) {
+ f->channel_layout = av_get_default_channel_layout(ost->enc_ctx->channels);
+ } else if (ost->enc->channel_layouts) {
+ count = 0;
+ while (ost->enc->channel_layouts[count])
+ count++;
+ f->channel_layouts = av_mallocz_array(count + 1, sizeof(*f->channel_layouts));
+ if (!f->channel_layouts)
+ exit_program(1);
+ memcpy(f->channel_layouts, ost->enc->channel_layouts,
+ (count + 1) * sizeof(*f->channel_layouts));
+ }
+ break;
+ }
+ }
+
+ }
+
/* check filename in case of an image number is expected */
if (oc->oformat->flags & AVFMT_NEEDNUMBER) {
if (!av_filename_number_test(oc->filename)) {
print_error(oc->filename, AVERROR(EINVAL));
- exit(1);
+ exit_program(1);
}
}
&oc->interrupt_callback,
&of->opts)) < 0) {
print_error(filename, err);
- exit(1);
+ exit_program(1);
}
}
if (in_file_index >= nb_input_files) {
av_log(NULL, AV_LOG_FATAL, "Invalid input file index %d while processing metadata maps\n", in_file_index);
- exit(1);
+ exit_program(1);
}
copy_metadata(o->metadata_map[i].specifier, *p ? p + 1 : p, oc,
in_file_index >= 0 ?
} else {
av_log(NULL, AV_LOG_FATAL, "Invalid input file index %d in chapter mapping.\n",
o->chapters_input_file);
- exit(1);
+ exit_program(1);
}
}
if (o->chapters_input_file >= 0)
if (!val) {
av_log(NULL, AV_LOG_FATAL, "No '=' character in metadata string %s.\n",
o->metadata[i].u.str);
- exit(1);
+ exit_program(1);
}
*val++ = 0;
if ((ret = check_stream_specifier(oc, oc->streams[j], stream_spec)) > 0) {
av_dict_set(&oc->streams[j]->metadata, o->metadata[i].u.str, *val ? val : NULL, 0);
} else if (ret < 0)
- exit(1);
+ exit_program(1);
}
}
else {
case 'c':
if (index < 0 || index >= oc->nb_chapters) {
av_log(NULL, AV_LOG_FATAL, "Invalid chapter index %d in metadata specifier.\n", index);
- exit(1);
+ exit_program(1);
}
m = &oc->chapters[index]->metadata;
break;
default:
av_log(NULL, AV_LOG_FATAL, "Invalid metadata specifier %s.\n", o->metadata[i].specifier);
- exit(1);
+ exit_program(1);
}
av_dict_set(m, o->metadata[i].u.str, *val ? val : NULL, 0);
}
int i, j, fr;
for (j = 0; j < nb_input_files; j++) {
for (i = 0; i < input_files[j]->nb_streams; i++) {
- AVCodecContext *c = input_files[j]->ctx->streams[i]->codec;
- if (c->codec_type != AVMEDIA_TYPE_VIDEO)
+ AVStream *st = input_files[j]->ctx->streams[i];
+ if (st->codecpar->codec_type != AVMEDIA_TYPE_VIDEO)
continue;
- fr = c->time_base.den * 1000 / c->time_base.num;
+ fr = st->time_base.den * 1000 / st->time_base.num;
if (fr == 25000) {
norm = PAL;
break;
av_log(NULL, AV_LOG_FATAL, "Could not determine norm (PAL/NTSC/NTSC-Film) for target.\n");
av_log(NULL, AV_LOG_FATAL, "Please prefix target with \"pal-\", \"ntsc-\" or \"film-\",\n");
av_log(NULL, AV_LOG_FATAL, "or set a framerate with \"-r xxx\".\n");
- exit(1);
+ exit_program(1);
}
if (!strcmp(arg, "vcd")) {
parse_option(o, "ac", "2", options);
opt_default(NULL, "packetsize", "2324");
- opt_default(NULL, "muxrate", "1411200"); // 2352 * 75 * 8;
+ opt_default(NULL, "muxrate", "3528"); // 2352 * 75 / 50;
/* We have to offset the PTS, so that it is consistent with the SCR.
SCR starts at 36000, but the first two packs contain only padding
opt_default(NULL, "maxrate", "2516000");
opt_default(NULL, "minrate", "0"); // 1145000;
opt_default(NULL, "bufsize", "1835008"); // 224*1024*8;
- opt_default(NULL, "flags", "+scan_offset");
+ opt_default(NULL, "scan_offset", "1");
opt_default(NULL, "b:a", "224000");
opt_default(NULL, "bufsize", "1835008"); // 224*1024*8;
opt_default(NULL, "packetsize", "2048"); // from www.mpucoder.com: DVD sectors contain 2048 bytes of data, this is also the size of one pack.
- opt_default(NULL, "muxrate", "10080000"); // from mplex project: data_rate = 1260000. mux_rate = data_rate * 8
+ opt_default(NULL, "muxrate", "25200"); // from mplex project: data_rate = 1260000. mux_rate = data_rate / 50
opt_default(NULL, "b:a", "448000");
parse_option(o, "ar", "48000", options);
av_log(NULL, AV_LOG_ERROR, "Unknown target: %s\n", arg);
return AVERROR(EINVAL);
}
+
+ av_dict_copy(&o->g->codec_opts, codec_opts, 0);
+ av_dict_copy(&o->g->format_opts, format_opts, 0);
+
return 0;
}
time_t today2 = time(NULL);
struct tm *today = localtime(&today2);
+ if (!today) { // maybe tomorrow
+ av_log(NULL, AV_LOG_FATAL, "Unable to get current time.\n");
+ exit_program(1);
+ }
+
snprintf(filename, sizeof(filename), "vstats_%02d%02d%02d.log", today->tm_hour, today->tm_min,
today->tm_sec);
return opt_vstats_file(NULL, opt, filename);
return 0;
}
-#if FF_API_DEINTERLACE
-static int opt_deinterlace(void *optctx, const char *opt, const char *arg)
-{
- av_log(NULL, AV_LOG_WARNING, "-%s is deprecated, use -filter:v yadif instead\n", opt);
- do_deinterlace = 1;
- return 0;
-}
-#endif
-
-int opt_cpuflags(void *optctx, const char *opt, const char *arg)
-{
- int flags = av_parse_cpu_flags(arg);
-
- if (flags < 0)
- return flags;
-
- av_set_cpu_flags_mask(flags);
- return 0;
-}
-
static int opt_channel_layout(void *optctx, const char *opt, const char *arg)
{
OptionsContext *o = optctx;
GROW_ARRAY(filtergraphs, nb_filtergraphs);
if (!(filtergraphs[nb_filtergraphs - 1] = av_mallocz(sizeof(*filtergraphs[0]))))
return AVERROR(ENOMEM);
- filtergraphs[nb_filtergraphs - 1]->index = nb_filtergraphs - 1;
- filtergraphs[nb_filtergraphs - 1]->graph_desc = arg;
+ filtergraphs[nb_filtergraphs - 1]->index = nb_filtergraphs - 1;
+ filtergraphs[nb_filtergraphs - 1]->graph_desc = av_strdup(arg);
+ if (!filtergraphs[nb_filtergraphs - 1]->graph_desc)
+ return AVERROR(ENOMEM);
+ return 0;
+}
+
+static int opt_filter_complex_script(void *optctx, const char *opt, const char *arg)
+{
+ uint8_t *graph_desc = read_file(arg);
+ if (!graph_desc)
+ return AVERROR(EINVAL);
+
+ GROW_ARRAY(filtergraphs, nb_filtergraphs);
+ if (!(filtergraphs[nb_filtergraphs - 1] = av_mallocz(sizeof(*filtergraphs[0]))))
+ return AVERROR(ENOMEM);
+ filtergraphs[nb_filtergraphs - 1]->index = nb_filtergraphs - 1;
+ filtergraphs[nb_filtergraphs - 1]->graph_desc = graph_desc;
return 0;
}
" -h -- print basic options\n"
" -h long -- print more options\n"
" -h full -- print all options (including all format and codec specific options, very long)\n"
+ " -h type=name -- print all options for the named decoder/encoder/demuxer/muxer/filter\n"
" See man %s for detailed description of the options.\n"
"\n", program_name);
show_help_children(avcodec_get_class(), flags);
show_help_children(avformat_get_class(), flags);
show_help_children(sws_get_class(), flags);
+ show_help_children(avfilter_get_class(), AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_AUDIO_PARAM);
}
}
goto fail;
}
+ /* create the complex filtergraphs */
+ ret = init_complex_filters();
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_FATAL, "Error initializing complex filters.\n");
+ goto fail;
+ }
+
/* open output files */
ret = open_files(&octx.groups[GROUP_OUTFILE], "output", open_output_file);
if (ret < 0) {
"force format", "fmt" },
{ "y", OPT_BOOL, { &file_overwrite },
"overwrite output files" },
+ { "n", OPT_BOOL, { &file_skip },
+ "never overwrite output files" },
{ "c", HAS_ARG | OPT_STRING | OPT_SPEC |
OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(codec_names) },
"codec name", "codec" },
{ "map_chapters", HAS_ARG | OPT_INT | OPT_EXPERT | OPT_OFFSET |
OPT_OUTPUT, { .off = OFFSET(chapters_input_file) },
"set chapters mapping", "input_file_index" },
- { "t", HAS_ARG | OPT_TIME | OPT_OFFSET | OPT_OUTPUT, { .off = OFFSET(recording_time) },
+ { "t", HAS_ARG | OPT_TIME | OPT_OFFSET |
+ OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(recording_time) },
"record or transcode \"duration\" seconds of audio/video",
"duration" },
{ "fs", HAS_ARG | OPT_INT64 | OPT_OFFSET | OPT_OUTPUT, { .off = OFFSET(limit_filesize) },
{ "ss", HAS_ARG | OPT_TIME | OPT_OFFSET |
OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(start_time) },
"set the start time offset", "time_off" },
+ { "accurate_seek", OPT_BOOL | OPT_OFFSET | OPT_EXPERT |
+ OPT_INPUT, { .off = OFFSET(accurate_seek) },
+ "enable/disable accurate seeking with -ss" },
{ "itsoffset", HAS_ARG | OPT_TIME | OPT_OFFSET |
OPT_EXPERT | OPT_INPUT, { .off = OFFSET(input_ts_offset) },
"set the input ts offset", "time_off" },
{ "target", HAS_ARG | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_target },
"specify target file type (\"vcd\", \"svcd\", \"dvd\","
" \"dv\", \"dv50\", \"pal-vcd\", \"ntsc-svcd\", ...)", "type" },
- { "vsync", HAS_ARG | OPT_EXPERT, { opt_vsync },
+ { "vsync", HAS_ARG | OPT_EXPERT, { .func_arg = opt_vsync },
"video sync method", "" },
{ "async", HAS_ARG | OPT_INT | OPT_EXPERT, { &audio_sync_method },
"audio sync method", "" },
{ "frames", OPT_INT64 | HAS_ARG | OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(max_frames) },
"set the number of frames to record", "number" },
{ "tag", OPT_STRING | HAS_ARG | OPT_SPEC |
- OPT_EXPERT | OPT_OUTPUT, { .off = OFFSET(codec_tags) },
+ OPT_EXPERT | OPT_OUTPUT | OPT_INPUT, { .off = OFFSET(codec_tags) },
"force codec tag/fourcc", "fourcc/tag" },
{ "q", HAS_ARG | OPT_EXPERT | OPT_DOUBLE |
OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(qscale) },
"use fixed quality scale (VBR)", "q" },
{ "filter", HAS_ARG | OPT_STRING | OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(filters) },
"set stream filterchain", "filter_list" },
+ { "filter_script", HAS_ARG | OPT_STRING | OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(filter_scripts) },
+ "read stream filtergraph description from a file", "filename" },
{ "filter_complex", HAS_ARG | OPT_EXPERT, { .func_arg = opt_filter_complex },
"create a complex filtergraph", "graph_description" },
+ { "filter_complex_script", HAS_ARG | OPT_EXPERT, { .func_arg = opt_filter_complex_script },
+ "read complex filtergraph description from a file", "filename" },
{ "stats", OPT_BOOL, { &print_stats },
"print progress report during encoding", },
{ "attach", HAS_ARG | OPT_PERFILE | OPT_EXPERT |
{ "dump_attachment", HAS_ARG | OPT_STRING | OPT_SPEC |
OPT_EXPERT | OPT_INPUT, { .off = OFFSET(dump_attachment) },
"extract an attachment into a file", "filename" },
- { "cpuflags", HAS_ARG | OPT_EXPERT, { .func_arg = opt_cpuflags },
- "set CPU flags mask", "mask" },
+ { "loop", OPT_INT | HAS_ARG | OPT_EXPERT | OPT_INPUT |
+ OPT_OFFSET, { .off = OFFSET(loop) }, "set number of times input stream shall be looped", "loop count" },
/* video options */
{ "vframes", OPT_VIDEO | HAS_ARG | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_video_frames },
{ "passlogfile", OPT_VIDEO | HAS_ARG | OPT_STRING | OPT_EXPERT | OPT_SPEC |
OPT_OUTPUT, { .off = OFFSET(passlogfiles) },
"select two pass log file name prefix", "prefix" },
-#if FF_API_DEINTERLACE
- { "deinterlace", OPT_VIDEO | OPT_EXPERT , { .func_arg = opt_deinterlace },
- "this option is deprecated, use the yadif filter instead" },
-#endif
- { "vstats", OPT_VIDEO | OPT_EXPERT , { &opt_vstats },
+ { "vstats", OPT_VIDEO | OPT_EXPERT , { .func_arg = &opt_vstats },
"dump video coding statistics to file" },
- { "vstats_file", OPT_VIDEO | HAS_ARG | OPT_EXPERT , { opt_vstats_file },
+ { "vstats_file", OPT_VIDEO | HAS_ARG | OPT_EXPERT , { .func_arg = opt_vstats_file },
"dump video coding statistics to file", "file" },
{ "vf", OPT_VIDEO | HAS_ARG | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_video_filters },
"video filters", "filter list" },
{ "force_key_frames", OPT_VIDEO | OPT_STRING | HAS_ARG | OPT_EXPERT |
OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(forced_key_frames) },
"force key frames at specified timestamps", "timestamps" },
+ { "hwaccel", OPT_VIDEO | OPT_STRING | HAS_ARG | OPT_EXPERT |
+ OPT_SPEC | OPT_INPUT, { .off = OFFSET(hwaccels) },
+ "use HW accelerated decoding", "hwaccel name" },
+ { "hwaccel_device", OPT_VIDEO | OPT_STRING | HAS_ARG | OPT_EXPERT |
+ OPT_SPEC | OPT_INPUT, { .off = OFFSET(hwaccel_devices) },
+ "select a device for HW acceleration", "devicename" },
+ { "hwaccel_output_format", OPT_VIDEO | OPT_STRING | HAS_ARG | OPT_EXPERT |
+ OPT_SPEC | OPT_INPUT, { .off = OFFSET(hwaccel_output_formats) },
+ "select output format used with HW accelerated decoding", "format" },
+
+ { "hwaccels", OPT_EXIT, { .func_arg = show_hwaccels },
+ "show available HW acceleration methods" },
+ { "autorotate", HAS_ARG | OPT_BOOL | OPT_SPEC |
+ OPT_EXPERT | OPT_INPUT, { .off = OFFSET(autorotate) },
+ "automatically insert correct rotate filters" },
+ { "hwaccel_lax_profile_check", OPT_BOOL | OPT_EXPERT, { &hwaccel_lax_profile_check},
+ "attempt to decode anyway if HW accelerated decoder's supported profiles do not exactly match the stream" },
/* audio options */
{ "aframes", OPT_AUDIO | HAS_ARG | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_audio_frames },
{ "bsf", HAS_ARG | OPT_STRING | OPT_SPEC | OPT_EXPERT | OPT_OUTPUT, { .off = OFFSET(bitstream_filters) },
"A comma-separated list of bitstream filters", "bitstream_filters" },
+ { "max_muxing_queue_size", HAS_ARG | OPT_INT | OPT_SPEC | OPT_EXPERT | OPT_OUTPUT, { .off = OFFSET(max_muxing_queue_size) },
+ "maximum number of packets that can be buffered while waiting for all streams to initialize", "packets" },
+
/* data codec support */
{ "dcodec", HAS_ARG | OPT_DATA | OPT_PERFILE | OPT_EXPERT | OPT_INPUT | OPT_OUTPUT, { .func_arg = opt_data_codec },
"force data codec ('copy' to copy stream)", "codec" },
+#if CONFIG_VAAPI
+ { "vaapi_device", HAS_ARG | OPT_EXPERT, { .func_arg = opt_vaapi_device },
+ "set VAAPI hardware device (DRM path or X11 display name)", "device" },
+#endif
+
{ NULL, },
};