[FFmpeg-devel] [PATCH v1 2/2] avfilter/vf_subtitles: Added shift option for subtitles/ass filters.

Manolis Stamatogiannakis mstamat at gmail.com
Wed Jul 21 21:38:07 EEST 2021


Would it be possible to have a quick review for this patch? It is pretty
straightforward.

Plus, this is its second submission. It already includes the requested
changes from the first time (~1y ago).

Thanks in advance,
Manolis


On Sun, 4 Jul 2021 at 18:13, Manolis Stamatogiannakis <mstamat at gmail.com>
wrote:

> 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 <mstamat at gmail.com>
> ---
>  doc/filters.texi           | 11 ++++++++
>  libavfilter/vf_subtitles.c | 55 +++++++++++++++++++++++++++++++++-----
>  2 files changed, 59 insertions(+), 7 deletions(-)
>
> diff --git a/doc/filters.texi b/doc/filters.texi
> index 61c4cfc150..eebf455692 100644
> --- a/doc/filters.texi
> +++ b/doc/filters.texi
> @@ -19474,6 +19474,9 @@ Common @ref{subtitles}/@ref{ass} filter options:
>  @item filename, f
>  Set the filename of the subtitle file to read. It must be specified.
>
> + at 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
> @@ -19487,6 +19490,9 @@ These fonts will be used in addition to whatever
> the font provider uses.
>
>  @item alpha
>  Process alpha channel, by default alpha channel is untouched.
> +
> + at item shift
> +Shift subtitles timings by the specified amount.
>  @end table
>
>  Additional options for @ref{subtitles} filter:
> @@ -19533,6 +19539,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:
> + at example
> +subtitles=filename=sub.srt:shift='-20\:20'
> + at 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 ab32e1b7f3..2c7ce267e1 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;
> @@ -66,11 +67,12 @@ typedef struct AssContext {
>  #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
>
>  #define COMMON_OPTIONS \
> -    {"filename",       "set the filename of file to read",
>          OFFSET(filename),   AV_OPT_TYPE_STRING,     {.str = NULL},  0, 0,
> FLAGS }, \
> -    {"f",              "set the filename of file to read",
>          OFFSET(filename),   AV_OPT_TYPE_STRING,     {.str = NULL},  0, 0,
> FLAGS }, \
> -    {"original_size",  "set the size of the original video (used to scale
> fonts)", OFFSET(original_w), AV_OPT_TYPE_IMAGE_SIZE, {.str = NULL},  0, 0,
> FLAGS }, \
> -    {"fontsdir",       "set the directory containing the fonts to read",
>          OFFSET(fontsdir),   AV_OPT_TYPE_STRING,     {.str = NULL},  0, 0,
> FLAGS }, \
> -    {"alpha",          "enable processing of alpha channel",
>          OFFSET(alpha),      AV_OPT_TYPE_BOOL,       {.i64 = 0   },
>  0,        1, FLAGS }, \
> +    {"filename",       "set the filename of file to read",
>          OFFSET(filename),   AV_OPT_TYPE_STRING,     {.str = NULL},
>  0,         0, FLAGS }, \
> +    {"f",              "set the filename of file to read",
>          OFFSET(filename),   AV_OPT_TYPE_STRING,     {.str = NULL},
>  0,         0, FLAGS }, \
> +    {"original_size",  "set the size of the original video (used to scale
> fonts)", OFFSET(original_w), AV_OPT_TYPE_IMAGE_SIZE, {.str = NULL},
>  0,         0, FLAGS }, \
> +    {"fontsdir",       "set the directory containing the fonts to read",
>          OFFSET(fontsdir),   AV_OPT_TYPE_STRING,     {.str = NULL},
>  0,         0, FLAGS }, \
> +    {"alpha",          "enable processing of alpha channel",
>          OFFSET(alpha),      AV_OPT_TYPE_BOOL,       {.i64 = 0   },
>  0,         1, FLAGS }, \
> +    {"shift",          "shift subtitles timing",
>          OFFSET(shift),      AV_OPT_TYPE_DURATION,   {.i64 = 0   },
> INT64_MIN, INT64_MAX, FLAGS }, \
>
>  /* libass supports a log level ranging from 0 to 7 */
>  static const int ass_libavfilter_log_level_map[] = {
> @@ -103,6 +105,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_INFO, "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");
> @@ -228,6 +235,8 @@ AVFILTER_DEFINE_CLASS(ass);
>
>  static av_cold int init_ass(AVFilterContext *ctx)
>  {
> +    int eid, nskip;
> +    ASS_Event *event;
>      AssContext *ass = ctx->priv;
>      int ret = init(ctx);
>
> @@ -244,6 +253,25 @@ static av_cold int init_ass(AVFilterContext *ctx)
>                 ass->filename);
>          return AVERROR(EINVAL);
>      }
> +
> +    /* Shift subtitles. */
> +    nskip = 0;
> +    for (eid = 0; eid < ass->track->n_events; eid++) {
> +        event = &ass->track->events[eid];
> +        event->Start += ass->shift;
> +        if (event->Start + event->Duration < 0) {
> +            ass_free_event(ass->track, eid);
> +            nskip++;
> +            continue;
> +        } else if (nskip > 0) {
> +            av_log(ctx, AV_LOG_INFO, "Skipped %d subtitles out of time
> range.\n", nskip);
> +            memmove(event - nskip, event, (ass->track->n_events - eid) *
> sizeof(ASS_Event));
> +            ass->track->n_events -= nskip;
> +            eid -= nskip;
> +            nskip = 0;
> +        }
> +    }
> +
>      return 0;
>  }
>
> @@ -298,7 +326,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;
> @@ -449,6 +477,7 @@ static av_cold int init_subtitles(AVFilterContext *ctx)
>          ass_process_codec_private(ass->track,
>                                    dec_ctx->subtitle_header,
>                                    dec_ctx->subtitle_header_size);
> +    nskip = 0;
>      while (av_read_frame(fmt, &pkt) >= 0) {
>          int i, got_subtitle;
>          AVSubtitle sub = {0};
> @@ -459,8 +488,18 @@ 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));
> +                /* Shift subtitles. */
> +                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)
> @@ -470,6 +509,8 @@ static av_cold int init_subtitles(AVFilterContext *ctx)
>                  }
>              }
>          }
> +
> +pkt_end:
>          av_packet_unref(&pkt);
>          avsubtitle_free(&sub);
>      }
> --
> 2.17.1
>
>


More information about the ffmpeg-devel mailing list