History

lavfi: add qrencode source and filter

Stefano Sabatini committed 2 years ago

Commit 899302b1 parent 732fb126 files · +1259 −0Browse files

Unified · Split

6 files
  1. Changelog +1 −0
  2. configure +7 −0
  3. doc/filters.texi +427 −0
  4. libavfilter/Makefile +2 −0
  5. libavfilter/allfilters.c +2 −0
  6. libavfilter/qrencode.c +820 −0
Changelog+1−0
@@ -13,6 +13,7 @@ version <next>: · 12 unmodified lines
1313 - IAMF raw demuxer and muxer
1414 - D3D12VA hardware accelerated H264, HEVC, VP9, AV1, MPEG-2 and VC1 decoding
1515 - tiltandshift filter
16+- qrencode filter and qrencodesrc source
1617
1718 version 6.1:
1819 - libaribcaption decoder
configure+7−0
@@ -256,6 +256,7 @@ External library support: · 255 unmodified lines
256256 --enable-libopus enable Opus de/encoding via libopus [no]
257257 --enable-libplacebo enable libplacebo library [no]
258258 --enable-libpulse enable Pulseaudio input via libpulse [no]
259+ --enable-libqrencode enable QR encode generation via libqrencode [no]
259260 --enable-librabbitmq enable RabbitMQ library [no]
260261 --enable-librav1e enable AV1 encoding via rav1e [no]
261262 --enable-librist enable RIST via librist [no]
@@ -1881,6 +1882,7 @@ EXTERNAL_LIBRARY_LIST=" · 1619 unmodified lines
18811882 libopus
18821883 libplacebo
18831884 libpulse
1885+ libqrencode
18841886 librabbitmq
18851887 librav1e
18861888 librist
@@ -3789,6 +3791,8 @@ nnedi_filter_deps="gpl" · 1902 unmodified lines
37893791 ocr_filter_deps="libtesseract"
37903792 ocv_filter_deps="libopencv"
37913793 openclsrc_filter_deps="opencl"
3794+qrencode_filter_deps="libqrencode"
3795+qrencodesrc_filter_deps="libqrencode"
37923796 overlay_opencl_filter_deps="opencl"
37933797 overlay_qsv_filter_deps="libmfx"
37943798 overlay_qsv_filter_select="qsvvpp"
@@ -6840,6 +6844,7 @@ enabled libopus && { · 3045 unmodified lines
68406844 }
68416845 enabled libplacebo && require_pkg_config libplacebo "libplacebo >= 4.192.0" libplacebo/vulkan.h pl_vulkan_create
68426846 enabled libpulse && require_pkg_config libpulse libpulse pulse/pulseaudio.h pa_context_new
6847+enabled libqrencode && require_pkg_config libqrencode libqrencode qrencode.h QRcode_encodeString
68436848 enabled librabbitmq && require_pkg_config librabbitmq "librabbitmq >= 0.7.1" amqp.h amqp_new_connection
68446849 enabled librav1e && require_pkg_config librav1e "rav1e >= 0.5.0" rav1e.h rav1e_context_new
68456850 enabled librist && require_pkg_config librist "librist >= 0.2.7" librist/librist.h rist_receiver_create
@@ -7668,6 +7673,8 @@ enabled mcdeint_filter && prepend avfilter_deps "avcodec" · 822 unmodified lines
76687673 enabled movie_filter && prepend avfilter_deps "avformat avcodec"
76697674 enabled pan_filter && prepend avfilter_deps "swresample"
76707675 enabled pp_filter && prepend avfilter_deps "postproc"
7676+enabled qrencode_filter && prepend_avfilter_deps "swscale"
7677+enabled qrencodesrc_filter && prepend_avfilter_deps "swscale"
76717678 enabled removelogo_filter && prepend avfilter_deps "avformat avcodec swscale"
76727679 enabled sab_filter && prepend avfilter_deps "swscale"
76737680 enabled scale_filter && prepend avfilter_deps "swscale"
doc/filters.texi+427−0
@@ -20096,6 +20096,302 @@ qp=2+2*sin(PI*qp) · 20095 unmodified lines
2009620096 @end example
2009720097 @end itemize
2009820098
20099+@section qrencode
20100+Generate a QR code using the libqrencode library (see
20101+@url{https://fukuchi.org/works/qrencode/}), and overlay it on top of the current
20102+frame.
20103+
20104+To enable the compilation of this filter, you need to configure FFmpeg with with
20105+@code{--enable-libqrencode}.
20106+
20107+The QR code is generated from the provided text or text pattern. The
20108+corresponding QR code is scaled and overlayed into the video output according to
20109+the specified options.
20110+
20111+In case no text is specified, no QR code is overlaied.
20112+
20113+This filter accepts the following options:
20114+
20115+@table @option
20116+
20117+@item qrcode_width, q
20118+@item padded_qrcode_width, Q
20119+Specify an expression for the width of the rendered QR code, with and without
20120+padding. The @var{qrcode_width} expression can reference the value set by the
20121+@var{padded_qrcode_width} expression, and vice versa.
20122+By default @var{padded_qrcode_width} is set to @var{qrcode_width}, meaning that
20123+there is no padding.
20124+
20125+These expressions are evaluated for each new frame.
20126+
20127+See the @ref{qrencode_expressions,,qrencode Expressions} section for details.
20128+
20129+@item x
20130+@item y
20131+Specify an expression for positioning the padded QR code top-left corner. The
20132+@var{x} expression can reference the value set by the @var{y} expression, and
20133+vice.
20134+
20135+By default @var{x} and @var{y} are set set to @var{0}, meaning that the QR code
20136+is placed in the top left corner of the input.
20137+
20138+These expressions are evaluated for each new frame.
20139+
20140+See the @ref{qrencode_expressions,,qrencode Expressions} section for details.
20141+
20142+@item case_sensitive, cs
20143+Instruct libqrencode to use case sensitive encoding. This is enabled by
20144+default. This can be disabled to reduce the QR encoding size.
20145+
20146+@item level, l
20147+Specify the QR encoding error correction level. With an higher correction level,
20148+the encoding size will increase but the code will be more robust to corruption.
20149+Lower level is @var{L}.
20150+
20151+It accepts the following values:
20152+@table @samp
20153+@item L
20154+@item M
20155+@item Q
20156+@item H
20157+@end table
20158+
20159+@item expansion
20160+Select how the input text is expanded. Can be either @code{none}, or
20161+@code{normal} (default). See the @ref{qrencode_text_expansion,,qrencode Text expansion}
20162+section below for details.
20163+
20164+@item text
20165+@item textfile
20166+Define the text to be rendered. In case neither is specified, no QR is encoded
20167+(just an empty colored frame).
20168+
20169+In case expansion is enabled, the text is treated as a text template, using the
20170+qrencode expansion mechanism. See the @ref{qrencode_text_expansion,,qrencode
20171+Text expansion} section below for details.
20172+
20173+@item background_color, bc
20174+@item foreground_color, fc
20175+Set the QR code and background color. The default value of
20176+@var{foreground_color} is "black", the default value of @var{background_color}
20177+is "white".
20178+
20179+For the syntax of the color options, check the @ref{color syntax,,"Color"
20180+section in the ffmpeg-utils manual,ffmpeg-utils}.
20181+@end table
20182+
20183+@anchor{qrencode_expressions}
20184+@subsection qrencode Expressions
20185+
20186+The expressions set by the options contain the following constants and functions.
20187+
20188+@table @option
20189+@item dar
20190+input display aspect ratio, it is the same as (@var{w} / @var{h}) * @var{sar}
20191+
20192+@item duration
20193+the current frame's duration, in seconds
20194+
20195+@item hsub
20196+@item vsub
20197+horizontal and vertical chroma subsample values. For example for the
20198+pixel format "yuv422p" @var{hsub} is 2 and @var{vsub} is 1.
20199+
20200+@item main_h, H
20201+the input height
20202+
20203+@item main_w, W
20204+the input width
20205+
20206+@item n
20207+the number of input frame, starting from 0
20208+
20209+@item pict_type
20210+a number representing the picture type
20211+
20212+@item qr_w, w
20213+the width of the encoded QR code
20214+
20215+@item rendered_qr_w, q
20216+@item rendered_padded_qr_w, Q
20217+the width of the rendered QR code, without and without padding.
20218+
20219+These parameters allow the @var{q} and @var{Q} expressions to refer to each
20220+other, so you can for example specify @code{q=3/4*Q}.
20221+
20222+@item rand(min, max)
20223+return a random number included between @var{min} and @var{max}
20224+
20225+@item sar
20226+the input sample aspect ratio
20227+
20228+@item t
20229+timestamp expressed in seconds, NAN if the input timestamp is unknown
20230+
20231+@item x
20232+@item y
20233+the x and y offset coordinates where the text is drawn.
20234+
20235+These parameters allow the @var{x} and @var{y} expressions to refer to each
20236+other, so you can for example specify @code{y=x/dar}.
20237+@end table
20238+
20239+@anchor{qrencode_text_expansion}
20240+@subsection qrencode Text expansion
20241+
20242+If @option{expansion} is set to @code{none}, the text is printed verbatim.
20243+
20244+If @option{expansion} is set to @code{normal} (which is the default),
20245+the following expansion mechanism is used.
20246+
20247+The backslash character @samp{\}, followed by any character, always expands to
20248+the second character.
20249+
20250+Sequences of the form @code{%@{...@}} are expanded. The text between the
20251+braces is a function name, possibly followed by arguments separated by ':'.
20252+If the arguments contain special characters or delimiters (':' or '@}'),
20253+they should be escaped.
20254+
20255+Note that they probably must also be escaped as the value for the @option{text}
20256+option in the filter argument string and as the filter argument in the
20257+filtergraph description, and possibly also for the shell, that makes up to four
20258+levels of escaping; using a text file with the @option{textfile} option avoids
20259+these problems.
20260+
20261+The following functions are available:
20262+
20263+@table @command
20264+@item n, frame_num
20265+return the frame number
20266+
20267+@item pts
20268+Return the presentation timestamp of the current frame.
20269+
20270+It can take up to two arguments.
20271+
20272+The first argument is the format of the timestamp; it defaults to @code{flt} for
20273+seconds as a decimal number with microsecond accuracy; @code{hms} stands for a
20274+formatted @var{[-]HH:MM:SS.mmm} timestamp with millisecond accuracy.
20275+@code{gmtime} stands for the timestamp of the frame formatted as UTC time;
20276+@code{localtime} stands for the timestamp of the frame formatted as local time
20277+zone time. If the format is set to @code{hms24hh}, the time is formatted in 24h
20278+format (00-23).
20279+
20280+The second argument is an offset added to the timestamp.
20281+
20282+If the format is set to @code{localtime} or @code{gmtime}, a third argument may
20283+be supplied: a @code{strftime} C function format string. By default,
20284+@var{YYYY-MM-DD HH:MM:SS} format will be used.
20285+
20286+@item expr, e
20287+Evaluate the expression's value and output as a double.
20288+
20289+It must take one argument specifying the expression to be evaluated, accepting
20290+the constants and functions defined in @ref{qrencode_expressions}.
20291+
20292+@item expr_formatted, ef
20293+Evaluate the expression's value and output as a formatted string.
20294+
20295+The first argument is the expression to be evaluated, just as for the @var{expr} function.
20296+The second argument specifies the output format. Allowed values are @samp{x},
20297+@samp{X}, @samp{d} and @samp{u}. They are treated exactly as in the
20298+@code{printf} function.
20299+The third parameter is optional and sets the number of positions taken by the output.
20300+It can be used to add padding with zeros from the left.
20301+
20302+@item gmtime
20303+The time at which the filter is running, expressed in UTC.
20304+It can accept an argument: a @code{strftime} C function format string.
20305+The format string is extended to support the variable @var{%[1-6]N}
20306+which prints fractions of the second with optionally specified number of digits.
20307+
20308+@item localtime
20309+The time at which the filter is running, expressed in the local time zone.
20310+It can accept an argument: a @code{strftime} C function format string.
20311+The format string is extended to support the variable @var{%[1-6]N}
20312+which prints fractions of the second with optionally specified number of digits.
20313+
20314+@item metadata
20315+Frame metadata. Takes one or two arguments.
20316+
20317+The first argument is mandatory and specifies the metadata key.
20318+
20319+The second argument is optional and specifies a default value, used when the
20320+metadata key is not found or empty.
20321+
20322+Available metadata can be identified by inspecting entries starting with TAG
20323+included within each frame section printed by running @code{ffprobe
20324+-show_frames}.
20325+
20326+String metadata generated in filters leading to the qrencode filter are also
20327+available.
20328+
20329+@item rand(min, max)
20330+return a random number included between @var{min} and @var{max}
20331+@end table
20332+
20333+@subsection Examples
20334+
20335+@itemize
20336+@item
20337+Generate a QR code encoding the specified text with the default size, overalaid
20338+in the top left corner of the input video, with the default size:
20339+@example
20340+qrencode=text=www.ffmpeg.org
20341+@end example
20342+
20343+@item
20344+Same as below, but select blue on pink colors:
20345+@example
20346+qrencode=text=www.ffmpeg.org:bc=pink@@0.5:fc=blue
20347+@end example
20348+
20349+@item
20350+Place the QR code in the bottom right corner of the input video:
20351+@example
20352+qrencode=text=www.ffmpeg.org:x=W-Q:y=H-Q
20353+@end example
20354+
20355+@item
20356+Generate a QR code with width of 200 pixels and padding, making the padded width
20357+4/3 of the QR code width:
20358+@example
20359+qrencode=text=www.ffmpeg.org:q=200:Q=4/3*q
20360+@end example
20361+
20362+@item
20363+Generate a QR code with padded width of 200 pixels and padding, making the QR
20364+code width 3/4 of the padded width:
20365+@example
20366+qrencode=text=www.ffmpeg.org:Q=200:q=3/4*Q
20367+@end example
20368+
20369+@item
20370+Make the QR code a fraction of the input video width:
20371+@example
20372+qrencode=text=www.ffmpeg.org:q=W/5
20373+@end example
20374+
20375+@item
20376+Generate a QR code encoding the frame number:
20377+@example
20378+qrencode=text=%@{n@}
20379+@end example
20380+
20381+@item
20382+Generate a QR code encoding the GMT timestamp:
20383+@example
20384+qrencode=text=%@{gmtime@}
20385+@end example
20386+
20387+@item
20388+Generate a QR code encoding the timestamp expressed as a float:
20389+@example
20390+qrencode=text=%@{pts@}
20391+@end example
20392+
20393+@end itemize
20394+
2009920395 @section random
2010020396
2010120397 Flush video frames from internal cache of frames into a random order.
@@ -28749,6 +29045,137 @@ ffplay -f lavfi life=s=300x200:mold=10:r=60:ratio=0.1:death_color=#C83232:life_c · 8647 unmodified lines
2874929045 @end example
2875029046 @end itemize
2875129047
29048+@section qrencodesrc
29049+
29050+Generate a QR code using the libqrencode library (see
29051+@url{https://fukuchi.org/works/qrencode/}).
29052+
29053+To enable the compilation of this source, you need to configure FFmpeg with with
29054+@code{--enable-libqrencode}.
29055+
29056+The QR code is generated from the provided text or text pattern. The
29057+corresponding QR code is scaled and put in the video output according to the
29058+specified output size options.
29059+
29060+In case no text is specified, the QR code is not generated, but an empty colored
29061+output is returned instead.
29062+
29063+This source accepts the following options:
29064+
29065+@table @option
29066+
29067+@item qrcode_width, q
29068+@item padded_qrcode_width, Q
29069+Specify an expression for the width of the rendered QR code, with and without
29070+padding. The @var{qrcode_width} expression can reference the value set by the
29071+@var{padded_qrcode_width} expression, and vice versa.
29072+By default @var{padded_qrcode_width} is set to @var{qrcode_width}, meaning that
29073+there is no padding.
29074+
29075+These expressions are evaluated only once, when initializing the source.
29076+See the @ref{qrencode_expressions,,qrencode Expressions} section for details.
29077+
29078+Note that some of the constants are missing for the source (for example the
29079+@var{x} or @var{t} or ¸@var{n}), since they only makes sense when evaluating the
29080+expression for each frame rather than at initialization time.
29081+
29082+@item rate, r
29083+Specify the frame rate of the sourced video, as the number of frames
29084+generated per second. It has to be a string in the format
29085+@var{frame_rate_num}/@var{frame_rate_den}, an integer number, a floating point
29086+number or a valid video frame rate abbreviation. The default value is
29087+"25".
29088+
29089+@item case_sensitive, cs
29090+Instruct libqrencode to use case sensitive encoding. This is enabled by
29091+default. This can be disabled to reduce the QR encoding size.
29092+
29093+@item level, l
29094+Specify the QR encoding error correction level. With an higher correction level,
29095+the encoding size will increase but the code will be more robust to corruption.
29096+Lower level is @var{L}.
29097+
29098+It accepts the following values:
29099+@table @samp
29100+@item L
29101+@item M
29102+@item Q
29103+@item H
29104+@end table
29105+
29106+@item expansion
29107+Select how the input text is expanded. Can be either @code{none}, or
29108+@code{normal} (default). See the @ref{qrencode_text_expansion,,qrencode Text expansion}
29109+section for details.
29110+
29111+@item text
29112+@item textfile
29113+Define the text to be rendered. In case neither is specified, no QR is encoded
29114+(just an empty colored frame).
29115+
29116+In case expansion is enabled, the text is treated as a text template, using the
29117+qrencode expansion mechanism. See the @ref{qrencode_text_expansion,,qrencode
29118+Text expansion} section for details.
29119+
29120+@item background_color, bc
29121+@item foreground_color, fc
29122+Set the QR code and background color. The default value of
29123+@var{foreground_color} is "black", the default value of @var{background_color}
29124+is "white".
29125+
29126+For the syntax of the color options, check the @ref{color syntax,,"Color"
29127+section in the ffmpeg-utils manual,ffmpeg-utils}.
29128+@end table
29129+
29130+@subsection Examples
29131+
29132+@itemize
29133+@item
29134+Generate a QR code encoding the specified text with the default size:
29135+@example
29136+qrencodesrc=text=www.ffmpeg.org
29137+@end example
29138+
29139+@item
29140+Same as below, but select blue on pink colors:
29141+@example
29142+qrencodesrc=text=www.ffmpeg.org:bc=pink:fc=blue
29143+@end example
29144+
29145+@item
29146+Generate a QR code with width of 200 pixels and padding, making the padded width
29147+4/3 of the QR code width:
29148+@example
29149+qrencodesrc=text=www.ffmpeg.org:q=200:Q=4/3*q
29150+@end example
29151+
29152+@item
29153+Generate a QR code with padded width of 200 pixels and padding, making the QR
29154+code width 3/4 of the padded width:
29155+@example
29156+qrencodesrc=text=www.ffmpeg.org:Q=200:q=3/4*Q
29157+@end example
29158+
29159+@item
29160+Generate a QR code encoding the frame number:
29161+@example
29162+qrencodesrc=text=%@{n@}
29163+@end example
29164+
29165+@item
29166+Generate a QR code encoding the GMT timestamp:
29167+@example
29168+qrencodesrc=text=%@{gmtime@}
29169+@end example
29170+
29171+@item
29172+Generate a QR code encoding the timestamp expressed as a float:
29173+@example
29174+qrencodesrc=text=%@{pts@}
29175+@end example
29176+
29177+@end itemize
29178+
2875229179 @anchor{allrgb}
2875329180 @anchor{allyuv}
2875429181 @anchor{color}
libavfilter/Makefile+2−0
@@ -599,6 +599,8 @@ OBJS-$(CONFIG_NULLSRC_FILTER) += vsrc_testsrc.o · 598 unmodified lines
599599 OBJS-$(CONFIG_OPENCLSRC_FILTER) += vf_program_opencl.o opencl.o
600600 OBJS-$(CONFIG_PAL75BARS_FILTER) += vsrc_testsrc.o
601601 OBJS-$(CONFIG_PAL100BARS_FILTER) += vsrc_testsrc.o
602+OBJS-$(CONFIG_QRENCODE_FILTER) += qrencode.o textutils.o
603+OBJS-$(CONFIG_QRENCODESRC_FILTER) += qrencode.o textutils.o
602604 OBJS-$(CONFIG_RGBTESTSRC_FILTER) += vsrc_testsrc.o
603605 OBJS-$(CONFIG_SIERPINSKI_FILTER) += vsrc_sierpinski.o
604606 OBJS-$(CONFIG_SMPTEBARS_FILTER) += vsrc_testsrc.o
libavfilter/allfilters.c+2−0
@@ -411,6 +411,7 @@ extern const AVFilter ff_vf_pseudocolor; · 410 unmodified lines
411411 extern const AVFilter ff_vf_psnr;
412412 extern const AVFilter ff_vf_pullup;
413413 extern const AVFilter ff_vf_qp;
414+extern const AVFilter ff_vf_qrencode;
414415 extern const AVFilter ff_vf_random;
415416 extern const AVFilter ff_vf_readeia608;
416417 extern const AVFilter ff_vf_readvitc;
@@ -561,6 +562,7 @@ extern const AVFilter ff_vsrc_mandelbrot; · 144 unmodified lines
561562 extern const AVFilter ff_vsrc_mptestsrc;
562563 extern const AVFilter ff_vsrc_nullsrc;
563564 extern const AVFilter ff_vsrc_openclsrc;
565+extern const AVFilter ff_vsrc_qrencodesrc;
564566 extern const AVFilter ff_vsrc_pal75bars;
565567 extern const AVFilter ff_vsrc_pal100bars;
566568 extern const AVFilter ff_vsrc_rgbtestsrc;
libavfilter/qrencode.c+820−0
@@ -0,0 +1,820 @@
1+/*
2+ * This file is part of FFmpeg.
3+ *
4+ * FFmpeg is free software; you can redistribute it and/or
5+ * modify it under the terms of the GNU Lesser General Public
6+ * License as published by the Free Software Foundation; either
7+ * version 2.1 of the License, or (at your option) any later version.
8+ *
9+ * FFmpeg is distributed in the hope that it will be useful,
10+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12+ * Lesser General Public License for more details.
13+ *
14+ * You should have received a copy of the GNU Lesser General Public
15+ * License along with FFmpeg; if not, write to the Free Software
16+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17+ */
18+
19+/**
20+ * @file QR encoder source and filter.
21+ *
22+ * A QR code (quick-response code) is a type of two-dimensional matrix
23+ * barcode, invented in 1994, by Japanese company Denso Wave for
24+ * labelling automobile parts.
25+ *
26+ * This source uses the libqrencode library to generate QR code:
27+ * https://fukuchi.org/works/qrencode/
28+ */
29+
30+//#define DEBUG
31+
32+#include "config_components.h"
33+
34+#include "libavutil/internal.h"
35+#include "libavutil/imgutils.h"
36+#include "libavutil/opt.h"
37+#include "libavutil/lfg.h"
38+#include "libavutil/random_seed.h"
39+
40+#include "avfilter.h"
41+#include "drawutils.h"
42+#include "internal.h"
43+#include "formats.h"
44+#include "textutils.h"
45+#include "video.h"
46+#include "libswscale/swscale.h"
47+
48+#include <qrencode.h>
49+
50+enum var_name {
51+ VAR_dar,
52+ VAR_duration,
53+ VAR_hsub, VAR_vsub,
54+ VAR_main_h, VAR_H,
55+ VAR_main_w, VAR_W,
56+ VAR_n,
57+ VAR_pict_type,
58+ VAR_qr_w, VAR_w,
59+ VAR_rendered_padded_qr_w, VAR_Q,
60+ VAR_rendered_qr_w, VAR_q,
61+ VAR_sar,
62+ VAR_t,
63+ VAR_x,
64+ VAR_y,
65+ VAR_VARS_NB
66+};
67+
68+static const char *const var_names[] = {
69+ "dar",
70+ "duration",
71+ "hsub", "vsub",
72+ "main_h", "H", ///< height of the input video
73+ "main_w", "W", ///< width of the input video
74+ "n", ///< number of frame
75+ "pict_type",
76+ "qr_w", "w", ///< width of the QR code
77+ "rendered_padded_qr_w", "Q", ///< width of the rendered QR code
78+ "rendered_qr_w", "q", ///< width of the rendered QR code
79+ "sar",
80+ "t", ///< timestamp expressed in seconds
81+ "x",
82+ "y",
83+ NULL
84+};
85+
86+#define V(name_) qr->var_values[VAR_##name_]
87+
88+enum Expansion {
89+ EXPANSION_NONE,
90+ EXPANSION_NORMAL
91+};
92+
93+typedef struct QREncodeContext {
94+ const AVClass *class;
95+
96+ char is_source;
97+ char *x_expr;
98+ char *y_expr;
99+ AVExpr *x_pexpr, *y_pexpr;
100+
101+ char *rendered_qrcode_width_expr;
102+ char *rendered_padded_qrcode_width_expr;
103+ AVExpr *rendered_qrcode_width_pexpr, *rendered_padded_qrcode_width_pexpr;
104+
105+ int rendered_qrcode_width;
106+ int rendered_padded_qrcode_width;
107+
108+ unsigned char *text;
109+ char *textfile;
110+ uint64_t pts;
111+
112+ int level;
113+ char case_sensitive;
114+
115+ uint8_t foreground_color[4];
116+ uint8_t background_color[4];
117+
118+ FFDrawContext draw;
119+ FFDrawColor draw_foreground_color; ///< foreground color
120+ FFDrawColor draw_background_color; ///< background color
121+
122+ /* these are only used when nothing must be encoded */
123+ FFDrawContext draw0;
124+ FFDrawColor draw0_background_color; ///< background color
125+
126+ uint8_t *qrcode_data[4];
127+ int qrcode_linesize[4];
128+ uint8_t *qrcode_mask_data[4];
129+ int qrcode_mask_linesize[4];
130+
131+ /* only used for filter to contain scaled image to blend on top of input */
132+ uint8_t *rendered_qrcode_data[4];
133+ int rendered_qrcode_linesize[4];
134+
135+ int qrcode_width;
136+ int padded_qrcode_width;
137+
138+ AVRational frame_rate;
139+
140+ int expansion; ///< expansion mode to use for the text
141+ FFExpandTextContext expand_text; ///< expand text in case expansion is enabled
142+ AVBPrint expanded_text; ///< used to contain the expanded text
143+
144+ double var_values[VAR_VARS_NB];
145+ AVLFG lfg; ///< random generator
146+ AVDictionary *metadata;
147+} QREncodeContext;
148+
149+#define OFFSET(x) offsetof(QREncodeContext, x)
150+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
151+#define TFLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_RUNTIME_PARAM
152+
153+#define COMMON_OPTIONS \
154+ { "qrcode_width", "set rendered QR code width expression", OFFSET(rendered_qrcode_width_expr), AV_OPT_TYPE_STRING, {.str = "64"}, 0, INT_MAX, FLAGS }, \
155+ { "q", "set rendered QR code width expression", OFFSET(rendered_qrcode_width_expr), AV_OPT_TYPE_STRING, {.str = "64"}, 0, INT_MAX, FLAGS }, \
156+ { "padded_qrcode_width", "set rendered padded QR code width expression", OFFSET(rendered_padded_qrcode_width_expr), AV_OPT_TYPE_STRING, {.str = "q"}, 0, INT_MAX, FLAGS }, \
157+ { "Q", "set rendered padded QR code width expression", OFFSET(rendered_padded_qrcode_width_expr), AV_OPT_TYPE_STRING, {.str = "q"}, 0, INT_MAX, FLAGS }, \
158+ { "case_sensitive", "generate code which is case sensitive", OFFSET(case_sensitive), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, FLAGS }, \
159+ { "cs", "generate code which is case sensitive", OFFSET(case_sensitive), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, FLAGS }, \
160+ \
161+ { "level", "error correction level, lowest is L", OFFSET(level), AV_OPT_TYPE_INT, { .i64 = AVCOL_SPC_UNSPECIFIED }, 0, QR_ECLEVEL_H, .flags = FLAGS, "level"}, \
162+ { "l", "error correction level, lowest is L", OFFSET(level), AV_OPT_TYPE_INT, { .i64 = AVCOL_SPC_UNSPECIFIED }, 0, QR_ECLEVEL_H, .flags = FLAGS, "level"}, \
163+ { "L", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = QR_ECLEVEL_L }, 0, 0, FLAGS, "level" }, \
164+ { "M", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = QR_ECLEVEL_M }, 0, 0, FLAGS, "level" }, \
165+ { "Q", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = QR_ECLEVEL_Q }, 0, 0, FLAGS, "level" }, \
166+ { "H", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = QR_ECLEVEL_H }, 0, 0, FLAGS, "level" }, \
167+ \
168+ {"expansion", "set the expansion mode", OFFSET(expansion), AV_OPT_TYPE_INT, {.i64=EXPANSION_NORMAL}, 0, 2, FLAGS, "expansion"}, \
169+ {"none", "set no expansion", OFFSET(expansion), AV_OPT_TYPE_CONST, {.i64 = EXPANSION_NONE}, 0, 0, FLAGS, "expansion"}, \
170+ {"normal", "set normal expansion", OFFSET(expansion), AV_OPT_TYPE_CONST, {.i64 = EXPANSION_NORMAL}, 0, 0, FLAGS, "expansion"}, \
171+ \
172+ { "foreground_color", "set QR foreground color", OFFSET(foreground_color), AV_OPT_TYPE_COLOR, {.str = "black"}, 0, 0, FLAGS }, \
173+ { "fc", "set QR foreground color", OFFSET(foreground_color), AV_OPT_TYPE_COLOR, {.str = "black"}, 0, 0, FLAGS }, \
174+ { "background_color", "set QR background color", OFFSET(background_color), AV_OPT_TYPE_COLOR, {.str = "white"}, 0, 0, FLAGS }, \
175+ { "bc", "set QR background color", OFFSET(background_color), AV_OPT_TYPE_COLOR, {.str = "white"}, 0, 0, FLAGS }, \
176+ \
177+ {"text", "set text to encode", OFFSET(text), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS}, \
178+ {"textfile", "set text file to encode", OFFSET(textfile), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS}, \
179+
180+static const char *const fun2_names[] = {
181+ "rand"
182+};
183+
184+static double drand(void *opaque, double min, double max)
185+{
186+ return min + (max-min) / UINT_MAX * av_lfg_get(opaque);
187+}
188+
189+static const ff_eval_func2 fun2[] = {
190+ drand,
191+ NULL
192+};
193+
194+static int func_pts(void *ctx, AVBPrint *bp, const char *function_name,
195+ unsigned argc, char **argv)
196+{
197+ QREncodeContext *qr = ((AVFilterContext *)ctx)->priv;
198+ const char *fmt;
199+ const char *strftime_fmt = NULL;
200+ const char *delta = NULL;
201+ double t = qr->var_values[VAR_t];
202+
203+ // argv: pts, FMT, [DELTA, strftime_fmt]
204+
205+ fmt = argc >= 1 ? argv[0] : "flt";
206+ if (argc >= 2) {
207+ delta = argv[1];
208+ }
209+ if (argc >= 3) {
210+ strftime_fmt = argv[2];
211+ }
212+
213+ return ff_print_pts(ctx, bp, t, delta, fmt, strftime_fmt);
214+}
215+
216+static int func_frame_num(void *ctx, AVBPrint *bp, const char *function_name,
217+ unsigned argc, char **argv)
218+{
219+ QREncodeContext *qr = ((AVFilterContext *)ctx)->priv;
220+
221+ av_bprintf(bp, "%d", (int)V(n));
222+ return 0;
223+}
224+
225+static int func_strftime(void *ctx, AVBPrint *bp, const char *function_name,
226+ unsigned argc, char **argv)
227+{
228+ const char *strftime_fmt = argc ? argv[0] : NULL;
229+
230+ return ff_print_time(ctx, bp, strftime_fmt, !strcmp(function_name, "localtime"));
231+}
232+
233+static int func_frame_metadata(void *ctx, AVBPrint *bp, const char *function_name,
234+ unsigned argc, char **argv)
235+{
236+ QREncodeContext *qr = ((AVFilterContext *)ctx)->priv;
237+ AVDictionaryEntry *e = av_dict_get(qr->metadata, argv[0], NULL, 0);
238+
239+ if (e && e->value)
240+ av_bprintf(bp, "%s", e->value);
241+ else if (argc >= 2)
242+ av_bprintf(bp, "%s", argv[1]);
243+
244+ return 0;
245+}
246+
247+static int func_eval_expr(void *ctx, AVBPrint *bp, const char *function_name,
248+ unsigned argc, char **argv)
249+{
250+ QREncodeContext *qr = ((AVFilterContext *)ctx)->priv;
251+
252+ return ff_print_eval_expr(ctx, bp, argv[0],
253+ fun2_names, fun2,
254+ var_names, qr->var_values, &qr->lfg);
255+}
256+
257+static int func_eval_expr_formatted(void *ctx, AVBPrint *bp, const char *function_name,
258+ unsigned argc, char **argv)
259+{
260+ QREncodeContext *qr = ((AVFilterContext *)ctx)->priv;
261+ int ret;
262+ int positions = -1;
263+
264+ /*
265+ * argv[0] expression to be converted to `int`
266+ * argv[1] format: 'x', 'X', 'd' or 'u'
267+ * argv[2] positions printed (optional)
268+ */
269+
270+ if (argc == 3) {
271+ ret = sscanf(argv[2], "%u", &positions);
272+ if (ret != 1) {
273+ av_log(ctx, AV_LOG_ERROR, "expr_int_format(): Invalid number of positions"
274+ " to print: '%s'\n", argv[2]);
275+ return AVERROR(EINVAL);
276+ }
277+ }
278+
279+ return ff_print_formatted_eval_expr(ctx, bp, argv[0],
280+ fun2_names, fun2,
281+ var_names, qr->var_values,
282+ &qr->lfg,
283+ argv[1][0], positions);
284+}
285+
286+static FFExpandTextFunction expand_text_functions[] = {
287+ { "expr", 1, 1, func_eval_expr },
288+ { "e", 1, 1, func_eval_expr },
289+ { "expr_formatted", 2, 3, func_eval_expr_formatted },
290+ { "ef", 2, 3, func_eval_expr_formatted },
291+ { "metadata", 1, 2, func_frame_metadata },
292+ { "frame_num", 0, 0, func_frame_num },
293+ { "n", 0, 0, func_frame_num },
294+ { "gmtime", 0, 1, func_strftime },
295+ { "localtime", 0, 1, func_strftime },
296+ { "pts", 0, 3, func_pts }
297+};
298+
299+static av_cold int init(AVFilterContext *ctx)
300+{
301+ QREncodeContext *qr = ctx->priv;
302+ int ret;
303+
304+ av_lfg_init(&qr->lfg, av_get_random_seed());
305+
306+ qr->qrcode_width = -1;
307+ qr->rendered_padded_qrcode_width = -1;
308+
309+ if (qr->textfile) {
310+ if (qr->text) {
311+ av_log(ctx, AV_LOG_ERROR,
312+ "Both text and text file provided. Please provide only one\n");
313+ return AVERROR(EINVAL);
314+ }
315+ if ((ret = ff_load_textfile(ctx, (const char *)qr->textfile, &(qr->text), NULL)) < 0)
316+ return ret;
317+ }
318+
319+ qr->expand_text = (FFExpandTextContext) {
320+ .log_ctx = ctx,
321+ .functions = expand_text_functions,
322+ .functions_nb = FF_ARRAY_ELEMS(expand_text_functions)
323+ };
324+
325+ av_bprint_init(&qr->expanded_text, 0, AV_BPRINT_SIZE_UNLIMITED);
326+
327+ return 0;
328+}
329+
330+static av_cold void uninit(AVFilterContext *ctx)
331+{
332+ QREncodeContext *qr = ctx->priv;
333+
334+ av_expr_free(qr->x_pexpr);
335+ av_expr_free(qr->y_pexpr);
336+
337+ av_bprint_finalize(&qr->expanded_text, NULL);
338+
339+ av_freep(&qr->qrcode_data[0]);
340+ av_freep(&qr->rendered_qrcode_data[0]);
341+ av_freep(&qr->qrcode_mask_data[0]);
342+}
343+
344+#ifdef DEBUG
345+static void show_qrcode(AVFilterContext *ctx, const QRcode *qrcode)
346+{
347+ int i, j;
348+ char *line = av_malloc(qrcode->width + 1);
349+ const char *p = qrcode->data;
350+
351+ if (!line)
352+ return;
353+ for (i = 0; i < qrcode->width; i++) {
354+ for (j = 0; j < qrcode->width; j++)
355+ line[j] = (*p++)&1 ? '@' : ' ';
356+ line[j] = 0;
357+ av_log(ctx, AV_LOG_DEBUG, "%3d: %s\n", i, line);
358+ }
359+ av_free(line);
360+}
361+#endif
362+
363+static int draw_qrcode(AVFilterContext *ctx, AVFrame *frame)
364+{
365+ QREncodeContext *qr = ctx->priv;
366+ struct SwsContext *sws = NULL;
367+ QRcode *qrcode = NULL;
368+ int i, j;
369+ char qrcode_width_changed;
370+ int ret;
371+ int offset;
372+ uint8_t *srcp;
373+ uint8_t *dstp0, *dstp;
374+
375+ av_bprint_clear(&qr->expanded_text);
376+
377+ switch (qr->expansion) {
378+ case EXPANSION_NONE:
379+ av_bprintf(&qr->expanded_text, "%s", qr->text);
380+ break;
381+ case EXPANSION_NORMAL:
382+ if ((ret = ff_expand_text(&qr->expand_text, qr->text, &qr->expanded_text)) < 0)
383+ return ret;
384+ break;
385+ }
386+
387+ if (!qr->expanded_text.str || qr->expanded_text.str[0] == 0) {
388+ if (qr->is_source) {
389+ ff_fill_rectangle(&qr->draw0, &qr->draw0_background_color,
390+ frame->data, frame->linesize,
391+ 0, 0, qr->rendered_padded_qrcode_width, qr->rendered_padded_qrcode_width);
392+ }
393+
394+ return 0;
395+ }
396+
397+ av_log(ctx, AV_LOG_DEBUG, "Encoding string '%s'\n", qr->expanded_text.str);
398+ qrcode = QRcode_encodeString(qr->expanded_text.str, 1, qr->level, QR_MODE_8,
399+ qr->case_sensitive);
400+ if (!qrcode) {
401+ ret = AVERROR(errno);
402+ av_log(ctx, AV_LOG_ERROR,
403+ "Failed to encode string with error \'%s\'\n", av_err2str(ret));
404+ goto end;
405+ }
406+
407+ av_log(ctx, AV_LOG_DEBUG,
408+ "Encoded QR with width:%d version:%d\n", qrcode->width, qrcode->version);
409+#ifdef DEBUG
410+ show_qrcode(ctx, (const QRcode *)qrcode);
411+#endif
412+
413+ qrcode_width_changed = qr->qrcode_width != qrcode->width;
414+ qr->qrcode_width = qrcode->width;
415+
416+ // realloc mask if needed
417+ if (qrcode_width_changed) {
418+ av_freep(&qr->qrcode_mask_data[0]);
419+ ret = av_image_alloc(qr->qrcode_mask_data, qr->qrcode_mask_linesize,
420+ qrcode->width, qrcode->width,
421+ AV_PIX_FMT_GRAY8, 16);
422+ if (ret < 0) {
423+ av_log(ctx, AV_LOG_ERROR,
424+ "Failed to allocate image for QR code with width %d\n", qrcode->width);
425+ goto end;
426+ }
427+ }
428+
429+ /* fill mask */
430+ dstp0 = qr->qrcode_mask_data[0];
431+ srcp = qrcode->data;
432+
433+ for (i = 0; i < qrcode->width; i++) {
434+ dstp = dstp0;
435+ for (j = 0; j < qrcode->width; j++)
436+ *dstp++ = (*srcp++ & 1) ? 255 : 0;
437+ dstp0 += qr->qrcode_mask_linesize[0];
438+ }
439+
440+ if (qr->is_source) {
441+ if (qrcode_width_changed) {
442+ /* realloc padded image */
443+
444+ // compute virtual non-rendered padded size
445+ // Q/q = W/w
446+ qr->padded_qrcode_width =
447+ ((double)qr->rendered_padded_qrcode_width / qr->rendered_qrcode_width) * qrcode->width;
448+
449+ av_freep(&qr->qrcode_data[0]);
450+ ret = av_image_alloc(qr->qrcode_data, qr->qrcode_linesize,
451+ qr->padded_qrcode_width, qr->padded_qrcode_width,
452+ AV_PIX_FMT_ARGB, 16);
453+ if (ret < 0) {
454+ av_log(ctx, AV_LOG_ERROR,
455+ "Failed to allocate image for QR code with width %d\n",
456+ qr->padded_qrcode_width);
457+ goto end;
458+ }
459+ }
460+
461+ /* fill padding */
462+ ff_fill_rectangle(&qr->draw, &qr->draw_background_color,
463+ qr->qrcode_data, qr->qrcode_linesize,
464+ 0, 0, qr->padded_qrcode_width, qr->padded_qrcode_width);
465+
466+ /* blend mask */
467+ offset = (qr->padded_qrcode_width - qr->qrcode_width) / 2;
468+ ff_blend_mask(&qr->draw, &qr->draw_foreground_color,
469+ qr->qrcode_data, qr->qrcode_linesize,
470+ qr->padded_qrcode_width, qr->padded_qrcode_width,
471+ qr->qrcode_mask_data[0], qr->qrcode_mask_linesize[0], qrcode->width, qrcode->width,
472+ 3, 0, offset, offset);
473+
474+ /* scale padded QR over the frame */
475+ sws = sws_alloc_context();
476+ if (!sws) {
477+ ret = AVERROR(ENOMEM);
478+ goto end;
479+ }
480+
481+ av_opt_set_int(sws, "srcw", qr->padded_qrcode_width, 0);
482+ av_opt_set_int(sws, "srch", qr->padded_qrcode_width, 0);
483+ av_opt_set_int(sws, "src_format", AV_PIX_FMT_ARGB, 0);
484+ av_opt_set_int(sws, "dstw", qr->rendered_padded_qrcode_width, 0);
485+ av_opt_set_int(sws, "dsth", qr->rendered_padded_qrcode_width, 0);
486+ av_opt_set_int(sws, "dst_format", frame->format, 0);
487+ av_opt_set_int(sws, "sws_flags", SWS_POINT, 0);
488+
489+ if ((ret = sws_init_context(sws, NULL, NULL)) < 0)
490+ goto end;
491+
492+ sws_scale(sws,
493+ (const uint8_t *const *)&qr->qrcode_data, qr->qrcode_linesize,
494+ 0, qr->padded_qrcode_width,
495+ frame->data, frame->linesize);
496+ } else {
497+#define EVAL_EXPR(name_) \
498+ av_expr_eval(qr->name_##_pexpr, qr->var_values, &qr->lfg);
499+
500+ V(qr_w) = V(w) = qrcode->width;
501+
502+ V(rendered_qr_w) = V(q) = EVAL_EXPR(rendered_qrcode_width);
503+ V(rendered_padded_qr_w) = V(Q) = EVAL_EXPR(rendered_padded_qrcode_width);
504+ /* It is necessary if q is expressed from Q */
505+ V(rendered_qr_w) = V(q) = EVAL_EXPR(rendered_qrcode_width);
506+
507+ V(x) = EVAL_EXPR(x);
508+ V(y) = EVAL_EXPR(y);
509+ /* It is necessary if x is expressed from y */
510+ V(x) = EVAL_EXPR(x);
511+
512+ av_log(ctx, AV_LOG_DEBUG,
513+ "Rendering QR code with values n:%d w:%d q:%d Q:%d x:%d y:%d t:%f\n",
514+ (int)V(n), (int)V(w), (int)V(q), (int)V(Q), (int)V(x), (int)V(y), V(t));
515+
516+ /* blend rectangle over the target */
517+ ff_blend_rectangle(&qr->draw, &qr->draw_background_color,
518+ frame->data, frame->linesize, frame->width, frame->height,
519+ V(x), V(y), V(Q), V(Q));
520+
521+ if (V(q) != qr->rendered_qrcode_width) {
522+ av_freep(&qr->rendered_qrcode_data[0]);
523+ qr->rendered_qrcode_width = V(q);
524+
525+ ret = av_image_alloc(qr->rendered_qrcode_data, qr->rendered_qrcode_linesize,
526+ qr->rendered_qrcode_width, qr->rendered_qrcode_width,
527+ AV_PIX_FMT_GRAY8, 16);
528+ if (ret < 0) {
529+ av_log(ctx, AV_LOG_ERROR,
530+ "Failed to allocate image for rendered QR code with width %d\n",
531+ qr->rendered_qrcode_width);
532+ goto end;
533+ }
534+ }
535+
536+ /* scale mask */
537+ sws = sws_alloc_context();
538+ if (!sws) {
539+ ret = AVERROR(ENOMEM);
540+ goto end;
541+ }
542+
543+ av_opt_set_int(sws, "srcw", qr->qrcode_width, 0);
544+ av_opt_set_int(sws, "srch", qr->qrcode_width, 0);
545+ av_opt_set_int(sws, "src_format", AV_PIX_FMT_GRAY8, 0);
546+ av_opt_set_int(sws, "dstw", qr->rendered_qrcode_width, 0);
547+ av_opt_set_int(sws, "dsth", qr->rendered_qrcode_width, 0);
548+ av_opt_set_int(sws, "dst_format", AV_PIX_FMT_GRAY8, 0);
549+ av_opt_set_int(sws, "sws_flags", SWS_POINT, 0);
550+
551+ if ((ret = sws_init_context(sws, NULL, NULL)) < 0)
552+ goto end;
553+
554+ sws_scale(sws,
555+ (const uint8_t *const *)&qr->qrcode_mask_data, qr->qrcode_mask_linesize,
556+ 0, qr->qrcode_width,
557+ qr->rendered_qrcode_data, qr->rendered_qrcode_linesize);
558+
559+ /* blend mask over the input frame */
560+ offset = (V(Q) - V(q)) / 2;
561+ ff_blend_mask(&qr->draw, &qr->draw_foreground_color,
562+ frame->data, frame->linesize, frame->width, frame->height,
563+ qr->rendered_qrcode_data[0], qr->rendered_qrcode_linesize[0],
564+ qr->rendered_qrcode_width, qr->rendered_qrcode_width,
565+ 3, 0, V(x) + offset, V(y) + offset);
566+ }
567+
568+end:
569+ sws_freeContext(sws);
570+ QRcode_free(qrcode);
571+
572+ return ret;
573+}
574+
575+#if CONFIG_QRENCODESRC_FILTER
576+
577+static const AVOption qrencodesrc_options[] = {
578+ COMMON_OPTIONS
579+ { "rate", "set video rate", OFFSET(frame_rate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, INT_MAX, FLAGS },
580+ { "r", "set video rate", OFFSET(frame_rate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, INT_MAX, FLAGS },
581+ { NULL }
582+};
583+
584+AVFILTER_DEFINE_CLASS(qrencodesrc);
585+
586+static int qrencodesrc_config_props(AVFilterLink *outlink)
587+{
588+ AVFilterContext *ctx = outlink->src;
589+ QREncodeContext *qr = ctx->priv;
590+ int ret;
591+
592+ qr->is_source = 1;
593+ V(x) = V(y) = 0;
594+
595+#define PARSE_AND_EVAL_EXPR(var_name_, expr_name_) \
596+ ret = av_expr_parse_and_eval(&qr->var_values[VAR_##var_name_], \
597+ qr->expr_name_##_expr, \
598+ var_names, qr->var_values, \
599+ NULL, NULL, \
600+ fun2_names, fun2, \
601+ &qr->lfg, 0, ctx); \
602+ if (ret < 0) { \
603+ av_log(ctx, AV_LOG_ERROR, \
604+ "Could not evaluate expression '%s'\n", \
605+ qr->expr_name_##_expr); \
606+ return ret; \
607+ }
608+
609+ /* undefined for the source */
610+ V(main_w) = V(W) = NAN;
611+ V(main_h) = V(H) = NAN;
612+ V(x) = V(y) = V(t) = V(n) = NAN;
613+ V(dar) = V(sar) = 1.0;
614+
615+ PARSE_AND_EVAL_EXPR(rendered_qr_w, rendered_qrcode_width);
616+ V(q) = V(rendered_qr_w);
617+ PARSE_AND_EVAL_EXPR(rendered_padded_qr_w, rendered_padded_qrcode_width);
618+ V(Q) = V(rendered_padded_qr_w);
619+ PARSE_AND_EVAL_EXPR(rendered_qr_w, rendered_qrcode_width);
620+ V(q) = V(rendered_qr_w);
621+
622+ qr->rendered_qrcode_width = V(rendered_qr_w);
623+ qr->rendered_padded_qrcode_width = V(rendered_padded_qr_w);
624+
625+ av_log(ctx, AV_LOG_VERBOSE,
626+ "q:%d Q:%d case_sensitive:%d level:%d\n",
627+ (int)qr->rendered_qrcode_width, (int)qr->rendered_padded_qrcode_width,
628+ qr->case_sensitive, qr->level);
629+
630+ if (qr->rendered_padded_qrcode_width < qr->rendered_qrcode_width) {
631+ av_log(ctx, AV_LOG_ERROR,
632+ "Resulting padded QR code width (%d) is lesser than the QR code width (%d)\n",
633+ qr->rendered_padded_qrcode_width, qr->rendered_qrcode_width);
634+ return AVERROR(EINVAL);
635+ }
636+
637+ ff_draw_init(&qr->draw, AV_PIX_FMT_ARGB, FF_DRAW_PROCESS_ALPHA);
638+ ff_draw_color(&qr->draw, &qr->draw_foreground_color, (const uint8_t *)&qr->foreground_color);
639+ ff_draw_color(&qr->draw, &qr->draw_background_color, (const uint8_t *)&qr->background_color);
640+
641+ ff_draw_init(&qr->draw0, outlink->format, FF_DRAW_PROCESS_ALPHA);
642+ ff_draw_color(&qr->draw0, &qr->draw0_background_color, (const uint8_t *)&qr->background_color);
643+
644+ outlink->w = qr->rendered_padded_qrcode_width;
645+ outlink->h = qr->rendered_padded_qrcode_width;
646+ outlink->time_base = av_inv_q(qr->frame_rate);
647+ outlink->frame_rate = qr->frame_rate;
648+
649+ return 0;
650+}
651+
652+static int request_frame(AVFilterLink *outlink)
653+{
654+ AVFilterContext *ctx = (AVFilterContext *)outlink->src;
655+ QREncodeContext *qr = ctx->priv;
656+ AVFrame *frame =
657+ ff_get_video_buffer(outlink, qr->rendered_padded_qrcode_width, qr->rendered_padded_qrcode_width);
658+ int ret;
659+
660+ if (!frame)
661+ return AVERROR(ENOMEM);
662+ frame->sample_aspect_ratio = (AVRational) {1, 1};
663+ V(n) = frame->pts = qr->pts++;
664+ V(t) = qr->pts * av_q2d(outlink->time_base);
665+
666+ if ((ret = draw_qrcode(ctx, frame)) < 0)
667+ return ret;
668+
669+ return ff_filter_frame(outlink, frame);
670+}
671+
672+static int qrencodesrc_query_formats(AVFilterContext *ctx)
673+{
674+ enum AVPixelFormat pix_fmt;
675+ FFDrawContext draw;
676+ AVFilterFormats *fmts = NULL;
677+ int ret;
678+
679+ // this is needed to support both the no-draw and draw cases
680+ // for the no-draw case we use FFDrawContext to write on the input picture ref
681+ for (pix_fmt = 0; av_pix_fmt_desc_get(pix_fmt); pix_fmt++)
682+ if (ff_draw_init(&draw, pix_fmt, 0) >= 0 &&
683+ sws_isSupportedOutput(pix_fmt) &&
684+ (ret = ff_add_format(&fmts, pix_fmt)) < 0)
685+ return ret;
686+
687+ return ff_set_common_formats(ctx, fmts);
688+}
689+
690+static const AVFilterPad qrencodesrc_outputs[] = {
691+ {
692+ .name = "default",
693+ .type = AVMEDIA_TYPE_VIDEO,
694+ .request_frame = request_frame,
695+ .config_props = qrencodesrc_config_props,
696+ }
697+};
698+
699+const AVFilter ff_vsrc_qrencodesrc = {
700+ .name = "qrencodesrc",
701+ .description = NULL_IF_CONFIG_SMALL("Generate a QR code."),
702+ .priv_size = sizeof(QREncodeContext),
703+ .priv_class = &qrencodesrc_class,
704+ .init = init,
705+ .uninit = uninit,
706+ .inputs = NULL,
707+ FILTER_OUTPUTS(qrencodesrc_outputs),
708+ FILTER_QUERY_FUNC(qrencodesrc_query_formats),
709+};
710+
711+#endif // CONFIG_QRENCODESRC_FILTER
712+
713+#if CONFIG_QRENCODE_FILTER
714+
715+static const AVOption qrencode_options[] = {
716+ COMMON_OPTIONS
717+ {"x", "set x expression", OFFSET(x_expr), AV_OPT_TYPE_STRING, {.str="0"}, 0, 0, TFLAGS},
718+ {"y", "set y expression", OFFSET(y_expr), AV_OPT_TYPE_STRING, {.str="0"}, 0, 0, TFLAGS},
719+ { NULL }
720+};
721+
722+AVFILTER_DEFINE_CLASS(qrencode);
723+
724+static int qrencode_config_input(AVFilterLink *inlink)
725+{
726+ AVFilterContext *ctx = inlink->dst;
727+ QREncodeContext *qr = ctx->priv;
728+ char *expr;
729+ int ret;
730+
731+ qr->is_source = 0;
732+
733+ ff_draw_init(&qr->draw, inlink->format, FF_DRAW_PROCESS_ALPHA);
734+
735+ V(W) = V(main_w) = inlink->w;
736+ V(H) = V(main_h) = inlink->h;
737+ V(sar) = inlink->sample_aspect_ratio.num ? av_q2d(inlink->sample_aspect_ratio) : 1;
738+ V(dar) = (double)inlink->w / inlink->h * V(sar);
739+ V(hsub) = 1 << qr->draw.hsub_max;
740+ V(vsub) = 1 << qr->draw.vsub_max;
741+ V(t) = NAN;
742+ V(x) = V(y) = NAN;
743+
744+ qr->x_pexpr = qr->y_pexpr = NULL;
745+ qr->x_pexpr = qr->y_pexpr = NULL;
746+
747+#define PARSE_EXPR(name_) \
748+ ret = av_expr_parse(&qr->name_##_pexpr, expr = qr->name_##_expr, var_names, \
749+ NULL, NULL, fun2_names, fun2, 0, ctx); \
750+ if (ret < 0) { \
751+ av_log(ctx, AV_LOG_ERROR, \
752+ "Could not to parse expression '%s' for '%s'\n", \
753+ expr, #name_); \
754+ return AVERROR(EINVAL); \
755+ }
756+
757+ PARSE_EXPR(x);
758+ PARSE_EXPR(y);
759+ PARSE_EXPR(rendered_qrcode_width);
760+ PARSE_EXPR(rendered_padded_qrcode_width);
761+
762+ ff_draw_init(&qr->draw, inlink->format, FF_DRAW_PROCESS_ALPHA);
763+ ff_draw_color(&qr->draw, &qr->draw_foreground_color, (const uint8_t *)&qr->foreground_color);
764+ ff_draw_color(&qr->draw, &qr->draw_background_color, (const uint8_t *)&qr->background_color);
765+
766+ qr->rendered_qrcode_width = -1;
767+
768+ return 0;
769+}
770+
771+static int qrencode_query_formats(AVFilterContext *ctx)
772+{
773+ return ff_set_common_formats(ctx, ff_draw_supported_pixel_formats(0));
774+}
775+
776+static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
777+{
778+ AVFilterContext *ctx = inlink->dst;
779+ AVFilterLink *outlink = ctx->outputs[0];
780+ QREncodeContext *qr = ctx->priv;
781+ int ret;
782+
783+ V(n) = inlink->frame_count_out;
784+ V(t) = frame->pts == AV_NOPTS_VALUE ?
785+ NAN : frame->pts * av_q2d(inlink->time_base);
786+ V(pict_type) = frame->pict_type;
787+ V(duration) = frame->duration * av_q2d(inlink->time_base);
788+
789+ qr->metadata = frame->metadata;
790+
791+ if ((ret = draw_qrcode(ctx, frame)) < 0)
792+ return ret;
793+
794+ return ff_filter_frame(outlink, frame);
795+}
796+
797+static const AVFilterPad avfilter_vf_qrencode_inputs[] = {
798+ {
799+ .name = "default",
800+ .type = AVMEDIA_TYPE_VIDEO,
801+ .flags = AVFILTERPAD_FLAG_NEEDS_WRITABLE,
802+ .filter_frame = filter_frame,
803+ .config_props = qrencode_config_input,
804+ },
805+};
806+
807+const AVFilter ff_vf_qrencode = {
808+ .name = "qrencode",
809+ .description = NULL_IF_CONFIG_SMALL("Draw a QR code on top of video frames."),
810+ .priv_size = sizeof(QREncodeContext),
811+ .priv_class = &qrencode_class,
812+ .init = init,
813+ .uninit = uninit,
814+ FILTER_INPUTS(avfilter_vf_qrencode_inputs),
815+ FILTER_OUTPUTS(ff_video_default_filterpad),
816+ FILTER_QUERY_FUNC(qrencode_query_formats),
817+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
818+};
819+
820+#endif // CONFIG_QRENCODE_FILTER

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t