#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;\
}\
}
+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
+ { 0 },
+};
+
char *vstats_filename;
float audio_drift_threshold = 0.1;
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 */
return ar;
}
+static int show_hwaccels(void *optctx, const char *opt, const char *arg)
+{
+ int i;
+
+ printf("Supported hardware acceleration:\n");
+ for (i = 0; i < FF_ARRAY_ELEMS(hwaccels) - 1; 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, ',')) {
* 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;
InputStream *ist = av_mallocz(sizeof(*ist));
- char *framerate = NULL;
+ char *framerate = NULL, *hwaccel = NULL, *hwaccel_device = NULL;
+ char *codec_tag = NULL;
+ char *next;
if (!ist)
exit_program(1);
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->codec->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, ist->st->codec->codec_id, ic, st, ist->dec);
+
+ 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_copy_context(ist->dec_ctx, dec);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Error initializing the decoder context.\n");
+ exit_program(1);
+ }
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->resample_height = ist->dec_ctx->height;
+ ist->resample_width = ist->dec_ctx->width;
+ ist->resample_pix_fmt = ist->dec_ctx->pix_fmt;
MATCH_PER_STREAM_OPT(frame_rates, str, framerate, ic, st);
if (framerate && av_parse_video_rate(&ist->framerate,
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);
+ }
+ 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;
+ ist->resample_sample_fmt = ist->dec_ctx->sample_fmt;
+ ist->resample_sample_rate = ist->dec_ctx->sample_rate;
+ ist->resample_channels = ist->dec_ctx->channels;
+ ist->resample_channel_layout = ist->dec_ctx->channel_layout;
break;
case AVMEDIA_TYPE_DATA:
}
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 && !file_skip) {
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;
/* 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);
}
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);
ost->st = st;
st->codec->codec_type = type;
choose_encoder(o, oc, ost);
+
+ 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)))) {
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);
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);
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;
}
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);
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)
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;
}
}
!(ost->logfile_prefix = av_strdup(ost->logfile_prefix)))
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->forced_keyframes = av_strdup(ost->forced_keyframes);
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) {
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;
{
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:
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_program(1);
- }
avfilter_inout_free(&ofilter->out_tmp);
}
+static int init_complex_filters(void)
+{
+ int i, ret = 0;
+
+ for (i = 0; i < nb_filtergraphs; i++) {
+ ret = init_complex_filtergraph(filtergraphs[i]);
+ if (ret < 0)
+ return ret;
+ }
+ return 0;
+}
+
static int configure_complex_filters(void)
{
int i, ret = 0;
AVDictionary *unused_opts = NULL;
AVDictionaryEntry *e = NULL;
- if (configure_complex_filters() < 0) {
- av_log(NULL, AV_LOG_FATAL, "Error configuring filters.\n");
- exit_program(1);
- }
-
GROW_ARRAY(output_files, nb_output_files);
of = av_mallocz(sizeof(*of));
if (!of)
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;
avio_close(pb);
}
+ 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);
}
}
av_dict_free(&unused_opts);
+ /* set the encoding/decoding_needed flags */
+ for (i = of->ost_index; i < nb_output_streams; i++) {
+ OutputStream *ost = output_streams[i];
+
+ ost->encoding_needed = !ost->stream_copy;
+ if (ost->encoding_needed && ost->source_index >= 0) {
+ InputStream *ist = input_streams[ost->source_index];
+ ist->decoding_needed = 1;
+ }
+ }
+
/* check filename in case of an image number is expected */
if (oc->oformat->flags & AVFMT_NEEDNUMBER) {
if (!av_filename_number_test(oc->filename)) {
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)
+ if (c->codec_type != AVMEDIA_TYPE_VIDEO ||
+ !c->time_base.num)
continue;
fr = c->time_base.den * 1000 / c->time_base.num;
if (fr == 25000) {
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;
}
-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;
" -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);
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) {
goto fail;
}
+ /* configure the complex filtergraphs */
+ ret = configure_complex_filters();
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_FATAL, "Error configuring complex filters.\n");
+ goto fail;
+ }
+
fail:
uninit_parse_context(&octx);
if (ret < 0) {
{ "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" },
{ "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) },
{ "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" },
/* video options */
{ "vframes", OPT_VIDEO | HAS_ARG | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_video_frames },
{ "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" },
+ { "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" },
/* audio options */
{ "aframes", OPT_AUDIO | HAS_ARG | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_audio_frames },