diff options
| author | Carl Hetherington <cth@carlh.net> | 2015-01-10 00:07:47 +0000 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2015-01-10 00:07:47 +0000 |
| commit | 67a414dc3826761c8933640e85560644f5f02310 (patch) | |
| tree | 6fc3ab11423d5fdd15847890be56bb98ed241852 /src | |
| parent | 9fc6bcde891567ca04fe2d9835ab48a17c9b69a7 (diff) | |
Fix handling of timing in SMPTE subtitles.
Diffstat (limited to 'src')
| -rw-r--r-- | src/dcp_time.cc | 98 | ||||
| -rw-r--r-- | src/dcp_time.h | 42 | ||||
| -rw-r--r-- | src/font.cc | 21 | ||||
| -rw-r--r-- | src/font.h | 7 | ||||
| -rw-r--r-- | src/interop_subtitle_content.cc | 16 | ||||
| -rw-r--r-- | src/smpte_subtitle_content.cc | 13 | ||||
| -rw-r--r-- | src/subtitle.cc | 39 | ||||
| -rw-r--r-- | src/subtitle.h | 5 | ||||
| -rw-r--r-- | src/text.cc | 9 | ||||
| -rw-r--r-- | src/text.h | 5 |
10 files changed, 151 insertions, 104 deletions
diff --git a/src/dcp_time.cc b/src/dcp_time.cc index 4033e5dd..83a7f2bb 100644 --- a/src/dcp_time.cc +++ b/src/dcp_time.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net> + Copyright (C) 2012-2015 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 @@ -33,31 +33,23 @@ using namespace std; using namespace boost; using namespace dcp; -Time::Time (int frame, int frames_per_second) +Time::Time (int frame, int frames_per_second, int tcr_) : h (0) , m (0) , s (0) - , t (0) + , e (0) + , tcr (tcr_) { - set (double (frame) / frames_per_second); -} - -Time::Time (int64_t ticks) -{ - h = ticks / (60 * 60 * 250); - ticks -= int64_t (h) * 60 * 60 * 250; - m = ticks / (60 * 250); - ticks -= int64_t (m) * 60 * 250; - s = ticks / 250; - ticks -= int64_t (s) * 250; - t = ticks; + set (double (frame) / frames_per_second, tcr); } void -Time::set (double ss) +Time::set (double seconds, int tcr_) { - s = floor (ss); - t = int (round (1000 * (ss - s) / 4)); + s = floor (seconds); + tcr = tcr_; + + e = int (round ((seconds - s) * tcr)); if (s >= 60) { m = s / 60; @@ -70,7 +62,8 @@ Time::set (double ss) } } -Time::Time (string time) +Time::Time (string time, int tcr_) + : tcr (tcr_) { vector<string> b; split (b, time, is_any_of (":")); @@ -81,13 +74,13 @@ Time::Time (string time) h = raw_convert<int> (b[0]); m = raw_convert<int> (b[1]); s = raw_convert<int> (b[2]); - t = raw_convert<int> (b[3]); + e = raw_convert<int> (b[3]); } bool dcp::operator== (Time const & a, Time const & b) { - return (a.h == b.h && a.m == b.m && a.s == b.s && a.t == b.t); + return (a.h == b.h && a.m == b.m && a.s == b.s && (a.e * b.tcr) == (b.e * a.tcr)); } bool @@ -123,8 +116,8 @@ dcp::operator< (Time const & a, Time const & b) return a.s < b.s; } - if (a.t != b.t) { - return a.t < b.t; + if ((a.e * b.tcr) != (b.e * a.tcr)) { + return (a.e * b.tcr) < (b.e * a.tcr); } return true; @@ -145,8 +138,8 @@ dcp::operator> (Time const & a, Time const & b) return a.s > b.s; } - if (a.t != b.t) { - return a.t > b.t; + if ((a.e * b.tcr) != (b.e * a.tcr)) { + return (a.e * b.tcr) > (b.e * a.tcr); } return true; @@ -155,18 +148,27 @@ dcp::operator> (Time const & a, Time const & b) ostream & dcp::operator<< (ostream& s, Time const & t) { - s << t.h << ":" << t.m << ":" << t.s << "." << t.t; + s << t.h << ":" << t.m << ":" << t.s << "." << t.e; return s; } dcp::Time -dcp::operator+ (Time a, Time const & b) +dcp::operator+ (Time a, Time b) { Time r; - r.t = a.t + b.t; - if (r.t >= 250) { - r.t -= 250; + /* Make sure we have a common tcr */ + if (a.tcr != b.tcr) { + a.e *= b.tcr; + b.e *= a.tcr; + r.tcr = a.tcr * b.tcr; + } else { + r.tcr = a.tcr; + } + + r.e = a.e + b.e; + if (r.e >= r.tcr) { + r.e -= r.tcr; r.s++; } @@ -188,13 +190,22 @@ dcp::operator+ (Time a, Time const & b) } dcp::Time -dcp::operator- (Time a, Time const & b) +dcp::operator- (Time a, Time b) { Time r; - r.t = a.t - b.t; - if (r.t < 0) { - r.t += 250; + /* Make sure we have a common tcr */ + if (a.tcr != b.tcr) { + a.e *= b.tcr; + b.e *= a.tcr; + r.tcr = a.tcr * b.tcr; + } else { + r.tcr = a.tcr; + } + + r.e = a.e - b.e; + if (r.e < 0) { + r.e += r.tcr; r.s--; } @@ -218,29 +229,22 @@ dcp::operator- (Time a, Time const & b) float dcp::operator/ (Time a, Time const & b) { - int64_t const at = a.h * 3600 * 250 + a.m * 60 * 250 + a.s * 250 + a.t; - int64_t const bt = b.h * 3600 * 250 + b.m * 60 * 250 + b.s * 250 + b.t; + int64_t const at = a.h * 3600 + a.m * 60 + a.s * float (a.e) / a.tcr; + int64_t const bt = b.h * 3600 + b.m * 60 + b.s * float (b.e) / b.tcr; return float (at) / bt; } -/** @return A string of the form h:m:s:t */ +/** @return A string of the form h:m:s:e */ string Time::to_string () const { stringstream str; - str << h << ":" << m << ":" << s << ":" << t; + str << h << ":" << m << ":" << s << ":" << e; return str.str (); } -/** @return This time in ticks */ int64_t -Time::to_ticks () const -{ - return int64_t(t) + int64_t(s) * 250 + int64_t(m) * 60 * 250 + int64_t(h) * 60 * 60 * 250; -} - -double -Time::to_seconds () const +Time::to_editable_units (int tcr_) const { - return double (to_ticks ()) / 250; + return (int64_t(e) * float (tcr_ / tcr)) + int64_t(s) * tcr_ + int64_t(m) * 60 * tcr_ + int64_t(h) * 60 * 60 * tcr_; } diff --git a/src/dcp_time.h b/src/dcp_time.h index 70bc5573..23f860cf 100644 --- a/src/dcp_time.h +++ b/src/dcp_time.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net> + Copyright (C) 2012-2015 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 @@ -37,41 +37,41 @@ namespace dcp { class Time { public: - Time () : h (0), m (0), s (0), t (0) {} + Time () : h (0), m (0), s (0), e (0), tcr (1) {} - Time (int64_t ticks); - - /** Construct a Time from a frame index (starting from 0) - * and a frames per second count. + /** Construct a Time from a frame index (starting from 0), + * a frames per second count and a timecode rate. */ - Time (int frame, int frames_per_second); + Time (int frame, int frames_per_second, int tcr); - /** Construct a Time from hours, minutes, seconds and ticks. + /** Construct a Time from hours, minutes, seconds, editable units and a timecode rate. * @param h_ Hours. * @param m_ Minutes. * @param s_ Seconds. - * @param t_ Ticks (where 1 tick is 4 milliseconds). + * @param e_ Editable units (where 1 editable unit is 1 / tcr_ seconds) + * @param tcr_ Timecode rate; i.e. number of editable units per second. */ - Time (int h_, int m_, int s_, int t_) + Time (int h_, int m_, int s_, int e_, int tcr_) : h (h_) , m (m_) , s (s_) - , t (t_) + , e (e_) + , tcr (tcr_) {} - Time (std::string time); + Time (std::string time, int tcr); - int h; ///< hours - int m; ///< minutes - int s; ///< seconds - int t; ///< `ticks', where 1 tick is 4 milliseconds + int h; ///< hours + int m; ///< minutes + int s; ///< seconds + int e; ///< editable units (where 1 editable unit is 1 / tcr_ seconds) + int tcr; ///< timecode rate: the number of editable units per second. std::string to_string () const; - int64_t to_ticks () const; - double to_seconds () const; + int64_t to_editable_units (int tcr_) const; private: - void set (double); + void set (double seconds, int tcr); }; extern bool operator== (Time const & a, Time const & b); @@ -81,8 +81,8 @@ extern bool operator< (Time const & a, Time const & b); extern bool operator> (Time const & a, Time const & b); extern bool operator>= (Time const & a, Time const & b); extern std::ostream & operator<< (std::ostream & s, Time const & t); -extern Time operator+ (Time a, Time const & b); -extern Time operator- (Time a, Time const & b); +extern Time operator+ (Time a, Time b); +extern Time operator- (Time a, Time b); extern float operator/ (Time a, Time const & b); } diff --git a/src/font.cc b/src/font.cc index 99f49f90..8656e909 100644 --- a/src/font.cc +++ b/src/font.cc @@ -23,6 +23,7 @@ #include "xml.h" #include "text.h" #include <libcxml/cxml.h> +#include <boost/foreach.hpp> using std::string; using std::list; @@ -30,7 +31,7 @@ using boost::shared_ptr; using boost::optional; using namespace dcp; -Font::Font (boost::shared_ptr<const cxml::Node> node) +Font::Font (cxml::ConstNodePtr node, int tcr) { text = node->content (); @@ -49,9 +50,21 @@ Font::Font (boost::shared_ptr<const cxml::Node> node) if (c) { effect_colour = Colour (c.get ()); } - subtitle_nodes = type_children<Subtitle> (node, "Subtitle"); - font_nodes = type_children<Font> (node, "Font"); - text_nodes = type_children<Text> (node, "Text"); + + list<cxml::NodePtr> s = node->node_children ("Subtitle"); + BOOST_FOREACH (cxml::NodePtr& i, s) { + subtitle_nodes.push_back (shared_ptr<Subtitle> (new Subtitle (i, tcr))); + } + + list<cxml::NodePtr> f = node->node_children ("Font"); + BOOST_FOREACH (cxml::NodePtr& i, f) { + font_nodes.push_back (shared_ptr<Font> (new Font (i, tcr))); + } + + list<cxml::NodePtr> t = node->node_children ("Text"); + BOOST_FOREACH (cxml::NodePtr& i, t) { + text_nodes.push_back (shared_ptr<Text> (new Text (i, tcr))); + } } Font::Font (std::list<boost::shared_ptr<Font> > const & font_nodes) @@ -23,14 +23,11 @@ #include "types.h" #include "subtitle.h" +#include <libcxml/cxml.h> #include <boost/shared_ptr.hpp> #include <boost/optional.hpp> #include <list> -namespace cxml { - class Node; -} - namespace dcp { /** @class Font @@ -43,7 +40,7 @@ public: : size (0) {} - Font (boost::shared_ptr<const cxml::Node> node); + Font (cxml::ConstNodePtr node, int tcr); Font (std::list<boost::shared_ptr<Font> > const & font_nodes); std::string text; diff --git a/src/interop_subtitle_content.cc b/src/interop_subtitle_content.cc index 218dbaea..1b6ee1a9 100644 --- a/src/interop_subtitle_content.cc +++ b/src/interop_subtitle_content.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net> + Copyright (C) 2012-2015 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 @@ -22,9 +22,11 @@ #include "xml.h" #include "raw_convert.h" #include "font.h" +#include <boost/foreach.hpp> using std::list; using std::string; +using std::cout; using boost::shared_ptr; using boost::optional; using boost::dynamic_pointer_cast; @@ -38,9 +40,13 @@ InteropSubtitleContent::InteropSubtitleContent (boost::filesystem::path file) _id = xml->string_child ("SubtitleID"); _movie_title = xml->string_child ("MovieTitle"); - _load_font_nodes = type_children<dcp::InteropLoadFont> (xml, "LoadFont"); - list<shared_ptr<dcp::Font> > font_nodes = type_children<dcp::Font> (xml, "Font"); + + list<cxml::NodePtr> f = xml->node_children ("Font"); + list<shared_ptr<dcp::Font> > font_nodes; + BOOST_FOREACH (cxml::NodePtr& i, f) { + font_nodes.push_back (shared_ptr<Font> (new Font (i, 250))); + } parse_common (xml, font_nodes); } @@ -148,8 +154,8 @@ InteropSubtitleContent::xml_as_string () const subtitle_element->set_attribute ("SpotNumber", raw_convert<string> (spot_number++)); subtitle_element->set_attribute ("TimeIn", i->in().to_string()); subtitle_element->set_attribute ("TimeOut", i->out().to_string()); - subtitle_element->set_attribute ("FadeUpTime", raw_convert<string> (i->fade_up_time().to_ticks())); - subtitle_element->set_attribute ("FadeDownTime", raw_convert<string> (i->fade_down_time().to_ticks())); + subtitle_element->set_attribute ("FadeUpTime", raw_convert<string> (i->fade_up_time().to_editable_units(250))); + subtitle_element->set_attribute ("FadeDownTime", raw_convert<string> (i->fade_down_time().to_editable_units(250))); last_in = i->in (); last_out = i->out (); diff --git a/src/smpte_subtitle_content.cc b/src/smpte_subtitle_content.cc index e54b33c3..910219cb 100644 --- a/src/smpte_subtitle_content.cc +++ b/src/smpte_subtitle_content.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net> + Copyright (C) 2012-2015 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 @@ -24,10 +24,12 @@ #include "xml.h" #include "AS_DCP.h" #include "KM_util.h" +#include <boost/foreach.hpp> using std::string; using std::list; using std::stringstream; +using std::cout; using boost::shared_ptr; using namespace dcp; @@ -62,8 +64,15 @@ SMPTESubtitleContent::SMPTESubtitleContent (boost::filesystem::path file, bool m _load_font_nodes = type_children<dcp::SMPTELoadFont> (xml, "LoadFont"); + int tcr = xml->number_child<int> ("TimeCodeRate"); + shared_ptr<cxml::Node> subtitle_list = xml->optional_node_child ("SubtitleList"); - list<shared_ptr<dcp::Font> > font_nodes = type_children<dcp::Font> (subtitle_list, "Font"); + + list<cxml::NodePtr> f = subtitle_list->node_children ("Font"); + list<shared_ptr<dcp::Font> > font_nodes; + BOOST_FOREACH (cxml::NodePtr& i, f) { + font_nodes.push_back (shared_ptr<Font> (new Font (i, tcr))); + } parse_common (xml, font_nodes); } diff --git a/src/subtitle.cc b/src/subtitle.cc index 12714961..6c2ccd7e 100644 --- a/src/subtitle.cc +++ b/src/subtitle.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net> + Copyright (C) 2012-2015 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 @@ -25,36 +25,47 @@ #include <boost/lexical_cast.hpp> using std::string; +using std::list; +using boost::optional; using boost::shared_ptr; using boost::lexical_cast; using namespace dcp; -Subtitle::Subtitle (boost::shared_ptr<const cxml::Node> node) +Subtitle::Subtitle (boost::shared_ptr<const cxml::Node> node, int tcr) { - in = Time (node->string_attribute ("TimeIn")); - out = Time (node->string_attribute ("TimeOut")); - font_nodes = type_children<Font> (node, "Font"); - text_nodes = type_children<Text> (node, "Text"); - fade_up_time = fade_time (node, "FadeUpTime"); - fade_down_time = fade_time (node, "FadeDownTime"); + in = Time (node->string_attribute ("TimeIn"), tcr); + out = Time (node->string_attribute ("TimeOut"), tcr); + + list<cxml::NodePtr> f = node->node_children ("Font"); + for (list<cxml::NodePtr>::iterator i = f.begin(); i != f.end(); ++i) { + font_nodes.push_back (shared_ptr<Font> (new Font (*i, tcr))); + } + + list<cxml::NodePtr> t = node->node_children ("Text"); + for (list<cxml::NodePtr>::iterator i = t.begin(); i != t.end(); ++i) { + text_nodes.push_back (shared_ptr<Text> (new Text (*i, tcr))); + } + + fade_up_time = fade_time (node, "FadeUpTime", tcr); + fade_down_time = fade_time (node, "FadeDownTime", tcr); } Time -Subtitle::fade_time (shared_ptr<const cxml::Node> node, string name) +Subtitle::fade_time (shared_ptr<const cxml::Node> node, string name, int tcr) { string const u = node->optional_string_attribute (name).get_value_or (""); Time t; if (u.empty ()) { - t = Time (0, 0, 0, 20); + t = Time (0, 0, 0, 20, 250); } else if (u.find (":") != string::npos) { - t = Time (u); + t = Time (u, tcr); } else { - t = Time (0, 0, 0, lexical_cast<int> (u)); + t = Time (0, 0, 0, lexical_cast<int> (u), tcr); } - if (t > Time (0, 0, 8, 0)) { - t = Time (0, 0, 8, 0); + if (t > Time (0, 0, 8, 0, 250)) { + t = Time (0, 0, 8, 0, 250); } return t; diff --git a/src/subtitle.h b/src/subtitle.h index 073bfb0c..0958a1d4 100644 --- a/src/subtitle.h +++ b/src/subtitle.h @@ -22,6 +22,7 @@ #include "dcp_time.h" #include <boost/shared_ptr.hpp> +#include <boost/optional.hpp> #include <list> namespace cxml { @@ -37,7 +38,7 @@ class Subtitle { public: Subtitle () {} - Subtitle (boost::shared_ptr<const cxml::Node> node); + Subtitle (boost::shared_ptr<const cxml::Node> node, int tcr); Time in; Time out; @@ -47,7 +48,7 @@ public: std::list<boost::shared_ptr<Text> > text_nodes; private: - Time fade_time (boost::shared_ptr<const cxml::Node>, std::string name); + Time fade_time (boost::shared_ptr<const cxml::Node>, std::string name, int tcr); }; } diff --git a/src/text.cc b/src/text.cc index 782d1711..a846d961 100644 --- a/src/text.cc +++ b/src/text.cc @@ -25,8 +25,10 @@ #include "xml.h" #include "font.h" #include <libcxml/cxml.h> +#include <boost/foreach.hpp> using std::string; +using std::list; using boost::shared_ptr; using boost::optional; using namespace dcp; @@ -35,7 +37,7 @@ using namespace dcp; * in this object's member variables. * @param node Node to read. */ -Text::Text (boost::shared_ptr<const cxml::Node> node) +Text::Text (boost::shared_ptr<const cxml::Node> node, int tcr) : v_align (CENTER) { text = node->content (); @@ -54,5 +56,8 @@ Text::Text (boost::shared_ptr<const cxml::Node> node) v_align = string_to_valign (v.get ()); } - font_nodes = type_children<Font> (node, "Font"); + list<cxml::NodePtr> f = node->node_children ("Font"); + BOOST_FOREACH (cxml::NodePtr& i, f) { + font_nodes.push_back (shared_ptr<Font> (new Font (i, tcr))); + } } @@ -1,5 +1,5 @@ /* - Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net> + Copyright (C) 2012-2015 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 @@ -23,6 +23,7 @@ #include "types.h" #include <boost/shared_ptr.hpp> +#include <boost/optional.hpp> #include <list> namespace cxml { @@ -45,7 +46,7 @@ public: , v_align (TOP) {} - Text (boost::shared_ptr<const cxml::Node> node); + Text (boost::shared_ptr<const cxml::Node> node, int tcr); float v_position; VAlign v_align; |
