using std::map;
using std::exception;
using std::find;
-using boost::shared_ptr;
-using boost::weak_ptr;
-using boost::dynamic_pointer_cast;
+using std::shared_ptr;
+using std::weak_ptr;
+using std::dynamic_pointer_cast;
using boost::optional;
using boost::is_any_of;
#if BOOST_VERSION >= 106100
root->add_child("LuminanceUnit")->add_child_text(dcp::Luminance::unit_to_string(_luminance.unit()));
root->add_child("UserExplicitContainer")->add_child_text(_user_explicit_container ? "1" : "0");
root->add_child("UserExplicitResolution")->add_child_text(_user_explicit_resolution ? "1" : "0");
+ BOOST_FOREACH (dcp::LanguageTag 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;
_user_explicit_container = f.optional_bool_child("UserExplicitContainer").get_value_or(true);
_user_explicit_resolution = f.optional_bool_child("UserExplicitResolution").get_value_or(true);
+ BOOST_FOREACH (cxml::ConstNodePtr 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);
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;
+
+ BOOST_FOREACH (cxml::ConstNodePtr i, f.node_child("Playlist")->node_children("Content")) {
+ cxml::ConstNodePtr 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) {
+ optional<string> 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;
}
for now I'm just appending -CCAP if we have any closed captions.
*/
- optional<string> subtitle_language;
bool burnt_in = true;
bool ccap = false;
BOOST_FOREACH (shared_ptr<Content> i, content()) {
BOOST_FOREACH (shared_ptr<TextContent> j, i->text) {
- if (j->type() == TEXT_OPEN_SUBTITLE && j->use()) {
- subtitle_language = j->language ();
- if (!j->burn()) {
- burnt_in = false;
- }
+ if (j->type() == TEXT_OPEN_SUBTITLE && j->use() && !j->burn()) {
+ burnt_in = false;
} else if (j->type() == TEXT_CLOSED_CAPTION && j->use()) {
ccap = true;
}
}
}
- if (dm.subtitle_language) {
- /* Subtitle language is overridden in ISDCF metadata, primarily to handle
- content with pre-burnt subtitles.
- */
- d += "-" + *dm.subtitle_language;
- if (ccap) {
- d += "-CCAP";
- }
- } else if (subtitle_language) {
- /* Language is worked out from the content */
- if (burnt_in && *subtitle_language != "XX") {
- transform (subtitle_language->begin(), subtitle_language->end(), subtitle_language->begin(), ::tolower);
+ if (!_subtitle_languages.empty()) {
+ string lang = _subtitle_languages.front().language().get_value_or("en").subtag();
+ if (burnt_in) {
+ transform (lang.begin(), lang.end(), lang.begin(), ::tolower);
} else {
- transform (subtitle_language->begin(), subtitle_language->end(), subtitle_language->begin(), ::toupper);
+ transform (lang.begin(), lang.end(), lang.begin(), ::toupper);
}
- d += "-" + *subtitle_language;
+ d += "-" + lang;
if (ccap) {
d += "-CCAP";
}
d->set_reference_audio(false);
change_made = true;
}
+ if (d->reference_text(TEXT_OPEN_SUBTITLE) && !d->can_reference_text(shared_from_this(), TEXT_OPEN_SUBTITLE, why_not)) {
+ d->set_reference_text(TEXT_OPEN_SUBTITLE, false);
+ change_made = true;
+ }
+ if (d->reference_text(TEXT_CLOSED_CAPTION) && !d->can_reference_text(shared_from_this(), TEXT_CLOSED_CAPTION, why_not)) {
+ d->set_reference_text(TEXT_CLOSED_CAPTION, false);
+ change_made = true;
+ }
}
if (change_made) {
return (available - required) > 1;
}
-string
-Film::subtitle_language () const
-{
- set<string> languages;
-
- BOOST_FOREACH (shared_ptr<Content> i, content()) {
- BOOST_FOREACH (shared_ptr<TextContent> j, i->text) {
- languages.insert (j->language ());
- }
- }
-
- string all;
- BOOST_FOREACH (string s, languages) {
- if (!all.empty ()) {
- all += "/" + s;
- } else {
- all += s;
- }
- }
-
- return all;
-}
-
/** @return The names of the channels that audio contents' outputs are passed into;
* this is either the DCP or a AudioProcessor.
*/
vector<NamedChannel> n;
for (int i = 0; i < audio_channels(); ++i) {
- if (i != 8 && i != 9) {
+ if (i != 8 && i != 9 && i != 15) {
n.push_back (NamedChannel(short_audio_channel_name(i), i));
}
}
}
+void
+Film::set_subtitle_language (dcp::LanguageTag language)
+{
+ vector<dcp::LanguageTag> lang;
+ lang.push_back (language);
+ set_subtitle_languages (lang);
+}
+
+
+void
+Film::unset_subtitle_language ()
+{
+ ChangeSignaller<Film> ch (this, SUBTITLE_LANGUAGES);
+ _subtitle_languages.clear();
+}
+
+
+void
+Film::set_subtitle_languages (vector<dcp::LanguageTag> languages)
+{
+ ChangeSignaller<Film> ch (this, SUBTITLE_LANGUAGES);
+ _subtitle_languages = languages;
+}
+
+
void
Film::set_facility (string f)
{
{
fclose (_handle);
}
+
+
+/** Add FFOC and LFOC markers to a list if they are not already there */
+void
+Film::add_ffoc_lfoc (Markers& markers) const
+{
+ if (markers.find(dcp::Marker::FFOC) == markers.end()) {
+ markers[dcp::Marker::FFOC] = dcpomatic::DCPTime(0);
+ }
+
+ if (markers.find(dcp::Marker::LFOC) == markers.end()) {
+ markers[dcp::Marker::LFOC] = length() - DCPTime::from_frames(1, video_frame_rate());
+ }
+}