FFmpeg
tf_mermaid.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) The FFmpeg developers
3  *
4  * This file is part of FFmpeg.
5  *
6  * FFmpeg is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * FFmpeg is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with FFmpeg; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 #include <limits.h>
22 #include <stdarg.h>
23 #include <stdint.h>
24 #include <stdio.h>
25 #include <string.h>
26 
27 #include "avtextformat.h"
28 #include "tf_internal.h"
29 #include "tf_mermaid.h"
30 #include "libavutil/bprint.h"
31 #include "libavutil/mem.h"
32 #include "libavutil/opt.h"
33 
34 
35 static const char *init_directive = ""
36  "%%{init: {"
37  "\"theme\": \"base\","
38  "\"curve\": \"monotoneX\","
39  "\"rankSpacing\": 10,"
40  "\"nodeSpacing\": 10,"
41  "\"themeCSS\": \"__###__\","
42  "\"fontFamily\": \"Roboto,Segoe UI,sans-serif\","
43  "\"themeVariables\": { "
44  "\"clusterBkg\": \"white\", "
45  "\"primaryBorderColor\": \"gray\", "
46  "\"lineColor\": \"gray\", "
47  "\"secondaryTextColor\": \"gray\", "
48  "\"tertiaryBorderColor\": \"gray\", "
49  "\"primaryTextColor\": \"#666\", "
50  "\"secondaryTextColor\": \"red\" "
51  "},"
52  "\"flowchart\": { "
53  "\"subGraphTitleMargin\": { \"top\": -15, \"bottom\": 20 }, "
54  "\"diagramPadding\": 20, "
55  "\"curve\": \"monotoneX\" "
56  "}"
57  " }}%%\n\n";
58 
59 static const char* init_directive_er = ""
60  "%%{init: {"
61  "\"theme\": \"base\","
62  "\"layout\": \"elk\","
63  "\"curve\": \"monotoneX\","
64  "\"rankSpacing\": 65,"
65  "\"nodeSpacing\": 60,"
66  "\"themeCSS\": \"__###__\","
67  "\"fontFamily\": \"Roboto,Segoe UI,sans-serif\","
68  "\"themeVariables\": { "
69  "\"clusterBkg\": \"white\", "
70  "\"primaryBorderColor\": \"gray\", "
71  "\"lineColor\": \"gray\", "
72  "\"secondaryTextColor\": \"gray\", "
73  "\"tertiaryBorderColor\": \"gray\", "
74  "\"primaryTextColor\": \"#666\", "
75  "\"secondaryTextColor\": \"red\" "
76  "},"
77  "\"er\": { "
78  "\"diagramPadding\": 12, "
79  "\"entityPadding\": 4, "
80  "\"minEntityWidth\": 150, "
81  "\"minEntityHeight\": 20, "
82  "\"curve\": \"monotoneX\" "
83  "}"
84  " }}%%\n\n";
85 
86 static const char *theme_css_er = ""
87 
88  // Variables
89  ".root { "
90  "--ff-colvideo: #6eaa7b; "
91  "--ff-colaudio: #477fb3; "
92  "--ff-colsubtitle: #ad76ab; "
93  "--ff-coltext: #666; "
94  "} "
95  " g.nodes g.node.default rect.basic.label-container, "
96  " g.nodes g.node.default path { "
97  " rx: 1; "
98  " ry: 1; "
99  " stroke-width: 1px !important; "
100  " stroke: #e9e9e9 !important; "
101  " fill: url(#ff-filtergradient) !important; "
102  " filter: drop-shadow(0px 0px 5.5px rgba(0, 0, 0, 0.05)); "
103  " fill: white !important; "
104  " } "
105  " "
106  " .relationshipLine { "
107  " stroke: gray; "
108  " stroke-width: 1; "
109  " fill: none; "
110  " filter: drop-shadow(0px 0px 3px rgba(0, 0, 0, 0.2)); "
111  " } "
112  " "
113  " g.node.default g.label.name foreignObject > div > span > p, "
114  " g.nodes g.node.default g.label:not(.attribute-name, .attribute-keys, .attribute-type, .attribute-comment) foreignObject > div > span > p { "
115  " font-size: 0.95rem; "
116  " font-weight: 500; "
117  " text-transform: uppercase; "
118  " min-width: 5.5rem; "
119  " margin-bottom: 0.5rem; "
120  " "
121  " } "
122  " "
123  " .edgePaths path { "
124  " marker-end: none; "
125  " marker-start: none; "
126  " "
127  "} ";
128 
129 
130 /* Mermaid Graph output */
131 
132 typedef struct MermaidContext {
133  const AVClass *class;
139 
140  // Options
141  int enable_link_colors; // Requires Mermaid 11.5
142 
143  struct section_data {
144  const char *section_id;
145  const char *section_type;
146  const char *src_id;
147  const char *dest_id;
153 
154  unsigned nb_link_captions[SECTION_MAX_NB_LEVELS]; ///< generic print buffer dedicated to each section,
155  AVBPrint link_buf; ///< print buffer for writing diagram links
158 
159 #undef OFFSET
160 #define OFFSET(x) offsetof(MermaidContext, x)
161 
162 static const AVOption mermaid_options[] = {
163  { "link_coloring", "enable colored links (requires Mermaid >= 11.5)", OFFSET(enable_link_colors), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1 },
164  ////{"diagram_css", "CSS for the diagram", OFFSET(diagram_css), AV_OPT_TYPE_STRING, {.i64=0}, 0, 1 },
165  ////{"html_template", "Template HTML", OFFSET(html_template), AV_OPT_TYPE_STRING, {.i64=0}, 0, 1 },
166  { NULL },
167 };
168 
169 DEFINE_FORMATTER_CLASS(mermaid);
170 
172 {
173  MermaidContext *mmc = tfc->priv;
174  mmc->diagram_config = diagram_config;
175 }
176 
177 static av_cold int has_link_pair(const AVTextFormatContext *tfc, const char *src, const char *dest)
178 {
179  MermaidContext *mmc = tfc->priv;
180  AVBPrint buf;
181 
183  av_bprintf(&buf, "%s--%s", src, dest);
184 
185  if (mmc->link_dict && av_dict_get(mmc->link_dict, buf.str, NULL, 0))
186  return 1;
187 
188  av_dict_set(&mmc->link_dict, buf.str, buf.str, 0);
189 
190  return 0;
191 }
192 
194 {
195  MermaidContext *mmc = tfc->priv;
196 
198 
199  ////mmc->enable_link_colors = 1; // Requires Mermaid 11.5
200  return 0;
201 }
202 
204 {
205  MermaidContext *mmc = tfc->priv;
206 
207  int ret = mermaid_init(tfc);
208 
209  if (ret < 0)
210  return ret;
211 
212  mmc->create_html = 1;
213 
214  return 0;
215 }
216 
218 {
219  MermaidContext *mmc = tfc->priv;
220 
222  av_dict_free(&mmc->link_dict);
223 
224  for (unsigned i = 0; i < SECTION_MAX_NB_LEVELS; i++) {
225  av_freep(&mmc->section_data[i].dest_id);
227  av_freep(&mmc->section_data[i].src_id);
229  }
230 
231  return 0;
232 }
233 
234 static void set_str(const char **dst, const char *src)
235 {
236  if (*dst)
237  av_freep(dst);
238 
239  if (src)
240  *dst = av_strdup(src);
241 }
242 
244  struct section_data parent_sec_data = mmc->section_data[level];
245  AVBPrint *parent_buf = &tfc->section_pbuf[level];
246 
247  if (parent_sec_data.subgraph_start_incomplete) {
248  if (parent_buf->len > 0)
249  writer_printf(tfc, "%s", parent_buf->str);
250 
251  writer_put_str(tfc, "</div>\"]\n");
252 
254  }
255 }
256 
257 #define MM_INDENT() writer_printf(tfc, "%*c", mmc->indent_level * 2, ' ')
258 
260 {
261  const AVTextFormatSection *section = tf_get_section(tfc, tfc->level);
262  const AVTextFormatSection *parent_section = tf_get_parent_section(tfc, tfc->level);
263 
264  if (!section)
265  return;
266  AVBPrint *buf = &tfc->section_pbuf[tfc->level];
267  MermaidContext *mmc = tfc->priv;
268  const AVTextFormatSectionContext *sec_ctx = data;
269 
270  if (tfc->level == 0) {
271  char *directive;
272  AVBPrint css_buf;
274  char *single_line_css = av_strireplace(mmc->diagram_config->diagram_css, "\n", " ");
275  (void)theme_css_er;
276  ////char *single_line_css = av_strireplace(theme_css_er, "\n", " ");
278  av_bprint_escape(&css_buf, single_line_css, "'\\", AV_ESCAPE_MODE_BACKSLASH, AV_ESCAPE_FLAG_STRICT);
279  av_freep(&single_line_css);
280 
281  directive = av_strireplace(diag_directive, "__###__", css_buf.str);
282  if (mmc->create_html) {
283  uint64_t length;
284  char *token_pos = av_stristr(mmc->diagram_config->html_template, "__###__");
285  if (!token_pos) {
286  av_log(tfc, AV_LOG_ERROR, "Unable to locate the required token (__###__) in the html template.");
287  return;
288  }
289 
290  length = token_pos - mmc->diagram_config->html_template;
291  for (uint64_t i = 0; i < length; i++)
293  }
294 
295  writer_put_str(tfc, directive);
296  switch (mmc->diagram_config->diagram_type) {
298  writer_put_str(tfc, "flowchart LR\n");
299  ////writer_put_str(tfc, " gradient_def@{ shape: text, label: \"<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"1\" height=\"1\"><defs><linearGradient id=\"ff-filtergradient\" x1=\"0%\" y1=\"0%\" x2=\"0%\" y2=\"100%\"><stop offset=\"0%\" style=\"stop-color:hsla(0, 0%, 30%, 0.02);\"/><stop offset=\"50%\" style=\"stop-color:hsla(0, 0%, 30%, 0);\"/><stop offset=\"100%\" style=\"stop-color:hsla(0, 0%, 30%, 0.05);\"/></linearGradient></defs></svg>\" }\n");
300  writer_put_str(tfc, " gradient_def@{ shape: text, label: \"<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"1\" height=\"1\"><defs><linearGradient id=\"ff-filtergradient\" x1=\"0%\" y1=\"0%\" x2=\"0%\" y2=\"100%\"><stop offset=\"0%\" style=\"stop-color:hsl(0, 0%, 98.6%); \"/><stop offset=\"50%\" style=\"stop-color:hsl(0, 0%, 100%); \"/><stop offset=\"100%\" style=\"stop-color:hsl(0, 0%, 96.5%); \"/></linearGradient><radialGradient id=\"ff-radgradient\" cx=\"50%\" cy=\"50%\" r=\"100%\" fx=\"45%\" fy=\"40%\"><stop offset=\"25%\" stop-color=\"hsl(0, 0%, 100%)\" /><stop offset=\"100%\" stop-color=\"hsl(0, 0%, 96%)\" /></radialGradient></defs></svg>\" }\n");
301  break;
303  writer_put_str(tfc, "erDiagram\n");
304  break;
305  }
306 
307  av_bprint_finalize(&css_buf, NULL);
308  av_freep(&directive);
309  return;
310  }
311 
312  if (parent_section && parent_section->flags & AV_TEXTFORMAT_SECTION_FLAG_IS_SUBGRAPH) {
313  mermaid_subgraph_complete_start(mmc, tfc, tfc->level - 1);
314  }
315 
316  av_freep(&mmc->section_data[tfc->level].section_id);
318  av_freep(&mmc->section_data[tfc->level].src_id);
319  av_freep(&mmc->section_data[tfc->level].dest_id);
320  mmc->section_data[tfc->level].current_is_textblock = 0;
321  mmc->section_data[tfc->level].current_is_stadium = 0;
324 
325  // NOTE: av_strdup() allocations aren't checked
327 
328  av_bprint_clear(buf);
329  writer_put_str(tfc, "\n");
330 
331  mmc->indent_level++;
332 
333  if (sec_ctx->context_id) {
334  MM_INDENT();
335  writer_printf(tfc, "subgraph %s[\"<div class=\"ff-%s\">", sec_ctx->context_id, section->name);
336  } else {
337  av_log(tfc, AV_LOG_ERROR, "Unable to write subgraph start. Missing id field. Section: %s", section->name);
338  }
339 
341  set_str(&mmc->section_data[tfc->level].section_id, sec_ctx->context_id);
342  }
343 
345 
346  av_bprint_clear(buf);
347  writer_put_str(tfc, "\n");
348 
349  mmc->indent_level++;
350 
351  if (sec_ctx->context_id) {
352 
353  set_str(&mmc->section_data[tfc->level].section_id, sec_ctx->context_id);
354 
355  switch (mmc->diagram_config->diagram_type) {
357  if (sec_ctx->context_flags & 1) {
358 
359  MM_INDENT();
360  writer_printf(tfc, "%s@{ shape: text, label: \"", sec_ctx->context_id);
361  mmc->section_data[tfc->level].current_is_textblock = 1;
362  } else if (sec_ctx->context_flags & 2) {
363 
364  MM_INDENT();
365  writer_printf(tfc, "%s([\"", sec_ctx->context_id);
366  mmc->section_data[tfc->level].current_is_stadium = 1;
367  } else {
368  MM_INDENT();
369  writer_printf(tfc, "%s(\"", sec_ctx->context_id);
370  }
371 
372  break;
374  MM_INDENT();
375  writer_printf(tfc, "%s {\n", sec_ctx->context_id);
376  break;
377  }
378 
379  } else {
380  av_log(tfc, AV_LOG_ERROR, "Unable to write shape start. Missing id field. Section: %s", section->name);
381  }
382 
383  set_str(&mmc->section_data[tfc->level].section_id, sec_ctx->context_id);
384  }
385 
386 
387  if (section->flags & AV_TEXTFORMAT_SECTION_PRINT_TAGS) {
388 
389  if (sec_ctx && sec_ctx->context_type)
390  writer_printf(tfc, "<div class=\"ff-%s %s\">", section->name, sec_ctx->context_type);
391  else
392  writer_printf(tfc, "<div class=\"ff-%s\">", section->name);
393  }
394 
395 
397 
398  av_bprint_clear(buf);
399  mmc->nb_link_captions[tfc->level] = 0;
400 
401  if (sec_ctx && sec_ctx->context_type)
402  set_str(&mmc->section_data[tfc->level].section_type, sec_ctx->context_type);
403 
404  ////if (section->flags & AV_TEXTFORMAT_SECTION_FLAG_HAS_TYPE) {
405  //// AVBPrint buf;
406  //// av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
407  //// av_bprint_escape(&buf, section->get_type(data), NULL,
408  //// AV_ESCAPE_MODE_XML, AV_ESCAPE_FLAG_XML_DOUBLE_QUOTES);
409  //// writer_printf(tfc, " type=\"%s\"", buf.str);
410  }
411 }
412 
414 {
415  MermaidContext *mmc = tfc->priv;
416  const AVTextFormatSection *section = tf_get_section(tfc, tfc->level);
417 
418  if (!section)
419  return;
420  AVBPrint *buf = &tfc->section_pbuf[tfc->level];
421  struct section_data sec_data = mmc->section_data[tfc->level];
422 
424  writer_put_str(tfc, "</div>");
425 
427 
428  switch (mmc->diagram_config->diagram_type) {
430 
431  if (sec_data.current_is_textblock) {
432  writer_printf(tfc, "\"}\n", section->name);
433 
434  if (sec_data.section_id) {
435  MM_INDENT();
436  writer_put_str(tfc, "class ");
437  writer_put_str(tfc, sec_data.section_id);
438  writer_put_str(tfc, " ff-");
439  writer_put_str(tfc, section->name);
440  writer_put_str(tfc, "\n");
441  }
442  } else if (sec_data.current_is_stadium) {
443  writer_printf(tfc, "\"]):::ff-%s\n", section->name);
444  } else {
445  writer_printf(tfc, "\"):::ff-%s\n", section->name);
446  }
447 
448  break;
450  MM_INDENT();
451  writer_put_str(tfc, "}\n\n");
452  break;
453  }
454 
455  mmc->indent_level--;
456 
457  } else if ((section->flags & AV_TEXTFORMAT_SECTION_FLAG_IS_SUBGRAPH)) {
458 
459  mermaid_subgraph_complete_start(mmc, tfc, tfc->level);
460 
461  MM_INDENT();
462  writer_put_str(tfc, "end\n");
463 
464  if (sec_data.section_id) {
465  MM_INDENT();
466  writer_put_str(tfc, "class ");
467  writer_put_str(tfc, sec_data.section_id);
468  writer_put_str(tfc, " ff-");
469  writer_put_str(tfc, section->name);
470  writer_put_str(tfc, "\n");
471  }
472 
473  mmc->indent_level--;
474  }
475 
477  if (sec_data.src_id && sec_data.dest_id
478  && !has_link_pair(tfc, sec_data.src_id, sec_data.dest_id))
479  switch (mmc->diagram_config->diagram_type) {
481 
482  if (sec_data.section_type && mmc->enable_link_colors)
483  av_bprintf(&mmc->link_buf, "\n %s %s-%s-%s@==", sec_data.src_id, sec_data.section_type, sec_data.src_id, sec_data.dest_id);
484  else
485  av_bprintf(&mmc->link_buf, "\n %s ==", sec_data.src_id);
486 
487  if (buf->len > 0) {
488  av_bprintf(&mmc->link_buf, " \"%s", buf->str);
489 
490  for (unsigned i = 0; i < mmc->nb_link_captions[tfc->level]; i++)
491  av_bprintf(&mmc->link_buf, "<br>&nbsp;");
492 
493  av_bprintf(&mmc->link_buf, "\" ==");
494  }
495 
496  av_bprintf(&mmc->link_buf, "> %s", sec_data.dest_id);
497 
498  break;
500 
501 
502  av_bprintf(&mmc->link_buf, "\n %s", sec_data.src_id);
503 
504  switch (sec_data.link_type) {
506  av_bprintf(&mmc->link_buf, "%s", " ||--o{ ");
507  break;
509  av_bprintf(&mmc->link_buf, "%s", " }o--|| ");
510  break;
512  av_bprintf(&mmc->link_buf, "%s", " ||--|| ");
513  break;
515  av_bprintf(&mmc->link_buf, "%s", " }o--o{ ");
516  break;
517  default:
518  av_bprintf(&mmc->link_buf, "%s", " ||--|| ");
519  break;
520  }
521 
522  av_bprintf(&mmc->link_buf, "%s : \"\"", sec_data.dest_id);
523 
524  break;
525  }
526 
527  if (tfc->level == 0) {
528 
529  writer_put_str(tfc, "\n");
530  if (mmc->create_html) {
531  char *token_pos = av_stristr(mmc->diagram_config->html_template, "__###__");
532  if (!token_pos) {
533  av_log(tfc, AV_LOG_ERROR, "Unable to locate the required token (__###__) in the html template.");
534  return;
535  }
536  token_pos += strlen("__###__");
537  writer_put_str(tfc, token_pos);
538  }
539  }
540 
541  if (tfc->level == 1) {
542 
543  if (mmc->link_buf.len > 0) {
544  writer_put_str(tfc, mmc->link_buf.str);
545  av_bprint_clear(&mmc->link_buf);
546  }
547 
548  writer_put_str(tfc, "\n");
549  }
550 }
551 
552 static void mermaid_print_value(AVTextFormatContext *tfc, const char *key,
553  const char *str, int64_t num, const int is_int)
554 {
555  MermaidContext *mmc = tfc->priv;
556  const AVTextFormatSection *section = tf_get_section(tfc, tfc->level);
557 
558  if (!section)
559  return;
560 
561  AVBPrint *buf = &tfc->section_pbuf[tfc->level];
562  struct section_data sec_data = mmc->section_data[tfc->level];
563  int exit = 0;
564 
565  if (section->id_key && !strcmp(section->id_key, key)) {
566  set_str(&mmc->section_data[tfc->level].section_id, str);
567  exit = 1;
568  }
569 
570  if (section->dest_id_key && !strcmp(section->dest_id_key, key)) {
571  set_str(&mmc->section_data[tfc->level].dest_id, str);
572  exit = 1;
573  }
574 
575  if (section->src_id_key && !strcmp(section->src_id_key, key)) {
576  set_str(&mmc->section_data[tfc->level].src_id, str);
577  exit = 1;
578  }
579 
580  if (section->linktype_key && !strcmp(section->linktype_key, key)) {
582  exit = 1;
583  }
584 
585  if (exit)
586  return;
587 
589  || (section->flags & AV_TEXTFORMAT_SECTION_FLAG_IS_SUBGRAPH && sec_data.subgraph_start_incomplete)) {
590  switch (mmc->diagram_config->diagram_type) {
592 
593  if (is_int) {
594  writer_printf(tfc, "<span class=\"%s\">%s: %"PRId64"</span>", key, key, num);
595  } else {
596  const char *tmp = av_strireplace(str, "\"", "'");
597  writer_printf(tfc, "<span class=\"%s\">%s</span>", key, tmp);
598  av_freep(&tmp);
599  }
600 
601  break;
603 
604  if (!is_int && str)
605  {
606  const char *col_type;
607 
608  if (key[0] == '_')
609  return;
610 
611  if (sec_data.section_id && !strcmp(str, sec_data.section_id))
612  col_type = "PK";
613  else if (sec_data.dest_id && !strcmp(str, sec_data.dest_id))
614  col_type = "FK";
615  else if (sec_data.src_id && !strcmp(str, sec_data.src_id))
616  col_type = "FK";
617  else
618  col_type = "";
619 
620  MM_INDENT();
621 
622  writer_printf(tfc, " %s %s %s\n", key, str, col_type);
623  }
624  break;
625  }
626 
627  } else if (section->flags & AV_TEXTFORMAT_SECTION_FLAG_HAS_LINKS) {
628  if (buf->len > 0)
629  av_bprintf(buf, "%s", "<br>");
630 
631  av_bprintf(buf, "");
632  if (is_int)
633  av_bprintf(buf, "<span>%s: %"PRId64"</span>", key, num);
634  else
635  av_bprintf(buf, "<span>%s</span>", str);
636 
637  mmc->nb_link_captions[tfc->level]++;
638  }
639 }
640 
641 static inline void mermaid_print_str(AVTextFormatContext *tfc, const char *key, const char *value)
642 {
643  mermaid_print_value(tfc, key, value, 0, 0);
644 }
645 
646 static void mermaid_print_int(AVTextFormatContext *tfc, const char *key, int64_t value)
647 {
648  mermaid_print_value(tfc, key, NULL, value, 1);
649 }
650 
652  .name = "mermaid",
653  .priv_size = sizeof(MermaidContext),
654  .init = mermaid_init,
656  .print_section_header = mermaid_print_section_header,
657  .print_section_footer = mermaid_print_section_footer,
658  .print_integer = mermaid_print_int,
659  .print_string = mermaid_print_str,
661  .priv_class = &mermaid_class,
662 };
663 
664 
666  .name = "mermaidhtml",
667  .priv_size = sizeof(MermaidContext),
670  .print_section_header = mermaid_print_section_header,
671  .print_section_footer = mermaid_print_section_footer,
672  .print_integer = mermaid_print_int,
673  .print_string = mermaid_print_str,
675  .priv_class = &mermaid_class,
676 };
flags
const SwsFlags flags[]
Definition: swscale.c:61
AV_BPRINT_SIZE_UNLIMITED
#define AV_BPRINT_SIZE_UNLIMITED
level
uint8_t level
Definition: svq3.c:208
AV_TEXTFORMAT_SECTION_PRINT_TAGS
#define AV_TEXTFORMAT_SECTION_PRINT_TAGS
...
Definition: avtextformat.h:53
MermaidContext::link_buf
AVBPrint link_buf
print buffer for writing diagram links
Definition: tf_mermaid.c:155
AV_TEXTFORMAT_FLAG_IS_DIAGRAM_FORMATTER
#define AV_TEXTFORMAT_FLAG_IS_DIAGRAM_FORMATTER
Definition: avtextformat.h:73
opt.h
AV_TEXTFORMAT_LINKTYPE_SRCDEST
@ AV_TEXTFORMAT_LINKTYPE_SRCDEST
Definition: avtextformat.h:83
av_bprint_init
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
Definition: bprint.c:69
av_stristr
char * av_stristr(const char *s1, const char *s2)
Locate the first case-independent occurrence in the string haystack of the string needle.
Definition: avstring.c:58
has_link_pair
static av_cold int has_link_pair(const AVTextFormatContext *tfc, const char *src, const char *dest)
Definition: tf_mermaid.c:177
int64_t
long long int64_t
Definition: coverity.c:34
AVTextFormatSection::src_id_key
const char * src_id_key
name of the key to be used as the source id for diagram connections
Definition: avtextformat.h:64
AV_DIAGRAMTYPE_ENTITYRELATIONSHIP
@ AV_DIAGRAMTYPE_ENTITYRELATIONSHIP
Definition: tf_mermaid.h:26
AVTextFormatSectionContext::context_type
const char * context_type
Definition: avtextformat.h:36
AVDiagramConfig::diagram_css
const char * diagram_css
Definition: tf_mermaid.h:31
writer_printf
static void writer_printf(AVTextFormatContext *wctx, const char *fmt,...)
Definition: tf_internal.h:73
AVOption
AVOption.
Definition: opt.h:429
data
const char data[16]
Definition: mxf.c:149
AV_TEXTFORMAT_SECTION_FLAG_IS_SUBGRAPH
#define AV_TEXTFORMAT_SECTION_FLAG_IS_SUBGRAPH
...
Definition: avtextformat.h:54
avtextformat.h
AVTextFormatContext
Definition: avtextformat.h:112
AVDictionary
Definition: dict.c:32
AV_TEXTFORMAT_LINKTYPE_ONETOMANY
@ AV_TEXTFORMAT_LINKTYPE_ONETOMANY
Definition: avtextformat.h:88
mermaid_print_int
static void mermaid_print_int(AVTextFormatContext *tfc, const char *key, int64_t value)
Definition: tf_mermaid.c:646
DEFINE_FORMATTER_CLASS
DEFINE_FORMATTER_CLASS(mermaid)
init_directive
static const char * init_directive
Definition: tf_mermaid.c:35
AVTextFormatContext::level
int level
current level, starting from 0
Definition: avtextformat.h:123
AVTextFormatSection::name
const char * name
Definition: avtextformat.h:43
AVDiagramConfig
Definition: tf_mermaid.h:29
AV_ESCAPE_FLAG_STRICT
#define AV_ESCAPE_FLAG_STRICT
Escape only specified special characters.
Definition: avstring.h:336
AVTextFormatLinkType
AVTextFormatLinkType
Definition: avtextformat.h:82
MermaidContext::link_dict
AVDictionary * link_dict
Definition: tf_mermaid.c:156
AV_TEXTFORMAT_LINKTYPE_MANYTOONE
@ AV_TEXTFORMAT_LINKTYPE_MANYTOONE
Definition: avtextformat.h:89
avtextformatter_mermaid
const AVTextFormatter avtextformatter_mermaid
Definition: tf_mermaid.c:651
mermaid_print_str
static void mermaid_print_str(AVTextFormatContext *tfc, const char *key, const char *value)
Definition: tf_mermaid.c:641
AVTextFormatSectionContext
Definition: avtextformat.h:34
mermaid_init_html
static av_cold int mermaid_init_html(AVTextFormatContext *tfc)
Definition: tf_mermaid.c:203
AVTextFormatSection::flags
int flags
Definition: avtextformat.h:56
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:210
av_cold
#define av_cold
Definition: attributes.h:106
av_dict_get
AVDictionaryEntry * av_dict_get(const AVDictionary *m, const char *key, const AVDictionaryEntry *prev, int flags)
Get a dictionary entry with matching key.
Definition: dict.c:60
AVTextFormatter
Definition: avtextformat.h:94
AVTextFormatSection
Definition: avtextformat.h:41
limits.h
AVTextFormatContext::priv
void * priv
private data for use by the filter
Definition: avtextformat.h:118
key
const char * key
Definition: hwcontext_opencl.c:189
tmp
static uint8_t tmp[40]
Definition: aes_ctr.c:52
MermaidContext::section_data::subgraph_start_incomplete
int subgraph_start_incomplete
Definition: tf_mermaid.c:151
MermaidContext
Definition: tf_mermaid.c:132
AV_DIAGRAMTYPE_GRAPH
@ AV_DIAGRAMTYPE_GRAPH
Definition: tf_mermaid.h:25
MermaidContext::within_tag
int within_tag
Definition: tf_mermaid.c:136
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:76
NULL
#define NULL
Definition: coverity.c:32
writer_w8
static void writer_w8(AVTextFormatContext *wctx, int b)
Definition: tf_internal.h:63
MermaidContext::create_html
int create_html
Definition: tf_mermaid.c:138
av_bprint_escape
void av_bprint_escape(AVBPrint *dstbuf, const char *src, const char *special_chars, enum AVEscapeMode mode, int flags)
Escape the content in src and append it to dstbuf.
Definition: bprint.c:263
tf_get_parent_section
static const AVTextFormatSection * tf_get_parent_section(AVTextFormatContext *tfc, int level)
Safely access the parent section.
Definition: tf_internal.h:55
OFFSET
#define OFFSET(x)
Definition: tf_mermaid.c:160
MermaidContext::section_data::current_is_textblock
int current_is_textblock
Definition: tf_mermaid.c:149
av_strireplace
char * av_strireplace(const char *str, const char *from, const char *to)
Locale-independent strings replace.
Definition: avstring.c:230
AV_TEXTFORMAT_LINKTYPE_MANYTOMANY
@ AV_TEXTFORMAT_LINKTYPE_MANYTOMANY
Definition: avtextformat.h:91
MermaidContext::section_data
Definition: tf_mermaid.c:143
MermaidContext::diagram_config
AVDiagramConfig * diagram_config
Definition: tf_mermaid.c:134
MermaidContext::subgraph_count
int subgraph_count
Definition: tf_mermaid.c:135
SECTION_MAX_NB_LEVELS
#define SECTION_MAX_NB_LEVELS
Definition: avtextformat.h:109
init
int(* init)(AVBSFContext *ctx)
Definition: dts2pts.c:550
mermaid_print_section_footer
static void mermaid_print_section_footer(AVTextFormatContext *tfc)
Definition: tf_mermaid.c:413
av_bprint_finalize
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
Definition: bprint.c:235
MM_INDENT
#define MM_INDENT()
Definition: tf_mermaid.c:257
dst
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
Definition: dsp.h:87
mermaid_print_value
static void mermaid_print_value(AVTextFormatContext *tfc, const char *key, const char *str, int64_t num, const int is_int)
Definition: tf_mermaid.c:552
AVTextFormatter::name
const char * name
Definition: avtextformat.h:97
MermaidContext::section_data::src_id
const char * src_id
Definition: tf_mermaid.c:146
AV_TEXTFORMAT_SECTION_FLAG_IS_SHAPE
#define AV_TEXTFORMAT_SECTION_FLAG_IS_SHAPE
...
Definition: avtextformat.h:51
MermaidContext::indent_level
int indent_level
Definition: tf_mermaid.c:137
AVTextFormatContext::section_pbuf
AVBPrint section_pbuf[SECTION_MAX_NB_LEVELS]
generic print buffer dedicated to each section, used by various formatters
Definition: avtextformat.h:131
theme_css_er
static const char * theme_css_er
Definition: tf_mermaid.c:86
avtextformatter_mermaidhtml
const AVTextFormatter avtextformatter_mermaidhtml
Definition: tf_mermaid.c:665
tf_internal.h
av_dict_free
void av_dict_free(AVDictionary **pm)
Free all the memory allocated for an AVDictionary struct and all keys and values.
Definition: dict.c:233
AVTextFormatSection::linktype_key
const char * linktype_key
name of the key to be used as the link type for diagram connections (AVTextFormatLinkType)
Definition: avtextformat.h:66
mermaid_print_section_header
static void mermaid_print_section_header(AVTextFormatContext *tfc, const void *data)
Definition: tf_mermaid.c:259
AVDiagramConfig::diagram_type
AVDiagramType diagram_type
Definition: tf_mermaid.h:30
MermaidContext::enable_link_colors
int enable_link_colors
Definition: tf_mermaid.c:141
writer_put_str
static void writer_put_str(AVTextFormatContext *wctx, const char *str)
Definition: tf_internal.h:68
uninit
static void uninit(AVBSFContext *ctx)
Definition: pcm_rechunk.c:68
bprint.h
AVTextFormatSectionContext::context_id
char * context_id
Definition: avtextformat.h:35
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:256
MermaidContext::nb_link_captions
unsigned nb_link_captions[SECTION_MAX_NB_LEVELS]
generic print buffer dedicated to each section,
Definition: tf_mermaid.c:154
set_str
static void set_str(const char **dst, const char *src)
Definition: tf_mermaid.c:234
mermaid_init
static av_cold int mermaid_init(AVTextFormatContext *tfc)
Definition: tf_mermaid.c:193
value
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
Definition: writing_filters.txt:86
AVTextFormatSectionContext::context_flags
int context_flags
Definition: avtextformat.h:37
MermaidContext::section_data
struct MermaidContext::section_data section_data[SECTION_MAX_NB_LEVELS]
AV_TEXTFORMAT_LINKTYPE_ONETOONE
@ AV_TEXTFORMAT_LINKTYPE_ONETOONE
Definition: avtextformat.h:90
ret
ret
Definition: filter_design.txt:187
AVTextFormatSection::dest_id_key
const char * dest_id_key
name of the key to be used as the target id for diagram connections
Definition: avtextformat.h:65
MermaidContext::section_data::dest_id
const char * dest_id
Definition: tf_mermaid.c:147
av_bprintf
void av_bprintf(AVBPrint *buf, const char *fmt,...)
Definition: bprint.c:122
AV_TEXTFORMAT_SECTION_FLAG_HAS_LINKS
#define AV_TEXTFORMAT_SECTION_FLAG_HAS_LINKS
...
Definition: avtextformat.h:52
AVDiagramConfig::html_template
const char * html_template
Definition: tf_mermaid.h:32
MermaidContext::section_data::section_id
const char * section_id
Definition: tf_mermaid.c:144
av_bprint_clear
void av_bprint_clear(AVBPrint *buf)
Reset the string to "" but keep internal allocated data.
Definition: bprint.c:227
mermaid_uninit
static av_cold int mermaid_uninit(AVTextFormatContext *tfc)
Definition: tf_mermaid.c:217
MermaidContext::section_data::current_is_stadium
int current_is_stadium
Definition: tf_mermaid.c:150
MermaidContext::section_data::section_type
const char * section_type
Definition: tf_mermaid.c:145
mermaid_subgraph_complete_start
static void mermaid_subgraph_complete_start(MermaidContext *mmc, AVTextFormatContext *tfc, int level)
Definition: tf_mermaid.c:243
av_strdup
char * av_strdup(const char *s)
Duplicate a string.
Definition: mem.c:272
mem.h
AVTextFormatSection::id_key
const char * id_key
name of the key to be used as the id
Definition: avtextformat.h:63
AV_OPT_TYPE_BOOL
@ AV_OPT_TYPE_BOOL
Underlying C type is int.
Definition: opt.h:327
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:35
av_dict_set
int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags)
Set the given entry in *pm, overwriting an existing entry.
Definition: dict.c:86
AV_ESCAPE_MODE_BACKSLASH
@ AV_ESCAPE_MODE_BACKSLASH
Use backslash escaping.
Definition: avstring.h:316
tf_get_section
static const AVTextFormatSection * tf_get_section(AVTextFormatContext *tfc, int level)
Safely validate and access a section at a given level.
Definition: tf_internal.h:42
av_diagram_init
void av_diagram_init(AVTextFormatContext *tfc, AVDiagramConfig *diagram_config)
Definition: tf_mermaid.c:171
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
MermaidContext::section_data::link_type
AVTextFormatLinkType link_type
Definition: tf_mermaid.c:148
src
#define src
Definition: vp8dsp.c:248
mermaid_options
static const AVOption mermaid_options[]
Definition: tf_mermaid.c:162
init_directive_er
static const char * init_directive_er
Definition: tf_mermaid.c:59
tf_mermaid.h