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