From: Carl Hetherington Date: Tue, 9 Jul 2013 19:35:39 +0000 (+0100) Subject: Merge master. X-Git-Tag: v2.0.48~1337^2~302 X-Git-Url: https://git.carlh.net/gitweb/?p=dcpomatic.git;a=commitdiff_plain;h=89115db77729a2c99f1a09ff6a461720e16f889e Merge master. --- 89115db77729a2c99f1a09ff6a461720e16f889e diff --cc cscript index c51f3a033,6a9b48a89..e7ef219d4 --- a/cscript +++ b/cscript @@@ -41,21 -40,21 +40,21 @@@ def package(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,'dvdomatic_%s-1_%s.deb video extra' % (version, cpu) + print >>f,'dcpomatic_%s-1_%s.deb video extra' % (version, cpu) shutil.rmtree('build/deb', ignore_errors=True) os.makedirs('build/deb') os.chdir('build/deb') - shutil.move('../../dvdomatic-%s.tar.bz2' % version, 'dvdomatic_%s.orig.tar.bz2' % version) - target.command('tar xjf dvdomatic_%s.orig.tar.bz2' % version) - os.chdir('dvdomatic-%s' % version) + 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 +62,16 @@@ 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/libdvdomatic.pot'), - os.path.abspath('build/src/wx/libdvdomatic-wx.pot'), - os.path.abspath('build/src/tools/dvdomatic.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')] diff --cc platform/linux/control-12.04-32 index dc104958a,753df4931..a337944c3 --- a/platform/linux/control-12.04-32 +++ b/platform/linux/control-12.04-32 @@@ -2,15 -2,15 +2,15 @@@ Source: dcpomati Section: video Priority: extra Maintainer: Carl Hetherington - 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/dvdomatic +Homepage: http://carlh.net/software/dcpomatic -Package: dvdomatic +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) - DVD-o-matic generates Digital Cinema Packages (DCPs) from video and audio + 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 digital projectors. diff --cc platform/linux/control-12.04-64 index 09c636e4a,bb7672f53..c2cfdf5d7 --- a/platform/linux/control-12.04-64 +++ b/platform/linux/control-12.04-64 @@@ -2,11 -2,11 +2,11 @@@ Source: dcpomati Section: video Priority: extra Maintainer: Carl Hetherington - 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/dvdomatic +Homepage: http://carlh.net/software/dcpomatic -Package: dvdomatic +Package: dcpomatic Architecture: amd64 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) Description: Generator of Digital Cinema Packages (DCPs) diff --cc platform/linux/control-12.10-32 index 1330b3e5f,116e26b75..14dc5a0dc --- a/platform/linux/control-12.10-32 +++ b/platform/linux/control-12.10-32 @@@ -2,15 -2,15 +2,15 @@@ Source: dcpomati Section: video Priority: extra Maintainer: Carl Hetherington - 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/dvdomatic +Homepage: http://carlh.net/software/dcpomatic -Package: dvdomatic +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) - DVD-o-matic generates Digital Cinema Packages (DCPs) from video and audio + 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 digital projectors. diff --cc platform/linux/control-12.10-64 index ea1c491ed,486d1f225..8a8019f01 --- a/platform/linux/control-12.10-64 +++ b/platform/linux/control-12.10-64 @@@ -2,15 -2,15 +2,15 @@@ Source: dcpomati Section: video Priority: extra Maintainer: Carl Hetherington - 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/dvdomatic +Homepage: http://carlh.net/software/dcpomatic -Package: dvdomatic +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) - DVD-o-matic generates Digital Cinema Packages (DCPs) from video and audio + 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 digital projectors. diff --cc platform/osx/make_dmg.sh index 1fcdc6d06,a409d82fe..debd4aaac --- a/platform/osx/make_dmg.sh +++ b/platform/osx/make_dmg.sh @@@ -19,46 -19,58 +19,58 @@@ mkdir -p $WORK/$maco 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/dvdomatic $WORK/$libs/*.dylib; do +for obj in $WORK/$macos/dcpomatic $WORK/$libs/*.dylib; do deps=`otool -L $obj | awk '{print $1}' | egrep "(/Users/carl|libboost|libssh)"` changes="" for dep in $deps; do @@@ -70,13 -82,12 +82,12 @@@ fi done - pwd cp build/platform/osx/Info.plist $WORK/$approot -cp icons/dvdomatic.icns $WORK/$resources/DVD-o-matic.icns +cp icons/dcpomatic.icns $WORK/$resources/DVD-o-matic.icns -tmp_dmg=$WORK/dvdomatic_tmp.dmg -dmg="$WORK/DVD-o-matic $version.dmg" -vol_name=DVD-o-matic-$version +tmp_dmg=$WORK/dcpomatic_tmp.dmg +dmg="$WORK/DCP-o-matic $version.dmg" +vol_name=DCP-o-matic-$version mkdir -p $WORK/$vol_name diff --cc platform/windows/installer.nsi.32.in index 3a2cdb9e8,6dd1de2d9..314fe176f --- a/platform/windows/installer.nsi.32.in +++ b/platform/windows/installer.nsi.32.in @@@ -79,15 -80,15 +80,16 @@@ File "%deps%/bin/libpixman-1-0.dll 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/dvdomatic-wx.dll" -File "%binaries%/src/lib/dvdomatic.dll" -File "%binaries%/src/tools/dvdomatic.exe" -File "%binaries%/src/tools/dvdomatic_batch.exe" -File "%binaries%/src/tools/makedcp.exe" -File "%binaries%/src/tools/servomatic_cli.exe" -File "%binaries%/src/tools/servomatic_gui.exe" +File "%binaries%/src/wx/dcpomatic-wx.dll" +File "%binaries%/src/lib/dcpomatic.dll" +File "%binaries%/src/tools/dcpomatic.exe" +File "%binaries%/src/tools/dcpomatic_batch.exe" +File "%binaries%/src/tools/dcpomatic_cli.exe" +File "%binaries%/src/tools/dcpomatic_server_cli.exe" +File "%binaries%/src/tools/dcpomatic_server.exe" # I don't know why, but sometimes it seems that # delegates.xml must be in with the binaries, and @@@ -135,22 -136,12 +137,12 @@@ Section "Uninstall RMDir /r "$INSTDIR\*.*" RMDir "$INSTDIR" - <<<<<<< HEAD -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" +Delete "$DESKTOP\DCP-o-matic.lnk" +Delete "$DESKTOP\DCP-o-matic batch converter.lnk" +Delete "$DESKTOP\DCP-o-matic encode server.lnk" +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 diff --cc platform/windows/installer.nsi.64.in index f4f1e9068,e98a3a6d8..4bf959119 --- a/platform/windows/installer.nsi.64.in +++ b/platform/windows/installer.nsi.64.in @@@ -89,15 -90,15 +90,16 @@@ File "%deps%/bin/libpixman-1-0.dll 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/dvdomatic-wx.dll" -File "%binaries%/src/lib/dvdomatic.dll" -File "%binaries%/src/tools/dvdomatic.exe" -File "%binaries%/src/tools/dvdomatic_batch.exe" -File "%binaries%/src/tools/makedcp.exe" -File "%binaries%/src/tools/servomatic_cli.exe" -File "%binaries%/src/tools/servomatic_gui.exe" +File "%binaries%/src/wx/dcpomatic-wx.dll" +File "%binaries%/src/lib/dcpomatic.dll" +File "%binaries%/src/tools/dcpomatic.exe" +File "%binaries%/src/tools/dcpomatic_batch.exe" +File "%binaries%/src/tools/dcpomatic_cli.exe" +File "%binaries%/src/tools/dcpomatic_server_cli.exe" +File "%binaries%/src/tools/dcpomatic_server.exe" # I don't know why, but sometimes it seems that # delegates.xml must be in with the binaries, and diff --cc src/lib/config.cc index c9ec730f2,d2d7fa2fd..e0fbcc703 --- a/src/lib/config.cc +++ b/src/lib/config.cc @@@ -37,21 -36,19 +37,22 @@@ using std::vector 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; 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) - , _reference_scaler (Scaler::from_id (N_("bicubic"))) , _tms_path (N_(".")) , _sound_processor (SoundProcessor::from_id (N_("dolby_cp750"))) - , _default_format (0) + , _default_still_length (10) + , _default_container (Ratio::from_id ("185")) , _default_dcp_content_type (0) { _allowed_dcp_frame_rates.push_back (24); diff --cc src/lib/cross.cc index ffd44eb02,124697fb4..ee0ef89b2 --- a/src/lib/cross.cc +++ b/src/lib/cross.cc @@@ -20,27 -20,35 +20,35 @@@ #include #include #include "cross.h" - #ifdef DCPOMATIC_POSIX + #include "compose.hpp" + #include "log.h" -#ifdef DVDOMATIC_LINUX ++#ifdef DCPOMATIC_LINUX #include + #include #endif -#ifdef DVDOMATIC_WINDOWS +#ifdef DCPOMATIC_WINDOWS - #include "windows.h" + #include + #undef DATADIR + #include #endif -#ifdef DVDOMATIC_OSX +#ifdef DCPOMATIC_OSX #include #endif using std::pair; + using std::list; using std::ifstream; using std::string; + using std::make_pair; + using boost::shared_ptr; void -dvdomatic_sleep (int s) +dcpomatic_sleep (int s) { -#ifdef DVDOMATIC_POSIX +#ifdef DCPOMATIC_POSIX sleep (s); #endif -#ifdef DVDOMATIC_WINDOWS +#ifdef DCPOMATIC_WINDOWS Sleep (s * 1000); #endif } @@@ -81,3 -89,101 +89,101 @@@ cpu_info ( return info; } + void + run_ffprobe (boost::filesystem::path content, boost::filesystem::path out, shared_ptr log) + { -#ifdef DVDOMATIC_WINDOWS ++#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 > + mount_info () + { + list > m; + -#ifdef DVDOMATIC_LINUX ++#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; + } diff --cc src/lib/cross.h index d185286b1,d9cc2d12f..a00fee679 --- a/src/lib/cross.h +++ b/src/lib/cross.h @@@ -17,9 -17,16 +17,15 @@@ */ -#include + #include + -class Log; - -#ifdef DVDOMATIC_WINDOWS +#ifdef DCPOMATIC_WINDOWS #define WEXITSTATUS(w) (w) #endif -extern void dvdomatic_sleep (int); ++class Log; ++ +void dcpomatic_sleep (int); extern std::pair cpu_info (); + extern void run_ffprobe (boost::filesystem::path, boost::filesystem::path, boost::shared_ptr); + extern std::list > mount_info (); diff --cc src/lib/encoder.cc index c3865d2c1,0ac32d3bf..d3181acd9 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@@ -40,9 -47,9 +40,10 @@@ using std::stringstream using std::vector; using std::list; using std::cout; + using std::min; using std::make_pair; -using namespace boost; +using boost::shared_ptr; +using boost::optional; int const Encoder::_history_size = 25; diff --cc src/lib/ffmpeg_decoder.cc index a3fdaf9b1,c2143b949..bf0949130 --- a/src/lib/ffmpeg_decoder.cc +++ b/src/lib/ffmpeg_decoder.cc @@@ -75,31 -158,70 +75,30 @@@ FFmpegDecoder::FFmpegDecoder (shared_pt } } -void -FFmpegDecoder::setup_video () +double +FFmpegDecoder::compute_pts_offset (double first_video, double first_audio, float video_frame_rate) { - assert (first_video >= 0); - assert (first_audio >= 0); - - boost::mutex::scoped_lock lm (_mutex); + double const old_first_video = first_video; - _video_codec_context = _format_context->streams[_video_stream]->codec; - _video_codec = avcodec_find_decoder (_video_codec_context->codec_id); - - if (_video_codec == 0) { - throw DecodeError (_("could not find video decoder")); + /* Round the first video to a frame boundary */ + if (fabs (rint (first_video * video_frame_rate) - first_video * video_frame_rate) > 1e-6) { + first_video = ceil (first_video * video_frame_rate) / video_frame_rate; } - if (avcodec_open2 (_video_codec_context, _video_codec, 0) < 0) { - throw DecodeError (N_("could not open video decoder")); - } + /* Compute the required offset (also removing any common start delay) */ + return first_video - old_first_video - min (first_video, first_audio); } -void -FFmpegDecoder::setup_audio () +FFmpegDecoder::~FFmpegDecoder () { + boost::mutex::scoped_lock lm (_mutex); - - if (!_audio_stream) { - return; - } - - shared_ptr ffa = dynamic_pointer_cast (_audio_stream); - assert (ffa); - - _audio_codec_context = _format_context->streams[ffa->id()]->codec; - _audio_codec = avcodec_find_decoder (_audio_codec_context->codec_id); + - if (_audio_codec == 0) { - throw DecodeError (_("could not find audio decoder")); - } - - if (avcodec_open2 (_audio_codec_context, _audio_codec, 0) < 0) { - throw DecodeError (N_("could not open audio decoder")); + if (_subtitle_codec_context) { + avcodec_close (_subtitle_codec_context); } -} +} void -FFmpegDecoder::setup_subtitle () -{ - boost::mutex::scoped_lock lm (_mutex); - - if (!_subtitle_stream || _subtitle_stream->id() >= int (_format_context->nb_streams)) { - return; - } - - _subtitle_codec_context = _format_context->streams[_subtitle_stream->id()]->codec; - _subtitle_codec = avcodec_find_decoder (_subtitle_codec_context->codec_id); - - if (_subtitle_codec == 0) { - throw DecodeError (_("could not find subtitle decoder")); - } - - if (avcodec_open2 (_subtitle_codec_context, _subtitle_codec, 0) < 0) { - throw DecodeError (N_("could not open subtitle decoder")); - } -} - - -bool FFmpegDecoder::pass () { int r = av_read_frame (_format_context, &_packet); @@@ -333,164 -604,123 +332,156 @@@ FFmpegDecoder::do_seek (VideoContent::F av_free_packet (&_packet); } } - - return r < 0; } -shared_ptr -FFmpegAudioStream::create (string t, optional v) +void +FFmpegDecoder::decode_audio_packet () { - if (!v) { - /* version < 1; no type in the string, and there's only FFmpeg streams anyway */ - return shared_ptr (new FFmpegAudioStream (t, v)); - } + /* Audio packets can contain multiple frames, so we may have to call avcodec_decode_audio4 + several times. + */ + + AVPacket copy_packet = _packet; - stringstream s (t); - string type; - s >> type; - if (type != N_("ffmpeg")) { - return shared_ptr (); - } + while (copy_packet.size > 0) { - return shared_ptr (new FFmpegAudioStream (t, v)); + int frame_finished; + int const decode_result = avcodec_decode_audio4 (audio_codec_context(), _frame, &frame_finished, ©_packet); + if (decode_result >= 0) { + if (frame_finished) { + + if (_audio_position == 0) { + /* Where we are in the source, in seconds */ + double const pts = av_q2d (_format_context->streams[copy_packet.stream_index]->time_base) + * av_frame_get_best_effort_timestamp(_frame) - _pts_offset; + + if (pts > 0) { + /* Emit some silence */ + shared_ptr silence ( + new AudioBuffers ( + _ffmpeg_content->audio_channels(), + pts * _ffmpeg_content->content_audio_frame_rate() + ) + ); + + silence->make_silent (); + audio (silence, _audio_position); + } + } + - - 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; + } + } } -FFmpegAudioStream::FFmpegAudioStream (string t, optional version) +bool +FFmpegDecoder::decode_video_packet () { - stringstream n (t); - - int name_index = 4; - if (!version) { - name_index = 2; - int channels; - n >> _id >> channels; - _channel_layout = av_get_default_channel_layout (channels); - _sample_rate = 0; - } else { - string type; - /* Current (marked version 1) */ - n >> type >> _id >> _sample_rate >> _channel_layout; - assert (type == N_("ffmpeg")); + int frame_finished; + if (avcodec_decode_video2 (video_codec_context(), _frame, &frame_finished, &_packet) < 0 || !frame_finished) { + return false; } + + boost::mutex::scoped_lock lm (_filter_graphs_mutex); - for (int i = 0; i < name_index; ++i) { - size_t const s = t.find (' '); - if (s != string::npos) { - t = t.substr (s + 1); - } + shared_ptr graph; + + list >::iterator i = _filter_graphs.begin(); + while (i != _filter_graphs.end() && !(*i)->can_process (libdcp::Size (_frame->width, _frame->height), (AVPixelFormat) _frame->format)) { + ++i; } - _name = t; -} + if (i == _filter_graphs.end ()) { + shared_ptr film = _film.lock (); + assert (film); -string -FFmpegAudioStream::to_string () const -{ - return String::compose (N_("ffmpeg %1 %2 %3 %4"), _id, _sample_rate, _channel_layout, _name); -} + graph.reset (new FilterGraph (_ffmpeg_content, libdcp::Size (_frame->width, _frame->height), (AVPixelFormat) _frame->format)); + _filter_graphs.push_back (graph); -void -FFmpegDecoder::film_changed (Film::Property p) -{ - switch (p) { - case Film::CROP: - case Film::FILTERS: - { - boost::mutex::scoped_lock lm (_filter_graphs_mutex); - _filter_graphs.clear (); + film->log()->log (String::compose (N_("New graph for %1x%2, pixel format %3"), _frame->width, _frame->height, _frame->format)); + } else { + graph = *i; } - OutputChanged (); - break; - default: - break; + list > images = graph->process (_frame); + + string post_process = Filter::ffmpeg_strings (_ffmpeg_content->filters()).second; + + for (list >::iterator i = images.begin(); i != images.end(); ++i) { + + shared_ptr image = *i; + if (!post_process.empty ()) { + image = image->post_process (post_process, true); + } + + int64_t const bet = av_frame_get_best_effort_timestamp (_frame); + if (bet != AV_NOPTS_VALUE) { + + double const pts = bet * av_q2d (_format_context->streams[_video_stream]->time_base) - _pts_offset; + double const next = _video_position / _ffmpeg_content->video_frame_rate(); + double const one_frame = 1 / _ffmpeg_content->video_frame_rate (); + double delta = pts - next; + + while (delta > one_frame) { + /* This PTS is more than one frame forward in time of where we think we should be; emit + a black frame. + */ + boost::shared_ptr black ( + new SimpleImage ( + static_cast (_frame->format), + libdcp::Size (video_codec_context()->width, video_codec_context()->height), + true + ) + ); + + black->make_black (); + video (image, false, _video_position); + delta -= one_frame; + } + + if (delta > -one_frame) { + /* This PTS is within a frame of being right; emit this (otherwise it will be dropped) */ + video (image, false, _video_position); + } + } else { + shared_ptr film = _film.lock (); + assert (film); + film->log()->log ("Dropping frame without PTS"); + } } -} -/** @return Length (in video frames) according to our content's header */ -SourceFrame -FFmpegDecoder::length () const -{ - return (double(_format_context->duration) / AV_TIME_BASE) * frames_per_second(); + return true; } + void -FFmpegDecoder::decode_audio_packet () +FFmpegDecoder::setup_subtitle () { - shared_ptr ffa = dynamic_pointer_cast (_audio_stream); - assert (ffa); - - /* Audio packets can contain multiple frames, so we may have to call avcodec_decode_audio4 - several times. - */ + boost::mutex::scoped_lock lm (_mutex); - AVPacket copy_packet = _packet; + if (!_ffmpeg_content->subtitle_stream() || _ffmpeg_content->subtitle_stream()->id >= int (_format_context->nb_streams)) { + return; + } - while (copy_packet.size > 0) { + _subtitle_codec_context = _format_context->streams[_ffmpeg_content->subtitle_stream()->id]->codec; + _subtitle_codec = avcodec_find_decoder (_subtitle_codec_context->codec_id); - int frame_finished; - int const decode_result = avcodec_decode_audio4 (_audio_codec_context, _frame, &frame_finished, ©_packet); - if (decode_result < 0) { - /* error */ - break; - } - - if (frame_finished) { - - /* Where we are in the source, in seconds */ - double const source_pts_seconds = av_q2d (_format_context->streams[copy_packet.stream_index]->time_base) - * av_frame_get_best_effort_timestamp(_frame); - - 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 == _film->audio_channels()); - Audio (deinterleave_audio (_frame->data, data_size), source_pts_seconds); - } - - copy_packet.data += decode_result; - copy_packet.size -= decode_result; + if (_subtitle_codec == 0) { + throw DecodeError (_("could not find subtitle decoder")); + } + + if (avcodec_open2 (_subtitle_codec_context, _subtitle_codec, 0) < 0) { + throw DecodeError (N_("could not open subtitle decoder")); } } + +bool +FFmpegDecoder::done () const +{ + bool const vd = !_decode_video || (_video_position >= _ffmpeg_content->video_length()); + bool const ad = !_decode_audio || !_ffmpeg_content->audio_stream() || (_audio_position >= _ffmpeg_content->audio_length()); + return vd && ad; +} + diff --cc src/lib/film.cc index ad565aca0,ce555ac8b..fa75ab1f1 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@@ -99,8 -107,9 +99,9 @@@ Film::Film (string d , _colour_lut (0) , _j2k_bandwidth (200000000) , _dci_metadata (Config::instance()->default_dci_metadata ()) - , _dcp_frame_rate (0) + , _dcp_video_frame_rate (24) + , _dcp_audio_channels (MAX_AUDIO_CHANNELS) + , _minimum_audio_channels (0) - , _source_frame_rate (0) , _dirty (false) { set_dci_date_today (); @@@ -127,7 -133,24 +128,6 @@@ } set_directory (result.string ()); - - if (!boost::filesystem::exists (directory())) { - if (must_exist) { - throw OpenFileError (directory()); - } else { - boost::filesystem::create_directory (directory()); - } - } - - _sndfile_stream = SndfileStream::create (); - -- _log.reset (new FileLog (file ("log"))); - - if (must_exist) { - read_metadata (); - } else { - write_metadata (); - } } Film::Film (Film const & o) @@@ -147,11 -184,24 +147,12 @@@ , _colour_lut (o._colour_lut) , _j2k_bandwidth (o._j2k_bandwidth) , _dci_metadata (o._dci_metadata) + , _dcp_video_frame_rate (o._dcp_video_frame_rate) , _dci_date (o._dci_date) - , _dcp_frame_rate (o._dcp_frame_rate) + , _minimum_audio_channels (o._minimum_audio_channels) - , _size (o._size) - , _length (o._length) - , _content_digest (o._content_digest) - , _content_audio_streams (o._content_audio_streams) - , _sndfile_stream (o._sndfile_stream) - , _subtitle_streams (o._subtitle_streams) - , _source_frame_rate (o._source_frame_rate) , _dirty (o._dirty) { - -} - -Film::~Film () -{ - + _playlist->ContentChanged.connect (bind (&Film::playlist_content_changed, this, _1, _2)); } string @@@ -268,13 -336,17 +268,17 @@@ Film::make_dcp ( #endif pair const c = cpu_info (); log()->log (String::compose ("CPU: %1, %2 processors", c.first, c.second)); + list > const m = mount_info (); + for (list >::const_iterator i = m.begin(); i != m.end(); ++i) { + log()->log (String::compose ("Mount: %1 %2", i->first, i->second)); + } - if (format() == 0) { - throw MissingSettingError (_("format")); + if (container() == 0) { + throw MissingSettingError (_("container")); } - if (content().empty ()) { - throw MissingSettingError (_("content")); + if (_playlist->content().empty ()) { + throw StringError (_("You must add some content to the DCP before creating it")); } if (dcp_content_type() == 0) { @@@ -328,34 -449,82 +332,35 @@@ Film::write_metadata () cons boost::filesystem::create_directories (directory()); - string const m = file ("metadata"); - ofstream f (m.c_str ()); - if (!f.good ()) { - throw CreateFileError (m); - } + xmlpp::Document doc; + xmlpp::Element* root = doc.create_root_node ("Metadata"); - f << "version " << state_version << endl; + root->add_child("Version")->add_child_text (lexical_cast (state_version)); + root->add_child("Name")->add_child_text (_name); + root->add_child("UseDCIName")->add_child_text (_use_dci_name ? "1" : "0"); - /* User stuff */ - f << "name " << _name << endl; - f << "use_dci_name " << _use_dci_name << endl; - f << "content " << _content << endl; - f << "trust_content_header " << (_trust_content_header ? "1" : "0") << endl; if (_dcp_content_type) { - f << "dcp_content_type " << _dcp_content_type->dci_name () << endl; - } - if (_format) { - f << "format " << _format->as_metadata () << endl; - } - f << "left_crop " << _crop.left << endl; - f << "right_crop " << _crop.right << endl; - f << "top_crop " << _crop.top << endl; - f << "bottom_crop " << _crop.bottom << endl; - for (vector::const_iterator i = _filters.begin(); i != _filters.end(); ++i) { - f << "filter " << (*i)->id () << endl; - } - f << "scaler " << _scaler->id () << endl; - f << "trim_start " << _trim_start << endl; - f << "trim_end " << _trim_end << endl; - switch (_trim_type) { - case CPL: - f << "trim_type cpl\n"; - break; - case ENCODE: - f << "trim_type encode\n"; - break; - } - f << "dcp_ab " << (_dcp_ab ? "1" : "0") << endl; - if (_content_audio_stream) { - f << "selected_content_audio_stream " << _content_audio_stream->to_string() << endl; + root->add_child("DCPContentType")->add_child_text (_dcp_content_type->dci_name ()); } - for (vector::const_iterator i = _external_audio.begin(); i != _external_audio.end(); ++i) { - f << "external_audio " << *i << endl; - } - f << "use_content_audio " << (_use_content_audio ? "1" : "0") << endl; - f << "audio_gain " << _audio_gain << endl; - f << "audio_delay " << _audio_delay << endl; - f << "still_duration " << _still_duration << endl; - if (_subtitle_stream) { - f << "selected_subtitle_stream " << _subtitle_stream->to_string() << endl; - } - f << "with_subtitles " << _with_subtitles << endl; - f << "subtitle_offset " << _subtitle_offset << endl; - f << "subtitle_scale " << _subtitle_scale << endl; - f << "colour_lut " << _colour_lut << endl; - f << "j2k_bandwidth " << _j2k_bandwidth << endl; - _dci_metadata.write (f); - f << "dci_date " << boost::gregorian::to_iso_string (_dci_date) << endl; - f << "dcp_frame_rate " << _dcp_frame_rate << endl; - f << "minimum_audio_channels " << _minimum_audio_channels << endl; - f << "width " << _size.width << endl; - f << "height " << _size.height << endl; - f << "length " << _length.get_value_or(0) << endl; - f << "content_digest " << _content_digest << endl; - - for (vector >::const_iterator i = _content_audio_streams.begin(); i != _content_audio_streams.end(); ++i) { - f << "content_audio_stream " << (*i)->to_string () << endl; - } - - f << "external_audio_stream " << _sndfile_stream->to_string() << endl; - for (vector >::const_iterator i = _subtitle_streams.begin(); i != _subtitle_streams.end(); ++i) { - f << "subtitle_stream " << (*i)->to_string () << endl; + if (_container) { + root->add_child("Container")->add_child_text (_container->id ()); } - f << "source_frame_rate " << _source_frame_rate << endl; + root->add_child("Scaler")->add_child_text (_scaler->id ()); + root->add_child("WithSubtitles")->add_child_text (_with_subtitles ? "1" : "0"); + root->add_child("SubtitleOffset")->add_child_text (lexical_cast (_subtitle_offset)); + root->add_child("SubtitleScale")->add_child_text (lexical_cast (_subtitle_scale)); + root->add_child("ColourLUT")->add_child_text (lexical_cast (_colour_lut)); + root->add_child("J2KBandwidth")->add_child_text (lexical_cast (_j2k_bandwidth)); + _dci_metadata.as_xml (root->add_child ("DCIMetadata")); + root->add_child("DCPVideoFrameRate")->add_child_text (lexical_cast (_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 (_dcp_audio_channels)); ++ root->add_child("MinimumAudioChannels")->add_child_text (lexical_cast (_minimum_audio_channels)); + _playlist->as_xml (root->add_child ("Playlist")); + + doc.write_to_file_formatted (file ("metadata.xml")); _dirty = false; } @@@ -390,19 -678,25 +395,20 @@@ Film::read_metadata ( } } - if (!version) { - if (audio_sample_rate) { - /* version < 1 didn't specify sample rate in the audio streams, so fill it in here */ - for (vector >::iterator i = _content_audio_streams.begin(); i != _content_audio_streams.end(); ++i) { - (*i)->set_sample_rate (audio_sample_rate.get()); - } - } + _scaler = Scaler::from_id (f.string_child ("Scaler")); + _with_subtitles = f.bool_child ("WithSubtitles"); + _subtitle_offset = f.number_child ("SubtitleOffset"); + _subtitle_scale = f.number_child ("SubtitleScale"); + _colour_lut = f.number_child ("ColourLUT"); + _j2k_bandwidth = f.number_child ("J2KBandwidth"); + _dci_metadata = DCIMetadata (f.node_child ("DCIMetadata")); + _dcp_video_frame_rate = f.number_child ("DCPVideoFrameRate"); + _dci_date = boost::gregorian::from_undelimited_string (f.string_child ("DCIDate")); + _dcp_audio_channels = f.number_child ("DCPAudioChannels"); ++ _minimum_audio_channels = f.number_child ("MinimumAudioChannels"); - /* also the selected stream was specified as an index */ - if (audio_stream_index && audio_stream_index.get() >= 0 && audio_stream_index.get() < (int) _content_audio_streams.size()) { - _content_audio_stream = _content_audio_streams[audio_stream_index.get()]; - } + _playlist->set_from_xml (shared_from_this(), f.node_child ("Playlist")); - /* similarly the subtitle */ - if (subtitle_stream_index && subtitle_stream_index.get() >= 0 && subtitle_stream_index.get() < (int) _subtitle_streams.size()) { - _subtitle_stream = _subtitle_streams[subtitle_stream_index.get()]; - } - } - _dirty = false; } @@@ -641,8 -1318,78 +647,18 @@@ Film::set_dci_metadata (DCIMetadata m } -void -Film::set_dcp_frame_rate (int f) -{ - { - boost::mutex::scoped_lock lm (_state_mutex); - _dcp_frame_rate = f; - } - signal_changed (DCP_FRAME_RATE); -} - + 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_size (libdcp::Size s) -{ - { - boost::mutex::scoped_lock lm (_state_mutex); - _size = s; - } - signal_changed (SIZE); -} - -void -Film::set_length (SourceFrame l) -{ - { - boost::mutex::scoped_lock lm (_state_mutex); - _length = l; - } - signal_changed (LENGTH); -} - -void -Film::unset_length () -{ - { - boost::mutex::scoped_lock lm (_state_mutex); - _length = boost::none; - } - signal_changed (LENGTH); -} - -void -Film::set_content_digest (string d) -{ - { - boost::mutex::scoped_lock lm (_state_mutex); - _content_digest = d; - } - _dirty = true; -} - -void -Film::set_content_audio_streams (vector > s) -{ - { - boost::mutex::scoped_lock lm (_state_mutex); - _content_audio_streams = s; - } - signal_changed (CONTENT_AUDIO_STREAMS); -} - -void -Film::set_subtitle_streams (vector > s) +Film::set_dcp_video_frame_rate (int f) { { boost::mutex::scoped_lock lm (_state_mutex); diff --cc src/lib/film.h index 5bb9acf29,ca9bd57f4..f5a7c1246 --- a/src/lib/film.h +++ b/src/lib/film.h @@@ -140,7 -148,13 +140,8 @@@ public COLOUR_LUT, J2K_BANDWIDTH, DCI_METADATA, - SIZE, - LENGTH, - CONTENT_AUDIO_STREAMS, - SUBTITLE_STREAMS, - SOURCE_FRAME_RATE, - DCP_FRAME_RATE, + DCP_VIDEO_FRAME_RATE, + MINIMUM_AUDIO_CHANNELS }; @@@ -206,17 -297,53 +207,22 @@@ return _dci_metadata; } - int dcp_frame_rate () const { - boost::mutex::scoped_lock lm (_state_mutex); - return _dcp_frame_rate; - } - - libdcp::Size size () const { - boost::mutex::scoped_lock lm (_state_mutex); - return _size; - } - - boost::optional length () const { - boost::mutex::scoped_lock lm (_state_mutex); - return _length; - } - - std::string content_digest () const { + /* XXX: -> "video_frame_rate" */ + int dcp_video_frame_rate () const { boost::mutex::scoped_lock lm (_state_mutex); - return _content_digest; - } - - std::vector > content_audio_streams () const { - boost::mutex::scoped_lock lm (_state_mutex); - return _content_audio_streams; + return _dcp_video_frame_rate; } - std::vector > subtitle_streams () const { - boost::mutex::scoped_lock lm (_state_mutex); - return _subtitle_streams; - } - - float source_frame_rate () const { + int dcp_audio_channels () const { boost::mutex::scoped_lock lm (_state_mutex); - if (content_type() == STILL) { - return 24; - } - - return _source_frame_rate; + return _dcp_audio_channels; } + int minimum_audio_channels () const { + boost::mutex::scoped_lock lm (_state_mutex); + return _minimum_audio_channels; + } + - boost::shared_ptr audio_stream () const; - bool has_audio () const; - /* SET */ void set_directory (std::string); @@@ -234,14 -377,20 +240,15 @@@ void set_colour_lut (int); void set_j2k_bandwidth (int); void set_dci_metadata (DCIMetadata); - void set_dcp_frame_rate (int); - void set_size (libdcp::Size); - void set_length (SourceFrame); - void unset_length (); - void set_content_digest (std::string); - void set_content_audio_streams (std::vector >); - void set_subtitle_streams (std::vector >); - void set_source_frame_rate (float); + void set_dcp_video_frame_rate (int); + void set_dci_date_today (); + void set_minimum_audio_channels (int); - /** Emitted when some property has changed */ + /** Emitted when some property has of the Film has changed */ mutable boost::signals2::signal Changed; - boost::signals2::signal AudioAnalysisSucceeded; + /** Emitted when some property of our content has changed */ + mutable boost::signals2::signal, int)> ContentChanged; /** Current version number of the state file */ static int const state_version; @@@ -291,14 -481,32 +298,15 @@@ private int _colour_lut; /** bandwidth for J2K files in bits per second */ int _j2k_bandwidth; - /** DCI naming stuff */ DCIMetadata _dci_metadata; + /** Frames per second to run our DCP at */ + int _dcp_video_frame_rate; /** The date that we should use in a DCI name */ boost::gregorian::date _dci_date; - /** Frames per second to run our DCP at */ - int _dcp_frame_rate; + int _dcp_audio_channels; + int _minimum_audio_channels; - /* Data which are cached to speed things up */ - - /** Size, in pixels, of the source (ignoring cropping) */ - libdcp::Size _size; - /** The length of the source, in video frames (as far as we know) */ - boost::optional _length; - /** MD5 digest of our content file */ - std::string _content_digest; - /** The audio streams in our content */ - std::vector > _content_audio_streams; - /** A stream to represent possible external audio (will always exist) */ - boost::shared_ptr _sndfile_stream; - /** the subtitle streams that we can use */ - std::vector > _subtitle_streams; - /** Frames per second of the source */ - float _source_frame_rate; - /** true if our state has changed since we last saved it */ mutable bool _dirty; diff --cc src/lib/ratio.h index 6916a7491,000000000..5480eee12 mode 100644,000000..100644 --- a/src/lib/ratio.h +++ b/src/lib/ratio.h @@@ -1,66 -1,0 +1,71 @@@ +/* + Copyright (C) 2013 Carl Hetherington + + 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. + +*/ + ++#ifndef DCPOMATIC_RATIO_H ++#define DCPOMATIC_RATIO_H ++ +#include +#include + +class Ratio +{ +public: + Ratio (float ratio, std::string id, std::string n, std::string d) + : _ratio (ratio) + , _id (id) + , _nickname (n) + , _dci_name (d) + {} + + libdcp::Size size (libdcp::Size) const; + + std::string id () const { + return _id; + } + + std::string nickname () const { + return _nickname; + } + + std::string dci_name () const { + return _dci_name; + } + + float ratio () const { + return _ratio; + } + + static void setup_ratios (); + static Ratio const * from_id (std::string i); + static std::vector all () { + return _ratios; + } + +private: + float _ratio; + /** id for use in metadata */ + std::string _id; + /** nickname (e.g. Flat, Scope) */ + std::string _nickname; + std::string _dci_name; + + static std::vector _ratios; +}; ++ ++#endif diff --cc src/lib/util.h index c68bb4f16,c9e5bef16..7af8ffedf --- a/src/lib/util.h +++ b/src/lib/util.h @@@ -52,9 -50,9 +52,10 @@@ 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); extern std::string seconds_to_approximate_hms (int); extern void stacktrace (std::ostream &, int); extern std::string dependency_version_summary (); diff --cc src/lib/version.h index 518862fc4,e1ec9067c..b70be8343 --- a/src/lib/version.h +++ b/src/lib/version.h @@@ -1,3 -1,4 +1,4 @@@ -extern char const * dvdomatic_version; -extern char const * dvdomatic_git_commit; -extern char const * dvdomatic_cxx_flags; +extern char const * dcpomatic_version; +extern char const * dcpomatic_git_commit; ++extern char const * dcpomatic_cxx_flags; diff --cc src/lib/wscript index 3e7f2e33b,7c7a64d58..2f8653984 --- a/src/lib/wscript +++ b/src/lib/wscript @@@ -73,17 -69,15 +73,17 @@@ 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++' + obj.source = sources + " version.cc" + obj.target = 'dcpomatic' - obj.target = 'dvdomatic' - - i18n.po_to_mo(os.path.join('src', 'lib'), 'libdvdomatic', bld) + i18n.po_to_mo(os.path.join('src', 'lib'), 'libdcpomatic', bld) def pot(bld): - i18n.pot(os.path.join('src', 'lib'), sources, 'libdvdomatic') + i18n.pot(os.path.join('src', 'lib'), sources, 'libdcpomatic') def pot_merge(bld): - i18n.pot_merge(os.path.join('src', 'lib'), 'libdvdomatic') + i18n.pot_merge(os.path.join('src', 'lib'), 'libdcpomatic') diff --cc src/tools/dcpomatic.cc index 683e60ceb,000000000..ac39d4fed mode 100644,000000..100644 --- a/src/tools/dcpomatic.cc +++ b/src/tools/dcpomatic.cc @@@ -1,518 -1,0 +1,518 @@@ +/* + Copyright (C) 2012 Carl Hetherington + + 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 +#include +#include +#ifdef __WXMSW__ +#include +#endif +#ifdef __WXOSX__ +#include +#endif +#include +#include +#include +#include "wx/film_viewer.h" +#include "wx/film_editor.h" +#include "wx/job_manager_view.h" +#include "wx/config_dialog.h" +#include "wx/job_wrapper.h" +#include "wx/wx_util.h" +#include "wx/new_film_dialog.h" +#include "wx/properties_dialog.h" +#include "wx/wx_ui_signaller.h" +#include "wx/about_dialog.h" +#include "lib/film.h" +#include "lib/config.h" +#include "lib/util.h" +#include "lib/version.h" +#include "lib/ui_signaller.h" +#include "lib/log.h" + +using std::cout; +using std::string; +using std::wstring; +using std::stringstream; +using std::map; +using std::make_pair; +using std::exception; +using std::ofstream; +using boost::shared_ptr; + +static FilmEditor* film_editor = 0; +static FilmViewer* film_viewer = 0; +static shared_ptr film; +static std::string log_level; +static std::string film_to_load; +static std::string film_to_create; +static wxMenu* jobs_menu = 0; + +static void set_menu_sensitivity (); + +class FilmChangedDialog +{ +public: + FilmChangedDialog () + { + _dialog = new wxMessageDialog ( + 0, + wxString::Format (_("Save changes to film \"%s\" before closing?"), std_to_wx (film->name ()).data()), + _("Film changed"), + wxYES_NO | wxYES_DEFAULT | wxICON_QUESTION + ); + } + + ~FilmChangedDialog () + { + _dialog->Destroy (); + } + + int run () + { + return _dialog->ShowModal (); + } + +private: + wxMessageDialog* _dialog; +}; + + +void +maybe_save_then_delete_film () +{ + if (!film) { + return; + } + + if (film->dirty ()) { + FilmChangedDialog d; + switch (d.run ()) { + case wxID_NO: + break; + case wxID_YES: + film->write_metadata (); + break; + } + } + + film.reset (); +} + +enum Sensitivity { + ALWAYS, + NEEDS_FILM +}; + +map menu_items; + +void +add_item (wxMenu* menu, wxString text, int id, Sensitivity sens) +{ + wxMenuItem* item = menu->Append (id, text); + menu_items.insert (make_pair (item, sens)); +} + +void +set_menu_sensitivity () +{ + for (map::iterator i = menu_items.begin(); i != menu_items.end(); ++i) { + if (i->second == NEEDS_FILM) { + i->first->Enable (film != 0); + } else { + i->first->Enable (true); + } + } +} + +enum { + ID_file_new = 1, + ID_file_open, + ID_file_save, + ID_file_properties, + ID_jobs_make_dcp, + ID_jobs_send_dcp_to_tms, + ID_jobs_show_dcp, +}; + +void +setup_menu (wxMenuBar* m) +{ + wxMenu* file = new wxMenu; + add_item (file, _("New..."), ID_file_new, ALWAYS); + add_item (file, _("&Open..."), ID_file_open, ALWAYS); + file->AppendSeparator (); + add_item (file, _("&Save"), ID_file_save, NEEDS_FILM); + file->AppendSeparator (); + add_item (file, _("&Properties..."), ID_file_properties, NEEDS_FILM); +#ifndef __WXOSX__ + file->AppendSeparator (); - #endif ++#endif + add_item (file, _("&Exit"), wxID_EXIT, ALWAYS); + +#ifdef __WXOSX__ + add_item (file, _("&Preferences..."), wxID_PREFERENCES, ALWAYS); +#else + wxMenu* edit = new wxMenu; + add_item (edit, _("&Preferences..."), wxID_PREFERENCES, ALWAYS); +#endif + + jobs_menu = new wxMenu; + add_item (jobs_menu, _("&Make DCP"), ID_jobs_make_dcp, NEEDS_FILM); + add_item (jobs_menu, _("&Send DCP to TMS"), ID_jobs_send_dcp_to_tms, NEEDS_FILM); + add_item (jobs_menu, _("S&how DCP"), ID_jobs_show_dcp, NEEDS_FILM); + + wxMenu* help = new wxMenu; +#ifdef __WXOSX__ + add_item (help, _("About DCP-o-matic"), wxID_ABOUT, ALWAYS); +#else + add_item (help, _("About"), wxID_ABOUT, ALWAYS); +#endif + + m->Append (file, _("&File")); +#ifndef __WXOSX__ + m->Append (edit, _("&Edit")); +#endif + m->Append (jobs_menu, _("&Jobs")); + m->Append (help, _("&Help")); +} + +bool +window_closed (wxCommandEvent &) +{ + maybe_save_then_delete_film (); + return false; +} + +class Frame : public wxFrame +{ +public: + Frame (wxString const & title) + : wxFrame (NULL, -1, title) + { + wxMenuBar* bar = new wxMenuBar; + setup_menu (bar); + SetMenuBar (bar); + + Connect (ID_file_new, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler (Frame::file_new)); + Connect (ID_file_open, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler (Frame::file_open)); + Connect (ID_file_save, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler (Frame::file_save)); + Connect (ID_file_properties, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler (Frame::file_properties)); + Connect (wxID_EXIT, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler (Frame::file_exit)); + Connect (wxID_PREFERENCES, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler (Frame::edit_preferences)); + Connect (ID_jobs_make_dcp, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler (Frame::jobs_make_dcp)); + Connect (ID_jobs_send_dcp_to_tms, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler (Frame::jobs_send_dcp_to_tms)); + Connect (ID_jobs_show_dcp, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler (Frame::jobs_show_dcp)); + Connect (wxID_ABOUT, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler (Frame::help_about)); + + Connect (wxID_ANY, wxEVT_MENU_OPEN, wxMenuEventHandler (Frame::menu_opened)); + + film_editor = new FilmEditor (film, this); + film_viewer = new FilmViewer (film, this); + JobManagerView* job_manager_view = new JobManagerView (this, static_cast (0)); + + wxBoxSizer* right_sizer = new wxBoxSizer (wxVERTICAL); + right_sizer->Add (film_viewer, 2, wxEXPAND | wxALL, 6); + right_sizer->Add (job_manager_view, 1, wxEXPAND | wxALL, 6); + + wxBoxSizer* main_sizer = new wxBoxSizer (wxHORIZONTAL); + main_sizer->Add (film_editor, 1, wxEXPAND | wxALL, 6); + main_sizer->Add (right_sizer, 2, wxEXPAND | wxALL, 6); + + set_menu_sensitivity (); + + film_editor->FileChanged.connect (bind (&Frame::file_changed, this, _1)); + if (film) { + file_changed (film->directory ()); + } else { + file_changed (""); + } + + set_film (); + SetSizer (main_sizer); + } + +private: + + void menu_opened (wxMenuEvent& ev) + { + if (ev.GetMenu() != jobs_menu) { + return; + } + + bool const have_dcp = film && film->have_dcp(); + jobs_menu->Enable (ID_jobs_send_dcp_to_tms, have_dcp); + jobs_menu->Enable (ID_jobs_show_dcp, have_dcp); + } + + void set_film () + { + film_viewer->set_film (film); + film_editor->set_film (film); + set_menu_sensitivity (); + } + + void file_changed (string f) + { + stringstream s; + s << wx_to_std (_("DCP-o-matic")); + if (!f.empty ()) { + s << " - " << f; + } + + SetTitle (std_to_wx (s.str())); + } + + void file_new (wxCommandEvent &) + { + NewFilmDialog* d = new NewFilmDialog (this); + int const r = d->ShowModal (); + + if (r == wxID_OK) { + + if (boost::filesystem::exists (d->get_path()) && !boost::filesystem::is_empty(d->get_path())) { + if (!confirm_dialog ( + this, + std_to_wx ( + String::compose (wx_to_std (_("The directory %1 already exists and is not empty. " + "Are you sure you want to use it?")), + d->get_path().c_str()) + ) + )) { + return; + } + } + + maybe_save_then_delete_film (); + film.reset (new Film (d->get_path ())); + film->write_metadata (); + film->log()->set_level (log_level); + film->set_name (boost::filesystem::path (d->get_path()).filename().generic_string()); + set_film (); + } + + d->Destroy (); + } + + void file_open (wxCommandEvent &) + { + wxDirDialog* c = new wxDirDialog (this, _("Select film to open"), wxStandardPaths::Get().GetDocumentsDir(), wxDEFAULT_DIALOG_STYLE | wxDD_DIR_MUST_EXIST); + int r; + while (1) { + r = c->ShowModal (); + if (r == wxID_OK && c->GetPath() == wxStandardPaths::Get().GetDocumentsDir()) { + error_dialog (this, _("You did not select a folder. Make sure that you select a folder before clicking Open.")); + } else { + break; + } + } + + if (r == wxID_OK) { + maybe_save_then_delete_film (); + try { + film.reset (new Film (wx_to_std (c->GetPath ()))); + film->log()->set_level (log_level); + set_film (); + } catch (std::exception& e) { + wxString p = c->GetPath (); + wxCharBuffer b = p.ToUTF8 (); + error_dialog (this, wxString::Format (_("Could not open film at %s (%s)"), p.data(), std_to_wx (e.what()).data())); + } + } + + c->Destroy (); + } + + void file_save (wxCommandEvent &) + { + film->write_metadata (); + } + + void file_properties (wxCommandEvent &) + { + PropertiesDialog* d = new PropertiesDialog (this, film); + d->ShowModal (); + d->Destroy (); + } + + void file_exit (wxCommandEvent &) + { + maybe_save_then_delete_film (); + Close (true); + } + + void edit_preferences (wxCommandEvent &) + { + ConfigDialog* d = new ConfigDialog (this); + d->ShowModal (); + d->Destroy (); + Config::instance()->write (); + } + + void jobs_make_dcp (wxCommandEvent &) + { + JobWrapper::make_dcp (this, film); + } + + void jobs_send_dcp_to_tms (wxCommandEvent &) + { + film->send_dcp_to_tms (); + } + + void jobs_show_dcp (wxCommandEvent &) + { +#ifdef __WXMSW__ + string d = film->directory(); + wstring w; + w.assign (d.begin(), d.end()); + ShellExecute (0, L"open", w.c_str(), 0, 0, SW_SHOWDEFAULT); +#else + int r = system ("which nautilus"); + if (WEXITSTATUS (r) == 0) { + system (string ("nautilus " + film->directory()).c_str ()); + } else { + int r = system ("which konqueror"); + if (WEXITSTATUS (r) == 0) { + system (string ("konqueror " + film->directory()).c_str ()); + } + } +#endif + } + + void help_about (wxCommandEvent &) + { + AboutDialog* d = new AboutDialog (this); + d->ShowModal (); + d->Destroy (); + } +}; + +#if wxMINOR_VERSION == 9 +static const wxCmdLineEntryDesc command_line_description[] = { + { wxCMD_LINE_OPTION, "l", "log", "set log level (silent, verbose or timing)", wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL }, + { wxCMD_LINE_SWITCH, "n", "new", "create new film", wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL }, + { wxCMD_LINE_PARAM, 0, 0, "film to load or create", wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_MULTIPLE | wxCMD_LINE_PARAM_OPTIONAL }, + { wxCMD_LINE_NONE, "", "", "", wxCmdLineParamType (0), 0 } +}; +#else +static const wxCmdLineEntryDesc command_line_description[] = { + { wxCMD_LINE_OPTION, wxT("l"), wxT("log"), wxT("set log level (silent, verbose or timing)"), wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL }, + { wxCMD_LINE_SWITCH, wxT("n"), wxT("new"), wxT("create new film"), wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL }, + { wxCMD_LINE_PARAM, 0, 0, wxT("film to load or create"), wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_MULTIPLE | wxCMD_LINE_PARAM_OPTIONAL }, + { wxCMD_LINE_NONE, wxT(""), wxT(""), wxT(""), wxCmdLineParamType (0), 0 } +}; +#endif + +class App : public wxApp +{ + bool OnInit () + { + if (!wxApp::OnInit()) { + return false; + } + +#ifdef DCPOMATIC_LINUX + unsetenv ("UBUNTU_MENUPROXY"); +#endif + +#ifdef __WXOSX__ + ProcessSerialNumber serial; + GetCurrentProcess (&serial); + TransformProcessType (&serial, kProcessTransformToForegroundApplication); +#endif + + wxInitAllImageHandlers (); + + /* Enable i18n; this will create a Config object + to look for a force-configured language. This Config + object will be wrong, however, because dcpomatic_setup + hasn't yet been called and there aren't any scalers, filters etc. + set up yet. + */ + dcpomatic_setup_i18n (); + + /* Set things up, including scalers / filters etc. + which will now be internationalised correctly. + */ + dcpomatic_setup (); + + /* Force the configuration to be re-loaded correctly next + time it is needed. + */ + Config::drop (); + + if (!film_to_load.empty() && boost::filesystem::is_directory (film_to_load)) { + try { + film.reset (new Film (film_to_load)); + film->read_metadata (); + film->log()->set_level (log_level); + } catch (exception& e) { + error_dialog (0, std_to_wx (String::compose (wx_to_std (_("Could not load film %1 (%2)")), film_to_load, e.what()))); + } + } + + if (!film_to_create.empty ()) { + film.reset (new Film (film_to_create)); + film->write_metadata (); + film->log()->set_level (log_level); + film->set_name (boost::filesystem::path (film_to_create).filename().generic_string ()); + } + + Frame* f = new Frame (_("DCP-o-matic")); + SetTopWindow (f); + f->Maximize (); + f->Show (); + + ui_signaller = new wxUISignaller (this); + this->Connect (-1, wxEVT_IDLE, wxIdleEventHandler (App::idle)); + + return true; + } + + void OnInitCmdLine (wxCmdLineParser& parser) + { + parser.SetDesc (command_line_description); + parser.SetSwitchChars (wxT ("-")); + } + + bool OnCmdLineParsed (wxCmdLineParser& parser) + { + if (parser.GetParamCount() > 0) { + if (parser.Found (wxT ("new"))) { + film_to_create = wx_to_std (parser.GetParam (0)); + } else { + film_to_load = wx_to_std (parser.GetParam(0)); + } + } + + wxString log; + if (parser.Found (wxT ("log"), &log)) { + log_level = wx_to_std (log); + } + + return true; + } + + void idle (wxIdleEvent &) + { + ui_signaller->ui_idle (); + } +}; + +IMPLEMENT_APP (App) diff --cc src/tools/dcpomatic_cli.cc index 8623d9194,000000000..ee9e2cdc0 mode 100644,000000..100644 --- a/src/tools/dcpomatic_cli.cc +++ b/src/tools/dcpomatic_cli.cc @@@ -1,199 -1,0 +1,204 @@@ +/* + Copyright (C) 2012 Carl Hetherington + + 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 +#include +#include +#include +#include "film.h" +#include "filter.h" +#include "transcode_job.h" +#include "job_manager.h" +#include "util.h" +#include "scaler.h" +#include "version.h" +#include "cross.h" +#include "config.h" +#include "log.h" + +using std::string; +using std::cerr; +using std::cout; +using std::vector; +using std::pair; +using std::list; +using boost::shared_ptr; + +static void +help (string n) +{ + cerr << "Syntax: " << n << " [OPTION] \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" + << " is the film directory.\n"; +} + +int +main (int argc, char* argv[]) +{ + string film_dir; + bool progress = true; + bool no_remote = false; + int log_level = 0; + + int option_index = 0; + while (1) { + static struct option long_options[] = { + { "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; + } + + switch (c) { + case 'v': + cout << "dcpomatic version " << dcpomatic_version << " " << dcpomatic_git_commit << "\n"; + exit (EXIT_SUCCESS); + case 'h': + help (argv[0]); + exit (EXIT_SUCCESS); + 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; + case 'r': + no_remote = true; + break; + case 'l': + log_level = atoi (optarg); + break; + } + } + + if (optind >= argc) { + help (argv[0]); + exit (EXIT_FAILURE); + } + + film_dir = argv[optind]; + + dcpomatic_setup (); + + if (no_remote) { + Config::instance()->set_servers (vector ()); + } + + cout << "DCP-o-matic " << dcpomatic_version << " git " << dcpomatic_git_commit; + char buf[256]; + if (gethostname (buf, 256) == 0) { + cout << " on " << buf; + } + cout << "\n"; + + shared_ptr film; + try { + film.reset (new Film (film_dir)); + film->read_metadata (); + } catch (std::exception& e) { + cerr << argv[0] << ": error reading film `" << film_dir << "' (" << e.what() << ")\n"; + exit (EXIT_FAILURE); + } + + film->log()->set_level ((Log::Level) log_level); + + cout << "\nMaking DCP for " << film->name() << "\n"; +// cout << "Content: " << film->content() << "\n"; +// pair const f = Filter::ffmpeg_strings (film->filters ()); +// cout << "Filters: " << f.first << " " << f.second << "\n"; + + film->make_dcp (); + + bool should_stop = false; + bool first = true; + bool error = false; + while (!should_stop) { + + dcpomatic_sleep (5); + + list > jobs = JobManager::instance()->get (); + + if (!first && progress) { + cout << "\033[" << jobs.size() << "A"; + cout.flush (); + } + + first = false; + + int unfinished = 0; + int finished_in_error = 0; + + for (list >::iterator i = jobs.begin(); i != jobs.end(); ++i) { + if (progress) { + cout << (*i)->name() << ": "; + + float const p = (*i)->overall_progress (); + + if (p >= 0) { + cout << (*i)->status() << " \n"; + } else { + cout << ": Running \n"; + } + } + + if (!(*i)->finished ()) { + ++unfinished; + } + + if ((*i)->finished_in_error ()) { + ++finished_in_error; + error = true; + } + + if (!progress && (*i)->finished_in_error ()) { + /* We won't see this error if we haven't been showing progress, + so show it now. + */ + cout << (*i)->status() << "\n"; + } + } + + if (unfinished == 0 || finished_in_error != 0) { + should_stop = true; + } + } + + return error ? EXIT_FAILURE : EXIT_SUCCESS; +} + + diff --cc src/tools/wscript index 38d986f25,20a92cad2..c7ab44604 --- a/src/tools/wscript +++ b/src/tools/wscript @@@ -4,29 -4,31 +4,31 @@@ from waflib import Log import i18n def build(bld): - for t in ['makedcp', 'servomatic_cli', 'servomatictest']: + 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 AVFORMAT AVFILTER AVCODEC AVUTIL SWSCALE POSTPROC CXML WXWIDGETS' ++ obj.uselib = 'BOOST_THREAD OPENJPEG DCP CXML AVFORMAT AVFILTER AVCODEC AVUTIL SWSCALE POSTPROC WXWIDGETS' obj.includes = ['..'] - obj.use = ['libdvdomatic'] + obj.use = ['libdcpomatic'] obj.source = '%s.cc' % t obj.target = t if not bld.env.DISABLE_GUI: - for t in ['dvdomatic', 'dvdomatic_batch', 'servomatic_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 = ['libdvdomatic', 'libdvdomatic-wx'] + obj.use = ['libdcpomatic', 'libdcpomatic-wx'] obj.source = '%s.cc' % t if bld.env.TARGET_WINDOWS: - obj.source += ' ../../platform/windows/dvdomatic.rc' + obj.source += ' ../../platform/windows/dcpomatic.rc' obj.target = t - i18n.po_to_mo(os.path.join('src', 'tools'), 'dvdomatic', bld) + i18n.po_to_mo(os.path.join('src', 'tools'), 'dcpomatic', bld) def pot(bld): - i18n.pot(os.path.join('src', 'tools'), 'dvdomatic.cc', 'dvdomatic') + i18n.pot(os.path.join('src', 'tools'), 'dcpomatic.cc', 'dcpomatic') def pot_merge(bld): - i18n.pot_merge(os.path.join('src', 'tools'), 'dvdomatic') + i18n.pot_merge(os.path.join('src', 'tools'), 'dcpomatic') diff --cc src/wx/audio_dialog.cc index ea7cc60dd,21e4e5940..22e09cc7a --- a/src/wx/audio_dialog.cc +++ b/src/wx/audio_dialog.cc @@@ -83,21 -84,41 +83,20 @@@ AudioDialog::AudioDialog (wxWindow* par } void -AudioDialog::set_film (boost::shared_ptr f) +AudioDialog::set_content (shared_ptr c) { - _film_changed_connection.disconnect (); - _film_audio_analysis_succeeded_connection.disconnect (); + _content_changed_connection.disconnect (); - _film = f; + _content = c; try_to_load_analysis (); - setup_channels (); - _plot->set_gain (_film->audio_gain ()); + _plot->set_gain (_content->audio_gain ()); - _film_changed_connection = _film->Changed.connect (bind (&AudioDialog::film_changed, this, _1)); - _film_audio_analysis_succeeded_connection = _film->AudioAnalysisSucceeded.connect (bind (&AudioDialog::try_to_load_analysis, this)); + _content_changed_connection = _content->Changed.connect (bind (&AudioDialog::content_changed, this, _2)); - SetTitle (wxString::Format (_("DVD-o-matic audio - %s"), std_to_wx(_film->name()).data())); + SetTitle (wxString::Format (_("DCP-o-matic audio - %s"), std_to_wx(_content->file().filename().string()).data())); } -void -AudioDialog::setup_channels () -{ - if (!_film->audio_stream()) { - return; - } - - AudioMapping m (_film); - - for (int i = 0; i < MAX_AUDIO_CHANNELS; ++i) { - if (m.dcp_to_source(static_cast(i))) { - _channel_checkbox[i]->Show (); - } else { - _channel_checkbox[i]->Hide (); - } - } -} -- void AudioDialog::try_to_load_analysis () { diff --cc src/wx/config_dialog.cc index 844b03ad7,e622c331b..e66be174d --- a/src/wx/config_dialog.cc +++ b/src/wx/config_dialog.cc @@@ -78,7 -80,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, DVDOMATIC_SIZER_X_GAP, DVDOMATIC_SIZER_Y_GAP); ++ wxFlexGridSizer* table = new wxFlexGridSizer (3, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP); table->AddGrowableCol (1, 1); s->Add (table, 1, wxALL | wxEXPAND, 8); @@@ -101,18 -103,13 +101,18 @@@ 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 DVDOMATIC_USE_OWN_DIR_PICKER ++#ifdef DCPOMATIC_USE_OWN_DIR_PICKER _default_directory = new DirPickerCtrl (_misc_panel); #else _default_directory = new wxDirPickerCtrl (_misc_panel, wxDD_DIR_MUST_EXIST); @@@ -125,12 -122,12 +125,12 @@@ 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 format"), true); - _default_format = new wxChoice (_misc_panel, wxID_ANY); - table->Add (_default_format); ++ 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,7 -194,7 +201,7 @@@ 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, DVDOMATIC_SIZER_X_GAP, DVDOMATIC_SIZER_Y_GAP); ++ wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP); table->AddGrowableCol (1, 1); s->Add (table, 1, wxALL | wxEXPAND, 8); @@@ -240,7 -233,7 +240,7 @@@ 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, DVDOMATIC_SIZER_X_GAP, DVDOMATIC_SIZER_Y_GAP); ++ wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP); table->AddGrowableCol (1, 1); s->Add (table, 1, wxALL | wxEXPAND, 8); @@@ -267,7 -302,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, DVDOMATIC_SIZER_X_GAP, DVDOMATIC_SIZER_Y_GAP); ++ wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP); table->AddGrowableCol (0, 1); s->Add (table, 1, wxALL | wxEXPAND, 8); diff --cc src/wx/config_dialog.h index 3da48fd08,a97788942..459d64dd7 --- a/src/wx/config_dialog.h +++ b/src/wx/config_dialog.h @@@ -81,8 -86,7 +82,8 @@@ private wxTextCtrl* _tms_user; wxTextCtrl* _tms_password; wxSpinCtrl* _num_local_encoding_threads; -#ifdef DVDOMATIC_USE_OWN_DIR_PICKER + wxSpinCtrl* _default_still_length; - #ifdef __WXMSW__ ++#ifdef DCPOMATIC_USE_OWN_DIR_PICKER DirPickerCtrl* _default_directory; #else wxDirPickerCtrl* _default_directory; diff --cc src/wx/dci_metadata_dialog.cc index c08c58ed4,9c124ed74..df3a24f62 --- a/src/wx/dci_metadata_dialog.cc +++ b/src/wx/dci_metadata_dialog.cc @@@ -27,10 -27,10 +27,10 @@@ 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, DVDOMATIC_SIZER_X_GAP, DVDOMATIC_SIZER_Y_GAP); ++ 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); diff --cc src/wx/film_editor.cc index 27803fb9a,a54b412b3..2d8c752a1 --- a/src/wx/film_editor.cc +++ b/src/wx/film_editor.cc @@@ -96,78 -91,119 +96,83 @@@ FilmEditor::FilmEditor (shared_ptrSetSizer (_film_sizer); + _dcp_panel = new wxPanel (_main_notebook); + _dcp_sizer = new wxBoxSizer (wxVERTICAL); + _dcp_panel->SetSizer (_dcp_sizer); - wxGridBagSizer* grid = new wxGridBagSizer (4, 4); - wxGridBagSizer* grid = new wxGridBagSizer (DVDOMATIC_SIZER_X_GAP, DVDOMATIC_SIZER_Y_GAP); - _film_sizer->Add (grid, 0, wxALL, 8); ++ 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, _film_panel, _("Name"), true, wxGBPosition (r, 0)); - _name = new wxTextCtrl (_film_panel, wxID_ANY); ++ 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, _film_panel, _("DCP Name"), true, wxGBPosition (r, 0)); - _dcp_name = new wxStaticText (_film_panel, wxID_ANY, wxT ("")); ++ 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 (_film_panel, wxID_ANY, _("Use DCI name")); ++ + _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 (_film_panel, wxID_ANY, _("Details...")); + _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, _film_panel, _("Content"), true, wxGBPosition (r, 0)); - _content = new wxFilePickerCtrl (_film_panel, wxID_ANY, wxT (""), _("Select Content File"), wxT("*.*")); - grid->Add (_content, wxGBPosition (r, 1), wxDefaultSpan, wxEXPAND); - ++r; - - _trust_content_header = new wxCheckBox (_film_panel, wxID_ANY, _("Trust content's header")); - video_control (_trust_content_header); - grid->Add (_trust_content_header, wxGBPosition (r, 0), wxGBSpan(1, 2)); ++ 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, _film_panel, _("Content Type"), true, wxGBPosition (r, 0)); - _dcp_content_type = new wxChoice (_film_panel, wxID_ANY); ++ 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; - video_control (add_label_to_grid_bag_sizer (grid, _film_panel, _("Original Frame Rate"), true, wxGBPosition (r, 0))); - _source_frame_rate = new wxStaticText (_film_panel, wxID_ANY, wxT ("")); - grid->Add (video_control (_source_frame_rate), wxGBPosition (r, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL); - ++r; - { - add_label_to_grid_bag_sizer (grid, _dcp_panel, _("DCP Frame Rate"), wxGBPosition (r, 0)); - add_label_to_grid_bag_sizer (grid, _film_panel, _("DCP Frame Rate"), true, 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 (_film_panel, wxID_ANY); + _dcp_frame_rate = new wxChoice (_dcp_panel, wxID_ANY); s->Add (_dcp_frame_rate, 1, wxALIGN_CENTER_VERTICAL); - _best_dcp_frame_rate = new wxButton (_film_panel, wxID_ANY, _("Use best")); - s->Add (_best_dcp_frame_rate, 1, wxALIGN_CENTER_VERTICAL | wxALL | wxEXPAND, 6); + _best_dcp_frame_rate = new wxButton (_dcp_panel, wxID_ANY, _("Use best")); + s->Add (_best_dcp_frame_rate, 1, wxALIGN_CENTER_VERTICAL | wxEXPAND); grid->Add (s, wxGBPosition (r, 1)); } ++r; - _frame_rate_description = new wxStaticText (_film_panel, wxID_ANY, wxT ("\n \n "), wxDefaultPosition, wxDefaultSize); - grid->Add (video_control (_frame_rate_description), wxGBPosition (r, 0), wxGBSpan (1, 2), wxEXPAND | wxALIGN_CENTER_VERTICAL | wxALL, 6); - wxFont font = _frame_rate_description->GetFont(); - font.SetStyle(wxFONTSTYLE_ITALIC); - font.SetPointSize(font.GetPointSize() - 1); - _frame_rate_description->SetFont(font); - ++r; - - video_control (add_label_to_grid_bag_sizer (grid, _film_panel, _("Length"), true, wxGBPosition (r, 0))); - _length = new wxStaticText (_film_panel, wxID_ANY, wxT ("")); - grid->Add (video_control (_length), wxGBPosition (r, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL); - ++r; - - { - add_label_to_grid_bag_sizer (grid, _dcp_panel, _("JPEG2000 bandwidth"), wxGBPosition (r, 0)); - video_control (add_label_to_grid_bag_sizer (grid, _film_panel, _("Trim frames"), true, wxGBPosition (r, 0))); - wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL); - video_control (add_label_to_sizer (s, _film_panel, _("Start"), true)); - _trim_start = new wxSpinCtrl (_film_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1)); - s->Add (video_control (_trim_start)); - video_control (add_label_to_sizer (s, _film_panel, _("End"), true)); - _trim_end = new wxSpinCtrl (_film_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1)); - s->Add (video_control (_trim_end)); - ++ 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)); - video_control (add_label_to_grid_bag_sizer (grid, _film_panel, _("Trim method"), true, wxGBPosition (r, 0))); - _trim_type = new wxChoice (_film_panel, wxID_ANY); - grid->Add (video_control (_trim_type), wxGBPosition (r, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL); ++ 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; - _dcp_ab = new wxCheckBox (_film_panel, wxID_ANY, _("A/B")); - video_control (_dcp_ab); - grid->Add (_dcp_ab, wxGBPosition (r, 0)); - ++r; + vector const sc = Scaler::all (); + for (vector::const_iterator i = sc.begin(); i != sc.end(); ++i) { + _scaler->Append (std_to_wx ((*i)->name())); + } - /* STILL-only stuff */ - { - still_control (add_label_to_grid_bag_sizer (grid, _film_panel, _("Duration"), true, wxGBPosition (r, 0))); - wxSizer* s = new wxBoxSizer (wxHORIZONTAL); - _still_duration = new wxSpinCtrl (_film_panel); - still_control (_still_duration); - s->Add (_still_duration, 1, wxEXPAND); - /// TRANSLATORS: `s' here is an abbreviation for seconds, the unit of time - still_control (add_label_to_sizer (s, _film_panel, _("s"), false)); - grid->Add (s, wxGBPosition (r, 1)); + vector const ratio = Ratio::all (); + for (vector::const_iterator i = ratio.begin(); i != ratio.end(); ++i) { + _container->Append (std_to_wx ((*i)->nickname ())); } - ++r; vector const ct = DCPContentType::all (); for (vector::const_iterator i = ct.begin(); i != ct.end(); ++i) { @@@ -185,33 -222,36 +190,35 @@@ void FilmEditor::connect_to_widgets () { - _name->Connect (wxID_ANY, wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler (FilmEditor::name_changed), 0, this); - _use_dci_name->Connect (wxID_ANY, wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler (FilmEditor::use_dci_name_toggled), 0, this); - _edit_dci_button->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (FilmEditor::edit_dci_button_clicked), 0, this); - _format->Connect (wxID_ANY, wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler (FilmEditor::format_changed), 0, this); - _content->Connect (wxID_ANY, wxEVT_COMMAND_FILEPICKER_CHANGED, wxCommandEventHandler (FilmEditor::content_changed), 0, this); - _trust_content_header->Connect (wxID_ANY, wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler (FilmEditor::trust_content_header_changed), 0, this); - _left_crop->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::left_crop_changed), 0, this); - _right_crop->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::right_crop_changed), 0, this); - _top_crop->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::top_crop_changed), 0, this); - _bottom_crop->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::bottom_crop_changed), 0, this); - _filters_button->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (FilmEditor::edit_filters_clicked), 0, this); - _scaler->Connect (wxID_ANY, wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler (FilmEditor::scaler_changed), 0, this); - _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); - _dcp_ab->Connect (wxID_ANY, wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler (FilmEditor::dcp_ab_toggled), 0, this); - _still_duration->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::still_duration_changed), 0, this); - _trim_start->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::trim_start_changed), 0, this); - _trim_end->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::trim_end_changed), 0, this); - _trim_type->Connect (wxID_ANY, wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler (FilmEditor::trim_type_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); - _colour_lut->Connect (wxID_ANY, wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler (FilmEditor::colour_lut_changed), 0, this); - _j2k_bandwidth->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::j2k_bandwidth_changed), 0, this); - _subtitle_stream->Connect (wxID_ANY, wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler (FilmEditor::subtitle_stream_changed), 0, this); - _audio_stream->Connect (wxID_ANY, wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler (FilmEditor::audio_stream_changed), 0, this); - _audio_gain->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::audio_gain_changed), 0, this); + _name->Connect (wxID_ANY, wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler (FilmEditor::name_changed), 0, this); + _use_dci_name->Connect (wxID_ANY, wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler (FilmEditor::use_dci_name_toggled), 0, this); + _edit_dci_button->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (FilmEditor::edit_dci_button_clicked), 0, this); + _container->Connect (wxID_ANY, wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler (FilmEditor::container_changed), 0, this); + _ratio->Connect (wxID_ANY, wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler (FilmEditor::ratio_changed), 0, this); + _content->Connect (wxID_ANY, wxEVT_COMMAND_LIST_ITEM_SELECTED, wxListEventHandler (FilmEditor::content_selection_changed), 0, this); + _content->Connect (wxID_ANY, wxEVT_COMMAND_LIST_ITEM_DESELECTED, wxListEventHandler (FilmEditor::content_selection_changed), 0, this); + _content_add->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (FilmEditor::content_add_clicked), 0, this); + _content_remove->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (FilmEditor::content_remove_clicked), 0, this); + _content_timeline->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (FilmEditor::content_timeline_clicked), 0, this); + _loop_content->Connect (wxID_ANY, wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler (FilmEditor::loop_content_toggled), 0, this); + _loop_count->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::loop_count_changed), 0, this); + _left_crop->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::left_crop_changed), 0, this); + _right_crop->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::right_crop_changed), 0, this); + _top_crop->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::top_crop_changed), 0, this); + _bottom_crop->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::bottom_crop_changed), 0, this); + _filters_button->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (FilmEditor::edit_filters_clicked), 0, this); + _scaler->Connect (wxID_ANY, wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler (FilmEditor::scaler_changed), 0, this); + _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); + _colour_lut->Connect (wxID_ANY, wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler (FilmEditor::colour_lut_changed), 0, this); + _j2k_bandwidth->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::j2k_bandwidth_changed), 0, this); + _audio_gain->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::audio_gain_changed), 0, this); _audio_gain_calculate_button->Connect ( wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (FilmEditor::audio_gain_calculate_button_clicked), 0, this ); @@@ -227,15 -269,20 +234,15 @@@ void FilmEditor::make_video_panel () { - _video_panel = new wxPanel (_notebook); - _video_sizer = new wxBoxSizer (wxVERTICAL); - _video_panel->SetSizer (_video_sizer); + _video_panel = new wxPanel (_content_notebook); + wxBoxSizer* video_sizer = new wxBoxSizer (wxVERTICAL); + _video_panel->SetSizer (video_sizer); - wxGridBagSizer* grid = new wxGridBagSizer (4, 4); - wxGridBagSizer* grid = new wxGridBagSizer (DVDOMATIC_SIZER_X_GAP, DVDOMATIC_SIZER_Y_GAP); - _video_sizer->Add (grid, 0, wxALL, 8); ++ 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, _("Format"), true, wxGBPosition (r, 0)); - _format = new wxChoice (_video_panel, wxID_ANY); - grid->Add (_format, wxGBPosition (r, 1)); - ++r; - + 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; @@@ -255,11 -302,6 +262,11 @@@ 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; + _scaling_description = new wxStaticText (_video_panel, wxID_ANY, wxT ("\n \n \n \n"), wxDefaultPosition, wxDefaultSize); grid->Add (_scaling_description, wxGBPosition (r, 0), wxGBSpan (1, 2), wxEXPAND | wxALIGN_CENTER_VERTICAL | wxALL, 6); wxFont font = _scaling_description->GetFont(); @@@ -270,17 -312,29 +277,17 @@@ /* VIDEO-only stuff */ { - add_label_to_grid_bag_sizer (grid, _video_panel, _("Filters"), wxGBPosition (r, 0)); - video_control (add_label_to_grid_bag_sizer (grid, _video_panel, _("Filters"), true, 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")); - video_control (_filters); 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); - video_control (_filters_button); + 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)); - video_control (add_label_to_grid_bag_sizer (grid, _video_panel, _("Scaler"), true, wxGBPosition (r, 0))); - _scaler = new wxChoice (_video_panel, wxID_ANY); - grid->Add (video_control (_scaler), wxGBPosition (r, 1)); - ++r; - - vector const sc = Scaler::all (); - for (vector::const_iterator i = sc.begin(); i != sc.end(); ++i) { - _scaler->Append (std_to_wx ((*i)->name())); - } - + 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))); @@@ -293,174 -357,122 +300,198 @@@ _top_crop->SetRange (0, 1024); _right_crop->SetRange (0, 1024); _bottom_crop->SetRange (0, 1024); - _still_duration->SetRange (1, 60 * 60); - _trim_start->SetRange (0, 24 * 60 * 60); - _trim_end->SetRange (0, 24 * 60 * 60); - _j2k_bandwidth->SetRange (50, 250); +} + +void +FilmEditor::make_content_panel () +{ + _content_panel = new wxPanel (_main_notebook); + _content_sizer = new wxBoxSizer (wxVERTICAL); + _content_panel->SetSizer (_content_sizer); + + { + wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL); + + _content = new wxListCtrl (_content_panel, wxID_ANY, wxDefaultPosition, wxSize (320, 160), wxLC_REPORT | wxLC_NO_HEADER | wxLC_SINGLE_SEL); + s->Add (_content, 1, wxEXPAND | wxTOP | wxBOTTOM, 6); + + _content->InsertColumn (0, wxT("")); + _content->SetColumnWidth (0, 512); + + wxBoxSizer* b = new wxBoxSizer (wxVERTICAL); + _content_add = new wxButton (_content_panel, wxID_ANY, _("Add...")); + b->Add (_content_add, 1, wxEXPAND | wxLEFT | wxRIGHT); + _content_remove = new wxButton (_content_panel, wxID_ANY, _("Remove")); + b->Add (_content_remove, 1, wxEXPAND | wxLEFT | wxRIGHT); + _content_timeline = new wxButton (_content_panel, wxID_ANY, _("Timeline...")); + b->Add (_content_timeline, 1, wxEXPAND | wxLEFT | wxRIGHT); + + s->Add (b, 0, wxALL, 4); + + _content_sizer->Add (s, 0.75, wxEXPAND | wxALL, 6); + } + + wxBoxSizer* h = new wxBoxSizer (wxHORIZONTAL); + _loop_content = new wxCheckBox (_content_panel, wxID_ANY, _("Loop everything")); + 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); + _content_sizer->Add (_content_notebook, 1, wxEXPAND | wxTOP, 6); + + make_video_panel (); + _content_notebook->AddPage (_video_panel, _("Video"), false); + make_audio_panel (); + _content_notebook->AddPage (_audio_panel, _("Audio"), false); + make_subtitle_panel (); + _content_notebook->AddPage (_subtitle_panel, _("Subtitles"), false); + make_timing_panel (); + _content_notebook->AddPage (_timing_panel, _("Timing"), false); + + _loop_count->SetRange (2, 1024); } void FilmEditor::make_audio_panel () { - _audio_panel = new wxPanel (_notebook); - _audio_sizer = new wxBoxSizer (wxVERTICAL); - _audio_panel->SetSizer (_audio_sizer); + _audio_panel = new wxPanel (_content_notebook); + wxBoxSizer* audio_sizer = new wxBoxSizer (wxVERTICAL); + _audio_panel->SetSizer (audio_sizer); - wxFlexGridSizer* grid = new wxFlexGridSizer (3, 4, 4); - wxFlexGridSizer* grid = new wxFlexGridSizer (2, DVDOMATIC_SIZER_X_GAP, DVDOMATIC_SIZER_Y_GAP); - _audio_sizer->Add (grid, 0, wxALL, 8); ++ 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...")); grid->Add (_show_audio, 1); 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); { - video_control (add_label_to_sizer (grid, _audio_panel, _("Audio Gain"), true)); wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL); _audio_gain = new wxSpinCtrl (_audio_panel); - s->Add (video_control (_audio_gain), 1); - video_control (add_label_to_sizer (s, _audio_panel, _("dB"), false)); - _audio_gain_calculate_button = new wxButton (_audio_panel, wxID_ANY, _("Calculate...")); - video_control (_audio_gain_calculate_button); - s->Add (_audio_gain_calculate_button, 1, wxEXPAND); - grid->Add (s); + 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); { - video_control (add_label_to_sizer (grid, _audio_panel, _("Audio Delay"), true)); wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL); _audio_delay = new wxSpinCtrl (_audio_panel); - s->Add (video_control (_audio_delay), 1); + s->Add (_audio_delay, 1); /// TRANSLATORS: this is an abbreviation for milliseconds, the unit of time - add_label_to_sizer (s, _audio_panel, _("ms")); - video_control (add_label_to_sizer (s, _audio_panel, _("ms"), false)); ++ 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 ("")); + grid->AddSpacer (0); + + grid->Add (_audio_description, 1, wxALIGN_CENTER_VERTICAL | wxLEFT, 8); + grid->AddSpacer (0); + grid->AddSpacer (0); + + _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); + } - - _use_external_audio = new wxRadioButton (_audio_panel, wxID_ANY, _("Use external audio")); - grid->Add (_use_external_audio); - grid->AddSpacer (0); - - for (int i = 0; i < MAX_AUDIO_CHANNELS; ++i) { - add_label_to_sizer (grid, _audio_panel, std_to_wx (audio_channel_name (i)), true); - _external_audio[i] = new wxFilePickerCtrl (_audio_panel, wxID_ANY, wxT (""), _("Select Audio File"), wxT ("*.wav")); - grid->Add (_external_audio[i], 1, wxEXPAND); - } ++#endif + _audio_gain->SetRange (-60, 60); _audio_delay->SetRange (-1000, 1000); - _minimum_audio_channels->SetRange (0, MAX_AUDIO_CHANNELS); ++// _minimum_audio_channels->SetRange (0, MAX_AUDIO_CHANNELS); } void FilmEditor::make_subtitle_panel () { - _subtitle_panel = new wxPanel (_notebook); - _subtitle_sizer = new wxBoxSizer (wxVERTICAL); - _subtitle_panel->SetSizer (_subtitle_sizer); - wxFlexGridSizer* grid = new wxFlexGridSizer (2, DVDOMATIC_SIZER_X_GAP, DVDOMATIC_SIZER_Y_GAP); - _subtitle_sizer->Add (grid, 0, wxALL, 8); + _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")); - video_control (_with_subtitles); grid->Add (_with_subtitles, 1); + grid->AddSpacer (0); - _subtitle_stream = new wxChoice (_subtitle_panel, wxID_ANY); - grid->Add (video_control (_subtitle_stream)); - { - add_label_to_sizer (grid, _subtitle_panel, _("Subtitle Offset")); - video_control (add_label_to_sizer (grid, _subtitle_panel, _("Subtitle Offset"), true)); ++ 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")); - video_control (add_label_to_sizer (s, _subtitle_panel, _("pixels"), false)); ++ add_label_to_sizer (s, _subtitle_panel, _("pixels"), false); grid->Add (s); } { - add_label_to_sizer (grid, _subtitle_panel, _("Subtitle Scale")); - video_control (add_label_to_sizer (grid, _subtitle_panel, _("Subtitle Scale"), true)); ++ add_label_to_sizer (grid, _subtitle_panel, _("Subtitle Scale"), true); wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL); _subtitle_scale = new wxSpinCtrl (_subtitle_panel); - s->Add (video_control (_subtitle_scale)); - video_control (add_label_to_sizer (s, _subtitle_panel, _("%"), false)); + 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); + _subtitle_offset->SetRange (-1024, 1024); _subtitle_scale->SetRange (1, 1000); } +void +FilmEditor::make_timing_panel () +{ + _timing_panel = new wxPanel (_content_notebook); + wxBoxSizer* timing_sizer = new wxBoxSizer (wxVERTICAL); + _timing_panel->SetSizer (timing_sizer); + 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); +} + + /** Called when the left crop widget has been changed */ void FilmEditor::left_crop_changed (wxCommandEvent &) @@@ -594,18 -639,64 +625,19 @@@ FilmEditor::film_changed (Film::Propert case Film::NONE: break; case Film::CONTENT: - checked_set (_content, _film->content ()); - setup_visibility (); - setup_formats (); - setup_subtitle_control_sensitivity (); - setup_streams (); - setup_show_audio_sensitivity (); - setup_frame_rate_description (); - setup_minimum_audio_channels (); - break; - case Film::TRUST_CONTENT_HEADER: - checked_set (_trust_content_header, _film->trust_content_header ()); - break; - case Film::SUBTITLE_STREAMS: + setup_content (); setup_subtitle_control_sensitivity (); - setup_streams (); - break; - case Film::CONTENT_AUDIO_STREAMS: - setup_streams (); setup_show_audio_sensitivity (); - setup_frame_rate_description (); + setup_minimum_audio_channels (); break; - case Film::FORMAT: - { - int n = 0; - vector::iterator i = _formats.begin (); - while (i != _formats.end() && *i != _film->format ()) { - ++i; - ++n; - } - if (i == _formats.end()) { - checked_set (_format, -1); - } else { - checked_set (_format, n); - } - setup_dcp_name (); - setup_scaling_description (); - break; - } - case Film::CROP: - checked_set (_left_crop, _film->crop().left); - checked_set (_right_crop, _film->crop().right); - checked_set (_top_crop, _film->crop().top); - checked_set (_bottom_crop, _film->crop().bottom); - setup_scaling_description (); + case Film::LOOP: + checked_set (_loop_content, _film->loop() > 1); + checked_set (_loop_count, _film->loop()); + setup_loop_sensitivity (); break; - case Film::FILTERS: - { - pair p = Filter::ffmpeg_strings (_film->filters ()); - if (p.first.empty () && p.second.empty ()) { - _filters->SetLabel (_("None")); - } else { - string const b = p.first + " " + p.second; - _filters->SetLabel (std_to_wx (b)); - } - _film_sizer->Layout (); + case Film::CONTAINER: + setup_container (); break; - } case Film::NAME: checked_set (_name, _film->name()); setup_dcp_name (); @@@ -652,13 -824,17 +684,17 @@@ } } - if (_film->source_frame_rate()) { - _best_dcp_frame_rate->Enable (best_dcp_frame_rate (_film->source_frame_rate ()) != _film->dcp_frame_rate ()); - } else { - _best_dcp_frame_rate->Disable (); + if (!done) { + checked_set (_dcp_frame_rate, -1); } - setup_frame_rate_description (); + _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 ()); ++// checked_set (_minimum_audio_channels, _film->minimum_audio_channels ()); + setup_minimum_audio_channels (); + break; } } @@@ -1325,181 -1437,37 +1361,213 @@@ XX } void -FilmEditor::trim_type_changed (wxCommandEvent &) +FilmEditor::loop_content_toggled (wxCommandEvent &) +{ + if (_loop_content->GetValue ()) { + _film->set_loop (_loop_count->GetValue ()); + } else { + _film->set_loop (1); + } + + setup_loop_sensitivity (); +} + +void +FilmEditor::loop_count_changed (wxCommandEvent &) { - _film->set_trim_type (_trim_type->GetSelection () == 0 ? Film::CPL : Film::ENCODE); + _film->set_loop (_loop_count->GetValue ()); +} + +void +FilmEditor::setup_loop_sensitivity () +{ + _loop_count->Enable (_loop_content->GetValue ()); +} + +void +FilmEditor::content_timeline_clicked (wxCommandEvent &) +{ + if (_timeline_dialog) { + _timeline_dialog->Destroy (); + _timeline_dialog = 0; + } + + _timeline_dialog = new TimelineDialog (this, _film); + _timeline_dialog->Show (); +} + +void +FilmEditor::audio_stream_changed (wxCommandEvent &) +{ + shared_ptr c = selected_content (); + if (!c) { + return; + } + + shared_ptr fc = dynamic_pointer_cast (c); + if (!fc) { + return; + } + + vector > a = fc->audio_streams (); + vector >::iterator i = a.begin (); + string const s = string_client_data (_audio_stream->GetClientObject (_audio_stream->GetSelection ())); + while (i != a.end() && lexical_cast ((*i)->id) != s) { + ++i; + } + + if (i != a.end ()) { + fc->set_audio_stream (*i); + } + + if (!fc->audio_stream ()) { + _audio_description->SetLabel (wxT ("")); + } else { + wxString s; + if (fc->audio_channels() == 1) { + s << _("1 channel"); + } else { + s << fc->audio_channels() << wxT (" ") << _("channels"); + } + s << wxT (", ") << fc->content_audio_frame_rate() << _("Hz"); + _audio_description->SetLabel (s); + } +} + + + +void +FilmEditor::subtitle_stream_changed (wxCommandEvent &) +{ + shared_ptr c = selected_content (); + if (!c) { + return; + } + + shared_ptr fc = dynamic_pointer_cast (c); + if (!fc) { + return; + } + + vector > a = fc->subtitle_streams (); + vector >::iterator i = a.begin (); + string const s = string_client_data (_subtitle_stream->GetClientObject (_subtitle_stream->GetSelection ())); + while (i != a.end() && lexical_cast ((*i)->id) != s) { + ++i; + } + + if (i != a.end ()) { + fc->set_subtitle_stream (*i); + } +} + +void +FilmEditor::audio_mapping_changed (AudioMapping m) +{ + shared_ptr c = selected_content (); + if (!c) { + return; + } + + shared_ptr ac = dynamic_pointer_cast (c); + if (!ac) { + return; + } + + ac->set_audio_mapping (m); +} + +void +FilmEditor::start_changed () +{ + shared_ptr c = selected_content (); + if (!c) { + return; + } + + c->set_start (_start->get (_film->dcp_video_frame_rate ())); +} + +void +FilmEditor::length_changed () +{ + shared_ptr c = selected_content (); + if (!c) { + return; + } + + shared_ptr ic = dynamic_pointer_cast (c); + if (ic) { + ic->set_video_length (_length->get(_film->dcp_video_frame_rate()) * ic->video_frame_rate() / TIME_HZ); + } +} + +void +FilmEditor::set_selection (weak_ptr wc) +{ + Playlist::ContentList content = _film->content (); + for (size_t i = 0; i < content.size(); ++i) { + if (content[i] == wc.lock ()) { + _content->SetItemState (i, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED); + } else { + _content->SetItemState (i, 0, wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED); + } + } +} + +void +FilmEditor::ratio_changed (wxCommandEvent &) +{ + if (!_film) { + return; + } + + shared_ptr c = selected_content (); + if (!c) { + return; + } + + shared_ptr vc = dynamic_pointer_cast (c); + if (!vc) { + return; + } + + int const n = _ratio->GetSelection (); + if (n >= 0) { + vector ratios = Ratio::all (); + assert (n < int (ratios.size())); + 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 &) + { - setup_audio_control_sensitivity (); ++ + } + + void + FilmEditor::minimum_audio_channels_changed (wxCommandEvent &) + { + if (!_film) { + return; + } + - _film->set_minimum_audio_channels (_minimum_audio_channels->GetValue ()); ++// _film->set_minimum_audio_channels (_minimum_audio_channels->GetValue ()); + } diff --cc src/wx/film_editor.h index 4b096a2e1,c2d064ca2..705eb16af --- a/src/wx/film_editor.h +++ b/src/wx/film_editor.h @@@ -85,18 -78,15 +85,20 @@@ private void subtitle_scale_changed (wxCommandEvent &); void colour_lut_changed (wxCommandEvent &); void j2k_bandwidth_changed (wxCommandEvent &); - void still_duration_changed (wxCommandEvent &); - void audio_stream_changed (wxCommandEvent &); - void subtitle_stream_changed (wxCommandEvent &); - void use_audio_changed (wxCommandEvent &); - void external_audio_changed (wxCommandEvent &); void dcp_frame_rate_changed (wxCommandEvent &); void best_dcp_frame_rate_clicked (wxCommandEvent &); + void edit_filters_clicked (wxCommandEvent &); + void loop_content_toggled (wxCommandEvent &); + void loop_count_changed (wxCommandEvent &); + void content_timeline_clicked (wxCommandEvent &); + void audio_stream_changed (wxCommandEvent &); + void subtitle_stream_changed (wxCommandEvent &); + void audio_mapping_changed (AudioMapping); + 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); @@@ -108,27 -100,27 +110,28 @@@ void setup_dcp_name (); void setup_show_audio_sensitivity (); void setup_scaling_description (); - void setup_notebook_size (); - void setup_frame_rate_description (); + void setup_main_notebook_size (); + void setup_content (); + void setup_container (); + void setup_content_sensitivity (); + void setup_loop_sensitivity (); + void setup_minimum_audio_channels (); - wxControl* video_control (wxControl *); - wxControl* still_control (wxControl *); - void active_jobs_changed (bool); - - wxNotebook* _notebook; - wxPanel* _film_panel; - wxSizer* _film_sizer; + boost::shared_ptr selected_content (); + boost::shared_ptr selected_video_content (); + boost::shared_ptr selected_audio_content (); + + wxNotebook* _main_notebook; + wxNotebook* _content_notebook; + wxPanel* _dcp_panel; + wxSizer* _dcp_sizer; + wxPanel* _content_panel; + wxSizer* _content_sizer; wxPanel* _video_panel; - wxSizer* _video_sizer; wxPanel* _audio_panel; - wxSizer* _audio_sizer; wxPanel* _subtitle_panel; - wxSizer* _subtitle_sizer; + wxPanel* _timing_panel; /** The film we are editing */ boost::shared_ptr _film; @@@ -164,17 -166,32 +167,19 @@@ wxSpinCtrl* _subtitle_scale; wxChoice* _colour_lut; wxSpinCtrl* _j2k_bandwidth; - /** The Film's DCP content type */ wxChoice* _dcp_content_type; - /** The Film's source frame rate */ - wxStaticText* _source_frame_rate; wxChoice* _dcp_frame_rate; wxButton* _best_dcp_frame_rate; + wxCheckBox* _pad_with_silence; + wxSpinCtrl* _minimum_audio_channels; - wxStaticText* _frame_rate_description; - /** The Film's length */ - wxStaticText* _length; - /** The Film's audio details */ - wxStaticText* _audio; - /** The Film's duration for still sources */ - wxSpinCtrl* _still_duration; - - wxSpinCtrl* _trim_start; - wxSpinCtrl* _trim_end; - wxChoice* _trim_type; - /** Selector to generate an A/B comparison DCP */ - wxCheckBox* _dcp_ab; - - std::list _video_controls; - std::list _still_controls; + wxChoice* _audio_stream; + wxStaticText* _audio_description; + wxChoice* _subtitle_stream; + AudioMappingView* _audio_mapping; + Timecode* _start; + Timecode* _length; - std::vector _formats; + std::vector _ratios; bool _generally_sensitive; AudioDialog* _audio_dialog; diff --cc src/wx/gain_calculator_dialog.cc index 22e6b447a,7499cbf8b..17ebbb983 --- a/src/wx/gain_calculator_dialog.cc +++ b/src/wx/gain_calculator_dialog.cc @@@ -26,10 -26,10 +26,10 @@@ 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, DVDOMATIC_SIZER_X_GAP, DVDOMATIC_SIZER_Y_GAP); ++ 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); diff --cc src/wx/imagemagick_content_dialog.cc index dfe4df2e7,000000000..6aa756260 mode 100644,000000..100644 --- a/src/wx/imagemagick_content_dialog.cc +++ b/src/wx/imagemagick_content_dialog.cc @@@ -1,70 -1,0 +1,70 @@@ +/* + Copyright (C) 2013 Carl Hetherington + + 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 +#include "lib/imagemagick_content.h" +#include "imagemagick_content_dialog.h" +#include "wx_util.h" + +using boost::shared_ptr; +using boost::dynamic_pointer_cast; + +ImageMagickContentDialog::ImageMagickContentDialog (wxWindow* parent, shared_ptr content) + : wxDialog (parent, wxID_ANY, _("Image")) + , _content (content) +{ + wxFlexGridSizer* grid = new wxFlexGridSizer (3, 6, 6); + 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); + } + + wxBoxSizer* overall_sizer = new wxBoxSizer (wxVERTICAL); + overall_sizer->Add (grid, 1, wxEXPAND | wxALL, 6); + + wxSizer* buttons = CreateSeparatedButtonSizer (wxOK); + if (buttons) { + overall_sizer->Add (buttons, wxSizerFlags().Expand().DoubleBorder()); + } + + SetSizer (overall_sizer); + overall_sizer->Layout (); + overall_sizer->SetSizeHints (this); + + checked_set (_video_length, content->video_length () / 24); + _video_length->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (ImageMagickContentDialog::video_length_changed), 0, this); +} + +void +ImageMagickContentDialog::video_length_changed (wxCommandEvent &) +{ + shared_ptr c = _content.lock (); + if (!c) { + return; + } + + c->set_video_length (_video_length->GetValue() * 24); +} diff --cc src/wx/new_film_dialog.cc index 191482a7c,289926b8e..d4b78d5bf --- a/src/wx/new_film_dialog.cc +++ b/src/wx/new_film_dialog.cc @@@ -21,10 -21,10 +21,10 @@@ #include #include "lib/config.h" #include "new_film_dialog.h" - #ifdef __WXMSW__ + #include "wx_util.h" -#ifdef DVDOMATIC_USE_OWN_DIR_PICKER ++#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 +37,18 @@@ NewFilmDialog::NewFilmDialog (wxWindow wxBoxSizer* overall_sizer = new wxBoxSizer (wxVERTICAL); SetSizer (overall_sizer); - wxFlexGridSizer* table = new wxFlexGridSizer (2, 6, 6); - wxFlexGridSizer* table = new wxFlexGridSizer (2, DVDOMATIC_SIZER_X_GAP, DVDOMATIC_SIZER_Y_GAP); ++ 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 DVDOMATIC_USE_OWN_DIR_PICKER ++#ifdef DCPOMATIC_USE_OWN_DIR_PICKER + _folder = new DirPickerCtrl (this); #else _folder = new wxDirPickerCtrl (this, wxDD_DIR_MUST_EXIST); #endif diff --cc src/wx/new_film_dialog.h index bfcbd423c,220bba732..f8f3aa08d --- a/src/wx/new_film_dialog.h +++ b/src/wx/new_film_dialog.h @@@ -32,10 -33,10 +33,10 @@@ public private: wxTextCtrl* _name; - #ifdef __WXMSW__ -#ifdef DVDOMATIC_USE_OWN_DIR_PICKER ++#ifdef DCPOMATIC_USE_OWN_DIR_PICKER DirPickerCtrl* _folder; - #else + #else wxDirPickerCtrl* _folder; - #endif + #endif static boost::optional _directory; }; diff --cc src/wx/properties_dialog.cc index 40527ded7,aa97623cd..d525fe38b --- a/src/wx/properties_dialog.cc +++ b/src/wx/properties_dialog.cc @@@ -36,9 -36,9 +36,9 @@@ PropertiesDialog::PropertiesDialog (wxW : 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, DVDOMATIC_SIZER_X_GAP, DVDOMATIC_SIZER_Y_GAP); ++ 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); diff --cc src/wx/server_dialog.cc index 7a9cf95c7,30e3c0f83..33cb392bf --- a/src/wx/server_dialog.cc +++ b/src/wx/server_dialog.cc @@@ -30,10 -30,10 +30,10 @@@ ServerDialog::ServerDialog (wxWindow* p _server = new ServerDescription (wx_to_std (N_("localhost")), 1); } - wxFlexGridSizer* table = new wxFlexGridSizer (2, 4, 4); - wxFlexGridSizer* table = new wxFlexGridSizer (2, DVDOMATIC_SIZER_X_GAP, DVDOMATIC_SIZER_Y_GAP); ++ 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); diff --cc src/wx/timecode.cc index 9072fb99e,000000000..6ce1c1cb8 mode 100644,000000..100644 --- a/src/wx/timecode.cc +++ b/src/wx/timecode.cc @@@ -1,115 -1,0 +1,115 @@@ +/* + Copyright (C) 2013 Carl Hetherington + + 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 +#include "timecode.h" +#include "wx_util.h" + +using std::string; +using std::cout; +using boost::lexical_cast; + +Timecode::Timecode (wxWindow* parent) + : wxPanel (parent) + , _in_set (false) +{ + wxClientDC dc (parent); + wxSize size = dc.GetTextExtent (wxT ("9999")); + size.SetHeight (-1); + + wxTextValidator validator (wxFILTER_INCLUDE_CHAR_LIST); + wxArrayString list; + + wxString n (wxT ("0123456789")); + for (size_t i = 0; i < n.Length(); ++i) { + list.Add (n[i]); + } + + validator.SetIncludes (list); + + wxBoxSizer* sizer = new wxBoxSizer (wxHORIZONTAL); + _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); + + _hours->Connect (wxID_ANY, wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler (Timecode::changed), 0, this); + _minutes->Connect (wxID_ANY, wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler (Timecode::changed), 0, this); + _seconds->Connect (wxID_ANY, wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler (Timecode::changed), 0, this); + _frames->Connect (wxID_ANY, wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler (Timecode::changed), 0, this); + + SetSizerAndFit (sizer); +} + +void +Timecode::set (Time t, int fps) +{ + _in_set = true; + + int const h = t / (3600 * TIME_HZ); + t -= h * 3600 * TIME_HZ; + int const m = t / (60 * TIME_HZ); + t -= m * 60 * TIME_HZ; + int const s = t / TIME_HZ; + t -= s * TIME_HZ; + int const f = t * fps / TIME_HZ; + + _hours->SetValue (wxString::Format (wxT ("%d"), h)); + _minutes->SetValue (wxString::Format (wxT ("%d"), m)); + _seconds->SetValue (wxString::Format (wxT ("%d"), s)); + _frames->SetValue (wxString::Format (wxT ("%d"), f)); + + _in_set = false; +} + +Time +Timecode::get (int fps) const +{ + Time t = 0; + string const h = wx_to_std (_hours->GetValue ()); + t += lexical_cast (h.empty() ? "0" : h) * 3600 * TIME_HZ; + string const m = wx_to_std (_minutes->GetValue()); + t += lexical_cast (m.empty() ? "0" : m) * 60 * TIME_HZ; + string const s = wx_to_std (_seconds->GetValue()); + t += lexical_cast (s.empty() ? "0" : s) * TIME_HZ; + string const f = wx_to_std (_frames->GetValue()); + t += lexical_cast (f.empty() ? "0" : f) * TIME_HZ / fps; + return t; +} + +void +Timecode::changed (wxCommandEvent &) +{ + if (_in_set) { + return; + } + + Changed (); +} diff --cc src/wx/wscript index 992f31175,345c02b08..1205fb21b --- a/src/wx/wscript +++ b/src/wx/wscript @@@ -42,14 -51,16 +56,16 @@@ def build(bld) obj.includes = [ '..' ] obj.export_includes = ['.'] obj.uselib = 'WXWIDGETS' + if bld.env.TARGET_LINUX: + obj.uselib += ' GTK' - obj.use = 'libdvdomatic' + obj.use = 'libdcpomatic' obj.source = sources - obj.target = 'dvdomatic-wx' + obj.target = 'dcpomatic-wx' - i18n.po_to_mo(os.path.join('src', 'wx'), 'libdvdomatic-wx', bld) + i18n.po_to_mo(os.path.join('src', 'wx'), 'libdcpomatic-wx', bld) def pot(bld): - i18n.pot(os.path.join('src', 'wx'), sources, 'libdvdomatic-wx') + i18n.pot(os.path.join('src', 'wx'), sources, 'libdcpomatic-wx') def pot_merge(bld): - i18n.pot_merge(os.path.join('src', 'wx'), 'libdvdomatic-wx') + i18n.pot_merge(os.path.join('src', 'wx'), 'libdcpomatic-wx') diff --cc src/wx/wx_util.h index bff11647e,18a9f251c..de6a09c35 --- a/src/wx/wx_util.h +++ b/src/wx/wx_util.h @@@ -17,6 -17,9 +17,9 @@@ */ -#ifndef DVDOMATIC_WX_UTIL_H -#define DVDOMATIC_WX_UTIL_H ++#ifndef DCPOMATIC_WX_UTIL_H ++#define DCPOMATIC_WX_UTIL_H + #include #include #include @@@ -26,17 -32,20 +32,20 @@@ class wxFilePickerCtrl class wxSpinCtrl; class wxGridBagSizer; -#define DVDOMATIC_SIZER_X_GAP 8 -#define DVDOMATIC_SIZER_Y_GAP 8 ++#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 dvdomatic_setup_i18n (); +extern void dcpomatic_setup_i18n (); /** @class ThreadedStaticText * @@@ -69,3 -78,12 +78,12 @@@ extern void checked_set (wxTextCtrl* wi 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 DVDOMATIC_USE_OWN_DIR_PICKER ++#define DCPOMATIC_USE_OWN_DIR_PICKER + #endif + + #endif diff --cc test/test.cc index 4494540a2,74d967a46..d6c7842d7 --- a/test/test.cc +++ b/test/test.cc @@@ -40,10 -39,10 +40,11 @@@ #include "scaler.h" #include "ffmpeg_decoder.h" #include "sndfile_decoder.h" -#include "trimmer.h" +#include "dcp_content_type.h" #include "ui_signaller.h" ++#include "ratio.h" #define BOOST_TEST_DYN_LINK -#define BOOST_TEST_MODULE dvdomatic_test +#define BOOST_TEST_MODULE dcpomatic_test #include using std::string; @@@ -66,8 -63,8 +67,8 @@@ struct TestConfi Config::instance()->set_servers (vector ()); 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_format (static_cast (0)); ++ Config::instance()->set_default_container (static_cast (0)); + Config::instance()->set_default_dcp_content_type (static_cast (0)); ui_signaller = new UISignaller (); } diff --cc test/wscript index 2fbbdacbf,71636a05d..60d846aea --- a/test/wscript +++ b/test/wscript @@@ -12,8 -12,8 +12,8 @@@ 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 = 'libdvdomatic' + obj.use = 'libdcpomatic' obj.source = 'test.cc' obj.target = 'unit-tests' obj.install_path = '' diff --cc wscript index b1d7eafe2,9d3a566fe..2c0a14580 --- a/wscript +++ b/wscript @@@ -29,10 -29,10 +29,10 @@@ 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', ['-DDVDOMATIC_WINDOWS', '-DWIN32_LEAN_AND_MEAN', '-DBOOST_USE_WINDOWS_H', '-DUNICODE']) + conf.env.append_value('CXXFLAGS', ['-DDCPOMATIC_WINDOWS', '-DWIN32_LEAN_AND_MEAN', '-DBOOST_USE_WINDOWS_H', '-DUNICODE']) wxrc = os.popen('wx-config --rescomp').read().split()[1:] conf.env.append_value('WINRCFLAGS', wxrc) if conf.options.enable_debug: @@@ -84,9 -86,7 +87,9 @@@ 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.check_cfg(package='libxml++-2.6', args='--cflags --libs', uselib_store='DCP', mandatory=True) + 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 @@@ -234,8 -243,15 +242,15 @@@ def create_version_cc(version, cxx_flag try: text = '#include "version.h"\n' - text += 'char const * dvdomatic_git_commit = \"%s\";\n' % commit - text += 'char const * dvdomatic_version = \"%s\";\n' % version + 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 * dvdomatic_cxx_flags = \"%s\";\n' % t[:-1] ++ 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)