/*
- Copyright (C) 2012-2019 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2021 Carl Hetherington <cth@carlh.net>
This file is part of libdcp.
#include "subtitle_image.h"
#include "dcp_assert.h"
#include "load_font_node.h"
+#include "reel_asset.h"
#include <asdcp/AS_DCP.h>
#include <asdcp/KM_util.h>
#include <libxml++/nodes/element.h>
#include <boost/shared_array.hpp>
#include <boost/foreach.hpp>
+using std::dynamic_pointer_cast;
using std::string;
-using std::list;
using std::cout;
using std::cerr;
using std::map;
-using boost::shared_ptr;
+using std::shared_ptr;
+using std::vector;
+using std::make_shared;
using boost::shared_array;
using boost::optional;
-using boost::dynamic_pointer_cast;
using boost::lexical_cast;
using namespace dcp;
}
void
-SubtitleAsset::parse_subtitles (xmlpp::Element const * node, list<ParseState>& state, optional<int> tcr, Standard standard)
+SubtitleAsset::parse_subtitles (xmlpp::Element const * node, vector<ParseState>& state, optional<int> tcr, Standard standard)
{
if (node->get_name() == "Font") {
state.push_back (font_node_state (node, standard));
}
void
-SubtitleAsset::maybe_add_subtitle (string text, list<ParseState> const & parse_state, Standard standard)
+SubtitleAsset::maybe_add_subtitle (string text, vector<ParseState> const & parse_state, Standard standard)
{
if (empty_or_white_space (text)) {
return;
_subtitles.push_back (
shared_ptr<Subtitle> (
new SubtitleImage (
- Data (),
+ ArrayData (),
standard == INTEROP ? text.substr(0, text.size() - 4) : text,
ps.in.get(),
ps.out.get(),
}
}
-list<shared_ptr<Subtitle> >
+
+vector<shared_ptr<const Subtitle>>
+SubtitleAsset::subtitles () const
+{
+ vector<shared_ptr<const Subtitle>> s;
+ for (auto i: _subtitles) {
+ s.push_back (i);
+ }
+ return s;
+}
+
+
+vector<shared_ptr<const Subtitle>>
SubtitleAsset::subtitles_during (Time from, Time to, bool starting) const
{
- list<shared_ptr<Subtitle> > s;
- BOOST_FOREACH (shared_ptr<Subtitle> i, _subtitles) {
+ vector<shared_ptr<const Subtitle>> s;
+ for (auto i: _subtitles) {
if ((starting && from <= i->in() && i->in() < to) || (!starting && i->out() >= from && i->in() <= to)) {
s.push_back (i);
}
return s;
}
+
+/* XXX: this needs a test */
+vector<shared_ptr<const Subtitle>>
+SubtitleAsset::subtitles_in_reel (shared_ptr<const dcp::ReelAsset> asset) const
+{
+ auto frame_rate = asset->edit_rate().as_float();
+ auto start = dcp::Time(asset->entry_point().get_value_or(0), frame_rate, time_code_rate());
+ auto during = subtitles_during (start, start + dcp::Time(asset->intrinsic_duration(), frame_rate, time_code_rate()), false);
+
+ vector<shared_ptr<const dcp::Subtitle>> corrected;
+ for (auto i: during) {
+ auto c = make_shared<dcp::Subtitle>(*i);
+ c->set_in (c->in() - start);
+ c->set_out (c->out() - start);
+ corrected.push_back (c);
+ }
+
+ return corrected;
+}
+
+
void
SubtitleAsset::add (shared_ptr<Subtitle> s)
{
}
if (_subtitles.size() != other->_subtitles.size()) {
- note (DCP_ERROR, "subtitles differ");
+ note (DCP_ERROR, String::compose("different number of subtitles: %1 vs %2", _subtitles.size(), other->_subtitles.size()));
return false;
}
- list<shared_ptr<Subtitle> >::const_iterator i = _subtitles.begin ();
- list<shared_ptr<Subtitle> >::const_iterator j = other->_subtitles.begin ();
+ auto i = _subtitles.begin();
+ auto j = other->_subtitles.begin();
while (i != _subtitles.end()) {
shared_ptr<SubtitleString> string_i = dynamic_pointer_cast<SubtitleString> (*i);
shared_ptr<SubtitleImage> image_j = dynamic_pointer_cast<SubtitleImage> (*j);
if ((string_i && !string_j) || (image_i && !image_j)) {
- note (DCP_ERROR, "subtitles differ");
+ note (DCP_ERROR, "subtitles differ: string vs. image");
return false;
}
if (string_i && *string_i != *string_j) {
- note (DCP_ERROR, "subtitles differ");
+ note (DCP_ERROR, String::compose("subtitles differ in text or metadata: %1 vs %2", string_i->text(), string_j->text()));
return false;
}
- if (image_i && *image_i != *image_j) {
- note (DCP_ERROR, "subtitles differ");
+ if (image_i && !image_i->equals(image_j, options, note)) {
return false;
}
}
/* Merge adjacent children with the same font */
- list<shared_ptr<order::Part> >::const_iterator i = part->children.begin();
- list<shared_ptr<order::Part> > merged;
+ auto i = part->children.begin();
+ vector<shared_ptr<order::Part>> merged;
while (i != part->children.end()) {
merged.push_back (*i);
++i;
} else {
- list<shared_ptr<order::Part> >::const_iterator j = i;
+ auto j = i;
++j;
while (j != part->children.end() && (*i)->font == (*j)->font) {
++j;
++i;
} else {
shared_ptr<order::Part> group (new order::Part (part, (*i)->font));
- for (list<shared_ptr<order::Part> >::const_iterator k = i; k != j; ++k) {
+ for (auto k = i; k != j; ++k) {
(*k)->font.clear ();
group->children.push_back (*k);
}
void
SubtitleAsset::subtitles_as_xml (xmlpp::Element* xml_root, int time_code_rate, Standard standard) const
{
- list<shared_ptr<Subtitle> > sorted = _subtitles;
- sorted.sort (SubtitleSorter ());
+ vector<shared_ptr<Subtitle> > sorted = _subtitles;
+ std::stable_sort(sorted.begin(), sorted.end(), SubtitleSorter());
/* Gather our subtitles into a hierarchy of Subtitle/Text/String objects, writing
font information into the bottom level (String) objects.
root->write_xml (xml_root, context);
}
-map<string, Data>
+map<string, ArrayData>
SubtitleAsset::font_data () const
{
- map<string, Data> out;
+ map<string, ArrayData> out;
BOOST_FOREACH (Font const & i, _fonts) {
out[i.load_id] = i.data;
}
return out;
}
+
+map<string, boost::filesystem::path>
+SubtitleAsset::font_filenames () const
+{
+ map<string, boost::filesystem::path> out;
+ BOOST_FOREACH (Font const& i, _fonts) {
+ if (i.file) {
+ out[i.load_id] = *i.file;
+ }
+ }
+ return out;
+}
+
+
/** Replace empty IDs in any <LoadFontId> and <Font> tags with
* a dummy string. Some systems give errors with empty font IDs
* (see DCP-o-matic bug #1689).
SubtitleAsset::fix_empty_font_ids ()
{
bool have_empty = false;
- list<string> ids;
+ vector<string> ids;
BOOST_FOREACH (shared_ptr<LoadFontNode> i, load_font_nodes()) {
if (i->id == "") {
have_empty = true;