Allows shifting of subtitle display times to align them with the video.
This avoids having to rewrite the subtitle file in order to display
subtitles correctly when input is seeked (-ss).
Also handy for minor subtitle timing corrections without rewriting the
subtitles file.

Signed-off-by: Manolis Stamatogiannakis <msta...@gmail.com>
---
 doc/filters.texi           |  8 ++++++++
 libavfilter/vf_subtitles.c | 23 +++++++++++++++++++++--
 2 files changed, 29 insertions(+), 2 deletions(-)

diff --git a/doc/filters.texi b/doc/filters.texi
index ad2448acb2..c962ac55b0 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -17935,6 +17935,9 @@ The filter accepts the following options:
 @item filename, f
 Set the filename of the subtitle file to read. It must be specified.
 
+@item shift
+Shift subtitles timings by the specified amount.
+
 @item original_size
 Specify the size of the original video, the video for which the ASS file
 was composed. For the syntax of this option, check the
@@ -17991,6 +17994,11 @@ To make the subtitles stream from @file{sub.srt} 
appear in 80% transparent blue
 subtitles=sub.srt:force_style='Fontname=DejaVu Serif,PrimaryColour=&HCCFF0000'
 @end example
 
+To re-sync subtitles after seeking the input e.g. with @code{-ss 20:20}, use:
+@example
+subtitles=filename=sub.srt:shift='-20\:20'
+@end example
+
 @section super2xsai
 
 Scale the input by 2x and smooth using the Super2xSaI (Scale and
diff --git a/libavfilter/vf_subtitles.c b/libavfilter/vf_subtitles.c
index 1bd42391e0..125fbd9ac7 100644
--- a/libavfilter/vf_subtitles.c
+++ b/libavfilter/vf_subtitles.c
@@ -52,6 +52,7 @@ typedef struct AssContext {
     char *filename;
     char *fontsdir;
     char *charenc;
+    int64_t shift;
     char *force_style;
     int stream_index;
     int alpha;
@@ -103,6 +104,11 @@ static av_cold int init(AVFilterContext *ctx)
         return AVERROR(EINVAL);
     }
 
+    if (ass->shift != 0) {
+        ass->shift = av_rescale_q(ass->shift, AV_TIME_BASE_Q, av_make_q(1, 
1000));
+        av_log(ctx, AV_LOG_DEBUG, "Shifting subtitles by %0.3fsec.\n", 
ass->shift/1000.0);
+    }
+
     ass->library = ass_library_init();
     if (!ass->library) {
         av_log(ctx, AV_LOG_ERROR, "Could not initialize libass.\n");
@@ -267,6 +273,7 @@ static const AVOption subtitles_options[] = {
     {"stream_index", "set stream index",             OFFSET(stream_index), 
AV_OPT_TYPE_INT,    { .i64 = -1 }, -1,       INT_MAX,  FLAGS},
     {"si",           "set stream index",             OFFSET(stream_index), 
AV_OPT_TYPE_INT,    { .i64 = -1 }, -1,       INT_MAX,  FLAGS},
     {"force_style",  "force subtitle style",         OFFSET(force_style),  
AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS},
+    {"shift",        "shift subtitles timing",       OFFSET(shift),        
AV_OPT_TYPE_DURATION, {.i64 = 0},  INT64_MIN, INT64_MAX, FLAGS },
     {NULL},
 };
 
@@ -297,7 +304,7 @@ AVFILTER_DEFINE_CLASS(subtitles);
 
 static av_cold int init_subtitles(AVFilterContext *ctx)
 {
-    int j, ret, sid;
+    int j, ret, sid, nskip;
     int k = 0;
     AVDictionary *codec_opts = NULL;
     AVFormatContext *fmt = NULL;
@@ -448,6 +455,7 @@ static av_cold int init_subtitles(AVFilterContext *ctx)
     av_init_packet(&pkt);
     pkt.data = NULL;
     pkt.size = 0;
+    nskip = 0;
     while (av_read_frame(fmt, &pkt) >= 0) {
         int i, got_subtitle;
         AVSubtitle sub = {0};
@@ -458,8 +466,17 @@ static av_cold int init_subtitles(AVFilterContext *ctx)
                 av_log(ctx, AV_LOG_WARNING, "Error decoding: %s (ignored)\n",
                        av_err2str(ret));
             } else if (got_subtitle) {
-                const int64_t start_time = av_rescale_q(sub.pts, 
AV_TIME_BASE_Q, av_make_q(1, 1000));
+                const int64_t start_time = av_rescale_q(sub.pts, 
AV_TIME_BASE_Q, av_make_q(1, 1000)) + ass->shift;
                 const int64_t duration   = sub.end_display_time;
+
+                if (start_time + duration < 0) {
+                    nskip++;
+                    goto pkt_end;
+                } else if (nskip > 0) {
+                    av_log(ctx, AV_LOG_INFO, "Skipped %d subtitles out of time 
range.\n", nskip);
+                    nskip = 0;
+                }
+
                 for (i = 0; i < sub.num_rects; i++) {
                     char *ass_line = sub.rects[i]->ass;
                     if (!ass_line)
@@ -472,6 +489,8 @@ static av_cold int init_subtitles(AVFilterContext *ctx)
                 }
             }
         }
+
+pkt_end:
         av_packet_unref(&pkt);
         avsubtitle_free(&sub);
     }
-- 
2.17.1

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".

Reply via email to