[FFmpeg-devel] [PATCH 5/9] avfilter/sub2video: Add sub2video filter
Soft Works
softworkz at hotmail.com
Thu Aug 19 10:43:22 EEST 2021
Signed-off-by: softworkz <softworkz at hotmail.com>
---
libavfilter/Makefile | 1 +
libavfilter/allfilters.c | 1 +
libavfilter/svf_sub2video.c | 260 ++++++++++++++++++++++++++++++++++++
3 files changed, 262 insertions(+)
create mode 100644 libavfilter/svf_sub2video.c
diff --git a/libavfilter/Makefile b/libavfilter/Makefile
index 68a7f5cb88..5f63ec0123 100644
--- a/libavfilter/Makefile
+++ b/libavfilter/Makefile
@@ -542,6 +542,7 @@ OBJS-$(CONFIG_SHOWSPECTRUMPIC_FILTER) += avf_showspectrum.o
OBJS-$(CONFIG_SHOWVOLUME_FILTER) += avf_showvolume.o
OBJS-$(CONFIG_SHOWWAVES_FILTER) += avf_showwaves.o
OBJS-$(CONFIG_SHOWWAVESPIC_FILTER) += avf_showwaves.o
+OBJS-$(CONFIG_SUB2VIDEO_FILTER) += svf_sub2video.o
OBJS-$(CONFIG_SPECTRUMSYNTH_FILTER) += vaf_spectrumsynth.o
# multimedia sources
diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c
index abd0a47750..5b631b3617 100644
--- a/libavfilter/allfilters.c
+++ b/libavfilter/allfilters.c
@@ -518,6 +518,7 @@ 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_sub2video;
/* multimedia sources */
extern const AVFilter ff_avsrc_amovie;
diff --git a/libavfilter/svf_sub2video.c b/libavfilter/svf_sub2video.c
new file mode 100644
index 0000000000..689c2a565c
--- /dev/null
+++ b/libavfilter/svf_sub2video.c
@@ -0,0 +1,260 @@
+/*
+ * Copyright (c) 2021 softworkz
+ *
+ * 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
+ */
+
+/**
+ * @file
+ * graphical subtitles to video conversion, based on previous sub2video
+ * implementation.
+ */
+
+#include <math.h>
+
+#include "libavutil/audio_fifo.h"
+#include "libavutil/avassert.h"
+#include "libavutil/avstring.h"
+#include "libavutil/channel_layout.h"
+#include "libavutil/opt.h"
+#include "libavutil/parseutils.h"
+#include "libavutil/xga_font_data.h"
+#include "avfilter.h"
+#include "blend.h"
+#include "filters.h"
+#include "internal.h"
+#include "libavcodec/avcodec.h"
+typedef struct Sub2VideoContext {
+ const AVClass *class;
+ int w, h;
+ AVFrame *outpicref;
+ int pixstep;
+} Sub2VideoContext;
+
+#define OFFSET(x) offsetof(Sub2VideoContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+
+////static int alloc_out_frame(Sub2VideoContext *s2v_ctx, const int16_t *p,
+//// const AVFilterLink *inlink, AVFilterLink *outlink,
+//// const AVFrame *in)
+////{
+//// if (!s2v_ctx->outpicref) {
+//// int j;
+//// AVFrame *out = s2v_ctx->outpicref =
+//// ff_get_video_buffer(outlink, outlink->w, outlink->h);
+//// if (!out)
+//// return AVERROR(ENOMEM);
+//// out->width = outlink->w;
+//// out->height = outlink->h;
+//// out->pts = in->pts + av_rescale_q((p - (int16_t *)in->data[0]) / inlink->channels,
+//// av_make_q(1, inlink->sample_rate),
+//// outlink->time_base);
+//// for (j = 0; j < outlink->h; j++)
+//// memset(out->data[0] + j*out->linesize[0], 0, outlink->w * s2v_ctx->pixstep);
+//// }
+//// return 0;
+////}
+
+
+static const AVOption sub2video_options[] = {
+ { "size", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = "640x512"}, 0, 0, FLAGS },
+ { "s", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = "640x512"}, 0, 0, FLAGS },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(sub2video);
+
+static int query_formats(AVFilterContext *ctx)
+{
+ AVFilterFormats *formats = NULL;
+ AVFilterLink *inlink = ctx->inputs[0];
+ AVFilterLink *outlink = ctx->outputs[0];
+ static const enum AVSubtitleType subtitle_fmts[] = { SUBTITLE_BITMAP, SUBTITLE_NONE };
+ static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_RGB32, AV_PIX_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 */
+ formats = ff_make_format_list(pix_fmts);
+ if ((ret = ff_formats_ref(formats, &outlink->incfg.formats)) < 0)
+ return ret;
+
+ return 0;
+}
+
+static int config_input(AVFilterLink *inlink)
+{
+ AVFilterContext *ctx = inlink->dst;
+ Sub2VideoContext *s = ctx->priv;
+
+ s->w = 1920; // inlink->w;
+ s->h = 1080; // inlink->h;
+ return 0;
+}
+
+static int config_output(AVFilterLink *outlink)
+{
+ Sub2VideoContext *s = outlink->src->priv;
+ float overlap;
+
+ outlink->w = s->w;
+ outlink->h = s->h;
+ outlink->sample_aspect_ratio = (AVRational){1,1};
+
+ return 0;
+}
+
+static void sub2video_copy_rect(uint8_t *dst, int dst_linesize, int w, int h,
+ AVSubtitleRect *r)
+{
+ uint32_t *pal, *dst2;
+ uint8_t *src, *src2;
+ int x, y;
+
+ if (r->type != SUBTITLE_BITMAP) {
+ av_log(NULL, AV_LOG_WARNING, "sub2video: non-bitmap subtitle\n");
+ return;
+ }
+ if (r->x < 0 || r->x + r->w > w || r->y < 0 || r->y + r->h > h) {
+ av_log(NULL, AV_LOG_WARNING, "sub2video: rectangle (%d %d %d %d) overflowing %d %d\n",
+ r->x, r->y, r->w, r->h, w, h
+ );
+ return;
+ }
+
+ dst += r->y * dst_linesize + r->x * 4;
+ src = r->data[0];
+ pal = (uint32_t *)r->data[1];
+ for (y = 0; y < r->h; y++) {
+ dst2 = (uint32_t *)dst;
+ src2 = src;
+ for (x = 0; x < r->w; x++)
+ *(dst2++) = pal[*(src2++)];
+ dst += dst_linesize;
+ src += r->linesize[0];
+ }
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *src_frame)
+{
+ Sub2VideoContext *s = inlink->dst->priv;
+ AVFilterLink *outlink = inlink->dst->outputs[0];
+ AVSubtitle *sub;
+ int ret;
+ int dst_linesize;
+ AVFrame *out;
+ unsigned int num_rects, i;
+ uint8_t *dst;
+
+ outlink->w = 1920;
+ outlink->h = 1080;
+
+ out = av_frame_alloc();
+ if (!out) {
+ av_frame_free(&src_frame);
+ return AVERROR(ENOMEM);
+ }
+
+ out->width = outlink->w;
+ out->height = outlink->h;
+ out->format = AV_PIX_FMT_RGB32;
+
+ if ((ret = av_frame_get_buffer(out, 0)) < 0)
+ return ret;
+
+ memset(out->data[0], 0, out->height * out->linesize[0]);
+
+ ////out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ ////if (!out) {
+ //// av_frame_free(&src_frame);
+ //// return AVERROR(ENOMEM);
+ ////}
+ ////memset(out->data[0], 0, out->linesize[0] * out->height );
+
+ out->pts = src_frame->pts;
+ out->repeat_pict = src_frame->repeat_pict;
+ out->pkt_dts = src_frame->pkt_dts;
+ out->pkt_pos = src_frame->pkt_pos;
+ out->pkt_size = src_frame->pkt_size;
+ out->pkt_duration = src_frame->pkt_duration;
+ out->reordered_opaque = src_frame->reordered_opaque;
+ out->best_effort_timestamp = src_frame->best_effort_timestamp;
+ out->flags = src_frame->flags;
+
+ sub = (AVSubtitle *)src_frame->data[0];
+
+ if (sub) {
+ num_rects = sub->num_rects;
+ dst = out->data [0];
+ dst_linesize = out->linesize[0];
+ for (i = 0; i < num_rects; i++)
+ sub2video_copy_rect(dst, dst_linesize, out->width, out->height, sub->rects[i]);
+ }
+
+ av_frame_free(&src_frame);
+ return ff_filter_frame(outlink, out);
+}
+
+////static int activate(AVFilterContext *ctx)
+////{
+//// AVFilterLink *inlink = ctx->inputs[0];
+//// AVFilterLink *outlink = ctx->outputs[0];
+//// Sub2VideoContext *s = ctx->priv;
+////
+//// do {
+//// int ret = ff_outlink_get_status(outlink);
+//// if (ret) {
+//// ff_inlink_set_status(inlink, ret);
+//// return 0;
+//// }
+//// } while (0);
+////
+//// return FFERROR_NOT_READY;
+////}
+
+static const AVFilterPad sub2video_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_SUBTITLE,
+ .filter_frame = filter_frame,
+ .config_props = config_input,
+ },
+ { NULL }
+};
+
+static const AVFilterPad sub2video_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_output,
+ },
+ { NULL }
+};
+
+AVFilter ff_svf_sub2video = {
+ .name = "sub2video",
+ .description = NULL_IF_CONFIG_SMALL("Convert graphical subtitles to video"),
+ .query_formats = query_formats,
+ .priv_size = sizeof(Sub2VideoContext),
+ .priv_class = &sub2video_class,
+ .inputs = sub2video_inputs,
+ .outputs = sub2video_outputs,
+};
--
2.28.0.windows.1
More information about the ffmpeg-devel
mailing list