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 
243 #define MM_INDENT() writer_printf(tfc, "%*c", mmc->indent_level * 2, ' ')
244 
246 {
247  const AVTextFormatSection *section = tf_get_section(tfc, tfc->level);
248  const AVTextFormatSection *parent_section = tf_get_parent_section(tfc, tfc->level);
249 
250  if (!section)
251  return;
252  AVBPrint *buf = &tfc->section_pbuf[tfc->level];
253  MermaidContext *mmc = tfc->priv;
254  const AVTextFormatSectionContext *sec_ctx = data;
255 
256  if (tfc->level == 0) {
257  char *directive;
258  AVBPrint css_buf;
260  char *single_line_css = av_strireplace(mmc->diagram_config->diagram_css, "\n", " ");
261  (void)theme_css_er;
262  ////char *single_line_css = av_strireplace(theme_css_er, "\n", " ");
264  av_bprint_escape(&css_buf, single_line_css, "'\\", AV_ESCAPE_MODE_BACKSLASH, AV_ESCAPE_FLAG_STRICT);
265  av_freep(&single_line_css);
266 
267  directive = av_strireplace(diag_directive, "__###__", css_buf.str);
268  if (mmc->create_html) {
269  uint64_t length;
270  char *token_pos = av_stristr(mmc->diagram_config->html_template, "__###__");
271  if (!token_pos) {
272  av_log(tfc, AV_LOG_ERROR, "Unable to locate the required token (__###__) in the html template.");
273  return;
274  }
275 
276  length = token_pos - mmc->diagram_config->html_template;
277  for (uint64_t i = 0; i < length; i++)
279  }
280 
281  writer_put_str(tfc, directive);
282  switch (mmc->diagram_config->diagram_type) {
284  writer_put_str(tfc, "flowchart LR\n");
285  ////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");
286  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");
287  break;
289  writer_put_str(tfc, "erDiagram\n");
290  break;
291  }
292 
293  av_bprint_finalize(&css_buf, NULL);
294  av_freep(&directive);
295  return;
296  }
297 
298  if (parent_section && parent_section->flags & AV_TEXTFORMAT_SECTION_FLAG_IS_SUBGRAPH) {
299 
300  struct section_data parent_sec_data = mmc->section_data[tfc->level - 1];
301  AVBPrint *parent_buf = &tfc->section_pbuf[tfc->level - 1];
302 
303  if (parent_sec_data.subgraph_start_incomplete) {
304 
305  if (parent_buf->len > 0)
306  writer_printf(tfc, "%s", parent_buf->str);
307 
308  writer_put_str(tfc, "</div>\"]\n");
309 
310  mmc->section_data[tfc->level - 1].subgraph_start_incomplete = 0;
311  }
312  }
313 
314  av_freep(&mmc->section_data[tfc->level].section_id);
316  av_freep(&mmc->section_data[tfc->level].src_id);
317  av_freep(&mmc->section_data[tfc->level].dest_id);
318  mmc->section_data[tfc->level].current_is_textblock = 0;
319  mmc->section_data[tfc->level].current_is_stadium = 0;
322 
323  // NOTE: av_strdup() allocations aren't checked
325 
326  av_bprint_clear(buf);
327  writer_put_str(tfc, "\n");
328 
329  mmc->indent_level++;
330 
331  if (sec_ctx->context_id) {
332  MM_INDENT();
333  writer_printf(tfc, "subgraph %s[\"<div class=\"ff-%s\">", sec_ctx->context_id, section->name);
334  } else {
335  av_log(tfc, AV_LOG_ERROR, "Unable to write subgraph start. Missing id field. Section: %s", section->name);
336  }
337 
339  set_str(&mmc->section_data[tfc->level].section_id, sec_ctx->context_id);
340  }
341 
343 
344  av_bprint_clear(buf);
345  writer_put_str(tfc, "\n");
346 
347  mmc->indent_level++;
348 
349  if (sec_ctx->context_id) {
350 
351  set_str(&mmc->section_data[tfc->level].section_id, sec_ctx->context_id);
352 
353  switch (mmc->diagram_config->diagram_type) {
355  if (sec_ctx->context_flags & 1) {
356 
357  MM_INDENT();
358  writer_printf(tfc, "%s@{ shape: text, label: \"", sec_ctx->context_id);
359  mmc->section_data[tfc->level].current_is_textblock = 1;
360  } else if (sec_ctx->context_flags & 2) {
361 
362  MM_INDENT();
363  writer_printf(tfc, "%s([\"", sec_ctx->context_id);
364  mmc->section_data[tfc->level].current_is_stadium = 1;
365  } else {
366  MM_INDENT();
367  writer_printf(tfc, "%s(\"", sec_ctx->context_id);
368  }
369 
370  break;
372  MM_INDENT();
373  writer_printf(tfc, "%s {\n", sec_ctx->context_id);
374  break;
375  }
376 
377  } else {
378  av_log(tfc, AV_LOG_ERROR, "Unable to write shape start. Missing id field. Section: %s", section->name);
379  }
380 
381  set_str(&mmc->section_data[tfc->level].section_id, sec_ctx->context_id);
382  }
383 
384 
385  if (section->flags & AV_TEXTFORMAT_SECTION_PRINT_TAGS) {
386 
387  if (sec_ctx && sec_ctx->context_type)
388  writer_printf(tfc, "<div class=\"ff-%s %s\">", section->name, sec_ctx->context_type);
389  else
390  writer_printf(tfc, "<div class=\"ff-%s\">", section->name);
391  }
392 
393 
395 
396  av_bprint_clear(buf);
397  mmc->nb_link_captions[tfc->level] = 0;
398 
399  if (sec_ctx && sec_ctx->context_type)
400  set_str(&mmc->section_data[tfc->level].section_type, sec_ctx->context_type);
401 
402  ////if (section->flags & AV_TEXTFORMAT_SECTION_FLAG_HAS_TYPE) {
403  //// AVBPrint buf;
404  //// av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
405  //// av_bprint_escape(&buf, section->get_type(data), NULL,
406  //// AV_ESCAPE_MODE_XML, AV_ESCAPE_FLAG_XML_DOUBLE_QUOTES);
407  //// writer_printf(tfc, " type=\"%s\"", buf.str);
408  }
409 }
410 
412 {
413  MermaidContext *mmc = tfc->priv;
414  const AVTextFormatSection *section = tf_get_section(tfc, tfc->level);
415 
416  if (!section)
417  return;
418  AVBPrint *buf = &tfc->section_pbuf[tfc->level];
419  struct section_data sec_data = mmc->section_data[tfc->level];
420 
422  writer_put_str(tfc, "</div>");
423 
425 
426  switch (mmc->diagram_config->diagram_type) {
428 
429  if (sec_data.current_is_textblock) {
430  writer_printf(tfc, "\"}\n", section->name);
431 
432  if (sec_data.section_id) {
433  MM_INDENT();
434  writer_put_str(tfc, "class ");
435  writer_put_str(tfc, sec_data.section_id);
436  writer_put_str(tfc, " ff-");
437  writer_put_str(tfc, section->name);
438  writer_put_str(tfc, "\n");
439  }
440  } else if (sec_data.current_is_stadium) {
441  writer_printf(tfc, "\"]):::ff-%s\n", section->name);
442  } else {
443  writer_printf(tfc, "\"):::ff-%s\n", section->name);
444  }
445 
446  break;
448  MM_INDENT();
449  writer_put_str(tfc, "}\n\n");
450  break;
451  }
452 
453  mmc->indent_level--;
454 
455  } else if ((section->flags & AV_TEXTFORMAT_SECTION_FLAG_IS_SUBGRAPH)) {
456 
457  MM_INDENT();
458  writer_put_str(tfc, "end\n");
459 
460  if (sec_data.section_id) {
461  MM_INDENT();
462  writer_put_str(tfc, "class ");
463  writer_put_str(tfc, sec_data.section_id);
464  writer_put_str(tfc, " ff-");
465  writer_put_str(tfc, section->name);
466  writer_put_str(tfc, "\n");
467  }
468 
469  mmc->indent_level--;
470  }
471 
473  if (sec_data.src_id && sec_data.dest_id
474  && !has_link_pair(tfc, sec_data.src_id, sec_data.dest_id))
475  switch (mmc->diagram_config->diagram_type) {
477 
478  if (sec_data.section_type && mmc->enable_link_colors)
479  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);
480  else
481  av_bprintf(&mmc->link_buf, "\n %s ==", sec_data.src_id);
482 
483  if (buf->len > 0) {
484  av_bprintf(&mmc->link_buf, " \"%s", buf->str);
485 
486  for (unsigned i = 0; i < mmc->nb_link_captions[tfc->level]; i++)
487  av_bprintf(&mmc->link_buf, "<br>&nbsp;");
488 
489  av_bprintf(&mmc->link_buf, "\" ==");
490  }
491 
492  av_bprintf(&mmc->link_buf, "> %s", sec_data.dest_id);
493 
494  break;
496 
497 
498  av_bprintf(&mmc->link_buf, "\n %s", sec_data.src_id);
499 
500  switch (sec_data.link_type) {
502  av_bprintf(&mmc->link_buf, "%s", " ||--o{ ");
503  break;
505  av_bprintf(&mmc->link_buf, "%s", " }o--|| ");
506  break;
508  av_bprintf(&mmc->link_buf, "%s", " ||--|| ");
509  break;
511  av_bprintf(&mmc->link_buf, "%s", " }o--o{ ");
512  break;
513  default:
514  av_bprintf(&mmc->link_buf, "%s", " ||--|| ");
515  break;
516  }
517 
518  av_bprintf(&mmc->link_buf, "%s : \"\"", sec_data.dest_id);
519 
520  break;
521  }
522 
523  if (tfc->level == 0) {
524 
525  writer_put_str(tfc, "\n");
526  if (mmc->create_html) {
527  char *token_pos = av_stristr(mmc->diagram_config->html_template, "__###__");
528  if (!token_pos) {
529  av_log(tfc, AV_LOG_ERROR, "Unable to locate the required token (__###__) in the html template.");
530  return;
531  }
532  token_pos += strlen("__###__");
533  writer_put_str(tfc, token_pos);
534  }
535  }
536 
537  if (tfc->level == 1) {
538 
539  if (mmc->link_buf.len > 0) {
540  writer_put_str(tfc, mmc->link_buf.str);
541  av_bprint_clear(&mmc->link_buf);
542  }
543 
544  writer_put_str(tfc, "\n");
545  }
546 }
547 
548 static void mermaid_print_value(AVTextFormatContext *tfc, const char *key,
549  const char *str, int64_t num, const int is_int)
550 {
551  MermaidContext *mmc = tfc->priv;
552  const AVTextFormatSection *section = tf_get_section(tfc, tfc->level);
553 
554  if (!section)
555  return;
556 
557  AVBPrint *buf = &tfc->section_pbuf[tfc->level];
558  struct section_data sec_data = mmc->section_data[tfc->level];
559  int exit = 0;
560 
561  if (section->id_key && !strcmp(section->id_key, key)) {
562  set_str(&mmc->section_data[tfc->level].section_id, str);
563  exit = 1;
564  }
565 
566  if (section->dest_id_key && !strcmp(section->dest_id_key, key)) {
567  set_str(&mmc->section_data[tfc->level].dest_id, str);
568  exit = 1;
569  }
570 
571  if (section->src_id_key && !strcmp(section->src_id_key, key)) {
572  set_str(&mmc->section_data[tfc->level].src_id, str);
573  exit = 1;
574  }
575 
576  if (section->linktype_key && !strcmp(section->linktype_key, key)) {
578  exit = 1;
579  }
580 
581  if (exit)
582  return;
583 
585  || (section->flags & AV_TEXTFORMAT_SECTION_FLAG_IS_SUBGRAPH && sec_data.subgraph_start_incomplete)) {
586  switch (mmc->diagram_config->diagram_type) {
588 
589  if (is_int) {
590  writer_printf(tfc, "<span class=\"%s\">%s: %"PRId64"</span>", key, key, num);
591  } else {
592  const char *tmp = av_strireplace(str, "\"", "'");
593  writer_printf(tfc, "<span class=\"%s\">%s</span>", key, tmp);
594  av_freep(&tmp);
595  }
596 
597  break;
599 
600  if (!is_int && str)
601  {
602  const char *col_type;
603 
604  if (key[0] == '_')
605  return;
606 
607  if (sec_data.section_id && !strcmp(str, sec_data.section_id))
608  col_type = "PK";
609  else if (sec_data.dest_id && !strcmp(str, sec_data.dest_id))
610  col_type = "FK";
611  else if (sec_data.src_id && !strcmp(str, sec_data.src_id))
612  col_type = "FK";
613  else
614  col_type = "";
615 
616  MM_INDENT();
617 
618  writer_printf(tfc, " %s %s %s\n", key, str, col_type);
619  }
620  break;
621  }
622 
623  } else if (section->flags & AV_TEXTFORMAT_SECTION_FLAG_HAS_LINKS) {
624  if (buf->len > 0)
625  av_bprintf(buf, "%s", "<br>");
626 
627  av_bprintf(buf, "");
628  if (is_int)
629  av_bprintf(buf, "<span>%s: %"PRId64"</span>", key, num);
630  else
631  av_bprintf(buf, "<span>%s</span>", str);
632 
633  mmc->nb_link_captions[tfc->level]++;
634  }
635 }
636 
637 static inline void mermaid_print_str(AVTextFormatContext *tfc, const char *key, const char *value)
638 {
639  mermaid_print_value(tfc, key, value, 0, 0);
640 }
641 
642 static void mermaid_print_int(AVTextFormatContext *tfc, const char *key, int64_t value)
643 {
644  mermaid_print_value(tfc, key, NULL, value, 1);
645 }
646 
648  .name = "mermaid",
649  .priv_size = sizeof(MermaidContext),
650  .init = mermaid_init,
652  .print_section_header = mermaid_print_section_header,
653  .print_section_footer = mermaid_print_section_footer,
654  .print_integer = mermaid_print_int,
655  .print_string = mermaid_print_str,
657  .priv_class = &mermaid_class,
658 };
659 
660 
662  .name = "mermaidhtml",
663  .priv_size = sizeof(MermaidContext),
666  .print_section_header = mermaid_print_section_header,
667  .print_section_footer = mermaid_print_section_footer,
668  .print_integer = mermaid_print_int,
669  .print_string = mermaid_print_str,
671  .priv_class = &mermaid_class,
672 };
flags
const SwsFlags flags[]
Definition: swscale.c:61
AV_BPRINT_SIZE_UNLIMITED
#define AV_BPRINT_SIZE_UNLIMITED
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:642
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:647
mermaid_print_str
static void mermaid_print_str(AVTextFormatContext *tfc, const char *key, const char *value)
Definition: tf_mermaid.c:637
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:90
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:368
mermaid_print_section_footer
static void mermaid_print_section_footer(AVTextFormatContext *tfc)
Definition: tf_mermaid.c:411
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:243
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:548
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:661
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:245
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
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