diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/ssa_reader.cc | 299 | ||||
| -rw-r--r-- | src/ssa_reader.h | 5 | ||||
| -rw-r--r-- | src/sub_time.cc | 25 | ||||
| -rw-r--r-- | src/sub_time.h | 5 | ||||
| -rw-r--r-- | src/wscript | 2 |
5 files changed, 74 insertions, 262 deletions
diff --git a/src/ssa_reader.cc b/src/ssa_reader.cc index c76a78d..a4daf24 100644 --- a/src/ssa_reader.cc +++ b/src/ssa_reader.cc @@ -22,6 +22,7 @@ #include "sub_assert.h" #include "raw_convert.h" #include "subtitle.h" +#include <ass/ass.h> #include <boost/algorithm/string.hpp> #include <boost/bind.hpp> #include <boost/foreach.hpp> @@ -43,281 +44,77 @@ using namespace sub; /** @param s Subtitle string encoded in UTF-8 */ SSAReader::SSAReader (string const & s) { - stringstream str (s); - this->read (boost::bind (&get_line_stringstream, &str)); + char* buffer = new char[s.length() + 1]; + strcpy (buffer, s.c_str()); + read (buffer, s.length() + 1); } /** @param f Subtitle file encoded in UTF-8 */ SSAReader::SSAReader (FILE* f) { - this->read (boost::bind (&get_line_file, f)); -} - -class Style -{ -public: - Style () - : font_size (24) - , primary_colour (255, 255, 255) - , bold (false) - , italic (false) - {} - - Style (string format_line, string style_line) - : font_size (24) - , primary_colour (255, 255, 255) - , bold (false) - , italic (false) - { - vector<string> keys; - split (keys, format_line, is_any_of (",")); - vector<string> style; - split (style, style_line, is_any_of (",")); - - SUB_ASSERT (!keys.empty()); - SUB_ASSERT (!style.empty()); - SUB_ASSERT (keys.size() == style.size()); - - for (size_t i = 0; i < style.size(); ++i) { - trim (keys[i]); - trim (style[i]); - if (keys[i] == "Name") { - name = style[i]; - } else if (keys[i] == "Fontname") { - font_name = style[i]; - } else if (keys[i] == "Fontsize") { - font_size = raw_convert<int> (style[i]); - } else if (keys[i] == "PrimaryColour") { - primary_colour = colour (raw_convert<int> (style[i])); - } else if (keys[i] == "BackColour") { - back_colour = colour (raw_convert<int> (style[i])); - } else if (keys[i] == "Bold") { - bold = style[i] == "-1"; - } else if (keys[i] == "Italic") { - italic = style[i] == "-1"; - } else if (keys[i] == "BorderStyle") { - if (style[i] == "1") { - effect = SHADOW; - } - } - } - } - - string name; - optional<string> font_name; - int font_size; - Colour primary_colour; - /** outline colour */ - optional<Colour> back_colour; - bool bold; - bool italic; - optional<Effect> effect; + fseek (f, 0, SEEK_END); + long const size = ftell (f); + fseek (f, 0, SEEK_SET); + char* buffer = new char[size]; + fread (buffer, size, 1, f); -private: - Colour colour (int c) const - { - return Colour ( - ((c & 0x0000ff) >> 0) / 255.0, - ((c & 0x00ff00) >> 8) / 255.0, - ((c & 0xff0000) >> 16) / 255.0 - ); - } -}; - -Time -SSAReader::parse_time (string t) const -{ - vector<string> bits; - split (bits, t, is_any_of (":.")); - SUB_ASSERT (bits.size() == 4); - return Time::from_hms ( - raw_convert<int> (bits[0]), - raw_convert<int> (bits[1]), - raw_convert<int> (bits[2]), - raw_convert<int> (bits[3]) * 10 - ); + read (buffer, size); } -/** @param base RawSubtitle filled in with any required common values. - * @param line SSA line string. - * @return List of RawSubtitles to represent line with vertical reference TOP_OF_SUBTITLE. - */ -list<RawSubtitle> -SSAReader::parse_line (RawSubtitle base, string line) +void +SSAReader::read (char* buffer, int size) { - enum { - TEXT, - STYLE, - BACKSLASH - } state = TEXT; - - list<RawSubtitle> subs; - RawSubtitle current = base; - string style; - - current.vertical_position.line = 0; - /* XXX: arbitrary */ - current.vertical_position.lines = 32; - current.vertical_position.reference = TOP_OF_SUBTITLE; - - for (size_t i = 0; i < line.length(); ++i) { - char const c = line[i]; - switch (state) { - case TEXT: - if (c == '{') { - state = STYLE; - } else if (c == '\\') { - state = BACKSLASH; - } else if (c != '\r' && c != '\n') { - current.text += c; - } - break; - case STYLE: - if (c == '}') { - if (!current.text.empty ()) { - subs.push_back (current); - current.text = ""; - } - if (style == "i1") { - current.italic = true; - } else if (style == "i0") { - current.italic = false; - } - style = ""; - state = TEXT; - } else { - style += c; - } - break; - case BACKSLASH: - if ((c == 'n' || c == 'N') && !current.text.empty ()) { - subs.push_back (current); - current.text = ""; - current.vertical_position.line = current.vertical_position.line.get() + 1; - } - state = TEXT; - break; - } + ASS_Library* library = ass_library_init (); + if (!library) { + delete[] buffer; + throw std::runtime_error ("Could not initialise libass"); } - if (!current.text.empty ()) { - subs.push_back (current); - } + char encoding[] = "UTF-8"; - return subs; -} + ASS_Track* track = ass_read_memory (library, buffer, size, encoding); + delete[] buffer; -void -SSAReader::read (function<optional<string> ()> get_line) -{ - enum { - INFO, - STYLES, - EVENTS - } part = INFO; + for (int i = 0; i < track->n_events; ++i) { + sub::RawSubtitle sub; - map<string, Style> styles; - string style_format_line; - vector<string> event_format; + ASS_Event const & event = track->events[i]; + ASS_Style const & style = track->styles[event.Style]; - while (true) { - optional<string> line = get_line (); - if (!line) { - break; - } + sub.text = event.Text; + sub.font = style.FontName; + sub.font_size.set_proportional (style.FontSize / track->PlayResY); - trim (*line); - remove_unicode_bom (line); + /* XXX: effect, effect_colour */ - if (starts_with (*line, ";") || line->empty ()) { - continue; - } + sub.bold = style.Bold; + sub.italic = style.Italic; + sub.underline = style.Underline; - if (starts_with (*line, "[")) { - /* Section heading */ - if (line.get() == "[Script Info]") { - part = INFO; - } else if (line.get() == "[V4 Styles]") { - part = STYLES; - } else if (line.get() == "[Events]") { - part = EVENTS; - } - continue; - } + cout << "align " << style.Alignment << "\n"; - size_t const colon = line->find (":"); - SUB_ASSERT (colon != string::npos); - SUB_ASSERT (line->length() > colon + 1); - string const type = line->substr (0, colon); - string const body = line->substr (colon + 2); + int valign = style.Alignment & 12; - switch (part) { - case INFO: + switch (valign) { + case VALIGN_SUB: + sub.vertical_position.reference = BOTTOM_OF_SCREEN; break; - case STYLES: - if (type == "Format") { - style_format_line = body; - } else if (type == "Style") { - SUB_ASSERT (!style_format_line.empty ()); - Style s (style_format_line, body); - styles[s.name] = s; - } + case VALIGN_CENTER: + sub.vertical_position.reference = CENTRE_OF_SCREEN; break; - case EVENTS: - if (type == "Format") { - split (event_format, body, is_any_of (",")); - BOOST_FOREACH (string& i, event_format) { - trim (i); - } - } else if (type == "Dialogue") { - SUB_ASSERT (!event_format.empty ()); - vector<string> event; - split (event, body, is_any_of (",")); - - /* There may be commas in the subtitle part; reassemble any extra parts - from when we just split it. - */ - while (event.size() > event_format.size()) { - string const ex = event.back (); - event.pop_back (); - event.back() += "," + ex; - } - - SUB_ASSERT (!event.empty()); - SUB_ASSERT (event_format.size() == event.size()); - - RawSubtitle sub; - - for (size_t i = 0; i < event.size(); ++i) { - trim (event[i]); - if (event_format[i] == "Start") { - sub.from = parse_time (event[i]); - } else if (event_format[i] == "End") { - sub.to = parse_time (event[i]); - } else if (event_format[i] == "Style") { - SUB_ASSERT (styles.find(event[i]) != styles.end()); - Style style = styles[event[i]]; - sub.font = style.font_name; - sub.font_size = FontSize::from_points (style.font_size); - sub.colour = style.primary_colour; - sub.effect_colour = style.back_colour; - sub.bold = style.bold; - sub.italic = style.italic; - sub.effect = style.effect; + case VALIGN_TOP: + sub.vertical_position.reference = TOP_OF_SCREEN; + break; + } - /* XXX: arbitrary */ - sub.vertical_position.lines = 32; - sub.vertical_position.reference = TOP_OF_SUBTITLE; - sub.vertical_position.line = 0; + sub.vertical_position.proportional = style.MarginV / track->PlayResY; - } else if (event_format[i] == "Text") { - BOOST_FOREACH (sub::RawSubtitle j, parse_line (sub, event[i])) { - _subs.push_back (j); - } - } - } - } - } + sub.from = Time::from_milliseconds (event.Start); + sub.to = sub.from + Time::from_milliseconds (event.Duration); + _subs.push_back (sub); } + + ass_free_track (track); + ass_library_done (library); } diff --git a/src/ssa_reader.h b/src/ssa_reader.h index 1fe64f3..b80aec4 100644 --- a/src/ssa_reader.h +++ b/src/ssa_reader.h @@ -35,11 +35,8 @@ public: SSAReader (FILE* f); SSAReader (std::string const & subs); - static std::list<RawSubtitle> parse_line (RawSubtitle base, std::string line); - private: - void read (boost::function<boost::optional<std::string> ()> get_line); - Time parse_time (std::string t) const; + void read (char* buffer, int size); }; } diff --git a/src/sub_time.cc b/src/sub_time.cc index c4e00ba..1c7d294 100644 --- a/src/sub_time.cc +++ b/src/sub_time.cc @@ -155,6 +155,12 @@ Time::from_hms (int h, int m, int s, int ms) return Time (h * 3600 + m * 60 + s, ms, Rational (1000, 1)); } +Time +Time::from_milliseconds (int64_t m) +{ + return Time (m / 1000, m % 1000, Rational (1000, 1)); +} + /** Create a Time from a number of frames. * rate must be integer. */ @@ -172,11 +178,9 @@ Time::all_as_seconds () const return _seconds + double(milliseconds ()) / 1000; } -/** Add a time to this one. This time must have an integer _rate - * and t must have the same rate. - */ -void -Time::add (Time t) +/** This time must have an integer _rate and t must have the same rate */ +Time & +Time::operator+= (Time const & t) { SUB_ASSERT (_rate); @@ -190,6 +194,17 @@ Time::add (Time t) _frames -= _rate.get().integer_fraction(); ++_seconds; } + + return *this; +} + +/** This time must have an integer _rate and t must have the same rate */ +Time +Time::operator+ (Time const & t) +{ + Time r = *this; + r += t; + return r; } void diff --git a/src/sub_time.h b/src/sub_time.h index 93088cb..f5d15d7 100644 --- a/src/sub_time.h +++ b/src/sub_time.h @@ -42,13 +42,16 @@ public: double all_as_seconds () const; - void add (Time t); void scale (float f); static Time from_hmsf (int h, int m, int s, int f, boost::optional<Rational> rate = boost::optional<Rational> ()); static Time from_hms (int h, int m, int s, int ms); + static Time from_milliseconds (int64_t ms); static Time from_frames (int frames, Rational rate); + Time operator+ (Time const & other); + Time& operator+= (Time const & other); + private: friend bool operator< (Time const & a, Time const & b); friend bool operator> (Time const & a, Time const & b); diff --git a/src/wscript b/src/wscript index 9136ea1..e493a07 100644 --- a/src/wscript +++ b/src/wscript @@ -8,7 +8,7 @@ def build(bld): obj.name = 'libsub%s' % bld.env.API_VERSION obj.target = 'sub%s' % bld.env.API_VERSION - obj.uselib = 'CXML DCP BOOST_FILESYSTEM BOOST_LOCALE BOOST_REGEX ASDCPLIB_CTH' + obj.uselib = 'CXML DCP BOOST_FILESYSTEM BOOST_LOCALE BOOST_REGEX ASDCPLIB_CTH LIBASS' obj.use = 'libkumu-libsub%s libasdcp-libsub%s' % (bld.env.API_VERSION, bld.env.API_VERSION) obj.export_includes = ['.'] obj.source = """ |
