[FFmpeg-devel] [PATCH v5 10/12] avfilter/textmod: Add textmod filter
Lynne
dev at lynne.ee
Mon Sep 13 03:10:50 EEST 2021
13 Sept 2021, 00:34 by softworkz at hotmail.com:
>
>
>> -----Original Message-----
>> From: ffmpeg-devel <ffmpeg-devel-bounces at ffmpeg.org> On Behalf Of
>> Andreas Rheinhardt
>> Sent: Sunday, 12 September 2021 23:56
>> To: ffmpeg-devel at ffmpeg.org
>> Subject: Re: [FFmpeg-devel] [PATCH v5 10/12] avfilter/textmod: Add
>> textmod filter
>>
>> Soft Works:
>> > Signed-off-by: softworkz <softworkz at hotmail.com>
>> > ---
>> > doc/filters.texi | 64 +++++++
>> > libavfilter/Makefile | 3 +
>> > libavfilter/allfilters.c | 1 +
>> > libavfilter/sf_textmod.c | 381
>> +++++++++++++++++++++++++++++++++++++++
>> > 4 files changed, 449 insertions(+)
>> > create mode 100644 libavfilter/sf_textmod.c
>> >
>> > diff --git a/doc/filters.texi b/doc/filters.texi
>> > index 1d76461ada..9fd2876d63 100644
>> > --- a/doc/filters.texi
>> > +++ b/doc/filters.texi
>> > @@ -25024,6 +25024,70 @@ existing filters using @code{--disable-
>> filters}.
>>
>
> [...]
>
>> > +static void uninit(AVFilterContext *ctx)
>> > +{
>> > + TextModContext *s = ctx->priv;
>> > + int i;
>> > +
>> > + for (i = 0; i < s->nb_find_list; i++) {
>> > + av_free(&s->find_list[i]);
>>
>> This is completely wrong and will crash: You either want to do
>> av_freep(&s->find_list[i]) or av_free(s->find_list[i]) if these
>> strings
>> were independently allocated; but looking at split_string() shows
>> that
>> they are not, they are substrings of s->find. Similar for the loop
>> below.
>>
>
> You are right of course, thanks.
>
>> > + }
>> > + s->nb_find_list = 0;
>> > + av_freep(&s->find_list);
>> > +
>> > + for (i = 0; i < s->nb_replace_list; i++) {
>> > + av_free(&s->replace_list[i]);
>> > + }
>> > + s->nb_replace_list = 0;
>> > + av_freep(&s->replace_list);
>> > +}
>> > +
>> > +static int query_formats(AVFilterContext *ctx)
>> > +{
>> > + AVFilterFormats *formats;
>> > + AVFilterLink *inlink = ctx->inputs[0];
>> > + AVFilterLink *outlink = ctx->outputs[0];
>> > + static const enum AVSubtitleType subtitle_fmts[] = {
>> AV_SUBTITLE_FMT_ASS, AV_SUBTITLE_FMT_NONE };
>> > + int ret;
>> > +
>> > + /* set input subtitle format */
>> > + formats = ff_make_format_list(subtitle_fmts);
>> > + if ((ret = ff_formats_ref(formats, &inlink->outcfg.formats)) <
>> 0)
>> > + return ret;
>> > +
>> > + /* set output video format */
>> > + if ((ret = ff_formats_ref(formats, &outlink->incfg.formats)) <
>> 0)
>> > + return ret;
>> > +
>> > + return 0;
>> > +}
>> > +
>> > +static char *process_text(TextModContext *s, char *text)
>> > +{
>> > + const char *char_src = s->find;
>> > + const char *char_dst = s->replace;
>> > + char *result = NULL;
>> > + int escape_level = 0, k = 0;
>> > +
>> > + switch (s->operation) {
>> > + case OP_LEET:
>> > + case OP_REPLACE_CHARS:
>> > +
>> > + if (s->operation == OP_LEET) {
>> > + char_src = leet_src;
>> > + char_dst = leet_dst;
>> > + }
>> > +
>> > + result = av_strdup(text);
>> > + if (!result)
>> > + return NULL;
>> > +
>> > + for (size_t n = 0; n < strlen(result); n++) {
>> > + if (result[n] == '{')
>> > + escape_level++;
>> > +
>> > + if (!escape_level) {
>> > + for (size_t t = 0; t < FF_ARRAY_ELEMS(char_src);
>> t++) {
>> > + if (result[n] == char_src[t]) {
>> > + result[n] = char_dst[t];
>> > + break;
>> > + }
>> > + }
>> > + }
>> > +
>> > + if (result[n] == '}')
>> > + escape_level--;
>> > + }
>> > +
>> > + break;
>> > + case OP_TO_UPPER:
>> > + case OP_TO_LOWER:
>> > +
>> > + result = av_strdup(text);
>> > + if (!result)
>> > + return NULL;
>> > +
>> > + for (size_t n = 0; n < strlen(result); n++) {
>> > + if (result[n] == '{')
>> > + escape_level++;
>> > + if (!escape_level)
>> > + result[n] = s->operation == OP_TO_LOWER ?
>> av_tolower(result[n]) : av_toupper(result[n]);
>> > + if (result[n] == '}')
>> > + escape_level--;
>> > + }
>> > +
>> > + break;
>> > + case OP_REMOVE_CHARS:
>> > +
>> > + result = av_strdup(text);
>> > + if (!result)
>> > + return NULL;
>> > +
>> > + for (size_t n = 0; n < strlen(result); n++) {
>> > + int skip_char = 0;
>> > +
>> > + if (result[n] == '{')
>> > + escape_level++;
>> > +
>> > + if (!escape_level) {
>> > + for (size_t t = 0; t < FF_ARRAY_ELEMS(char_src);
>> t++) {
>> > + if (result[n] == char_src[t]) {
>> > + skip_char = 1;
>> > + break;
>> > + }
>> > + }
>> > + }
>> > +
>> > + if (!skip_char)
>> > + result[k++] = result[n];
>> > +
>> > + if (result[n] == '}')
>> > + escape_level--;
>> > + }
>> > +
>> > + result[k] = 0;
>> > +
>> > + break;
>> > + case OP_REPLACE_WORDS:
>> > + case OP_REMOVE_WORDS:
>> > +
>> > + result = av_strdup(text);
>> > + if (!result)
>> > + return NULL;
>> > +
>> > + for (int n = 0; n < s->nb_find_list; n++) {
>> > + char *tmp = result;
>> > + const char *replace = (s->operation ==
>> OP_REPLACE_WORDS) ? s->replace_list[n] : "";
>> > +
>> > + result = av_strireplace(result, s->find_list[n],
>> replace);
>> > + if (!result)
>> > + return NULL;
>> > +
>> > + av_free(tmp);
>> > + }
>> > +
>> > + break;
>> > + }
>> > +
>> > + return result;
>> > +}
>> > +
>> > +static char *process_dialog(TextModContext *s, char *ass_line)
>> > +{
>> > + ASSDialog *dialog = ff_ass_split_dialog(NULL, ass_line);
>> > + char *result, *text;
>> > +
>> > + if (!dialog)
>> > + return NULL;
>> > +
>> > + text = process_text(s, dialog->text);
>> > + if (!text)
>> > + return NULL;
>> > +
>> > + result = ff_ass_get_dialog(dialog->readorder, dialog->layer,
>> dialog->style, dialog->name, text);
>> > +
>> > + av_free(text);
>> > + ff_ass_free_dialog(&dialog);
>> > + return result;
>> > +}
>> > +
>> > +static int filter_frame(AVFilterLink *inlink, AVFrame *src_frame)
>> > +{
>> > + TextModContext *s = inlink->dst->priv;
>> > + AVFilterLink *outlink = inlink->dst->outputs[0];
>> > + int ret;
>> > + AVFrame *out;
>> > +
>> > + outlink->format = inlink->format;
>> > +
>> > + out = av_frame_clone(src_frame);
>>
>> Why clone? You can just reuse src_frame as is.
>>
>
> [..]
>
>>
>> You may not be the sole owner of this AVSubtitleRect; after all,
>> they are shared. Ergo you must not modify it. Is it possible that you
>> believed that av_frame_clone() would make the frame writable? It does
>> not. For non-subtitle frames, av_frame_make_writable() makes them
>> writable; but it does not for subtitles, because you made
>> av_frame_get_buffer2() a no-op for subtitles and so
>> av_frame_make_writable() will temporarily increment the refcount and
>> then decrement it again.
>>
>
> One unsolved problem I have about dealing with AVSubtitleRect
> as being part of AVFrame is that it's not possible to make a copy,
> in a reliable way because the allocated sizes of the data[4] pointers
> are not reliably known.
>
We have cropping fields and cropping side data (IIRC) now,
can they be used for this?
> Usually, data[0] is the image and data[1] is the palette, but will
> it always be like this? Then better not have a data array but
> named pointer variables instead.
>
>
> I was not sure what will be the general route: Merging AVSubtitle
> into AVFrame or attaching AVSubtitle as a property to AVFrame.
>
I think that's not really the best way to go. Subtitles ought to
be contained in the data[] fields and described by the other
fields like with audio and video. While we do sometimes
have data[] contain pointers to structs (hardware frames),
for this case it's a crude solution.
More information about the ffmpeg-devel
mailing list