screenshots/*.pdf
+verify_bv21_errors.xml
+verify_errors.xml
+verify_warnings.xml
# DCP-o-matic manual makefile
INKSCAPE = ~/Applications/inkscape
+LIBDCP = ~/src/libdcp
all: html pdf
shortcuts.xml: $(SHORTCUTS) shortcuts.py
python3 shortcuts.py $(SHORTCUTS) > $@
+LIBDCP_DEPS = $(LIBDCP)/src/verify_j2k.cc $(LIBDCP)/src/dcp.cc $(LIBDCP)/src/verify.cc
+
+verify_errors.xml: verifier.py $(LIBDCP_DEPS)
+ python3 verifier.py $(LIBDCP) ERROR > $@
+
+verify_bv21_errors.xml: verifier.py $(LIBDCP_DEPS)
+ python3 verifier.py $(LIBDCP) BV21_ERROR > $@
+
+verify_warnings.xml: verifier.py $(LIBDCP_DEPS)
+ python3 verifier.py $(LIBDCP) WARNING > $@
+
+
#
# HTML
#
-html: $(XML) config.xml shortcuts.xml dcpomatic-html.xsl extensions-html.ent dcpomatic.css dcpomatic_create.xml dcpomatic_cli.xml dcpomatic_kdm_cli.xml \
+html: $(XML) config.xml shortcuts.xml verify_errors.xml verify_bv21_errors.xml verify_warnings.xml \
+ dcpomatic-html.xsl extensions-html.ent dcpomatic.css dcpomatic_create.xml dcpomatic_cli.xml dcpomatic_kdm_cli.xml \
$(subst .pdf,.png,$(addprefix html/screenshots/,$(SCREENSHOTS))) \
$(subst .svg,.png,$(addprefix diagrams/,$(DIAGRAMS))) \
# PDF
#
-pdf: $(XML) config.xml dcpomatic-pdf.xsl extensions-pdf.ent dcpomatic_create.xml dcpomatic_cli.xml dcpomatic_kdm_cli.xml \
+pdf: $(XML) config.xml shortcuts.xml verify_errors.xml verify_bv21_errors.xml verify_warnings.xml \
+ dcpomatic-pdf.xsl extensions-pdf.ent dcpomatic_create.xml dcpomatic_cli.xml dcpomatic_kdm_cli.xml \
$(addprefix screenshots/,$(SCREENSHOTS)) \
$(subst .svg,.pdf,$(addprefix diagrams/,$(DIAGRAMS)))
</chapter>
<chapter xml:id="ch-player" xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en">
- <title>Playing and verifying DCPs</title>
+ <title>Playing DCPs</title>
<para>DCP-o-matic includes a DCP player, and although it requires a
very high-speed CPU to play DCPs in full resolution, it can also
resolution.
</para>
+</chapter>
+
+
+<chapter xml:id="ch-verifier" xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en">
+ <title>Verifying DCPs</title>
+
<para>
- The player also offers a simple DCP validator. To check a DCP,
+ The player also offers a DCP validator. To check a DCP,
open it and then select <guilabel>Verify DCP</guilabel> from the
- <guilabel>Tools</guilabel> menu. This will run some basic checks to see if the DCP meets the required standards.
+ <guilabel>Tools</guilabel> menu. This will run various checks on the DCP.
+ </para>
+
+ <para>
+ The validator will report three kinds of problems:
</para>
+ <itemizedlist>
+ <listitem>Errors — serious problems with the DCP that are likely to cause problems on playback.</listitem>
+ <listitem>Bv2.1 errors — errors described by the <ulink url="https://ieeexplore.ieee.org/stamp/stamp.jsp?arnumber=9161348">SMPTE Bv2.1 standard</ulink>.</listitem>
+ <listitem>Warnings — small problems that may not matter.</listitem>
+ </itemizedlist>
+
+ <section>
+ <title>Errors</title>
+ <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="verify_errors.xml"/>
+ </section>
+
+ <section>
+ <title>Bv2.1 errors</title>
+ <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="verify_bv21_errors.xml"/>
+ </section>
+
+ <section>
+ <title>Warnings</title>
+ <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="verify_warnings.xml"/>
+ </section>
+
</chapter>
--- /dev/null
+#!/usr/bin/python3
+
+from pathlib import Path
+import re
+import sys
+import subprocess
+
+if len(sys.argv) < 3:
+ print(f"Syntax: {sys.argv[0]} <path-to-libdcp-source-tree> <ERROR|BV21_ERROR|WARNING>")
+ sys.exit(1)
+
+libdcp = Path(sys.argv[1])
+type = sys.argv[2]
+header = libdcp / "src" / "verify.h"
+
+types = ("BV21_ERROR", "ERROR", "WARNING")
+
+def find_type(name):
+ """
+ Search source code to find where a given code is used and hence find out whether
+ it represents an error, Bv2.1 "error" or warning.
+ """
+ previous = ''
+ for source in ["verify_j2k.cc", "dcp.cc", "verify.cc"]:
+ path = libdcp / "src" / source
+ with open(path) as s:
+ for line in s:
+ if line.find(name) != -1:
+ line_with_previous = previous + line
+ for t in types:
+ if line_with_previous.find(t) != -1:
+ return t
+ assert False
+ previous = line
+
+
+print('<itemizedlist>')
+
+active = False
+with open(header) as h:
+ for line in h:
+ strip = line.strip()
+ if strip == "enum class Code {":
+ active = True
+ elif strip == "};":
+ active = False
+ elif active:
+ if strip.startswith('/**'):
+ text = strip.replace('/**', '').replace('*/', '').strip()
+ elif not strip.startswith('/*') and not strip.startswith('*') and strip.endswith(','):
+ this_type = find_type(strip[:-1])
+ if this_type == type:
+ text = re.sub(r"\[.*?\]", lambda m: f'(Bv2.1 {m[0][7:-1]})', text)
+ text = text.replace('<', '<')
+ text = text.replace('>', '>')
+ text = re.sub(r"_(.*?)_", r"<code>\1</code>", text)
+ print(f'<listitem>{text}.</listitem>')
+
+print('</itemizedlist>')