Merge master.
authorCarl Hetherington <cth@carlh.net>
Mon, 2 Jun 2014 11:06:20 +0000 (12:06 +0100)
committerCarl Hetherington <cth@carlh.net>
Mon, 2 Jun 2014 11:06:20 +0000 (12:06 +0100)
43 files changed:
ChangeLog
debian/changelog
platform/osx/make_dmg.sh
src/lib/config.cc
src/lib/config.h
src/lib/content.h
src/lib/cross.cc
src/lib/dcp_video_frame.cc
src/lib/decoder.h
src/lib/encoder.cc
src/lib/ffmpeg_content.cc
src/lib/ffmpeg_decoder.cc
src/lib/ffmpeg_examiner.cc
src/lib/film.cc
src/lib/film.h
src/lib/image_decoder.cc
src/lib/image_proxy.cc
src/lib/image_proxy.h
src/lib/job.cc
src/lib/kdm.cc
src/lib/kdm.h
src/lib/log.cc
src/lib/log.h
src/lib/player.cc
src/lib/player_video_frame.cc
src/lib/player_video_frame.h
src/lib/scp_dcp_job.cc
src/lib/server.cc
src/lib/transcode_job.cc
src/lib/types.h
src/lib/util.h
src/lib/writer.cc
src/tools/dcpomatic.cc
src/tools/dcpomatic_cli.cc
src/tools/dcpomatic_kdm.cc
src/wx/about_dialog.cc
src/wx/config_dialog.cc
src/wx/film_editor.cc
src/wx/kdm_dialog.cc
src/wx/kdm_dialog.h
src/wx/wx_util.h
test/client_server_test.cc
test/ffmpeg_dcp_test.cc

index 6f31dd5d24fbcd839fa07968a0e32c77d0e27977..e31fc719ebcf398dddbe0f0ee605bc0620b00612 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,6 +2,63 @@
 
        * Add subtitle view.
 
+2014-05-29  Carl Hetherington  <cth@carlh.net>
+
+       * Version 1.69.18 released.
+
+2014-05-28  Carl Hetherington  <cth@carlh.net>
+
+       * Version 1.69.17 released.
+
+2014-05-28  Carl Hetherington  <cth@carlh.net>
+
+       * Version 1.69.16 released.
+
+2014-05-28  Carl Hetherington  <cth@carlh.net>
+
+       * Rework KDM generation to be about CPLs rather than DCPs,
+       and allow specification of any CPL to generate KDMs for.
+
+       Requested-by: Richard Turner
+
+2014-05-27  Carl Hetherington  <cth@carlh.net>
+
+       * Version 1.69.15 released.
+
+2014-05-26  Carl Hetherington  <cth@carlh.net>
+
+       * Version 1.69.14 released.
+
+2014-05-26  Carl Hetherington  <cth@carlh.net>
+
+       * Fix problems with non-zero FFmpeg content start times.
+
+2014-05-24  Carl Hetherington  <cth@carlh.net>
+
+       * Version 1.69.13 released.
+
+2014-05-24  Carl Hetherington  <cth@carlh.net>
+
+       * Fix problems with log setup from config.
+
+2014-05-23  Carl Hetherington  <cth@carlh.net>
+
+       * Version 1.69.12 released.
+
+2014-05-22  Carl Hetherington  <cth@carlh.net>
+
+       * Version 1.69.11 released.
+
+2014-05-21  Carl Hetherington  <cth@carlh.net>
+
+       * Version 1.69.10 released.
+
+2014-05-21  Carl Hetherington  <cth@carlh.net>
+
+       * Tidy up logging a bit and make it configurable from the GUI
+       (moving a few things into an Advanced preferences tab at
+       the same time).
+
 2014-05-19  Carl Hetherington  <cth@carlh.net>
 
        * Version 1.69.9 released.
index 9043657d831745e14cbc4ba225445807d75c4db7..9ac1367780526e62c0398ed4df013a645e6c5d1d 100644 (file)
@@ -1,4 +1,4 @@
-dcpomatic (1.69.9-1) UNRELEASED; urgency=low
+dcpomatic (1.69.18-1) UNRELEASED; urgency=low
 
   * New upstream release.
   * New upstream release.
@@ -133,8 +133,17 @@ dcpomatic (1.69.9-1) UNRELEASED; urgency=low
   * New upstream release.
   * New upstream release.
   * New upstream release.
+  * New upstream release.
+  * New upstream release.
+  * New upstream release.
+  * New upstream release.
+  * New upstream release.
+  * New upstream release.
+  * New upstream release.
+  * New upstream release.
+  * New upstream release.
 
- -- Carl Hetherington <carl@d1stkfactory>  Mon, 19 May 2014 11:16:15 +0100
+ -- Carl Hetherington <carl@d1stkfactory>  Thu, 29 May 2014 16:38:35 +0100
 
 dcpomatic (0.87-1) UNRELEASED; urgency=low
 
index faa7f44ed41fe46d97ce00ddb61886ae769ca636..93af4f3342e75d155d6fd9ab8a1ebbc68f6d47e4 100644 (file)
@@ -87,7 +87,7 @@ universal_copy $ENV lib/libcurl*.dylib $WORK/$libs
 universal_copy $ENV lib/libffi*.dylib $WORK/$libs
 universal_copy $ENV lib/libiconv*.dylib $WORK/$libs
 
-for obj in $WORK/$macos/dcpomatic $WORK/$macos/ffprobe $WORK/$libs/*.dylib; do
+for obj in $WORK/$macos/dcpomatic $WORK/$macos/dcpomatic_batch $WORK/$macos/dcpomatic_cli $WORK/$macos/dcpomatic_server_cli $WORK/$macos/ffprobe $WORK/$libs/*.dylib; do
   deps=`otool -L $obj | awk '{print $1}' | egrep "(/Users/carl|libboost|libssh|libltdl|libxmlsec)"`
   changes=""
   for dep in $deps; do
index 754346418e2f4c83b66b0972a1e7868497620fd5..8be31a329645151bd424c4b77f7f52b13d74cc60 100644 (file)
@@ -73,6 +73,7 @@ Config::Config ()
        , _check_for_updates (false)
        , _check_for_test_updates (false)
        , _maximum_j2k_bandwidth (250000000)
+       , _log_types (Log::TYPE_GENERAL | Log::TYPE_WARNING | Log::TYPE_ERROR)
 {
        _allowed_dcp_frame_rates.push_back (24);
        _allowed_dcp_frame_rates.push_back (25);
@@ -189,6 +190,8 @@ Config::read ()
 
        _maximum_j2k_bandwidth = f.optional_number_child<int> ("MaximumJ2KBandwidth").get_value_or (250000000);
        _allow_any_dcp_frame_rate = f.optional_bool_child ("AllowAnyDCPFrameRate");
+
+       _log_types = f.optional_number_child<int> ("LogTypes").get_value_or (Log::TYPE_GENERAL | Log::TYPE_WARNING | Log::TYPE_ERROR);
 }
 
 void
@@ -366,6 +369,7 @@ Config::write () const
 
        root->add_child("MaximumJ2KBandwidth")->add_child_text (raw_convert<string> (_maximum_j2k_bandwidth));
        root->add_child("AllowAnyDCPFrameRate")->add_child_text (_allow_any_dcp_frame_rate ? "1" : "0");
+       root->add_child("LogTypes")->add_child_text (raw_convert<string> (_log_types));
        
        doc.write_to_file_formatted (file(false).string ());
 }
index ffaacf8f17870fcfc559732d7b41c9b39b7b29ec..ccd37ec1e22a2bc2d133b82138bf0a6268428196 100644 (file)
@@ -188,6 +188,10 @@ public:
        int maximum_j2k_bandwidth () const {
                return _maximum_j2k_bandwidth;
        }
+
+       int log_types () const {
+               return _log_types;
+       }
        
        /** @param n New number of local encoding threads */
        void set_num_local_encoding_threads (int n) {
@@ -339,6 +343,11 @@ public:
                _maximum_j2k_bandwidth = b;
                changed ();
        }
+
+       void set_log_types (int t) {
+               _log_types = t;
+               changed ();
+       }
        
        boost::filesystem::path signer_chain_directory () const;
 
@@ -401,6 +410,7 @@ private:
        bool _check_for_test_updates;
        /** maximum allowed J2K bandwidth in bits per second */
        int _maximum_j2k_bandwidth;
+       int _log_types;
 
        /** Singleton instance, or 0 */
        static Config* _instance;
index 1d3764c20192bd883f5efffe79249e736325f79a..6bbf33b35cd4d4e10377bdda2ad77be6cf673f7c 100644 (file)
@@ -138,6 +138,10 @@ public:
                _change_signals_frequent = f;
        }
 
+       boost::shared_ptr<const Film> film () const {
+               return _film.lock ();
+       }
+
        boost::signals2::signal<void (boost::weak_ptr<Content>, int, bool)> Changed;
 
 protected:
index eadbd75d87d1c203ea7a4a2719079a4da81fbb83..53ef5723ac50232d5e05fb8664a7b8dc3eba766d 100644 (file)
 #endif
 #include "exceptions.h"
 
+#include "i18n.h"
+
+#define LOG_GENERAL(...) log->log (String::compose (__VA_ARGS__), Log::TYPE_GENERAL);
+#define LOG_ERROR(...) log->log (String::compose (__VA_ARGS__), Log::TYPE_ERROR);
+#define LOG_ERROR_NC(...) log->log (__VA_ARGS__, Log::TYPE_ERROR);
+
 using std::pair;
 using std::list;
 using std::ifstream;
@@ -157,7 +163,7 @@ run_ffprobe (boost::filesystem::path content, boost::filesystem::path out, share
        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)");
+               LOG_ERROR_NC ("ffprobe call failed (could not CreatePipe)");
                return;
        }
 
@@ -184,13 +190,13 @@ run_ffprobe (boost::filesystem::path content, boost::filesystem::path out, share
        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)");
+               LOG_ERROR_NC (N_("ffprobe call failed (could not CreateProcess)"));
                return;
        }
 
        FILE* o = fopen_boost (out, "w");
        if (!o) {
-               log->log ("ffprobe call failed (could not create output file)");
+               LOG_ERROR_NC (N_("ffprobe call failed (could not create output file)"));
                return;
        }
 
@@ -215,7 +221,7 @@ run_ffprobe (boost::filesystem::path content, boost::filesystem::path out, share
 
 #ifdef DCPOMATIC_LINUX 
        string ffprobe = "ffprobe \"" + content.string() + "\" 2> \"" + out.string() + "\"";
-       log->log (String::compose ("Probing with %1", ffprobe));
+       LOG_GENERAL (N_("Probing with %1"), ffprobe);
         system (ffprobe.c_str ());
 #endif
 
@@ -225,7 +231,7 @@ run_ffprobe (boost::filesystem::path content, boost::filesystem::path out, share
        path /= "ffprobe";
        
        string ffprobe = path.string() + " \"" + content.string() + "\" 2> \"" + out.string() + "\"";
-       log->log (String::compose ("Probing with %1", ffprobe));
+       LOG_GENERAL (N_("Probing with %1"), ffprobe);
        system (ffprobe.c_str ());
 #endif
 }
index d154ba96b074298824da3713de768e892e6e5ed2..1aae64ac7aafd98fa40e59316dcb73872fc421b0 100644 (file)
@@ -62,6 +62,8 @@
 #include "cross.h"
 #include "player_video_frame.h"
 
+#define LOG_GENERAL(...) _log->log (String::compose (__VA_ARGS__), Log::TYPE_GENERAL);
+
 #include "i18n.h"
 
 using std::string;
@@ -247,13 +249,13 @@ DCPVideoFrame::encode_locally ()
 
        switch (_frame->eyes()) {
        case EYES_BOTH:
-               _log->log (String::compose (N_("Finished locally-encoded frame %1 for mono"), _index));
+               LOG_GENERAL (N_("Finished locally-encoded frame %1 for mono"), _index);
                break;
        case EYES_LEFT:
-               _log->log (String::compose (N_("Finished locally-encoded frame %1 for L"), _index));
+               LOG_GENERAL (N_("Finished locally-encoded frame %1 for L"), _index);
                break;
        case EYES_RIGHT:
-               _log->log (String::compose (N_("Finished locally-encoded frame %1 for R"), _index));
+               LOG_GENERAL (N_("Finished locally-encoded frame %1 for R"), _index);
                break;
        default:
                break;
@@ -290,7 +292,7 @@ DCPVideoFrame::encode_remotely (ServerDescription serv)
        root->add_child("Version")->add_child_text (raw_convert<string> (SERVER_LINK_VERSION));
        add_metadata (root);
 
-       _log->log (String::compose (N_("Sending frame %1 to remote"), _index));
+       LOG_GENERAL (N_("Sending frame %1 to remote"), _index);
        
        /* Send XML metadata */
        stringstream xml;
@@ -307,7 +309,7 @@ DCPVideoFrame::encode_remotely (ServerDescription serv)
        shared_ptr<EncodedData> e (new RemotelyEncodedData (socket->read_uint32 ()));
        socket->read (e->data(), e->size());
 
-       _log->log (String::compose (N_("Finished remotely-encoded frame %1"), _index));
+       LOG_GENERAL (N_("Finished remotely-encoded frame %1"), _index);
        
        return e;
 }
index 0ec73ba91f47147af16b057dcef31004a0b75c47..18f612e538c5e645470c33cfcca91175a58a0b13 100644 (file)
@@ -31,7 +31,6 @@
 #include "dcpomatic_time.h"
 
 class Decoded;
-class Film;
 
 /** @class Decoder.
  *  @brief Parent class for decoders of content.
index 2364b67a7ceccb5a1ced874efad51b83228fdcaa..5dc9e47c772cb7ec0e7c13a91b332c54bce63307 100644 (file)
 
 #include "i18n.h"
 
+#define LOG_GENERAL(...) _film->log()->log (String::compose (__VA_ARGS__), Log::TYPE_GENERAL);
+#define LOG_ERROR(...) _film->log()->log (String::compose (__VA_ARGS__), Log::TYPE_ERROR);
+#define LOG_TIMING(...) _film->log()->microsecond_log (String::compose (__VA_ARGS__), Log::TYPE_TIMING);
+
 using std::pair;
 using std::string;
 using std::stringstream;
@@ -76,7 +80,7 @@ Encoder::~Encoder ()
 void
 Encoder::add_worker_threads (ServerDescription d)
 {
-       _film->log()->log (String::compose (N_("Adding %1 worker threads for remote %2"), d.host_name ()));
+       LOG_GENERAL (N_("Adding %1 worker threads for remote %2"), d.host_name ());
        for (int i = 0; i < d.threads(); ++i) {
                _threads.push_back (new boost::thread (boost::bind (&Encoder::encoder_thread, this, d)));
        }
@@ -98,11 +102,10 @@ Encoder::process_end ()
 {
        boost::mutex::scoped_lock lock (_mutex);
 
-       _film->log()->log (String::compose (N_("Clearing queue of %1"), _queue.size ()));
+       LOG_GENERAL (N_("Clearing queue of %1"), _queue.size ());
 
        /* Keep waking workers until the queue is empty */
        while (!_queue.empty ()) {
-               _film->log()->log (String::compose (N_("Waking with %1"), _queue.size ()), Log::VERBOSE);
                _condition.notify_all ();
                _condition.wait (lock);
        }
@@ -111,7 +114,7 @@ Encoder::process_end ()
        
        terminate_threads ();
 
-       _film->log()->log (String::compose (N_("Mopping up %1"), _queue.size()));
+       LOG_GENERAL (N_("Mopping up %1"), _queue.size());
 
        /* The following sequence of events can occur in the above code:
             1. a remote worker takes the last image off the queue
@@ -123,12 +126,12 @@ Encoder::process_end ()
        */
 
        for (list<shared_ptr<DCPVideoFrame> >::iterator i = _queue.begin(); i != _queue.end(); ++i) {
-               _film->log()->log (String::compose (N_("Encode left-over frame %1"), (*i)->index ()));
+               LOG_GENERAL (N_("Encode left-over frame %1"), (*i)->index ());
                try {
                        _writer->write ((*i)->encode_locally(), (*i)->index (), (*i)->eyes ());
                        frame_done ();
                } catch (std::exception& e) {
-                       _film->log()->log (String::compose (N_("Local encode failed (%1)"), e.what ()));
+                       LOG_ERROR (N_("Local encode failed (%1)"), e.what ());
                }
        }
                
@@ -188,9 +191,9 @@ Encoder::process_video (shared_ptr<PlayerVideoFrame> pvf)
 
        /* Wait until the queue has gone down a bit */
        while (_queue.size() >= _threads.size() * 2 && !_terminate) {
-               TIMING ("decoder sleeps with queue of %1", _queue.size());
+               LOG_TIMING ("decoder sleeps with queue of %1", _queue.size());
                _condition.wait (lock);
-               TIMING ("decoder wakes with queue of %1", _queue.size());
+               LOG_TIMING ("decoder wakes with queue of %1", _queue.size());
        }
 
        if (_terminate) {
@@ -209,7 +212,7 @@ Encoder::process_video (shared_ptr<PlayerVideoFrame> pvf)
                frame_done ();
        } else {
                /* Queue this new frame for encoding */
-               TIMING ("adding to queue of %1", _queue.size ());
+               LOG_TIMING ("adding to queue of %1", _queue.size ());
                _queue.push_back (shared_ptr<DCPVideoFrame> (
                                          new DCPVideoFrame (
                                                  pvf,
@@ -266,7 +269,7 @@ try
        
        while (1) {
 
-               TIMING ("encoder thread %1 sleeps", boost::this_thread::get_id());
+               LOG_TIMING ("[%1] encoder thread sleeps", boost::this_thread::get_id());
                boost::mutex::scoped_lock lock (_mutex);
                while (_queue.empty () && !_terminate) {
                        _condition.wait (lock);
@@ -276,9 +279,9 @@ try
                        return;
                }
 
-               TIMING ("encoder thread %1 wakes with queue of %2", boost::this_thread::get_id(), _queue.size());
+               LOG_TIMING ("[%1] encoder thread wakes with queue of %2", boost::this_thread::get_id(), _queue.size());
                shared_ptr<DCPVideoFrame> vf = _queue.front ();
-               TIMING ("encoder thread %1 pops frame %2 (%3) from queue", boost::this_thread::get_id(), vf->index(), vf->eyes ());
+               LOG_TIMING ("[%1] encoder thread pops frame %2 (%3) from queue", boost::this_thread::get_id(), vf->index(), vf->eyes ());
                _queue.pop_front ();
                
                lock.unlock ();
@@ -290,7 +293,7 @@ try
                                encoded = vf->encode_remotely (server.get ());
 
                                if (remote_backoff > 0) {
-                                       _film->log()->log (String::compose (N_("%1 was lost, but now she is found; removing backoff"), server->host_name ()));
+                                       LOG_GENERAL ("%1 was lost, but now she is found; removing backoff", server->host_name ());
                                }
                                
                                /* This job succeeded, so remove any backoff */
@@ -301,20 +304,19 @@ try
                                        /* back off more */
                                        remote_backoff += 10;
                                }
-                               _film->log()->log (
-                                       String::compose (
-                                               N_("Remote encode of %1 on %2 failed (%3); thread sleeping for %4s"),
-                                               vf->index(), server->host_name(), e.what(), remote_backoff)
+                               LOG_ERROR (
+                                       N_("Remote encode of %1 on %2 failed (%3); thread sleeping for %4s"),
+                                       vf->index(), server->host_name(), e.what(), remote_backoff
                                        );
                        }
                                
                } else {
                        try {
-                               TIMING ("encoder thread %1 begins local encode of %2", boost::this_thread::get_id(), vf->index());
+                               LOG_TIMING ("[%1] encoder thread begins local encode of %2", boost::this_thread::get_id(), vf->index());
                                encoded = vf->encode_locally ();
-                               TIMING ("encoder thread %1 finishes local encode of %2", boost::this_thread::get_id(), vf->index());
+                               LOG_TIMING ("[%1] encoder thread finishes local encode of %2", boost::this_thread::get_id(), vf->index());
                        } catch (std::exception& e) {
-                               _film->log()->log (String::compose (N_("Local encode failed (%1)"), e.what ()));
+                               LOG_ERROR (N_("Local encode failed (%1)"), e.what ());
                        }
                }
 
@@ -323,9 +325,7 @@ try
                        frame_done ();
                } else {
                        lock.lock ();
-                       _film->log()->log (
-                               String::compose (N_("Encoder thread %1 pushes frame %2 back onto queue after failure"), boost::this_thread::get_id(), vf->index())
-                               );
+                       LOG_GENERAL (N_("[%1] Encoder thread pushes frame %2 back onto queue after failure"), boost::this_thread::get_id(), vf->index());
                        _queue.push_front (vf);
                        lock.unlock ();
                }
index 2b507ab371adf3187c08d5b1241ff80c7f359edc..9889d511cd45016c97b08746bce15856a953e265 100644 (file)
@@ -36,6 +36,8 @@ extern "C" {
 
 #include "i18n.h"
 
+#define LOG_GENERAL(...) film->log()->log (String::compose (__VA_ARGS__), Log::TYPE_GENERAL);
+
 using std::string;
 using std::stringstream;
 using std::vector;
@@ -173,7 +175,7 @@ FFmpegContent::examine (shared_ptr<Job> job)
 
        shared_ptr<const Film> film = _film.lock ();
        assert (film);
-       film->log()->log (String::compose ("Video length obtained from header as %1 frames", video_length.frames (video_frame_rate ())));
+       LOG_GENERAL ("Video length obtained from header as %1 frames", video_length.frames (video_frame_rate ()));
 
        {
                boost::mutex::scoped_lock lm (_mutex);
index d668deb6f6bbeee617128acbe05489e30874f9a4..0dae2a4edc41be11d70855d94e93b9594dc27c39 100644 (file)
@@ -44,9 +44,14 @@ extern "C" {
 #include "audio_buffers.h"
 #include "ffmpeg_content.h"
 #include "image_proxy.h"
+#include "film.h"
 
 #include "i18n.h"
 
+#define LOG_GENERAL(...) _video_content->film()->log()->log (String::compose (__VA_ARGS__), Log::TYPE_GENERAL);
+#define LOG_ERROR(...) _video_content->film()->log()->log (String::compose (__VA_ARGS__), Log::TYPE_ERROR);
+#define LOG_WARNING(...) _video_content->film()->log()->log (__VA_ARGS__, Log::TYPE_WARNING);
+
 using std::cout;
 using std::string;
 using std::vector;
@@ -138,7 +143,7 @@ FFmpegDecoder::pass ()
                        /* Maybe we should fail here, but for now we'll just finish off instead */
                        char buf[256];
                        av_strerror (r, buf, sizeof(buf));
-                       _log->log (String::compose (N_("error on av_read_frame (%1) (%2)"), buf, r));
+                       LOG_ERROR (N_("error on av_read_frame (%1) (%2)"), buf, r);
                }
 
                flush ();
@@ -431,7 +436,7 @@ FFmpegDecoder::decode_audio_packet ()
                int const decode_result = avcodec_decode_audio4 (audio_codec_context(), _frame, &frame_finished, &copy_packet);
 
                if (decode_result < 0) {
-                       _log->log (String::compose ("avcodec_decode_audio4 failed (%1)", decode_result));
+                       LOG_ERROR ("avcodec_decode_audio4 failed (%1)", decode_result);
                        return;
                }
 
@@ -473,7 +478,7 @@ FFmpegDecoder::decode_video_packet ()
        if (i == _filter_graphs.end ()) {
                graph.reset (new FilterGraph (_ffmpeg_content, dcp::Size (_frame->width, _frame->height), (AVPixelFormat) _frame->format));
                _filter_graphs.push_back (graph);
-               _log->log (String::compose (N_("New graph for %1x%2, pixel format %3"), _frame->width, _frame->height, _frame->format));
+               LOG_GENERAL (N_("New graph for %1x%2, pixel format %3"), _frame->width, _frame->height, _frame->format);
        } else {
                graph = *i;
        }
@@ -486,9 +491,12 @@ FFmpegDecoder::decode_video_packet ()
                
                if (i->second != AV_NOPTS_VALUE) {
                        double const pts = i->second * av_q2d (_format_context->streams[_video_stream]->time_base) + _pts_offset.seconds ();
-                       video (shared_ptr<ImageProxy> (new RawImageProxy (image)), rint (pts * _ffmpeg_content->video_frame_rate ()));
+                       video (
+                               shared_ptr<ImageProxy> (new RawImageProxy (image, _video_content->film()->log())),
+                               rint (pts * _ffmpeg_content->video_frame_rate ())
+                               );
                } else {
-                       _log->log ("Dropping frame without PTS");
+                       LOG_WARNING ("Dropping frame without PTS");
                }
        }
 
index df12830f819eb182c2c04db9838e71f550e236ff..d9bcedfc528f196ba9a85b064d1f3900f32fdbbc 100644 (file)
@@ -176,7 +176,7 @@ FFmpegExaminer::video_size () const
 ContentTime
 FFmpegExaminer::video_length () const
 {
-       ContentTime const length = ContentTime::from_seconds (double (_format_context->duration) / AV_TIME_BASE);
+       ContentTime const length = ContentTime::from_seconds (double (_format_context->duration - _format_context->start_time) / AV_TIME_BASE);
        return ContentTime (max (int64_t (1), length.get ()));
 }
 
index 50b1b4fad309e18c7bd848f829fce4e159b8fad6..25730ae1cbe8bff7e07da16c6eced81e099c7c79 100644 (file)
@@ -81,6 +81,9 @@ using dcp::Size;
 using dcp::Signer;
 using dcp::raw_convert;
 
+#define LOG_GENERAL(...) log()->log (String::compose (__VA_ARGS__), Log::TYPE_GENERAL);
+#define LOG_GENERAL_NC(...) log()->log (__VA_ARGS__, Log::TYPE_GENERAL);
+
 /* 5 -> 6
  * AudioMapping XML changed.
  * 6 -> 7
@@ -256,43 +259,43 @@ Film::make_dcp ()
         */
        write_metadata ();
 
-       log()->log (String::compose ("DCP-o-matic %1 git %2 using %3", dcpomatic_version, dcpomatic_git_commit, dependency_version_summary()));
+       LOG_GENERAL ("DCP-o-matic %1 git %2 using %3", dcpomatic_version, dcpomatic_git_commit, dependency_version_summary());
 
        {
                char buffer[128];
                gethostname (buffer, sizeof (buffer));
-               log()->log (String::compose ("Starting to make DCP on %1", buffer));
+               LOG_GENERAL ("Starting to make DCP on %1", buffer);
        }
 
        ContentList cl = content ();
        for (ContentList::const_iterator i = cl.begin(); i != cl.end(); ++i) {
-               log()->log (String::compose ("Content: %1", (*i)->technical_summary()));
+               LOG_GENERAL ("Content: %1", (*i)->technical_summary());
        }
-       log()->log (String::compose ("DCP video rate %1 fps", video_frame_rate()));
-       log()->log (String::compose ("%1 threads", Config::instance()->num_local_encoding_threads()));
-       log()->log (String::compose ("J2K bandwidth %1", j2k_bandwidth()));
+       LOG_GENERAL ("DCP video rate %1 fps", video_frame_rate());
+       LOG_GENERAL ("%1 threads", Config::instance()->num_local_encoding_threads());
+       LOG_GENERAL ("J2K bandwidth %1", j2k_bandwidth());
 #ifdef DCPOMATIC_DEBUG
-       log()->log ("DCP-o-matic built in debug mode.");
+       LOG_GENERAL_NC ("DCP-o-matic built in debug mode.");
 #else
-       log()->log ("DCP-o-matic built in optimised mode.");
+       LOG_GENERAL_NC ("DCP-o-matic built in optimised mode.");
 #endif
 #ifdef LIBDCP_DEBUG
-       log()->log ("libdcp built in debug mode.");
+       LOG_GENERAL_NC ("libdcp built in debug mode.");
 #else
-       log()->log ("libdcp built in optimised mode.");
+       LOG_GENERAL_NC ("libdcp built in optimised mode.");
 #endif
 
 #ifdef DCPOMATIC_WINDOWS
        OSVERSIONINFO info;
        info.dwOSVersionInfoSize = sizeof (info);
        GetVersionEx (&info);
-       log()->log (String::compose ("Windows version %1.%2.%3 SP %4", info.dwMajorVersion, info.dwMinorVersion, info.dwBuildNumber, info.szCSDVersion));
+       LOG_GENERAL ("Windows version %1.%2.%3 SP %4", info.dwMajorVersion, info.dwMinorVersion, info.dwBuildNumber, info.szCSDVersion);
 #endif 
        
-       log()->log (String::compose ("CPU: %1, %2 processors", cpu_info(), boost::thread::hardware_concurrency ()));
+       LOG_GENERAL ("CPU: %1, %2 processors", cpu_info(), boost::thread::hardware_concurrency ());
        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));
+               LOG_GENERAL ("Mount: %1 %2", i->first, i->second);
        }
        
        if (container() == 0) {
@@ -766,11 +769,11 @@ Film::j2c_path (int f, Eyes e, bool t) const
        return file (p);
 }
 
-/** @return List of subdirectories (not full paths) containing DCPs that can be successfully dcp::DCP::read() */
-list<boost::filesystem::path>
-Film::dcps () const
+/** Find all the DCPs in our directory that can be libdcp::DCP::read() and return details of their CPLs */
+vector<CPLSummary>
+Film::cpls () const
 {
-       list<boost::filesystem::path> out;
+       vector<CPLSummary> out;
        
        boost::filesystem::path const dir = directory ();
        for (boost::filesystem::directory_iterator i = boost::filesystem::directory_iterator(dir); i != boost::filesystem::directory_iterator(); ++i) {
@@ -782,7 +785,14 @@ Film::dcps () const
                        try {
                                dcp::DCP dcp (*i);
                                dcp.read ();
-                               out.push_back (i->path().leaf ());
+                               out.push_back (
+                                       CPLSummary (
+                                               i->path().leaf().string(),
+                                               dcp.cpls().front()->id(),
+                                               dcp.cpls().front()->annotation_text(),
+                                               dcp.cpls().front()->file()
+                                               )
+                                       );
                        } catch (...) {
 
                        }
@@ -961,26 +971,15 @@ Film::frame_size () const
 dcp::EncryptedKDM
 Film::make_kdm (
        shared_ptr<dcp::Certificate> target,
-       boost::filesystem::path dcp_dir,
+       boost::filesystem::path cpl_file,
        dcp::LocalTime from,
        dcp::LocalTime until
        ) const
 {
-       shared_ptr<const Signer> signer = make_signer ();
-
-       dcp::DCP dcp (dir (dcp_dir.string ()));
-       
-       try {
-               dcp.read ();
-       } catch (...) {
-               throw KDMError (_("Could not read DCP to make KDM for"));
-       }
-       
-       dcp.cpls().front()->set_mxf_keys (key ());
-       
+       shared_ptr<const dcp::CPL> cpl (new dcp::CPL (cpl_file));
        return dcp::DecryptedKDM (
-               dcp.cpls().front(), from, until, "DCP-o-matic", dcp.cpls().front()->content_title_text(), dcp::LocalTime().as_string()
-               ).encrypt (signer, target);
+               cpl, from, until, "DCP-o-matic", cpl->content_title_text(), dcp::LocalTime().as_string()
+               ).encrypt (make_signer(), target);
 }
 
 list<dcp::EncryptedKDM>
index ee8756b3dfdcf860d837c0dd90a11188427bd350..d9d7e82fd2140a4cbf9fae20c69ea9e6badd4db6 100644 (file)
@@ -99,7 +99,7 @@ public:
        dcp::Size full_frame () const;
        dcp::Size frame_size () const;
 
-       std::list<boost::filesystem::path> dcps () const;
+       std::vector<CPLSummary> cpls () const;
 
        boost::shared_ptr<Player> make_player () const;
        boost::shared_ptr<Playlist> playlist () const;
@@ -120,14 +120,14 @@ public:
        dcp::EncryptedKDM
        make_kdm (
                boost::shared_ptr<dcp::Certificate> target,
-               boost::filesystem::path dcp,
+               boost::filesystem::path cpl_file,
                dcp::LocalTime from,
                dcp::LocalTime until
                ) const;
        
        std::list<dcp::EncryptedKDM> make_kdms (
                std::list<boost::shared_ptr<Screen> >,
-               boost::filesystem::path dcp,
+               boost::filesystem::path cpl_file,
                dcp::LocalTime from,
                dcp::LocalTime until
                ) const;
index 9f83d1d896d1444579bcd157b214b389468b9f30..d3cdbd6f1ee753b994919cd677828662c1b96a8e 100644 (file)
@@ -49,7 +49,7 @@ ImageDecoder::pass ()
 
        if (!_image_content->still() || !_image) {
                /* Either we need an image or we are using moving images, so load one */
-               _image.reset (new MagickImageProxy (_image_content->path (_image_content->still() ? 0 : _video_position)));
+               _image.reset (new MagickImageProxy (_image_content->path (_image_content->still() ? 0 : _video_position), _image_content->film()->log ()));
        }
                
        video (_image, _video_position);
index c74e846c99680b1e0e3f4ab0319ad17c109f1c9a..16bd92f6ece1ea0f933cc0b09ec8a168533c0ece 100644 (file)
 #include "image.h"
 #include "exceptions.h"
 #include "cross.h"
+#include "log.h"
 
 #include "i18n.h"
 
+#define LOG_TIMING(...) _log->microsecond_log (String::compose (__VA_ARGS__), Log::TYPE_TIMING);
+
 using std::cout;
 using std::string;
 using std::stringstream;
 using boost::shared_ptr;
 
-RawImageProxy::RawImageProxy (shared_ptr<Image> image)
-       : _image (image)
+ImageProxy::ImageProxy (shared_ptr<Log> log)
+       : _log (log)
 {
 
 }
 
-RawImageProxy::RawImageProxy (shared_ptr<cxml::Node> xml, shared_ptr<Socket> socket)
+RawImageProxy::RawImageProxy (shared_ptr<Image> image, shared_ptr<Log> log)
+       : ImageProxy (log)
+       , _image (image)
+{
+
+}
+
+RawImageProxy::RawImageProxy (shared_ptr<cxml::Node> xml, shared_ptr<Socket> socket, shared_ptr<Log> log)
+       : ImageProxy (log)
 {
        dcp::Size size (
                xml->number_child<int> ("Width"), xml->number_child<int> ("Height")
@@ -68,7 +79,8 @@ RawImageProxy::send_binary (shared_ptr<Socket> socket) const
        _image->write_to_socket (socket);
 }
 
-MagickImageProxy::MagickImageProxy (boost::filesystem::path path)
+MagickImageProxy::MagickImageProxy (boost::filesystem::path path, shared_ptr<Log> log)
+       : ImageProxy (log)
 {
        /* Read the file into a Blob */
        
@@ -89,7 +101,8 @@ MagickImageProxy::MagickImageProxy (boost::filesystem::path path)
        delete[] data;
 }
 
-MagickImageProxy::MagickImageProxy (shared_ptr<cxml::Node>, shared_ptr<Socket> socket)
+MagickImageProxy::MagickImageProxy (shared_ptr<cxml::Node>, shared_ptr<Socket> socket, shared_ptr<Log> log)
+       : ImageProxy (log)
 {
        uint32_t const size = socket->read_uint32 ();
        uint8_t* data = new uint8_t[size];
@@ -105,6 +118,8 @@ MagickImageProxy::image () const
                return _image;
        }
 
+       LOG_TIMING ("[%1] MagickImageProxy begins decode and convert of %2 bytes", boost::this_thread::get_id(), _blob.length());
+
        Magick::Image* magick_image = 0;
        try {
                magick_image = new Magick::Image (_blob);
@@ -113,6 +128,7 @@ MagickImageProxy::image () const
        }
 
        dcp::Size size (magick_image->columns(), magick_image->rows());
+       LOG_TIMING ("[%1] MagickImageProxy decode finished", boost::this_thread::get_id ());
 
        _image.reset (new Image (PIX_FMT_RGB24, size, true));
 
@@ -132,6 +148,8 @@ MagickImageProxy::image () const
 
        delete magick_image;
 
+       LOG_TIMING ("[%1] MagickImageProxy completes decode and convert of %2 bytes", boost::this_thread::get_id(), _blob.length());
+
        return _image;
 }
 
@@ -149,12 +167,12 @@ MagickImageProxy::send_binary (shared_ptr<Socket> socket) const
 }
 
 shared_ptr<ImageProxy>
-image_proxy_factory (shared_ptr<cxml::Node> xml, shared_ptr<Socket> socket)
+image_proxy_factory (shared_ptr<cxml::Node> xml, shared_ptr<Socket> socket, shared_ptr<Log> log)
 {
        if (xml->string_child("Type") == N_("Raw")) {
-               return shared_ptr<ImageProxy> (new RawImageProxy (xml, socket));
+               return shared_ptr<ImageProxy> (new RawImageProxy (xml, socket, log));
        } else if (xml->string_child("Type") == N_("Magick")) {
-               return shared_ptr<MagickImageProxy> (new MagickImageProxy (xml, socket));
+               return shared_ptr<MagickImageProxy> (new MagickImageProxy (xml, socket, log));
        }
 
        throw NetworkError (_("Unexpected image type received by server"));
index 792fa004aea931e3d3a4041822571a4c89ec3633..b499b329283362788c778b40ccb33769f3e36ea8 100644 (file)
@@ -28,6 +28,7 @@
 
 class Image;
 class Socket;
+class Log;
 
 namespace cxml {
        class Node;
@@ -44,19 +45,24 @@ namespace cxml {
  *  the TIFF data TIFF until such a time that the actual image is needed.
  *  At this point, the class decodes the TIFF to an Image.
  */
-class ImageProxy
+class ImageProxy : public boost::noncopyable
 {
 public:
+       ImageProxy (boost::shared_ptr<Log> log);
+       
        virtual boost::shared_ptr<Image> image () const = 0;
        virtual void add_metadata (xmlpp::Node *) const = 0;
        virtual void send_binary (boost::shared_ptr<Socket>) const = 0;
+
+protected:
+       boost::shared_ptr<Log> _log;
 };
 
 class RawImageProxy : public ImageProxy
 {
 public:
-       RawImageProxy (boost::shared_ptr<Image>);
-       RawImageProxy (boost::shared_ptr<cxml::Node> xml, boost::shared_ptr<Socket> socket);
+       RawImageProxy (boost::shared_ptr<Image>, boost::shared_ptr<Log> log);
+       RawImageProxy (boost::shared_ptr<cxml::Node> xml, boost::shared_ptr<Socket> socket, boost::shared_ptr<Log> log);
 
        boost::shared_ptr<Image> image () const;
        void add_metadata (xmlpp::Node *) const;
@@ -69,8 +75,8 @@ private:
 class MagickImageProxy : public ImageProxy
 {
 public:
-       MagickImageProxy (boost::filesystem::path);
-       MagickImageProxy (boost::shared_ptr<cxml::Node> xml, boost::shared_ptr<Socket> socket);
+       MagickImageProxy (boost::filesystem::path, boost::shared_ptr<Log> log);
+       MagickImageProxy (boost::shared_ptr<cxml::Node> xml, boost::shared_ptr<Socket> socket, boost::shared_ptr<Log> log);
 
        boost::shared_ptr<Image> image () const;
        void add_metadata (xmlpp::Node *) const;
@@ -81,4 +87,4 @@ private:
        mutable boost::shared_ptr<Image> _image;
 };
 
-boost::shared_ptr<ImageProxy> image_proxy_factory (boost::shared_ptr<cxml::Node> xml, boost::shared_ptr<Socket> socket);
+boost::shared_ptr<ImageProxy> image_proxy_factory (boost::shared_ptr<cxml::Node> xml, boost::shared_ptr<Socket> socket, boost::shared_ptr<Log> log);
index c6a6b90a808fcdd234c053ce1c21a31d3128d3eb..594c0da34f1b5cdc7a55177e61bee698b5ac21d5 100644 (file)
@@ -281,7 +281,7 @@ Job::error_summary () const
 void
 Job::set_error (string s, string d)
 {
-       _film->log()->log (String::compose ("Error in job: %1 (%2)", s, d));
+       _film->log()->log (String::compose ("Error in job: %1 (%2)", s, d), Log::TYPE_ERROR);
        boost::mutex::scoped_lock lm (_state_mutex);
        _error_summary = s;
        _error_details = d;
index 902f0d33322a48617e71e193801780704a46ca39..c08750961e2c7c77245191e8e99f2b97daf5d875 100644 (file)
@@ -102,12 +102,12 @@ static list<ScreenKDM>
 make_screen_kdms (
        shared_ptr<const Film> film,
        list<shared_ptr<Screen> > screens,
-       boost::filesystem::path dcp,
+       boost::filesystem::path cpl,
        dcp::LocalTime from,
        dcp::LocalTime to
        )
 {
-       list<dcp::EncryptedKDM> kdms = film->make_kdms (screens, dcp, from, to);
+       list<dcp::EncryptedKDM> kdms = film->make_kdms (screens, cpl, from, to);
           
        list<ScreenKDM> screen_kdms;
        
@@ -126,12 +126,12 @@ static list<CinemaKDMs>
 make_cinema_kdms (
        shared_ptr<const Film> film,
        list<shared_ptr<Screen> > screens,
-       boost::filesystem::path dcp,
+       boost::filesystem::path cpl,
        dcp::LocalTime from,
        dcp::LocalTime to
        )
 {
-       list<ScreenKDM> screen_kdms = make_screen_kdms (film, screens, dcp, from, to);
+       list<ScreenKDM> screen_kdms = make_screen_kdms (film, screens, cpl, from, to);
        list<CinemaKDMs> cinema_kdms;
 
        while (!screen_kdms.empty ()) {
@@ -171,13 +171,13 @@ void
 write_kdm_files (
        shared_ptr<const Film> film,
        list<shared_ptr<Screen> > screens,
-       boost::filesystem::path dcp,
+       boost::filesystem::path cpl,
        dcp::LocalTime from,
        dcp::LocalTime to,
        boost::filesystem::path directory
        )
 {
-       list<ScreenKDM> screen_kdms = make_screen_kdms (film, screens, dcp, from, to);
+       list<ScreenKDM> screen_kdms = make_screen_kdms (film, screens, cpl, from, to);
 
        /* Write KDMs to the specified directory */
        for (list<ScreenKDM>::iterator i = screen_kdms.begin(); i != screen_kdms.end(); ++i) {
@@ -191,13 +191,13 @@ void
 write_kdm_zip_files (
        shared_ptr<const Film> film,
        list<shared_ptr<Screen> > screens,
-       boost::filesystem::path dcp,
+       boost::filesystem::path cpl,
        dcp::LocalTime from,
        dcp::LocalTime to,
        boost::filesystem::path directory
        )
 {
-       list<CinemaKDMs> cinema_kdms = make_cinema_kdms (film, screens, dcp, from, to);
+       list<CinemaKDMs> cinema_kdms = make_cinema_kdms (film, screens, cpl, from, to);
 
        for (list<CinemaKDMs>::const_iterator i = cinema_kdms.begin(); i != cinema_kdms.end(); ++i) {
                boost::filesystem::path path = directory;
@@ -210,12 +210,12 @@ void
 email_kdms (
        shared_ptr<const Film> film,
        list<shared_ptr<Screen> > screens,
-       boost::filesystem::path dcp,
+       boost::filesystem::path cpl,
        dcp::LocalTime from,
        dcp::LocalTime to
        )
 {
-       list<CinemaKDMs> cinema_kdms = make_cinema_kdms (film, screens, dcp, from, to);
+       list<CinemaKDMs> cinema_kdms = make_cinema_kdms (film, screens, cpl, from, to);
 
        for (list<CinemaKDMs>::const_iterator i = cinema_kdms.begin(); i != cinema_kdms.end(); ++i) {
                
index 5df161b2a03404beafc39d88fa2d7dddb0b83e8e..023107a826875f169c4e1c780ee9666ba366eefc 100644 (file)
@@ -26,7 +26,7 @@ class Film;
 extern void write_kdm_files (
        boost::shared_ptr<const Film> film,
        std::list<boost::shared_ptr<Screen> > screens,
-       boost::filesystem::path dcp,
+       boost::filesystem::path cpl,
        dcp::LocalTime from,
        dcp::LocalTime to,
        boost::filesystem::path directory
@@ -35,7 +35,7 @@ extern void write_kdm_files (
 extern void write_kdm_zip_files (
        boost::shared_ptr<const Film> film,
        std::list<boost::shared_ptr<Screen> > screens,
-       boost::filesystem::path dcp,
+       boost::filesystem::path cpl,
        dcp::LocalTime from,
        dcp::LocalTime to,
        boost::filesystem::path directory
@@ -44,7 +44,7 @@ extern void write_kdm_zip_files (
 extern void email_kdms (
        boost::shared_ptr<const Film> film,
        std::list<boost::shared_ptr<Screen> > screens,
-       boost::filesystem::path dcp,
+       boost::filesystem::path cpl,
        dcp::LocalTime from,
        dcp::LocalTime to
        );
index a0b031589bf1836080c98c170c2fde1860df8dfe..52dff2982222620d81a9b7426c13c2a32beb523e 100644 (file)
 #include <cstdio>
 #include "log.h"
 #include "cross.h"
+#include "config.h"
 
 #include "i18n.h"
 
 using namespace std;
 
+int const Log::TYPE_GENERAL = 0x1;
+int const Log::TYPE_WARNING = 0x2;
+int const Log::TYPE_ERROR   = 0x4;
+int const Log::TYPE_TIMING  = 0x8;
+
 Log::Log ()
-       : _level (STANDARD)
+       : _types (0)
 {
+       Config::instance()->Changed.connect (boost::bind (&Log::config_changed, this));
+       config_changed ();
+}
 
+void
+Log::config_changed ()
+{
+       set_types (Config::instance()->log_types ());
 }
 
 /** @param n String to log */
 void
-Log::log (string m, Level l)
+Log::log (string message, int type)
 {
        boost::mutex::scoped_lock lm (_mutex);
 
-       if (l > _level) {
+       if ((_types & type) == 0) {
                return;
        }
 
@@ -51,16 +64,26 @@ Log::log (string m, Level l)
        string a = ctime (&t);
 
        stringstream s;
-       s << a.substr (0, a.length() - 1) << N_(": ") << m;
+       s << a.substr (0, a.length() - 1) << N_(": ");
+
+       if (type & TYPE_ERROR) {
+               s << "ERROR: ";
+       }
+
+       if (type & TYPE_WARNING) {
+               s << "WARNING: ";
+       }
+       
+       s << message;
        do_log (s.str ());
 }
 
 void
-Log::microsecond_log (string m, Level l)
+Log::microsecond_log (string m, int t)
 {
        boost::mutex::scoped_lock lm (_mutex);
 
-       if (l > _level) {
+       if ((_types & t) == 0) {
                return;
        }
 
@@ -73,24 +96,10 @@ Log::microsecond_log (string m, Level l)
 }      
 
 void
-Log::set_level (Level l)
+Log::set_types (int t)
 {
        boost::mutex::scoped_lock lm (_mutex);
-       _level = l;
-}
-
-void
-Log::set_level (string l)
-{
-       if (l == N_("verbose")) {
-               set_level (VERBOSE);
-               return;
-       } else if (l == N_("timing")) {
-               set_level (TIMING);
-               return;
-       }
-
-       set_level (STANDARD);
+       _types = t;
 }
 
 /** @param file Filename to write log to */
index 991532404293a7a01fc59762b3b1b8b0d15af6ec..2ba273b44dd09e2e254c3a914ce16d2829959cee 100644 (file)
@@ -37,17 +37,15 @@ public:
        Log ();
        virtual ~Log () {}
 
-       enum Level {
-               STANDARD = 0,
-               VERBOSE = 1,
-               TIMING = 2
-       };
+       static const int TYPE_GENERAL;
+       static const int TYPE_WARNING;
+       static const int TYPE_ERROR;
+       static const int TYPE_TIMING;
 
-       void log (std::string m, Level l = STANDARD);
-       void microsecond_log (std::string m, Level l = STANDARD);
+       void log (std::string message, int type);
+       void microsecond_log (std::string message, int type);
 
-       void set_level (Level l);
-       void set_level (std::string l);
+       void set_types (int types);
 
 protected:     
        /** mutex to protect the log */
@@ -55,9 +53,10 @@ protected:
        
 private:
        virtual void do_log (std::string m) = 0;
+       void config_changed ();
        
-       /** level above which to ignore log messages */
-       Level _level;
+       /** bit-field of log types which should be put into the log (others are ignored) */
+       int _types;
 };
 
 class FileLog : public Log
index b60dd846786056a2918b3a1338a8382183e81cea..77def1e60d7eec92d83bbe66168fcb562107b827 100644 (file)
@@ -43,6 +43,8 @@
 #include "content_video.h"
 #include "player_video_frame.h"
 
+#define LOG_GENERAL(...) _film->log()->log (String::compose (__VA_ARGS__), Log::TYPE_GENERAL);
+
 using std::list;
 using std::cout;
 using std::min;
@@ -293,7 +295,7 @@ Player::black_player_video_frame () const
 {
        return shared_ptr<PlayerVideoFrame> (
                new PlayerVideoFrame (
-                       shared_ptr<const ImageProxy> (new RawImageProxy (_black_image)),
+                       shared_ptr<const ImageProxy> (new RawImageProxy (_black_image, _film->log ())),
                        Crop (),
                        _video_container_size,
                        _video_container_size,
@@ -496,8 +498,6 @@ Player::get_audio (DCPTime time, DCPTime length, bool accurate)
                        min (AudioFrame (all->audio->frames()), length_frames) - offset.frames (_film->audio_frame_rate ())
                        );
        }
-
-       return audio;
 }
 
 VideoFrame
@@ -538,8 +538,8 @@ Player::dcp_to_content_subtitle (shared_ptr<const Piece> piece, DCPTime t) const
 void
 PlayerStatistics::dump (shared_ptr<Log> log) const
 {
-       log->log (String::compose ("Video: %1 good %2 skipped %3 black %4 repeat", video.good, video.skip, video.black, video.repeat));
-       log->log (String::compose ("Audio: %1 good %2 skipped %3 silence", audio.good, audio.skip, audio.silence.seconds()));
+       log->log (String::compose ("Video: %1 good %2 skipped %3 black %4 repeat", video.good, video.skip, video.black, video.repeat), Log::TYPE_GENERAL);
+       log->log (String::compose ("Audio: %1 good %2 skipped %3 silence", audio.good, audio.skip, audio.silence.seconds()), Log::TYPE_GENERAL);
 }
 
 PlayerStatistics const &
index 2544f8bbcb0f3c7f330d7c6cc1073bd01a427ba8..5463925bf89e015bf31b58ebbccccad54ac19b5b 100644 (file)
@@ -50,7 +50,7 @@ PlayerVideoFrame::PlayerVideoFrame (
 
 }
 
-PlayerVideoFrame::PlayerVideoFrame (shared_ptr<cxml::Node> node, shared_ptr<Socket> socket)
+PlayerVideoFrame::PlayerVideoFrame (shared_ptr<cxml::Node> node, shared_ptr<Socket> socket, shared_ptr<Log> log)
 {
        _crop = Crop (node);
 
@@ -61,7 +61,7 @@ PlayerVideoFrame::PlayerVideoFrame (shared_ptr<cxml::Node> node, shared_ptr<Sock
        _part = (Part) node->number_child<int> ("Part");
        _colour_conversion = ColourConversion (node);
 
-       _in = image_proxy_factory (node->node_child ("In"), socket);
+       _in = image_proxy_factory (node->node_child ("In"), socket, log);
 
        if (node->optional_number_child<int> ("SubtitleX")) {
                
index 225b0a4bafe43c8dee4be008b8e5bdb5b519fb1b..4c6a9c63008cd6b30f2898b27e8b9e8974dddd8a 100644 (file)
@@ -27,6 +27,7 @@ class Image;
 class ImageProxy;
 class Scaler;
 class Socket;
+class Log;
 
 /** Everything needed to describe a video frame coming out of the player, but with the
  *  bits still their raw form.  We may want to combine the bits on a remote machine,
@@ -36,7 +37,7 @@ class PlayerVideoFrame
 {
 public:
        PlayerVideoFrame (boost::shared_ptr<const ImageProxy>, Crop, dcp::Size, dcp::Size, Scaler const *, Eyes, Part, ColourConversion);
-       PlayerVideoFrame (boost::shared_ptr<cxml::Node>, boost::shared_ptr<Socket>);
+       PlayerVideoFrame (boost::shared_ptr<cxml::Node>, boost::shared_ptr<Socket>, boost::shared_ptr<Log>);
 
        void set_subtitle (PositionImage);
        
index 0b713b0427b15c62cdda2e39455c0a5e3dab1bc3..63784081356e9eb0fc4d81ea97d551a7078e224d 100644 (file)
@@ -37,6 +37,8 @@
 
 #include "i18n.h"
 
+#define LOG_GENERAL_NC(...) _film->log()->log (__VA_ARGS__, Log::TYPE_GENERAL);
+
 using std::string;
 using std::stringstream;
 using std::min;
@@ -119,7 +121,7 @@ SCPDCPJob::json_name () const
 void
 SCPDCPJob::run ()
 {
-       _film->log()->log (N_("SCP DCP job starting"));
+       LOG_GENERAL_NC (N_("SCP DCP job starting"));
        
        SSHSession ss;
        
index d72b7e5025b84e57513a97864014137d5658eacd..507ff2ae593ae2bfa5c15e818d16d561281e83de 100644 (file)
 
 #include "i18n.h"
 
+#define LOG_GENERAL(...)    _log->log (String::compose (__VA_ARGS__), Log::TYPE_GENERAL);
+#define LOG_GENERAL_NC(...) _log->log (__VA_ARGS__, Log::TYPE_GENERAL);
+#define LOG_ERROR(...)      _log->log (String::compose (__VA_ARGS__), Log::TYPE_ERROR);
+#define LOG_ERROR_NC(...)   _log->log (__VA_ARGS__, Log::TYPE_ERROR);
+
 using std::string;
 using std::stringstream;
 using std::multimap;
@@ -82,11 +87,11 @@ Server::process (shared_ptr<Socket> socket, struct timeval& after_read, struct t
        xml->read_stream (s);
        if (xml->number_child<int> ("Version") != SERVER_LINK_VERSION) {
                cerr << "Mismatched server/client versions\n";
-               _log->log ("Mismatched server/client versions");
+               LOG_ERROR_NC ("Mismatched server/client versions");
                return -1;
        }
 
-       shared_ptr<PlayerVideoFrame> pvf (new PlayerVideoFrame (xml, socket));
+       shared_ptr<PlayerVideoFrame> pvf (new PlayerVideoFrame (xml, socket, _log));
 
        DCPVideoFrame dcp_video_frame (pvf, xml, _log);
 
@@ -99,7 +104,7 @@ Server::process (shared_ptr<Socket> socket, struct timeval& after_read, struct t
        try {
                encoded->send (socket);
        } catch (std::exception& e) {
-               _log->log (String::compose ("Send failed; frame %1", dcp_video_frame.index()));
+               LOG_ERROR ("Send failed; frame %1", dcp_video_frame.index());
                throw;
        }
 
@@ -134,7 +139,7 @@ Server::worker_thread ()
                        frame = process (socket, after_read, after_encode);
                        ip = socket->socket().remote_endpoint().address().to_string();
                } catch (std::exception& e) {
-                       _log->log (String::compose ("Error: %1", e.what()));
+                       LOG_ERROR ("Error: %1", e.what());
                }
 
                gettimeofday (&end, 0);
@@ -159,7 +164,7 @@ Server::worker_thread ()
                                cout << message.str() << "\n";
                        }
 
-                       _log->log (message.str ());
+                       LOG_GENERAL_NC (message.str ());
                }
                
                _worker_condition.notify_all ();
@@ -169,7 +174,7 @@ Server::worker_thread ()
 void
 Server::run (int num_threads)
 {
-       _log->log (String::compose ("Server starting with %1 threads", num_threads));
+       LOG_GENERAL ("Server starting with %1 threads", num_threads);
        if (_verbose) {
                cout << "DCP-o-matic server starting with " << num_threads << " threads.\n";
        }
index 97e8bd416a0432697b14dcb2503d6f82d62ba2e0..4a85fa18aa8935d0a2c0ff5670f504de012b439e 100644 (file)
@@ -30,6 +30,9 @@
 
 #include "i18n.h"
 
+#define LOG_GENERAL_NC(...) _film->log()->log (__VA_ARGS__, Log::TYPE_GENERAL);
+#define LOG_ERROR_NC(...)   _film->log()->log (__VA_ARGS__, Log::TYPE_ERROR);
+
 using std::string;
 using std::stringstream;
 using std::fixed;
@@ -62,17 +65,20 @@ TranscodeJob::run ()
 {
        try {
 
-               _film->log()->log (N_("Transcode job starting"));
+               LOG_GENERAL_NC (N_("Transcode job starting"));
 
                _transcoder.reset (new Transcoder (_film, shared_from_this ()));
                _transcoder->go ();
                set_progress (1);
                set_state (FINISHED_OK);
 
-               _film->log()->log (N_("Transcode job completed successfully"));
+               LOG_GENERAL_NC (N_("Transcode job completed successfully"));
                _transcoder.reset ();
 
        } catch (...) {
+               set_progress (1);
+               set_state (FINISHED_ERROR);
+               LOG_ERROR_NC (N_("Transcode job failed or cancelled"));
                _transcoder.reset ();
                throw;
        }
index e858d1e1feb6b7827ce09d79822e5817b4fa3df0..9a6a30b861d45344325507186f5c08b2b200ea42 100644 (file)
@@ -138,6 +138,21 @@ struct Crop
        void as_xml (xmlpp::Node *) const;
 };
 
+struct CPLSummary
+{
+       CPLSummary (std::string d, std::string i, std::string a, boost::filesystem::path f)
+               : dcp_directory (d)
+               , cpl_id (i)
+               , cpl_annotation_text (a)
+               , cpl_file (f)
+       {}
+       
+       std::string dcp_directory;
+       std::string cpl_id;
+       std::string cpl_annotation_text;
+       boost::filesystem::path cpl_file;
+};
+
 extern bool operator== (Crop const & a, Crop const & b);
 extern bool operator!= (Crop const & a, Crop const & b);
 
index 196a6e8f93b13e3314fca48423f1e70e5702f108..28af8ef2f88c41bcfbdb8bad30806248ff98af35 100644 (file)
@@ -41,12 +41,6 @@ extern "C" {
 #include "types.h"
 #include "video_content.h"
 
-#ifdef DCPOMATIC_DEBUG
-#define TIMING(...) _film->log()->microsecond_log (String::compose (__VA_ARGS__), Log::TIMING);
-#else
-#define TIMING(...)
-#endif
-
 #undef check
 
 /** The maximum number of audio channels that we can have in a DCP */
index 306f6d7f4968c387965014baf084e43668bee5f6..9410dd565b4a9ba963cda63af72aea763c489511 100644 (file)
 
 #include "i18n.h"
 
+#define LOG_GENERAL(...) _film->log()->log (String::compose (__VA_ARGS__), Log::TYPE_GENERAL);
+#define LOG_TIMING(...) _film->log()->microsecond_log (String::compose (__VA_ARGS__), Log::TYPE_TIMING);
+#define LOG_WARNING_NC(...) _film->log()->log (__VA_ARGS__, Log::TYPE_WARNING);
+
 /* OS X strikes again */
 #undef set_key
 
@@ -242,9 +246,9 @@ try
                                break;
                        }
 
-                       TIMING (N_("writer sleeps with a queue of %1"), _queue.size());
+                       LOG_TIMING (N_("writer sleeps with a queue of %1"), _queue.size());
                        _empty_condition.wait (lock);
-                       TIMING (N_("writer wakes with a queue of %1"), _queue.size());
+                       LOG_TIMING (N_("writer wakes with a queue of %1"), _queue.size());
                }
 
                if (_finish && _queue.empty()) {
@@ -263,7 +267,7 @@ try
                        switch (qi.type) {
                        case QueueItem::FULL:
                        {
-                               _film->log()->log (String::compose (N_("Writer FULL-writes %1 to MXF"), qi.frame));
+                               LOG_GENERAL (N_("Writer FULL-writes %1 to MXF"), qi.frame);
                                if (!qi.encoded) {
                                        qi.encoded.reset (new EncodedData (_film->j2c_path (qi.frame, qi.eyes, false)));
                                }
@@ -275,7 +279,7 @@ try
                                break;
                        }
                        case QueueItem::FAKE:
-                               _film->log()->log (String::compose (N_("Writer FAKE-writes %1 to MXF"), qi.frame));
+                               LOG_GENERAL (N_("Writer FAKE-writes %1 to MXF"), qi.frame);
                                _picture_mxf_writer->fake_write (qi.size);
                                _last_written[qi.eyes].reset ();
                                ++_fake_written;
@@ -319,11 +323,10 @@ try
                        
                        lock.unlock ();
 
-                       _film->log()->log (
-                               String::compose (
-                                       "Writer full (awaiting %1 [last eye was %2]); pushes %3 to disk",
-                                       _last_written_frame + 1,
-                                       _last_written_eyes, qi.frame)
+                       LOG_GENERAL (
+                               "Writer full (awaiting %1 [last eye was %2]); pushes %3 to disk",
+                               _last_written_frame + 1,
+                               _last_written_eyes, qi.frame
                                );
                        
                        qi.encoded->write (_film, qi.frame, qi.eyes);
@@ -390,7 +393,7 @@ Writer::finish ()
        if (ec) {
                /* hard link failed; copy instead */
                boost::filesystem::copy_file (video_from, video_to);
-               _film->log()->log ("Hard-link failed; fell back to copying");
+               LOG_WARNING_NC ("Hard-link failed; fell back to copying");
        }
 
        _picture_mxf->set_file (video_to);
@@ -460,8 +463,8 @@ Writer::finish ()
 
        dcp.write_xml (_film->interop () ? dcp::INTEROP : dcp::SMPTE, meta, _film->is_signed() ? make_signer () : shared_ptr<const dcp::Signer> ());
 
-       _film->log()->log (
-               String::compose (N_("Wrote %1 FULL, %2 FAKE, %3 pushed to disk"), _full_written, _fake_written, _pushed_to_disk)
+       LOG_GENERAL (
+               N_("Wrote %1 FULL, %2 FAKE, %3 pushed to disk"), _full_written, _fake_written, _pushed_to_disk
                );
 }
 
@@ -471,14 +474,14 @@ Writer::check_existing_picture_mxf_frame (FILE* mxf, int f, Eyes eyes)
        /* Read the frame info as written */
        FILE* ifi = fopen_boost (_film->info_path (f, eyes), "r");
        if (!ifi) {
-               _film->log()->log (String::compose ("Existing frame %1 has no info file", f));
+               LOG_GENERAL ("Existing frame %1 has no info file", f);
                return false;
        }
        
        dcp::FrameInfo info (ifi);
        fclose (ifi);
        if (info.size == 0) {
-               _film->log()->log (String::compose ("Existing frame %1 has no info file", f));
+               LOG_GENERAL ("Existing frame %1 has no info file", f);
                return false;
        }
        
@@ -487,13 +490,13 @@ Writer::check_existing_picture_mxf_frame (FILE* mxf, int f, Eyes eyes)
        EncodedData data (info.size);
        size_t const read = fread (data.data(), 1, data.size(), mxf);
        if (read != static_cast<size_t> (data.size ())) {
-               _film->log()->log (String::compose ("Existing frame %1 is incomplete", f));
+               LOG_GENERAL ("Existing frame %1 is incomplete", f);
                return false;
        }
        
        string const existing_hash = md5_digest (data.data(), data.size());
        if (existing_hash != info.hash) {
-               _film->log()->log (String::compose ("Existing frame %1 failed hash check", f));
+               LOG_GENERAL ("Existing frame %1 failed hash check", f);
                return false;
        }
 
@@ -509,7 +512,7 @@ Writer::check_existing_picture_mxf ()
        p /= _film->internal_video_mxf_filename ();
        FILE* mxf = fopen_boost (p, "rb");
        if (!mxf) {
-               _film->log()->log (String::compose ("Could not open existing MXF at %1 (errno=%2)", p.string(), errno));
+               LOG_GENERAL ("Could not open existing MXF at %1 (errno=%2)", p.string(), errno);
                return;
        }
 
@@ -540,7 +543,7 @@ Writer::check_existing_picture_mxf ()
                        }
                }
 
-               _film->log()->log (String::compose ("Have existing frame %1", _first_nonexistant_frame));
+               LOG_GENERAL ("Have existing frame %1", _first_nonexistant_frame);
                ++_first_nonexistant_frame;
        }
 
index f2aff9359a35412684f4262bbfe7afdd9c6aa110..23c1e500512a750f17468445a2cfcfd1cd78f7de 100644 (file)
@@ -30,6 +30,7 @@
 #include <wx/stdpaths.h>
 #include <wx/cmdline.h>
 #include <wx/preferences.h>
+#include <libdcp/exceptions.h>
 #include "wx/film_viewer.h"
 #include "wx/film_editor.h"
 #include "wx/job_manager_view.h"
@@ -74,7 +75,6 @@ using boost::dynamic_pointer_cast;
 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 std::string content_to_add;
@@ -157,13 +157,12 @@ load_film (boost::filesystem::path file)
        for (list<string>::const_iterator i = notes.begin(); i != notes.end(); ++i) {
                error_dialog (0, std_to_wx (*i));
        }
-       film->log()->set_level (log_level);
 }
 
 #define ALWAYS                  0x0
 #define NEEDS_FILM              0x1
 #define NOT_DURING_DCP_CREATION 0x2
-#define NEEDS_DCP               0x4
+#define NEEDS_CPL               0x4
 
 map<wxMenuItem*, int> menu_items;
        
@@ -183,7 +182,7 @@ set_menu_sensitivity ()
                ++i;
        }
        bool const dcp_creation = (i != jobs.end ()) && !(*i)->finished ();
-       bool const have_dcp = film && !film->dcps().empty ();
+       bool const have_cpl = film && !film->cpls().empty ();
 
        for (map<wxMenuItem*, int>::iterator j = menu_items.begin(); j != menu_items.end(); ++j) {
 
@@ -197,7 +196,7 @@ set_menu_sensitivity ()
                        enabled = false;
                }
 
-               if ((j->second & NEEDS_DCP) && !have_dcp) {
+               if ((j->second & NEEDS_CPL) && !have_cpl) {
                        enabled = false;
                }
                
@@ -249,9 +248,9 @@ setup_menu (wxMenuBar* m)
 
        jobs_menu = new wxMenu;
        add_item (jobs_menu, _("&Make DCP"), ID_jobs_make_dcp, NEEDS_FILM | NOT_DURING_DCP_CREATION);
-       add_item (jobs_menu, _("Make &KDMs..."), ID_jobs_make_kdms, NEEDS_FILM | NEEDS_DCP);
-       add_item (jobs_menu, _("&Send DCP to TMS"), ID_jobs_send_dcp_to_tms, NEEDS_FILM | NOT_DURING_DCP_CREATION | NEEDS_DCP);
-       add_item (jobs_menu, _("S&how DCP"), ID_jobs_show_dcp, NEEDS_FILM | NOT_DURING_DCP_CREATION | NEEDS_DCP);
+       add_item (jobs_menu, _("Make &KDMs..."), ID_jobs_make_kdms, NEEDS_FILM);
+       add_item (jobs_menu, _("&Send DCP to TMS"), ID_jobs_send_dcp_to_tms, NEEDS_FILM | NOT_DURING_DCP_CREATION | NEEDS_CPL);
+       add_item (jobs_menu, _("S&how DCP"), ID_jobs_show_dcp, NEEDS_FILM | NOT_DURING_DCP_CREATION | NEEDS_CPL);
 
        wxMenu* tools = new wxMenu;
        add_item (tools, _("Hints..."), ID_tools_hints, 0);
@@ -401,7 +400,6 @@ private:
                        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 ();
                }
@@ -497,12 +495,14 @@ private:
 
                try {
                        if (d->write_to ()) {
-                               write_kdm_files (film, d->screens (), d->dcp (), d->from (), d->until (), d->directory ());
+                               write_kdm_files (film, d->screens (), d->cpl (), d->from (), d->until (), d->directory ());
                        } else {
                                JobManager::instance()->add (
-                                       shared_ptr<Job> (new SendKDMEmailJob (film, d->screens (), d->dcp (), d->from (), d->until ()))
+                                       shared_ptr<Job> (new SendKDMEmailJob (film, d->screens (), d->cpl (), d->from (), d->until ()))
                                        );
                        }
+               } catch (libdcp::NotEncryptedError& e) {
+                       error_dialog (this, _("CPL's content is not encrypted."));
                } catch (exception& e) {
                        error_dialog (this, e.what ());
                } catch (...) {
@@ -609,7 +609,6 @@ private:
 };
 
 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_OPTION, "c", "content", "add content file", wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL },
        { wxCMD_LINE_PARAM, 0, 0, "film to load or create", wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL },
@@ -671,7 +670,6 @@ class App : public wxApp
                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 ());
                }
 
@@ -729,11 +727,6 @@ class App : public wxApp
                        content_to_add = wx_to_std (content);
                }
 
-               wxString log;
-               if (parser.Found (wxT ("log"), &log)) {
-                       log_level = wx_to_std (log);
-               }
-
                return true;
        }
 
index d95b2ed99f63fac0a2c0e923c4272bedf1fa69ae..acd1335e62d5e5ef57c469232e429db29c22e6c6 100644 (file)
@@ -65,7 +65,6 @@ main (int argc, char* argv[])
        string film_dir;
        bool progress = true;
        bool no_remote = false;
-       int log_level = 0;
        int json_port = 0;
        bool keep_going = false;
 
@@ -78,13 +77,12 @@ main (int argc, char* argv[])
                        { "flags", no_argument, 0, 'f'},
                        { "no-progress", no_argument, 0, 'n'},
                        { "no-remote", no_argument, 0, 'r'},
-                       { "log-level", required_argument, 0, 'l' },
                        { "json", required_argument, 0, 'j' },
                        { "keep-going", no_argument, 0, 'k' },
                        { 0, 0, 0, 0 }
                };
 
-               int c = getopt_long (argc, argv, "vhdfnrl:j:k", long_options, &option_index);
+               int c = getopt_long (argc, argv, "vhdfnrj:k", long_options, &option_index);
 
                if (c == -1) {
                        break;
@@ -109,9 +107,6 @@ main (int argc, char* argv[])
                case 'r':
                        no_remote = true;
                        break;
-               case 'l':
-                       log_level = atoi (optarg);
-                       break;
                case 'j':
                        json_port = atoi (optarg);
                        break;
@@ -155,8 +150,6 @@ main (int argc, char* argv[])
                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 ());
index 2f6916df2be684ae5569e30a73af3922eaba3c72..0f2d5b8a31ad5e6c757a27d8702a1fe0d396726e 100644 (file)
@@ -30,6 +30,7 @@ using std::stringstream;
 using std::cout;
 using std::cerr;
 using std::list;
+using std::vector;
 using boost::shared_ptr;
 
 static string program_name;
@@ -219,14 +220,14 @@ int main (int argc, char* argv[])
        }
 
        /* XXX: allow specification of this */
-       list<boost::filesystem::path> dcps = film->dcps ();
-       if (dcps.empty ()) {
-               error ("no DCPs found in film");
-       } else if (dcps.size() > 1) {
-               error ("more than one DCP found in film");
+       vector<CPLSummary> cpls = film->cpls ();
+       if (cpls.empty ()) {
+               error ("no CPLs found in film");
+       } else if (cpls.size() > 1) {
+               error ("more than one CPL found in film");
        }
 
-       boost::filesystem::path dcp = dcps.front ();
+       boost::filesystem::path cpl = cpls.front().cpl_file;
 
        if (cinema_name.empty ()) {
 
@@ -235,7 +236,7 @@ int main (int argc, char* argv[])
                }
                
                shared_ptr<dcp::Certificate> certificate (new dcp::Certificate (boost::filesystem::path (certificate_file)));
-               dcp::EncryptedKDM kdm = film->make_kdm (certificate, dcp, valid_from.get(), valid_to.get());
+               dcp::EncryptedKDM kdm = film->make_kdm (certificate, cpl, valid_from.get(), valid_to.get());
                kdm.as_xml (output);
                if (verbose) {
                        cout << "Generated KDM " << output << " for certificate.\n";
@@ -259,12 +260,13 @@ int main (int argc, char* argv[])
 
                try {
                        if (zip) {
-                               write_kdm_zip_files (film, (*i)->screens(), dcp, dcp::LocalTime (valid_from.get()), dcp::LocalTime (valid_to.get()), output);
+                               write_kdm_zip_files (film, (*i)->screens(), cpl, dcp::LocalTime (valid_from.get()), dcp::LocalTime (valid_to.get()), output);
+
                                if (verbose) {
                                        cout << "Wrote ZIP files to " << output << "\n";
                                }
                        } else {
-                               write_kdm_files (film, (*i)->screens(), dcp, dcp::LocalTime (valid_from.get()), dcp::LocalTime (valid_to.get()), output);
+                               write_kdm_files (film, (*i)->screens(), cpl, dcp::LocalTime (valid_from.get()), dcp::LocalTime (valid_to.get()), output);
                                if (verbose) {
                                        cout << "Wrote KDM files to " << output << "\n";
                                }
index 276f5507ae9b9c521abd1dbb4320946a5f74c37c..105831014eccc81354e7910b3fd0b76fce86c717 100644 (file)
@@ -162,8 +162,10 @@ AboutDialog::AboutDialog (wxWindow* parent)
        tested_by.Add (wxT ("Andreas Eli"));
        tested_by.Add (wxT ("Maurizio Giampà"));
        tested_by.Add (wxT ("Luke Granger-Brown"));
+       tested_by.Add (wxT ("Sumit Guha"));
        tested_by.Add (wxT ("Steve Guttag"));
        tested_by.Add (wxT ("Patrick Haderer"));
+       tested_by.Add (wxT ("Bill Hamell"));
        tested_by.Add (wxT ("Jonathan Jensen"));
        tested_by.Add (wxT ("Thierry Journet"));
        tested_by.Add (wxT ("Ada de Kamper"));
index f06670dfb222c7d2e613b48ae7055cfd41e335c3..631628e1d1d0a13163a0800107d75fe9f2a55b9c 100644 (file)
@@ -106,14 +106,6 @@ public:
                _num_local_encoding_threads = new wxSpinCtrl (panel);
                table->Add (_num_local_encoding_threads, 1);
 
-               add_label_to_sizer (table, panel, _("Maximum JPEG2000 bandwidth"), true);
-               _maximum_j2k_bandwidth = new wxSpinCtrl (panel);
-               table->Add (_maximum_j2k_bandwidth, 1);
-
-               _allow_any_dcp_frame_rate = new wxCheckBox (panel, wxID_ANY, _("Allow any DCP frame rate"));
-               table->Add (_allow_any_dcp_frame_rate, 1, wxEXPAND | wxALL);
-               table->AddSpacer (0);
-               
                add_label_to_sizer (table, panel, _("Outgoing mail server"), true);
                _mail_server = new wxTextCtrl (panel, wxID_ANY);
                table->Add (_mail_server, 1, wxEXPAND | wxALL);
@@ -171,10 +163,6 @@ public:
                _num_local_encoding_threads->SetValue (config->num_local_encoding_threads ());
                _num_local_encoding_threads->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&GeneralPage::num_local_encoding_threads_changed, this));
 
-               _maximum_j2k_bandwidth->SetRange (1, 500);
-               _maximum_j2k_bandwidth->SetValue (config->maximum_j2k_bandwidth() / 1000000);
-               _maximum_j2k_bandwidth->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&GeneralPage::maximum_j2k_bandwidth_changed, this));
-               
                _mail_server->SetValue (std_to_wx (config->mail_server ()));
                _mail_server->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&GeneralPage::mail_server_changed, this));
                _mail_user->SetValue (std_to_wx (config->mail_user ()));
@@ -187,8 +175,6 @@ public:
                _check_for_updates->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&GeneralPage::check_for_updates_changed, this));
                _check_for_test_updates->SetValue (config->check_for_test_updates ());
                _check_for_test_updates->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&GeneralPage::check_for_test_updates_changed, this));
-               _allow_any_dcp_frame_rate->SetValue (config->allow_any_dcp_frame_rate ());
-               _allow_any_dcp_frame_rate->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&GeneralPage::allow_any_dcp_frame_rate_changed, this));
                
                return panel;
        }
@@ -271,21 +257,9 @@ private:
                Config::instance()->set_num_local_encoding_threads (_num_local_encoding_threads->GetValue ());
        }
 
-       void maximum_j2k_bandwidth_changed ()
-       {
-               Config::instance()->set_maximum_j2k_bandwidth (_maximum_j2k_bandwidth->GetValue() * 1000000);
-       }
-
-       void allow_any_dcp_frame_rate_changed ()
-       {
-               Config::instance()->set_allow_any_dcp_frame_rate (_allow_any_dcp_frame_rate->GetValue ());
-       }
-       
        wxCheckBox* _set_language;
        wxChoice* _language;
        wxSpinCtrl* _num_local_encoding_threads;
-       wxSpinCtrl* _maximum_j2k_bandwidth;
-       wxCheckBox* _allow_any_dcp_frame_rate;
        wxTextCtrl* _mail_server;
        wxTextCtrl* _mail_user;
        wxTextCtrl* _mail_password;
@@ -742,6 +716,104 @@ private:
        wxTextCtrl* _kdm_email;
 };
 
+class AdvancedPage : public wxStockPreferencesPage, public Page
+{
+public:
+
+       AdvancedPage (wxSize panel_size, int border)
+               : wxStockPreferencesPage (Kind_Advanced)
+               , Page (panel_size, border)
+       {}
+       
+       wxWindow* CreateWindow (wxWindow* parent)
+       {
+               wxPanel* panel = new wxPanel (parent);
+
+               wxBoxSizer* s = new wxBoxSizer (wxVERTICAL);
+               panel->SetSizer (s);
+
+               wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
+               table->AddGrowableCol (1, 1);
+               s->Add (table, 1, wxALL | wxEXPAND, _border);
+               
+               add_label_to_sizer (table, panel, _("Maximum JPEG2000 bandwidth"), true);
+               _maximum_j2k_bandwidth = new wxSpinCtrl (panel);
+               table->Add (_maximum_j2k_bandwidth, 1);
+
+               _allow_any_dcp_frame_rate = new wxCheckBox (panel, wxID_ANY, _("Allow any DCP frame rate"));
+               table->Add (_allow_any_dcp_frame_rate, 1, wxEXPAND | wxALL);
+               table->AddSpacer (0);
+
+               add_label_to_sizer (table, panel, _("Log"), true);
+               _log_general = new wxCheckBox (panel, wxID_ANY, _("General"));
+               table->Add (_log_general, 1, wxEXPAND | wxALL);
+               _log_warning = new wxCheckBox (panel, wxID_ANY, _("Warnings"));
+               table->AddSpacer (0);
+               table->Add (_log_warning, 1, wxEXPAND | wxALL);
+               _log_error = new wxCheckBox (panel, wxID_ANY, _("Errors"));
+               table->AddSpacer (0);
+               table->Add (_log_error, 1, wxEXPAND | wxALL);
+               _log_timing = new wxCheckBox (panel, wxID_ANY, _("Timing"));
+               table->AddSpacer (0);
+               table->Add (_log_timing, 1, wxEXPAND | wxALL);
+
+               Config* config = Config::instance ();
+               
+               _maximum_j2k_bandwidth->SetRange (1, 500);
+               _maximum_j2k_bandwidth->SetValue (config->maximum_j2k_bandwidth() / 1000000);
+               _maximum_j2k_bandwidth->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&AdvancedPage::maximum_j2k_bandwidth_changed, this));
+               _allow_any_dcp_frame_rate->SetValue (config->allow_any_dcp_frame_rate ());
+               _allow_any_dcp_frame_rate->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::allow_any_dcp_frame_rate_changed, this));
+               _log_general->SetValue (config->log_types() & Log::TYPE_GENERAL);
+               _log_general->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
+               _log_warning->SetValue (config->log_types() & Log::TYPE_WARNING);
+               _log_warning->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
+               _log_error->SetValue (config->log_types() & Log::TYPE_ERROR);
+               _log_error->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
+               _log_timing->SetValue (config->log_types() & Log::TYPE_TIMING);
+               _log_timing->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
+               
+               return panel;
+       }
+
+private:
+
+       void maximum_j2k_bandwidth_changed ()
+       {
+               Config::instance()->set_maximum_j2k_bandwidth (_maximum_j2k_bandwidth->GetValue() * 1000000);
+       }
+
+       void allow_any_dcp_frame_rate_changed ()
+       {
+               Config::instance()->set_allow_any_dcp_frame_rate (_allow_any_dcp_frame_rate->GetValue ());
+       }
+
+       void log_changed ()
+       {
+               int types = 0;
+               if (_log_general->GetValue ()) {
+                       types |= Log::TYPE_GENERAL;
+               }
+               if (_log_warning->GetValue ()) {
+                       types |= Log::TYPE_WARNING;
+               }
+               if (_log_error->GetValue ())  {
+                       types |= Log::TYPE_ERROR;
+               }
+               if (_log_timing->GetValue ()) {
+                       types |= Log::TYPE_TIMING;
+               }
+               Config::instance()->set_log_types (types);
+       }
+       
+       wxSpinCtrl* _maximum_j2k_bandwidth;
+       wxCheckBox* _allow_any_dcp_frame_rate;
+       wxCheckBox* _log_general;
+       wxCheckBox* _log_warning;
+       wxCheckBox* _log_error;
+       wxCheckBox* _log_timing;
+};
+       
 wxPreferencesEditor*
 create_config_dialog ()
 {
@@ -768,5 +840,6 @@ create_config_dialog ()
        e->AddPage (new ColourConversionsPage (ps, border));
        e->AddPage (new TMSPage (ps, border));
        e->AddPage (new KDMEmailPage (ps, border));
+       e->AddPage (new AdvancedPage (ps, border));
        return e;
 }
index c20a1232402f1b4f5bc337aa9b724219d40f3fb7..a6cb77f8561cf36de0aed3594e62a5a8b058acc6 100644 (file)
@@ -275,25 +275,19 @@ FilmEditor::make_content_panel ()
                _content->InsertColumn (0, wxT(""));
                _content->SetColumnWidth (0, 512);
 
-#ifdef DCPOMATIC_OSX
-               int const pad = 2;
-#else
-               int const pad = 0;
-#endif         
-
                wxBoxSizer* b = new wxBoxSizer (wxVERTICAL);
                _content_add_file = new wxButton (_content_panel, wxID_ANY, _("Add file(s)..."));
-               b->Add (_content_add_file, 1, wxEXPAND | wxALL, pad);
+               b->Add (_content_add_file, 1, wxEXPAND | wxALL, DCPOMATIC_BUTTON_STACK_GAP);
                _content_add_folder = new wxButton (_content_panel, wxID_ANY, _("Add folder..."));
-               b->Add (_content_add_folder, 1, wxEXPAND | wxALL, pad);
+               b->Add (_content_add_folder, 1, wxEXPAND | wxALL, DCPOMATIC_BUTTON_STACK_GAP);
                _content_remove = new wxButton (_content_panel, wxID_ANY, _("Remove"));
-               b->Add (_content_remove, 1, wxEXPAND | wxALL, pad);
+               b->Add (_content_remove, 1, wxEXPAND | wxALL, DCPOMATIC_BUTTON_STACK_GAP);
                _content_earlier = new wxButton (_content_panel, wxID_ANY, _("Up"));
-               b->Add (_content_earlier, 1, wxEXPAND | wxALL, pad);
+               b->Add (_content_earlier, 1, wxEXPAND | wxALL, DCPOMATIC_BUTTON_STACK_GAP);
                _content_later = new wxButton (_content_panel, wxID_ANY, _("Down"));
-               b->Add (_content_later, 1, wxEXPAND | wxALL, pad);
+               b->Add (_content_later, 1, wxEXPAND | wxALL, DCPOMATIC_BUTTON_STACK_GAP);
                _content_timeline = new wxButton (_content_panel, wxID_ANY, _("Timeline..."));
-               b->Add (_content_timeline, 1, wxEXPAND | wxALL, pad);
+               b->Add (_content_timeline, 1, wxEXPAND | wxALL, DCPOMATIC_BUTTON_STACK_GAP);
 
                s->Add (b, 0, wxALL, 4);
 
index 5fb031324e4d9d5f649f9902b6748df0b9fc05b3..42b8297f0fc64e608c6580bbcabee6b9cce5f956 100644 (file)
@@ -22,6 +22,7 @@
 #include <wx/timectrl.h>
 #include <wx/stdpaths.h>
 #include <wx/listctrl.h>
+#include <libcxml/cxml.h>
 #include "lib/cinema.h"
 #include "lib/config.h"
 #include "lib/film.h"
@@ -40,17 +41,29 @@ using std::map;
 using std::list;
 using std::pair;
 using std::cout;
+using std::vector;
 using std::make_pair;
 using boost::shared_ptr;
 
 KDMDialog::KDMDialog (wxWindow* parent, boost::shared_ptr<const Film> film)
        : wxDialog (parent, wxID_ANY, _("Make KDMs"))
 {
+       /* Main sizer */
        wxBoxSizer* vertical = new wxBoxSizer (wxVERTICAL);
-       wxBoxSizer* targets = new wxBoxSizer (wxHORIZONTAL);
+
+       /* Font for sub-headings */
+       wxFont subheading_font (*wxNORMAL_FONT);
+       subheading_font.SetWeight (wxFONTWEIGHT_BOLD);
+
+
+       /* Sub-heading: Screens */
+       wxStaticText* h = new wxStaticText (this, wxID_ANY, _("Screens"));
+       h->SetFont (subheading_font);
+       vertical->Add (h, 0, wxALIGN_CENTER_VERTICAL);
        
+       wxBoxSizer* targets = new wxBoxSizer (wxHORIZONTAL);
        _targets = new wxTreeCtrl (this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTR_HIDE_ROOT | wxTR_MULTIPLE | wxTR_HAS_BUTTONS);
-       targets->Add (_targets, 1, wxEXPAND | wxALL, 6);
+       targets->Add (_targets, 1, wxEXPAND | wxTOP | wxRIGHT, DCPOMATIC_SIZER_GAP);
 
        _root = _targets->AddRoot ("Foo");
 
@@ -64,24 +77,30 @@ KDMDialog::KDMDialog (wxWindow* parent, boost::shared_ptr<const Film> film)
        wxBoxSizer* target_buttons = new wxBoxSizer (wxVERTICAL);
 
        _add_cinema = new wxButton (this, wxID_ANY, _("Add Cinema..."));
-       target_buttons->Add (_add_cinema, 1, wxEXPAND, 6);
+       target_buttons->Add (_add_cinema, 1, wxEXPAND | wxALL, DCPOMATIC_BUTTON_STACK_GAP);
        _edit_cinema = new wxButton (this, wxID_ANY, _("Edit Cinema..."));
-       target_buttons->Add (_edit_cinema, 1, wxEXPAND, 6);
+       target_buttons->Add (_edit_cinema, 1, wxEXPAND | wxALL, DCPOMATIC_BUTTON_STACK_GAP);
        _remove_cinema = new wxButton (this, wxID_ANY, _("Remove Cinema"));
-       target_buttons->Add (_remove_cinema, 1, wxEXPAND, 6);
+       target_buttons->Add (_remove_cinema, 1, wxEXPAND | wxALL, DCPOMATIC_BUTTON_STACK_GAP);
        
        _add_screen = new wxButton (this, wxID_ANY, _("Add Screen..."));
-       target_buttons->Add (_add_screen, 1, wxEXPAND, 6);
+       target_buttons->Add (_add_screen, 1, wxEXPAND | wxALL, DCPOMATIC_BUTTON_STACK_GAP);
        _edit_screen = new wxButton (this, wxID_ANY, _("Edit Screen..."));
-       target_buttons->Add (_edit_screen, 1, wxEXPAND, 6);
+       target_buttons->Add (_edit_screen, 1, wxEXPAND | wxALL, DCPOMATIC_BUTTON_STACK_GAP);
        _remove_screen = new wxButton (this, wxID_ANY, _("Remove Screen"));
-       target_buttons->Add (_remove_screen, 1, wxEXPAND, 6);
+       target_buttons->Add (_remove_screen, 1, wxEXPAND | wxALL, DCPOMATIC_BUTTON_STACK_GAP);
+
+       targets->Add (target_buttons, 0, 0);
 
-       targets->Add (target_buttons, 0, 0, 6);
+       vertical->Add (targets, 1, wxEXPAND);
 
-       vertical->Add (targets, 1, wxEXPAND | wxALL, 6);
 
-       wxFlexGridSizer* table = new wxFlexGridSizer (3, 2, 6);
+       /* Sub-heading: Timing */
+       h = new wxStaticText (this, wxID_ANY, _("Timing"));
+       h->SetFont (subheading_font);
+       vertical->Add (h, 0, wxALIGN_CENTER_VERTICAL | wxTOP, DCPOMATIC_SIZER_Y_GAP * 2);
+       
+       wxFlexGridSizer* table = new wxFlexGridSizer (3, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
        add_label_to_sizer (table, this, _("From"), true);
        wxDateTime from;
        from.SetToCurrent ();
@@ -99,30 +118,46 @@ KDMDialog::KDMDialog (wxWindow* parent, boost::shared_ptr<const Film> film)
        _until_time = new wxTimePickerCtrl (this, wxID_ANY, to);
        table->Add (_until_time, 1, wxEXPAND);
 
-       vertical->Add (table, 0, wxEXPAND | wxALL, 6);
+       vertical->Add (table, 0, wxEXPAND | wxTOP, DCPOMATIC_SIZER_GAP);
+
 
-       _dcps = new wxListCtrl (this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_REPORT | wxLC_SINGLE_SEL);
-       wxListItem ip;
-       ip.SetId (0);
-       ip.SetText (_("DCP"));
-       ip.SetWidth (400);
-       _dcps->InsertColumn (0, ip);
-       vertical->Add (_dcps, 0, wxEXPAND | wxALL, 6);
+       /* Sub-heading: CPL */
+       h = new wxStaticText (this, wxID_ANY, _("CPL"));
+       h->SetFont (subheading_font);
+       vertical->Add (h, 0, wxALIGN_CENTER_VERTICAL | wxTOP, DCPOMATIC_SIZER_Y_GAP * 2);
        
-       list<boost::filesystem::path> dcps = film->dcps ();
-       for (list<boost::filesystem::path>::const_iterator i = dcps.begin(); i != dcps.end(); ++i) {
-               wxListItem item;
-               int const n = _dcps->GetItemCount ();
-               item.SetId (n);
-               _dcps->InsertItem (item);
-               _dcps->SetItem (n, 0, std_to_wx (i->string ()));
-
-               if (dcps.size() == 1 || i->string() == film->dcp_name ()) {
-                       _dcps->SetItemState (n, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
-               }
-       }
+       /* CPL choice */
+       wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
+       add_label_to_sizer (s, this, _("CPL"), true);
+       _cpl = new wxChoice (this, wxID_ANY);
+       s->Add (_cpl, 1, wxEXPAND);
+       _cpl_browse = new wxButton (this, wxID_ANY, _("Browse..."));
+       s->Add (_cpl_browse, 0);
+       vertical->Add (s, 0, wxEXPAND | wxTOP, DCPOMATIC_SIZER_GAP + 2);
+
+       /* CPL details */
+       table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
+       add_label_to_sizer (table, this, _("DCP directory"), true);
+       _dcp_directory = new wxStaticText (this, wxID_ANY, "");
+       table->Add (_dcp_directory);
+       add_label_to_sizer (table, this, _("CPL ID"), true);
+       _cpl_id = new wxStaticText (this, wxID_ANY, "");
+       table->Add (_cpl_id);
+       add_label_to_sizer (table, this, _("CPL annotation text"), true);
+       _cpl_annotation_text = new wxStaticText (this, wxID_ANY, "");
+       table->Add (_cpl_annotation_text);
+       vertical->Add (table, 0, wxEXPAND | wxTOP, DCPOMATIC_SIZER_GAP + 2);
+       
+       _cpls = film->cpls ();
+       update_cpl_choice ();
        
-       table = new wxFlexGridSizer (2, 2, 6);
+
+       /* Sub-heading: Output */
+       h = new wxStaticText (this, wxID_ANY, _("Output"));
+       h->SetFont (subheading_font);
+       vertical->Add (h, 0, wxALIGN_CENTER_VERTICAL | wxTOP, DCPOMATIC_SIZER_Y_GAP * 2);
+       
+       table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, 0);
 
        _write_to = new wxRadioButton (this, wxID_ANY, _("Write to"));
        table->Add (_write_to, 1, wxEXPAND);
@@ -141,15 +176,22 @@ KDMDialog::KDMDialog (wxWindow* parent, boost::shared_ptr<const Film> film)
        table->Add (_email, 1, wxEXPAND);
        table->AddSpacer (0);
        
-       vertical->Add (table, 0, wxEXPAND | wxALL, 6);
+       vertical->Add (table, 0, wxEXPAND | wxTOP, DCPOMATIC_SIZER_GAP);
+
+       /* Make an overall sizer to get a nice border, and put some buttons in */
+
+       wxBoxSizer* overall_sizer = new wxBoxSizer (wxVERTICAL);
+       overall_sizer->Add (vertical, 0, wxEXPAND | wxTOP | wxLEFT | wxRIGHT, DCPOMATIC_DIALOG_BORDER);
 
        wxSizer* buttons = CreateSeparatedButtonSizer (wxOK | wxCANCEL);
        if (buttons) {
-               vertical->Add (buttons, wxSizerFlags().Expand().DoubleBorder());
+               overall_sizer->Add (buttons, 0, wxEXPAND | wxTOP, DCPOMATIC_SIZER_Y_GAP);
        }
 
        _write_to->SetValue (true);
 
+       /* Bind */
+
        _targets->Bind       (wxEVT_COMMAND_TREE_SEL_CHANGED, boost::bind (&KDMDialog::setup_sensitivity, this));
 
        _add_cinema->Bind    (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KDMDialog::add_cinema_clicked, this));
@@ -160,17 +202,17 @@ KDMDialog::KDMDialog (wxWindow* parent, boost::shared_ptr<const Film> film)
        _edit_screen->Bind   (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KDMDialog::edit_screen_clicked, this));
        _remove_screen->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KDMDialog::remove_screen_clicked, this));
 
-       _dcps->Bind          (wxEVT_COMMAND_LIST_ITEM_SELECTED,   boost::bind (&KDMDialog::setup_sensitivity, this));
-       _dcps->Bind          (wxEVT_COMMAND_LIST_ITEM_DESELECTED, boost::bind (&KDMDialog::setup_sensitivity, this));
+       _cpl->Bind           (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&KDMDialog::update_cpl_summary, this));
+       _cpl_browse->Bind    (wxEVT_COMMAND_BUTTON_CLICKED,  boost::bind (&KDMDialog::cpl_browse_clicked, this));
 
        _write_to->Bind      (wxEVT_COMMAND_RADIOBUTTON_SELECTED, boost::bind (&KDMDialog::setup_sensitivity, this));
        _email->Bind         (wxEVT_COMMAND_RADIOBUTTON_SELECTED, boost::bind (&KDMDialog::setup_sensitivity, this));
 
        setup_sensitivity ();
-       
-       SetSizer (vertical);
-       vertical->Layout ();
-       vertical->SetSizeHints (this);
+
+       SetSizer (overall_sizer);
+       overall_sizer->Layout ();
+       overall_sizer->SetSizeHints (this);
 }
 
 list<pair<wxTreeItemId, shared_ptr<Cinema> > >
@@ -212,7 +254,7 @@ KDMDialog::setup_sensitivity ()
 {
        bool const sc = selected_cinemas().size() == 1;
        bool const ss = selected_screens().size() == 1;
-       bool const sd = _dcps->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED) != -1;
+       bool const sd = _cpl->GetSelection() != -1;
        
        _edit_cinema->Enable (sc);
        _remove_cinema->Enable (sc);
@@ -419,11 +461,11 @@ KDMDialog::until () const
 }
 
 boost::filesystem::path
-KDMDialog::dcp () const
+KDMDialog::cpl () const
 {
-       int const item = _dcps->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
+       int const item = _cpl->GetSelection ();
        assert (item >= 0);
-       return wx_to_std (_dcps->GetItemText (item));
+       return _cpls[item].cpl_file;
 }
 
 boost::filesystem::path
@@ -437,3 +479,66 @@ KDMDialog::write_to () const
 {
        return _write_to->GetValue ();
 }
+
+void
+KDMDialog::update_cpl_choice ()
+{
+       _cpl->Clear ();
+       
+       for (vector<CPLSummary>::const_iterator i = _cpls.begin(); i != _cpls.end(); ++i) {
+               _cpl->Append (std_to_wx (i->cpl_id));
+
+               if (_cpls.size() > 0) {
+                       _cpl->SetSelection (0);
+               }
+       }
+
+       update_cpl_summary ();
+}
+
+void
+KDMDialog::update_cpl_summary ()
+{
+       int const n = _cpl->GetSelection();
+       if (n == wxNOT_FOUND) {
+               return;
+       }
+
+       _dcp_directory->SetLabel (std_to_wx (_cpls[n].dcp_directory));
+       _cpl_id->SetLabel (std_to_wx (_cpls[n].cpl_id));
+       _cpl_annotation_text->SetLabel (std_to_wx (_cpls[n].cpl_annotation_text));
+}
+
+void
+KDMDialog::cpl_browse_clicked ()
+{
+       wxFileDialog d (this, _("Select CPL XML file"), wxEmptyString, wxEmptyString, "*.xml");
+       if (d.ShowModal() == wxID_CANCEL) {
+               return;
+       }
+
+       boost::filesystem::path cpl_file (wx_to_std (d.GetPath ()));
+       boost::filesystem::path dcp_dir = cpl_file.parent_path ();
+
+       /* XXX: hack alert */
+       cxml::Document cpl_document ("CompositionPlaylist");
+       cpl_document.read_file (cpl_file);
+
+       try {
+               _cpls.push_back (
+                       CPLSummary (
+                               dcp_dir.filename().string(),
+                               cpl_document.string_child("Id").substr (9),
+                               cpl_document.string_child ("ContentTitleText"),
+                               cpl_file
+                               )
+                       );
+       } catch (cxml::Error) {
+               error_dialog (this, _("This is not a valid CPL file"));
+               return;
+       }
+       
+       update_cpl_choice ();
+       _cpl->SetSelection (_cpls.size() - 1);
+       update_cpl_summary ();
+}
index db51d6d0380baf0dba4c8f510d5625396cac0c46..6327b29e8d1b84db982a3529b499da97150b31b3 100644 (file)
@@ -45,7 +45,7 @@ public:
        /** @return KDM until time in local time */
        boost::posix_time::ptime until () const;
        
-       boost::filesystem::path dcp () const;
+       boost::filesystem::path cpl () const;
        boost::filesystem::path directory () const;
        bool write_to () const;
 
@@ -61,6 +61,9 @@ private:
        std::list<std::pair<wxTreeItemId, boost::shared_ptr<Cinema> > > selected_cinemas () const;
        std::list<std::pair<wxTreeItemId, boost::shared_ptr<Screen> > > selected_screens () const;
        void setup_sensitivity ();
+       void update_cpl_choice ();
+       void update_cpl_summary ();
+       void cpl_browse_clicked ();
 
        static boost::posix_time::ptime posix_time (wxDatePickerCtrl *, wxTimePickerCtrl *);
        
@@ -75,7 +78,11 @@ private:
        wxDatePickerCtrl* _until_date;
        wxTimePickerCtrl* _from_time;
        wxTimePickerCtrl* _until_time;
-       wxListCtrl* _dcps;
+       wxChoice* _cpl;
+       wxButton* _cpl_browse;
+       wxStaticText* _dcp_directory;
+       wxStaticText* _cpl_id;
+       wxStaticText* _cpl_annotation_text;
        wxRadioButton* _write_to;
 #ifdef DCPOMATIC_USE_OWN_DIR_PICKER
        DirPickerCtrl* _folder;
@@ -87,4 +94,5 @@ private:
        wxTreeItemId _root;
        std::map<wxTreeItemId, boost::shared_ptr<Cinema> > _cinemas;
        std::map<wxTreeItemId, boost::shared_ptr<Screen> > _screens;
+       std::vector<CPLSummary> _cpls;
 };
index 5855411501f8b3be074be3a29e95f6317e322e4c..56ed500f6887974a2e0c1f7af60bef4ca43fcdff 100644 (file)
@@ -35,8 +35,16 @@ class wxGridBagSizer;
 
 #define DCPOMATIC_SIZER_X_GAP 8
 #define DCPOMATIC_SIZER_Y_GAP 8
+#define DCPOMATIC_SIZER_GAP 8
 #define DCPOMATIC_DIALOG_BORDER 12
 
+/** Spacing to use between buttons in a vertical line */
+#ifdef DCPOMATIC_OSX
+#define DCPOMATIC_BUTTON_STACK_GAP 2
+#else
+#define DCPOMATIC_BUTTON_STACK_GAP 0
+#endif
+
 /** @file src/wx/wx_util.h
  *  @brief Some utility functions and classes.
  */
index 8e4fb0e1867e845e644864012eae8812b2468183..c0eddd8f6a7f8eee16dcbbef3d27119a2cf45898 100644 (file)
@@ -78,9 +78,11 @@ BOOST_AUTO_TEST_CASE (client_server_test)
                p += sub_image->stride()[0];
        }
 
+       shared_ptr<FileLog> log (new FileLog ("build/test/client_server_test.log"));
+
        shared_ptr<PlayerVideoFrame> pvf (
                new PlayerVideoFrame (
-                       shared_ptr<ImageProxy> (new RawImageProxy (image)),
+                       shared_ptr<ImageProxy> (new RawImageProxy (image, log)),
                        Crop (),
                        dcp::Size (1998, 1080),
                        dcp::Size (1998, 1080),
@@ -93,8 +95,6 @@ BOOST_AUTO_TEST_CASE (client_server_test)
 
        pvf->set_subtitle (PositionImage (sub_image, Position<int> (50, 60)));
 
-       shared_ptr<FileLog> log (new FileLog ("build/test/client_server_test.log"));
-
        shared_ptr<DCPVideoFrame> frame (
                new DCPVideoFrame (
                        pvf,
index 1c897bcd93a90bc158fcbbb9232debe7e72a1529..234bf2c79b10bd8dafc5e74f71d2a36c98c22d3e 100644 (file)
@@ -51,16 +51,16 @@ BOOST_AUTO_TEST_CASE (ffmpeg_dcp_test)
        wait_for_jobs ();
 }
 
-/** Test Film::have_dcp().  Requires the output from ffmpeg_dcp_test above */
+/** Briefly test Film::cpls().  Requires the output from ffmpeg_dcp_test above */
 BOOST_AUTO_TEST_CASE (ffmpeg_have_dcp_test)
 {
        boost::filesystem::path p = test_film_dir ("ffmpeg_dcp_test");
        shared_ptr<Film> f (new Film (p.string ()));
        f->read_metadata ();
-       BOOST_CHECK (!f->dcps().empty());
+       BOOST_CHECK (!f->cpls().empty());
 
        p /= f->dcp_name();
        p /= f->video_mxf_filename();
        boost::filesystem::remove (p);
-       BOOST_CHECK (f->dcps().empty());
+       BOOST_CHECK (f->cpls().empty());
 }