Merge master.
authorCarl Hetherington <cth@carlh.net>
Sat, 10 May 2014 13:13:10 +0000 (14:13 +0100)
committerCarl Hetherington <cth@carlh.net>
Sat, 10 May 2014 13:13:10 +0000 (14:13 +0100)
1  2 
ChangeLog
src/lib/audio_mapping.cc
src/lib/film.cc
src/lib/resampler.cc
src/lib/util.cc
src/lib/util.h
src/wx/audio_mapping_view.cc
src/wx/film_editor.cc
test/audio_mapping_test.cc
test/silence_padding_test.cc

diff --combined ChangeLog
index b7e9ad74fd3c52fb23dc3f46727e1d9c542b61d8,1a031b445a22c696969b4740989d91780e4237b9..662983a74a4598610f8752a66c8dc5d800c8c61c
+++ b/ChangeLog
@@@ -1,7 -1,21 +1,25 @@@
 +2014-03-07  Carl Hetherington  <cth@carlh.net>
 +
 +      * Add subtitle view.
 +
+ 2014-05-10  Carl Hetherington  <cth@carlh.net>
+       * Version 1.69.2 released.
+ 2014-05-10  Carl Hetherington  <cth@carlh.net>
+       * Fix setup of the libswresample context to work with high channel counts.
+ 2014-05-09  Carl Hetherington  <cth@carlh.net>
+       * Version 1.69.1 released.
+ 2014-05-09  Carl Hetherington  <cth@carlh.net>
+       * Fix crash on using content with more than 12 audio channels.
+       * Re-introduce ffprobe call when adding content.
  2014-05-05  Carl Hetherington  <cth@carlh.net>
  
        * Version 1.69.0 released.
  
        * Another attempt to fix colour conversion dialog strange behaviour
        on OS X.
- >>>>>>> master
  
  2014-03-18  Carl Hetherington  <cth@carlh.net>
  
diff --combined src/lib/audio_mapping.cc
index f6d747b9b49e6add9027c23360e9307818ffd386,301d44fa665f0840f60cdd30956352ec3f1d76b0..969397b0bdf9a1a43f696cfc9d4b22ac04e125ef
@@@ -1,5 -1,5 +1,5 @@@
  /*
 -    Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
 +    Copyright (C) 2013-2014 Carl Hetherington <cth@carlh.net>
  
      This program is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published by
@@@ -28,6 -28,7 +28,7 @@@ using std::cout
  using std::make_pair;
  using std::pair;
  using std::string;
+ using std::min;
  using boost::shared_ptr;
  using boost::lexical_cast;
  using boost::dynamic_pointer_cast;
@@@ -39,11 -40,11 +40,11 @@@ AudioMapping::AudioMapping (
  }
  
  /** Create a default AudioMapping for a given channel count.
 - *  @param c Number of channels.
 + *  @param channels Number of channels.
   */
 -AudioMapping::AudioMapping (int c)
 +AudioMapping::AudioMapping (int channels)
  {
 -      setup (c);
 +      setup (channels);
  }
  
  void
@@@ -53,7 -54,7 +54,7 @@@ AudioMapping::setup (int c
        
        _gain.resize (_content_channels);
        for (int i = 0; i < _content_channels; ++i) {
-               _gain[i].resize (MAX_AUDIO_CHANNELS);
+               _gain[i].resize (MAX_DCP_AUDIO_CHANNELS);
        }
  }
  
@@@ -61,18 -62,18 +62,18 @@@ voi
  AudioMapping::make_default ()
  {
        for (int i = 0; i < _content_channels; ++i) {
-               for (int j = 0; j < MAX_AUDIO_CHANNELS; ++j) {
+               for (int j = 0; j < MAX_DCP_AUDIO_CHANNELS; ++j) {
                        _gain[i][j] = 0;
                }
        }
  
        if (_content_channels == 1) {
                /* Mono -> Centre */
 -              set (0, libdcp::CENTRE, 1);
 +              set (0, dcp::CENTRE, 1);
        } else {
                /* 1:1 mapping */
-               for (int i = 0; i < _content_channels; ++i) {
+               for (int i = 0; i < min (_content_channels, MAX_DCP_AUDIO_CHANNELS); ++i) {
 -                      set (i, static_cast<libdcp::Channel> (i), 1);
 +                      set (i, static_cast<dcp::Channel> (i), 1);
                }
        }
  }
@@@ -85,14 -86,14 +86,14 @@@ AudioMapping::AudioMapping (shared_ptr<
                /* Old-style: on/off mapping */
                list<cxml::NodePtr> const c = node->node_children ("Map");
                for (list<cxml::NodePtr>::const_iterator i = c.begin(); i != c.end(); ++i) {
 -                      set ((*i)->number_child<int> ("ContentIndex"), static_cast<libdcp::Channel> ((*i)->number_child<int> ("DCP")), 1);
 +                      set ((*i)->number_child<int> ("ContentIndex"), static_cast<dcp::Channel> ((*i)->number_child<int> ("DCP")), 1);
                }
        } else {
                list<cxml::NodePtr> const c = node->node_children ("Gain");
                for (list<cxml::NodePtr>::const_iterator i = c.begin(); i != c.end(); ++i) {
                        set (
                                (*i)->number_attribute<int> ("Content"),
 -                              static_cast<libdcp::Channel> ((*i)->number_attribute<int> ("DCP")),
 +                              static_cast<dcp::Channel> ((*i)->number_attribute<int> ("DCP")),
                                lexical_cast<float> ((*i)->content ())
                                );
                }
  }
  
  void
 -AudioMapping::set (int c, libdcp::Channel d, float g)
 +AudioMapping::set (int c, dcp::Channel d, float g)
  {
        _gain[c][d] = g;
  }
  
  float
 -AudioMapping::get (int c, libdcp::Channel d) const
 +AudioMapping::get (int c, dcp::Channel d) const
  {
        return _gain[c][d];
  }
@@@ -117,11 -118,11 +118,11 @@@ AudioMapping::as_xml (xmlpp::Node* node
        node->add_child ("ContentChannels")->add_child_text (lexical_cast<string> (_content_channels));
  
        for (int c = 0; c < _content_channels; ++c) {
-               for (int d = 0; d < MAX_AUDIO_CHANNELS; ++d) {
+               for (int d = 0; d < MAX_DCP_AUDIO_CHANNELS; ++d) {
                        xmlpp::Element* t = node->add_child ("Gain");
                        t->set_attribute ("Content", lexical_cast<string> (c));
                        t->set_attribute ("DCP", lexical_cast<string> (d));
 -                      t->add_child_text (lexical_cast<string> (get (c, static_cast<libdcp::Channel> (d))));
 +                      t->add_child_text (lexical_cast<string> (get (c, static_cast<dcp::Channel> (d))));
                }
        }
  }
diff --combined src/lib/film.cc
index 267138ce63b74d51054d695b52777bd405a6ebc9,7b72126f95c9d459ba2b209b0e24b4d9d29260e9..33cb304600cda8146deb44a6d1ada1e214925729
  #include <boost/filesystem.hpp>
  #include <boost/algorithm/string.hpp>
  #include <boost/lexical_cast.hpp>
 -#include <boost/date_time.hpp>
  #include <libxml++/libxml++.h>
  #include <libcxml/cxml.h>
 -#include <libdcp/signer_chain.h>
 -#include <libdcp/cpl.h>
 -#include <libdcp/signer.h>
 -#include <libdcp/util.h>
 -#include <libdcp/kdm.h>
 +#include <dcp/signer_chain.h>
 +#include <dcp/cpl.h>
 +#include <dcp/signer.h>
 +#include <dcp/util.h>
 +#include <dcp/local_time.h>
  #include "film.h"
  #include "job.h"
  #include "util.h"
@@@ -77,8 -78,8 +77,8 @@@ using boost::to_upper_copy
  using boost::ends_with;
  using boost::starts_with;
  using boost::optional;
 -using libdcp::Size;
 -using libdcp::Signer;
 +using dcp::Size;
 +using dcp::Signer;
  
  /* 5 -> 6
   * AudioMapping XML changed.
@@@ -435,7 -436,7 +435,7 @@@ Film::read_metadata (
        _sequence_video = f.bool_child ("SequenceVideo");
        _three_d = f.bool_child ("ThreeD");
        _interop = f.bool_child ("Interop");
 -      _key = libdcp::Key (f.string_child ("Key"));
 +      _key = dcp::Key (f.string_child ("Key"));
  
        list<string> notes;
        /* This method is the only one that can return notes (so far) */
@@@ -765,7 -766,7 +765,7 @@@ Film::j2c_path (int f, Eyes e, bool t) 
        return file (p);
  }
  
 -/** @return List of subdirectories (not full paths) containing DCPs that can be successfully libdcp::DCP::read() */
 +/** @return List of subdirectories (not full paths) containing DCPs that can be successfully dcp::DCP::read() */
  list<boost::filesystem::path>
  Film::dcps () const
  {
                        ) {
  
                        try {
 -                              libdcp::DCP dcp (*i);
 +                              dcp::DCP dcp (*i);
                                dcp.read ();
                                out.push_back (i->path().leaf ());
                        } catch (...) {
@@@ -826,6 -827,10 +826,10 @@@ Film::content () cons
  void
  Film::examine_and_add_content (shared_ptr<Content> c)
  {
+       if (dynamic_pointer_cast<FFmpegContent> (c)) {
+               run_ffprobe (c->path(0), file ("ffprobe.log"), _log);
+       }
+                       
        shared_ptr<Job> j (new ExamineContentJob (shared_from_this(), c));
        j->Finished.connect (bind (&Film::maybe_add_content, this, boost::weak_ptr<Job> (j), boost::weak_ptr<Content> (c)));
        JobManager::instance()->add (j);
@@@ -874,7 -879,7 +878,7 @@@ Film::move_content_later (shared_ptr<Co
        _playlist->move_later (c);
  }
  
 -Time
 +DCPTime
  Film::length () const
  {
        return _playlist->length ();
@@@ -886,18 -891,12 +890,18 @@@ Film::has_subtitles () cons
        return _playlist->has_subtitles ();
  }
  
 -OutputVideoFrame
 +int
  Film::best_video_frame_rate () const
  {
        return _playlist->best_dcp_frame_rate ();
  }
  
 +FrameRateChange
 +Film::active_frame_rate_change (DCPTime t) const
 +{
 +      return _playlist->active_frame_rate_change (t, video_frame_rate ());
 +}
 +
  void
  Film::playlist_content_changed (boost::weak_ptr<Content> c, int p)
  {
@@@ -916,7 -915,31 +920,7 @@@ Film::playlist_changed (
        signal_changed (CONTENT);
  }     
  
 -OutputAudioFrame
 -Film::time_to_audio_frames (Time t) const
 -{
 -      return divide_with_round (t * audio_frame_rate (), TIME_HZ);
 -}
 -
 -OutputVideoFrame
 -Film::time_to_video_frames (Time t) const
 -{
 -      return divide_with_round (t * video_frame_rate (), TIME_HZ);
 -}
 -
 -Time
 -Film::audio_frames_to_time (OutputAudioFrame f) const
 -{
 -      return divide_with_round (f * TIME_HZ, audio_frame_rate ());
 -}
 -
 -Time
 -Film::video_frames_to_time (OutputVideoFrame f) const
 -{
 -      return divide_with_round (f * TIME_HZ, video_frame_rate ());
 -}
 -
 -OutputAudioFrame
 +int
  Film::audio_frame_rate () const
  {
        /* XXX */
@@@ -932,38 -955,38 +936,38 @@@ Film::set_sequence_video (bool s
  }
  
  /** @return Size of the largest possible image in whatever resolution we are using */
 -libdcp::Size
 +dcp::Size
  Film::full_frame () const
  {
        switch (_resolution) {
        case RESOLUTION_2K:
 -              return libdcp::Size (2048, 1080);
 +              return dcp::Size (2048, 1080);
        case RESOLUTION_4K:
 -              return libdcp::Size (4096, 2160);
 +              return dcp::Size (4096, 2160);
        }
  
        assert (false);
 -      return libdcp::Size ();
 +      return dcp::Size ();
  }
  
  /** @return Size of the frame */
 -libdcp::Size
 +dcp::Size
  Film::frame_size () const
  {
        return fit_ratio_within (container()->ratio(), full_frame ());
  }
  
 -libdcp::KDM
 +dcp::EncryptedKDM
  Film::make_kdm (
 -      shared_ptr<libdcp::Certificate> target,
 +      shared_ptr<dcp::Certificate> target,
        boost::filesystem::path dcp_dir,
 -      boost::posix_time::ptime from,
 -      boost::posix_time::ptime until
 +      dcp::LocalTime from,
 +      dcp::LocalTime until
        ) const
  {
        shared_ptr<const Signer> signer = make_signer ();
  
 -      libdcp::DCP dcp (dir (dcp_dir.string ()));
 +      dcp::DCP dcp (dir (dcp_dir.string ()));
        
        try {
                dcp.read ();
                throw KDMError (_("Could not read DCP to make KDM for"));
        }
        
 -      time_t now = time (0);
 -      struct tm* tm = localtime (&now);
 -      string const issue_date = libdcp::tm_to_string (tm);
 -      
        dcp.cpls().front()->set_mxf_keys (key ());
        
 -      return libdcp::KDM (dcp.cpls().front(), signer, target, from, until, "DCP-o-matic", issue_date);
 +      return dcp::DecryptedKDM (
 +              dcp.cpls().front(), from, until, "DCP-o-matic", dcp.cpls().front()->content_title_text(), dcp::LocalTime().as_string()
 +              ).encrypt (signer, target);
  }
  
 -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
 +      dcp::LocalTime from,
 +      dcp::LocalTime until
        ) 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));
  uint64_t
  Film::required_disk_space () const
  {
 -      return uint64_t (j2k_bandwidth() / 8) * length() / TIME_HZ;
 +      return uint64_t (j2k_bandwidth() / 8) * length().seconds();
  }
  
  /** This method checks the disk that the Film is on and tries to decide whether or not
diff --combined src/lib/resampler.cc
index 00121384dce7617ab59f0ee85ea0373a7ab0c440,e6b1623d9cbeb3afbe7df32a758323d9980b36b9..9a81df4993e5da7132938afd25db6dbf29c6d392
@@@ -1,5 -1,5 +1,5 @@@
  /*
-     Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+     Copyright (C) 2013-2014 Carl Hetherington <cth@carlh.net>
  
      This program is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published by
@@@ -19,6 -19,7 +19,7 @@@
  
  extern "C" {
  #include "libavutil/channel_layout.h"
+ #include "libavutil/opt.h"
  }     
  #include "resampler.h"
  #include "audio_buffers.h"
@@@ -37,24 -38,19 +38,19 @@@ Resampler::Resampler (int in, int out, 
        , _out_rate (out)
        , _channels (channels)
  {
-       /* We will be using planar float data when we call the
-          resampler.  As far as I can see, the audio channel
-          layout is not necessary for our purposes; it seems
-          only to be used get the number of channels and
-          decide if rematrixing is needed.  It won't be, since
-          input and output layouts are the same.
-       */
+       _swr_context = swr_alloc ();
  
-       _swr_context = swr_alloc_set_opts (
-               0,
-               av_get_default_channel_layout (_channels),
-               AV_SAMPLE_FMT_FLTP,
-               _out_rate,
-               av_get_default_channel_layout (_channels),
-               AV_SAMPLE_FMT_FLTP,
-               _in_rate,
-               0, 0
-               );
+       /* Sample formats */
+       av_opt_set_int (_swr_context, "isf", AV_SAMPLE_FMT_FLTP, 0);
+       av_opt_set_int (_swr_context, "osf", AV_SAMPLE_FMT_FLTP, 0);
+       /* Channel counts */
+       av_opt_set_int (_swr_context, "ich", _channels, 0);
+       av_opt_set_int (_swr_context, "och", _channels, 0);
+       /* Sample rates */
+       av_opt_set_int (_swr_context, "isr", _in_rate, 0);
+       av_opt_set_int (_swr_context, "osr", _out_rate, 0);
        
        swr_init (_swr_context);
  }
@@@ -64,9 -60,11 +60,9 @@@ Resampler::~Resampler (
        swr_free (&_swr_context);
  }
  
 -pair<shared_ptr<const AudioBuffers>, AudioContent::Frame>
 -Resampler::run (shared_ptr<const AudioBuffers> in, AudioContent::Frame frame)
 +shared_ptr<const AudioBuffers>
 +Resampler::run (shared_ptr<const AudioBuffers> in)
  {
 -      AudioContent::Frame const resamp_time = swr_next_pts (_swr_context, frame * _out_rate) / _in_rate;
 -              
        /* Compute the resampled frames count and add 32 for luck */
        int const max_resampled_frames = ceil ((double) in->frames() * _out_rate / _in_rate) + 32;
        shared_ptr<AudioBuffers> resampled (new AudioBuffers (_channels, max_resampled_frames));
@@@ -82,7 -80,7 +78,7 @@@
        }
        
        resampled->set_frames (resampled_frames);
 -      return make_pair (resampled, resamp_time);
 +      return resampled;
  }     
  
  shared_ptr<const AudioBuffers>
diff --combined src/lib/util.cc
index 45d5a757cc2783a0c40cdefda99c9c5fd52b2528,62416163bc4aa080ef58cb0acab6d954dd34d0df..0eb14845d7da6dba601412a34c72544cd590db4b
@@@ -1,5 -1,5 +1,5 @@@
  /*
 -    Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
 +    Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
      Copyright (C) 2000-2007 Paul Davis
  
      This program is free software; you can redistribute it and/or modify
  #include <glib.h>
  #include <openjpeg.h>
  #include <openssl/md5.h>
 +#include <pangomm/init.h>
  #include <magick/MagickCore.h>
  #include <magick/version.h>
 -#include <libdcp/version.h>
 -#include <libdcp/util.h>
 -#include <libdcp/signer_chain.h>
 -#include <libdcp/signer.h>
 +#include <dcp/version.h>
 +#include <dcp/util.h>
 +#include <dcp/signer_chain.h>
 +#include <dcp/signer.h>
  extern "C" {
  #include <libavcodec/avcodec.h>
  #include <libavformat/avformat.h>
@@@ -71,7 -70,6 +71,7 @@@
  #include "job.h"
  #include "cross.h"
  #include "video_content.h"
 +#include "rect.h"
  #ifdef DCPOMATIC_WINDOWS
  #include "stack.hpp"
  #endif
@@@ -103,7 -101,7 +103,7 @@@ using boost::shared_ptr
  using boost::thread;
  using boost::lexical_cast;
  using boost::optional;
 -using libdcp::Size;
 +using dcp::Size;
  
  static boost::thread::id ui_thread;
  static boost::filesystem::path backtrace_file;
@@@ -239,6 -237,24 +239,6 @@@ ffmpeg_version_to_string (int v
        return s.str ();
  }
  
 -/** Return a user-readable string summarising the versions of our dependencies */
 -string
 -dependency_version_summary ()
 -{
 -      stringstream s;
 -      s << N_("libopenjpeg ") << opj_version () << N_(", ")
 -        << N_("libavcodec ") << ffmpeg_version_to_string (avcodec_version()) << N_(", ")
 -        << N_("libavfilter ") << ffmpeg_version_to_string (avfilter_version()) << N_(", ")
 -        << N_("libavformat ") << ffmpeg_version_to_string (avformat_version()) << N_(", ")
 -        << N_("libavutil ") << ffmpeg_version_to_string (avutil_version()) << N_(", ")
 -        << N_("libswscale ") << ffmpeg_version_to_string (swscale_version()) << N_(", ")
 -        << MagickVersion << N_(", ")
 -        << N_("libssh ") << ssh_version (0) << N_(", ")
 -        << N_("libdcp ") << libdcp::version << N_(" git ") << libdcp::git_commit;
 -
 -      return s.str ();
 -}
 -
  double
  seconds (struct timeval t)
  {
@@@ -325,8 -341,7 +325,8 @@@ dcpomatic_setup (
  
        set_terminate (terminate);
  
 -      libdcp::init ();
 +      Pango::init ();
 +      dcp::init ();
        
        Ratio::setup_ratios ();
        VideoContentScale::setup_scales ();
@@@ -475,6 -490,33 +475,6 @@@ md5_digest (vector<boost::filesystem::p
        return s.str ();
  }
  
 -static bool
 -about_equal (float a, float b)
 -{
 -      /* A film of F seconds at f FPS will be Ff frames;
 -         Consider some delta FPS d, so if we run the same
 -         film at (f + d) FPS it will last F(f + d) seconds.
 -
 -         Hence the difference in length over the length of the film will
 -         be F(f + d) - Ff frames
 -          = Ff + Fd - Ff frames
 -          = Fd frames
 -          = Fd/f seconds
 - 
 -         So if we accept a difference of 1 frame, ie 1/f seconds, we can
 -         say that
 -
 -         1/f = Fd/f
 -      ie 1 = Fd
 -      ie d = 1/F
 - 
 -         So for a 3hr film, ie F = 3 * 60 * 60 = 10800, the acceptable
 -         FPS error is 1/F ~= 0.0001 ~= 10-e4
 -      */
 -
 -      return (fabs (a - b) < 1e-4);
 -}
 -
  /** @param An arbitrary audio frame rate.
   *  @return The appropriate DCP-approved frame rate (48kHz or 96kHz).
   */
@@@ -734,10 -776,21 +734,10 @@@ ensure_ui_thread (
        assert (boost::this_thread::get_id() == ui_thread);
  }
  
 -/** @param v Content video frame.
 - *  @param audio_sample_rate Source audio sample rate.
 - *  @param frames_per_second Number of video frames per second.
 - *  @return Equivalent number of audio frames for `v'.
 - */
 -int64_t
 -video_frames_to_audio_frames (VideoContent::Frame v, float audio_sample_rate, float frames_per_second)
 -{
 -      return ((int64_t) v * audio_sample_rate / frames_per_second);
 -}
 -
  string
  audio_channel_name (int c)
  {
-       assert (MAX_AUDIO_CHANNELS == 12);
+       assert (MAX_DCP_AUDIO_CHANNELS == 12);
  
        /* TRANSLATORS: these are the names of audio channels; Lfe (sub) is the low-frequency
           enhancement channel (sub-woofer).  HI is the hearing-impaired audio track and
        return channels[c];
  }
  
 -FrameRateConversion::FrameRateConversion (float source, int dcp)
 -      : skip (false)
 -      , repeat (1)
 -      , change_speed (false)
 -{
 -      if (fabs (source / 2.0 - dcp) < fabs (source - dcp)) {
 -              /* The difference between source and DCP frame rate will be lower
 -                 (i.e. better) if we skip.
 -              */
 -              skip = true;
 -      } else if (fabs (source * 2 - dcp) < fabs (source - dcp)) {
 -              /* The difference between source and DCP frame rate would be better
 -                 if we repeated each frame once; it may be better still if we
 -                 repeated more than once.  Work out the required repeat.
 -              */
 -              repeat = round (dcp / source);
 -      }
 -
 -      change_speed = !about_equal (source * factor(), dcp);
 -
 -      if (!skip && repeat == 1 && !change_speed) {
 -              description = _("Content and DCP have the same rate.\n");
 -      } else {
 -              if (skip) {
 -                      description = _("DCP will use every other frame of the content.\n");
 -              } else if (repeat == 2) {
 -                      description = _("Each content frame will be doubled in the DCP.\n");
 -              } else if (repeat > 2) {
 -                      description = String::compose (_("Each content frame will be repeated %1 more times in the DCP.\n"), repeat - 1);
 -              }
 -
 -              if (change_speed) {
 -                      float const pc = dcp * 100 / (source * factor());
 -                      description += String::compose (_("DCP will run at %1%% of the content speed.\n"), pc);
 -              }
 -      }
 -}
 -
  LocaleGuard::LocaleGuard ()
        : _old (0)
  {
@@@ -803,7 -894,7 +803,7 @@@ tidy_for_filename (string f
        return t;
  }
  
 -shared_ptr<const libdcp::Signer>
 +shared_ptr<const dcp::Signer>
  make_signer ()
  {
        boost::filesystem::path const sd = Config::instance()->signer_chain_directory ();
                if (!boost::filesystem::exists (p)) {
                        boost::filesystem::remove_all (sd);
                        boost::filesystem::create_directories (sd);
 -                      libdcp::make_signer_chain (sd, openssl_path ());
 +                      dcp::make_signer_chain (sd, openssl_path ());
                        break;
                }
  
                ++i;
        }
        
 -      libdcp::CertificateChain chain;
 +      dcp::CertificateChain chain;
  
        {
                boost::filesystem::path p (sd);
                p /= "ca.self-signed.pem";
 -              chain.add (shared_ptr<libdcp::Certificate> (new libdcp::Certificate (p)));
 +              chain.add (shared_ptr<dcp::Certificate> (new dcp::Certificate (p)));
        }
  
        {
                boost::filesystem::path p (sd);
                p /= "intermediate.signed.pem";
 -              chain.add (shared_ptr<libdcp::Certificate> (new libdcp::Certificate (p)));
 +              chain.add (shared_ptr<dcp::Certificate> (new dcp::Certificate (p)));
        }
  
        {
                boost::filesystem::path p (sd);
                p /= "leaf.signed.pem";
 -              chain.add (shared_ptr<libdcp::Certificate> (new libdcp::Certificate (p)));
 +              chain.add (shared_ptr<dcp::Certificate> (new dcp::Certificate (p)));
        }
  
        boost::filesystem::path signer_key (sd);
        signer_key /= "leaf.key";
  
 -      return shared_ptr<const libdcp::Signer> (new libdcp::Signer (chain, signer_key));
 +      return shared_ptr<const dcp::Signer> (new dcp::Signer (chain, signer_key));
  }
  
  map<string, string>
@@@ -902,14 -993,14 +902,14 @@@ split_get_request (string url
        return r;
  }
  
 -libdcp::Size
 -fit_ratio_within (float ratio, libdcp::Size full_frame)
 +dcp::Size
 +fit_ratio_within (float ratio, dcp::Size full_frame)
  {
        if (ratio < full_frame.ratio ()) {
 -              return libdcp::Size (rint (full_frame.height * ratio), full_frame.height);
 +              return dcp::Size (rint (full_frame.height * ratio), full_frame.height);
        }
        
 -      return libdcp::Size (full_frame.width, rint (full_frame.width / ratio));
 +      return dcp::Size (full_frame.width, rint (full_frame.width / ratio));
  }
  
  void *
@@@ -940,34 -1031,12 +940,34 @@@ divide_with_round (int64_t a, int64_t b
        }
  }
  
 +/** Return a user-readable string summarising the versions of our dependencies */
 +string
 +dependency_version_summary ()
 +{
 +      stringstream s;
 +      s << N_("libopenjpeg ") << opj_version () << N_(", ")
 +        << N_("libavcodec ") << ffmpeg_version_to_string (avcodec_version()) << N_(", ")
 +        << N_("libavfilter ") << ffmpeg_version_to_string (avfilter_version()) << N_(", ")
 +        << N_("libavformat ") << ffmpeg_version_to_string (avformat_version()) << N_(", ")
 +        << N_("libavutil ") << ffmpeg_version_to_string (avutil_version()) << N_(", ")
 +        << N_("libswscale ") << ffmpeg_version_to_string (swscale_version()) << N_(", ")
 +        << MagickVersion << N_(", ")
 +        << N_("libssh ") << ssh_version (0) << N_(", ")
 +        << N_("libdcp ") << dcp::version << N_(" git ") << dcp::git_commit;
 +
 +      return s.str ();
 +}
 +
 +/** Construct a ScopedTemporary.  A temporary filename is decided but the file is not opened
 + *  until ::open() is called.
 + */
  ScopedTemporary::ScopedTemporary ()
        : _open (0)
  {
        _file = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path ();
  }
  
 +/** Close and delete the temporary file */
  ScopedTemporary::~ScopedTemporary ()
  {
        close ();       
        boost::filesystem::remove (_file, ec);
  }
  
 +/** @return temporary filename */
  char const *
  ScopedTemporary::c_str () const
  {
        return _file.string().c_str ();
  }
  
 +/** Open the temporary file.
 + *  @return File's FILE pointer.
 + */
  FILE*
  ScopedTemporary::open (char const * params)
  {
        return _open;
  }
  
 +/** Close the file */
  void
  ScopedTemporary::close ()
  {
diff --combined src/lib/util.h
index a13d7ff734faca494ee0a53c68e923790b4af1f4,473c902395529ebaa8c3878ddbc67419717d7166..8e65bbb5415cc236e496e56a83b92dbd45503082
@@@ -31,8 -31,7 +31,8 @@@
  #include <boost/asio.hpp>
  #include <boost/optional.hpp>
  #include <boost/filesystem.hpp>
 -#include <libdcp/util.h>
 +#include <dcp/util.h>
 +#include <dcp/signer.h>
  extern "C" {
  #include <libavcodec/avcodec.h>
  #include <libavfilter/avfilter.h>
@@@ -49,8 -48,8 +49,8 @@@
  
  #undef check
  
- /** The maximum number of audio channels that we can cope with */
- #define MAX_AUDIO_CHANNELS 12
+ /** The maximum number of audio channels that we can have in a DCP */
+ #define MAX_DCP_AUDIO_CHANNELS 12
  
  #define DCPOMATIC_HELLO "Boys, you gotta learn not to talk to nuns that way"
  
@@@ -77,10 -76,44 +77,10 @@@ extern bool valid_image_file (boost::fi
  extern boost::filesystem::path mo_path ();
  #endif
  extern std::string tidy_for_filename (std::string);
 -extern boost::shared_ptr<const libdcp::Signer> make_signer ();
 -extern libdcp::Size fit_ratio_within (float ratio, libdcp::Size);
 +extern boost::shared_ptr<const dcp::Signer> make_signer ();
 +extern dcp::Size fit_ratio_within (float ratio, dcp::Size);
  extern std::string entities_to_text (std::string e);
  extern std::map<std::string, std::string> split_get_request (std::string url);
 -
 -struct FrameRateConversion
 -{
 -      FrameRateConversion (float, int);
 -
 -      /** @return factor by which to multiply a source frame rate
 -          to get the effective rate after any skip or repeat has happened.
 -      */
 -      float factor () const {
 -              if (skip) {
 -                      return 0.5;
 -              }
 -
 -              return repeat;
 -      }
 -
 -      /** true to skip every other frame */
 -      bool skip;
 -      /** number of times to use each frame (e.g. 1 is normal, 2 means repeat each frame once, and so on) */
 -      int repeat;
 -      /** true if this DCP will run its video faster or slower than the source
 -       *  without taking into account `repeat' nor `skip'.
 -       *  (e.g. change_speed will be true if
 -       *          source is 29.97fps, DCP is 30fps
 -       *          source is 14.50fps, DCP is 30fps
 -       *  but not if
 -       *          source is 15.00fps, DCP is 30fps
 -       *          source is 12.50fps, DCP is 25fps)
 -       */
 -      bool change_speed;
 -
 -      std::string description;
 -};
 -
  extern int dcp_audio_frame_rate (int);
  extern int stride_round_up (int, int const *, int);
  extern std::multimap<std::string, std::string> read_key_value (std::istream& s);
@@@ -131,6 -164,8 +131,6 @@@ private
        int _timeout;
  };
  
 -extern int64_t video_frames_to_audio_frames (VideoContent::Frame v, float audio_sample_rate, float frames_per_second);
 -
  class LocaleGuard
  {
  public:
@@@ -141,20 -176,16 +141,20 @@@ private
        char* _old;
  };
  
 +/** @class ScopedTemporary
 + *  @brief A temporary file which is deleted when the ScopedTemporary object goes out of scope.
 + */
  class ScopedTemporary
  {
  public:
        ScopedTemporary ();
        ~ScopedTemporary ();
  
 +      /** @return temporary filename */
        boost::filesystem::path file () const {
                return _file;
        }
 -      
 +
        char const * c_str () const;
        FILE* open (char const *);
        void close ();
index be1bd67b9cd4d0a388f85e5030363352cf0d7cb3,39bc0825b9c7245ad184190fa9e1fc7c1eb9fe37..9375010865dbc0cc2a9c0dd34834edd97d53934f
@@@ -1,5 -1,5 +1,5 @@@
  /*
 -    Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
 +    Copyright (C) 2013-2014 Carl Hetherington <cth@carlh.net>
  
      This program is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published by
  
  */
  
 +/** @file  src/wx/audio_mapping_view.cc
 + *  @brief AudioMappingView class and helpers.
 + */
 +
  #include <wx/wx.h>
  #include <wx/renderer.h>
  #include <wx/grid.h>
 -#include <libdcp/types.h>
 +#include <dcp/types.h>
  #include "lib/audio_mapping.h"
  #include "lib/util.h"
  #include "audio_mapping_view.h"
@@@ -56,9 -52,6 +56,9 @@@ public
        }
  };
  
 +/** @class ValueRenderer
 + *  @brief wxGridCellRenderer for a gain value.
 + */
  class ValueRenderer : public wxGridCellRenderer
  {
  public:
@@@ -118,7 -111,7 +118,7 @@@ AudioMappingView::AudioMappingView (wxW
  {
        _grid = new wxGrid (this, wxID_ANY);
  
-       _grid->CreateGrid (0, MAX_AUDIO_CHANNELS + 1);
+       _grid->CreateGrid (0, MAX_DCP_AUDIO_CHANNELS + 1);
        _grid->HideRowLabels ();
        _grid->DisableDragRowSize ();
        _grid->DisableDragColSize ();
@@@ -163,7 -156,7 +163,7 @@@ AudioMappingView::left_click (wxGridEve
                return;
        }
  
 -      libdcp::Channel d = static_cast<libdcp::Channel> (ev.GetCol() - 1);
 +      dcp::Channel d = static_cast<dcp::Channel> (ev.GetCol() - 1);
        
        if (_map.get (ev.GetRow(), d) > 0) {
                _map.set (ev.GetRow(), d, 0);
@@@ -189,28 -182,28 +189,28 @@@ AudioMappingView::right_click (wxGridEv
  void
  AudioMappingView::off ()
  {
 -      _map.set (_menu_row, static_cast<libdcp::Channel> (_menu_column - 1), 0);
 +      _map.set (_menu_row, static_cast<dcp::Channel> (_menu_column - 1), 0);
        map_changed ();
  }
  
  void
  AudioMappingView::full ()
  {
 -      _map.set (_menu_row, static_cast<libdcp::Channel> (_menu_column - 1), 1);
 +      _map.set (_menu_row, static_cast<dcp::Channel> (_menu_column - 1), 1);
        map_changed ();
  }
  
  void
  AudioMappingView::minus3dB ()
  {
 -      _map.set (_menu_row, static_cast<libdcp::Channel> (_menu_column - 1), 1 / sqrt (2));
 +      _map.set (_menu_row, static_cast<dcp::Channel> (_menu_column - 1), 1 / sqrt (2));
        map_changed ();
  }
  
  void
  AudioMappingView::edit ()
  {
 -      libdcp::Channel d = static_cast<libdcp::Channel> (_menu_column - 1);
 +      dcp::Channel d = static_cast<dcp::Channel> (_menu_column - 1);
        
        AudioGainDialog* dialog = new AudioGainDialog (this, _menu_row, _menu_column - 1, _map.get (_menu_row, d));
        if (dialog->ShowModal () == wxID_OK) {
@@@ -240,7 -233,7 +240,7 @@@ AudioMappingView::update_cells (
        _grid->InsertRows (0, _map.content_channels ());
  
        for (int i = 0; i < _map.content_channels(); ++i) {
-               for (int j = 0; j < MAX_AUDIO_CHANNELS; ++j) {
+               for (int j = 0; j < MAX_DCP_AUDIO_CHANNELS; ++j) {
                        _grid->SetCellRenderer (i, j + 1, new ValueRenderer);
                }
        }
                _grid->SetCellValue (i, 0, wxString::Format (wxT("%d"), i + 1));
  
                for (int j = 1; j < _grid->GetNumberCols(); ++j) {
 -                      _grid->SetCellValue (i, j, std_to_wx (lexical_cast<string> (_map.get (i, static_cast<libdcp::Channel> (j - 1)))));
 +                      _grid->SetCellValue (i, j, std_to_wx (lexical_cast<string> (_map.get (i, static_cast<dcp::Channel> (j - 1)))));
                }
        }
  
@@@ -279,8 -272,8 +279,8 @@@ AudioMappingView::set_column_labels (
        
        _grid->SetColLabelValue (0, _("Content"));
  
- #if MAX_AUDIO_CHANNELS != 12
- #warning AudioMappingView::set_column_labels() is expecting the wrong MAX_AUDIO_CHANNELS
+ #if MAX_DCP_AUDIO_CHANNELS != 12
+ #warning AudioMappingView::set_column_labels() is expecting the wrong MAX_DCP_AUDIO_CHANNELS
  #endif        
        
        if (c > 0) {
@@@ -353,7 -346,7 +353,7 @@@ AudioMappingView::mouse_moved (wxMouseE
        if (row != _last_tooltip_row || column != _last_tooltip_column) {
  
                wxString s;
 -              float const gain = _map.get (row, static_cast<libdcp::Channel> (column - 1));
 +              float const gain = _map.get (row, static_cast<dcp::Channel> (column - 1));
                if (gain == 0) {
                        s = wxString::Format (_("No audio will be passed from content channel %d to DCP channel %d."), row + 1, column);
                } else if (gain == 1) {
diff --combined src/wx/film_editor.cc
index 2cf6a0b6ccc6847a627bfeb63a848a8e407d6ab8,17198e8b330a113426677d56b191a0756294e533..3fd63e9224c6e363e74027f5371f17840bb2d41c
@@@ -214,7 -214,7 +214,7 @@@ FilmEditor::make_dcp_panel (
                _frame_rate->Append (std_to_wx (boost::lexical_cast<string> (*i)));
        }
  
-       _audio_channels->SetRange (0, MAX_AUDIO_CHANNELS);
+       _audio_channels->SetRange (0, MAX_DCP_AUDIO_CHANNELS);
        _j2k_bandwidth->SetRange (1, Config::instance()->maximum_j2k_bandwidth() / 1000000);
  
        _resolution->Append (_("2K"));
@@@ -854,7 -854,7 +854,7 @@@ FilmEditor::setup_content_sensitivity (
  
        _video_panel->Enable    (video_selection.size() > 0 && _generally_sensitive);
        _audio_panel->Enable    (audio_selection.size() > 0 && _generally_sensitive);
 -      _subtitle_panel->Enable (selection.size() == 1 && dynamic_pointer_cast<FFmpegContent> (selection.front()) && _generally_sensitive);
 +      _subtitle_panel->Enable (selection.size() == 1 && dynamic_pointer_cast<SubtitleContent> (selection.front()) && _generally_sensitive);
        _timing_panel->Enable   (selection.size() == 1 && _generally_sensitive);
  }
  
index f8467f3de9b144f70e2f620e1510eb2ee05191ab,bfb53b0871193c681c333497b3343403d5d1e761..fc597b91df10e4ca9dadaf8303a4b7cb844de983
  
  */
  
 +/** @file  test/audio_mapping_test.cc
 + *  @brief Basic tests of the AudioMapping class, which itself doesn't really do much.
 + */
 +
  #include <boost/test/unit_test.hpp>
  #include "lib/audio_mapping.h"
  #include "lib/util.h"
  
 -/* Basic tests of the AudioMapping class, which itself
 -   doesn't really do much.
 -*/
  BOOST_AUTO_TEST_CASE (audio_mapping_test)
  {
        AudioMapping none;
        four.make_default ();
  
        for (int i = 0; i < 4; ++i) {
-               for (int j = 0; j < MAX_AUDIO_CHANNELS; ++j) {
+               for (int j = 0; j < MAX_DCP_AUDIO_CHANNELS; ++j) {
 -                      BOOST_CHECK_EQUAL (four.get (i, static_cast<libdcp::Channel> (j)), i == j ? 1 : 0);
 +                      BOOST_CHECK_EQUAL (four.get (i, static_cast<dcp::Channel> (j)), i == j ? 1 : 0);
                }
        }
  
 -      four.set (0, libdcp::RIGHT, 1);
 -      BOOST_CHECK_EQUAL (four.get (0, libdcp::RIGHT), 1);
 +      four.set (0, dcp::RIGHT, 1);
 +      BOOST_CHECK_EQUAL (four.get (0, dcp::RIGHT), 1);
  }
index ff369062662b6807fe45a56e57d5d4631c033d48,d5236c144486f125a57ed300bb063c02dea84175..82b9def0e12f3ccbfa471f7e977d1272576b0eca
@@@ -1,5 -1,5 +1,5 @@@
  /*
 -    Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
 +    Copyright (C) 2013-2014 Carl Hetherington <cth@carlh.net>
  
      This program is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published by
  
  */
  
 +/** @file  test/silence_padding_test.cc
 + *  @brief Test the padding (with silence) of a mono source to a 6-channel DCP.
 + */
 +
  #include <boost/test/unit_test.hpp>
 -#include <libdcp/cpl.h>
 -#include <libdcp/dcp.h>
 -#include <libdcp/sound_asset.h>
 -#include <libdcp/sound_frame.h>
 -#include <libdcp/reel.h>
 +#include <dcp/cpl.h>
 +#include <dcp/dcp.h>
 +#include <dcp/sound_mxf.h>
 +#include <dcp/sound_frame.h>
 +#include <dcp/reel.h>
 +#include <dcp/reel_sound_asset.h>
  #include "lib/sndfile_content.h"
  #include "lib/film.h"
  #include "lib/dcp_content_type.h"
@@@ -38,8 -33,7 +38,8 @@@ using std::string
  using boost::lexical_cast;
  using boost::shared_ptr;
  
 -static void test_silence_padding (int channels)
 +static void
 +test_silence_padding (int channels)
  {
        string const film_name = "silence_padding_test_" + lexical_cast<string> (channels);
        shared_ptr<Film> film = new_test_film (film_name);
        boost::filesystem::path path = "build/test";
        path /= film_name;
        path /= film->dcp_name ();
 -      libdcp::DCP check (path.string ());
 +      dcp::DCP check (path.string ());
        check.read ();
  
 -      shared_ptr<const libdcp::SoundAsset> sound_asset = check.cpls().front()->reels().front()->main_sound ();
 +      shared_ptr<const dcp::ReelSoundAsset> sound_asset = check.cpls().front()->reels().front()->main_sound ();
        BOOST_CHECK (sound_asset);
 -      BOOST_CHECK (sound_asset->channels () == channels);
 +      BOOST_CHECK_EQUAL (sound_asset->mxf()->channels (), channels);
  
        /* Sample index in the DCP */
        int n = 0;
        /* DCP sound asset frame */
        int frame = 0;
  
 -      while (n < sound_asset->intrinsic_duration()) {
 -              shared_ptr<const libdcp::SoundFrame> sound_frame = sound_asset->get_frame (frame++);
 +      while (n < sound_asset->mxf()->intrinsic_duration()) {
 +              shared_ptr<const dcp::SoundFrame> sound_frame = sound_asset->mxf()->get_frame (frame++);
                uint8_t const * d = sound_frame->data ();
                
 -              for (int i = 0; i < sound_frame->size(); i += (3 * sound_asset->channels())) {
 +              for (int i = 0; i < sound_frame->size(); i += (3 * sound_asset->mxf()->channels())) {
  
 -                      if (sound_asset->channels() > 0) {
 +                      if (sound_asset->mxf()->channels() > 0) {
                                /* L should be silent */
                                int const sample = d[i + 0] | (d[i + 1] << 8);
                                BOOST_CHECK_EQUAL (sample, 0);
                        }
  
 -                      if (sound_asset->channels() > 1) {
 +                      if (sound_asset->mxf()->channels() > 1) {
                                /* R should be silent */
                                int const sample = d[i + 2] | (d[i + 3] << 8);
                                BOOST_CHECK_EQUAL (sample, 0);
                        }
                        
 -                      if (sound_asset->channels() > 2) {
 +                      if (sound_asset->mxf()->channels() > 2) {
                                /* Mono input so it will appear on centre */
                                int const sample = d[i + 7] | (d[i + 8] << 8);
                                BOOST_CHECK_EQUAL (sample, n);
                        }
  
 -                      if (sound_asset->channels() > 3) {
 +                      if (sound_asset->mxf()->channels() > 3) {
                                /* Lfe should be silent */
                                int const sample = d[i + 9] | (d[i + 10] << 8);
                                BOOST_CHECK_EQUAL (sample, 0);
                        }
  
 -                      if (sound_asset->channels() > 4) {
 +                      if (sound_asset->mxf()->channels() > 4) {
                                /* Ls should be silent */
                                int const sample = d[i + 11] | (d[i + 12] << 8);
                                BOOST_CHECK_EQUAL (sample, 0);
                        }
  
  
 -                      if (sound_asset->channels() > 5) {
 +                      if (sound_asset->mxf()->channels() > 5) {
                                /* Rs should be silent */
                                int const sample = d[i + 13] | (d[i + 14] << 8);
                                BOOST_CHECK_EQUAL (sample, 0);
  
  BOOST_AUTO_TEST_CASE (silence_padding_test)
  {
-       for (int i = 1; i < MAX_AUDIO_CHANNELS; ++i) {
+       for (int i = 1; i < MAX_DCP_AUDIO_CHANNELS; ++i) {
                test_silence_padding (i);
        }
  }