Go to the documentation of this file.
77 #define USER_VAR_COUNT 20
80 #define VAR_COUNT (VAR_U0 + USER_VAR_COUNT)
117 static double vgs_fn_p(
void *,
double,
double);
205 {
"butt", CAIRO_LINE_CAP_BUTT },
206 {
"round", CAIRO_LINE_CAP_ROUND },
207 {
"square", CAIRO_LINE_CAP_SQUARE },
212 {
"bevel", CAIRO_LINE_JOIN_BEVEL },
213 {
"miter", CAIRO_LINE_JOIN_MITER },
214 {
"round", CAIRO_LINE_JOIN_ROUND },
240 #define MAX_COMMAND_PARAMS 8
246 #define MAX_PROC_ARGS (MAX_COMMAND_PARAMS - 2)
248 #define VGS_MAX_RECURSION_DEPTH 100
259 #define PARAMS(...) (const struct VGSParameter[]){ __VA_ARGS__ }
260 #define L(...) PARAMS(__VA_ARGS__, { PARAM_END })
261 #define R(...) PARAMS(__VA_ARGS__, { PARAM_MAY_REPEAT })
262 #define NONE PARAMS({ PARAM_END })
265 #define N { PARAM_NUMERIC }
266 #define V { PARAM_VAR_NAME }
267 #define P { PARAM_SUBPROGRAM }
268 #define C(c) { PARAM_CONSTANT, .constants = c }
287 {
"call",
CMD_PROC_CALL,
L({ PARAM_PROC_NAME }, { PARAM_PROC_ARGS }) },
309 {
"print",
CMD_PRINT,
L({ PARAM_NUMERIC_METADATA }, { PARAM_VARIADIC }) },
366 if (length >=
sizeof(bufname))
369 memcpy(bufname,
name, length);
370 bufname[length] =
'\0';
487 && str[token->
length] ==
'\0';
502 const char *sep = strchr(
source,
'\n');
515 void vgs_log_invalid_token(
519 const
char *extra_fmt,
529 va_start(ap, extra_fmt);
530 vsnprintf(extra,
sizeof(extra), extra_fmt, ap);
534 "Invalid token '%.*s' at line %zu, column %zu: %s\n",
535 (
int)token->length, token->lexeme,
line, column, extra);
551 #define WORD_SEPARATOR " \n\t\r,"
554 size_t cursor, length;
567 token->
type = TOKEN_EOF;
578 switch (
source[cursor + length]) {
581 vgs_log_invalid_token(log_ctx, parser, token,
"Unmatched parenthesis.");
596 token->
type = TOKEN_EXPR;
601 token->
type = TOKEN_LEFT_BRACKET;
606 token->
type = TOKEN_RIGHT_BRACKET;
623 token->
type = TOKEN_LITERAL;
632 if (
source[cursor + 1] ==
'/') {
633 parser->
cursor += cursor + strcspn(token->
lexeme,
"\n");
640 token->
type = TOKEN_WORD;
735 for (
int i = 0;
i <
program->statements_count;
i++)
741 for (
int i = 0;
i <
program->proc_names_count;
i++)
758 vgs_log_invalid_token(log_ctx, parser, token,
"Expected color.");
795 if (token.
length + 1 <
sizeof(stack_buf)) {
807 switch (token.
type) {
809 arg->type = ARG_LITERAL;
813 vgs_log_invalid_token(log_ctx, parser, &token,
"Expected valid number.");
819 arg->type = ARG_EXPR;
833 vgs_log_invalid_token(log_ctx, parser, &token,
"Invalid expression.");
841 if (accept_colors &&
lexeme[0] ==
'#') {
853 arg->type = ARG_VARIABLE;
866 vgs_log_invalid_token(log_ctx, parser, &token,
"Expected numeric argument.");
879 memset(
arg, 0,
sizeof(*
arg));
902 switch (token.
type) {
917 if (accept_colors && token.
lexeme[0] ==
'#')
943 for (
int i = 0;
i < token->
length;
i++) {
946 && !(
c >=
'a' &&
c <=
'z')
947 && !(
c >=
'A' &&
c <=
'Z')
948 && !(
i > 0 &&
c >=
'0' &&
c <=
'9')
970 vgs_statement_free(&statement); \
971 return AVERROR(err); \
982 int proc_args_count = 0;
991 switch (param->
type) {
1007 case PARAM_MAY_REPEAT:
1020 if (param->
type != PARAM_END
1023 param = &decl->
params[0];
1024 statement.args =
NULL;
1025 statement.args_count = 0;
1058 case PARAM_CONSTANT: {
1060 char expected_names[64] = { 0 };
1085 vgs_log_invalid_token(log_ctx, parser, &token,
"Expected one of%s.", expected_names);
1092 case PARAM_PROC_ARGS:
1100 vgs_log_invalid_token(log_ctx, parser, &token,
1108 case PARAM_NUMERIC_COLOR:
1109 case PARAM_NUMERIC_METADATA:
1114 param->
type == PARAM_NUMERIC_METADATA,
1115 param->
type == PARAM_NUMERIC_COLOR || param->
type == PARAM_PROC_ARGS
1123 case PARAM_PROC_NAME: {
1131 vgs_log_invalid_token(log_ctx, parser, &token,
"Invalid procedure name.");
1164 case PARAM_RAW_IDENT:
1169 switch (token.
type) {
1177 vgs_log_invalid_token(log_ctx, parser, &token,
"Expected '{'.");
1183 case PARAM_SUBPROGRAM:
1188 if (token.
type != TOKEN_LEFT_BRACKET) {
1189 vgs_log_invalid_token(log_ctx, parser, &token,
"Expected '{'.");
1204 case PARAM_PROC_PARAMS:
1210 vgs_log_invalid_token(log_ctx, parser, &token,
1215 if (token.
type != TOKEN_WORD) {
1223 case PARAM_VAR_NAME: {
1242 if (var_idx == -1) {
1243 vgs_log_invalid_token(log_ctx, parser, &token,
1244 "Too many user variables. Can define up to %d variables.",
USER_VAR_COUNT);
1251 vgs_log_invalid_token(log_ctx, parser, &token,
"Reserved variable name.");
1258 vgs_log_invalid_token(log_ctx, parser, &token,
"Invalid variable name.");
1266 arg.constant = var_idx;
1275 (
void*)&statement.
args,
1284 switch (param->
type) {
1285 case PARAM_PROC_ARGS:
1286 case PARAM_PROC_PARAMS:
1344 "Exceeded maximum drawvg block nesting depth (%d)\n",
1356 switch (token.
type) {
1359 vgs_log_invalid_token(log_ctx, parser, &token,
"Expected '}'.");
1381 case TOKEN_RIGHT_BRACKET:
1396 vgs_log_invalid_token(log_ctx, parser, &token,
"Expected command.");
1417 #define RANDOM_STATES 4
1499 int max_segments = (int)
arg;
1501 double lmx =
NAN, lmy =
NAN;
1502 double cx =
NAN, cy =
NAN;
1505 cairo_path_t *path = cairo_copy_path_flat(
state->cairo_ctx);
1507 for (
int i = 0;
i < path->num_data;
i += path->data[
i].header.length) {
1509 cairo_path_data_t *
data = &path->data[
i];
1512 case CAIRO_PATH_MOVE_TO:
1513 cx = lmx =
data[1].point.x;
1514 cy = lmy =
data[1].point.y;
1519 case CAIRO_PATH_LINE_TO:
1520 x =
data[1].point.x;
1521 y =
data[1].point.y;
1524 case CAIRO_PATH_CLOSE_PATH:
1533 length +=
hypot(cx - x, cy - y);
1540 if (--max_segments == 0)
1544 cairo_path_destroy(path);
1563 const uint64_t iarg = (uint64_t)
arg;
1588 cairo_user_to_device(
state->cairo_ctx, &x0, &y0);
1590 const int x = (int)x0;
1591 const int y = (int)y0;
1593 if (x < 0 || y < 0 || x >=
frame->width || y >=
frame->height)
1598 uint32_t
color[4] = { 0, 0, 0, 255 };
1600 for (
int c = 0;
c <
desc->nb_components;
c++) {
1614 const int depth =
desc->comp[
c].depth;
1638 state->last_fn_p_color.numeric = num;
1640 state->last_fn_p_color.components[
i] = (uint8_t)
color[
i];
1657 state->last_fn_p_color.numeric =
NAN;
1678 cairo_pattern_destroy(
state->pattern_builder);
1691 static void draw_ellipse(cairo_t *
c,
double x,
double y,
double rx,
double ry) {
1693 cairo_translate(
c, x, y);
1696 cairo_scale(
c, 1, ry / rx);
1698 cairo_new_sub_path(
c);
1699 cairo_arc(
c, 0, 0, rx, 0, 2 *
M_PI);
1700 cairo_close_path(
c);
1701 cairo_new_sub_path(
c);
1721 double x0 = 0, y0 = 0;
1722 double xa, ya, xb, yb;
1724 const int use_reflected =
isnan(x1);
1729 if (!use_reflected) {
1738 if (use_reflected) {
1740 x1 =
state->rcp.quad_x;
1741 y1 =
state->rcp.quad_y;
1748 xa = (x0 + 2 * x1) / 3;
1749 ya = (y0 + 2 * y1) / 3;
1750 xb = (x + 2 * x1) / 3;
1751 yb = (y + 2 * y1) / 3;
1752 cairo_curve_to(
state->cairo_ctx, xa, ya, xb, yb, x, y);
1755 state->rcp.cubic_x = x1;
1756 state->rcp.cubic_y = y1;
1757 state->rcp.quad_x = 2 * x - x1;
1758 state->rcp.quad_y = 2 * y - y1;
1772 double x0 = 0, y0 = 0;
1774 const int use_reflected =
isnan(x1);
1779 if (!use_reflected) {
1790 if (use_reflected) {
1792 x1 =
state->rcp.cubic_x;
1793 y1 =
state->rcp.cubic_y;
1800 cairo_curve_to(
state->cairo_ctx, x1, y1, x2, y2, x, y);
1803 state->rcp.cubic_x = 2 * x - x2;
1804 state->rcp.cubic_y = 2 * y - y2;
1805 state->rcp.quad_x = x2;
1806 state->rcp.quad_y = y2;
1819 cairo_new_sub_path(
c);
1820 cairo_arc(
c, x + radius, y + radius, radius,
M_PI, 3 *
M_PI / 2);
1821 cairo_arc(
c, x +
width - radius, y + radius, radius, 3 *
M_PI / 2, 2 *
M_PI);
1822 cairo_arc(
c, x +
width - radius, y +
height - radius, radius, 0,
M_PI / 2);
1823 cairo_arc(
c, x + radius, y +
height - radius, radius,
M_PI / 2,
M_PI);
1824 cairo_close_path(
c);
1839 if (h < 0 || h >= 360)
1849 switch ((
int)
floor(h1)) {
1912 #define ASSERT_ARGS(n) av_assert0(statement->args_count == n)
1916 #define MAY_PRESERVE(funcname) \
1918 if (state->preserve_path) { \
1919 state->preserve_path = 0; \
1920 funcname##_preserve(state->cairo_ctx); \
1922 funcname(state->cairo_ctx); \
1933 for (
int st_number = 0; st_number <
program->statements_count; st_number++) {
1966 numerics[
arg] =
a->literal;
1971 numerics[
arg] =
state->vars[
a->variable];
1990 switch (statement->
cmd) {
1997 cairo_pattern_destroy(
state->pattern_builder);
2003 switch (statement->
cmd) {
2030 draw_ellipse(
state->cairo_ctx, numerics[0], numerics[1], numerics[2], numerics[2]);
2036 cairo_set_fill_rule(
2039 CAIRO_FILL_RULE_WINDING :
2040 CAIRO_FILL_RULE_EVEN_ODD
2048 cairo_close_path(
state->cairo_ctx);
2058 cairo_pattern_add_color_stop_rgba(
2059 state->pattern_builder,
2093 hsl2rgb(numerics[1], numerics[2], numerics[3], &
r, &
g, &
b);
2100 double *
const color_var =
state->color_vars[user_var -
VAR_U0];
2104 color_var[3] = numerics[4];
2111 draw_ellipse(
state->cairo_ctx, numerics[0], numerics[1], numerics[2], numerics[3]);
2118 cairo_set_fill_rule(
2121 CAIRO_FILL_RULE_WINDING :
2122 CAIRO_FILL_RULE_EVEN_ODD
2155 state->interrupted = 1;
2161 if (
isfinite(numerics[0]) && numerics[0] != 0.0) {
2164 if (
ret != 0 ||
state->interrupted != 0)
2174 cairo_pattern_destroy(
state->pattern_builder);
2176 state->pattern_builder = cairo_pattern_create_linear(
2186 cairo_line_to(
state->cairo_ctx, numerics[0], numerics[1]);
2191 cairo_rel_line_to(
state->cairo_ctx, numerics[0], numerics[1]);
2196 cairo_move_to(
state->cairo_ctx, numerics[0], numerics[1]);
2201 cairo_rel_move_to(
state->cairo_ctx, numerics[0], numerics[1]);
2206 cairo_new_sub_path(
state->cairo_ctx);
2211 state->preserve_path = 1;
2220 int capacity =
sizeof(msg) -
len;
2232 if (written >= capacity)
2245 const int proc_args = statement->
args_count - 2;
2253 proc->
args[
i] = i < proc_args ? statement->
args[
i + 1].constant : -1;
2259 const int proc_args = statement->
args_count - 1;
2270 "Procedure expects %d arguments, but received %d.",
2279 const char *proc_name =
state->proc_names[proc_id];
2281 "Missing body for procedure '%s'\n", proc_name);
2287 for (
int i = 0;
i < proc_args;
i++) {
2288 const int var = proc->
args[
i];
2292 const int color_var = var -
VAR_U0;
2296 current_vars[
i] =
state->vars[var];
2299 state->vars[var] = numerics[
i + 1];
2306 for (
int i = 0;
i < proc_args;
i++) {
2307 const int var = proc->
args[
i];
2311 const int color_var = var -
VAR_U0;
2314 state->vars[var] = current_vars[
i];
2321 if (
state->interrupted) {
2322 state->interrupted = 0;
2348 cairo_pattern_destroy(
state->pattern_builder);
2350 state->pattern_builder = cairo_pattern_create_radial(
2361 cairo_reset_clip(
state->cairo_ctx);
2369 cairo_identity_matrix(
state->cairo_ctx);
2374 cairo_rectangle(
state->cairo_ctx, numerics[0], numerics[1], numerics[2], numerics[3]);
2385 for (
int i = 0, count = (
int)numerics[0];
i < count;
i++) {
2393 if (
state->interrupted) {
2394 state->interrupted = 0;
2405 cairo_restore(
state->cairo_ctx);
2410 cairo_rotate(
state->cairo_ctx, numerics[0]);
2427 cairo_save(
state->cairo_ctx);
2432 cairo_scale(
state->cairo_ctx, numerics[0], numerics[0]);
2437 cairo_scale(
state->cairo_ctx, numerics[0], numerics[1]);
2444 cairo_pattern_destroy(
state->pattern_builder);
2446 state->pattern_builder = cairo_pattern_create_rgba(
2466 cairo_set_line_width(
state->cairo_ctx, numerics[0]);
2472 double *dashes,
offset, stack_buf[16];
2481 dashes =
av_calloc(num + 1,
sizeof(
double));
2490 dashes[num] = numerics[0];
2498 if (dashes != stack_buf)
2511 cairo_pattern_destroy(
state->pattern_builder);
2514 hsl2rgb(numerics[0], numerics[1], numerics[2], &
r, &
g, &
b);
2521 state->pattern_builder = cairo_pattern_create_rgba(
r,
g,
b, numerics[3]);
2531 state->vars[user_var] = numerics[1];
2535 if (
state->last_fn_p_color.numeric == numerics[1]) {
2537 (*
color)[
i] =
state->last_fn_p_color.components[
i] / 255.0;
2567 cairo_translate(
state->cairo_ctx, numerics[0], numerics[1]);
2584 double d = numerics[0];
2586 switch (statement->
cmd) {
2593 cairo_line_to(
state->cairo_ctx, cx, cy);
2602 if (
state->rcp.status == RCP_UPDATED) {
2603 state->rcp.status = RCP_VALID;
2605 state->rcp.status = RCP_NONE;
2613 "Error in cairo context: %s\n",
2651 #define OPT(name, field, help) \
2655 offsetof(DrawVGContext, field), \
2656 AV_OPT_TYPE_STRING, \
2659 AV_OPT_FLAG_FILTERING_PARAM \
2660 | AV_OPT_FLAG_VIDEO_PARAM \
2664 OPT(
"script", script_text,
"script source to draw the graphics"),
2665 OPT(
"s", script_text,
"script source to draw the graphics"),
2666 OPT(
"file", script_file,
"file to load the script source"),
2690 CAIRO_FORMAT_ARGB32,
2692 CAIRO_FORMAT_RGB16_565,
2694 CAIRO_FORMAT_INVALID,
2705 return CAIRO_FORMAT_INVALID;
2711 cairo_surface_t* surface;
2725 surface = cairo_image_surface_create_for_data(
2733 if (cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) {
2738 eval_state.
cairo_ctx = cairo_create(surface);
2757 cairo_surface_destroy(surface);
2786 drawvg->time_start =
NAN;
2788 if ((drawvg->script_text ==
NULL) == (drawvg->script_file ==
NULL)) {
2790 "Either 'source' or 'file' must be provided\n");
2795 if (drawvg->script_file !=
NULL) {
2798 (
const char *)drawvg->script_file,
2799 &drawvg->script_text,
2834 .p.priv_class = &drawvg_class,
FFSFC64 random_state[RANDOM_STATES]
State for each index available for the randomg function.
static const AVFilterPad drawvg_inputs[]
AVPixelFormat
Pixel format.
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf default minimum maximum flags name is the option name
@ CMD_PROC_ASSIGN
proc name varnames* { subprogram }
Undefined Behavior In the C some operations are like signed integer dereferencing freed accessing outside allocated Undefined Behavior must not occur in a C program
#define MAX_COMMAND_PARAMS
static const AVOption drawvg_options[]
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
@ CMD_COLOR_STOP
colorstop (offset color)
int args[MAX_PROC_ARGS]
Variable ids where each argument is stored.
void cairo_set_dash(cairo_t *cr, const double *dashes, int num_dashes, double offset)
@ CMD_DEF_RGBA
defrgba (varname r g b a)
AVFILTER_DEFINE_CLASS(drawvg)
static const char *const vgs_default_vars[]
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
int av_parse_color(uint8_t *rgba_color, const char *color_string, int slen, void *log_ctx)
Put the RGBA values that correspond to color_string in rgba_color.
@ CMD_Q_CURVE_TO
Q (x1 y1 x y)
static void vgs_statement_free(struct VGSStatement *stm)
static double vgs_fn_pathlen(void *, double)
Function pathlen(n) for av_expr_eval.
The exact code depends on how similar the blocks are and how related they are to the and needs to apply these operations to the correct inlink or outlink if there are several Macros are available to factor that when no extra processing is inlink
char * av_asprintf(const char *fmt,...)
@ CMD_ARC_NEG
arcn (cx cy radius angle1 angle2)
@ CMD_ROTATE
rotate (angle)
AVDictionary * metadata
Frame metadata, if any.
@ CMD_SCALEXY
scalexy (sx sy)
This structure describes decoded (raw) audio or video data.
@ CMD_RECT
rect (x y width height)
static av_cold int drawvg_init(AVFilterContext *ctx)
static int vgs_comp_command_spec(const void *cs1, const void *cs2)
Comparator for VGSCommandDecl, to be used with bsearch(3).
void * av_dynarray2_add(void **tab_ptr, int *nb_ptr, size_t elem_size, const uint8_t *elem_data)
Add an element of size elem_size to a dynamic array.
uint8_t * script_text
Inline source.
static int vgs_parse_numeric_argument(void *log_ctx, struct VGSParser *parser, struct VGSArgument *arg, int metadata, bool accept_colors)
Consume the next argument as a numeric value, and store it in arg.
@ CMD_T_CURVE_TO_REL
t (dx dy)
static int drawvg_config_props(AVFilterLink *inlink)
static av_always_inline void color_reset(cairo_color *const dest)
static void ff_sfc64_init(FFSFC64 *s, uint64_t seeda, uint64_t seedb, uint64_t seedc, int rounds)
Initialize sfc64 with up to 3 seeds.
static const struct VGSCommandSpec * vgs_get_command(const char *name, size_t length)
Return the specs for the given command, or NULL if the name is not valid.
@ CMD_ARC
arc (cx cy radius angle1 angle2)
static int vgs_parser_next_token(void *log_ctx, struct VGSParser *parser, struct VGSParserToken *token, int advance)
Return the next token in the source.
struct VGSArgument * args
const char * name
Filter name.
@ CMD_MOVE_TO
M, moveto (x y)
static const struct VGSConstant vgs_consts_line_join[]
int preserve_path
Next call to [eo]fill, [eo]clip, or stroke, should use the _preserve function.
A link between two filters.
struct VGSEvalState::@413 last_fn_p_color
Track last color read by the p() function.
size_t av_strlcatf(char *dst, size_t size, const char *fmt,...)
@ CMD_SET_LINE_CAP
setlinecap (cap)
#define OPT(name, field, help)
static cairo_format_t cairo_format_from_pix_fmt(DrawVGContext *ctx, enum AVPixelFormat format)
static void vgs_parser_free(struct VGSParser *parser)
Link properties exposed to filter code, but not external callers.
@ CMD_RESET_CLIP
resetclip
enum VGSParserToken::@409 type
@ CMD_IF
if (condition) { subprogram }
int av_expr_parse(AVExpr **expr, const char *s, const char *const *const_names, const char *const *func1_names, double(*const *funcs1)(void *, double), const char *const *func2_names, double(*const *funcs2)(void *, double, double), int log_offset, void *log_ctx)
Parse an expression.
struct VGSProgram * subprogram
struct VGSProcedure * procedures
Subprograms associated to each procedure identifier.
cairo_bool_t cairo_get_dash_count(cairo_t *cr)
@ CMD_SET_DASH
setdash (length)
@ CMD_SET_RGBA
setrgba (r g b a)
static double(*const vgs_func2_impls[])(void *, double, double)
Constants for some commands, like setlinejoin.
@ CMD_RESET_MATRIX
resetmatrix
#define FILTER_PIXFMTS_ARRAY(array)
static av_cold void drawvg_uninit(AVFilterContext *ctx)
static double vgs_fn_randomg(void *, double)
Function randomg(n) for av_expr_eval.
static FilteringContext * filter_ctx
@ CMD_MOVE_TO_REL
m, rmoveto (dx dy)
static int vgs_token_is_string(const struct VGSParserToken *token, const char *str)
Check if token is the value of str.
void av_expr_free(AVExpr *e)
Free a parsed expression previously created with av_expr_parse().
A filter pad used for either input or output.
#define VAR_COUNT
Total number of variables (default- and user-variables).
static int vgs_parser_can_repeat_cmd(void *log_ctx, struct VGSParser *parser, bool accept_colors)
Check if the next token is a numeric value (or a color, if accept_colors is true),...
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
struct VGSEvalState::@414 rcp
#define FF_ARRAY_ELEMS(a)
@ CMD_CIRCLE
circle (cx cy radius)
int ff_load_textfile(void *log_ctx, const char *textfile, unsigned char **text, size_t *text_size)
const AVFilterPad ff_video_default_filterpad[1]
An AVFilterPad array whose only entry has name "default" and is of type AVMEDIA_TYPE_VIDEO.
const FFFilter ff_vf_drawvg
AVDictionaryEntry * av_dict_get(const AVDictionary *m, const char *key, const AVDictionaryEntry *prev, int flags)
Get a dictionary entry with matching key.
double cairo_color[4]
Colors in cairo are defined by 4 values, between 0 and 1.
@ CMD_Q_CURVE_TO_REL
q (dx1 dy1 dx dy)
#define FILTER_OUTPUTS(array)
@ VAR_I
Loop counter, to use with repeat {}.
static __device__ float floor(float a)
static FilterLink * ff_filter_link(AVFilterLink *link)
static double av_q2d(AVRational a)
Convert an AVRational to a double.
static int vgs_is_valid_identifier(const struct VGSParserToken *token)
#define av_assert0(cond)
assert() equivalent, that is always enabled.
static int vgs_eval(struct VGSEvalState *state, const struct VGSProgram *program, int stack_level)
Interpreter for VGSProgram.
@ VAR_TS
Time in seconds of the first frame.
static AVFormatContext * ctx
double av_expr_eval(AVExpr *e, const double *const_values, void *opaque)
Evaluate a previously parsed expression.
void cairo_set_source(cairo_t *cr, cairo_pattern_t *source)
@ VAR_CY
Y coordinate for current point.
void av_read_image_line2(void *dst, const uint8_t *data[4], const int linesize[4], const AVPixFmtDescriptor *desc, int x, int y, int c, int w, int read_pal_component, int dst_element_size)
Read a line from an image, and write the values of the pixel format component c to dst.
static void vgs_free(struct VGSProgram *program)
Release the memory allocated by the program.
cairo_bool_t cairo_has_current_point(cairo_t *cr)
@ CMD_LINE_TO_REL
l, rlineto (dx dy)
Describe the class of an AVClass context structure.
static __device__ float fabs(float a)
New swscale design to change SwsGraph is what coordinates multiple passes These can include cascaded scaling error diffusion and so on Or we could have separate passes for the vertical and horizontal scaling In between each SwsPass lies a fully allocated image buffer Graph passes may have different levels of e g we can have a single threaded error diffusion pass following a multi threaded scaling pass SwsGraph is internally recreated whenever the image format
void cairo_get_dash(cairo_t *cr, double *dashes, double *offset)
double vars[VAR_COUNT]
Values for the variables in expressions.
@ CMD_CURVE_TO_REL
c, rcurveto (dx1 dy1 dx2 dy2 dx dy)
static double(*const vgs_func1_impls[])(void *, double)
#define AVFILTERPAD_FLAG_NEEDS_WRITABLE
The filter expects writable frames from its input link, duplicating data buffers if needed.
static int vgs_parse(void *log_ctx, struct VGSParser *parser, struct VGSProgram *program, int subprogram)
Build a program by parsing a script.
@ CMD_S_CURVE_TO
S (x2 y2 x y)
cairo_pattern_t * pattern_builder
Pattern being built by commands like colorstop.
static void draw_ellipse(cairo_t *c, double x, double y, double rx, double ry)
Draw an ellipse.
@ CMD_REPEAT
repeat (count) { subprogram }
static av_always_inline void color_copy(cairo_color *dest, const cairo_color *src)
Undefined Behavior In the C some operations are like signed integer dereferencing freed accessing outside allocated Undefined Behavior must not occur in a C it is not safe even if the output of undefined operations is unused The unsafety may seem nit picking but Optimizing compilers have in fact optimized code on the assumption that no undefined Behavior occurs Optimizing code based on wrong assumptions can and has in some cases lead to effects beyond the output of computations The signed integer overflow problem in speed critical code Code which is highly optimized and works with signed integers sometimes has the problem that often the output of the computation does not c
uint8_t * script_file
File path to load the source.
static int vgs_parse_color(void *log_ctx, struct VGSArgument *arg, const struct VGSParser *parser, const struct VGSParserToken *token)
@ CMD_SET_VAR
setvar (varname value)
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several the filter must be ready for frames arriving randomly on any input any filter with several inputs will most likely require some kind of queuing mechanism It is perfectly acceptable to have a limited queue and to drop frames when the inputs are too unbalanced request_frame For filters that do not use the this method is called when a frame is wanted on an output For a source
void cairo_get_current_point(cairo_t *cr, double *x, double *y)
static IPT relative(const CmsCtx *ctx, IPT ipt)
double time_start
Time in seconds of the first frame.
int(* init)(AVBSFContext *ctx)
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
int interrupted
Register if break was called in a subprogram.
#define i(width, name, range_min, range_max)
const struct VGSParameter * params
enum VGSEvalState::@414::@415 status
static av_const double hypot(double x, double y)
@ CMD_ELLIPSE
ellipse (cx cy rx ry)
static int drawvg_filter_frame(AVFilterLink *inlink, AVFrame *frame)
static const uint8_t header[24]
static int vgs_eval_state_init(struct VGSEvalState *state, const struct VGSProgram *program, void *log_ctx, AVFrame *frame)
The reader does not expect b to be semantically here and if the code is changed by maybe adding a a division or other the signedness will almost certainly be mistaken To avoid this confusion a new type was SUINT is the C unsigned type but it holds a signed int to use the same example SUINT a
cairo_t * cairo_ctx
Cairo context for drawing operations.
#define AVERROR_EXTERNAL
Generic error in an external library.
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf offset
static const struct VGSConstant vgs_consts_line_cap[]
#define AV_LOG_INFO
Standard information.
@ CMD_SET_COLOR
setcolor (color)
#define AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC
Some filters support a generic "enable" expression option that can be used to enable or disable a fil...
@ CMD_RADIAL_GRAD
radialgrad (cx0 cy0 radius0 cx1 cy1 radius1)
static int vgs_cmd_change_path(enum VGSCommand cmd)
Return 1 if the command changes the current path in the cairo context.
static void uninit(AVBSFContext *ctx)
enum VGSArgument::@410 type
@ CMD_S_CURVE_TO_REL
s (dx2 dy2 dx dy)
struct VGSStatement * statements
static double vgs_fn_p(void *, double, double)
Function p(x, y) for av_expr_eval.
@ VAR_DURATION
Frame duration.
AVFrame * frame
Current frame.
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf default value
@ CMD_GET_METADATA
getmetadata varname key
#define AV_PIX_FMT_X2RGB10
#define USER_VAR_COUNT
Number of user variables that can be created with setvar.
@ CMD_LINEAR_GRAD
lineargrad (x0 y0 x1 y1)
const char * name
Pad name.
Block assigned to a procedure by a call to the proc command.
static void draw_quad_curve_to(struct VGSEvalState *state, int relative, double x1, double y1, double x, double y)
Draw a quadratic bezier from the current point to x, y, The control point is specified by x1,...
struct VGSProgram program
@ CMD_RESET_DASH
resetdash
void * av_calloc(size_t nmemb, size_t size)
static uint64_t ff_sfc64_get(FFSFC64 *s)
#define VGS_MAX_RECURSION_DEPTH
#define AV_PIX_FMT_RGB565
@ CMD_SET_LINE_JOIN
setlinejoin (join)
@ CMD_CURVE_TO
C, curveto (x1 y1 x2 y2 x y)
static const char *const vgs_func2_names[]
static enum AVPixelFormat drawvg_pix_fmts[]
#define FFSWAP(type, a, b)
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several the filter must be ready for frames arriving randomly on any input any filter with several inputs will most likely require some kind of queuing mechanism It is perfectly acceptable to have a limited queue and to drop frames when the inputs are too unbalanced request_frame For filters that do not use the this method is called when a frame is wanted on an output For a it should directly call filter_frame on the corresponding output For a if there are queued frames already one of these frames should be pushed If the filter should request a frame on one of its repeatedly until at least one frame has been pushed Return or at least make progress towards producing a frame
double av_strtod(const char *numstr, char **tail)
Parse the string in numstr and return its value as a double.
#define AV_PIX_FMT_0RGB32
@ CMD_SET_LINE_WIDTH
setlinewidth (width)
static void vgs_eval_state_free(struct VGSEvalState *state)
@ CMD_SET_DASH_OFFSET
setdashoffset (offset)
#define FILTER_INPUTS(array)
@ CMD_ROUNDEDRECT
roundedrect (x y width height radius)
static av_printf_format(4, 5)
const struct VGSProgram * program
@ VAR_T
Timestamp in seconds.
@ CMD_DEF_HSLA
defhsla (varname h s l a)
const FormatMap format_map[]
const char * var_names[VAR_COUNT+1]
enum VGSParameter::@408 type
cairo_status_t cairo_status(cairo_t *cr)
@ CMD_TRANSLATE
translate (tx ty)
AVFilter p
The public AVFilter.
static const struct VGSCommandSpec vgs_commands[]
static int vgs_parse_statement(void *log_ctx, struct VGSParser *parser, struct VGSProgram *program, const struct VGSCommandSpec *decl)
Extract the arguments for a command, and add a new statement to the program.
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
static void vgs_token_span(const struct VGSParser *parser, const struct VGSParserToken *token, size_t *line, size_t *column)
Compute the line/column numbers of the given token.
@ CMD_PROC_CALL
call name (expr)*
@ VAR_CX
X coordinate for current point.
#define AVERROR_BUG
Internal bug, also see AVERROR_BUG2.
#define MAY_PRESERVE(funcname)
const char *const * proc_names
Reference to the procedure names in the VGSProgram.
const struct VGSConstant * constants
Array for PARAM_CONSTANT.
#define RANDOM_STATES
Number of different states for the randomg function.
@ CMD_SET_HSLA
sethsla (h s l a)
char * av_strndup(const char *s, size_t len)
Duplicate a substring of a string.
static void draw_rounded_rect(cairo_t *c, double x, double y, double width, double height, double radius)
static void hsl2rgb(double h, double s, double l, double *pr, double *pg, double *pb)
cairo_color color_vars[USER_VAR_COUNT]
Colors stored in variables.
cairo_format_t cairo_format
Equivalent to AVPixelFormat.
@ CMD_LINE_TO
L, lineto (x y)
static void vgs_parser_init(struct VGSParser *parser, const char *source)
static const char *const vgs_func1_names[]
int proc_args_count
Number of expected arguments.
The official guide to swscale for confused that consecutive non overlapping rectangles of slice_bottom special converter These generally are unscaled converters of common like for each output line the vertical scaler pulls lines from a ring buffer When the ring buffer does not contain the wanted line
const char * av_get_pix_fmt_name(enum AVPixelFormat pix_fmt)
Return the short name for a pixel format, NULL in case pix_fmt is unknown.
static void draw_cubic_curve_to(struct VGSEvalState *state, int relative, double x1, double y1, double x2, double y2, double x, double y)
Similar to quad_curve_to, but for cubic curves.
@ CMD_CLOSE_PATH
Z, z, closepath.