summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2024-04-09 02:02:28 +0200
committerCarl Hetherington <cth@carlh.net>2024-04-17 09:36:45 +0200
commitaf20e21e2363f7c4d5f7031c444984f383c26914 (patch)
tree072277c1a9c48d81367384d0c0f4a3ae356ce54e
parent39960bc88eee794ade1a73b00523e749945b9eab (diff)
Separate GUI verifier with basic reporting (#1823).
-rw-r--r--cscript6
-rw-r--r--graphics/linux/128/dcpomatic2_verifier.pngbin0 -> 23196 bytes
-rw-r--r--graphics/linux/16/dcpomatic2_verifier.pngbin0 -> 935 bytes
-rw-r--r--graphics/linux/22/dcpomatic2_verifier.pngbin0 -> 1496 bytes
-rw-r--r--graphics/linux/256/dcpomatic2_verifier.pngbin0 -> 70647 bytes
-rw-r--r--graphics/linux/32/dcpomatic2_verifier.pngbin0 -> 2714 bytes
-rw-r--r--graphics/linux/48/dcpomatic2_verifier.pngbin0 -> 5152 bytes
-rw-r--r--graphics/linux/512/dcpomatic2_verifier.pngbin0 -> 242957 bytes
-rw-r--r--graphics/linux/64/dcpomatic2_verifier.pngbin0 -> 8150 bytes
-rw-r--r--graphics/osx/dcpomatic2_verifier.icnsbin0 -> 778023 bytes
-rw-r--r--graphics/osx/dcpomatic2_verifier.iconset/icon_128x128.pngbin0 -> 23196 bytes
-rw-r--r--graphics/osx/dcpomatic2_verifier.iconset/icon_128x128@2x.pngbin0 -> 23196 bytes
-rw-r--r--graphics/osx/dcpomatic2_verifier.iconset/icon_16x16.pngbin0 -> 935 bytes
-rw-r--r--graphics/osx/dcpomatic2_verifier.iconset/icon_16x16@2x.pngbin0 -> 935 bytes
-rw-r--r--graphics/osx/dcpomatic2_verifier.iconset/icon_256x256.pngbin0 -> 70647 bytes
-rw-r--r--graphics/osx/dcpomatic2_verifier.iconset/icon_256x256@2x.pngbin0 -> 70647 bytes
-rw-r--r--graphics/osx/dcpomatic2_verifier.iconset/icon_32x32.pngbin0 -> 2714 bytes
-rw-r--r--graphics/osx/dcpomatic2_verifier.iconset/icon_32x32@2x.pngbin0 -> 2714 bytes
-rw-r--r--graphics/osx/dcpomatic2_verifier.iconset/icon_512x512.pngbin0 -> 242957 bytes
-rw-r--r--graphics/osx/dcpomatic2_verifier.iconset/icon_512x512@2x.pngbin0 -> 242957 bytes
-rw-r--r--graphics/src/dcpomatic2_verifier.svg248
-rwxr-xr-xgraphics/update2
-rw-r--r--graphics/windows/dcpomatic2_verifier.icobin0 -> 99678 bytes
-rw-r--r--graphics/wscript3
-rw-r--r--platform/linux/dcpomatic_verifier.desktop.in10
-rw-r--r--platform/linux/wscript1
-rw-r--r--platform/osx/dcpomatic2_verifier.Info.plist.in36
-rw-r--r--platform/osx/make_dmg.sh16
-rw-r--r--platform/osx/wscript1
-rw-r--r--platform/windows/dcpomatic2_verifier.bat1
-rw-r--r--platform/windows/dcpomatic_verifier.rc2
-rw-r--r--platform/windows/wscript1
-rwxr-xr-xrun/dcpomatic_verifier24
-rw-r--r--src/lib/config.cc1
-rw-r--r--src/lib/verify_dcp_job.cc4
-rw-r--r--src/lib/verify_dcp_job.h6
-rw-r--r--src/tools/dcpomatic_verifier.cc247
-rw-r--r--src/tools/wscript10
-rw-r--r--src/wx/verify_dcp_result_dialog.cc1
-rw-r--r--src/wx/verify_dcp_result_panel.cc67
-rw-r--r--src/wx/verify_dcp_result_panel.h8
-rw-r--r--test/reels_test.cc36
-rw-r--r--test/test.cc6
43 files changed, 709 insertions, 28 deletions
diff --git a/cscript b/cscript
index 4bef0f3d7..5d931f471 100644
--- a/cscript
+++ b/cscript
@@ -431,6 +431,7 @@ def make_spec(filename, version, target, options, requires=None):
print('%{_bindir}/dcpomatic2_openssl', file=f)
print('%{_bindir}/dcpomatic2_combiner', file=f)
print('%{_bindir}/dcpomatic2_verify_cli', file=f)
+ print('%{_bindir}/dcpomatic2_verifier', file=f)
print('%{_bindir}/dcpomatic2_kdm_inspect', file=f)
print('%{_bindir}/dcpomatic2_map', file=f)
if can_build_disk(target):
@@ -439,6 +440,7 @@ def make_spec(filename, version, target, options, requires=None):
print('%{_datadir}/applications/dcpomatic2.desktop', file=f)
print('%{_datadir}/applications/dcpomatic2_batch.desktop', file=f)
print('%{_datadir}/applications/dcpomatic2_editor.desktop', file=f)
+ print('%{_datadir}/applications/dcpomatic2_verifier.desktop', file=f)
print('%{_datadir}/applications/dcpomatic2_server.desktop', file=f)
print('%{_datadir}/applications/dcpomatic2_kdm.desktop', file=f)
print('%{_datadir}/applications/dcpomatic2_player.desktop', file=f)
@@ -472,6 +474,7 @@ def make_spec(filename, version, target, options, requires=None):
print('%%{_datadir}/icons/hicolor/%s/apps/dcpomatic2.png' % r, file=f)
print('%%{_datadir}/icons/hicolor/%s/apps/dcpomatic2_batch.png' % r, file=f)
print('%%{_datadir}/icons/hicolor/%s/apps/dcpomatic2_editor.png' % r, file=f)
+ print('%%{_datadir}/icons/hicolor/%s/apps/dcpomatic2_verifier.png' % r, file=f)
print('%%{_datadir}/icons/hicolor/%s/apps/dcpomatic2_kdm.png' % r, file=f)
print('%%{_datadir}/icons/hicolor/%s/apps/dcpomatic2_server.png' % r, file=f)
print('%%{_datadir}/icons/hicolor/%s/apps/dcpomatic2_player.png' % r, file=f)
@@ -535,7 +538,7 @@ def dependencies(target, options):
# Use distro-provided FFmpeg on Arch
deps = []
- deps.append(('libdcp', '56b3586247d76b2d07911018ccba63d4b05f4995', {'c++17': target.platform == 'osx'}))
+ deps.append(('libdcp', 'v1.9.5', {'c++17': target.platform == 'osx'}))
deps.append(('libsub', 'v1.6.47'))
deps.append(('leqm-nrt', '30dcaea1373ac62fba050e02ce5b0c1085797a23'))
deps.append(('rtaudio', 'f619b76'))
@@ -874,6 +877,7 @@ def package(target, version, options):
out.append(make_appimage(target, 'DCP-o-matic Encode Server', 'dcpomatic2_server', version))
out.append(make_appimage(target, 'DCP-o-matic Combiner', 'dcpomatic2_combiner', version))
out.append(make_appimage(target, 'DCP-o-matic Editor', 'dcpomatic2_editor', version))
+ out.append(make_appimage(target, 'DCP-o-matic Verifier', 'dcpomatic2_verifier', version))
return out
else:
if target.bits == 32:
diff --git a/graphics/linux/128/dcpomatic2_verifier.png b/graphics/linux/128/dcpomatic2_verifier.png
new file mode 100644
index 000000000..d28ceb27b
--- /dev/null
+++ b/graphics/linux/128/dcpomatic2_verifier.png
Binary files differ
diff --git a/graphics/linux/16/dcpomatic2_verifier.png b/graphics/linux/16/dcpomatic2_verifier.png
new file mode 100644
index 000000000..9ad2929dc
--- /dev/null
+++ b/graphics/linux/16/dcpomatic2_verifier.png
Binary files differ
diff --git a/graphics/linux/22/dcpomatic2_verifier.png b/graphics/linux/22/dcpomatic2_verifier.png
new file mode 100644
index 000000000..dbe6cbd4d
--- /dev/null
+++ b/graphics/linux/22/dcpomatic2_verifier.png
Binary files differ
diff --git a/graphics/linux/256/dcpomatic2_verifier.png b/graphics/linux/256/dcpomatic2_verifier.png
new file mode 100644
index 000000000..f5198a733
--- /dev/null
+++ b/graphics/linux/256/dcpomatic2_verifier.png
Binary files differ
diff --git a/graphics/linux/32/dcpomatic2_verifier.png b/graphics/linux/32/dcpomatic2_verifier.png
new file mode 100644
index 000000000..61afb5f9f
--- /dev/null
+++ b/graphics/linux/32/dcpomatic2_verifier.png
Binary files differ
diff --git a/graphics/linux/48/dcpomatic2_verifier.png b/graphics/linux/48/dcpomatic2_verifier.png
new file mode 100644
index 000000000..5f5188ea3
--- /dev/null
+++ b/graphics/linux/48/dcpomatic2_verifier.png
Binary files differ
diff --git a/graphics/linux/512/dcpomatic2_verifier.png b/graphics/linux/512/dcpomatic2_verifier.png
new file mode 100644
index 000000000..b8417ed85
--- /dev/null
+++ b/graphics/linux/512/dcpomatic2_verifier.png
Binary files differ
diff --git a/graphics/linux/64/dcpomatic2_verifier.png b/graphics/linux/64/dcpomatic2_verifier.png
new file mode 100644
index 000000000..b17249b55
--- /dev/null
+++ b/graphics/linux/64/dcpomatic2_verifier.png
Binary files differ
diff --git a/graphics/osx/dcpomatic2_verifier.icns b/graphics/osx/dcpomatic2_verifier.icns
new file mode 100644
index 000000000..ffd23360c
--- /dev/null
+++ b/graphics/osx/dcpomatic2_verifier.icns
Binary files differ
diff --git a/graphics/osx/dcpomatic2_verifier.iconset/icon_128x128.png b/graphics/osx/dcpomatic2_verifier.iconset/icon_128x128.png
new file mode 100644
index 000000000..d28ceb27b
--- /dev/null
+++ b/graphics/osx/dcpomatic2_verifier.iconset/icon_128x128.png
Binary files differ
diff --git a/graphics/osx/dcpomatic2_verifier.iconset/icon_128x128@2x.png b/graphics/osx/dcpomatic2_verifier.iconset/icon_128x128@2x.png
new file mode 100644
index 000000000..d28ceb27b
--- /dev/null
+++ b/graphics/osx/dcpomatic2_verifier.iconset/icon_128x128@2x.png
Binary files differ
diff --git a/graphics/osx/dcpomatic2_verifier.iconset/icon_16x16.png b/graphics/osx/dcpomatic2_verifier.iconset/icon_16x16.png
new file mode 100644
index 000000000..9ad2929dc
--- /dev/null
+++ b/graphics/osx/dcpomatic2_verifier.iconset/icon_16x16.png
Binary files differ
diff --git a/graphics/osx/dcpomatic2_verifier.iconset/icon_16x16@2x.png b/graphics/osx/dcpomatic2_verifier.iconset/icon_16x16@2x.png
new file mode 100644
index 000000000..9ad2929dc
--- /dev/null
+++ b/graphics/osx/dcpomatic2_verifier.iconset/icon_16x16@2x.png
Binary files differ
diff --git a/graphics/osx/dcpomatic2_verifier.iconset/icon_256x256.png b/graphics/osx/dcpomatic2_verifier.iconset/icon_256x256.png
new file mode 100644
index 000000000..f5198a733
--- /dev/null
+++ b/graphics/osx/dcpomatic2_verifier.iconset/icon_256x256.png
Binary files differ
diff --git a/graphics/osx/dcpomatic2_verifier.iconset/icon_256x256@2x.png b/graphics/osx/dcpomatic2_verifier.iconset/icon_256x256@2x.png
new file mode 100644
index 000000000..f5198a733
--- /dev/null
+++ b/graphics/osx/dcpomatic2_verifier.iconset/icon_256x256@2x.png
Binary files differ
diff --git a/graphics/osx/dcpomatic2_verifier.iconset/icon_32x32.png b/graphics/osx/dcpomatic2_verifier.iconset/icon_32x32.png
new file mode 100644
index 000000000..61afb5f9f
--- /dev/null
+++ b/graphics/osx/dcpomatic2_verifier.iconset/icon_32x32.png
Binary files differ
diff --git a/graphics/osx/dcpomatic2_verifier.iconset/icon_32x32@2x.png b/graphics/osx/dcpomatic2_verifier.iconset/icon_32x32@2x.png
new file mode 100644
index 000000000..61afb5f9f
--- /dev/null
+++ b/graphics/osx/dcpomatic2_verifier.iconset/icon_32x32@2x.png
Binary files differ
diff --git a/graphics/osx/dcpomatic2_verifier.iconset/icon_512x512.png b/graphics/osx/dcpomatic2_verifier.iconset/icon_512x512.png
new file mode 100644
index 000000000..b8417ed85
--- /dev/null
+++ b/graphics/osx/dcpomatic2_verifier.iconset/icon_512x512.png
Binary files differ
diff --git a/graphics/osx/dcpomatic2_verifier.iconset/icon_512x512@2x.png b/graphics/osx/dcpomatic2_verifier.iconset/icon_512x512@2x.png
new file mode 100644
index 000000000..b8417ed85
--- /dev/null
+++ b/graphics/osx/dcpomatic2_verifier.iconset/icon_512x512@2x.png
Binary files differ
diff --git a/graphics/src/dcpomatic2_verifier.svg b/graphics/src/dcpomatic2_verifier.svg
new file mode 100644
index 000000000..5572f0a61
--- /dev/null
+++ b/graphics/src/dcpomatic2_verifier.svg
@@ -0,0 +1,248 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ viewBox="0 0 960.00004 960.00004"
+ sodipodi:docname="dcpomatic2_verifier.svg"
+ inkscape:version="1.1.1 (3bf5ae0, 2021-09-20)"
+ version="1.1"
+ id="svg2"
+ height="1024"
+ width="1024"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:dc="http://purl.org/dc/elements/1.1/">
+ <defs
+ id="defs4">
+ <marker
+ inkscape:isstock="true"
+ style="overflow:visible"
+ id="Arrow1Mstart"
+ refX="0"
+ refY="0"
+ orient="auto"
+ inkscape:stockid="Arrow1Mstart">
+ <path
+ transform="matrix(0.4,0,0,0.4,4,0)"
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ id="path893" />
+ </marker>
+ <marker
+ inkscape:isstock="true"
+ style="overflow:visible"
+ id="marker1193"
+ refX="0"
+ refY="0"
+ orient="auto"
+ inkscape:stockid="Arrow1Lend">
+ <path
+ transform="matrix(-0.8,0,0,-0.8,-10,0)"
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ id="path1191" />
+ </marker>
+ <marker
+ inkscape:isstock="true"
+ style="overflow:visible"
+ id="marker1189"
+ refX="0"
+ refY="0"
+ orient="auto"
+ inkscape:stockid="Arrow1Lstart">
+ <path
+ transform="matrix(0.8,0,0,0.8,10,0)"
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ id="path1187" />
+ </marker>
+ <marker
+ inkscape:isstock="true"
+ style="overflow:visible"
+ id="marker1167"
+ refX="0"
+ refY="0"
+ orient="auto"
+ inkscape:stockid="Arrow1Lstart">
+ <path
+ transform="matrix(0.8,0,0,0.8,10,0)"
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ id="path1165" />
+ </marker>
+ <marker
+ inkscape:isstock="true"
+ style="overflow:visible"
+ id="Arrow1Lend"
+ refX="0"
+ refY="0"
+ orient="auto"
+ inkscape:stockid="Arrow1Lend">
+ <path
+ transform="matrix(-0.8,0,0,-0.8,-10,0)"
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ id="path890" />
+ </marker>
+ <marker
+ inkscape:isstock="true"
+ style="overflow:visible"
+ id="Arrow1Lstart"
+ refX="0"
+ refY="0"
+ orient="auto"
+ inkscape:stockid="Arrow1Lstart">
+ <path
+ transform="matrix(0.8,0,0,0.8,10,0)"
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ id="path887" />
+ </marker>
+ <linearGradient
+ id="linearGradient3594"
+ y2="742.5"
+ gradientUnits="userSpaceOnUse"
+ x2="-886.76001"
+ gradientTransform="matrix(-0.84033,-0.84033,-0.84033,0.84033,136.32259,-691.39649)"
+ y1="742.5"
+ x1="-772.01001">
+ <stop
+ id="stop4687"
+ stop-color="#fff"
+ offset="0" />
+ <stop
+ id="stop4689"
+ stop-color="#fff"
+ stop-opacity="0"
+ offset="1" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3601"
+ y2="613.94"
+ gradientUnits="userSpaceOnUse"
+ x2="385.04001"
+ gradientTransform="matrix(0.70711,-0.70711,0.70711,0.70711,-203.97741,756.21351)"
+ y1="63.870998"
+ x1="386.39001">
+ <stop
+ id="stop3797"
+ stop-color="#ffe800"
+ offset="0" />
+ <stop
+ id="stop3799"
+ stop-color="#dfb300"
+ offset="1" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3609"
+ y2="161.84"
+ gradientUnits="userSpaceOnUse"
+ x2="212.92999"
+ y1="358.29999"
+ x1="409.38"
+ gradientTransform="translate(-77.797413,384.00351)">
+ <stop
+ id="stop4034"
+ stop-color="#dfb300"
+ offset="0" />
+ <stop
+ id="stop3374"
+ stop-color="#dfb300"
+ offset=".5" />
+ <stop
+ id="stop3376"
+ stop-color="#dfb300"
+ offset="1" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3632"
+ y2="448.35001"
+ gradientUnits="userSpaceOnUse"
+ x2="382.89999"
+ gradientTransform="matrix(0.70711,-0.70711,0.70711,0.70711,-203.97741,756.21351)"
+ y1="448.35001"
+ x1="403.63">
+ <stop
+ id="stop3636"
+ stop-color="#ffe800"
+ stop-opacity=".39216"
+ offset="0" />
+ <stop
+ id="stop3638"
+ stop-color="#dfb300"
+ stop-opacity=".39216"
+ offset="1" />
+ </linearGradient>
+ </defs>
+ <sodipodi:namedview
+ inkscape:snap-midpoints="true"
+ inkscape:document-rotation="0"
+ inkscape:window-maximized="1"
+ inkscape:window-y="0"
+ inkscape:window-x="1920"
+ inkscape:window-height="1048"
+ inkscape:window-width="1920"
+ showgrid="false"
+ inkscape:current-layer="layer1"
+ inkscape:document-units="px"
+ inkscape:cy="799.70529"
+ inkscape:cx="784.52101"
+ inkscape:zoom="0.49393196"
+ inkscape:pageshadow="2"
+ inkscape:pageopacity="0.0"
+ borderopacity="1.0"
+ bordercolor="#666666"
+ pagecolor="#ffffff"
+ id="base"
+ inkscape:pagecheckerboard="0"
+ inkscape:snap-object-midpoints="true"
+ inkscape:snap-bbox="true"
+ inkscape:snap-bbox-midpoints="true"
+ inkscape:snap-global="false" />
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ transform="translate(0,-52.362188)"
+ id="layer1"
+ inkscape:groupmode="layer"
+ inkscape:label="Layer 1">
+ <g
+ id="g1445"
+ transform="translate(-10.670155,-28.024289)">
+ <image
+ xlink:href="dcpomatic.png"
+ id="image4358"
+ preserveAspectRatio="none"
+ height="960.00006"
+ width="960.00006"
+ x="10.670144"
+ y="80.386467" />
+ <rect
+ style="font-variation-settings:normal;opacity:0.792898;vector-effect:none;fill:#5e5e5e;fill-opacity:1;stroke:#000000;stroke-width:14.2122;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;-inkscape-stroke:none;stop-color:#000000"
+ id="rect1581"
+ width="232.89954"
+ height="83.860855"
+ x="797.59167"
+ y="-15.120205"
+ transform="matrix(0.69206236,0.72183772,-0.69206236,0.72183772,0,0)" />
+ <circle
+ style="font-variation-settings:normal;opacity:0.792898;fill:#5e5e5e;fill-opacity:1;stroke:#000000;stroke-width:23.4375;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1"
+ id="path1076"
+ cx="424.06757"
+ cy="478.95279"
+ r="167.43817" />
+ </g>
+ </g>
+</svg>
diff --git a/graphics/update b/graphics/update
index 46964470b..f04ce3fea 100755
--- a/graphics/update
+++ b/graphics/update
@@ -25,7 +25,7 @@ function required_font()
fi
}
-svg_apps="dcpomatic2_kdm dcpomatic2_server dcpomatic2_batch dcpomatic2_player dcpomatic2_playlist dcpomatic2_disk dcpomatic2_combiner dcpomatic2_editor"
+svg_apps="dcpomatic2_kdm dcpomatic2_server dcpomatic2_batch dcpomatic2_player dcpomatic2_playlist dcpomatic2_disk dcpomatic2_combiner dcpomatic2_editor dcpomatic2_verifier"
if [ `uname -s` == "Darwin" ]; then
diff --git a/graphics/windows/dcpomatic2_verifier.ico b/graphics/windows/dcpomatic2_verifier.ico
new file mode 100644
index 000000000..2a85de433
--- /dev/null
+++ b/graphics/windows/dcpomatic2_verifier.ico
Binary files differ
diff --git a/graphics/wscript b/graphics/wscript
index 663e28287..287a6dec4 100644
--- a/graphics/wscript
+++ b/graphics/wscript
@@ -32,7 +32,8 @@ def build(bld):
'dcpomatic2_playlist',
'dcpomatic2_disk',
'dcpomatic2_combiner',
- 'dcpomatic2_editor']:
+ 'dcpomatic2_editor',
+ 'dcpomatic2_verifier']:
bld.install_files('${PREFIX}/share/icons/hicolor/%dx%d/apps' % (r, r), 'linux/%d/%s.png' % (r, p))
# Install stuff for POSIX systems
diff --git a/platform/linux/dcpomatic_verifier.desktop.in b/platform/linux/dcpomatic_verifier.desktop.in
new file mode 100644
index 000000000..b52a6fc3d
--- /dev/null
+++ b/platform/linux/dcpomatic_verifier.desktop.in
@@ -0,0 +1,10 @@
+[Desktop Entry]
+Encoding=UTF-8
+Version=1.0
+Type=Application
+Terminal=false
+Exec=@INSTALL_PREFIX@/bin/dcpomatic2_verifier
+Name=DCP-o-matic 2 Verifier
+Icon=dcpomatic2_verifier
+Comment=DCP generator
+Categories=AudioVideo;Video
diff --git a/platform/linux/wscript b/platform/linux/wscript
index 98aff905d..4a3516fd0 100644
--- a/platform/linux/wscript
+++ b/platform/linux/wscript
@@ -16,6 +16,7 @@ def build(bld):
desktop(bld, '_playlist'),
desktop(bld, '_combiner'),
desktop(bld, '_editor'),
+ desktop(bld, '_verifier'),
]
if bld.env.ENABLE_DISK:
diff --git a/platform/osx/dcpomatic2_verifier.Info.plist.in b/platform/osx/dcpomatic2_verifier.Info.plist.in
new file mode 100644
index 000000000..d88a8ce50
--- /dev/null
+++ b/platform/osx/dcpomatic2_verifier.Info.plist.in
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>dcpomatic2_verifier</string>
+ <key>CFBundleGetInfoString</key>
+ <string>DCP-o-matic 2 Verifier</string>
+ <key>CFBundleIconFile</key>
+ <string>dcpomatic2_verifier.icns</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.dcpomatic.verifier</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>DCP-o-matic 2 Verifier</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersions</key>
+ <string>@VERSION@</string>
+ <key>CFBundleSignature</key>
+ <string>DOMC</string>
+ <key>CFBundleVersion</key>
+ <string>@VERSION@</string>
+ <key>CFBundleAllowMixedLocalizations</key>
+ <true/>
+ <key>LSUIElement</key>
+ <string>0</string>
+ <key>NSMainNibFile</key>
+ <string>MainMenu</string>
+ <key>NSPrincipalClass</key>
+ <string>NSApplication</string>
+</dict>
+</plist>
diff --git a/platform/osx/make_dmg.sh b/platform/osx/make_dmg.sh
index be4394649..a223556af 100644
--- a/platform/osx/make_dmg.sh
+++ b/platform/osx/make_dmg.sh
@@ -7,7 +7,7 @@ SYNTAX="make_dmg.sh -e <environment> -r <builddir> -i <apple-id> -p <apple-passw
# Don't set -e here as egrep (used a few times) returns 1 if no matches
# were found.
-BUILD="main kdm server batch player playlist combiner editor disk"
+BUILD="main kdm server batch player playlist combiner editor disk verifier"
while getopts "e:r:i:p:a:b:" o; do
case "${o}" in
e)
@@ -227,6 +227,7 @@ function copy_resources {
cp $prefix/src/dcpomatic/graphics/osx/dcpomatic2_disk.icns "$dest"
cp $prefix/src/dcpomatic/graphics/osx/dcpomatic2_combiner.icns "$dest"
cp $prefix/src/dcpomatic/graphics/osx/dcpomatic2_editor.icns "$dest"
+ cp $prefix/src/dcpomatic/graphics/osx/dcpomatic2_verifier.icns "$dest"
cp $prefix/src/dcpomatic/graphics/osx/preferences/defaults*.png "$dest"
cp $prefix/src/dcpomatic/graphics/osx/preferences/kdm_email*.png "$dest"
cp $prefix/src/dcpomatic/graphics/osx/preferences/email*.png "$dest"
@@ -592,6 +593,19 @@ if [[ "$BUILD" == *editor* ]]; then
make_dmg "$appdir" "" "DCP-o-matic Editor" "dcpomatic2_verify_cli dcpomatic2_kdm_inspect openssl dcpomatic2_editor"
fi
+if [[ "$BUILD" == *verifier* ]]; then
+ # DCP-o-matic Verifier
+ setup "DCP-o-matic 2 Verifier.app"
+ copy $ROOT src/dcpomatic/build/src/tools/dcpomatic2_verifier "$approot/MacOS"
+ copy $ROOT src/openssl/apps/openssl "$approot/MacOS"
+ copy_verify
+ copy_kdm
+ cp $prefix/src/dcpomatic/build/platform/osx/dcpomatic2_verifier.Info.plist "$approot/Info.plist"
+ rl=("$approot/MacOS/dcpomatic2_verifier" "$approot/Frameworks/"*.dylib)
+ relink_relative "${rl[@]}"
+ make_dmg "$appdir" "" "DCP-o-matic Verifier" "dcpomatic2_verify_cli dcpomatic2_kdm_inspect openssl dcpomatic2_verifier"
+fi
+
if [[ "$BUILD" == *disk* ]]; then
# DCP-o-matic Disk Writer .app
setup "DCP-o-matic 2 Disk Writer.app"
diff --git a/platform/osx/wscript b/platform/osx/wscript
index fd6733a66..cdb018473 100644
--- a/platform/osx/wscript
+++ b/platform/osx/wscript
@@ -8,3 +8,4 @@ def build(bld):
obj = bld(features='subst', source='dcpomatic2_disk.Info.plist.in', target='dcpomatic2_disk.Info.plist', version=bld.env.VERSION)
obj = bld(features='subst', source='dcpomatic2_combiner.Info.plist.in', target='dcpomatic2_combiner.Info.plist', version=bld.env.VERSION)
obj = bld(features='subst', source='dcpomatic2_editor.Info.plist.in', target='dcpomatic2_editor.Info.plist', version=bld.env.VERSION)
+ obj = bld(features='subst', source='dcpomatic2_verifier.Info.plist.in', target='dcpomatic2_verifier.Info.plist', version=bld.env.VERSION)
diff --git a/platform/windows/dcpomatic2_verifier.bat b/platform/windows/dcpomatic2_verifier.bat
new file mode 100644
index 000000000..d8850d9fe
--- /dev/null
+++ b/platform/windows/dcpomatic2_verifier.bat
@@ -0,0 +1 @@
+gdb.exe -x gdb_script dcpomatic2_verifier.exe > %HOMEPATH%/Documents/dcpomatic_debug_log.txt
diff --git a/platform/windows/dcpomatic_verifier.rc b/platform/windows/dcpomatic_verifier.rc
new file mode 100644
index 000000000..8f1ba073f
--- /dev/null
+++ b/platform/windows/dcpomatic_verifier.rc
@@ -0,0 +1,2 @@
+id ICON "../../graphics/windows/dcpomatic2_verifier.ico"
+#include "wx-3.1/wx/msw/wx.rc"
diff --git a/platform/windows/wscript b/platform/windows/wscript
index 13927f170..c6718db41 100644
--- a/platform/windows/wscript
+++ b/platform/windows/wscript
@@ -22,6 +22,7 @@ def write_installer(bits, dcpomatic_version, debug, disk):
('combiner', 'Combiner'),
('editor', 'Editor'),
('map', 'Map'),
+ ('verifier', 'Verifier'),
]
if disk:
diff --git a/run/dcpomatic_verifier b/run/dcpomatic_verifier
new file mode 100755
index 000000000..a87c3d4dc
--- /dev/null
+++ b/run/dcpomatic_verifier
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
+source $DIR/environment
+binary=$build/src/tools/dcpomatic2_verifier
+
+if [[ "$(uname -m)" == arm64 ]]; then
+ env=arm64/11.0
+else
+ env=x86_64/10.10
+fi
+
+export DYLD_LIBRARY_PATH=/Users/cah/osx-environment/$env/lib:/usr/local/lib
+
+if [ "$1" == "--debug" ]; then
+ shift
+ if [[ "$(uname)" == Darwin ]]; then
+ /Applications/Xcode.app/Contents/Developer/usr/bin/lldb $binary $*
+ else
+ gdb --args $binary $*
+ fi
+else
+ $binary $* 2> >(grep -v Gtk-CRITICAL | grep -v Gtk-WARNING)
+fi
diff --git a/src/lib/config.cc b/src/lib/config.cc
index c80ef224e..21192ad30 100644
--- a/src/lib/config.cc
+++ b/src/lib/config.cc
@@ -200,6 +200,7 @@ Config::set_defaults ()
_initial_paths["CinemaDatabasePath"] = boost::none;
_initial_paths["ConfigFilePath"] = boost::none;
_initial_paths["Preferences"] = boost::none;
+ _initial_paths["SaveVerificationReport"] = boost::none;
_use_isdcf_name_by_default = true;
_write_kdms_to_disk = true;
_email_kdms = false;
diff --git a/src/lib/verify_dcp_job.cc b/src/lib/verify_dcp_job.cc
index 5e50ec51d..668b1eab4 100644
--- a/src/lib/verify_dcp_job.cc
+++ b/src/lib/verify_dcp_job.cc
@@ -86,7 +86,7 @@ VerifyDCPJob::run ()
}
}
- _notes = dcp::verify(
+ _result = dcp::verify(
_directories,
decrypted_kdms,
bind(&VerifyDCPJob::update_stage, this, _1, _2),
@@ -96,7 +96,7 @@ VerifyDCPJob::run ()
);
bool failed = false;
- for (auto i: _notes) {
+ for (auto i: _result.notes) {
if (i.type() == dcp::VerificationNote::Type::ERROR) {
failed = true;
}
diff --git a/src/lib/verify_dcp_job.h b/src/lib/verify_dcp_job.h
index 61a347507..d7ac21d41 100644
--- a/src/lib/verify_dcp_job.h
+++ b/src/lib/verify_dcp_job.h
@@ -36,8 +36,8 @@ public:
std::string json_name () const override;
void run () override;
- std::vector<dcp::VerificationNote> notes () const {
- return _notes;
+ dcp::VerificationResult const& result() const {
+ return _result;
}
private:
@@ -45,5 +45,5 @@ private:
std::vector<boost::filesystem::path> _directories;
std::vector<boost::filesystem::path> _kdms;
- std::vector<dcp::VerificationNote> _notes;
+ dcp::VerificationResult _result;
};
diff --git a/src/tools/dcpomatic_verifier.cc b/src/tools/dcpomatic_verifier.cc
new file mode 100644
index 000000000..382516acc
--- /dev/null
+++ b/src/tools/dcpomatic_verifier.cc
@@ -0,0 +1,247 @@
+/*
+ Copyright (C) 2024 Carl Hetherington <cth@carlh.net>
+
+ This file is part of DCP-o-matic.
+
+ DCP-o-matic is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ DCP-o-matic is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with DCP-o-matic. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+
+/** @file src/tools/dcpomatic_verify.cc
+ * @brief A DCP verify GUI.
+ */
+
+
+#include "wx/check_box.h"
+#include "wx/dcpomatic_button.h"
+#include "wx/dir_picker_ctrl.h"
+#include "wx/verify_dcp_progress_panel.h"
+#include "wx/verify_dcp_result_panel.h"
+#include "wx/wx_util.h"
+#include "lib/constants.h"
+#include "lib/cross.h"
+#include "lib/job_manager.h"
+#include "lib/verify_dcp_job.h"
+#include "lib/util.h"
+#include <dcp/verify_report.h>
+LIBDCP_DISABLE_WARNINGS
+#include <wx/evtloop.h>
+#include <wx/wx.h>
+LIBDCP_ENABLE_WARNINGS
+#ifdef __WXGTK__
+#include <X11/Xlib.h>
+#endif
+
+
+using std::exception;
+using std::make_shared;
+
+
+class DOMFrame : public wxFrame
+{
+public:
+ explicit DOMFrame(wxString const& title)
+ : wxFrame(nullptr, -1, title)
+ {
+#ifdef DCPOMATIC_WINDOWS
+ SetIcon(wxIcon(std_to_wx("id")));
+#endif
+ auto overall_sizer = new wxBoxSizer(wxVERTICAL);
+
+ auto dcp_sizer = new wxBoxSizer(wxHORIZONTAL);
+ add_label_to_sizer(dcp_sizer, this, _("DCP"), true, 0, wxALIGN_CENTER_VERTICAL);
+ _dcp = new DirPickerCtrl(this, true);
+ dcp_sizer->Add(_dcp, 1, wxEXPAND);
+ overall_sizer->Add(dcp_sizer, 0, wxEXPAND | wxALL, DCPOMATIC_DIALOG_BORDER);
+
+ auto options_sizer = new wxBoxSizer(wxVERTICAL);
+ _write_log = new CheckBox(this, _("Write log to DCP folder"));
+ options_sizer->Add(_write_log, 0, wxBOTTOM, DCPOMATIC_SIZER_GAP);
+ overall_sizer->Add(options_sizer, 0, wxLEFT, DCPOMATIC_DIALOG_BORDER);
+
+ _verify = new Button(this, _("Verify"));
+ overall_sizer->Add(_verify, 0, wxEXPAND | wxLEFT | wxRIGHT, DCPOMATIC_DIALOG_BORDER);
+
+ _progress_panel = new VerifyDCPProgressPanel(this);
+ overall_sizer->Add(_progress_panel, 0, wxEXPAND | wxALL, DCPOMATIC_DIALOG_BORDER);
+
+ _result_panel = new VerifyDCPResultPanel(this);
+ overall_sizer->Add(_result_panel, 0, wxEXPAND | wxALL, DCPOMATIC_DIALOG_BORDER);
+
+ SetSizerAndFit(overall_sizer);
+
+ _dcp->Changed.connect(boost::bind(&DOMFrame::setup_sensitivity, this));
+ _verify->bind(&DOMFrame::verify_clicked, this);
+
+ setup_sensitivity();
+ }
+
+private:
+ void setup_sensitivity()
+ {
+ _verify->Enable(!_dcp->GetPath().IsEmpty());
+ }
+
+ void verify_clicked()
+ {
+ auto dcp = boost::filesystem::path(wx_to_std(_dcp->GetPath()));
+ if (dcp.empty()) {
+ return;
+ }
+
+ auto job_manager = JobManager::instance();
+ auto job = make_shared<VerifyDCPJob>(std::vector<boost::filesystem::path>{dcp}, std::vector<boost::filesystem::path>());
+ job_manager->add(job);
+
+ while (job_manager->work_to_do()) {
+ wxEventLoopBase::GetActive()->YieldFor(wxEVT_CATEGORY_UI | wxEVT_CATEGORY_USER_INPUT);
+ dcpomatic_sleep_seconds(1);
+
+ _progress_panel->update(job);
+ }
+
+ _result_panel->fill(job);
+ if (_write_log->get()) {
+ dcp::TextFormatter formatter(dcp / "REPORT.txt");
+ dcp::verify_report(job->result(), formatter);
+ }
+ }
+
+ DirPickerCtrl* _dcp;
+ CheckBox* _write_log;
+ Button* _verify;
+ VerifyDCPProgressPanel* _progress_panel;
+ VerifyDCPResultPanel* _result_panel;
+};
+
+
+/** @class App
+ * @brief The magic App class for wxWidgets.
+ */
+class App : public wxApp
+{
+public:
+ App()
+ : wxApp()
+ {
+ dcpomatic_setup_path_encoding();
+#ifdef DCPOMATIC_LINUX
+ XInitThreads();
+#endif
+ }
+
+private:
+ bool OnInit() override
+ {
+ try {
+ SetAppName(_("DCP-o-matic Verifier"));
+
+ if (!wxApp::OnInit()) {
+ return false;
+ }
+
+#ifdef DCPOMATIC_LINUX
+ unsetenv("UBUNTU_MENUPROXY");
+#endif
+
+#ifdef DCPOMATIC_OSX
+ dcpomatic_sleep_seconds(1);
+ make_foreground_application();
+#endif
+
+ /* Enable i18n; this will create a Config object
+ to look for a force-configured language. This Config
+ object will be wrong, however, because dcpomatic_setup
+ hasn't yet been called and there aren't any filters etc.
+ set up yet.
+ */
+ dcpomatic_setup_i18n();
+
+ /* Set things up, including filters etc.
+ which will now be internationalised correctly.
+ */
+ dcpomatic_setup();
+
+ /* Force the configuration to be re-loaded correctly next
+ time it is needed.
+ */
+ Config::drop();
+
+ _frame = new DOMFrame(_("DCP-o-matic Verifier"));
+ SetTopWindow(_frame);
+ _frame->SetSize({480, 640});
+ _frame->Show();
+ }
+ catch (exception& e)
+ {
+ error_dialog(nullptr, wxString::Format("DCP-o-matic Verifier could not start."), std_to_wx(e.what()));
+ }
+
+ return true;
+ }
+
+ void report_exception()
+ {
+ try {
+ throw;
+ } catch (FileError& e) {
+ error_dialog(
+ nullptr,
+ wxString::Format(
+ _("An exception occurred: %s (%s)\n\n") + REPORT_PROBLEM,
+ std_to_wx(e.what()),
+ std_to_wx(e.file().string().c_str())
+ )
+ );
+ } catch (boost::filesystem::filesystem_error& e) {
+ error_dialog(
+ nullptr,
+ wxString::Format(
+ _("An exception occurred: %s (%s) (%s)\n\n") + REPORT_PROBLEM,
+ std_to_wx(e.what()),
+ std_to_wx(e.path1().string()),
+ std_to_wx(e.path2().string())
+ )
+ );
+ } catch (exception& e) {
+ error_dialog(
+ nullptr,
+ wxString::Format(
+ _("An exception occurred: %s.\n\n") + REPORT_PROBLEM,
+ std_to_wx(e.what())
+ )
+ );
+ } catch (...) {
+ error_dialog(nullptr, _("An unknown exception occurred.") + " " + REPORT_PROBLEM);
+ }
+ }
+
+ /* An unhandled exception has occurred inside the main event loop */
+ bool OnExceptionInMainLoop() override
+ {
+ report_exception();
+ return false;
+ }
+
+ void OnUnhandledException() override
+ {
+ report_exception();
+ }
+
+ DOMFrame* _frame = nullptr;
+};
+
+
+IMPLEMENT_APP(App)
diff --git a/src/tools/wscript b/src/tools/wscript
index c3b2b5fe0..65e4d0e4c 100644
--- a/src/tools/wscript
+++ b/src/tools/wscript
@@ -62,7 +62,15 @@ def build(bld):
gui_tools = []
if not bld.env.DISABLE_GUI:
- gui_tools = ['dcpomatic', 'dcpomatic_batch', 'dcpomatic_server', 'dcpomatic_kdm', 'dcpomatic_player', 'dcpomatic_playlist', 'dcpomatic_combiner', 'dcpomatic_editor']
+ gui_tools = ['dcpomatic',
+ 'dcpomatic_batch',
+ 'dcpomatic_server',
+ 'dcpomatic_kdm',
+ 'dcpomatic_player',
+ 'dcpomatic_playlist',
+ 'dcpomatic_combiner',
+ 'dcpomatic_editor',
+ 'dcpomatic_verifier']
if bld.env.ENABLE_DISK:
gui_tools.append('dcpomatic_disk')
diff --git a/src/wx/verify_dcp_result_dialog.cc b/src/wx/verify_dcp_result_dialog.cc
index 9617878c5..806eac85a 100644
--- a/src/wx/verify_dcp_result_dialog.cc
+++ b/src/wx/verify_dcp_result_dialog.cc
@@ -44,5 +44,4 @@ VerifyDCPResultDialog::VerifyDCPResultDialog(wxWindow* parent, shared_ptr<Verify
SetSizer (sizer);
sizer->Layout ();
sizer->SetSizeHints (this);
-
}
diff --git a/src/wx/verify_dcp_result_panel.cc b/src/wx/verify_dcp_result_panel.cc
index 4920ab350..bfeb14640 100644
--- a/src/wx/verify_dcp_result_panel.cc
+++ b/src/wx/verify_dcp_result_panel.cc
@@ -19,11 +19,14 @@
*/
+#include "dcpomatic_button.h"
+#include "file_dialog.h"
#include "verify_dcp_result_panel.h"
#include "wx_util.h"
#include "lib/verify_dcp_job.h"
#include <dcp/raw_convert.h>
#include <dcp/verify.h>
+#include <dcp/verify_report.h>
#include <dcp/warnings.h>
LIBDCP_DISABLE_WARNINGS
#include <wx/richtext/richtextctrl.h>
@@ -56,6 +59,13 @@ VerifyDCPResultPanel::VerifyDCPResultPanel(wxWindow* parent)
_summary = new wxStaticText(this, wxID_ANY, wxT(""));
sizer->Add(_summary, 0, wxALL, DCPOMATIC_DIALOG_BORDER);
+ auto save_sizer = new wxBoxSizer(wxHORIZONTAL);
+ _save_text_report = new Button(this, _("Save report as text..."));
+ save_sizer->Add(_save_text_report, 0, wxALL, DCPOMATIC_SIZER_GAP);
+ _save_html_report = new Button(this, _("Save report as HTML..."));
+ save_sizer->Add(_save_html_report, 0, wxALL, DCPOMATIC_SIZER_GAP);
+ sizer->Add(save_sizer);
+
SetSizer(sizer);
sizer->Layout();
sizer->SetSizeHints(this);
@@ -63,13 +73,19 @@ VerifyDCPResultPanel::VerifyDCPResultPanel(wxWindow* parent)
for (auto const& i: _pages) {
i.second->GetCaret()->Hide();
}
+
+ _save_text_report->bind(&VerifyDCPResultPanel::save_text_report, this);
+ _save_html_report->bind(&VerifyDCPResultPanel::save_html_report, this);
+
+ _save_text_report->Enable(false);
+ _save_html_report->Enable(false);
}
void
VerifyDCPResultPanel::fill(shared_ptr<VerifyDCPJob> job)
{
- if (job->finished_ok() && job->notes().empty()) {
+ if (job->finished_ok() && job->result().notes.empty()) {
_summary->SetLabel(_("DCP validates OK."));
return;
}
@@ -132,7 +148,7 @@ VerifyDCPResultPanel::fill(shared_ptr<VerifyDCPJob> job)
++counts[dcp::VerificationNote::Type::ERROR];
}
- for (auto i: job->notes()) {
+ for (auto i: job->result().notes) {
switch (i.code()) {
case dcp::VerificationNote::Code::FAILED_READ:
add(i, _("Could not read DCP (%n)"));
@@ -448,6 +464,19 @@ VerifyDCPResultPanel::fill(shared_ptr<VerifyDCPJob> job)
case dcp::VerificationNote::Code::EMPTY_CONTENT_VERSION_LABEL_TEXT:
add(i, _("The <LabelText> in a <ContentVersion> in CPL %id is empty"));
break;
+ case dcp::VerificationNote::Code::MATCHING_CPL_HASHES:
+ case dcp::VerificationNote::Code::CORRECT_PICTURE_HASH:
+ case dcp::VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES:
+ case dcp::VerificationNote::Code::VALID_RELEASE_TERRITORY:
+ case dcp::VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT:
+ case dcp::VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL:
+ case dcp::VerificationNote::Code::ALL_ENCRYPTED:
+ case dcp::VerificationNote::Code::NONE_ENCRYPTED:
+ case dcp::VerificationNote::Code::VALID_CONTENT_KIND:
+ case dcp::VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA:
+ case dcp::VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT:
+ /* These are all "OK" messages which we don't report here */
+ break;
}
}
@@ -490,5 +519,39 @@ VerifyDCPResultPanel::fill(shared_ptr<VerifyDCPJob> job)
if (counts[dcp::VerificationNote::Type::WARNING] == 0) {
add_bullet(dcp::VerificationNote::Type::WARNING, _("No warnings found."));
}
+
+ _job = job;
+ _save_text_report->Enable(true);
+ _save_html_report->Enable(true);
+}
+
+
+template <class T>
+void save(wxWindow* parent, wxString filter, dcp::VerificationResult const& result)
+{
+ FileDialog dialog(parent, _("Verification report"), filter, wxFD_SAVE | wxFD_OVERWRITE_PROMPT, "SaveVerificationReport");
+ if (!dialog.show()) {
+ return;
+ }
+
+ T formatter(dialog.path());
+ dcp::verify_report(result, formatter);
}
+
+void
+VerifyDCPResultPanel::save_text_report()
+{
+ if (_job) {
+ save<dcp::TextFormatter>(this, wxT("Text files (*.txt)|*.txt"), _job->result());
+ }
+}
+
+
+void
+VerifyDCPResultPanel::save_html_report()
+{
+ if (_job) {
+ save<dcp::HTMLFormatter>(this, wxT("HTML files (*.htm;*html)|*.htm;*.html"), _job->result());
+ }
+}
diff --git a/src/wx/verify_dcp_result_panel.h b/src/wx/verify_dcp_result_panel.h
index f0a502064..8cf92118b 100644
--- a/src/wx/verify_dcp_result_panel.h
+++ b/src/wx/verify_dcp_result_panel.h
@@ -25,6 +25,7 @@
#include <memory>
+class Button;
class VerifyDCPJob;
class wxRichTextCtrl;
@@ -37,6 +38,13 @@ public:
void fill(std::shared_ptr<VerifyDCPJob> job);
private:
+ void save_text_report();
+ void save_html_report();
+
wxStaticText* _summary;
std::map<dcp::VerificationNote::Type, wxRichTextCtrl*> _pages;
+ Button* _save_text_report;
+ Button* _save_html_report;
+
+ std::shared_ptr<VerifyDCPJob> _job;
};
diff --git a/test/reels_test.cc b/test/reels_test.cc
index d4a783f91..df4bbbbe6 100644
--- a/test/reels_test.cc
+++ b/test/reels_test.cc
@@ -54,6 +54,14 @@ using std::vector;
using namespace dcpomatic;
+static
+void
+filter_ok(std::vector<dcp::VerificationNote>& notes)
+{
+ notes.erase(std::remove_if(notes.begin(), notes.end(), [](dcp::VerificationNote const& note) { return note.type() == dcp::VerificationNote::Type::OK; }), notes.end());
+}
+
+
/** Test Film::reels() */
BOOST_AUTO_TEST_CASE (reels_test1)
{
@@ -508,9 +516,10 @@ BOOST_AUTO_TEST_CASE (reels_should_not_be_short1)
make_and_verify_dcp (film);
vector<boost::filesystem::path> dirs = { film->dir(film->dcp_name(false)) };
- auto notes = dcp::verify(dirs, {}, boost::bind(&no_op), boost::bind(&no_op), {}, TestPaths::xsd());
- dump_notes (notes);
- BOOST_REQUIRE (notes.empty());
+ auto result = dcp::verify(dirs, {}, boost::bind(&no_op), boost::bind(&no_op), {}, TestPaths::xsd());
+ filter_ok(result.notes);
+ dump_notes(result.notes);
+ BOOST_REQUIRE(result.notes.empty());
}
@@ -533,9 +542,10 @@ BOOST_AUTO_TEST_CASE (reels_should_not_be_short2)
make_and_verify_dcp (film);
vector<boost::filesystem::path> dirs = { film->dir(film->dcp_name(false)) };
- auto const notes = dcp::verify(dirs, {}, boost::bind(&no_op), boost::bind(&no_op), {}, TestPaths::xsd());
- dump_notes (notes);
- BOOST_REQUIRE (notes.empty());
+ auto result = dcp::verify(dirs, {}, boost::bind(&no_op), boost::bind(&no_op), {}, TestPaths::xsd());
+ filter_ok(result.notes);
+ dump_notes(result.notes);
+ BOOST_REQUIRE(result.notes.empty());
}
@@ -554,9 +564,10 @@ BOOST_AUTO_TEST_CASE (reels_should_not_be_short3)
make_and_verify_dcp (film);
- auto const notes = dcp::verify({}, {}, boost::bind(&no_op), boost::bind(&no_op), {}, TestPaths::xsd());
- dump_notes (notes);
- BOOST_REQUIRE (notes.empty());
+ auto result = dcp::verify({}, {}, boost::bind(&no_op), boost::bind(&no_op), {}, TestPaths::xsd());
+ filter_ok(result.notes);
+ dump_notes(result.notes);
+ BOOST_REQUIRE(result.notes.empty());
}
@@ -584,9 +595,10 @@ BOOST_AUTO_TEST_CASE (reels_should_not_be_short4)
BOOST_REQUIRE (!wait_for_jobs());
vector<boost::filesystem::path> dirs = { film->dir(film->dcp_name(false)) };
- auto const notes = dcp::verify(dirs, {}, boost::bind(&no_op), boost::bind(&no_op), {}, TestPaths::xsd());
- dump_notes (notes);
- BOOST_REQUIRE (notes.empty());
+ auto result = dcp::verify(dirs, {}, boost::bind(&no_op), boost::bind(&no_op), {}, TestPaths::xsd());
+ filter_ok(result.notes);
+ dump_notes(result.notes);
+ BOOST_REQUIRE(result.notes.empty());
}
diff --git a/test/test.cc b/test/test.cc
index ff4a3c9c0..4064f9b0e 100644
--- a/test/test.cc
+++ b/test/test.cc
@@ -965,10 +965,10 @@ void progress (float) {}
void
verify_dcp(boost::filesystem::path dir, vector<dcp::VerificationNote::Code> ignore)
{
- auto notes = dcp::verify({dir}, {}, &stage, &progress, {}, TestPaths::xsd());
+ auto result = dcp::verify({dir}, {}, &stage, &progress, {}, TestPaths::xsd());
bool ok = true;
- for (auto i: notes) {
- if (find(ignore.begin(), ignore.end(), i.code()) == ignore.end()) {
+ for (auto i: result.notes) {
+ if (i.type() != dcp::VerificationNote::Type::OK && find(ignore.begin(), ignore.end(), i.code()) == ignore.end()) {
std::cout << "\t" << dcp::note_to_string(i) << "\n";
ok = false;
}