Allow DCPContent to recover and serialise marker positions.
authorCarl Hetherington <cth@carlh.net>
Tue, 21 Apr 2020 00:10:35 +0000 (02:10 +0200)
committerCarl Hetherington <cth@carlh.net>
Tue, 21 Apr 2020 00:12:34 +0000 (02:12 +0200)
src/lib/dcp_content.cc
src/lib/dcp_content.h
src/lib/dcp_examiner.cc
src/lib/dcp_examiner.h
test/import_dcp_test.cc

index 52ac6132c2dc12de27e7c4345cd80507097816c4..94d5c010bd0b7202c79b48fb1dc4e809373c06fc 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2014-2018 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2014-2020 Carl Hetherington <cth@carlh.net>
 
     This file is part of DCP-o-matic.
 
@@ -49,6 +49,7 @@ using std::distance;
 using std::pair;
 using std::vector;
 using std::list;
+using std::map;
 using boost::shared_ptr;
 using boost::scoped_ptr;
 using boost::optional;
@@ -146,6 +147,10 @@ DCPContent::DCPContent (cxml::ConstNodePtr node, int version)
        BOOST_FOREACH (cxml::ConstNodePtr i, node->node_children("ReelLength")) {
                _reel_lengths.push_back (raw_convert<int64_t> (i->content ()));
        }
+
+       BOOST_FOREACH (cxml::ConstNodePtr i, node->node_children("Marker")) {
+               _markers[dcp::marker_from_string(i->string_attribute("type"))] = ContentTime(raw_convert<int64_t>(i->content()));
+       }
 }
 
 void
@@ -240,6 +245,10 @@ DCPContent::examine (shared_ptr<const Film> film, shared_ptr<Job> job)
                _content_kind = examiner->content_kind ();
                _cpl = examiner->cpl ();
                _reel_lengths = examiner->reel_lengths ();
+               map<dcp::Marker, dcp::Time> markers = examiner->markers();
+               for (map<dcp::Marker, dcp::Time>::const_iterator i = markers.begin(); i != markers.end(); ++i) {
+                       _markers[i->first] = ContentTime(i->second.as_editable_units(DCPTime::HZ));
+               }
        }
 
        if (old_texts == texts) {
@@ -339,6 +348,12 @@ DCPContent::as_xml (xmlpp::Node* node, bool with_paths) const
        BOOST_FOREACH (int64_t i, _reel_lengths) {
                node->add_child("ReelLength")->add_child_text (raw_convert<string> (i));
        }
+
+       for (map<dcp::Marker, ContentTime>::const_iterator i = _markers.begin(); i != _markers.end(); ++i) {
+               xmlpp::Element* marker = node->add_child("Marker");
+               marker->set_attribute("type", dcp::marker_to_string(i->first));
+               marker->add_child_text(raw_convert<string>(i->second.get()));
+       }
 }
 
 DCPTime
index fb8d9178198caedca8847a0b19dae0887783fad8..b9c4d9ee511a0a0ea90c6119bb67ec09c28b52bb 100644 (file)
@@ -150,6 +150,10 @@ public:
                return _standard.get ();
        }
 
+       std::map<dcp::Marker, dcpomatic::ContentTime> markers () const {
+               return _markers;
+       }
+
        bool kdm_timing_window_valid () const;
 
 private:
@@ -198,6 +202,7 @@ private:
        boost::optional<std::string> _cpl;
        /** List of the lengths of the reels in this DCP */
        std::list<int64_t> _reel_lengths;
+       std::map<dcp::Marker, dcpomatic::ContentTime> _markers;
 };
 
 #endif
index 9bf401125dda6dea75e3a880541603256588e079..a7d451eca75e14d326ea82d527a5e090b30e1782 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2014-2019 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2014-2020 Carl Hetherington <cth@carlh.net>
 
     This file is part of DCP-o-matic.
 
@@ -40,6 +40,7 @@
 #include <dcp/subtitle_asset.h>
 #include <dcp/reel_subtitle_asset.h>
 #include <dcp/reel_closed_caption_asset.h>
+#include <dcp/reel_markers_asset.h>
 #include <dcp/sound_asset.h>
 #include <boost/foreach.hpp>
 #include <iostream>
@@ -49,6 +50,7 @@
 using std::list;
 using std::cout;
 using std::runtime_error;
+using std::map;
 using boost::shared_ptr;
 using boost::dynamic_pointer_cast;
 
@@ -183,6 +185,11 @@ DCPExaminer::DCPExaminer (shared_ptr<const DCPContent> content, bool tolerant)
                        _text_count[TEXT_CLOSED_CAPTION]++;
                }
 
+               if (i->main_markers ()) {
+                       map<dcp::Marker, dcp::Time> rm = i->main_markers()->get();
+                       _markers.insert (rm.begin(), rm.end());
+               }
+
                if (i->main_picture()) {
                        _reel_lengths.push_back (i->main_picture()->actual_duration());
                } else if (i->main_sound()) {
index e52234e360fde46d827c6238abc6407c25810b3b..c1ba54deed3c34f29d52ed980a6f68c6f5a704ea 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2014-2019 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2014-2020 Carl Hetherington <cth@carlh.net>
 
     This file is part of DCP-o-matic.
 
@@ -25,6 +25,7 @@
 #include "video_examiner.h"
 #include "audio_examiner.h"
 #include "dcp.h"
+#include <dcp/dcp_time.h>
 
 class DCPContent;
 
@@ -118,6 +119,10 @@ public:
                return _reel_lengths;
        }
 
+       std::map<dcp::Marker, dcp::Time> markers () const {
+               return _markers;
+       }
+
 private:
        boost::optional<double> _video_frame_rate;
        boost::optional<dcp::Size> _video_size;
@@ -140,4 +145,5 @@ private:
        dcp::ContentKind _content_kind;
        std::string _cpl;
        std::list<int64_t> _reel_lengths;
+       std::map<dcp::Marker, dcp::Time> _markers;
 };
index 16ebfa454f14b32e81b1a4b7da320bed7c5c5e36..4c227ac34aea35cd81764062d0489aa0f6c6c6fc 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2014 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2014-2020 Carl Hetherington <cth@carlh.net>
 
     This file is part of DCP-o-matic.
 
 #include "lib/job_manager.h"
 #include "lib/config.h"
 #include "lib/cross.h"
+#include "lib/video_content.h"
+#include "lib/content_factory.h"
 #include <dcp/cpl.h>
 #include <boost/test/unit_test.hpp>
 
 using std::vector;
 using std::string;
+using std::map;
 using boost::shared_ptr;
+using boost::dynamic_pointer_cast;
 
 /** Make an encrypted DCP, import it and make a new unencrypted DCP */
 BOOST_AUTO_TEST_CASE (import_dcp_test)
@@ -94,3 +98,57 @@ BOOST_AUTO_TEST_CASE (import_dcp_test)
        /* Should be 1s red, 1s green, 1s blue */
        check_dcp ("test/data/import_dcp_test2", "build/test/import_dcp_test2/" + B->dcp_name());
 }
+
+
+/** Check that DCP markers are imported correctly */
+BOOST_AUTO_TEST_CASE (import_dcp_markers_test)
+{
+       /* Make a DCP with some markers */
+       shared_ptr<Film> film = new_test_film2 ("import_dcp_markers_test");
+       shared_ptr<Content> content = content_factory("test/data/flat_red.png").front();
+       film->examine_and_add_content (content);
+       BOOST_REQUIRE (!wait_for_jobs());
+
+       content->video->set_length (24 * 60 * 10);
+
+       film->set_marker(dcp::FFOC, dcpomatic::DCPTime::from_seconds(1.91));
+       film->set_marker(dcp::FFMC, dcpomatic::DCPTime::from_seconds(9.4));
+       film->set_marker(dcp::LFMC, dcpomatic::DCPTime::from_seconds(9.99));
+
+       film->make_dcp ();
+       BOOST_REQUIRE (!wait_for_jobs());
+
+       /* Import the DCP to a new film and check the markers */
+       shared_ptr<Film> film2 = new_test_film2 ("import_dcp_markers_test2");
+       shared_ptr<DCPContent> imported (new DCPContent(film->dir(film->dcp_name())));
+       film2->examine_and_add_content (imported);
+       BOOST_REQUIRE (!wait_for_jobs());
+       film2->write_metadata ();
+
+       BOOST_CHECK_EQUAL (imported->markers().size(), 3);
+
+       map<dcp::Marker, dcpomatic::ContentTime> markers = imported->markers();
+       BOOST_REQUIRE(markers.find(dcp::FFOC) != markers.end());
+       BOOST_CHECK(markers[dcp::FFOC] == dcpomatic::ContentTime(184000));
+       BOOST_REQUIRE(markers.find(dcp::FFMC) != markers.end());
+       BOOST_CHECK(markers[dcp::FFMC] == dcpomatic::ContentTime(904000));
+       BOOST_REQUIRE(markers.find(dcp::LFMC) != markers.end());
+       BOOST_CHECK(markers[dcp::LFMC] == dcpomatic::ContentTime(960000));
+
+       /* Load that film and check that the markers have been loaded */
+       shared_ptr<Film> film3(new Film(boost::filesystem::path("build/test/import_dcp_markers_test2")));
+       film3->read_metadata ();
+       BOOST_REQUIRE (film3->content().size() == 1);
+       shared_ptr<DCPContent> reloaded = dynamic_pointer_cast<DCPContent>(film3->content().front());
+       BOOST_REQUIRE (reloaded);
+
+       BOOST_CHECK_EQUAL (reloaded->markers().size(), 3);
+
+       markers = reloaded->markers();
+       BOOST_REQUIRE(markers.find(dcp::FFOC) != markers.end());
+       BOOST_CHECK(markers[dcp::FFOC] == dcpomatic::ContentTime(184000));
+       BOOST_REQUIRE(markers.find(dcp::FFMC) != markers.end());
+       BOOST_CHECK(markers[dcp::FFMC] == dcpomatic::ContentTime(904000));
+       BOOST_REQUIRE(markers.find(dcp::LFMC) != markers.end());
+       BOOST_CHECK(markers[dcp::LFMC] == dcpomatic::ContentTime(960000));
+}