diff options
| author | Carl Hetherington <cth@carlh.net> | 2016-06-06 08:59:53 +0100 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2016-06-06 08:59:53 +0100 |
| commit | aba52dd5cc2fa9736fd9b007962923d4dae8c4a6 (patch) | |
| tree | aa206963eaf22e3be47d9a10f83553cfb57879fc /src/ssa_reader.cc | |
| parent | a06e701131b813bc42ae81b9c5e8c7dbbfea7eb9 (diff) | |
Hacks.libssa
Diffstat (limited to 'src/ssa_reader.cc')
| -rw-r--r-- | src/ssa_reader.cc | 299 |
1 files changed, 48 insertions, 251 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); } |
