Basics of front-end 3D (as far as viewer, at least).
[dcpomatic.git] / src / lib / film.cc
index 2bb8b3155cf36b145d775cf239fe31fb5d5f1d6f..40c6962563e29d4856029479fdef3e7cc7bf448c 100644 (file)
@@ -95,6 +95,8 @@ Film::Film (string d)
        , _dci_metadata (Config::instance()->default_dci_metadata ())
        , _dcp_video_frame_rate (24)
        , _dcp_audio_channels (MAX_AUDIO_CHANNELS)
+       , _dcp_3d (false)
+       , _sequence_video (true)
        , _dirty (false)
 {
        set_dci_date_today ();
@@ -122,6 +124,8 @@ Film::Film (string d)
 
        set_directory (result.string ());
        _log.reset (new FileLog ("log"));
+
+       _playlist->set_sequence_video (_sequence_video);
 }
 
 string
@@ -138,6 +142,10 @@ Film::video_identifier () const
          << "_" << scaler()->id()
          << "_" << j2k_bandwidth();
 
+       if (_dcp_3d) {
+               s << "_3D";
+       }
+
        return s.str ();
 }
          
@@ -246,7 +254,7 @@ Film::make_dcp ()
                throw MissingSettingError (_("container"));
        }
 
-       if (content_without_loop().empty()) {
+       if (content().empty()) {
                throw StringError (_("You must add some content to the DCP before creating it"));
        }
 
@@ -324,6 +332,8 @@ Film::write_metadata () const
        root->add_child("DCPVideoFrameRate")->add_child_text (lexical_cast<string> (_dcp_video_frame_rate));
        root->add_child("DCIDate")->add_child_text (boost::gregorian::to_iso_string (_dci_date));
        root->add_child("DCPAudioChannels")->add_child_text (lexical_cast<string> (_dcp_audio_channels));
+       root->add_child("DCP3D")->add_child_text (_dcp_3d ? "1" : "0");
+       root->add_child("SequenceVideo")->add_child_text (_sequence_video ? "1" : "0");
        _playlist->as_xml (root->add_child ("Playlist"));
 
        doc.write_to_file_formatted (file ("metadata.xml"));
@@ -369,6 +379,7 @@ Film::read_metadata ()
        _dcp_video_frame_rate = f.number_child<int> ("DCPVideoFrameRate");
        _dci_date = boost::gregorian::from_undelimited_string (f.string_child ("DCIDate"));
        _dcp_audio_channels = f.number_child<int> ("DCPAudioChannels");
+       _sequence_video = f.bool_child ("SequenceVideo");
 
        _playlist->set_from_xml (shared_from_this(), f.node_child ("Playlist"));
 
@@ -434,6 +445,14 @@ Film::dci_name (bool if_created_now) const
                d << "_" << dcp_content_type()->dci_name();
        }
 
+       if (dcp_3d ()) {
+               d << "-3D";
+       }
+
+       if (dcp_video_frame_rate() != 24) {
+               d << "-" << dcp_video_frame_rate();
+       }
+
        if (container()) {
                d << "_" << container()->dci_name();
        }
@@ -630,6 +649,16 @@ Film::set_dcp_audio_channels (int c)
        signal_changed (DCP_AUDIO_CHANNELS);
 }
 
+void
+Film::set_dcp_3d (bool t)
+{
+       {
+               boost::mutex::scoped_lock lm (_state_mutex);
+               _dcp_3d = t;
+       }
+       signal_changed (DCP_3D);
+}
+
 void
 Film::signal_changed (Property p)
 {
@@ -643,6 +672,7 @@ Film::signal_changed (Property p)
                set_dcp_video_frame_rate (_playlist->best_dcp_frame_rate ());
                break;
        case Film::DCP_VIDEO_FRAME_RATE:
+       case Film::SEQUENCE_VIDEO:
                _playlist->maybe_sequence_video ();
                break;
        default:
@@ -661,15 +691,23 @@ Film::set_dci_date_today ()
 }
 
 string
-Film::info_path (int f) const
+Film::info_path (int f, Eyes e) const
 {
        boost::filesystem::path p;
        p /= info_dir ();
 
        stringstream s;
        s.width (8);
-       s << setfill('0') << f << ".md5";
+       s << setfill('0') << f;
 
+       if (e == EYES_LEFT) {
+               s << ".L";
+       } else if (e == EYES_RIGHT) {
+               s << ".R";
+       }
+
+       s << ".md5";
+       
        p /= s.str();
 
        /* info_dir() will already have added any initial bit of the path,
@@ -679,7 +717,7 @@ Film::info_path (int f) const
 }
 
 string
-Film::j2c_path (int f, bool t) const
+Film::j2c_path (int f, Eyes e, bool t) const
 {
        boost::filesystem::path p;
        p /= "j2c";
@@ -687,7 +725,15 @@ Film::j2c_path (int f, bool t) const
 
        stringstream s;
        s.width (8);
-       s << setfill('0') << f << ".j2c";
+       s << setfill('0') << f;
+
+       if (e == EYES_LEFT) {
+               s << ".L";
+       } else if (e == EYES_RIGHT) {
+               s << ".R";
+       }
+       
+       s << ".j2c";
 
        if (t) {
                s << ".tmp";
@@ -728,23 +774,28 @@ Film::playlist () const
        return _playlist;
 }
 
-Playlist::ContentList
-Film::content_without_loop () const
+ContentList
+Film::content () const
 {
-       return _playlist->content_without_loop ();
+       return _playlist->content ();
 }
 
 void
 Film::examine_and_add_content (shared_ptr<Content> c)
 {
        shared_ptr<Job> j (new ExamineContentJob (shared_from_this(), c));
-       j->Finished.connect (bind (&Film::add_content_weak, this, boost::weak_ptr<Content> (c)));
+       j->Finished.connect (bind (&Film::maybe_add_content, this, boost::weak_ptr<Job> (j), boost::weak_ptr<Content> (c)));
        JobManager::instance()->add (j);
 }
 
 void
-Film::add_content_weak (weak_ptr<Content> c)
+Film::maybe_add_content (weak_ptr<Job> j, weak_ptr<Content> c)
 {
+       shared_ptr<Job> job = j.lock ();
+       if (!job || !job->finished_ok ()) {
+               return;
+       }
+       
        shared_ptr<Content> content = c.lock ();
        if (content) {
                add_content (content);
@@ -769,15 +820,9 @@ Film::remove_content (shared_ptr<Content> c)
 }
 
 Time
-Film::length_with_loop () const
-{
-       return _playlist->length_with_loop ();
-}
-
-Time
-Film::length_without_loop () const
+Film::length () const
 {
-       return _playlist->length_without_loop ();
+       return _playlist->length ();
 }
 
 bool
@@ -810,18 +855,6 @@ Film::playlist_changed ()
        signal_changed (CONTENT);
 }      
 
-int
-Film::loop () const
-{
-       return _playlist->loop ();
-}
-
-void
-Film::set_loop (int c)
-{
-       _playlist->set_loop (c);
-}
-
 OutputAudioFrame
 Film::time_to_audio_frames (Time t) const
 {
@@ -856,7 +889,13 @@ Film::dcp_audio_frame_rate () const
 void
 Film::set_sequence_video (bool s)
 {
-       _playlist->set_sequence_video (s);
+       {
+               boost::mutex::scoped_lock lm (_state_mutex);
+               _sequence_video = s;
+               _playlist->set_sequence_video (s);
+       }
+       
+       signal_changed (SEQUENCE_VIDEO);
 }
 
 libdcp::Size