X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Flib%2Ffilm.cc;h=e54268805ca9c71d752ecd89026d84cf6ebdc6ca;hb=09063d5958cad17ce89935f38f12c4fcbaaedf4f;hp=e7861a032c12ce1a3688454b0febe533e827b4cb;hpb=9fa17d52810490359f899cc0cbdb4c25ac74bc92;p=dcpomatic.git diff --git a/src/lib/film.cc b/src/lib/film.cc index e7861a032..e54268805 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -92,12 +92,14 @@ using std::runtime_error; using std::copy; using std::back_inserter; using std::map; +using std::exception; using boost::shared_ptr; using boost::weak_ptr; using boost::dynamic_pointer_cast; using boost::optional; using boost::is_any_of; using dcp::raw_convert; +using namespace dcpomatic; string const Film::metadata_file = "metadata.xml"; @@ -402,6 +404,14 @@ Film::metadata (bool with_content_paths) const root->add_child("UploadAfterMakeDCP")->add_child_text (_upload_after_make_dcp ? "1" : "0"); root->add_child("ReencodeJ2K")->add_child_text (_reencode_j2k ? "1" : "0"); root->add_child("UserExplicitVideoFrameRate")->add_child_text(_user_explicit_video_frame_rate ? "1" : "0"); + for (map::const_iterator i = _markers.begin(); i != _markers.end(); ++i) { + xmlpp::Element* m = root->add_child("Marker"); + m->set_attribute("Type", dcp::marker_to_string(i->first)); + m->add_child_text(raw_convert(i->second.get())); + } + BOOST_FOREACH (dcp::Rating i, _ratings) { + i.as_xml (root->add_child("Rating")); + } _playlist->as_xml (root->add_child ("Playlist"), with_content_paths); return doc; @@ -454,6 +464,16 @@ Film::read_metadata (optional path) _state_version = f.number_child ("Version"); if (_state_version > current_state_version) { throw runtime_error (_("This film was created with a newer version of DCP-o-matic, and it cannot be loaded into this version. Sorry!")); + } else if (_state_version < current_state_version) { + /* This is an older version; save a copy (if we haven't already) */ + boost::filesystem::path const older = path->parent_path() / String::compose("metadata.%1.xml", _state_version); + if (!boost::filesystem::is_regular_file(older)) { + try { + boost::filesystem::copy_file(*path, older); + } catch (...) { + /* Never mind; at least we tried */ + } + } } _name = f.string_child ("Name"); @@ -467,6 +487,7 @@ Film::read_metadata (optional path) _isdcf_date = boost::gregorian::from_undelimited_string (f.string_child ("DCIDate")); } + { optional c = f.optional_string_child ("DCPContentType"); if (c) { @@ -519,8 +540,15 @@ Film::read_metadata (optional path) _reencode_j2k = f.optional_bool_child("ReencodeJ2K").get_value_or(false); _user_explicit_video_frame_rate = f.optional_bool_child("UserExplicitVideoFrameRate").get_value_or(false); + BOOST_FOREACH (cxml::ConstNodePtr i, f.node_children("Marker")) { + _markers[dcp::marker_from_string(i->string_attribute("Type"))] = DCPTime(dcp::raw_convert(i->content())); + } + + BOOST_FOREACH (cxml::ConstNodePtr i, f.node_children("Rating")) { + _ratings.push_back (dcp::Rating(i)); + } + list notes; - /* This method is the only one that can return notes (so far) */ _playlist->set_from_xml (shared_from_this(), f.node_child ("Playlist"), _state_version, notes); /* Write backtraces to this film's directory, until another film is loaded */ @@ -711,36 +739,49 @@ Film::isdcf_name (bool if_created_now) const if (!dm.audio_language.empty ()) { d += "_" + dm.audio_language; - if (!dm.subtitle_language.empty()) { - /* I'm not clear on the precise details of the convention for CCAP labelling; - for now I'm just appending -CCAP if we have any closed captions. - */ + /* I'm not clear on the precise details of the convention for CCAP labelling; + for now I'm just appending -CCAP if we have any closed captions. + */ - bool burnt_in = true; - bool ccap = false; - BOOST_FOREACH (shared_ptr i, content()) { - BOOST_FOREACH (shared_ptr j, i->text) { - if (j->type() == TEXT_OPEN_SUBTITLE && j->use() && !j->burn()) { + optional subtitle_language; + bool burnt_in = true; + bool ccap = false; + BOOST_FOREACH (shared_ptr i, content()) { + BOOST_FOREACH (shared_ptr j, i->text) { + if (j->type() == TEXT_OPEN_SUBTITLE && j->use()) { + subtitle_language = j->language (); + if (!j->burn()) { burnt_in = false; - } else if (j->type() == TEXT_CLOSED_CAPTION) { - ccap = true; } + } else if (j->type() == TEXT_CLOSED_CAPTION && j->use()) { + ccap = true; } } + } - string language = dm.subtitle_language; - if (burnt_in && language != "XX") { - transform (language.begin(), language.end(), language.begin(), ::tolower); + if (dm.subtitle_language) { + /* Subtitle language is overridden in ISDCF metadata, primarily to handle + content with pre-burnt subtitles. + */ + d += "-" + *dm.subtitle_language; + if (ccap) { + d += "-CCAP"; + } + } else if (subtitle_language) { + /* Language is worked out from the content */ + if (burnt_in && *subtitle_language != "XX") { + transform (subtitle_language->begin(), subtitle_language->end(), subtitle_language->begin(), ::tolower); } else { - transform (language.begin(), language.end(), language.begin(), ::toupper); + transform (subtitle_language->begin(), subtitle_language->end(), subtitle_language->begin(), ::toupper); } - d += "-" + language; + d += "-" + *subtitle_language; if (ccap) { d += "-CCAP"; } } else { + /* No subtitles */ d += "-XX"; } } @@ -1027,7 +1068,16 @@ Film::j2c_path (int reel, Frame frame, Eyes eyes, bool tmp) const return file (p); } -/** Find all the DCPs in our directory that can be dcp::DCP::read() and return details of their CPLs */ +static +bool +cpl_summary_compare (CPLSummary const & a, CPLSummary const & b) +{ + return a.last_write_time > b.last_write_time; +} + +/** Find all the DCPs in our directory that can be dcp::DCP::read() and return details of their CPLs. + * The list will be returned in reverse order of timestamp (i.e. most recent first). + */ vector Film::cpls () const { @@ -1045,23 +1095,15 @@ Film::cpls () const ) { try { - dcp::DCP dcp (*i); - dcp.read (); - DCPOMATIC_ASSERT (dcp.cpls().front()->file()); - out.push_back ( - CPLSummary ( - i->path().leaf().string(), - dcp.cpls().front()->id(), - dcp.cpls().front()->annotation_text(), - dcp.cpls().front()->file().get() - ) - ); + out.push_back (CPLSummary(*i)); } catch (...) { } } } + sort (out.begin(), out.end(), cpl_summary_compare); + return out; } @@ -1342,26 +1384,25 @@ Film::make_kdm ( map, dcp::Key> keys; - BOOST_FOREACH(shared_ptr i, cpl->reel_assets ()) { - shared_ptr mxf = boost::dynamic_pointer_cast (i); - if (!mxf || !mxf->key_id()) { + BOOST_FOREACH(shared_ptr i, cpl->reel_mxfs()) { + if (!i->key_id()) { continue; } /* Get any imported key for this ID */ bool done = false; BOOST_FOREACH (dcp::DecryptedKDMKey j, imported_keys) { - if (j.id() == mxf->key_id().get()) { - LOG_GENERAL ("Using imported key for %1", mxf->key_id().get()); - keys[mxf] = j.key(); + if (j.id() == i->key_id().get()) { + LOG_GENERAL ("Using imported key for %1", i->key_id().get()); + keys[i] = j.key(); done = true; } } if (!done) { /* No imported key; it must be an asset that we encrypted */ - LOG_GENERAL ("Using our own key for %1", mxf->key_id().get()); - keys[mxf] = key(); + LOG_GENERAL ("Using our own key for %1", i->key_id().get()); + keys[i] = key(); } } @@ -1379,7 +1420,7 @@ Film::make_kdm ( * @param disable_forensic_marking_audio if not set, don't disable forensic marking of audio. If set to 0, * disable all forensic marking; if set above 0, disable forensic marking above that channel. */ -list +list > Film::make_kdms ( list > screens, boost::filesystem::path cpl_file, @@ -1390,7 +1431,7 @@ Film::make_kdms ( optional disable_forensic_marking_audio ) const { - list kdms; + list > kdms; BOOST_FOREACH (shared_ptr i, screens) { if (i->recipient) { @@ -1405,7 +1446,7 @@ Film::make_kdms ( disable_forensic_marking_audio ); - kdms.push_back (ScreenKDM (i, kdm)); + kdms.push_back (shared_ptr(new DCPScreenKDM(i, kdm))); } } @@ -1650,7 +1691,7 @@ Film::closed_caption_tracks () const list tt; BOOST_FOREACH (shared_ptr i, content()) { BOOST_FOREACH (shared_ptr j, i->text) { - /* XXX: Empty DCPTextTrack ends up being a magic value here */ + /* XXX: Empty DCPTextTrack ends up being a magic value here - the "unknown" or "not specified" track */ DCPTextTrack dtt = j->dcp_track().get_value_or(DCPTextTrack()); if (j->type() == TEXT_CLOSED_CAPTION && find(tt.begin(), tt.end(), dtt) == tt.end()) { tt.push_back (dtt); @@ -1660,3 +1701,34 @@ Film::closed_caption_tracks () const return tt; } + +void +Film::set_marker (dcp::Marker type, DCPTime time) +{ + ChangeSignaller ch (this, MARKERS); + _markers[type] = time; +} + +void +Film::unset_marker (dcp::Marker type) +{ + ChangeSignaller ch (this, MARKERS); + _markers.erase (type); +} + +void +Film::set_ratings (vector r) +{ + ChangeSignaller ch (this, RATINGS); + _ratings = r; +} + +optional +Film::marker (dcp::Marker type) const +{ + map::const_iterator i = _markers.find (type); + if (i == _markers.end()) { + return optional(); + } + return i->second; +}