Merge master.
authorCarl Hetherington <cth@carlh.net>
Thu, 26 Jun 2014 22:36:24 +0000 (23:36 +0100)
committerCarl Hetherington <cth@carlh.net>
Thu, 26 Jun 2014 22:36:24 +0000 (23:36 +0100)
30 files changed:
1  2 
ChangeLog
cscript
src/lib/encoder.cc
src/lib/encoder.h
src/lib/film.cc
src/lib/film.h
src/lib/image.cc
src/lib/kdm.cc
src/lib/kdm.h
src/lib/playlist.cc
src/lib/playlist.h
src/lib/send_kdm_email_job.cc
src/lib/send_kdm_email_job.h
src/lib/server.cc
src/lib/server.h
src/lib/util.h
src/lib/video_content.cc
src/lib/video_content.h
src/lib/writer.cc
src/tools/dcpomatic.cc
src/tools/dcpomatic_kdm.cc
src/wx/about_dialog.cc
src/wx/kdm_dialog.cc
src/wx/kdm_dialog.h
src/wx/timeline.cc
src/wx/timeline.h
src/wx/timing_panel.cc
src/wx/wscript
test/make_black_test.cc
wscript

diff --cc ChangeLog
index e8978daec22e180af55e5241064a234c25ee5c15,14032c101b52cf8100d6c00289940a29fe8d9aa1..cb4d1c3c7d74511b0e682af494b31f1dfc8bb1c6
+++ b/ChangeLog
@@@ -1,9 -1,40 +1,44 @@@
 +2014-03-07  Carl Hetherington  <cth@carlh.net>
 +
 +      * Add subtitle view.
 +
+ 2014-06-26  Carl Hetherington  <cth@carlh.net>
+       * Version 1.70.1 released.
+ 2014-06-26  Carl Hetherington  <cth@carlh.net>
+       * Support different KDM formulations.
+       * Allow override of detected video frame rates.
+       * Optimisation of uncertain effect to encoder and server
+       thread handling.
+       * Version 1.70.0 released.
+ 2014-06-25  Carl Hetherington  <cth@carlh.net>
+       * Version 1.69.37 released.
+ 2014-06-25  Carl Hetherington  <cth@carlh.net>
+       * Version 1.69.36 released.
+ 2014-06-25  Carl Hetherington  <cth@carlh.net>
+       * Support pixel format 46 in make_black().
+ 2014-06-24  Carl Hetherington  <cth@carlh.net>
+       * Re-assign timeline tracks when things are
+       moved about.
  2014-06-23  Carl Hetherington  <cth@carlh.net>
  
+       * Try harder to cope with DCP names specified
+       already in CamelCase.
        * Add option to CC a KDM email, and add
        $SCREENS and $CINEMA_NAME as variables
        in the email.
diff --cc cscript
Simple merge
index 5dc9e47c772cb7ec0e7c13a91b332c54bce63307,02a2710290f5c8ef6656fd3a49497dc65dbc45bc..0756586a91d54101ce89ba61d41f4cca2f3790f6
@@@ -215,16 -222,16 +215,19 @@@ Encoder::process_video (shared_ptr<Play
                LOG_TIMING ("adding to queue of %1", _queue.size ());
                _queue.push_back (shared_ptr<DCPVideoFrame> (
                                          new DCPVideoFrame (
 -                                                pvf, _video_frames_out, _film->video_frame_rate(),
 -                                                _film->j2k_bandwidth(), _film->resolution(), _film->log()
 +                                                pvf,
 +                                                _video_frames_out,
 +                                                _film->video_frame_rate(),
 +                                                _film->j2k_bandwidth(),
 +                                                _film->resolution(),
 +                                                _film->log()
                                                  )
                                          ));
-               
-               _condition.notify_all ();
+               /* The queue might not be empty any more, so notify anything which is
+                  waiting on that.
+               */
+               _empty_condition.notify_all ();
 -              _have_a_real_frame[pvf->eyes()] = true;
        }
  
        if (pvf->eyes() != EYES_LEFT) {
Simple merge
diff --cc src/lib/film.cc
index b01a70b7277789958ea2452687d7411ac82d254a,0a77caf502cc4405695a84c6db8aec6fa9f23387..1456314bebb58a700181947a3260283ff80e7017
@@@ -77,9 -77,10 +77,11 @@@ using boost::to_upper_copy
  using boost::ends_with;
  using boost::starts_with;
  using boost::optional;
 -using libdcp::Size;
 -using libdcp::Signer;
 -using libdcp::raw_convert;
+ using boost::is_any_of;
 +using dcp::Size;
 +using dcp::Signer;
 +using dcp::raw_convert;
++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);
@@@ -829,7 -864,7 +854,7 @@@ Film::j2c_path (int f, Eyes e, bool t) 
        return file (p);
  }
  
--/** Find all the DCPs in our directory that can be libdcp::DCP::read() and return details of their CPLs */
++/** Find all the DCPs in our directory that can be dcp::DCP::read() and return details of their CPLs */
  vector<CPLSummary>
  Film::cpls () const
  {
@@@ -1022,32 -1078,40 +1047,34 @@@ Film::frame_size () cons
        return fit_ratio_within (container()->ratio(), full_frame ());
  }
  
 -/** @param from KDM from time in local time.
 - *  @param to KDM to time in local time.
 - */
 -libdcp::KDM
 +dcp::EncryptedKDM
  Film::make_kdm (
 -      shared_ptr<libdcp::Certificate> target,
 +      shared_ptr<dcp::Certificate> target,
        boost::filesystem::path cpl_file,
 -      boost::posix_time::ptime from,
 -      boost::posix_time::ptime until,
 -      libdcp::KDM::Formulation formulation
 +      dcp::LocalTime from,
-       dcp::LocalTime until
++      dcp::LocalTime until,
++      dcp::Formulation formulation
        ) const
  {
 -      shared_ptr<const Signer> signer = make_signer ();
 -
 -      time_t now = time (0);
 -      struct tm* tm = localtime (&now);
 -      string const issue_date = libdcp::tm_to_string (tm);
 -      
 -      return libdcp::KDM (cpl_file, signer, target, key (), from, until, "DCP-o-matic", issue_date, formulation);
 +      shared_ptr<const dcp::CPL> cpl (new dcp::CPL (cpl_file));
 +      return dcp::DecryptedKDM (
 +              cpl, from, until, "DCP-o-matic", cpl->content_title_text(), dcp::LocalTime().as_string()
-               ).encrypt (make_signer(), target);
++              ).encrypt (make_signer(), target, formulation);
  }
  
 -list<libdcp::KDM>
 +list<dcp::EncryptedKDM>
  Film::make_kdms (
        list<shared_ptr<Screen> > screens,
        boost::filesystem::path dcp,
 -      boost::posix_time::ptime from,
 -      boost::posix_time::ptime until,
 -      libdcp::KDM::Formulation formulation
 +      dcp::LocalTime from,
-       dcp::LocalTime until
++      dcp::LocalTime until,
++      dcp::Formulation formulation
        ) const
  {
 -      list<libdcp::KDM> kdms;
 +      list<dcp::EncryptedKDM> kdms;
  
        for (list<shared_ptr<Screen> >::iterator i = screens.begin(); i != screens.end(); ++i) {
-               kdms.push_back (make_kdm ((*i)->certificate, dcp, from, until));
+               kdms.push_back (make_kdm ((*i)->certificate, dcp, from, until, formulation));
        }
  
        return kdms;
diff --cc src/lib/film.h
index a44c606d680af9b60eb0f4b3e5bc642f6b8d013c,b7d105688d06c2a1bf644544fb43aff9e9fd9c37..178fd9002d18cff8b586790d5d14c473e796374b
@@@ -114,26 -118,29 +114,28 @@@ public
        /* Proxies for some Playlist methods */
  
        ContentList content () const;
 -      Time length () const;
 -      bool has_subtitles () const;
 -      OutputVideoFrame best_video_frame_rate () const;
 -      FrameRateChange active_frame_rate_change (Time) const;
 +      DCPTime length () const;
 +      int best_video_frame_rate () const;
 +      FrameRateChange active_frame_rate_change (DCPTime) const;
  
 -      libdcp::KDM
 +      dcp::EncryptedKDM
        make_kdm (
 -              boost::shared_ptr<libdcp::Certificate> target,
 +              boost::shared_ptr<dcp::Certificate> target,
                boost::filesystem::path cpl_file,
 -              boost::posix_time::ptime from,
 -              boost::posix_time::ptime until,
 -              libdcp::KDM::Formulation formulation
 +              dcp::LocalTime from,
-               dcp::LocalTime until
++              dcp::LocalTime until,
++              dcp::Formulation formulation
                ) const;
        
 -      std::list<libdcp::KDM> make_kdms (
 +      std::list<dcp::EncryptedKDM> make_kdms (
                std::list<boost::shared_ptr<Screen> >,
                boost::filesystem::path cpl_file,
 -              boost::posix_time::ptime from,
 -              boost::posix_time::ptime until,
 -              libdcp::KDM::Formulation formulation
 +              dcp::LocalTime from,
-               dcp::LocalTime until
++              dcp::LocalTime until,
++              dcp::Formulation formulation
                ) const;
  
 -      libdcp::Key key () const {
 +      dcp::Key key () const {
                return _key;
        }
  
Simple merge
diff --cc src/lib/kdm.cc
index 5754fd469f3be91f44a00590932ef36a98280d7d,49bfae20ad727c36d62d057582c943c2edc9ac8c..dd2b756c19e79184b25cec9b95bed3e4a6540adc
@@@ -21,7 -21,7 +21,8 @@@
  #include <boost/shared_ptr.hpp>
  #include <quickmail.h>
  #include <zip.h>
 -#include <libdcp/kdm.h>
 +#include <dcp/encrypted_kdm.h>
++#include <dcp/types.h>
  #include "kdm.h"
  #include "cinema.h"
  #include "exceptions.h"
@@@ -104,11 -104,12 +105,12 @@@ make_screen_kdms 
        shared_ptr<const Film> film,
        list<shared_ptr<Screen> > screens,
        boost::filesystem::path cpl,
 -      boost::posix_time::ptime from,
 -      boost::posix_time::ptime to,
 -      libdcp::KDM::Formulation formulation
 +      dcp::LocalTime from,
-       dcp::LocalTime to
++      dcp::LocalTime to,
++      dcp::Formulation formulation
        )
  {
-       list<dcp::EncryptedKDM> kdms = film->make_kdms (screens, cpl, from, to);
 -      list<libdcp::KDM> kdms = film->make_kdms (screens, cpl, from, to, formulation);
++      list<dcp::EncryptedKDM> kdms = film->make_kdms (screens, cpl, from, to, formulation);
           
        list<ScreenKDM> screen_kdms;
        
@@@ -128,11 -129,12 +130,12 @@@ make_cinema_kdms 
        shared_ptr<const Film> film,
        list<shared_ptr<Screen> > screens,
        boost::filesystem::path cpl,
 -      boost::posix_time::ptime from,
 -      boost::posix_time::ptime to,
 -      libdcp::KDM::Formulation formulation
 +      dcp::LocalTime from,
-       dcp::LocalTime to
++      dcp::LocalTime to,
++      dcp::Formulation formulation
        )
  {
-       list<ScreenKDM> screen_kdms = make_screen_kdms (film, screens, cpl, from, to);
+       list<ScreenKDM> screen_kdms = make_screen_kdms (film, screens, cpl, from, to, formulation);
        list<CinemaKDMs> cinema_kdms;
  
        while (!screen_kdms.empty ()) {
@@@ -173,8 -175,9 +176,9 @@@ write_kdm_files 
        shared_ptr<const Film> film,
        list<shared_ptr<Screen> > screens,
        boost::filesystem::path cpl,
 -      boost::posix_time::ptime from,
 -      boost::posix_time::ptime to,
 -      libdcp::KDM::Formulation formulation,
 +      dcp::LocalTime from,
 +      dcp::LocalTime to,
++      dcp::Formulation formulation,
        boost::filesystem::path directory
        )
  {
@@@ -193,8 -196,9 +197,9 @@@ write_kdm_zip_files 
        shared_ptr<const Film> film,
        list<shared_ptr<Screen> > screens,
        boost::filesystem::path cpl,
 -      boost::posix_time::ptime from,
 -      boost::posix_time::ptime to,
 -      libdcp::KDM::Formulation formulation,
 +      dcp::LocalTime from,
 +      dcp::LocalTime to,
++      dcp::Formulation formulation,
        boost::filesystem::path directory
        )
  {
@@@ -212,11 -216,12 +217,12 @@@ email_kdms 
        shared_ptr<const Film> film,
        list<shared_ptr<Screen> > screens,
        boost::filesystem::path cpl,
 -      boost::posix_time::ptime from,
 -      boost::posix_time::ptime to,
 -      libdcp::KDM::Formulation formulation
 +      dcp::LocalTime from,
-       dcp::LocalTime to
++      dcp::LocalTime to,
++      dcp::Formulation formulation
        )
  {
-       list<CinemaKDMs> cinema_kdms = make_cinema_kdms (film, screens, cpl, from, to);
+       list<CinemaKDMs> cinema_kdms = make_cinema_kdms (film, screens, cpl, from, to, formulation);
  
        for (list<CinemaKDMs>::const_iterator i = cinema_kdms.begin(); i != cinema_kdms.end(); ++i) {
                
diff --cc src/lib/kdm.h
index 023107a826875f169c4e1c780ee9666ba366eefc,8fb4ec494d2e2a52866e8fe68d1cc5a2ff92766a..b80ef454f2ddc2b3092b19bb55783f5f63aa5c01
@@@ -27,8 -27,9 +27,9 @@@ extern void write_kdm_files 
        boost::shared_ptr<const Film> film,
        std::list<boost::shared_ptr<Screen> > screens,
        boost::filesystem::path cpl,
 -      boost::posix_time::ptime from,
 -      boost::posix_time::ptime to,
 -      libdcp::KDM::Formulation formulation,
 +      dcp::LocalTime from,
 +      dcp::LocalTime to,
++      dcp::Formulation formulation,
        boost::filesystem::path directory
        );
  
@@@ -36,8 -37,9 +37,9 @@@ extern void write_kdm_zip_files 
        boost::shared_ptr<const Film> film,
        std::list<boost::shared_ptr<Screen> > screens,
        boost::filesystem::path cpl,
 -      boost::posix_time::ptime from,
 -      boost::posix_time::ptime to,
 -      libdcp::KDM::Formulation formulation,
 +      dcp::LocalTime from,
 +      dcp::LocalTime to,
++      dcp::Formulation formulation,
        boost::filesystem::path directory
        );
  
@@@ -45,7 -47,8 +47,8 @@@ extern void email_kdms 
        boost::shared_ptr<const Film> film,
        std::list<boost::shared_ptr<Screen> > screens,
        boost::filesystem::path cpl,
 -      boost::posix_time::ptime from,
 -      boost::posix_time::ptime to,
 -      libdcp::KDM::Formulation formulation
 +      dcp::LocalTime from,
-       dcp::LocalTime to
++      dcp::LocalTime to,
++      dcp::Formulation formulation
        );
  
index 1c268ca110a90a42f7997e94d46ffd1a13ff4483,e847e623baf00d9f73150cc005c6e074dca4f4e6..710b9cc099ea5a9e96f6118f836c9ff1ab8c1cc9
@@@ -398,6 -392,21 +396,4 @@@ Playlist::move_later (shared_ptr<Conten
        (*next)->set_position (c->position ());
        c->set_position (p + c->length_after_trim ());
        sort (_content.begin(), _content.end(), ContentSorter ());
-       
-       Changed ();
  }
 -
 -FrameRateChange
 -Playlist::active_frame_rate_change (Time t, int dcp_video_frame_rate) const
 -{
 -      for (ContentList::const_iterator i = _content.begin(); i != _content.end(); ++i) {
 -              shared_ptr<const VideoContent> vc = dynamic_pointer_cast<const VideoContent> (*i);
 -              if (!vc) {
 -                      continue;
 -              }
 -
 -              if (vc->position() >= t && t < vc->end()) {
 -                      return FrameRateChange (vc->video_frame_rate(), dcp_video_frame_rate);
 -              }
 -      }
 -
 -      return FrameRateChange (dcp_video_frame_rate, dcp_video_frame_rate);
 -}
Simple merge
index 8af0b556a13e7f1a5ceffcc066e9c02d0038c04d,1dec2ffb001dc7ce77fdfd4d1c595e8646bb90c9..de03222725074b9a6a9fdfa670a463de0f88f396
@@@ -33,7 -33,8 +33,8 @@@ SendKDMEmailJob::SendKDMEmailJob 
        list<shared_ptr<Screen> > screens,
        boost::filesystem::path dcp,
        boost::posix_time::ptime from,
-       boost::posix_time::ptime to
+       boost::posix_time::ptime to,
 -      libdcp::KDM::Formulation formulation
++      dcp::Formulation formulation
        )
        : Job (f)
        , _screens (screens)
index f4d154a9183b227dc897c97c5660f9f04aef3114,8a8903040c06b573815fe2d3be9b999fa90c47b1..084836715f865fe6a62b52eae1e7ac1536bd202f
@@@ -18,6 -18,7 +18,7 @@@
  */
  
  #include <boost/filesystem.hpp>
 -#include <libdcp/kdm.h>
++#include <dcp/types.h>
  #include "job.h"
  
  class Screen;
@@@ -30,7 -31,8 +31,8 @@@ public
                std::list<boost::shared_ptr<Screen> >,
                boost::filesystem::path,
                boost::posix_time::ptime,
-               boost::posix_time::ptime
+               boost::posix_time::ptime,
 -              libdcp::KDM::Formulation
++              dcp::Formulation
                );
  
        std::string name () const;
@@@ -42,4 -44,5 +44,5 @@@ private
        boost::filesystem::path _dcp;
        boost::posix_time::ptime _from;
        boost::posix_time::ptime _to;
 -      libdcp::KDM::Formulation _formulation;
++      dcp::Formulation _formulation;
  };
index 66ee2b0e3cf2ca93eeb7512a03763c2598836dcc,7450fd12e476324c190b9b93aa9e68b1e0ac4c35..fe792e307424501b2c8a6df845c4b202f01d1504
@@@ -74,25 -72,6 +74,25 @@@ Server::Server (shared_ptr<Log> log, bo
  
  }
  
-               _worker_condition.notify_all ();
 +Server::~Server ()
 +{
 +      {
 +              boost::mutex::scoped_lock lm (_worker_mutex);
 +              _terminate = true;
++              _empty_condition.notify_all ();
 +      }
 +
 +      for (vector<boost::thread*>::iterator i = _worker_threads.begin(); i != _worker_threads.end(); ++i) {
 +              (*i)->join ();
 +              delete *i;
 +      }
 +
 +      _io_service.stop ();
 +
 +      _broadcast.io_service.stop ();
 +      _broadcast.thread->join ();
 +}
 +
  /** @param after_read Filled in with gettimeofday() after reading the input from the network.
   *  @param after_encode Filled in with gettimeofday() after encoding the image.
   */
@@@ -138,14 -117,10 +138,14 @@@ Server::worker_thread (
  {
        while (1) {
                boost::mutex::scoped_lock lock (_worker_mutex);
 -              while (_queue.empty ()) {
 +              while (_queue.empty () && !_terminate) {
-                       _worker_condition.wait (lock);
+                       _empty_condition.wait (lock);
                }
  
 +              if (_terminate) {
 +                      return;
 +              }
 +
                shared_ptr<Socket> socket = _queue.front ();
                _queue.pop_front ();
                
@@@ -268,35 -264,3 +268,35 @@@ Server::broadcast_received (
                _broadcast.send_endpoint, boost::bind (&Server::broadcast_received, this)
                );
  }
-               _worker_condition.wait (lock);
 +
 +void
 +Server::start_accept ()
 +{
 +      if (_terminate) {
 +              return;
 +      }
 +
 +      shared_ptr<Socket> socket (new Socket);
 +      _acceptor.async_accept (socket->socket (), boost::bind (&Server::handle_accept, this, socket, boost::asio::placeholders::error));
 +}
 +
 +void
 +Server::handle_accept (shared_ptr<Socket> socket, boost::system::error_code const & error)
 +{
 +      if (error) {
 +              return;
 +      }
 +
 +      boost::mutex::scoped_lock lock (_worker_mutex);
 +      
 +      /* Wait until the queue has gone down a bit */
 +      while (_queue.size() >= _worker_threads.size() * 2 && !_terminate) {
-       _worker_condition.notify_all ();
++              _full_condition.wait (lock);
 +      }
 +      
 +      _queue.push_back (socket);
++      _empty_condition.notify_all ();
 +
 +      start_accept ();
 +}
 +      
Simple merge
diff --cc src/lib/util.h
index 7d3afb022856e963ee870b9b323b82c8ff235c5c,70bf495c682c42332ea22bf5294497c243ad5276..094d57f40ee21ab741e5b6afdf9d6dfeae92d424
@@@ -48,7 -47,7 +48,7 @@@ extern "C" 
  
  #define DCPOMATIC_HELLO "Boys, you gotta learn not to talk to nuns that way"
  
--namespace libdcp {
++namespace dcp {
        class Signer;
  }
  
Simple merge
Simple merge
Simple merge
index 237fa4e58ee311f1882d4bbe46ade60b707ceac4,588fd5c486da54bd037cf2228bcaa05ceac4c448..1fb7feb7de2a8da436650af4f78de93be7101c57
@@@ -470,13 -470,13 +470,13 @@@ private
  
                try {
                        if (d->write_to ()) {
-                               write_kdm_files (film, d->screens (), d->cpl (), d->from (), d->until (), d->directory ());
+                               write_kdm_files (film, d->screens (), d->cpl (), d->from (), d->until (), d->formulation (), d->directory ());
                        } else {
                                JobManager::instance()->add (
-                                       shared_ptr<Job> (new SendKDMEmailJob (film, d->screens (), d->cpl (), d->from (), d->until ()))
+                                       shared_ptr<Job> (new SendKDMEmailJob (film, d->screens (), d->cpl (), d->from (), d->until (), d->formulation ()))
                                        );
                        }
 -              } catch (libdcp::NotEncryptedError& e) {
 +              } catch (dcp::NotEncryptedError& e) {
                        error_dialog (this, _("CPL's content is not encrypted."));
                } catch (exception& e) {
                        error_dialog (this, e.what ());
index 0f2d5b8a31ad5e6c757a27d8702a1fe0d396726e,8c26ba4ccc5cba33eb8eadd0b06cfae9e9bf461a..fa14dd141ad03f210380e76fa1245b534e6d5b96
@@@ -41,9 -41,10 +41,10 @@@ help (
        cerr << "Syntax: " << program_name << " [OPTION] [<FILM>]\n"
                "  -h, --help             show this help\n"
                "  -o, --output           output file or directory\n"
 -              "  -f, --valid-from       valid from time (e.g. \"2013-09-28 01:41:51\") or \"now\"\n"
 -              "  -t, --valid-to         valid to time (e.g. \"2014-09-28 01:41:51\")\n"
 +              "  -f, --valid-from       valid from time (in local time zone) (e.g. \"2013-09-28 01:41:51\") or \"now\"\n"
 +              "  -t, --valid-to         valid to time (in local time zone) (e.g. \"2014-09-28 01:41:51\")\n"
                "  -d, --valid-duration   valid duration (e.g. \"1 day\", \"4 hours\", \"2 weeks\")\n"
+               "      --formulation      modified-transitional-1, dci-any or dci-specific [default modified-transitional-1]\n"
                "  -z, --zip              ZIP each cinema's KDMs into its own file\n"
                "  -v, --verbose          be verbose\n"
                "  -c, --cinema           specify a cinema, either by name or email address\n"
@@@ -110,6 -111,7 +111,7 @@@ int main (int argc, char* argv[]
        bool cinemas = false;
        string duration_string;
        bool verbose = false;
 -      libdcp::KDM::Formulation formulation = libdcp::KDM::MODIFIED_TRANSITIONAL_1;
++      dcp::Formulation formulation = dcp::MODIFIED_TRANSITIONAL_1;
  
        program_name = argv[0];
        
                case 'v':
                        verbose = true;
                        break;
 -                              formulation = libdcp::KDM::MODIFIED_TRANSITIONAL_1;
+               case 'C':
+                       if (string (optarg) == "modified-transitional-1") {
 -                              formulation = libdcp::KDM::DCI_ANY;
++                              formulation = dcp::MODIFIED_TRANSITIONAL_1;
+                       } else if (string (optarg) == "dci-any") {
 -                              formulation = libdcp::KDM::DCI_SPECIFIC;
++                              formulation = dcp::DCI_ANY;
+                       } else if (string (optarg) == "dci-specific") {
++                              formulation = dcp::DCI_SPECIFIC;
+                       } else {
+                               error ("unrecognised KDM formulation " + formulation);
+                       }
                }
        }
  
                        error ("you must specify --output");
                }
                
 -              shared_ptr<libdcp::Certificate> certificate (new libdcp::Certificate (boost::filesystem::path (certificate_file)));
 -              libdcp::KDM kdm = film->make_kdm (certificate, cpl, valid_from.get(), valid_to.get(), formulation);
 +              shared_ptr<dcp::Certificate> certificate (new dcp::Certificate (boost::filesystem::path (certificate_file)));
-               dcp::EncryptedKDM kdm = film->make_kdm (certificate, cpl, valid_from.get(), valid_to.get());
++              dcp::EncryptedKDM kdm = film->make_kdm (certificate, cpl, valid_from.get(), valid_to.get(), formulation);
                kdm.as_xml (output);
                if (verbose) {
                        cout << "Generated KDM " << output << " for certificate.\n";
  
                try {
                        if (zip) {
-                               write_kdm_zip_files (film, (*i)->screens(), cpl, dcp::LocalTime (valid_from.get()), dcp::LocalTime (valid_to.get()), output);
 -                              write_kdm_zip_files (film, (*i)->screens(), cpl, valid_from.get(), valid_to.get(), formulation, output);
++                              write_kdm_zip_files (
++                                      film, (*i)->screens(), cpl, dcp::LocalTime (valid_from.get()), dcp::LocalTime (valid_to.get()), formulation, output
++                                      );
++                              
                                if (verbose) {
                                        cout << "Wrote ZIP files to " << output << "\n";
                                }
                        } else {
-                               write_kdm_files (film, (*i)->screens(), cpl, dcp::LocalTime (valid_from.get()), dcp::LocalTime (valid_to.get()), output);
 -                              write_kdm_files (film, (*i)->screens(), cpl, valid_from.get(), valid_to.get(), formulation, output);
++                              write_kdm_files (
++                                      film, (*i)->screens(), cpl, dcp::LocalTime (valid_from.get()), dcp::LocalTime (valid_to.get()), formulation, output
++                                      );
++                              
                                if (verbose) {
                                        cout << "Wrote KDM files to " << output << "\n";
                                }
Simple merge
index 6750e0e98cb5606fa154c15e7f1cbc0a861759b1,8df94de9c5f06a986213d479d56e5463d83df51d..0fdb1fe5051eda24adf941bde7eeafbc287ddddf
@@@ -480,6 -488,21 +488,21 @@@ KDMDialog::write_to () cons
        return _write_to->GetValue ();
  }
  
 -libdcp::KDM::Formulation
++dcp::Formulation
+ KDMDialog::formulation () const
+ {
+       switch (_type->GetSelection()) {
+       case 0:
 -              return libdcp::KDM::MODIFIED_TRANSITIONAL_1;
++              return dcp::MODIFIED_TRANSITIONAL_1;
+       case 1:
 -              return libdcp::KDM::DCI_ANY;
++              return dcp::DCI_ANY;
+       case 2:
 -              return libdcp::KDM::DCI_SPECIFIC;
++              return dcp::DCI_SPECIFIC;
+       default:
+               assert (false);
+       }
+ }
  void
  KDMDialog::update_cpl_choice ()
  {
index 6327b29e8d1b84db982a3529b499da97150b31b3,13e9196ea055180a4ee29e6b664338b2d94b1a33..0fc95db8443dee447023e7170b3ee964c0daef85
@@@ -48,6 -48,7 +48,7 @@@ public
        boost::filesystem::path cpl () const;
        boost::filesystem::path directory () const;
        bool write_to () const;
 -      libdcp::KDM::Formulation formulation () const;
++      dcp::Formulation formulation () const;
  
  private:
        void add_cinema (boost::shared_ptr<Cinema>);
index 4b56168a1d0636be5d56642d212b8050e19b61ce,eba12c47faff1421269b2f42067ec09ce90c8d6a..534f4eda752ad4078c9d6afbc982a138de4586d9
@@@ -440,6 -418,18 +445,18 @@@ Timeline::playlist_changed (
        Refresh ();
  }
  
 -              setup_pixels_per_time_unit ();
+ void
+ Timeline::playlist_content_changed (int property)
+ {
+       ensure_ui_thread ();
+       if (property == ContentProperty::POSITION) {
+               assign_tracks ();
++              setup_pixels_per_second ();
+               Refresh ();
+       }
+ }
  void
  Timeline::assign_tracks ()
  {
@@@ -677,10 -671,10 +701,10 @@@ Timeline::set_position_from_event (wxMo
                }
        }
        
 -      if (new_position < 0) {
 -              new_position = 0;
 +      if (new_position < DCPTime ()) {
 +              new_position = DCPTime ();
        }
-       
        _down_view->content()->set_position (new_position);
        
        shared_ptr<Film> film = _film.lock ();
Simple merge
index 9a4551193e9672dfe2ed4468fe01678f5af556c5,ef963bbfcce89751a70b5f979e3d83dcccec0aa0..df77a2ef1a5b38006fae2c31e60c0a5341e7dbd9
@@@ -17,6 -17,7 +17,7 @@@
  
  */
  
 -#include <libdcp/raw_convert.h>
++#include <dcp/raw_convert.h>
  #include "lib/content.h"
  #include "lib/image_content.h"
  #include "timing_panel.h"
@@@ -28,7 -29,7 +29,7 @@@ using std::cout
  using std::string;
  using boost::shared_ptr;
  using boost::dynamic_pointer_cast;
- using boost::lexical_cast;
 -using libdcp::raw_convert;
++using dcp::raw_convert;
  
  TimingPanel::TimingPanel (FilmEditor* e)
        /* horrid hack for apparent lack of context support with wxWidgets i18n code */
diff --cc src/wx/wscript
Simple merge
index 0ae2fd13713f3bb45d25fbd8c34dbf6f5e688735,dd0208b1d1dd7379a82ee945c53ff5b573dd54c2..f6c3a4bb2bbc87616ffc3cfbeb84a3ffacc07704
@@@ -34,13 -27,16 +34,13 @@@ extern "C" 
  
  using std::list;
  
 -/* Check that Image::make_black works, and doesn't use values which crash
 -   sws_scale().
 -*/
  BOOST_AUTO_TEST_CASE (make_black_test)
  {
 -      libdcp::Size in_size (512, 512);
 -      libdcp::Size out_size (1024, 1024);
 +      dcp::Size in_size (512, 512);
 +      dcp::Size out_size (1024, 1024);
  
        list<AVPixelFormat> pix_fmts;
-       pix_fmts.push_back (AV_PIX_FMT_RGB24);
+       pix_fmts.push_back (AV_PIX_FMT_RGB24); // 2
        pix_fmts.push_back (AV_PIX_FMT_ARGB);
        pix_fmts.push_back (AV_PIX_FMT_RGBA);
        pix_fmts.push_back (AV_PIX_FMT_ABGR);
diff --cc wscript
index 57f8a1bb693a3ee9b7cbf3c99108ec8676631859,2625ee852d16fb35db02b60fbb799aa4c508e4b2..df839a96befcd1087d2ad00c445ac71fb077d9b4
+++ b/wscript
@@@ -55,9 -56,9 +56,9 @@@ def dynamic_openjpeg(conf)
      conf.check_cfg(package='libopenjpeg', args='--cflags --libs', max_version='1.5.2', mandatory=True)
  
  def static_dcp(conf, static_boost, static_xmlpp, static_xmlsec, static_ssh):
-     conf.check_cfg(package='libdcp-1.0', atleast_version='0.92', args='--cflags', uselib_store='DCP', mandatory=True)
 -    conf.check_cfg(package='libdcp', atleast_version='0.95', args='--cflags', uselib_store='DCP', mandatory=True)
++    conf.check_cfg(package='libdcp-1.0', atleast_version='0.95', args='--cflags', uselib_store='DCP', mandatory=True)
      conf.env.DEFINES_DCP = [f.replace('\\', '') for f in conf.env.DEFINES_DCP]
 -    conf.env.STLIB_DCP = ['dcp', 'asdcp-libdcp', 'kumu-libdcp']
 +    conf.env.STLIB_DCP = ['dcp-1.0', 'asdcp-libdcp-1.0', 'kumu-libdcp-1.0']
      conf.env.LIB_DCP = ['glibmm-2.4', 'ssl', 'crypto', 'bz2', 'xslt']
  
      if static_boost: