*/
class DCPReader : public Reader
{
-protected:
+protected:
struct ParseState {
std::list<boost::shared_ptr<dcp::Font> > font_nodes;
void parse_common (cxml::NodePtr root, boost::optional<int> tcr);
std::string _id;
-
+
private:
void parse_node (xmlpp::Node const * node, ParseState& parse_state, boost::optional<int> tcr);
void maybe_add_subtitle (std::string text, ParseState const & parse_state);
-
+
std::string _reel_number;
std::string _language;
};
void set_proportional (float p) {
_proportional = p;
}
-
+
void set_points (int p) {
_points = p;
}
boost::optional<float> proportional () const {
return _proportional;
}
-
+
boost::optional<int> points () const {
return _points;
}
-
+
float proportional (int screen_height_in_points) const;
int points (int screen_height_in_points) const;
-
-private:
+
+private:
/** as a proportion of screen height */
boost::optional<float> _proportional;
/** in points */
boost::optional<int> _points;
-
+
};
}
boost::optional<Effect> effect;
boost::optional<Colour> effect_colour;
-
+
Colour colour;
bool bold; ///< true to use a bold version of font
bool italic; ///< true to use an italic version of font
Time from;
/** to time */
Time to;
-
+
boost::optional<Time> fade_up;
boost::optional<Time> fade_down;
};
-bool operator< (RawSubtitle const &, RawSubtitle const &);
+bool operator< (RawSubtitle const &, RawSubtitle const &);
}
{
public:
virtual ~Reader () {}
-
+
std::list<RawSubtitle> subtitles () const {
return _subs;
}
return shared_ptr<Reader> (new SMPTEDCPReader (file_name, false));
}
}
-
+
if (ext == ".mxf") {
/* Assume this is some MXF-wrapped SMPTE subtitles */
return shared_ptr<Reader> (new SMPTEDCPReader (file_name, true));
SMPTEDCPReader::SMPTEDCPReader (boost::filesystem::path file, bool mxf)
{
shared_ptr<cxml::Document> xml (new cxml::Document ("SubtitleReel"));
-
+
if (mxf) {
ASDCP::TimedText::MXFReader reader;
Kumu::Result_t r = reader.OpenRead (file.string().c_str ());
if (ASDCP_FAILURE (r)) {
boost::throw_exception (MXFError ("could not open MXF file for reading"));
}
-
+
string s;
reader.ReadTimedTextResource (s, 0, 0);
stringstream t;
ASDCP::WriterInfo info;
reader.FillWriterInfo (info);
-
+
char buffer[64];
Kumu::bin2UUIDhex (info.AssetUUID, ASDCP::UUIDlen, buffer, sizeof (buffer));
_id = buffer;
xml->read_file (file);
_id = xml->string_child("Id").substr (9);
}
-
+
_load_font_nodes = type_children<dcp::SMPTELoadFont> (xml, "LoadFont");
parse_common (xml, xml->number_child<int> ("TimeCodeRate"));
return boost::optional<E> ();
}
-
+
DisplayStandard
STLBinaryTables::display_standard_file_to_enum (string s) const
{
{
return enum_to_file (v, _comment_map);
}
-
+
string
STLBinaryTables::display_standard_enum_to_description (DisplayStandard v) const
{
return enum_to_description (v, _display_standard_map);
}
-
+
string
STLBinaryTables::language_group_enum_to_description (LanguageGroup v) const
{
code<DisplayStandard, string> (_display_standard_map, "0", DISPLAY_STANDARD_OPEN_SUBTITLING, "Open subtitling");
code<DisplayStandard, string> (_display_standard_map, "1", DISPLAY_STANDARD_LEVEL_1_TELETEXT, "Level 1 teletext");
code<DisplayStandard, string> (_display_standard_map, "2", DISPLAY_STANDARD_LEVEL_2_TELETEXT, "Level 2 teletext");
-
+
code<LanguageGroup, string> (_language_group_map, "00", LANGUAGE_GROUP_LATIN, "Latin");
code<LanguageGroup, string> (_language_group_map, "01", LANGUAGE_GROUP_LATIN_CYRILLIC, "Latin/Cyrillic");
code<LanguageGroup, string> (_language_group_map, "02", LANGUAGE_GROUP_LATIN_ARABIC, "Latin/Arabic");
code<LanguageGroup, string> (_language_group_map, "03", LANGUAGE_GROUP_LATIN_GREEK, "Latin/Greek");
code<LanguageGroup, string> (_language_group_map, "04", LANGUAGE_GROUP_LATIN_HEBREW, "Latin/Hebrew");
-
+
code<Language, string> (_language_map, "00", LANGUAGE_UNKNOWN, "Unknown");
code<Language, string> (_language_map, "01", LANGUAGE_ALBANIAN, "Albanian");
code<Language, string> (_language_map, "02", LANGUAGE_BRETON, "Breton");
DISPLAY_STANDARD_LEVEL_1_TELETEXT,
DISPLAY_STANDARD_LEVEL_2_TELETEXT
};
-
+
enum LanguageGroup {
LANGUAGE_GROUP_LATIN,
LANGUAGE_GROUP_LATIN_CYRILLIC,
: value (v)
, description (d)
{}
-
+
T value;
std::string description;
};
boost::optional<Language> language_description_to_enum (std::string) const;
-private:
+private:
std::map<std::string, STLBinaryCode<DisplayStandard> > _display_standard_map;
std::map<std::string, STLBinaryCode<LanguageGroup> > _language_group_map;
std::map<std::string, STLBinaryCode<Language> > _language_map;
put_string (char* p, unsigned int n, string s)
{
assert (s.length() <= n);
-
+
memcpy (p, s.c_str (), s.length ());
memset (p + s.length(), ' ', n - s.length ());
}
assert (publisher.size() <= 32);
assert (editor_name.size() <= 32);
assert (editor_contact_details.size() <= 32);
-
+
char* buffer = new char[1024];
memset (buffer, 0, 1024);
ofstream output (file_name.string().c_str ());
++lines;
}
}
-
+
/* Code page: 850 */
put_string (buffer + 0, "850");
/* Disk format code */
put_int_as_int (buffer + 14, tables.justification_enum_to_file (JUSTIFICATION_NONE), 1);
/* Comment flag */
put_int_as_int (buffer + 15, tables.comment_enum_to_file (COMMENT_NO), 1);
-
+
/* Text */
string text;
bool italic = false;
bool underline = false;
-
+
for (list<Block>::const_iterator k = j->blocks.begin(); k != j->blocks.end(); ++k) {
if (k->underline && !underline) {
text += "\x82";
text += "\x81";
italic = false;
}
-
+
text += utf16_to_iso6937 (utf_to_utf<wchar_t> (k->text));
}
-
+
text += "\x8A";
-
+
if (text.length() > 111) {
text = text.substr (111);
}
-
+
while (text.length() < 112) {
text += "\x8F";
}
-
+
put_string (buffer + 16, text);
output.write (buffer, 128);
#include <boost/optional.hpp>
namespace sub {
-
+
class Rational
{
public:
: numerator (numerator_)
, denominator (denominator_)
{}
-
+
int numerator;
int denominator;
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);
-
+
private:
friend bool operator< (Time const & a, Time const & b);
friend bool operator> (Time const & a, Time const & b);
, _frames (frames)
, _rate (rate)
{}
-
+
int _seconds;
int _frames;
boost::optional<Rational> _rate;
bool operator== (Time const & a, Time const & b);
bool operator!= (Time const & a, Time const & b);
std::ostream& operator<< (std::ostream& s, Time const & t);
-
+
}
#endif
, italic (s.italic)
, underline (s.underline)
{
-
+
}
/** Construct a Block taking any relevant information from a RawSubtitle */
Block (RawSubtitle s);
-
+
/** Subtitle text in UTF-8 */
std::string text;
boost::optional<std::string> font;
boost::optional<Effect> effect;
boost::optional<Colour> effect_colour;
-
+
Colour colour;
bool bold; ///< true to use a bold version of font
bool italic; ///< true to use an italic version of font
{
public:
Line () {}
-
+
/** Construct a Line taking any relevant information from a RawSubtitle */
Line (RawSubtitle s);
/** Construct a Line taking any relevant information from a RawSubtitle */
Subtitle (RawSubtitle s);
-
+
/** from time */
Time from;
/** to time */
Time to;
-
+
boost::optional<Time> fade_up;
boost::optional<Time> fade_down;
}
float const prop = proportional ? proportional.get() : (float (line.get()) / lines.get ());
-
+
switch (reference.get ()) {
case TOP_OF_SCREEN:
return prop;
boost::optional<int> lines;
/** reference point */
boost::optional<VerticalReference> reference;
-
+
bool operator== (VerticalPosition const & other) const;
bool operator< (VerticalPosition const & other) const;
float fraction_from_screen_top () const;
};
-
+
}
#endif
} else if (s == "bottom") {
return BOTTOM_OF_SCREEN;
}
-
+
throw XMLError ("unknown subtitle valign type");
}
};
VerticalReference string_to_vertical_reference (std::string s);
-
+
}
#endif
boost::shared_ptr<T> type_child (boost::shared_ptr<const cxml::Node> node, std::string name) {
return boost::shared_ptr<T> (new T (node->node_child (name)));
}
-
+
template <class T>
boost::shared_ptr<T>
optional_type_child (boost::shared_ptr<const cxml::Node> node, std::string name)
{
return type_children<T> (*node.get(), name);
}
-
+
template <class T>
std::list<boost::shared_ptr<T> >
type_grand_children (cxml::Node const & node, std::string name, std::string sub)
{
return type_grand_children<T> (*node.get(), name, sub);
}
-
+
}
#endif
l.vertical_position.line = 0;
l.vertical_position.lines = 32;
l.vertical_position.reference = sub::TOP_OF_SCREEN;
-
+
sub::Block b;
b.text = "This is some ";
b.font = "Arial";
"Editor contact",
"build/test/test.stl"
);
-
+
}
list<sub::Subtitle>::iterator i = subs.begin ();
-
+
/* First subtitle */
BOOST_CHECK (i != subs.end ());
BOOST_CHECK_EQUAL (i->from, sub::Time::from_hmsf (0, 0, 41, 9));
BOOST_CHECK_EQUAL (i->to, sub::Time::from_hmsf (0, 0, 42, 21));
-
+
list<sub::Line>::iterator j = i->lines.begin ();
BOOST_CHECK (j != i->lines.end ());
BOOST_CHECK_EQUAL (j->blocks.size(), 1);
BOOST_CHECK_EQUAL (j->vertical_position.line.get(), 1);
++i;
-
+
/* Second subtitle */
-
+
BOOST_CHECK (i != subs.end ());
BOOST_CHECK_EQUAL (i->from, sub::Time::from_hmsf (0, 1, 1, 1));
BOOST_CHECK_EQUAL (i->to, sub::Time::from_hmsf (0, 1, 2, 10));
-
+
BOOST_CHECK_EQUAL (i->lines.size(), 1);
sub::Line l = i->lines.front ();
BOOST_CHECK_EQUAL (l.blocks.size(), 7);
BOOST_CHECK_EQUAL (l.vertical_position.line.get(), 0);
list<sub::Block>::iterator k = l.blocks.begin ();
-
+
BOOST_CHECK (k != l.blocks.end ());
BOOST_CHECK_EQUAL (k->text, " This is some ");
BOOST_CHECK_EQUAL (k->font.get(), "Arial");
BOOST_CHECK_EQUAL (k->italic, false);
BOOST_CHECK_EQUAL (k->underline, false);
++k;
-
+
BOOST_CHECK (k == l.blocks.end ());
}
BOOST_AUTO_TEST_CASE (time_conversion_test)
{
sub::Time p;
-
+
/* 40ms = 1 frame at 25fps */
p = sub::Time::from_hms (3, 5, 7, 40);
BOOST_CHECK_EQUAL (p.frames_at (sub::Rational (25, 1)), 1);
{
sub::VerticalPosition a;
sub::VerticalPosition b;
-
+
/* Simple */
-
+
a.proportional = 0.3;
a.reference = sub::TOP_OF_SCREEN;
b.proportional = 0.4;
BOOST_CHECK (b < a);
/* Different line counts with lines */
-
+
a.proportional = optional<float> ();
b.proportional = optional<float> ();