#!/bin/bash
--iconutil --convert icns --output dvdomatic.icns dvdomatic.iconset/
++iconutil --convert icns --output dcpomatic.icns dcpomatic.iconset/
+++ /dev/null
--[Desktop Entry]
--Encoding=UTF-8
--Version=1.0
--Type=Application
--Terminal=false
--Exec=@PREFIX@/bin/dvdomatic
--Name=DVD-o-matic
--Icon=dvdomatic
--Comment=DCP generator
--Categories=AudioVideo;Video
+++ /dev/null
--[Desktop Entry]
--Encoding=UTF-8
--Version=1.0
--Type=Application
--Terminal=false
--Exec=@PREFIX@/bin/dvdomatic_batch
--Name=DVD-o-matic Batch Converter
--Icon=dvdomatic
--Comment=Batch DCP generator
--Categories=AudioVideo;Video
+++ /dev/null
--[Desktop Entry]
--Encoding=UTF-8
--Version=1.0
--Type=Application
--Terminal=false
--Exec=@PREFIX@/bin/servomatic_gui
--Name=DVD-o-matic Encode Server
--Icon=dvdomatic
--Comment=DCP generator
--Categories=AudioVideo;Video
d = { 'PREFIX' : '${PREFIX' }
obj = bld(features = 'subst')
-- obj.source = 'dvdomatic.desktop.in'
-- obj.target = 'dvdomatic.desktop'
++ obj.source = 'dcpomatic.desktop.in'
++ obj.target = 'dcpomatic.desktop'
obj.dict = d
obj = bld(features = 'subst')
-- obj.source = 'dvdomatic_batch.desktop.in'
-- obj.target = 'dvdomatic_batch.desktop'
++ obj.source = 'dcpomatic_batch.desktop.in'
++ obj.target = 'dcpomatic_batch.desktop'
obj.dict = d
obj = bld(features = 'subst')
-- obj.source = 'servomatic.desktop.in'
-- obj.target = 'servomatic.desktop'
++ obj.source = 'dcpomatic_server.desktop.in'
++ obj.target = 'dcpomatic_server.desktop'
obj.dict = d
-- bld.install_files('${PREFIX}/share/applications', ['dvdomatic.desktop', 'dvdomatic_batch.desktop', 'servomatic.desktop'])
++ bld.install_files('${PREFIX}/share/applications', ['dcpomatic.desktop', 'dcpomatic_batch.desktop', 'dcpomatic_server.desktop'])
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
-- <string>dvdomatic</string>
++ <string>dcpomatic</string>
<key>CFBundleGetInfoString</key>
<string>DCP generator</string>
<key>CFBundleIconFile</key>
-- <string>DVD-o-matic.icns</string>
++ <string>DCP-o-matic.icns</string>
<key>CFBundleIdentifier</key>
-- <string>net.carlh.dvdomatic</string>
++ <string>net.carlh.dcpomatic</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
-- <string>DVD-o-matic</string>
++ <string>DCP-o-matic</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersions</key>
mkdir -p $WORK/$libs
mkdir -p $WORK/$resources
--cp build/src/tools/dvdomatic $WORK/$macos/
--cp build/src/lib/libdvdomatic.dylib $WORK/$libs/
--cp build/src/wx/libdvdomatic-wx.dylib $WORK/$libs/
++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 $ENV/lib/libfreetype*.dylib $WORK/$libs/
cp $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
set arrangement of theViewOptions to not arranged
set icon size of theViewOptions to 64
make new alias file at container window to POSIX file "/Applications" with properties {name:"Applications"}
- set position of item "DVD-o-matic.app" of container window to {90, 100}
- set position of item "Applications" of container window to {310, 100}
- set position of item "DVD-o-matic.app" of container window to {90, 80}
++ set position of item "DCP-o-matic.app" of container window to {90, 80}
+ set position of item "Applications" of container window to {310, 80}
close
open
update without registering applications
umount $device
hdiutil eject $device
hdiutil convert -format UDZO $tmp_dmg -imagekey zlib-level=9 -o "$dmg"
--sips -i $WORK/$resources/DVD-o-matic.icns
--DeRez -only icns $WORK/$resources/DVD-o-matic.icns > $WORK/$resources/DVD-o-matic.rsrc
--Rez -append $WORK/$resources/DVD-o-matic.rsrc -o "$dmg"
++sips -i $WORK/$resources/DCP-o-matic.icns
++DeRez -only icns $WORK/$resources/DCP-o-matic.icns > $WORK/$resources/DCP-o-matic.rsrc
++Rez -append $WORK/$resources/DCP-o-matic.rsrc -o "$dmg"
SetFile -a C "$dmg"
File "%deps%/bin/libfontconfig-1.dll"
File "%deps%/bin/libexpat-1.dll"
File "%deps%/bin/libbz2.dll"
+File "%deps%/bin/cxml.dll"
-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\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 "%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
+++ /dev/null
--#!/bin/bash
--
--export DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:build/src/lib:build/src:/Users/carl/Environments/osx/10.8/lib
--if [ "$1" == "--debug" ]; then
-- shift
-- gdb --args build/src/tools/dvdomatic "$*"
--elif [ "$1" == "--valgrind" ]; then
-- shift
-- valgrind --tool="memcheck" build/src/tools/dvdomatic $*
--elif [ "$1" == "--i18n" ]; then
-- shift
-- LANGUAGE=fr_FR.UTF8 LANG=fr_FR.UTF8 build/src/tools/dvdomatic "$*"
--else
-- build/src/tools/dvdomatic "$*"
--fi
+++ /dev/null
--#!/bin/bash
--
--export LD_LIBRARY_PATH=build/src/lib:build/src/wx:build/src/asdcplib/src:$LD_LIBRARY_PATH
--if [ "$1" == "--debug" ]; then
-- shift
-- gdb --args build/src/tools/dvdomatic_batch "$*"
--elif [ "$1" == "--valgrind" ]; then
-- shift
-- valgrind --tool="memcheck" build/src/tools/dvdomatic_batch $*
--elif [ "$1" == "--i18n" ]; then
-- shift
-- LANGUAGE=fr_FR.UTF8 LANG=fr_FR.UTF8 build/src/tools/dvdomatic_batch "$*"
--else
-- build/src/tools/dvdomatic_batch
--fi
#include <stdexcept>
#include "ab_transcode_job.h"
#include "film.h"
-#include "format.h"
-#include "filter.h"
#include "ab_transcoder.h"
#include "config.h"
-#include "encoder.h"
+ #include "log.h"
#include "i18n.h"
*/
+ #include <fstream>
+ #include <boost/algorithm/string.hpp>
#include "cross.h"
-#ifdef DVDOMATIC_POSIX
+#ifdef DCPOMATIC_POSIX
#include <unistd.h>
#endif
-#ifdef DVDOMATIC_WINDOWS
+#ifdef DCPOMATIC_WINDOWS
#include "windows.h"
#endif
-#ifdef DVDOMATIC_OSX
++#ifdef DCPOMATIC_OSX
+ #include <sys/sysctl.h>
+ #endif
+
+ using std::pair;
+ using std::ifstream;
+ using std::string;
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
}
-#ifdef DVDOMATIC_LINUX
+
+ /** @return A pair containing CPU model name and the number of processors */
+ pair<string, int>
+ cpu_info ()
+ {
+ pair<string, int> info;
+ info.second = 0;
+
-#ifdef DVDOMATIC_OSX
++#ifdef DCPOMATIC_LINUX
+ ifstream f ("/proc/cpuinfo");
+ while (f.good ()) {
+ string l;
+ getline (f, l);
+ if (boost::algorithm::starts_with (l, "model name")) {
+ string::size_type const c = l.find (':');
+ if (c != string::npos) {
+ info.first = l.substr (c + 2);
+ }
+ } else if (boost::algorithm::starts_with (l, "processor")) {
+ ++info.second;
+ }
+ }
+ #endif
+
++#ifdef DCPOMATIC_OSX
+ size_t N = sizeof (info.second);
+ sysctlbyname ("hw.ncpu", &info.second, &N, 0, 0);
+ char buffer[64];
+ N = sizeof (buffer);
+ if (sysctlbyname ("machdep.cpu.brand_string", buffer, &N, 0, 0) == 0) {
+ info.first = buffer;
+ }
+ #endif
+
+ return info;
+ }
+
#define WEXITSTATUS(w) (w)
#endif
-void dvdomatic_sleep (int);
+void dcpomatic_sleep (int);
+ extern std::pair<std::string, int> cpu_info ();
#include "config.h"
#include "version.h"
#include "ui_signaller.h"
-#include "video_decoder.h"
-#include "audio_decoder.h"
-#include "sndfile_decoder.h"
#include "analyse_audio_job.h"
+#include "playlist.h"
+#include "player.h"
+#include "ffmpeg_content.h"
+#include "imagemagick_content.h"
+#include "sndfile_content.h"
+#include "dcp_content_type.h"
+#include "ratio.h"
+ #include "cross.h"
#include "i18n.h"
--- /dev/null
- #ifndef DVDOMATIC_IMAGEMAGICK_CONTENT_H
- #define DVDOMATIC_IMAGEMAGICK_CONTENT_H
+/*
+ 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_IMAGEMAGICK_CONTENT_H
++#define DCPOMATIC_IMAGEMAGICK_CONTENT_H
+
+#include <boost/enable_shared_from_this.hpp>
+#include "video_content.h"
+
+namespace cxml {
+ class Node;
+}
+
+class ImageMagickContent : public VideoContent
+{
+public:
+ ImageMagickContent (boost::shared_ptr<const Film>, boost::filesystem::path);
+ ImageMagickContent (boost::shared_ptr<const Film>, boost::shared_ptr<const cxml::Node>);
+
+ boost::shared_ptr<ImageMagickContent> shared_from_this () {
+ return boost::dynamic_pointer_cast<ImageMagickContent> (Content::shared_from_this ());
+ };
+
+ void examine (boost::shared_ptr<Job>);
+ std::string summary () const;
+ void as_xml (xmlpp::Node *) const;
+ boost::shared_ptr<Content> clone () const;
+ Time length () const;
+
+ void set_video_length (ContentVideoFrame);
+
+ static bool valid_file (boost::filesystem::path);
+};
+
+#endif
--- /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.
+
+*/
+
++#include <stdint.h>
+#include "player.h"
+#include "film.h"
+#include "ffmpeg_decoder.h"
+#include "ffmpeg_content.h"
+#include "imagemagick_decoder.h"
+#include "imagemagick_content.h"
+#include "sndfile_decoder.h"
+#include "sndfile_content.h"
+#include "playlist.h"
+#include "job.h"
+#include "image.h"
+#include "null_content.h"
+#include "black_decoder.h"
+#include "silence_decoder.h"
+
+using std::list;
+using std::cout;
+using std::min;
+using std::max;
+using std::vector;
+using boost::shared_ptr;
+using boost::weak_ptr;
+using boost::dynamic_pointer_cast;
+
+struct Piece
+{
+ Piece (shared_ptr<Content> c, shared_ptr<Decoder> d)
+ : content (c)
+ , decoder (d)
+ {}
+
+ shared_ptr<Content> content;
+ shared_ptr<Decoder> decoder;
+};
+
+Player::Player (shared_ptr<const Film> f, shared_ptr<const Playlist> p)
+ : _film (f)
+ , _playlist (p)
+ , _video (true)
+ , _audio (true)
+ , _subtitles (true)
+ , _have_valid_pieces (false)
+ , _position (0)
+ , _audio_buffers (f->dcp_audio_channels(), 0)
+ , _next_audio (0)
+{
+ _playlist->Changed.connect (bind (&Player::playlist_changed, this));
+ _playlist->ContentChanged.connect (bind (&Player::content_changed, this, _1, _2));
+}
+
+void
+Player::disable_video ()
+{
+ _video = false;
+}
+
+void
+Player::disable_audio ()
+{
+ _audio = false;
+}
+
+void
+Player::disable_subtitles ()
+{
+ _subtitles = false;
+}
+
+bool
+Player::pass ()
+{
+ if (!_have_valid_pieces) {
+ setup_pieces ();
+ _have_valid_pieces = true;
+ }
+
+ /* Here we are just finding the active decoder with the earliest last emission time, then
+ calling pass on it.
+ */
+
+ Time earliest_t = TIME_MAX;
+ shared_ptr<Piece> earliest;
+
+ for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
+ cout << "check " << (*i)->content->file()
+ << " start=" << (*i)->content->start()
+ << ", next=" << (*i)->decoder->next()
+ << ", end=" << (*i)->content->end() << "\n";
+
+ if ((*i)->decoder->done ()) {
+ continue;
+ }
+
+ if (!_audio && dynamic_pointer_cast<AudioDecoder> ((*i)->decoder) && !dynamic_pointer_cast<VideoDecoder> ((*i)->decoder)) {
+ continue;
+ }
+
+ Time const t = (*i)->content->start() + (*i)->decoder->next();
+ if (t < earliest_t) {
+ cout << "\t candidate; " << t << " " << (t / TIME_HZ) << ".\n";
+ earliest_t = t;
+ earliest = *i;
+ }
+ }
+
+ if (!earliest) {
+ flush ();
+ return true;
+ }
+
+ cout << "PASS:\n";
+ cout << "\tpass " << earliest->content->file() << " ";
+ if (dynamic_pointer_cast<FFmpegContent> (earliest->content)) {
+ cout << " FFmpeg.\n";
+ } else if (dynamic_pointer_cast<ImageMagickContent> (earliest->content)) {
+ cout << " ImageMagickContent.\n";
+ } else if (dynamic_pointer_cast<SndfileContent> (earliest->content)) {
+ cout << " SndfileContent.\n";
+ } else if (dynamic_pointer_cast<BlackDecoder> (earliest->decoder)) {
+ cout << " Black.\n";
+ } else if (dynamic_pointer_cast<SilenceDecoder> (earliest->decoder)) {
+ cout << " Silence.\n";
+ }
+
+ earliest->decoder->pass ();
+ _position = earliest->content->start() + earliest->decoder->next ();
+ cout << "\tpassed to " << _position << " " << (_position / TIME_HZ) << "\n";
+
+ return false;
+}
+
+void
+Player::process_video (weak_ptr<Content> weak_content, shared_ptr<const Image> image, bool same, Time time)
+{
+ shared_ptr<Content> content = weak_content.lock ();
+ if (!content) {
+ return;
+ }
+
+ time += content->start ();
+
+ Video (image, same, time);
+}
+
+void
+Player::process_audio (weak_ptr<Content> weak_content, shared_ptr<const AudioBuffers> audio, Time time)
+{
+ shared_ptr<Content> content = weak_content.lock ();
+ if (!content) {
+ return;
+ }
+
+ /* The time of this audio may indicate that some of our buffered audio is not going to
+ be added to any more, so it can be emitted.
+ */
+
+ time += content->start ();
+
+ if (time > _next_audio) {
+ /* We can emit some audio from our buffers */
+ OutputAudioFrame const N = _film->time_to_audio_frames (time - _next_audio);
+ assert (N <= _audio_buffers.frames());
+ shared_ptr<AudioBuffers> emit (new AudioBuffers (_audio_buffers.channels(), N));
+ emit->copy_from (&_audio_buffers, N, 0, 0);
+ Audio (emit, _next_audio);
+ _next_audio += _film->audio_frames_to_time (N);
+
+ /* And remove it from our buffers */
+ if (_audio_buffers.frames() > N) {
+ _audio_buffers.move (N, 0, _audio_buffers.frames() - N);
+ }
+ _audio_buffers.set_frames (_audio_buffers.frames() - N);
+ }
+
+ /* Now accumulate the new audio into our buffers */
+ _audio_buffers.ensure_size (_audio_buffers.frames() + audio->frames());
+ _audio_buffers.accumulate_frames (audio.get(), 0, 0, audio->frames ());
+ _audio_buffers.set_frames (_audio_buffers.frames() + audio->frames());
+}
+
+void
+Player::flush ()
+{
+ if (_audio_buffers.frames() > 0) {
+ shared_ptr<AudioBuffers> emit (new AudioBuffers (_audio_buffers.channels(), _audio_buffers.frames()));
+ emit->copy_from (&_audio_buffers, _audio_buffers.frames(), 0, 0);
+ Audio (emit, _next_audio);
+ _next_audio += _film->audio_frames_to_time (_audio_buffers.frames ());
+ _audio_buffers.set_frames (0);
+ }
+}
+
+/** @return true on error */
+void
+Player::seek (Time t)
+{
+ if (!_have_valid_pieces) {
+ setup_pieces ();
+ _have_valid_pieces = true;
+ }
+
+ if (_pieces.empty ()) {
+ return;
+ }
+
+// cout << "seek to " << t << " " << (t / TIME_HZ) << "\n";
+
+ for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
+ Time s = t - (*i)->content->start ();
+ s = max (static_cast<Time> (0), s);
+ s = min ((*i)->content->length(), s);
+// cout << "seek [" << (*i)->content->file() << "," << (*i)->content->start() << "," << (*i)->content->end() << "] to " << s << "\n";
+ (*i)->decoder->seek (s);
+ }
+
+ /* XXX: don't seek audio because we don't need to... */
+}
+
+
+void
+Player::seek_back ()
+{
+
+}
+
+void
+Player::seek_forward ()
+{
+
+}
+
+void
+Player::add_black_piece (Time s, Time len)
+{
+ shared_ptr<NullContent> nc (new NullContent (_film, s, len));
+ nc->set_ratio (_film->container ());
+ shared_ptr<BlackDecoder> bd (new BlackDecoder (_film, nc));
+ bd->Video.connect (bind (&Player::process_video, this, nc, _1, _2, _3));
+ _pieces.push_back (shared_ptr<Piece> (new Piece (nc, bd)));
+ cout << "\tblack @ " << s << " -- " << (s + len) << "\n";
+}
+
+void
+Player::add_silent_piece (Time s, Time len)
+{
+ shared_ptr<NullContent> nc (new NullContent (_film, s, len));
+ shared_ptr<SilenceDecoder> sd (new SilenceDecoder (_film, nc));
+ sd->Audio.connect (bind (&Player::process_audio, this, nc, _1, _2));
+ _pieces.push_back (shared_ptr<Piece> (new Piece (nc, sd)));
+ cout << "\tsilence @ " << s << " -- " << (s + len) << "\n";
+}
+
+
+void
+Player::setup_pieces ()
+{
+ cout << "----- Player SETUP PIECES.\n";
+
+ list<shared_ptr<Piece> > old_pieces = _pieces;
+
+ _pieces.clear ();
+
+ Playlist::ContentList content = _playlist->content ();
+ sort (content.begin(), content.end(), ContentSorter ());
+
+ for (Playlist::ContentList::iterator i = content.begin(); i != content.end(); ++i) {
+
+ shared_ptr<Decoder> decoder;
+
+ /* XXX: into content? */
+
+ shared_ptr<const FFmpegContent> fc = dynamic_pointer_cast<const FFmpegContent> (*i);
+ if (fc) {
+ shared_ptr<FFmpegDecoder> fd (new FFmpegDecoder (_film, fc, _video, _audio, _subtitles));
+
+ fd->Video.connect (bind (&Player::process_video, this, *i, _1, _2, _3));
+ fd->Audio.connect (bind (&Player::process_audio, this, *i, _1, _2));
+
+ decoder = fd;
+ cout << "\tFFmpeg @ " << fc->start() << " -- " << fc->end() << "\n";
+ }
+
+ shared_ptr<const ImageMagickContent> ic = dynamic_pointer_cast<const ImageMagickContent> (*i);
+ if (ic) {
+ shared_ptr<ImageMagickDecoder> id;
+
+ /* See if we can re-use an old ImageMagickDecoder */
+ for (list<shared_ptr<Piece> >::const_iterator j = old_pieces.begin(); j != old_pieces.end(); ++j) {
+ shared_ptr<ImageMagickDecoder> imd = dynamic_pointer_cast<ImageMagickDecoder> ((*j)->decoder);
+ if (imd && imd->content() == ic) {
+ id = imd;
+ }
+ }
+
+ if (!id) {
+ id.reset (new ImageMagickDecoder (_film, ic));
+ id->Video.connect (bind (&Player::process_video, this, *i, _1, _2, _3));
+ }
+
+ decoder = id;
+ cout << "\tImageMagick @ " << ic->start() << " -- " << ic->end() << "\n";
+ }
+
+ shared_ptr<const SndfileContent> sc = dynamic_pointer_cast<const SndfileContent> (*i);
+ if (sc) {
+ shared_ptr<AudioDecoder> sd (new SndfileDecoder (_film, sc));
+ sd->Audio.connect (bind (&Player::process_audio, this, *i, _1, _2));
+
+ decoder = sd;
+ cout << "\tSndfile @ " << sc->start() << " -- " << sc->end() << "\n";
+ }
+
+ _pieces.push_back (shared_ptr<Piece> (new Piece (*i, decoder)));
+ }
+
+ /* Fill in visual gaps with black and audio gaps with silence */
+
+ Time video_pos = 0;
+ Time audio_pos = 0;
+ list<shared_ptr<Piece> > pieces_copy = _pieces;
+ for (list<shared_ptr<Piece> >::iterator i = pieces_copy.begin(); i != pieces_copy.end(); ++i) {
+ if (dynamic_pointer_cast<VideoContent> ((*i)->content)) {
+ Time const diff = (*i)->content->start() - video_pos;
+ if (diff > 0) {
+ add_black_piece (video_pos, diff);
+ }
+ video_pos = (*i)->content->end();
+ }
+
+ shared_ptr<AudioContent> ac = dynamic_pointer_cast<AudioContent> ((*i)->content);
+ if (ac && ac->audio_channels()) {
+ Time const diff = (*i)->content->start() - audio_pos;
+ if (diff > 0) {
+ add_silent_piece (video_pos, diff);
+ }
+ audio_pos = (*i)->content->end();
+ }
+ }
+
+ if (video_pos < audio_pos) {
+ add_black_piece (video_pos, audio_pos - video_pos);
+ } else if (audio_pos < video_pos) {
+ add_silent_piece (audio_pos, video_pos - audio_pos);
+ }
+}
+
+void
+Player::content_changed (weak_ptr<Content> w, int p)
+{
+ shared_ptr<Content> c = w.lock ();
+ if (!c) {
+ return;
+ }
+
+ if (p == ContentProperty::START || p == ContentProperty::LENGTH) {
+ _have_valid_pieces = false;
+ }
+}
+
+void
+Player::playlist_changed ()
+{
+ _have_valid_pieces = false;
+}
#include "filter.h"
#include "sound_processor.h"
#include "config.h"
-#ifdef DVDOMATIC_WINDOWS
+#include "ratio.h"
- #ifdef DVDOMATIC_WINDOWS
++#ifdef DCPOMATIC_WINDOWS
#include "stack.hpp"
#endif
return t.tv_sec + (double (t.tv_usec) / 1e6);
}
--#ifdef DVDOMATIC_WINDOWS
++#ifdef DCPOMATIC_WINDOWS
LONG WINAPI exception_handler(struct _EXCEPTION_POINTERS *)
{
dbg::stack s;
* Must be called from the UI thread, if there is one.
*/
void
-dvdomatic_setup ()
+dcpomatic_setup ()
{
--#ifdef DVDOMATIC_WINDOWS
++#ifdef DCPOMATIC_WINDOWS
backtrace_file /= g_get_user_config_dir ();
backtrace_file /= "backtrace.txt";
SetUnhandledExceptionFilter(exception_handler);
return ((int64_t) v * audio_sample_rate / frames_per_second);
}
- /** @return A pair containing CPU model name and the number of processors */
- pair<string, int>
- cpu_info ()
-/** @param f Filename.
- * @return true if this file is a still image, false if it is something else.
- */
-bool
-still_image_file (string f)
--{
- pair<string, int> info;
- info.second = 0;
-
- #ifdef DCPOMATIC_POSIX
- ifstream f (N_("/proc/cpuinfo"));
- while (f.good ()) {
- string l;
- getline (f, l);
- if (boost::algorithm::starts_with (l, N_("model name"))) {
- string::size_type const c = l.find (':');
- if (c != string::npos) {
- info.first = l.substr (c + 2);
- }
- } else if (boost::algorithm::starts_with (l, N_("processor"))) {
- ++info.second;
- }
- }
- #endif
- string ext = boost::filesystem::path(f).extension().string();
--
- return info;
- transform (ext.begin(), ext.end(), ext.begin(), ::tolower);
-
- return (ext == N_(".tif") || ext == N_(".tiff") || ext == N_(".jpg") || ext == N_(".jpeg") || ext == N_(".png") || ext == N_(".bmp"));
--}
--
string
audio_channel_name (int c)
{
int _timeout;
};
-/** @class AudioBuffers
- * @brief A class to hold multi-channel audio data in float format.
- */
-class AudioBuffers
-{
-public:
- AudioBuffers (int channels, int frames);
- AudioBuffers (AudioBuffers const &);
- AudioBuffers (boost::shared_ptr<const AudioBuffers>);
- ~AudioBuffers ();
-
- float** data () const {
- return _data;
- }
-
- float* data (int) const;
-
- int channels () const {
- return _channels;
- }
-
- int frames () const {
- return _frames;
- }
-
- void set_frames (int f);
-
- void make_silent ();
- void make_silent (int c);
-
- void copy_from (AudioBuffers* from, int frames_to_copy, int read_offset, int write_offset);
- void move (int from, int to, int frames);
-
-private:
- /** Number of channels */
- int _channels;
- /** Number of frames (where a frame is one sample across all channels) */
- int _frames;
- /** Number of frames that _data can hold */
- int _allocated_frames;
- /** Audio data (so that, e.g. _data[2][6] is channel 2, sample 6) */
- float** _data;
-};
-
-class AudioMapping
-{
-public:
- AudioMapping (int);
-
- boost::optional<libdcp::Channel> source_to_dcp (int c) const;
- boost::optional<int> dcp_to_source (libdcp::Channel c) const;
- int dcp_channels () const;
-
-private:
- int _source_channels;
-};
-
-extern int64_t video_frames_to_audio_frames (SourceFrame v, float audio_sample_rate, float frames_per_second);
-extern bool still_image_file (std::string);
+extern int64_t video_frames_to_audio_frames (ContentVideoFrame v, float audio_sample_rate, float frames_per_second);
- extern std::pair<std::string, int> cpu_info ();
class LocaleGuard
{
--- /dev/null
- #include <wx/aboutdlg.h>
+/*
+ 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
- add_item (help, _("About DVD-o-matic"), wxID_ABOUT, ALWAYS);
++#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,
+ ID_jobs_analyse_audio,
+};
+
+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);
+ jobs_menu->AppendSeparator ();
+ add_item (jobs_menu, _("&Analyse audio"), ID_jobs_analyse_audio, NEEDS_FILM);
+
+ wxMenu* help = new wxMenu;
+#ifdef __WXOSX__
- wxAboutDialogInfo info;
- info.SetName (_("DCP-o-matic"));
- if (strcmp (dcpomatic_git_commit, "release") == 0) {
- info.SetVersion (std_to_wx (String::compose ("version %1", dcpomatic_version)));
- } else {
- info.SetVersion (std_to_wx (String::compose ("version %1 git %2", dcpomatic_version, dcpomatic_git_commit)));
- }
- info.SetDescription (_("Free, open-source DCP generation from almost anything."));
- info.SetCopyright (_("(C) 2012-2013 Carl Hetherington, Terrence Meiczinger, Paul Davis, Ole Laursen"));
-
- wxArrayString authors;
- authors.Add (wxT ("Carl Hetherington"));
- authors.Add (wxT ("Terrence Meiczinger"));
- authors.Add (wxT ("Paul Davis"));
- authors.Add (wxT ("Ole Laursen"));
- info.SetDevelopers (authors);
-
- wxArrayString translators;
- translators.Add (wxT ("Olivier Perriere"));
- translators.Add (wxT ("Lilian Lefranc"));
- translators.Add (wxT ("Thierry Journet"));
- translators.Add (wxT ("Massimiliano Broggi"));
- translators.Add (wxT ("Manuel AC"));
- translators.Add (wxT ("Adam Klotblixt"));
- info.SetTranslators (translators);
-
- info.SetWebSite (wxT ("http://carlh.net/software/dcpomatic"));
- wxAboutBox (info);
++ 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 (ID_jobs_analyse_audio, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler (Frame::jobs_analyse_audio));
+ 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 jobs_analyse_audio (wxCommandEvent &)
+ {
+ film->analyse_audio ();
+ }
+
+ void help_about (wxCommandEvent &)
+ {
- #ifdef DCPOMATIC_POSIX
++ 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
- #ifdef DCPOMATIC_POSIX
+/*
+ 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/aboutdlg.h>
+#include <wx/stdpaths.h>
+#include <wx/wx.h>
+#include "lib/version.h"
+#include "lib/compose.hpp"
+#include "lib/config.h"
+#include "lib/util.h"
+#include "lib/film.h"
+#include "lib/job_manager.h"
+#include "wx/wx_util.h"
+#include "wx/wx_ui_signaller.h"
+#include "wx/job_manager_view.h"
+
+using boost::shared_ptr;
+
+enum {
+ ID_file_add_film = 1,
+ ID_file_quit,
+ ID_help_about
+};
+
+void
+setup_menu (wxMenuBar* m)
+{
+ wxMenu* file = new wxMenu;
+ file->Append (ID_file_add_film, _("&Add Film..."));
+ file->Append (ID_file_quit, _("&Quit"));
+
+ wxMenu* help = new wxMenu;
+ help->Append (ID_help_about, _("About"));
+
+ m->Append (file, _("&File"));
+ m->Append (help, _("&Help"));
+}
+
+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_add_film, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler (Frame::file_add_film));
+ Connect (ID_file_quit, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler (Frame::file_quit));
+ Connect (ID_help_about, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler (Frame::help_about));
+
+ wxPanel* panel = new wxPanel (this);
+ wxSizer* s = new wxBoxSizer (wxHORIZONTAL);
+ s->Add (panel, 1, wxEXPAND);
+ SetSizer (s);
+
+ wxSizer* sizer = new wxBoxSizer (wxVERTICAL);
+
+ JobManagerView* job_manager_view = new JobManagerView (panel, JobManagerView::PAUSE);
+ sizer->Add (job_manager_view, 1, wxALL | wxEXPAND, 6);
+
+ wxSizer* buttons = new wxBoxSizer (wxHORIZONTAL);
+ wxButton* add = new wxButton (panel, wxID_ANY, _("Add Film..."));
+ add->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (Frame::add_film));
+ buttons->Add (add, 1, wxALL, 6);
+
+ sizer->Add (buttons, 0, wxALL, 6);
+
+ panel->SetSizer (sizer);
+
+ Connect (wxID_ANY, wxEVT_CLOSE_WINDOW, wxCloseEventHandler (Frame::close));
+ }
+
+private:
+ bool should_close ()
+ {
+ if (!JobManager::instance()->work_to_do ()) {
+ return true;
+ }
+
+ wxMessageDialog* d = new wxMessageDialog (
+ 0,
+ _("There are unfinished jobs; are you sure you want to quit?"),
+ _("Unfinished jobs"),
+ wxYES_NO | wxYES_DEFAULT | wxICON_QUESTION
+ );
+
+ bool const r = d->ShowModal() == wxID_YES;
+ d->Destroy ();
+ return r;
+ }
+
+ void close (wxCloseEvent& ev)
+ {
+ if (!should_close ()) {
+ ev.Veto ();
+ return;
+ }
+
+ ev.Skip ();
+ }
+
+ void file_add_film (wxCommandEvent& ev)
+ {
+ add_film (ev);
+ }
+
+ void file_quit (wxCommandEvent &)
+ {
+ if (should_close ()) {
+ Close (true);
+ }
+ }
+
+ void help_about (wxCommandEvent &)
+ {
+ wxAboutDialogInfo info;
+ info.SetName (_("DCP-o-matic Batch Converter"));
+ if (strcmp (dcpomatic_git_commit, "release") == 0) {
+ info.SetVersion (std_to_wx (String::compose ("version %1", dcpomatic_version)));
+ } else {
+ info.SetVersion (std_to_wx (String::compose ("version %1 git %2", dcpomatic_version, dcpomatic_git_commit)));
+ }
+ info.SetDescription (_("Free, open-source DCP generation from almost anything."));
+ info.SetCopyright (_("(C) 2012-2013 Carl Hetherington, Terrence Meiczinger, Paul Davis, Ole Laursen"));
+
+ wxArrayString authors;
+ authors.Add (wxT ("Carl Hetherington"));
+ authors.Add (wxT ("Terrence Meiczinger"));
+ authors.Add (wxT ("Paul Davis"));
+ authors.Add (wxT ("Ole Laursen"));
+ info.SetDevelopers (authors);
+
+ wxArrayString translators;
+ translators.Add (wxT ("Olivier Perriere"));
+ translators.Add (wxT ("Lilian Lefranc"));
+ translators.Add (wxT ("Thierry Journet"));
+ translators.Add (wxT ("Massimiliano Broggi"));
+ translators.Add (wxT ("Manuel AC"));
+ translators.Add (wxT ("Adam Klotblixt"));
+ info.SetTranslators (translators);
+
+ info.SetWebSite (wxT ("http://carlh.net/software/dcpomatic"));
+ wxAboutBox (info);
+ }
+
+ void add_film (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) {
+ try {
+ shared_ptr<Film> film (new Film (wx_to_std (c->GetPath ())));
+ film->read_metadata ();
+ film->make_dcp ();
+ } 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 ();
+ }
+};
+
+class App : public wxApp
+{
+ bool OnInit ()
+ {
+ if (!wxApp::OnInit()) {
+ return false;
+ }
+
++#ifdef DCPOMATIC_LINUX
+ unsetenv ("UBUNTU_MENUPROXY");
+#endif
+
+ /* Enable i18n; this will create a Config object
+ to look for a force-configured language. This Config
+ object will be wrong, however, because dcpomatic_setup
+ hasn't yet been called and there aren't any 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 ();
+
+ Frame* f = new Frame (_("DCP-o-matic Batch Converter"));
+ SetTopWindow (f);
+ f->Maximize ();
+ f->Show ();
+
+ ui_signaller = new wxUISignaller (this);
+ this->Connect (-1, wxEVT_IDLE, wxIdleEventHandler (App::idle));
+
+ return true;
+ }
+
+ void idle (wxIdleEvent &)
+ {
+ ui_signaller->ui_idle ();
+ }
+};
+
+IMPLEMENT_APP (App)
msgid "Film changed"
msgstr "Película cambiada"
- #: src/tools/dcpomatic.cc:416
- #: src/tools/dvdomatic.cc:288 src/tools/dvdomatic.cc:419
- #: src/tools/dvdomatic.cc:506
- msgid "DCP-o-matic"
- msgstr "DCP-o-matic"
-
-#: src/tools/dvdomatic.cc:437
+#: src/tools/dvdomatic.cc:425
msgid "Free, open-source DCP generation from almost anything."
msgstr ""
"Generación de DCP a partir de casi cualquier fuente, libre y de código "
--- /dev/null
- : wxDialog (parent, wxID_ANY, _("About DVD-o-matic"))
+ /*
+ 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/notebook.h>
+ #include <wx/hyperlink.h>
+ #include "lib/version.h"
+ #include "lib/compose.hpp"
+ #include "about_dialog.h"
+ #include "wx_util.h"
+
+ using std::vector;
+
+ AboutDialog::AboutDialog (wxWindow* parent)
- wxStaticText* t = new wxStaticText (this, wxID_ANY, _("DVD-o-matic"));
++ : wxDialog (parent, wxID_ANY, _("About DCP-o-matic"))
+ {
+ wxBoxSizer* sizer = new wxBoxSizer (wxVERTICAL);
+
+ wxFont title_font (*wxNORMAL_FONT);
+ title_font.SetPointSize (title_font.GetPointSize() + 4);
+ title_font.SetWeight (wxFONTWEIGHT_BOLD);
+
+ wxFont version_font (*wxNORMAL_FONT);
+ version_font.SetWeight (wxFONTWEIGHT_BOLD);
+
- if (strcmp (dvdomatic_git_commit, "release") == 0) {
- t = new wxStaticText (this, wxID_ANY, std_to_wx (String::compose ("Version %1", dvdomatic_version)));
++ wxStaticText* t = new wxStaticText (this, wxID_ANY, _("DCP-o-matic"));
+ t->SetFont (title_font);
+ sizer->Add (t, wxSizerFlags().Centre().Border());
+
+ wxString s;
- t = new wxStaticText (this, wxID_ANY, std_to_wx (String::compose ("Version %1 git %2", dvdomatic_version, dvdomatic_git_commit)));
++ if (strcmp (dcpomatic_git_commit, "release") == 0) {
++ t = new wxStaticText (this, wxID_ANY, std_to_wx (String::compose ("Version %1", dcpomatic_version)));
+ } else {
- wxT ("www.carlh.net/software/dvdomatic"),
- wxT ("http://www.carlh.net/software/dvdomatic")
++ t = new wxStaticText (this, wxID_ANY, std_to_wx (String::compose ("Version %1 git %2", dcpomatic_version, dcpomatic_git_commit)));
+ }
+ t->SetFont (version_font);
+ sizer->Add (t, wxSizerFlags().Centre().Border());
+ sizer->AddSpacer (12);
+
+ t = new wxStaticText (
+ this, wxID_ANY,
+ _("Free, open-source DCP generation from almost anything."),
+ wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER
+ );
+
+ sizer->Add (t, wxSizerFlags().Centre().Border());
+
+ wxHyperlinkCtrl* h = new wxHyperlinkCtrl (
+ this, wxID_ANY,
-#if 0
- info.SetWebSite (wxT ("http://carlh.net/software/dvdomatic"));
-#endif
-
++ wxT ("www.carlh.net/software/dcpomatic"),
++ wxT ("http://www.carlh.net/software/dcpomatic")
+ );
+
+ sizer->Add (h, wxSizerFlags().Centre().Border());
+
+ t = new wxStaticText (
+ this, wxID_ANY,
+ _("(C) 2012-2013 Carl Hetherington, Terrence Meiczinger, Paul Davis, Ole Laursen"),
+ wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER
+ );
+
+ sizer->Add (t, wxSizerFlags().Centre().Border());
+
+ _notebook = new wxNotebook (this, wxID_ANY);
+
+ wxArrayString written_by;
+ written_by.Add (wxT ("Carl Hetherington"));
+ written_by.Add (wxT ("Terrence Meiczinger"));
+ written_by.Add (wxT ("Paul Davis"));
+ written_by.Add (wxT ("Ole Laursen"));
+ add_section (_("Written by"), written_by);
+
+ wxArrayString translated_by;
+ translated_by.Add (wxT ("Olivier Perriere"));
+ translated_by.Add (wxT ("Lilian Lefranc"));
+ translated_by.Add (wxT ("Thierry Journet"));
+ translated_by.Add (wxT ("Massimiliano Broggi"));
+ translated_by.Add (wxT ("Manuel AC"));
+ translated_by.Add (wxT ("Adam Klotblixt"));
+ add_section (_("Translated by"), translated_by);
+
+ wxArrayString supported_by;
+ supported_by.Add (wxT ("Carsten Kurz"));
+ supported_by.Add (wxT ("Wolfgang Woehl"));
+ supported_by.Add (wxT ("Manual AC"));
+ supported_by.Add (wxT ("Theo Lipfert"));
+ supported_by.Add (wxT ("Olivier Lemaire"));
+ supported_by.Add (wxT ("Andrä Steiner"));
+ supported_by.Add (wxT ("Jonathan Jensen"));
+ supported_by.Add (wxT ("Kjarten Michaelsen"));
+ supported_by.Add (wxT ("Jussi Siponen"));
+ supported_by.Add (wxT ("Cinema Clarici"));
+ supported_by.Add (wxT ("Evan Freeze"));
+ supported_by.Add (wxT ("Flor Guillaume"));
+ supported_by.Add (wxT ("Adam Klotblixt "));
+ supported_by.Add (wxT ("Lilian Lefranc"));
+ supported_by.Add (wxT ("Gavin Lewarne"));
+ supported_by.Add (wxT ("Lasse Salling"));
+ supported_by.Add (wxT ("Andres Fink"));
+ supported_by.Add (wxT ("Kieran Carroll"));
+ add_section (_("Supported by"), supported_by);
+
+ sizer->Add (_notebook, wxSizerFlags().Centre().Border().Expand());
+
+ SetSizerAndFit (sizer);
+ }
+
+ void
+ AboutDialog::add_section (wxString name, wxArrayString credits)
+ {
+ static bool first = true;
+ int const N = 3;
+
+ wxPanel* panel = new wxPanel (_notebook, wxID_ANY);
+ wxSizer* overall_sizer = new wxBoxSizer (wxHORIZONTAL);
+
+ vector<wxSizer*> sizers;
+
+ for (int i = 0; i < N; ++i) {
+ sizers.push_back (new wxBoxSizer (wxVERTICAL));
+ overall_sizer->Add (sizers.back (), 1, wxEXPAND | wxALL, 6);
+ }
+
+ int c = 0;
+ for (size_t i = 0; i < credits.Count(); ++i) {
+ add_label_to_sizer (sizers[c], panel, credits[i]);
+ ++c;
+ if (c == N) {
+ c = 0;
+ }
+ }
+
+ panel->SetSizerAndFit (overall_sizer);
+ _notebook->AddPage (panel, name, first);
+ first = false;
+ }
msgid "%"
msgstr "%"
- msgid "(restart DCP-o-matic to see language changes)"
-#: src/wx/config_dialog.cc:98
-msgid "(restart DVD-o-matic to see language changes)"
-msgstr ""
--
#: src/wx/film_editor.cc:1276
msgid "1 channel"
msgstr "1 canal"
import i18n
sources = """
+ about_dialog.cc
audio_dialog.cc
+ audio_mapping_view.cc
audio_plot.cc
config_dialog.cc
dci_metadata_dialog.cc
if conf.options.target_windows:
conf.load('winres')
- conf.env.append_value('CXXFLAGS', ['-D__STDC_CONSTANT_MACROS', '-msse', '-mfpmath=sse', '-ffast-math', '-fno-strict-aliasing',
+ conf.env.TARGET_WINDOWS = conf.options.target_windows
+ conf.env.DISABLE_GUI = conf.options.disable_gui
+ conf.env.STATIC = conf.options.static
+ conf.env.VERSION = VERSION
+ conf.env.TARGET_OSX = sys.platform == 'darwin'
+ 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'])
- if conf.options.target_windows:
+ 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:
boost_lib_suffix = ''
boost_thread = 'boost_thread'
conf.env.append_value('LINKFLAGS', '-pthread')
- # libxml2 seems to be linked against this on Ubuntu, but it doesn't mention it in its .pc file
+
+ if conf.env.TARGET_LINUX:
+ # libxml2 seems to be linked against this on Ubuntu but it doesn't mention it in its .pc file
conf.env.append_value('LIB', 'lzma')
- conf.env.append_value('CXXFLAGS', '-DDVDOMATIC_LINUX')
++ conf.env.append_value('CXXFLAGS', '-DDCPOMATIC_LINUX')
- conf.env.TARGET_WINDOWS = conf.options.target_windows
- conf.env.DISABLE_GUI = conf.options.disable_gui
- conf.env.STATIC = conf.options.static
- conf.env.VERSION = VERSION
- conf.env.TARGET_OSX = conf.options.osx
- conf.env.TARGET_LINUX = not conf.options.target_windows and not conf.options.osx
+ if conf.env.TARGET_OSX:
- conf.env.append_value('CXXFLAGS', '-DDVDOMATIC_OSX')
++ conf.env.append_value('CXXFLAGS', '-DDCPOMATIC_OSX')
if conf.options.enable_debug:
- conf.env.append_value('CXXFLAGS', ['-g', '-DDVDOMATIC_DEBUG'])
+ conf.env.append_value('CXXFLAGS', ['-g', '-DDCPOMATIC_DEBUG'])
else:
conf.env.append_value('CXXFLAGS', '-O2')