Add subtitle X offset option.
authorCarl Hetherington <cth@carlh.net>
Wed, 29 Jan 2014 22:03:05 +0000 (22:03 +0000)
committerCarl Hetherington <cth@carlh.net>
Wed, 29 Jan 2014 22:03:05 +0000 (22:03 +0000)
Suggested-by: Thierry Journet
ChangeLog
src/lib/ffmpeg_content.cc
src/lib/film.cc
src/lib/player.cc
src/lib/subtitle_content.cc
src/lib/subtitle_content.h
src/wx/subtitle_panel.cc
src/wx/subtitle_panel.h

index 84efa7546d905ad2bd4811d462be6c5909e84c28..38a37430faf29046321a12d6d1c81e529044a016 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,7 @@
 2014-01-29  Carl Hetherington  <cth@carlh.net>
 
+       * Add subtitle X offset option.
+
        * Fix missing subtitles when subtitled content is at a non-zero position.
 
 2014-01-28  Carl Hetherington  <cth@carlh.net>
index f59551d1d02bf0c888a20601386d2d066c7d05aa..2c5fcf70e1e09915245711103a1f76081a395680 100644 (file)
@@ -62,7 +62,7 @@ FFmpegContent::FFmpegContent (shared_ptr<const Film> f, shared_ptr<const cxml::N
        : Content (f, node)
        , VideoContent (f, node)
        , AudioContent (f, node)
-       , SubtitleContent (f, node)
+       , SubtitleContent (f, node, version)
 {
        list<cxml::NodePtr> c = node->node_children ("SubtitleStream");
        for (list<cxml::NodePtr>::const_iterator i = c.begin(); i != c.end(); ++i) {
index 1290cbda21fc67f44b924d323607262c1799bff4..8690d3ee0b97eb22e1080337ff4d7e1b27c88746 100644 (file)
@@ -83,8 +83,10 @@ using libdcp::Signer;
 
 /* 5 -> 6
  * AudioMapping XML changed.
+ * 6 -> 7
+ * Subtitle offset changed to subtitle y offset, and subtitle x offset added.
  */
-int const Film::state_version = 6;
+int const Film::state_version = 7;
 
 /** Construct a Film object in a given directory.
  *
index 1c54d0fc5d4a3259f7f44b082e9d9dfd6bf83f12..e661a7b3693930eac8b0348fd250de185a098706 100644 (file)
@@ -521,7 +521,11 @@ Player::content_changed (weak_ptr<Content> w, int property, bool frequent)
                _have_valid_pieces = false;
                Changed (frequent);
 
-       } else if (property == SubtitleContentProperty::SUBTITLE_OFFSET || property == SubtitleContentProperty::SUBTITLE_SCALE) {
+       } else if (
+               property == SubtitleContentProperty::SUBTITLE_X_OFFSET ||
+               property == SubtitleContentProperty::SUBTITLE_Y_OFFSET ||
+               property == SubtitleContentProperty::SUBTITLE_SCALE
+               ) {
 
                update_subtitle ();
                Changed (frequent);
@@ -658,7 +662,8 @@ Player::update_subtitle ()
        dcpomatic::Rect<double> in_rect = _in_subtitle.rect;
        libdcp::Size scaled_size;
 
-       in_rect.y += sc->subtitle_offset ();
+       in_rect.x += sc->subtitle_x_offset ();
+       in_rect.y += sc->subtitle_y_offset ();
 
        /* We will scale the subtitle up to fit _video_container_size, and also by the additional subtitle_scale */
        scaled_size.width = in_rect.width * _video_container_size.width * sc->subtitle_scale ();
index 6c0d3af86a6687571d74e3bb576add9494c67567..8f88574e5e7ff53950c903b710c571fe1b151cce 100644 (file)
@@ -30,25 +30,34 @@ using boost::shared_ptr;
 using boost::lexical_cast;
 using boost::dynamic_pointer_cast;
 
-int const SubtitleContentProperty::SUBTITLE_OFFSET = 500;
-int const SubtitleContentProperty::SUBTITLE_SCALE = 501;
+int const SubtitleContentProperty::SUBTITLE_X_OFFSET = 500;
+int const SubtitleContentProperty::SUBTITLE_Y_OFFSET = 501;
+int const SubtitleContentProperty::SUBTITLE_SCALE = 502;
 
 SubtitleContent::SubtitleContent (shared_ptr<const Film> f, boost::filesystem::path p)
        : Content (f, p)
-       , _subtitle_offset (0)
+       , _subtitle_x_offset (0)
+       , _subtitle_y_offset (0)
        , _subtitle_scale (1)
 {
 
 }
 
-SubtitleContent::SubtitleContent (shared_ptr<const Film> f, shared_ptr<const cxml::Node> node)
+SubtitleContent::SubtitleContent (shared_ptr<const Film> f, shared_ptr<const cxml::Node> node, int version)
        : Content (f, node)
-       , _subtitle_offset (0)
+       , _subtitle_x_offset (0)
+       , _subtitle_y_offset (0)
        , _subtitle_scale (1)
 {
        LocaleGuard lg;
+
+       if (version >= 7) {
+               _subtitle_x_offset = node->number_child<float> ("SubtitleXOffset");
+               _subtitle_y_offset = node->number_child<float> ("SubtitleYOffset");
+       } else {
+               _subtitle_y_offset = node->number_child<float> ("SubtitleOffset");
+       }
        
-       _subtitle_offset = node->number_child<float> ("SubtitleOffset");
        _subtitle_scale = node->number_child<float> ("SubtitleScale");
 }
 
@@ -61,8 +70,12 @@ SubtitleContent::SubtitleContent (shared_ptr<const Film> f, vector<shared_ptr<Co
        for (size_t i = 0; i < c.size(); ++i) {
                shared_ptr<SubtitleContent> sc = dynamic_pointer_cast<SubtitleContent> (c[i]);
 
-               if (sc->subtitle_offset() != ref->subtitle_offset()) {
-                       throw JoinError (_("Content to be joined must have the same subtitle offset."));
+               if (sc->subtitle_x_offset() != ref->subtitle_x_offset()) {
+                       throw JoinError (_("Content to be joined must have the same subtitle X offset."));
+               }
+               
+               if (sc->subtitle_y_offset() != ref->subtitle_y_offset()) {
+                       throw JoinError (_("Content to be joined must have the same subtitle Y offset."));
                }
 
                if (sc->subtitle_scale() != ref->subtitle_scale()) {
@@ -70,7 +83,8 @@ SubtitleContent::SubtitleContent (shared_ptr<const Film> f, vector<shared_ptr<Co
                }
        }
 
-       _subtitle_offset = ref->subtitle_offset ();
+       _subtitle_x_offset = ref->subtitle_x_offset ();
+       _subtitle_y_offset = ref->subtitle_y_offset ();
        _subtitle_scale = ref->subtitle_scale ();
 }
 
@@ -79,18 +93,29 @@ SubtitleContent::as_xml (xmlpp::Node* root) const
 {
        LocaleGuard lg;
        
-       root->add_child("SubtitleOffset")->add_child_text (lexical_cast<string> (_subtitle_offset));
+       root->add_child("SubtitleXOffset")->add_child_text (lexical_cast<string> (_subtitle_x_offset));
+       root->add_child("SubtitleYOffset")->add_child_text (lexical_cast<string> (_subtitle_y_offset));
        root->add_child("SubtitleScale")->add_child_text (lexical_cast<string> (_subtitle_scale));
 }
 
 void
-SubtitleContent::set_subtitle_offset (double o)
+SubtitleContent::set_subtitle_x_offset (double o)
+{
+       {
+               boost::mutex::scoped_lock lm (_mutex);
+               _subtitle_x_offset = o;
+       }
+       signal_changed (SubtitleContentProperty::SUBTITLE_X_OFFSET);
+}
+
+void
+SubtitleContent::set_subtitle_y_offset (double o)
 {
        {
                boost::mutex::scoped_lock lm (_mutex);
-               _subtitle_offset = o;
+               _subtitle_y_offset = o;
        }
-       signal_changed (SubtitleContentProperty::SUBTITLE_OFFSET);
+       signal_changed (SubtitleContentProperty::SUBTITLE_Y_OFFSET);
 }
 
 void
index 854647d181dfc065f11ed191b051d5c939965683..38863768889adb1cbea41dd019afc6fad1517ea0 100644 (file)
@@ -25,7 +25,8 @@
 class SubtitleContentProperty
 {
 public:
-       static int const SUBTITLE_OFFSET;
+       static int const SUBTITLE_X_OFFSET;
+       static int const SUBTITLE_Y_OFFSET;
        static int const SUBTITLE_SCALE;
 };
 
@@ -33,17 +34,23 @@ class SubtitleContent : public virtual Content
 {
 public:
        SubtitleContent (boost::shared_ptr<const Film>, boost::filesystem::path);
-       SubtitleContent (boost::shared_ptr<const Film>, boost::shared_ptr<const cxml::Node>);
+       SubtitleContent (boost::shared_ptr<const Film>, boost::shared_ptr<const cxml::Node>, int version);
        SubtitleContent (boost::shared_ptr<const Film>, std::vector<boost::shared_ptr<Content> >);
        
        void as_xml (xmlpp::Node *) const;
 
-       void set_subtitle_offset (double);
+       void set_subtitle_x_offset (double);
+       void set_subtitle_y_offset (double);
        void set_subtitle_scale (double);
 
-       double subtitle_offset () const {
+       double subtitle_x_offset () const {
                boost::mutex::scoped_lock lm (_mutex);
-               return _subtitle_offset;
+               return _subtitle_x_offset;
+       }
+
+       double subtitle_y_offset () const {
+               boost::mutex::scoped_lock lm (_mutex);
+               return _subtitle_y_offset;
        }
 
        double subtitle_scale () const {
@@ -53,11 +60,15 @@ public:
        
 private:
        friend class ffmpeg_pts_offset_test;
-       
+
+       /** x offset for placing subtitles, as a proportion of the container width;
+        * +ve is further right, -ve is further left.
+        */
+       double _subtitle_x_offset;
        /** y offset for placing subtitles, as a proportion of the container height;
-           +ve is further down the frame, -ve is further up.
-       */
-       double _subtitle_offset;
+        *  +ve is further down the frame, -ve is further up.
+        */
+       double _subtitle_y_offset;
        /** scale factor to apply to subtitles */
        double _subtitle_scale;
 };
index 0e3f2e89d389d8d25da1c3dfe43ae5817084f443..02c8776d6f8c5ea3a57e50e4885cf34bd6196d72 100644 (file)
@@ -41,14 +41,23 @@ SubtitlePanel::SubtitlePanel (FilmEditor* e)
        grid->AddSpacer (0);
        
        {
-               add_label_to_sizer (grid, this, _("Subtitle Offset"), true);
+               add_label_to_sizer (grid, this, _("Subtitle Offset"), true);
                wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
-               _offset = new wxSpinCtrl (this);
-               s->Add (_offset);
+               _x_offset = new wxSpinCtrl (this);
+               s->Add (_x_offset);
                add_label_to_sizer (s, this, _("%"), false);
                grid->Add (s);
        }
 
+       {
+               add_label_to_sizer (grid, this, _("Subtitle Y Offset"), true);
+               wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
+               _y_offset = new wxSpinCtrl (this);
+               s->Add (_y_offset);
+               add_label_to_sizer (s, this, _("%"), false);
+               grid->Add (s);
+       }
+       
        {
                add_label_to_sizer (grid, this, _("Subtitle Scale"), true);
                wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
@@ -62,12 +71,14 @@ SubtitlePanel::SubtitlePanel (FilmEditor* e)
        _stream = new wxChoice (this, wxID_ANY);
        grid->Add (_stream, 1, wxEXPAND);
        
-       _offset->SetRange (-100, 100);
+       _x_offset->SetRange (-100, 100);
+       _y_offset->SetRange (-100, 100);
        _scale->SetRange (1, 1000);
        _scale->SetValue (100);
 
        _with_subtitles->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&SubtitlePanel::with_subtitles_toggled, this));
-       _offset->Bind         (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&SubtitlePanel::offset_changed, this));
+       _x_offset->Bind       (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&SubtitlePanel::x_offset_changed, this));
+       _y_offset->Bind       (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&SubtitlePanel::y_offset_changed, this));
        _scale->Bind          (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&SubtitlePanel::scale_changed, this));
        _stream->Bind         (wxEVT_COMMAND_CHOICE_SELECTED,  boost::bind (&SubtitlePanel::stream_changed, this));
 }
@@ -119,8 +130,10 @@ SubtitlePanel::film_content_changed (int property)
                        }
                }
                setup_sensitivity ();
-       } else if (property == SubtitleContentProperty::SUBTITLE_OFFSET) {
-               checked_set (_offset, scs ? (scs->subtitle_offset() * 100) : 0);
+       } else if (property == SubtitleContentProperty::SUBTITLE_X_OFFSET) {
+               checked_set (_x_offset, scs ? (scs->subtitle_x_offset() * 100) : 0);
+       } else if (property == SubtitleContentProperty::SUBTITLE_Y_OFFSET) {
+               checked_set (_y_offset, scs ? (scs->subtitle_y_offset() * 100) : 0);
        } else if (property == SubtitleContentProperty::SUBTITLE_SCALE) {
                checked_set (_scale, scs ? (scs->subtitle_scale() * 100) : 100);
        }
@@ -147,7 +160,8 @@ SubtitlePanel::setup_sensitivity ()
        }
        
        _with_subtitles->Enable (h);
-       _offset->Enable (j);
+       _x_offset->Enable (j);
+       _y_offset->Enable (j);
        _scale->Enable (j);
        _stream->Enable (j);
 }
@@ -175,11 +189,20 @@ SubtitlePanel::stream_changed ()
 }
 
 void
-SubtitlePanel::offset_changed ()
+SubtitlePanel::x_offset_changed ()
+{
+       SubtitleContentList c = _editor->selected_subtitle_content ();
+       if (c.size() == 1) {
+               c.front()->set_subtitle_x_offset (_x_offset->GetValue() / 100.0);
+       }
+}
+
+void
+SubtitlePanel::y_offset_changed ()
 {
        SubtitleContentList c = _editor->selected_subtitle_content ();
        if (c.size() == 1) {
-               c.front()->set_subtitle_offset (_offset->GetValue() / 100.0);
+               c.front()->set_subtitle_y_offset (_y_offset->GetValue() / 100.0);
        }
 }
 
@@ -196,6 +219,7 @@ void
 SubtitlePanel::content_selection_changed ()
 {
        film_content_changed (FFmpegContentProperty::SUBTITLE_STREAMS);
-       film_content_changed (SubtitleContentProperty::SUBTITLE_OFFSET);
+       film_content_changed (SubtitleContentProperty::SUBTITLE_X_OFFSET);
+       film_content_changed (SubtitleContentProperty::SUBTITLE_Y_OFFSET);
        film_content_changed (SubtitleContentProperty::SUBTITLE_SCALE);
 }
index 19df26436af6c79cd7c8712d6ba568616dbac2a0..20d7c40c2eb1d3eb1add4350a1b1482b3cbfc2a1 100644 (file)
@@ -33,14 +33,16 @@ public:
        
 private:
        void with_subtitles_toggled ();
-       void offset_changed ();
+       void x_offset_changed ();
+       void y_offset_changed ();
        void scale_changed ();
        void stream_changed ();
 
        void setup_sensitivity ();
        
        wxCheckBox* _with_subtitles;
-       wxSpinCtrl* _offset;
+       wxSpinCtrl* _x_offset;
+       wxSpinCtrl* _y_offset;
        wxSpinCtrl* _scale;
        wxChoice* _stream;
 };