#include "libavutil/avassert.h"
+#define VSYNC_AUTO -1
+#define VSYNC_PASSTHROUGH 0
+#define VSYNC_CFR 1
+#define VSYNC_VFR 2
+
const char program_name[] = "avconv";
const int program_birth_year = 2000;
static int do_pkt_dump = 0;
static int do_pass = 0;
static const char *pass_logfilename_prefix;
-static int video_sync_method = -1;
+static int video_sync_method = VSYNC_AUTO;
static int audio_sync_method = 0;
static float audio_drift_threshold = 0.1;
static int copy_ts = 0;
static int print_stats = 1;
static uint8_t *audio_buf;
-static uint8_t *audio_out;
-static unsigned int allocated_audio_out_size, allocated_audio_buf_size;
+static unsigned int allocated_audio_buf_size;
#define DEFAULT_PASS_LOGFILENAME_PREFIX "av2pass"
AVBitStreamFilterContext *bitstream_filters;
AVCodec *enc;
int64_t max_frames;
+ AVFrame *output_frame;
/* video only */
int video_resample;
if ((ret = avfilter_graph_parse(ost->graph, ost->avfilter, &inputs, &outputs, NULL)) < 0)
return ret;
- av_freep(&ost->avfilter);
} else {
if ((ret = avfilter_link(last_filter, 0, ost->output_video_filter, 0)) < 0)
return ret;
avformat_free_context(s);
av_dict_free(&output_files[i].opts);
}
+ for (i = 0; i < nb_output_streams; i++) {
+ AVBitStreamFilterContext *bsfc = output_streams[i].bitstream_filters;
+ while (bsfc) {
+ AVBitStreamFilterContext *next = bsfc->next;
+ av_bitstream_filter_close(bsfc);
+ bsfc = next;
+ }
+ output_streams[i].bitstream_filters = NULL;
+
+ if (output_streams[i].output_frame) {
+ AVFrame *frame = output_streams[i].output_frame;
+ if (frame->extended_data != frame->data)
+ av_freep(&frame->extended_data);
+ av_freep(&frame);
+ }
+
+#if CONFIG_AVFILTER
+ av_freep(&output_streams[i].avfilter);
+#endif
+ }
for (i = 0; i < nb_input_files; i++) {
avformat_close_input(&input_files[i].ctx);
}
uninit_opts();
av_free(audio_buf);
- av_free(audio_out);
- allocated_audio_buf_size = allocated_audio_out_size = 0;
+ allocated_audio_buf_size = 0;
#if CONFIG_AVFILTER
avfilter_uninit();
return (double)(ist->pts - of->start_time) / AV_TIME_BASE;
}
-static void write_frame(AVFormatContext *s, AVPacket *pkt, AVCodecContext *avctx, AVBitStreamFilterContext *bsfc)
+static void write_frame(AVFormatContext *s, AVPacket *pkt, OutputStream *ost)
{
+ AVBitStreamFilterContext *bsfc = ost->bitstream_filters;
+ AVCodecContext *avctx = ost->st->codec;
int ret;
+ /*
+ * Audio encoders may split the packets -- #frames in != #packets out.
+ * But there is no reordering, so we can limit the number of output packets
+ * by simply dropping them here.
+ * Counting encoded video frames needs to be done separately because of
+ * reordering, see do_video_out()
+ */
+ if (!(avctx->codec_type == AVMEDIA_TYPE_VIDEO && avctx->codec)) {
+ if (ost->frame_number >= ost->max_frames)
+ return;
+ ost->frame_number++;
+ }
+
while (bsfc) {
AVPacket new_pkt = *pkt;
int a = av_bitstream_filter_filter(bsfc, avctx, NULL,
memset(buf, fill_char, size);
}
+static int encode_audio_frame(AVFormatContext *s, OutputStream *ost,
+ const uint8_t *buf, int buf_size)
+{
+ AVCodecContext *enc = ost->st->codec;
+ AVFrame *frame = NULL;
+ AVPacket pkt;
+ int ret, got_packet;
+
+ av_init_packet(&pkt);
+ pkt.data = NULL;
+ pkt.size = 0;
+
+ if (buf) {
+ if (!ost->output_frame) {
+ ost->output_frame = avcodec_alloc_frame();
+ if (!ost->output_frame) {
+ av_log(NULL, AV_LOG_FATAL, "out-of-memory in encode_audio_frame()\n");
+ exit_program(1);
+ }
+ }
+ frame = ost->output_frame;
+ if (frame->extended_data != frame->data)
+ av_freep(&frame->extended_data);
+ avcodec_get_frame_defaults(frame);
+
+ frame->nb_samples = buf_size /
+ (enc->channels * av_get_bytes_per_sample(enc->sample_fmt));
+ if ((ret = avcodec_fill_audio_frame(frame, enc->channels, enc->sample_fmt,
+ buf, buf_size, 1)) < 0) {
+ av_log(NULL, AV_LOG_FATAL, "Audio encoding failed\n");
+ exit_program(1);
+ }
+ }
+
+ got_packet = 0;
+ if (avcodec_encode_audio2(enc, &pkt, frame, &got_packet) < 0) {
+ av_log(NULL, AV_LOG_FATAL, "Audio encoding failed\n");
+ exit_program(1);
+ }
+
+ if (got_packet) {
+ pkt.stream_index = ost->index;
+ if (pkt.pts != AV_NOPTS_VALUE)
+ pkt.pts = av_rescale_q(pkt.pts, enc->time_base, ost->st->time_base);
+ if (pkt.duration > 0)
+ pkt.duration = av_rescale_q(pkt.duration, enc->time_base, ost->st->time_base);
+
+ write_frame(s, &pkt, ost);
+
+ audio_size += pkt.size;
+ }
+
+ if (frame)
+ ost->sync_opts += frame->nb_samples;
+
+ return pkt.size;
+}
+
static void do_audio_out(AVFormatContext *s, OutputStream *ost,
InputStream *ist, AVFrame *decoded_frame)
{
uint8_t *buftmp;
- int64_t audio_out_size, audio_buf_size;
+ int64_t audio_buf_size;
- int size_out, frame_bytes, ret, resample_changed;
+ int size_out, frame_bytes, resample_changed;
AVCodecContext *enc = ost->st->codec;
AVCodecContext *dec = ist->st->codec;
int osize = av_get_bytes_per_sample(enc->sample_fmt);
int isize = av_get_bytes_per_sample(dec->sample_fmt);
- const int coded_bps = av_get_bits_per_sample(enc->codec->id);
uint8_t *buf = decoded_frame->data[0];
int size = decoded_frame->nb_samples * dec->channels * isize;
int64_t allocated_for_size = size;
audio_buf_size = FFMAX(audio_buf_size, enc->frame_size);
audio_buf_size *= osize * enc->channels;
- audio_out_size = FFMAX(audio_buf_size, enc->frame_size * osize * enc->channels);
- if (coded_bps > 8 * osize)
- audio_out_size = audio_out_size * coded_bps / (8*osize);
- audio_out_size += FF_MIN_BUFFER_SIZE;
-
- if (audio_out_size > INT_MAX || audio_buf_size > INT_MAX) {
+ if (audio_buf_size > INT_MAX) {
av_log(NULL, AV_LOG_FATAL, "Buffer sizes too large\n");
exit_program(1);
}
av_fast_malloc(&audio_buf, &allocated_audio_buf_size, audio_buf_size);
- av_fast_malloc(&audio_out, &allocated_audio_out_size, audio_out_size);
- if (!audio_buf || !audio_out) {
+ if (!audio_buf) {
av_log(NULL, AV_LOG_FATAL, "Out of memory in do_audio_out\n");
exit_program(1);
}
}
/* now encode as many frames as possible */
- if (enc->frame_size > 1) {
+ if (!(enc->codec->capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE)) {
/* output resampled raw samples */
if (av_fifo_realloc2(ost->fifo, av_fifo_size(ost->fifo) + size_out) < 0) {
av_log(NULL, AV_LOG_FATAL, "av_fifo_realloc2() failed\n");
frame_bytes = enc->frame_size * osize * enc->channels;
while (av_fifo_size(ost->fifo) >= frame_bytes) {
- AVPacket pkt;
- av_init_packet(&pkt);
-
av_fifo_generic_read(ost->fifo, audio_buf, frame_bytes, NULL);
-
- // FIXME pass ost->sync_opts as AVFrame.pts in avcodec_encode_audio()
-
- ret = avcodec_encode_audio(enc, audio_out, audio_out_size,
- (short *)audio_buf);
- if (ret < 0) {
- av_log(NULL, AV_LOG_FATAL, "Audio encoding failed\n");
- exit_program(1);
- }
- audio_size += ret;
- pkt.stream_index = ost->index;
- pkt.data = audio_out;
- pkt.size = ret;
- if (enc->coded_frame && enc->coded_frame->pts != AV_NOPTS_VALUE)
- pkt.pts = av_rescale_q(enc->coded_frame->pts, enc->time_base, ost->st->time_base);
- pkt.flags |= AV_PKT_FLAG_KEY;
- write_frame(s, &pkt, enc, ost->bitstream_filters);
-
- ost->sync_opts += enc->frame_size;
+ encode_audio_frame(s, ost, audio_buf, frame_bytes);
}
} else {
- AVPacket pkt;
- av_init_packet(&pkt);
-
- ost->sync_opts += size_out / (osize * enc->channels);
-
- /* output a pcm frame */
- /* determine the size of the coded buffer */
- size_out /= osize;
- if (coded_bps)
- size_out = size_out * coded_bps / 8;
-
- if (size_out > audio_out_size) {
- av_log(NULL, AV_LOG_FATAL, "Internal error, buffer size too small\n");
- exit_program(1);
- }
-
- // FIXME pass ost->sync_opts as AVFrame.pts in avcodec_encode_audio()
- ret = avcodec_encode_audio(enc, audio_out, size_out,
- (short *)buftmp);
- if (ret < 0) {
- av_log(NULL, AV_LOG_FATAL, "Audio encoding failed\n");
- exit_program(1);
- }
- audio_size += ret;
- pkt.stream_index = ost->index;
- pkt.data = audio_out;
- pkt.size = ret;
- if (enc->coded_frame && enc->coded_frame->pts != AV_NOPTS_VALUE)
- pkt.pts = av_rescale_q(enc->coded_frame->pts, enc->time_base, ost->st->time_base);
- pkt.flags |= AV_PKT_FLAG_KEY;
- write_frame(s, &pkt, enc, ost->bitstream_filters);
+ encode_audio_frame(s, ost, buftmp, size_out);
}
}
else
pkt.pts += 90 * sub->end_display_time;
}
- write_frame(s, &pkt, ost->st->codec, ost->bitstream_filters);
+ write_frame(s, &pkt, ost);
}
}
static int bit_buffer_size = 1024 * 256;
static uint8_t *bit_buffer = NULL;
+#if !CONFIG_AVFILTER
static void do_video_resample(OutputStream *ost,
InputStream *ist,
AVFrame *in_picture,
AVCodecContext *enc = ost->st->codec;
*out_picture = in_picture;
- resample_changed = ost->resample_width != dec->width ||
- ost->resample_height != dec->height ||
- ost->resample_pix_fmt != dec->pix_fmt;
+ resample_changed = ost->resample_width != in_picture->width ||
+ ost->resample_height != in_picture->height ||
+ ost->resample_pix_fmt != in_picture->format;
-#if !CONFIG_AVFILTER
if (resample_changed) {
av_log(NULL, AV_LOG_INFO,
- "Input stream #%d:%d frame changed from size:%dx%d fmt:%s to size:%dx%d fmt:%s\n",
+ "Input stream #%d:%d frame changed from size:%dx%d fmt:%s to size:%dx%d fmt:%s / frm size:%dx%d fmt:%s\n",
ist->file_index, ist->st->index,
ost->resample_width, ost->resample_height, av_get_pix_fmt_name(ost->resample_pix_fmt),
- dec->width , dec->height , av_get_pix_fmt_name(dec->pix_fmt));
- ost->resample_width = dec->width;
- ost->resample_height = dec->height;
- ost->resample_pix_fmt = dec->pix_fmt;
+ dec->width , dec->height , av_get_pix_fmt_name(dec->pix_fmt),
+ in_picture->width, in_picture->height, av_get_pix_fmt_name(in_picture->format));
+ ost->resample_width = in_picture->width;
+ ost->resample_height = in_picture->height;
+ ost->resample_pix_fmt = in_picture->format;
}
ost->video_resample = dec->width != enc->width ||
dec->height != enc->height ||
dec->pix_fmt != enc->pix_fmt;
+
if (ost->video_resample) {
*out_picture = &ost->resample_frame;
if (!ost->img_resample_ctx || resample_changed) {
sws_scale(ost->img_resample_ctx, in_picture->data, in_picture->linesize,
0, ost->resample_height, (*out_picture)->data, (*out_picture)->linesize);
}
-#else
if (resample_changed) {
- avfilter_graph_free(&ost->graph);
- if (configure_video_filters(ist, ost)) {
- av_log(NULL, AV_LOG_FATAL, "Error reinitializing filters!\n");
- exit_program(1);
- }
- }
-#endif
- if (resample_changed) {
- ost->resample_width = dec->width;
- ost->resample_height = dec->height;
- ost->resample_pix_fmt = dec->pix_fmt;
+ ost->resample_width = in_picture->width;
+ ost->resample_height = in_picture->height;
+ ost->resample_pix_fmt = in_picture->format;
}
}
+#endif
static void do_video_out(AVFormatContext *s,
*frame_size = 0;
format_video_sync = video_sync_method;
- if (format_video_sync < 0)
- format_video_sync = (s->oformat->flags & AVFMT_NOTIMESTAMPS) ? 0 :
- (s->oformat->flags & AVFMT_VARIABLE_FPS) ? 2 : 1;
+ if (format_video_sync == VSYNC_AUTO)
+ format_video_sync = (s->oformat->flags & AVFMT_NOTIMESTAMPS) ? VSYNC_PASSTHROUGH :
+ (s->oformat->flags & AVFMT_VARIABLE_FPS) ? VSYNC_VFR : VSYNC_CFR;
- if (format_video_sync) {
+ if (format_video_sync != VSYNC_PASSTHROUGH) {
double vdelta = sync_ipts - ost->sync_opts;
// FIXME set to 0.5 after we fix some dts/pts bugs like in avidec.c
if (vdelta < -1.1)
nb_frames = 0;
- else if (format_video_sync == 2) {
+ else if (format_video_sync == VSYNC_VFR) {
if (vdelta <= -0.6) {
nb_frames = 0;
} else if (vdelta > 0.6)
if (nb_frames <= 0)
return;
+#if !CONFIG_AVFILTER
do_video_resample(ost, ist, in_picture, &final_picture);
+#else
+ final_picture = in_picture;
+#endif
/* duplicates frame if needed */
for (i = 0; i < nb_frames; i++) {
pkt.pts = av_rescale_q(ost->sync_opts, enc->time_base, ost->st->time_base);
pkt.flags |= AV_PKT_FLAG_KEY;
- write_frame(s, &pkt, ost->st->codec, ost->bitstream_filters);
+ write_frame(s, &pkt, ost);
} else {
AVFrame big_picture;
if (enc->coded_frame->key_frame)
pkt.flags |= AV_PKT_FLAG_KEY;
- write_frame(s, &pkt, ost->st->codec, ost->bitstream_filters);
+ write_frame(s, &pkt, ost);
*frame_size = ret;
video_size += ret;
// fprintf(stderr,"\nFrame: %3d size: %5d type: %d",
}
}
ost->sync_opts++;
+ /*
+ * For video, number of frames in == number of packets out.
+ * But there may be reordering, so we can't throw away frames on encoder
+ * flush, we need to limit them here, before they go into encoder.
+ */
ost->frame_number++;
}
}
OutputStream *ost = &ost_table[i];
AVCodecContext *enc = ost->st->codec;
AVFormatContext *os = output_files[ost->file_index].ctx;
+ int stop_encoding = 0;
if (!ost->encoding_needed)
continue;
AVPacket pkt;
int fifo_bytes;
av_init_packet(&pkt);
- pkt.stream_index = ost->index;
+ pkt.data = NULL;
+ pkt.size = 0;
switch (ost->st->codec->codec_type) {
case AVMEDIA_TYPE_AUDIO:
fifo_bytes = av_fifo_size(ost->fifo);
- ret = 0;
- /* encode any samples remaining in fifo */
if (fifo_bytes > 0) {
- int osize = av_get_bytes_per_sample(enc->sample_fmt);
- int fs_tmp = enc->frame_size;
+ /* encode any samples remaining in fifo */
+ int frame_bytes = fifo_bytes;
av_fifo_generic_read(ost->fifo, audio_buf, fifo_bytes, NULL);
- if (enc->codec->capabilities & CODEC_CAP_SMALL_LAST_FRAME) {
- enc->frame_size = fifo_bytes / (osize * enc->channels);
- } else { /* pad */
- int frame_bytes = enc->frame_size*osize*enc->channels;
+
+ /* pad last frame with silence if needed */
+ if (!(enc->codec->capabilities & CODEC_CAP_SMALL_LAST_FRAME)) {
+ frame_bytes = enc->frame_size * enc->channels *
+ av_get_bytes_per_sample(enc->sample_fmt);
if (allocated_audio_buf_size < frame_bytes)
exit_program(1);
generate_silence(audio_buf+fifo_bytes, enc->sample_fmt, frame_bytes - fifo_bytes);
}
-
- ret = avcodec_encode_audio(enc, bit_buffer, bit_buffer_size, (short *)audio_buf);
- pkt.duration = av_rescale((int64_t)enc->frame_size*ost->st->time_base.den,
- ost->st->time_base.num, enc->sample_rate);
- enc->frame_size = fs_tmp;
- }
- if (ret <= 0) {
- ret = avcodec_encode_audio(enc, bit_buffer, bit_buffer_size, NULL);
- }
- if (ret < 0) {
- av_log(NULL, AV_LOG_FATAL, "Audio encoding failed\n");
- exit_program(1);
+ encode_audio_frame(os, ost, audio_buf, frame_bytes);
+ } else {
+ /* flush encoder with NULL frames until it is done
+ returning packets */
+ if (encode_audio_frame(os, ost, NULL, 0) == 0) {
+ stop_encoding = 1;
+ break;
+ }
}
- audio_size += ret;
- pkt.flags |= AV_PKT_FLAG_KEY;
break;
case AVMEDIA_TYPE_VIDEO:
ret = avcodec_encode_video(enc, bit_buffer, bit_buffer_size, NULL);
if (ost->logfile && enc->stats_out) {
fprintf(ost->logfile, "%s", enc->stats_out);
}
+ if (ret <= 0) {
+ stop_encoding = 1;
+ break;
+ }
+ pkt.stream_index = ost->index;
+ pkt.data = bit_buffer;
+ pkt.size = ret;
+ if (enc->coded_frame && enc->coded_frame->pts != AV_NOPTS_VALUE)
+ pkt.pts = av_rescale_q(enc->coded_frame->pts, enc->time_base, ost->st->time_base);
+ write_frame(os, &pkt, ost);
break;
default:
- ret = -1;
+ stop_encoding = 1;
}
-
- if (ret <= 0)
+ if (stop_encoding)
break;
- pkt.data = bit_buffer;
- pkt.size = ret;
- if (enc->coded_frame && enc->coded_frame->pts != AV_NOPTS_VALUE)
- pkt.pts = av_rescale_q(enc->coded_frame->pts, enc->time_base, ost->st->time_base);
- write_frame(os, &pkt, ost->st->codec, ost->bitstream_filters);
}
}
}
opkt.flags |= AV_PKT_FLAG_KEY;
}
- write_frame(of->ctx, &opkt, ost->st->codec, ost->bitstream_filters);
+ write_frame(of->ctx, &opkt, ost);
ost->st->codec->frame_number++;
- ost->frame_number++;
av_free_packet(&opkt);
}
for (i = 0; i < nb_output_streams; i++) {
OutputStream *ost = &output_streams[i];
- int frame_size;
+ int frame_size, resample_changed;
if (!check_output_constraints(ist, ost) || !ost->encoding_needed)
continue;
#if CONFIG_AVFILTER
+ resample_changed = ost->resample_width != decoded_frame->width ||
+ ost->resample_height != decoded_frame->height ||
+ ost->resample_pix_fmt != decoded_frame->format;
+ if (resample_changed) {
+ av_log(NULL, AV_LOG_INFO,
+ "Input stream #%d:%d frame changed from size:%dx%d fmt:%s to size:%dx%d fmt:%s\n",
+ ist->file_index, ist->st->index,
+ ost->resample_width, ost->resample_height, av_get_pix_fmt_name(ost->resample_pix_fmt),
+ decoded_frame->width, decoded_frame->height, av_get_pix_fmt_name(decoded_frame->format));
+
+ avfilter_graph_free(&ost->graph);
+ if (configure_video_filters(ist, ost)) {
+ av_log(NULL, AV_LOG_FATAL, "Error reinitializing filters!\n");
+ exit_program(1);
+ }
+
+ ost->resample_width = decoded_frame->width;
+ ost->resample_height = decoded_frame->height;
+ ost->resample_pix_fmt = decoded_frame->format;
+ }
+
if (!decoded_frame->sample_aspect_ratio.num)
decoded_frame->sample_aspect_ratio = ist->st->sample_aspect_ratio;
decoded_frame->pts = ist->pts;
ist->st->codec->opaque = ist;
}
+ if (!av_dict_get(ist->opts, "threads", NULL, 0))
+ av_dict_set(&ist->opts, "threads", "auto", 0);
if (avcodec_open2(ist->st->codec, codec, &ist->opts) < 0) {
snprintf(error, error_len, "Error while opening decoder for input stream #%d:%d",
ist->file_index, ist->st->index);
memcpy(ost->st->codec->subtitle_header, dec->subtitle_header, dec->subtitle_header_size);
ost->st->codec->subtitle_header_size = dec->subtitle_header_size;
}
+ if (!av_dict_get(ost->opts, "threads", NULL, 0))
+ av_dict_set(&ost->opts, "threads", "auto", 0);
if (avcodec_open2(ost->st->codec, codec, &ost->opts) < 0) {
snprintf(error, sizeof(error), "Error while opening encoder for output stream #%d:%d - maybe incorrect parameters such as bit_rate, rate, width or height",
ost->file_index, ost->index);
*/
static void add_input_streams(OptionsContext *o, AVFormatContext *ic)
{
- int i, rfps, rfps_base;
+ int i;
for (i = 0; i < ic->nb_streams; i++) {
AVStream *st = ic->streams[i];
case AVMEDIA_TYPE_VIDEO:
if(!ist->dec)
ist->dec = avcodec_find_decoder(dec->codec_id);
- rfps = ic->streams[i]->r_frame_rate.num;
- rfps_base = ic->streams[i]->r_frame_rate.den;
if (dec->lowres) {
dec->flags |= CODEC_FLAG_EMU_EDGE;
}
- if (dec->time_base.den != rfps * dec->ticks_per_frame || dec->time_base.num != rfps_base) {
-
- av_log(NULL, AV_LOG_INFO,"\nSeems stream %d codec frame rate differs from container frame rate: %2.2f (%d/%d) -> %2.2f (%d/%d)\n",
- i, (float)dec->time_base.den / dec->time_base.num, dec->time_base.den, dec->time_base.num,
- (float)rfps / rfps_base, rfps, rfps_base);
- }
-
if (o->video_disable)
st->discard = AVDISCARD_ALL;
else if (video_discard)
ost->top_field_first = -1;
MATCH_PER_STREAM_OPT(top_field_first, i, ost->top_field_first, oc, st);
- MATCH_PER_STREAM_OPT(copy_initial_nonkeyframes, i, ost->copy_initial_nonkeyframes, oc ,st);
-
#if CONFIG_AVFILTER
MATCH_PER_STREAM_OPT(filters, str, filters, oc, st);
if (filters)
ost->avfilter = av_strdup(filters);
#endif
+ } else {
+ MATCH_PER_STREAM_OPT(copy_initial_nonkeyframes, i, ost->copy_initial_nonkeyframes, oc ,st);
}
return ost;
static void show_usage(void)
{
- printf("Hyper fast Audio and Video encoder\n");
- printf("usage: %s [options] [[infile options] -i infile]... {[outfile options] outfile}...\n", program_name);
- printf("\n");
+ av_log(NULL, AV_LOG_INFO, "Hyper fast Audio and Video encoder\n");
+ av_log(NULL, AV_LOG_INFO, "usage: %s [options] [[infile options] -i infile]... {[outfile options] outfile}...\n", program_name);
+ av_log(NULL, AV_LOG_INFO, "\n");
}
static int opt_help(const char *opt, const char *arg)
return parse_option(o, "filter:v", arg, options);
}
+static int opt_vsync(const char *opt, const char *arg)
+{
+ if (!av_strcasecmp(arg, "cfr")) video_sync_method = VSYNC_CFR;
+ else if (!av_strcasecmp(arg, "vfr")) video_sync_method = VSYNC_VFR;
+ else if (!av_strcasecmp(arg, "passthrough")) video_sync_method = VSYNC_PASSTHROUGH;
+
+ if (video_sync_method == VSYNC_AUTO)
+ video_sync_method = parse_number_or_die("vsync", arg, OPT_INT, VSYNC_AUTO, VSYNC_VFR);
+ return 0;
+}
+
#define OFFSET(x) offsetof(OptionsContext, x)
static const OptionDef options[] = {
/* main options */
"when dumping packets, also dump the payload" },
{ "re", OPT_BOOL | OPT_EXPERT | OPT_OFFSET, {.off = OFFSET(rate_emu)}, "read input at native frame rate", "" },
{ "target", HAS_ARG | OPT_FUNC2, {(void*)opt_target}, "specify target file type (\"vcd\", \"svcd\", \"dvd\", \"dv\", \"dv50\", \"pal-vcd\", \"ntsc-svcd\", ...)", "type" },
- { "vsync", HAS_ARG | OPT_INT | OPT_EXPERT, {(void*)&video_sync_method}, "video sync method", "" },
+ { "vsync", HAS_ARG | OPT_EXPERT, {(void*)opt_vsync}, "video sync method", "" },
{ "async", HAS_ARG | OPT_INT | OPT_EXPERT, {(void*)&audio_sync_method}, "audio sync method", "" },
{ "adrift_threshold", HAS_ARG | OPT_FLOAT | OPT_EXPERT, {(void*)&audio_drift_threshold}, "audio drift threshold", "threshold" },
{ "copyts", OPT_BOOL | OPT_EXPERT, {(void*)©_ts}, "copy timestamps" },