Merge master.
authorCarl Hetherington <cth@carlh.net>
Tue, 9 Jul 2013 19:35:39 +0000 (20:35 +0100)
committerCarl Hetherington <cth@carlh.net>
Tue, 9 Jul 2013 19:35:39 +0000 (20:35 +0100)
54 files changed:
ChangeLog
cscript
platform/linux/control-12.04-32
platform/linux/control-12.04-64
platform/linux/control-12.10-32
platform/linux/control-12.10-64
platform/linux/control-13.04-32 [new file with mode: 0644]
platform/linux/control-13.04-64 [new file with mode: 0644]
platform/osx/make_dmg.sh
platform/osx/waf
platform/windows/installer.nsi.32.in
platform/windows/installer.nsi.64.in
run/dvdomatic-osx [new file with mode: 0755]
run/makedcp-osx
run/tests
src/lib/combiner.cc [new file with mode: 0644]
src/lib/config.cc
src/lib/cross.cc
src/lib/cross.h
src/lib/encoder.cc
src/lib/ffmpeg_decoder.cc
src/lib/film.cc
src/lib/film.h
src/lib/ratio.h
src/lib/trimmer.cc [new file with mode: 0644]
src/lib/util.h
src/lib/version.h
src/lib/writer.cc
src/lib/wscript
src/tools/dcpomatic.cc
src/tools/dcpomatic_cli.cc
src/tools/wscript
src/wx/about_dialog.cc
src/wx/audio_dialog.cc
src/wx/config_dialog.cc
src/wx/config_dialog.h
src/wx/dci_metadata_dialog.cc
src/wx/film_editor.cc
src/wx/film_editor.h
src/wx/gain_calculator_dialog.cc
src/wx/imagemagick_content_dialog.cc
src/wx/job_manager_view.cc
src/wx/new_film_dialog.cc
src/wx/new_film_dialog.h
src/wx/properties_dialog.cc
src/wx/server_dialog.cc
src/wx/timecode.cc
src/wx/wscript
src/wx/wx_util.cc
src/wx/wx_util.h
test/test.cc
test/trimmer_test.cc [new file with mode: 0644]
test/wscript
wscript

index f412c2e90028fce8b43ed84847500c42e741bb47..a6dc6585801e949b77ffe76b801df7ea85e65896 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,102 @@
+2013-07-08  Carl Hetherington  <cth@carlh.net>
+
+       * Version 0.108 released.
+
+2013-07-08  Carl Hetherington  <cth@carlh.net>
+
+       * Add option to pad sound so that silent channels
+       can be added.
+
+2013-07-08  Carl Hetherington  <cth@carlh.net>
+
+       * Version 0.107 released.
+
+2013-07-06  Carl Hetherington  <cth@carlh.net>
+
+       * Various tweaks to layout, trying to make
+       it more consistent and better looking
+       (especially on OS X).
+
+2013-07-04  Carl Hetherington  <cth@carlh.net>
+
+       * Version 0.107beta1 released.
+
+2013-07-04  Carl Hetherington  <cth@carlh.net>
+
+       * Try to initialise the number of threads to the number
+       of cores in the machine (#170).
+
+       * Pass _FILE_OFFSET_BITS=64 so that fopen() doesn't refuse
+       to open files of >2GB; fixes failure to re-start jobs
+       where the MXF has grown larger than 2GB on 32-bit machines.
+
+2013-07-01  Carl Hetherington  <cth@carlh.net>
+
+       * Version 0.106 released.
+
+2013-07-01  Carl Hetherington  <cth@carlh.net>
+
+       * Version 0.106beta1 released.
+
+2013-06-28  Carl Hetherington  <cth@carlh.net>
+
+       * Version 0.105 released.
+
+2013-06-28  Carl Hetherington  <cth@carlh.net>
+
+       * Work around GTK bugs related to the directory
+       picker (in the new film dialogue).  There is a
+       buggy GTK included in Ubuntu 13.04 (and Mint 15).
+
+2013-06-27  Carl Hetherington  <cth@carlh.net>
+
+       * Version 0.104 released.
+
+2013-06-27  Carl Hetherington  <cth@carlh.net>
+
+       * Hopefully fix problems with end-trim not working.
+
+2013-06-24  Carl Hetherington  <cth@carlh.net>
+
+       * Version 0.103 released.
+
+2013-06-20  Carl Hetherington  <cth@carlh.net>
+
+       * Version 0.102 released.
+
+2013-06-19  Carl Hetherington  <cth@carlh.net>
+
+       * Version 0.101 released.
+
+2013-06-19  Carl Hetherington  <cth@carlh.net>
+
+       * Version 0.101beta5 released.
+
+2013-06-19  Carl Hetherington  <cth@carlh.net>
+
+       * Fix hang when there are problems decoding
+       audio.
+
+2013-06-19  Carl Hetherington  <cth@carlh.net>
+
+       * Version 0.101beta4 released.
+
+2013-06-19  Carl Hetherington  <cth@carlh.net>
+
+       * Version 0.101beta3 released.
+
+2013-06-19  Carl Hetherington  <cth@carlh.net>
+
+       * Version 0.101beta2 released.
+
+2013-06-19  Carl Hetherington  <cth@carlh.net>
+
+       * Version 0.101beta1 released.
+
+2013-06-14  Carl Hetherington  <cth@carlh.net>
+
+       * Version 0.100 released.
+
 2013-06-13  Carl Hetherington  <cth@carlh.net>
 
        * Fix ffmpeg's pixel format 13.
diff --git a/cscript b/cscript
index c51f3a033fb3aa22e54cc998e52e85da62858291..e7ef219d4b24f233413010d2e4462b361043ebf8 100644 (file)
--- a/cscript
+++ b/cscript
@@ -6,33 +6,32 @@ def dependencies(target):
     if target.platform == 'windows':
         return ()
     else:
-        return (('openjpeg-cdist', None),
-                ('libcxml', None),
-                ('ffmpeg-cdist', '7a23ec9c771184ab563cfe24ad9b427f38368961'),
-                ('libdcp', None))
+       # XXX: should be some versions in here
+        return (('ffmpeg-cdist', 'e797834288eaf05a2f406524ae04aaa0f114cb08'),
+                ('libdcp', 'v0.54'))
 
-def build(env, target):
-    cmd = './waf configure --prefix=%s' % env.work_dir_cscript()
+def build(target):
+    cmd = './waf configure --prefix=%s' % target.work_dir_cscript()
     if target.platform == 'windows':
         cmd += ' --target-windows'
     elif target.platform == 'linux':
         cmd += ' --static'
-    env.command(cmd)
+    target.command(cmd)
 
-    env.command('./waf')
+    target.command('./waf')
 
     if target.platform == 'linux' or target.platform == 'osx':
-        env.command('./waf install')
+        target.command('./waf install')
 
 
-def package(env, target, version):
+def package(target, version):
     if target.platform == 'windows':
         shutil.copyfile('build/platform/windows/installer.%s.nsi' % target.bits, 'build/platform/windows/installer2.%s.nsi' % target.bits)
-        env.command('sed -i "s~%%resources%%~%s/platform/windows~g" build/platform/windows/installer2.%s.nsi' % (os.getcwd(), target.bits))
-        env.command('sed -i "s~%%deps%%~%s~g" build/platform/windows/installer2.%s.nsi' % (env.windows_prefix, target.bits))
-        env.command('sed -i "s~%%binaries%%~%s/build~g" build/platform/windows/installer2.%s.nsi' % (os.getcwd(), target.bits))
-        env.command('sed -i "s~%%bits%%~32~g" build/platform/windows/installer2.%s.nsi' % target.bits)
-        env.command('makensis build/platform/windows/installer2.%s.nsi' % target.bits)
+        target.command('sed -i "s~%%resources%%~%s/platform/windows~g" build/platform/windows/installer2.%s.nsi' % (os.getcwd(), target.bits))
+        target.command('sed -i "s~%%deps%%~%s~g" build/platform/windows/installer2.%s.nsi' % (target.windows_prefix, target.bits))
+        target.command('sed -i "s~%%binaries%%~%s/build~g" build/platform/windows/installer2.%s.nsi' % (os.getcwd(), target.bits))
+        target.command('sed -i "s~%%bits%%~32~g" build/platform/windows/installer2.%s.nsi' % target.bits)
+        target.command('makensis build/platform/windows/installer2.%s.nsi' % target.bits)
         return os.path.abspath(glob.glob('build/platform/windows/*%s*.exe' % target.bits)[0])
     elif target.platform == 'linux':
         if target.bits == 32:
@@ -41,7 +40,7 @@ def package(env, target, version):
             cpu = 'amd64'
 
         shutil.copyfile('platform/linux/control-%s-%d' % (target.version, target.bits), 'debian/control')
-        env.command('./waf dist')
+        target.command('./waf dist')
         f = open('debian/files', 'w')
         print >>f,'dcpomatic_%s-1_%s.deb video extra' % (version, cpu)
         shutil.rmtree('build/deb', ignore_errors=True)
@@ -49,13 +48,13 @@ def package(env, target, version):
         os.makedirs('build/deb')
         os.chdir('build/deb')
         shutil.move('../../dcpomatic-%s.tar.bz2' % version, 'dcpomatic_%s.orig.tar.bz2' % version)
-        env.command('tar xjf dcpomatic_%s.orig.tar.bz2' % version)
+        target.command('tar xjf dcpomatic_%s.orig.tar.bz2' % version)
         os.chdir('dcpomatic-%s' % version)
-        env.command('dch -b -v %s-1 "New upstream release."' % version)
-        env.set('CDIST_LINKFLAGS', env.get('LINKFLAGS'))
-        env.set('CDIST_CXXFLAGS', env.get('CXXFLAGS'))
-        env.set('CDIST_PKG_CONFIG_PATH', env.get('PKG_CONFIG_PATH'))
-        env.command('dpkg-buildpackage')
+        target.command('dch -b -v %s-1 "New upstream release."' % version)
+        target.set('CDIST_LINKFLAGS', target.get('LINKFLAGS'))
+        target.set('CDIST_CXXFLAGS', target.get('CXXFLAGS'))
+        target.set('CDIST_PKG_CONFIG_PATH', target.get('PKG_CONFIG_PATH'))
+        target.command('dpkg-buildpackage')
         
         debs = []
         for p in glob.glob('../*.deb'):
@@ -63,16 +62,16 @@ def package(env, target, version):
 
         return debs
     elif target.platform == 'osx':
-        env.command('bash platform/osx/make_dmg.sh')
+        target.command('bash platform/osx/make_dmg.sh')
         return os.path.abspath(glob.glob('build/platform/osx/DVD-o-matic*.dmg')[0])
 
-def make_pot(env):
-    env.command('./waf pot')
+def make_pot(target):
+    target.command('./waf pot')
     return [os.path.abspath('build/src/lib/libdcpomatic.pot'),
             os.path.abspath('build/src/wx/libdcpomatic-wx.pot'),
            os.path.abspath('build/src/tools/dcpomatic.pot')]
 
-def make_manual(env):
+def make_manual(target):
     os.chdir('doc/manual')
-    env.command('make')
+    target.command('make')
     return [os.path.abspath('pdf'), os.path.abspath('html')]
index dc104958ac13e633d6c81d1d80354305d3b26184..a337944c3a2ab060d7aa804f7db42cbf86be4942 100644 (file)
@@ -2,13 +2,13 @@ Source: dcpomatic
 Section: video
 Priority: extra
 Maintainer: Carl Hetherington <cth@carlh.net>
-Build-Depends: debhelper (>= 8.0.0), python (>= 2.7.3), g++ (>= 4:4.6.3), pkg-config (>= 0.26), libwxgtk2.8-dev (>= 2.8.12.1), libssh-dev (>= 0.5.2), libboost-filesystem-dev (>= 1.46.0), libboost-thread-dev (>= 1.46.0), libsndfile1-dev (>= 1.0.25), libmagick++-dev (>= 8:6.6.9.7)
+Build-Depends: debhelper (>= 8.0.0), python (>= 2.7.3), g++ (>= 4:4.6.3), pkg-config (>= 0.26), libssh-dev (>= 0.5.2), libboost-filesystem-dev (>= 1.46.0), libboost-thread-dev (>= 1.46.0), libsndfile1-dev (>= 1.0.25), libmagick++-dev (>= 8:6.6.9.7), libgtk2.0-dev (>= 2.24.10)
 Standards-Version: 3.9.3
 Homepage: http://carlh.net/software/dcpomatic
 
 Package: dcpomatic
 Architecture: i386
-Depends: libc6 (>= 2.15), libwxgtk2.8-0 (>= 2.8.12.1), libssh-4 (>= 0.5.2), libboost-filesystem1.46.1 (>= 1.46.1), libboost-thread1.46.1 (>= 1.46.1), libsndfile1 (>= 1.0.25), libmagick++4 (>= 8:6.6.9.7), libxml++2.6-2 (>= 2.34.1)
+Depends: libc6 (>= 2.15), libssh-4 (>= 0.5.2), libboost-filesystem1.46.1 (>= 1.46.1), libboost-thread1.46.1 (>= 1.46.1), libsndfile1 (>= 1.0.25), libmagick++4 (>= 8:6.6.9.7), libxml++2.6-2 (>= 2.34.1), libgtk2.0-0 (>= 2.24.10)
 Description: Generator of Digital Cinema Packages (DCPs)
   DCP-o-matic generates Digital Cinema Packages (DCPs) from video and audio
   files (such as those from DVDs or Blu-Rays) for presentation on DCI-compliant
index 09c636e4aca9021a7d6ed8e3ec21aa2d13af4c9d..c2cfdf5d7a04150e4a17e965c8ad05653a4bcc30 100644 (file)
@@ -2,7 +2,7 @@ Source: dcpomatic
 Section: video
 Priority: extra
 Maintainer: Carl Hetherington <cth@carlh.net>
-Build-Depends: debhelper (>= 8.0.0), python (>= 2.7.3), g++ (>= 4:4.6.3), pkg-config (>= 0.26), libwxgtk2.8-dev (>= 2.8.12.1), libssh-dev (>= 0.5.2), libboost-filesystem-dev (>= 1.46.0), libboost-thread-dev (>= 1.46.0), libsndfile1-dev (>= 1.0.25), libmagick++-dev (>= 8:6.6.9.7)
+Build-Depends: debhelper (>= 8.0.0), python (>= 2.7.3), g++ (>= 4:4.6.3), pkg-config (>= 0.26), libssh-dev (>= 0.5.2), libboost-filesystem-dev (>= 1.46.0), libboost-thread-dev (>= 1.46.0), libsndfile1-dev (>= 1.0.25), libmagick++-dev (>= 8:6.6.9.7), libgtk2.0-dev (>= 2.4.10)
 Standards-Version: 3.9.3
 Homepage: http://carlh.net/software/dcpomatic
 
index 1330b3e5fe470e938edba26e2f52f9ca3ece6bff..14dc5a0dc4907d251c9df6bc18b260c2dcccb71e 100644 (file)
@@ -2,13 +2,13 @@ Source: dcpomatic
 Section: video
 Priority: extra
 Maintainer: Carl Hetherington <cth@carlh.net>
-Build-Depends: debhelper (>= 8.0.0), python (>= 2.7.3), g++ (>= 4:4.6.3), pkg-config (>= 0.26), libwxgtk2.8-dev (>= 2.8.12.1), libssh-dev (>= 0.5.2), libboost-filesystem-dev (>= 1.46.0), libboost-thread-dev (>= 1.46.0), libsndfile1-dev (>= 1.0.25), libmagick++-dev (>= 8:6.6.9.7)
+Build-Depends: debhelper (>= 8.0.0), python (>= 2.7.3), g++ (>= 4:4.6.3), pkg-config (>= 0.26), libssh-dev (>= 0.5.2), libboost-filesystem-dev (>= 1.46.0), libboost-thread-dev (>= 1.46.0), libsndfile1-dev (>= 1.0.25), libmagick++-dev (>= 8:6.6.9.7), libgtk2.0-dev (>= 2.24.13)
 Standards-Version: 3.9.3
 Homepage: http://carlh.net/software/dcpomatic
 
 Package: dcpomatic
 Architecture: i386
-Depends: libc6 (>= 2.15), libwxgtk2.8-0 (>= 2.8.12.1), libssh-4 (>= 0.5.2), libboost-filesystem1.49.0 (>= 1.49.0), libboost-thread1.49.0 (>= 1.49.0), libsndfile1 (>= 1.0.25), libmagick++5 (>= 8:6.7.7.10), libxml++2.6-2 (>= 2.34.2)
+Depends: libc6 (>= 2.15), libssh-4 (>= 0.5.2), libboost-filesystem1.49.0 (>= 1.49.0), libboost-thread1.49.0 (>= 1.49.0), libsndfile1 (>= 1.0.25), libmagick++5 (>= 8:6.7.7.10), libxml++2.6-2 (>= 2.34.2), libgtk2.0-0 (>= 2.24.13)
 Description: Generator of Digital Cinema Packages (DCPs)
   DCP-o-matic generates Digital Cinema Packages (DCPs) from video and audio
   files (such as those from DVDs or Blu-Rays) for presentation on DCI-compliant
index ea1c491ed8a3ebc785596f599b3e12d5f70f41f1..8a8019f013e3db3303db8a01b5a1cae129c2b7a0 100644 (file)
@@ -2,13 +2,13 @@ Source: dcpomatic
 Section: video
 Priority: extra
 Maintainer: Carl Hetherington <cth@carlh.net>
-Build-Depends: debhelper (>= 8.0.0), python (>= 2.7.3), g++ (>= 4:4.6.3), pkg-config (>= 0.26), libwxgtk2.8-dev (>= 2.8.12.1), libssh-dev (>= 0.5.2), libboost-filesystem-dev (>= 1.46.0), libboost-thread-dev (>= 1.46.0), libsndfile1-dev (>= 1.0.25), libmagick++-dev (>= 8:6.6.9.7)
+Build-Depends: debhelper (>= 8.0.0), python (>= 2.7.3), g++ (>= 4:4.6.3), pkg-config (>= 0.26), libssh-dev (>= 0.5.2), libboost-filesystem-dev (>= 1.46.0), libboost-thread-dev (>= 1.46.0), libsndfile1-dev (>= 1.0.25), libmagick++-dev (>= 8:6.6.9.7), libgtk2.0-dev (>= 2.24.13)
 Standards-Version: 3.9.3
 Homepage: http://carlh.net/software/dcpomatic
 
 Package: dcpomatic
 Architecture: amd64
-Depends: libc6 (>= 2.15), libwxgtk2.8-0 (>= 2.8.12.1), libssh-4 (>= 0.5.2), libboost-filesystem1.49.0 (>= 1.49.0), libboost-thread1.49.0 (>= 1.49.0), libsndfile1 (>= 1.0.25), libmagick++5 (>= 8:6.7.7.10), libxml++2.6-2 (>= 2.34.2)
+Depends: libc6 (>= 2.15), libssh-4 (>= 0.5.2), libboost-filesystem1.49.0 (>= 1.49.0), libboost-thread1.49.0 (>= 1.49.0), libsndfile1 (>= 1.0.25), libmagick++5 (>= 8:6.7.7.10), libxml++2.6-2 (>= 2.34.2), libgtk2.0-0 (>= 2.24.13)
 Description: Generator of Digital Cinema Packages (DCPs)
   DCP-o-matic generates Digital Cinema Packages (DCPs) from video and audio
   files (such as those from DVDs or Blu-Rays) for presentation on DCI-compliant
diff --git a/platform/linux/control-13.04-32 b/platform/linux/control-13.04-32
new file mode 100644 (file)
index 0000000..116e26b
--- /dev/null
@@ -0,0 +1,23 @@
+Source: dvdomatic
+Section: video
+Priority: extra
+Maintainer: Carl Hetherington <cth@carlh.net>
+Build-Depends: debhelper (>= 8.0.0), python (>= 2.7.3), g++ (>= 4:4.6.3), pkg-config (>= 0.26), libssh-dev (>= 0.5.2), libboost-filesystem-dev (>= 1.46.0), libboost-thread-dev (>= 1.46.0), libsndfile1-dev (>= 1.0.25), libmagick++-dev (>= 8:6.6.9.7), libgtk2.0-dev (>= 2.24.13)
+Standards-Version: 3.9.3
+Homepage: http://carlh.net/software/dvdomatic
+
+Package: dvdomatic
+Architecture: i386
+Depends: libc6 (>= 2.15), libssh-4 (>= 0.5.2), libboost-filesystem1.49.0 (>= 1.49.0), libboost-thread1.49.0 (>= 1.49.0), libsndfile1 (>= 1.0.25), libmagick++5 (>= 8:6.7.7.10), libxml++2.6-2 (>= 2.34.2), libgtk2.0-0 (>= 2.24.13)
+Description: Generator of Digital Cinema Packages (DCPs)
+  DVD-o-matic generates Digital Cinema Packages (DCPs) from video and audio
+  files (such as those from DVDs or Blu-Rays) for presentation on DCI-compliant
+  digital projectors.
+
+Package: dvdomatic-dbg
+Architecture: i386
+Section: debug
+Priority: extra
+Depends: ${dvdomatic:Depends}, ${misc:Depends}
+Description: debugging symbols for dvdomatic
+  This package contains the debugging symbols for dvdomatic.
diff --git a/platform/linux/control-13.04-64 b/platform/linux/control-13.04-64
new file mode 100644 (file)
index 0000000..486d1f2
--- /dev/null
@@ -0,0 +1,24 @@
+Source: dvdomatic
+Section: video
+Priority: extra
+Maintainer: Carl Hetherington <cth@carlh.net>
+Build-Depends: debhelper (>= 8.0.0), python (>= 2.7.3), g++ (>= 4:4.6.3), pkg-config (>= 0.26), libssh-dev (>= 0.5.2), libboost-filesystem-dev (>= 1.46.0), libboost-thread-dev (>= 1.46.0), libsndfile1-dev (>= 1.0.25), libmagick++-dev (>= 8:6.6.9.7), libgtk2.0-dev (>= 2.24.13)
+Standards-Version: 3.9.3
+Homepage: http://carlh.net/software/dvdomatic
+
+Package: dvdomatic
+Architecture: amd64
+Depends: libc6 (>= 2.15), libssh-4 (>= 0.5.2), libboost-filesystem1.49.0 (>= 1.49.0), libboost-thread1.49.0 (>= 1.49.0), libsndfile1 (>= 1.0.25), libmagick++5 (>= 8:6.7.7.10), libxml++2.6-2 (>= 2.34.2), libgtk2.0-0 (>= 2.24.13)
+Description: Generator of Digital Cinema Packages (DCPs)
+  DVD-o-matic generates Digital Cinema Packages (DCPs) from video and audio
+  files (such as those from DVDs or Blu-Rays) for presentation on DCI-compliant
+  digital projectors.
+
+Package: dvdomatic-dbg
+Architecture: amd64
+Section: debug
+Priority: extra
+Depends: ${dvdomatic:Depends}, ${misc:Depends}
+Description: debugging symbols for dvdomatic
+  This package contains the debugging symbols for dvdomatic.
+
index 1fcdc6d0629782eccce9aa8c7176d95ca7b30fb5..debd4aaac5a5c4af41875739b365f3d5985dce08 100644 (file)
@@ -5,8 +5,8 @@ version=`cat wscript | egrep ^VERSION | awk '{print $3}' | sed -e "s/'//g"`
 # DMG size in megabytes
 DMG_SIZE=256
 WORK=build/platform/osx
-ENV=/Users/carl/Environments/osx/10.8
-DEPS=/Users/carl/cdist
+ENV=/Users/carl/Environments/osx
+ROOT=/Users/carl/cdist
 
 appdir="DVD-o-matic.app"
 approot=$appdir/Contents
@@ -19,44 +19,56 @@ mkdir -p $WORK/$macos
 mkdir -p $WORK/$libs
 mkdir -p $WORK/$resources
 
-cp build/src/tools/dcpomatic $WORK/$macos/
-cp build/src/lib/libdcpomatic.dylib $WORK/$libs/
-cp build/src/wx/libdcpomatic-wx.dylib $WORK/$libs/
-cp $DEPS/lib/libdcp.dylib $WORK/$libs/
-cp $DEPS/lib/libasdcp-libdcp.dylib $WORK/$libs/
-cp $DEPS/lib/libkumu-libdcp.dylib $WORK/$libs/
-cp $DEPS/lib/libopenjpeg*.dylib $WORK/$libs/
-cp $DEPS/lib/libavformat*.dylib $WORK/$libs/
-cp $DEPS/lib/libavfilter*.dylib $WORK/$libs/
-cp $DEPS/lib/libavutil*.dylib $WORK/$libs/
-cp $DEPS/lib/libavcodec*.dylib $WORK/$libs/
-cp $DEPS/lib/libswscale*.dylib $WORK/$libs/
-cp $DEPS/lib/libpostproc*.dylib $WORK/$libs/
-cp $DEPS/lib/libswresample*.dylib $WORK/$libs/
-cp $ENV/lib/libboost_system.dylib $WORK/$libs/
-cp $ENV/lib/libboost_filesystem.dylib $WORK/$libs/
-cp $ENV/lib/libboost_thread.dylib $WORK/$libs/
-cp $ENV/lib/libboost_date_time.dylib $WORK/$libs/
-cp $ENV/lib/libssl*.dylib $WORK/$libs/
-cp $ENV/lib/libcrypto*.dylib $WORK/$libs/
-cp $ENV/lib/libxml++-2.6*.dylib $WORK/$libs/
-cp $ENV/lib/libxml2*.dylib $WORK/$libs/
-cp $ENV/lib/libglibmm-2.4*.dylib $WORK/$libs/
-cp $ENV/lib/libgobject*.dylib $WORK/$libs/
-cp $ENV/lib/libgthread*.dylib $WORK/$libs/
-cp $ENV/lib/libgmodule*.dylib $WORK/$libs/
-cp $ENV/lib/libsigc*.dylib $WORK/$libs/
-cp $ENV/lib/libglib-2*.dylib $WORK/$libs/
-cp $ENV/lib/libintl*.dylib $WORK/$libs/
-cp $ENV/lib/libsndfile*.dylib $WORK/$libs/
-cp $ENV/lib/libMagick++*.dylib $WORK/$libs/
-cp $ENV/lib/libMagickCore*.dylib $WORK/$libs/
-cp $ENV/lib/libMagickWand*.dylib $WORK/$libs/
-cp $ENV/lib/libssh*.dylib $WORK/$libs/
-cp $ENV/lib/libwx*.dylib $WORK/$libs/
-cp $ENV/lib/libfontconfig*.dylib $WORK/$libs/
-cp $ENV/lib/libfreetype*.dylib $WORK/$libs/
-cp $ENV/lib/libexpat*.dylib $WORK/$libs/
+function universal_copy {
+    echo $2
+    for f in $1/32/$2; do
+        if [ -h $f ]; then
+           ln -s $(readlink $f) $3/`basename $f`
+        else
+          g=`echo $f | sed -e "s/\/32\//\/64\//g"`
+         mkdir -p $3
+          lipo -create $f $g -output $3/`basename $f`
+        fi
+    done
+}
+
+universal_copy $ROOT src/dvdomatic/build/src/tools/dvdomatic $WORK/$macos
+universal_copy $ROOT src/dvdomatic/build/src/lib/libdvdomatic.dylib $WORK/$libs
+universal_copy $ROOT src/dvdomatic/build/src/wx/libdvdomatic-wx.dylib $WORK/$libs
+universal_copy $ROOT lib/libcxml.dylib $WORK/$libs
+universal_copy $ROOT lib/libdcp.dylib $WORK/$libs
+universal_copy $ROOT lib/libasdcp-libdcp.dylib $WORK/$libs
+universal_copy $ROOT lib/libkumu-libdcp.dylib $WORK/$libs
+universal_copy $ROOT lib/libopenjpeg*.dylib $WORK/$libs
+universal_copy $ROOT lib/libavformat*.dylib $WORK/$libs
+universal_copy $ROOT lib/libavfilter*.dylib $WORK/$libs
+universal_copy $ROOT lib/libavutil*.dylib $WORK/$libs
+universal_copy $ROOT lib/libavcodec*.dylib $WORK/$libs
+universal_copy $ROOT lib/libswscale*.dylib $WORK/$libs
+universal_copy $ROOT lib/libpostproc*.dylib $WORK/$libs
+universal_copy $ROOT lib/libswresample*.dylib $WORK/$libs
+universal_copy $ENV lib/libboost_system.dylib $WORK/$libs
+universal_copy $ENV lib/libboost_filesystem.dylib $WORK/$libs
+universal_copy $ENV lib/libboost_thread.dylib $WORK/$libs
+universal_copy $ENV lib/libboost_date_time.dylib $WORK/$libs
+universal_copy $ENV lib/libxml++-2.6*.dylib $WORK/$libs
+universal_copy $ENV lib/libxml2*.dylib $WORK/$libs
+universal_copy $ENV lib/libglibmm-2.4*.dylib $WORK/$libs
+universal_copy $ENV lib/libgobject*.dylib $WORK/$libs
+universal_copy $ENV lib/libgthread*.dylib $WORK/$libs
+universal_copy $ENV lib/libgmodule*.dylib $WORK/$libs
+universal_copy $ENV lib/libsigc*.dylib $WORK/$libs
+universal_copy $ENV lib/libglib-2*.dylib $WORK/$libs
+universal_copy $ENV lib/libintl*.dylib $WORK/$libs
+universal_copy $ENV lib/libsndfile*.dylib $WORK/$libs
+universal_copy $ENV lib/libMagick++*.dylib $WORK/$libs
+universal_copy $ENV lib/libMagickCore*.dylib $WORK/$libs
+universal_copy $ENV lib/libMagickWand*.dylib $WORK/$libs
+universal_copy $ENV lib/libssh*.dylib $WORK/$libs
+universal_copy $ENV lib/libwx*.dylib $WORK/$libs
+universal_copy $ENV lib/libfontconfig*.dylib $WORK/$libs
+universal_copy $ENV lib/libfreetype*.dylib $WORK/$libs
+universal_copy $ENV lib/libexpat*.dylib $WORK/$libs
 
 for obj in $WORK/$macos/dcpomatic $WORK/$libs/*.dylib; do
   deps=`otool -L $obj | awk '{print $1}' | egrep "(/Users/carl|libboost|libssh)"`
@@ -70,7 +82,6 @@ for obj in $WORK/$macos/dcpomatic $WORK/$libs/*.dylib; do
   fi  
 done
 
-pwd
 cp build/platform/osx/Info.plist $WORK/$approot
 cp icons/dcpomatic.icns $WORK/$resources/DVD-o-matic.icns
 
index 7423eb973080711ee03922b37eec011869cf800e..dda678542235f37df7af9165a81b02816d02d1c2 100755 (executable)
@@ -2,10 +2,10 @@
 
 set -e
 
-ENV=/Users/carl/Environments/osx/10.8
-DEPS=/Users/carl/cdist
+ENV=/Users/carl/Environments/osx/64
+DEPS=/Users/carl/cdist/64
 
-export PKG_CONFIG_PATH=$DEPS/lib/pkgconfig:$ENV/lib/pkgconfig
+export PKG_CONFIG_PATH=$DEPS/lib/pkgconfig:$ENV/lib/pkgconfig:/usr/lib/pkgconfig
 export LINKFLAGS="-L$ENV/lib"
 export CXXFLAGS="-I$ENV/include"
 export PATH=$PATH:$ENV/bin
index 3a2cdb9e824800600683fe441db37085a7cdbe40..314fe176ff6277edb1a9bf6e1297245b1772b47a 100644 (file)
@@ -32,6 +32,7 @@ File "%deps%/bin/avcodec-55.dll"
 File "%deps%/bin/avfilter-3.dll"
 File "%deps%/bin/avformat-55.dll"
 File "%deps%/bin/avutil-52.dll"
+File "%deps%/bin/avdevice-55.dll"
 File "%deps%/bin/dcp.dll"
 File "%deps%/bin/libintl-8.dll"
 File "%deps%/bin/kumu-libdcp.dll"
@@ -80,6 +81,7 @@ File "%deps%/bin/libfontconfig-1.dll"
 File "%deps%/bin/libexpat-1.dll"
 File "%deps%/bin/libbz2.dll"
 File "%deps%/bin/cxml.dll"
+File "%deps%/bin/ffprobe.exe"
 
 File "%binaries%/src/wx/dcpomatic-wx.dll"
 File "%binaries%/src/lib/dcpomatic.dll"
@@ -135,7 +137,6 @@ Section "Uninstall"
  
 RMDir /r "$INSTDIR\*.*"    
 RMDir "$INSTDIR"
-<<<<<<< HEAD
 Delete "$DESKTOP\DCP-o-matic.lnk"
 Delete "$DESKTOP\DCP-o-matic batch converter.lnk"
 Delete "$DESKTOP\DCP-o-matic encode server.lnk"
@@ -143,14 +144,5 @@ Delete "$SMPROGRAMS\DCP-o-matic\*.*"
 RmDir  "$SMPROGRAMS\DCP-o-matic"
 DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\DCP-o-matic"
 DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\DCP-o-matic"
-=======
-Delete "$DESKTOP\DVD-o-matic.lnk"
-Delete "$DESKTOP\DVD-o-matic batch converter.lnk"
-Delete "$DESKTOP\DVD-o-matic encode server.lnk"
-Delete "$SMPROGRAMS\DVD-o-matic\*.*"
-RmDir  "$SMPROGRAMS\DVD-o-matic"
-DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\DVD-o-matic"
-DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\DVD-o-matic"
->>>>>>> master
  
 SectionEnd
index f4f1e90684b546e121285b489137f019b02fd5a4..4bf959119579972df9d33171cbf2d26805e7dd60 100644 (file)
@@ -42,6 +42,7 @@ File "%deps%/bin/avcodec-55.dll"
 File "%deps%/bin/avfilter-3.dll"
 File "%deps%/bin/avformat-55.dll"
 File "%deps%/bin/avutil-52.dll"
+File "%deps%/bin/avdevice-55.dll"
 File "%deps%/bin/dcp.dll"
 File "%deps%/bin/libintl-8.dll"
 File "%deps%/bin/kumu-libdcp.dll"
@@ -90,6 +91,7 @@ File "%deps%/bin/libfontconfig-1.dll"
 File "%deps%/bin/libexpat-1.dll"
 File "%deps%/bin/libbz2.dll"
 File "%deps%/bin/cxml.dll"
+File "%deps%/bin/ffprobe.exe"
 
 File "%binaries%/src/wx/dcpomatic-wx.dll"
 File "%binaries%/src/lib/dcpomatic.dll"
diff --git a/run/dvdomatic-osx b/run/dvdomatic-osx
new file mode 100755 (executable)
index 0000000..8fef27f
--- /dev/null
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+export DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:build/src/lib:build/src:/Users/carl/Environments/osx/64/lib
+if [ "$1" == "--debug" ]; then
+    shift
+    gdb --args build/src/tools/dvdomatic "$*"
+elif [ "$1" == "--valgrind" ]; then
+    shift
+    valgrind --tool="memcheck" build/src/tools/dvdomatic $*
+elif [ "$1" == "--i18n" ]; then
+    shift
+    LANGUAGE=fr_FR.UTF8 LANG=fr_FR.UTF8 build/src/tools/dvdomatic "$*"
+else
+    build/src/tools/dvdomatic "$*"
+fi
index 1b95ecc5d076f3956c17b96f91c8496a95621e0d..03756f524e08055ecdf35623ddaf8490b8003019 100755 (executable)
@@ -1,6 +1,6 @@
 #!/bin/bash
 
-export DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:build/src/lib:build/src:/Users/carl/Environments/osx/10.8/lib
+export DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:build/src/lib:build/src:/Users/carl/Environments/osx/64/lib
 if [ "$1" == "--debug" ]; then
     shift
     gdb --args build/src/tools/makedcp "$@"
index e1686a55cac84eff6af6f3f06ed2b321ace805d7..e6cdf4ba84656f4b739b0c54bd3e4d5ff16a6652 100755 (executable)
--- a/run/tests
+++ b/run/tests
@@ -2,10 +2,10 @@
 
 export LD_LIBRARY_PATH=build/src/lib:$LD_LIBRARY_PATH
 if [ "$1" == "--debug" ]; then
-    gdb --args build/test/unit-tests
+    gdb --args build/test/unit-tests --catch_system_errors=no
 elif [ "$1" == "--valgrind" ]; then
     valgrind --tool="memcheck" --leak-check=full build/test/unit-tests
 else
-    build/test/unit-tests
+    build/test/unit-tests --catch_system_errors=no
 fi
 
diff --git a/src/lib/combiner.cc b/src/lib/combiner.cc
new file mode 100644 (file)
index 0000000..f7d6348
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+    Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+
+    This program 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.
+
+    This program 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 this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "combiner.h"
+#include "image.h"
+
+using boost::shared_ptr;
+
+Combiner::Combiner (shared_ptr<Log> log)
+       : TimedVideoProcessor (log)
+{
+
+}
+
+/** Process video for the left half of the frame.
+ *  Subtitle parameter will be ignored.
+ *  @param image Frame image.
+ */
+void
+Combiner::process_video (shared_ptr<const Image> image, bool, shared_ptr<Subtitle>, double)
+{
+       _image.reset (new SimpleImage (image));
+}
+
+/** Process video for the right half of the frame.
+ *  @param image Frame image.
+ *  @param sub Subtitle (which will be put onto the whole frame)
+ */
+void
+Combiner::process_video_b (shared_ptr<const Image> image, bool, shared_ptr<Subtitle> sub, double t)
+{
+       if (!_image) {
+               /* It's possible for filters in the A-side to mean that we get a B frame
+                  before any A; just skip the B frame in that case.  This at least prevents
+                  a crash, but may not be right.
+               */
+               return;
+       }
+       
+       /* Copy the right half of this image into our _image */
+       /* XXX: this should probably be in the Image class */
+       for (int i = 0; i < image->components(); ++i) {
+               int const line_size = image->line_size()[i];
+               int const half_line_size = line_size / 2;
+
+               uint8_t* p = _image->data()[i];
+               uint8_t* q = image->data()[i];
+                       
+               for (int j = 0; j < image->lines (i); ++j) {
+                       memcpy (p + half_line_size, q + half_line_size, half_line_size);
+                       p += _image->stride()[i];
+                       q += image->stride()[i];
+               }
+       }
+
+       Video (_image, false, sub, t);
+       _image.reset ();
+}
index c9ec730f20aa94c03357b56cbd9398e21698eb46..e0fbcc703f58042948cb3a1dc83aa62d58f09fe3 100644 (file)
@@ -38,6 +38,7 @@ using std::ifstream;
 using std::string;
 using std::ofstream;
 using std::list;
+using std::max;
 using boost::shared_ptr;
 using boost::lexical_cast;
 using boost::optional;
@@ -46,7 +47,7 @@ Config* Config::_instance = 0;
 
 /** Construct default configuration */
 Config::Config ()
-       : _num_local_encoding_threads (2)
+       : _num_local_encoding_threads (max (2U, boost::thread::hardware_concurrency()))
        , _server_port (6192)
        , _tms_path (N_("."))
        , _sound_processor (SoundProcessor::from_id (N_("dolby_cp750")))
index ffd44eb02810cd0107145e8a3e5eaeedb917509f..ee0ef89b2ea0c9394b53124b700605d5c703a3af 100644 (file)
 #include <fstream>
 #include <boost/algorithm/string.hpp>
 #include "cross.h"
-#ifdef DCPOMATIC_POSIX
+#include "compose.hpp"
+#include "log.h"
+#ifdef DCPOMATIC_LINUX
 #include <unistd.h>
+#include <mntent.h>
 #endif
 #ifdef DCPOMATIC_WINDOWS
-#include "windows.h"
+#include <windows.h>
+#undef DATADIR
+#include <shlwapi.h>
 #endif
 #ifdef DCPOMATIC_OSX
 #include <sys/sysctl.h>
 #endif
 
 using std::pair;
+using std::list;
 using std::ifstream;
 using std::string;
+using std::make_pair;
+using boost::shared_ptr;
 
 void
 dcpomatic_sleep (int s)
@@ -81,3 +89,101 @@ cpu_info ()
        return info;
 }
 
+void
+run_ffprobe (boost::filesystem::path content, boost::filesystem::path out, shared_ptr<Log> log)
+{
+#ifdef DCPOMATIC_WINDOWS
+       SECURITY_ATTRIBUTES security;
+       security.nLength = sizeof (security);
+       security.bInheritHandle = TRUE;
+       security.lpSecurityDescriptor = 0;
+
+       HANDLE child_stderr_read;
+       HANDLE child_stderr_write;
+       if (!CreatePipe (&child_stderr_read, &child_stderr_write, &security, 0)) {
+               log->log ("ffprobe call failed (could not CreatePipe)");
+               return;
+       }
+
+       wchar_t dir[512];
+       GetModuleFileName (GetModuleHandle (0), dir, sizeof (dir));
+       PathRemoveFileSpec (dir);
+       SetCurrentDirectory (dir);
+
+       STARTUPINFO startup_info;
+       ZeroMemory (&startup_info, sizeof (startup_info));
+       startup_info.cb = sizeof (startup_info);
+       startup_info.hStdError = child_stderr_write;
+       startup_info.dwFlags |= STARTF_USESTDHANDLES;
+
+       wchar_t command[512];
+       wcscpy (command, L"ffprobe.exe \"");
+
+       wchar_t file[512];
+       MultiByteToWideChar (CP_UTF8, 0, content.string().c_str(), -1, file, sizeof(file));
+       wcscat (command, file);
+
+       wcscat (command, L"\"");
+
+       PROCESS_INFORMATION process_info;
+       ZeroMemory (&process_info, sizeof (process_info));
+       if (!CreateProcess (0, command, 0, 0, TRUE, CREATE_NO_WINDOW, 0, 0, &startup_info, &process_info)) {
+               log->log ("ffprobe call failed (could not CreateProcess)");
+               return;
+       }
+
+       FILE* o = fopen (out.string().c_str(), "w");
+       if (!o) {
+               log->log ("ffprobe call failed (could not create output file)");
+               return;
+       }
+
+       CloseHandle (child_stderr_write);
+
+       while (1) {
+               char buffer[512];
+               DWORD read;
+               if (!ReadFile(child_stderr_read, buffer, sizeof(buffer), &read, 0) || read == 0) {
+                       break;
+               }
+               fwrite (buffer, read, 1, o);
+       }
+
+       fclose (o);
+
+       WaitForSingleObject (process_info.hProcess, INFINITE);
+       CloseHandle (process_info.hProcess);
+       CloseHandle (process_info.hThread);
+       CloseHandle (child_stderr_read);
+#else
+       string ffprobe = "ffprobe \"" + content.string() + "\" 2> \"" + out.string() + "\"";
+       log->log (String::compose ("Probing with %1", ffprobe));
+       system (ffprobe.c_str ());
+#endif 
+}
+
+list<pair<string, string> >
+mount_info ()
+{
+       list<pair<string, string> > m;
+       
+#ifdef DCPOMATIC_LINUX
+       FILE* f = setmntent ("/etc/mtab", "r");
+       if (!f) {
+               return m;
+       }
+       
+       while (1) {
+               struct mntent* mnt = getmntent (f);
+               if (!mnt) {
+                       break;
+               }
+
+               m.push_back (make_pair (mnt->mnt_dir, mnt->mnt_type));
+       }
+
+       endmntent (f);
+#endif
+
+       return m;
+}
index d185286b1f381d02395ba36261313eaac3c10432..a00fee67917c95031a038c7b14fdeec0b8d85f30 100644 (file)
 
 */
 
+#include <boost/filesystem.hpp>
+
 #ifdef DCPOMATIC_WINDOWS
 #define WEXITSTATUS(w) (w)
 #endif
 
+class Log;
+
 void dcpomatic_sleep (int);
 extern std::pair<std::string, int> cpu_info ();
+extern void run_ffprobe (boost::filesystem::path, boost::filesystem::path, boost::shared_ptr<Log>);
+extern std::list<std::pair<std::string, std::string> > mount_info ();
index c3865d2c16ebf44852cede103a97d94f93c3c022..d3181acd9b1f7df35f0224a96be318b6203f5f1d 100644 (file)
@@ -40,6 +40,7 @@ using std::stringstream;
 using std::vector;
 using std::list;
 using std::cout;
+using std::min;
 using std::make_pair;
 using boost::shared_ptr;
 using boost::optional;
index a3fdaf9b13a1f3acc013802609cbd15853d9e318..bf094913082104a1392048f2b8003daf245c825e 100644 (file)
@@ -78,9 +78,6 @@ FFmpegDecoder::FFmpegDecoder (shared_ptr<const Film> f, shared_ptr<const FFmpegC
 double
 FFmpegDecoder::compute_pts_offset (double first_video, double first_audio, float video_frame_rate)
 {
-       assert (first_video >= 0);
-       assert (first_audio >= 0);
-       
        double const old_first_video = first_video;
        
        /* Round the first video to a frame boundary */
@@ -94,6 +91,8 @@ FFmpegDecoder::compute_pts_offset (double first_video, double first_audio, float
 
 FFmpegDecoder::~FFmpegDecoder ()
 {
+       boost::mutex::scoped_lock lm (_mutex);
+
        if (_subtitle_codec_context) {
                avcodec_close (_subtitle_codec_context);
        }
@@ -370,17 +369,9 @@ FFmpegDecoder::decode_audio_packet ()
                                        }
                                }
                                        
-                               
-                               int const data_size = av_samples_get_buffer_size (
-                                       0, audio_codec_context()->channels, _frame->nb_samples, audio_sample_format (), 1
-                                       );
-                               
-                               assert (audio_codec_context()->channels == _ffmpeg_content->audio_channels());
-                               audio (deinterleave_audio (_frame->data, data_size), _audio_position);
+                               copy_packet.data += decode_result;
+                               copy_packet.size -= decode_result;
                        }
-                       
-                       copy_packet.data += decode_result;
-                       copy_packet.size -= decode_result;
                }
        }
 }
index ad565aca0b2e6bcd16717fd9f64f6d31f0ec8187..fa75ab1f1d444905dc61a0d864db5fe7a9a8cf6c 100644 (file)
@@ -101,6 +101,7 @@ Film::Film (string d)
        , _dci_metadata (Config::instance()->default_dci_metadata ())
        , _dcp_video_frame_rate (24)
        , _dcp_audio_channels (MAX_AUDIO_CHANNELS)
+       , _minimum_audio_channels (0)
        , _dirty (false)
 {
        set_dci_date_today ();
@@ -127,7 +128,6 @@ Film::Film (string d)
        }
 
        set_directory (result.string ());
-       _log.reset (new FileLog (file ("log")));
 }
 
 Film::Film (Film const & o)
@@ -149,6 +149,7 @@ Film::Film (Film const & o)
        , _dci_metadata      (o._dci_metadata)
        , _dcp_video_frame_rate (o._dcp_video_frame_rate)
        , _dci_date          (o._dci_date)
+       , _minimum_audio_channels (o._minimum_audio_channels)
        , _dirty             (o._dirty)
 {
        _playlist->ContentChanged.connect (bind (&Film::playlist_content_changed, this, _1, _2));
@@ -184,7 +185,6 @@ Film::info_dir () const
 string
 Film::internal_video_mxf_dir () const
 {
-       boost::filesystem::path p;
        return dir ("video");
 }
 
@@ -268,6 +268,10 @@ Film::make_dcp ()
 #endif
        pair<string, int> const c = cpu_info ();
        log()->log (String::compose ("CPU: %1, %2 processors", c.first, c.second));
+       list<pair<string, string> > const m = mount_info ();
+       for (list<pair<string, string> >::const_iterator i = m.begin(); i != m.end(); ++i) {
+               log()->log (String::compose ("Mount: %1 %2", i->first, i->second));
+       }
        
        if (container() == 0) {
                throw MissingSettingError (_("container"));
@@ -353,6 +357,7 @@ Film::write_metadata () const
        root->add_child("DCPVideoFrameRate")->add_child_text (lexical_cast<string> (_dcp_video_frame_rate));
        root->add_child("DCIDate")->add_child_text (boost::gregorian::to_iso_string (_dci_date));
        root->add_child("DCPAudioChannels")->add_child_text (lexical_cast<string> (_dcp_audio_channels));
+       root->add_child("MinimumAudioChannels")->add_child_text (lexical_cast<string> (_minimum_audio_channels));
        _playlist->as_xml (root->add_child ("Playlist"));
 
        doc.write_to_file_formatted (file ("metadata.xml"));
@@ -400,6 +405,7 @@ Film::read_metadata ()
        _dcp_video_frame_rate = f.number_child<int> ("DCPVideoFrameRate");
        _dci_date = boost::gregorian::from_undelimited_string (f.string_child ("DCIDate"));
        _dcp_audio_channels = f.number_child<int> ("DCPAudioChannels");
+       _minimum_audio_channels = f.number_child<int> ("MinimumAudioChannels");
 
        _playlist->set_from_xml (shared_from_this(), f.node_child ("Playlist"));
 
@@ -641,6 +647,16 @@ Film::set_dci_metadata (DCIMetadata m)
 }
 
 
+void
+Film::set_minimum_audio_channels (int c)
+{
+       {
+               boost::mutex::scoped_lock lm (_state_mutex);
+               _minimum_audio_channels = c;
+       }
+       signal_changed (MINIMUM_AUDIO_CHANNELS);
+}
+                       
 void
 Film::set_dcp_video_frame_rate (int f)
 {
index 5bb9acf297be8091ef7db70934eed336aa657c39..f5a7c1246c38c2f133f8d82044be6531b26662f8 100644 (file)
@@ -141,6 +141,7 @@ public:
                J2K_BANDWIDTH,
                DCI_METADATA,
                DCP_VIDEO_FRAME_RATE,
+               MINIMUM_AUDIO_CHANNELS
        };
 
 
@@ -217,6 +218,11 @@ public:
                return _dcp_audio_channels;
        }
 
+       int minimum_audio_channels () const {
+               boost::mutex::scoped_lock lm (_state_mutex);
+               return _minimum_audio_channels;
+       }
+
        /* SET */
 
        void set_directory (std::string);
@@ -236,6 +242,7 @@ public:
        void set_dci_metadata (DCIMetadata);
        void set_dcp_video_frame_rate (int);
        void set_dci_date_today ();
+       void set_minimum_audio_channels (int);
 
        /** Emitted when some property has of the Film has changed */
        mutable boost::signals2::signal<void (Property)> Changed;
@@ -298,6 +305,7 @@ private:
        /** The date that we should use in a DCI name */
        boost::gregorian::date _dci_date;
        int _dcp_audio_channels;
+       int _minimum_audio_channels;
 
        /** true if our state has changed since we last saved it */
        mutable bool _dirty;
index 6916a74912cdaa5c9c322312e867747b40d9f700..5480eee124929b9f99239ea536a909a73ffdfe42 100644 (file)
@@ -17,6 +17,9 @@
 
 */
 
+#ifndef DCPOMATIC_RATIO_H
+#define DCPOMATIC_RATIO_H
+
 #include <vector>
 #include <libdcp/util.h>
 
@@ -64,3 +67,5 @@ private:
 
        static std::vector<Ratio const *> _ratios;      
 };
+
+#endif
diff --git a/src/lib/trimmer.cc b/src/lib/trimmer.cc
new file mode 100644 (file)
index 0000000..99f0479
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+    Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+
+    This program 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.
+
+    This program 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 this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <boost/shared_ptr.hpp>
+#include <stdint.h>
+#include "trimmer.h"
+
+using std::cout;
+using std::max;
+using boost::shared_ptr;
+
+/** @param audio_sample_rate Audio sampling rate, or 0 if there is no audio */
+Trimmer::Trimmer (
+       shared_ptr<Log> log,
+       int video_trim_start,
+       int video_trim_end,
+       int video_length,
+       int audio_sample_rate,
+       float frames_per_second,
+       int dcp_frames_per_second
+       )
+       : AudioVideoProcessor (log)
+       , _video_start (video_trim_start)
+       , _video_end (video_length - video_trim_end)
+       , _video_in (0)
+       , _audio_in (0)
+{
+       FrameRateConversion frc (frames_per_second, dcp_frames_per_second);
+
+       if (frc.skip) {
+               _video_start /= 2;
+               _video_end /= 2;
+       } else if (frc.repeat) {
+               _video_start *= 2;
+               _video_end *= 2;
+       }
+
+       if (audio_sample_rate) {
+               _audio_start = video_frames_to_audio_frames (_video_start, audio_sample_rate, frames_per_second);
+               _audio_end = video_frames_to_audio_frames (_video_end, audio_sample_rate, frames_per_second);
+       }
+
+       /* XXX: this is a hack; if there is no trim at the end, set
+          the audio end point to infinity so that
+          shorter-video-than-audio does not trim audio (which breaks
+          the current set of regression tests).  This could be
+          removed if a) the regression tests are regenerated and b) I
+          can work out what DCP length should be.
+
+          There is also a problem whereby black video frames inserted
+          at the start of the output by the matcher are not taken into account,
+          so if black frames are inserted it means more gets trimmed off the
+          end than should be.  Hack around this in similar fashion with the
+          _video_end = INT_MAX line.
+       */
+       if (video_trim_end == 0) {
+               _video_end = INT_MAX;
+               _audio_end = INT64_MAX;
+       }
+}
+
+void
+Trimmer::process_video (shared_ptr<const Image> image, bool same, shared_ptr<Subtitle> sub)
+{
+       if (_video_in >= _video_start && _video_in < _video_end) {
+               Video (image, same, sub);
+       }
+       
+       ++_video_in;
+}
+
+void
+Trimmer::process_audio (shared_ptr<const AudioBuffers> audio)
+{
+       int64_t offset = _audio_start - _audio_in;
+       if (offset > audio->frames()) {
+               /* we haven't reached the start of the untrimmed section yet */
+               _audio_in += audio->frames ();
+               return;
+       }
+
+       if (offset < 0) {
+               offset = 0;
+       }
+
+       int64_t length = _audio_end - max (_audio_in, _audio_start);
+       if (length < 0) {
+               _audio_in += audio->frames ();
+               return;
+       }
+
+       if (length > (audio->frames() - offset)) {
+               length = audio->frames () - offset;
+       }
+
+       _audio_in += audio->frames ();
+       
+       if (offset != 0 || length != audio->frames ()) {
+               shared_ptr<AudioBuffers> copy (new AudioBuffers (audio));
+               copy->move (offset, 0, length);
+               copy->set_frames (length);
+               audio = copy;
+       }
+       
+       Audio (audio);
+}
+
index c68bb4f1619614b29e91b9ceb7f45c88898547b1..7af8ffedf27b07e357011bfaa467c6b8a0eb9ff5 100644 (file)
@@ -52,6 +52,7 @@ extern "C" {
 #define MAX_AUDIO_CHANNELS 6
 
 class Scaler;
+class Film;
 
 extern std::string seconds_to_hms (int);
 extern std::string time_to_hms (Time);
index 518862fc472082f77a21bbe974696df57c1d4766..b70be8343ec11b4fe86bc9e16c74b6604f5d3fa1 100644 (file)
@@ -1,3 +1,4 @@
 
 extern char const * dcpomatic_version;
 extern char const * dcpomatic_git_commit;
+extern char const * dcpomatic_cxx_flags;
index cf81d5b70a8e4a902a697a7b94899b2a20f52a7a..cbb84a94019bc0a97fc67abf14e05545ccaf4675 100644 (file)
@@ -18,6 +18,7 @@
 */
 
 #include <fstream>
+#include <cerrno>
 #include <libdcp/picture_asset.h>
 #include <libdcp/sound_asset.h>
 #include <libdcp/picture_frame.h>
@@ -342,8 +343,9 @@ Writer::check_existing_picture_mxf ()
        boost::filesystem::path p;
        p /= _film->internal_video_mxf_dir ();
        p /= _film->internal_video_mxf_filename ();
-       FILE* mxf = fopen (p.string().c_str(), N_("rb"));
+       FILE* mxf = fopen (p.string().c_str(), "rb");
        if (!mxf) {
+               _film->log()->log (String::compose ("Could not open existing MXF at %1 (errno=%2)", p.string(), errno));
                return;
        }
 
index 3e7f2e33be88ada8822bfd2b8e5312f02f1173cb..2f86539841da3efade020391e8b9a97aeb8972a6 100644 (file)
@@ -73,7 +73,7 @@ def build(bld):
     obj.source = sources + ' version.cc'
 
     if bld.env.TARGET_WINDOWS:
-        obj.uselib += ' WINSOCK2 BFD DBGHELP IBERTY'
+        obj.uselib += ' WINSOCK2 BFD DBGHELP IBERTY SHLWAPI'
         obj.source += ' stack.cpp'
     if bld.env.STATIC:
         obj.uselib += ' XML++'
index 683e60ceb2b930e56b23c492ac889d23a4dca38b..ac39d4fedb823ccdf76c83de4f35f5cd04871dfc 100644 (file)
@@ -163,7 +163,7 @@ setup_menu (wxMenuBar* m)
        add_item (file, _("&Properties..."), ID_file_properties, NEEDS_FILM);
 #ifndef __WXOSX__      
        file->AppendSeparator ();
-#endif 
+#endif
        add_item (file, _("&Exit"), wxID_EXIT, ALWAYS);
 
 #ifdef __WXOSX__       
index 8623d919468ab3f95d7e2230000a2cc7e667c2f4..ee9e2cdc08fddc0746bd08f5afbdef63745e4f7f 100644 (file)
@@ -47,6 +47,7 @@ help (string n)
             << "  -v, --version      show DCP-o-matic version\n"
             << "  -h, --help         show this help\n"
             << "  -d, --deps         list DCP-o-matic dependency details and quit\n"
+            << "  -f, --flags        show flags passed to C++ compiler on build\n"
             << "  -n, --no-progress  do not print progress to stdout\n"
             << "  -r, --no-remote    do not use any remote servers\n"
             << "\n"
@@ -67,13 +68,14 @@ main (int argc, char* argv[])
                        { "version", no_argument, 0, 'v'},
                        { "help", no_argument, 0, 'h'},
                        { "deps", no_argument, 0, 'd'},
+                       { "flags", no_argument, 0, 'f'},
                        { "no-progress", no_argument, 0, 'n'},
                        { "no-remote", no_argument, 0, 'r'},
                        { "log-level", required_argument, 0, 'l' },
                        { 0, 0, 0, 0 }
                };
 
-               int c = getopt_long (argc, argv, "vhdnrl:", long_options, &option_index);
+               int c = getopt_long (argc, argv, "vhdfnrl:", long_options, &option_index);
 
                if (c == -1) {
                        break;
@@ -89,6 +91,9 @@ main (int argc, char* argv[])
                case 'd':
                        cout << dependency_version_summary () << "\n";
                        exit (EXIT_SUCCESS);
+               case 'f':
+                       cout << dcpomatic_cxx_flags << "\n";
+                       exit (EXIT_SUCCESS);
                case 'n':
                        progress = false;
                        break;
index 38d986f25fe0af7ae42383af65dc5fea56cc6bbf..c7ab4460401ef99656ddacdbd11edcd2576038db 100644 (file)
@@ -6,7 +6,7 @@ import i18n
 def build(bld):
     for t in ['dcpomatic_cli', 'dcpomatic_server_cli']:
         obj = bld(features = 'cxx cxxprogram')
-        obj.uselib = 'BOOST_THREAD OPENJPEG DCP CXML AVFORMAT AVFILTER AVCODEC AVUTIL SWSCALE POSTPROC'
+        obj.uselib = 'BOOST_THREAD OPENJPEG DCP CXML AVFORMAT AVFILTER AVCODEC AVUTIL SWSCALE POSTPROC WXWIDGETS'
         obj.includes = ['..']
         obj.use    = ['libdcpomatic']
         obj.source = '%s.cc' % t
@@ -15,7 +15,9 @@ def build(bld):
     if not bld.env.DISABLE_GUI:
         for t in ['dcpomatic', 'dcpomatic_batch', 'dcpomatic_server']:
             obj = bld(features = 'cxx cxxprogram')
-            obj.uselib = 'DCP CXML OPENJPEG AVFORMAT AVFILTER AVCODEC AVUTIL SWSCALE POSTPROC'
+            obj.uselib = 'DCP OPENJPEG AVFORMAT AVFILTER AVCODEC AVUTIL SWSCALE POSTPROC CXML WXWIDGETS'
+            if bld.env.STATIC:
+                obj.uselib += ' GTK'
             obj.includes = ['..']
             obj.use    = ['libdcpomatic', 'libdcpomatic-wx']
             obj.source = '%s.cc' % t
index 0c56cf1be0ea56c865922f93c590e006f6c4346d..ca19326a1de2abacd87ef7311332d4258cc1c4fe 100644 (file)
@@ -138,7 +138,7 @@ AboutDialog::add_section (wxString name, wxArrayString credits)
 
        int c = 0;
        for (size_t i = 0; i < credits.Count(); ++i) {
-               add_label_to_sizer (sizers[c], panel, credits[i]);
+               add_label_to_sizer (sizers[c], panel, credits[i], false);
                ++c;
                if (c == N) {
                        c = 0;
index ea7cc60dd0d135044ce8acc94c452bcc5fc8ffa0..22e09cc7a8c1988973c21011a2027f064803ad38 100644 (file)
@@ -97,7 +97,6 @@ AudioDialog::set_content (shared_ptr<AudioContent> c)
        SetTitle (wxString::Format (_("DCP-o-matic audio - %s"), std_to_wx(_content->file().filename().string()).data()));
 }
 
-
 void
 AudioDialog::try_to_load_analysis ()
 {
index 844b03ad7e65c5653a698c26c6992f87e835d1fd..e66be174d003045b1bc8807a8f21e14935e81a99 100644 (file)
@@ -78,7 +78,7 @@ ConfigDialog::make_misc_panel ()
        wxBoxSizer* s = new wxBoxSizer (wxVERTICAL);
        _misc_panel->SetSizer (s);
 
-       wxFlexGridSizer* table = new wxFlexGridSizer (3, 6, 6);
+       wxFlexGridSizer* table = new wxFlexGridSizer (3, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
        table->AddGrowableCol (1, 1);
        s->Add (table, 1, wxALL | wxEXPAND, 8);
 
@@ -93,7 +93,7 @@ ConfigDialog::make_misc_panel ()
        table->Add (_language, 1, wxEXPAND);
        table->AddSpacer (0);
 
-       wxStaticText* restart = add_label_to_sizer (table, _misc_panel, _("(restart DVD-o-matic to see language changes)"));
+       wxStaticText* restart = add_label_to_sizer (table, _misc_panel, _("(restart DVD-o-matic to see language changes)"), false);
        wxFont font = restart->GetFont();
        font.SetStyle (wxFONTSTYLE_ITALIC);
        font.SetPointSize (font.GetPointSize() - 1);
@@ -101,18 +101,18 @@ ConfigDialog::make_misc_panel ()
        table->AddSpacer (0);
        table->AddSpacer (0);
 
-       add_label_to_sizer (table, _misc_panel, _("Threads to use for encoding on this host"));
+       add_label_to_sizer (table, _misc_panel, _("Threads to use for encoding on this host"), true);
        _num_local_encoding_threads = new wxSpinCtrl (_misc_panel);
-       table->Add (_num_local_encoding_threads, 1, wxEXPAND);
+       table->Add (_num_local_encoding_threads, 1);
        table->AddSpacer (0);
 
-       add_label_to_sizer (table, _misc_panel, _("Default duration of still images"));
+       add_label_to_sizer (table, _misc_panel, _("Default duration of still images"), true);
        _default_still_length = new wxSpinCtrl (_misc_panel);
        table->Add (_default_still_length, 1, wxEXPAND);
-       add_label_to_sizer (table, _misc_panel, _("s"));
+       add_label_to_sizer (table, _misc_panel, _("s"), false);
 
-       add_label_to_sizer (table, _misc_panel, _("Default directory for new films"));
-#ifdef __WXMSW__
+       add_label_to_sizer (table, _misc_panel, _("Default directory for new films"), true);
+#ifdef DCPOMATIC_USE_OWN_DIR_PICKER
        _default_directory = new DirPickerCtrl (_misc_panel);
 #else  
        _default_directory = new wxDirPickerCtrl (_misc_panel, wxDD_DIR_MUST_EXIST);
@@ -120,17 +120,17 @@ ConfigDialog::make_misc_panel ()
        table->Add (_default_directory, 1, wxEXPAND);
        table->AddSpacer (0);
 
-       add_label_to_sizer (table, _misc_panel, _("Default DCI name details"));
+       add_label_to_sizer (table, _misc_panel, _("Default DCI name details"), true);
        _default_dci_metadata_button = new wxButton (_misc_panel, wxID_ANY, _("Edit..."));
        table->Add (_default_dci_metadata_button);
        table->AddSpacer (1);
 
-       add_label_to_sizer (table, _misc_panel, _("Default container"));
+       add_label_to_sizer (table, _misc_panel, _("Default container"), true);
        _default_container = new wxChoice (_misc_panel, wxID_ANY);
        table->Add (_default_container);
        table->AddSpacer (1);
 
-       add_label_to_sizer (table, _misc_panel, _("Default content type"));
+       add_label_to_sizer (table, _misc_panel, _("Default content type"), true);
        _default_dcp_content_type = new wxChoice (_misc_panel, wxID_ANY);
        table->Add (_default_dcp_content_type);
        table->AddSpacer (1);
@@ -201,23 +201,23 @@ ConfigDialog::make_tms_panel ()
        wxBoxSizer* s = new wxBoxSizer (wxVERTICAL);
        _tms_panel->SetSizer (s);
 
-       wxFlexGridSizer* table = new wxFlexGridSizer (2, 6, 6);
+       wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
        table->AddGrowableCol (1, 1);
        s->Add (table, 1, wxALL | wxEXPAND, 8);
 
-       add_label_to_sizer (table, _tms_panel, _("IP address"));
+       add_label_to_sizer (table, _tms_panel, _("IP address"), true);
        _tms_ip = new wxTextCtrl (_tms_panel, wxID_ANY);
        table->Add (_tms_ip, 1, wxEXPAND);
 
-       add_label_to_sizer (table, _tms_panel, _("Target path"));
+       add_label_to_sizer (table, _tms_panel, _("Target path"), true);
        _tms_path = new wxTextCtrl (_tms_panel, wxID_ANY);
        table->Add (_tms_path, 1, wxEXPAND);
 
-       add_label_to_sizer (table, _tms_panel, _("User name"));
+       add_label_to_sizer (table, _tms_panel, _("User name"), true);
        _tms_user = new wxTextCtrl (_tms_panel, wxID_ANY);
        table->Add (_tms_user, 1, wxEXPAND);
 
-       add_label_to_sizer (table, _tms_panel, _("Password"));
+       add_label_to_sizer (table, _tms_panel, _("Password"), true);
        _tms_password = new wxTextCtrl (_tms_panel, wxID_ANY);
        table->Add (_tms_password, 1, wxEXPAND);
 
@@ -240,15 +240,15 @@ ConfigDialog::make_metadata_panel ()
        wxBoxSizer* s = new wxBoxSizer (wxVERTICAL);
        _metadata_panel->SetSizer (s);
 
-       wxFlexGridSizer* table = new wxFlexGridSizer (2, 6, 6);
+       wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
        table->AddGrowableCol (1, 1);
        s->Add (table, 1, wxALL | wxEXPAND, 8);
 
-       add_label_to_sizer (table, _metadata_panel, _("Issuer"));
+       add_label_to_sizer (table, _metadata_panel, _("Issuer"), true);
        _issuer = new wxTextCtrl (_metadata_panel, wxID_ANY);
        table->Add (_issuer, 1, wxEXPAND);
 
-       add_label_to_sizer (table, _metadata_panel, _("Creator"));
+       add_label_to_sizer (table, _metadata_panel, _("Creator"), true);
        _creator = new wxTextCtrl (_metadata_panel, wxID_ANY);
        table->Add (_creator, 1, wxEXPAND);
 
@@ -267,7 +267,7 @@ ConfigDialog::make_servers_panel ()
        wxBoxSizer* s = new wxBoxSizer (wxVERTICAL);
        _servers_panel->SetSizer (s);
 
-       wxFlexGridSizer* table = new wxFlexGridSizer (2, 6, 6);
+       wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
        table->AddGrowableCol (0, 1);
        s->Add (table, 1, wxALL | wxEXPAND, 8);
 
@@ -288,11 +288,11 @@ ConfigDialog::make_servers_panel ()
        {
                wxSizer* s = new wxBoxSizer (wxVERTICAL);
                _add_server = new wxButton (_servers_panel, wxID_ANY, _("Add"));
-               s->Add (_add_server);
+               s->Add (_add_server, 0, wxTOP | wxBOTTOM, 2);
                _edit_server = new wxButton (_servers_panel, wxID_ANY, _("Edit"));
-               s->Add (_edit_server);
+               s->Add (_edit_server, 0, wxTOP | wxBOTTOM, 2);
                _remove_server = new wxButton (_servers_panel, wxID_ANY, _("Remove"));
-               s->Add (_remove_server);
+               s->Add (_remove_server, 0, wxTOP | wxBOTTOM, 2);
                table->Add (s, 0);
        }
 
index 3da48fd08f3758207a59de2616ca5e966f6bf15a..459d64dd701327c2e8bd07f6f5f9e027aae58ebd 100644 (file)
@@ -25,6 +25,7 @@
 #include <wx/spinctrl.h>
 #include <wx/listctrl.h>
 #include <wx/filepicker.h>
+#include "wx_util.h"
 
 class DirPickerCtrl;
 class wxNotebook;
@@ -82,7 +83,7 @@ private:
        wxTextCtrl* _tms_password;
        wxSpinCtrl* _num_local_encoding_threads;
        wxSpinCtrl* _default_still_length;
-#ifdef __WXMSW__       
+#ifdef DCPOMATIC_USE_OWN_DIR_PICKER
        DirPickerCtrl* _default_directory;
 #else
        wxDirPickerCtrl* _default_directory;
index c08c58ed460abb15846f0c637968119024c51be5..df3a24f626aa786f74aaab693de2199ab04036d9 100644 (file)
@@ -27,34 +27,34 @@ using boost::shared_ptr;
 DCIMetadataDialog::DCIMetadataDialog (wxWindow* parent, DCIMetadata dm)
        : wxDialog (parent, wxID_ANY, _("DCI name"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
 {
-       wxFlexGridSizer* table = new wxFlexGridSizer (2, 6, 6);
+       wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
        table->AddGrowableCol (1, 1);
 
-       add_label_to_sizer (table, this, _("Audio Language (e.g. EN)"));
+       add_label_to_sizer (table, this, _("Audio Language (e.g. EN)"), true);
        _audio_language = new wxTextCtrl (this, wxID_ANY);
        table->Add (_audio_language, 1, wxEXPAND);
 
-       add_label_to_sizer (table, this, _("Subtitle Language (e.g. FR)"));
+       add_label_to_sizer (table, this, _("Subtitle Language (e.g. FR)"), true);
        _subtitle_language = new wxTextCtrl (this, wxID_ANY);
        table->Add (_subtitle_language, 1, wxEXPAND);
        
-       add_label_to_sizer (table, this, _("Territory (e.g. UK)"));
+       add_label_to_sizer (table, this, _("Territory (e.g. UK)"), true);
        _territory = new wxTextCtrl (this, wxID_ANY);
        table->Add (_territory, 1, wxEXPAND);
 
-       add_label_to_sizer (table, this, _("Rating (e.g. 15)"));
+       add_label_to_sizer (table, this, _("Rating (e.g. 15)"), true);
        _rating = new wxTextCtrl (this, wxID_ANY);
        table->Add (_rating, 1, wxEXPAND);
 
-       add_label_to_sizer (table, this, _("Studio (e.g. TCF)"));
+       add_label_to_sizer (table, this, _("Studio (e.g. TCF)"), true);
        _studio = new wxTextCtrl (this, wxID_ANY);
        table->Add (_studio, 1, wxEXPAND);
 
-       add_label_to_sizer (table, this, _("Facility (e.g. DLA)"));
+       add_label_to_sizer (table, this, _("Facility (e.g. DLA)"), true);
        _facility = new wxTextCtrl (this, wxID_ANY);
        table->Add (_facility, 1, wxEXPAND);
 
-       add_label_to_sizer (table, this, _("Package Type (e.g. OV)"));
+       add_label_to_sizer (table, this, _("Package Type (e.g. OV)"), true);
        _package_type = new wxTextCtrl (this, wxID_ANY);
        table->Add (_package_type, 1, wxEXPAND);
 
index 27803fb9a7e2464778a2eae26f0fb76c811d8d7d..2d8c752a1229883cfd313031e9eb627805d98bb8 100644 (file)
@@ -102,39 +102,44 @@ FilmEditor::make_dcp_panel ()
        _dcp_sizer = new wxBoxSizer (wxVERTICAL);
        _dcp_panel->SetSizer (_dcp_sizer);
 
-       wxGridBagSizer* grid = new wxGridBagSizer (4, 4);
+       wxGridBagSizer* grid = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
        _dcp_sizer->Add (grid, 0, wxEXPAND | wxALL, 8);
 
        int r = 0;
        
-       add_label_to_grid_bag_sizer (grid, _dcp_panel, _("Name"), wxGBPosition (r, 0));
+       add_label_to_grid_bag_sizer (grid, _dcp_panel, _("Name"), true, wxGBPosition (r, 0));
        _name = new wxTextCtrl (_dcp_panel, wxID_ANY);
-       grid->Add (_name, wxGBPosition(r, 1), wxDefaultSpan, wxEXPAND);
+       grid->Add (_name, wxGBPosition(r, 1), wxDefaultSpan, wxEXPAND | wxLEFT | wxRIGHT);
        ++r;
        
-       add_label_to_grid_bag_sizer (grid, _dcp_panel, _("DCP Name"), wxGBPosition (r, 0));
+       add_label_to_grid_bag_sizer (grid, _dcp_panel, _("DCP Name"), true, wxGBPosition (r, 0));
        _dcp_name = new wxStaticText (_dcp_panel, wxID_ANY, wxT (""));
        grid->Add (_dcp_name, wxGBPosition(r, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
        ++r;
 
+       int flags = wxALIGN_CENTER_VERTICAL;
+#ifdef __WXOSX__
+       flags |= wxALIGN_RIGHT;
+#endif 
+
        _use_dci_name = new wxCheckBox (_dcp_panel, wxID_ANY, _("Use DCI name"));
-       grid->Add (_use_dci_name, wxGBPosition (r, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
+       grid->Add (_use_dci_name, wxGBPosition (r, 0), wxDefaultSpan, flags);
        _edit_dci_button = new wxButton (_dcp_panel, wxID_ANY, _("Details..."));
        grid->Add (_edit_dci_button, wxGBPosition (r, 1), wxDefaultSpan);
        ++r;
 
-       add_label_to_grid_bag_sizer (grid, _dcp_panel, _("Container"), wxGBPosition (r, 0));
+       add_label_to_grid_bag_sizer (grid, _dcp_panel, _("Container"), true, wxGBPosition (r, 0));
        _container = new wxChoice (_dcp_panel, wxID_ANY);
-       grid->Add (_container, wxGBPosition (r, 1));
+       grid->Add (_container, wxGBPosition (r, 1), wxDefaultSpan, wxEXPAND);
        ++r;
 
-       add_label_to_grid_bag_sizer (grid, _dcp_panel, _("Content Type"), wxGBPosition (r, 0));
+       add_label_to_grid_bag_sizer (grid, _dcp_panel, _("Content Type"), true, wxGBPosition (r, 0));
        _dcp_content_type = new wxChoice (_dcp_panel, wxID_ANY);
        grid->Add (_dcp_content_type, wxGBPosition (r, 1));
        ++r;
 
        {
-               add_label_to_grid_bag_sizer (grid, _dcp_panel, _("DCP Frame Rate"), wxGBPosition (r, 0));
+               add_label_to_grid_bag_sizer (grid, _dcp_panel, _("DCP Frame Rate"), true, wxGBPosition (r, 0));
                wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
                _dcp_frame_rate = new wxChoice (_dcp_panel, wxID_ANY);
                s->Add (_dcp_frame_rate, 1, wxALIGN_CENTER_VERTICAL);
@@ -145,18 +150,18 @@ FilmEditor::make_dcp_panel ()
        ++r;
 
        {
-               add_label_to_grid_bag_sizer (grid, _dcp_panel, _("JPEG2000 bandwidth"), wxGBPosition (r, 0));
+               add_label_to_grid_bag_sizer (grid, _dcp_panel, _("JPEG2000 bandwidth"), true, wxGBPosition (r, 0));
                wxSizer* s = new wxBoxSizer (wxHORIZONTAL);
                _j2k_bandwidth = new wxSpinCtrl (_dcp_panel, wxID_ANY);
                s->Add (_j2k_bandwidth, 1);
-               add_label_to_sizer (s, _dcp_panel, _("MBps"));
+               add_label_to_sizer (s, _dcp_panel, _("MBps"), false);
                grid->Add (s, wxGBPosition (r, 1));
        }
        ++r;
 
-       add_label_to_grid_bag_sizer (grid, _dcp_panel, _("Scaler"), wxGBPosition (r, 0));
+       add_label_to_grid_bag_sizer (grid, _dcp_panel, _("Scaler"), true, wxGBPosition (r, 0));
        _scaler = new wxChoice (_dcp_panel, wxID_ANY);
-       grid->Add (_scaler, wxGBPosition (r, 1));
+       grid->Add (_scaler, wxGBPosition (r, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
        ++r;
 
        vector<Scaler const *> const sc = Scaler::all ();
@@ -206,6 +211,8 @@ FilmEditor::connect_to_widgets ()
        _dcp_content_type->Connect       (wxID_ANY, wxEVT_COMMAND_CHOICE_SELECTED,      wxCommandEventHandler (FilmEditor::dcp_content_type_changed), 0, this);
        _dcp_frame_rate->Connect         (wxID_ANY, wxEVT_COMMAND_CHOICE_SELECTED,      wxCommandEventHandler (FilmEditor::dcp_frame_rate_changed), 0, this);
        _best_dcp_frame_rate->Connect    (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED,       wxCommandEventHandler (FilmEditor::best_dcp_frame_rate_clicked), 0, this);
+//     _pad_with_silence->Connect       (wxID_ANY, wxEVT_COMMAND_CHECKBOX_CLICKED,     wxCommandEventHandler (FilmEditor::pad_with_silence_toggled), 0, this);
+//     _minimum_audio_channels->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED,   wxCommandEventHandler (FilmEditor::minimum_audio_channels_changed), 0, this);
        _with_subtitles->Connect         (wxID_ANY, wxEVT_COMMAND_CHECKBOX_CLICKED,     wxCommandEventHandler (FilmEditor::with_subtitles_toggled), 0, this);
        _subtitle_offset->Connect        (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED,     wxCommandEventHandler (FilmEditor::subtitle_offset_changed), 0, this);
        _subtitle_scale->Connect         (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED,     wxCommandEventHandler (FilmEditor::subtitle_scale_changed), 0, this);
@@ -231,31 +238,31 @@ FilmEditor::make_video_panel ()
        wxBoxSizer* video_sizer = new wxBoxSizer (wxVERTICAL);
        _video_panel->SetSizer (video_sizer);
        
-       wxGridBagSizer* grid = new wxGridBagSizer (4, 4);
+       wxGridBagSizer* grid = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
        video_sizer->Add (grid, 0, wxALL, 8);
 
        int r = 0;
-       add_label_to_grid_bag_sizer (grid, _video_panel, _("Left crop"), wxGBPosition (r, 0));
+       add_label_to_grid_bag_sizer (grid, _video_panel, _("Left crop"), true, wxGBPosition (r, 0));
        _left_crop = new wxSpinCtrl (_video_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1));
        grid->Add (_left_crop, wxGBPosition (r, 1));
        ++r;
 
-       add_label_to_grid_bag_sizer (grid, _video_panel, _("Right crop"), wxGBPosition (r, 0));
+       add_label_to_grid_bag_sizer (grid, _video_panel, _("Right crop"), true, wxGBPosition (r, 0));
        _right_crop = new wxSpinCtrl (_video_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1));
        grid->Add (_right_crop, wxGBPosition (r, 1));
        ++r;
        
-       add_label_to_grid_bag_sizer (grid, _video_panel, _("Top crop"), wxGBPosition (r, 0));
+       add_label_to_grid_bag_sizer (grid, _video_panel, _("Top crop"), true, wxGBPosition (r, 0));
        _top_crop = new wxSpinCtrl (_video_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1));
        grid->Add (_top_crop, wxGBPosition (r, 1));
        ++r;
        
-       add_label_to_grid_bag_sizer (grid, _video_panel, _("Bottom crop"), wxGBPosition (r, 0));
+       add_label_to_grid_bag_sizer (grid, _video_panel, _("Bottom crop"), true, wxGBPosition (r, 0));
        _bottom_crop = new wxSpinCtrl (_video_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1));
        grid->Add (_bottom_crop, wxGBPosition (r, 1));
        ++r;
 
-       add_label_to_grid_bag_sizer (grid, _video_panel, _("Scale to"), wxGBPosition (r, 0));
+       add_label_to_grid_bag_sizer (grid, _video_panel, _("Scale to"), true, wxGBPosition (r, 0));
        _ratio = new wxChoice (_video_panel, wxID_ANY);
        grid->Add (_ratio, wxGBPosition (r, 1));
        ++r;
@@ -270,17 +277,17 @@ FilmEditor::make_video_panel ()
 
        /* VIDEO-only stuff */
        {
-               add_label_to_grid_bag_sizer (grid, _video_panel, _("Filters"), wxGBPosition (r, 0));
+               add_label_to_grid_bag_sizer (grid, _video_panel, _("Filters"), true, wxGBPosition (r, 0));
                wxSizer* s = new wxBoxSizer (wxHORIZONTAL);
                _filters = new wxStaticText (_video_panel, wxID_ANY, _("None"));
                s->Add (_filters, 1, wxEXPAND | wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM | wxRIGHT, 6);
                _filters_button = new wxButton (_video_panel, wxID_ANY, _("Edit..."));
-               s->Add (_filters_button, 0);
+               s->Add (_filters_button, 0, wxALIGN_CENTER_VERTICAL);
                grid->Add (s, wxGBPosition (r, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
        }
        ++r;
 
-       add_label_to_grid_bag_sizer (grid, _video_panel, _("Colour look-up table"), wxGBPosition (r, 0));
+       add_label_to_grid_bag_sizer (grid, _video_panel, _("Colour look-up table"), true, wxGBPosition (r, 0));
        _colour_lut = new wxChoice (_video_panel, wxID_ANY);
        for (int i = 0; i < 2; ++i) {
                _colour_lut->Append (std_to_wx (colour_lut_index_to_name (i)));
@@ -329,7 +336,7 @@ FilmEditor::make_content_panel ()
        h->Add (_loop_content, 0, wxALL, 6);
        _loop_count = new wxSpinCtrl (_content_panel, wxID_ANY);
        h->Add (_loop_count, 0, wxALL, 6);
-       add_label_to_sizer (h, _content_panel, _("times"));
+       add_label_to_sizer (h, _content_panel, _("times"), false);
        _content_sizer->Add (h, 0, wxALL, 6);
 
        _content_notebook = new wxNotebook (_content_panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNB_LEFT);
@@ -354,7 +361,7 @@ FilmEditor::make_audio_panel ()
        wxBoxSizer* audio_sizer = new wxBoxSizer (wxVERTICAL);
        _audio_panel->SetSizer (audio_sizer);
        
-       wxFlexGridSizer* grid = new wxFlexGridSizer (3, 4, 4);
+       wxFlexGridSizer* grid = new wxFlexGridSizer (3, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
        audio_sizer->Add (grid, 0, wxALL, 8);
 
        _show_audio = new wxButton (_audio_panel, wxID_ANY, _("Show Audio..."));
@@ -362,31 +369,31 @@ FilmEditor::make_audio_panel ()
        grid->AddSpacer (0);
        grid->AddSpacer (0);
 
-       add_label_to_sizer (grid, _audio_panel, _("Audio Gain"));
+       add_label_to_sizer (grid, _audio_panel, _("Audio Gain"), true);
        {
                wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
                _audio_gain = new wxSpinCtrl (_audio_panel);
                s->Add (_audio_gain, 1);
-               add_label_to_sizer (s, _audio_panel, _("dB"));
+               add_label_to_sizer (s, _audio_panel, _("dB"), false);
                grid->Add (s, 1);
        }
        
        _audio_gain_calculate_button = new wxButton (_audio_panel, wxID_ANY, _("Calculate..."));
        grid->Add (_audio_gain_calculate_button);
 
-       add_label_to_sizer (grid, _audio_panel, _("Audio Delay"));
+       add_label_to_sizer (grid, _audio_panel, _("Audio Delay"), false);
        {
                wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
                _audio_delay = new wxSpinCtrl (_audio_panel);
                s->Add (_audio_delay, 1);
                /// TRANSLATORS: this is an abbreviation for milliseconds, the unit of time
-               add_label_to_sizer (s, _audio_panel, _("ms"));
+               add_label_to_sizer (s, _audio_panel, _("ms"), false);
                grid->Add (s);
        }
 
        grid->AddSpacer (0);
 
-       add_label_to_sizer (grid, _audio_panel, _("Audio Stream"));
+       add_label_to_sizer (grid, _audio_panel, _("Audio Stream"), true);
        _audio_stream = new wxChoice (_audio_panel, wxID_ANY);
        grid->Add (_audio_stream, 1);
        _audio_description = new wxStaticText (_audio_panel, wxID_ANY, wxT (""));
@@ -399,8 +406,32 @@ FilmEditor::make_audio_panel ()
        _audio_mapping = new AudioMappingView (_audio_panel);
        audio_sizer->Add (_audio_mapping, 1, wxEXPAND | wxALL, 6);
 
+#if 0  
+       {
+               _pad_with_silence = new wxCheckBox (_audio_panel, wxID_ANY, _("Pad with silence to"));
+               grid->Add (_pad_with_silence);
+               wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
+               _minimum_audio_channels = new wxSpinCtrl (_audio_panel);
+               s->Add (_minimum_audio_channels, 1);
+               add_label_to_sizer (s, _audio_panel, _("channels"), false);
+               grid->Add (s);
+       }
+
+       {
+               _use_content_audio = new wxRadioButton (_audio_panel, wxID_ANY, _("Use content's audio"), wxDefaultPosition, wxDefaultSize, wxRB_GROUP);
+               grid->Add (video_control (_use_content_audio));
+               wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
+               _audio_stream = new wxChoice (_audio_panel, wxID_ANY);
+               s->Add (video_control (_audio_stream), 1);
+               _audio = new wxStaticText (_audio_panel, wxID_ANY, wxT (""));
+               s->Add (video_control (_audio), 1, wxALIGN_CENTER_VERTICAL | wxLEFT, 8);
+               grid->Add (s);
+       }
+#endif 
+
        _audio_gain->SetRange (-60, 60);
        _audio_delay->SetRange (-1000, 1000);
+//     _minimum_audio_channels->SetRange (0, MAX_AUDIO_CHANNELS);
 }
 
 void
@@ -409,7 +440,7 @@ FilmEditor::make_subtitle_panel ()
        _subtitle_panel = new wxPanel (_content_notebook);
        wxBoxSizer* subtitle_sizer = new wxBoxSizer (wxVERTICAL);
        _subtitle_panel->SetSizer (subtitle_sizer);
-       wxFlexGridSizer* grid = new wxFlexGridSizer (2, 4, 4);
+       wxFlexGridSizer* grid = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
        subtitle_sizer->Add (grid, 0, wxALL, 8);
 
        _with_subtitles = new wxCheckBox (_subtitle_panel, wxID_ANY, _("With Subtitles"));
@@ -417,24 +448,24 @@ FilmEditor::make_subtitle_panel ()
        grid->AddSpacer (0);
        
        {
-               add_label_to_sizer (grid, _subtitle_panel, _("Subtitle Offset"));
+               add_label_to_sizer (grid, _subtitle_panel, _("Subtitle Offset"), true);
                wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
                _subtitle_offset = new wxSpinCtrl (_subtitle_panel);
                s->Add (_subtitle_offset);
-               add_label_to_sizer (s, _subtitle_panel, _("pixels"));
+               add_label_to_sizer (s, _subtitle_panel, _("pixels"), false);
                grid->Add (s);
        }
 
        {
-               add_label_to_sizer (grid, _subtitle_panel, _("Subtitle Scale"));
+               add_label_to_sizer (grid, _subtitle_panel, _("Subtitle Scale"), true);
                wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
                _subtitle_scale = new wxSpinCtrl (_subtitle_panel);
                s->Add (_subtitle_scale);
-               add_label_to_sizer (s, _subtitle_panel, _("%"));
+               add_label_to_sizer (s, _subtitle_panel, _("%"), false);
                grid->Add (s);
        }
 
-       add_label_to_sizer (grid, _subtitle_panel, _("Subtitle Stream"));
+       add_label_to_sizer (grid, _subtitle_panel, _("Subtitle Stream"), true);
        _subtitle_stream = new wxChoice (_subtitle_panel, wxID_ANY);
        grid->Add (_subtitle_stream, 1, wxEXPAND | wxALL, 6);
        grid->AddSpacer (0);
@@ -452,10 +483,10 @@ FilmEditor::make_timing_panel ()
        wxFlexGridSizer* grid = new wxFlexGridSizer (2, 4, 4);
        timing_sizer->Add (grid, 0, wxALL, 8);
 
-       add_label_to_sizer (grid, _timing_panel, _("Start time"));
+       add_label_to_sizer (grid, _timing_panel, _("Start time"), true);
        _start = new Timecode (_timing_panel);
        grid->Add (_start);
-       add_label_to_sizer (grid, _timing_panel, _("Length"));
+       add_label_to_sizer (grid, _timing_panel, _("Length"), true);
        _length = new Timecode (_timing_panel);
        grid->Add (_length);
 }
@@ -597,6 +628,7 @@ FilmEditor::film_changed (Film::Property p)
                setup_content ();
                setup_subtitle_control_sensitivity ();
                setup_show_audio_sensitivity ();
+               setup_minimum_audio_channels ();
                break;
        case Film::LOOP:
                checked_set (_loop_content, _film->loop() > 1);
@@ -659,6 +691,10 @@ FilmEditor::film_changed (Film::Property p)
                _best_dcp_frame_rate->Enable (_film->best_dcp_video_frame_rate () != _film->dcp_video_frame_rate ());
                break;
        }
+       case Film::MINIMUM_AUDIO_CHANNELS:
+//             checked_set (_minimum_audio_channels, _film->minimum_audio_channels ());
+               setup_minimum_audio_channels ();
+               break;
        }
 }
 
@@ -1284,8 +1320,8 @@ XXX
        }
 
        Crop const crop = _film->crop ();
-       if (crop.left || crop.right || crop.top || crop.bottom) {
-               libdcp::Size const cropped = _film->cropped_size (_film->video_size ());
+       if ((crop.left || crop.right || crop.top || crop.bottom) && _film->size() != libdcp::Size (0, 0)) {
+               libdcp::Size const cropped = _film->cropped_size (_film->size ());
                d << wxString::Format (
                        _("Cropped to %dx%d (%.2f:1)\n"),
                        cropped.width, cropped.height,
@@ -1503,3 +1539,35 @@ FilmEditor::ratio_changed (wxCommandEvent &)
                vc->set_ratio (ratios[n]);
        }
 }
+
+void
+FilmEditor::setup_minimum_audio_channels ()
+{
+#if 0  
+       if (!_film || !_film->audio_stream ()) {
+               _pad_with_silence->SetValue (false);
+               return;
+       }
+
+       _pad_with_silence->SetValue (_film->audio_stream()->channels() < _film->minimum_audio_channels());
+
+       AudioMapping m (_film);
+       _minimum_audio_channels->SetRange (m.minimum_dcp_channels() + 1, MAX_AUDIO_CHANNELS);
+#endif 
+}
+
+void
+FilmEditor::pad_with_silence_toggled (wxCommandEvent &)
+{
+
+}
+
+void
+FilmEditor::minimum_audio_channels_changed (wxCommandEvent &)
+{
+       if (!_film) {
+               return;
+       }
+
+//     _film->set_minimum_audio_channels (_minimum_audio_channels->GetValue ());
+}
index 4b096a2e15242ac592280e6075da30e8798a6f7d..705eb16af9b98f6305a3d28d4d7d251f339e56fc 100644 (file)
@@ -97,6 +97,8 @@ private:
        void start_changed ();
        void length_changed ();
        void ratio_changed (wxCommandEvent &);
+       void pad_with_silence_toggled (wxCommandEvent &);
+       void minimum_audio_channels_changed (wxCommandEvent &);
 
        /* Handle changes to the model */
        void film_changed (Film::Property);
@@ -113,6 +115,7 @@ private:
        void setup_container ();
        void setup_content_sensitivity ();
        void setup_loop_sensitivity ();
+       void setup_minimum_audio_channels ();
        
        void active_jobs_changed (bool);
        boost::shared_ptr<Content> selected_content ();
@@ -167,6 +170,8 @@ private:
        wxChoice* _dcp_content_type;
        wxChoice* _dcp_frame_rate;
        wxButton* _best_dcp_frame_rate;
+       wxCheckBox* _pad_with_silence;
+       wxSpinCtrl* _minimum_audio_channels;
        wxChoice* _audio_stream;
        wxStaticText* _audio_description;
        wxChoice* _subtitle_stream;
index 22e6b447ab1bb96f69f0946986b0c0f4b3d8651f..17ebbb9831c37ad7ab297903ad0d62bc90571ce3 100644 (file)
@@ -26,14 +26,14 @@ using namespace boost;
 GainCalculatorDialog::GainCalculatorDialog (wxWindow* parent)
        : wxDialog (parent, wxID_ANY, _("Gain Calculator"))
 {
-       wxFlexGridSizer* table = new wxFlexGridSizer (2, 6, 6);
+       wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
        table->AddGrowableCol (1, 1);
 
-       add_label_to_sizer (table, this, _("I want to play this back at fader"));
+       add_label_to_sizer (table, this, _("I want to play this back at fader"), true);
        _wanted = new wxTextCtrl (this, wxID_ANY, wxT (""), wxDefaultPosition, wxDefaultSize, 0, wxTextValidator (wxFILTER_NUMERIC));
        table->Add (_wanted, 1, wxEXPAND);
 
-       add_label_to_sizer (table, this, _("But I have to use fader"));
+       add_label_to_sizer (table, this, _("But I have to use fader"), true);
        _actual = new wxTextCtrl (this, wxID_ANY, wxT (""), wxDefaultPosition, wxDefaultSize, 0, wxTextValidator (wxFILTER_NUMERIC));
        table->Add (_actual, 1, wxEXPAND);
 
index dfe4df2e79883e33cf3f60e3f089c3fd4266da36..6aa75626059dcc1dd84500c7efddceaceb582fd8 100644 (file)
@@ -33,12 +33,12 @@ ImageMagickContentDialog::ImageMagickContentDialog (wxWindow* parent, shared_ptr
        grid->AddGrowableCol (1, 1);
 
        {
-               add_label_to_sizer (grid, this, (_("Duration")));
+               add_label_to_sizer (grid, this, _("Duration"), true);
                wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
                _video_length = new wxSpinCtrl (this);
                s->Add (_video_length);
                /// TRANSLATORS: this is an abbreviation for seconds, the unit of time
-               add_label_to_sizer (s, this, _("s"));
+               add_label_to_sizer (s, this, _("s"), false);
                grid->Add (s);
        }
 
index 1594dfc91e62a51523d033b281015c7dbc7903ca..b5c66bd3ed5740f74136b29a49195b56e5543f8e 100644 (file)
@@ -152,7 +152,6 @@ JobManagerView::update ()
                        if (!(*i)->finished_cancelled()) {
                                _job_records[*i].gauge->SetValue (100);
                        }
-                       (*i)->Finished ();
                        _job_records[*i].finalised = true;
                        _job_records[*i].cancel->Enable (false);
                        if (!(*i)->error_details().empty ()) {
index 191482a7cbcdb23ca3da8f48720dbbcdc7bf2d06..d4b78d5bff1ad845afd1732c3ef79c83720aecf7 100644 (file)
 #include <wx/stdpaths.h>
 #include "lib/config.h"
 #include "new_film_dialog.h"
-#ifdef __WXMSW__
+#include "wx_util.h"
+#ifdef DCPOMATIC_USE_OWN_DIR_PICKER
 #include "dir_picker_ctrl.h"
 #endif
-#include "wx_util.h"
 
 using namespace std;
 using namespace boost;
@@ -37,17 +37,18 @@ NewFilmDialog::NewFilmDialog (wxWindow* parent)
        wxBoxSizer* overall_sizer = new wxBoxSizer (wxVERTICAL);
        SetSizer (overall_sizer);
        
-       wxFlexGridSizer* table = new wxFlexGridSizer (2, 6, 6);
+       wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
        table->AddGrowableCol (1, 1);
        overall_sizer->Add (table, 1, wxEXPAND | wxALL, 6);
 
-       add_label_to_sizer (table, this, _("Film name"));
+       add_label_to_sizer (table, this, _("Film name"), true);
        _name = new wxTextCtrl (this, wxID_ANY);
-       table->Add (_name, 1, wxEXPAND);
+       table->Add (_name, 0, wxEXPAND);
+
+       add_label_to_sizer (table, this, _("Create in folder"), true);
 
-       add_label_to_sizer (table, this, _("Create in folder"));
-#ifdef __WXMSW__
-       _folder = new DirPickerCtrl (this);
+#ifdef DCPOMATIC_USE_OWN_DIR_PICKER
+       _folder = new DirPickerCtrl (this); 
 #else  
        _folder = new wxDirPickerCtrl (this, wxDD_DIR_MUST_EXIST);
 #endif
index bfcbd423c2cb31a3cc60a9a07bfbc15ab8ad7e17..f8f3aa08dd1ca5f360afaa495299afd1d8470346 100644 (file)
@@ -19,6 +19,7 @@
 
 #include <wx/wx.h>
 #include <wx/filepicker.h>
+#include "wx_util.h"
 
 class DirPickerCtrl;
 
@@ -32,10 +33,10 @@ public:
 
 private:
        wxTextCtrl* _name;
-#ifdef __WXMSW__       
+#ifdef DCPOMATIC_USE_OWN_DIR_PICKER
        DirPickerCtrl* _folder;
-#else
+#else  
        wxDirPickerCtrl* _folder;
-#endif
+#endif 
        static boost::optional<std::string> _directory;
 };
index 40527ded712b038c25d4c3b3ff13e329400504fb..d525fe38b115d059bd2cc2f279952540dccb456b 100644 (file)
@@ -36,17 +36,17 @@ PropertiesDialog::PropertiesDialog (wxWindow* parent, shared_ptr<Film> film)
        : wxDialog (parent, wxID_ANY, _("Film Properties"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE)
        , _film (film)
 {
-       wxFlexGridSizer* table = new wxFlexGridSizer (2, 3, 6);
+       wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
 
-       add_label_to_sizer (table, this, _("Frames"));
+       add_label_to_sizer (table, this, _("Frames"), true);
        _frames = new wxStaticText (this, wxID_ANY, wxT (""));
        table->Add (_frames, 1, wxALIGN_CENTER_VERTICAL);
 
-       add_label_to_sizer (table, this, _("Disk space required"));
+       add_label_to_sizer (table, this, _("Disk space required"), true);
        _disk = new wxStaticText (this, wxID_ANY, wxT (""));
        table->Add (_disk, 1, wxALIGN_CENTER_VERTICAL);
 
-       add_label_to_sizer (table, this, _("Frames already encoded"));
+       add_label_to_sizer (table, this, _("Frames already encoded"), true);
        _encoded = new ThreadedStaticText (this, _("counting..."), boost::bind (&PropertiesDialog::frames_already_encoded, this));
        table->Add (_encoded, 1, wxALIGN_CENTER_VERTICAL);
 
index 7a9cf95c7a98eeb2f13aa929c0907bc0a634ad08..33cb392bfe52886f2878ebfd33ad001022483f58 100644 (file)
@@ -30,14 +30,14 @@ ServerDialog::ServerDialog (wxWindow* parent, ServerDescription* server)
                _server = new ServerDescription (wx_to_std (N_("localhost")), 1);
        }
                
-       wxFlexGridSizer* table = new wxFlexGridSizer (2, 4, 4);
+       wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
        table->AddGrowableCol (1, 1);
 
-       add_label_to_sizer (table, this, _("Host name or IP address"));
+       add_label_to_sizer (table, this, _("Host name or IP address"), true);
        _host = new wxTextCtrl (this, wxID_ANY);
        table->Add (_host, 1, wxEXPAND);
 
-       add_label_to_sizer (table, this, _("Threads to use"));
+       add_label_to_sizer (table, this, _("Threads to use"), true);
        _threads = new wxSpinCtrl (this, wxID_ANY);
        table->Add (_threads, 1, wxEXPAND);
 
index 9072fb99e0327f151c45362b450eba6047c823b3..6ce1c1cb8370c729714489cfbdb3d75ada23f9b6 100644 (file)
@@ -47,15 +47,15 @@ Timecode::Timecode (wxWindow* parent)
        _hours = new wxTextCtrl (this, wxID_ANY, wxT(""), wxDefaultPosition, size, 0, validator);
        _hours->SetMaxLength (2);
        sizer->Add (_hours);
-       add_label_to_sizer (sizer, this, wxT (":"));
+       add_label_to_sizer (sizer, this, wxT (":"), false);
        _minutes = new wxTextCtrl (this, wxID_ANY, wxT(""), wxDefaultPosition, size);
        _minutes->SetMaxLength (2);
        sizer->Add (_minutes);
-       add_label_to_sizer (sizer, this, wxT (":"));
+       add_label_to_sizer (sizer, this, wxT (":"), false);
        _seconds = new wxTextCtrl (this, wxID_ANY, wxT(""), wxDefaultPosition, size);
        _seconds->SetMaxLength (2);
        sizer->Add (_seconds);
-       add_label_to_sizer (sizer, this, wxT ("."));
+       add_label_to_sizer (sizer, this, wxT ("."), false);
        _frames = new wxTextCtrl (this, wxID_ANY, wxT(""), wxDefaultPosition, size);
        _frames->SetMaxLength (2);
        sizer->Add (_frames);
index 992f31175eb0e27cfb36ed1209f7c411d53567a8..1205fb21b22e833b07acd6f98ed5c06a406fc84e 100644 (file)
@@ -30,7 +30,21 @@ sources = """
           """
 
 def configure(conf):
-    conf.check_cfg(package = '', path = conf.options.wx_config, args = '--cppflags --cxxflags --libs', uselib_store = 'WXWIDGETS', mandatory = True)
+    conf.check_cfg(msg='Checking for wxWidgets', package='', path=conf.options.wx_config, args='--cppflags --cxxflags --libs',
+                   uselib_store='WXWIDGETS', mandatory=True)
+
+    if conf.env.STATIC:
+       # wx-config returns its static libraries as full paths, without -l prefixes, which confuses
+        # check_cfg(), so just hard-code it all.
+        conf.env.STLIB_WXWIDGETS = ['wx_gtk2u_xrc-2.9', 'wx_gtk2u_qa-2.9', 'wx_baseu_net-2.9', 'wx_gtk2u_html-2.9',
+                                    'wx_gtk2u_adv-2.9', 'wx_gtk2u_core-2.9', 'wx_baseu_xml-2.9', 'wx_baseu-2.9']
+        conf.env.LIB_WXWIDGETS = ['tiff', 'SM']
+    conf.in_msg = 1
+    wx_version = conf.check_cfg(package='', path=conf.options.wx_config, args='--version').strip()
+    conf.im_msg = 0
+    if wx_version != '2.9.4':
+        conf.fatal('wxwidgets version 2.9.4 is required; %s found' % wx_version)
 
 def build(bld):
     if bld.env.STATIC:
@@ -42,6 +56,8 @@ def build(bld):
     obj.includes = [ '..' ]
     obj.export_includes = ['.']
     obj.uselib = 'WXWIDGETS'
+    if bld.env.TARGET_LINUX:
+        obj.uselib += ' GTK'
     obj.use = 'libdcpomatic'
     obj.source = sources
     obj.target = 'dcpomatic-wx'
index 5691d341a0eba0ff0bd501c666c5032e050648cb..c5887e17d80b5f3f8b5faade084fac29c73978ec 100644 (file)
@@ -35,21 +35,37 @@ using namespace boost;
  *  @param s Sizer to add to.
  *  @param p Parent window for the wxStaticText.
  *  @param t Text for the wxStaticText.
+ *  @param left true if this label is a `left label'; ie the sort
+ *  of label which should be right-aligned on OS X.
  *  @param prop Proportion to pass when calling Add() on the wxSizer.
  */
 wxStaticText *
-add_label_to_sizer (wxSizer* s, wxWindow* p, wxString t, int prop)
+add_label_to_sizer (wxSizer* s, wxWindow* p, wxString t, bool left, int prop)
 {
+       int flags = wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT;
+#ifdef __WXOSX__
+       if (left) {
+               flags |= wxALIGN_RIGHT;
+               t += wxT (":");
+       }
+#endif 
        wxStaticText* m = new wxStaticText (p, wxID_ANY, t);
-       s->Add (m, prop, wxALIGN_CENTER_VERTICAL | wxALL, 6);
+       s->Add (m, prop, flags, 6);
        return m;
 }
 
 wxStaticText *
-add_label_to_grid_bag_sizer (wxGridBagSizer* s, wxWindow* p, wxString t, wxGBPosition pos, wxGBSpan span)
+add_label_to_grid_bag_sizer (wxGridBagSizer* s, wxWindow* p, wxString t, bool left, wxGBPosition pos, wxGBSpan span)
 {
+       int flags = wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT;
+#ifdef __WXOSX__
+       if (left) {
+               flags |= wxALIGN_RIGHT;
+               t += wxT (":");
+       }
+#endif 
        wxStaticText* m = new wxStaticText (p, wxID_ANY, t);
-       s->Add (m, pos, span, wxALIGN_CENTER_VERTICAL | wxALL, 6);
+       s->Add (m, pos, span, flags);
        return m;
 }
 
index bff11647edb653c92eade0b72ac6d3a939f04538..de6a09c35298fcc0b53460e4e8be8ef299695bed 100644 (file)
 
 */
 
+#ifndef DCPOMATIC_WX_UTIL_H
+#define DCPOMATIC_WX_UTIL_H
+
 #include <wx/wx.h>
 #include <wx/gbsizer.h>
 #include <boost/function.hpp>
 #include <boost/thread.hpp>
+#ifdef __WXGTK__
+#include <gtk/gtk.h>
+#endif
 
 class wxFilePickerCtrl;
 class wxSpinCtrl;
 class wxGridBagSizer;
 
+#define DCPOMATIC_SIZER_X_GAP 8
+#define DCPOMATIC_SIZER_Y_GAP 8
+
 /** @file src/wx/wx_util.h
  *  @brief Some utility functions and classes.
  */
 
 extern void error_dialog (wxWindow *, wxString);
 extern bool confirm_dialog (wxWindow *, wxString);
-extern wxStaticText* add_label_to_sizer (wxSizer *, wxWindow *, wxString, int prop = 0);
-extern wxStaticText* add_label_to_grid_bag_sizer (wxGridBagSizer *, wxWindow *, wxString, wxGBPosition, wxGBSpan span = wxDefaultSpan);
+extern wxStaticText* add_label_to_sizer (wxSizer *, wxWindow *, wxString, bool left, int prop = 0);
+extern wxStaticText* add_label_to_grid_bag_sizer (wxGridBagSizer *, wxWindow *, wxString, bool, wxGBPosition, wxGBSpan span = wxDefaultSpan);
 extern std::string wx_to_std (wxString);
 extern wxString std_to_wx (std::string);
 extern void dcpomatic_setup_i18n ();
@@ -69,3 +78,12 @@ extern void checked_set (wxTextCtrl* widget, std::string value);
 extern void checked_set (wxCheckBox* widget, bool value);
 extern void checked_set (wxRadioButton* widget, bool value);
 extern void checked_set (wxStaticText* widget, std::string value);
+
+/* GTK 2.24.17 has a buggy GtkFileChooserButton and it was put in Ubuntu 13.04.
+   Use our own dir picker as this is the least bad option I can think of.
+*/
+#if defined(__WXMSW__) || (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION == 24 && GTK_MICRO_VERSION == 17)
+#define DCPOMATIC_USE_OWN_DIR_PICKER
+#endif
+
+#endif
index 4494540a2ac31e5069f1a6c3f192b4c8be837b14..d6c7842d711692cc2acd39d296a41916af6cba57 100644 (file)
@@ -42,6 +42,7 @@
 #include "sndfile_decoder.h"
 #include "dcp_content_type.h"
 #include "ui_signaller.h"
+#include "ratio.h"
 #define BOOST_TEST_DYN_LINK
 #define BOOST_TEST_MODULE dcpomatic_test
 #include <boost/test/unit_test.hpp>
@@ -66,8 +67,8 @@ struct TestConfig
                Config::instance()->set_servers (vector<ServerDescription*> ());
                Config::instance()->set_server_port (61920);
                Config::instance()->set_default_dci_metadata (DCIMetadata ());
-               Config::instance()->set_default_container (0);
-               Config::instance()->set_default_dcp_content_type (0);
+               Config::instance()->set_default_container (static_cast<Ratio*> (0));
+               Config::instance()->set_default_dcp_content_type (static_cast<DCPContentType*> (0));
 
                ui_signaller = new UISignaller ();
        }
diff --git a/test/trimmer_test.cc b/test/trimmer_test.cc
new file mode 100644 (file)
index 0000000..ad2f2f6
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+    Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+
+    This program 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.
+
+    This program 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 this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+using boost::shared_ptr;
+
+shared_ptr<const Image> trimmer_test_last_video;
+int trimmer_test_video_frames = 0;
+shared_ptr<const AudioBuffers> trimmer_test_last_audio;
+
+void
+trimmer_test_video_helper (shared_ptr<const Image> image, bool, shared_ptr<Subtitle>)
+{
+       trimmer_test_last_video = image;
+       ++trimmer_test_video_frames;
+}
+
+void
+trimmer_test_audio_helper (shared_ptr<const AudioBuffers> audio)
+{
+       trimmer_test_last_audio = audio;
+}
+
+BOOST_AUTO_TEST_CASE (trimmer_passthrough_test)
+{
+       Trimmer trimmer (shared_ptr<Log> (), 0, 0, 200, 48000, 25, 25);
+       trimmer.Video.connect (bind (&trimmer_test_video_helper, _1, _2, _3));
+       trimmer.Audio.connect (bind (&trimmer_test_audio_helper, _1));
+
+       shared_ptr<SimpleImage> video (new SimpleImage (PIX_FMT_RGB24, libdcp::Size (1998, 1080), true));
+       shared_ptr<AudioBuffers> audio (new AudioBuffers (6, 42 * 1920));
+
+       trimmer.process_video (video, false, shared_ptr<Subtitle> ());
+       trimmer.process_audio (audio);
+
+       BOOST_CHECK_EQUAL (video.get(), trimmer_test_last_video.get());
+       BOOST_CHECK_EQUAL (audio.get(), trimmer_test_last_audio.get());
+       BOOST_CHECK_EQUAL (audio->frames(), trimmer_test_last_audio->frames());
+}
+
+
+/** Test the audio handling of the Trimmer */
+BOOST_AUTO_TEST_CASE (trimmer_audio_test)
+{
+       Trimmer trimmer (shared_ptr<Log> (), 25, 75, 200, 48000, 25, 25);
+
+       trimmer.Audio.connect (bind (&trimmer_test_audio_helper, _1));
+
+       /* 21 video frames-worth of audio frames; should be completely stripped */
+       trimmer_test_last_audio.reset ();
+       shared_ptr<AudioBuffers> audio (new AudioBuffers (6, 21 * 1920));
+       trimmer.process_audio (audio);
+       BOOST_CHECK (trimmer_test_last_audio == 0);
+
+       /* 42 more video frames-worth, 4 should be stripped from the start */
+       audio.reset (new AudioBuffers (6, 42 * 1920));
+       trimmer.process_audio (audio);
+       BOOST_CHECK (trimmer_test_last_audio);
+       BOOST_CHECK_EQUAL (trimmer_test_last_audio->frames(), 38 * 1920);
+
+       /* 42 more video frames-worth, should be kept as-is */
+       trimmer_test_last_audio.reset ();
+       audio.reset (new AudioBuffers (6, 42 * 1920));
+       trimmer.process_audio (audio);
+       BOOST_CHECK (trimmer_test_last_audio);
+       BOOST_CHECK_EQUAL (trimmer_test_last_audio->frames(), 42 * 1920);
+
+       /* 25 more video frames-worth, 5 should be trimmed from the end */
+       trimmer_test_last_audio.reset ();
+       audio.reset (new AudioBuffers (6, 25 * 1920));
+       trimmer.process_audio (audio);
+       BOOST_CHECK (trimmer_test_last_audio);
+       BOOST_CHECK_EQUAL (trimmer_test_last_audio->frames(), 20 * 1920);
+
+       /* Now some more; all should be trimmed */
+       trimmer_test_last_audio.reset ();
+       audio.reset (new AudioBuffers (6, 100 * 1920));
+       trimmer.process_audio (audio);
+       BOOST_CHECK (trimmer_test_last_audio == 0);
+}
+
+BOOST_AUTO_TEST_CASE (trim_end_test)
+{
+       Trimmer trimmer (shared_ptr<Log> (), 0, 75, 200, 48000, 25, 25);
+
+       shared_ptr<SimpleImage> image (new SimpleImage (PIX_FMT_RGB24, libdcp::Size (256, 256), true));
+
+       trimmer.Video.connect (bind (&trimmer_test_video_helper, _1, _2, _3));
+       trimmer_test_video_frames = 0;
+       for (int i = 0; i < 200; ++i) {
+               trimmer.process_video (image, false, shared_ptr<Subtitle> ());
+       }
+
+       BOOST_CHECK_EQUAL (trimmer_test_video_frames, 125);
+}
index 2fbbdacbf881d84390fcb0b9e7281809b56cbbd0..60d846aeab386e647084164e829e62de732aab22 100644 (file)
@@ -12,7 +12,7 @@ def configure(conf):
 def build(bld):
     obj = bld(features = 'cxx cxxprogram')
     obj.name   = 'unit-tests'
-    obj.uselib = 'BOOST_TEST CXML DCP OPENJPEG AVFORMAT AVFILTER AVCODEC AVUTIL SWSCALE POSTPROC'
+    obj.uselib = 'BOOST_TEST DCP OPENJPEG AVFORMAT AVFILTER AVCODEC AVUTIL SWSCALE POSTPROC CXML'
     obj.use    = 'libdcpomatic'
     obj.source = 'test.cc'
     obj.target = 'unit-tests'
diff --git a/wscript b/wscript
index b1d7eafe2a155fa134fe2298db66060f52ba412c..2c0a145801310f92ac5dd233206d801a20eccb35 100644 (file)
--- a/wscript
+++ b/wscript
@@ -29,7 +29,7 @@ def configure(conf):
     conf.env.TARGET_LINUX = not conf.env.TARGET_WINDOWS and not conf.env.TARGET_OSX
 
     conf.env.append_value('CXXFLAGS', ['-D__STDC_CONSTANT_MACROS', '-D__STDC_LIMIT_MACROS', '-msse', '-mfpmath=sse', '-ffast-math', '-fno-strict-aliasing',
-                                       '-Wall', '-Wno-attributes', '-Wextra'])
+                                       '-Wall', '-Wno-attributes', '-Wextra', '-D_FILE_OFFSET_BITS=64'])
 
     if conf.env.TARGET_WINDOWS:
         conf.env.append_value('CXXFLAGS', ['-DDCPOMATIC_WINDOWS', '-DWIN32_LEAN_AND_MEAN', '-DBOOST_USE_WINDOWS_H', '-DUNICODE'])
@@ -42,6 +42,7 @@ def configure(conf):
         conf.check(lib = 'bfd', uselib_store = 'BFD', msg = "Checking for library bfd")
         conf.check(lib = 'dbghelp', uselib_store = 'DBGHELP', msg = "Checking for library dbghelp")
         conf.check(lib = 'iberty', uselib_store = 'IBERTY', msg = "Checking for library iberty")
+        conf.check(lib = 'shlwapi', uselib_store = 'SHLWAPI', msg = "Checking for library shlwapi")
         boost_lib_suffix = '-mt'
         boost_thread = 'boost_thread_win32-mt'
     else:
@@ -78,15 +79,17 @@ def configure(conf):
     else:
         # This is hackio grotesquio for static builds (ie for .deb packages).  We need to link some things
         # statically and some dynamically, or things get horribly confused and the dynamic linker (I think)
-        # crashes horribly.  These calls do what the check_cfg calls would have done, but specify the
+        # crashes.  These calls do what the check_cfg calls would have done, but specify the
         # different bits as static or dynamic as required.  It'll break if you look at it funny, but
         # I think anyone else who builds would do so dynamically.
+        conf.env.HAVE_CXML = 1
+        conf.env.STLIB_CXML = ['cxml']
         conf.env.HAVE_DCP = 1
         conf.env.STLIB_DCP = ['dcp', 'asdcp-libdcp', 'kumu-libdcp']
         conf.env.LIB_DCP = ['glibmm-2.4', 'xml++-2.6', 'ssl', 'crypto', 'bz2']
         conf.env.HAVE_CXML = 1
         conf.env.STLIB_CXML = ['cxml']
-        conf.check_cfg(package = 'libxml++-2.6', args = '--cflags --libs', uselib_store = 'XML++', mandatory = True)
+        conf.check_cfg(package='libxml++-2.6', args='--cflags --libs', uselib_store='XML++', mandatory=True)
         conf.env.HAVE_AVFORMAT = 1
         conf.env.STLIB_AVFORMAT = ['avformat']
         conf.env.HAVE_AVFILTER = 1
@@ -108,6 +111,11 @@ def configure(conf):
 
     if conf.env.TARGET_LINUX:
         conf.check_cfg(package='liblzma', args='--cflags --libs', uselib_store='LZMA', mandatory=True)
+        if conf.env.STATIC:
+            conf.check_cfg(package='gtk+-2.0', args='--cflags --libs', uselib_store='GTK', mandatory=True)
+        else:
+            # On Linux we need to be able to include <gtk/gtk.h> to check GTK's version
+            conf.check_cfg(package='gtk+-2.0', args='--cflags', uselib_store='GTK', mandatory=True)
 
     conf.check_cfg(package = '', path = conf.options.magickpp_config, args = '--cppflags --cxxflags --libs', uselib_store = 'MAGICK', mandatory = True)
 
@@ -197,7 +205,7 @@ def configure(conf):
     conf.recurse('test')
 
 def build(bld):
-    create_version_cc(VERSION)
+    create_version_cc(VERSION, bld.env.CXXFLAGS)
 
     bld.recurse('src')
     bld.recurse('test')
@@ -223,7 +231,7 @@ def dist(ctx):
                GRSYMS GRTAGS GSYMS GTAGS
                """
 
-def create_version_cc(version):
+def create_version_cc(version, cxx_flags):
     if os.path.exists('.git'):
         cmd = "LANG= git log --abbrev HEAD^..HEAD ."
         output = subprocess.Popen(cmd, shell=True, stderr=subprocess.STDOUT, stdout=subprocess.PIPE).communicate()[0].splitlines()
@@ -236,6 +244,13 @@ def create_version_cc(version):
         text =  '#include "version.h"\n'
         text += 'char const * dcpomatic_git_commit = \"%s\";\n' % commit
         text += 'char const * dcpomatic_version = \"%s\";\n' % version
+
+        t = ''
+        for f in cxx_flags:
+            f = f.replace('"', '\\"')
+            t += f + ' '
+        text += 'char const * dcpomatic_cxx_flags = \"%s\";\n' % t[:-1]
+
         print('Writing version information to src/lib/version.cc')
         o = open('src/lib/version.cc', 'w')
         o.write(text)