summaryrefslogtreecommitdiff
path: root/src/ssa_reader.cc
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2016-06-06 08:59:53 +0100
committerCarl Hetherington <cth@carlh.net>2016-06-06 08:59:53 +0100
commitaba52dd5cc2fa9736fd9b007962923d4dae8c4a6 (patch)
treeaa206963eaf22e3be47d9a10f83553cfb57879fc /src/ssa_reader.cc
parenta06e701131b813bc42ae81b9c5e8c7dbbfea7eb9 (diff)
Hacks.libssa
Diffstat (limited to 'src/ssa_reader.cc')
-rw-r--r--src/ssa_reader.cc299
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);
}