Write OCAP/CCAP into ISDCF names in a hopefully more correct fashion. v2.18.4
authorCarl Hetherington <cth@carlh.net>
Sat, 11 Jan 2025 23:16:15 +0000 (00:16 +0100)
committerCarl Hetherington <cth@carlh.net>
Sun, 12 Jan 2025 01:06:50 +0000 (02:06 +0100)
src/lib/film.cc
src/lib/film.h
test/isdcf_name_test.cc

index 7b6b46ab939a449ba6991dd01a30bf347662941e..6c5aa0cbbd46806a78e787ec4050bd8bca2c0909 100644 (file)
@@ -819,7 +819,7 @@ Film::mapped_audio_channels () const
 
 
 pair<optional<dcp::LanguageTag>, vector<dcp::LanguageTag>>
-Film::open_text_languages(bool* burnt_in) const
+Film::open_text_languages(bool* burnt_in, bool* caption) const
 {
        if (burnt_in) {
                *burnt_in = true;
@@ -829,7 +829,9 @@ Film::open_text_languages(bool* burnt_in) const
        for (auto i: content()) {
                auto dcp = dynamic_pointer_cast<DCPContent>(i);
                for (auto const& text: i->text) {
-                       auto const use = text->use() || (dcp && dcp->reference_text(TextType::OPEN_SUBTITLE));
+                       auto const use = text->use() ||
+                               (dcp && (dcp->reference_text(TextType::OPEN_SUBTITLE) || dcp->reference_text(TextType::OPEN_CAPTION)));
+
                        if (use && is_open(text->type())) {
                                if (!text->burn() && burnt_in) {
                                        *burnt_in = false;
@@ -839,6 +841,9 @@ Film::open_text_languages(bool* burnt_in) const
                                                result.second.push_back(text->language().get());
                                        } else {
                                                result.first = text->language().get();
+                                               if (caption && text->type() == TextType::OPEN_CAPTION) {
+                                                       *caption = true;
+                                               }
                                        }
                                }
                        }
@@ -856,13 +861,16 @@ Film::open_text_languages(bool* burnt_in) const
 
 
 vector<dcp::LanguageTag>
-Film::closed_text_languages() const
+Film::closed_text_languages(bool* caption) const
 {
        vector<dcp::LanguageTag> result;
        for (auto i: content()) {
                for (auto text: i->text) {
                        if (text->use() && is_closed(text->type()) && text->dcp_track() && text->dcp_track()->language) {
                                result.push_back(*text->dcp_track()->language);
+                               if (caption && result.size() == 1 && text->type() == TextType::CLOSED_CAPTION) {
+                                       *caption = true;
+                               }
                        }
                }
        }
@@ -1009,8 +1017,12 @@ Film::isdcf_name (bool if_created_now) const
        isdcf_name += "_" + to_upper (audio_language);
 
        bool burnt_in;
-       auto const open_langs = open_text_languages(&burnt_in);
-       auto const closed_langs = closed_text_languages();
+       bool open_caption = false;
+       auto const open_langs = open_text_languages(&burnt_in, &open_caption);
+
+       bool closed_caption = false;
+       auto const closed_langs = closed_text_languages(&closed_caption);
+
        if (open_langs.first && open_langs.first->language()) {
                auto lang = entry_for_language(*open_langs.first);
                if (burnt_in) {
@@ -1020,8 +1032,14 @@ Film::isdcf_name (bool if_created_now) const
                }
 
                isdcf_name += "-" + lang;
+               if (open_caption) {
+                       isdcf_name += "-OCAP";
+               }
        } else if (!closed_langs.empty()) {
-               isdcf_name += "-" + to_upper(entry_for_language(closed_langs[0])) + "-CCAP";
+               isdcf_name += "-" + to_upper(entry_for_language(closed_langs[0]));
+               if (closed_caption) {
+                       isdcf_name += "-CCAP";
+               }
        } else {
                /* No subtitles */
                isdcf_name += "-XX";
index 6f02a96e6ac0693ce84e7f436bbef0a161798f92..aeb389cde6d4ae9a6138d5c1df5be1713d9fa5a4 100644 (file)
@@ -80,6 +80,7 @@ struct atmos_encrypted_passthrough_test;
 struct isdcf_name_test;
 struct isdcf_name_with_atmos;
 struct isdcf_name_with_ccap;
+struct isdcf_name_with_closed_subtitles;
 struct ov_subs_in_vf_name;
 struct recover_test_2d_encrypted;
 
@@ -178,11 +179,16 @@ public:
        }
 
        /** @param burnt_in If non-null, filled with true if all open subtitles/captions are burnt in, otherwise false.
-        *  @return pair containing the main open subtitle/caption language, and additional languages
+        *  @param caption If non-null, filled with true if the first returned language is a caption rather than a subtitle.
+        *  @return Pair containing the main open subtitle/caption language, and additional languages
         */
-       std::pair<boost::optional<dcp::LanguageTag>, std::vector<dcp::LanguageTag>> open_text_languages(bool* burnt_in = nullptr) const;
-       /** @return all closed subtitle/caption languages in the film */
-       std::vector<dcp::LanguageTag> closed_text_languages() const;
+       std::pair<boost::optional<dcp::LanguageTag>, std::vector<dcp::LanguageTag>> open_text_languages(
+               bool* burnt_in = nullptr, bool* caption = nullptr
+       ) const;
+       /** @param caption If non-null, filled with true if the first returned language is a caption rather than a subtitle.
+        *  @return All closed subtitle/caption languages in the film.
+        */
+       std::vector<dcp::LanguageTag> closed_text_languages(bool* caption = nullptr) const;
 
        std::string content_summary (dcpomatic::DCPTimePeriod period) const;
 
@@ -463,6 +469,7 @@ private:
        friend struct ::isdcf_name_test;
        friend struct ::isdcf_name_with_atmos;
        friend struct ::isdcf_name_with_ccap;
+       friend struct ::isdcf_name_with_closed_subtitles;
        friend struct ::ov_subs_in_vf_name;
        friend struct paths_test;
        friend struct ::recover_test_2d_encrypted;
index bd2289138e2f3f090b9f9976e787d758b2707066..3bab735ce72daa22ab5996f35076308f1a3330ca 100644 (file)
@@ -94,9 +94,10 @@ BOOST_AUTO_TEST_CASE (isdcf_name_test)
        film->set_interop (false);
        BOOST_CHECK_EQUAL (film->isdcf_name(false), "MyNiceFilmWith_TLR-2_S_DE-fr_US-R_MOS_4K_DI_20140704_PPF_SMPTE_OV");
 
-       /* Should be the same if the subs are marked as open captions */
+       /* Test the subs being marked as open captions */
        text->text[0]->set_type(TextType::OPEN_CAPTION);
-       BOOST_CHECK_EQUAL(film->isdcf_name(false), "MyNiceFilmWith_TLR-2_S_DE-fr_US-R_MOS_4K_DI_20140704_PPF_SMPTE_OV");
+       BOOST_CHECK_EQUAL(film->isdcf_name(false), "MyNiceFilmWith_TLR-2_S_DE-fr-OCAP_US-R_MOS_4K_DI_20140704_PPF_SMPTE_OV");
+       text->text[0]->set_type(TextType::OPEN_SUBTITLE);
 
        /* Test to see that RU ratings like 6+ are stripped of their + */
        film->set_ratings({dcp::Rating("RARS", "6+")});
@@ -265,3 +266,16 @@ BOOST_AUTO_TEST_CASE(isdcf_name_with_ccap)
        BOOST_CHECK_EQUAL(film->isdcf_name(false), "Hello_TST-1_F_XX-DE-CCAP_MOS_2K_20230118_SMPTE_OV");
 }
 
+
+BOOST_AUTO_TEST_CASE(isdcf_name_with_closed_subtitles)
+{
+       auto content = content_factory("test/data/short.srt")[0];
+       auto film = new_test_film("isdcf_name_with_closed_subtitles", { content });
+       content->text[0]->set_use(true);
+       content->text[0]->set_type(TextType::CLOSED_SUBTITLE);
+       content->text[0]->set_dcp_track(DCPTextTrack("Foo", dcp::LanguageTag("de-DE")));
+       film->_isdcf_date = boost::gregorian::date(2023, boost::gregorian::Jan, 18);
+       film->set_name("Hello");
+
+       BOOST_CHECK_EQUAL(film->isdcf_name(false), "Hello_TST-1_F_XX-DE_MOS_2K_20230118_SMPTE_OV");
+}