/*
- Copyright (C) 2014-2022 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2014-2023 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
#include "job.h"
#include "log.h"
#include "overlaps.h"
+#include "scope_guard.h"
#include "text_content.h"
#include "video_content.h"
#include <dcp/dcp.h>
using std::cout;
using std::dynamic_pointer_cast;
+using std::exception;
using std::function;
using std::list;
using std::make_shared;
read_directory (p);
set_default_colour_conversion ();
-
- for (int i = 0; i < static_cast<int>(TextType::COUNT); ++i) {
- _reference_text[i] = false;
- }
}
DCPContent::DCPContent (cxml::ConstNodePtr node, int version)
text = TextContent::from_xml (this, node, version, notes);
atmos = AtmosContent::from_xml (this, node);
- for (int i = 0; i < static_cast<int>(TextType::COUNT); ++i) {
- _reference_text[i] = false;
- }
-
if (video && audio) {
audio->set_stream (
make_shared<AudioStream> (
node->optional_number_child<Frame>("AudioLength").get_value_or (
video->length() * node->number_child<int>("AudioFrameRate") / video_frame_rate().get()
),
- AudioMapping (node->node_child ("AudioMapping"), version)
+ AudioMapping(node->node_child("AudioMapping"), version),
+ 24
)
);
}
_reference_video = node->optional_bool_child ("ReferenceVideo").get_value_or (false);
_reference_audio = node->optional_bool_child ("ReferenceAudio").get_value_or (false);
if (version >= 37) {
- _reference_text[static_cast<int>(TextType::OPEN_SUBTITLE)] = node->optional_bool_child("ReferenceOpenSubtitle").get_value_or(false);
- _reference_text[static_cast<int>(TextType::CLOSED_CAPTION)] = node->optional_bool_child("ReferenceClosedCaption").get_value_or(false);
+ _reference_text[TextType::OPEN_SUBTITLE] = node->optional_bool_child("ReferenceOpenSubtitle").get_value_or(false);
+ _reference_text[TextType::CLOSED_CAPTION] = node->optional_bool_child("ReferenceClosedCaption").get_value_or(false);
} else {
- _reference_text[static_cast<int>(TextType::OPEN_SUBTITLE)] = node->optional_bool_child("ReferenceSubtitle").get_value_or(false);
- _reference_text[static_cast<int>(TextType::CLOSED_CAPTION)] = false;
+ _reference_text[TextType::OPEN_SUBTITLE] = node->optional_bool_child("ReferenceSubtitle").get_value_or(false);
+ _reference_text[TextType::CLOSED_CAPTION] = false;
}
if (node->optional_string_child("Standard")) {
auto const s = node->optional_string_child("Standard").get();
for (auto i: node->node_children("ContentVersion")) {
_content_versions.push_back (i->content());
}
+
+ _active_audio_channels = node->optional_number_child<int>("ActiveAudioChannels");
}
void
void
DCPContent::read_sub_directory (boost::filesystem::path p)
{
+ using namespace boost::filesystem;
+
LOG_GENERAL ("DCPContent::read_sub_directory reads %1", p.string());
- for (auto i: boost::filesystem::directory_iterator(p)) {
- if (boost::filesystem::is_regular_file(i.path())) {
- LOG_GENERAL ("Inside there's regular file %1", i.path().string());
- add_path (i.path());
- } else if (boost::filesystem::is_directory(i.path()) && i.path().filename() != ".AppleDouble") {
- LOG_GENERAL ("Inside there's directory %1", i.path().string());
- read_sub_directory (i.path());
- } else {
- LOG_GENERAL("Ignoring %1 from inside: status is %2", i.path().string(), static_cast<int>(boost::filesystem::status(i.path()).type()));
+ try {
+ for (auto i: directory_iterator(p)) {
+ if (is_regular_file(i.path())) {
+ LOG_GENERAL ("Inside there's regular file %1", i.path().string());
+ add_path (i.path());
+ } else if (is_directory(i.path()) && i.path().filename() != ".AppleDouble") {
+ LOG_GENERAL ("Inside there's directory %1", i.path().string());
+ read_sub_directory (i.path());
+ } else {
+ LOG_GENERAL("Ignoring %1 from inside: status is %2", i.path().string(), static_cast<int>(status(i.path()).type()));
+ }
}
+ } catch (exception& e) {
+ LOG_GENERAL("Failed to iterate over %1: %2", p.string(), e.what());
}
}
bool const needed_kdm = needs_kdm ();
string const old_name = name ();
+ ContentChangeSignalDespatcher::instance()->suspend();
+ ScopeGuard sg = []() {
+ ContentChangeSignalDespatcher::instance()->resume();
+ };
+
ContentChangeSignaller cc_texts (this, DCPContentProperty::TEXTS);
ContentChangeSignaller cc_assets (this, DCPContentProperty::NEEDS_ASSETS);
ContentChangeSignaller cc_kdm (this, DCPContentProperty::NEEDS_KDM);
boost::mutex::scoped_lock lm (_mutex);
video = make_shared<VideoContent>(this);
}
- video->take_from_examiner (examiner);
+ video->take_from_examiner(film, examiner);
set_default_colour_conversion ();
}
boost::mutex::scoped_lock lm (_mutex);
audio = make_shared<AudioContent>(this);
}
- auto as = make_shared<AudioStream>(examiner->audio_frame_rate(), examiner->audio_length(), examiner->audio_channels());
+ auto as = make_shared<AudioStream>(examiner->audio_frame_rate(), examiner->audio_length(), examiner->audio_channels(), 24);
audio->set_stream (as);
auto m = as->mapping ();
m.make_default (film ? film->audio_processor() : 0);
as->set_mapping (m);
+
+ _active_audio_channels = examiner->active_audio_channels();
}
if (examiner->has_atmos()) {
atmos->set_length (examiner->atmos_length());
}
- list<shared_ptr<TextContent>> new_text;
+ vector<shared_ptr<TextContent>> new_text;
for (int i = 0; i < examiner->text_count(TextType::OPEN_SUBTITLE); ++i) {
auto c = make_shared<TextContent>(this, TextType::OPEN_SUBTITLE, TextType::OPEN_SUBTITLE);
c->set_language (examiner->open_subtitle_language());
- add_fonts_from_examiner(c, examiner->fonts());
+ examiner->add_fonts(c);
new_text.push_back (c);
}
for (int i = 0; i < examiner->text_count(TextType::CLOSED_CAPTION); ++i) {
auto c = make_shared<TextContent>(this, TextType::CLOSED_CAPTION, TextType::CLOSED_CAPTION);
c->set_dcp_track (examiner->dcp_text_track(i));
+ examiner->add_fonts(c);
new_text.push_back (c);
}
}
boost::mutex::scoped_lock lm (_mutex);
+
node->add_child("Name")->add_child_text (_name);
node->add_child("Encrypted")->add_child_text (_encrypted ? "1" : "0");
node->add_child("NeedsAssets")->add_child_text (_needs_assets ? "1" : "0");
node->add_child("KDMValid")->add_child_text (_kdm_valid ? "1" : "0");
node->add_child("ReferenceVideo")->add_child_text (_reference_video ? "1" : "0");
node->add_child("ReferenceAudio")->add_child_text (_reference_audio ? "1" : "0");
- node->add_child("ReferenceOpenSubtitle")->add_child_text(_reference_text[static_cast<int>(TextType::OPEN_SUBTITLE)] ? "1" : "0");
- node->add_child("ReferenceClosedCaption")->add_child_text(_reference_text[static_cast<int>(TextType::CLOSED_CAPTION)] ? "1" : "0");
+ node->add_child("ReferenceOpenSubtitle")->add_child_text(_reference_text[TextType::OPEN_SUBTITLE] ? "1" : "0");
+ node->add_child("ReferenceClosedCaption")->add_child_text(_reference_text[TextType::CLOSED_CAPTION] ? "1" : "0");
if (_standard) {
switch (_standard.get ()) {
case dcp::Standard::INTEROP:
for (auto i: _content_versions) {
node->add_child("ContentVersion")->add_child_text(i);
}
+
+ if (_active_audio_channels) {
+ node->add_child("ActiveAudioChannels")->add_child_text(raw_convert<string>(*_active_audio_channels));
+ }
}
DCPTime
s += i->identifier () + " ";
}
+ boost::mutex::scoped_lock lm(_mutex);
+
s += string (_reference_video ? "1" : "0");
- for (int i = 0; i < static_cast<int>(TextType::COUNT); ++i) {
- s += string (_reference_text[i] ? "1" : "0");
+ for (auto text: _reference_text) {
+ s += string(text ? "1" : "0");
}
return s;
}
{
boost::mutex::scoped_lock lm (_mutex);
- _reference_text[static_cast<int>(type)] = r;
+ _reference_text[type] = r;
}
}
return true;
}
-static
-bool check_video (shared_ptr<const Content> c)
-{
- return static_cast<bool>(c->video) && c->video->use();
-}
bool
DCPContent::can_reference_video (shared_ptr<const Film> film, string& why_not) const
}
/// TRANSLATORS: this string will follow "Cannot reference this DCP: "
- return can_reference (film, bind (&check_video, _1), _("it overlaps other video content; remove the other content."), why_not);
+ return can_reference(
+ film,
+ [](shared_ptr<const Content> c) {
+ return static_cast<bool>(c->video) && c->video->use();
+ },
+ _("it overlaps other video content; remove the other content."),
+ why_not
+ );
}
-static
-bool check_audio (shared_ptr<const Content> c)
-{
- return static_cast<bool>(c->audio) && !c->audio->mapping().mapped_output_channels().empty();
-}
bool
DCPContent::can_reference_audio (shared_ptr<const Film> film, string& why_not) const
}
/// TRANSLATORS: this string will follow "Cannot reference this DCP: "
- return can_reference (film, bind (&check_audio, _1), _("it overlaps other audio content; remove the other content."), why_not);
+ return can_reference(
+ film, [](shared_ptr<const Content> c) {
+ return static_cast<bool>(c->audio) && !c->audio->mapping().mapped_output_channels().empty();
+ },
+ _("it overlaps other audio content; remove the other content."),
+ why_not
+ );
}
-static
-bool check_text (shared_ptr<const Content> c)
-{
- return !c->text.empty();
-}
bool
DCPContent::can_reference_text (shared_ptr<const Film> film, TextType type, string& why_not) const
}
/// TRANSLATORS: this string will follow "Cannot reference this DCP: "
- return can_reference (film, bind (&check_text, _1), _("it overlaps other text content; remove the other content."), why_not);
+ return can_reference(
+ film,
+ [type](shared_ptr<const Content> c) {
+ return std::find_if(c->text.begin(), c->text.end(), [type](shared_ptr<const TextContent> t) { return t->type() == type; }) != c->text.end();
+ },
+ _("they overlap other text content; remove the other content."),
+ why_not
+ );
}
void
return;
}
+ if (this == dc.get()) {
+ return;
+ }
+
+ boost::mutex::scoped_lock lm(_mutex);
+ boost::mutex::scoped_lock lm2(dc->_mutex);
+
_reference_video = dc->_reference_video;
_reference_audio = dc->_reference_audio;
- for (int i = 0; i < static_cast<int>(TextType::COUNT); ++i) {
- _reference_text[i] = dc->_reference_text[i];
- }
+ _reference_text = dc->_reference_text;
}
void
}
-void
-add_fonts_from_examiner(shared_ptr<TextContent> text, vector<vector<shared_ptr<Font>>> const & all_fonts)
-{
- int reel_number = 0;
- for (auto reel_fonts: all_fonts) {
- for (auto font: reel_fonts) {
- /* Each reel could have its own font with the same ID, so we disambiguate them here
- * by prepending the reel number. We do the same disambiguation when emitting the
- * subtitles in the DCP decoder.
- */
- font->set_id(id_for_font_in_reel(font->id(), reel_number));
- text->add_font(font);
- }
- ++reel_number;
- }
-
-}
-
-
-string
-id_for_font_in_reel(string id, int reel)
-{
- return String::compose("%1_%2", reel, id);
-}
-
-
void
DCPContent::check_font_ids()
{
}
DCPExaminer examiner(shared_from_this(), true);
- add_fonts_from_examiner(text.front(), examiner.fonts());
+ examiner.add_fonts(text.front());
+}
+
+
+int
+DCPContent::active_audio_channels() const
+{
+ return _active_audio_channels.get_value_or(
+ (audio && audio->stream()) ? audio->stream()->channels() : 0
+ );
}