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>
: 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) {
/* 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.
*
_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);
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 ();
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");
}
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()) {
}
}
- _subtitle_offset = ref->subtitle_offset ();
+ _subtitle_x_offset = ref->subtitle_x_offset ();
+ _subtitle_y_offset = ref->subtitle_y_offset ();
_subtitle_scale = ref->subtitle_scale ();
}
{
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
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;
};
{
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 {
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;
};
grid->AddSpacer (0);
{
- add_label_to_sizer (grid, this, _("Subtitle Offset"), true);
+ add_label_to_sizer (grid, this, _("Subtitle X 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);
_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));
}
}
}
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);
}
}
_with_subtitles->Enable (h);
- _offset->Enable (j);
+ _x_offset->Enable (j);
+ _y_offset->Enable (j);
_scale->Enable (j);
_stream->Enable (j);
}
}
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);
}
}
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);
}
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;
};