diff options
| author | Carl Hetherington <cth@carlh.net> | 2014-01-11 14:04:58 +0000 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2014-01-11 14:04:58 +0000 |
| commit | 3af978d2d688cb1e4be7c8d95155a6b8cc7456a3 (patch) | |
| tree | fdb7f3fe7eea7a433d38d14307e78731d1e49dc2 /src/lib | |
| parent | 0523d4a83d7d334560d261686bdb329eea8bfb96 (diff) | |
Various work on SubRip.
Diffstat (limited to 'src/lib')
| -rw-r--r-- | src/lib/content_factory.cc | 8 | ||||
| -rw-r--r-- | src/lib/exceptions.cc | 8 | ||||
| -rw-r--r-- | src/lib/exceptions.h | 7 | ||||
| -rw-r--r-- | src/lib/subrip.cc | 215 | ||||
| -rw-r--r-- | src/lib/subrip.h | 43 | ||||
| -rw-r--r-- | src/lib/subrip_content.cc | 93 | ||||
| -rw-r--r-- | src/lib/subrip_content.h | 35 | ||||
| -rw-r--r-- | src/lib/subrip_subtitle.h | 58 | ||||
| -rw-r--r-- | src/lib/wscript | 2 |
9 files changed, 468 insertions, 1 deletions
diff --git a/src/lib/content_factory.cc b/src/lib/content_factory.cc index bab22b8eb..825c80498 100644 --- a/src/lib/content_factory.cc +++ b/src/lib/content_factory.cc @@ -21,6 +21,7 @@ #include "ffmpeg_content.h" #include "image_content.h" #include "sndfile_content.h" +#include "subrip_content.h" #include "util.h" using std::string; @@ -39,6 +40,8 @@ content_factory (shared_ptr<const Film> film, cxml::NodePtr node, int version) content.reset (new ImageContent (film, node, version)); } else if (type == "Sndfile") { content.reset (new SndfileContent (film, node, version)); + } else if (type == "SubRip") { + content.reset (new SubRipContent (film, node, version)); } return content; @@ -48,11 +51,16 @@ shared_ptr<Content> content_factory (shared_ptr<const Film> film, boost::filesystem::path path) { shared_ptr<Content> content; + + string ext = path.extension().string (); + transform (ext.begin(), ext.end(), ext.begin(), ::tolower); if (valid_image_file (path)) { content.reset (new ImageContent (film, path)); } else if (SndfileContent::valid_file (path)) { content.reset (new SndfileContent (film, path)); + } else if (ext == ".srt") { + content.reset (new SubRipContent (film, path)); } else { content.reset (new FFmpegContent (film, path)); } diff --git a/src/lib/exceptions.cc b/src/lib/exceptions.cc index 8144f41b9..e05ac4ff0 100644 --- a/src/lib/exceptions.cc +++ b/src/lib/exceptions.cc @@ -56,8 +56,14 @@ MissingSettingError::MissingSettingError (string s) } -PixelFormatError::PixelFormatError (std::string o, AVPixelFormat f) +PixelFormatError::PixelFormatError (string o, AVPixelFormat f) : StringError (String::compose (_("Cannot handle pixel format %1 during %2"), f, o)) { } + +SubRipError::SubRipError (string saw, string expecting, boost::filesystem::path f) + : FileError (String::compose (_("Error in SubRip file: saw %1 while expecting %2"), saw, expecting), f) +{ + +} diff --git a/src/lib/exceptions.h b/src/lib/exceptions.h index c1240538f..61163c8d1 100644 --- a/src/lib/exceptions.h +++ b/src/lib/exceptions.h @@ -230,6 +230,13 @@ public: PixelFormatError (std::string o, AVPixelFormat f); }; +/** An error that occurs while parsing a SubRip file */ +class SubRipError : public FileError +{ +public: + SubRipError (std::string, std::string, boost::filesystem::path); +}; + /** A parent class for classes which have a need to catch and * re-throw exceptions. This is intended for classes * which run their own thread; they should do something like diff --git a/src/lib/subrip.cc b/src/lib/subrip.cc new file mode 100644 index 000000000..50931e12a --- /dev/null +++ b/src/lib/subrip.cc @@ -0,0 +1,215 @@ +/* + Copyright (C) 2014 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include <boost/algorithm/string.hpp> +#include "subrip.h" +#include "subrip_content.h" +#include "subrip_subtitle.h" +#include "cross.h" +#include "exceptions.h" + +#include "i18n.h" + +using std::string; +using std::list; +using std::vector; +using boost::shared_ptr; +using boost::lexical_cast; +using boost::algorithm::trim; + +SubRip::SubRip (shared_ptr<SubRipContent> content) +{ + FILE* f = fopen_boost (content->path (0), "r"); + if (!f) { + throw OpenFileError (content->path (0)); + } + + enum { + COUNTER, + METADATA, + CONTENT + } state = COUNTER; + + char buffer[256]; + int next_count = 1; + + boost::optional<SubRipSubtitle> current; + list<string> lines; + + while (!feof (f)) { + fgets (buffer, sizeof (buffer), f); + string line (buffer); + trim (line); + + switch (state) { + case COUNTER: + { + int x = 0; + try { + x = lexical_cast<int> (line); + } catch (...) { + + } + + if (x == next_count) { + state = METADATA; + ++next_count; + current = SubRipSubtitle (); + } else { + throw SubRipError (line, _("a subtitle count"), content->path (0)); + } + } + break; + case METADATA: + { + vector<string> p; + boost::algorithm::split (p, line, boost::algorithm::is_any_of (" ")); + if (p.size() != 3 && p.size() != 7) { + throw SubRipError (line, _("a time/position line"), content->path (0)); + } + + current->from = convert_time (p[0]); + current->to = convert_time (p[2]); + + if (p.size() > 3) { + current->x1 = convert_coordinate (p[3]); + current->x2 = convert_coordinate (p[4]); + current->y1 = convert_coordinate (p[5]); + current->y2 = convert_coordinate (p[6]); + } + break; + } + case CONTENT: + if (line.empty ()) { + state = COUNTER; + current->pieces = convert_content (lines); + _subtitles.push_back (current.get ()); + current.reset (); + lines.clear (); + } else { + lines.push_back (line); + } + break; + } + } + + fclose (f); +} + +Time +SubRip::convert_time (string t) +{ + Time r = 0; + + vector<string> a; + boost::algorithm::split (a, t, boost::is_any_of (":")); + assert (a.size() == 3); + r += lexical_cast<int> (a[0]) * 60 * 60 * TIME_HZ; + r += lexical_cast<int> (a[1]) * 60 * TIME_HZ; + + vector<string> b; + boost::algorithm::split (b, a[2], boost::is_any_of (",")); + r += lexical_cast<int> (b[0]) * TIME_HZ; + r += lexical_cast<int> (b[1]) * TIME_HZ / 1000; + + return r; +} + +int +SubRip::convert_coordinate (string t) +{ + vector<string> a; + boost::algorithm::split (a, t, boost::is_any_of (":")); + assert (a.size() == 2); + return lexical_cast<int> (a[1]); +} + +void +SubRip::maybe_content (list<SubRipSubtitlePiece>& pieces, SubRipSubtitlePiece& p) +{ + if (!p.text.empty ()) { + pieces.push_back (p); + p.text.clear (); + } +} + +list<SubRipSubtitlePiece> +SubRip::convert_content (list<string> t) +{ + list<SubRipSubtitlePiece> pieces; + + SubRipSubtitlePiece p; + + enum { + TEXT, + TAG + } state = TEXT; + + string tag; + + /* XXX: missing <font> support */ + /* XXX: nesting of tags e.g. <b>foo<i>bar<b>baz</b>fred</i>jim</b> might + not work, I think. + */ + + for (list<string>::const_iterator i = t.begin(); i != t.end(); ++i) { + for (size_t j = 0; j < i->size(); ++j) { + switch (state) { + case TEXT: + if ((*i)[j] == '<' || (*i)[j] == '{') { + state = TAG; + } else { + p.text += (*i)[j]; + } + break; + case TAG: + if ((*i)[j] == '>' || (*i)[j] == '}') { + if (tag == "b") { + maybe_content (pieces, p); + p.bold = true; + } else if (tag == "/b") { + maybe_content (pieces, p); + p.bold = false; + } else if (tag == "i") { + maybe_content (pieces, p); + p.italic = true; + } else if (tag == "/i") { + maybe_content (pieces, p); + p.italic = false; + } else if (tag == "u") { + maybe_content (pieces, p); + p.underline = true; + } else if (tag == "/u") { + maybe_content (pieces, p); + p.underline = false; + } + tag.clear (); + state = TEXT; + } else { + tag += (*i)[j]; + } + break; + } + } + } + + maybe_content (pieces, p); + + return pieces; +} diff --git a/src/lib/subrip.h b/src/lib/subrip.h new file mode 100644 index 000000000..a8d8104c4 --- /dev/null +++ b/src/lib/subrip.h @@ -0,0 +1,43 @@ +/* + Copyright (C) 2014 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include "subrip_subtitle.h" + +class SubRipContent; +class subrip_time_test; +class subrip_coordinate_test; +class subrip_content_test; + +class SubRip +{ +public: + SubRip (boost::shared_ptr<SubRipContent>); + +private: + friend class subrip_time_test; + friend class subrip_coordinate_test; + friend class subrip_content_test; + + static Time convert_time (std::string); + static int convert_coordinate (std::string); + static std::list<SubRipSubtitlePiece> convert_content (std::list<std::string>); + static void maybe_content (std::list<SubRipSubtitlePiece> &, SubRipSubtitlePiece &); + + std::list<SubRipSubtitle> _subtitles; +}; diff --git a/src/lib/subrip_content.cc b/src/lib/subrip_content.cc new file mode 100644 index 000000000..79a1d4999 --- /dev/null +++ b/src/lib/subrip_content.cc @@ -0,0 +1,93 @@ +/* + Copyright (C) 2014 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include "subrip_content.h" +#include "util.h" + +#include "i18n.h" + +using std::stringstream; +using std::string; +using boost::shared_ptr; + +SubRipContent::SubRipContent (shared_ptr<const Film> film, boost::filesystem::path path) + : Content (film, path) + , SubtitleContent (film, path) +{ + +} + +SubRipContent::SubRipContent (shared_ptr<const Film> film, shared_ptr<const cxml::Node> node, int version) + : Content (film, node) + , SubtitleContent (film, node) +{ + +} + +void +SubRipContent::examine (boost::shared_ptr<Job>) +{ + +} + +string +SubRipContent::summary () const +{ + return path_summary() + " " + _("[subtitles]"); +} + +string +SubRipContent::technical_summary () const +{ + return Content::technical_summary() + " - " + _("SubRip subtitles"); +} + +string +SubRipContent::information () const +{ + +} + +void +SubRipContent::as_xml (xmlpp::Node* node) +{ + node->add_child("Type")->add_child_text ("SubRip"); + Content::as_xml (node); + SubtitleContent::as_xml (node); +} + +Time +SubRipContent::full_length () const +{ + +} + +string +SubRipContent::identifier () const +{ + LocaleGuard lg; + + stringstream s; + s << Content::identifier() + << "_" << subtitle_scale() + << "_" << subtitle_offset(); + + return s.str (); +} + diff --git a/src/lib/subrip_content.h b/src/lib/subrip_content.h new file mode 100644 index 000000000..1551081b6 --- /dev/null +++ b/src/lib/subrip_content.h @@ -0,0 +1,35 @@ +/* + Copyright (C) 2014 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include "subtitle_content.h" + +class SubRipContent : public SubtitleContent +{ +public: + SubRipContent (boost::shared_ptr<const Film>, boost::filesystem::path); + SubRipContent (boost::shared_ptr<const Film>, boost::shared_ptr<const cxml::Node>, int); + + void examine (boost::shared_ptr<Job>); + std::string summary () const; + std::string technical_summary () const; + std::string information () const; + void as_xml (xmlpp::Node *); + Time full_length () const; + std::string identifier () const; +}; diff --git a/src/lib/subrip_subtitle.h b/src/lib/subrip_subtitle.h new file mode 100644 index 000000000..933e0fc02 --- /dev/null +++ b/src/lib/subrip_subtitle.h @@ -0,0 +1,58 @@ +/* + Copyright (C) 2014 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef DCPOMATIC_SUBRIP_SUBTITLE_H +#define DCPOMATIC_SUBRIP_SUBTITLE_H + +#include <boost/optional.hpp> +#include <libdcp/types.h> +#include "types.h" + +struct SubRipSubtitlePiece +{ + SubRipSubtitlePiece () + : bold (false) + , italic (false) + , underline (false) + {} + + std::string text; + bool bold; + bool italic; + bool underline; + libdcp::Color color; +}; + +struct SubRipSubtitle +{ + SubRipSubtitle () + : from (0) + , to (0) + {} + + Time from; + Time to; + boost::optional<int> x1; + boost::optional<int> x2; + boost::optional<int> y1; + boost::optional<int> y2; + std::list<SubRipSubtitlePiece> pieces; +}; + +#endif diff --git a/src/lib/wscript b/src/lib/wscript index 81a55a160..284baa725 100644 --- a/src/lib/wscript +++ b/src/lib/wscript @@ -50,6 +50,8 @@ sources = """ sndfile_content.cc sndfile_decoder.cc sound_processor.cc + subrip.cc + subrip_content.cc subtitle_content.cc subtitle_decoder.cc timer.cc |
