Signed-off-by: softworkz <softwo...@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 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".