summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2015-06-04 12:25:48 +0100
committerCarl Hetherington <cth@carlh.net>2015-06-05 15:53:48 +0100
commit42a65cba0d8da23c12af52015e66cd9dc0b5a5fa (patch)
treeff0a017c49d0975f21a5314d2f77be20f68bd379 /src
parent943e75e0ac5730714f3823771f127fe78e4cf82b (diff)
Initial work on SMPTE subtitles.
Diffstat (limited to 'src')
-rw-r--r--src/dcp_time.cc1
-rw-r--r--src/interop_subtitle_asset.cc127
-rw-r--r--src/interop_subtitle_asset.h33
-rw-r--r--src/mxf.cc2
-rw-r--r--src/mxf.h2
-rw-r--r--src/smpte_subtitle_asset.cc109
-rw-r--r--src/smpte_subtitle_asset.h33
-rw-r--r--src/subtitle_asset.cc147
-rw-r--r--src/subtitle_asset.h25
-rw-r--r--src/types.cc7
-rw-r--r--src/types.h2
11 files changed, 326 insertions, 162 deletions
diff --git a/src/dcp_time.cc b/src/dcp_time.cc
index d34804e9..5d9bed81 100644
--- a/src/dcp_time.cc
+++ b/src/dcp_time.cc
@@ -66,6 +66,7 @@ Time::set (double seconds, int tcr_)
}
}
+/** @param time String of the form HH:MM:SS:EE */
Time::Time (string time, int tcr_)
: tcr (tcr_)
{
diff --git a/src/interop_subtitle_asset.cc b/src/interop_subtitle_asset.cc
index a6bdfcaf..528b7d90 100644
--- a/src/interop_subtitle_asset.cc
+++ b/src/interop_subtitle_asset.cc
@@ -22,9 +22,11 @@
#include "xml.h"
#include "raw_convert.h"
#include "font_node.h"
+#include "util.h"
#include <libxml++/libxml++.h>
#include <boost/foreach.hpp>
#include <cmath>
+#include <cstdio>
using std::list;
using std::string;
@@ -40,7 +42,8 @@ InteropSubtitleAsset::InteropSubtitleAsset (boost::filesystem::path file)
shared_ptr<cxml::Document> xml (new cxml::Document ("DCSubtitle"));
xml->read_file (file);
_id = xml->string_child ("SubtitleID");
-
+ _reel_number = xml->string_child ("ReelNumber");
+ _language = xml->string_child ("Language");
_movie_title = xml->string_child ("MovieTitle");
_load_font_nodes = type_children<dcp::InteropLoadFontNode> (xml, "LoadFont");
@@ -59,15 +62,6 @@ InteropSubtitleAsset::InteropSubtitleAsset (string movie_title, string language)
_language = language;
}
-struct SubtitleSorter {
- bool operator() (SubtitleString const & a, SubtitleString const & b) {
- if (a.in() != b.in()) {
- return a.in() < b.in();
- }
- return a.v_position() < b.v_position();
- }
-};
-
Glib::ustring
InteropSubtitleAsset::xml_as_string () const
{
@@ -86,102 +80,7 @@ InteropSubtitleAsset::xml_as_string () const
load_font->set_attribute ("URI", (*i)->uri);
}
- list<SubtitleString> sorted = _subtitles;
- sorted.sort (SubtitleSorter ());
-
- /* XXX: script, underlined, weight not supported */
-
- optional<string> font;
- bool italic = false;
- Colour colour;
- int size = 0;
- float aspect_adjust = 1.0;
- Effect effect = NONE;
- Colour effect_colour;
- int spot_number = 1;
- Time last_in;
- Time last_out;
- Time last_fade_up_time;
- Time last_fade_down_time;
-
- xmlpp::Element* font_element = 0;
- xmlpp::Element* subtitle_element = 0;
-
- for (list<SubtitleString>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
-
- /* We will start a new <Font>...</Font> whenever some font property changes.
- I suppose we should really make an optimal hierarchy of <Font> tags, but
- that seems hard.
- */
-
- bool const font_changed =
- font != i->font() ||
- italic != i->italic() ||
- colour != i->colour() ||
- size != i->size() ||
- fabs (aspect_adjust - i->aspect_adjust()) > ASPECT_ADJUST_EPSILON ||
- effect != i->effect() ||
- effect_colour != i->effect_colour();
-
- if (font_changed) {
- font = i->font ();
- italic = i->italic ();
- colour = i->colour ();
- size = i->size ();
- aspect_adjust = i->aspect_adjust ();
- effect = i->effect ();
- effect_colour = i->effect_colour ();
- }
-
- if (!font_element || font_changed) {
- font_element = root->add_child ("Font");
- if (font) {
- font_element->set_attribute ("Id", font.get ());
- }
- font_element->set_attribute ("Italic", italic ? "yes" : "no");
- font_element->set_attribute ("Color", colour.to_argb_string());
- font_element->set_attribute ("Size", raw_convert<string> (size));
- if (fabs (aspect_adjust - 1.0) > ASPECT_ADJUST_EPSILON) {
- font_element->set_attribute ("AspectAdjust", raw_convert<string> (aspect_adjust));
- }
- font_element->set_attribute ("Effect", effect_to_string (effect));
- font_element->set_attribute ("EffectColor", effect_colour.to_argb_string());
- font_element->set_attribute ("Script", "normal");
- font_element->set_attribute ("Underlined", "no");
- font_element->set_attribute ("Weight", "normal");
- }
-
- if (!subtitle_element || font_changed ||
- (last_in != i->in() ||
- last_out != i->out() ||
- last_fade_up_time != i->fade_up_time() ||
- last_fade_down_time != i->fade_down_time()
- )) {
-
- subtitle_element = font_element->add_child ("Subtitle");
- subtitle_element->set_attribute ("SpotNumber", raw_convert<string> (spot_number++));
- subtitle_element->set_attribute ("TimeIn", i->in().as_string());
- subtitle_element->set_attribute ("TimeOut", i->out().as_string());
- subtitle_element->set_attribute ("FadeUpTime", raw_convert<string> (i->fade_up_time().as_editable_units(250)));
- subtitle_element->set_attribute ("FadeDownTime", raw_convert<string> (i->fade_down_time().as_editable_units(250)));
-
- last_in = i->in ();
- last_out = i->out ();
- last_fade_up_time = i->fade_up_time ();
- last_fade_down_time = i->fade_down_time ();
- }
-
- xmlpp::Element* text = subtitle_element->add_child ("Text");
- if (i->h_align() != HALIGN_CENTER) {
- text->set_attribute ("HAlign", halign_to_string (i->h_align ()));
- }
- if (i->h_position() > ALIGN_EPSILON) {
- text->set_attribute ("HPosition", raw_convert<string> (i->h_position() * 100, 6));
- }
- text->set_attribute ("VAlign", valign_to_string (i->v_align()));
- text->set_attribute ("VPosition", raw_convert<string> (i->v_position() * 100, 6));
- text->add_child_text (i->text());
- }
+ subtitles_as_xml (root, 250, "");
return doc.write_to_string_formatted ("UTF-8");
}
@@ -237,3 +136,19 @@ InteropSubtitleAsset::load_font_nodes () const
copy (_load_font_nodes.begin(), _load_font_nodes.end(), back_inserter (lf));
return lf;
}
+
+/** Write this content to an XML file */
+void
+InteropSubtitleAsset::write (boost::filesystem::path p) const
+{
+ FILE* f = fopen_boost (p, "w");
+ if (!f) {
+ throw FileError ("Could not open file for writing", p, -1);
+ }
+
+ Glib::ustring const s = xml_as_string ();
+ fwrite (s.c_str(), 1, s.bytes(), f);
+ fclose (f);
+
+ _file = p;
+}
diff --git a/src/interop_subtitle_asset.h b/src/interop_subtitle_asset.h
index 586bb67c..2a1fae7f 100644
--- a/src/interop_subtitle_asset.h
+++ b/src/interop_subtitle_asset.h
@@ -41,8 +41,41 @@ public:
void add_font (std::string id, std::string uri);
Glib::ustring xml_as_string () const;
+ void write (boost::filesystem::path path) const;
+
+ void set_reel_number (std::string n) {
+ _reel_number = n;
+ }
+
+ void set_language (std::string l) {
+ _language = l;
+ }
+
+ void set_movie_title (std::string m) {
+ _movie_title = m;
+ }
+
+ std::string reel_number () const {
+ return _reel_number;
+ }
+
+ std::string language () const {
+ return _language;
+ }
+
+ std::string movie_title () const {
+ return _movie_title;
+ }
+
+protected:
+
+ std::string pkl_type (Standard) const {
+ return "text/xml";
+ }
private:
+ std::string _reel_number;
+ std::string _language;
std::string _movie_title;
std::list<boost::shared_ptr<InteropLoadFontNode> > _load_font_nodes;
};
diff --git a/src/mxf.cc b/src/mxf.cc
index 80a351e6..0cde395c 100644
--- a/src/mxf.cc
+++ b/src/mxf.cc
@@ -54,7 +54,7 @@ MXF::~MXF ()
}
void
-MXF::fill_writer_info (ASDCP::WriterInfo* writer_info, string id, Standard standard)
+MXF::fill_writer_info (ASDCP::WriterInfo* writer_info, string id, Standard standard) const
{
writer_info->ProductVersion = _metadata.product_version;
writer_info->CompanyName = _metadata.company_name;
diff --git a/src/mxf.h b/src/mxf.h
index a9f1bfa3..60c635be 100644
--- a/src/mxf.h
+++ b/src/mxf.h
@@ -95,7 +95,7 @@ protected:
* @param w struct to fill in.
* @param standard INTEROP or SMPTE.
*/
- void fill_writer_info (ASDCP::WriterInfo* w, std::string id, Standard standard);
+ void fill_writer_info (ASDCP::WriterInfo* w, std::string id, Standard standard) const;
ASDCP::AESDecContext* _decryption_context;
/** ID of the key used for encryption/decryption, if there is one */
diff --git a/src/smpte_subtitle_asset.cc b/src/smpte_subtitle_asset.cc
index e5a083b1..40afc76d 100644
--- a/src/smpte_subtitle_asset.cc
+++ b/src/smpte_subtitle_asset.cc
@@ -24,13 +24,19 @@
#include "xml.h"
#include "AS_DCP.h"
#include "KM_util.h"
+#include "raw_convert.h"
+#include <libxml++/libxml++.h>
#include <boost/foreach.hpp>
+#include <boost/algorithm/string.hpp>
using std::string;
using std::list;
using std::stringstream;
using std::cout;
+using std::vector;
using boost::shared_ptr;
+using boost::split;
+using boost::is_any_of;
using namespace dcp;
SMPTESubtitleAsset::SMPTESubtitleAsset (boost::filesystem::path file, bool mxf)
@@ -64,16 +70,37 @@ SMPTESubtitleAsset::SMPTESubtitleAsset (boost::filesystem::path file, bool mxf)
_load_font_nodes = type_children<dcp::SMPTELoadFontNode> (xml, "LoadFont");
- int tcr = xml->number_child<int> ("TimeCodeRate");
+ _content_title_text = xml->string_child ("ContentTitleText");
+ _annotation_text = xml->optional_string_child ("AnnotationText");
+ _issue_date = LocalTime (xml->string_child ("IssueDate"));
+ _reel_number = xml->optional_number_child<int> ("ReelNumber");
+ _language = xml->optional_string_child ("Language");
+
+ /* This is supposed to be two numbers, but a single number has been seen in the wild */
+ string const er = xml->string_child ("EditRate");
+ vector<string> er_parts;
+ split (er_parts, er, is_any_of (" "));
+ if (er_parts.size() == 1) {
+ _edit_rate = Fraction (raw_convert<int> (er_parts[0]), 1);
+ } else if (er_parts.size() == 2) {
+ _edit_rate = Fraction (raw_convert<int> (er_parts[0]), raw_convert<int> (er_parts[1]));
+ } else {
+ throw XMLError ("malformed EditRate " + er);
+ }
+
+ _time_code_rate = xml->number_child<int> ("TimeCodeRate");
+ if (xml->optional_string_child ("StartTime")) {
+ _start_time = Time (xml->string_child ("StartTime"), _time_code_rate);
+ }
shared_ptr<cxml::Node> subtitle_list = xml->optional_node_child ("SubtitleList");
list<cxml::NodePtr> f = subtitle_list->node_children ("Font");
list<shared_ptr<dcp::FontNode> > font_nodes;
BOOST_FOREACH (cxml::NodePtr& i, f) {
- font_nodes.push_back (shared_ptr<FontNode> (new FontNode (i, tcr)));
+ font_nodes.push_back (shared_ptr<FontNode> (new FontNode (i, _time_code_rate)));
}
-
+
parse_common (xml, font_nodes);
}
@@ -92,3 +119,79 @@ SMPTESubtitleAsset::valid_mxf (boost::filesystem::path file)
Kumu::Result_t r = reader.OpenRead (file.string().c_str ());
return !ASDCP_FAILURE (r);
}
+
+Glib::ustring
+SMPTESubtitleAsset::xml_as_string () const
+{
+ xmlpp::Document doc;
+ xmlpp::Element* root = doc.create_root_node ("dcst:SubtitleReel");
+ root->set_namespace_declaration ("http://www.smpte-ra.org/schemas/428-7/2010/DCST", "dcst");
+ root->set_namespace_declaration ("http://www.w3.org/2001/XMLSchema", "xs");
+
+ root->add_child("ID", "dcst")->add_child_text (_id);
+ root->add_child("ContentTitleText", "dcst")->add_child_text (_content_title_text);
+ if (_annotation_text) {
+ root->add_child("AnnotationText", "dcst")->add_child_text (_annotation_text.get ());
+ }
+ root->add_child("IssueDate", "dcst")->add_child_text (_issue_date.as_string (true));
+ if (_reel_number) {
+ root->add_child("ReelNumber", "dcst")->add_child_text (raw_convert<string> (_reel_number.get ()));
+ }
+ if (_language) {
+ root->add_child("Language", "dcst")->add_child_text (_language.get ());
+ }
+ root->add_child("EditRate", "dcst")->add_child_text (_edit_rate.as_string ());
+ root->add_child("TimeCodeRate", "dcst")->add_child_text (raw_convert<string> (_time_code_rate));
+ if (_start_time) {
+ root->add_child("StartTime", "dcst")->add_child_text (_start_time.get().as_string ());
+ }
+
+ BOOST_FOREACH (shared_ptr<SMPTELoadFontNode> i, _load_font_nodes) {
+ xmlpp::Element* load_font = root->add_child("LoadFont", "dcst");
+ load_font->add_child_text (i->urn);
+ load_font->set_attribute ("ID", i->id);
+ }
+
+ subtitles_as_xml (root->add_child ("SubtitleList", "dcst"), _time_code_rate, "dcst");
+
+ return doc.write_to_string_formatted ("UTF-8");
+}
+
+/** Write this content to a MXF file */
+void
+SMPTESubtitleAsset::write (boost::filesystem::path p) const
+{
+ ASDCP::WriterInfo writer_info;
+ fill_writer_info (&writer_info, _id, SMPTE);
+
+ ASDCP::TimedText::TimedTextDescriptor descriptor;
+ descriptor.EditRate = ASDCP::Rational (_edit_rate.numerator, _edit_rate.denominator);
+ descriptor.EncodingName = "UTF-8";
+ descriptor.ResourceList.clear ();
+ descriptor.NamespaceName = "dcst";
+ memcpy (descriptor.AssetID, writer_info.AssetUUID, ASDCP::UUIDlen);
+ descriptor.ContainerDuration = latest_subtitle_out().as_editable_units (_edit_rate.numerator / _edit_rate.denominator);
+
+ /* XXX: fonts into descriptor? */
+
+ ASDCP::TimedText::MXFWriter writer;
+ Kumu::Result_t r = writer.OpenWrite (p.string().c_str(), writer_info, descriptor);
+ if (ASDCP_FAILURE (r)) {
+ boost::throw_exception (FileError ("could not open subtitle MXF for writing", p.string(), r));
+ }
+
+ /* XXX: no encryption */
+ writer.WriteTimedTextResource (xml_as_string ());
+
+ writer.Finalize ();
+
+ _file = p;
+}
+
+bool
+SMPTESubtitleAsset::equals (shared_ptr<const Asset> other_asset, EqualityOptions options, NoteHandler note) const
+{
+ /* XXX */
+ return false;
+}
+
diff --git a/src/smpte_subtitle_asset.h b/src/smpte_subtitle_asset.h
index 639c8eb7..5f4d8833 100644
--- a/src/smpte_subtitle_asset.h
+++ b/src/smpte_subtitle_asset.h
@@ -18,13 +18,15 @@
*/
#include "subtitle_asset.h"
+#include "local_time.h"
+#include "mxf.h"
#include <boost/filesystem.hpp>
namespace dcp {
class SMPTELoadFontNode;
-class SMPTESubtitleAsset : public SubtitleAsset
+class SMPTESubtitleAsset : public SubtitleAsset, public MXF
{
public:
/** @param file File name
@@ -32,11 +34,40 @@ public:
*/
SMPTESubtitleAsset (boost::filesystem::path file, bool mxf = true);
+ bool equals (
+ boost::shared_ptr<const Asset>,
+ EqualityOptions,
+ NoteHandler note
+ ) const;
+
std::list<boost::shared_ptr<LoadFontNode> > load_font_nodes () const;
+ Glib::ustring xml_as_string () const;
+ void write (boost::filesystem::path path) const;
+
+ /** @return language, if one was specified */
+ boost::optional<std::string> language () const {
+ return _language;
+ }
+
static bool valid_mxf (boost::filesystem::path);
+
+protected:
+
+ std::string pkl_type (Standard) const {
+ return "application/mxf";
+ }
private:
+ std::string _content_title_text;
+ boost::optional<std::string> _annotation_text;
+ LocalTime _issue_date;
+ boost::optional<int> _reel_number;
+ boost::optional<std::string> _language;
+ Fraction _edit_rate;
+ int _time_code_rate;
+ boost::optional<Time> _start_time;
+
std::list<boost::shared_ptr<SMPTELoadFontNode> > _load_font_nodes;
};
diff --git a/src/subtitle_asset.cc b/src/subtitle_asset.cc
index f1ecc939..1c341de4 100644
--- a/src/subtitle_asset.cc
+++ b/src/subtitle_asset.cc
@@ -43,14 +43,12 @@ using boost::dynamic_pointer_cast;
using namespace dcp;
SubtitleAsset::SubtitleAsset ()
- : _reel_number ("1")
{
}
SubtitleAsset::SubtitleAsset (boost::filesystem::path file)
: Asset (file)
- , _reel_number ("1")
{
}
@@ -58,13 +56,7 @@ SubtitleAsset::SubtitleAsset (boost::filesystem::path file)
void
SubtitleAsset::parse_common (shared_ptr<cxml::Document> xml, list<shared_ptr<dcp::FontNode> > font_nodes)
{
- _reel_number = xml->string_child ("ReelNumber");
- _language = xml->string_child ("Language");
-
- /* Now make Subtitle objects to represent the raw XML nodes
- in a sane way.
- */
-
+ /* Make Subtitle objects to represent the raw XML nodes in a sane way */
ParseState parse_state;
examine_font_nodes (xml, font_nodes, parse_state);
}
@@ -169,21 +161,6 @@ SubtitleAsset::add (SubtitleString s)
_subtitles.push_back (s);
}
-void
-SubtitleAsset::write_xml (boost::filesystem::path p) const
-{
- FILE* f = fopen_boost (p, "w");
- if (!f) {
- throw FileError ("Could not open file for writing", p, -1);
- }
-
- Glib::ustring const s = xml_as_string ();
- fwrite (s.c_str(), 1, s.bytes(), f);
- fclose (f);
-
- _file = p;
-}
-
Time
SubtitleAsset::latest_subtitle_out () const
{
@@ -209,16 +186,6 @@ SubtitleAsset::equals (shared_ptr<const Asset> other_asset, EqualityOptions opti
return false;
}
- if (_reel_number != other->_reel_number) {
- note (DCP_ERROR, "subtitle reel numbers differ");
- return false;
- }
-
- if (_language != other->_language) {
- note (DCP_ERROR, "subtitle languages differ");
- return false;
- }
-
if (_subtitles != other->_subtitles) {
note (DCP_ERROR, "subtitles differ");
return false;
@@ -226,3 +193,115 @@ SubtitleAsset::equals (shared_ptr<const Asset> other_asset, EqualityOptions opti
return true;
}
+
+struct SubtitleSorter {
+ bool operator() (SubtitleString const & a, SubtitleString const & b) {
+ if (a.in() != b.in()) {
+ return a.in() < b.in();
+ }
+ return a.v_position() < b.v_position();
+ }
+};
+
+void
+SubtitleAsset::subtitles_as_xml (xmlpp::Element* root, int time_code_rate, string xmlns) const
+{
+ list<SubtitleString> sorted = _subtitles;
+ sorted.sort (SubtitleSorter ());
+
+ /* XXX: script, underlined, weight not supported */
+
+ optional<string> font;
+ bool italic = false;
+ Colour colour;
+ int size = 0;
+ float aspect_adjust = 1.0;
+ Effect effect = NONE;
+ Colour effect_colour;
+ int spot_number = 1;
+ Time last_in;
+ Time last_out;
+ Time last_fade_up_time;
+ Time last_fade_down_time;
+
+ xmlpp::Element* font_element = 0;
+ xmlpp::Element* subtitle_element = 0;
+
+ for (list<SubtitleString>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
+
+ /* We will start a new <Font>...</Font> whenever some font property changes.
+ I suppose we should really make an optimal hierarchy of <Font> tags, but
+ that seems hard.
+ */
+
+ bool const font_changed =
+ font != i->font() ||
+ italic != i->italic() ||
+ colour != i->colour() ||
+ size != i->size() ||
+ fabs (aspect_adjust - i->aspect_adjust()) > ASPECT_ADJUST_EPSILON ||
+ effect != i->effect() ||
+ effect_colour != i->effect_colour();
+
+ if (font_changed) {
+ font = i->font ();
+ italic = i->italic ();
+ colour = i->colour ();
+ size = i->size ();
+ aspect_adjust = i->aspect_adjust ();
+ effect = i->effect ();
+ effect_colour = i->effect_colour ();
+ }
+
+ if (!font_element || font_changed) {
+ font_element = root->add_child ("Font", xmlns);
+ if (font) {
+ font_element->set_attribute ("Id", font.get ());
+ }
+ font_element->set_attribute ("Italic", italic ? "yes" : "no");
+ font_element->set_attribute ("Color", colour.to_argb_string());
+ font_element->set_attribute ("Size", raw_convert<string> (size));
+ if (fabs (aspect_adjust - 1.0) > ASPECT_ADJUST_EPSILON) {
+ font_element->set_attribute ("AspectAdjust", raw_convert<string> (aspect_adjust));
+ }
+ font_element->set_attribute ("Effect", effect_to_string (effect));
+ font_element->set_attribute ("EffectColor", effect_colour.to_argb_string());
+ font_element->set_attribute ("Script", "normal");
+ font_element->set_attribute ("Underlined", "no");
+ font_element->set_attribute ("Weight", "normal");
+ }
+
+ if (!subtitle_element || font_changed ||
+ (last_in != i->in() ||
+ last_out != i->out() ||
+ last_fade_up_time != i->fade_up_time() ||
+ last_fade_down_time != i->fade_down_time()
+ )) {
+
+ subtitle_element = font_element->add_child ("Subtitle", xmlns);
+ subtitle_element->set_attribute ("SpotNumber", raw_convert<string> (spot_number++));
+ subtitle_element->set_attribute ("TimeIn", i->in().rebase(time_code_rate).as_string());
+ subtitle_element->set_attribute ("TimeOut", i->out().rebase(time_code_rate).as_string());
+ subtitle_element->set_attribute ("FadeUpTime", raw_convert<string> (i->fade_up_time().as_editable_units(time_code_rate)));
+ subtitle_element->set_attribute ("FadeDownTime", raw_convert<string> (i->fade_down_time().as_editable_units(time_code_rate)));
+
+ last_in = i->in ();
+ last_out = i->out ();
+ last_fade_up_time = i->fade_up_time ();
+ last_fade_down_time = i->fade_down_time ();
+ }
+
+ xmlpp::Element* text = subtitle_element->add_child ("Text", xmlns);
+ if (i->h_align() != HALIGN_CENTER) {
+ text->set_attribute ("HAlign", halign_to_string (i->h_align ()));
+ }
+ if (i->h_position() > ALIGN_EPSILON) {
+ text->set_attribute ("HPosition", raw_convert<string> (i->h_position() * 100, 6));
+ }
+ text->set_attribute ("VAlign", valign_to_string (i->v_align()));
+ text->set_attribute ("VPosition", raw_convert<string> (i->v_position() * 100, 6));
+ text->add_child_text (i->text());
+ }
+}
+
+
diff --git a/src/subtitle_asset.h b/src/subtitle_asset.h
index deb72ece..c8100d58 100644
--- a/src/subtitle_asset.h
+++ b/src/subtitle_asset.h
@@ -25,6 +25,10 @@
#include "subtitle_string.h"
#include <libcxml/cxml.h>
+namespace xmlpp {
+ class Element;
+}
+
namespace dcp
{
@@ -49,10 +53,6 @@ public:
NoteHandler note
) const;
- std::string language () const {
- return _language;
- }
-
std::list<SubtitleString> subtitles_during (Time from, Time to) const;
std::list<SubtitleString> const & subtitles () const {
return _subtitles;
@@ -60,11 +60,8 @@ public:
void add (SubtitleString);
- void write_xml (boost::filesystem::path) const;
- virtual Glib::ustring xml_as_string () const {
- /* XXX: this should be pure virtual when SMPTE writing is implemented */
- return "";
- }
+ virtual void write (boost::filesystem::path) const = 0;
+ virtual Glib::ustring xml_as_string () const = 0;
Time latest_subtitle_out () const;
@@ -73,18 +70,14 @@ public:
protected:
void parse_common (boost::shared_ptr<cxml::Document> xml, std::list<boost::shared_ptr<FontNode> > font_nodes);
- std::string pkl_type (Standard) const {
- return "text/xml";
- }
+ virtual std::string pkl_type (Standard) const = 0;
std::string asdcp_kind () const {
return "Subtitle";
}
-
- /* strangely, this is sometimes a string */
- std::string _reel_number;
- std::string _language;
+ void subtitles_as_xml (xmlpp::Element* root, int time_code_rate, std::string xmlns) const;
+
std::list<SubtitleString> _subtitles;
private:
diff --git a/src/types.cc b/src/types.cc
index e86e999c..37666701 100644
--- a/src/types.cc
+++ b/src/types.cc
@@ -20,6 +20,7 @@
#include "raw_convert.h"
#include "types.h"
#include "exceptions.h"
+#include "compose.hpp"
#include <boost/algorithm/string.hpp>
#include <vector>
#include <cstdio>
@@ -43,6 +44,12 @@ Fraction::Fraction (string s)
denominator = raw_convert<int> (b[1]);
}
+string
+Fraction::as_string () const
+{
+ return String::compose ("%1 %2", numerator, denominator);
+}
+
bool
dcp::operator== (Fraction const & a, Fraction const & b)
{
diff --git a/src/types.h b/src/types.h
index 626666b4..ca7603ab 100644
--- a/src/types.h
+++ b/src/types.h
@@ -139,6 +139,8 @@ public:
return float (numerator) / denominator;
}
+ std::string as_string () const;
+
int numerator;
int denominator;
};