[FFmpeg-devel] [PATCH v5 00/25] Subtitle Filtering 2022
Paul B Mahol
onemda at gmail.com
Sat Jul 2 19:39:11 EEST 2022
On Sat, Jun 25, 2022 at 11:58 AM ffmpegagent <ffmpegagent at gmail.com> wrote:
>
> Subtitle Filtering 2022
> =======================
>
> This is a substantial update to the earlier subtitle filtering patch
> series.
> A primary goal has been to address others' concerns as much as possible on
> one side and to provide more clarity and control over the way things are
> working. Clarity is is specifically important to allow for a better
> understanding of the need for a subtitle start pts value that can be
> different from the frame's pts value. This is done by refactoring the
> subtitle timing fields in AVFrame, adding a frame field to indicate
> repeated
> subtitle frames, and finally the full removal of the heartbeat
> functionality, replaced by a new 'subfeed' filter that provides different
> modes for arbitrating subtitle frames in a filter graph. Finally, each
> subtitle filter's documentation has been amended by a section describing
> the
> filter's timeline behavior (in v3 update).
>
>
> Subtitle Filtering Demos
> ========================
>
> I published a demonstration of subtitle filtering capabilities with OCR,
> text and bitmap subtitle manipulation involved: Demo 1: Text-Manipulation
> with Bitmap Subtitles
> [https://github.com/softworkz/SubtitleFilteringDemos/tree/master/Demo1]
>
>
> v5 - Conversion to Graphic Subtitles, and other enhancements
> ============================================================
>
> * I'm glad to announce that Traian (@tcoza) has joined the project and
> contributed a new 'text2graphicsub' filter to convert text subtitles to
> graphic subtitles, which can in turn be encoded as dvd, dvb or x-subs
> (and any other encoder for graphic subs that might be added in the
> future). This filter closes the last open "gap" in subtitle processing.
> * stripstyles filter: now allows very fine-grained control over which ASS
> style codes should be preserved or stripped
> * stripstyles: do not drop dialog margin values
> * subfeed filter: eliminates duplicate frames with duplicate start times
> when 'fix_overlap' is specified
> * textmod: do not drop effect values
> * graphicsub2text: reduce font size jitter
> * ass_split: add function to selectively preserve elements when splitting
> * add strim, snull and ssink and further unify subtitle frame handling
> with
> audio and video
> * ffmpeg_filter: get simple filter notation working for subtitles
>
>
> v4 - Quality Improvements
> =========================
>
> * finally an updated version
> * includes many improvements from internal testing
> * all FATE tests passed
> * all example commands from the docs verified to work
> * can't list all the detail changes..
> * I have left out the extra commits which can be handled separately, just
> in case somebody wonders why these are missing:
> * avcodec/webvttenc: Don't encode drawing codes and empty lines
> * avcodec/webvttenc: convert hard-space tags to
> * avutil/ass_split: Add parsing of hard-space tags (\h)
> * avutil/ass_split: Treat all content in curly braces as hidden
> * avutil/ass_split: Fix ass parsing of style codes with comments
>
>
> v3 - Rebase
> ===========
>
> due to merge conflicts - apologies.
>
>
> Changes in v2
> =============
>
> * added .gitattributes file to enforce binary diffs for the test refs that
> cannot be applied when being sent via e-mail
> * perform filter graph re-init due to subtitle "frame size" change only
> when the size was unknown before and not set via -canvas_size
> * overlaytextsubs: Make sure to request frames on the subtitle input
> * avfilter/splitcc: Start parsing cc data on key frames only
> * avcodec/webvttenc: Don't encode ass drawing codes and empty lines
> * stripstyles: fix mem leak
> * gs2t: improve color detection
> * gs2t: empty frames must not be skipped
> * subfeed: fix name
> * textmod: preserve margins
> * added .gitattributes file to enforce binary diffs for the test refs that
> cannot be applied when being sent via e-mail
> * perform filter graph re-init due to subtitle "frame size" change only
> when the size was unknown before and not set via -canvas_size
> * avcodec/dvbsubdec: Fix conditions for fallback to default resolution
> * Made changes suggested by Andreas
> * Fixed failing command line reported by Michael
>
> Changes from previous version v24:
>
>
> AVFrame
> =======
>
> * Removed sub_start_time The start time is now added to the subtitle
> start_pts during decoding The sub_end_time field is adjusted accordingly
> * Renamed sub_end_time to duration which it is effectively after removing
> the start_time
> * Added a sub-struct 'subtitle_timing' to av frame Contains subtitle_pts
> renamed to 'subtitle_timing.start_pts' and 'subtitle_timing.duration'
> * Change both fields to (fixed) time_base AV_TIMEBASE
> * add repeat_sub field provides a clear indication whether a subtitle
> frame
> is an actual subtitle event or a repeated subtitle frame in a filter
> graph
>
>
> Heartbeat Removal
> =================
>
> * completely removed the earlier heartbeat implementation
> * filtering arbitration is now implemented in a new filter: 'subfeed'
> * subfeed will be auto-inserted for compatiblity with sub2video command
> lines
> * the new behavior is not exactly identical to the earlier behavior, but
> it
> basically allows to achieve the same results
> * there's a small remainder, now named subtitle kickoff which serves to
> get
> things (in the filter graph) going right from the start
>
>
> New 'subfeed' Filter
> ====================
>
> * a versatile filter for solving all kinds of problems with subtile frame
> flow in filter graphs
> * Can be inserted at any position in a graph
> * Auto-inserted for sub2video command lines (in repeat-mode)
> * Allows duration fixup delay input frames with unknown duration and infer
> duration from start of subsequent frame
> * Provides multiple modes of operation:
> * repeat mode (default) Queues input frames Outputs frames at a fixed
> (configurable) rate Either sends a matching input frame (repeatedly)
> or
> empty frames otherwise
> * scatter mode similar to repeat mode, but splits input frames by
> duration into small segments with same content
> * forward mode No fixed output rate Useful in combination with duration
> fixup or overlap fixup
>
>
> ffmpeg Tool Changes
> ===================
>
> * delay subtitle output stream initialization (like for audio and video)
> This is needed for example when a format header depends on having
> received an initial frame to derive certain header values from
> * decoding: set subtitle frame size from decoding context
> * re-init graph when subtitle size changes
> * always insert subscale filter for sub2video command lines (to ensure
> correct scaling)
>
>
> Subtitle Encoding
> =================
>
> * ignore repeated frames for encoding based on repeat_sub field in AVFrame
> * support multi-area encoding for text subtitles Subtitle OCR can create
> multiple areas at different positions. Previously, the texts were always
> squashed into a single area ('subtitle rect'), which was not ideal.
> Multiple text areas are now generally supported:
> * ASS Encoder Changed to use the 'receive_packet' encoding API A single
> frame with multiple text areas will create multiple packets now
> * All other text subtitle encoders A newline is inserted between the
> text
> from multiple areas
>
>
> graphicsub2text (OCR)
> =====================
>
> * enhanced preprocessing
> * using elbg algorithm for color quantization
> * detection and removal of text outlines
> * map-based identification of colors per word (text, outline,
> background)
> * add option for duration fixup
> * add option to dump preprocessing bitmaps
> * Recognize formatting and apply as ASS inline styles
> * per word(!)
> * paragraph alignment
> * positioning
> * font names
> * font size
> * font style (italic, underline, bold)
> * text color, outline color
>
>
> Other Filter Changes
> ====================
>
> * all: Make sure to forward all link properties (time base, frame rate, w,
> h) where appropriate
> * overlaytextsubs: request frames on the subtitle input
> * overlaytextsubs: disable read-order checking
> * overlaytextsubs: improve implementation of render_latest_only
> * overlaytextsubs: ensure equal in/out video formats
> * splitcc: derive framerate from realtime_latency
> * graphicsub2video: implement caching of converted frames
> * graphicsub2video: use 1x1 output frame size as long as subtitle size is
> unknown (0x0)
>
> Plus a dozen of things I forgot..
>
> softworkz (24):
> avcodec,avutil: Move enum AVSubtitleType to avutil, add new and
> deprecate old values
> avutil/frame: Prepare AVFrame for subtitle handling
> avcodec/subtitles: Introduce new frame-based subtitle decoding API
> avcodec/libzvbi: set subtitle type
> avfilter/subtitles: Update vf_subtitles to use new decoding api
> avcodec,avutil: Move ass helper functions to avutil as avpriv_ and
> extend ass dialog parsing
> avcodec/subtitles: Replace deprecated enum values
> fftools/play,probe: Adjust for subtitle changes
> avfilter/subtitles: Add subtitles.c for subtitle frame allocation
> avfilter/avfilter: Handle subtitle frames
> avfilter/avfilter: Fix hardcoded input index
> avfilter/sbuffer: Add sbuffersrc and sbuffersink filters
> avfilter/overlaygraphicsubs: Add overlaygraphicsubs and
> graphicsub2video filters
> avfilter/overlaytextsubs: Add overlaytextsubs and textsubs2video
> filters
> avfilter/textmod: Add textmod, censor and show_speaker filters
> avfilter/stripstyles: Add stripstyles filter
> avfilter/splitcc: Add splitcc filter for closed caption handling
> avfilter/graphicsub2text: Add new graphicsub2text filter (OCR)
> avfilter/subscale: Add filter for scaling and/or re-arranging
> graphical subtitles
> avfilter/subfeed: add subtitle feed filter
> avfilter/snull,strim: Add snull and strim filters
> avcodec/subtitles: Migrate subtitle encoders to frame-based API
> fftools/ffmpeg: Introduce subtitle filtering and new frame-based
> subtitle encoding
> avcodec/dvbsubdec: Fix conditions for fallback to default resolution
>
>
Can this be properly finally be fully reviewed and accepted?
Otherwise if its kept mainly ignored than it should be regarded as spam.
Current status quo is bad.
> tcoza (1):
> avfilter/text2graphicsub: Added text2graphicsub subtitle filter
>
> configure | 10 +-
> doc/filters.texi | 807 ++++++++++++++
> fftools/ffmpeg.c | 613 +++++-----
> fftools/ffmpeg.h | 17 +-
> fftools/ffmpeg_filter.c | 270 +++--
> fftools/ffmpeg_hw.c | 2 +-
> fftools/ffmpeg_opt.c | 28 +-
> fftools/ffplay.c | 102 +-
> fftools/ffprobe.c | 47 +-
> libavcodec/Makefile | 56 +-
> libavcodec/ass.h | 151 +--
> libavcodec/ass_split.h | 191 ----
> libavcodec/assdec.c | 4 +-
> libavcodec/assenc.c | 191 +++-
> libavcodec/avcodec.c | 8 +
> libavcodec/avcodec.h | 34 +-
> libavcodec/ccaption_dec.c | 20 +-
> libavcodec/codec_internal.h | 12 -
> libavcodec/decode.c | 60 +-
> libavcodec/dvbsubdec.c | 53 +-
> libavcodec/dvbsubenc.c | 96 +-
> libavcodec/dvdsubdec.c | 2 +-
> libavcodec/dvdsubenc.c | 102 +-
> libavcodec/encode.c | 61 +-
> libavcodec/internal.h | 16 +
> libavcodec/jacosubdec.c | 2 +-
> libavcodec/libaribb24.c | 2 +-
> libavcodec/libzvbi-teletextdec.c | 17 +-
> libavcodec/microdvddec.c | 7 +-
> libavcodec/movtextdec.c | 3 +-
> libavcodec/movtextenc.c | 126 ++-
> libavcodec/mpl2dec.c | 2 +-
> libavcodec/pgssubdec.c | 2 +-
> libavcodec/realtextdec.c | 2 +-
> libavcodec/samidec.c | 2 +-
> libavcodec/srtdec.c | 2 +-
> libavcodec/srtenc.c | 116 +-
> libavcodec/subviewerdec.c | 2 +-
> libavcodec/tests/avcodec.c | 5 +-
> libavcodec/textdec.c | 4 +-
> libavcodec/ttmlenc.c | 114 +-
> libavcodec/utils.c | 185 ++-
> libavcodec/webvttdec.c | 2 +-
> libavcodec/webvttenc.c | 94 +-
> libavcodec/xsubdec.c | 2 +-
> libavcodec/xsubenc.c | 88 +-
> libavfilter/Makefile | 18 +
> libavfilter/allfilters.c | 19 +
> libavfilter/avfilter.c | 34 +-
> libavfilter/avfilter.h | 11 +
> libavfilter/avfiltergraph.c | 5 +
> libavfilter/buffersink.c | 54 +
> libavfilter/buffersink.h | 7 +
> libavfilter/buffersrc.c | 72 ++
> libavfilter/buffersrc.h | 1 +
> libavfilter/formats.c | 16 +
> libavfilter/formats.h | 3 +
> libavfilter/internal.h | 19 +-
> libavfilter/sf_graphicsub2text.c | 1137 +++++++++++++++++++
> libavfilter/sf_snull.c | 50 +
> libavfilter/sf_splitcc.c | 395 +++++++
> libavfilter/sf_stripstyles.c | 237 ++++
> libavfilter/sf_subfeed.c | 412 +++++++
> libavfilter/sf_subscale.c | 884 +++++++++++++++
> libavfilter/sf_text2graphicsub.c | 630 +++++++++++
> libavfilter/sf_textmod.c | 710 ++++++++++++
> libavfilter/subtitles.c | 63 ++
> libavfilter/subtitles.h | 44 +
> libavfilter/trim.c | 46 +-
> libavfilter/vf_overlaygraphicsubs.c | 765 +++++++++++++
> libavfilter/vf_overlaytextsubs.c | 680 +++++++++++
> libavfilter/vf_subtitles.c | 67 +-
> libavutil/Makefile | 4 +
> {libavcodec => libavutil}/ass.c | 115 +-
> libavutil/ass_internal.h | 135 +++
> {libavcodec => libavutil}/ass_split.c | 179 ++-
> libavutil/ass_split_internal.h | 254 +++++
> libavutil/frame.c | 206 +++-
> libavutil/frame.h | 85 +-
> libavutil/subfmt.c | 45 +
> libavutil/subfmt.h | 115 ++
> libavutil/version.h | 1 +
> tests/ref/fate/filter-overlay-dvdsub-2397 | 182 +--
> tests/ref/fate/sub-dvb | 162 +--
> tests/ref/fate/sub-scc | 1 -
> tests/ref/fate/sub2video | 1091 +++++++++++++++++-
> tests/ref/fate/sub2video_basic | 1238 +++++++++++++++++++--
> tests/ref/fate/sub2video_time_limited | 78 +-
> 88 files changed, 12398 insertions(+), 1604 deletions(-)
> delete mode 100644 libavcodec/ass_split.h
> create mode 100644 libavfilter/sf_graphicsub2text.c
> create mode 100644 libavfilter/sf_snull.c
> create mode 100644 libavfilter/sf_splitcc.c
> create mode 100644 libavfilter/sf_stripstyles.c
> create mode 100644 libavfilter/sf_subfeed.c
> create mode 100644 libavfilter/sf_subscale.c
> create mode 100644 libavfilter/sf_text2graphicsub.c
> create mode 100644 libavfilter/sf_textmod.c
> create mode 100644 libavfilter/subtitles.c
> create mode 100644 libavfilter/subtitles.h
> create mode 100644 libavfilter/vf_overlaygraphicsubs.c
> create mode 100644 libavfilter/vf_overlaytextsubs.c
> rename {libavcodec => libavutil}/ass.c (59%)
> create mode 100644 libavutil/ass_internal.h
> rename {libavcodec => libavutil}/ass_split.c (71%)
> create mode 100644 libavutil/ass_split_internal.h
> create mode 100644 libavutil/subfmt.c
> create mode 100644 libavutil/subfmt.h
>
>
> base-commit: 6a82412bf33108111eb3f63076fd5a51349ae114
> Published-As:
> https://github.com/ffstaging/FFmpeg/releases/tag/pr-ffstaging-18%2Fsoftworkz%2Fsubmit_subfiltering-v5
> Fetch-It-Via
> <https://github.com/ffstaging/FFmpeg/releases/tag/pr-ffstaging-18%2Fsoftworkz%2Fsubmit_subfiltering-v5Fetch-It-Via>:
> git fetch https://github.com/ffstaging/FFmpeg
> pr-ffstaging-18/softworkz/submit_subfiltering-v5
> Pull-Request: https://github.com/ffstaging/FFmpeg/pull/18
>
> Range-diff vs v4:
>
> 1: 2f3ba171f5 = 1: aa32b9048f avcodec,avutil: Move enum
> AVSubtitleType to avutil, add new and deprecate old values
> 2: ff101f8a76 ! 2: d5ab9d1919 avutil/frame: Prepare AVFrame for
> subtitle handling
> @@ libavutil/frame.c: FF_ENABLE_DEPRECATION_WARNINGS
> + case AVMEDIA_TYPE_VIDEO:
> return frame_copy_video(dst, src);
> - else if (dst->nb_samples > 0 &&
> -- (av_channel_layout_check(&dst->ch_layout)
> --#if FF_API_OLD_CHANNEL_LAYOUT
> -- || dst->channel_layout || dst->channels
> --#endif
> -- ))
> + case AVMEDIA_TYPE_AUDIO:
> - return frame_copy_audio(dst, src);
> ++ if (dst->nb_samples > 0 &&
> + (av_channel_layout_check(&dst->ch_layout)
> + #if FF_API_OLD_CHANNEL_LAYOUT
> + || dst->channels > 0
> + #endif
> + ))
> +- return frame_copy_audio(dst, src);
> -FF_ENABLE_DEPRECATION_WARNINGS
> --
> -- return AVERROR(EINVAL);
> ++ return frame_copy_audio(dst, src);
> ++ break;
> + case AVMEDIA_TYPE_SUBTITLE:
> + return frame_copy_subtitles(dst, src, 1);
> -+ default:
> -+ return AVERROR(EINVAL);
> + }
> - }
>
> - void av_frame_remove_side_data(AVFrame *frame, enum
> AVFrameSideDataType type)
> + return AVERROR(EINVAL);
> + }
>
> ## libavutil/frame.h ##
> @@
> 3: b8935d5e68 = 3: 0a685a6b19 avcodec/subtitles: Introduce new
> frame-based subtitle decoding API
> 4: 4b44732e07 = 4: 0b69b1ce19 avcodec/libzvbi: set subtitle type
> 5: 8faa7a4043 = 5: 0c2091e57c avfilter/subtitles: Update vf_subtitles
> to use new decoding api
> 6: 1664026d7c ! 6: 4903cdd1cd avcodec,avutil: Move ass helper
> functions to avutil as avpriv_ and extend ass dialog parsing
> @@ Commit message
>
> - hard_space callback (for upcoming fix)
> - extensible callback (for future extension)
> + - new API which allows tag filtering
>
> Signed-off-by: softworkz <softworkz at hotmail.com>
>
> @@ libavcodec/ass.h
> - const char *linebreaks, int
> keep_ass_markup);
> #endif /* AVCODEC_ASS_H */
>
> + ## libavcodec/ass_split.h (deleted) ##
> +@@
> +-/*
> +- * SSA/ASS spliting functions
> +- * Copyright (c) 2010 Aurelien Jacobs <aurel at gnuage.org>
> +- *
> +- * This file is part of FFmpeg.
> +- *
> +- * FFmpeg is free software; you can redistribute it and/or
> +- * modify it under the terms of the GNU Lesser General Public
> +- * License as published by the Free Software Foundation; either
> +- * version 2.1 of the License, or (at your option) any later
> version.
> +- *
> +- * FFmpeg is distributed in the hope that it will be useful,
> +- * but WITHOUT ANY WARRANTY; without even the implied warranty of
> +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> +- * Lesser General Public License for more details.
> +- *
> +- * You should have received a copy of the GNU Lesser General Public
> +- * License along with FFmpeg; if not, write to the Free Software
> +- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
> 02110-1301 USA
> +- */
> +-
> +-#ifndef AVCODEC_ASS_SPLIT_H
> +-#define AVCODEC_ASS_SPLIT_H
> +-
> +-/**
> +- * fields extracted from the [Script Info] section
> +- */
> +-typedef struct {
> +- char *script_type; /**< SSA script format version (eg.
> v4.00) */
> +- char *collisions; /**< how subtitles are moved to prevent
> collisions */
> +- int play_res_x; /**< video width that ASS coords are
> referring to */
> +- int play_res_y; /**< video height that ASS coords are
> referring to */
> +- float timer; /**< time multiplier to apply to SSA
> clock (in %) */
> +-} ASSScriptInfo;
> +-
> +-/**
> +- * fields extracted from the [V4(+) Styles] section
> +- */
> +-typedef struct {
> +- char *name; /**< name of the tyle (case sensitive) */
> +- char *font_name; /**< font face (case sensitive) */
> +- int font_size; /**< font height */
> +- int primary_color; /**< color that a subtitle will normally
> appear in */
> +- int secondary_color;
> +- int outline_color; /**< color for outline in ASS, called
> tertiary in SSA */
> +- int back_color; /**< color of the subtitle outline or
> shadow */
> +- int bold; /**< whether text is bold (1) or not (0)
> */
> +- int italic; /**< whether text is italic (1) or not
> (0) */
> +- int underline; /**< whether text is underlined (1) or
> not (0) */
> +- int strikeout;
> +- float scalex;
> +- float scaley;
> +- float spacing;
> +- float angle;
> +- int border_style;
> +- float outline;
> +- float shadow;
> +- int alignment; /**< position of the text (left, center,
> top...),
> +- defined after the layout of the
> numpad
> +- (1-3 sub, 4-6 mid, 7-9 top) */
> +- int margin_l;
> +- int margin_r;
> +- int margin_v;
> +- int alpha_level;
> +- int encoding;
> +-} ASSStyle;
> +-
> +-/**
> +- * fields extracted from the [Events] section
> +- */
> +-typedef struct {
> +- int readorder;
> +- int layer; /**< higher numbered layers are drawn over
> lower numbered */
> +- int start; /**< start time of the dialog in centiseconds */
> +- int end; /**< end time of the dialog in centiseconds */
> +- char *style; /**< name of the ASSStyle to use with this
> dialog */
> +- char *name;
> +- int margin_l;
> +- int margin_r;
> +- int margin_v;
> +- char *effect;
> +- char *text; /**< actual text which will be displayed as a
> subtitle,
> +- can include style override control codes
> (see
> +- ff_ass_split_override_codes()) */
> +-} ASSDialog;
> +-
> +-/**
> +- * structure containing the whole split ASS data
> +- */
> +-typedef struct {
> +- ASSScriptInfo script_info; /**< general information about the
> SSA script*/
> +- ASSStyle *styles; /**< array of split out styles */
> +- int styles_count; /**< number of ASSStyle in the
> styles array */
> +- ASSDialog *dialogs; /**< array of split out dialogs */
> +- int dialogs_count; /**< number of ASSDialog in the
> dialogs array*/
> +-} ASS;
> +-
> +-/**
> +- * This struct can be casted to ASS to access to the split data.
> +- */
> +-typedef struct ASSSplitContext ASSSplitContext;
> +-
> +-/**
> +- * Split a full ASS file or a ASS header from a string buffer and
> store
> +- * the split structure in a newly allocated context.
> +- *
> +- * @param buf String containing the ASS formatted data.
> +- * @return Newly allocated struct containing split data.
> +- */
> +-ASSSplitContext *ff_ass_split(const char *buf);
> +-
> +-/**
> +- * Free a dialogue obtained from ff_ass_split_dialog().
> +- */
> +-void ff_ass_free_dialog(ASSDialog **dialogp);
> +-
> +-/**
> +- * Split one ASS Dialogue line from a string buffer.
> +- *
> +- * @param ctx Context previously initialized by ff_ass_split().
> +- * @param buf String containing the ASS "Dialogue" line.
> +- * @return Pointer to the split ASSDialog. Must be freed with
> ff_ass_free_dialog()
> +- */
> +-ASSDialog *ff_ass_split_dialog(ASSSplitContext *ctx, const char
> *buf);
> +-
> +-/**
> +- * Free all the memory allocated for an ASSSplitContext.
> +- *
> +- * @param ctx Context previously initialized by ff_ass_split().
> +- */
> +-void ff_ass_split_free(ASSSplitContext *ctx);
> +-
> +-
> +-/**
> +- * Set of callback functions corresponding to each override codes
> that can
> +- * be encountered in a "Dialogue" Text field.
> +- */
> +-typedef struct {
> +- /**
> +- * @defgroup ass_styles ASS styles
> +- * @{
> +- */
> +- void (*text)(void *priv, const char *text, int len);
> +- void (*new_line)(void *priv, int forced);
> +- void (*style)(void *priv, char style, int close);
> +- void (*color)(void *priv, unsigned int /* color */, unsigned
> int color_id);
> +- void (*alpha)(void *priv, int alpha, int alpha_id);
> +- void (*font_name)(void *priv, const char *name);
> +- void (*font_size)(void *priv, int size);
> +- void (*alignment)(void *priv, int alignment);
> +- void (*cancel_overrides)(void *priv, const char *style);
> +- /** @} */
> +-
> +- /**
> +- * @defgroup ass_functions ASS functions
> +- * @{
> +- */
> +- void (*move)(void *priv, int x1, int y1, int x2, int y2, int
> t1, int t2);
> +- void (*origin)(void *priv, int x, int y);
> +- /** @} */
> +-
> +- /**
> +- * @defgroup ass_end end of Dialogue Event
> +- * @{
> +- */
> +- void (*end)(void *priv);
> +- /** @} */
> +-} ASSCodesCallbacks;
> +-
> +-/**
> +- * Split override codes out of a ASS "Dialogue" Text field.
> +- *
> +- * @param callbacks Set of callback functions called for each
> override code
> +- * encountered.
> +- * @param priv Opaque pointer passed to the callback functions.
> +- * @param buf The ASS "Dialogue" Text field to split.
> +- * @return >= 0 on success otherwise an error code <0
> +- */
> +-int ff_ass_split_override_codes(const ASSCodesCallbacks *callbacks,
> void *priv,
> +- const char *buf);
> +-
> +-/**
> +- * Find an ASSStyle structure by its name.
> +- *
> +- * @param ctx Context previously initialized by ff_ass_split().
> +- * @param style name of the style to search for.
> +- * @return the ASSStyle corresponding to style, or NULL if style
> can't be found
> +- */
> +-ASSStyle *ff_ass_style_get(ASSSplitContext *ctx, const char *style);
> +-
> +-#endif /* AVCODEC_ASS_SPLIT_H */
> +
> ## libavcodec/assdec.c ##
> @@
> #include <string.h>
> @@ libavutil/ass.c: char *ff_ass_get_dialog(int readorder, int layer,
> const char *s
> - const char *speaker)
> +char *avpriv_ass_get_dialog_ex(int readorder, int layer, const char
> *style,
> + const char *speaker, int margin_l, int
> margin_r,
> -+ int margin_v, const char *text)
> ++ int margin_v, const char *effect, const
> char *text)
> {
> - return ff_ass_add_rect2(sub, dialog, readorder, layer, style,
> speaker, NULL);
> -}
> @@ libavutil/ass.c: char *ff_ass_get_dialog(int readorder, int layer,
> const char *s
> - FFASSDecoderContext *s = avctx->priv_data;
> - if (!(avctx->flags2 & AV_CODEC_FLAG2_RO_FLUSH_NOOP))
> - s->readorder = 0;
> -+ return av_asprintf("%d,%d,%s,%s,%d,%d,%d,,%s",
> ++ return av_asprintf("%d,%d,%s,%s,%d,%d,%d,%s,%s",
> + readorder, layer, style ? style : "Default",
> + speaker ? speaker : "", margin_l, margin_r,
> -+ margin_v, text);
> ++ margin_v, effect ? effect : "", text);
> }
>
> -void ff_ass_bprint_text_event(AVBPrint *buf, const char *p, int
> size,
> @@ libavutil/ass_internal.h (new)
> + */
> +char *avpriv_ass_get_dialog_ex(int readorder, int layer, const char
> *style,
> + const char *speaker, int margin_l, int
> margin_r,
> -+ int margin_v, const char *text);
> ++ int margin_v, const char *effect, const
> char *text);
> +
> +/**
> + * Escape a text subtitle using ASS syntax into an AVBPrint buffer.
> @@ libavutil/ass_split.c: ASSDialog
> *ff_ass_split_dialog(ASSSplitContext *ctx, cons
> if (ctx) {
> int i;
> @@ libavutil/ass_split.c: void ff_ass_split_free(ASSSplitContext
> *ctx)
> + }
> }
>
> ++static int ass_remove_empty_braces(AVBPrint* buffer)
> ++{
> ++ char* tmp;
> ++ int ret = 0, n = 0;
>
> -int ff_ass_split_override_codes(const ASSCodesCallbacks *callbacks,
> void *priv,
> -+int avpriv_ass_split_override_codes(const ASSCodesCallbacks
> *callbacks, void *priv,
> - const char *buf)
> +- const char *buf)
> ++ if (buffer == NULL || buffer->len == 0 ||
> !av_bprint_is_complete(buffer))
> ++ return 0;
> ++
> ++ ret = av_bprint_finalize(buffer, &tmp);
> ++ if (ret)
> ++ return ret;
> ++
> ++ for (unsigned i = 0; i < buffer->len; i++) {
> ++ if (tmp[i] == '{' && tmp[i+1] == '}')
> ++ i++;
> ++ else
> ++ tmp[n++] = tmp[i];
> ++ }
> ++
> ++ tmp[n++] = '\0';
> ++
> ++ av_bprint_init(buffer, n, n);
> ++ av_bprint_append_data(buffer, tmp, n - 1);
> ++ av_free(tmp);
> ++
> ++ return ret;
> ++}
> ++
> ++static void ass_write_filtered_line(AVBPrint* buffer, const char
> *buf, int len, enum ASSSplitComponents keep_flags, enum ASSSplitComponents
> split_component)
> ++{
> ++ if (buffer == NULL || buf == NULL || len == 0)
> ++ return;
> ++
> ++ if (split_component != ASS_SPLIT_ANY && !(keep_flags &
> split_component))
> ++ return;
> ++
> ++
> ++ av_bprint_append_data(buffer, buf, len - 1);
> ++}
> ++
> ++int avpriv_ass_filter_override_codes(const ASSCodesCallbacks
> *callbacks, void *priv, const char *buf, AVBPrint* outbuffer, enum
> ASSSplitComponents keep_flags)
> {
> const char *text = NULL;
> -@@ libavutil/ass_split.c: int ff_ass_split_override_codes(const
> ASSCodesCallbacks *callbacks, void *priv,
> + char new_line[2];
> +- int text_len = 0;
> ++ int text_len = 0, ret = 0;
> +
> + while (buf && *buf) {
> +- if (text && callbacks->text &&
> +- (sscanf(buf, "\\%1[nN]", new_line) == 1 ||
> +- !strncmp(buf, "{\\", 2))) {
> +- callbacks->text(priv, text, text_len);
> ++
> ++ if (text && (sscanf(buf, "\\%1[nN]", new_line) == 1 ||
> !strncmp(buf, "{\\", 2))) {
> ++ ass_write_filtered_line(outbuffer, text, text_len + 1,
> keep_flags, ASS_SPLIT_TEXT | ASS_SPLIT_TEXT2);
> ++
> ++ if (callbacks->text)
> ++ callbacks->text(priv, text, text_len);
> + text = NULL;
> + }
> ++
> + if (sscanf(buf, "\\%1[nN]", new_line) == 1) {
> + if (callbacks->new_line)
> + callbacks->new_line(priv, new_line[0] == 'N');
> ++ ass_write_filtered_line(outbuffer, buf, 3, keep_flags,
> ASS_SPLIT_ANY);
> + buf += 2;
> + } else if (!strncmp(buf, "{\\", 2)) {
> ++ ass_write_filtered_line(outbuffer, buf, 2, keep_flags,
> ASS_SPLIT_ANY);
> + buf++;
> while (*buf == '\\') {
> - char style[2], c[2], sep[2], c_num[2] = "0",
> tmp[128] = {0};
> +- char style[2], c[2], sep[2], c_num[2] = "0",
> tmp[128] = {0};
> ++ char style[4], c[2], axis[3], sep[3], c_num[2] =
> "0", tmp[128] = {0};
> unsigned int color = 0xFFFFFFFF;
> - int len, size = -1, an = -1, alpha = -1;
> - int x1, y1, x2, y2, t1 = -1, t2 = -1;
> + int len, size = -1, an = -1, alpha = -1, scale = 0;
> -+ int x1, y1, x2, y2, t1 = -1, t2 = -1, accel = 1;
> ++ float f1 = 1;
> ++ int x1, y1, x2, y2, x3, t1 = -1, t2 = -1, t3 = -1,
> t4 = -1, accel = 1;
> if (sscanf(buf, "\\%1[bisu]%1[01\\}]%n", style, c,
> &len) > 1) {
> int close = c[0] == '0' ? 1 : c[0] == '1' ? 0 :
> -1;
> len += close != -1;
> -@@ libavutil/ass_split.c: int ff_ass_split_override_codes(const
> ASSCodesCallbacks *callbacks, void *priv,
> ++ switch (c[0]) {
> ++ case 'b':
> ++ ass_write_filtered_line(outbuffer, buf,
> len, keep_flags, ASS_SPLIT_FONT_BOLD);
> ++ break;
> ++ case 'u':
> ++ ass_write_filtered_line(outbuffer, buf,
> len, keep_flags, ASS_SPLIT_FONT_UNDERLINE);
> ++ break;
> ++ case 'i':
> ++ ass_write_filtered_line(outbuffer, buf,
> len, keep_flags, ASS_SPLIT_FONT_ITALIC);
> ++ break;
> ++ case 'a':
> ++ ass_write_filtered_line(outbuffer, buf,
> len, keep_flags, ASS_SPLIT_FONT_STRIKEOUT);
> ++ break;
> ++ }
> + if (callbacks->style)
> + callbacks->style(priv, style[0], close);
> + } else if (sscanf(buf, "\\c%1[\\}]%n", sep, &len) >
> 0 ||
> + sscanf(buf, "\\c&H%X&%1[\\}]%n", &color,
> sep, &len) > 1 ||
> + sscanf(buf, "\\%1[1234]c%1[\\}]%n",
> c_num, sep, &len) > 1 ||
> + sscanf(buf, "\\%1[1234]c&H%X&%1[\\}]%n",
> c_num, &color, sep, &len) > 2) {
> ++ ass_write_filtered_line(outbuffer, buf, len,
> keep_flags, ASS_SPLIT_COLOR);
> + if (callbacks->color)
> + callbacks->color(priv, color, c_num[0] -
> '0');
> + } else if (sscanf(buf, "\\alpha%1[\\}]%n", sep,
> &len) > 0 ||
> + sscanf(buf, "\\alpha&H%2X&%1[\\}]%n",
> &alpha, sep, &len) > 1 ||
> + sscanf(buf, "\\%1[1234]a%1[\\}]%n",
> c_num, sep, &len) > 1 ||
> + sscanf(buf,
> "\\%1[1234]a&H%2X&%1[\\}]%n", c_num, &alpha, sep, &len) > 2) {
> ++ ass_write_filtered_line(outbuffer, buf, len,
> keep_flags, ASS_SPLIT_ALPHA);
> + if (callbacks->alpha)
> + callbacks->alpha(priv, alpha, c_num[0] -
> '0');
> + } else if (sscanf(buf, "\\fn%1[\\}]%n", sep, &len)
> > 0 ||
> + sscanf(buf, "\\fn%127[^\\}]%1[\\}]%n",
> tmp, sep, &len) > 1) {
> ++ ass_write_filtered_line(outbuffer, buf, len,
> keep_flags, ASS_SPLIT_FONT_NAME);
> + if (callbacks->font_name)
> + callbacks->font_name(priv, tmp[0] ? tmp :
> NULL);
> + } else if (sscanf(buf, "\\fs%1[\\}]%n", sep, &len)
> > 0 ||
> + sscanf(buf, "\\fs%u%1[\\}]%n", &size,
> sep, &len) > 1) {
> ++ ass_write_filtered_line(outbuffer, buf, len,
> keep_flags, ASS_SPLIT_FONT_SIZE);
> + if (callbacks->font_size)
> + callbacks->font_size(priv, size);
> ++ } else if (sscanf(buf, "\\fscx%1[\\}]%n", sep,
> &len) > 0 ||
> ++ sscanf(buf, "\\fscx%f%1[\\}]%n", &f1,
> sep, &len) > 1) {
> ++ ass_write_filtered_line(outbuffer, buf, len,
> keep_flags, ASS_SPLIT_FONT_SCALE);
> ++ } else if (sscanf(buf, "\\fscy%1[\\}]%n", sep,
> &len) > 0 ||
> ++ sscanf(buf, "\\fscy%f%1[\\}]%n", &f1,
> sep, &len) > 1) {
> ++ ass_write_filtered_line(outbuffer, buf, len,
> keep_flags, ASS_SPLIT_FONT_SCALE);
> ++ } else if (sscanf(buf, "\\fsp%1[\\}]%n", sep, &len)
> > 0 ||
> ++ sscanf(buf, "\\fsp%u%1[\\}]%n", &size,
> sep, &len) > 1) {
> ++ ass_write_filtered_line(outbuffer, buf, len,
> keep_flags, ASS_SPLIT_FONT_SPACING);
> ++ } else if (sscanf(buf, "\\fe%1[\\}]%n", sep, &len)
> > 0 ||
> ++ sscanf(buf, "\\fe%u%1[\\}]%n", &size,
> sep, &len) > 1) {
> ++ ass_write_filtered_line(outbuffer, buf, len,
> keep_flags, ASS_SPLIT_FONT_CHARSET);
> ++ } else if (sscanf(buf, "\\bord%1[\\}]%n", sep,
> &len) > 0 ||
> ++ sscanf(buf, "\\bord%u%1[\\}]%n", &size,
> sep, &len) > 1) {
> ++ ass_write_filtered_line(outbuffer, buf, len,
> keep_flags, ASS_SPLIT_TEXT_BORDER);
> ++ } else if (sscanf(buf, "\\shad%1[\\}]%n", sep,
> &len) > 0 ||
> ++ sscanf(buf, "\\shad%u%1[\\}]%n", &size,
> sep, &len) > 1) {
> ++ ass_write_filtered_line(outbuffer, buf, len,
> keep_flags, ASS_SPLIT_TEXT_SHADOW);
> ++ } else if (sscanf(buf, "\\fr%1[\\}]%n", sep, &len)
> > 0 ||
> ++ sscanf(buf, "\\fr%u%1[\\}]%n", &x1, sep,
> &len) > 1 ||
> ++ sscanf(buf, "\\fr%1[xyz]%1[\\}]%n",
> axis, sep, &len) > 1 ||
> ++ sscanf(buf, "\\fr%1[xyz]%u%1[\\}]%n",
> axis, &size, sep, &len) > 2) {
> ++ ass_write_filtered_line(outbuffer, buf, len,
> keep_flags, ASS_SPLIT_TEXT_ROTATE);
> ++ } else if (sscanf(buf, "\\blur%1[\\}]%n", sep,
> &len) > 0 ||
> ++ sscanf(buf, "\\blur%u%1[\\}]%n", &size,
> sep, &len) > 1) {
> ++ ass_write_filtered_line(outbuffer, buf, len,
> keep_flags, ASS_SPLIT_TEXT_BLUR);
> ++ } else if (sscanf(buf, "\\be%1[\\}]%n", sep, &len)
> > 0 ||
> ++ sscanf(buf, "\\be%u%1[\\}]%n", &size,
> sep, &len) > 1) {
> ++ ass_write_filtered_line(outbuffer, buf, len,
> keep_flags, ASS_SPLIT_TEXT_BLUR);
> ++ } else if (sscanf(buf, "\\q%1[\\}]%n", sep, &len) >
> 0 ||
> ++ sscanf(buf, "\\q%u%1[\\}]%n", &size,
> sep, &len) > 1) {
> ++ ass_write_filtered_line(outbuffer, buf, len,
> keep_flags, ASS_SPLIT_TEXT_WRAP);
> + } else if (sscanf(buf, "\\a%1[\\}]%n", sep, &len) >
> 0 ||
> + sscanf(buf, "\\a%2u%1[\\}]%n", &an, sep,
> &len) > 1 ||
> + sscanf(buf, "\\an%1[\\}]%n", sep, &len)
> > 0 ||
> + sscanf(buf, "\\an%1u%1[\\}]%n", &an,
> sep, &len) > 1) {
> + if (an != -1 && buf[2] != 'n')
> + an = (an&3) + (an&4 ? 6 : an&8 ? 3 : 0);
> ++ ass_write_filtered_line(outbuffer, buf, len,
> keep_flags, ASS_SPLIT_TEXT_ALIGNMENT);
> + if (callbacks->alignment)
> + callbacks->alignment(priv, an);
> + } else if (sscanf(buf, "\\r%1[\\}]%n", sep, &len) >
> 0 ||
> + sscanf(buf, "\\r%127[^\\}]%1[\\}]%n",
> tmp, sep, &len) > 1) {
> ++ ass_write_filtered_line(outbuffer, buf, len,
> keep_flags, ASS_SPLIT_CANCELLING);
> + if (callbacks->cancel_overrides)
> + callbacks->cancel_overrides(priv, tmp);
> + } else if (sscanf(buf,
> "\\move(%d,%d,%d,%d)%1[\\}]%n", &x1, &y1, &x2, &y2, sep, &len) > 4 ||
> + sscanf(buf,
> "\\move(%d,%d,%d,%d,%d,%d)%1[\\}]%n", &x1, &y1, &x2, &y2, &t1, &t2, sep,
> &len) > 6) {
> ++ ass_write_filtered_line(outbuffer, buf, len,
> keep_flags, ASS_SPLIT_MOVE);
> + if (callbacks->move)
> + callbacks->move(priv, x1, y1, x2, y2, t1,
> t2);
> + } else if (sscanf(buf, "\\pos(%d,%d)%1[\\}]%n",
> &x1, &y1, sep, &len) > 2) {
> ++ ass_write_filtered_line(outbuffer, buf, len,
> keep_flags, ASS_SPLIT_POS);
> + if (callbacks->move)
> + callbacks->move(priv, x1, y1, x1, y1, -1,
> -1);
> } else if (sscanf(buf, "\\org(%d,%d)%1[\\}]%n",
> &x1, &y1, sep, &len) > 2) {
> ++ ass_write_filtered_line(outbuffer, buf, len,
> keep_flags, ASS_SPLIT_ORIGIN);
> if (callbacks->origin)
> callbacks->origin(priv, x1, y1);
> -+ } else if (sscanf(buf, "\\t(%d,%d,%1[\\}]%n", &t1,
> &t2, sep, &len) > 2 ||
> ++ } else if (sscanf(buf, "\\t(%1[\\}]%n", sep, &len)
> > 0 ||
> ++ sscanf(buf, "\\t(%d,%d,%1[\\}]%n", &t1,
> &t2, sep, &len) > 2 ||
> + sscanf(buf, "\\t(%d,%d,%d,%1[\\}]%n",
> &t1, &t2, &accel, sep, &len) > 3) {
> ++
> ++ len = strcspn(buf, ")") + 2;
> ++
> ++ ass_write_filtered_line(outbuffer, buf, len,
> keep_flags, ASS_SPLIT_ANIMATE);
> + if (callbacks->animate)
> + callbacks->animate(priv, t1, t2, accel,
> tmp);
> ++ } else if (sscanf(buf,
> "\\fade(%d,%d,%d,%d,%d,%d,%d)%1[\\}]%n", &x1, &x2, &x3, &t1, &t2, &t3, &t4,
> sep, &len) > 7) {
> ++ ass_write_filtered_line(outbuffer, buf, len,
> keep_flags, ASS_SPLIT_FADE);
> ++ } else if (sscanf(buf, "\\fad(%d,%d)%1[\\}]%n",
> &t1, &t2, sep, &len) > 2) {
> ++ ass_write_filtered_line(outbuffer, buf, len,
> keep_flags, ASS_SPLIT_FADE);
> ++ } else if (sscanf(buf,
> "\\clip(%d,%d,%d,%d)%1[\\}]%n", &x1, &y1, &x2, &y2, sep, &len) > 4) {
> ++ ass_write_filtered_line(outbuffer, buf, len,
> keep_flags, ASS_SPLIT_CLIP);
> + } else if (sscanf(buf, "\\p%1[\\}]%n", sep, &len) >
> 0 ||
> + sscanf(buf, "\\p%u%1[\\}]%n", &scale,
> sep, &len) > 1) {
> ++ ass_write_filtered_line(outbuffer, buf, len,
> keep_flags, ASS_SPLIT_DRAW);
> + if (callbacks->drawing_mode)
> + callbacks->drawing_mode(priv, scale);
> } else {
> - len = strcspn(buf+1, "\\}") + 2; /* skip
> unknown code */
> - }
> +- len = strcspn(buf+1, "\\}") + 2; /* skip
> unknown code */
> +- }
> ++ len = strcspn(buf+1, "\\}") + 2; /* unknown
> code */
> ++ ass_write_filtered_line(outbuffer, buf, len,
> keep_flags, ASS_SPLIT_UNKNOWN);
> ++ }
> + buf += len - 1;
> + }
> + if (*buf++ != '}')
> + return AVERROR_INVALIDDATA;
> +- } else {
> ++
> ++ ass_write_filtered_line(outbuffer, "}", 2, keep_flags,
> ASS_SPLIT_ANY);
> ++ } else {
> + if (!text) {
> + text = buf;
> + text_len = 1;
> @@ libavutil/ass_split.c: int ff_ass_split_override_codes(const
> ASSCodesCallbacks *callbacks, void *priv,
> - return 0;
> + buf++;
> + }
> + }
> ++ if (text)
> ++ ass_write_filtered_line(outbuffer, text, text_len + 1,
> keep_flags, ASS_SPLIT_TEXT | ASS_SPLIT_TEXT2);
> + if (text && callbacks->text)
> + callbacks->text(priv, text, text_len);
> + if (callbacks->end)
> + callbacks->end(priv);
> +- return 0;
> ++
> ++ if (outbuffer)
> ++ ret = ass_remove_empty_braces(outbuffer);
> ++
> ++ return ret;
> ++}
> ++
> ++
> ++int avpriv_ass_split_override_codes(const ASSCodesCallbacks
> *callbacks, void *priv,
> ++ const char *buf)
> ++{
> ++ return avpriv_ass_filter_override_codes(callbacks, priv, buf,
> NULL, 0);
> }
>
> -ASSStyle *ff_ass_style_get(ASSSplitContext *ctx, const char *style)
> @@ libavutil/ass_split.c: int ff_ass_split_override_codes(const
> ASSCodesCallbacks *
> ASS *ass = &ctx->ass;
> int i;
>
> - ## libavcodec/ass_split.h => libavutil/ass_split_internal.h ##
> + ## libavutil/ass_split_internal.h (new) ##
> @@
> - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
> 02110-1301 USA
> - */
> -
> --#ifndef AVCODEC_ASS_SPLIT_H
> --#define AVCODEC_ASS_SPLIT_H
> ++/*
> ++ * SSA/ASS spliting functions
> ++ * Copyright (c) 2010 Aurelien Jacobs <aurel at gnuage.org>
> ++ *
> ++ * This file is part of FFmpeg.
> ++ *
> ++ * FFmpeg is free software; you can redistribute it and/or
> ++ * modify it under the terms of the GNU Lesser General Public
> ++ * License as published by the Free Software Foundation; either
> ++ * version 2.1 of the License, or (at your option) any later
> version.
> ++ *
> ++ * FFmpeg is distributed in the hope that it will be useful,
> ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
> ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> ++ * Lesser General Public License for more details.
> ++ *
> ++ * You should have received a copy of the GNU Lesser General Public
> ++ * License along with FFmpeg; if not, write to the Free Software
> ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
> 02110-1301 USA
> ++ */
> ++
> +#ifndef AVUTIL_ASS_SPLIT_INTERNAL_H
> +#define AVUTIL_ASS_SPLIT_INTERNAL_H
> -
> - /**
> - * fields extracted from the [Script Info] section
> -@@ libavutil/ass_split_internal.h: typedef struct {
> - char *effect;
> - char *text; /**< actual text which will be displayed as a
> subtitle,
> - can include style override control codes
> (see
> -- ff_ass_split_override_codes()) */
> -+ avpriv_ass_split_override_codes()) */
> - } ASSDialog;
> -
> - /**
> -@@ libavutil/ass_split_internal.h: typedef struct ASSSplitContext
> ASSSplitContext;
> - * @param buf String containing the ASS formatted data.
> - * @return Newly allocated struct containing split data.
> - */
> --ASSSplitContext *ff_ass_split(const char *buf);
> ++
> ++#include "bprint.h"
> ++
> ++enum ASSSplitComponents
> ++{
> ++ ASS_SPLIT_ANY = 0,
> ++ ASS_SPLIT_TEXT = (1 << 0),
> ++ ASS_SPLIT_TEXT2 = (1 << 1), // Same semantics as
> ASS_SPLIT_TEXT. To work around help output default display.
> ++ ASS_SPLIT_COLOR = (1 << 2),
> ++ ASS_SPLIT_ALPHA = (1 << 3),
> ++ ASS_SPLIT_FONT_NAME = (1 << 4),
> ++ ASS_SPLIT_FONT_SIZE = (1 << 5),
> ++ ASS_SPLIT_FONT_SCALE = (1 << 6),
> ++ ASS_SPLIT_FONT_SPACING = (1 << 7),
> ++ ASS_SPLIT_FONT_CHARSET = (1 << 8),
> ++ ASS_SPLIT_FONT_BOLD = (1 << 9),
> ++ ASS_SPLIT_FONT_ITALIC = (1 << 10),
> ++ ASS_SPLIT_FONT_UNDERLINE = (1 << 11),
> ++ ASS_SPLIT_FONT_STRIKEOUT = (1 << 12),
> ++ ASS_SPLIT_TEXT_BORDER = (1 << 13),
> ++ ASS_SPLIT_TEXT_SHADOW = (1 << 14),
> ++ ASS_SPLIT_TEXT_ROTATE = (1 << 15),
> ++ ASS_SPLIT_TEXT_BLUR = (1 << 16),
> ++ ASS_SPLIT_TEXT_WRAP = (1 << 17),
> ++ ASS_SPLIT_TEXT_ALIGNMENT = (1 << 18),
> ++ ASS_SPLIT_CANCELLING = (1 << 19),
> ++ ASS_SPLIT_MOVE = (1 << 20),
> ++ ASS_SPLIT_POS = (1 << 21),
> ++ ASS_SPLIT_ORIGIN = (1 << 22),
> ++ ASS_SPLIT_DRAW = (1 << 23),
> ++ ASS_SPLIT_ANIMATE = (1 << 24),
> ++ ASS_SPLIT_FADE = (1 << 25),
> ++ ASS_SPLIT_CLIP = (1 << 26),
> ++ ASS_SPLIT_UNKNOWN = (1 << 27),
> ++
> ++ ASS_SPLIT_BASIC = ASS_SPLIT_TEXT2 | ASS_SPLIT_COLOR |
> ASS_SPLIT_ALPHA | ASS_SPLIT_FONT_NAME | ASS_SPLIT_FONT_SIZE |
> ASS_SPLIT_FONT_SCALE | ASS_SPLIT_FONT_SPACING | ASS_SPLIT_FONT_CHARSET |
> ASS_SPLIT_FONT_BOLD | ASS_SPLIT_FONT_ITALIC | ASS_SPLIT_FONT_UNDERLINE |
> ASS_SPLIT_FONT_STRIKEOUT | ASS_SPLIT_TEXT_BORDER | ASS_SPLIT_TEXT_SHADOW |
> ASS_SPLIT_TEXT_WRAP | ASS_SPLIT_TEXT_ALIGNMENT | ASS_SPLIT_POS |
> ASS_SPLIT_CANCELLING,
> ++ ASS_SPLIT_ALL_KNOWN = ASS_SPLIT_TEXT2 | ASS_SPLIT_COLOR |
> ASS_SPLIT_ALPHA | ASS_SPLIT_FONT_NAME | ASS_SPLIT_FONT_SIZE |
> ASS_SPLIT_FONT_SCALE | ASS_SPLIT_FONT_SPACING | ASS_SPLIT_FONT_CHARSET |
> ASS_SPLIT_FONT_BOLD | ASS_SPLIT_FONT_ITALIC | ASS_SPLIT_FONT_UNDERLINE |
> ASS_SPLIT_FONT_STRIKEOUT | ASS_SPLIT_TEXT_BORDER | ASS_SPLIT_TEXT_SHADOW |
> ASS_SPLIT_TEXT_ROTATE | ASS_SPLIT_TEXT_BLUR | ASS_SPLIT_TEXT_WRAP |
> ASS_SPLIT_TEXT_ALIGNMENT | ASS_SPLIT_CANCELLING | ASS_SPLIT_POS |
> ASS_SPLIT_MOVE | ASS_SPLIT_ORIGIN | ASS_SPLIT_DRAW | ASS_SPLIT_ANIMATE |
> ASS_SPLIT_FADE | ASS_SPLIT_CLIP,
> ++};
> ++
> ++ /**
> ++ * fields extracted from the [Script Info] section
> ++ */
> ++ typedef struct {
> ++ char *script_type; /**< SSA script format version (eg. v4.00)
> */
> ++ char *collisions; /**< how subtitles are moved to prevent
> collisions */
> ++ int play_res_x; /**< video width that ASS coords are referring
> to */
> ++ int play_res_y; /**< video height that ASS coords are
> referring to */
> ++ float timer; /**< time multiplier to apply to SSA clock (in
> %) */
> ++} ASSScriptInfo;
> ++
> ++/**
> ++ * fields extracted from the [V4(+) Styles] section
> ++ */
> ++typedef struct {
> ++ char *name; /**< name of the tyle (case sensitive) */
> ++ char *font_name; /**< font face (case sensitive) */
> ++ int font_size; /**< font height */
> ++ int primary_color; /**< color that a subtitle will normally
> appear in */
> ++ int secondary_color;
> ++ int outline_color; /**< color for outline in ASS, called tertiary
> in SSA */
> ++ int back_color; /**< color of the subtitle outline or shadow */
> ++ int bold; /**< whether text is bold (1) or not (0) */
> ++ int italic; /**< whether text is italic (1) or not (0) */
> ++ int underline; /**< whether text is underlined (1) or not (0)
> */
> ++ int strikeout;
> ++ float scalex;
> ++ float scaley;
> ++ float spacing;
> ++ float angle;
> ++ int border_style;
> ++ float outline;
> ++ float shadow;
> ++ int alignment; /**< position of the text (left, center, top...),
> ++ defined after the layout of the numpad
> ++ (1-3 sub, 4-6 mid, 7-9 top) */
> ++ int margin_l;
> ++ int margin_r;
> ++ int margin_v;
> ++ int alpha_level;
> ++ int encoding;
> ++} ASSStyle;
> ++
> ++/**
> ++ * fields extracted from the [Events] section
> ++ */
> ++typedef struct {
> ++ int readorder;
> ++ int layer; /**< higher numbered layers are drawn over lower
> numbered */
> ++ int start; /**< start time of the dialog in centiseconds */
> ++ int end; /**< end time of the dialog in centiseconds */
> ++ char *style; /**< name of the ASSStyle to use with this dialog */
> ++ char *name;
> ++ int margin_l;
> ++ int margin_r;
> ++ int margin_v;
> ++ char *effect;
> ++ char *text; /**< actual text which will be displayed as a
> subtitle,
> ++ can include style override control codes (see
> ++ avpriv_ass_split_override_codes()) */
> ++} ASSDialog;
> ++
> ++/**
> ++ * structure containing the whole split ASS data
> ++ */
> ++typedef struct {
> ++ ASSScriptInfo script_info; /**< general information about the SSA
> script*/
> ++ ASSStyle *styles; /**< array of split out styles */
> ++ int styles_count; /**< number of ASSStyle in the styles
> array */
> ++ ASSDialog *dialogs; /**< array of split out dialogs */
> ++ int dialogs_count; /**< number of ASSDialog in the
> dialogs array*/
> ++} ASS;
> ++
> ++/**
> ++ * This struct can be casted to ASS to access to the split data.
> ++ */
> ++typedef struct ASSSplitContext ASSSplitContext;
> ++
> ++/**
> ++ * Split a full ASS file or a ASS header from a string buffer and
> store
> ++ * the split structure in a newly allocated context.
> ++ *
> ++ * @param buf String containing the ASS formatted data.
> ++ * @return Newly allocated struct containing split data.
> ++ */
> +ASSSplitContext *avpriv_ass_split(const char *buf);
> -
> - /**
> -- * Free a dialogue obtained from ff_ass_split_dialog().
> ++
> ++/**
> + * Free a dialogue obtained from avpriv_ass_split_dialog().
> - */
> --void ff_ass_free_dialog(ASSDialog **dialogp);
> ++ */
> +void avpriv_ass_free_dialog(ASSDialog **dialogp);
> -
> - /**
> - * Split one ASS Dialogue line from a string buffer.
> -@@ libavutil/ass_split_internal.h: void ff_ass_free_dialog(ASSDialog
> **dialogp);
> - * @param buf String containing the ASS "Dialogue" line.
> - * @return Pointer to the split ASSDialog. Must be freed with
> ff_ass_free_dialog()
> - */
> --ASSDialog *ff_ass_split_dialog(ASSSplitContext *ctx, const char
> *buf);
> ++
> ++/**
> ++ * Split one ASS Dialogue line from a string buffer.
> ++ *
> ++ * @param ctx Context previously initialized by ff_ass_split().
> ++ * @param buf String containing the ASS "Dialogue" line.
> ++ * @return Pointer to the split ASSDialog. Must be freed with
> ++ * ff_ass_free_dialog()
> ++ */
> +ASSDialog *avpriv_ass_split_dialog(ASSSplitContext *ctx, const char
> *buf);
> -
> - /**
> - * Free all the memory allocated for an ASSSplitContext.
> - *
> - * @param ctx Context previously initialized by ff_ass_split().
> - */
> --void ff_ass_split_free(ASSSplitContext *ctx);
> ++
> ++/**
> ++ * Free all the memory allocated for an ASSSplitContext.
> ++ *
> ++ * @param ctx Context previously initialized by ff_ass_split().
> ++ */
> +void avpriv_ass_split_free(ASSSplitContext *ctx);
> -
> -
> - /**
> -@@ libavutil/ass_split_internal.h: typedef struct {
> - * @{
> - */
> - void (*text)(void *priv, const char *text, int len);
> -+ void (*hard_space)(void *priv);
> - void (*new_line)(void *priv, int forced);
> - void (*style)(void *priv, char style, int close);
> - void (*color)(void *priv, unsigned int /* color */, unsigned
> int color_id);
> -@@ libavutil/ass_split_internal.h: typedef struct {
> - * @{
> - */
> - void (*move)(void *priv, int x1, int y1, int x2, int y2, int
> t1, int t2);
> -+ void (*animate)(void *priv, int t1, int t2, int accel, char
> *style);
> - void (*origin)(void *priv, int x, int y);
> -+ void (*drawing_mode)(void *priv, int scale);
> -+ /** @} */
> +
> -+ /**
> -+ * @defgroup ass_ext ASS extensible parsing callback
> -+ * @{
> -+ */
> -+ void (*ext)(void *priv, int ext_id, const char *text, int p1,
> int p2);
> - /** @} */
> -
> - /**
> -@@ libavutil/ass_split_internal.h: typedef struct {
> - * @param buf The ASS "Dialogue" Text field to split.
> - * @return >= 0 on success otherwise an error code <0
> - */
> --int ff_ass_split_override_codes(const ASSCodesCallbacks *callbacks,
> void *priv,
> -+int avpriv_ass_split_override_codes(const ASSCodesCallbacks
> *callbacks, void *priv,
> - const char *buf);
> -
> - /**
> -@@ libavutil/ass_split_internal.h: int
> ff_ass_split_override_codes(const ASSCodesCallbacks *callbacks, void *priv,
> - * @param style name of the style to search for.
> - * @return the ASSStyle corresponding to style, or NULL if style
> can't be found
> - */
> --ASSStyle *ff_ass_style_get(ASSSplitContext *ctx, const char *style);
> ++/**
> ++ * Set of callback functions corresponding to each override codes
> that can
> ++ * be encountered in a "Dialogue" Text field.
> ++ */
> ++typedef struct {
> ++ /**
> ++ * @defgroup ass_styles ASS styles
> ++ * @{
> ++ */
> ++ void (*text)(void *priv, const char *text, int len);
> ++ void (*hard_space)(void *priv);
> ++ void (*new_line)(void *priv, int forced);
> ++ void (*style)(void *priv, char style, int close);
> ++ void (*color)(void *priv, unsigned int /* color */, unsigned int
> color_id);
> ++ void (*alpha)(void *priv, int alpha, int alpha_id);
> ++ void (*font_name)(void *priv, const char *name);
> ++ void (*font_size)(void *priv, int size);
> ++ void (*alignment)(void *priv, int alignment);
> ++ void (*cancel_overrides)(void *priv, const char *style);
> ++ /** @} */
> ++
> ++ /**
> ++ * @defgroup ass_functions ASS functions
> ++ * @{
> ++ */
> ++ void (*move)(void *priv, int x1, int y1, int x2, int y2, int t1,
> int t2);
> ++ void (*animate)(void *priv, int t1, int t2, int accel, char
> *style);
> ++ void (*origin)(void *priv, int x, int y);
> ++ void (*drawing_mode)(void *priv, int scale);
> ++ /** @} */
> ++
> ++ /**
> ++ * @defgroup ass_ext ASS extensible parsing callback
> ++ * @{
> ++ */
> ++ void (*ext)(void *priv, int ext_id, const char *text, int p1, int
> p2);
> ++ /** @} */
> ++
> ++ /**
> ++ * @defgroup ass_end end of Dialogue Event
> ++ * @{
> ++ */
> ++ void (*end)(void *priv);
> ++ /** @} */
> ++} ASSCodesCallbacks;
> ++
> ++/**
> ++ * Split override codes out of a ASS "Dialogue" Text field.
> ++ *
> ++ * @param callbacks Set of callback functions called for each
> override code
> ++ * encountered.
> ++ * @param priv Opaque pointer passed to the callback functions.
> ++ * @param buf The ASS "Dialogue" Text field to split.
> ++ * @param outbuffer The output buffer.
> ++ * @param keep_flags Flags for filtering ass codes.
> ++ * @return >= 0 on success otherwise an error code <0
> ++ */
> ++int avpriv_ass_filter_override_codes(const ASSCodesCallbacks
> *callbacks,
> ++ void *priv, const char *buf,
> ++ AVBPrint *outbuffer, enum
> ASSSplitComponents keep_flags);
> ++
> ++/**
> ++ * Split override codes out of a ASS "Dialogue" Text field.
> ++ *
> ++ * @param callbacks Set of callback functions called for each
> override code
> ++ * encountered.
> ++ * @param priv Opaque pointer passed to the callback functions.
> ++ * @param buf The ASS "Dialogue" Text field to split.
> ++ * @return >= 0 on success otherwise an error code <0
> ++ */
> ++int avpriv_ass_split_override_codes(const ASSCodesCallbacks
> *callbacks,
> ++ void *priv, const char *buf);
> ++
> ++/**
> ++ * Find an ASSStyle structure by its name.
> ++ *
> ++ * @param ctx Context previously initialized by ff_ass_split().
> ++ * @param style name of the style to search for.
> ++ * @return the ASSStyle corresponding to style, or NULL if style
> can't be found
> ++ */
> +ASSStyle *avpriv_ass_style_get(ASSSplitContext *ctx, const char
> *style);
> -
> --#endif /* AVCODEC_ASS_SPLIT_H */
> ++
> +#endif /* AVUTIL_ASS_SPLIT_INTERNAL_H */
> 7: 09d8cf7880 = 7: 98f12ad7e9 avcodec/subtitles: Replace deprecated
> enum values
> 8: 897299bf7f = 8: 12c8a308d3 fftools/play,probe: Adjust for subtitle
> changes
> 9: ca580c6d21 = 9: 2e55dbe180 avfilter/subtitles: Add subtitles.c for
> subtitle frame allocation
> 10: 0781e974a2 = 10: c931041103 avfilter/avfilter: Handle subtitle
> frames
> 11: d9d9f42558 = 11: 36cab55ff2 avfilter/avfilter: Fix hardcoded input
> index
> 12: af69a4b321 = 12: f41070479c avfilter/sbuffer: Add sbuffersrc and
> sbuffersink filters
> 13: f7e5b590a2 ! 13: 9bfaba4ace avfilter/overlaygraphicsubs: Add
> overlaygraphicsubs and graphicsub2video filters
> @@ libavfilter/allfilters.c: extern const AVFilter ff_vf_overlay_qsv;
> extern const AVFilter ff_vf_owdenoise;
> extern const AVFilter ff_vf_pad;
> extern const AVFilter ff_vf_pad_opencl;
> -@@ libavfilter/allfilters.c: extern const AVFilter ff_avf_showvolume;
> +@@ libavfilter/allfilters.c: extern const AVFilter
> ff_avf_showspectrumpic;
> + extern const AVFilter ff_avf_showvolume;
> extern const AVFilter ff_avf_showwaves;
> extern const AVFilter ff_avf_showwavespic;
> - extern const AVFilter ff_vaf_spectrumsynth;
> +extern const AVFilter ff_svf_graphicsub2video;
> + extern const AVFilter ff_vaf_spectrumsynth;
>
> /* multimedia sources */
> - extern const AVFilter ff_avsrc_avsynctest;
>
> ## libavfilter/vf_overlaygraphicsubs.c (new) ##
> @@
> 14: 4c8092357f ! 14: 918fd9aaf5 avfilter/overlaytextsubs: Add
> overlaytextsubs and textsubs2video filters
> @@ libavfilter/allfilters.c: extern const AVFilter
> ff_vf_overlay_vaapi;
> extern const AVFilter ff_vf_owdenoise;
> extern const AVFilter ff_vf_pad;
> extern const AVFilter ff_vf_pad_opencl;
> -@@ libavfilter/allfilters.c: extern const AVFilter ff_avf_showwaves;
> +@@ libavfilter/allfilters.c: extern const AVFilter ff_avf_showvolume;
> + extern const AVFilter ff_avf_showwaves;
> extern const AVFilter ff_avf_showwavespic;
> - extern const AVFilter ff_vaf_spectrumsynth;
> extern const AVFilter ff_svf_graphicsub2video;
> +extern const AVFilter ff_svf_textsub2video;
> + extern const AVFilter ff_vaf_spectrumsynth;
>
> /* multimedia sources */
> - extern const AVFilter ff_avsrc_avsynctest;
>
> ## libavfilter/vf_overlaytextsubs.c (new) ##
> @@
> 15: 8fdbdf7c5f ! 15: a361ad35c5 avfilter/textmod: Add textmod, censor
> and show_speaker filters
> @@ libavfilter/Makefile: OBJS-$(CONFIG_YUVTESTSRC_FILTER)
> += vsrc_tests
> OBJS-$(CONFIG_ADRAWGRAPH_FILTER) += f_drawgraph.o
>
> ## libavfilter/allfilters.c ##
> -@@ libavfilter/allfilters.c: extern const AVFilter ff_avf_showvolume;
> - extern const AVFilter ff_avf_showwaves;
> - extern const AVFilter ff_avf_showwavespic;
> - extern const AVFilter ff_vaf_spectrumsynth;
> +@@ libavfilter/allfilters.c: extern const AVFilter
> ff_avsrc_avsynctest;
> + extern const AVFilter ff_avsrc_amovie;
> + extern const AVFilter ff_avsrc_movie;
> +
> ++/* subtitle filters */
> +extern const AVFilter ff_sf_censor;
> +extern const AVFilter ff_sf_showspeaker;
> +extern const AVFilter ff_sf_textmod;
> - extern const AVFilter ff_svf_graphicsub2video;
> - extern const AVFilter ff_svf_textsub2video;
> -
> ++
> + /* those filters are part of public or internal API,
> + * they are formatted to not be found by the grep
> + * as they are manually added again (due to their 'names'
>
> ## libavfilter/sf_textmod.c (new) ##
> @@
> @@ libavfilter/sf_textmod.c (new)
> +
> + av_bprint_finalize(&pbuf, &text);
> +
> -+ result = avpriv_ass_get_dialog_ex(dialog->readorder,
> dialog->layer, dialog->style, dialog->name, dialog->margin_l,
> dialog->margin_r, dialog->margin_v, text);
> ++ result = avpriv_ass_get_dialog_ex(dialog->readorder,
> dialog->layer, dialog->style, dialog->name, dialog->margin_l,
> dialog->margin_r, dialog->margin_v, dialog->effect, text);
> +
> + av_free(text);
> + avpriv_ass_free_dialog(&dialog);
> @@ libavfilter/sf_textmod.c (new)
> + if (!text)
> + return NULL;
> +
> -+ result = avpriv_ass_get_dialog_ex(dialog->readorder,
> dialog->layer, dialog->style, dialog->name, dialog->margin_l,
> dialog->margin_r, dialog->margin_v, text);
> ++ result = avpriv_ass_get_dialog_ex(dialog->readorder,
> dialog->layer, dialog->style, dialog->name, dialog->margin_l,
> dialog->margin_r, dialog->margin_v, dialog->effect, text);
> +
> + av_free(text);
> + avpriv_ass_free_dialog(&dialog);
> 16: d44b22f15b ! 16: bca90ebc3e avfilter/stripstyles: Add stripstyles
> filter
> @@ doc/filters.texi: ffmpeg -i "
> http://streams.videolan.org/samples/sub/SSA/subtitl
>
> ## libavfilter/Makefile ##
> @@ libavfilter/Makefile: OBJS-$(CONFIG_NULLSINK_FILTER)
> += vsink_nullsink.o
> + # subtitle filters
> OBJS-$(CONFIG_CENSOR_FILTER) += sf_textmod.o
> OBJS-$(CONFIG_SHOW_SPEAKER_FILTER) += sf_textmod.o
> - OBJS-$(CONFIG_TEXTMOD_FILTER) += sf_textmod.o
> +OBJS-$(CONFIG_STRIPSTYLES_FILTER) += sf_stripstyles.o
> + OBJS-$(CONFIG_TEXTMOD_FILTER) += sf_textmod.o
>
> # multimedia filters
> - OBJS-$(CONFIG_ABITSCOPE_FILTER) += avf_abitscope.o
>
> ## libavfilter/allfilters.c ##
> -@@ libavfilter/allfilters.c: extern const AVFilter
> ff_avf_showwavespic;
> - extern const AVFilter ff_vaf_spectrumsynth;
> +@@ libavfilter/allfilters.c: extern const AVFilter ff_avsrc_movie;
> + /* subtitle filters */
> extern const AVFilter ff_sf_censor;
> extern const AVFilter ff_sf_showspeaker;
> +extern const AVFilter ff_sf_stripstyles;
> extern const AVFilter ff_sf_textmod;
> - extern const AVFilter ff_svf_graphicsub2video;
> - extern const AVFilter ff_svf_textsub2video;
> +
> + /* those filters are part of public or internal API,
>
> ## libavfilter/sf_stripstyles.c (new) ##
> @@
> @@ libavfilter/sf_stripstyles.c (new)
> +
> +#include "libavutil/opt.h"
> +#include "internal.h"
> ++#include "libavutil/ass_internal.h"
> +#include "libavutil/ass_split_internal.h"
> +#include "libavutil/bprint.h"
> +
> @@ libavfilter/sf_stripstyles.c (new)
> + const AVClass *class;
> + enum AVSubtitleType format;
> + int remove_animated;
> ++ enum ASSSplitComponents keep_flags;
> + int select_layer;
> +} StripStylesContext;
> +
> @@ libavfilter/sf_stripstyles.c (new)
> + AVBPrint buffer;
> + int drawing_scale;
> + int is_animated;
> ++ int plain_text_length;
> +} DialogContext;
> +
> +static void dialog_text_cb(void *priv, const char *text, int len)
> @@ libavfilter/sf_stripstyles.c (new)
> + av_log(s->ss_ctx, AV_LOG_DEBUG, "dialog_text_cb: %s\n", text);
> +
> + if (!s->drawing_scale && (!s->is_animated ||
> !s->ss_ctx->remove_animated))
> -+ av_bprint_append_data(&s->buffer, text, len);
> ++ s->plain_text_length += len;
> ++ ////av_bprint_append_data(&s->buffer, text, len);
> +}
> +
> +static void dialog_new_line_cb(void *priv, int forced)
> +{
> + DialogContext *s = priv;
> + if (!s->drawing_scale && !s->is_animated)
> -+ av_bprint_append_data(&s->buffer, forced ? "\\N" : "\\n",
> 2);
> ++ s->plain_text_length += 2;
> ++ ////av_bprint_append_data(&s->buffer, forced ? "\\N" :
> "\\n", 2);
> +}
> +
> +static void dialog_drawing_mode_cb(void *priv, int scale)
> @@ libavfilter/sf_stripstyles.c (new)
> + .move = dialog_move_cb,
> +};
> +
> -+static char *ass_get_line(int readorder, int layer, const char
> *style,
> -+ const char *speaker, const char *effect,
> const char *text)
> -+{
> -+ return av_asprintf("%d,%d,%s,%s,0,0,0,%s,%s",
> -+ readorder, layer, style ? style : "Default",
> -+ speaker ? speaker : "", effect, text);
> -+}
> -+
> +static char *process_dialog(StripStylesContext *s, const char
> *ass_line)
> +{
> + DialogContext dlg_ctx = { .ss_ctx = s };
> @@ libavfilter/sf_stripstyles.c (new)
> +
> + dlg_ctx.ss_ctx = s;
> +
> -+ av_bprint_init(&dlg_ctx.buffer, 0, AV_BPRINT_SIZE_UNLIMITED);
> ++ av_bprint_init(&dlg_ctx.buffer, 512, AV_BPRINT_SIZE_UNLIMITED);
> +
> -+ avpriv_ass_split_override_codes(&dialog_callbacks, &dlg_ctx,
> dialog->text);
> ++ avpriv_ass_filter_override_codes(&dialog_callbacks, &dlg_ctx,
> dialog->text, &dlg_ctx.buffer, s->keep_flags);
> +
> -+ if (av_bprint_is_complete(&dlg_ctx.buffer)
> -+ && dlg_ctx.buffer.len > 0)
> -+ result = ass_get_line(dialog->readorder, dialog->layer,
> dialog->style, dialog->name, dialog->effect, dlg_ctx.buffer.str);
> ++ if (av_bprint_is_complete(&dlg_ctx.buffer) &&
> dlg_ctx.buffer.len > 0 && dlg_ctx.plain_text_length > 0)
> ++ result = avpriv_ass_get_dialog_ex(dialog->readorder,
> dialog->layer, dialog->style, dialog->name, dialog->margin_l,
> dialog->margin_r, dialog->margin_v, dialog->effect, dlg_ctx.buffer.str);
> +
> + av_bprint_finalize(&dlg_ctx.buffer, NULL);
> + avpriv_ass_free_dialog(&dialog);
> @@ libavfilter/sf_stripstyles.c (new)
> + area->ass = process_dialog(s, area->ass);
> +
> + if (area->ass) {
> -+ av_log(inlink->dst, AV_LOG_INFO, "original: %d
> %s\n", i, tmp);
> -+ av_log(inlink->dst, AV_LOG_INFO, "stripped: %d
> %s\n", i, area->ass);
> ++ av_log(inlink->dst, AV_LOG_DEBUG, "original: %d
> %s\n", i, tmp);
> ++ av_log(inlink->dst, AV_LOG_DEBUG, "stripped: %d
> %s\n", i, area->ass);
> + }
> + else
> + area->ass = NULL;
> @@ libavfilter/sf_stripstyles.c (new)
> +#define FLAGS (AV_OPT_FLAG_SUBTITLE_PARAM |
> AV_OPT_FLAG_FILTERING_PARAM)
> +
> +static const AVOption stripstyles_options[] = {
> ++ { "keep_flags", "flags to control which override codes to
> keep", OFFSET(keep_flags), AV_OPT_TYPE_FLAGS, { .i64 = ASS_SPLIT_TEXT },
> .flags = FLAGS, .unit = "keepflags" },
> ++ { "basic", "keep static style tags only",
> .type = AV_OPT_TYPE_CONST, { .i64 = ASS_SPLIT_BASIC },
> .flags=FLAGS, .unit = "keepflags" },
> ++ { "all_known", "keep all known tags",
> .type = AV_OPT_TYPE_CONST, { .i64 = ASS_SPLIT_ALL_KNOWN },
> .flags=FLAGS, .unit = "keepflags" },
> ++ { "text", "keep text content",
> .type = AV_OPT_TYPE_CONST, { .i64 = ASS_SPLIT_TEXT },
> .flags=FLAGS, .unit = "keepflags" },
> ++ { "color", "keep color tags (\\c, \\<n>c)",
> .type = AV_OPT_TYPE_CONST, { .i64 = ASS_SPLIT_COLOR },
> .flags=FLAGS, .unit = "keepflags" },
> ++ { "alpha", "keep color alpha tags (\\alpha,
> \\<n>a)", .type = AV_OPT_TYPE_CONST, { .i64 = ASS_SPLIT_ALPHA },
> .flags=FLAGS, .unit = "keepflags" },
> ++ { "font_name", "keep font name tags (\\fn)",
> .type = AV_OPT_TYPE_CONST, { .i64 = ASS_SPLIT_FONT_NAME },
> .flags=FLAGS, .unit = "keepflags" },
> ++ { "font_size", "keep font size tags (\\fs)",
> .type = AV_OPT_TYPE_CONST, { .i64 = ASS_SPLIT_FONT_SIZE },
> .flags=FLAGS, .unit = "keepflags" },
> ++ { "font_scale", "keep font scale tags (\\fscx,
> \\fscy)", .type = AV_OPT_TYPE_CONST, { .i64 = ASS_SPLIT_FONT_SCALE
> }, .flags=FLAGS, .unit = "keepflags" },
> ++ { "font_spacing", "keep font spacing tags (\\fsp)",
> .type = AV_OPT_TYPE_CONST, { .i64 = ASS_SPLIT_FONT_SPACING },
> .flags=FLAGS, .unit = "keepflags" },
> ++ { "font_charset", "keep font charset tags (\\fe)",
> .type = AV_OPT_TYPE_CONST, { .i64 = ASS_SPLIT_FONT_CHARSET },
> .flags=FLAGS, .unit = "keepflags" },
> ++ { "font_bold", "keep font bold tags (\\b)",
> .type = AV_OPT_TYPE_CONST, { .i64 = ASS_SPLIT_FONT_BOLD },
> .flags=FLAGS, .unit = "keepflags" },
> ++ { "font_italic", "keep font italic tags (\\i)",
> .type = AV_OPT_TYPE_CONST, { .i64 = ASS_SPLIT_FONT_ITALIC },
> .flags=FLAGS, .unit = "keepflags" },
> ++ { "font_underline", "keep font underline tags (\\u)",
> .type = AV_OPT_TYPE_CONST, { .i64 = ASS_SPLIT_FONT_UNDERLINE },
> .flags=FLAGS, .unit = "keepflags" },
> ++ { "font_strikeout", "keep font strikeout tags (\\s)",
> .type = AV_OPT_TYPE_CONST, { .i64 = ASS_SPLIT_FONT_STRIKEOUT },
> .flags=FLAGS, .unit = "keepflags" },
> ++ { "text_border", "keep text border tags (\\bord)",
> .type = AV_OPT_TYPE_CONST, { .i64 = ASS_SPLIT_TEXT_BORDER },
> .flags=FLAGS, .unit = "keepflags" },
> ++ { "text_shadow", "keep text shadow tags (\\shad)",
> .type = AV_OPT_TYPE_CONST, { .i64 = ASS_SPLIT_TEXT_SHADOW },
> .flags=FLAGS, .unit = "keepflags" },
> ++ { "text_rotate", "keep text rotate tags (\\fr)",
> .type = AV_OPT_TYPE_CONST, { .i64 = ASS_SPLIT_TEXT_ROTATE },
> .flags=FLAGS, .unit = "keepflags" },
> ++ { "text_blur", "keep text blur tags (\\blur, \\be)",
> .type = AV_OPT_TYPE_CONST, { .i64 = ASS_SPLIT_TEXT_BLUR },
> .flags=FLAGS, .unit = "keepflags" },
> ++ { "text_wrap", "keep text wrap tags (\\q)",
> .type = AV_OPT_TYPE_CONST, { .i64 = ASS_SPLIT_TEXT_WRAP },
> .flags=FLAGS, .unit = "keepflags" },
> ++ { "text_align", "keep text align tags (\\a, \\an)",
> .type = AV_OPT_TYPE_CONST, { .i64 = ASS_SPLIT_TEXT_ALIGNMENT },
> .flags=FLAGS, .unit = "keepflags" },
> ++ { "reset_override", "keep override reset tags (\\r)",
> .type = AV_OPT_TYPE_CONST, { .i64 = ASS_SPLIT_CANCELLING },
> .flags=FLAGS, .unit = "keepflags" },
> ++ { "move", "keep move tags (\\move)",
> .type = AV_OPT_TYPE_CONST, { .i64 = ASS_SPLIT_MOVE },
> .flags=FLAGS, .unit = "keepflags" },
> ++ { "pos", "keep position tags (\\pos)",
> .type = AV_OPT_TYPE_CONST, { .i64 = ASS_SPLIT_POS },
> .flags=FLAGS, .unit = "keepflags" },
> ++ { "origin", "keep origin tags (\\org)",
> .type = AV_OPT_TYPE_CONST, { .i64 = ASS_SPLIT_ORIGIN },
> .flags=FLAGS, .unit = "keepflags" },
> ++ { "draw", "keep drawing tags (\\p)",
> .type = AV_OPT_TYPE_CONST, { .i64 = ASS_SPLIT_DRAW },
> .flags=FLAGS, .unit = "keepflags" },
> ++ { "animate", "keep animation tags (\\t)",
> .type = AV_OPT_TYPE_CONST, { .i64 = ASS_SPLIT_ANIMATE },
> .flags=FLAGS, .unit = "keepflags" },
> ++ { "fade", "keep fade tags (\\fad, \\fade)",
> .type = AV_OPT_TYPE_CONST, { .i64 = ASS_SPLIT_FADE },
> .flags=FLAGS, .unit = "keepflags" },
> ++ { "clip", "keep clip tags (\\clip)",
> .type = AV_OPT_TYPE_CONST, { .i64 = ASS_SPLIT_CLIP },
> .flags=FLAGS, .unit = "keepflags" },
> ++ { "unknown", "keep unknown tags",
> .type = AV_OPT_TYPE_CONST, { .i64 = ASS_SPLIT_UNKNOWN },
> .flags=FLAGS, .unit = "keepflags" },
> + { "remove_animated", "remove animated text (default: yes)",
> OFFSET(remove_animated), AV_OPT_TYPE_BOOL, {.i64 = 1 }, 0, 1, FLAGS, 0 },
> -+ { "select_layer", "process a specific ass layer only",
> OFFSET(remove_animated), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, INT_MAX,
> FLAGS, 0 },
> ++ { "select_layer", "process a specific ass layer only",
> OFFSET(select_layer), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, INT_MAX, FLAGS,
> 0 },
> + { NULL },
> +};
> +
> 17: 28d75dc982 ! 17: 6e488e495f avfilter/splitcc: Add splitcc filter
> for closed caption handling
> @@ doc/filters.texi: ffmpeg -i INPUT -filter_complex
> "showspeaker=format=colon:styl
>
> ## libavfilter/Makefile ##
> @@ libavfilter/Makefile: OBJS-$(CONFIG_NULLSINK_FILTER)
> += vsink_nullsink.o
> + # subtitle filters
> OBJS-$(CONFIG_CENSOR_FILTER) += sf_textmod.o
> OBJS-$(CONFIG_SHOW_SPEAKER_FILTER) += sf_textmod.o
> - OBJS-$(CONFIG_TEXTMOD_FILTER) += sf_textmod.o
> +OBJS-$(CONFIG_SPLITCC_FILTER) += sf_splitcc.o
> OBJS-$(CONFIG_STRIPSTYLES_FILTER) += sf_stripstyles.o
> + OBJS-$(CONFIG_TEXTMOD_FILTER) += sf_textmod.o
>
> - # multimedia filters
>
> ## libavfilter/allfilters.c ##
> -@@ libavfilter/allfilters.c: extern const AVFilter
> ff_avf_showwavespic;
> - extern const AVFilter ff_vaf_spectrumsynth;
> +@@ libavfilter/allfilters.c: extern const AVFilter ff_avsrc_movie;
> + /* subtitle filters */
> extern const AVFilter ff_sf_censor;
> extern const AVFilter ff_sf_showspeaker;
> +extern const AVFilter ff_sf_splitcc;
> extern const AVFilter ff_sf_stripstyles;
> extern const AVFilter ff_sf_textmod;
> - extern const AVFilter ff_svf_graphicsub2video;
> +
>
> ## libavfilter/sf_splitcc.c (new) ##
> @@
> 18: 42d1d1c819 ! 18: 1057dff7da avfilter/graphicsub2text: Add new
> graphicsub2text filter (OCR)
> @@ libavfilter/Makefile: OBJS-$(CONFIG_GBLUR_FILTER)
> += vf_gblur.o
> OBJS-$(CONFIG_GRAYWORLD_FILTER) += vf_grayworld.o
>
> ## libavfilter/allfilters.c ##
> -@@ libavfilter/allfilters.c: extern const AVFilter ff_avf_showwaves;
> - extern const AVFilter ff_avf_showwavespic;
> - extern const AVFilter ff_vaf_spectrumsynth;
> +@@ libavfilter/allfilters.c: extern const AVFilter ff_avsrc_movie;
> +
> + /* subtitle filters */
> extern const AVFilter ff_sf_censor;
> +extern const AVFilter ff_sf_graphicsub2text;
> extern const AVFilter ff_sf_showspeaker;
> @@ libavfilter/sf_graphicsub2text.c (new)
> + }
> + }
> +
> -+ if (pointsize != cur_pointsize && s->recognize &
> RFLAGS_FONTSIZE) {
> -+ av_log(s, AV_LOG_DEBUG, "pointsize - pointsize:
> %d\n", pointsize);
> -+ in_code = print_code(&s->buffer, in_code, "\\fs%d",
> (int)(pointsize * font_factor));
> -+ cur_pointsize = pointsize;
> ++ if (pointsize > 0 && pointsize != cur_pointsize &&
> s->recognize & RFLAGS_FONTSIZE) {
> ++ float change_factor = (float)(FFABS(pointsize -
> cur_pointsize)) / FFMAX(pointsize, cur_pointsize);
> ++
> ++ // Avoid small changes due to recognition variance
> ++ if (change_factor > 0.12f) {
> ++ av_log(s, AV_LOG_DEBUG, "pointsize - pointsize:
> %d\n", pointsize);
> ++ in_code = print_code(&s->buffer, in_code,
> "\\fs%d", (int)(pointsize * font_factor));
> ++ cur_pointsize = pointsize;
> ++ }
> + }
> +
> + if (is_italic && !cur_is_italic && s->recognize &
> RFLAGS_FITALIC)
> @@ libavfilter/sf_graphicsub2text.c (new)
> +
> + const int layer = s->recognize ? i : 0;
> + char *tmp = area->ass;
> -+ area->ass =
> avpriv_ass_get_dialog_ex(s->readorder_counter++, layer, "Default", NULL, 0,
> 0, margin_v, tmp);
> ++ area->ass =
> avpriv_ass_get_dialog_ex(s->readorder_counter++, layer, "Default", NULL, 0,
> 0, margin_v, NULL, tmp);
> + av_free(tmp);
> + }
> + }
> 19: 7095e8aa26 ! 19: 4e85fb5d2f avfilter/subscale: Add filter for
> scaling and/or re-arranging graphical subtitles
> @@ doc/filters.texi: Set the rendering margin in pixels.
> @chapter Multimedia Filters
>
> ## libavfilter/Makefile ##
> -@@ libavfilter/Makefile: OBJS-$(CONFIG_SHOW_SPEAKER_FILTER)
> += sf_textmod.o
> - OBJS-$(CONFIG_TEXTMOD_FILTER) += sf_textmod.o
> +@@ libavfilter/Makefile: OBJS-$(CONFIG_CENSOR_FILTER)
> += sf_textmod.o
> + OBJS-$(CONFIG_SHOW_SPEAKER_FILTER) += sf_textmod.o
> OBJS-$(CONFIG_SPLITCC_FILTER) += sf_splitcc.o
> OBJS-$(CONFIG_STRIPSTYLES_FILTER) += sf_stripstyles.o
> +OBJS-$(CONFIG_SUBSCALE_FILTER) += sf_subscale.o
> + OBJS-$(CONFIG_TEXTMOD_FILTER) += sf_textmod.o
>
> # multimedia filters
> - OBJS-$(CONFIG_ABITSCOPE_FILTER) += avf_abitscope.o
>
> ## libavfilter/allfilters.c ##
> @@ libavfilter/allfilters.c: extern const AVFilter
> ff_sf_graphicsub2text;
> @@ libavfilter/allfilters.c: extern const AVFilter
> ff_sf_graphicsub2text;
> extern const AVFilter ff_sf_stripstyles;
> +extern const AVFilter ff_sf_subscale;
> extern const AVFilter ff_sf_textmod;
> - extern const AVFilter ff_svf_graphicsub2video;
> - extern const AVFilter ff_svf_textsub2video;
> +
> + /* those filters are part of public or internal API,
>
> ## libavfilter/sf_subscale.c (new) ##
> @@
> 20: 697939451e ! 20: 88e8adb889 avfilter/subfeed: add subtitle feed
> filter
> @@ Commit message
> Signed-off-by: softworkz <softworkz at hotmail.com>
>
> ## libavfilter/Makefile ##
> -@@ libavfilter/Makefile: OBJS-$(CONFIG_TEXTMOD_FILTER)
> += sf_textmod.o
> +@@ libavfilter/Makefile: OBJS-$(CONFIG_CENSOR_FILTER)
> += sf_textmod.o
> + OBJS-$(CONFIG_SHOW_SPEAKER_FILTER) += sf_textmod.o
> OBJS-$(CONFIG_SPLITCC_FILTER) += sf_splitcc.o
> OBJS-$(CONFIG_STRIPSTYLES_FILTER) += sf_stripstyles.o
> - OBJS-$(CONFIG_SUBSCALE_FILTER) += sf_subscale.o
> +OBJS-$(CONFIG_SUBFEED_FILTER) += sf_subfeed.o
> + OBJS-$(CONFIG_SUBSCALE_FILTER) += sf_subscale.o
> + OBJS-$(CONFIG_TEXTMOD_FILTER) += sf_textmod.o
>
> - # multimedia filters
> - OBJS-$(CONFIG_ABITSCOPE_FILTER) += avf_abitscope.o
>
> ## libavfilter/allfilters.c ##
> -@@ libavfilter/allfilters.c: extern const AVFilter ff_sf_showspeaker;
> +@@ libavfilter/allfilters.c: extern const AVFilter
> ff_sf_graphicsub2text;
> + extern const AVFilter ff_sf_showspeaker;
> extern const AVFilter ff_sf_splitcc;
> extern const AVFilter ff_sf_stripstyles;
> - extern const AVFilter ff_sf_subscale;
> +extern const AVFilter ff_sf_subfeed;
> + extern const AVFilter ff_sf_subscale;
> extern const AVFilter ff_sf_textmod;
> - extern const AVFilter ff_svf_graphicsub2video;
> - extern const AVFilter ff_svf_textsub2video;
> +
>
> ## libavfilter/sf_subfeed.c (new) ##
> @@
> @@ libavfilter/sf_subfeed.c (new)
> + if (pts_diff <= 0) {
> + av_log(ctx, AV_LOG_WARNING, "The pts_diff to the
> previous frame (index #%"PRId64") is <= 0: %"PRId64" ms. The previous
> frame duration is %"PRId64" ms.\n",
> + index, avtb_to_ms(pts_diff),
> avtb_to_ms(previous_frame->subtitle_timing.duration));
> ++
> ++ if (s->fix_overlap) {
> ++ av_log(ctx, AV_LOG_VERBOSE, "Removing previous
> frame\n");
> ++ previous_frame = ff_framequeue_take(&s->fifo);
> ++ while (nb_queued_frames > 1) {
> ++ ff_framequeue_add(&s->fifo, previous_frame);
> ++ previous_frame = ff_framequeue_take(&s->fifo);
> ++ nb_queued_frames--;
> ++ }
> ++ }
> + }
> + }
> +
> -: ---------- > 21: a96bb5c788 avfilter/text2graphicsub: Added
> text2graphicsub subtitle filter
> -: ---------- > 22: c4922f8466 avfilter/snull,strim: Add snull and
> strim filters
> 21: 32e9af0806 = 23: 848f84d5dc avcodec/subtitles: Migrate subtitle
> encoders to frame-based API
> 22: fa0b5c2077 ! 24: 2645a1a842 fftools/ffmpeg: Introduce subtitle
> filtering and new frame-based subtitle encoding
> @@ Commit message
> Overlay results have slightly different CRCs due to different
> blending implementation
>
> + - sub-scc
> + The first entry is no longer in the output because it is before
> + the actual start time and the strim filter removes such entries
> + now (like for video and audio)
> +
> Signed-off-by: softworkz <softworkz at hotmail.com>
>
> ## fftools/ffmpeg.c ##
> @@ fftools/ffmpeg.c: static int init_output_stream(OutputStream *ost,
> AVFrame *fram
> return AVERROR_INVALIDDATA;
> }
> }
> +@@ fftools/ffmpeg.c: static int transcode_init(void)
> + for (i = 0; i < nb_output_streams; i++) {
> + if (!output_streams[i]->stream_copy &&
> + (output_streams[i]->enc_ctx->codec_type ==
> AVMEDIA_TYPE_VIDEO ||
> +- output_streams[i]->enc_ctx->codec_type ==
> AVMEDIA_TYPE_AUDIO))
> ++ output_streams[i]->enc_ctx->codec_type ==
> AVMEDIA_TYPE_AUDIO ||
> ++ output_streams[i]->enc_ctx->codec_type ==
> AVMEDIA_TYPE_SUBTITLE))
> + continue;
> +
> + ret = init_output_stream_wrapper(output_streams[i], NULL,
> 0);
> @@ fftools/ffmpeg.c: static OutputStream *choose_output(void)
> av_rescale_q(ost->last_mux_dts,
> ost->st->time_base,
> AV_TIME_BASE_Q);
> @@ fftools/ffmpeg_filter.c: static void init_input_filter(FilterGraph
> *fg, AVFilter
> continue;
> if (check_stream_specifier(s, s->streams[i], *p == ':'
> ? p + 1 : p) == 1) {
> st = s->streams[i];
> +@@ fftools/ffmpeg_filter.c: static int insert_trim(int64_t
> start_time, int64_t duration,
> + const char *name = (type == AVMEDIA_TYPE_VIDEO) ? "trim" :
> "atrim";
> + int ret = 0;
> +
> ++ switch (type) {
> ++ case AVMEDIA_TYPE_VIDEO:
> ++ name = "trim";
> ++ break;
> ++ case AVMEDIA_TYPE_AUDIO:
> ++ name = "atrim";
> ++ break;
> ++ case AVMEDIA_TYPE_SUBTITLE:
> ++ name = "strim";
> ++ break;
> ++ default:
> ++ av_log(NULL, AV_LOG_ERROR, "insert_trim: Invalid media
> type: %d\n", type);
> ++ return AVERROR_INVALIDDATA;
> ++ }
> ++
> + if (duration == INT64_MAX && start_time == AV_NOPTS_VALUE)
> + return 0;
> +
> @@ fftools/ffmpeg_filter.c: static int insert_filter(AVFilterContext
> **last_filter, int *pad_idx,
> return 0;
> }
> @@ fftools/ffmpeg_filter.c: static int insert_filter(AVFilterContext
> **last_filter,
> +static int configure_output_subtitle_filter(FilterGraph *fg,
> OutputFilter *ofilter, AVFilterInOut *out)
> +{
> + OutputStream *ost = ofilter->ost;
> ++ OutputFile *of = output_files[ost->file_index];
> + AVFilterContext *last_filter = out->filter_ctx;
> + int pad_idx = out->pad_idx;
> + int ret;
> @@ fftools/ffmpeg_filter.c: static int insert_filter(AVFilterContext
> **last_filter,
> + return ret;
> + }
> +
> -+ ////snprintf(name, sizeof(name), "trim_out_%d_%d",
> -+ //// ost->file_index, ost->index);
> -+ ////ret = insert_trim(of->start_time, of->recording_time,
> -+ //// &last_filter, &pad_idx, name);
> -+ ////if (ret < 0)
> -+ //// return ret;
> ++ snprintf(name, sizeof(name), "trim_out_%d_%d",
> ++ ost->file_index, ost->index);
> ++ ret = insert_trim(of->start_time, of->recording_time,
> ++ &last_filter, &pad_idx, name);
> ++ if (ret < 0)
> ++ return ret;
> +
> + ////ost->st->codecpar->codec_tag = MKTAG('a', 's', 's', 's');
> +
> @@ fftools/ffmpeg_filter.c: void check_filter_outputs(void)
> + AVFilterContext *last_filter;
> + const AVFilter *buffer_filt = avfilter_get_by_name("sbuffer");
> + InputStream *ist = ifilter->ist;
> ++ InputFile *f = input_files[ist->file_index];
> + AVBPrint args;
> + char name[255];
> + int ret, pad_idx = 0;
> + int w, h;
> ++ int64_t tsoffset = 0;
> + AVBufferSrcParameters *par = av_buffersrc_parameters_alloc();
> + enum AVMediaType media_type;
> +
> @@ fftools/ffmpeg_filter.c: void check_filter_outputs(void)
> - if (avf->streams[i]->codecpar->codec_type ==
> AVMEDIA_TYPE_VIDEO) {
> - w = FFMAX(w, avf->streams[i]->codecpar->width);
> - h = FFMAX(h, avf->streams[i]->codecpar->height);
> -- }
> -- }
> -- if (!(w && h)) {
> -- w = FFMAX(w, 720);
> -- h = FFMAX(h, 576);
> -- }
> -- av_log(avf, AV_LOG_INFO, "sub2video: using %dx%d canvas\n",
> w, h);
> + w = ist->dec_ctx->width;
> + h = ist->dec_ctx->height;
> + }
> @@ fftools/ffmpeg_filter.c: void check_filter_outputs(void)
> + w = ass->script_info.play_res_x;
> + h = ass->script_info.play_res_y;
> + avpriv_ass_split_free(ass_ctx);
> - }
> -- ist->sub2video.w = ifilter->width = w;
> -- ist->sub2video.h = ifilter->height = h;
> -
> -- ifilter->width = ist->dec_ctx->width ? ist->dec_ctx->width :
> ist->sub2video.w;
> -- ifilter->height = ist->dec_ctx->height ? ist->dec_ctx->height :
> ist->sub2video.h;
> ++ }
> ++
> + ist->subtitle_kickoff.w = w;
> + ist->subtitle_kickoff.h = h;
> + av_log(ifilter, AV_LOG_INFO, "subtitle input filter: decoding
> size %dx%d\n", ist->subtitle_kickoff.w, ist->subtitle_kickoff.h);
> -
> -- /* rectangles are AV_PIX_FMT_PAL8, but we have no guarantee
> that the
> -- palettes for all rectangles are identical or compatible */
> -- ifilter->format = AV_PIX_FMT_RGB32;
> ++
> + ifilter->width = w;
> + ifilter->height = h;
> + ist->dec_ctx->width = w;
> + ist->dec_ctx->height = h;
> -
> -- ist->sub2video.frame = av_frame_alloc();
> -- if (!ist->sub2video.frame)
> -- return AVERROR(ENOMEM);
> -- ist->sub2video.last_pts = INT64_MIN;
> -- ist->sub2video.end_pts = INT64_MIN;
> ++
> + ist->subtitle_kickoff.last_pts = INT64_MIN;
> +
> + snprintf(name, sizeof(name), "graph %d subtitle input from
> stream %d:%d", fg->index,
> @@ fftools/ffmpeg_filter.c: void check_filter_outputs(void)
> + if ((ret = avfilter_graph_create_filter(&ifilter->filter,
> buffer_filt, name,
> + args.str, NULL,
> fg->graph)) < 0)
> + goto fail;
> -
> -- /* sub2video structure has been (re-)initialized.
> -- Mark it as such so that the system will be
> -- initialized with the first received heartbeat. */
> -- ist->sub2video.initialize = 1;
> ++
> + par->hw_frames_ctx = ifilter->hw_frames_ctx;
> + par->format = ifilter->format;
> + par->width = ifilter->width;
> @@ fftools/ffmpeg_filter.c: void check_filter_outputs(void)
> + subscale_h = input->height;
> + break;
> + }
> -+ }
> -+ }
> -+
> + }
> + }
> +- if (!(w && h)) {
> +- w = FFMAX(w, 720);
> +- h = FFMAX(h, 576);
> +- }
> +- av_log(avf, AV_LOG_INFO, "sub2video: using %dx%d canvas\n",
> w, h);
> +- }
> +- ist->sub2video.w = ifilter->width = w;
> +- ist->sub2video.h = ifilter->height = h;
> +
> +- ifilter->width = ist->dec_ctx->width ? ist->dec_ctx->width :
> ist->sub2video.w;
> +- ifilter->height = ist->dec_ctx->height ? ist->dec_ctx->height :
> ist->sub2video.h;
> + if (subscale_w && subscale_h) {
> + char subscale_params[64];
> + snprintf(subscale_params, sizeof(subscale_params),
> "w=%d:h=%d", subscale_w, subscale_h);
> @@ fftools/ffmpeg_filter.c: void check_filter_outputs(void)
> + if (ret < 0)
> + return ret;
> + }
> -+
> +
> +- /* rectangles are AV_PIX_FMT_PAL8, but we have no guarantee
> that the
> +- palettes for all rectangles are identical or compatible */
> +- ifilter->format = AV_PIX_FMT_RGB32;
> + av_log(NULL, AV_LOG_INFO, "Auto-inserting graphicsub2video
> filter\n");
> + ret = insert_filter(&last_filter, &pad_idx,
> "graphicsub2video", NULL);
> + if (ret < 0)
> + return ret;
> + }
> -+
> +
> +- ist->sub2video.frame = av_frame_alloc();
> +- if (!ist->sub2video.frame)
> +- return AVERROR(ENOMEM);
> +- ist->sub2video.last_pts = INT64_MIN;
> +- ist->sub2video.end_pts = INT64_MIN;
> ++ if (copy_ts) {
> ++ tsoffset = f->start_time == AV_NOPTS_VALUE ? 0 :
> f->start_time;
> ++ if (!start_at_zero && f->ctx->start_time != AV_NOPTS_VALUE)
> ++ tsoffset += f->ctx->start_time;
> ++ }
> ++ ret = insert_trim(((f->start_time == AV_NOPTS_VALUE) ||
> !f->accurate_seek) ?
> ++ AV_NOPTS_VALUE : tsoffset, f->recording_time,
> ++ &last_filter, &pad_idx, name);
> ++ if (ret < 0)
> ++ return ret;
> +
> +- /* sub2video structure has been (re-)initialized.
> +- Mark it as such so that the system will be
> +- initialized with the first received heartbeat. */
> +- ist->sub2video.initialize = 1;
> + if ((ret = avfilter_link(last_filter, 0, in->filter_ctx,
> in->pad_idx)) < 0)
> + return ret;
>
> @@ fftools/ffmpeg_filter.c: static int
> configure_input_video_filter(FilterGraph *fg
> int64_t tsoffset = 0;
> - AVBufferSrcParameters *par = av_buffersrc_parameters_alloc();
> + AVBufferSrcParameters *par;
> -
> ++
> + if (ist->dec_ctx->codec_type == AVMEDIA_TYPE_SUBTITLE) {
> + // Automatically insert conversion filter to retain
> compatibility
> + // with sub2video command lines
> + return configure_input_subtitle_filter(fg, ifilter, in);
> + }
> -+
> +
> + par = av_buffersrc_parameters_alloc();
> if (!par)
> return AVERROR(ENOMEM);
> @@ fftools/ffmpeg_opt.c: static void add_input_streams(OptionsContext
> *o, AVFormatC
> break;
> }
> case AVMEDIA_TYPE_ATTACHMENT:
> +@@ fftools/ffmpeg_opt.c: static char *get_ost_filters(OptionsContext
> *o, AVFormatContext *oc,
> +
> + if (ost->filters_script)
> + return read_file(ost->filters_script);
> +- else if (ost->filters)
> ++ if (ost->filters)
> + return av_strdup(ost->filters);
> +
> +- return av_strdup(st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO
> ?
> +- "null" : "anull");
> ++ switch (st->codecpar->codec_type) {
> ++ case AVMEDIA_TYPE_VIDEO: return av_strdup("null");
> ++ case AVMEDIA_TYPE_AUDIO: return av_strdup("anull");
> ++ case AVMEDIA_TYPE_SUBTITLE: return av_strdup("snull");
> ++ default: av_assert0(0); return NULL;
> ++ }
> + }
> +
> + static void check_streamcopy_filters(OptionsContext *o,
> AVFormatContext *oc,
> +@@ fftools/ffmpeg_opt.c: static OutputStream
> *new_subtitle_stream(OptionsContext *o, AVFormatContext *oc,
> +
> + subtitle_enc->codec_type = AVMEDIA_TYPE_SUBTITLE;
> +
> ++ MATCH_PER_STREAM_OPT(filter_scripts, str, ost->filters_script,
> oc, st);
> ++ MATCH_PER_STREAM_OPT(filters, str, ost->filters,
> oc, st);
> ++
> + if (!ost->stream_copy) {
> + char *frame_size = NULL;
> +
> +@@ fftools/ffmpeg_opt.c: static OutputStream
> *new_subtitle_stream(OptionsContext *o, AVFormatContext *oc,
> + av_log(NULL, AV_LOG_FATAL, "Invalid frame size: %s.\n",
> frame_size);
> + exit_program(1);
> + }
> ++
> ++ ost->avfilter = get_ost_filters(o, oc, ost);
> ++ if (!ost->avfilter)
> ++ exit_program(1);
> + }
> +
> + return ost;
> @@ fftools/ffmpeg_opt.c: static void init_output_filter(OutputFilter
> *ofilter, OptionsContext *o,
> switch (ofilter->type) {
> case AVMEDIA_TYPE_VIDEO: ost = new_video_stream(o, oc, -1);
> break;
> @@ fftools/ffmpeg_opt.c: static void init_output_filter(OutputFilter
> *ofilter, Opti
> "currently.\n");
> exit_program(1);
> }
> +@@ fftools/ffmpeg_opt.c: loop_end:
> + ist->processing_needed = 1;
> +
> + if (ost->st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO
> ||
> +- ost->st->codecpar->codec_type ==
> AVMEDIA_TYPE_AUDIO) {
> ++ ost->st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO
> ||
> ++ ost->st->codecpar->codec_type ==
> AVMEDIA_TYPE_SUBTITLE) {
> + err = init_simple_filtergraph(ist, ost);
> + if (err < 0) {
> + av_log(NULL, AV_LOG_ERROR,
> +@@ fftools/ffmpeg_opt.c: loop_end:
> + } else if (ost->enc->ch_layouts) {
> + f->ch_layouts = ost->enc->ch_layouts;
> + }
> ++ break;
> ++ case AVMEDIA_TYPE_SUBTITLE:
> ++ f->format = ost->enc_ctx->subtitle_type;
> ++
> + break;
> + }
> + }
>
> ## tests/ref/fate/filter-overlay-dvdsub-2397 ##
> @@
> @@ tests/ref/fate/sub-dvb
> +0, 31400000, 31400000, 479000, 14, 0x0959015b
> +0, 31879000, 31879000, 479000, 14, 0x09c9016b
>
> + ## tests/ref/fate/sub-scc ##
> +@@ tests/ref/fate/sub-scc: Style:
> Default,Monospace,16,&Hffffff,&Hffffff,&H0,&H0,0,0,0,0,100,100,0,0,3,1,0,
> +
> + [Events]
> + Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV,
> Effect, Text
> +-Dialogue:
> 0,0:00:-2.-47,0:00:00.70,Default,,0,0,0,,{\an7}{\pos(76,228)}WE HAVE FOUND
> A WITCH !\N{\an7}{\pos(76,243)}MAY WE BURN HER ?
> + Dialogue:
> 0,0:00:00.69,0:00:03.29,Default,,0,0,0,,{\an7}{\pos(115,228)}[ Crowd
> ]\N{\an7}{\pos(115,243)}BURN HER ! BURN HER !
> + Dialogue:
> 0,0:00:03.30,0:00:07.07,Default,,0,0,0,,{\an7}{\pos(38,197)}HOW DO YOU
> KNOW\N{\an7}{\pos(38,213)}SHE IS A WITCH ?\N{\an7}{\pos(153,243)}SHE LOOKS
> LIKE ONE !
> + Dialogue:
> 0,0:00:07.07,0:00:09.27,Default,,0,0,0,,{\an7}{\pos(192,228)}[
> Shouting\N{\an7}{\pos(192,243)}\h\hAffirmations ]
> +
> ## tests/ref/fate/sub2video ##
> @@
> 0, 47, 47, 1, 518400, 0xde69683f
> 23: a66debd96e = 25: a90a6e1086 avcodec/dvbsubdec: Fix conditions for
> fallback to default resolution
>
> --
> ffmpeg-codebot
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel at ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request at ffmpeg.org with subject "unsubscribe".
>
More information about the ffmpeg-devel
mailing list