#!/bin/bash -e
#
-# Run our test suite, which (amongst other things)
-# builds a couple of DCPs.
-# The outputs are compared against the ones
-# in test/ref/DCP, and an error is given
-# if anything is different.
+# Run our test suite.
+# Private test data; this is stuff that is non-distributable
private=../libdcp1-test-private
+# Work directory
work=build/test
+# Path to dcpinfo tool
dcpinfo=build/tools/dcpinfo
export LD_LIBRARY_PATH=build/src:build/asdcplib/src:$LD_LIBRARY_PATH
+# Make sure we have the required tools
for c in xmlsec1 xmldiff; do
hash $c 2>/dev/null || { echo >&2 "$c required but not found; aborting"; exit 1; }
done
fi
# Run dcpinfo on all the DCPs in private/metadata, writing $work/info.log
+# This writes details of the CPLs and all subtitle details, so it checks
+# if the code is reading subtitle files correctly.
rm -f $work/info.log
for d in `find $private/metadata -mindepth 1 -maxdepth 1 -type d | sort -f -d`; do
if [ `basename $d` != ".git" ]; then
exit 1
fi
-# Copy test/private into build/ then re-write the subtitles of every DCP using
+# Copy $private into build/ then re-write the subtitles of every DCP using
# $work/rewrite_subs. This tests round-trip of subtitle reading/writing.
+# Note that all the subs in $private/metadata are Interop.
rm -f $work/info2.log
rm -rf $work/private
mkdir $work/private
exit 1
fi
-# Dump the subs of JourneyToJah... (which has MXF-wrapped subtitles)
+# Dump the subs of JourneyToJah... (which has MXF-wrapped SMPTE subtitles)
# and check that they are right
$dcpinfo -s $private/data/JourneyToJah_TLR-1_F_EN-DE-FR_CH_51_2K_LOK_20140225_DGL_SMPTE_OV >> $work/jah.log
+# Rewrite the subs of JourneyToJah...
+#cp -r $private/data/JourneyToJah_TLR-1_F_EN-DE-FR_CH_51_2K_LOK_20140225_DGL_SMPTE_OV $work/
+#$work/rewrite_subs $WORK/Jou
+
echo "PASS"
}
}
+/** @param time String of the form HH:MM:SS:EE */
Time::Time (string time, int tcr_)
: tcr (tcr_)
{
#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;
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");
_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
{
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");
}
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;
+}
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;
};
}
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;
* @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 */
#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)
_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);
}
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;
+}
+
*/
#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
*/
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;
};
using namespace dcp;
SubtitleAsset::SubtitleAsset ()
- : _reel_number ("1")
{
}
SubtitleAsset::SubtitleAsset (boost::filesystem::path file)
: Asset (file)
- , _reel_number ("1")
{
}
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);
}
_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
{
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;
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());
+ }
+}
+
+
#include "subtitle_string.h"
#include <libcxml/cxml.h>
+namespace xmlpp {
+ class Element;
+}
+
namespace dcp
{
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;
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;
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:
#include "raw_convert.h"
#include "types.h"
#include "exceptions.h"
+#include "compose.hpp"
#include <boost/algorithm/string.hpp>
#include <vector>
#include <cstdio>
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)
{
return float (numerator) / denominator;
}
+ std::string as_string () const;
+
int numerator;
int denominator;
};
for (list<shared_ptr<Reel> >::iterator j = reels.begin(); j != reels.end(); ++j) {
if ((*j)->main_subtitle()) {
- (*j)->main_subtitle()->subtitle_asset()->write_xml ((*j)->main_subtitle()->subtitle_asset()->file ());
+ (*j)->main_subtitle()->subtitle_asset()->write ((*j)->main_subtitle()->subtitle_asset()->file ());
}
}
}
BOOST_AUTO_TEST_CASE (write_subtitle_test)
{
dcp::InteropSubtitleAsset c ("Test", "EN");
+ c.set_reel_number ("1");
c.add (
dcp::SubtitleString (
" <ReelNumber>1</ReelNumber>\n"
" <Language>EN</Language>\n"
" <Font Id=\"Frutiger\" Italic=\"no\" Color=\"FFFFFFFF\" Size=\"48\" Effect=\"none\" EffectColor=\"FF000000\" Script=\"normal\" Underlined=\"no\" Weight=\"normal\">\n"
- " <Subtitle SpotNumber=\"1\" TimeIn=\"00:04:09:022\" TimeOut=\"00:04:11:022\" FadeUpTime=\"0\" FadeDownTime=\"0\">\n"
+ " <Subtitle SpotNumber=\"1\" TimeIn=\"00:04:09:229\" TimeOut=\"00:04:11:229\" FadeUpTime=\"0\" FadeDownTime=\"0\">\n"
" <Text VAlign=\"top\" VPosition=\"80\">Hello world</Text>\n"
" </Subtitle>\n"
" </Font>\n"
" <Font Italic=\"yes\" Color=\"FF800040\" Size=\"91\" Effect=\"border\" EffectColor=\"FF010203\" Script=\"normal\" Underlined=\"no\" Weight=\"normal\">\n"
- " <Subtitle SpotNumber=\"2\" TimeIn=\"05:41:00:021\" TimeOut=\"06:12:15:021\" FadeUpTime=\"930790\" FadeDownTime=\"4591830\">\n"
+ " <Subtitle SpotNumber=\"2\" TimeIn=\"05:41:00:219\" TimeOut=\"06:12:15:219\" FadeUpTime=\"930790\" FadeDownTime=\"4591830\">\n"
" <Text VAlign=\"bottom\" VPosition=\"40\">What's going on</Text>\n"
" </Subtitle>\n"
" </Font>\n"
#include "reel_sound_asset.h"
#include "reel_subtitle_asset.h"
#include "subtitle_string.h"
+#include "interop_subtitle_asset.h"
+#include "smpte_subtitle_asset.h"
#include "cpl.h"
#include "common.h"
#include <getopt.h>
using std::cout;
using std::list;
using boost::shared_ptr;
+using boost::dynamic_pointer_cast;
using namespace dcp;
static void
}
list<SubtitleString> subs = reel->main_subtitle()->subtitle_asset()->subtitles ();
- cout << " Subtitle: " << subs.size() << " subtitles in " << reel->main_subtitle()->subtitle_asset()->language() << "\n";
+ cout << " Subtitle: " << subs.size() << " subtitles";
+ shared_ptr<InteropSubtitleAsset> iop = dynamic_pointer_cast<InteropSubtitleAsset> (reel->main_subtitle()->subtitle_asset());
+ if (iop) {
+ cout << " in " << iop->language() << "\n";
+ }
+ shared_ptr<SMPTESubtitleAsset> smpte = dynamic_pointer_cast<SMPTESubtitleAsset> (reel->main_subtitle()->subtitle_asset());
+ if (smpte && smpte->language ()) {
+ cout << " in " << smpte->language().get() << "\n";
+ }
if (list_subtitles) {
BOOST_FOREACH (SubtitleString const& k, subs) {
cout << k << "\n";