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 <inttypes.h>
22 #include <limits.h>
23 #include <stdarg.h>
24 #include <string.h>
25 
26 #include "avtextformat.h"
27 #include "tf_internal.h"
28 #include "tf_mermaid.h"
29 #include "libavutil/bprint.h"
30 #include "libavutil/mem.h"
31 #include "libavutil/opt.h"
32 
33 
34 static const char *init_directive = ""
35  "%%{init: {"
36  "\"theme\": \"base\","
37  "\"curve\": \"monotoneX\","
38  "\"rankSpacing\": 10,"
39  "\"nodeSpacing\": 10,"
40  "\"themeCSS\": \"__###__\","
41  "\"fontFamily\": \"Roboto,Segoe UI,sans-serif\","
42  "\"themeVariables\": { "
43  "\"clusterBkg\": \"white\", "
44  "\"primaryBorderColor\": \"gray\", "
45  "\"lineColor\": \"gray\", "
46  "\"secondaryTextColor\": \"gray\", "
47  "\"tertiaryBorderColor\": \"gray\", "
48  "\"primaryTextColor\": \"#666\", "
49  "\"secondaryTextColor\": \"red\" "
50  "},"
51  "\"flowchart\": { "
52  "\"subGraphTitleMargin\": { \"top\": -15, \"bottom\": 20 }, "
53  "\"diagramPadding\": 20, "
54  "\"curve\": \"monotoneX\" "
55  "}"
56  " }}%%\n\n";
57 
58 static const char* init_directive_er = ""
59  "%%{init: {"
60  "\"theme\": \"base\","
61  "\"layout\": \"elk\","
62  "\"curve\": \"monotoneX\","
63  "\"rankSpacing\": 65,"
64  "\"nodeSpacing\": 60,"
65  "\"themeCSS\": \"__###__\","
66  "\"fontFamily\": \"Roboto,Segoe UI,sans-serif\","
67  "\"themeVariables\": { "
68  "\"clusterBkg\": \"white\", "
69  "\"primaryBorderColor\": \"gray\", "
70  "\"lineColor\": \"gray\", "
71  "\"secondaryTextColor\": \"gray\", "
72  "\"tertiaryBorderColor\": \"gray\", "
73  "\"primaryTextColor\": \"#666\", "
74  "\"secondaryTextColor\": \"red\" "
75  "},"
76  "\"er\": { "
77  "\"diagramPadding\": 12, "
78  "\"entityPadding\": 4, "
79  "\"minEntityWidth\": 150, "
80  "\"minEntityHeight\": 20, "
81  "\"curve\": \"monotoneX\" "
82  "}"
83  " }}%%\n\n";
84 
85 static const char *theme_css_er = ""
86 
87  // Variables
88  ".root { "
89  "--ff-colvideo: #6eaa7b; "
90  "--ff-colaudio: #477fb3; "
91  "--ff-colsubtitle: #ad76ab; "
92  "--ff-coltext: #666; "
93  "} "
94  " g.nodes g.node.default rect.basic.label-container, "
95  " g.nodes g.node.default path { "
96  " rx: 1; "
97  " ry: 1; "
98  " stroke-width: 1px !important; "
99  " stroke: #e9e9e9 !important; "
100  " fill: url(#ff-filtergradient) !important; "
101  " filter: drop-shadow(0px 0px 5.5px rgba(0, 0, 0, 0.05)); "
102  " fill: white !important; "
103  " } "
104  " "
105  " .relationshipLine { "
106  " stroke: gray; "
107  " stroke-width: 1; "
108  " fill: none; "
109  " filter: drop-shadow(0px 0px 3px rgba(0, 0, 0, 0.2)); "
110  " } "
111  " "
112  " g.node.default g.label.name foreignObject > div > span > p, "
113  " g.nodes g.node.default g.label:not(.attribute-name, .attribute-keys, .attribute-type, .attribute-comment) foreignObject > div > span > p { "
114  " font-size: 0.95rem; "
115  " font-weight: 500; "
116  " text-transform: uppercase; "
117  " min-width: 5.5rem; "
118  " margin-bottom: 0.5rem; "
119  " "
120  " } "
121  " "
122  " .edgePaths path { "
123  " marker-end: none; "
124  " marker-start: none; "
125  " "
126  "} ";
127 
128 
129 /* Mermaid Graph output */
130 
131 typedef struct MermaidContext {
132  const AVClass *class;
138 
139  // Options
140  int enable_link_colors; // Requires Mermaid 11.5
141 
142  struct section_data {
143  const char *section_id;
144  const char *section_type;
145  const char *src_id;
146  const char *dest_id;
152 
153  unsigned nb_link_captions[SECTION_MAX_NB_LEVELS]; ///< generic print buffer dedicated to each section,
154  AVBPrint link_buf; ///< print buffer for writing diagram links
157 
158 #undef OFFSET
159 #define OFFSET(x) offsetof(MermaidContext, x)
160 
161 static const AVOption mermaid_options[] = {
162  { "link_coloring", "enable colored links (requires Mermaid >= 11.5)", OFFSET(enable_link_colors), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1 },
163  ////{"diagram_css", "CSS for the diagram", OFFSET(diagram_css), AV_OPT_TYPE_STRING, {.i64=0}, 0, 1 },
164  ////{"html_template", "Template HTML", OFFSET(html_template), AV_OPT_TYPE_STRING, {.i64=0}, 0, 1 },
165  { NULL },
166 };
167 
168 DEFINE_FORMATTER_CLASS(mermaid);
169 
171 {
172  MermaidContext *mmc = tfc->priv;
173  mmc->diagram_config = diagram_config;
174 }
175 
176 static av_cold int has_link_pair(const AVTextFormatContext *tfc, const char *src, const char *dest)
177 {
178  MermaidContext *mmc = tfc->priv;
179  AVBPrint buf;
180 
182  av_bprintf(&buf, "%s--%s", src, dest);
183 
184  if (mmc->link_dict && av_dict_get(mmc->link_dict, buf.str, NULL, 0))
185  return 1;
186 
187  av_dict_set(&mmc->link_dict, buf.str, buf.str, 0);
188 
189  return 0;
190 }
191 
193 {
194  MermaidContext *mmc = tfc->priv;
195 
197 
198  ////mmc->enable_link_colors = 1; // Requires Mermaid 11.5
199  return 0;
200 }
201 
203 {
204  MermaidContext *mmc = tfc->priv;
205 
206  int ret = mermaid_init(tfc);
207 
208  if (ret < 0)
209  return ret;
210 
211  mmc->create_html = 1;
212 
213  return 0;
214 }
215 
217 {
218  MermaidContext *mmc = tfc->priv;
219 
221  av_dict_free(&mmc->link_dict);
222 
223  for (unsigned i = 0; i < SECTION_MAX_NB_LEVELS; i++) {
224  av_freep(&mmc->section_data[i].dest_id);
226  av_freep(&mmc->section_data[i].src_id);
228  }
229 
230  return 0;
231 }
232 
233 static void set_str(const char **dst, const char *src)
234 {
235  if (*dst)
236  av_freep(dst);
237 
238  if (src)
239  *dst = av_strdup(src);
240 }
241 
243  struct section_data parent_sec_data = mmc->section_data[level];
244  AVBPrint *parent_buf = &tfc->section_pbuf[level];
245 
246  if (parent_sec_data.subgraph_start_incomplete) {
247  if (parent_buf->len > 0)
248  writer_printf(tfc, "%s", parent_buf->str);
249 
250  writer_put_str(tfc, "</div>\"]\n");
251 
253  }
254 }
255 
256 #define MM_INDENT() writer_printf(tfc, "%*c", mmc->indent_level * 2, ' ')
257 
259 {
260  const AVTextFormatSection *section = tf_get_section(tfc, tfc->level);
261  const AVTextFormatSection *parent_section = tf_get_parent_section(tfc, tfc->level);
262 
263  if (!section)
264  return;
265  AVBPrint *buf = &tfc->section_pbuf[tfc->level];
266  MermaidContext *mmc = tfc->priv;
267  const AVTextFormatSectionContext *sec_ctx = data;
268 
269  if (tfc->level == 0) {
270  char *directive;
271  AVBPrint css_buf;
273  char *single_line_css = av_strireplace(mmc->diagram_config->diagram_css, "\n", " ");
274  (void)theme_css_er;
275  ////char *single_line_css = av_strireplace(theme_css_er, "\n", " ");
277  av_bprint_escape(&css_buf, single_line_css, "'\\", AV_ESCAPE_MODE_BACKSLASH, AV_ESCAPE_FLAG_STRICT);
278  av_freep(&single_line_css);
279 
280  directive = av_strireplace(diag_directive, "__###__", css_buf.str);
281  if (mmc->create_html) {
282  uint64_t length;
283  char *token_pos = av_stristr(mmc->diagram_config->html_template, "__###__");
284  if (!token_pos) {
285  av_log(tfc, AV_LOG_ERROR, "Unable to locate the required token (__###__) in the html template.");
286  return;
287  }
288 
289  length = token_pos - mmc->diagram_config->html_template;
290  for (uint64_t i = 0; i < length; i++)
292  }
293 
294  writer_put_str(tfc, directive);
295  switch (mmc->diagram_config->diagram_type) {
297  writer_put_str(tfc, "flowchart LR\n");
298  ////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");
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: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");
300  break;
302  writer_put_str(tfc, "erDiagram\n");
303  break;
304  }
305 
306  av_bprint_finalize(&css_buf, NULL);
307  av_freep(&directive);
308  return;
309  }
310 
311  if (parent_section && parent_section->flags & AV_TEXTFORMAT_SECTION_FLAG_IS_SUBGRAPH) {
312  mermaid_subgraph_complete_start(mmc, tfc, tfc->level - 1);
313  }
314 
315  av_freep(&mmc->section_data[tfc->level].section_id);
317  av_freep(&mmc->section_data[tfc->level].src_id);
318  av_freep(&mmc->section_data[tfc->level].dest_id);
319  mmc->section_data[tfc->level].current_is_textblock = 0;
320  mmc->section_data[tfc->level].current_is_stadium = 0;
323 
324  // NOTE: av_strdup() allocations aren't checked
326 
327  av_bprint_clear(buf);
328  writer_put_str(tfc, "\n");
329 
330  mmc->indent_level++;
331 
332  if (sec_ctx->context_id) {
333  MM_INDENT();
334  writer_printf(tfc, "subgraph %s[\"<div class=\"ff-%s\">", sec_ctx->context_id, section->name);
335  } else {
336  av_log(tfc, AV_LOG_ERROR, "Unable to write subgraph start. Missing id field. Section: %s", section->name);
337  }
338 
340  set_str(&mmc->section_data[tfc->level].section_id, sec_ctx->context_id);
341  }
342 
344 
345  av_bprint_clear(buf);
346  writer_put_str(tfc, "\n");
347 
348  mmc->indent_level++;
349 
350  if (sec_ctx->context_id) {
351 
352  set_str(&mmc->section_data[tfc->level].section_id, sec_ctx->context_id);
353 
354  switch (mmc->diagram_config->diagram_type) {
356  if (sec_ctx->context_flags & 1) {
357 
358  MM_INDENT();
359  writer_printf(tfc, "%s@{ shape: text, label: \"", sec_ctx->context_id);
360  mmc->section_data[tfc->level].current_is_textblock = 1;
361  } else if (sec_ctx->context_flags & 2) {
362 
363  MM_INDENT();
364  writer_printf(tfc, "%s([\"", sec_ctx->context_id);
365  mmc->section_data[tfc->level].current_is_stadium = 1;
366  } else {
367  MM_INDENT();
368  writer_printf(tfc, "%s(\"", sec_ctx->context_id);
369  }
370 
371  break;
373  MM_INDENT();
374  writer_printf(tfc, "%s {\n", sec_ctx->context_id);
375  break;
376  }
377 
378  } else {
379  av_log(tfc, AV_LOG_ERROR, "Unable to write shape start. Missing id field. Section: %s", section->name);
380  }
381 
382  set_str(&mmc->section_data[tfc->level].section_id, sec_ctx->context_id);
383  }
384 
385 
386  if (section->flags & AV_TEXTFORMAT_SECTION_PRINT_TAGS) {
387 
388  if (sec_ctx && sec_ctx->context_type)
389  writer_printf(tfc, "<div class=\"ff-%s %s\">", section->name, sec_ctx->context_type);
390  else
391  writer_printf(tfc, "<div class=\"ff-%s\">", section->name);
392  }
393 
394 
396 
397  av_bprint_clear(buf);
398  mmc->nb_link_captions[tfc->level] = 0;
399 
400  if (sec_ctx && sec_ctx->context_type)
401  set_str(&mmc->section_data[tfc->level].section_type, sec_ctx->context_type);
402 
403  ////if (section->flags & AV_TEXTFORMAT_SECTION_FLAG_HAS_TYPE) {
404  //// AVBPrint buf;
405  //// av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
406  //// av_bprint_escape(&buf, section->get_type(data), NULL,
407  //// AV_ESCAPE_MODE_XML, AV_ESCAPE_FLAG_XML_DOUBLE_QUOTES);
408  //// writer_printf(tfc, " type=\"%s\"", buf.str);
409  }
410 }
411 
413 {
414  MermaidContext *mmc = tfc->priv;
415  const AVTextFormatSection *section = tf_get_section(tfc, tfc->level);
416 
417  if (!section)
418  return;
419  AVBPrint *buf = &tfc->section_pbuf[tfc->level];
420  struct section_data sec_data = mmc->section_data[tfc->level];
421 
423  writer_put_str(tfc, "</div>");
424 
426 
427  switch (mmc->diagram_config->diagram_type) {
429 
430  if (sec_data.current_is_textblock) {
431  writer_printf(tfc, "\"}\n", section->name);
432 
433  if (sec_data.section_id) {
434  MM_INDENT();
435  writer_put_str(tfc, "class ");
436  writer_put_str(tfc, sec_data.section_id);
437  writer_put_str(tfc, " ff-");
438  writer_put_str(tfc, section->name);
439  writer_put_str(tfc, "\n");
440  }
441  } else if (sec_data.current_is_stadium) {
442  writer_printf(tfc, "\"]):::ff-%s\n", section->name);
443  } else {
444  writer_printf(tfc, "\"):::ff-%s\n", section->name);
445  }
446 
447  break;
449  MM_INDENT();
450  writer_put_str(tfc, "}\n\n");
451  break;
452  }
453 
454  mmc->indent_level--;
455 
456  } else if ((section->flags & AV_TEXTFORMAT_SECTION_FLAG_IS_SUBGRAPH)) {
457 
458  mermaid_subgraph_complete_start(mmc, tfc, tfc->level);
459 
460  MM_INDENT();
461  writer_put_str(tfc, "end\n");
462 
463  if (sec_data.section_id) {
464  MM_INDENT();
465  writer_put_str(tfc, "class ");
466  writer_put_str(tfc, sec_data.section_id);
467  writer_put_str(tfc, " ff-");
468  writer_put_str(tfc, section->name);
469  writer_put_str(tfc, "\n");
470  }
471 
472  mmc->indent_level--;
473  }
474 
476  if (sec_data.src_id && sec_data.dest_id
477  && !has_link_pair(tfc, sec_data.src_id, sec_data.dest_id))
478  switch (mmc->diagram_config->diagram_type) {
480 
481  if (sec_data.section_type && mmc->enable_link_colors)
482  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);
483  else
484  av_bprintf(&mmc->link_buf, "\n %s ==", sec_data.src_id);
485 
486  if (buf->len > 0) {
487  av_bprintf(&mmc->link_buf, " \"%s", buf->str);
488 
489  for (unsigned i = 0; i < mmc->nb_link_captions[tfc->level]; i++)
490  av_bprintf(&mmc->link_buf, "<br>&nbsp;");
491 
492  av_bprintf(&mmc->link_buf, "\" ==");
493  }
494 
495  av_bprintf(&mmc->link_buf, "> %s", sec_data.dest_id);
496 
497  break;
499 
500 
501  av_bprintf(&mmc->link_buf, "\n %s", sec_data.src_id);
502 
503  switch (sec_data.link_type) {
505  av_bprintf(&mmc->link_buf, "%s", " ||--o{ ");
506  break;
508  av_bprintf(&mmc->link_buf, "%s", " }o--|| ");
509  break;
511  av_bprintf(&mmc->link_buf, "%s", " ||--|| ");
512  break;
514  av_bprintf(&mmc->link_buf, "%s", " }o--o{ ");
515  break;
516  default:
517  av_bprintf(&mmc->link_buf, "%s", " ||--|| ");
518  break;
519  }
520 
521  av_bprintf(&mmc->link_buf, "%s : \"\"", sec_data.dest_id);
522 
523  break;
524  }
525 
526  if (tfc->level == 0) {
527 
528  writer_put_str(tfc, "\n");
529  if (mmc->create_html) {
530  char *token_pos = av_stristr(mmc->diagram_config->html_template, "__###__");
531  if (!token_pos) {
532  av_log(tfc, AV_LOG_ERROR, "Unable to locate the required token (__###__) in the html template.");
533  return;
534  }
535  token_pos += strlen("__###__");
536  writer_put_str(tfc, token_pos);
537  }
538  }
539 
540  if (tfc->level == 1) {
541 
542  if (mmc->link_buf.len > 0) {
543  writer_put_str(tfc, mmc->link_buf.str);
544  av_bprint_clear(&mmc->link_buf);
545  }
546 
547  writer_put_str(tfc, "\n");
548  }
549 }
550 
551 static void mermaid_print_value(AVTextFormatContext *tfc, const char *key,
552  const char *str, int64_t num, const int is_int)
553 {
554  MermaidContext *mmc = tfc->priv;
555  const AVTextFormatSection *section = tf_get_section(tfc, tfc->level);
556 
557  if (!section)
558  return;
559 
560  AVBPrint *buf = &tfc->section_pbuf[tfc->level];
561  struct section_data sec_data = mmc->section_data[tfc->level];
562  int exit = 0;
563 
564  if (section->id_key && !strcmp(section->id_key, key)) {
565  set_str(&mmc->section_data[tfc->level].section_id, str);
566  exit = 1;
567  }
568 
569  if (section->dest_id_key && !strcmp(section->dest_id_key, key)) {
570  set_str(&mmc->section_data[tfc->level].dest_id, str);
571  exit = 1;
572  }
573 
574  if (section->src_id_key && !strcmp(section->src_id_key, key)) {
575  set_str(&mmc->section_data[tfc->level].src_id, str);
576  exit = 1;
577  }
578 
579  if (section->linktype_key && !strcmp(section->linktype_key, key)) {
581  exit = 1;
582  }
583 
584  if (exit)
585  return;
586 
588  || (section->flags & AV_TEXTFORMAT_SECTION_FLAG_IS_SUBGRAPH && sec_data.subgraph_start_incomplete)) {
589  switch (mmc->diagram_config->diagram_type) {
591 
592  if (is_int) {
593  writer_printf(tfc, "<span class=\"%s\">%s: %"PRId64"</span>", key, key, num);
594  } else {
595  const char *tmp = av_strireplace(str, "\"", "'");
596  writer_printf(tfc, "<span class=\"%s\">%s</span>", key, tmp);
597  av_freep(&tmp);
598  }
599 
600  break;
602 
603  if (!is_int && str)
604  {
605  const char *col_type;
606 
607  if (key[0] == '_')
608  return;
609 
610  if (sec_data.section_id && !strcmp(str, sec_data.section_id))
611  col_type = "PK";
612  else if (sec_data.dest_id && !strcmp(str, sec_data.dest_id))
613  col_type = "FK";
614  else if (sec_data.src_id && !strcmp(str, sec_data.src_id))
615  col_type = "FK";
616  else
617  col_type = "";
618 
619  MM_INDENT();
620 
621  writer_printf(tfc, " %s %s %s\n", key, str, col_type);
622  }
623  break;
624  }
625 
626  } else if (section->flags & AV_TEXTFORMAT_SECTION_FLAG_HAS_LINKS) {
627  if (buf->len > 0)
628  av_bprintf(buf, "%s", "<br>");
629 
630  av_bprintf(buf, "");
631  if (is_int)
632  av_bprintf(buf, "<span>%s: %"PRId64"</span>", key, num);
633  else
634  av_bprintf(buf, "<span>%s</span>", str);
635 
636  mmc->nb_link_captions[tfc->level]++;
637  }
638 }
639 
640 static inline void mermaid_print_str(AVTextFormatContext *tfc, const char *key, const char *value)
641 {
642  mermaid_print_value(tfc, key, value, 0, 0);
643 }
644 
645 static void mermaid_print_int(AVTextFormatContext *tfc, const char *key, int64_t value)
646 {
647  mermaid_print_value(tfc, key, NULL, value, 1);
648 }
649 
651  .name = "mermaid",
652  .priv_size = sizeof(MermaidContext),
653  .init = mermaid_init,
655  .print_section_header = mermaid_print_section_header,
656  .print_section_footer = mermaid_print_section_footer,
657  .print_integer = mermaid_print_int,
658  .print_string = mermaid_print_str,
660  .priv_class = &mermaid_class,
661 };
662 
663 
665  .name = "mermaidhtml",
666  .priv_size = sizeof(MermaidContext),
669  .print_section_header = mermaid_print_section_header,
670  .print_section_footer = mermaid_print_section_footer,
671  .print_integer = mermaid_print_int,
672  .print_string = mermaid_print_str,
674  .priv_class = &mermaid_class,
675 };
flags
const SwsFlags flags[]
Definition: swscale.c:85
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:154
AV_TEXTFORMAT_FLAG_IS_DIAGRAM_FORMATTER
#define AV_TEXTFORMAT_FLAG_IS_DIAGRAM_FORMATTER
Definition: avtextformat.h:71
opt.h
AV_TEXTFORMAT_LINKTYPE_SRCDEST
@ AV_TEXTFORMAT_LINKTYPE_SRCDEST
Definition: avtextformat.h:81
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:176
av_cold
#define av_cold
Definition: attributes.h:119
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:62
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:428
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:133
AVDictionary
Definition: dict.c:32
AV_TEXTFORMAT_LINKTYPE_ONETOMANY
@ AV_TEXTFORMAT_LINKTYPE_ONETOMANY
Definition: avtextformat.h:86
mermaid_print_int
static void mermaid_print_int(AVTextFormatContext *tfc, const char *key, int64_t value)
Definition: tf_mermaid.c:645
DEFINE_FORMATTER_CLASS
DEFINE_FORMATTER_CLASS(mermaid)
init_directive
static const char * init_directive
Definition: tf_mermaid.c:34
AVTextFormatContext::level
int level
current level, starting from 0
Definition: avtextformat.h:144
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:80
MermaidContext::link_dict
AVDictionary * link_dict
Definition: tf_mermaid.c:155
AV_TEXTFORMAT_LINKTYPE_MANYTOONE
@ AV_TEXTFORMAT_LINKTYPE_MANYTOONE
Definition: avtextformat.h:87
avtextformatter_mermaid
const AVTextFormatter avtextformatter_mermaid
Definition: tf_mermaid.c:650
mermaid_print_str
static void mermaid_print_str(AVTextFormatContext *tfc, const char *key, const char *value)
Definition: tf_mermaid.c:640
AVTextFormatSectionContext
Definition: avtextformat.h:34
mermaid_init_html
static av_cold int mermaid_init_html(AVTextFormatContext *tfc)
Definition: tf_mermaid.c:202
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_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:97
AVTextFormatSection
Definition: avtextformat.h:41
limits.h
AVTextFormatContext::priv
void * priv
private data for use by the filter
Definition: avtextformat.h:139
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:150
MermaidContext
Definition: tf_mermaid.c:131
AV_DIAGRAMTYPE_GRAPH
@ AV_DIAGRAMTYPE_GRAPH
Definition: tf_mermaid.h:25
MermaidContext::within_tag
int within_tag
Definition: tf_mermaid.c:135
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:137
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:159
MermaidContext::section_data::current_is_textblock
int current_is_textblock
Definition: tf_mermaid.c:148
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:89
MermaidContext::section_data
Definition: tf_mermaid.c:142
MermaidContext::diagram_config
AVDiagramConfig * diagram_config
Definition: tf_mermaid.c:133
MermaidContext::subgraph_count
int subgraph_count
Definition: tf_mermaid.c:134
SECTION_MAX_NB_LEVELS
#define SECTION_MAX_NB_LEVELS
Definition: avtextformat.h:112
init
int(* init)(AVBSFContext *ctx)
Definition: dts2pts.c:579
mermaid_print_section_footer
static void mermaid_print_section_footer(AVTextFormatContext *tfc)
Definition: tf_mermaid.c:412
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:256
dst
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
Definition: dsp.h:87
i
#define i(width, name, range_min, range_max)
Definition: cbs_h264.c:63
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:551
AVTextFormatter::name
const char * name
Definition: avtextformat.h:100
MermaidContext::section_data::src_id
const char * src_id
Definition: tf_mermaid.c:145
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:136
AVTextFormatContext::section_pbuf
AVBPrint section_pbuf[SECTION_MAX_NB_LEVELS]
generic print buffer dedicated to each section, used by various formatters
Definition: avtextformat.h:152
theme_css_er
static const char * theme_css_er
Definition: tf_mermaid.c:85
avtextformatter_mermaidhtml
const AVTextFormatter avtextformatter_mermaidhtml
Definition: tf_mermaid.c:664
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:64
mermaid_print_section_header
static void mermaid_print_section_header(AVTextFormatContext *tfc, const void *data)
Definition: tf_mermaid.c:258
AVDiagramConfig::diagram_type
AVDiagramType diagram_type
Definition: tf_mermaid.h:30
MermaidContext::enable_link_colors
int enable_link_colors
Definition: tf_mermaid.c:140
writer_put_str
static void writer_put_str(AVTextFormatContext *wctx, const char *str)
Definition: tf_internal.h:68
bprint.h
AVTextFormatSectionContext::context_id
char * context_id
Definition: avtextformat.h:35
MermaidContext::nb_link_captions
unsigned nb_link_captions[SECTION_MAX_NB_LEVELS]
generic print buffer dedicated to each section,
Definition: tf_mermaid.c:153
set_str
static void set_str(const char **dst, const char *src)
Definition: tf_mermaid.c:233
mermaid_init
static av_cold int mermaid_init(AVTextFormatContext *tfc)
Definition: tf_mermaid.c:192
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
uninit
static av_cold void uninit(AVBitStreamFilterContext *ctx)
Definition: lcevc_merge.c:135
MermaidContext::section_data
struct MermaidContext::section_data section_data[SECTION_MAX_NB_LEVELS]
AV_TEXTFORMAT_LINKTYPE_ONETOONE
@ AV_TEXTFORMAT_LINKTYPE_ONETOONE
Definition: avtextformat.h:88
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:63
MermaidContext::section_data::dest_id
const char * dest_id
Definition: tf_mermaid.c:146
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:143
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:216
MermaidContext::section_data::current_is_stadium
int current_is_stadium
Definition: tf_mermaid.c:149
MermaidContext::section_data::section_type
const char * section_type
Definition: tf_mermaid.c:144
mermaid_subgraph_complete_start
static void mermaid_subgraph_complete_start(MermaidContext *mmc, AVTextFormatContext *tfc, int level)
Definition: tf_mermaid.c:242
mem.h
AVTextFormatSection::id_key
const char * id_key
name of the key to be used as the id
Definition: avtextformat.h:61
av_strdup
#define av_strdup(s)
Definition: ops_asmgen.c:47
AV_OPT_TYPE_BOOL
@ AV_OPT_TYPE_BOOL
Underlying C type is int.
Definition: opt.h:326
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:170
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
MermaidContext::section_data::link_type
AVTextFormatLinkType link_type
Definition: tf_mermaid.c:147
src
#define src
Definition: vp8dsp.c:248
mermaid_options
static const AVOption mermaid_options[]
Definition: tf_mermaid.c:161
init_directive_er
static const char * init_directive_er
Definition: tf_mermaid.c:58
tf_mermaid.h