diff options
| author | Carl Hetherington <cth@carlh.net> | 2015-01-13 23:04:11 +0000 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2015-01-13 23:04:11 +0000 |
| commit | f1ba458a19a9b998ecdb1db726106876953abcc0 (patch) | |
| tree | 1e414103fec758275f92dff3b7973cc02dbf39a3 | |
| parent | d15ef17dccf87b633d1971c38032a2049abe3db0 (diff) | |
Various development / fixes.rework
| -rw-r--r-- | src/exceptions.h | 7 | ||||
| -rw-r--r-- | src/font_size.cc | 12 | ||||
| -rw-r--r-- | src/font_size.h | 5 | ||||
| -rw-r--r-- | src/sub_time.cc | 160 | ||||
| -rw-r--r-- | src/sub_time.h | 14 | ||||
| -rw-r--r-- | src/subtitle.cc | 107 | ||||
| -rw-r--r-- | src/subtitle.h | 9 | ||||
| -rw-r--r-- | src/wscript | 3 | ||||
| -rw-r--r-- | test/time_test.cc | 75 | ||||
| -rw-r--r-- | tools/dumpsubs.cc | 61 |
10 files changed, 389 insertions, 64 deletions
diff --git a/src/exceptions.h b/src/exceptions.h index 8602517..0531279 100644 --- a/src/exceptions.h +++ b/src/exceptions.h @@ -107,6 +107,13 @@ public: {} }; +class MismatchedFrameRateException : public MessageError +{ +public: + MismatchedFrameRateException () + : MessageError ("cannot perform this operation with different frame rates") + {} +}; } #endif diff --git a/src/font_size.cc b/src/font_size.cc index d11ee89..7d556af 100644 --- a/src/font_size.cc +++ b/src/font_size.cc @@ -40,3 +40,15 @@ FontSize::points (int screen_height_in_points) const return _proportional.get() * screen_height_in_points; } + +bool +FontSize::operator== (FontSize const & other) const +{ + if (_proportional && other._proportional) { + return _proportional.get() == other._proportional.get(); + } else if (_points && other._points) { + return _points.get() == other._points.get(); + } + + return false; +} diff --git a/src/font_size.h b/src/font_size.h index 0b4b357..6c3a284 100644 --- a/src/font_size.h +++ b/src/font_size.h @@ -20,6 +20,8 @@ #ifndef LIBSUB_FONT_SIZE_H #define LIBSUB_FONT_SIZE_H +#include <boost/optional.hpp> + namespace sub { /** @class FontSize @@ -48,7 +50,10 @@ public: } float proportional (int screen_height_in_points) const; + int pixels (int screen_height_in_points) const; int points (int screen_height_in_points) const; + + bool operator== (FontSize const & other) const; private: /** as a proportion of screen height */ diff --git a/src/sub_time.cc b/src/sub_time.cc index 780dbc9..9c7b98b 100644 --- a/src/sub_time.cc +++ b/src/sub_time.cc @@ -86,6 +86,46 @@ Time::from_hmsm (int h, int m, int s, int ms) return Time (h, m, s, ms, optional<int> (), optional<FrameRate> ()); } +Time +Time::from_frames (int64_t f, FrameRate r) +{ + double s = f / enum_to_value (r); + int const hours = floor (s / 3600); + s -= hours * 3600; + int const minutes = floor (s / 60); + s -= minutes * 60; + int const seconds = floor (s); + s -= seconds; + int const frames = rint (s * enum_to_value (r)); + + return Time::from_hmsf (hours, minutes, seconds, frames, r); +} + +Time +Time::from_milliseconds (int64_t m) +{ + int const hours = m / 3600000; + m -= hours * 3600000; + int const minutes = m / 60000; + m -= minutes * 60000; + int const seconds = m / 1000; + m -= seconds * 1000; + + return Time (hours, minutes, seconds, m, optional<int> (), optional<FrameRate> ()); +} + +bool +Time::operator<= (Time const & other) const +{ + return *this < other || *this == other; +} + +bool +Time::operator>= (Time const & other) const +{ + return *this > other || *this == other; +} + bool Time::operator< (Time const & other) const { @@ -159,7 +199,7 @@ Time::operator== (Time const & other) const } /* Otherwise we have to do it by comparing milliseconds */ - return abs (as_milliseconds() - other.as_milliseconds()) <= 1; + return as_milliseconds() == other.as_milliseconds(); } bool @@ -184,6 +224,124 @@ sub::operator<< (ostream& s, Time const & t) return s; } +Time +sub::operator+ (Time const & a, Time const & b) +{ + int seconds = 0; + int minutes = 0; + int hours = 0; + + optional<int> frames; + optional<FrameRate> frame_rate; + optional<int> milliseconds; + + if (a._frames && b._frames) { + if (!a._frame_rate || !b._frame_rate) { + throw UnknownFrameRateException (); + } + if (a._frame_rate.get() != b._frame_rate.get()) { + throw MismatchedFrameRateException (); + } + + frame_rate = a._frame_rate.get (); + frames = a._frames.get() + b._frames.get(); + if (frames.get() >= enum_to_value (frame_rate.get ())) { + frames = frames.get() - enum_to_value (frame_rate.get ()); + ++seconds; + } + } else if (a._milliseconds && b._milliseconds) { + milliseconds = a._milliseconds.get() + b._milliseconds.get(); + if (milliseconds >= 1000) { + milliseconds = milliseconds.get() - 1000; + ++seconds; + } + } else { + return Time::from_milliseconds (a.as_milliseconds() + b.as_milliseconds()); + } + + seconds += a.seconds + b.seconds; + if (seconds >= 60) { + seconds -= 60; + ++minutes; + } + + minutes += a.minutes + b.minutes; + if (minutes >= 60) { + minutes -= 60; + ++hours; + } + + hours += a.hours + b.hours; + + if (frames) { + return sub::Time (hours, minutes, seconds, optional<int> (), frames.get(), frame_rate.get()); + } else { + return sub::Time (hours, minutes, seconds, milliseconds.get(), optional<int> (), optional<FrameRate> ()); + } +} + +Time +sub::operator- (Time const & a, Time const & b) +{ + int seconds = 0; + int minutes = 0; + int hours = 0; + + optional<int> frames; + optional<FrameRate> frame_rate; + optional<int> milliseconds; + + if (a._frames && b._frames) { + if (!a._frame_rate || !b._frame_rate) { + throw UnknownFrameRateException (); + } + if (a._frame_rate.get() != b._frame_rate.get()) { + throw MismatchedFrameRateException (); + } + + frame_rate = a._frame_rate.get (); + frames = a._frames.get() - b._frames.get(); + if (frames.get() < 0) { + frames = frames.get() + enum_to_value (frame_rate.get ()); + --seconds; + } + } else if (a._milliseconds && b._milliseconds) { + milliseconds = a._milliseconds.get() - b._milliseconds.get(); + if (milliseconds < 0) { + milliseconds = milliseconds.get() + 1000; + --seconds; + } + } else { + return Time::from_milliseconds (a.as_milliseconds() - b.as_milliseconds()); + } + + seconds += a.seconds - b.seconds; + if (seconds < 0) { + seconds += 60; + --minutes; + } + + minutes += a.minutes - b.minutes; + if (minutes < 0) { + minutes += 60; + --hours; + } + + hours += a.hours - b.hours; + + if (frames) { + return sub::Time (hours, minutes, seconds, optional<int> (), frames.get(), frame_rate.get()); + } else { + return sub::Time (hours, minutes, seconds, milliseconds.get(), optional<int> (), optional<FrameRate> ()); + } +} + +double +sub::operator/ (Time const & a, Time const & b) +{ + return double (a.as_milliseconds()) / b.as_milliseconds(); +} + Time::Time (int h, int m, int s, optional<int> ms, optional<int> f, optional<FrameRate> r) : hours (h) , minutes (m) diff --git a/src/sub_time.h b/src/sub_time.h index 4b3f0e1..48a868c 100644 --- a/src/sub_time.h +++ b/src/sub_time.h @@ -40,6 +40,10 @@ public: int minutes; int seconds; + boost::optional<int> frames () const { + return _frames; + } + /** @return the frames part of the time at a particular frame rate */ int frames (FrameRate r) const; @@ -50,14 +54,21 @@ public: static Time from_hmsf (int h, int m, int s, int f, FrameRate r); static Time from_hms (int h, int m, double s); static Time from_hmsm (int h, int m, int s, int ms); + static Time from_frames (int64_t f, FrameRate r); + static Time from_milliseconds (int64_t ms); bool operator== (Time const & other) const; bool operator!= (Time const & other) const; bool operator< (Time const & other) const; + bool operator<= (Time const & other) const; bool operator> (Time const & other) const; + bool operator>= (Time const & other) const; private: friend std::ostream & operator<< (std::ostream& s, Time const & t); + friend Time operator+ (Time const & a, Time const & b); + friend Time operator- (Time const & a, Time const & b); + friend double operator/ (Time const & a, Time const & b); friend struct ::time_construction_test; @@ -69,6 +80,9 @@ private: }; std::ostream& operator<< (std::ostream& s, Time const & t); +Time operator+ (Time const & a, Time const & b); +Time operator- (Time const & a, Time const & b); +double operator/ (Time const & a, Time const & b); } diff --git a/src/subtitle.cc b/src/subtitle.cc index dc316c3..231abc6 100644 --- a/src/subtitle.cc +++ b/src/subtitle.cc @@ -19,6 +19,8 @@ #include "subtitle.h" +using std::ostream; +using std::list; using namespace sub; Subtitle::Subtitle (RawSubtitle s) @@ -56,6 +58,18 @@ Subtitle::same_metadata (RawSubtitle s) const return true; } +bool +sub::operator== (Subtitle const & a, Subtitle const & b) +{ + return ( + a.from == b.from && + a.to == b.to && + a.fade_up == b.fade_up && + a.fade_down == b.fade_down && + a.lines == b.lines + ); +} + Line::Line (RawSubtitle s) : vertical_position (s.vertical_position) { @@ -68,6 +82,15 @@ Line::same_metadata (RawSubtitle s) const return vertical_position == s.vertical_position; } +bool +sub::operator== (Line const & a, Line const & b) +{ + return ( + a.vertical_position == b.vertical_position && + a.blocks == b.blocks + ); +} + Block::Block (RawSubtitle s) : text (s.text) , font (s.font) @@ -81,3 +104,87 @@ Block::Block (RawSubtitle s) { } + +bool +sub::operator== (Block const & a, Block const & b) +{ + return ( + a.text == b.text && + a.font == b.font && + a.font_size == b.font_size && + a.effect == b.effect && + a.effect_colour == b.effect_colour && + a.colour == b.colour && + a.bold == b.bold && + a.italic == b.italic && + a.underline == b.underline + ); +} + +/* The output of this method should not be relied upon + as part of the API. +*/ +ostream & +sub::operator<< (ostream& s, Subtitle const & sub) +{ + s << "Subtitle at " << sub.from << " -> " << sub.to << "\n"; + for (list<sub::Line>::const_iterator i = sub.lines.begin(); i != sub.lines.end(); ++i) { + + s << "\t"; + + /* XXX: should be in VerticalPosition operator<< */ + if (i->vertical_position.proportional) { + s << i->vertical_position.proportional.get() << " of screen"; + } else if (i->vertical_position.line) { + s << i->vertical_position.line.get() << " lines of " << i->vertical_position.lines.get(); + } + if (i->vertical_position.reference) { + s << " from "; + switch (i->vertical_position.reference.get()) { + case TOP_OF_SCREEN: + s << "top"; + break; + case CENTRE_OF_SCREEN: + s << "centre"; + break; + case BOTTOM_OF_SCREEN: + s << "bottom"; + break; + case TOP_OF_SUBTITLE: + s << "top of subtitle"; + break; + } + } + + s << "\t"; + bool italic = false; + bool underline = false; + for (list<sub::Block>::const_iterator j = i->blocks.begin(); j != i->blocks.end(); ++j) { + if (j->italic && !italic) { + s << "<i>"; + } else if (italic && !j->italic) { + s << "</i>"; + } + if (j->underline && !underline) { + s << "<u>"; + } else if (underline && !j->underline) { + s << "</u>"; + } + + italic = j->italic; + underline = j->underline; + + s << j->text; + } + + if (italic) { + s << "</i>"; + } + if (underline) { + s << "</u>"; + } + s << "\n"; + } + + return s; +} diff --git a/src/subtitle.h b/src/subtitle.h index d747a60..582823b 100644 --- a/src/subtitle.h +++ b/src/subtitle.h @@ -67,6 +67,8 @@ public: bool underline; ///< true to underline }; +bool operator== (Block const & a, Block const & b); + /** @class Line * @brief A line of text within a subtitle. * @@ -88,6 +90,8 @@ public: bool same_metadata (RawSubtitle) const; }; +bool operator== (Line const & a, Line const & b); + /** @class Subtitle * @brief A subtitle which has been collected into lines and blocks. * @@ -102,7 +106,7 @@ public: /** Construct a Line taking any relevant information from a RawSubtitle */ Subtitle (RawSubtitle s); - + /** from time */ Time from; /** to time */ @@ -116,6 +120,9 @@ public: bool same_metadata (RawSubtitle) const; }; +bool operator== (Subtitle const & a, Subtitle const & b); +std::ostream & operator<< (std::ostream &, Subtitle const & sub); + } #endif diff --git a/src/wscript b/src/wscript index b1a4ca4..c4f1d44 100644 --- a/src/wscript +++ b/src/wscript @@ -15,6 +15,7 @@ def build(bld): colour.cc dcp_reader.cc effect.cc + font_size.cc frame_rate.cc interop_dcp_reader.cc iso6937.cc @@ -47,6 +48,7 @@ def build(bld): dcp_reader.h effect.h font_size.h + frame_rate.h raw_subtitle.h reader.h reader_factory.h @@ -54,6 +56,7 @@ def build(bld): stl_binary_tables.h stl_binary_writer.h stl_text_reader.h + sub_time.h subrip_reader.h subtitle.h vertical_position.h diff --git a/test/time_test.cc b/test/time_test.cc index 2179815..5bf057c 100644 --- a/test/time_test.cc +++ b/test/time_test.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2014 Carl Hetherington <cth@carlh.net> + Copyright (C) 2014-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 @@ -17,8 +17,9 @@ */ -#include <boost/test/unit_test.hpp> #include "sub_time.h" +#include "exceptions.h" +#include <boost/test/unit_test.hpp> /* Check time construction */ BOOST_AUTO_TEST_CASE (time_construction_test) @@ -38,6 +39,22 @@ BOOST_AUTO_TEST_CASE (time_construction_test) BOOST_CHECK_EQUAL (t.seconds, 2); BOOST_CHECK_EQUAL (t._milliseconds.get(), 3); } + + { + sub::Time t = sub::Time::from_frames (91231513, sub::TWENTY_FOUR); + BOOST_CHECK_EQUAL (t.hours, 1055); + BOOST_CHECK_EQUAL (t.minutes, 55); + BOOST_CHECK_EQUAL (t.seconds, 13); + BOOST_CHECK_EQUAL (t._frames.get(), 1); + } + + { + sub::Time t = sub::Time::from_milliseconds (91231513); + BOOST_CHECK_EQUAL (t.hours, 25); + BOOST_CHECK_EQUAL (t.minutes, 20); + BOOST_CHECK_EQUAL (t.seconds, 31); + BOOST_CHECK_EQUAL (t._milliseconds.get(), 513); + } } /* Check time conversions */ @@ -55,3 +72,57 @@ BOOST_AUTO_TEST_CASE (time_conversion_test) p = sub::Time::from_hmsf (3, 5, 7, 3, sub::TWENTY_FIVE); BOOST_CHECK_EQUAL (p.as_milliseconds (), sub::Time::from_hmsm (3, 5, 7, 120).as_milliseconds ()); } + +BOOST_AUTO_TEST_CASE (time_addition_test) +{ + { + sub::Time a = sub::Time::from_hmsf (4, 54, 23, 5); + sub::Time b = sub::Time::from_hmsf (4, 54, 23, 5); + BOOST_CHECK_THROW (a + b, sub::UnknownFrameRateException); + } + + { + sub::Time a = sub::Time::from_hmsf (4, 54, 23, 5, sub::THIRTY); + sub::Time b = sub::Time::from_hmsf (4, 54, 23, 5, sub::TWENTY_FOUR); + BOOST_CHECK_THROW (a + b, sub::MismatchedFrameRateException); + } + + { + sub::Time a = sub::Time::from_hmsf (4, 54, 23, 5, sub::TWENTY_FOUR); + sub::Time b = sub::Time::from_hmsf (1, 9, 55, 23, sub::TWENTY_FOUR); + BOOST_CHECK_EQUAL (a + b, sub::Time::from_hmsf (6, 4, 19, 4, sub::TWENTY_FOUR)); + } + + { + sub::Time a = sub::Time::from_hmsm (4, 54, 23, 512); + sub::Time b = sub::Time::from_hmsm (1, 9, 55, 998); + BOOST_CHECK_EQUAL (a + b, sub::Time::from_hmsm (6, 4, 19, 510)); + } +} + +BOOST_AUTO_TEST_CASE (time_subtraction_test) +{ + { + sub::Time a = sub::Time::from_hmsf (4, 54, 23, 5); + sub::Time b = sub::Time::from_hmsf (4, 54, 23, 5); + BOOST_CHECK_THROW (a - b, sub::UnknownFrameRateException); + } + + { + sub::Time a = sub::Time::from_hmsf (4, 54, 23, 5, sub::THIRTY); + sub::Time b = sub::Time::from_hmsf (4, 54, 23, 5, sub::TWENTY_FOUR); + BOOST_CHECK_THROW (a - b, sub::MismatchedFrameRateException); + } + + { + sub::Time a = sub::Time::from_hmsf (2, 1, 1, 1, sub::TWENTY_FOUR); + sub::Time b = sub::Time::from_hmsf (1, 59, 59, 23, sub::TWENTY_FOUR); + BOOST_CHECK_EQUAL (a - b, sub::Time::from_hmsf (0, 1, 1, 2, sub::TWENTY_FOUR)); + } + + { + sub::Time a = sub::Time::from_hmsm (2, 1, 1, 1); + sub::Time b = sub::Time::from_hmsm (1, 59, 59, 999); + BOOST_CHECK_EQUAL (a - b, sub::Time::from_hmsm (0, 1, 1, 2)); + } +} diff --git a/tools/dumpsubs.cc b/tools/dumpsubs.cc index fe7350d..886d720 100644 --- a/tools/dumpsubs.cc +++ b/tools/dumpsubs.cc @@ -83,67 +83,8 @@ main (int argc, char* argv[]) } list<sub::Subtitle> subs = collect<list<sub::Subtitle> > (reader->subtitles ()); - int n = 0; for (list<sub::Subtitle>::const_iterator i = subs.begin(); i != subs.end(); ++i) { - cout << "Subtitle " << n << " at " << i->from << " -> " << i->to << "\n"; - for (list<sub::Line>::const_iterator j = i->lines.begin(); j != i->lines.end(); ++j) { - - cout << "\t"; - - if (j->vertical_position.proportional) { - cout << j->vertical_position.proportional.get() << " of screen"; - } else if (j->vertical_position.line) { - cout << j->vertical_position.line.get() << " lines of " << j->vertical_position.lines.get(); - } - if (j->vertical_position.reference) { - cout << " from "; - switch (j->vertical_position.reference.get()) { - case TOP_OF_SCREEN: - cout << "top"; - break; - case CENTRE_OF_SCREEN: - cout << "centre"; - break; - case BOTTOM_OF_SCREEN: - cout << "bottom"; - break; - case TOP_OF_SUBTITLE: - cout << "top of subtitle"; - break; - } - } - - cout << "\t"; - bool italic = false; - bool underline = false; - for (list<sub::Block>::const_iterator k = j->blocks.begin(); k != j->blocks.end(); ++k) { - if (k->italic && !italic) { - cout << "<i>"; - } else if (italic && !k->italic) { - cout << "</i>"; - } - if (k->underline && !underline) { - cout << "<u>"; - } else if (underline && !k->underline) { - cout << "</u>"; - } - - italic = k->italic; - underline = k->underline; - - cout << k->text; - } - - if (italic) { - cout << "</i>"; - } - if (underline) { - cout << "</u>"; - } - cout << "\n"; - } - - ++n; + cout << *i; } return 0; |
