summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2025-03-20 21:02:55 +0100
committerCarl Hetherington <cth@carlh.net>2025-03-24 00:29:31 +0100
commit8edb46702b372b6e672d0ac8f810e151e1aa5707 (patch)
treee2a458fc456b3bd98982e6e31c0ec7589ab25274
parent0322c4604bf79c11a99dcd929a6f74685a0a4e31 (diff)
Read/write subtitle variable Z.v1.10.16
-rw-r--r--src/text.cc17
-rw-r--r--src/text.h13
-rw-r--r--src/text_asset.cc52
-rw-r--r--src/text_asset.h5
-rw-r--r--src/text_asset_internal.cc46
-rw-r--r--src/text_asset_internal.h36
-rw-r--r--src/text_image.cc8
-rw-r--r--src/text_image.h2
-rw-r--r--src/text_string.cc8
-rw-r--r--src/text_string.h2
-rw-r--r--test/data/subtitles_with_vZani.xml61
-rw-r--r--test/data/subtitles_with_vZani_parsed.xml59
-rw-r--r--test/decryption_test.cc2
-rw-r--r--test/interop_subtitle_test.cc31
-rw-r--r--test/load_variable_z_test.cc10
-rw-r--r--test/shared_subtitle_test.cc8
-rw-r--r--test/smpte_subtitle_test.cc25
-rw-r--r--test/test.cc1
-rw-r--r--test/verify_test.cc6
19 files changed, 373 insertions, 19 deletions
diff --git a/src/text.cc b/src/text.cc
index 158af38c..8f72b953 100644
--- a/src/text.cc
+++ b/src/text.cc
@@ -44,6 +44,9 @@
using std::shared_ptr;
+using std::string;
+using std::vector;
+using boost::optional;
using namespace dcp;
@@ -56,6 +59,7 @@ Text::Text(
float v_position,
VAlign v_align,
float z_position,
+ vector<VariableZPosition> variable_z_positions,
Time fade_up_time,
Time fade_down_time
)
@@ -66,6 +70,7 @@ Text::Text(
, _v_position (v_position)
, _v_align (v_align)
, _z_position(z_position)
+ , _variable_z_positions(variable_z_positions)
, _fade_up_time (fade_up_time)
, _fade_down_time (fade_down_time)
{
@@ -117,6 +122,11 @@ Text::equals(shared_ptr<const Text> other, EqualityOptions const& options, NoteH
same = false;
}
+ if (variable_z_positions() != other->variable_z_positions()) {
+ note(NoteType::ERROR, "text variable Z positions differ");
+ same = false;
+ }
+
if (fade_up_time() != other->fade_up_time()) {
note(NoteType::ERROR, "text fade-up times differ");
same = false;
@@ -129,3 +139,10 @@ Text::equals(shared_ptr<const Text> other, EqualityOptions const& options, NoteH
return same;
}
+
+
+bool dcp::operator==(Text::VariableZPosition a, Text::VariableZPosition b)
+{
+ return a.position == b.position && a.duration == b.duration;
+}
+
diff --git a/src/text.h b/src/text.h
index 70dfa3a6..f3b6ecea 100644
--- a/src/text.h
+++ b/src/text.h
@@ -97,6 +97,10 @@ public:
int64_t duration;
};
+ std::vector<VariableZPosition> variable_z_positions() const {
+ return _variable_z_positions;
+ }
+
Time fade_up_time () const {
return _fade_up_time;
}
@@ -128,6 +132,10 @@ public:
_z_position = z;
}
+ void set_variable_z_positions(std::vector<VariableZPosition> z) {
+ _variable_z_positions = std::move(z);
+ }
+
void set_fade_up_time (Time t) {
_fade_up_time = t;
}
@@ -148,6 +156,7 @@ protected:
float v_position,
VAlign v_align,
float z_position,
+ std::vector<VariableZPosition> variable_z,
Time fade_up_time,
Time fade_down_time
);
@@ -165,11 +174,15 @@ protected:
float _v_position = 0;
VAlign _v_align = VAlign::CENTER;
float _z_position = 0;
+ std::vector<VariableZPosition> _variable_z_positions;
Time _fade_up_time;
Time _fade_down_time;
};
+bool operator==(Text::VariableZPosition a, Text::VariableZPosition b);
+
+
}
diff --git a/src/text_asset.cc b/src/text_asset.cc
index c3341452..41690d93 100644
--- a/src/text_asset.cc
+++ b/src/text_asset.cc
@@ -206,6 +206,10 @@ TextAsset::position_align(TextAsset::ParseState& ps, xmlpp::Element const * node
if (auto zp = optional_number_attribute<float>(node, "Zposition")) {
ps.z_position = zp.get() / 100;
}
+
+ if (auto variable_z = optional_string_attribute(node, "VariableZ")) {
+ ps.variable_z = *variable_z;
+ }
}
@@ -248,6 +252,14 @@ TextAsset::subtitle_node_state(xmlpp::Element const * node, optional<int> tcr) c
ps.out = Time (string_attribute(node, "TimeOut"), tcr);
ps.fade_up_time = fade_time (node, "FadeUpTime", tcr);
ps.fade_down_time = fade_time (node, "FadeDownTime", tcr);
+
+ for (auto child: node->get_children()) {
+ auto element = dynamic_cast<xmlpp::Element const*>(child);
+ if (element && element->get_name() == "LoadVariableZ") {
+ ps.load_variable_z.push_back(LoadVariableZ(element));
+ }
+ }
+
return ps;
}
@@ -287,6 +299,8 @@ TextAsset::parse_texts(xmlpp::Element const * node, vector<ParseState>& state, o
state.push_back (ParseState ());
} else if (node->get_name() == "Image") {
state.push_back (image_node_state (node));
+ } else if (node->get_name() == "LoadVariableZ") {
+ return;
} else {
throw XMLError ("unexpected node " + node->get_name());
}
@@ -453,6 +467,9 @@ TextAsset::maybe_add_text(
if (i.z_position) {
ps.z_position = i.z_position.get();
}
+ if (i.variable_z) {
+ ps.variable_z = i.variable_z.get();
+ }
if (i.direction) {
ps.direction = i.direction.get();
}
@@ -471,6 +488,13 @@ TextAsset::maybe_add_text(
if (i.type) {
ps.type = i.type.get();
}
+ for (auto j: i.load_variable_z) {
+ /* j is a LoadVariableZ from this "sub" ParseState. See if we should add it to the end result */
+ auto const k = std::find_if(ps.load_variable_z.begin(), ps.load_variable_z.end(), [j](LoadVariableZ const& z) { return j.id() == z.id(); });
+ if (k == ps.load_variable_z.end()) {
+ ps.load_variable_z.push_back(j);
+ }
+ }
}
if (!ps.in || !ps.out) {
@@ -482,6 +506,12 @@ TextAsset::maybe_add_text(
switch (ps.type.get()) {
case ParseState::Type::TEXT:
+ {
+ vector<Text::VariableZPosition> variable_z;
+ auto iter = std::find_if(ps.load_variable_z.begin(), ps.load_variable_z.end(), [&ps](LoadVariableZ const& z) { return z.id() == ps.variable_z; });
+ if (iter != ps.load_variable_z.end()) {
+ variable_z = iter->positions();
+ }
_texts.push_back (
make_shared<TextString>(
ps.font_id,
@@ -498,6 +528,7 @@ TextAsset::maybe_add_text(
ps.v_position.get_value_or(0),
ps.v_align.get_value_or(VAlign::CENTER),
ps.z_position.get_value_or(0),
+ variable_z,
ps.direction.get_value_or (Direction::LTR),
text,
ps.effect.get_value_or (Effect::NONE),
@@ -509,6 +540,7 @@ TextAsset::maybe_add_text(
)
);
break;
+ }
case ParseState::Type::IMAGE:
{
switch (standard) {
@@ -530,6 +562,12 @@ TextAsset::maybe_add_text(
break;
}
+ vector<Text::VariableZPosition> variable_z;
+ auto iter = std::find_if(ps.load_variable_z.begin(), ps.load_variable_z.end(), [&ps](LoadVariableZ const& z) { return ps.variable_z && z.id() == *ps.variable_z; });
+ if (iter != ps.load_variable_z.end()) {
+ variable_z = iter->positions();
+ }
+
/* Add a text with no image data and we'll fill that in later */
_texts.push_back(
make_shared<TextImage>(
@@ -542,6 +580,7 @@ TextAsset::maybe_add_text(
ps.v_position.get_value_or(0),
ps.v_align.get_value_or(VAlign::CENTER),
ps.z_position.get_value_or(0),
+ variable_z,
ps.fade_up_time.get_value_or(Time()),
ps.fade_down_time.get_value_or(Time())
)
@@ -747,6 +786,7 @@ TextAsset::texts_as_xml(xmlpp::Element* xml_root, int time_code_rate, Standard s
float last_v_position;
float last_z_position;
Direction last_direction;
+ int load_variable_z_index = 1;
for (auto i: sorted) {
if (!subtitle ||
@@ -783,6 +823,7 @@ TextAsset::texts_as_xml(xmlpp::Element* xml_root, int time_code_rate, Standard s
is->v_align(),
is->v_position(),
is->z_position(),
+ subtitle->find_or_add_variable_z_positions(is->variable_z_positions(), load_variable_z_index),
is->direction(),
is->rubies()
);
@@ -802,7 +843,16 @@ TextAsset::texts_as_xml(xmlpp::Element* xml_root, int time_code_rate, Standard s
if (auto ii = dynamic_pointer_cast<TextImage>(i)) {
text.reset ();
subtitle->children.push_back (
- make_shared<order::Image>(subtitle, ii->id(), ii->png_image(), ii->h_align(), ii->h_position(), ii->v_align(), ii->v_position(), ii->z_position())
+ make_shared<order::Image>(
+ subtitle, ii->id(),
+ ii->png_image(),
+ ii->h_align(),
+ ii->h_position(),
+ ii->v_align(),
+ ii->v_position(),
+ ii->z_position(),
+ subtitle->find_or_add_variable_z_positions(ii->variable_z_positions(), load_variable_z_index)
+ )
);
}
}
diff --git a/src/text_asset.h b/src/text_asset.h
index 4d739027..113896f8 100644
--- a/src/text_asset.h
+++ b/src/text_asset.h
@@ -44,6 +44,7 @@
#include "array_data.h"
#include "asset.h"
#include "dcp_time.h"
+#include "load_variable_z.h"
#include "subtitle_standard.h"
#include "text_string.h"
#include <libcxml/cxml.h>
@@ -156,6 +157,7 @@ protected:
boost::optional<float> v_position;
boost::optional<VAlign> v_align;
boost::optional<float> z_position;
+ boost::optional<std::string> variable_z;
boost::optional<Direction> direction;
boost::optional<Time> in;
boost::optional<Time> out;
@@ -167,6 +169,8 @@ protected:
};
boost::optional<Type> type;
float space_before = 0;
+
+ std::vector<LoadVariableZ> load_variable_z;
};
void parse_texts(xmlpp::Element const * node, std::vector<ParseState>& state, boost::optional<int> tcr, Standard standard);
@@ -181,6 +185,7 @@ protected:
/** All our texts, in no particular order */
std::vector<std::shared_ptr<Text>> _texts;
+ std::vector<LoadVariableZ> _load_variable_z;
class Font
{
diff --git a/src/text_asset_internal.cc b/src/text_asset_internal.cc
index 549bbec9..4ae5dbfe 100644
--- a/src/text_asset_internal.cc
+++ b/src/text_asset_internal.cc
@@ -44,9 +44,12 @@
#include <cmath>
+using std::dynamic_pointer_cast;
using std::string;
using std::map;
using std::shared_ptr;
+using std::vector;
+using boost::optional;
using namespace dcp;
@@ -166,7 +169,16 @@ order::Part::write_xml (xmlpp::Element* parent, order::Context& context) const
static void
-position_align (xmlpp::Element* e, order::Context& context, HAlign h_align, float h_position, VAlign v_align, float v_position, float z_position)
+position_align(
+ xmlpp::Element* e,
+ order::Context& context,
+ HAlign h_align,
+ float h_position,
+ VAlign v_align,
+ float v_position,
+ float z_position,
+ optional<string> variable_z
+ )
{
if (h_align != HAlign::CENTER) {
if (context.standard == Standard::SMPTE) {
@@ -207,6 +219,10 @@ position_align (xmlpp::Element* e, order::Context& context, HAlign h_align, floa
if (fabs(z_position) > ALIGN_EPSILON && context.standard == Standard::SMPTE) {
e->set_attribute("Zposition", fmt::format("{:.6}", z_position * 100));
}
+
+ if (variable_z) {
+ e->set_attribute("VariableZ", *variable_z);
+ }
}
@@ -215,7 +231,7 @@ order::Text::as_xml (xmlpp::Element* parent, Context& context) const
{
auto e = cxml::add_child(parent, "Text");
- position_align(e, context, _h_align, _h_position, _v_align, _v_position, _z_position);
+ position_align(e, context, _h_align, _h_position, _v_align, _v_position, _z_position, _variable_z);
/* Interop only supports "horizontal" or "vertical" for direction, so only write this
for SMPTE.
@@ -240,6 +256,24 @@ order::Text::as_xml (xmlpp::Element* parent, Context& context) const
}
+optional<string>
+order::Subtitle::find_or_add_variable_z_positions(vector<dcp::Text::VariableZPosition> const& positions, int& load_variable_z_index)
+{
+ if (positions.empty()) {
+ return {};
+ }
+
+ auto iter = std::find_if(_load_variable_z.begin(), _load_variable_z.end(), [positions](LoadVariableZ const& load) { return positions == load.positions(); });
+ if (iter == _load_variable_z.end()) {
+ auto const id = fmt::format("Zvector{}", load_variable_z_index++);
+ _load_variable_z.push_back(LoadVariableZ(id, positions));
+ return id;
+ }
+
+ return iter->id();
+}
+
+
xmlpp::Element*
order::Subtitle::as_xml (xmlpp::Element* parent, Context& context) const
{
@@ -254,6 +288,11 @@ order::Subtitle::as_xml (xmlpp::Element* parent, Context& context) const
e->set_attribute("FadeUpTime", fmt::to_string(_fade_up.as_editable_units_ceil(context.time_code_rate)));
e->set_attribute("FadeDownTime", fmt::to_string(_fade_down.as_editable_units_ceil(context.time_code_rate)));
}
+
+ for (auto const& vz: _load_variable_z) {
+ vz.as_xml(cxml::add_child(e, "LoadVariableZ"));
+ }
+
return e;
}
@@ -277,7 +316,7 @@ order::Image::as_xml (xmlpp::Element* parent, Context& context) const
{
auto e = cxml::add_child(parent, "Image");
- position_align(e, context, _h_align, _h_position, _v_align, _v_position, _z_position);
+ position_align(e, context, _h_align, _h_position, _v_align, _v_position, _z_position, _variable_z);
if (context.standard == Standard::SMPTE) {
e->add_child_text ("urn:uuid:" + _id);
} else {
@@ -286,3 +325,4 @@ order::Image::as_xml (xmlpp::Element* parent, Context& context) const
return e;
}
+
diff --git a/src/text_asset_internal.h b/src/text_asset_internal.h
index ddbc8833..2dfccce9 100644
--- a/src/text_asset_internal.h
+++ b/src/text_asset_internal.h
@@ -44,6 +44,7 @@
#include "array_data.h"
#include "dcp_time.h"
#include "h_align.h"
+#include "load_variable_z.h"
#include "raw_convert.h"
#include "v_align.h"
#include "warnings.h"
@@ -146,25 +147,41 @@ private:
class Text : public Part
{
public:
- Text(std::shared_ptr<Part> parent, HAlign h_align, float h_position, VAlign v_align, float v_position, float z_position, Direction direction, std::vector<Ruby> rubies)
+ Text(
+ std::shared_ptr<Part> parent,
+ HAlign h_align,
+ float h_position,
+ VAlign v_align,
+ float v_position,
+ float z_position,
+ boost::optional<std::string> variable_z,
+ Direction direction,
+ std::vector<Ruby> rubies
+ )
: Part (parent)
, _h_align (h_align)
, _h_position (h_position)
, _v_align (v_align)
, _v_position (v_position)
, _z_position(z_position)
+ , _variable_z(variable_z)
, _direction (direction)
, _rubies(rubies)
{}
xmlpp::Element* as_xml (xmlpp::Element* parent, Context& context) const override;
+ boost::optional<std::string> variable_z() {
+ return _variable_z;
+ }
+
private:
HAlign _h_align;
float _h_position;
VAlign _v_align;
float _v_position;
float _z_position;
+ boost::optional<std::string> _variable_z;
Direction _direction;
std::vector<Ruby> _rubies;
};
@@ -181,6 +198,8 @@ public:
, _fade_down (fade_down)
{}
+ boost::optional<std::string> find_or_add_variable_z_positions(std::vector<dcp::Text::VariableZPosition> const& positions, int& load_variable_z_index);
+
xmlpp::Element* as_xml (xmlpp::Element* parent, Context& context) const override;
private:
@@ -188,13 +207,24 @@ private:
Time _out;
Time _fade_up;
Time _fade_down;
+ std::vector<LoadVariableZ> _load_variable_z;
};
class Image : public Part
{
public:
- Image (std::shared_ptr<Part> parent, std::string id, ArrayData png_data, HAlign h_align, float h_position, VAlign v_align, float v_position, float z_position)
+ Image(
+ std::shared_ptr<Part> parent,
+ std::string id,
+ ArrayData png_data,
+ HAlign h_align,
+ float h_position,
+ VAlign v_align,
+ float v_position,
+ float z_position,
+ boost::optional<std::string> variable_z
+ )
: Part (parent)
, _png_data (png_data)
, _id (id)
@@ -203,6 +233,7 @@ public:
, _v_align (v_align)
, _v_position (v_position)
, _z_position(z_position)
+ , _variable_z(variable_z)
{}
xmlpp::Element* as_xml (xmlpp::Element* parent, Context& context) const override;
@@ -215,6 +246,7 @@ private:
VAlign _v_align;
float _v_position;
float _z_position;
+ boost::optional<std::string> _variable_z;
};
diff --git a/src/text_image.cc b/src/text_image.cc
index 7a6c4222..119a6301 100644
--- a/src/text_image.cc
+++ b/src/text_image.cc
@@ -47,6 +47,8 @@ using std::dynamic_pointer_cast;
using std::ostream;
using std::shared_ptr;
using std::string;
+using std::vector;
+using boost::optional;
using namespace dcp;
@@ -59,10 +61,11 @@ TextImage::TextImage(
float v_position,
VAlign v_align,
float z_position,
+ vector<VariableZPosition> variable_z_positions,
Time fade_up_time,
Time fade_down_time
)
- : Text(in, out, h_position, h_align, v_position, v_align, z_position, fade_up_time, fade_down_time)
+ : Text(in, out, h_position, h_align, v_position, v_align, z_position, variable_z_positions, fade_up_time, fade_down_time)
, _png_image (png_image)
, _id (make_uuid ())
{
@@ -80,10 +83,11 @@ TextImage::TextImage(
float v_position,
VAlign v_align,
float z_position,
+ vector<VariableZPosition> variable_z_positions,
Time fade_up_time,
Time fade_down_time
)
- : Text(in, out, h_position, h_align, v_position, v_align, z_position, fade_up_time, fade_down_time)
+ : Text(in, out, h_position, h_align, v_position, v_align, z_position, variable_z_positions, fade_up_time, fade_down_time)
, _png_image (png_image)
, _id (id)
{
diff --git a/src/text_image.h b/src/text_image.h
index 1f1e464e..5b78f380 100644
--- a/src/text_image.h
+++ b/src/text_image.h
@@ -66,6 +66,7 @@ public:
float v_position,
VAlign v_align,
float z_position,
+ std::vector<VariableZPosition> variable_z_positions,
Time fade_up_time,
Time fade_down_time
);
@@ -80,6 +81,7 @@ public:
float v_position,
VAlign v_align,
float z_position,
+ std::vector<VariableZPosition> variable_z_positions,
Time fade_up_time,
Time fade_down_time
);
diff --git a/src/text_string.cc b/src/text_string.cc
index 32f9e4ed..12e86fce 100644
--- a/src/text_string.cc
+++ b/src/text_string.cc
@@ -69,6 +69,7 @@ TextString::TextString(
float v_position,
VAlign v_align,
float z_position,
+ vector<VariableZPosition> variable_z_positions,
Direction direction,
string text,
Effect effect,
@@ -78,7 +79,7 @@ TextString::TextString(
float space_before,
vector<Ruby> rubies
)
- : Text(in, out, h_position, h_align, v_position, v_align, z_position, fade_up_time, fade_down_time)
+ : Text(in, out, h_position, h_align, v_position, v_align, z_position, variable_z_positions, fade_up_time, fade_down_time)
, _font (font)
, _italic (italic)
, _bold (bold)
@@ -127,6 +128,7 @@ dcp::operator==(TextString const & a, TextString const & b)
a.v_position() == b.v_position() &&
a.v_align() == b.v_align() &&
a.z_position() == b.z_position() &&
+ a.variable_z_positions() == b.variable_z_positions() &&
a.direction() == b.direction() &&
a.text() == b.text() &&
a.effect() == b.effect() &&
@@ -173,8 +175,8 @@ dcp::operator<<(ostream& s, TextString const & sub)
<< ", colour (" << sub.colour().r << ", " << sub.colour().g << ", " << sub.colour().b << ")"
<< ", vpos " << sub.v_position() << ", valign " << ((int) sub.v_align())
<< ", hpos " << sub.h_position() << ", halign " << ((int) sub.h_align())
- << ", zpos " << sub.z_position()
- << ", direction " << ((int) sub.direction())
+ << ", zpos " << sub.z_position();
+ s << ", direction " << ((int) sub.direction())
<< ", effect " << ((int) sub.effect())
<< ", effect colour (" << sub.effect_colour().r << ", " << sub.effect_colour().g << ", " << sub.effect_colour().b << ")"
<< ", space before " << sub.space_before();
diff --git a/src/text_string.h b/src/text_string.h
index f532bafe..78788786 100644
--- a/src/text_string.h
+++ b/src/text_string.h
@@ -72,6 +72,7 @@ public:
* @param v_align Vertical alignment point
* @param z_position Z position as a proportion of the primary picture width between -1 and +1;
* +ve moves the image away from the viewer, -ve moves it toward the viewer, 0 is in the plane of the screen.
+ * @param variable_z_positions List of variable Z positions for this text (or empty).
* @param direction Direction of text
* @param text The text to display
* @param effect Effect to use
@@ -95,6 +96,7 @@ public:
float v_position,
VAlign v_align,
float z_position,
+ std::vector<VariableZPosition> variable_z_positions,
Direction direction,
std::string text,
Effect effect,
diff --git a/test/data/subtitles_with_vZani.xml b/test/data/subtitles_with_vZani.xml
new file mode 100644
index 00000000..32f08c6a
--- /dev/null
+++ b/test/data/subtitles_with_vZani.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<SubtitleReel xmlns="http://www.smpte-ra.org/schemas/428-7/2014/DCST" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <Id>urn:uuid:6382e2f3-8d75-441a-8324-4d0713549056</Id>
+ <ContentTitleText>Stereoscopic Subtitles: timeline01</ContentTitleText>
+ <AnnotationText>3D subs made with Davinci</AnnotationText>
+ <IssueDate>2025-01-28T20:47:47.904-00:00</IssueDate>
+ <ReelNumber>1</ReelNumber>
+ <Language>en</Language>
+ <EditRate>24 1</EditRate>
+ <TimeCodeRate>24</TimeCodeRate>
+ <StartTime>00:00:00:00</StartTime>
+ <DisplayType>MainSubtitle</DisplayType>
+ <LoadFont ID="MyFont">urn:uuid:d621dedd-089d-4d1f-8c24-fb976e1439df</LoadFont>
+ <SubtitleList>
+ <Font ID="MyFont" Color="FFFFFFFF" Weight="normal" Size="45">
+ <Subtitle SpotNumber="1" TimeIn="00:00:10:00" TimeOut="00:00:15:00">
+ <Text Valign="bottom" Vposition="20.00" Zposition="0.0">subtitle - position 0 - subtitle</Text>
+ </Subtitle>
+ <Subtitle SpotNumber="2" TimeIn="00:00:15:00" TimeOut="00:00:20:00">
+ <Text Valign="bottom" Vposition="20.00" Zposition="-0.5">subtitle - position -0.5 - subtitle</Text>
+ </Subtitle>
+ <Subtitle SpotNumber="3" TimeIn="00:00:20:00" TimeOut="00:00:25:00">
+ <Text Valign="bottom" Vposition="20.00" Zposition="-1">subtitle - position -1 - subtitle</Text>
+ </Subtitle>
+ <Subtitle SpotNumber="4" TimeIn="00:00:25:00" TimeOut="00:00:30:00">
+ <Text Valign="bottom" Vposition="20.00" Zposition="-1.5">subtitle - position -1.5 - subtitle</Text>
+ </Subtitle>
+ <Subtitle SpotNumber="5" TimeIn="00:00:30:00" TimeOut="00:00:35:00">
+ <Text Valign="bottom" Vposition="20.00" Zposition="-2.0">subtitle - position -2 - subtitle</Text>
+ </Subtitle>
+ <Subtitle SpotNumber="6" TimeIn="00:00:35:00" TimeOut="00:00:40:00">
+ <Text Valign="bottom" Vposition="20.00" Zposition="0.0">subtitle - position 0 - subtitle</Text>
+ </Subtitle>
+ <Subtitle SpotNumber="7" TimeIn="00:00:40:00" TimeOut="00:00:45:00">
+ <Text Valign="bottom" Vposition="20.00" Zposition="0.5">subtitle - position 0.5 - subtitle</Text>
+ </Subtitle>
+ <Subtitle SpotNumber="8" TimeIn="00:00:45:00" TimeOut="00:00:50:00">
+ <Text Valign="bottom" Vposition="20.00" Zposition="1.0">subtitle - position 1 - subtitle</Text>
+ </Subtitle>
+ <Subtitle SpotNumber="9" TimeIn="00:00:50:00" TimeOut="00:00:55:00">
+ <Text Valign="bottom" Vposition="20.00" Zposition="1.5">subtitle - position 1.5 - subtitle</Text>
+ </Subtitle>
+ <Subtitle SpotNumber="10" TimeIn="00:00:55:00" TimeOut="00:01:00:00">
+ <Text Valign="bottom" Vposition="20.00" Zposition="2.0">subtitle - position 2 - subtitle</Text>
+ </Subtitle>
+ <Subtitle SpotNumber="11" TimeIn="00:01:05:00" TimeOut="00:01:20:00">
+ <LoadVariableZ ID="Zvector1">-2.0:120 0.0:120 2.0:120</LoadVariableZ>
+ <Text Valign="bottom" Vposition="10.00" Zposition="-2.0" VariableZ="Zvector1">animation -2 to 0 to 2</Text>
+ </Subtitle>
+ <Subtitle SpotNumber="12" TimeIn="00:01:24:00" TimeOut="00:01:39:00">
+ <LoadVariableZ ID="Zvector2">0.0:120 2.0:120 -2.0:120</LoadVariableZ>
+ <Text Valign="bottom" Vposition="10.00" Zposition="0.0" VariableZ="Zvector2">animation 0 to 2 to - 2</Text>
+ </Subtitle>
+ <Subtitle SpotNumber="13" TimeIn="00:01:42:13" TimeOut="00:01:57:13">
+ <LoadVariableZ ID="Zvector3">2.0:180 0.0:180</LoadVariableZ>
+ <Text Valign="bottom" Vposition="10.00" Zposition="2.0" VariableZ="Zvector3">animation 2 to 0</Text>
+ </Subtitle>
+ </Font>
+ </SubtitleList>
+</SubtitleReel> \ No newline at end of file
diff --git a/test/data/subtitles_with_vZani_parsed.xml b/test/data/subtitles_with_vZani_parsed.xml
new file mode 100644
index 00000000..7c9c797d
--- /dev/null
+++ b/test/data/subtitles_with_vZani_parsed.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<SubtitleReel xmlns="http://www.smpte-ra.org/schemas/428-7/2014/DCST">
+ <Id>urn:uuid:6382e2f3-8d75-441a-8324-4d0713549056</Id>
+ <ContentTitleText>Stereoscopic Subtitles: timeline01</ContentTitleText>
+ <AnnotationText>3D subs made with Davinci</AnnotationText>
+ <IssueDate>2025-01-28T20:47:47</IssueDate>
+ <ReelNumber>1</ReelNumber>
+ <Language>en</Language>
+ <EditRate>24 1</EditRate>
+ <TimeCodeRate>24</TimeCodeRate>
+ <StartTime>00:00:00:00</StartTime>
+ <LoadFont ID="MyFont">urn:uuid:d621dedd-089d-4d1f-8c24-fb976e1439df</LoadFont>
+ <SubtitleList>
+ <Font AspectAdjust="1.0" Color="FFFFFFFF" Effect="none" EffectColor="FF000000" ID="MyFont" Italic="no" Script="normal" Size="45" Underline="no" Weight="normal">
+ <Subtitle SpotNumber="1" TimeIn="00:00:10:00" TimeOut="00:00:15:00" FadeUpTime="00:00:00:02" FadeDownTime="00:00:00:02">
+ <Text Valign="bottom" Vposition="20">subtitle - position 0 - subtitle</Text>
+ </Subtitle>
+ <Subtitle SpotNumber="2" TimeIn="00:00:15:00" TimeOut="00:00:20:00" FadeUpTime="00:00:00:02" FadeDownTime="00:00:00:02">
+ <Text Valign="bottom" Vposition="20" Zposition="-0.5">subtitle - position -0.5 - subtitle</Text>
+ </Subtitle>
+ <Subtitle SpotNumber="3" TimeIn="00:00:20:00" TimeOut="00:00:25:00" FadeUpTime="00:00:00:02" FadeDownTime="00:00:00:02">
+ <Text Valign="bottom" Vposition="20" Zposition="-1">subtitle - position -1 - subtitle</Text>
+ </Subtitle>
+ <Subtitle SpotNumber="4" TimeIn="00:00:25:00" TimeOut="00:00:30:00" FadeUpTime="00:00:00:02" FadeDownTime="00:00:00:02">
+ <Text Valign="bottom" Vposition="20" Zposition="-1.5">subtitle - position -1.5 - subtitle</Text>
+ </Subtitle>
+ <Subtitle SpotNumber="5" TimeIn="00:00:30:00" TimeOut="00:00:35:00" FadeUpTime="00:00:00:02" FadeDownTime="00:00:00:02">
+ <Text Valign="bottom" Vposition="20" Zposition="-2">subtitle - position -2 - subtitle</Text>
+ </Subtitle>
+ <Subtitle SpotNumber="6" TimeIn="00:00:35:00" TimeOut="00:00:40:00" FadeUpTime="00:00:00:02" FadeDownTime="00:00:00:02">
+ <Text Valign="bottom" Vposition="20">subtitle - position 0 - subtitle</Text>
+ </Subtitle>
+ <Subtitle SpotNumber="7" TimeIn="00:00:40:00" TimeOut="00:00:45:00" FadeUpTime="00:00:00:02" FadeDownTime="00:00:00:02">
+ <Text Valign="bottom" Vposition="20" Zposition="0.5">subtitle - position 0.5 - subtitle</Text>
+ </Subtitle>
+ <Subtitle SpotNumber="8" TimeIn="00:00:45:00" TimeOut="00:00:50:00" FadeUpTime="00:00:00:02" FadeDownTime="00:00:00:02">
+ <Text Valign="bottom" Vposition="20" Zposition="1">subtitle - position 1 - subtitle</Text>
+ </Subtitle>
+ <Subtitle SpotNumber="9" TimeIn="00:00:50:00" TimeOut="00:00:55:00" FadeUpTime="00:00:00:02" FadeDownTime="00:00:00:02">
+ <Text Valign="bottom" Vposition="20" Zposition="1.5">subtitle - position 1.5 - subtitle</Text>
+ </Subtitle>
+ <Subtitle SpotNumber="10" TimeIn="00:00:55:00" TimeOut="00:01:00:00" FadeUpTime="00:00:00:02" FadeDownTime="00:00:00:02">
+ <Text Valign="bottom" Vposition="20" Zposition="2">subtitle - position 2 - subtitle</Text>
+ </Subtitle>
+ <Subtitle SpotNumber="11" TimeIn="00:01:05:00" TimeOut="00:01:20:00" FadeUpTime="00:00:00:02" FadeDownTime="00:00:00:02">
+ <LoadVariableZ ID="Zvector1">-2.0:120 0.0:120 2.0:120</LoadVariableZ>
+ <Text Valign="bottom" Vposition="10" Zposition="-2" VariableZ="Zvector1">animation -2 to 0 to 2</Text>
+ </Subtitle>
+ <Subtitle SpotNumber="12" TimeIn="00:01:24:00" TimeOut="00:01:39:00" FadeUpTime="00:00:00:02" FadeDownTime="00:00:00:02">
+ <LoadVariableZ ID="Zvector2">0.0:120 2.0:120 -2.0:120</LoadVariableZ>
+ <Text Valign="bottom" Vposition="10" VariableZ="Zvector2">animation 0 to 2 to - 2</Text>
+ </Subtitle>
+ <Subtitle SpotNumber="13" TimeIn="00:01:42:13" TimeOut="00:01:57:13" FadeUpTime="00:00:00:02" FadeDownTime="00:00:00:02">
+ <LoadVariableZ ID="Zvector3">2.0:180 0.0:180</LoadVariableZ>
+ <Text Valign="bottom" Vposition="10" Zposition="2" VariableZ="Zvector3">animation 2 to 0</Text>
+ </Subtitle>
+ </Font>
+ </SubtitleList>
+</SubtitleReel>
diff --git a/test/decryption_test.cc b/test/decryption_test.cc
index 3bb62d21..2b34cd25 100644
--- a/test/decryption_test.cc
+++ b/test/decryption_test.cc
@@ -191,7 +191,7 @@ BOOST_AUTO_TEST_CASE (decryption_test2)
dcp::Time(0, 0, 5, 0, 24),
0.5, dcp::HAlign::CENTER,
0.5, dcp::VAlign::CENTER,
- 0,
+ 0, vector<dcp::Text::VariableZPosition>(),
dcp::Direction::LTR,
"Hello world",
dcp::Effect::NONE,
diff --git a/test/interop_subtitle_test.cc b/test/interop_subtitle_test.cc
index 2d7f4a43..27dcaf23 100644
--- a/test/interop_subtitle_test.cc
+++ b/test/interop_subtitle_test.cc
@@ -46,6 +46,7 @@ using std::dynamic_pointer_cast;
using std::shared_ptr;
using std::string;
using std::vector;
+using boost::optional;
/** Load some subtitle content from Interop XML and check that it is read correctly */
@@ -83,6 +84,7 @@ BOOST_AUTO_TEST_CASE (read_interop_subtitle_test1)
0.15,
dcp::VAlign::BOTTOM,
0,
+ vector<dcp::Text::VariableZPosition>(),
dcp::Direction::LTR,
"My jacket was ",
dcp::Effect::BORDER,
@@ -108,6 +110,7 @@ BOOST_AUTO_TEST_CASE (read_interop_subtitle_test1)
0.15,
dcp::VAlign::BOTTOM,
0,
+ vector<dcp::Text::VariableZPosition>(),
dcp::Direction::LTR,
"Idi Amin's",
dcp::Effect::BORDER,
@@ -136,6 +139,7 @@ BOOST_AUTO_TEST_CASE (read_interop_subtitle_test1)
0.21,
dcp::VAlign::BOTTOM,
0,
+ vector<dcp::Text::VariableZPosition>(),
dcp::Direction::LTR,
"My corset was H.M. The Queen's",
dcp::Effect::BORDER,
@@ -161,6 +165,7 @@ BOOST_AUTO_TEST_CASE (read_interop_subtitle_test1)
0.15,
dcp::VAlign::BOTTOM,
0,
+ vector<dcp::Text::VariableZPosition>(),
dcp::Direction::LTR,
"My large wonderbra",
dcp::Effect::BORDER,
@@ -189,6 +194,7 @@ BOOST_AUTO_TEST_CASE (read_interop_subtitle_test1)
0.15,
dcp::VAlign::BOTTOM,
0,
+ vector<dcp::Text::VariableZPosition>(),
dcp::Direction::LTR,
"Once belonged to the Shah",
dcp::Effect::BORDER,
@@ -217,6 +223,7 @@ BOOST_AUTO_TEST_CASE (read_interop_subtitle_test1)
0.15,
dcp::VAlign::BOTTOM,
0,
+ vector<dcp::Text::VariableZPosition>(),
dcp::Direction::LTR,
"And these are Roy Hattersley's jeans",
dcp::Effect::BORDER,
@@ -251,6 +258,7 @@ BOOST_AUTO_TEST_CASE (read_interop_subtitle_test2)
0.89,
dcp::VAlign::TOP,
0,
+ vector<dcp::Text::VariableZPosition>(),
dcp::Direction::LTR,
"At afternoon tea with John Peel",
dcp::Effect::BORDER,
@@ -276,6 +284,7 @@ BOOST_AUTO_TEST_CASE (read_interop_subtitle_test2)
0.95,
dcp::VAlign::TOP,
0,
+ vector<dcp::Text::VariableZPosition>(),
dcp::Direction::LTR,
"I enquired if his accent was real",
dcp::Effect::BORDER,
@@ -304,6 +313,7 @@ BOOST_AUTO_TEST_CASE (read_interop_subtitle_test2)
0.89,
dcp::VAlign::TOP,
0,
+ vector<dcp::Text::VariableZPosition>(),
dcp::Direction::LTR,
"He said \"out of the house",
dcp::Effect::BORDER,
@@ -329,6 +339,7 @@ BOOST_AUTO_TEST_CASE (read_interop_subtitle_test2)
0.95,
dcp::VAlign::TOP,
0,
+ vector<dcp::Text::VariableZPosition>(),
dcp::Direction::LTR,
"I'm incredibly scouse",
dcp::Effect::BORDER,
@@ -357,6 +368,7 @@ BOOST_AUTO_TEST_CASE (read_interop_subtitle_test2)
0.89,
dcp::VAlign::TOP,
0,
+ vector<dcp::Text::VariableZPosition>(),
dcp::Direction::LTR,
"At home it depends how I feel.\"",
dcp::Effect::BORDER,
@@ -382,6 +394,7 @@ BOOST_AUTO_TEST_CASE (read_interop_subtitle_test2)
0.95,
dcp::VAlign::TOP,
0,
+ vector<dcp::Text::VariableZPosition>(),
dcp::Direction::LTR,
"I spent a long weekend in Brighton",
dcp::Effect::BORDER,
@@ -410,6 +423,7 @@ BOOST_AUTO_TEST_CASE (read_interop_subtitle_test2)
0.89,
dcp::VAlign::TOP,
0,
+ vector<dcp::Text::VariableZPosition>(),
dcp::Direction::RTL,
"With the legendary Miss Enid Blyton",
dcp::Effect::BORDER,
@@ -435,6 +449,7 @@ BOOST_AUTO_TEST_CASE (read_interop_subtitle_test2)
0.95,
dcp::VAlign::TOP,
0,
+ vector<dcp::Text::VariableZPosition>(),
dcp::Direction::TTB,
"She said \"you be Noddy",
dcp::Effect::BORDER,
@@ -463,6 +478,7 @@ BOOST_AUTO_TEST_CASE (read_interop_subtitle_test2)
0.89,
dcp::VAlign::TOP,
0,
+ vector<dcp::Text::VariableZPosition>(),
dcp::Direction::BTT,
"That curious creature the Sphinx",
dcp::Effect::BORDER,
@@ -488,6 +504,7 @@ BOOST_AUTO_TEST_CASE (read_interop_subtitle_test2)
0.95,
dcp::VAlign::TOP,
0,
+ vector<dcp::Text::VariableZPosition>(),
dcp::Direction::LTR,
"Is smarter than anyone thinks",
dcp::Effect::BORDER,
@@ -516,6 +533,7 @@ BOOST_AUTO_TEST_CASE (read_interop_subtitle_test2)
0.89,
dcp::VAlign::TOP,
0,
+ vector<dcp::Text::VariableZPosition>(),
dcp::Direction::LTR,
"It sits there and smirks",
dcp::Effect::BORDER,
@@ -541,6 +559,7 @@ BOOST_AUTO_TEST_CASE (read_interop_subtitle_test2)
0.95,
dcp::VAlign::TOP,
0,
+ vector<dcp::Text::VariableZPosition>(),
dcp::Direction::LTR,
"And you don't think it works",
dcp::Effect::BORDER,
@@ -569,6 +588,7 @@ BOOST_AUTO_TEST_CASE (read_interop_subtitle_test2)
0.89,
dcp::VAlign::TOP,
0,
+ vector<dcp::Text::VariableZPosition>(),
dcp::Direction::LTR,
"Then when you're not looking, it winks.",
dcp::Effect::BORDER,
@@ -594,6 +614,7 @@ BOOST_AUTO_TEST_CASE (read_interop_subtitle_test2)
0.95,
dcp::VAlign::TOP,
0,
+ vector<dcp::Text::VariableZPosition>(),
dcp::Direction::LTR,
"When it snows you will find Sister Sledge",
dcp::Effect::BORDER,
@@ -622,6 +643,7 @@ BOOST_AUTO_TEST_CASE (read_interop_subtitle_test2)
0.89,
dcp::VAlign::TOP,
0,
+ vector<dcp::Text::VariableZPosition>(),
dcp::Direction::LTR,
"Out mooning, at night, on the ledge",
dcp::Effect::BORDER,
@@ -647,6 +669,7 @@ BOOST_AUTO_TEST_CASE (read_interop_subtitle_test2)
0.95,
dcp::VAlign::TOP,
0,
+ vector<dcp::Text::VariableZPosition>(),
dcp::Direction::LTR,
"One storey down",
dcp::Effect::BORDER,
@@ -675,6 +698,7 @@ BOOST_AUTO_TEST_CASE (read_interop_subtitle_test2)
0.89,
dcp::VAlign::TOP,
0,
+ vector<dcp::Text::VariableZPosition>(),
dcp::Direction::LTR,
"HELLO",
dcp::Effect::BORDER,
@@ -700,6 +724,7 @@ BOOST_AUTO_TEST_CASE (read_interop_subtitle_test2)
0.95,
dcp::VAlign::TOP,
0,
+ vector<dcp::Text::VariableZPosition>(),
dcp::Direction::LTR,
"WORLD",
dcp::Effect::BORDER,
@@ -747,6 +772,7 @@ BOOST_AUTO_TEST_CASE (write_interop_subtitle_test)
0.8,
dcp::VAlign::TOP,
0,
+ vector<dcp::Text::VariableZPosition>(),
dcp::Direction::LTR,
"Hello world",
dcp::Effect::NONE,
@@ -774,6 +800,7 @@ BOOST_AUTO_TEST_CASE (write_interop_subtitle_test)
0.4,
dcp::VAlign::BOTTOM,
0,
+ vector<dcp::Text::VariableZPosition>(),
dcp::Direction::LTR,
"What's going ",
dcp::Effect::BORDER,
@@ -801,6 +828,7 @@ BOOST_AUTO_TEST_CASE (write_interop_subtitle_test)
0.4,
dcp::VAlign::BOTTOM,
0,
+ vector<dcp::Text::VariableZPosition>(),
dcp::Direction::LTR,
"on",
dcp::Effect::BORDER,
@@ -862,6 +890,7 @@ BOOST_AUTO_TEST_CASE (write_interop_subtitle_test2)
0.8,
dcp::VAlign::TOP,
0,
+ vector<dcp::Text::VariableZPosition>(),
dcp::Direction::LTR,
"Hello world",
dcp::Effect::NONE,
@@ -889,6 +918,7 @@ BOOST_AUTO_TEST_CASE (write_interop_subtitle_test2)
0.4,
dcp::VAlign::BOTTOM,
0,
+ vector<dcp::Text::VariableZPosition>(),
dcp::Direction::LTR,
"What's going on",
dcp::Effect::BORDER,
@@ -944,6 +974,7 @@ BOOST_AUTO_TEST_CASE (write_interop_subtitle_test3)
0.8,
dcp::VAlign::TOP,
0,
+ vector<dcp::Text::VariableZPosition>(),
dcp::Time (0, 0, 0, 0, 24),
dcp::Time (0, 0, 0, 0, 24)
)
diff --git a/test/load_variable_z_test.cc b/test/load_variable_z_test.cc
index 8448480f..07c45a57 100644
--- a/test/load_variable_z_test.cc
+++ b/test/load_variable_z_test.cc
@@ -33,6 +33,7 @@
#include "load_variable_z.h"
+#include "smpte_text_asset.h"
#include "warnings.h"
#include "compose.hpp"
LIBDCP_DISABLE_WARNINGS
@@ -89,3 +90,12 @@ BOOST_AUTO_TEST_CASE(variable_z_test)
made.set_positions({{-0.6, 2}, {4.2, 9}, {5, 1}});
BOOST_CHECK_EQUAL(xml(made), "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<LoadVariableZ ID=\"baz\">-0.6:2 4.2:9 5.0</LoadVariableZ>\n");
}
+
+
+BOOST_AUTO_TEST_CASE(variable_z_pass_through)
+{
+ dcp::SMPTETextAsset asset("test/data/subtitles_with_vZani.xml");
+ BOOST_CHECK_EQUAL(asset.xml_as_string(), dcp::file_to_string("test/data/subtitles_with_vZani_parsed.xml"));
+}
+
+
diff --git a/test/shared_subtitle_test.cc b/test/shared_subtitle_test.cc
index 82595cd0..1a7ba853 100644
--- a/test/shared_subtitle_test.cc
+++ b/test/shared_subtitle_test.cc
@@ -108,7 +108,7 @@ BOOST_AUTO_TEST_CASE (pull_fonts_test1)
auto root = make_shared<dcp::order::Part>(shared_ptr<dcp::order::Part>());
auto sub1 = make_shared<dcp::order::Subtitle>(root, dcp::Time(), dcp::Time(), dcp::Time(), dcp::Time());
root->children.push_back (sub1);
- auto text1 = make_shared<dcp::order::Text>(sub1, dcp::HAlign::CENTER, 0, dcp::VAlign::TOP, 0, 0, dcp::Direction::LTR, std::vector<dcp::Ruby>());
+ auto text1 = make_shared<dcp::order::Text>(sub1, dcp::HAlign::CENTER, 0, dcp::VAlign::TOP, 0, 0, optional<string>(), dcp::Direction::LTR, std::vector<dcp::Ruby>());
sub1->children.push_back (text1);
text1->font._values["font"] = "Inconsolata";
text1->font._values["size"] = "42";
@@ -127,11 +127,11 @@ BOOST_AUTO_TEST_CASE (pull_fonts_test2)
auto root = make_shared<dcp::order::Part>(shared_ptr<dcp::order::Part> ());
auto sub1 = make_shared<dcp::order::Subtitle>(root, dcp::Time(), dcp::Time(), dcp::Time(), dcp::Time());
root->children.push_back (sub1);
- auto text1 = make_shared<dcp::order::Text>(sub1, dcp::HAlign::CENTER, 0, dcp::VAlign::TOP, 0, 0, dcp::Direction::LTR, std::vector<dcp::Ruby>());
+ auto text1 = make_shared<dcp::order::Text>(sub1, dcp::HAlign::CENTER, 0, dcp::VAlign::TOP, 0, 0, optional<string>(), dcp::Direction::LTR, std::vector<dcp::Ruby>());
sub1->children.push_back (text1);
text1->font._values["font"] = "Inconsolata";
text1->font._values["size"] = "42";
- auto text2 = make_shared<dcp::order::Text>(sub1, dcp::HAlign::CENTER, 0, dcp::VAlign::TOP, 0, 0, dcp::Direction::LTR, std::vector<dcp::Ruby>());
+ auto text2 = make_shared<dcp::order::Text>(sub1, dcp::HAlign::CENTER, 0, dcp::VAlign::TOP, 0, 0, optional<string>(), dcp::Direction::LTR, std::vector<dcp::Ruby>());
sub1->children.push_back (text2);
text2->font._values["font"] = "Inconsolata";
text2->font._values["size"] = "48";
@@ -152,7 +152,7 @@ BOOST_AUTO_TEST_CASE (pull_fonts_test3)
auto root = make_shared<dcp::order::Part>(shared_ptr<dcp::order::Part> ());
auto sub1 = make_shared<dcp::order::Subtitle>(root, dcp::Time(), dcp::Time(), dcp::Time(), dcp::Time());
root->children.push_back (sub1);
- auto text1 = make_shared<dcp::order::Text>(sub1, dcp::HAlign::CENTER, 0, dcp::VAlign::TOP, 0, 0, dcp::Direction::LTR, std::vector<dcp::Ruby>());
+ auto text1 = make_shared<dcp::order::Text>(sub1, dcp::HAlign::CENTER, 0, dcp::VAlign::TOP, 0, 0, optional<string>(), dcp::Direction::LTR, std::vector<dcp::Ruby>());
sub1->children.push_back (text1);
dcp::order::Font font;
font._values["font"] = "Inconsolata";
diff --git a/test/smpte_subtitle_test.cc b/test/smpte_subtitle_test.cc
index e1dabc44..5aa6bea6 100644
--- a/test/smpte_subtitle_test.cc
+++ b/test/smpte_subtitle_test.cc
@@ -66,6 +66,7 @@ BOOST_AUTO_TEST_CASE (smpte_subtitle_id_test)
0.5,
dcp::VAlign::CENTER,
0,
+ vector<dcp::Text::VariableZPosition>(),
dcp::Direction::LTR,
"Hello",
dcp::Effect::NONE,
@@ -196,6 +197,7 @@ BOOST_AUTO_TEST_CASE (write_smpte_subtitle_test)
0.8,
dcp::VAlign::TOP,
0.3,
+ vector<dcp::Text::VariableZPosition>(),
dcp::Direction::LTR,
"Hello world",
dcp::Effect::NONE,
@@ -223,6 +225,7 @@ BOOST_AUTO_TEST_CASE (write_smpte_subtitle_test)
0.4,
dcp::VAlign::BOTTOM,
0,
+ vector<dcp::Text::VariableZPosition>(),
dcp::Direction::RTL,
"What's going ",
dcp::Effect::BORDER,
@@ -250,6 +253,7 @@ BOOST_AUTO_TEST_CASE (write_smpte_subtitle_test)
0.4,
dcp::VAlign::BOTTOM,
0,
+ vector<dcp::Text::VariableZPosition>(),
dcp::Direction::RTL,
"on",
dcp::Effect::BORDER,
@@ -318,6 +322,7 @@ BOOST_AUTO_TEST_CASE (write_smpte_subtitle_test2)
0.8,
dcp::VAlign::TOP,
0,
+ vector<dcp::Text::VariableZPosition>(),
dcp::Direction::LTR,
"Testing is ",
dcp::Effect::NONE,
@@ -345,6 +350,7 @@ BOOST_AUTO_TEST_CASE (write_smpte_subtitle_test2)
0.8,
dcp::VAlign::TOP,
0,
+ vector<dcp::Text::VariableZPosition>(),
dcp::Direction::LTR,
"really",
dcp::Effect::NONE,
@@ -372,6 +378,7 @@ BOOST_AUTO_TEST_CASE (write_smpte_subtitle_test2)
0.8,
dcp::VAlign::TOP,
0,
+ vector<dcp::Text::VariableZPosition>(),
dcp::Direction::LTR,
" fun",
dcp::Effect::NONE,
@@ -399,6 +406,7 @@ BOOST_AUTO_TEST_CASE (write_smpte_subtitle_test2)
0.9,
dcp::VAlign::TOP,
0,
+ vector<dcp::Text::VariableZPosition>(),
dcp::Direction::LTR,
"This is the ",
dcp::Effect::NONE,
@@ -426,6 +434,7 @@ BOOST_AUTO_TEST_CASE (write_smpte_subtitle_test2)
0.9,
dcp::VAlign::TOP,
0,
+ vector<dcp::Text::VariableZPosition>(),
dcp::Direction::LTR,
"second",
dcp::Effect::NONE,
@@ -453,6 +462,7 @@ BOOST_AUTO_TEST_CASE (write_smpte_subtitle_test2)
0.9,
dcp::VAlign::TOP,
0,
+ vector<dcp::Text::VariableZPosition>(),
dcp::Direction::LTR,
" line",
dcp::Effect::NONE,
@@ -511,6 +521,7 @@ BOOST_AUTO_TEST_CASE (write_smpte_subtitle_test3)
0.8,
dcp::VAlign::TOP,
-88,
+ vector<dcp::Text::VariableZPosition>(),
dcp::Time (0, 0, 0, 0, 24),
dcp::Time (0, 0, 0, 0, 24)
)
@@ -568,6 +579,7 @@ BOOST_AUTO_TEST_CASE (write_subtitles_in_vertical_order_with_top_alignment)
0.8,
dcp::VAlign::TOP,
0,
+ vector<dcp::Text::VariableZPosition>(),
dcp::Direction::LTR,
"Top line",
dcp::Effect::NONE,
@@ -595,6 +607,7 @@ BOOST_AUTO_TEST_CASE (write_subtitles_in_vertical_order_with_top_alignment)
0.9,
dcp::VAlign::TOP,
0,
+ vector<dcp::Text::VariableZPosition>(),
dcp::Direction::LTR,
"Bottom line",
dcp::Effect::NONE,
@@ -658,6 +671,7 @@ BOOST_AUTO_TEST_CASE (write_subtitles_in_vertical_order_with_bottom_alignment)
0.8,
dcp::VAlign::BOTTOM,
0,
+ vector<dcp::Text::VariableZPosition>(),
dcp::Direction::LTR,
"Top line",
dcp::Effect::NONE,
@@ -685,6 +699,7 @@ BOOST_AUTO_TEST_CASE (write_subtitles_in_vertical_order_with_bottom_alignment)
0.7,
dcp::VAlign::BOTTOM,
0,
+ vector<dcp::Text::VariableZPosition>(),
dcp::Direction::LTR,
"Bottom line",
dcp::Effect::NONE,
@@ -782,3 +797,13 @@ BOOST_AUTO_TEST_CASE(smpte_subtitle_intrinsic_duration_read_correctly)
BOOST_CHECK_EQUAL(check.intrinsic_duration(), duration);
}
+
+
+BOOST_AUTO_TEST_CASE(pass_through_smpte_subtitle_with_variable_z)
+{
+ auto source = "test/data/subtitles_with_vZani.xml";
+ dcp::SMPTETextAsset test("test/data/subtitles_with_vZani.xml");
+ /* _parsed is a version of the source with some changes made by libdcp that are OK */
+ check_xml(dcp::file_to_string("test/data/subtitles_with_vZani_parsed.xml"), test.xml_as_string(), { "IssueDate" }, true);
+}
+
diff --git a/test/test.cc b/test/test.cc
index 0de9c73c..42619683 100644
--- a/test/test.cc
+++ b/test/test.cc
@@ -410,6 +410,7 @@ simple_text()
0.8,
dcp::VAlign::TOP,
0,
+ vector<dcp::Text::VariableZPosition>(),
dcp::Direction::LTR,
"Hello world",
dcp::Effect::NONE,
diff --git a/test/verify_test.cc b/test/verify_test.cc
index 3352b472..6c09cbe0 100644
--- a/test/verify_test.cc
+++ b/test/verify_test.cc
@@ -2092,7 +2092,7 @@ add_test_subtitle (shared_ptr<dcp::TextAsset> asset, int start_frame, int end_fr
dcp::HAlign::CENTER,
v_position,
v_align,
- 0,
+ 0, vector<dcp::Text::VariableZPosition>(),
dcp::Direction::LTR,
text,
dcp::Effect::NONE,
@@ -5896,7 +5896,7 @@ BOOST_AUTO_TEST_CASE(overlapping_subtitles)
dcp::Time(0, 0, 8, 0, 24),
0, dcp::HAlign::CENTER,
0, dcp::VAlign::CENTER,
- 0,
+ 0, vector<dcp::Text::VariableZPosition>(),
dcp::Direction::LTR,
"",
dcp::Effect::NONE, dcp::Colour{}, dcp::Time{}, dcp::Time{}, 0, vector<dcp::Ruby>{}
@@ -5909,7 +5909,7 @@ BOOST_AUTO_TEST_CASE(overlapping_subtitles)
dcp::Time(0, 0, 4, 0, 24),
0, dcp::HAlign::CENTER,
0, dcp::VAlign::CENTER,
- 0,
+ 0, vector<dcp::Text::VariableZPosition>(),
dcp::Direction::LTR,
"Hello",
dcp::Effect::NONE, dcp::Colour{}, dcp::Time{}, dcp::Time{}, 0, vector<dcp::Ruby>{}