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