Fix crash on opening content menu for DCPs that have had incorrect KDMs added.
[dcpomatic.git] / src / lib / film.cc
1 /*
2     Copyright (C) 2012-2016 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 <libxml++/libxml++.h>
61 #include <boost/filesystem.hpp>
62 #include <boost/algorithm/string.hpp>
63 #include <boost/foreach.hpp>
64 #include <boost/regex.hpp>
65 #include <unistd.h>
66 #include <stdexcept>
67 #include <iostream>
68 #include <algorithm>
69 #include <cstdlib>
70 #include <iomanip>
71 #include <set>
72
73 #include "i18n.h"
74
75 using std::string;
76 using std::pair;
77 using std::vector;
78 using std::setfill;
79 using std::min;
80 using std::max;
81 using std::make_pair;
82 using std::cout;
83 using std::list;
84 using std::set;
85 using std::runtime_error;
86 using boost::shared_ptr;
87 using boost::weak_ptr;
88 using boost::dynamic_pointer_cast;
89 using boost::optional;
90 using boost::is_any_of;
91 using dcp::raw_convert;
92
93 #define LOG_GENERAL(...) log()->log (String::compose (__VA_ARGS__), LogEntry::TYPE_GENERAL);
94 #define LOG_GENERAL_NC(...) log()->log (__VA_ARGS__, LogEntry::TYPE_GENERAL);
95
96 /* 5 -> 6
97  * AudioMapping XML changed.
98  * 6 -> 7
99  * Subtitle offset changed to subtitle y offset, and subtitle x offset added.
100  * 7 -> 8
101  * Use <Scale> tag in <VideoContent> rather than <Ratio>.
102  * 8 -> 9
103  * DCI -> ISDCF
104  * 9 -> 10
105  * Subtitle X and Y scale.
106  *
107  * Bumped to 32 for 2.0 branch; some times are expressed in Times rather
108  * than frames now.
109  *
110  * 32 -> 33
111  * Changed <Period> to <Subtitle> in FFmpegSubtitleStream
112  * 33 -> 34
113  * Content only contains audio/subtitle-related tags if those things
114  * are present.
115  * 34 -> 35
116  * VideoFrameType in VideoContent is a string rather than an integer.
117  * 35 -> 36
118  * EffectColour rather than OutlineColour in Subtitle.
119  */
120 int const Film::current_state_version = 36;
121
122 /** Construct a Film object in a given directory.
123  *
124  *  @param dir Film directory.
125  */
126
127 Film::Film (optional<boost::filesystem::path> dir)
128         : _playlist (new Playlist)
129         , _use_isdcf_name (true)
130         , _dcp_content_type (Config::instance()->default_dcp_content_type ())
131         , _container (Config::instance()->default_container ())
132         , _resolution (RESOLUTION_2K)
133         , _signed (true)
134         , _encrypted (false)
135         , _j2k_bandwidth (Config::instance()->default_j2k_bandwidth ())
136         , _isdcf_metadata (Config::instance()->default_isdcf_metadata ())
137         , _video_frame_rate (24)
138         , _audio_channels (Config::instance()->default_dcp_audio_channels ())
139         , _three_d (false)
140         , _sequence (true)
141         , _interop (Config::instance()->default_interop ())
142         , _audio_processor (0)
143         , _reel_type (REELTYPE_SINGLE)
144         , _reel_length (2000000000)
145         , _upload_after_make_dcp (false)
146         , _state_version (current_state_version)
147         , _dirty (false)
148 {
149         set_isdcf_date_today ();
150
151         _playlist_changed_connection = _playlist->Changed.connect (bind (&Film::playlist_changed, this));
152         _playlist_order_changed_connection = _playlist->OrderChanged.connect (bind (&Film::playlist_order_changed, this));
153         _playlist_content_changed_connection = _playlist->ContentChanged.connect (bind (&Film::playlist_content_changed, this, _1, _2, _3));
154
155         if (dir) {
156                 /* Make state.directory a complete path without ..s (where possible)
157                    (Code swiped from Adam Bowen on stackoverflow)
158                    XXX: couldn't/shouldn't this just be boost::filesystem::canonical?
159                 */
160
161                 boost::filesystem::path p (boost::filesystem::system_complete (dir.get()));
162                 boost::filesystem::path result;
163                 for (boost::filesystem::path::iterator i = p.begin(); i != p.end(); ++i) {
164                         if (*i == "..") {
165                                 if (boost::filesystem::is_symlink (result) || result.filename() == "..") {
166                                         result /= *i;
167                                 } else {
168                                         result = result.parent_path ();
169                                 }
170                         } else if (*i != ".") {
171                                 result /= *i;
172                         }
173                 }
174
175                 set_directory (result.make_preferred ());
176         }
177
178         if (_directory) {
179                 _log.reset (new FileLog (file ("log")));
180         } else {
181                 _log.reset (new NullLog);
182         }
183
184         _playlist->set_sequence (_sequence);
185 }
186
187 Film::~Film ()
188 {
189         BOOST_FOREACH (boost::signals2::connection& i, _job_connections) {
190                 i.disconnect ();
191         }
192
193         BOOST_FOREACH (boost::signals2::connection& i, _audio_analysis_connections) {
194                 i.disconnect ();
195         }
196 }
197
198 string
199 Film::video_identifier () const
200 {
201         DCPOMATIC_ASSERT (container ());
202
203         string s = container()->id()
204                 + "_" + resolution_to_string (_resolution)
205                 + "_" + _playlist->video_identifier()
206                 + "_" + raw_convert<string>(_video_frame_rate)
207                 + "_" + raw_convert<string>(j2k_bandwidth());
208
209         if (encrypted ()) {
210                 s += "_E";
211         } else {
212                 s += "_P";
213         }
214
215         if (_interop) {
216                 s += "_I";
217         } else {
218                 s += "_S";
219         }
220
221         if (_three_d) {
222                 s += "_3D";
223         }
224
225         return s;
226 }
227
228 /** @return The file to write video frame info to */
229 boost::filesystem::path
230 Film::info_file (DCPTimePeriod period) const
231 {
232         boost::filesystem::path p;
233         p /= "info";
234         p /= video_identifier () + "_" + raw_convert<string> (period.from.get()) + "_" + raw_convert<string> (period.to.get());
235         return file (p);
236 }
237
238 boost::filesystem::path
239 Film::internal_video_asset_dir () const
240 {
241         return dir ("video");
242 }
243
244 boost::filesystem::path
245 Film::internal_video_asset_filename (DCPTimePeriod p) const
246 {
247         return video_identifier() + "_" + raw_convert<string> (p.from.get()) + "_" + raw_convert<string> (p.to.get()) + ".mxf";
248 }
249
250 boost::filesystem::path
251 Film::audio_analysis_path (shared_ptr<const Playlist> playlist) const
252 {
253         boost::filesystem::path p = dir ("analysis");
254
255         Digester digester;
256         BOOST_FOREACH (shared_ptr<Content> i, playlist->content ()) {
257                 if (!i->audio) {
258                         continue;
259                 }
260
261                 digester.add (i->digest ());
262                 digester.add (i->audio->mapping().digest ());
263                 if (playlist->content().size() != 1) {
264                         /* Analyses should be considered equal regardless of gain
265                            if they were made from just one piece of content.  This
266                            is because we can fake any gain change in a single-content
267                            analysis at the plotting stage rather than having to
268                            recompute it.
269                         */
270                         digester.add (i->audio->gain ());
271                 }
272         }
273
274         if (audio_processor ()) {
275                 digester.add (audio_processor()->id ());
276         }
277
278         p /= digester.get ();
279         return p;
280 }
281
282 /** Add suitable Jobs to the JobManager to create a DCP for this Film */
283 void
284 Film::make_dcp ()
285 {
286         if (dcp_name().find ("/") != string::npos) {
287                 throw BadSettingError (_("name"), _("cannot contain slashes"));
288         }
289
290         set_isdcf_date_today ();
291
292         BOOST_FOREACH (string i, environment_info ()) {
293                 LOG_GENERAL_NC (i);
294         }
295
296         BOOST_FOREACH (shared_ptr<const Content> i, content ()) {
297                 LOG_GENERAL ("Content: %1", i->technical_summary());
298         }
299         LOG_GENERAL ("DCP video rate %1 fps", video_frame_rate());
300         if (Config::instance()->only_servers_encode ()) {
301                 LOG_GENERAL_NC ("0 threads: ONLY SERVERS SET TO ENCODE");
302         } else {
303                 LOG_GENERAL ("%1 threads", Config::instance()->num_local_encoding_threads());
304         }
305         LOG_GENERAL ("J2K bandwidth %1", j2k_bandwidth());
306
307         if (container() == 0) {
308                 throw MissingSettingError (_("container"));
309         }
310
311         if (content().empty()) {
312                 throw runtime_error (_("You must add some content to the DCP before creating it"));
313         }
314
315         if (dcp_content_type() == 0) {
316                 throw MissingSettingError (_("content type"));
317         }
318
319         if (name().empty()) {
320                 throw MissingSettingError (_("name"));
321         }
322
323         JobManager::instance()->add (shared_ptr<Job> (new TranscodeJob (shared_from_this())));
324 }
325
326 /** Start a job to send our DCP to the configured TMS */
327 void
328 Film::send_dcp_to_tms ()
329 {
330         shared_ptr<Job> j (new UploadJob (shared_from_this()));
331         JobManager::instance()->add (j);
332 }
333
334 shared_ptr<xmlpp::Document>
335 Film::metadata (bool with_content_paths) const
336 {
337         shared_ptr<xmlpp::Document> doc (new xmlpp::Document);
338         xmlpp::Element* root = doc->create_root_node ("Metadata");
339
340         root->add_child("Version")->add_child_text (raw_convert<string> (current_state_version));
341         root->add_child("Name")->add_child_text (_name);
342         root->add_child("UseISDCFName")->add_child_text (_use_isdcf_name ? "1" : "0");
343
344         if (_dcp_content_type) {
345                 root->add_child("DCPContentType")->add_child_text (_dcp_content_type->isdcf_name ());
346         }
347
348         if (_container) {
349                 root->add_child("Container")->add_child_text (_container->id ());
350         }
351
352         root->add_child("Resolution")->add_child_text (resolution_to_string (_resolution));
353         root->add_child("J2KBandwidth")->add_child_text (raw_convert<string> (_j2k_bandwidth));
354         _isdcf_metadata.as_xml (root->add_child ("ISDCFMetadata"));
355         root->add_child("VideoFrameRate")->add_child_text (raw_convert<string> (_video_frame_rate));
356         root->add_child("ISDCFDate")->add_child_text (boost::gregorian::to_iso_string (_isdcf_date));
357         root->add_child("AudioChannels")->add_child_text (raw_convert<string> (_audio_channels));
358         root->add_child("ThreeD")->add_child_text (_three_d ? "1" : "0");
359         root->add_child("Sequence")->add_child_text (_sequence ? "1" : "0");
360         root->add_child("Interop")->add_child_text (_interop ? "1" : "0");
361         root->add_child("Signed")->add_child_text (_signed ? "1" : "0");
362         root->add_child("Encrypted")->add_child_text (_encrypted ? "1" : "0");
363         root->add_child("Key")->add_child_text (_key.hex ());
364         if (_audio_processor) {
365                 root->add_child("AudioProcessor")->add_child_text (_audio_processor->id ());
366         }
367         root->add_child("ReelType")->add_child_text (raw_convert<string> (static_cast<int> (_reel_type)));
368         root->add_child("ReelLength")->add_child_text (raw_convert<string> (_reel_length));
369         root->add_child("UploadAfterMakeDCP")->add_child_text (_upload_after_make_dcp ? "1" : "0");
370         _playlist->as_xml (root->add_child ("Playlist"), with_content_paths);
371
372         return doc;
373 }
374
375 /** Write state to our `metadata' file */
376 void
377 Film::write_metadata () const
378 {
379         DCPOMATIC_ASSERT (directory());
380         boost::filesystem::create_directories (directory().get());
381         shared_ptr<xmlpp::Document> doc = metadata ();
382         doc->write_to_file_formatted (file("metadata.xml").string ());
383         _dirty = false;
384 }
385
386 /** Write a template from this film */
387 void
388 Film::write_template (boost::filesystem::path path) const
389 {
390         boost::filesystem::create_directories (path.parent_path());
391         shared_ptr<xmlpp::Document> doc = metadata (false);
392         doc->write_to_file_formatted (path.string ());
393 }
394
395 /** Read state from our metadata file.
396  *  @return Notes about things that the user should know about, or empty.
397  */
398 list<string>
399 Film::read_metadata (optional<boost::filesystem::path> path)
400 {
401         if (!path) {
402                 if (boost::filesystem::exists (file ("metadata")) && !boost::filesystem::exists (file ("metadata.xml"))) {
403                         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!"));
404                 }
405
406                 path = file ("metadata.xml");
407         }
408
409         cxml::Document f ("Metadata");
410         f.read_file (path.get ());
411
412         _state_version = f.number_child<int> ("Version");
413         if (_state_version > current_state_version) {
414                 throw runtime_error (_("This film was created with a newer version of DCP-o-matic, and it cannot be loaded into this version.  Sorry!"));
415         }
416
417         _name = f.string_child ("Name");
418         if (_state_version >= 9) {
419                 _use_isdcf_name = f.bool_child ("UseISDCFName");
420                 _isdcf_metadata = ISDCFMetadata (f.node_child ("ISDCFMetadata"));
421                 _isdcf_date = boost::gregorian::from_undelimited_string (f.string_child ("ISDCFDate"));
422         } else {
423                 _use_isdcf_name = f.bool_child ("UseDCIName");
424                 _isdcf_metadata = ISDCFMetadata (f.node_child ("DCIMetadata"));
425                 _isdcf_date = boost::gregorian::from_undelimited_string (f.string_child ("DCIDate"));
426         }
427
428         {
429                 optional<string> c = f.optional_string_child ("DCPContentType");
430                 if (c) {
431                         _dcp_content_type = DCPContentType::from_isdcf_name (c.get ());
432                 }
433         }
434
435         {
436                 optional<string> c = f.optional_string_child ("Container");
437                 if (c) {
438                         _container = Ratio::from_id (c.get ());
439                 }
440         }
441
442         _resolution = string_to_resolution (f.string_child ("Resolution"));
443         _j2k_bandwidth = f.number_child<int> ("J2KBandwidth");
444         _video_frame_rate = f.number_child<int> ("VideoFrameRate");
445         _signed = f.optional_bool_child("Signed").get_value_or (true);
446         _encrypted = f.bool_child ("Encrypted");
447         _audio_channels = f.number_child<int> ("AudioChannels");
448         /* We used to allow odd numbers (and zero) channels, but it's just not worth
449            the pain.
450         */
451         if (_audio_channels == 0) {
452                 _audio_channels = 2;
453         } else if ((_audio_channels % 2) == 1) {
454                 _audio_channels++;
455         }
456
457         if (f.optional_bool_child("SequenceVideo")) {
458                 _sequence = f.bool_child("SequenceVideo");
459         } else {
460                 _sequence = f.bool_child("Sequence");
461         }
462
463         _three_d = f.bool_child ("ThreeD");
464         _interop = f.bool_child ("Interop");
465         _key = dcp::Key (f.string_child ("Key"));
466
467         if (f.optional_string_child ("AudioProcessor")) {
468                 _audio_processor = AudioProcessor::from_id (f.string_child ("AudioProcessor"));
469         } else {
470                 _audio_processor = 0;
471         }
472
473         _reel_type = static_cast<ReelType> (f.optional_number_child<int>("ReelType").get_value_or (static_cast<int>(REELTYPE_SINGLE)));
474         _reel_length = f.optional_number_child<int64_t>("ReelLength").get_value_or (2000000000);
475         _upload_after_make_dcp = f.optional_bool_child("UploadAfterMakeDCP").get_value_or (false);
476
477         list<string> notes;
478         /* This method is the only one that can return notes (so far) */
479         _playlist->set_from_xml (shared_from_this(), f.node_child ("Playlist"), _state_version, notes);
480
481         /* Write backtraces to this film's directory, until another film is loaded */
482         if (_directory) {
483                 set_backtrace_file (file ("backtrace.txt"));
484         }
485
486         _dirty = false;
487         return notes;
488 }
489
490 /** Given a directory name, return its full path within the Film's directory.
491  *  The directory (and its parents) will be created if they do not exist.
492  */
493 boost::filesystem::path
494 Film::dir (boost::filesystem::path d) const
495 {
496         DCPOMATIC_ASSERT (_directory);
497
498         boost::filesystem::path p;
499         p /= _directory.get();
500         p /= d;
501
502         boost::filesystem::create_directories (p);
503
504         return p;
505 }
506
507 /** Given a file or directory name, return its full path within the Film's directory.
508  *  Any required parent directories will be created.
509  */
510 boost::filesystem::path
511 Film::file (boost::filesystem::path f) const
512 {
513         DCPOMATIC_ASSERT (_directory);
514
515         boost::filesystem::path p;
516         p /= _directory.get();
517         p /= f;
518
519         boost::filesystem::create_directories (p.parent_path ());
520
521         return p;
522 }
523
524 list<int>
525 Film::mapped_audio_channels () const
526 {
527         list<int> mapped;
528
529         if (audio_processor ()) {
530                 /* Processors are mapped 1:1 to DCP outputs so we can work out mappings from there */
531                 for (int i = 0; i < audio_processor()->out_channels(); ++i) {
532                         mapped.push_back (i);
533                 }
534         } else {
535                 BOOST_FOREACH (shared_ptr<Content> i, content ()) {
536                         if (i->audio) {
537                                 list<int> c = i->audio->mapping().mapped_output_channels ();
538                                 copy (c.begin(), c.end(), back_inserter (mapped));
539                         }
540                 }
541
542                 mapped.sort ();
543                 mapped.unique ();
544         }
545
546         return mapped;
547 }
548
549 /** @return a ISDCF-compliant name for a DCP of this film */
550 string
551 Film::isdcf_name (bool if_created_now) const
552 {
553         string d;
554
555         string raw_name = name ();
556
557         /* Split the raw name up into words */
558         vector<string> words;
559         split (words, raw_name, is_any_of (" _-"));
560
561         string fixed_name;
562
563         /* Add each word to fixed_name */
564         for (vector<string>::const_iterator i = words.begin(); i != words.end(); ++i) {
565                 string w = *i;
566
567                 /* First letter is always capitalised */
568                 w[0] = toupper (w[0]);
569
570                 /* Count caps in w */
571                 size_t caps = 0;
572                 for (size_t i = 0; i < w.size(); ++i) {
573                         if (isupper (w[i])) {
574                                 ++caps;
575                         }
576                 }
577
578                 /* If w is all caps make the rest of it lower case, otherwise
579                    leave it alone.
580                 */
581                 if (caps == w.size ()) {
582                         for (size_t i = 1; i < w.size(); ++i) {
583                                 w[i] = tolower (w[i]);
584                         }
585                 }
586
587                 for (size_t i = 0; i < w.size(); ++i) {
588                         fixed_name += w[i];
589                 }
590         }
591
592         if (fixed_name.length() > 14) {
593                 fixed_name = fixed_name.substr (0, 14);
594         }
595
596         d += fixed_name;
597
598         if (dcp_content_type()) {
599                 d += "_" + dcp_content_type()->isdcf_name();
600                 d += "-" + raw_convert<string>(isdcf_metadata().content_version);
601         }
602
603         ISDCFMetadata const dm = isdcf_metadata ();
604
605         if (dm.temp_version) {
606                 d += "-Temp";
607         }
608
609         if (dm.pre_release) {
610                 d += "-Pre";
611         }
612
613         if (dm.red_band) {
614                 d += "-RedBand";
615         }
616
617         if (!dm.chain.empty ()) {
618                 d += "-" + dm.chain;
619         }
620
621         if (three_d ()) {
622                 d += "-3D";
623         }
624
625         if (dm.two_d_version_of_three_d) {
626                 d += "-2D";
627         }
628
629         if (!dm.mastered_luminance.empty ()) {
630                 d += "-" + dm.mastered_luminance;
631         }
632
633         if (video_frame_rate() != 24) {
634                 d += "-" + raw_convert<string>(video_frame_rate());
635         }
636
637         if (container()) {
638                 d += "_" + container()->isdcf_name();
639         }
640
641         /* XXX: this uses the first bit of content only */
642
643         /* The standard says we don't do this for trailers, for some strange reason */
644         if (dcp_content_type() && dcp_content_type()->libdcp_kind() != dcp::TRAILER) {
645                 Ratio const * content_ratio = 0;
646                 BOOST_FOREACH (shared_ptr<Content> i, content ()) {
647                         if (i->video) {
648                                 /* Here's the first piece of video content */
649                                 if (i->video->scale().ratio ()) {
650                                         content_ratio = i->video->scale().ratio ();
651                                 } else {
652                                         content_ratio = Ratio::from_ratio (i->video->size().ratio ());
653                                 }
654                                 break;
655                         }
656                 }
657
658                 if (content_ratio && content_ratio != container()) {
659                         d += "-" + content_ratio->isdcf_name();
660                 }
661         }
662
663         if (!dm.audio_language.empty ()) {
664                 d += "_" + dm.audio_language;
665                 if (!dm.subtitle_language.empty()) {
666
667                         bool burnt_in = true;
668                         BOOST_FOREACH (shared_ptr<Content> i, content ()) {
669                                 if (!i->subtitle) {
670                                         continue;
671                                 }
672
673                                 if (i->subtitle->use() && !i->subtitle->burn()) {
674                                         burnt_in = false;
675                                 }
676                         }
677
678                         string language = dm.subtitle_language;
679                         if (burnt_in && language != "XX") {
680                                 transform (language.begin(), language.end(), language.begin(), ::tolower);
681                         } else {
682                                 transform (language.begin(), language.end(), language.begin(), ::toupper);
683                         }
684
685                         d += "-" + language;
686                 } else {
687                         d += "-XX";
688                 }
689         }
690
691         if (!dm.territory.empty ()) {
692                 d += "_" + dm.territory;
693                 if (dm.rating.empty ()) {
694                         d += "-NR";
695                 } else {
696                         d += "-" + dm.rating;
697                 }
698         }
699
700         /* Count mapped audio channels */
701
702         int non_lfe = 0;
703         int lfe = 0;
704
705         BOOST_FOREACH (int i, mapped_audio_channels ()) {
706                 if (i >= audio_channels()) {
707                         /* This channel is mapped but is not included in the DCP */
708                         continue;
709                 }
710
711                 if (static_cast<dcp::Channel> (i) == dcp::LFE) {
712                         ++lfe;
713                 } else {
714                         ++non_lfe;
715                 }
716         }
717
718         if (non_lfe) {
719                 d += String::compose("_%1%2", non_lfe, lfe);
720         }
721
722         /* XXX: HI/VI */
723
724         d += "_" + resolution_to_string (_resolution);
725
726         if (!dm.studio.empty ()) {
727                 d += "_" + dm.studio;
728         }
729
730         if (if_created_now) {
731                 d += "_" + boost::gregorian::to_iso_string (boost::gregorian::day_clock::local_day ());
732         } else {
733                 d += "_" + boost::gregorian::to_iso_string (_isdcf_date);
734         }
735
736         if (!dm.facility.empty ()) {
737                 d += "_" + dm.facility;
738         }
739
740         if (_interop) {
741                 d += "_IOP";
742         } else {
743                 d += "_SMPTE";
744         }
745
746         if (three_d ()) {
747                 d += "-3D";
748         }
749
750         bool vf = false;
751         BOOST_FOREACH (shared_ptr<Content> i, content ()) {
752                 shared_ptr<const DCPContent> dc = dynamic_pointer_cast<const DCPContent> (i);
753                 if (dc && (dc->reference_video() || dc->reference_audio() || dc->reference_subtitle())) {
754                         vf = true;
755                 }
756         }
757
758         if (vf) {
759                 d += "_VF";
760         } else {
761                 d += "_OV";
762         }
763
764         return d;
765 }
766
767 /** @return name to give the DCP */
768 string
769 Film::dcp_name (bool if_created_now) const
770 {
771         string unfiltered;
772         if (use_isdcf_name()) {
773                 unfiltered = isdcf_name (if_created_now);
774         } else {
775                 unfiltered = name ();
776         }
777
778         /* Filter out `bad' characters which cause problems with some systems.
779            There's no apparent list of what really is allowed, so this is a guess.
780         */
781
782         string filtered;
783         string const allowed = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_";
784         for (size_t i = 0; i < unfiltered.size(); ++i) {
785                 if (allowed.find (unfiltered[i]) != string::npos) {
786                         filtered += unfiltered[i];
787                 }
788         }
789
790         return filtered;
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 from KDM from time expressed as a local time with an offset from UTC
1201  *  @param to KDM to time expressed as a local time with an offset from UTC
1202  */
1203 dcp::EncryptedKDM
1204 Film::make_kdm (
1205         dcp::Certificate recipient,
1206         vector<dcp::Certificate> trusted_devices,
1207         boost::filesystem::path cpl_file,
1208         dcp::LocalTime from,
1209         dcp::LocalTime until,
1210         dcp::Formulation formulation
1211         ) const
1212 {
1213         shared_ptr<const dcp::CPL> cpl (new dcp::CPL (cpl_file));
1214         shared_ptr<const dcp::CertificateChain> signer = Config::instance()->signer_chain ();
1215         if (!signer->valid ()) {
1216                 throw InvalidSignerError ();
1217         }
1218
1219         return dcp::DecryptedKDM (
1220                 cpl, key(), from, until, cpl->content_title_text(), cpl->content_title_text(), dcp::LocalTime().as_string()
1221                 ).encrypt (signer, recipient, trusted_devices, formulation);
1222 }
1223
1224 /** @param from KDM from time expressed as a local time in the time zone of the Screen's Cinema.
1225  *  @param to KDM to time expressed as a local time in the time zone of the Screen's Cinema.
1226  */
1227 list<ScreenKDM>
1228 Film::make_kdms (
1229         list<shared_ptr<Screen> > screens,
1230         boost::filesystem::path dcp,
1231         boost::posix_time::ptime from,
1232         boost::posix_time::ptime until,
1233         dcp::Formulation formulation
1234         ) const
1235 {
1236         list<ScreenKDM> kdms;
1237
1238         BOOST_FOREACH (shared_ptr<Screen> i, screens) {
1239                 if (i->recipient) {
1240                         dcp::EncryptedKDM const kdm = make_kdm (
1241                                 i->recipient.get(),
1242                                 i->trusted_devices,
1243                                 dcp,
1244                                 dcp::LocalTime (from, i->cinema->utc_offset_hour(), i->cinema->utc_offset_minute()),
1245                                 dcp::LocalTime (until, i->cinema->utc_offset_hour(), i->cinema->utc_offset_minute()),
1246                                 formulation
1247                                 );
1248
1249                         kdms.push_back (ScreenKDM (i, kdm));
1250                 }
1251         }
1252
1253         return kdms;
1254 }
1255
1256 /** @return The approximate disk space required to encode a DCP of this film with the
1257  *  current settings, in bytes.
1258  */
1259 uint64_t
1260 Film::required_disk_space () const
1261 {
1262         return _playlist->required_disk_space (j2k_bandwidth(), audio_channels(), audio_frame_rate());
1263 }
1264
1265 /** This method checks the disk that the Film is on and tries to decide whether or not
1266  *  there will be enough space to make a DCP for it.  If so, true is returned; if not,
1267  *  false is returned and required and available are filled in with the amount of disk space
1268  *  required and available respectively (in Gb).
1269  *
1270  *  Note: the decision made by this method isn't, of course, 100% reliable.
1271  */
1272 bool
1273 Film::should_be_enough_disk_space (double& required, double& available, bool& can_hard_link) const
1274 {
1275         /* Create a test file and see if we can hard-link it */
1276         boost::filesystem::path test = internal_video_asset_dir() / "test";
1277         boost::filesystem::path test2 = internal_video_asset_dir() / "test2";
1278         can_hard_link = true;
1279         FILE* f = fopen_boost (test, "w");
1280         if (f) {
1281                 fclose (f);
1282                 boost::system::error_code ec;
1283                 boost::filesystem::create_hard_link (test, test2, ec);
1284                 if (ec) {
1285                         can_hard_link = false;
1286                 }
1287                 boost::filesystem::remove (test);
1288                 boost::filesystem::remove (test2);
1289         }
1290
1291         boost::filesystem::space_info s = boost::filesystem::space (internal_video_asset_dir ());
1292         required = double (required_disk_space ()) / 1073741824.0f;
1293         if (!can_hard_link) {
1294                 required *= 2;
1295         }
1296         available = double (s.available) / 1073741824.0f;
1297         return (available - required) > 1;
1298 }
1299
1300 string
1301 Film::subtitle_language () const
1302 {
1303         set<string> languages;
1304
1305         ContentList cl = content ();
1306         BOOST_FOREACH (shared_ptr<Content>& c, cl) {
1307                 if (c->subtitle) {
1308                         languages.insert (c->subtitle->language ());
1309                 }
1310         }
1311
1312         string all;
1313         BOOST_FOREACH (string s, languages) {
1314                 if (!all.empty ()) {
1315                         all += "/" + s;
1316                 } else {
1317                         all += s;
1318                 }
1319         }
1320
1321         return all;
1322 }
1323
1324 /** Change the gains of the supplied AudioMapping to make it a default
1325  *  for this film.  The defaults are guessed based on what processor (if any)
1326  *  is in use, the number of input channels and any filename supplied.
1327  */
1328 void
1329 Film::make_audio_mapping_default (AudioMapping& mapping, optional<boost::filesystem::path> filename) const
1330 {
1331         static string const regex[] = {
1332                 ".*[\\._-]L[\\._-].*",
1333                 ".*[\\._-]R[\\._-].*",
1334                 ".*[\\._-]C[\\._-].*",
1335                 ".*[\\._-]Lfe[\\._-].*",
1336                 ".*[\\._-]Ls[\\._-].*",
1337                 ".*[\\._-]Rs[\\._-].*"
1338         };
1339
1340         static int const regexes = sizeof(regex) / sizeof(*regex);
1341
1342         if (audio_processor ()) {
1343                 audio_processor()->make_audio_mapping_default (mapping);
1344         } else {
1345                 mapping.make_zero ();
1346                 if (mapping.input_channels() == 1) {
1347                         bool guessed = false;
1348
1349                         /* See if we can guess where this stream should go */
1350                         if (filename) {
1351                                 for (int i = 0; i < regexes; ++i) {
1352                                         boost::regex e (regex[i], boost::regex::icase);
1353                                         if (boost::regex_match (filename->string(), e) && i < mapping.output_channels()) {
1354                                                 mapping.set (0, i, 1);
1355                                                 guessed = true;
1356                                         }
1357                                 }
1358                         }
1359
1360                         if (!guessed) {
1361                                 /* If we have no idea, just put it on centre */
1362                                 mapping.set (0, static_cast<int> (dcp::CENTRE), 1);
1363                         }
1364                 } else {
1365                         /* 1:1 mapping */
1366                         for (int i = 0; i < min (mapping.input_channels(), mapping.output_channels()); ++i) {
1367                                 mapping.set (i, i, 1);
1368                         }
1369                 }
1370         }
1371 }
1372
1373 /** @return The names of the channels that audio contents' outputs are passed into;
1374  *  this is either the DCP or a AudioProcessor.
1375  */
1376 vector<string>
1377 Film::audio_output_names () const
1378 {
1379         if (audio_processor ()) {
1380                 return audio_processor()->input_names ();
1381         }
1382
1383         DCPOMATIC_ASSERT (MAX_DCP_AUDIO_CHANNELS == 16);
1384
1385         vector<string> n;
1386
1387         for (int i = 0; i < audio_channels(); ++i) {
1388                 n.push_back (short_audio_channel_name (i));
1389         }
1390
1391         return n;
1392 }
1393
1394 void
1395 Film::repeat_content (ContentList c, int n)
1396 {
1397         _playlist->repeat (c, n);
1398 }
1399
1400 void
1401 Film::remove_content (ContentList c)
1402 {
1403         _playlist->remove (c);
1404 }
1405
1406 void
1407 Film::audio_analysis_finished ()
1408 {
1409         /* XXX */
1410 }
1411
1412 list<DCPTimePeriod>
1413 Film::reels () const
1414 {
1415         list<DCPTimePeriod> p;
1416         DCPTime const len = length().round_up (video_frame_rate ());
1417
1418         switch (reel_type ()) {
1419         case REELTYPE_SINGLE:
1420                 p.push_back (DCPTimePeriod (DCPTime (), len));
1421                 break;
1422         case REELTYPE_BY_VIDEO_CONTENT:
1423         {
1424                 optional<DCPTime> last_split;
1425                 shared_ptr<Content> last_video;
1426                 BOOST_FOREACH (shared_ptr<Content> c, content ()) {
1427                         if (c->video) {
1428                                 BOOST_FOREACH (DCPTime t, c->reel_split_points()) {
1429                                         if (last_split) {
1430                                                 p.push_back (DCPTimePeriod (last_split.get(), t));
1431                                         }
1432                                         last_split = t;
1433                                 }
1434                                 last_video = c;
1435                         }
1436                 }
1437
1438                 DCPTime video_end = last_video ? last_video->end() : DCPTime(0);
1439                 if (last_split) {
1440                         /* Definitely go from the last split to the end of the video content */
1441                         p.push_back (DCPTimePeriod (last_split.get(), video_end));
1442                 }
1443
1444                 if (video_end < len) {
1445                         /* And maybe go after that as well if there is any non-video hanging over the end */
1446                         p.push_back (DCPTimePeriod (video_end, len));
1447                 }
1448                 break;
1449         }
1450         case REELTYPE_BY_LENGTH:
1451         {
1452                 DCPTime current;
1453                 /* Integer-divide reel length by the size of one frame to give the number of frames per reel */
1454                 Frame const reel_in_frames = _reel_length / ((j2k_bandwidth() / video_frame_rate()) / 8);
1455                 while (current < len) {
1456                         DCPTime end = min (len, current + DCPTime::from_frames (reel_in_frames, video_frame_rate ()));
1457                         p.push_back (DCPTimePeriod (current, end));
1458                         current = end;
1459                 }
1460                 break;
1461         }
1462         }
1463
1464         return p;
1465 }
1466
1467 string
1468 Film::content_summary (DCPTimePeriod period) const
1469 {
1470         return _playlist->content_summary (period);
1471 }
1472
1473 list<string>
1474 Film::fix_conflicting_settings ()
1475 {
1476         list<string> notes;
1477
1478         list<boost::filesystem::path> was_referencing;
1479         BOOST_FOREACH (shared_ptr<Content> i, content()) {
1480                 shared_ptr<DCPContent> d = dynamic_pointer_cast<DCPContent> (i);
1481                 if (d) {
1482                         list<string> reasons;
1483                         bool was = false;
1484                         if (!d->can_reference_video(reasons) && d->reference_video()) {
1485                                 d->set_reference_video (false);
1486                                 was = true;
1487                         }
1488                         if (!d->can_reference_audio(reasons) && d->reference_audio()) {
1489                                 d->set_reference_audio (false);
1490                                 was = true;
1491                         }
1492                         if (!d->can_reference_subtitle(reasons) && d->reference_subtitle()) {
1493                                 d->set_reference_subtitle (false);
1494                                 was = true;
1495                         }
1496                         if (was) {
1497                                 was_referencing.push_back (d->path(0).parent_path().filename());
1498                         }
1499                 }
1500         }
1501
1502         BOOST_FOREACH (boost::filesystem::path d, was_referencing) {
1503                 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()));
1504         }
1505
1506         return notes;
1507 }
1508
1509 void
1510 Film::use_template (string name)
1511 {
1512         _template_film.reset (new Film (optional<boost::filesystem::path>()));
1513         _template_film->read_metadata (Config::instance()->template_path (name));
1514         _use_isdcf_name = _template_film->_use_isdcf_name;
1515         _dcp_content_type = _template_film->_dcp_content_type;
1516         _container = _template_film->_container;
1517         _resolution = _template_film->_resolution;
1518         _j2k_bandwidth = _template_film->_j2k_bandwidth;
1519         _video_frame_rate = _template_film->_video_frame_rate;
1520         _signed = _template_film->_signed;
1521         _encrypted = _template_film->_encrypted;
1522         _audio_channels = _template_film->_audio_channels;
1523         _sequence = _template_film->_sequence;
1524         _three_d = _template_film->_three_d;
1525         _interop = _template_film->_interop;
1526         _audio_processor = _template_film->_audio_processor;
1527         _reel_type = _template_film->_reel_type;
1528         _reel_length = _template_film->_reel_length;
1529         _upload_after_make_dcp = _template_film->_upload_after_make_dcp;
1530 }