Basics of reel split.
[dcpomatic.git] / src / lib / film.cc
index 9066b7c5a7f7b79bca06aa07e365bf7e651aa7a6..77e1be872b3b981b3391665d224454e1f9226efe 100644 (file)
@@ -28,7 +28,8 @@
 #include "job_manager.h"
 #include "transcode_job.h"
 #include "upload_job.h"
-#include "log.h"
+#include "null_log.h"
+#include "file_log.h"
 #include "exceptions.h"
 #include "examine_content_job.h"
 #include "config.h"
 #include "md5_digester.h"
 #include "compose.hpp"
 #include "screen.h"
+#include "audio_content.h"
+#include "video_content.h"
+#include "subtitle_content.h"
+#include "ffmpeg_content.h"
+#include "dcp_content.h"
+#include "screen_kdm.h"
 #include <libcxml/cxml.h>
 #include <dcp/cpl.h>
 #include <dcp/certificate_chain.h>
@@ -79,8 +86,8 @@ using boost::dynamic_pointer_cast;
 using boost::optional;
 using boost::is_any_of;
 
-#define LOG_GENERAL(...) log()->log (String::compose (__VA_ARGS__), Log::TYPE_GENERAL);
-#define LOG_GENERAL_NC(...) log()->log (__VA_ARGS__, Log::TYPE_GENERAL);
+#define LOG_GENERAL(...) log()->log (String::compose (__VA_ARGS__), LogEntry::TYPE_GENERAL);
+#define LOG_GENERAL_NC(...) log()->log (__VA_ARGS__, LogEntry::TYPE_GENERAL);
 
 /* 5 -> 6
  * AudioMapping XML changed.
@@ -117,7 +124,7 @@ Film::Film (boost::filesystem::path dir, bool log)
        , _audio_channels (6)
        , _three_d (false)
        , _sequence_video (true)
-       , _interop (false)
+       , _interop (Config::instance()->default_interop ())
        , _audio_processor (0)
        , _state_version (current_state_version)
        , _dirty (false)
@@ -157,8 +164,12 @@ Film::Film (boost::filesystem::path dir, bool log)
 
 Film::~Film ()
 {
-       for (list<boost::signals2::connection>::const_iterator i = _job_connections.begin(); i != _job_connections.end(); ++i) {
-               i->disconnect ();
+       BOOST_FOREACH (boost::signals2::connection& i, _job_connections) {
+               i.disconnect ();
+       }
+
+       BOOST_FOREACH (boost::signals2::connection& i, _audio_analysis_connections) {
+               i.disconnect ();
        }
 }
 
@@ -197,11 +208,11 @@ Film::video_identifier () const
 
 /** @return The file to write video frame info to */
 boost::filesystem::path
-Film::info_file () const
+Film::info_file (DCPTimePeriod period) const
 {
        boost::filesystem::path p;
        p /= "info";
-       p /= video_identifier ();
+       p /= video_identifier () + "_" + raw_convert<string> (period.from.get()) + "_" + raw_convert<string> (period.to.get());
        return file (p);
 }
 
@@ -212,9 +223,9 @@ Film::internal_video_asset_dir () const
 }
 
 boost::filesystem::path
-Film::internal_video_asset_filename () const
+Film::internal_video_asset_filename (DCPTimePeriod p) const
 {
-       return video_identifier() + ".mxf";
+       return video_identifier() + "_" + raw_convert<string> (p.from.get()) + "_" + raw_convert<string> (p.to.get()) + ".mxf";
 }
 
 boost::filesystem::path
@@ -266,7 +277,11 @@ Film::make_dcp ()
                LOG_GENERAL ("Content: %1", i->technical_summary());
        }
        LOG_GENERAL ("DCP video rate %1 fps", video_frame_rate());
-       LOG_GENERAL ("%1 threads", Config::instance()->num_local_encoding_threads());
+       if (Config::instance()->only_servers_encode ()) {
+               LOG_GENERAL_NC ("0 threads: ONLY SERVERS SET TO ENCODE");
+       } else {
+               LOG_GENERAL ("%1 threads", Config::instance()->num_local_encoding_threads());
+       }
        LOG_GENERAL ("J2K bandwidth %1", j2k_bandwidth());
 
        if (container() == 0) {
@@ -545,15 +560,13 @@ Film::isdcf_name (bool if_created_now) const
                d << "_" << container()->isdcf_name();
        }
 
-       ContentList cl = content ();
-
        /* XXX: this uses the first bit of content only */
 
        /* The standard says we don't do this for trailers, for some strange reason */
        if (dcp_content_type() && dcp_content_type()->libdcp_kind() != dcp::TRAILER) {
                Ratio const * content_ratio = 0;
-               for (ContentList::iterator i = cl.begin(); i != cl.end(); ++i) {
-                       shared_ptr<VideoContent> vc = dynamic_pointer_cast<VideoContent> (*i);
+               BOOST_FOREACH (shared_ptr<Content> i, content ()) {
+                       shared_ptr<VideoContent> vc = dynamic_pointer_cast<VideoContent> (i);
                        if (vc) {
                                /* Here's the first piece of video content */
                                if (vc->scale().ratio ()) {
@@ -604,8 +617,8 @@ Film::isdcf_name (bool if_created_now) const
                }
        } else {
                list<int> mapped;
-               for (ContentList::const_iterator i = cl.begin(); i != cl.end(); ++i) {
-                       shared_ptr<const AudioContent> ac = dynamic_pointer_cast<const AudioContent> (*i);
+               BOOST_FOREACH (shared_ptr<Content> i, content ()) {
+                       shared_ptr<const AudioContent> ac = dynamic_pointer_cast<const AudioContent> (i);
                        if (ac) {
                                list<int> c = ac->audio_mapping().mapped_output_channels ();
                                copy (c.begin(), c.end(), back_inserter (mapped));
@@ -663,8 +676,18 @@ Film::isdcf_name (bool if_created_now) const
                d << "-3D";
        }
 
-       if (!dm.package_type.empty ()) {
-               d << "_" << dm.package_type;
+       bool vf = false;
+       BOOST_FOREACH (shared_ptr<Content> i, content ()) {
+               shared_ptr<const DCPContent> dc = dynamic_pointer_cast<const DCPContent> (i);
+               if (dc && (dc->reference_video() || dc->reference_audio() || dc->reference_subtitle())) {
+                       vf = true;
+               }
+       }
+
+       if (vf) {
+               d << "_VF";
+       } else {
+               d << "_OV";
        }
 
        return d.str ();
@@ -938,8 +961,19 @@ Film::maybe_add_content (weak_ptr<Job> j, weak_ptr<Content> c)
        }
 
        shared_ptr<Content> content = c.lock ();
-       if (content) {
-               add_content (content);
+       if (!content) {
+               return;
+       }
+
+       add_content (content);
+       if (Config::instance()->automatic_audio_analysis ()) {
+               shared_ptr<Playlist> playlist (new Playlist);
+               playlist->add (content);
+               boost::signals2::connection c;
+               JobManager::instance()->analyse_audio (
+                       shared_from_this (), playlist, c, bind (&Film::audio_analysis_finished, this)
+                       );
+               _audio_analysis_connections.push_back (c);
        }
 }
 
@@ -972,6 +1006,7 @@ Film::move_content_later (shared_ptr<Content> c)
        _playlist->move_later (c);
 }
 
+/** @return length of the film from time 0 to the last thing on the playlist */
 DCPTime
 Film::length () const
 {
@@ -1074,7 +1109,7 @@ Film::make_kdm (
                ).encrypt (signer, target, formulation);
 }
 
-list<dcp::EncryptedKDM>
+list<ScreenKDM>
 Film::make_kdms (
        list<shared_ptr<Screen> > screens,
        boost::filesystem::path dcp,
@@ -1083,11 +1118,11 @@ Film::make_kdms (
        dcp::Formulation formulation
        ) const
 {
-       list<dcp::EncryptedKDM> kdms;
+       list<ScreenKDM> kdms;
 
-       for (list<shared_ptr<Screen> >::iterator i = screens.begin(); i != screens.end(); ++i) {
-               if ((*i)->certificate) {
-                       kdms.push_back (make_kdm ((*i)->certificate.get(), dcp, from, until, formulation));
+       BOOST_FOREACH (shared_ptr<Screen> i, screens) {
+               if (i->certificate) {
+                       kdms.push_back (ScreenKDM (i, make_kdm (i->certificate.get(), dcp, from, until, formulation)));
                }
        }
 
@@ -1224,3 +1259,18 @@ Film::remove_content (ContentList c)
 {
        _playlist->remove (c);
 }
+
+void
+Film::audio_analysis_finished ()
+{
+       /* XXX */
+}
+
+list<DCPTimePeriod>
+Film::reels () const
+{
+       list<DCPTimePeriod> p;
+       p.push_back (DCPTimePeriod (DCPTime (), length ()));
+       return p;
+}
+