Browse code

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>

Michael Niedermayer authored on 2013/08/06 17:57:04
Showing 5 changed files
... ...
@@ -8,6 +8,9 @@ version <next>
8 8
 - ffprobe -show_programs option
9 9
 - compand filter
10 10
 - RTMP seek support
11
+- when transcoding with ffmpeg (i.e. not streamcopying), -ss is now accurate
12
+  even when used as an input option. Previous behavior can be restored with
13
+  the -noaccurate_seek option.
11 14
 
12 15
 
13 16
 version 2.0:
... ...
@@ -272,9 +272,15 @@ Set the file size limit, expressed in bytes.
272 272
 
273 273
 @item -ss @var{position} (@emph{input/output})
274 274
 When used as an input option (before @code{-i}), seeks in this input file to
275
-@var{position}. When used as an output option (before an output filename),
276
-decodes but discards input until the timestamps reach @var{position}. This is
277
-slower, but more accurate.
275
+@var{position}. Note the in most formats it is not possible to seek exactly, so
276
+@command{ffmpeg} will seek to the closest seek point before @var{position}.
277
+When transcoding and @option{-accurate_seek} is enabled (the default), this
278
+extra segment between the seek point and @var{position} will be decoded and
279
+discarded. When doing stream copy or when @option{-noaccurate_seek} is used, it
280
+will be preserved.
281
+
282
+When used as an output option (before an output filename), decodes but discards
283
+input until the timestamps reach @var{position}.
278 284
 
279 285
 @var{position} may be either in seconds or in @code{hh:mm:ss[.xxx]} form.
280 286
 
... ...
@@ -1060,6 +1066,12 @@ This option is similar to @option{-filter_complex}, the only difference is that
1060 1060
 its argument is the name of the file from which a complex filtergraph
1061 1061
 description is to be read.
1062 1062
 
1063
+@item -accurate_seek (@emph{input})
1064
+This option enables or disables accurate seeking in input files with the
1065
+@option{-ss} option. It is enabled by default, so seeking is accurate when
1066
+transcoding. Use @option{-noaccurate_seek} to disable it, which may be useful
1067
+e.g. when copying some streams and transcoding the others.
1068
+
1063 1069
 @item -override_ffserver (@emph{global})
1064 1070
 Overrides the input specifications from ffserver. Using this option you can
1065 1071
 map any input stream to ffserver and control many aspects of the encoding from
... ...
@@ -93,6 +93,7 @@ typedef struct OptionsContext {
93 93
     /* input options */
94 94
     int64_t input_ts_offset;
95 95
     int rate_emu;
96
+    int accurate_seek;
96 97
 
97 98
     SpecifierOpt *ts_scale;
98 99
     int        nb_ts_scale;
... ...
@@ -282,10 +283,12 @@ typedef struct InputFile {
282 282
     int ist_index;        /* index of first stream in input_streams */
283 283
     int64_t ts_offset;
284 284
     int64_t last_ts;
285
+    int64_t start_time;   /* user-specified start time in AV_TIME_BASE or AV_NOPTS_VALUE */
285 286
     int nb_streams;       /* number of stream that ffmpeg is aware of; may be different
286 287
                              from ctx.nb_streams if new streams appear during av_read_frame() */
287 288
     int nb_streams_warn;  /* number of streams that the user was warned of */
288 289
     int rate_emu;
290
+    int accurate_seek;
289 291
 
290 292
 #if HAVE_PTHREADS
291 293
     pthread_t thread;           /* thread reading from this file */
... ...
@@ -276,21 +276,22 @@ static void init_input_filter(FilterGraph *fg, AVFilterInOut *in)
276 276
     ist->filters[ist->nb_filters - 1] = fg->inputs[fg->nb_inputs - 1];
277 277
 }
278 278
 
279
-static int insert_trim(OutputStream *ost, AVFilterContext **last_filter, int *pad_idx)
279
+static int insert_trim(int64_t start_time, int64_t duration,
280
+                       AVFilterContext **last_filter, int *pad_idx,
281
+                       const char *filter_name)
280 282
 {
281
-    OutputFile *of = output_files[ost->file_index];
282 283
     AVFilterGraph *graph = (*last_filter)->graph;
283 284
     AVFilterContext *ctx;
284 285
     const AVFilter *trim;
285
-    const char *name = ost->st->codec->codec_type == AVMEDIA_TYPE_VIDEO ? "trim" : "atrim";
286
-    char filter_name[128];
286
+    enum AVMediaType type = avfilter_pad_get_type((*last_filter)->output_pads, *pad_idx);
287
+    const char *name = (type == AVMEDIA_TYPE_VIDEO) ? "trim" : "atrim";
287 288
     int ret = 0;
288 289
 
289
-    if (of->recording_time == INT64_MAX && of->start_time == AV_NOPTS_VALUE)
290
+    if (duration == INT64_MAX && start_time == AV_NOPTS_VALUE)
290 291
         return 0;
291 292
 
292 293
     // Use with duration and without output starttime is buggy with trim filters
293
-    if (of->start_time == AV_NOPTS_VALUE)
294
+    if (start_time == AV_NOPTS_VALUE)
294 295
         return 0;
295 296
 
296 297
     trim = avfilter_get_by_name(name);
... ...
@@ -300,18 +301,16 @@ static int insert_trim(OutputStream *ost, AVFilterContext **last_filter, int *pa
300 300
         return AVERROR_FILTER_NOT_FOUND;
301 301
     }
302 302
 
303
-    snprintf(filter_name, sizeof(filter_name), "%s for output stream %d:%d",
304
-             name, ost->file_index, ost->index);
305 303
     ctx = avfilter_graph_alloc_filter(graph, trim, filter_name);
306 304
     if (!ctx)
307 305
         return AVERROR(ENOMEM);
308 306
 
309
-    if (of->recording_time != INT64_MAX) {
310
-        ret = av_opt_set_double(ctx, "duration", (double)of->recording_time / 1e6,
307
+    if (duration != INT64_MAX) {
308
+        ret = av_opt_set_double(ctx, "duration", (double)duration / 1e6,
311 309
                                 AV_OPT_SEARCH_CHILDREN);
312 310
     }
313
-    if (ret >= 0 && of->start_time != AV_NOPTS_VALUE) {
314
-        ret = av_opt_set_double(ctx, "start", (double)of->start_time / 1e6,
311
+    if (ret >= 0 && start_time != AV_NOPTS_VALUE) {
312
+        ret = av_opt_set_double(ctx, "start", (double)start_time / 1e6,
315 313
                                 AV_OPT_SEARCH_CHILDREN);
316 314
     }
317 315
     if (ret < 0) {
... ...
@@ -336,6 +335,7 @@ static int configure_output_video_filter(FilterGraph *fg, OutputFilter *ofilter,
336 336
 {
337 337
     char *pix_fmts;
338 338
     OutputStream *ost = ofilter->ost;
339
+    OutputFile    *of = output_files[ost->file_index];
339 340
     AVCodecContext *codec = ost->st->codec;
340 341
     AVFilterContext *last_filter = out->filter_ctx;
341 342
     int pad_idx = out->pad_idx;
... ...
@@ -408,7 +408,10 @@ static int configure_output_video_filter(FilterGraph *fg, OutputFilter *ofilter,
408 408
         pad_idx = 0;
409 409
     }
410 410
 
411
-    ret = insert_trim(ost, &last_filter, &pad_idx);
411
+    snprintf(name, sizeof(name), "trim for output stream %d:%d",
412
+             ost->file_index, ost->index);
413
+    ret = insert_trim(of->start_time, of->recording_time,
414
+                      &last_filter, &pad_idx, name);
412 415
     if (ret < 0)
413 416
         return ret;
414 417
 
... ...
@@ -422,9 +425,9 @@ static int configure_output_video_filter(FilterGraph *fg, OutputFilter *ofilter,
422 422
 static int configure_output_audio_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out)
423 423
 {
424 424
     OutputStream *ost = ofilter->ost;
425
+    OutputFile    *of = output_files[ost->file_index];
425 426
     AVCodecContext *codec  = ost->st->codec;
426 427
     AVFilterContext *last_filter = out->filter_ctx;
427
-    OutputFile *of = output_files[ost->file_index];
428 428
     int pad_idx = out->pad_idx;
429 429
     char *sample_fmts, *sample_rates, *channel_layouts;
430 430
     char name[255];
... ...
@@ -534,7 +537,10 @@ static int configure_output_audio_filter(FilterGraph *fg, OutputFilter *ofilter,
534 534
         }
535 535
     }
536 536
 
537
-    ret = insert_trim(ost, &last_filter, &pad_idx);
537
+    snprintf(name, sizeof(name), "trim for output stream %d:%d",
538
+             ost->file_index, ost->index);
539
+    ret = insert_trim(of->start_time, of->recording_time,
540
+                      &last_filter, &pad_idx, name);
538 541
     if (ret < 0)
539 542
         return ret;
540 543
 
... ...
@@ -615,13 +621,14 @@ static int configure_input_video_filter(FilterGraph *fg, InputFilter *ifilter,
615 615
     AVFilterContext *last_filter;
616 616
     const AVFilter *buffer_filt = avfilter_get_by_name("buffer");
617 617
     InputStream *ist = ifilter->ist;
618
+    InputFile     *f = input_files[ist->file_index];
618 619
     AVRational tb = ist->framerate.num ? av_inv_q(ist->framerate) :
619 620
                                          ist->st->time_base;
620 621
     AVRational fr = ist->framerate;
621 622
     AVRational sar;
622 623
     AVBPrint args;
623 624
     char name[255];
624
-    int ret;
625
+    int ret, pad_idx = 0;
625 626
 
626 627
     if (!fr.num)
627 628
         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,
688 688
         last_filter = yadif;
689 689
     }
690 690
 
691
+    snprintf(name, sizeof(name), "trim for input stream %d:%d",
692
+             ist->file_index, ist->st->index);
693
+    ret = insert_trim(((f->start_time == AV_NOPTS_VALUE) || !f->accurate_seek) ?
694
+                      AV_NOPTS_VALUE : 0, INT64_MAX, &last_filter, &pad_idx, name);
695
+    if (ret < 0)
696
+        return ret;
697
+
691 698
     if ((ret = avfilter_link(last_filter, 0, in->filter_ctx, in->pad_idx)) < 0)
692 699
         return ret;
693 700
     return 0;
... ...
@@ -699,9 +713,10 @@ static int configure_input_audio_filter(FilterGraph *fg, InputFilter *ifilter,
699 699
     AVFilterContext *last_filter;
700 700
     const AVFilter *abuffer_filt = avfilter_get_by_name("abuffer");
701 701
     InputStream *ist = ifilter->ist;
702
+    InputFile     *f = input_files[ist->file_index];
702 703
     AVBPrint args;
703 704
     char name[255];
704
-    int ret;
705
+    int ret, pad_idx = 0;
705 706
 
706 707
     av_bprint_init(&args, 0, AV_BPRINT_SIZE_AUTOMATIC);
707 708
     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,
776 776
         snprintf(args, sizeof(args), "%f", audio_volume / 256.);
777 777
         AUTO_INSERT_FILTER_INPUT("-vol", "volume", args);
778 778
     }
779
+
780
+    snprintf(name, sizeof(name), "trim for input stream %d:%d",
781
+             ist->file_index, ist->st->index);
782
+    ret = insert_trim(((f->start_time == AV_NOPTS_VALUE) || !f->accurate_seek) ?
783
+                      AV_NOPTS_VALUE : 0, INT64_MAX, &last_filter, &pad_idx, name);
784
+    if (ret < 0)
785
+        return ret;
786
+
779 787
     if ((ret = avfilter_link(last_filter, 0, in->filter_ctx, in->pad_idx)) < 0)
780 788
         return ret;
781 789
 
... ...
@@ -150,6 +150,7 @@ static void init_options(OptionsContext *o, int is_input)
150 150
     o->start_time     = AV_NOPTS_VALUE;
151 151
     o->limit_filesize = UINT64_MAX;
152 152
     o->chapters_input_file = INT_MAX;
153
+    o->accurate_seek  = 1;
153 154
 }
154 155
 
155 156
 /* 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)
853 853
 
854 854
     f->ctx        = ic;
855 855
     f->ist_index  = nb_input_streams - ic->nb_streams;
856
+    f->start_time = o->start_time;
856 857
     f->ts_offset  = o->input_ts_offset - (copy_ts ? 0 : timestamp);
857 858
     f->nb_streams = ic->nb_streams;
858 859
     f->rate_emu   = o->rate_emu;
860
+    f->accurate_seek = o->accurate_seek;
859 861
 
860 862
     /* check if all codec options have been used */
861 863
     unused_opts = strip_specifiers(o->g->codec_opts);
... ...
@@ -2619,6 +2622,9 @@ const OptionDef options[] = {
2619 2619
     { "ss",             HAS_ARG | OPT_TIME | OPT_OFFSET |
2620 2620
                         OPT_INPUT | OPT_OUTPUT,                      { .off = OFFSET(start_time) },
2621 2621
         "set the start time offset", "time_off" },
2622
+    { "accurate_seek",  OPT_BOOL | OPT_OFFSET | OPT_EXPERT |
2623
+                        OPT_INPUT,                                   { .off = OFFSET(accurate_seek) },
2624
+        "enable/disable accurate seeking with -ss" },
2622 2625
     { "itsoffset",      HAS_ARG | OPT_TIME | OPT_OFFSET |
2623 2626
                         OPT_EXPERT | OPT_INPUT,                      { .off = OFFSET(input_ts_offset) },
2624 2627
         "set the input ts offset", "time_off" },