Even more logging when reading DCPs.
[dcpomatic.git] / src / lib / dcp_content.cc
index f6a74501c7cae8b13102e0f9a586bd9bd08d90cf..62b74be90cb7765db19ad34a2ad51656da271abf 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2014-2020 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2014-2022 Carl Hetherington <cth@carlh.net>
 
     This file is part of DCP-o-matic.
 
 
 */
 
+
 #include "atmos_content.h"
-#include "dcp_content.h"
-#include "video_content.h"
 #include "audio_content.h"
-#include "dcp_examiner.h"
-#include "job.h"
-#include "film.h"
-#include "config.h"
-#include "overlaps.h"
 #include "compose.hpp"
+#include "config.h"
+#include "dcp_content.h"
 #include "dcp_decoder.h"
-#include "log.h"
+#include "dcp_examiner.h"
 #include "dcpomatic_log.h"
+#include "film.h"
+#include "job.h"
+#include "log.h"
+#include "overlaps.h"
 #include "text_content.h"
+#include "video_content.h"
 #include <dcp/dcp.h>
 #include <dcp/raw_convert.h>
 #include <dcp/exceptions.h>
 
 #include "i18n.h"
 
+
 using std::cout;
-using std::distance;
+using std::dynamic_pointer_cast;
+using std::function;
 using std::list;
 using std::make_shared;
-using std::map;
-using std::pair;
 using std::shared_ptr;
 using std::string;
 using std::vector;
-using boost::scoped_ptr;
 using boost::optional;
-using std::function;
-using std::dynamic_pointer_cast;
+using boost::scoped_ptr;
 #if BOOST_VERSION >= 106100
 using namespace boost::placeholders;
 #endif
 using dcp::raw_convert;
 using namespace dcpomatic;
 
+
 int const DCPContentProperty::NEEDS_ASSETS       = 600;
 int const DCPContentProperty::NEEDS_KDM          = 601;
 int const DCPContentProperty::REFERENCE_VIDEO    = 602;
@@ -73,6 +73,7 @@ int const DCPContentProperty::NAME               = 605;
 int const DCPContentProperty::TEXTS              = 606;
 int const DCPContentProperty::CPL                = 607;
 
+
 DCPContent::DCPContent (boost::filesystem::path p)
        : _encrypted (false)
        , _needs_assets (false)
@@ -94,9 +95,10 @@ DCPContent::DCPContent (boost::filesystem::path p)
 DCPContent::DCPContent (cxml::ConstNodePtr node, int version)
        : Content (node)
 {
-       video = VideoContent::from_xml (this, node, version);
+       video = VideoContent::from_xml (this, node, version, VideoRange::FULL);
        audio = AudioContent::from_xml (this, node, version);
-       text = TextContent::from_xml (this, node, version);
+       list<string> notes;
+       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) {
@@ -174,10 +176,10 @@ DCPContent::read_directory (boost::filesystem::path p)
        bool have_assetmap = false;
        bool have_metadata = false;
 
-       for (directory_iterator i(p); i != directory_iterator(); ++i) {
-               if (i->path().filename() == "ASSETMAP" || i->path().filename() == "ASSETMAP.xml") {
+       for (auto i: directory_iterator(p)) {
+               if (i.path().filename() == "ASSETMAP" || i.path().filename() == "ASSETMAP.xml") {
                        have_assetmap = true;
-               } else if (i->path().filename() == "metadata.xml") {
+               } else if (i.path().filename() == "metadata.xml") {
                        have_metadata = true;
                }
        }
@@ -201,9 +203,11 @@ DCPContent::read_sub_directory (boost::filesystem::path 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())) {
+               } 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()));
                }
        }
 }
@@ -242,7 +246,6 @@ DCPContent::examine (shared_ptr<const Film> film, shared_ptr<Job> job)
                        boost::mutex::scoped_lock lm (_mutex);
                        audio = make_shared<AudioContent>(this);
                }
-               audio->set_language (examiner->audio_language());
                auto as = make_shared<AudioStream>(examiner->audio_frame_rate(), examiner->audio_length(), examiner->audio_channels());
                audio->set_stream (as);
                auto m = as->mapping ();
@@ -267,6 +270,7 @@ DCPContent::examine (shared_ptr<const Film> film, shared_ptr<Job> job)
        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());
                new_text.push_back (c);
        }
 
@@ -689,7 +693,7 @@ DCPContent::can_reference_audio (shared_ptr<const Film> film, string& why_not) c
 {
        shared_ptr<DCPDecoder> decoder;
        try {
-               decoder.reset (new DCPDecoder (film, shared_from_this(), false, film->tolerant(), shared_ptr<DCPDecoder>()));
+               decoder = make_shared<DCPDecoder>(film, shared_from_this(), false, film->tolerant(), shared_ptr<DCPDecoder>());
        } catch (dcp::ReadError &) {
                /* We couldn't read the DCP, so it's probably missing */
                return false;
@@ -724,7 +728,7 @@ DCPContent::can_reference_text (shared_ptr<const Film> film, TextType type, stri
 {
        shared_ptr<DCPDecoder> decoder;
        try {
-               decoder.reset (new DCPDecoder (film, shared_from_this(), false, film->tolerant(), shared_ptr<DCPDecoder>()));
+               decoder = make_shared<DCPDecoder>(film, shared_from_this(), false, film->tolerant(), shared_ptr<DCPDecoder>());
        } catch (dcp::ReadError &) {
                /* We couldn't read the DCP, so it's probably missing */
                return false;
@@ -741,7 +745,7 @@ DCPContent::can_reference_text (shared_ptr<const Film> film, TextType type, stri
                                return false;
                        } else if (i->main_subtitle()->entry_point().get_value_or(0) != 0) {
                                /// TRANSLATORS: this string will follow "Cannot reference this DCP: "
-                               why_not = _("one if its subtitle reels has a non-zero entry point so it must be re-written.");
+                               why_not = _("one of its subtitle reels has a non-zero entry point so it must be re-written.");
                                return false;
                        }
                 }
@@ -754,7 +758,7 @@ DCPContent::can_reference_text (shared_ptr<const Film> film, TextType type, stri
                        for (auto j: i->closed_captions()) {
                                if (j->entry_point().get_value_or(0) != 0) {
                                        /// TRANSLATORS: this string will follow "Cannot reference this DCP: "
-                                       why_not = _("one if its closed caption has a non-zero entry point so it must be re-written.");
+                                       why_not = _("one of its closed caption has a non-zero entry point so it must be re-written.");
                                        return false;
                                }
                        }
@@ -819,3 +823,41 @@ DCPContent::resolution () const
        return Resolution::TWO_K;
 }
 
+
+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()
+{
+       if (text.empty()) {
+               return;
+       }
+
+       DCPExaminer examiner(shared_from_this(), true);
+       add_fonts_from_examiner(text.front(), examiner.fonts());
+}
+