1
0
mirror of https://github.com/FFmpeg/FFmpeg.git synced 2024-12-23 12:43:46 +02:00

Merge commit '811bd0784679dfcb4ed02043a37c92f9df10500e'

* commit '811bd0784679dfcb4ed02043a37c92f9df10500e':
  avconv: make input -ss accurate when transcoding

Conflicts:
	Changelog
	doc/ffmpeg.texi
	ffmpeg.h
	ffmpeg_filter.c

Merged-by: Michael Niedermayer <michaelni@gmx.at>
This commit is contained in:
Michael Niedermayer 2013-08-06 10:57:04 +02:00
commit 7cbef2ed7e
5 changed files with 67 additions and 20 deletions

View File

@ -8,6 +8,9 @@ version <next>
- ffprobe -show_programs option - ffprobe -show_programs option
- compand filter - compand filter
- RTMP seek support - RTMP seek support
- when transcoding with ffmpeg (i.e. not streamcopying), -ss is now accurate
even when used as an input option. Previous behavior can be restored with
the -noaccurate_seek option.
version 2.0: version 2.0:

View File

@ -272,9 +272,15 @@ Set the file size limit, expressed in bytes.
@item -ss @var{position} (@emph{input/output}) @item -ss @var{position} (@emph{input/output})
When used as an input option (before @code{-i}), seeks in this input file to When used as an input option (before @code{-i}), seeks in this input file to
@var{position}. When used as an output option (before an output filename), @var{position}. Note the in most formats it is not possible to seek exactly, so
decodes but discards input until the timestamps reach @var{position}. This is @command{ffmpeg} will seek to the closest seek point before @var{position}.
slower, but more accurate. When transcoding and @option{-accurate_seek} is enabled (the default), this
extra segment between the seek point and @var{position} will be decoded and
discarded. When doing stream copy or when @option{-noaccurate_seek} is used, it
will be preserved.
When used as an output option (before an output filename), decodes but discards
input until the timestamps reach @var{position}.
@var{position} may be either in seconds or in @code{hh:mm:ss[.xxx]} form. @var{position} may be either in seconds or in @code{hh:mm:ss[.xxx]} form.
@ -1060,6 +1066,12 @@ This option is similar to @option{-filter_complex}, the only difference is that
its argument is the name of the file from which a complex filtergraph its argument is the name of the file from which a complex filtergraph
description is to be read. description is to be read.
@item -accurate_seek (@emph{input})
This option enables or disables accurate seeking in input files with the
@option{-ss} option. It is enabled by default, so seeking is accurate when
transcoding. Use @option{-noaccurate_seek} to disable it, which may be useful
e.g. when copying some streams and transcoding the others.
@item -override_ffserver (@emph{global}) @item -override_ffserver (@emph{global})
Overrides the input specifications from ffserver. Using this option you can Overrides the input specifications from ffserver. Using this option you can
map any input stream to ffserver and control many aspects of the encoding from map any input stream to ffserver and control many aspects of the encoding from

View File

@ -93,6 +93,7 @@ typedef struct OptionsContext {
/* input options */ /* input options */
int64_t input_ts_offset; int64_t input_ts_offset;
int rate_emu; int rate_emu;
int accurate_seek;
SpecifierOpt *ts_scale; SpecifierOpt *ts_scale;
int nb_ts_scale; int nb_ts_scale;
@ -282,10 +283,12 @@ typedef struct InputFile {
int ist_index; /* index of first stream in input_streams */ int ist_index; /* index of first stream in input_streams */
int64_t ts_offset; int64_t ts_offset;
int64_t last_ts; int64_t last_ts;
int64_t start_time; /* user-specified start time in AV_TIME_BASE or AV_NOPTS_VALUE */
int nb_streams; /* number of stream that ffmpeg is aware of; may be different int nb_streams; /* number of stream that ffmpeg is aware of; may be different
from ctx.nb_streams if new streams appear during av_read_frame() */ from ctx.nb_streams if new streams appear during av_read_frame() */
int nb_streams_warn; /* number of streams that the user was warned of */ int nb_streams_warn; /* number of streams that the user was warned of */
int rate_emu; int rate_emu;
int accurate_seek;
#if HAVE_PTHREADS #if HAVE_PTHREADS
pthread_t thread; /* thread reading from this file */ pthread_t thread; /* thread reading from this file */

View File

@ -276,21 +276,22 @@ static void init_input_filter(FilterGraph *fg, AVFilterInOut *in)
ist->filters[ist->nb_filters - 1] = fg->inputs[fg->nb_inputs - 1]; ist->filters[ist->nb_filters - 1] = fg->inputs[fg->nb_inputs - 1];
} }
static int insert_trim(OutputStream *ost, AVFilterContext **last_filter, int *pad_idx) static int insert_trim(int64_t start_time, int64_t duration,
AVFilterContext **last_filter, int *pad_idx,
const char *filter_name)
{ {
OutputFile *of = output_files[ost->file_index];
AVFilterGraph *graph = (*last_filter)->graph; AVFilterGraph *graph = (*last_filter)->graph;
AVFilterContext *ctx; AVFilterContext *ctx;
const AVFilter *trim; const AVFilter *trim;
const char *name = ost->st->codec->codec_type == AVMEDIA_TYPE_VIDEO ? "trim" : "atrim"; enum AVMediaType type = avfilter_pad_get_type((*last_filter)->output_pads, *pad_idx);
char filter_name[128]; const char *name = (type == AVMEDIA_TYPE_VIDEO) ? "trim" : "atrim";
int ret = 0; int ret = 0;
if (of->recording_time == INT64_MAX && of->start_time == AV_NOPTS_VALUE) if (duration == INT64_MAX && start_time == AV_NOPTS_VALUE)
return 0; return 0;
// Use with duration and without output starttime is buggy with trim filters // Use with duration and without output starttime is buggy with trim filters
if (of->start_time == AV_NOPTS_VALUE) if (start_time == AV_NOPTS_VALUE)
return 0; return 0;
trim = avfilter_get_by_name(name); trim = avfilter_get_by_name(name);
@ -300,18 +301,16 @@ static int insert_trim(OutputStream *ost, AVFilterContext **last_filter, int *pa
return AVERROR_FILTER_NOT_FOUND; return AVERROR_FILTER_NOT_FOUND;
} }
snprintf(filter_name, sizeof(filter_name), "%s for output stream %d:%d",
name, ost->file_index, ost->index);
ctx = avfilter_graph_alloc_filter(graph, trim, filter_name); ctx = avfilter_graph_alloc_filter(graph, trim, filter_name);
if (!ctx) if (!ctx)
return AVERROR(ENOMEM); return AVERROR(ENOMEM);
if (of->recording_time != INT64_MAX) { if (duration != INT64_MAX) {
ret = av_opt_set_double(ctx, "duration", (double)of->recording_time / 1e6, ret = av_opt_set_double(ctx, "duration", (double)duration / 1e6,
AV_OPT_SEARCH_CHILDREN); AV_OPT_SEARCH_CHILDREN);
} }
if (ret >= 0 && of->start_time != AV_NOPTS_VALUE) { if (ret >= 0 && start_time != AV_NOPTS_VALUE) {
ret = av_opt_set_double(ctx, "start", (double)of->start_time / 1e6, ret = av_opt_set_double(ctx, "start", (double)start_time / 1e6,
AV_OPT_SEARCH_CHILDREN); AV_OPT_SEARCH_CHILDREN);
} }
if (ret < 0) { if (ret < 0) {
@ -336,6 +335,7 @@ static int configure_output_video_filter(FilterGraph *fg, OutputFilter *ofilter,
{ {
char *pix_fmts; char *pix_fmts;
OutputStream *ost = ofilter->ost; OutputStream *ost = ofilter->ost;
OutputFile *of = output_files[ost->file_index];
AVCodecContext *codec = ost->st->codec; AVCodecContext *codec = ost->st->codec;
AVFilterContext *last_filter = out->filter_ctx; AVFilterContext *last_filter = out->filter_ctx;
int pad_idx = out->pad_idx; int pad_idx = out->pad_idx;
@ -408,7 +408,10 @@ static int configure_output_video_filter(FilterGraph *fg, OutputFilter *ofilter,
pad_idx = 0; pad_idx = 0;
} }
ret = insert_trim(ost, &last_filter, &pad_idx); snprintf(name, sizeof(name), "trim for output stream %d:%d",
ost->file_index, ost->index);
ret = insert_trim(of->start_time, of->recording_time,
&last_filter, &pad_idx, name);
if (ret < 0) if (ret < 0)
return ret; return ret;
@ -422,9 +425,9 @@ static int configure_output_video_filter(FilterGraph *fg, OutputFilter *ofilter,
static int configure_output_audio_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out) static int configure_output_audio_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out)
{ {
OutputStream *ost = ofilter->ost; OutputStream *ost = ofilter->ost;
OutputFile *of = output_files[ost->file_index];
AVCodecContext *codec = ost->st->codec; AVCodecContext *codec = ost->st->codec;
AVFilterContext *last_filter = out->filter_ctx; AVFilterContext *last_filter = out->filter_ctx;
OutputFile *of = output_files[ost->file_index];
int pad_idx = out->pad_idx; int pad_idx = out->pad_idx;
char *sample_fmts, *sample_rates, *channel_layouts; char *sample_fmts, *sample_rates, *channel_layouts;
char name[255]; char name[255];
@ -534,7 +537,10 @@ static int configure_output_audio_filter(FilterGraph *fg, OutputFilter *ofilter,
} }
} }
ret = insert_trim(ost, &last_filter, &pad_idx); snprintf(name, sizeof(name), "trim for output stream %d:%d",
ost->file_index, ost->index);
ret = insert_trim(of->start_time, of->recording_time,
&last_filter, &pad_idx, name);
if (ret < 0) if (ret < 0)
return ret; return ret;
@ -615,13 +621,14 @@ static int configure_input_video_filter(FilterGraph *fg, InputFilter *ifilter,
AVFilterContext *last_filter; AVFilterContext *last_filter;
const AVFilter *buffer_filt = avfilter_get_by_name("buffer"); const AVFilter *buffer_filt = avfilter_get_by_name("buffer");
InputStream *ist = ifilter->ist; InputStream *ist = ifilter->ist;
InputFile *f = input_files[ist->file_index];
AVRational tb = ist->framerate.num ? av_inv_q(ist->framerate) : AVRational tb = ist->framerate.num ? av_inv_q(ist->framerate) :
ist->st->time_base; ist->st->time_base;
AVRational fr = ist->framerate; AVRational fr = ist->framerate;
AVRational sar; AVRational sar;
AVBPrint args; AVBPrint args;
char name[255]; char name[255];
int ret; int ret, pad_idx = 0;
if (!fr.num) if (!fr.num)
fr = av_guess_frame_rate(input_files[ist->file_index]->ctx, ist->st, NULL); fr = av_guess_frame_rate(input_files[ist->file_index]->ctx, ist->st, NULL);
@ -688,6 +695,13 @@ static int configure_input_video_filter(FilterGraph *fg, InputFilter *ifilter,
last_filter = yadif; last_filter = yadif;
} }
snprintf(name, sizeof(name), "trim for input stream %d:%d",
ist->file_index, ist->st->index);
ret = insert_trim(((f->start_time == AV_NOPTS_VALUE) || !f->accurate_seek) ?
AV_NOPTS_VALUE : 0, INT64_MAX, &last_filter, &pad_idx, name);
if (ret < 0)
return ret;
if ((ret = avfilter_link(last_filter, 0, in->filter_ctx, in->pad_idx)) < 0) if ((ret = avfilter_link(last_filter, 0, in->filter_ctx, in->pad_idx)) < 0)
return ret; return ret;
return 0; return 0;
@ -699,9 +713,10 @@ static int configure_input_audio_filter(FilterGraph *fg, InputFilter *ifilter,
AVFilterContext *last_filter; AVFilterContext *last_filter;
const AVFilter *abuffer_filt = avfilter_get_by_name("abuffer"); const AVFilter *abuffer_filt = avfilter_get_by_name("abuffer");
InputStream *ist = ifilter->ist; InputStream *ist = ifilter->ist;
InputFile *f = input_files[ist->file_index];
AVBPrint args; AVBPrint args;
char name[255]; char name[255];
int ret; int ret, pad_idx = 0;
av_bprint_init(&args, 0, AV_BPRINT_SIZE_AUTOMATIC); av_bprint_init(&args, 0, AV_BPRINT_SIZE_AUTOMATIC);
av_bprintf(&args, "time_base=%d/%d:sample_rate=%d:sample_fmt=%s", av_bprintf(&args, "time_base=%d/%d:sample_rate=%d:sample_fmt=%s",
@ -776,6 +791,14 @@ static int configure_input_audio_filter(FilterGraph *fg, InputFilter *ifilter,
snprintf(args, sizeof(args), "%f", audio_volume / 256.); snprintf(args, sizeof(args), "%f", audio_volume / 256.);
AUTO_INSERT_FILTER_INPUT("-vol", "volume", args); AUTO_INSERT_FILTER_INPUT("-vol", "volume", args);
} }
snprintf(name, sizeof(name), "trim for input stream %d:%d",
ist->file_index, ist->st->index);
ret = insert_trim(((f->start_time == AV_NOPTS_VALUE) || !f->accurate_seek) ?
AV_NOPTS_VALUE : 0, INT64_MAX, &last_filter, &pad_idx, name);
if (ret < 0)
return ret;
if ((ret = avfilter_link(last_filter, 0, in->filter_ctx, in->pad_idx)) < 0) if ((ret = avfilter_link(last_filter, 0, in->filter_ctx, in->pad_idx)) < 0)
return ret; return ret;

View File

@ -150,6 +150,7 @@ static void init_options(OptionsContext *o, int is_input)
o->start_time = AV_NOPTS_VALUE; o->start_time = AV_NOPTS_VALUE;
o->limit_filesize = UINT64_MAX; o->limit_filesize = UINT64_MAX;
o->chapters_input_file = INT_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 a copy of the input with the stream specifiers removed from the keys */
@ -853,9 +854,11 @@ static int open_input_file(OptionsContext *o, const char *filename)
f->ctx = ic; f->ctx = ic;
f->ist_index = nb_input_streams - ic->nb_streams; f->ist_index = nb_input_streams - ic->nb_streams;
f->start_time = o->start_time;
f->ts_offset = o->input_ts_offset - (copy_ts ? 0 : timestamp); f->ts_offset = o->input_ts_offset - (copy_ts ? 0 : timestamp);
f->nb_streams = ic->nb_streams; f->nb_streams = ic->nb_streams;
f->rate_emu = o->rate_emu; f->rate_emu = o->rate_emu;
f->accurate_seek = o->accurate_seek;
/* check if all codec options have been used */ /* check if all codec options have been used */
unused_opts = strip_specifiers(o->g->codec_opts); unused_opts = strip_specifiers(o->g->codec_opts);
@ -2619,6 +2622,9 @@ const OptionDef options[] = {
{ "ss", HAS_ARG | OPT_TIME | OPT_OFFSET | { "ss", HAS_ARG | OPT_TIME | OPT_OFFSET |
OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(start_time) }, OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(start_time) },
"set the start time offset", "time_off" }, "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 | { "itsoffset", HAS_ARG | OPT_TIME | OPT_OFFSET |
OPT_EXPERT | OPT_INPUT, { .off = OFFSET(input_ts_offset) }, OPT_EXPERT | OPT_INPUT, { .off = OFFSET(input_ts_offset) },
"set the input ts offset", "time_off" }, "set the input ts offset", "time_off" },