diff options
| author | Carl Hetherington <cth@carlh.net> | 2020-09-11 01:07:46 +0200 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2020-09-20 01:30:41 +0200 |
| commit | 5a3e836da9480bca0c3ef3384fa2010f358ccc7e (patch) | |
| tree | 2a15662a32dc00c86740641db6eedaf99daacb42 | |
| parent | 44dde2ee811eb35535633d760e6c0671cdf45cae (diff) | |
Add dcpomatic_combine tool (#1245).
37 files changed, 757 insertions, 6 deletions
@@ -373,8 +373,8 @@ def dependencies(target, options): (target.platform == 'osx' and target.bits == 64) or (target.platform == 'windows')) else {} - deps.append(('libdcp', '184bdd2', cpp_lib_options)) - deps.append(('libsub', '72bf4fc', cpp_lib_options)) + deps.append(('libdcp', '40f6f7d', cpp_lib_options)) + deps.append(('libsub', 'c5b7a36', cpp_lib_options)) deps.append(('leqm-nrt', 'carl')) deps.append(('rtaudio', 'carl')) # We get our OpenSSL libraries from the environment, but we diff --git a/graphics/linux/128/dcpomatic2_combiner.png b/graphics/linux/128/dcpomatic2_combiner.png Binary files differnew file mode 100644 index 000000000..27ad5d0e7 --- /dev/null +++ b/graphics/linux/128/dcpomatic2_combiner.png diff --git a/graphics/linux/16/dcpomatic2_combiner.png b/graphics/linux/16/dcpomatic2_combiner.png Binary files differnew file mode 100644 index 000000000..ae6f698cc --- /dev/null +++ b/graphics/linux/16/dcpomatic2_combiner.png diff --git a/graphics/linux/22/dcpomatic2_combiner.png b/graphics/linux/22/dcpomatic2_combiner.png Binary files differnew file mode 100644 index 000000000..4fa3d3b0a --- /dev/null +++ b/graphics/linux/22/dcpomatic2_combiner.png diff --git a/graphics/linux/256/dcpomatic2_combiner.png b/graphics/linux/256/dcpomatic2_combiner.png Binary files differnew file mode 100644 index 000000000..7388b2ee8 --- /dev/null +++ b/graphics/linux/256/dcpomatic2_combiner.png diff --git a/graphics/linux/32/dcpomatic2_combiner.png b/graphics/linux/32/dcpomatic2_combiner.png Binary files differnew file mode 100644 index 000000000..e24e0e0e5 --- /dev/null +++ b/graphics/linux/32/dcpomatic2_combiner.png diff --git a/graphics/linux/48/dcpomatic2_combiner.png b/graphics/linux/48/dcpomatic2_combiner.png Binary files differnew file mode 100644 index 000000000..10fcca296 --- /dev/null +++ b/graphics/linux/48/dcpomatic2_combiner.png diff --git a/graphics/linux/512/dcpomatic2_combiner.png b/graphics/linux/512/dcpomatic2_combiner.png Binary files differnew file mode 100644 index 000000000..345166990 --- /dev/null +++ b/graphics/linux/512/dcpomatic2_combiner.png diff --git a/graphics/linux/64/dcpomatic2_combiner.png b/graphics/linux/64/dcpomatic2_combiner.png Binary files differnew file mode 100644 index 000000000..4c52f59c3 --- /dev/null +++ b/graphics/linux/64/dcpomatic2_combiner.png diff --git a/graphics/osx/dcpomatic2_combiner.icns b/graphics/osx/dcpomatic2_combiner.icns Binary files differnew file mode 100644 index 000000000..8f4f5c2a7 --- /dev/null +++ b/graphics/osx/dcpomatic2_combiner.icns diff --git a/graphics/osx/dcpomatic2_combiner.iconset/icon_128x128.png b/graphics/osx/dcpomatic2_combiner.iconset/icon_128x128.png Binary files differnew file mode 100644 index 000000000..27ad5d0e7 --- /dev/null +++ b/graphics/osx/dcpomatic2_combiner.iconset/icon_128x128.png diff --git a/graphics/osx/dcpomatic2_combiner.iconset/icon_128x128@2x.png b/graphics/osx/dcpomatic2_combiner.iconset/icon_128x128@2x.png Binary files differnew file mode 100644 index 000000000..27ad5d0e7 --- /dev/null +++ b/graphics/osx/dcpomatic2_combiner.iconset/icon_128x128@2x.png diff --git a/graphics/osx/dcpomatic2_combiner.iconset/icon_16x16.png b/graphics/osx/dcpomatic2_combiner.iconset/icon_16x16.png Binary files differnew file mode 100644 index 000000000..ae6f698cc --- /dev/null +++ b/graphics/osx/dcpomatic2_combiner.iconset/icon_16x16.png diff --git a/graphics/osx/dcpomatic2_combiner.iconset/icon_16x16@2x.png b/graphics/osx/dcpomatic2_combiner.iconset/icon_16x16@2x.png Binary files differnew file mode 100644 index 000000000..ae6f698cc --- /dev/null +++ b/graphics/osx/dcpomatic2_combiner.iconset/icon_16x16@2x.png diff --git a/graphics/osx/dcpomatic2_combiner.iconset/icon_256x256.png b/graphics/osx/dcpomatic2_combiner.iconset/icon_256x256.png Binary files differnew file mode 100644 index 000000000..7388b2ee8 --- /dev/null +++ b/graphics/osx/dcpomatic2_combiner.iconset/icon_256x256.png diff --git a/graphics/osx/dcpomatic2_combiner.iconset/icon_256x256@2x.png b/graphics/osx/dcpomatic2_combiner.iconset/icon_256x256@2x.png Binary files differnew file mode 100644 index 000000000..7388b2ee8 --- /dev/null +++ b/graphics/osx/dcpomatic2_combiner.iconset/icon_256x256@2x.png diff --git a/graphics/osx/dcpomatic2_combiner.iconset/icon_32x32.png b/graphics/osx/dcpomatic2_combiner.iconset/icon_32x32.png Binary files differnew file mode 100644 index 000000000..e24e0e0e5 --- /dev/null +++ b/graphics/osx/dcpomatic2_combiner.iconset/icon_32x32.png diff --git a/graphics/osx/dcpomatic2_combiner.iconset/icon_32x32@2x.png b/graphics/osx/dcpomatic2_combiner.iconset/icon_32x32@2x.png Binary files differnew file mode 100644 index 000000000..e24e0e0e5 --- /dev/null +++ b/graphics/osx/dcpomatic2_combiner.iconset/icon_32x32@2x.png diff --git a/graphics/osx/dcpomatic2_combiner.iconset/icon_512x512.png b/graphics/osx/dcpomatic2_combiner.iconset/icon_512x512.png Binary files differnew file mode 100644 index 000000000..345166990 --- /dev/null +++ b/graphics/osx/dcpomatic2_combiner.iconset/icon_512x512.png diff --git a/graphics/osx/dcpomatic2_combiner.iconset/icon_512x512@2x.png b/graphics/osx/dcpomatic2_combiner.iconset/icon_512x512@2x.png Binary files differnew file mode 100644 index 000000000..345166990 --- /dev/null +++ b/graphics/osx/dcpomatic2_combiner.iconset/icon_512x512@2x.png diff --git a/graphics/src/dcpomatic2_combiner.svg b/graphics/src/dcpomatic2_combiner.svg new file mode 100644 index 000000000..8a150c521 --- /dev/null +++ b/graphics/src/dcpomatic2_combiner.svg @@ -0,0 +1,231 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + viewBox="0 0 1000 1000" + sodipodi:docname="dcpomatic2_combine.svg" + inkscape:version="1.0 (4035a4f, 2020-05-01)" + version="1.1" + id="svg2" + height="1066.6666" + width="1066.6666"> + <defs + id="defs4"> + <marker + inkscape:isstock="true" + style="overflow:visible" + id="Arrow1Mstart" + refX="0.0" + refY="0.0" + orient="auto" + inkscape:stockid="Arrow1Mstart"> + <path + transform="scale(0.4) translate(10,0)" + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt" + d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z " + id="path893" /> + </marker> + <marker + inkscape:isstock="true" + style="overflow:visible;" + id="marker1193" + refX="0.0" + refY="0.0" + orient="auto" + inkscape:stockid="Arrow1Lend"> + <path + transform="scale(0.8) rotate(180) translate(12.5,0)" + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;" + d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z " + id="path1191" /> + </marker> + <marker + inkscape:isstock="true" + style="overflow:visible" + id="marker1189" + refX="0.0" + refY="0.0" + orient="auto" + inkscape:stockid="Arrow1Lstart"> + <path + transform="scale(0.8) translate(12.5,0)" + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt" + d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z " + id="path1187" /> + </marker> + <marker + inkscape:isstock="true" + style="overflow:visible" + id="marker1167" + refX="0.0" + refY="0.0" + orient="auto" + inkscape:stockid="Arrow1Lstart"> + <path + transform="scale(0.8) translate(12.5,0)" + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt" + d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z " + id="path1165" /> + </marker> + <marker + inkscape:isstock="true" + style="overflow:visible;" + id="Arrow1Lend" + refX="0.0" + refY="0.0" + orient="auto" + inkscape:stockid="Arrow1Lend"> + <path + transform="scale(0.8) rotate(180) translate(12.5,0)" + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;" + d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z " + id="path890" /> + </marker> + <marker + inkscape:isstock="true" + style="overflow:visible" + id="Arrow1Lstart" + refX="0.0" + refY="0.0" + orient="auto" + inkscape:stockid="Arrow1Lstart"> + <path + transform="scale(0.8) translate(12.5,0)" + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt" + d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 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="27" + inkscape:window-x="0" + inkscape:window-height="986" + inkscape:window-width="1680" + showgrid="false" + inkscape:current-layer="layer1" + inkscape:document-units="px" + inkscape:cy="589.03894" + inkscape:cx="-138.64759" + inkscape:zoom="0.34926264" + inkscape:pageshadow="2" + inkscape:pageopacity="0.0" + borderopacity="1.0" + bordercolor="#666666" + pagecolor="#ffffff" + id="base" /> + <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" /> + <dc:title /> + </cc:Work> + </rdf:RDF> + </metadata> + <g + transform="translate(0,-52.362188)" + id="layer1" + inkscape:groupmode="layer" + inkscape:label="Layer 1"> + <image + sodipodi:absref="/home/carl/src/dcpomatic/graphics/src/dcpomatic.png" + xlink:href="dcpomatic.png" + id="image4358" + preserveAspectRatio="none" + height="960.00006" + width="960.00006" + x="10.670144" + y="80.386467" /> + <path + d="m 490.67101,280.27778 a 46.083593,46.083593 0 0 0 -46.08414,46.08418 V 514.30317 H 256.6457 a 46.083685,46.083685 0 0 0 -46.08423,46.08417 46.083685,46.083685 0 0 0 46.08423,46.08249 h 187.94117 v 187.94291 a 46.083593,46.083593 0 0 0 46.08414,46.08248 46.083593,46.083593 0 0 0 46.08256,-46.08248 V 606.46983 h 187.94284 a 46.083685,46.083685 0 0 0 46.08247,-46.08249 46.083685,46.083685 0 0 0 -46.08247,-46.08417 H 536.75357 V 326.36196 a 46.083593,46.083593 0 0 0 -46.08256,-46.08418 z" + style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#5e5e5e;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:15.5608;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate;stop-color:#000000;opacity:0.79289843" + id="path1288" /> + </g> +</svg> diff --git a/graphics/update b/graphics/update index cee8a3ca1..5896867bc 100755 --- a/graphics/update +++ b/graphics/update @@ -23,7 +23,7 @@ function required_font() fi } -svg_apps="dcpomatic2_kdm dcpomatic2_server dcpomatic2_batch dcpomatic2_player dcpomatic2_playlist dcpomatic2_disk" +svg_apps="dcpomatic2_kdm dcpomatic2_server dcpomatic2_batch dcpomatic2_player dcpomatic2_playlist dcpomatic2_disk dcpomatic2_combiner" required_font "Libre Baskerville" diff --git a/graphics/windows/dcpomatic2_combiner.ico b/graphics/windows/dcpomatic2_combiner.ico Binary files differnew file mode 100644 index 000000000..0db1eb108 --- /dev/null +++ b/graphics/windows/dcpomatic2_combiner.ico diff --git a/platform/linux/dcpomatic_combiner.desktop.in b/platform/linux/dcpomatic_combiner.desktop.in new file mode 100644 index 000000000..2b875ee99 --- /dev/null +++ b/platform/linux/dcpomatic_combiner.desktop.in @@ -0,0 +1,10 @@ +[Desktop Entry] +Encoding=UTF-8 +Version=1.0 +Type=Application +Terminal=false +Exec=@INSTALL_PREFIX@/bin/dcpomatic2_combiner +Name=DCP-o-matic 2 Combiner +Icon=dcpomatic2_combiner +Comment=DCP combiner +Categories=AudioVideo;Video diff --git a/platform/linux/wscript b/platform/linux/wscript index 0fc593f56..dad5778a6 100644 --- a/platform/linux/wscript +++ b/platform/linux/wscript @@ -51,4 +51,11 @@ def build(bld): obj.VERSION = bld.env.VERSION desktops.append(obj.target) + obj = bld(features='subst') + obj.source = 'dcpomatic_combiner.desktop.in' + obj.target = 'dcpomatic2_combiner.desktop' + obj.INSTALL_PREFIX = bld.env.INSTALL_PREFIX + obj.VERSION = bld.env.VERSION + desktops.append(obj.target) + bld.install_files('${PREFIX}/share/applications', desktops) diff --git a/platform/osx/dcpomatic2_combiner.Info.plist.in b/platform/osx/dcpomatic2_combiner.Info.plist.in new file mode 100644 index 000000000..a9ab61968 --- /dev/null +++ b/platform/osx/dcpomatic2_combiner.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_combiner</string> + <key>CFBundleGetInfoString</key> + <string>DCP-o-matic 2 Combiner</string> + <key>CFBundleIconFile</key> + <string>dcpomatic2_combiner.icns</string> + <key>CFBundleIdentifier</key> + <string>com.dcpomatic.combiner</string> + <key>CFBundleInfoDictionaryVersion</key> + <string>6.0</string> + <key>CFBundleName</key> + <string>DCP-o-matic 2 Combiner</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 f55a0e8b1..643e6af33 100644 --- a/platform/osx/make_dmg.sh +++ b/platform/osx/make_dmg.sh @@ -191,6 +191,7 @@ function copy_resources { cp $prefix/src/dcpomatic/graphics/osx/dcpomatic2_batch.icns "$dest" cp $prefix/src/dcpomatic/graphics/osx/dcpomatic2_playlist.icns "$dest" 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/preferences/defaults.png "$dest" cp $prefix/src/dcpomatic/graphics/osx/preferences/defaults@2x.png "$dest" cp $prefix/src/dcpomatic/graphics/osx/preferences/kdm_email.png "$dest" @@ -522,6 +523,15 @@ rl=("$approot/MacOS/dcpomatic2_playlist" "$approot/Frameworks/"*.dylib) relink_relative "${rl[@]}" make_dmg "$appdir" "" "DCP-o-matic Playlist Editor" com.dcpomatic.playlist +# DCP-o-matic Combiner +setup "DCP-o-matic 2 Combiner.app" +copy $ROOT src/dcpomatic/build/src/tools/dcpomatic2_combiner "$approot/MacOS" +copy $ROOT src/openssl/apps/openssl "$approot/MacOS" +cp $prefix/src/dcpomatic/build/platform/osx/dcpomatic2_combiner.Info.plist "$approot/Info.plist" +rl=("$approot/MacOS/dcpomatic2_combiner" "$approot/Frameworks/"*.dylib) +relink_relative "${rl[@]}" +make_dmg "$appdir" "" "DCP-o-matic Combiner" com.dcpomatic.combiner + # DCP-o-matic Disk Writer .app setup "DCP-o-matic 2 Disk Writer.app" copy $ROOT src/dcpomatic/build/src/tools/dcpomatic2_disk "$approot/MacOS" diff --git a/platform/osx/wscript b/platform/osx/wscript index da20065f5..c0b3d9d10 100644 --- a/platform/osx/wscript +++ b/platform/osx/wscript @@ -6,3 +6,4 @@ def build(bld): obj = bld(features='subst', source='dcpomatic2_player.Info.plist.in', target='dcpomatic2_player.Info.plist', version=bld.env.VERSION) obj = bld(features='subst', source='dcpomatic2_playlist.Info.plist.in', target='dcpomatic2_playlist.Info.plist', version=bld.env.VERSION) 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) diff --git a/platform/windows/dcpomatic2_combiner_debug.bat b/platform/windows/dcpomatic2_combiner_debug.bat new file mode 100644 index 000000000..a4aae9f0c --- /dev/null +++ b/platform/windows/dcpomatic2_combiner_debug.bat @@ -0,0 +1 @@ +gdb.exe -x gdb_script dcpomatic2_combiner.exe > %HOMEPATH%/Documents/dcpomatic_debug_log.txt diff --git a/platform/windows/dcpomatic_combiner.rc b/platform/windows/dcpomatic_combiner.rc new file mode 100644 index 000000000..1b72bf58a --- /dev/null +++ b/platform/windows/dcpomatic_combiner.rc @@ -0,0 +1,2 @@ +id ICON "../../graphics/windows/dcpomatic2_combiner.ico" +#include "wx-3.0/wx/msw/wx.rc" diff --git a/platform/windows/wscript b/platform/windows/wscript index 64f0a57cf..e46038087 100644 --- a/platform/windows/wscript +++ b/platform/windows/wscript @@ -10,7 +10,8 @@ def write_installer(bits, dcpomatic_version, debug, variant, disk): ('player', 'Player'), ('cli', 'CLI'), ('create', 'Creator'), - ('playlist', 'Playlist Editor') + ('playlist', 'Playlist Editor'), + ('combiner', 'Combiner'), ] if disk: diff --git a/run/dcpomatic_combiner b/run/dcpomatic_combiner new file mode 100755 index 000000000..3cf60d831 --- /dev/null +++ b/run/dcpomatic_combiner @@ -0,0 +1,25 @@ +#!/bin/bash + +export LD_LIBRARY_PATH=build/src/lib:build/src/wx:build/src/asdcplib/src:/home/c.hetherington/lib:$LD_LIBRARY_PATH +export DYLD_LIBRARY_PATH=build/src/lib:build/src/wx:build/src/asdcplib/src:/Users/c.hetherington/osx-environment/64/lib +if [ "$1" == "--debug" ]; then + shift + gdb --args build/src/tools/dcpomatic2_combiner $* +elif [ "$1" == "--valgrind" ]; then + shift + valgrind --tool="memcheck" --suppressions=suppressions --track-fds=yes build/src/tools/dcpomatic2_combiner $* +elif [ "$1" == "--callgrind" ]; then + shift + valgrind --tool="callgrind" build/src/tools/dcpomatic2_combiner $* +elif [ "$1" == "--massif" ]; then + shift + valgrind --tool="massif" build/src/tools/dcpomatic2_combiner $* +elif [ "$1" == "--i18n" ]; then + shift + LANGUAGE=fr_FR.UTF8 LANG=fr_FR.UTF8 LC_ALL=fr_FR.UTF8 build/src/tools/dcpomatic2_combiner "$*" +elif [ "$1" == "--perf" ]; then + shift + perf record build/src/tools/dcpomatic2_combiner $* +else + build/src/tools/dcpomatic2_combiner $* +fi diff --git a/src/lib/combine_dcp_job.cc b/src/lib/combine_dcp_job.cc new file mode 100644 index 000000000..b3c29b205 --- /dev/null +++ b/src/lib/combine_dcp_job.cc @@ -0,0 +1,74 @@ +/* + Copyright (C) 2020 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/>. + +*/ + + +#include "combine_dcp_job.h" +#include <dcp/combine.h> +#include <dcp/exceptions.h> + +#include "i18n.h" + + +using std::string; +using std::vector; +using boost::shared_ptr; + + +CombineDCPJob::CombineDCPJob (vector<boost::filesystem::path> inputs, boost::filesystem::path output) + : Job (shared_ptr<Film>()) + , _inputs (inputs) + , _output (output) +{ + +} + + +string +CombineDCPJob::name () const +{ + return _("Combine DCPs"); +} + + +string +CombineDCPJob::json_name () const +{ + return N_("combine_dcps"); +} + + +void +CombineDCPJob::run () +{ + try { + dcp::combine (_inputs, _output); + } catch (dcp::CombineError& e) { + set_state (FINISHED_ERROR); + set_error (e.what(), ""); + return; + } catch (dcp::ReadError& e) { + set_state (FINISHED_ERROR); + set_error (e.what(), e.detail().get_value_or("")); + return; + } + + set_progress (1); + set_state (FINISHED_OK); +} diff --git a/src/lib/combine_dcp_job.h b/src/lib/combine_dcp_job.h new file mode 100644 index 000000000..97bf20110 --- /dev/null +++ b/src/lib/combine_dcp_job.h @@ -0,0 +1,39 @@ +/* + Copyright (C) 2020 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/>. + +*/ + + +#include "job.h" +#include <boost/filesystem.hpp> + + +class CombineDCPJob : public Job +{ +public: + CombineDCPJob (std::vector<boost::filesystem::path> inputs, boost::filesystem::path output); + + std::string name () const; + std::string json_name () const; + void run (); + +private: + std::vector<boost::filesystem::path> _inputs; + boost::filesystem::path _output; +}; + diff --git a/src/lib/wscript b/src/lib/wscript index 0c9cddfa4..04044a8c3 100644 --- a/src/lib/wscript +++ b/src/lib/wscript @@ -55,6 +55,7 @@ sources = """ config.cc content.cc content_factory.cc + combine_dcp_job.cc copy_dcp_details_to_film.cc create_cli.cc cross_common.cc diff --git a/src/tools/dcpomatic_combiner.cc b/src/tools/dcpomatic_combiner.cc new file mode 100644 index 000000000..5f1a7722a --- /dev/null +++ b/src/tools/dcpomatic_combiner.cc @@ -0,0 +1,313 @@ +/* + Copyright (C) 2020 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/>. + +*/ + + +#include "wx/dir_picker_ctrl.h" +#include "wx/editable_list.h" +#include "wx/wx_signal_manager.h" +#include "lib/combine_dcp_job.h" +#include "lib/config.h" +#include "lib/cross.h" +#include "lib/job_manager.h" +#include "lib/util.h" +#include <dcp/combine.h> +DCPOMATIC_DISABLE_WARNINGS +#include <wx/filepicker.h> +DCPOMATIC_ENABLE_WARNINGS +#include <wx/wx.h> +#include <boost/bind.hpp> +#include <boost/filesystem.hpp> +#include <exception> + + +using std::exception; +using std::string; +using std::vector; +using boost::dynamic_pointer_cast; +using boost::optional; +using boost::shared_ptr; + + +static string +display_string (boost::filesystem::path p, int) +{ + return p.filename().string(); +} + + +class DirDialogWrapper : public wxDirDialog +{ +public: + DirDialogWrapper (wxWindow* parent) + : wxDirDialog (parent, _("Choose a DCP folder"), wxT(""), wxDD_DIR_MUST_EXIST) + { + + } + + boost::filesystem::path get () const + { + return boost::filesystem::path(wx_to_std(GetPath())); + } + + void set (boost::filesystem::path) + { + /* Not used */ + } +}; + + +class DOMFrame : public wxFrame +{ +public: + explicit DOMFrame (wxString const & title) + : wxFrame (0, -1, title) + { + /* Use a panel as the only child of the Frame so that we avoid + the dark-grey background on Windows. + */ + wxPanel* overall_panel = new wxPanel (this); + wxSizer* s = new wxBoxSizer (wxHORIZONTAL); + s->Add (overall_panel, 1, wxEXPAND); + SetSizer (s); + + vector<EditableListColumn> columns; + columns.push_back(EditableListColumn(_("Input DCP"), 600, true)); + + _input = new EditableList<boost::filesystem::path, DirDialogWrapper>( + overall_panel, + columns, + boost::bind(&DOMFrame::inputs, this), + boost::bind(&DOMFrame::set_inputs, this, _1), + &display_string, + false, + true + ); + + wxBoxSizer* output = new wxBoxSizer (wxHORIZONTAL); + add_label_to_sizer (output, overall_panel, _("Output DCP folder"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL); + _output = new DirPickerCtrl (overall_panel); + output->Add (_output, 1, wxEXPAND); + + _combine = new Button (overall_panel, _("Combine")); + + wxBoxSizer* sizer = new wxBoxSizer (wxVERTICAL); + sizer->Add (_input, 1, wxALL | wxEXPAND, DCPOMATIC_DIALOG_BORDER); + sizer->Add (output, 0, wxALL | wxEXPAND, DCPOMATIC_DIALOG_BORDER); + sizer->Add (_combine, 0, wxALL | wxALIGN_RIGHT, DCPOMATIC_DIALOG_BORDER); + overall_panel->SetSizer (sizer); + Fit (); + SetSize (768, GetSize().GetHeight() + 32); + + _combine->Bind (wxEVT_BUTTON, boost::bind(&DOMFrame::combine, this)); + _output->Bind (wxEVT_DIRPICKER_CHANGED, boost::bind(&DOMFrame::setup_sensitivity, this)); + + setup_sensitivity (); + } + +private: + void set_inputs (vector<boost::filesystem::path> inputs) + { + _inputs = inputs; + } + + vector<boost::filesystem::path> inputs () const + { + return _inputs; + } + + void combine () + { + boost::filesystem::path const output = wx_to_std(_output->GetPath()); + + if (boost::filesystem::is_directory(output) && !boost::filesystem::is_empty(output)) { + if (!confirm_dialog ( + this, + std_to_wx ( + String::compose(wx_to_std(_("The directory %1 already exists and is not empty. " + "Are you sure you want to use it?")), + output.string()) + ) + )) { + return; + } + } else if (boost::filesystem::is_regular_file(output)) { + error_dialog ( + this, + String::compose (wx_to_std(_("%1 already exists as a file, so you cannot use it for a DCP.")), output.string()) + ); + return; + } + + JobManager* jm = JobManager::instance (); + jm->add (shared_ptr<Job>(new CombineDCPJob(_inputs, output))); + bool const ok = display_progress (_("DCP-o-matic Combine"), _("Combining DCPs")); + if (!ok) { + return; + } + + DCPOMATIC_ASSERT (!jm->get().empty()); + shared_ptr<CombineDCPJob> last = dynamic_pointer_cast<CombineDCPJob> (jm->get().back()); + DCPOMATIC_ASSERT (last); + + if (last->finished_ok()) { + message_dialog (this, _("DCPs combined successfully.")); + } else { + wxString m = std_to_wx(last->error_summary()); + if (!last->error_details().empty()) { + m += wxString::Format(" (%s)", std_to_wx(last->error_details())); + } + error_dialog (this, m); + } + } + + void setup_sensitivity () + { + _combine->Enable (!_output->GetPath().IsEmpty()); + } + + EditableList<boost::filesystem::path, DirDialogWrapper>* _input; + DirPickerCtrl* _output; + vector<boost::filesystem::path> _inputs; + Button* _combine; +}; + + +class App : public wxApp +{ +public: + App () + : _frame (0) + {} + + bool OnInit () + { + try { + Config::FailedToLoad.connect (boost::bind (&App::config_failed_to_load, this)); + Config::Warning.connect (boost::bind (&App::config_warning, this, _1)); + + SetAppName (_("DCP-o-matic Combiner")); + + if (!wxApp::OnInit()) { + return false; + } + +#ifdef DCPOMATIC_LINUX + unsetenv ("UBUNTU_MENUPROXY"); +#endif + +#ifdef DCPOMATIC_OSX + make_foreground_application (); +#endif + + dcpomatic_setup_path_encoding (); + + /* 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 DCP Combiner")); + SetTopWindow (_frame); + + _frame->Show (); + + signal_manager = new wxSignalManager (this); + Bind (wxEVT_IDLE, boost::bind(&App::idle, this, _1)); + } + catch (exception& e) + { + error_dialog (0, wxString::Format ("DCP-o-matic DCP Combiner could not start."), std_to_wx(e.what())); + return false; + } + + return true; + } + + void config_failed_to_load () + { + message_dialog (_frame, _("The existing configuration failed to load. Default values will be used instead. These may take a short time to create.")); + } + + void config_warning (string m) + { + message_dialog (_frame, std_to_wx(m)); + } + + void idle (wxIdleEvent& ev) + { + signal_manager->ui_idle (); + ev.Skip (); + } + + void report_exception () + { + try { + throw; + } catch (FileError& e) { + error_dialog ( + 0, + 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 (exception& e) { + error_dialog ( + 0, + wxString::Format ( + _("An exception occurred: %s.\n\n") + REPORT_PROBLEM, + std_to_wx (e.what ()) + ) + ); + } catch (...) { + error_dialog (0, _("An unknown exception occurred.") + " " + REPORT_PROBLEM); + } + } + + bool OnExceptionInMainLoop () + { + report_exception (); + /* This will terminate the program */ + return false; + } + + void OnUnhandledException () + { + report_exception (); + } + + DOMFrame* _frame; +}; + +IMPLEMENT_APP (App) diff --git a/src/tools/wscript b/src/tools/wscript index 7eeeecddf..9caa84e9b 100644 --- a/src/tools/wscript +++ b/src/tools/wscript @@ -1,5 +1,5 @@ # -# Copyright (C) 2012-2015 Carl Hetherington <cth@carlh.net> +# Copyright (C) 2012-2020 Carl Hetherington <cth@carlh.net> # # This file is part of DCP-o-matic. # @@ -73,7 +73,7 @@ def build(bld): elif bld.env.VARIANT == 'swaroop-studio': gui_tools = ['dcpomatic', 'dcpomatic_batch', 'dcpomatic_server', 'dcpomatic_kdm', 'dcpomatic_player', 'swaroop_dcpomatic_playlist'] else: - gui_tools = ['dcpomatic', 'dcpomatic_batch', 'dcpomatic_server', 'dcpomatic_kdm', 'dcpomatic_player', 'dcpomatic_playlist'] + gui_tools = ['dcpomatic', 'dcpomatic_batch', 'dcpomatic_server', 'dcpomatic_kdm', 'dcpomatic_player', 'dcpomatic_playlist', 'dcpomatic_combiner'] if bld.env.ENABLE_DISK: gui_tools.append('dcpomatic_disk') |
