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