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'):
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')]
Section: video
Priority: extra
Maintainer: Carl Hetherington <cth@carlh.net>
- Build-Depends: debhelper (>= 8.0.0), python (>= 2.7.3), g++ (>= 4:4.6.3), pkg-config (>= 0.26), libwxgtk2.8-dev (>= 2.8.12.1), libssh-dev (>= 0.5.2), libboost-filesystem-dev (>= 1.46.0), libboost-thread-dev (>= 1.46.0), libsndfile1-dev (>= 1.0.25), libmagick++-dev (>= 8:6.6.9.7)
+ Build-Depends: debhelper (>= 8.0.0), python (>= 2.7.3), g++ (>= 4:4.6.3), pkg-config (>= 0.26), libssh-dev (>= 0.5.2), libboost-filesystem-dev (>= 1.46.0), libboost-thread-dev (>= 1.46.0), libsndfile1-dev (>= 1.0.25), libmagick++-dev (>= 8:6.6.9.7), libgtk2.0-dev (>= 2.24.10)
Standards-Version: 3.9.3
-Homepage: http://carlh.net/software/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.
Section: video
Priority: extra
Maintainer: Carl Hetherington <cth@carlh.net>
- Build-Depends: debhelper (>= 8.0.0), python (>= 2.7.3), g++ (>= 4:4.6.3), pkg-config (>= 0.26), libwxgtk2.8-dev (>= 2.8.12.1), libssh-dev (>= 0.5.2), libboost-filesystem-dev (>= 1.46.0), libboost-thread-dev (>= 1.46.0), libsndfile1-dev (>= 1.0.25), libmagick++-dev (>= 8:6.6.9.7)
+ Build-Depends: debhelper (>= 8.0.0), python (>= 2.7.3), g++ (>= 4:4.6.3), pkg-config (>= 0.26), libssh-dev (>= 0.5.2), libboost-filesystem-dev (>= 1.46.0), libboost-thread-dev (>= 1.46.0), libsndfile1-dev (>= 1.0.25), libmagick++-dev (>= 8:6.6.9.7), libgtk2.0-dev (>= 2.4.10)
Standards-Version: 3.9.3
-Homepage: http://carlh.net/software/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)
Section: video
Priority: extra
Maintainer: Carl Hetherington <cth@carlh.net>
- Build-Depends: debhelper (>= 8.0.0), python (>= 2.7.3), g++ (>= 4:4.6.3), pkg-config (>= 0.26), libwxgtk2.8-dev (>= 2.8.12.1), libssh-dev (>= 0.5.2), libboost-filesystem-dev (>= 1.46.0), libboost-thread-dev (>= 1.46.0), libsndfile1-dev (>= 1.0.25), libmagick++-dev (>= 8:6.6.9.7)
+ Build-Depends: debhelper (>= 8.0.0), python (>= 2.7.3), g++ (>= 4:4.6.3), pkg-config (>= 0.26), libssh-dev (>= 0.5.2), libboost-filesystem-dev (>= 1.46.0), libboost-thread-dev (>= 1.46.0), libsndfile1-dev (>= 1.0.25), libmagick++-dev (>= 8:6.6.9.7), libgtk2.0-dev (>= 2.24.13)
Standards-Version: 3.9.3
-Homepage: http://carlh.net/software/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.
Section: video
Priority: extra
Maintainer: Carl Hetherington <cth@carlh.net>
- Build-Depends: debhelper (>= 8.0.0), python (>= 2.7.3), g++ (>= 4:4.6.3), pkg-config (>= 0.26), libwxgtk2.8-dev (>= 2.8.12.1), libssh-dev (>= 0.5.2), libboost-filesystem-dev (>= 1.46.0), libboost-thread-dev (>= 1.46.0), libsndfile1-dev (>= 1.0.25), libmagick++-dev (>= 8:6.6.9.7)
+ Build-Depends: debhelper (>= 8.0.0), python (>= 2.7.3), g++ (>= 4:4.6.3), pkg-config (>= 0.26), libssh-dev (>= 0.5.2), libboost-filesystem-dev (>= 1.46.0), libboost-thread-dev (>= 1.46.0), libsndfile1-dev (>= 1.0.25), libmagick++-dev (>= 8:6.6.9.7), libgtk2.0-dev (>= 2.24.13)
Standards-Version: 3.9.3
-Homepage: http://carlh.net/software/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.
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
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
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
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
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
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);
#include <fstream>
#include <boost/algorithm/string.hpp>
#include "cross.h"
- #ifdef DCPOMATIC_POSIX
+ #include "compose.hpp"
+ #include "log.h"
-#ifdef DVDOMATIC_LINUX
++#ifdef DCPOMATIC_LINUX
#include <unistd.h>
+ #include <mntent.h>
#endif
-#ifdef DVDOMATIC_WINDOWS
+#ifdef DCPOMATIC_WINDOWS
- #include "windows.h"
+ #include <windows.h>
+ #undef DATADIR
+ #include <shlwapi.h>
#endif
-#ifdef DVDOMATIC_OSX
+#ifdef DCPOMATIC_OSX
#include <sys/sysctl.h>
#endif
using std::pair;
+ using std::list;
using std::ifstream;
using std::string;
+ using std::make_pair;
+ using boost::shared_ptr;
void
-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
}
return info;
}
-#ifdef DVDOMATIC_WINDOWS
+ void
+ run_ffprobe (boost::filesystem::path content, boost::filesystem::path out, shared_ptr<Log> log)
+ {
-#ifdef DVDOMATIC_LINUX
++#ifdef DCPOMATIC_WINDOWS
+ SECURITY_ATTRIBUTES security;
+ security.nLength = sizeof (security);
+ security.bInheritHandle = TRUE;
+ security.lpSecurityDescriptor = 0;
+
+ HANDLE child_stderr_read;
+ HANDLE child_stderr_write;
+ if (!CreatePipe (&child_stderr_read, &child_stderr_write, &security, 0)) {
+ log->log ("ffprobe call failed (could not CreatePipe)");
+ return;
+ }
+
+ wchar_t dir[512];
+ GetModuleFileName (GetModuleHandle (0), dir, sizeof (dir));
+ PathRemoveFileSpec (dir);
+ SetCurrentDirectory (dir);
+
+ STARTUPINFO startup_info;
+ ZeroMemory (&startup_info, sizeof (startup_info));
+ startup_info.cb = sizeof (startup_info);
+ startup_info.hStdError = child_stderr_write;
+ startup_info.dwFlags |= STARTF_USESTDHANDLES;
+
+ wchar_t command[512];
+ wcscpy (command, L"ffprobe.exe \"");
+
+ wchar_t file[512];
+ MultiByteToWideChar (CP_UTF8, 0, content.string().c_str(), -1, file, sizeof(file));
+ wcscat (command, file);
+
+ wcscat (command, L"\"");
+
+ PROCESS_INFORMATION process_info;
+ ZeroMemory (&process_info, sizeof (process_info));
+ if (!CreateProcess (0, command, 0, 0, TRUE, CREATE_NO_WINDOW, 0, 0, &startup_info, &process_info)) {
+ log->log ("ffprobe call failed (could not CreateProcess)");
+ return;
+ }
+
+ FILE* o = fopen (out.string().c_str(), "w");
+ if (!o) {
+ log->log ("ffprobe call failed (could not create output file)");
+ return;
+ }
+
+ CloseHandle (child_stderr_write);
+
+ while (1) {
+ char buffer[512];
+ DWORD read;
+ if (!ReadFile(child_stderr_read, buffer, sizeof(buffer), &read, 0) || read == 0) {
+ break;
+ }
+ fwrite (buffer, read, 1, o);
+ }
+
+ fclose (o);
+
+ WaitForSingleObject (process_info.hProcess, INFINITE);
+ CloseHandle (process_info.hProcess);
+ CloseHandle (process_info.hThread);
+ CloseHandle (child_stderr_read);
+ #else
+ string ffprobe = "ffprobe \"" + content.string() + "\" 2> \"" + out.string() + "\"";
+ log->log (String::compose ("Probing with %1", ffprobe));
+ system (ffprobe.c_str ());
+ #endif
+ }
+
+ list<pair<string, string> >
+ mount_info ()
+ {
+ list<pair<string, string> > m;
+
++#ifdef DCPOMATIC_LINUX
+ FILE* f = setmntent ("/etc/mtab", "r");
+ if (!f) {
+ return m;
+ }
+
+ while (1) {
+ struct mntent* mnt = getmntent (f);
+ if (!mnt) {
+ break;
+ }
+
+ m.push_back (make_pair (mnt->mnt_dir, mnt->mnt_type));
+ }
+
+ endmntent (f);
+ #endif
+
+ return m;
+ }
*/
-#include <string>
+ #include <boost/filesystem.hpp>
+
-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<std::string, int> cpu_info ();
+ extern void run_ffprobe (boost::filesystem::path, boost::filesystem::path, boost::shared_ptr<Log>);
+ extern std::list<std::pair<std::string, std::string> > mount_info ();
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;
}
}
-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 ()
{
-
- if (!_audio_stream) {
- return;
- }
-
- shared_ptr<FFmpegAudioStream> ffa = dynamic_pointer_cast<FFmpegAudioStream> (_audio_stream);
- assert (ffa);
-
- _audio_codec_context = _format_context->streams[ffa->id()]->codec;
- _audio_codec = avcodec_find_decoder (_audio_codec_context->codec_id);
+ boost::mutex::scoped_lock lm (_mutex);
- 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);
av_free_packet (&_packet);
}
}
-
- return r < 0;
}
-shared_ptr<FFmpegAudioStream>
-FFmpegAudioStream::create (string t, optional<int> 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<FFmpegAudioStream> (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<FFmpegAudioStream> ();
- }
+ while (copy_packet.size > 0) {
- return shared_ptr<FFmpegAudioStream> (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<AudioBuffers> 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<int> 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<FilterGraph> graph;
+
+ list<shared_ptr<FilterGraph> >::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<const Film> 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<shared_ptr<Image> > images = graph->process (_frame);
+
+ string post_process = Filter::ffmpeg_strings (_ffmpeg_content->filters()).second;
+
+ for (list<shared_ptr<Image> >::iterator i = images.begin(); i != images.end(); ++i) {
+
+ shared_ptr<Image> 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<Image> black (
+ new SimpleImage (
+ static_cast<AVPixelFormat> (_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<const Film> 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<FFmpegAudioStream> ffa = dynamic_pointer_cast<FFmpegAudioStream> (_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;
+}
+
, _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 ();
}
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)
, _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
#endif
pair<string, int> const c = cpu_info ();
log()->log (String::compose ("CPU: %1, %2 processors", c.first, c.second));
+ list<pair<string, string> > const m = mount_info ();
+ for (list<pair<string, string> >::const_iterator i = m.begin(); i != m.end(); ++i) {
+ log()->log (String::compose ("Mount: %1 %2", i->first, i->second));
+ }
- if (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) {
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<string> (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<Filter const *>::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<string>::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<shared_ptr<AudioStream> >::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<shared_ptr<SubtitleStream> >::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<string> (_subtitle_offset));
+ root->add_child("SubtitleScale")->add_child_text (lexical_cast<string> (_subtitle_scale));
+ root->add_child("ColourLUT")->add_child_text (lexical_cast<string> (_colour_lut));
+ root->add_child("J2KBandwidth")->add_child_text (lexical_cast<string> (_j2k_bandwidth));
+ _dci_metadata.as_xml (root->add_child ("DCIMetadata"));
+ root->add_child("DCPVideoFrameRate")->add_child_text (lexical_cast<string> (_dcp_video_frame_rate));
+ root->add_child("DCIDate")->add_child_text (boost::gregorian::to_iso_string (_dci_date));
+ root->add_child("DCPAudioChannels")->add_child_text (lexical_cast<string> (_dcp_audio_channels));
++ root->add_child("MinimumAudioChannels")->add_child_text (lexical_cast<string> (_minimum_audio_channels));
+ _playlist->as_xml (root->add_child ("Playlist"));
+
+ doc.write_to_file_formatted (file ("metadata.xml"));
_dirty = false;
}
}
}
- if (!version) {
- if (audio_sample_rate) {
- /* version < 1 didn't specify sample rate in the audio streams, so fill it in here */
- for (vector<shared_ptr<AudioStream> >::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<float> ("SubtitleOffset");
+ _subtitle_scale = f.number_child<float> ("SubtitleScale");
+ _colour_lut = f.number_child<int> ("ColourLUT");
+ _j2k_bandwidth = f.number_child<int> ("J2KBandwidth");
+ _dci_metadata = DCIMetadata (f.node_child ("DCIMetadata"));
+ _dcp_video_frame_rate = f.number_child<int> ("DCPVideoFrameRate");
+ _dci_date = boost::gregorian::from_undelimited_string (f.string_child ("DCIDate"));
+ _dcp_audio_channels = f.number_child<int> ("DCPAudioChannels");
++ _minimum_audio_channels = f.number_child<int> ("MinimumAudioChannels");
- /* 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;
}
}
-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<shared_ptr<AudioStream> > s)
-{
- {
- boost::mutex::scoped_lock lm (_state_mutex);
- _content_audio_streams = s;
- }
- signal_changed (CONTENT_AUDIO_STREAMS);
-}
-
-void
-Film::set_subtitle_streams (vector<shared_ptr<SubtitleStream> > s)
+Film::set_dcp_video_frame_rate (int f)
{
{
boost::mutex::scoped_lock lm (_state_mutex);
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
};
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<SourceFrame> 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<boost::shared_ptr<AudioStream> > content_audio_streams () const {
- boost::mutex::scoped_lock lm (_state_mutex);
- return _content_audio_streams;
+ return _dcp_video_frame_rate;
}
- std::vector<boost::shared_ptr<SubtitleStream> > 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;
}
- boost::shared_ptr<AudioStream> audio_stream () const;
- bool has_audio () const;
-
+ int minimum_audio_channels () const {
+ boost::mutex::scoped_lock lm (_state_mutex);
+ return _minimum_audio_channels;
+ }
+
/* SET */
void set_directory (std::string);
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<boost::shared_ptr<AudioStream> >);
- void set_subtitle_streams (std::vector<boost::shared_ptr<SubtitleStream> >);
- 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<void (Property)> Changed;
- boost::signals2::signal<void ()> AudioAnalysisSucceeded;
+ /** Emitted when some property of our content has changed */
+ mutable boost::signals2::signal<void (boost::weak_ptr<Content>, int)> ContentChanged;
/** Current version number of the state file */
static int const state_version;
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<SourceFrame> _length;
- /** MD5 digest of our content file */
- std::string _content_digest;
- /** The audio streams in our content */
- std::vector<boost::shared_ptr<AudioStream> > _content_audio_streams;
- /** A stream to represent possible external audio (will always exist) */
- boost::shared_ptr<AudioStream> _sndfile_stream;
- /** the subtitle streams that we can use */
- std::vector<boost::shared_ptr<SubtitleStream> > _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;
--- /dev/null
+/*
+ Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
++#ifndef DCPOMATIC_RATIO_H
++#define DCPOMATIC_RATIO_H
++
+#include <vector>
+#include <libdcp/util.h>
+
+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<Ratio const *> 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<Ratio const *> _ratios;
+};
++
++#endif
#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 ();
-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;
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')
--- /dev/null
- #endif
+/*
+ Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <iostream>
+#include <fstream>
+#include <boost/filesystem.hpp>
+#ifdef __WXMSW__
+#include <shellapi.h>
+#endif
+#ifdef __WXOSX__
+#include <ApplicationServices/ApplicationServices.h>
+#endif
+#include <wx/generic/aboutdlgg.h>
+#include <wx/stdpaths.h>
+#include <wx/cmdline.h>
+#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> 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<wxMenuItem*, Sensitivity> 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<wxMenuItem*, Sensitivity>::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
+ 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<JobManagerView::Buttons> (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)
--- /dev/null
- int c = getopt_long (argc, argv, "vhdnrl:", long_options, &option_index);
+/*
+ Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <iostream>
+#include <iomanip>
+#include <getopt.h>
+#include <libdcp/version.h>
+#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] <FILM>\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"
+ << "<FILM> 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, "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<ServerDescription*> ());
+ }
+
+ 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> 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<string, string> 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<shared_ptr<Job> > 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<shared_ptr<Job> >::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;
+}
+
+
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')
}
void
-AudioDialog::set_film (boost::shared_ptr<Film> f)
+AudioDialog::set_content (shared_ptr<AudioContent> 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<libdcp::Channel>(i))) {
- _channel_checkbox[i]->Show ();
- } else {
- _channel_checkbox[i]->Hide ();
- }
- }
-}
--
void
AudioDialog::try_to_load_analysis ()
{
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);
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);
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);
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);
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);
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);
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;
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);
}
void
-FilmEditor::make_film_panel ()
+FilmEditor::make_dcp_panel ()
{
- _film_panel = new wxPanel (_notebook);
- _film_sizer = new wxBoxSizer (wxVERTICAL);
- _film_panel->SetSizer (_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;
-
- _use_dci_name = new wxCheckBox (_film_panel, wxID_ANY, _("Use DCI name"));
+ int flags = wxALIGN_CENTER_VERTICAL;
+ #ifdef __WXOSX__
+ flags |= wxALIGN_RIGHT;
+ #endif
- grid->Add (_use_dci_name, wxGBPosition (r, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
++
+ _use_dci_name = new wxCheckBox (_dcp_panel, wxID_ANY, _("Use DCI name"));
- _edit_dci_button = new wxButton (_film_panel, wxID_ANY, _("Details..."));
+ grid->Add (_use_dci_name, wxGBPosition (r, 0), wxDefaultSpan, flags);
+ _edit_dci_button = new wxButton (_dcp_panel, wxID_ANY, _("Details..."));
grid->Add (_edit_dci_button, wxGBPosition (r, 1), wxDefaultSpan);
++r;
- add_label_to_grid_bag_sizer (grid, _dcp_panel, _("Container"), wxGBPosition (r, 0));
- add_label_to_grid_bag_sizer (grid, _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<Scaler const *> const sc = Scaler::all ();
+ for (vector<Scaler const *>::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<Ratio const *> const ratio = Ratio::all ();
+ for (vector<Ratio const *>::const_iterator i = ratio.begin(); i != ratio.end(); ++i) {
+ _container->Append (std_to_wx ((*i)->nickname ()));
}
- ++r;
vector<DCPContentType const *> const ct = DCPContentType::all ();
for (vector<DCPContentType const *>::const_iterator i = ct.begin(); i != ct.end(); ++i) {
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
);
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;
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();
/* 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<Scaler const *> const sc = Scaler::all ();
- for (vector<Scaler const *>::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)));
_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);
}
- add_label_to_sizer (grid, _audio_panel, _("Audio Stream"));
+ grid->AddSpacer (0);
+
-
- _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);
- }
++ 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);
+ }
++#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);
}
- add_label_to_sizer (grid, _timing_panel, _("Start time"));
+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, _("Length"));
++ 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"), true);
+ _length = new Timecode (_timing_panel);
+ grid->Add (_length);
+}
+
+
/** Called when the left crop widget has been changed */
void
FilmEditor::left_crop_changed (wxCommandEvent &)
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<Format const *>::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<string, string> 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 ();
}
}
- 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;
}
}
}
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<Content> c = selected_content ();
+ if (!c) {
+ return;
+ }
+
+ shared_ptr<FFmpegContent> fc = dynamic_pointer_cast<FFmpegContent> (c);
+ if (!fc) {
+ return;
+ }
+
+ vector<shared_ptr<FFmpegAudioStream> > a = fc->audio_streams ();
+ vector<shared_ptr<FFmpegAudioStream> >::iterator i = a.begin ();
+ string const s = string_client_data (_audio_stream->GetClientObject (_audio_stream->GetSelection ()));
+ while (i != a.end() && lexical_cast<string> ((*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<Content> c = selected_content ();
+ if (!c) {
+ return;
+ }
+
+ shared_ptr<FFmpegContent> fc = dynamic_pointer_cast<FFmpegContent> (c);
+ if (!fc) {
+ return;
+ }
+
+ vector<shared_ptr<FFmpegSubtitleStream> > a = fc->subtitle_streams ();
+ vector<shared_ptr<FFmpegSubtitleStream> >::iterator i = a.begin ();
+ string const s = string_client_data (_subtitle_stream->GetClientObject (_subtitle_stream->GetSelection ()));
+ while (i != a.end() && lexical_cast<string> ((*i)->id) != s) {
+ ++i;
+ }
+
+ if (i != a.end ()) {
+ fc->set_subtitle_stream (*i);
+ }
+}
+
+void
+FilmEditor::audio_mapping_changed (AudioMapping m)
+{
+ shared_ptr<Content> c = selected_content ();
+ if (!c) {
+ return;
+ }
+
+ shared_ptr<AudioContent> ac = dynamic_pointer_cast<AudioContent> (c);
+ if (!ac) {
+ return;
+ }
+
+ ac->set_audio_mapping (m);
+}
+
+void
+FilmEditor::start_changed ()
+{
+ shared_ptr<Content> c = selected_content ();
+ if (!c) {
+ return;
+ }
+
+ c->set_start (_start->get (_film->dcp_video_frame_rate ()));
+}
+
+void
+FilmEditor::length_changed ()
+{
+ shared_ptr<Content> c = selected_content ();
+ if (!c) {
+ return;
+ }
+
+ shared_ptr<ImageMagickContent> ic = dynamic_pointer_cast<ImageMagickContent> (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<Content> 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<Content> c = selected_content ();
+ if (!c) {
+ return;
+ }
+
+ shared_ptr<VideoContent> vc = dynamic_pointer_cast<VideoContent> (c);
+ if (!vc) {
+ return;
+ }
+
+ int const n = _ratio->GetSelection ();
+ if (n >= 0) {
+ vector<Ratio const *> ratios = Ratio::all ();
+ assert (n < int (ratios.size()));
+ vc->set_ratio (ratios[n]);
+ }
}
- setup_audio_control_sensitivity ();
+
+ 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 &)
+ {
- _film->set_minimum_audio_channels (_minimum_audio_channels->GetValue ());
++
+ }
+
+ void
+ FilmEditor::minimum_audio_channels_changed (wxCommandEvent &)
+ {
+ if (!_film) {
+ return;
+ }
+
++// _film->set_minimum_audio_channels (_minimum_audio_channels->GetValue ());
+ }
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);
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<Content> selected_content ();
+ boost::shared_ptr<VideoContent> selected_video_content ();
+ boost::shared_ptr<AudioContent> 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> _film;
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;
- 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<wxControl*> _video_controls;
- std::list<wxControl*> _still_controls;
+ wxCheckBox* _pad_with_silence;
+ wxSpinCtrl* _minimum_audio_channels;
+ wxChoice* _audio_stream;
+ wxStaticText* _audio_description;
+ wxChoice* _subtitle_stream;
+ AudioMappingView* _audio_mapping;
+ Timecode* _start;
+ Timecode* _length;
- std::vector<Format const *> _formats;
+ std::vector<Ratio const *> _ratios;
bool _generally_sensitive;
AudioDialog* _audio_dialog;
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);
--- /dev/null
- add_label_to_sizer (grid, this, (_("Duration")));
+/*
+ Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <wx/spinctrl.h>
+#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<ImageMagickContent> content)
+ : wxDialog (parent, wxID_ANY, _("Image"))
+ , _content (content)
+{
+ wxFlexGridSizer* grid = new wxFlexGridSizer (3, 6, 6);
+ grid->AddGrowableCol (1, 1);
+
+ {
- add_label_to_sizer (s, this, _("s"));
++ 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"), 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<ImageMagickContent> c = _content.lock ();
+ if (!c) {
+ return;
+ }
+
+ c->set_video_length (_video_length->GetValue() * 24);
+}
#include <wx/stdpaths.h>
#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;
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
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<std::string> _directory;
};
: 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);
_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);
--- /dev/null
- add_label_to_sizer (sizer, this, wxT (":"));
+/*
+ Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <boost/lexical_cast.hpp>
+#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 ("."), 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<int> (h.empty() ? "0" : h) * 3600 * TIME_HZ;
+ string const m = wx_to_std (_minutes->GetValue());
+ t += lexical_cast<int> (m.empty() ? "0" : m) * 60 * TIME_HZ;
+ string const s = wx_to_std (_seconds->GetValue());
+ t += lexical_cast<int> (s.empty() ? "0" : s) * TIME_HZ;
+ string const f = wx_to_std (_frames->GetValue());
+ t += lexical_cast<int> (f.empty() ? "0" : f) * TIME_HZ / fps;
+ return t;
+}
+
+void
+Timecode::changed (wxCommandEvent &)
+{
+ if (_in_set) {
+ return;
+ }
+
+ Changed ();
+}
obj.includes = [ '..' ]
obj.export_includes = ['.']
obj.uselib = 'WXWIDGETS'
- obj.use = 'libdvdomatic'
+ if bld.env.TARGET_LINUX:
+ obj.uselib += ' GTK'
+ 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')
*/
-#ifndef DVDOMATIC_WX_UTIL_H
-#define DVDOMATIC_WX_UTIL_H
++#ifndef DCPOMATIC_WX_UTIL_H
++#define DCPOMATIC_WX_UTIL_H
+
#include <wx/wx.h>
#include <wx/gbsizer.h>
#include <boost/function.hpp>
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
*
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);
-#define DVDOMATIC_USE_OWN_DIR_PICKER
+
+ /* GTK 2.24.17 has a buggy GtkFileChooserButton and it was put in Ubuntu 13.04.
+ Use our own dir picker as this is the least bad option I can think of.
+ */
+ #if defined(__WXMSW__) || (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION == 24 && GTK_MICRO_VERSION == 17)
++#define DCPOMATIC_USE_OWN_DIR_PICKER
+ #endif
+
+ #endif
#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 <boost/test/unit_test.hpp>
using std::string;
Config::instance()->set_servers (vector<ServerDescription*> ());
Config::instance()->set_server_port (61920);
Config::instance()->set_default_dci_metadata (DCIMetadata ());
- Config::instance()->set_default_container (0);
- Config::instance()->set_default_dcp_content_type (0);
- Config::instance()->set_default_format (static_cast<Format*> (0));
++ Config::instance()->set_default_container (static_cast<Ratio*> (0));
+ Config::instance()->set_default_dcp_content_type (static_cast<DCPContentType*> (0));
ui_signaller = new UISignaller ();
}
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 = ''
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:
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
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)