From 0cb5e386c282ae34dd065e7e294030969645913e Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Mon, 20 Oct 2025 21:22:17 +0200 Subject: Replace find_and_resolve_cpls() with storing all CPL IDs in DCPContent (sometimes). In some places we need other details than the ID, but in lots of places this saves some disk searching. --- src/lib/dcp_content.cc | 21 ++++++++++++++++++--- src/lib/dcp_content.h | 6 ++++++ src/lib/dcp_decoder.cc | 4 ++++ src/lib/dcp_examiner.cc | 5 +++-- src/lib/dcp_examiner.h | 5 +++++ src/lib/show_playlist_content_store.cc | 9 +++++---- src/tools/dcpomatic_player.cc | 7 +++---- src/wx/content_menu.cc | 8 ++++---- 8 files changed, 48 insertions(+), 17 deletions(-) diff --git a/src/lib/dcp_content.cc b/src/lib/dcp_content.cc index 6e071e5c0..98c49fae4 100644 --- a/src/lib/dcp_content.cc +++ b/src/lib/dcp_content.cc @@ -145,7 +145,17 @@ DCPContent::DCPContent(cxml::ConstNodePtr node, boost::optionaloptional_string_child("CPL"); + for (auto cpl: node->node_children("CPL")) { + _cpls.push_back(cpl->content()); + if (auto selected = cpl->optional_bool_attribute("selected")) { + if (selected) { + _cpl = cpl->content(); + } + } + } + if (!_cpl && !_cpls.empty()) { + _cpl = _cpls.front(); + } for (auto i: node->node_children("ReelLength")) { _reel_lengths.push_back(raw_convert(i->content())); } @@ -340,6 +350,7 @@ DCPContent::examine(shared_ptr job, bool tolerant) _video_encoding = examiner->video_encoding(); _three_d = examiner->three_d(); _content_kind = examiner->content_kind(); + _cpls = examiner->cpls(); _cpl = examiner->cpl(); _reel_lengths = examiner->reel_lengths(); _markers = examiner->markers(); @@ -466,8 +477,12 @@ DCPContent::as_xml(xmlpp::Element* element, bool with_paths, PathBehaviour path_ if (_content_kind) { cxml::add_text_child(element, "ContentKind", _content_kind->name()); } - if (_cpl) { - cxml::add_text_child(element, "CPL", _cpl.get()); + for (auto cpl: _cpls) { + auto e = cxml::add_child(element, "CPL"); + e->add_child_text(cpl); + if (cpl == _cpl) { + e->set_attribute("selected", "1"); + } } for (auto i: _reel_lengths) { cxml::add_text_child(element, "ReelLength", fmt::to_string(i)); diff --git a/src/lib/dcp_content.h b/src/lib/dcp_content.h index 8a34c4bbe..a76028a67 100644 --- a/src/lib/dcp_content.h +++ b/src/lib/dcp_content.h @@ -166,6 +166,11 @@ public: void set_cpl(std::string id); + std::vector cpls() const { + boost::mutex::scoped_lock lm(_mutex); + return _cpls; + } + boost::optional cpl() const { boost::mutex::scoped_lock lm(_mutex); return _cpl; @@ -278,6 +283,7 @@ private: boost::optional _video_encoding; boost::optional _content_kind; bool _three_d; + std::vector _cpls; /** ID of the CPL to use; older metadata might not specify this: in that case * just use the only CPL. */ diff --git a/src/lib/dcp_decoder.cc b/src/lib/dcp_decoder.cc index 42119a041..4809d772a 100644 --- a/src/lib/dcp_decoder.cc +++ b/src/lib/dcp_decoder.cc @@ -101,6 +101,10 @@ DCPDecoder::DCPDecoder(shared_ptr film, shared_ptr We do this by storing a digest of the important bits of the DCPContent and then checking that's the same before we re-use _reels. + + XXX: this seems a bit dubious - why is a complete re-examine not necessary in this case? + Or why is this done for DCPs only, and not other files that might change? + (see blame for the comment above for some reasons) */ _lazy_digest = calculate_lazy_digest(content); diff --git a/src/lib/dcp_examiner.cc b/src/lib/dcp_examiner.cc index b749c9686..e5e42a923 100644 --- a/src/lib/dcp_examiner.cc +++ b/src/lib/dcp_examiner.cc @@ -119,6 +119,9 @@ DCPExaminer::DCPExaminer(shared_ptr content, bool tolerant) selected_cpl->add(decrypt_kdm_with_helpful_error(content->kdm().get())); } + for (auto cpl: cpls) { + _cpls.push_back(cpl->id()); + } _cpl = selected_cpl->id(); _name = selected_cpl->content_title_text(); _content_kind = selected_cpl->content_kind(); @@ -364,8 +367,6 @@ DCPExaminer::DCPExaminer(shared_ptr content, bool tolerant) for (auto version: selected_cpl->content_versions()) { _content_versions.push_back(version.label_text); } - - _cpl = selected_cpl->id(); } diff --git a/src/lib/dcp_examiner.h b/src/lib/dcp_examiner.h index 7e73a8b09..12cd32500 100644 --- a/src/lib/dcp_examiner.h +++ b/src/lib/dcp_examiner.h @@ -163,6 +163,10 @@ public: return *_content_kind; } + std::vector cpls() const { + return _cpls; + } + std::string cpl() const { return _cpl; } @@ -249,6 +253,7 @@ private: boost::optional _video_encoding; bool _three_d = false; boost::optional _content_kind; + std::vector _cpls; std::string _cpl; std::list _reel_lengths; std::map _markers; diff --git a/src/lib/show_playlist_content_store.cc b/src/lib/show_playlist_content_store.cc index 1a9f533af..6e1100c70 100644 --- a/src/lib/show_playlist_content_store.cc +++ b/src/lib/show_playlist_content_store.cc @@ -70,12 +70,13 @@ ShowPlaylistContentStore::update(std::function pulse) if (is_directory(i) && contains_assetmap(i)) { auto dcp = make_shared(i); + examine(dcp); /* Add a Content for each CPL in this DCP, so we can choose CPLs to play * rather than DCPs. */ - for (auto cpl: dcp::find_and_resolve_cpls(dcp->directories(), true)) { + for (auto cpl: dcp->cpls()) { auto copy = dynamic_pointer_cast(dcp->clone()); - copy->set_cpl(cpl->id()); + copy->set_cpl(cpl); examine(copy); } } else if (i.path().extension() == ".mp4") { @@ -121,8 +122,8 @@ ShowPlaylistContentStore::get(string const& uuid) const { auto iter = std::find_if(_content.begin(), _content.end(), [uuid](shared_ptr content) { if (auto dcp = dynamic_pointer_cast(content)) { - for (auto cpl: dcp::find_and_resolve_cpls(dcp->directories(), true)) { - if (cpl->id() == uuid) { + for (auto cpl: dcp->cpls()) { + if (cpl == uuid) { return true; } } diff --git a/src/tools/dcpomatic_player.cc b/src/tools/dcpomatic_player.cc index 30a8d1071..b4425fe25 100644 --- a/src/tools/dcpomatic_player.cc +++ b/src/tools/dcpomatic_player.cc @@ -549,8 +549,7 @@ public: if (_film->content().size() == 1) { /* Offer a CPL menu */ - auto first = dynamic_pointer_cast(_film->content().front()); - if (first) { + if (auto first = dynamic_pointer_cast(_film->content().front())) { int id = ID_view_cpl; for (auto i: dcp::find_and_resolve_cpls(first->directories(), true)) { auto j = _cpl_menu->AppendRadioItem( @@ -916,7 +915,7 @@ private: { auto dcp = std::dynamic_pointer_cast(_film->content().front()); DCPOMATIC_ASSERT(dcp); - auto cpls = dcp::find_and_resolve_cpls(dcp->directories(), true); + auto cpls = dcp->cpls(); int id = ev.GetId() - ID_view_cpl; DCPOMATIC_ASSERT(id >= 0); DCPOMATIC_ASSERT(id < int(cpls.size())); @@ -927,7 +926,7 @@ private: } _viewer.set_coalesce_player_changes(true); - dcp->set_cpl((*i)->id()); + dcp->set_cpl(*i); examine_content(); _viewer.set_coalesce_player_changes(false); diff --git a/src/wx/content_menu.cc b/src/wx/content_menu.cc index b75c29660..527e28624 100644 --- a/src/wx/content_menu.cc +++ b/src/wx/content_menu.cc @@ -454,8 +454,8 @@ ContentMenu::kdm() return; } - auto cpls = dcp::find_and_resolve_cpls(dcp->directories(), true); - bool const kdm_matches_any_cpl = std::any_of(cpls.begin(), cpls.end(), [kdm](shared_ptr cpl) { return cpl->id() == kdm->cpl_id(); }); + auto cpls = dcp->cpls(); + bool const kdm_matches_any_cpl = std::any_of(cpls.begin(), cpls.end(), [kdm](std::string const& cpl) { return cpl == kdm->cpl_id(); }); bool const kdm_matches_selected_cpl = dcp->cpl() || kdm->cpl_id() == dcp->cpl().get(); if (!kdm_matches_any_cpl) { @@ -549,11 +549,11 @@ ContentMenu::cpl_selected(wxCommandEvent& ev) auto dcp = dynamic_pointer_cast(_content.front()); DCPOMATIC_ASSERT(dcp); - auto cpls = dcp::find_and_resolve_cpls(dcp->directories(), true); + auto cpls = dcp->cpls(); DCPOMATIC_ASSERT(ev.GetId() >= DCPOMATIC_CPL_MENU); DCPOMATIC_ASSERT(ev.GetId() < int(DCPOMATIC_CPL_MENU + cpls.size())); - dcp->set_cpl(cpls[ev.GetId() - DCPOMATIC_CPL_MENU]->id()); + dcp->set_cpl(cpls[ev.GetId() - DCPOMATIC_CPL_MENU]); auto film = _film.lock(); DCPOMATIC_ASSERT(film); -- cgit v1.2.3