summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/content.h2
-rw-r--r--src/lib/film.cc94
-rw-r--r--src/lib/film.h9
-rw-r--r--src/lib/reel_writer.cc10
-rw-r--r--src/lib/subtitle_encoder.cc10
-rw-r--r--src/lib/text_content.cc49
-rw-r--r--src/lib/text_content.h25
-rw-r--r--src/lib/writer.cc12
8 files changed, 113 insertions, 98 deletions
diff --git a/src/lib/content.h b/src/lib/content.h
index b8626e212..567cd5c1f 100644
--- a/src/lib/content.h
+++ b/src/lib/content.h
@@ -196,7 +196,7 @@ public:
std::shared_ptr<VideoContent> video;
std::shared_ptr<AudioContent> audio;
- std::list<std::shared_ptr<TextContent> > text;
+ std::list<std::shared_ptr<TextContent>> text;
std::shared_ptr<AtmosContent> atmos;
std::shared_ptr<TextContent> only_text () const;
diff --git a/src/lib/film.cc b/src/lib/film.cc
index 46074e2ad..763af8f8a 100644
--- a/src/lib/film.cc
+++ b/src/lib/film.cc
@@ -496,9 +496,6 @@ Film::metadata (bool with_content_paths) const
}
root->add_child("UserExplicitContainer")->add_child_text(_user_explicit_container ? "1" : "0");
root->add_child("UserExplicitResolution")->add_child_text(_user_explicit_resolution ? "1" : "0");
- for (auto i: _subtitle_languages) {
- root->add_child("SubtitleLanguage")->add_child_text(i.to_string());
- }
_playlist->as_xml (root->add_child ("Playlist"), with_content_paths);
return doc;
@@ -680,10 +677,6 @@ Film::read_metadata (optional<boost::filesystem::path> path)
_user_explicit_container = f.optional_bool_child("UserExplicitContainer").get_value_or(true);
_user_explicit_resolution = f.optional_bool_child("UserExplicitResolution").get_value_or(true);
- for (auto i: f.node_children("SubtitleLanguage")) {
- _subtitle_languages.push_back (dcp::LanguageTag(i->content()));
- }
-
list<string> notes;
_playlist->set_from_xml (shared_from_this(), f.node_child ("Playlist"), _state_version, notes);
@@ -692,41 +685,6 @@ Film::read_metadata (optional<boost::filesystem::path> path)
set_backtrace_file (file ("backtrace.txt"));
}
- /* Around 2.15.108 we removed subtitle language state from the text content and the ISDCF
- * metadata and put it into the Film instead. If we've loaded an old Film let's try and fish
- * out the settings from where they were so that they don't get lost.
- */
-
- optional<dcp::LanguageTag> found_language;
-
- for (auto i: f.node_child("Playlist")->node_children("Content")) {
- auto text = i->optional_node_child("Text");
- if (text && text->optional_string_child("Language") && !found_language) {
- try {
- found_language = dcp::LanguageTag(text->string_child("Language"));
- } catch (...) {}
- }
- }
-
- if (_state_version >= 9) {
- auto isdcf_language = f.node_child("ISDCFMetadata")->optional_string_child("SubtitleLanguage");
- if (isdcf_language && !found_language) {
- try {
- found_language = dcp::LanguageTag(*isdcf_language);
- } catch (...) {
- try {
- found_language = dcp::LanguageTag(boost::algorithm::to_lower_copy(*isdcf_language));
- } catch (...) {
-
- }
- }
- }
- }
-
- if (found_language) {
- _subtitle_languages.push_back (*found_language);
- }
-
_dirty = false;
return notes;
}
@@ -793,6 +751,30 @@ Film::mapped_audio_channels () const
return mapped;
}
+
+pair<optional<dcp::LanguageTag>, vector<dcp::LanguageTag>>
+Film::subtitle_languages () const
+{
+ pair<optional<dcp::LanguageTag>, vector<dcp::LanguageTag>> result;
+ for (auto i: content()) {
+ for (auto j: i->text) {
+ if (j->use() && j->type() == TextType::OPEN_SUBTITLE && j->language()) {
+ if (j->language_is_additional()) {
+ result.second.push_back (j->language().get());
+ } else {
+ result.first = j->language().get();
+ }
+ }
+ }
+ }
+
+ std::sort (result.second.begin(), result.second.end());
+ auto last = std::unique (result.second.begin(), result.second.end());
+ result.second.erase (last, result.second.end());
+ return result;
+}
+
+
/** @return a ISDCF-compliant name for a DCP of this film */
string
Film::isdcf_name (bool if_created_now) const
@@ -924,8 +906,9 @@ Film::isdcf_name (bool if_created_now) const
}
}
- if (!_subtitle_languages.empty()) {
- auto lang = _subtitle_languages.front().language().get_value_or("en").subtag();
+ auto sublangs = subtitle_languages();
+ if (sublangs.first && sublangs.first->language()) {
+ auto lang = sublangs.first->language()->subtag();
if (burnt_in) {
transform (lang.begin(), lang.end(), lang.begin(), ::tolower);
} else {
@@ -2038,29 +2021,6 @@ Film::set_luminance (optional<dcp::Luminance> l)
void
-Film::set_subtitle_language (dcp::LanguageTag language)
-{
- set_subtitle_languages ({language});
-}
-
-
-void
-Film::unset_subtitle_language ()
-{
- FilmChangeSignaller ch (this, Property::SUBTITLE_LANGUAGES);
- _subtitle_languages.clear();
-}
-
-
-void
-Film::set_subtitle_languages (vector<dcp::LanguageTag> languages)
-{
- FilmChangeSignaller ch (this, Property::SUBTITLE_LANGUAGES);
- _subtitle_languages = languages;
-}
-
-
-void
Film::set_facility (optional<string> f)
{
FilmChangeSignaller ch (this, Property::FACILITY);
diff --git a/src/lib/film.h b/src/lib/film.h
index 9b45fd073..9feb5d0d3 100644
--- a/src/lib/film.h
+++ b/src/lib/film.h
@@ -184,6 +184,7 @@ public:
std::list<dcpomatic::DCPTimePeriod> reels () const;
std::list<int> mapped_audio_channels () const;
+ std::pair<boost::optional<dcp::LanguageTag>, std::vector<dcp::LanguageTag>> subtitle_languages () const;
std::string content_summary (dcpomatic::DCPTimePeriod period) const;
@@ -376,10 +377,6 @@ public:
return _luminance;
}
- std::vector<dcp::LanguageTag> subtitle_languages () const {
- return _subtitle_languages;
- }
-
/* SET */
void set_directory (boost::filesystem::path);
@@ -421,9 +418,6 @@ public:
void set_facility (boost::optional<std::string> f = boost::none);
void set_distributor (boost::optional<std::string> d = boost::none);
void set_luminance (boost::optional<dcp::Luminance> l = boost::none);
- void set_subtitle_language (dcp::LanguageTag language);
- void unset_subtitle_language ();
- void set_subtitle_languages (std::vector<dcp::LanguageTag> languages);
void add_ffoc_lfoc (Markers& markers) const;
@@ -529,7 +523,6 @@ private:
boost::optional<std::string> _distributor;
boost::optional<std::string> _facility;
boost::optional<dcp::Luminance> _luminance;
- std::vector<dcp::LanguageTag> _subtitle_languages;
int _state_version;
diff --git a/src/lib/reel_writer.cc b/src/lib/reel_writer.cc
index 366e6edc6..2c55f0f06 100644
--- a/src/lib/reel_writer.cc
+++ b/src/lib/reel_writer.cc
@@ -623,8 +623,8 @@ ReelWriter::create_reel_text (
if (subtitle) {
/* We have a subtitle asset that we either made or are referencing */
- if (!film()->subtitle_languages().empty()) {
- subtitle->set_language (film()->subtitle_languages().front());
+ if (auto main_language = film()->subtitle_languages().first) {
+ subtitle->set_language (*main_language);
}
} else if (ensure_subtitles) {
/* We had no subtitle asset, but we've been asked to make sure there is one */
@@ -776,7 +776,7 @@ ReelWriter::empty_text_asset (TextType type, optional<DCPTextTrack> track) const
auto s = make_shared<dcp::InteropSubtitleAsset>();
s->set_movie_title (film()->name());
if (type == TextType::OPEN_SUBTITLE) {
- s->set_language (lang.empty() ? "Unknown" : lang.front().to_string());
+ s->set_language (lang.first ? lang.first->to_string() : "Unknown");
} else if (!track->language.empty()) {
s->set_language (track->language);
}
@@ -786,8 +786,8 @@ ReelWriter::empty_text_asset (TextType type, optional<DCPTextTrack> track) const
auto s = make_shared<dcp::SMPTESubtitleAsset>();
s->set_content_title_text (film()->name());
s->set_metadata (mxf_metadata());
- if (type == TextType::OPEN_SUBTITLE && !lang.empty()) {
- s->set_language (lang.front());
+ if (type == TextType::OPEN_SUBTITLE && lang.first) {
+ s->set_language (*lang.first);
} else if (track && !track->language.empty()) {
s->set_language (dcp::LanguageTag(track->language));
}
diff --git a/src/lib/subtitle_encoder.cc b/src/lib/subtitle_encoder.cc
index 3721ee02b..b61876ad6 100644
--- a/src/lib/subtitle_encoder.cc
+++ b/src/lib/subtitle_encoder.cc
@@ -135,20 +135,20 @@ SubtitleEncoder::text (PlayerText subs, TextType type, optional<DCPTextTrack> tr
if (!_assets[_reel_index].first) {
shared_ptr<dcp::SubtitleAsset> asset;
- vector<dcp::LanguageTag> lang = _film->subtitle_languages ();
+ auto lang = _film->subtitle_languages ();
if (_film->interop ()) {
auto s = make_shared<dcp::InteropSubtitleAsset>();
s->set_movie_title (_film->name());
- if (!lang.empty()) {
- s->set_language (lang.front().to_string());
+ if (lang.first) {
+ s->set_language (lang.first->to_string());
}
s->set_reel_number (raw_convert<string>(_reel_index + 1));
_assets[_reel_index].first = s;
} else {
auto s = make_shared<dcp::SMPTESubtitleAsset>();
s->set_content_title_text (_film->name());
- if (!lang.empty()) {
- s->set_language (lang.front());
+ if (lang.first) {
+ s->set_language (*lang.first);
} else if (!track->language.empty()) {
s->set_language (dcp::LanguageTag(track->language));
}
diff --git a/src/lib/text_content.cc b/src/lib/text_content.cc
index 0c25e5696..c86150881 100644
--- a/src/lib/text_content.cc
+++ b/src/lib/text_content.cc
@@ -18,6 +18,7 @@
*/
+
#include "text_content.h"
#include "util.h"
#include "exceptions.h"
@@ -30,6 +31,7 @@
#include "i18n.h"
+
using std::string;
using std::vector;
using std::cout;
@@ -41,6 +43,7 @@ using boost::optional;
using dcp::raw_convert;
using namespace dcpomatic;
+
int const TextContentProperty::X_OFFSET = 500;
int const TextContentProperty::Y_OFFSET = 501;
int const TextContentProperty::X_SCALE = 502;
@@ -57,6 +60,9 @@ int const TextContentProperty::FADE_OUT = 512;
int const TextContentProperty::OUTLINE_WIDTH = 513;
int const TextContentProperty::TYPE = 514;
int const TextContentProperty::DCP_TRACK = 515;
+int const TextContentProperty::LANGUAGE = 516;
+int const TextContentProperty::LANGUAGE_IS_ADDITIONAL = 517;
+
TextContent::TextContent (Content* parent, TextType type, TextType original_type)
: ContentPart (parent)
@@ -95,9 +101,7 @@ TextContent::from_xml (Content* parent, cxml::ConstNodePtr node, int version)
if (!node->optional_number_child<double>("SubtitleXOffset") && !node->optional_number_child<double>("SubtitleOffset")) {
return {};
}
- list<shared_ptr<TextContent>> c;
- c.push_back (make_shared<TextContent>(parent, node, version));
- return c;
+ return { make_shared<TextContent>(parent, node, version) };
}
if (!node->optional_node_child("Text")) {
@@ -124,6 +128,7 @@ TextContent::TextContent (Content* parent, cxml::ConstNodePtr node, int version)
, _outline_width (node->optional_number_child<int>("OutlineWidth").get_value_or(4))
, _type (TextType::OPEN_SUBTITLE)
, _original_type (TextType::OPEN_SUBTITLE)
+ , _language ("en-US")
{
if (version >= 37) {
_use = node->bool_child ("Use");
@@ -231,6 +236,13 @@ TextContent::TextContent (Content* parent, cxml::ConstNodePtr node, int version)
if (dt) {
_dcp_track = DCPTextTrack (dt);
}
+
+ auto lang = node->optional_node_child("Language");
+ if (lang) {
+ _language = dcp::LanguageTag(lang->content());
+ auto add = lang->optional_bool_attribute("Additional");
+ _language_is_additional = add && *add;
+ }
}
TextContent::TextContent (Content* parent, vector<shared_ptr<Content>> c)
@@ -290,6 +302,14 @@ TextContent::TextContent (Content* parent, vector<shared_ptr<Content>> c)
throw JoinError (_("Content to be joined must use the same DCP track."));
}
+ if (c[i]->only_text()->language() != ref->language()) {
+ throw JoinError (_("Content to be joined must use the same text language."));
+ }
+
+ if (c[i]->only_text()->language_is_additional() != ref->language_is_additional()) {
+ throw JoinError (_("Content to be joined must both be main subtitle languages or both additional."));
+ }
+
auto j = ref_fonts.begin ();
auto k = fonts.begin ();
@@ -316,6 +336,8 @@ TextContent::TextContent (Content* parent, vector<shared_ptr<Content>> c)
_type = ref->type ();
_original_type = ref->original_type ();
_dcp_track = ref->dcp_track ();
+ _language = ref->language ();
+ _language_is_additional = ref->language_is_additional ();
connect_to_fonts ();
}
@@ -375,6 +397,11 @@ TextContent::as_xml (xmlpp::Node* root) const
if (_dcp_track) {
_dcp_track->as_xml(text->add_child("DCPTrack"));
}
+ if (_language) {
+ auto lang = text->add_child("Language");
+ lang->add_child_text (_language->to_string());
+ lang->set_attribute ("Additional", _language_is_additional ? "1" : "0");
+ }
}
string
@@ -400,7 +427,7 @@ TextContent::identifier () const
s += "_" + f->file().get_value_or("Default").string();
}
- /* The DCP track is for metadata only, and doesn't affect how this content looks */
+ /* The DCP track and language are for metadata only, and don't affect how this content looks */
return s;
}
@@ -560,6 +587,18 @@ TextContent::unset_dcp_track ()
}
void
+TextContent::set_language (optional<dcp::LanguageTag> language)
+{
+ maybe_set (_language, language, TextContentProperty::LANGUAGE);
+}
+
+void
+TextContent::set_language_is_additional (bool additional)
+{
+ maybe_set (_language_is_additional, additional, TextContentProperty::LANGUAGE_IS_ADDITIONAL);
+}
+
+void
TextContent::take_settings_from (shared_ptr<const TextContent> c)
{
set_use (c->_use);
@@ -595,4 +634,6 @@ TextContent::take_settings_from (shared_ptr<const TextContent> c)
} else {
unset_dcp_track ();
}
+ set_language (c->_language);
+ set_language_is_additional (c->_language_is_additional);
}
diff --git a/src/lib/text_content.h b/src/lib/text_content.h
index e566d0552..4c6918a42 100644
--- a/src/lib/text_content.h
+++ b/src/lib/text_content.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2013-2020 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-2021 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
@@ -18,15 +18,19 @@
*/
+
#ifndef DCPOMATIC_CAPTION_CONTENT_H
#define DCPOMATIC_CAPTION_CONTENT_H
+
#include "content_part.h"
#include "dcp_text_track.h"
#include <libcxml/cxml.h>
+#include <dcp/language_tag.h>
#include <dcp/types.h>
#include <boost/signals2.hpp>
+
namespace dcpomatic {
class Font;
}
@@ -50,8 +54,11 @@ public:
static int const OUTLINE_WIDTH;
static int const TYPE;
static int const DCP_TRACK;
+ static int const LANGUAGE;
+ static int const LANGUAGE_IS_ADDITIONAL;
};
+
/** @class TextContent
* @brief Description of how some text content should be presented.
*
@@ -92,6 +99,8 @@ public:
void set_type (TextType type);
void set_dcp_track (DCPTextTrack track);
void unset_dcp_track ();
+ void set_language (boost::optional<dcp::LanguageTag> language = boost::none);
+ void set_language_is_additional (bool additional);
bool use () const {
boost::mutex::scoped_lock lm (_mutex);
@@ -178,7 +187,17 @@ public:
return _dcp_track;
}
- static std::list<std::shared_ptr<TextContent> > from_xml (Content* parent, cxml::ConstNodePtr, int version);
+ boost::optional<dcp::LanguageTag> language () const {
+ boost::mutex::scoped_lock lm (_mutex);
+ return _language;
+ }
+
+ bool language_is_additional () const {
+ boost::mutex::scoped_lock lm (_mutex);
+ return _language_is_additional;
+ }
+
+ static std::list<std::shared_ptr<TextContent>> from_xml (Content* parent, cxml::ConstNodePtr, int version);
private:
friend struct ffmpeg_pts_offset_test;
@@ -219,6 +238,8 @@ private:
TextType _original_type;
/** the track of closed captions that this content should be put in, or empty to put in the default (only) track */
boost::optional<DCPTextTrack> _dcp_track;
+ boost::optional<dcp::LanguageTag> _language;
+ bool _language_is_additional = false;
};
#endif
diff --git a/src/lib/writer.cc b/src/lib/writer.cc
index 839156d34..3448c5bca 100644
--- a/src/lib/writer.cc
+++ b/src/lib/writer.cc
@@ -663,9 +663,9 @@ Writer::finish (boost::filesystem::path output_dcp)
cpl->set_main_picture_active_area (active_area);
}
- vector<dcp::LanguageTag> sl = film()->subtitle_languages();
- if (sl.size() > 1) {
- cpl->set_additional_subtitle_languages(std::vector<dcp::LanguageTag>(sl.begin() + 1, sl.end()));
+ auto sl = film()->subtitle_languages().second;
+ if (!sl.empty()) {
+ cpl->set_additional_subtitle_languages(sl);
}
auto signer = Config::instance()->signer_chain();
@@ -709,10 +709,10 @@ Writer::write_cover_sheet (boost::filesystem::path output_dcp)
boost::algorithm::replace_all (text, "$AUDIO_LANGUAGE", film()->isdcf_metadata().audio_language);
auto subtitle_languages = film()->subtitle_languages();
- if (subtitle_languages.empty()) {
- boost::algorithm::replace_all (text, "$SUBTITLE_LANGUAGE", "None");
+ if (subtitle_languages.first) {
+ boost::algorithm::replace_all (text, "$SUBTITLE_LANGUAGE", subtitle_languages.first->description());
} else {
- boost::algorithm::replace_all (text, "$SUBTITLE_LANGUAGE", subtitle_languages.front().description());
+ boost::algorithm::replace_all (text, "$SUBTITLE_LANGUAGE", "None");
}
boost::uintmax_t size = 0;