Be more careful about allowing possibly-trouble-causing characters in DCP filenames.
[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  *  The directory (and its parents) will be created if they do not exist.
513  */
514 boost::filesystem::path
515 Film::dir (boost::filesystem::path d) const
516 {
517         DCPOMATIC_ASSERT (_directory);
518
519         boost::filesystem::path p;
520         p /= _directory.get();
521         p /= d;
522
523         boost::filesystem::create_directories (p);
524
525         return p;
526 }
527
528 /** Given a file or directory name, return its full path within the Film's directory.
529  *  Any required parent directories will be created.
530  */
531 boost::filesystem::path
532 Film::file (boost::filesystem::path f) const
533 {
534         DCPOMATIC_ASSERT (_directory);
535
536         boost::filesystem::path p;
537         p /= _directory.get();
538         p /= f;
539
540         boost::filesystem::create_directories (p.parent_path ());
541
542         return p;
543 }
544
545 list<int>
546 Film::mapped_audio_channels () const
547 {
548         list<int> mapped;
549
550         if (audio_processor ()) {
551                 /* Processors are mapped 1:1 to DCP outputs so we can work out mappings from there */
552                 for (int i = 0; i < audio_processor()->out_channels(); ++i) {
553                         mapped.push_back (i);
554                 }
555         } else {
556                 BOOST_FOREACH (shared_ptr<Content> i, content ()) {
557                         if (i->audio) {
558                                 list<int> c = i->audio->mapping().mapped_output_channels ();
559                                 copy (c.begin(), c.end(), back_inserter (mapped));
560                         }
561                 }
562
563                 mapped.sort ();
564                 mapped.unique ();
565         }
566
567         return mapped;
568 }
569
570 /** @return a ISDCF-compliant name for a DCP of this film */
571 string
572 Film::isdcf_name (bool if_created_now) const
573 {
574         string d;
575
576         string raw_name = name ();
577
578         /* Split the raw name up into words */
579         vector<string> words;
580         split (words, raw_name, is_any_of (" _-"));
581
582         string fixed_name;
583
584         /* Add each word to fixed_name */
585         for (vector<string>::const_iterator i = words.begin(); i != words.end(); ++i) {
586                 string w = *i;
587
588                 /* First letter is always capitalised */
589                 w[0] = toupper (w[0]);
590
591                 /* Count caps in w */
592                 size_t caps = 0;
593                 for (size_t i = 0; i < w.size(); ++i) {
594                         if (isupper (w[i])) {
595                                 ++caps;
596                         }
597                 }
598
599                 /* If w is all caps make the rest of it lower case, otherwise
600                    leave it alone.
601                 */
602                 if (caps == w.size ()) {
603                         for (size_t i = 1; i < w.size(); ++i) {
604                                 w[i] = tolower (w[i]);
605                         }
606                 }
607
608                 for (size_t i = 0; i < w.size(); ++i) {
609                         fixed_name += w[i];
610                 }
611         }
612
613         if (fixed_name.length() > 14) {
614                 fixed_name = fixed_name.substr (0, 14);
615         }
616
617         d += fixed_name;
618
619         if (dcp_content_type()) {
620                 d += "_" + dcp_content_type()->isdcf_name();
621                 d += "-" + raw_convert<string>(isdcf_metadata().content_version);
622         }
623
624         ISDCFMetadata const dm = isdcf_metadata ();
625
626         if (dm.temp_version) {
627                 d += "-Temp";
628         }
629
630         if (dm.pre_release) {
631                 d += "-Pre";
632         }
633
634         if (dm.red_band) {
635                 d += "-RedBand";
636         }
637
638         if (!dm.chain.empty ()) {
639                 d += "-" + dm.chain;
640         }
641
642         if (three_d ()) {
643                 d += "-3D";
644         }
645
646         if (dm.two_d_version_of_three_d) {
647                 d += "-2D";
648         }
649
650         if (!dm.mastered_luminance.empty ()) {
651                 d += "-" + dm.mastered_luminance;
652         }
653
654         if (video_frame_rate() != 24) {
655                 d += "-" + raw_convert<string>(video_frame_rate());
656         }
657
658         if (container()) {
659                 d += "_" + container()->isdcf_name();
660         }
661
662         /* XXX: this uses the first bit of content only */
663
664         /* The standard says we don't do this for trailers, for some strange reason */
665         if (dcp_content_type() && dcp_content_type()->libdcp_kind() != dcp::TRAILER) {
666                 Ratio const * content_ratio = 0;
667                 BOOST_FOREACH (shared_ptr<Content> i, content ()) {
668                         if (i->video) {
669                                 /* Here's the first piece of video content */
670                                 if (i->video->scale().ratio ()) {
671                                         content_ratio = i->video->scale().ratio ();
672                                 } else {
673                                         content_ratio = Ratio::from_ratio (i->video->size().ratio ());
674                                 }
675                                 break;
676                         }
677                 }
678
679                 if (content_ratio && content_ratio != container()) {
680                         d += "-" + content_ratio->isdcf_name();
681                 }
682         }
683
684         if (!dm.audio_language.empty ()) {
685                 d += "_" + dm.audio_language;
686                 if (!dm.subtitle_language.empty()) {
687
688                         bool burnt_in = true;
689                         BOOST_FOREACH (shared_ptr<Content> i, content ()) {
690                                 if (!i->subtitle) {
691                                         continue;
692                                 }
693
694                                 if (i->subtitle->use() && !i->subtitle->burn()) {
695                                         burnt_in = false;
696                                 }
697                         }
698
699                         string language = dm.subtitle_language;
700                         if (burnt_in && language != "XX") {
701                                 transform (language.begin(), language.end(), language.begin(), ::tolower);
702                         } else {
703                                 transform (language.begin(), language.end(), language.begin(), ::toupper);
704                         }
705
706                         d += "-" + language;
707                 } else {
708                         d += "-XX";
709                 }
710         }
711
712         if (!dm.territory.empty ()) {
713                 d += "_" + dm.territory;
714                 if (dm.rating.empty ()) {
715                         d += "-NR";
716                 } else {
717                         d += "-" + dm.rating;
718                 }
719         }
720
721         /* Count mapped audio channels */
722
723         int non_lfe = 0;
724         int lfe = 0;
725
726         BOOST_FOREACH (int i, mapped_audio_channels ()) {
727                 if (i >= audio_channels()) {
728                         /* This channel is mapped but is not included in the DCP */
729                         continue;
730                 }
731
732                 if (static_cast<dcp::Channel> (i) == dcp::LFE) {
733                         ++lfe;
734                 } else {
735                         ++non_lfe;
736                 }
737         }
738
739         if (non_lfe) {
740                 d += String::compose("_%1%2", non_lfe, lfe);
741         }
742
743         /* XXX: HI/VI */
744
745         d += "_" + resolution_to_string (_resolution);
746
747         if (!dm.studio.empty ()) {
748                 d += "_" + dm.studio;
749         }
750
751         if (if_created_now) {
752                 d += "_" + boost::gregorian::to_iso_string (boost::gregorian::day_clock::local_day ());
753         } else {
754                 d += "_" + boost::gregorian::to_iso_string (_isdcf_date);
755         }
756
757         if (!dm.facility.empty ()) {
758                 d += "_" + dm.facility;
759         }
760
761         if (_interop) {
762                 d += "_IOP";
763         } else {
764                 d += "_SMPTE";
765         }
766
767         if (three_d ()) {
768                 d += "-3D";
769         }
770
771         bool vf = false;
772         BOOST_FOREACH (shared_ptr<Content> i, content ()) {
773                 shared_ptr<const DCPContent> dc = dynamic_pointer_cast<const DCPContent> (i);
774                 if (dc && (dc->reference_video() || dc->reference_audio() || dc->reference_subtitle())) {
775                         vf = true;
776                 }
777         }
778
779         if (vf) {
780                 d += "_VF";
781         } else {
782                 d += "_OV";
783         }
784
785         return d;
786 }
787
788 /** @return name to give the DCP */
789 string
790 Film::dcp_name (bool if_created_now) const
791 {
792         string unfiltered;
793         if (use_isdcf_name()) {
794                 return careful_string_filter (isdcf_name (if_created_now));
795         }
796
797         return careful_string_filter (name ());
798 }
799
800 void
801 Film::set_directory (boost::filesystem::path d)
802 {
803         _directory = d;
804         _dirty = true;
805 }
806
807 void
808 Film::set_name (string n)
809 {
810         _name = n;
811         signal_changed (NAME);
812 }
813
814 void
815 Film::set_use_isdcf_name (bool u)
816 {
817         _use_isdcf_name = u;
818         signal_changed (USE_ISDCF_NAME);
819 }
820
821 void
822 Film::set_dcp_content_type (DCPContentType const * t)
823 {
824         _dcp_content_type = t;
825         signal_changed (DCP_CONTENT_TYPE);
826 }
827
828 void
829 Film::set_container (Ratio const * c)
830 {
831         _container = c;
832         signal_changed (CONTAINER);
833 }
834
835 void
836 Film::set_resolution (Resolution r)
837 {
838         _resolution = r;
839         signal_changed (RESOLUTION);
840 }
841
842 void
843 Film::set_j2k_bandwidth (int b)
844 {
845         _j2k_bandwidth = b;
846         signal_changed (J2K_BANDWIDTH);
847 }
848
849 void
850 Film::set_isdcf_metadata (ISDCFMetadata m)
851 {
852         _isdcf_metadata = m;
853         signal_changed (ISDCF_METADATA);
854 }
855
856 void
857 Film::set_video_frame_rate (int f)
858 {
859         _video_frame_rate = f;
860         signal_changed (VIDEO_FRAME_RATE);
861 }
862
863 void
864 Film::set_audio_channels (int c)
865 {
866         _audio_channels = c;
867         signal_changed (AUDIO_CHANNELS);
868 }
869
870 void
871 Film::set_three_d (bool t)
872 {
873         _three_d = t;
874         signal_changed (THREE_D);
875
876         if (_three_d && _isdcf_metadata.two_d_version_of_three_d) {
877                 _isdcf_metadata.two_d_version_of_three_d = false;
878                 signal_changed (ISDCF_METADATA);
879         }
880 }
881
882 void
883 Film::set_interop (bool i)
884 {
885         _interop = i;
886         signal_changed (INTEROP);
887 }
888
889 void
890 Film::set_audio_processor (AudioProcessor const * processor)
891 {
892         _audio_processor = processor;
893         signal_changed (AUDIO_PROCESSOR);
894         signal_changed (AUDIO_CHANNELS);
895 }
896
897 void
898 Film::set_reel_type (ReelType t)
899 {
900         _reel_type = t;
901         signal_changed (REEL_TYPE);
902 }
903
904 /** @param r Desired reel length in bytes */
905 void
906 Film::set_reel_length (int64_t r)
907 {
908         _reel_length = r;
909         signal_changed (REEL_LENGTH);
910 }
911
912 void
913 Film::set_upload_after_make_dcp (bool u)
914 {
915         _upload_after_make_dcp = u;
916         signal_changed (UPLOAD_AFTER_MAKE_DCP);
917 }
918
919 void
920 Film::signal_changed (Property p)
921 {
922         _dirty = true;
923
924         switch (p) {
925         case Film::CONTENT:
926                 set_video_frame_rate (_playlist->best_video_frame_rate ());
927                 break;
928         case Film::VIDEO_FRAME_RATE:
929         case Film::SEQUENCE:
930                 _playlist->maybe_sequence ();
931                 break;
932         default:
933                 break;
934         }
935
936         emit (boost::bind (boost::ref (Changed), p));
937 }
938
939 void
940 Film::set_isdcf_date_today ()
941 {
942         _isdcf_date = boost::gregorian::day_clock::local_day ();
943 }
944
945 boost::filesystem::path
946 Film::j2c_path (int reel, Frame frame, Eyes eyes, bool tmp) const
947 {
948         boost::filesystem::path p;
949         p /= "j2c";
950         p /= video_identifier ();
951
952         char buffer[256];
953         snprintf(buffer, sizeof(buffer), "%08d_%08" PRId64, reel, frame);
954         string s (buffer);
955
956         if (eyes == EYES_LEFT) {
957                 s += ".L";
958         } else if (eyes == EYES_RIGHT) {
959                 s += ".R";
960         }
961
962         s += ".j2c";
963
964         if (tmp) {
965                 s += ".tmp";
966         }
967
968         p /= s;
969         return file (p);
970 }
971
972 /** Find all the DCPs in our directory that can be dcp::DCP::read() and return details of their CPLs */
973 vector<CPLSummary>
974 Film::cpls () const
975 {
976         if (!directory ()) {
977                 return vector<CPLSummary> ();
978         }
979
980         vector<CPLSummary> out;
981
982         boost::filesystem::path const dir = directory().get();
983         for (boost::filesystem::directory_iterator i = boost::filesystem::directory_iterator(dir); i != boost::filesystem::directory_iterator(); ++i) {
984                 if (
985                         boost::filesystem::is_directory (*i) &&
986                         i->path().leaf() != "j2c" && i->path().leaf() != "video" && i->path().leaf() != "info" && i->path().leaf() != "analysis"
987                         ) {
988
989                         try {
990                                 dcp::DCP dcp (*i);
991                                 dcp.read ();
992                                 DCPOMATIC_ASSERT (dcp.cpls().front()->file());
993                                 out.push_back (
994                                         CPLSummary (
995                                                 i->path().leaf().string(),
996                                                 dcp.cpls().front()->id(),
997                                                 dcp.cpls().front()->annotation_text(),
998                                                 dcp.cpls().front()->file().get()
999                                                 )
1000                                         );
1001                         } catch (...) {
1002
1003                         }
1004                 }
1005         }
1006
1007         return out;
1008 }
1009
1010 void
1011 Film::set_signed (bool s)
1012 {
1013         _signed = s;
1014         signal_changed (SIGNED);
1015 }
1016
1017 void
1018 Film::set_encrypted (bool e)
1019 {
1020         _encrypted = e;
1021         signal_changed (ENCRYPTED);
1022 }
1023
1024 void
1025 Film::set_key (dcp::Key key)
1026 {
1027         _key = key;
1028         signal_changed (KEY);
1029 }
1030
1031 ContentList
1032 Film::content () const
1033 {
1034         return _playlist->content ();
1035 }
1036
1037 void
1038 Film::examine_and_add_content (shared_ptr<Content> c)
1039 {
1040         if (dynamic_pointer_cast<FFmpegContent> (c) && _directory) {
1041                 run_ffprobe (c->path(0), file ("ffprobe.log"), _log);
1042         }
1043
1044         shared_ptr<Job> j (new ExamineContentJob (shared_from_this(), c));
1045
1046         _job_connections.push_back (
1047                 j->Finished.connect (bind (&Film::maybe_add_content, this, weak_ptr<Job> (j), weak_ptr<Content> (c)))
1048                 );
1049
1050         JobManager::instance()->add (j);
1051 }
1052
1053 void
1054 Film::maybe_add_content (weak_ptr<Job> j, weak_ptr<Content> c)
1055 {
1056         shared_ptr<Job> job = j.lock ();
1057         if (!job || !job->finished_ok ()) {
1058                 return;
1059         }
1060
1061         shared_ptr<Content> content = c.lock ();
1062         if (!content) {
1063                 return;
1064         }
1065
1066         add_content (content);
1067
1068         if (Config::instance()->automatic_audio_analysis() && content->audio) {
1069                 shared_ptr<Playlist> playlist (new Playlist);
1070                 playlist->add (content);
1071                 boost::signals2::connection c;
1072                 JobManager::instance()->analyse_audio (
1073                         shared_from_this (), playlist, c, bind (&Film::audio_analysis_finished, this)
1074                         );
1075                 _audio_analysis_connections.push_back (c);
1076         }
1077 }
1078
1079 void
1080 Film::add_content (shared_ptr<Content> c)
1081 {
1082         /* Add {video,subtitle} content after any existing {video,subtitle} content */
1083         if (c->video) {
1084                 c->set_position (_playlist->video_end ());
1085         } else if (c->subtitle) {
1086                 c->set_position (_playlist->subtitle_end ());
1087         }
1088
1089         if (_template_film) {
1090                 /* Take settings from the first piece of content of c's type in _template */
1091                 BOOST_FOREACH (shared_ptr<Content> i, _template_film->content()) {
1092                         if (typeid(i.get()) == typeid(c.get())) {
1093                                 c->use_template (i);
1094                         }
1095                 }
1096         }
1097
1098         _playlist->add (c);
1099 }
1100
1101 void
1102 Film::remove_content (shared_ptr<Content> c)
1103 {
1104         _playlist->remove (c);
1105 }
1106
1107 void
1108 Film::move_content_earlier (shared_ptr<Content> c)
1109 {
1110         _playlist->move_earlier (c);
1111 }
1112
1113 void
1114 Film::move_content_later (shared_ptr<Content> c)
1115 {
1116         _playlist->move_later (c);
1117 }
1118
1119 /** @return length of the film from time 0 to the last thing on the playlist */
1120 DCPTime
1121 Film::length () const
1122 {
1123         return _playlist->length ();
1124 }
1125
1126 int
1127 Film::best_video_frame_rate () const
1128 {
1129         return _playlist->best_video_frame_rate ();
1130 }
1131
1132 FrameRateChange
1133 Film::active_frame_rate_change (DCPTime t) const
1134 {
1135         return _playlist->active_frame_rate_change (t, video_frame_rate ());
1136 }
1137
1138 void
1139 Film::playlist_content_changed (weak_ptr<Content> c, int p, bool frequent)
1140 {
1141         _dirty = true;
1142
1143         if (p == ContentProperty::VIDEO_FRAME_RATE) {
1144                 set_video_frame_rate (_playlist->best_video_frame_rate ());
1145         } else if (p == AudioContentProperty::STREAMS) {
1146                 signal_changed (NAME);
1147         }
1148
1149         emit (boost::bind (boost::ref (ContentChanged), c, p, frequent));
1150 }
1151
1152 void
1153 Film::playlist_changed ()
1154 {
1155         signal_changed (CONTENT);
1156         signal_changed (NAME);
1157 }
1158
1159 void
1160 Film::playlist_order_changed ()
1161 {
1162         signal_changed (CONTENT_ORDER);
1163 }
1164
1165 int
1166 Film::audio_frame_rate () const
1167 {
1168         BOOST_FOREACH (shared_ptr<Content> i, content ()) {
1169                 if (i->audio && i->audio->has_rate_above_48k ()) {
1170                         return 96000;
1171                 }
1172         }
1173
1174         return 48000;
1175 }
1176
1177 void
1178 Film::set_sequence (bool s)
1179 {
1180         _sequence = s;
1181         _playlist->set_sequence (s);
1182         signal_changed (SEQUENCE);
1183 }
1184
1185 /** @return Size of the largest possible image in whatever resolution we are using */
1186 dcp::Size
1187 Film::full_frame () const
1188 {
1189         switch (_resolution) {
1190         case RESOLUTION_2K:
1191                 return dcp::Size (2048, 1080);
1192         case RESOLUTION_4K:
1193                 return dcp::Size (4096, 2160);
1194         }
1195
1196         DCPOMATIC_ASSERT (false);
1197         return dcp::Size ();
1198 }
1199
1200 /** @return Size of the frame */
1201 dcp::Size
1202 Film::frame_size () const
1203 {
1204         return fit_ratio_within (container()->ratio(), full_frame ());
1205 }
1206
1207 /** @param from KDM from time expressed as a local time with an offset from UTC
1208  *  @param to KDM to time expressed as a local time with an offset from UTC
1209  */
1210 dcp::EncryptedKDM
1211 Film::make_kdm (
1212         dcp::Certificate recipient,
1213         vector<dcp::Certificate> trusted_devices,
1214         boost::filesystem::path cpl_file,
1215         dcp::LocalTime from,
1216         dcp::LocalTime until,
1217         dcp::Formulation formulation
1218         ) const
1219 {
1220         shared_ptr<const dcp::CPL> cpl (new dcp::CPL (cpl_file));
1221         shared_ptr<const dcp::CertificateChain> signer = Config::instance()->signer_chain ();
1222         if (!signer->valid ()) {
1223                 throw InvalidSignerError ();
1224         }
1225
1226         /* Find keys that have been added to imported, encrypted DCP content */
1227         list<dcp::DecryptedKDMKey> imported_keys;
1228         BOOST_FOREACH (shared_ptr<Content> i, content()) {
1229                 shared_ptr<DCPContent> d = dynamic_pointer_cast<DCPContent> (i);
1230                 if (d && d->kdm()) {
1231                         dcp::DecryptedKDM kdm (d->kdm().get(), Config::instance()->decryption_chain()->key().get());
1232                         list<dcp::DecryptedKDMKey> keys = kdm.keys ();
1233                         copy (keys.begin(), keys.end(), back_inserter (imported_keys));
1234                 }
1235         }
1236
1237         map<shared_ptr<const dcp::ReelMXF>, dcp::Key> keys;
1238
1239         BOOST_FOREACH(shared_ptr<const dcp::ReelAsset> i, cpl->reel_assets ()) {
1240                 shared_ptr<const dcp::ReelMXF> mxf = boost::dynamic_pointer_cast<const dcp::ReelMXF> (i);
1241                 if (!mxf || !mxf->key_id()) {
1242                         continue;
1243                 }
1244
1245                 /* Get any imported key for this ID */
1246                 bool done = false;
1247                 BOOST_FOREACH (dcp::DecryptedKDMKey j, imported_keys) {
1248                         if (j.id() == mxf->key_id().get()) {
1249                                 LOG_GENERAL ("Using imported key for %1", mxf->key_id().get());
1250                                 keys[mxf] = j.key();
1251                                 done = true;
1252                         }
1253                 }
1254
1255                 if (!done) {
1256                         /* No imported key; it must be an asset that we encrypted */
1257                         LOG_GENERAL ("Using our own key for %1", mxf->key_id().get());
1258                         keys[mxf] = key();
1259                 }
1260         }
1261
1262         return dcp::DecryptedKDM (
1263                 cpl->id(), keys, from, until, cpl->content_title_text(), cpl->content_title_text(), dcp::LocalTime().as_string()
1264                 ).encrypt (signer, recipient, trusted_devices, formulation);
1265 }
1266
1267 /** @param from KDM from time expressed as a local time in the time zone of the Screen's Cinema.
1268  *  @param to KDM to time expressed as a local time in the time zone of the Screen's Cinema.
1269  */
1270 list<ScreenKDM>
1271 Film::make_kdms (
1272         list<shared_ptr<Screen> > screens,
1273         boost::filesystem::path dcp,
1274         boost::posix_time::ptime from,
1275         boost::posix_time::ptime until,
1276         dcp::Formulation formulation
1277         ) const
1278 {
1279         list<ScreenKDM> kdms;
1280
1281         BOOST_FOREACH (shared_ptr<Screen> i, screens) {
1282                 if (i->recipient) {
1283                         dcp::EncryptedKDM const kdm = make_kdm (
1284                                 i->recipient.get(),
1285                                 i->trusted_devices,
1286                                 dcp,
1287                                 dcp::LocalTime (from, i->cinema->utc_offset_hour(), i->cinema->utc_offset_minute()),
1288                                 dcp::LocalTime (until, i->cinema->utc_offset_hour(), i->cinema->utc_offset_minute()),
1289                                 formulation
1290                                 );
1291
1292                         kdms.push_back (ScreenKDM (i, kdm));
1293                 }
1294         }
1295
1296         return kdms;
1297 }
1298
1299 /** @return The approximate disk space required to encode a DCP of this film with the
1300  *  current settings, in bytes.
1301  */
1302 uint64_t
1303 Film::required_disk_space () const
1304 {
1305         return _playlist->required_disk_space (j2k_bandwidth(), audio_channels(), audio_frame_rate());
1306 }
1307
1308 /** This method checks the disk that the Film is on and tries to decide whether or not
1309  *  there will be enough space to make a DCP for it.  If so, true is returned; if not,
1310  *  false is returned and required and available are filled in with the amount of disk space
1311  *  required and available respectively (in Gb).
1312  *
1313  *  Note: the decision made by this method isn't, of course, 100% reliable.
1314  */
1315 bool
1316 Film::should_be_enough_disk_space (double& required, double& available, bool& can_hard_link) const
1317 {
1318         /* Create a test file and see if we can hard-link it */
1319         boost::filesystem::path test = internal_video_asset_dir() / "test";
1320         boost::filesystem::path test2 = internal_video_asset_dir() / "test2";
1321         can_hard_link = true;
1322         FILE* f = fopen_boost (test, "w");
1323         if (f) {
1324                 fclose (f);
1325                 boost::system::error_code ec;
1326                 boost::filesystem::create_hard_link (test, test2, ec);
1327                 if (ec) {
1328                         can_hard_link = false;
1329                 }
1330                 boost::filesystem::remove (test);
1331                 boost::filesystem::remove (test2);
1332         }
1333
1334         boost::filesystem::space_info s = boost::filesystem::space (internal_video_asset_dir ());
1335         required = double (required_disk_space ()) / 1073741824.0f;
1336         if (!can_hard_link) {
1337                 required *= 2;
1338         }
1339         available = double (s.available) / 1073741824.0f;
1340         return (available - required) > 1;
1341 }
1342
1343 string
1344 Film::subtitle_language () const
1345 {
1346         set<string> languages;
1347
1348         ContentList cl = content ();
1349         BOOST_FOREACH (shared_ptr<Content>& c, cl) {
1350                 if (c->subtitle) {
1351                         languages.insert (c->subtitle->language ());
1352                 }
1353         }
1354
1355         string all;
1356         BOOST_FOREACH (string s, languages) {
1357                 if (!all.empty ()) {
1358                         all += "/" + s;
1359                 } else {
1360                         all += s;
1361                 }
1362         }
1363
1364         return all;
1365 }
1366
1367 /** Change the gains of the supplied AudioMapping to make it a default
1368  *  for this film.  The defaults are guessed based on what processor (if any)
1369  *  is in use, the number of input channels and any filename supplied.
1370  */
1371 void
1372 Film::make_audio_mapping_default (AudioMapping& mapping, optional<boost::filesystem::path> filename) const
1373 {
1374         static string const regex[] = {
1375                 ".*[\\._-]L[\\._-].*",
1376                 ".*[\\._-]R[\\._-].*",
1377                 ".*[\\._-]C[\\._-].*",
1378                 ".*[\\._-]Lfe[\\._-].*",
1379                 ".*[\\._-]Ls[\\._-].*",
1380                 ".*[\\._-]Rs[\\._-].*"
1381         };
1382
1383         static int const regexes = sizeof(regex) / sizeof(*regex);
1384
1385         if (audio_processor ()) {
1386                 audio_processor()->make_audio_mapping_default (mapping);
1387         } else {
1388                 mapping.make_zero ();
1389                 if (mapping.input_channels() == 1) {
1390                         bool guessed = false;
1391
1392                         /* See if we can guess where this stream should go */
1393                         if (filename) {
1394                                 for (int i = 0; i < regexes; ++i) {
1395                                         boost::regex e (regex[i], boost::regex::icase);
1396                                         if (boost::regex_match (filename->string(), e) && i < mapping.output_channels()) {
1397                                                 mapping.set (0, i, 1);
1398                                                 guessed = true;
1399                                         }
1400                                 }
1401                         }
1402
1403                         if (!guessed) {
1404                                 /* If we have no idea, just put it on centre */
1405                                 mapping.set (0, static_cast<int> (dcp::CENTRE), 1);
1406                         }
1407                 } else {
1408                         /* 1:1 mapping */
1409                         for (int i = 0; i < min (mapping.input_channels(), mapping.output_channels()); ++i) {
1410                                 mapping.set (i, i, 1);
1411                         }
1412                 }
1413         }
1414 }
1415
1416 /** @return The names of the channels that audio contents' outputs are passed into;
1417  *  this is either the DCP or a AudioProcessor.
1418  */
1419 vector<string>
1420 Film::audio_output_names () const
1421 {
1422         if (audio_processor ()) {
1423                 return audio_processor()->input_names ();
1424         }
1425
1426         DCPOMATIC_ASSERT (MAX_DCP_AUDIO_CHANNELS == 16);
1427
1428         vector<string> n;
1429
1430         for (int i = 0; i < audio_channels(); ++i) {
1431                 n.push_back (short_audio_channel_name (i));
1432         }
1433
1434         return n;
1435 }
1436
1437 void
1438 Film::repeat_content (ContentList c, int n)
1439 {
1440         _playlist->repeat (c, n);
1441 }
1442
1443 void
1444 Film::remove_content (ContentList c)
1445 {
1446         _playlist->remove (c);
1447 }
1448
1449 void
1450 Film::audio_analysis_finished ()
1451 {
1452         /* XXX */
1453 }
1454
1455 list<DCPTimePeriod>
1456 Film::reels () const
1457 {
1458         list<DCPTimePeriod> p;
1459         DCPTime const len = length().ceil (video_frame_rate ());
1460
1461         switch (reel_type ()) {
1462         case REELTYPE_SINGLE:
1463                 p.push_back (DCPTimePeriod (DCPTime (), len));
1464                 break;
1465         case REELTYPE_BY_VIDEO_CONTENT:
1466         {
1467                 optional<DCPTime> last_split;
1468                 shared_ptr<Content> last_video;
1469                 BOOST_FOREACH (shared_ptr<Content> c, content ()) {
1470                         if (c->video) {
1471                                 BOOST_FOREACH (DCPTime t, c->reel_split_points()) {
1472                                         if (last_split) {
1473                                                 p.push_back (DCPTimePeriod (last_split.get(), t));
1474                                         }
1475                                         last_split = t;
1476                                 }
1477                                 last_video = c;
1478                         }
1479                 }
1480
1481                 DCPTime video_end = last_video ? last_video->end() : DCPTime(0);
1482                 if (last_split) {
1483                         /* Definitely go from the last split to the end of the video content */
1484                         p.push_back (DCPTimePeriod (last_split.get(), video_end));
1485                 }
1486
1487                 if (video_end < len) {
1488                         /* And maybe go after that as well if there is any non-video hanging over the end */
1489                         p.push_back (DCPTimePeriod (video_end, len));
1490                 }
1491                 break;
1492         }
1493         case REELTYPE_BY_LENGTH:
1494         {
1495                 DCPTime current;
1496                 /* Integer-divide reel length by the size of one frame to give the number of frames per reel */
1497                 Frame const reel_in_frames = _reel_length / ((j2k_bandwidth() / video_frame_rate()) / 8);
1498                 while (current < len) {
1499                         DCPTime end = min (len, current + DCPTime::from_frames (reel_in_frames, video_frame_rate ()));
1500                         p.push_back (DCPTimePeriod (current, end));
1501                         current = end;
1502                 }
1503                 break;
1504         }
1505         }
1506
1507         return p;
1508 }
1509
1510 string
1511 Film::content_summary (DCPTimePeriod period) const
1512 {
1513         return _playlist->content_summary (period);
1514 }
1515
1516 list<string>
1517 Film::fix_conflicting_settings ()
1518 {
1519         list<string> notes;
1520
1521         list<boost::filesystem::path> was_referencing;
1522         BOOST_FOREACH (shared_ptr<Content> i, content()) {
1523                 shared_ptr<DCPContent> d = dynamic_pointer_cast<DCPContent> (i);
1524                 if (d) {
1525                         list<string> reasons;
1526                         bool was = false;
1527                         if (!d->can_reference_video(reasons) && d->reference_video()) {
1528                                 d->set_reference_video (false);
1529                                 was = true;
1530                         }
1531                         if (!d->can_reference_audio(reasons) && d->reference_audio()) {
1532                                 d->set_reference_audio (false);
1533                                 was = true;
1534                         }
1535                         if (!d->can_reference_subtitle(reasons) && d->reference_subtitle()) {
1536                                 d->set_reference_subtitle (false);
1537                                 was = true;
1538                         }
1539                         if (was) {
1540                                 was_referencing.push_back (d->path(0).parent_path().filename());
1541                         }
1542                 }
1543         }
1544
1545         BOOST_FOREACH (boost::filesystem::path d, was_referencing) {
1546                 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()));
1547         }
1548
1549         return notes;
1550 }
1551
1552 void
1553 Film::use_template (string name)
1554 {
1555         _template_film.reset (new Film (optional<boost::filesystem::path>()));
1556         _template_film->read_metadata (Config::instance()->template_path (name));
1557         _use_isdcf_name = _template_film->_use_isdcf_name;
1558         _dcp_content_type = _template_film->_dcp_content_type;
1559         _container = _template_film->_container;
1560         _resolution = _template_film->_resolution;
1561         _j2k_bandwidth = _template_film->_j2k_bandwidth;
1562         _video_frame_rate = _template_film->_video_frame_rate;
1563         _signed = _template_film->_signed;
1564         _encrypted = _template_film->_encrypted;
1565         _audio_channels = _template_film->_audio_channels;
1566         _sequence = _template_film->_sequence;
1567         _three_d = _template_film->_three_d;
1568         _interop = _template_film->_interop;
1569         _audio_processor = _template_film->_audio_processor;
1570         _reel_type = _template_film->_reel_type;
1571         _reel_length = _template_film->_reel_length;
1572         _upload_after_make_dcp = _template_film->_upload_after_make_dcp;
1573 }