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