Manual updates.
[dcpomatic.git] / src / lib / film.cc
index 3378b2042818a4f716f589c3aef2655c310f3120..edb9112177ef7362fdc5da2585a7565552c1772a 100644 (file)
@@ -38,9 +38,7 @@
 #include "dcp_content_type.h"
 #include "ratio.h"
 #include "cross.h"
-#include "safe_stringstream.h"
 #include "environment_info.h"
-#include "raw_convert.h"
 #include "audio_processor.h"
 #include "digester.h"
 #include "compose.hpp"
 #include <dcp/util.h>
 #include <dcp/local_time.h>
 #include <dcp/decrypted_kdm.h>
+#include <dcp/raw_convert.h>
 #include <libxml++/libxml++.h>
 #include <boost/filesystem.hpp>
 #include <boost/algorithm/string.hpp>
 #include <boost/foreach.hpp>
-#include <boost/make_shared.hpp>
 #include <boost/regex.hpp>
 #include <unistd.h>
 #include <stdexcept>
@@ -90,7 +88,7 @@ using boost::weak_ptr;
 using boost::dynamic_pointer_cast;
 using boost::optional;
 using boost::is_any_of;
-using boost::make_shared;
+using dcp::raw_convert;
 
 #define LOG_GENERAL(...) log()->log (String::compose (__VA_ARGS__), LogEntry::TYPE_GENERAL);
 #define LOG_GENERAL_NC(...) log()->log (__VA_ARGS__, LogEntry::TYPE_GENERAL);
@@ -116,8 +114,10 @@ using boost::make_shared;
  * are present.
  * 34 -> 35
  * VideoFrameType in VideoContent is a string rather than an integer.
+ * 35 -> 36
+ * EffectColour rather than OutlineColour in Subtitle.
  */
-int const Film::current_state_version = 35;
+int const Film::current_state_version = 36;
 
 /** Construct a Film object in a given directory.
  *
@@ -197,32 +197,29 @@ Film::video_identifier () const
 {
        DCPOMATIC_ASSERT (container ());
 
-       SafeStringStream s;
-       s.imbue (std::locale::classic ());
-
-       s << container()->id()
-         << "_" << resolution_to_string (_resolution)
-         << "_" << _playlist->video_identifier()
-         << "_" << _video_frame_rate
-         << "_" << j2k_bandwidth();
+       string s = container()->id()
+               + "_" + resolution_to_string (_resolution)
+               + "_" + _playlist->video_identifier()
+               + "_" + raw_convert<string>(_video_frame_rate)
+               + "_" + raw_convert<string>(j2k_bandwidth());
 
        if (encrypted ()) {
-               s << "_E";
+               s += "_E";
        } else {
-               s << "_P";
+               s += "_P";
        }
 
        if (_interop) {
-               s << "_I";
+               s += "_I";
        } else {
-               s << "_S";
+               s += "_S";
        }
 
        if (_three_d) {
-               s << "_3D";
+               s += "_3D";
        }
 
-       return s.str ();
+       return s;
 }
 
 /** @return The file to write video frame info to */
@@ -320,21 +317,21 @@ Film::make_dcp ()
                throw MissingSettingError (_("name"));
        }
 
-       JobManager::instance()->add (make_shared<TranscodeJob> (shared_from_this()));
+       JobManager::instance()->add (shared_ptr<Job> (new TranscodeJob (shared_from_this())));
 }
 
 /** Start a job to send our DCP to the configured TMS */
 void
 Film::send_dcp_to_tms ()
 {
-       shared_ptr<Job> j = make_shared<UploadJob> (shared_from_this());
+       shared_ptr<Job> j (new UploadJob (shared_from_this()));
        JobManager::instance()->add (j);
 }
 
 shared_ptr<xmlpp::Document>
 Film::metadata () const
 {
-       shared_ptr<xmlpp::Document> doc = make_shared<xmlpp::Document> ();
+       shared_ptr<xmlpp::Document> doc (new xmlpp::Document);
        xmlpp::Element* root = doc->create_root_node ("Metadata");
 
        root->add_child("Version")->add_child_text (raw_convert<string> (current_state_version));
@@ -364,7 +361,7 @@ Film::metadata () const
        if (_audio_processor) {
                root->add_child("AudioProcessor")->add_child_text (_audio_processor->id ());
        }
-       root->add_child("ReelType")->add_child_text (raw_convert<string> (_reel_type));
+       root->add_child("ReelType")->add_child_text (raw_convert<string> (static_cast<int> (_reel_type)));
        root->add_child("ReelLength")->add_child_text (raw_convert<string> (_reel_length));
        root->add_child("UploadAfterMakeDCP")->add_child_text (_upload_after_make_dcp ? "1" : "0");
        _playlist->as_xml (root->add_child ("Playlist"));
@@ -530,7 +527,7 @@ Film::mapped_audio_channels () const
 string
 Film::isdcf_name (bool if_created_now) const
 {
-       SafeStringStream d;
+       string d;
 
        string raw_name = name ();
 
@@ -573,49 +570,49 @@ Film::isdcf_name (bool if_created_now) const
                fixed_name = fixed_name.substr (0, 14);
        }
 
-       d << fixed_name;
+       d += fixed_name;
 
        if (dcp_content_type()) {
-               d << "_" << dcp_content_type()->isdcf_name();
-               d << "-" << isdcf_metadata().content_version;
+               d += "_" + dcp_content_type()->isdcf_name();
+               d += "-" + raw_convert<string>(isdcf_metadata().content_version);
        }
 
        ISDCFMetadata const dm = isdcf_metadata ();
 
        if (dm.temp_version) {
-               d << "-Temp";
+               d += "-Temp";
        }
 
        if (dm.pre_release) {
-               d << "-Pre";
+               d += "-Pre";
        }
 
        if (dm.red_band) {
-               d << "-RedBand";
+               d += "-RedBand";
        }
 
        if (!dm.chain.empty ()) {
-               d << "-" << dm.chain;
+               d += "-" + dm.chain;
        }
 
        if (three_d ()) {
-               d << "-3D";
+               d += "-3D";
        }
 
        if (dm.two_d_version_of_three_d) {
-               d << "-2D";
+               d += "-2D";
        }
 
        if (!dm.mastered_luminance.empty ()) {
-               d << "-" << dm.mastered_luminance;
+               d += "-" + dm.mastered_luminance;
        }
 
        if (video_frame_rate() != 24) {
-               d << "-" << video_frame_rate();
+               d += "-" + raw_convert<string>(video_frame_rate());
        }
 
        if (container()) {
-               d << "_" << container()->isdcf_name();
+               d += "_" + container()->isdcf_name();
        }
 
        /* XXX: this uses the first bit of content only */
@@ -636,12 +633,12 @@ Film::isdcf_name (bool if_created_now) const
                }
 
                if (content_ratio && content_ratio != container()) {
-                       d << "-" << content_ratio->isdcf_name();
+                       d += "-" + content_ratio->isdcf_name();
                }
        }
 
        if (!dm.audio_language.empty ()) {
-               d << "_" << dm.audio_language;
+               d += "_" + dm.audio_language;
                if (!dm.subtitle_language.empty()) {
 
                        bool burnt_in = true;
@@ -662,18 +659,18 @@ Film::isdcf_name (bool if_created_now) const
                                transform (language.begin(), language.end(), language.begin(), ::toupper);
                        }
 
-                       d << "-" << language;
+                       d += "-" + language;
                } else {
-                       d << "-XX";
+                       d += "-XX";
                }
        }
 
        if (!dm.territory.empty ()) {
-               d << "_" << dm.territory;
+               d += "_" + dm.territory;
                if (dm.rating.empty ()) {
-                       d << "-NR";
+                       d += "-NR";
                } else {
-                       d << "-" << dm.rating;
+                       d += "-" + dm.rating;
                }
        }
 
@@ -696,35 +693,35 @@ Film::isdcf_name (bool if_created_now) const
        }
 
        if (non_lfe) {
-               d << "_" << non_lfe << lfe;
+               d += String::compose("_%1%2", non_lfe, lfe);
        }
 
        /* XXX: HI/VI */
 
-       d << "_" << resolution_to_string (_resolution);
+       d += "_" + resolution_to_string (_resolution);
 
        if (!dm.studio.empty ()) {
-               d << "_" << dm.studio;
+               d += "_" + dm.studio;
        }
 
        if (if_created_now) {
-               d << "_" << boost::gregorian::to_iso_string (boost::gregorian::day_clock::local_day ());
+               d += "_" + boost::gregorian::to_iso_string (boost::gregorian::day_clock::local_day ());
        } else {
-               d << "_" << boost::gregorian::to_iso_string (_isdcf_date);
+               d += "_" + boost::gregorian::to_iso_string (_isdcf_date);
        }
 
        if (!dm.facility.empty ()) {
-               d << "_" << dm.facility;
+               d += "_" + dm.facility;
        }
 
        if (_interop) {
-               d << "_IOP";
+               d += "_IOP";
        } else {
-               d << "_SMPTE";
+               d += "_SMPTE";
        }
 
        if (three_d ()) {
-               d << "-3D";
+               d += "-3D";
        }
 
        bool vf = false;
@@ -736,12 +733,12 @@ Film::isdcf_name (bool if_created_now) const
        }
 
        if (vf) {
-               d << "_VF";
+               d += "_VF";
        } else {
-               d << "_OV";
+               d += "_OV";
        }
 
-       return d.str ();
+       return d;
 }
 
 /** @return name to give the DCP */
@@ -922,23 +919,23 @@ Film::j2c_path (int reel, Frame frame, Eyes eyes, bool tmp) const
        p /= "j2c";
        p /= video_identifier ();
 
-       SafeStringStream s;
-       s.width (8);
-       s << setfill('0') << reel << "_" << frame;
+       char buffer[256];
+       snprintf(buffer, sizeof(buffer), "%08d_%08" PRId64, reel, frame);
+       string s (buffer);
 
        if (eyes == EYES_LEFT) {
-               s << ".L";
+               s += ".L";
        } else if (eyes == EYES_RIGHT) {
-               s << ".R";
+               s += ".R";
        }
 
-       s << ".j2c";
+       s += ".j2c";
 
        if (tmp) {
-               s << ".tmp";
+               s += ".tmp";
        }
 
-       p /= s.str();
+       p /= s;
        return file (p);
 }
 
@@ -958,12 +955,13 @@ 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()
+                                               dcp.cpls().front()->file().get()
                                                )
                                        );
                        } catch (...) {
@@ -1005,7 +1003,7 @@ Film::content () const
 void
 Film::examine_content (shared_ptr<Content> c)
 {
-       shared_ptr<Job> j = make_shared<ExamineContentJob> (shared_from_this(), c);
+       shared_ptr<Job> j (new ExamineContentJob (shared_from_this(), c));
        JobManager::instance()->add (j);
 }
 
@@ -1016,7 +1014,7 @@ Film::examine_and_add_content (shared_ptr<Content> c)
                run_ffprobe (c->path(0), file ("ffprobe.log"), _log);
        }
 
-       shared_ptr<Job> j = make_shared<ExamineContentJob> (shared_from_this(), c);
+       shared_ptr<Job> j (new ExamineContentJob (shared_from_this(), c));
 
        _job_connections.push_back (
                j->Finished.connect (bind (&Film::maybe_add_content, this, weak_ptr<Job> (j), weak_ptr<Content> (c)))
@@ -1040,7 +1038,7 @@ Film::maybe_add_content (weak_ptr<Job> j, weak_ptr<Content> c)
 
        add_content (content);
        if (Config::instance()->automatic_audio_analysis() && content->audio) {
-               shared_ptr<Playlist> playlist = make_shared<Playlist> ();
+               shared_ptr<Playlist> playlist (new Playlist);
                playlist->add (content);
                boost::signals2::connection c;
                JobManager::instance()->analyse_audio (
@@ -1182,7 +1180,7 @@ Film::make_kdm (
        dcp::Formulation formulation
        ) const
 {
-       shared_ptr<const dcp::CPL> cpl = make_shared<dcp::CPL> (cpl_file);
+       shared_ptr<const dcp::CPL> cpl (new dcp::CPL (cpl_file));
        shared_ptr<const dcp::CertificateChain> signer = Config::instance()->signer_chain ();
        if (!signer->valid ()) {
                throw InvalidSignerError ();
@@ -1407,7 +1405,6 @@ Film::reels () const
        {
                optional<DCPTime> last_split;
                shared_ptr<Content> last_video;
-               ContentList cl = content ();
                BOOST_FOREACH (shared_ptr<Content> c, content ()) {
                        if (c->video) {
                                BOOST_FOREACH (DCPTime t, c->reel_split_points()) {
@@ -1448,3 +1445,45 @@ Film::reels () const
 
        return p;
 }
+
+string
+Film::content_summary (DCPTimePeriod period) const
+{
+       return _playlist->content_summary (period);
+}
+
+list<string>
+Film::fix_conflicting_settings ()
+{
+       list<string> notes;
+
+       list<boost::filesystem::path> was_referencing;
+       BOOST_FOREACH (shared_ptr<Content> i, content()) {
+               shared_ptr<DCPContent> d = dynamic_pointer_cast<DCPContent> (i);
+               if (d) {
+                       list<string> reasons;
+                       bool was = false;
+                       if (!d->can_reference_video(reasons) && d->reference_video()) {
+                               d->set_reference_video (false);
+                               was = true;
+                       }
+                       if (!d->can_reference_audio(reasons) && d->reference_audio()) {
+                               d->set_reference_audio (false);
+                               was = true;
+                       }
+                       if (!d->can_reference_subtitle(reasons) && d->reference_subtitle()) {
+                               d->set_reference_subtitle (false);
+                               was = true;
+                       }
+                       if (was) {
+                               was_referencing.push_back (d->path(0).parent_path().filename());
+                       }
+               }
+       }
+
+       BOOST_FOREACH (boost::filesystem::path d, was_referencing) {
+               notes.push_back (String::compose (_("The DCP %1 was being referred to by this film.  This not now possible because the reel sizes in the film no longer agree with those in the imported DCP.\n\nSetting the 'Reel type' to 'split by video content' will probably help.\n\nAfter doing that you would need to re-tick the appropriate 'refer to existing DCP' checkboxes."), d.string()));
+       }
+
+       return notes;
+}