+
+void
+Film::set_marker (dcp::Marker type, DCPTime time)
+{
+ FilmChangeSignaller ch (this, Property::MARKERS);
+ _markers[type] = time;
+}
+
+
+void
+Film::unset_marker (dcp::Marker type)
+{
+ FilmChangeSignaller ch (this, Property::MARKERS);
+ _markers.erase (type);
+}
+
+
+void
+Film::clear_markers ()
+{
+ FilmChangeSignaller ch (this, Property::MARKERS);
+ _markers.clear ();
+}
+
+
+void
+Film::set_ratings (vector<dcp::Rating> r)
+{
+ FilmChangeSignaller ch (this, Property::RATINGS);
+ _ratings = r;
+}
+
+void
+Film::set_content_versions (vector<string> v)
+{
+ FilmChangeSignaller ch (this, Property::CONTENT_VERSIONS);
+ _content_versions = v;
+}
+
+
+void
+Film::set_name_language (dcp::LanguageTag lang)
+{
+ FilmChangeSignaller ch (this, Property::NAME_LANGUAGE);
+ _name_language = lang;
+}
+
+
+void
+Film::set_audio_language (dcp::LanguageTag lang)
+{
+ FilmChangeSignaller ch (this, Property::AUDIO_LANGUAGE);
+ _audio_language = lang;
+}
+
+
+void
+Film::set_release_territory (optional<dcp::LanguageTag::RegionSubtag> region)
+{
+ FilmChangeSignaller ch (this, Property::RELEASE_TERRITORY);
+ _release_territory = region;
+}
+
+
+void
+Film::set_status (dcp::Status s)
+{
+ FilmChangeSignaller ch (this, Property::STATUS);
+ _status = s;
+}
+
+
+void
+Film::set_version_number (int v)
+{
+ FilmChangeSignaller ch (this, Property::VERSION_NUMBER);
+ _version_number = v;
+}
+
+
+void
+Film::set_chain (optional<string> c)
+{
+ FilmChangeSignaller ch (this, Property::CHAIN);
+ _chain = c;
+}
+
+
+void
+Film::set_distributor (optional<string> d)
+{
+ FilmChangeSignaller ch (this, Property::DISTRIBUTOR);
+ _distributor = d;
+}
+
+
+void
+Film::set_luminance (optional<dcp::Luminance> l)
+{
+ FilmChangeSignaller ch (this, Property::LUMINANCE);
+ _luminance = l;
+}
+
+
+void
+Film::set_facility (optional<string> f)
+{
+ FilmChangeSignaller ch (this, Property::FACILITY);
+ _facility = f;
+}
+
+
+optional<DCPTime>
+Film::marker (dcp::Marker type) const
+{
+ auto i = _markers.find (type);
+ if (i == _markers.end()) {
+ return {};
+ }
+ return i->second;
+}
+
+shared_ptr<InfoFileHandle>
+Film::info_file_handle (DCPTimePeriod period, bool read) const
+{
+ return std::make_shared<InfoFileHandle>(_info_file_mutex, info_file(period), read);
+}
+
+InfoFileHandle::InfoFileHandle (boost::mutex& mutex, boost::filesystem::path file, bool read)
+ : _lock (mutex)
+ , _file (file)
+{
+ if (read) {
+ _handle = fopen_boost (file, "rb");
+ if (!_handle) {
+ throw OpenFileError (file, errno, OpenFileError::READ);
+ }
+ } else {
+ auto const exists = boost::filesystem::exists (file);
+ if (exists) {
+ _handle = fopen_boost (file, "r+b");
+ } else {
+ _handle = fopen_boost (file, "wb");
+ }
+
+ if (!_handle) {
+ throw OpenFileError (file, errno, exists ? OpenFileError::READ_WRITE : OpenFileError::WRITE);
+ }
+ }
+}
+
+InfoFileHandle::~InfoFileHandle ()
+{
+ fclose (_handle);
+}
+
+
+/** Add FFOC and LFOC markers to a list if they are not already there */
+void
+Film::add_ffoc_lfoc (Markers& markers) const
+{
+ if (markers.find(dcp::Marker::FFOC) == markers.end()) {
+ markers[dcp::Marker::FFOC] = dcpomatic::DCPTime::from_frames(1, video_frame_rate());
+ }
+
+ if (markers.find(dcp::Marker::LFOC) == markers.end()) {
+ markers[dcp::Marker::LFOC] = length() - DCPTime::from_frames(1, video_frame_rate());
+ }
+}