Confirm overwrite of existing DCP when creating a new one.
[dcpomatic.git] / src / lib / film.cc
1 /*
2     Copyright (C) 2012-2017 Carl Hetherington <cth@carlh.net>
3
4     This file is part of DCP-o-matic.
5
6     DCP-o-matic is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     DCP-o-matic is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
18
19 */
20
21 /** @file  src/film.cc
22  *  @brief A representation of some audio and video content, and details of
23  *  how they should be presented in a DCP.
24  */
25
26 #include "film.h"
27 #include "job.h"
28 #include "util.h"
29 #include "job_manager.h"
30 #include "transcode_job.h"
31 #include "upload_job.h"
32 #include "null_log.h"
33 #include "file_log.h"
34 #include "exceptions.h"
35 #include "examine_content_job.h"
36 #include "config.h"
37 #include "playlist.h"
38 #include "dcp_content_type.h"
39 #include "ratio.h"
40 #include "cross.h"
41 #include "environment_info.h"
42 #include "audio_processor.h"
43 #include "digester.h"
44 #include "compose.hpp"
45 #include "screen.h"
46 #include "audio_content.h"
47 #include "video_content.h"
48 #include "subtitle_content.h"
49 #include "ffmpeg_content.h"
50 #include "dcp_content.h"
51 #include "screen_kdm.h"
52 #include "cinema.h"
53 #include <libcxml/cxml.h>
54 #include <dcp/cpl.h>
55 #include <dcp/certificate_chain.h>
56 #include <dcp/util.h>
57 #include <dcp/local_time.h>
58 #include <dcp/decrypted_kdm.h>
59 #include <dcp/raw_convert.h>
60 #include <dcp/reel_mxf.h>
61 #include <dcp/reel_asset.h>
62 #include <libxml++/libxml++.h>
63 #include <boost/filesystem.hpp>
64 #include <boost/algorithm/string.hpp>
65 #include <boost/foreach.hpp>
66 #include <boost/regex.hpp>
67 #include <unistd.h>
68 #include <stdexcept>
69 #include <iostream>
70 #include <algorithm>
71 #include <cstdlib>
72 #include <iomanip>
73 #include <set>
74
75 #include "i18n.h"
76
77 using std::string;
78 using std::pair;
79 using std::vector;
80 using std::setfill;
81 using std::min;
82 using std::max;
83 using std::make_pair;
84 using std::cout;
85 using std::list;
86 using std::set;
87 using std::runtime_error;
88 using std::copy;
89 using std::back_inserter;
90 using std::map;
91 using boost::shared_ptr;
92 using boost::weak_ptr;
93 using boost::dynamic_pointer_cast;
94 using boost::optional;
95 using boost::is_any_of;
96 using dcp::raw_convert;
97
98 #define LOG_GENERAL(...) log()->log (String::compose (__VA_ARGS__), LogEntry::TYPE_GENERAL);
99 #define LOG_GENERAL_NC(...) log()->log (__VA_ARGS__, LogEntry::TYPE_GENERAL);
100
101 /* 5 -> 6
102  * AudioMapping XML changed.
103  * 6 -> 7
104  * Subtitle offset changed to subtitle y offset, and subtitle x offset added.
105  * 7 -> 8
106  * Use <Scale> tag in <VideoContent> rather than <Ratio>.
107  * 8 -> 9
108  * DCI -> ISDCF
109  * 9 -> 10
110  * Subtitle X and Y scale.
111  *
112  * Bumped to 32 for 2.0 branch; some times are expressed in Times rather
113  * than frames now.
114  *
115  * 32 -> 33
116  * Changed <Period> to <Subtitle> in FFmpegSubtitleStream
117  * 33 -> 34
118  * Content only contains audio/subtitle-related tags if those things
119  * are present.
120  * 34 -> 35
121  * VideoFrameType in VideoContent is a string rather than an integer.
122  * 35 -> 36
123  * EffectColour rather than OutlineColour in Subtitle.
124  */
125 int const Film::current_state_version = 36;
126
127 /** Construct a Film object in a given directory.
128  *
129  *  @param dir Film directory.
130  */
131
132 Film::Film (optional<boost::filesystem::path> dir)
133         : _playlist (new Playlist)
134         , _use_isdcf_name (true)
135         , _dcp_content_type (Config::instance()->default_dcp_content_type ())
136         , _container (Config::instance()->default_container ())
137         , _resolution (RESOLUTION_2K)
138         , _signed (true)
139         , _encrypted (false)
140         , _context_id (dcp::make_uuid ())
141         , _j2k_bandwidth (Config::instance()->default_j2k_bandwidth ())
142         , _isdcf_metadata (Config::instance()->default_isdcf_metadata ())
143         , _video_frame_rate (24)
144         , _audio_channels (Config::instance()->default_dcp_audio_channels ())
145         , _three_d (false)
146         , _sequence (true)
147         , _interop (Config::instance()->default_interop ())
148         , _audio_processor (0)
149         , _reel_type (REELTYPE_SINGLE)
150         , _reel_length (2000000000)
151         , _upload_after_make_dcp (false)
152         , _state_version (current_state_version)
153         , _dirty (false)
154 {
155         set_isdcf_date_today ();
156
157         _playlist_changed_connection = _playlist->Changed.connect (bind (&Film::playlist_changed, this));
158         _playlist_order_changed_connection = _playlist->OrderChanged.connect (bind (&Film::playlist_order_changed, this));
159         _playlist_content_changed_connection = _playlist->ContentChanged.connect (bind (&Film::playlist_content_changed, this, _1, _2, _3));
160
161         if (dir) {
162                 /* Make state.directory a complete path without ..s (where possible)
163                    (Code swiped from Adam Bowen on stackoverflow)
164                    XXX: couldn't/shouldn't this just be boost::filesystem::canonical?
165                 */
166
167                 boost::filesystem::path p (boost::filesystem::system_complete (dir.get()));
168                 boost::filesystem::path result;
169                 for (boost::filesystem::path::iterator i = p.begin(); i != p.end(); ++i) {
170                         if (*i == "..") {
171                                 if (boost::filesystem::is_symlink (result) || result.filename() == "..") {
172                                         result /= *i;
173                                 } else {
174                                         result = result.parent_path ();
175                                 }
176                         } else if (*i != ".") {
177                                 result /= *i;
178                         }
179                 }
180
181                 set_directory (result.make_preferred ());
182         }
183
184         if (_directory) {
185                 _log.reset (new FileLog (file ("log")));
186         } else {
187                 _log.reset (new NullLog);
188         }
189
190         _playlist->set_sequence (_sequence);
191 }
192
193 Film::~Film ()
194 {
195         BOOST_FOREACH (boost::signals2::connection& i, _job_connections) {
196                 i.disconnect ();
197         }
198
199         BOOST_FOREACH (boost::signals2::connection& i, _audio_analysis_connections) {
200                 i.disconnect ();
201         }
202 }
203
204 string
205 Film::video_identifier () const
206 {
207         DCPOMATIC_ASSERT (container ());
208
209         string s = container()->id()
210                 + "_" + resolution_to_string (_resolution)
211                 + "_" + _playlist->video_identifier()
212                 + "_" + raw_convert<string>(_video_frame_rate)
213                 + "_" + raw_convert<string>(j2k_bandwidth());
214
215         if (encrypted ()) {
216                 s += "_E";
217         } else {
218                 s += "_P";
219         }
220
221         if (_interop) {
222                 s += "_I";
223         } else {
224                 s += "_S";
225         }
226
227         if (_three_d) {
228                 s += "_3D";
229         }
230
231         return s;
232 }
233
234 /** @return The file to write video frame info to */
235 boost::filesystem::path
236 Film::info_file (DCPTimePeriod period) const
237 {
238         boost::filesystem::path p;
239         p /= "info";
240         p /= video_identifier () + "_" + raw_convert<string> (period.from.get()) + "_" + raw_convert<string> (period.to.get());
241         return file (p);
242 }
243
244 boost::filesystem::path
245 Film::internal_video_asset_dir () const
246 {
247         return dir ("video");
248 }
249
250 boost::filesystem::path
251 Film::internal_video_asset_filename (DCPTimePeriod p) const
252 {
253         return video_identifier() + "_" + raw_convert<string> (p.from.get()) + "_" + raw_convert<string> (p.to.get()) + ".mxf";
254 }
255
256 boost::filesystem::path
257 Film::audio_analysis_path (shared_ptr<const Playlist> playlist) const
258 {
259         boost::filesystem::path p = dir ("analysis");
260
261         Digester digester;
262         BOOST_FOREACH (shared_ptr<Content> i, playlist->content ()) {
263                 if (!i->audio) {
264                         continue;
265                 }
266
267                 digester.add (i->digest ());
268                 digester.add (i->audio->mapping().digest ());
269                 if (playlist->content().size() != 1) {
270                         /* Analyses should be considered equal regardless of gain
271                            if they were made from just one piece of content.  This
272                            is because we can fake any gain change in a single-content
273                            analysis at the plotting stage rather than having to
274                            recompute it.
275                         */
276                         digester.add (i->audio->gain ());
277                 }
278         }
279
280         if (audio_processor ()) {
281                 digester.add (audio_processor()->id ());
282         }
283
284         p /= digester.get ();
285         return p;
286 }
287
288 /** Add suitable Jobs to the JobManager to create a DCP for this Film */
289 void
290 Film::make_dcp ()
291 {
292         if (dcp_name().find ("/") != string::npos) {
293                 throw BadSettingError (_("name"), _("cannot contain slashes"));
294         }
295
296         if (container() == 0) {
297                 throw MissingSettingError (_("container"));
298         }
299
300         if (content().empty()) {
301                 throw runtime_error (_("you must add some content to the DCP before creating it"));
302         }
303
304         if (dcp_content_type() == 0) {
305                 throw MissingSettingError (_("content type"));
306         }
307
308         if (name().empty()) {
309                 throw MissingSettingError (_("name"));
310         }
311
312         BOOST_FOREACH (shared_ptr<const Content> i, content ()) {
313                 if (!i->paths_valid()) {
314                         throw runtime_error (_("some of your content is missing"));
315                 }
316                 shared_ptr<const DCPContent> dcp = dynamic_pointer_cast<const DCPContent> (i);
317                 if (dcp && dcp->needs_kdm()) {
318                         throw runtime_error (_("some of your content needs a KDM"));
319                 }
320                 if (dcp && dcp->needs_assets()) {
321                         throw runtime_error (_("some of your content needs an OV"));
322                 }
323         }
324
325         set_isdcf_date_today ();
326
327         BOOST_FOREACH (string i, environment_info ()) {
328                 LOG_GENERAL_NC (i);
329         }
330
331         BOOST_FOREACH (shared_ptr<const Content> i, content ()) {
332                 LOG_GENERAL ("Content: %1", i->technical_summary());
333         }
334         LOG_GENERAL ("DCP video rate %1 fps", video_frame_rate());
335         if (Config::instance()->only_servers_encode ()) {
336                 LOG_GENERAL_NC ("0 threads: ONLY SERVERS SET TO ENCODE");
337         } else {
338                 LOG_GENERAL ("%1 threads", Config::instance()->num_local_encoding_threads());
339         }
340         LOG_GENERAL ("J2K bandwidth %1", j2k_bandwidth());
341
342         JobManager::instance()->add (shared_ptr<Job> (new TranscodeJob (shared_from_this())));
343 }
344
345 /** Start a job to send our DCP to the configured TMS */
346 void
347 Film::send_dcp_to_tms ()
348 {
349         shared_ptr<Job> j (new UploadJob (shared_from_this()));
350         JobManager::instance()->add (j);
351 }
352
353 shared_ptr<xmlpp::Document>
354 Film::metadata (bool with_content_paths) const
355 {
356         shared_ptr<xmlpp::Document> doc (new xmlpp::Document);
357         xmlpp::Element* root = doc->create_root_node ("Metadata");
358
359         root->add_child("Version")->add_child_text (raw_convert<string> (current_state_version));
360         root->add_child("Name")->add_child_text (_name);
361         root->add_child("UseISDCFName")->add_child_text (_use_isdcf_name ? "1" : "0");
362
363         if (_dcp_content_type) {
364                 root->add_child("DCPContentType")->add_child_text (_dcp_content_type->isdcf_name ());
365         }
366
367         if (_container) {
368                 root->add_child("Container")->add_child_text (_container->id ());
369         }
370
371         root->add_child("Resolution")->add_child_text (resolution_to_string (_resolution));
372         root->add_child("J2KBandwidth")->add_child_text (raw_convert<string> (_j2k_bandwidth));
373         _isdcf_metadata.as_xml (root->add_child ("ISDCFMetadata"));
374         root->add_child("VideoFrameRate")->add_child_text (raw_convert<string> (_video_frame_rate));
375         root->add_child("ISDCFDate")->add_child_text (boost::gregorian::to_iso_string (_isdcf_date));
376         root->add_child("AudioChannels")->add_child_text (raw_convert<string> (_audio_channels));
377         root->add_child("ThreeD")->add_child_text (_three_d ? "1" : "0");
378         root->add_child("Sequence")->add_child_text (_sequence ? "1" : "0");
379         root->add_child("Interop")->add_child_text (_interop ? "1" : "0");
380         root->add_child("Signed")->add_child_text (_signed ? "1" : "0");
381         root->add_child("Encrypted")->add_child_text (_encrypted ? "1" : "0");
382         root->add_child("Key")->add_child_text (_key.hex ());
383         root->add_child("ContextID")->add_child_text (_context_id);
384         if (_audio_processor) {
385                 root->add_child("AudioProcessor")->add_child_text (_audio_processor->id ());
386         }
387         root->add_child("ReelType")->add_child_text (raw_convert<string> (static_cast<int> (_reel_type)));
388         root->add_child("ReelLength")->add_child_text (raw_convert<string> (_reel_length));
389         root->add_child("UploadAfterMakeDCP")->add_child_text (_upload_after_make_dcp ? "1" : "0");
390         _playlist->as_xml (root->add_child ("Playlist"), with_content_paths);
391
392         return doc;
393 }
394
395 /** Write state to our `metadata' file */
396 void
397 Film::write_metadata () const
398 {
399         DCPOMATIC_ASSERT (directory());
400         boost::filesystem::create_directories (directory().get());
401         shared_ptr<xmlpp::Document> doc = metadata ();
402         doc->write_to_file_formatted (file("metadata.xml").string ());
403         _dirty = false;
404 }
405
406 /** Write a template from this film */
407 void
408 Film::write_template (boost::filesystem::path path) const
409 {
410         boost::filesystem::create_directories (path.parent_path());
411         shared_ptr<xmlpp::Document> doc = metadata (false);
412         doc->write_to_file_formatted (path.string ());
413 }
414
415 /** Read state from our metadata file.
416  *  @return Notes about things that the user should know about, or empty.
417  */
418 list<string>
419 Film::read_metadata (optional<boost::filesystem::path> path)
420 {
421         if (!path) {
422                 if (boost::filesystem::exists (file ("metadata")) && !boost::filesystem::exists (file ("metadata.xml"))) {
423                         throw runtime_error (_("This film was created with an older version of DCP-o-matic, and unfortunately it cannot be loaded into this version.  You will need to create a new Film, re-add your content and set it up again.  Sorry!"));
424                 }
425
426                 path = file ("metadata.xml");
427         }
428
429         cxml::Document f ("Metadata");
430         f.read_file (path.get ());
431
432         _state_version = f.number_child<int> ("Version");
433         if (_state_version > current_state_version) {
434                 throw runtime_error (_("This film was created with a newer version of DCP-o-matic, and it cannot be loaded into this version.  Sorry!"));
435         }
436
437         _name = f.string_child ("Name");
438         if (_state_version >= 9) {
439                 _use_isdcf_name = f.bool_child ("UseISDCFName");
440                 _isdcf_metadata = ISDCFMetadata (f.node_child ("ISDCFMetadata"));
441                 _isdcf_date = boost::gregorian::from_undelimited_string (f.string_child ("ISDCFDate"));
442         } else {
443                 _use_isdcf_name = f.bool_child ("UseDCIName");
444                 _isdcf_metadata = ISDCFMetadata (f.node_child ("DCIMetadata"));
445                 _isdcf_date = boost::gregorian::from_undelimited_string (f.string_child ("DCIDate"));
446         }
447
448         {
449                 optional<string> c = f.optional_string_child ("DCPContentType");
450                 if (c) {
451                         _dcp_content_type = DCPContentType::from_isdcf_name (c.get ());
452                 }
453         }
454
455         {
456                 optional<string> c = f.optional_string_child ("Container");
457                 if (c) {
458                         _container = Ratio::from_id (c.get ());
459                 }
460         }
461
462         _resolution = string_to_resolution (f.string_child ("Resolution"));
463         _j2k_bandwidth = f.number_child<int> ("J2KBandwidth");
464         _video_frame_rate = f.number_child<int> ("VideoFrameRate");
465         _signed = f.optional_bool_child("Signed").get_value_or (true);
466         _encrypted = f.bool_child ("Encrypted");
467         _audio_channels = f.number_child<int> ("AudioChannels");
468         /* We used to allow odd numbers (and zero) channels, but it's just not worth
469            the pain.
470         */
471         if (_audio_channels == 0) {
472                 _audio_channels = 2;
473         } else if ((_audio_channels % 2) == 1) {
474                 _audio_channels++;
475         }
476
477         if (f.optional_bool_child("SequenceVideo")) {
478                 _sequence = f.bool_child("SequenceVideo");
479         } else {
480                 _sequence = f.bool_child("Sequence");
481         }
482
483         _three_d = f.bool_child ("ThreeD");
484         _interop = f.bool_child ("Interop");
485         _key = dcp::Key (f.string_child ("Key"));
486         _context_id = f.optional_string_child("ContextID").get_value_or (dcp::make_uuid ());
487
488         if (f.optional_string_child ("AudioProcessor")) {
489                 _audio_processor = AudioProcessor::from_id (f.string_child ("AudioProcessor"));
490         } else {
491                 _audio_processor = 0;
492         }
493
494         _reel_type = static_cast<ReelType> (f.optional_number_child<int>("ReelType").get_value_or (static_cast<int>(REELTYPE_SINGLE)));
495         _reel_length = f.optional_number_child<int64_t>("ReelLength").get_value_or (2000000000);
496         _upload_after_make_dcp = f.optional_bool_child("UploadAfterMakeDCP").get_value_or (false);
497
498         list<string> notes;
499         /* This method is the only one that can return notes (so far) */
500         _playlist->set_from_xml (shared_from_this(), f.node_child ("Playlist"), _state_version, notes);
501
502         /* Write backtraces to this film's directory, until another film is loaded */
503         if (_directory) {
504                 set_backtrace_file (file ("backtrace.txt"));
505         }
506
507         _dirty = false;
508         return notes;
509 }
510
511 /** Given a directory name, return its full path within the Film's directory.
512  *  @param d directory name within the Filn's directory.
513  *  @param create true to create the directory (and its parents) if they do not exist.
514  */
515 boost::filesystem::path
516 Film::dir (boost::filesystem::path d, bool create) const
517 {
518         DCPOMATIC_ASSERT (_directory);
519
520         boost::filesystem::path p;
521         p /= _directory.get();
522         p /= d;
523
524         if (create) {
525                 boost::filesystem::create_directories (p);
526         }
527
528         return p;
529 }
530
531 /** Given a file or directory name, return its full path within the Film's directory.
532  *  Any required parent directories will be created.
533  */
534 boost::filesystem::path
535 Film::file (boost::filesystem::path f) const
536 {
537         DCPOMATIC_ASSERT (_directory);
538
539         boost::filesystem::path p;
540         p /= _directory.get();
541         p /= f;
542
543         boost::filesystem::create_directories (p.parent_path ());
544
545         return p;
546 }
547
548 list<int>
549 Film::mapped_audio_channels () const
550 {
551         list<int> mapped;
552
553         if (audio_processor ()) {
554                 /* Processors are mapped 1:1 to DCP outputs so we can work out mappings from there */
555                 for (int i = 0; i < audio_processor()->out_channels(); ++i) {
556                         mapped.push_back (i);
557                 }
558         } else {
559                 BOOST_FOREACH (shared_ptr<Content> i, content ()) {
560                         if (i->audio) {
561                                 list<int> c = i->audio->mapping().mapped_output_channels ();
562                                 copy (c.begin(), c.end(), back_inserter (mapped));
563                         }
564                 }
565
566                 mapped.sort ();
567                 mapped.unique ();
568         }
569
570         return mapped;
571 }
572
573 /** @return a ISDCF-compliant name for a DCP of this film */
574 string
575 Film::isdcf_name (bool if_created_now) const
576 {
577         string d;
578
579         string raw_name = name ();
580
581         /* Split the raw name up into words */
582         vector<string> words;
583         split (words, raw_name, is_any_of (" _-"));
584
585         string fixed_name;
586
587         /* Add each word to fixed_name */
588         for (vector<string>::const_iterator i = words.begin(); i != words.end(); ++i) {
589                 string w = *i;
590
591                 /* First letter is always capitalised */
592                 w[0] = toupper (w[0]);
593
594                 /* Count caps in w */
595                 size_t caps = 0;
596                 for (size_t i = 0; i < w.size(); ++i) {
597                         if (isupper (w[i])) {
598                                 ++caps;
599                         }
600                 }
601
602                 /* If w is all caps make the rest of it lower case, otherwise
603                    leave it alone.
604                 */
605                 if (caps == w.size ()) {
606                         for (size_t i = 1; i < w.size(); ++i) {
607                                 w[i] = tolower (w[i]);
608                         }
609                 }
610
611                 for (size_t i = 0; i < w.size(); ++i) {
612                         fixed_name += w[i];
613                 }
614         }
615
616         if (fixed_name.length() > 14) {
617                 fixed_name = fixed_name.substr (0, 14);
618         }
619
620         d += fixed_name;
621
622         if (dcp_content_type()) {
623                 d += "_" + dcp_content_type()->isdcf_name();
624                 d += "-" + raw_convert<string>(isdcf_metadata().content_version);
625         }
626
627         ISDCFMetadata const dm = isdcf_metadata ();
628
629         if (dm.temp_version) {
630                 d += "-Temp";
631         }
632
633         if (dm.pre_release) {
634                 d += "-Pre";
635         }
636
637         if (dm.red_band) {
638                 d += "-RedBand";
639         }
640
641         if (!dm.chain.empty ()) {
642                 d += "-" + dm.chain;
643         }
644
645         if (three_d ()) {
646                 d += "-3D";
647         }
648
649         if (dm.two_d_version_of_three_d) {
650                 d += "-2D";
651         }
652
653         if (!dm.mastered_luminance.empty ()) {
654                 d += "-" + dm.mastered_luminance;
655         }
656
657         if (video_frame_rate() != 24) {
658                 d += "-" + raw_convert<string>(video_frame_rate());
659         }
660
661         if (container()) {
662                 d += "_" + container()->isdcf_name();
663         }
664
665         /* XXX: this uses the first bit of content only */
666
667         /* The standard says we don't do this for trailers, for some strange reason */
668         if (dcp_content_type() && dcp_content_type()->libdcp_kind() != dcp::TRAILER) {
669                 Ratio const * content_ratio = 0;
670                 BOOST_FOREACH (shared_ptr<Content> i, content ()) {
671                         if (i->video) {
672                                 /* Here's the first piece of video content */
673                                 if (i->video->scale().ratio ()) {
674                                         content_ratio = i->video->scale().ratio ();
675                                 } else {
676                                         content_ratio = Ratio::from_ratio (i->video->size().ratio ());
677                                 }
678                                 break;
679                         }
680                 }
681
682                 if (content_ratio && content_ratio != container()) {
683                         d += "-" + content_ratio->isdcf_name();
684                 }
685         }
686
687         if (!dm.audio_language.empty ()) {
688                 d += "_" + dm.audio_language;
689                 if (!dm.subtitle_language.empty()) {
690
691                         bool burnt_in = true;
692                         BOOST_FOREACH (shared_ptr<Content> i, content ()) {
693                                 if (!i->subtitle) {
694                                         continue;
695                                 }
696
697                                 if (i->subtitle->use() && !i->subtitle->burn()) {
698                                         burnt_in = false;
699                                 }
700                         }
701
702                         string language = dm.subtitle_language;
703                         if (burnt_in && language != "XX") {
704                                 transform (language.begin(), language.end(), language.begin(), ::tolower);
705                         } else {
706                                 transform (language.begin(), language.end(), language.begin(), ::toupper);
707                         }
708
709                         d += "-" + language;
710                 } else {
711                         d += "-XX";
712                 }
713         }
714
715         if (!dm.territory.empty ()) {
716                 d += "_" + dm.territory;
717                 if (dm.rating.empty ()) {
718                         d += "-NR";
719                 } else {
720                         d += "-" + dm.rating;
721                 }
722         }
723
724         /* Count mapped audio channels */
725
726         int non_lfe = 0;
727         int lfe = 0;
728
729         BOOST_FOREACH (int i, mapped_audio_channels ()) {
730                 if (i >= audio_channels()) {
731                         /* This channel is mapped but is not included in the DCP */
732                         continue;
733                 }
734
735                 if (static_cast<dcp::Channel> (i) == dcp::LFE) {
736                         ++lfe;
737                 } else {
738                         ++non_lfe;
739                 }
740         }
741
742         if (non_lfe) {
743                 d += String::compose("_%1%2", non_lfe, lfe);
744         }
745
746         /* XXX: HI/VI */
747
748         d += "_" + resolution_to_string (_resolution);
749
750         if (!dm.studio.empty ()) {
751                 d += "_" + dm.studio;
752         }
753
754         if (if_created_now) {
755                 d += "_" + boost::gregorian::to_iso_string (boost::gregorian::day_clock::local_day ());
756         } else {
757                 d += "_" + boost::gregorian::to_iso_string (_isdcf_date);
758         }
759
760         if (!dm.facility.empty ()) {
761                 d += "_" + dm.facility;
762         }
763
764         if (_interop) {
765                 d += "_IOP";
766         } else {
767                 d += "_SMPTE";
768         }
769
770         if (three_d ()) {
771                 d += "-3D";
772         }
773
774         bool vf = false;
775         BOOST_FOREACH (shared_ptr<Content> i, content ()) {
776                 shared_ptr<const DCPContent> dc = dynamic_pointer_cast<const DCPContent> (i);
777                 if (dc && (dc->reference_video() || dc->reference_audio() || dc->reference_subtitle())) {
778                         vf = true;
779                 }
780         }
781
782         if (vf) {
783                 d += "_VF";
784         } else {
785                 d += "_OV";
786         }
787
788         return d;
789 }
790
791 /** @return name to give the DCP */
792 string
793 Film::dcp_name (bool if_created_now) const
794 {
795         string unfiltered;
796         if (use_isdcf_name()) {
797                 return careful_string_filter (isdcf_name (if_created_now));
798         }
799
800         return careful_string_filter (name ());
801 }
802
803 void
804 Film::set_directory (boost::filesystem::path d)
805 {
806         _directory = d;
807         _dirty = true;
808 }
809
810 void
811 Film::set_name (string n)
812 {
813         _name = n;
814         signal_changed (NAME);
815 }
816
817 void
818 Film::set_use_isdcf_name (bool u)
819 {
820         _use_isdcf_name = u;
821         signal_changed (USE_ISDCF_NAME);
822 }
823
824 void
825 Film::set_dcp_content_type (DCPContentType const * t)
826 {
827         _dcp_content_type = t;
828         signal_changed (DCP_CONTENT_TYPE);
829 }
830
831 void
832 Film::set_container (Ratio const * c)
833 {
834         _container = c;
835         signal_changed (CONTAINER);
836 }
837
838 void
839 Film::set_resolution (Resolution r)
840 {
841         _resolution = r;
842         signal_changed (RESOLUTION);
843 }
844
845 void
846 Film::set_j2k_bandwidth (int b)
847 {
848         _j2k_bandwidth = b;
849         signal_changed (J2K_BANDWIDTH);
850 }
851
852 void
853 Film::set_isdcf_metadata (ISDCFMetadata m)
854 {
855         _isdcf_metadata = m;
856         signal_changed (ISDCF_METADATA);
857 }
858
859 void
860 Film::set_video_frame_rate (int f)
861 {
862         _video_frame_rate = f;
863         signal_changed (VIDEO_FRAME_RATE);
864 }
865
866 void
867 Film::set_audio_channels (int c)
868 {
869         _audio_channels = c;
870         signal_changed (AUDIO_CHANNELS);
871 }
872
873 void
874 Film::set_three_d (bool t)
875 {
876         _three_d = t;
877         signal_changed (THREE_D);
878
879         if (_three_d && _isdcf_metadata.two_d_version_of_three_d) {
880                 _isdcf_metadata.two_d_version_of_three_d = false;
881                 signal_changed (ISDCF_METADATA);
882         }
883 }
884
885 void
886 Film::set_interop (bool i)
887 {
888         _interop = i;
889         signal_changed (INTEROP);
890 }
891
892 void
893 Film::set_audio_processor (AudioProcessor const * processor)
894 {
895         _audio_processor = processor;
896         signal_changed (AUDIO_PROCESSOR);
897         signal_changed (AUDIO_CHANNELS);
898 }
899
900 void
901 Film::set_reel_type (ReelType t)
902 {
903         _reel_type = t;
904         signal_changed (REEL_TYPE);
905 }
906
907 /** @param r Desired reel length in bytes */
908 void
909 Film::set_reel_length (int64_t r)
910 {
911         _reel_length = r;
912         signal_changed (REEL_LENGTH);
913 }
914
915 void
916 Film::set_upload_after_make_dcp (bool u)
917 {
918         _upload_after_make_dcp = u;
919         signal_changed (UPLOAD_AFTER_MAKE_DCP);
920 }
921
922 void
923 Film::signal_changed (Property p)
924 {
925         _dirty = true;
926
927         switch (p) {
928         case Film::CONTENT:
929                 set_video_frame_rate (_playlist->best_video_frame_rate ());
930                 break;
931         case Film::VIDEO_FRAME_RATE:
932         case Film::SEQUENCE:
933                 _playlist->maybe_sequence ();
934                 break;
935         default:
936                 break;
937         }
938
939         emit (boost::bind (boost::ref (Changed), p));
940 }
941
942 void
943 Film::set_isdcf_date_today ()
944 {
945         _isdcf_date = boost::gregorian::day_clock::local_day ();
946 }
947
948 boost::filesystem::path
949 Film::j2c_path (int reel, Frame frame, Eyes eyes, bool tmp) const
950 {
951         boost::filesystem::path p;
952         p /= "j2c";
953         p /= video_identifier ();
954
955         char buffer[256];
956         snprintf(buffer, sizeof(buffer), "%08d_%08" PRId64, reel, frame);
957         string s (buffer);
958
959         if (eyes == EYES_LEFT) {
960                 s += ".L";
961         } else if (eyes == EYES_RIGHT) {
962                 s += ".R";
963         }
964
965         s += ".j2c";
966
967         if (tmp) {
968                 s += ".tmp";
969         }
970
971         p /= s;
972         return file (p);
973 }
974
975 /** Find all the DCPs in our directory that can be dcp::DCP::read() and return details of their CPLs */
976 vector<CPLSummary>
977 Film::cpls () const
978 {
979         if (!directory ()) {
980                 return vector<CPLSummary> ();
981         }
982
983         vector<CPLSummary> out;
984
985         boost::filesystem::path const dir = directory().get();
986         for (boost::filesystem::directory_iterator i = boost::filesystem::directory_iterator(dir); i != boost::filesystem::directory_iterator(); ++i) {
987                 if (
988                         boost::filesystem::is_directory (*i) &&
989                         i->path().leaf() != "j2c" && i->path().leaf() != "video" && i->path().leaf() != "info" && i->path().leaf() != "analysis"
990                         ) {
991
992                         try {
993                                 dcp::DCP dcp (*i);
994                                 dcp.read ();
995                                 DCPOMATIC_ASSERT (dcp.cpls().front()->file());
996                                 out.push_back (
997                                         CPLSummary (
998                                                 i->path().leaf().string(),
999                                                 dcp.cpls().front()->id(),
1000                                                 dcp.cpls().front()->annotation_text(),
1001                                                 dcp.cpls().front()->file().get()
1002                                                 )
1003                                         );
1004                         } catch (...) {
1005
1006                         }
1007                 }
1008         }
1009
1010         return out;
1011 }
1012
1013 void
1014 Film::set_signed (bool s)
1015 {
1016         _signed = s;
1017         signal_changed (SIGNED);
1018 }
1019
1020 void
1021 Film::set_encrypted (bool e)
1022 {
1023         _encrypted = e;
1024         signal_changed (ENCRYPTED);
1025 }
1026
1027 void
1028 Film::set_key (dcp::Key key)
1029 {
1030         _key = key;
1031         signal_changed (KEY);
1032 }
1033
1034 ContentList
1035 Film::content () const
1036 {
1037         return _playlist->content ();
1038 }
1039
1040 void
1041 Film::examine_and_add_content (shared_ptr<Content> c)
1042 {
1043         if (dynamic_pointer_cast<FFmpegContent> (c) && _directory) {
1044                 run_ffprobe (c->path(0), file ("ffprobe.log"), _log);
1045         }
1046
1047         shared_ptr<Job> j (new ExamineContentJob (shared_from_this(), c));
1048
1049         _job_connections.push_back (
1050                 j->Finished.connect (bind (&Film::maybe_add_content, this, weak_ptr<Job> (j), weak_ptr<Content> (c)))
1051                 );
1052
1053         JobManager::instance()->add (j);
1054 }
1055
1056 void
1057 Film::maybe_add_content (weak_ptr<Job> j, weak_ptr<Content> c)
1058 {
1059         shared_ptr<Job> job = j.lock ();
1060         if (!job || !job->finished_ok ()) {
1061                 return;
1062         }
1063
1064         shared_ptr<Content> content = c.lock ();
1065         if (!content) {
1066                 return;
1067         }
1068
1069         add_content (content);
1070
1071         if (Config::instance()->automatic_audio_analysis() && content->audio) {
1072                 shared_ptr<Playlist> playlist (new Playlist);
1073                 playlist->add (content);
1074                 boost::signals2::connection c;
1075                 JobManager::instance()->analyse_audio (
1076                         shared_from_this (), playlist, c, bind (&Film::audio_analysis_finished, this)
1077                         );
1078                 _audio_analysis_connections.push_back (c);
1079         }
1080 }
1081
1082 void
1083 Film::add_content (shared_ptr<Content> c)
1084 {
1085         /* Add {video,subtitle} content after any existing {video,subtitle} content */
1086         if (c->video) {
1087                 c->set_position (_playlist->video_end ());
1088         } else if (c->subtitle) {
1089                 c->set_position (_playlist->subtitle_end ());
1090         }
1091
1092         if (_template_film) {
1093                 /* Take settings from the first piece of content of c's type in _template */
1094                 BOOST_FOREACH (shared_ptr<Content> i, _template_film->content()) {
1095                         if (typeid(i.get()) == typeid(c.get())) {
1096                                 c->use_template (i);
1097                         }
1098                 }
1099         }
1100
1101         _playlist->add (c);
1102 }
1103
1104 void
1105 Film::remove_content (shared_ptr<Content> c)
1106 {
1107         _playlist->remove (c);
1108 }
1109
1110 void
1111 Film::move_content_earlier (shared_ptr<Content> c)
1112 {
1113         _playlist->move_earlier (c);
1114 }
1115
1116 void
1117 Film::move_content_later (shared_ptr<Content> c)
1118 {
1119         _playlist->move_later (c);
1120 }
1121
1122 /** @return length of the film from time 0 to the last thing on the playlist */
1123 DCPTime
1124 Film::length () const
1125 {
1126         return _playlist->length ();
1127 }
1128
1129 int
1130 Film::best_video_frame_rate () const
1131 {
1132         return _playlist->best_video_frame_rate ();
1133 }
1134
1135 FrameRateChange
1136 Film::active_frame_rate_change (DCPTime t) const
1137 {
1138         return _playlist->active_frame_rate_change (t, video_frame_rate ());
1139 }
1140
1141 void
1142 Film::playlist_content_changed (weak_ptr<Content> c, int p, bool frequent)
1143 {
1144         _dirty = true;
1145
1146         if (p == ContentProperty::VIDEO_FRAME_RATE) {
1147                 set_video_frame_rate (_playlist->best_video_frame_rate ());
1148         } else if (p == AudioContentProperty::STREAMS) {
1149                 signal_changed (NAME);
1150         }
1151
1152         emit (boost::bind (boost::ref (ContentChanged), c, p, frequent));
1153 }
1154
1155 void
1156 Film::playlist_changed ()
1157 {
1158         signal_changed (CONTENT);
1159         signal_changed (NAME);
1160 }
1161
1162 void
1163 Film::playlist_order_changed ()
1164 {
1165         signal_changed (CONTENT_ORDER);
1166 }
1167
1168 int
1169 Film::audio_frame_rate () const
1170 {
1171         BOOST_FOREACH (shared_ptr<Content> i, content ()) {
1172                 if (i->audio && i->audio->has_rate_above_48k ()) {
1173                         return 96000;
1174                 }
1175         }
1176
1177         return 48000;
1178 }
1179
1180 void
1181 Film::set_sequence (bool s)
1182 {
1183         _sequence = s;
1184         _playlist->set_sequence (s);
1185         signal_changed (SEQUENCE);
1186 }
1187
1188 /** @return Size of the largest possible image in whatever resolution we are using */
1189 dcp::Size
1190 Film::full_frame () const
1191 {
1192         switch (_resolution) {
1193         case RESOLUTION_2K:
1194                 return dcp::Size (2048, 1080);
1195         case RESOLUTION_4K:
1196                 return dcp::Size (4096, 2160);
1197         }
1198
1199         DCPOMATIC_ASSERT (false);
1200         return dcp::Size ();
1201 }
1202
1203 /** @return Size of the frame */
1204 dcp::Size
1205 Film::frame_size () const
1206 {
1207         return fit_ratio_within (container()->ratio(), full_frame ());
1208 }
1209
1210 /** @param from KDM from time expressed as a local time with an offset from UTC
1211  *  @param to KDM to time expressed as a local time with an offset from UTC
1212  */
1213 dcp::EncryptedKDM
1214 Film::make_kdm (
1215         dcp::Certificate recipient,
1216         vector<dcp::Certificate> trusted_devices,
1217         boost::filesystem::path cpl_file,
1218         dcp::LocalTime from,
1219         dcp::LocalTime until,
1220         dcp::Formulation formulation
1221         ) const
1222 {
1223         shared_ptr<const dcp::CPL> cpl (new dcp::CPL (cpl_file));
1224         shared_ptr<const dcp::CertificateChain> signer = Config::instance()->signer_chain ();
1225         if (!signer->valid ()) {
1226                 throw InvalidSignerError ();
1227         }
1228
1229         /* Find keys that have been added to imported, encrypted DCP content */
1230         list<dcp::DecryptedKDMKey> imported_keys;
1231         BOOST_FOREACH (shared_ptr<Content> i, content()) {
1232                 shared_ptr<DCPContent> d = dynamic_pointer_cast<DCPContent> (i);
1233                 if (d && d->kdm()) {
1234                         dcp::DecryptedKDM kdm (d->kdm().get(), Config::instance()->decryption_chain()->key().get());
1235                         list<dcp::DecryptedKDMKey> keys = kdm.keys ();
1236                         copy (keys.begin(), keys.end(), back_inserter (imported_keys));
1237                 }
1238         }
1239
1240         map<shared_ptr<const dcp::ReelMXF>, dcp::Key> keys;
1241
1242         BOOST_FOREACH(shared_ptr<const dcp::ReelAsset> i, cpl->reel_assets ()) {
1243                 shared_ptr<const dcp::ReelMXF> mxf = boost::dynamic_pointer_cast<const dcp::ReelMXF> (i);
1244                 if (!mxf || !mxf->key_id()) {
1245                         continue;
1246                 }
1247
1248                 /* Get any imported key for this ID */
1249                 bool done = false;
1250                 BOOST_FOREACH (dcp::DecryptedKDMKey j, imported_keys) {
1251                         if (j.id() == mxf->key_id().get()) {
1252                                 LOG_GENERAL ("Using imported key for %1", mxf->key_id().get());
1253                                 keys[mxf] = j.key();
1254                                 done = true;
1255                         }
1256                 }
1257
1258                 if (!done) {
1259                         /* No imported key; it must be an asset that we encrypted */
1260                         LOG_GENERAL ("Using our own key for %1", mxf->key_id().get());
1261                         keys[mxf] = key();
1262                 }
1263         }
1264
1265         return dcp::DecryptedKDM (
1266                 cpl->id(), keys, from, until, cpl->content_title_text(), cpl->content_title_text(), dcp::LocalTime().as_string()
1267                 ).encrypt (signer, recipient, trusted_devices, formulation);
1268 }
1269
1270 /** @param from KDM from time expressed as a local time in the time zone of the Screen's Cinema.
1271  *  @param to KDM to time expressed as a local time in the time zone of the Screen's Cinema.
1272  */
1273 list<ScreenKDM>
1274 Film::make_kdms (
1275         list<shared_ptr<Screen> > screens,
1276         boost::filesystem::path dcp,
1277         boost::posix_time::ptime from,
1278         boost::posix_time::ptime until,
1279         dcp::Formulation formulation
1280         ) const
1281 {
1282         list<ScreenKDM> kdms;
1283
1284         BOOST_FOREACH (shared_ptr<Screen> i, screens) {
1285                 if (i->recipient) {
1286                         dcp::EncryptedKDM const kdm = make_kdm (
1287                                 i->recipient.get(),
1288                                 i->trusted_devices,
1289                                 dcp,
1290                                 dcp::LocalTime (from, i->cinema->utc_offset_hour(), i->cinema->utc_offset_minute()),
1291                                 dcp::LocalTime (until, i->cinema->utc_offset_hour(), i->cinema->utc_offset_minute()),
1292                                 formulation
1293                                 );
1294
1295                         kdms.push_back (ScreenKDM (i, kdm));
1296                 }
1297         }
1298
1299         return kdms;
1300 }
1301
1302 /** @return The approximate disk space required to encode a DCP of this film with the
1303  *  current settings, in bytes.
1304  */
1305 uint64_t
1306 Film::required_disk_space () const
1307 {
1308         return _playlist->required_disk_space (j2k_bandwidth(), audio_channels(), audio_frame_rate());
1309 }
1310
1311 /** This method checks the disk that the Film is on and tries to decide whether or not
1312  *  there will be enough space to make a DCP for it.  If so, true is returned; if not,
1313  *  false is returned and required and available are filled in with the amount of disk space
1314  *  required and available respectively (in Gb).
1315  *
1316  *  Note: the decision made by this method isn't, of course, 100% reliable.
1317  */
1318 bool
1319 Film::should_be_enough_disk_space (double& required, double& available, bool& can_hard_link) const
1320 {
1321         /* Create a test file and see if we can hard-link it */
1322         boost::filesystem::path test = internal_video_asset_dir() / "test";
1323         boost::filesystem::path test2 = internal_video_asset_dir() / "test2";
1324         can_hard_link = true;
1325         FILE* f = fopen_boost (test, "w");
1326         if (f) {
1327                 fclose (f);
1328                 boost::system::error_code ec;
1329                 boost::filesystem::create_hard_link (test, test2, ec);
1330                 if (ec) {
1331                         can_hard_link = false;
1332                 }
1333                 boost::filesystem::remove (test);
1334                 boost::filesystem::remove (test2);
1335         }
1336
1337         boost::filesystem::space_info s = boost::filesystem::space (internal_video_asset_dir ());
1338         required = double (required_disk_space ()) / 1073741824.0f;
1339         if (!can_hard_link) {
1340                 required *= 2;
1341         }
1342         available = double (s.available) / 1073741824.0f;
1343         return (available - required) > 1;
1344 }
1345
1346 string
1347 Film::subtitle_language () const
1348 {
1349         set<string> languages;
1350
1351         ContentList cl = content ();
1352         BOOST_FOREACH (shared_ptr<Content>& c, cl) {
1353                 if (c->subtitle) {
1354                         languages.insert (c->subtitle->language ());
1355                 }
1356         }
1357
1358         string all;
1359         BOOST_FOREACH (string s, languages) {
1360                 if (!all.empty ()) {
1361                         all += "/" + s;
1362                 } else {
1363                         all += s;
1364                 }
1365         }
1366
1367         return all;
1368 }
1369
1370 /** Change the gains of the supplied AudioMapping to make it a default
1371  *  for this film.  The defaults are guessed based on what processor (if any)
1372  *  is in use, the number of input channels and any filename supplied.
1373  */
1374 void
1375 Film::make_audio_mapping_default (AudioMapping& mapping, optional<boost::filesystem::path> filename) const
1376 {
1377         static string const regex[] = {
1378                 ".*[\\._-]L[\\._-].*",
1379                 ".*[\\._-]R[\\._-].*",
1380                 ".*[\\._-]C[\\._-].*",
1381                 ".*[\\._-]Lfe[\\._-].*",
1382                 ".*[\\._-]Ls[\\._-].*",
1383                 ".*[\\._-]Rs[\\._-].*"
1384         };
1385
1386         static int const regexes = sizeof(regex) / sizeof(*regex);
1387
1388         if (audio_processor ()) {
1389                 audio_processor()->make_audio_mapping_default (mapping);
1390         } else {
1391                 mapping.make_zero ();
1392                 if (mapping.input_channels() == 1) {
1393                         bool guessed = false;
1394
1395                         /* See if we can guess where this stream should go */
1396                         if (filename) {
1397                                 for (int i = 0; i < regexes; ++i) {
1398                                         boost::regex e (regex[i], boost::regex::icase);
1399                                         if (boost::regex_match (filename->string(), e) && i < mapping.output_channels()) {
1400                                                 mapping.set (0, i, 1);
1401                                                 guessed = true;
1402                                         }
1403                                 }
1404                         }
1405
1406                         if (!guessed) {
1407                                 /* If we have no idea, just put it on centre */
1408                                 mapping.set (0, static_cast<int> (dcp::CENTRE), 1);
1409                         }
1410                 } else {
1411                         /* 1:1 mapping */
1412                         for (int i = 0; i < min (mapping.input_channels(), mapping.output_channels()); ++i) {
1413                                 mapping.set (i, i, 1);
1414                         }
1415                 }
1416         }
1417 }
1418
1419 /** @return The names of the channels that audio contents' outputs are passed into;
1420  *  this is either the DCP or a AudioProcessor.
1421  */
1422 vector<string>
1423 Film::audio_output_names () const
1424 {
1425         if (audio_processor ()) {
1426                 return audio_processor()->input_names ();
1427         }
1428
1429         DCPOMATIC_ASSERT (MAX_DCP_AUDIO_CHANNELS == 16);
1430
1431         vector<string> n;
1432
1433         for (int i = 0; i < audio_channels(); ++i) {
1434                 n.push_back (short_audio_channel_name (i));
1435         }
1436
1437         return n;
1438 }
1439
1440 void
1441 Film::repeat_content (ContentList c, int n)
1442 {
1443         _playlist->repeat (c, n);
1444 }
1445
1446 void
1447 Film::remove_content (ContentList c)
1448 {
1449         _playlist->remove (c);
1450 }
1451
1452 void
1453 Film::audio_analysis_finished ()
1454 {
1455         /* XXX */
1456 }
1457
1458 list<DCPTimePeriod>
1459 Film::reels () const
1460 {
1461         list<DCPTimePeriod> p;
1462         DCPTime const len = length().ceil (video_frame_rate ());
1463
1464         switch (reel_type ()) {
1465         case REELTYPE_SINGLE:
1466                 p.push_back (DCPTimePeriod (DCPTime (), len));
1467                 break;
1468         case REELTYPE_BY_VIDEO_CONTENT:
1469         {
1470                 optional<DCPTime> last_split;
1471                 shared_ptr<Content> last_video;
1472                 BOOST_FOREACH (shared_ptr<Content> c, content ()) {
1473                         if (c->video) {
1474                                 BOOST_FOREACH (DCPTime t, c->reel_split_points()) {
1475                                         if (last_split) {
1476                                                 p.push_back (DCPTimePeriod (last_split.get(), t));
1477                                         }
1478                                         last_split = t;
1479                                 }
1480                                 last_video = c;
1481                         }
1482                 }
1483
1484                 DCPTime video_end = last_video ? last_video->end() : DCPTime(0);
1485                 if (last_split) {
1486                         /* Definitely go from the last split to the end of the video content */
1487                         p.push_back (DCPTimePeriod (last_split.get(), video_end));
1488                 }
1489
1490                 if (video_end < len) {
1491                         /* And maybe go after that as well if there is any non-video hanging over the end */
1492                         p.push_back (DCPTimePeriod (video_end, len));
1493                 }
1494                 break;
1495         }
1496         case REELTYPE_BY_LENGTH:
1497         {
1498                 DCPTime current;
1499                 /* Integer-divide reel length by the size of one frame to give the number of frames per reel */
1500                 Frame const reel_in_frames = _reel_length / ((j2k_bandwidth() / video_frame_rate()) / 8);
1501                 while (current < len) {
1502                         DCPTime end = min (len, current + DCPTime::from_frames (reel_in_frames, video_frame_rate ()));
1503                         p.push_back (DCPTimePeriod (current, end));
1504                         current = end;
1505                 }
1506                 break;
1507         }
1508         }
1509
1510         return p;
1511 }
1512
1513 string
1514 Film::content_summary (DCPTimePeriod period) const
1515 {
1516         return _playlist->content_summary (period);
1517 }
1518
1519 list<string>
1520 Film::fix_conflicting_settings ()
1521 {
1522         list<string> notes;
1523
1524         list<boost::filesystem::path> was_referencing;
1525         BOOST_FOREACH (shared_ptr<Content> i, content()) {
1526                 shared_ptr<DCPContent> d = dynamic_pointer_cast<DCPContent> (i);
1527                 if (d) {
1528                         list<string> reasons;
1529                         bool was = false;
1530                         if (!d->can_reference_video(reasons) && d->reference_video()) {
1531                                 d->set_reference_video (false);
1532                                 was = true;
1533                         }
1534                         if (!d->can_reference_audio(reasons) && d->reference_audio()) {
1535                                 d->set_reference_audio (false);
1536                                 was = true;
1537                         }
1538                         if (!d->can_reference_subtitle(reasons) && d->reference_subtitle()) {
1539                                 d->set_reference_subtitle (false);
1540                                 was = true;
1541                         }
1542                         if (was) {
1543                                 was_referencing.push_back (d->path(0).parent_path().filename());
1544                         }
1545                 }
1546         }
1547
1548         BOOST_FOREACH (boost::filesystem::path d, was_referencing) {
1549                 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()));
1550         }
1551
1552         return notes;
1553 }
1554
1555 void
1556 Film::use_template (string name)
1557 {
1558         _template_film.reset (new Film (optional<boost::filesystem::path>()));
1559         _template_film->read_metadata (Config::instance()->template_path (name));
1560         _use_isdcf_name = _template_film->_use_isdcf_name;
1561         _dcp_content_type = _template_film->_dcp_content_type;
1562         _container = _template_film->_container;
1563         _resolution = _template_film->_resolution;
1564         _j2k_bandwidth = _template_film->_j2k_bandwidth;
1565         _video_frame_rate = _template_film->_video_frame_rate;
1566         _signed = _template_film->_signed;
1567         _encrypted = _template_film->_encrypted;
1568         _audio_channels = _template_film->_audio_channels;
1569         _sequence = _template_film->_sequence;
1570         _three_d = _template_film->_three_d;
1571         _interop = _template_film->_interop;
1572         _audio_processor = _template_film->_audio_processor;
1573         _reel_type = _template_film->_reel_type;
1574         _reel_length = _template_film->_reel_length;
1575         _upload_after_make_dcp = _template_film->_upload_after_make_dcp;
1576 }