Merge master.
authorCarl Hetherington <cth@carlh.net>
Thu, 12 Jun 2014 21:27:50 +0000 (22:27 +0100)
committerCarl Hetherington <cth@carlh.net>
Thu, 12 Jun 2014 21:27:50 +0000 (22:27 +0100)
1  2 
ChangeLog
src/lib/video_content.cc
src/lib/video_content.h
src/tools/dcpomatic.cc

diff --combined ChangeLog
index 126730e27f8e232e481b470e7fda00549606f49e,41713f4d27a2097bfbf6c72472b51eac33c8fa7b..3194262ef06886fa797af33075cf0ad15cf0948f
+++ b/ChangeLog
@@@ -1,9 -1,12 +1,16 @@@
 +2014-03-07  Carl Hetherington  <cth@carlh.net>
 +
 +      * Add subtitle view.
 +
  2014-06-12  Carl Hetherington  <cth@carlh.net>
  
+       * Version 1.69.27 released.
+ 2014-06-12  Carl Hetherington  <cth@carlh.net>
+       * Add Content menu with "scale to fit width" and "scale
+       to fit height" options.
        * Version 1.69.26 released.
  
  2014-06-12  Carl Hetherington  <cth@carlh.net>
diff --combined src/lib/video_content.cc
index f871f2df666438a1846d465642f8cb991e729723,6f6b2c4415cdfe9ae6440b21853b82bc9baffed6..05f5c538eee2a81c6344f603ab2bfa3e60dfd2cb
@@@ -19,8 -19,8 +19,8 @@@
  
  #include <iomanip>
  #include <libcxml/cxml.h>
 -#include <libdcp/colour_matrix.h>
 -#include <libdcp/raw_convert.h>
 +#include <dcp/colour_matrix.h>
 +#include <dcp/raw_convert.h>
  #include "video_content.h"
  #include "video_examiner.h"
  #include "compose.hpp"
@@@ -46,10 -46,12 +46,12 @@@ using std::stringstream
  using std::setprecision;
  using std::cout;
  using std::vector;
+ using std::min;
+ using std::max;
  using boost::shared_ptr;
  using boost::optional;
  using boost::dynamic_pointer_cast;
 -using libdcp::raw_convert;
 +using dcp::raw_convert;
  
  vector<VideoContentScale> VideoContentScale::_scales;
  
@@@ -63,7 -65,7 +65,7 @@@ VideoContent::VideoContent (shared_ptr<
        setup_default_colour_conversion ();
  }
  
 -VideoContent::VideoContent (shared_ptr<const Film> f, Time s, VideoContent::Frame len)
 +VideoContent::VideoContent (shared_ptr<const Film> f, DCPTime s, ContentTime len)
        : Content (f, s)
        , _video_length (len)
        , _video_frame_rate (0)
@@@ -83,20 -85,13 +85,20 @@@ VideoContent::VideoContent (shared_ptr<
        setup_default_colour_conversion ();
  }
  
 -VideoContent::VideoContent (shared_ptr<const Film> f, shared_ptr<const cxml::Node> node, int version)
 +VideoContent::VideoContent (shared_ptr<const Film> f, cxml::ConstNodePtr node, int version)
        : Content (f, node)
  {
 -      _video_length = node->number_child<VideoContent::Frame> ("VideoLength");
        _video_size.width = node->number_child<int> ("VideoWidth");
        _video_size.height = node->number_child<int> ("VideoHeight");
        _video_frame_rate = node->number_child<float> ("VideoFrameRate");
 +
 +      if (version < 32) {
 +              /* DCP-o-matic 1.0 branch */
 +              _video_length = ContentTime::from_frames (node->number_child<int64_t> ("VideoLength"), _video_frame_rate);
 +      } else {
 +              _video_length = ContentTime (node->number_child<int64_t> ("VideoLength"));
 +      }
 +      
        _video_frame_type = static_cast<VideoFrameType> (node->number_child<int> ("VideoFrameType"));
        _crop.left = node->number_child<int> ("LeftCrop");
        _crop.right = node->number_child<int> ("RightCrop");
@@@ -164,7 -159,7 +166,7 @@@ voi
  VideoContent::as_xml (xmlpp::Node* node) const
  {
        boost::mutex::scoped_lock lm (_mutex);
 -      node->add_child("VideoLength")->add_child_text (raw_convert<string> (_video_length));
 +      node->add_child("VideoLength")->add_child_text (raw_convert<string> (_video_length.get ()));
        node->add_child("VideoWidth")->add_child_text (raw_convert<string> (_video_size.width));
        node->add_child("VideoHeight")->add_child_text (raw_convert<string> (_video_size.height));
        node->add_child("VideoFrameRate")->add_child_text (raw_convert<string> (_video_frame_rate));
  void
  VideoContent::setup_default_colour_conversion ()
  {
 -      _colour_conversion = PresetColourConversion (_("sRGB"), 2.4, true, libdcp::colour_matrix::srgb_to_xyz, 2.6).conversion;
 +      _colour_conversion = PresetColourConversion (_("sRGB"), 2.4, true, dcp::colour_matrix::srgb_to_xyz, 2.6).conversion;
  }
  
  void
  VideoContent::take_from_video_examiner (shared_ptr<VideoExaminer> d)
  {
        /* These examiner calls could call other content methods which take a lock on the mutex */
 -      libdcp::Size const vs = d->video_size ();
 +      dcp::Size const vs = d->video_size ();
        float const vfr = d->video_frame_rate ();
        
        {
@@@ -325,17 -320,14 +327,17 @@@ VideoContent::technical_summary () cons
  {
        return String::compose (
                "video: length %1, size %2x%3, rate %4",
 -              video_length_after_3d_combine(), video_size().width, video_size().height, video_frame_rate()
 +              video_length_after_3d_combine().seconds(),
 +              video_size().width,
 +              video_size().height,
 +              video_frame_rate()
                );
  }
  
 -libdcp::Size
 +dcp::Size
  VideoContent::video_size_after_3d_split () const
  {
 -      libdcp::Size const s = video_size ();
 +      dcp::Size const s = video_size ();
        switch (video_frame_type ()) {
        case VIDEO_FRAME_TYPE_2D:
        case VIDEO_FRAME_TYPE_3D_ALTERNATE:
        case VIDEO_FRAME_TYPE_3D_RIGHT:
                return s;
        case VIDEO_FRAME_TYPE_3D_LEFT_RIGHT:
 -              return libdcp::Size (s.width / 2, s.height);
 +              return dcp::Size (s.width / 2, s.height);
        case VIDEO_FRAME_TYPE_3D_TOP_BOTTOM:
 -              return libdcp::Size (s.width, s.height / 2);
 +              return dcp::Size (s.width, s.height / 2);
        }
  
        assert (false);
@@@ -363,23 -355,56 +365,49 @@@ VideoContent::set_colour_conversion (Co
  }
  
  /** @return Video size after 3D split and crop */
 -libdcp::Size
 +dcp::Size
  VideoContent::video_size_after_crop () const
  {
        return crop().apply (video_size_after_3d_split ());
  }
  
  /** @param t A time offset from the start of this piece of content.
 - *  @return Corresponding frame index.
 + *  @return Corresponding time with respect to the content.
   */
 -VideoContent::Frame
 -VideoContent::time_to_content_video_frames (Time t) const
 +ContentTime
 +VideoContent::dcp_time_to_content_time (DCPTime t) const
  {
        shared_ptr<const Film> film = _film.lock ();
        assert (film);
 -      
 -      FrameRateChange frc (video_frame_rate(), film->video_frame_rate());
 -
 -      /* Here we are converting from time (in the DCP) to a frame number in the content.
 -         Hence we need to use the DCP's frame rate and the double/skip correction, not
 -         the source's rate.
 -      */
 -      return t * film->video_frame_rate() / (frc.factor() * TIME_HZ);
 +      return ContentTime (t, FrameRateChange (video_frame_rate(), film->video_frame_rate()));
  }
  
+ void
+ VideoContent::scale_and_crop_to_fit_width ()
+ {
+       shared_ptr<const Film> film = _film.lock ();
+       assert (film);
+       set_scale (VideoContentScale (film->container ()));
+       int const crop = max (0, int (video_size().height - double (film->frame_size().height) * video_size().width / film->frame_size().width));
+       set_top_crop (crop / 2);
+       set_bottom_crop (crop / 2);
+ }
+ void
+ VideoContent::scale_and_crop_to_fit_height ()
+ {
+       shared_ptr<const Film> film = _film.lock ();
+       assert (film);
+       set_scale (VideoContentScale (film->container ()));
+       int const crop = max (0, int (video_size().width - double (film->frame_size().width) * video_size().height / film->frame_size().height));
+       set_left_crop (crop / 2);
+       set_right_crop (crop / 2);
+ }
  VideoContentScale::VideoContentScale (Ratio const * r)
        : _ratio (r)
        , _scale (true)
@@@ -401,7 -426,7 +429,7 @@@ VideoContentScale::VideoContentScale (b
  
  }
  
 -VideoContentScale::VideoContentScale (shared_ptr<cxml::Node> node)
 +VideoContentScale::VideoContentScale (cxml::NodePtr node)
        : _ratio (0)
        , _scale (true)
  {
@@@ -454,14 -479,14 +482,14 @@@ VideoContentScale::name () cons
  /** @param display_container Size of the container that we are displaying this content in.
   *  @param film_container The size of the film's image.
   */
 -libdcp::Size
 -VideoContentScale::size (shared_ptr<const VideoContent> c, libdcp::Size display_container, libdcp::Size film_container) const
 +dcp::Size
 +VideoContentScale::size (shared_ptr<const VideoContent> c, dcp::Size display_container, dcp::Size film_container) const
  {
        if (_ratio) {
                return fit_ratio_within (_ratio->ratio (), display_container);
        }
  
 -      libdcp::Size const ac = c->video_size_after_crop ();
 +      dcp::Size const ac = c->video_size_after_crop ();
  
        /* Force scale if the film_container is smaller than the content's image */
        if (_scale || film_container.width < ac.width || film_container.height < ac.height) {
        /* Scale the image so that it will be in the right place in film_container, even if display_container is a
           different size.
        */
 -      return libdcp::Size (
 +      return dcp::Size (
                c->video_size().width  * float(display_container.width)  / film_container.width,
                c->video_size().height * float(display_container.height) / film_container.height
                );
diff --combined src/lib/video_content.h
index 8313c73eeb8a32b8d65a79e2caa6d22466966042,f23bf0abe87980746b892def1244ff7241f38c0d..4206efc2c487d047a744d6634271f810d6d447e2
@@@ -43,9 -43,9 +43,9 @@@ public
        VideoContentScale ();
        VideoContentScale (Ratio const *);
        VideoContentScale (bool);
 -      VideoContentScale (boost::shared_ptr<cxml::Node>);
 +      VideoContentScale (cxml::NodePtr);
  
 -      libdcp::Size size (boost::shared_ptr<const VideoContent>, libdcp::Size, libdcp::Size) const;
 +      dcp::Size size (boost::shared_ptr<const VideoContent>, dcp::Size, dcp::Size) const;
        std::string id () const;
        std::string name () const;
        void as_xml (xmlpp::Node *) const;
@@@ -81,9 -81,9 +81,9 @@@ public
        typedef int Frame;
  
        VideoContent (boost::shared_ptr<const Film>);
 -      VideoContent (boost::shared_ptr<const Film>, Time, VideoContent::Frame);
 +      VideoContent (boost::shared_ptr<const Film>, DCPTime, ContentTime);
        VideoContent (boost::shared_ptr<const Film>, boost::filesystem::path);
 -      VideoContent (boost::shared_ptr<const Film>, boost::shared_ptr<const cxml::Node>, int);
 +      VideoContent (boost::shared_ptr<const Film>, cxml::ConstNodePtr, int);
        VideoContent (boost::shared_ptr<const Film>, std::vector<boost::shared_ptr<Content> >);
  
        void as_xml (xmlpp::Node *) const;
        virtual std::string information () const;
        virtual std::string identifier () const;
  
 -      VideoContent::Frame video_length () const {
 +      ContentTime video_length () const {
                boost::mutex::scoped_lock lm (_mutex);
                return _video_length;
        }
  
 -      VideoContent::Frame video_length_after_3d_combine () const {
 +      ContentTime video_length_after_3d_combine () const {
                boost::mutex::scoped_lock lm (_mutex);
                if (_video_frame_type == VIDEO_FRAME_TYPE_3D_ALTERNATE) {
 -                      return _video_length / 2;
 +                      return ContentTime (_video_length.get() / 2);
                }
                
                return _video_length;
        }
  
 -      libdcp::Size video_size () const {
 +      dcp::Size video_size () const {
                boost::mutex::scoped_lock lm (_mutex);
                return _video_size;
        }
                return _colour_conversion;
        }
  
 -      libdcp::Size video_size_after_3d_split () const;
 -      libdcp::Size video_size_after_crop () const;
 +      dcp::Size video_size_after_3d_split () const;
 +      dcp::Size video_size_after_crop () const;
  
 -      VideoContent::Frame time_to_content_video_frames (Time) const;
 +      ContentTime dcp_time_to_content_time (DCPTime) const;
  
+       void scale_and_crop_to_fit_width ();
+       void scale_and_crop_to_fit_height ();
  protected:
        void take_from_video_examiner (boost::shared_ptr<VideoExaminer>);
  
 -      VideoContent::Frame _video_length;
 +      ContentTime _video_length;
        float _video_frame_rate;
  
  private:
  
        void setup_default_colour_conversion ();
        
 -      libdcp::Size _video_size;
 +      dcp::Size _video_size;
        VideoFrameType _video_frame_type;
        Crop _crop;
        VideoContentScale _scale;
diff --combined src/tools/dcpomatic.cc
index 23c1e500512a750f17468445a2cfcfd1cd78f7de,c9d17eb9b7ee4ce92939fe51bdc1db599bd058d7..d46ddf1d712ab171f403e689de32f9395156ab6d
@@@ -72,16 -72,12 +72,12 @@@ using std::exception
  using boost::shared_ptr;
  using boost::dynamic_pointer_cast;
  
- static FilmEditor* film_editor = 0;
- static FilmViewer* film_viewer = 0;
  static shared_ptr<Film> film;
  static std::string film_to_load;
  static std::string film_to_create;
  static std::string content_to_add;
  static wxMenu* jobs_menu = 0;
  
- static void set_menu_sensitivity ();
  // #define DCPOMATIC_WINDOWS_CONSOLE 1
  
  class FilmChangedDialog
@@@ -159,10 -155,11 +155,11 @@@ load_film (boost::filesystem::path file
        }
  }
  
- #define ALWAYS                  0x0
- #define NEEDS_FILM              0x1
- #define NOT_DURING_DCP_CREATION 0x2
- #define NEEDS_CPL               0x4
+ #define ALWAYS                       0x0
+ #define NEEDS_FILM                   0x1
+ #define NOT_DURING_DCP_CREATION      0x2
+ #define NEEDS_CPL                    0x4
+ #define NEEDS_SELECTED_VIDEO_CONTENT 0x8
  
  map<wxMenuItem*, int> menu_items;
        
@@@ -173,42 -170,13 +170,13 @@@ add_item (wxMenu* menu, wxString text, 
        menu_items.insert (make_pair (item, sens));
  }
  
- static void
- set_menu_sensitivity ()
- {
-       list<shared_ptr<Job> > jobs = JobManager::instance()->get ();
-       list<shared_ptr<Job> >::iterator i = jobs.begin();
-       while (i != jobs.end() && dynamic_pointer_cast<TranscodeJob> (*i) == 0) {
-               ++i;
-       }
-       bool const dcp_creation = (i != jobs.end ()) && !(*i)->finished ();
-       bool const have_cpl = film && !film->cpls().empty ();
-       for (map<wxMenuItem*, int>::iterator j = menu_items.begin(); j != menu_items.end(); ++j) {
-               bool enabled = true;
-               if ((j->second & NEEDS_FILM) && film == 0) {
-                       enabled = false;
-               }
-               if ((j->second & NOT_DURING_DCP_CREATION) && dcp_creation) {
-                       enabled = false;
-               }
-               if ((j->second & NEEDS_CPL) && !have_cpl) {
-                       enabled = false;
-               }
-               
-               j->first->Enable (enabled);
-       }
- }
  enum {
        ID_file_new = 1,
        ID_file_open,
        ID_file_save,
        ID_file_properties,
+       ID_content_scale_to_fit_width,
+       ID_content_scale_to_fit_height,
        ID_jobs_make_dcp,
        ID_jobs_make_kdms,
        ID_jobs_send_dcp_to_tms,
@@@ -244,7 -212,11 +212,11 @@@ setup_menu (wxMenuBar* m
  #else
        wxMenu* edit = new wxMenu;
        add_item (edit, _("&Preferences..."), wxID_PREFERENCES, ALWAYS);
- #endif        
+ #endif
+       wxMenu* content = new wxMenu;
+       add_item (content, _("Scale to fit &width"), ID_content_scale_to_fit_width, NEEDS_FILM | NEEDS_SELECTED_VIDEO_CONTENT);
+       add_item (content, _("Scale to fit &height"), ID_content_scale_to_fit_height, NEEDS_FILM | NEEDS_SELECTED_VIDEO_CONTENT);
  
        jobs_menu = new wxMenu;
        add_item (jobs_menu, _("&Make DCP"), ID_jobs_make_dcp, NEEDS_FILM | NOT_DURING_DCP_CREATION);
        m->Append (file, _("&File"));
  #ifndef __WXOSX__     
        m->Append (edit, _("&Edit"));
- #endif        
+ #endif
+       m->Append (content, _("&Content"));
        m->Append (jobs_menu, _("&Jobs"));
        m->Append (tools, _("&Tools"));
        m->Append (help, _("&Help"));
@@@ -308,6 -281,8 +281,8 @@@ public
                Bind (wxEVT_COMMAND_MENU_SELECTED, boost::bind (&Frame::file_properties, this),         ID_file_properties);
                Bind (wxEVT_COMMAND_MENU_SELECTED, boost::bind (&Frame::file_exit, this),               wxID_EXIT);
                Bind (wxEVT_COMMAND_MENU_SELECTED, boost::bind (&Frame::edit_preferences, this),        wxID_PREFERENCES);
+               Bind (wxEVT_COMMAND_MENU_SELECTED, boost::bind (&Frame::content_scale_to_fit_width, this), ID_content_scale_to_fit_width);
+               Bind (wxEVT_COMMAND_MENU_SELECTED, boost::bind (&Frame::content_scale_to_fit_height, this), ID_content_scale_to_fit_height);
                Bind (wxEVT_COMMAND_MENU_SELECTED, boost::bind (&Frame::jobs_make_dcp, this),           ID_jobs_make_dcp);
                Bind (wxEVT_COMMAND_MENU_SELECTED, boost::bind (&Frame::jobs_make_kdms, this),          ID_jobs_make_kdms);
                Bind (wxEVT_COMMAND_MENU_SELECTED, boost::bind (&Frame::jobs_send_dcp_to_tms, this),    ID_jobs_send_dcp_to_tms);
                */
                wxPanel* overall_panel = new wxPanel (this, wxID_ANY);
  
-               film_editor = new FilmEditor (film, overall_panel);
-               film_viewer = new FilmViewer (film, overall_panel);
+               _film_editor = new FilmEditor (film, overall_panel);
+               _film_viewer = new FilmViewer (film, overall_panel);
                JobManagerView* job_manager_view = new JobManagerView (overall_panel, static_cast<JobManagerView::Buttons> (0));
  
                wxBoxSizer* right_sizer = new wxBoxSizer (wxVERTICAL);
-               right_sizer->Add (film_viewer, 2, wxEXPAND | wxALL, 6);
+               right_sizer->Add (_film_viewer, 2, wxEXPAND | wxALL, 6);
                right_sizer->Add (job_manager_view, 1, wxEXPAND | wxALL, 6);
  
                wxBoxSizer* main_sizer = new wxBoxSizer (wxHORIZONTAL);
-               main_sizer->Add (film_editor, 1, wxEXPAND | wxALL, 6);
+               main_sizer->Add (_film_editor, 1, wxEXPAND | wxALL, 6);
                main_sizer->Add (right_sizer, 2, wxEXPAND | wxALL, 6);
  
                set_menu_sensitivity ();
  
-               film_editor->FileChanged.connect (bind (&Frame::file_changed, this, _1));
+               _film_editor->FileChanged.connect (bind (&Frame::file_changed, this, _1));
                if (film) {
                        file_changed (film->directory ());
                } else {
                        file_changed ("");
                }
  
-               JobManager::instance()->ActiveJobsChanged.connect (boost::bind (set_menu_sensitivity));
+               JobManager::instance()->ActiveJobsChanged.connect (boost::bind (&Frame::set_menu_sensitivity, this));
  
                set_film ();
                overall_panel->SetSizer (main_sizer);
@@@ -355,8 -330,8 +330,8 @@@ private
  
        void set_film ()
        {
-               film_viewer->set_film (film);
-               film_editor->set_film (film);
+               _film_viewer->set_film (film);
+               _film_editor->set_film (film);
                set_menu_sensitivity ();
        }
  
        
                d->Destroy ();
        }
+       void content_scale_to_fit_width ()
+       {
+               VideoContentList vc = _film_editor->selected_video_content ();
+               for (VideoContentList::iterator i = vc.begin(); i != vc.end(); ++i) {
+                       (*i)->scale_and_crop_to_fit_width ();
+               }
+       }
+       void content_scale_to_fit_height ()
+       {
+               VideoContentList vc = _film_editor->selected_video_content ();
+               for (VideoContentList::iterator i = vc.begin(); i != vc.end(); ++i) {
+                       (*i)->scale_and_crop_to_fit_height ();
+               }
+       }
        
        void jobs_send_dcp_to_tms ()
        {
                ev.Skip ();
        }
  
+       void set_menu_sensitivity ()
+       {
+               list<shared_ptr<Job> > jobs = JobManager::instance()->get ();
+               list<shared_ptr<Job> >::iterator i = jobs.begin();
+               while (i != jobs.end() && dynamic_pointer_cast<TranscodeJob> (*i) == 0) {
+                       ++i;
+               }
+               bool const dcp_creation = (i != jobs.end ()) && !(*i)->finished ();
+               bool const have_cpl = film && !film->cpls().empty ();
+               bool const have_selected_video_content = !_film_editor->selected_video_content().empty();
+               
+               for (map<wxMenuItem*, int>::iterator j = menu_items.begin(); j != menu_items.end(); ++j) {
+                       
+                       bool enabled = true;
+                       
+                       if ((j->second & NEEDS_FILM) && film == 0) {
+                               enabled = false;
+                       }
+                       
+                       if ((j->second & NOT_DURING_DCP_CREATION) && dcp_creation) {
+                               enabled = false;
+                       }
+                       
+                       if ((j->second & NEEDS_CPL) && !have_cpl) {
+                               enabled = false;
+                       }
+                       
+                       if ((j->second & NEEDS_SELECTED_VIDEO_CONTENT) && !have_selected_video_content) {
+                               enabled = false;
+                       }
+                       
+                       j->first->Enable (enabled);
+               }
+       }
+       
+       FilmEditor* _film_editor;
+       FilmViewer* _film_viewer;
        HintsDialog* _hints_dialog;
        ServersListDialog* _servers_list_dialog;
        wxPreferencesEditor* _config_dialog;
@@@ -615,9 -643,6 +643,9 @@@ static const wxCmdLineEntryDesc command
        { wxCMD_LINE_NONE, "", "", "", wxCmdLineParamType (0), 0 }
  };
  
 +/** @class App
 + *  @brief The magic App class for wxWidgets.
 + */
  class App : public wxApp
  {
        bool OnInit ()