Some work on making KDMs in Film
[dcpomatic.git] / src / lib / film.cc
1 /*
2     Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include <stdexcept>
21 #include <iostream>
22 #include <algorithm>
23 #include <fstream>
24 #include <cstdlib>
25 #include <sstream>
26 #include <iomanip>
27 #include <unistd.h>
28 #include <boost/filesystem.hpp>
29 #include <boost/algorithm/string.hpp>
30 #include <boost/lexical_cast.hpp>
31 #include <boost/date_time.hpp>
32 #include <libxml++/libxml++.h>
33 #include <libdcp/crypt_chain.h>
34 #include <libdcp/certificates.h>
35 #include "cinema.h"
36 #include "film.h"
37 #include "format.h"
38 #include "job.h"
39 #include "filter.h"
40 #include "transcoder.h"
41 #include "util.h"
42 #include "job_manager.h"
43 #include "ab_transcode_job.h"
44 #include "transcode_job.h"
45 #include "scp_dcp_job.h"
46 #include "make_dcp_job.h"
47 #include "log.h"
48 #include "options.h"
49 #include "exceptions.h"
50 #include "examine_content_job.h"
51 #include "scaler.h"
52 #include "decoder_factory.h"
53 #include "config.h"
54 #include "check_hashes_job.h"
55 #include "version.h"
56 #include "ui_signaller.h"
57 #include "video_decoder.h"
58 #include "audio_decoder.h"
59 #include "external_audio_decoder.h"
60
61 using std::string;
62 using std::stringstream;
63 using std::multimap;
64 using std::pair;
65 using std::map;
66 using std::vector;
67 using std::ifstream;
68 using std::ofstream;
69 using std::setfill;
70 using std::min;
71 using std::make_pair;
72 using std::list;
73 using std::cout;
74 using boost::shared_ptr;
75 using boost::lexical_cast;
76 using boost::to_upper_copy;
77 using boost::ends_with;
78 using boost::starts_with;
79 using boost::optional;
80
81 int const Film::state_version = 1;
82
83 /** Construct a Film object in a given directory, reading any metadata
84  *  file that exists in that directory.  An exception will be thrown if
85  *  must_exist is true and the specified directory does not exist.
86  *
87  *  @param d Film directory.
88  *  @param must_exist true to throw an exception if does not exist.
89  */
90
91 Film::Film (string d, bool must_exist)
92         : _use_dci_name (true)
93         , _trust_content_header (true)
94         , _dcp_content_type (0)
95         , _format (0)
96         , _scaler (Scaler::from_id ("bicubic"))
97         , _dcp_trim_start (0)
98         , _dcp_trim_end (0)
99         , _dcp_ab (false)
100         , _use_content_audio (true)
101         , _audio_gain (0)
102         , _audio_delay (0)
103         , _still_duration (10)
104         , _with_subtitles (false)
105         , _subtitle_offset (0)
106         , _subtitle_scale (1)
107         , _encrypted (false)
108         , _frames_per_second (0)
109         , _dirty (false)
110 {
111         /* Make state.directory a complete path without ..s (where possible)
112            (Code swiped from Adam Bowen on stackoverflow)
113         */
114         
115         boost::filesystem::path p (boost::filesystem::system_complete (d));
116         boost::filesystem::path result;
117         for (boost::filesystem::path::iterator i = p.begin(); i != p.end(); ++i) {
118                 if (*i == "..") {
119                         if (boost::filesystem::is_symlink (result) || result.filename() == "..") {
120                                 result /= *i;
121                         } else {
122                                 result = result.parent_path ();
123                         }
124                 } else if (*i != ".") {
125                         result /= *i;
126                 }
127         }
128
129         set_directory (result.string ());
130         
131         if (!boost::filesystem::exists (directory())) {
132                 if (must_exist) {
133                         throw OpenFileError (directory());
134                 } else {
135                         boost::filesystem::create_directory (directory());
136                 }
137         }
138
139         _external_audio_stream = ExternalAudioStream::create ();
140         
141         if (must_exist) {
142                 read_metadata ();
143         }
144
145         _log = new FileLog (file ("log"));
146         set_dci_date_today ();
147 }
148
149 Film::Film (Film const & o)
150         : boost::enable_shared_from_this<Film> (o)
151         , _log (0)
152         , _directory         (o._directory)
153         , _name              (o._name)
154         , _use_dci_name      (o._use_dci_name)
155         , _content           (o._content)
156         , _trust_content_header (o._trust_content_header)
157         , _dcp_content_type  (o._dcp_content_type)
158         , _format            (o._format)
159         , _crop              (o._crop)
160         , _filters           (o._filters)
161         , _scaler            (o._scaler)
162         , _dcp_trim_start    (o._dcp_trim_start)
163         , _dcp_trim_end      (o._dcp_trim_end)
164         , _dcp_ab            (o._dcp_ab)
165         , _content_audio_stream (o._content_audio_stream)
166         , _external_audio    (o._external_audio)
167         , _use_content_audio (o._use_content_audio)
168         , _audio_gain        (o._audio_gain)
169         , _audio_delay       (o._audio_delay)
170         , _still_duration    (o._still_duration)
171         , _subtitle_stream   (o._subtitle_stream)
172         , _with_subtitles    (o._with_subtitles)
173         , _subtitle_offset   (o._subtitle_offset)
174         , _subtitle_scale    (o._subtitle_scale)
175         , _encrypted         (o._encrypted)
176         , _audio_language    (o._audio_language)
177         , _subtitle_language (o._subtitle_language)
178         , _territory         (o._territory)
179         , _rating            (o._rating)
180         , _studio            (o._studio)
181         , _facility          (o._facility)
182         , _package_type      (o._package_type)
183         , _size              (o._size)
184         , _length            (o._length)
185         , _content_digest    (o._content_digest)
186         , _content_audio_streams (o._content_audio_streams)
187         , _external_audio_stream (o._external_audio_stream)
188         , _subtitle_streams  (o._subtitle_streams)
189         , _frames_per_second (o._frames_per_second)
190         , _dirty             (o._dirty)
191 {
192
193 }
194
195 Film::~Film ()
196 {
197         delete _log;
198 }
199           
200 /** @return The path to the directory to write JPEG2000 files to */
201 string
202 Film::j2k_dir () const
203 {
204         assert (format());
205
206         boost::filesystem::path p;
207
208         /* Start with j2c */
209         p /= "j2c";
210
211         pair<string, string> f = Filter::ffmpeg_strings (filters());
212
213         /* Write stuff to specify the filter / post-processing settings that are in use,
214            so that we don't get confused about J2K files generated using different
215            settings.
216         */
217         stringstream s;
218         s << format()->id()
219           << "_" << content_digest()
220           << "_" << crop().left << "_" << crop().right << "_" << crop().top << "_" << crop().bottom
221           << "_" << f.first << "_" << f.second
222           << "_" << scaler()->id();
223
224         p /= s.str ();
225
226         /* Similarly for the A/B case */
227         if (dcp_ab()) {
228                 stringstream s;
229                 pair<string, string> fa = Filter::ffmpeg_strings (Config::instance()->reference_filters());
230                 s << "ab_" << Config::instance()->reference_scaler()->id() << "_" << fa.first << "_" << fa.second;
231                 p /= s.str ();
232         }
233         
234         return dir (p.string());
235 }
236
237 /** Add suitable Jobs to the JobManager to create a DCP for this Film.
238  *  @param true to transcode, false to use the WAV and J2K files that are already there.
239  */
240 void
241 Film::make_dcp (bool transcode)
242 {
243         set_dci_date_today ();
244         
245         if (dcp_name().find ("/") != string::npos) {
246                 throw BadSettingError ("name", "cannot contain slashes");
247         }
248         
249         log()->log (String::compose ("DVD-o-matic %1 git %2 using %3", dvdomatic_version, dvdomatic_git_commit, dependency_version_summary()));
250
251         {
252                 char buffer[128];
253                 gethostname (buffer, sizeof (buffer));
254                 log()->log (String::compose ("Starting to make DCP on %1", buffer));
255                 log()->log (String::compose ("Content is %1; type %2", content_path(), (content_type() == STILL ? "still" : "video")));
256                 log()->log (String::compose ("Content length %1", length()));
257         }
258                 
259         if (format() == 0) {
260                 throw MissingSettingError ("format");
261         }
262
263         if (content().empty ()) {
264                 throw MissingSettingError ("content");
265         }
266
267         if (dcp_content_type() == 0) {
268                 throw MissingSettingError ("content type");
269         }
270
271         if (name().empty()) {
272                 throw MissingSettingError ("name");
273         }
274
275         shared_ptr<EncodeOptions> oe (new EncodeOptions (j2k_dir(), ".j2c", dir ("wavs")));
276         oe->out_size = format()->dcp_size ();
277         oe->padding = format()->dcp_padding (shared_from_this ());
278         if (dcp_length ()) {
279                 oe->video_range = make_pair (dcp_trim_start(), dcp_trim_start() + dcp_length().get());
280                 if (audio_stream()) {
281                         oe->audio_range = make_pair (
282
283                                 video_frames_to_audio_frames (
284                                         oe->video_range.get().first,
285                                         dcp_audio_sample_rate (audio_stream()->sample_rate()),
286                                         dcp_frame_rate (frames_per_second()).frames_per_second
287                                         ),
288                                 
289                                 video_frames_to_audio_frames (
290                                         oe->video_range.get().second,
291                                         dcp_audio_sample_rate (audio_stream()->sample_rate()),
292                                         dcp_frame_rate (frames_per_second()).frames_per_second
293                                         )
294                                 );
295                 }
296                         
297         }
298         
299         oe->video_skip = dcp_frame_rate (frames_per_second()).skip;
300
301         shared_ptr<DecodeOptions> od (new DecodeOptions);
302         od->decode_subtitles = with_subtitles ();
303
304         shared_ptr<Job> r;
305
306         if (transcode) {
307                 if (dcp_ab()) {
308                         r = JobManager::instance()->add (shared_ptr<Job> (new ABTranscodeJob (shared_from_this(), od, oe, shared_ptr<Job> ())));
309                 } else {
310                         r = JobManager::instance()->add (shared_ptr<Job> (new TranscodeJob (shared_from_this(), od, oe, shared_ptr<Job> ())));
311                 }
312         }
313
314         r = JobManager::instance()->add (shared_ptr<Job> (new CheckHashesJob (shared_from_this(), od, oe, r)));
315         JobManager::instance()->add (shared_ptr<Job> (new MakeDCPJob (shared_from_this(), oe, r)));
316 }
317
318 /** Start a job to examine our content file */
319 void
320 Film::examine_content ()
321 {
322         if (_examine_content_job) {
323                 return;
324         }
325
326         _examine_content_job.reset (new ExamineContentJob (shared_from_this(), shared_ptr<Job> ()));
327         _examine_content_job->Finished.connect (bind (&Film::examine_content_finished, this));
328         JobManager::instance()->add (_examine_content_job);
329 }
330
331 void
332 Film::examine_content_finished ()
333 {
334         _examine_content_job.reset ();
335 }
336
337 /** @return full paths to any audio files that this Film has */
338 vector<string>
339 Film::audio_files () const
340 {
341         vector<string> f;
342         for (boost::filesystem::directory_iterator i = boost::filesystem::directory_iterator (dir("wavs")); i != boost::filesystem::directory_iterator(); ++i) {
343                 f.push_back (i->path().string ());
344         }
345
346         return f;
347 }
348
349 /** Start a job to send our DCP to the configured TMS */
350 void
351 Film::send_dcp_to_tms ()
352 {
353         shared_ptr<Job> j (new SCPDCPJob (shared_from_this(), shared_ptr<Job> ()));
354         JobManager::instance()->add (j);
355 }
356
357 /** Count the number of frames that have been encoded for this film.
358  *  @return frame count.
359  */
360 int
361 Film::encoded_frames () const
362 {
363         if (format() == 0) {
364                 return 0;
365         }
366
367         int N = 0;
368         for (boost::filesystem::directory_iterator i = boost::filesystem::directory_iterator (j2k_dir ()); i != boost::filesystem::directory_iterator(); ++i) {
369                 ++N;
370                 boost::this_thread::interruption_point ();
371         }
372
373         return N;
374 }
375
376 /** Write state to our `metadata' file */
377 void
378 Film::write_metadata () const
379 {
380         boost::mutex::scoped_lock lm (_state_mutex);
381
382         boost::filesystem::create_directories (directory());
383
384         string const m = file ("metadata");
385         ofstream f (m.c_str ());
386         if (!f.good ()) {
387                 throw CreateFileError (m);
388         }
389
390         f << "version " << state_version << "\n";
391
392         /* User stuff */
393         f << "name " << _name << "\n";
394         f << "use_dci_name " << _use_dci_name << "\n";
395         f << "content " << _content << "\n";
396         f << "trust_content_header " << (_trust_content_header ? "1" : "0") << "\n";
397         if (_dcp_content_type) {
398                 f << "dcp_content_type " << _dcp_content_type->pretty_name () << "\n";
399         }
400         if (_format) {
401                 f << "format " << _format->as_metadata () << "\n";
402         }
403         f << "left_crop " << _crop.left << "\n";
404         f << "right_crop " << _crop.right << "\n";
405         f << "top_crop " << _crop.top << "\n";
406         f << "bottom_crop " << _crop.bottom << "\n";
407         for (vector<Filter const *>::const_iterator i = _filters.begin(); i != _filters.end(); ++i) {
408                 f << "filter " << (*i)->id () << "\n";
409         }
410         f << "scaler " << _scaler->id () << "\n";
411         f << "dcp_trim_start " << _dcp_trim_start << "\n";
412         f << "dcp_trim_end " << _dcp_trim_end << "\n";
413         f << "dcp_ab " << (_dcp_ab ? "1" : "0") << "\n";
414         if (_content_audio_stream) {
415                 f << "selected_content_audio_stream " << _content_audio_stream->to_string() << "\n";
416         }
417         for (vector<string>::const_iterator i = _external_audio.begin(); i != _external_audio.end(); ++i) {
418                 f << "external_audio " << *i << "\n";
419         }
420         f << "use_content_audio " << (_use_content_audio ? "1" : "0") << "\n";
421         f << "audio_gain " << _audio_gain << "\n";
422         f << "audio_delay " << _audio_delay << "\n";
423         f << "still_duration " << _still_duration << "\n";
424         if (_subtitle_stream) {
425                 f << "selected_subtitle_stream " << _subtitle_stream->to_string() << "\n";
426         }
427         f << "with_subtitles " << _with_subtitles << "\n";
428         f << "subtitle_offset " << _subtitle_offset << "\n";
429         f << "subtitle_scale " << _subtitle_scale << "\n";
430         f << "encrypted " << _encrypted << "\n";
431         f << "audio_language " << _audio_language << "\n";
432         f << "subtitle_language " << _subtitle_language << "\n";
433         f << "territory " << _territory << "\n";
434         f << "rating " << _rating << "\n";
435         f << "studio " << _studio << "\n";
436         f << "facility " << _facility << "\n";
437         f << "package_type " << _package_type << "\n";
438
439         f << "width " << _size.width << "\n";
440         f << "height " << _size.height << "\n";
441         f << "length " << _length.get_value_or(0) << "\n";
442         f << "content_digest " << _content_digest << "\n";
443
444         for (vector<shared_ptr<AudioStream> >::const_iterator i = _content_audio_streams.begin(); i != _content_audio_streams.end(); ++i) {
445                 f << "content_audio_stream " << (*i)->to_string () << "\n";
446         }
447
448         f << "external_audio_stream " << _external_audio_stream->to_string() << "\n";
449
450         for (vector<shared_ptr<SubtitleStream> >::const_iterator i = _subtitle_streams.begin(); i != _subtitle_streams.end(); ++i) {
451                 f << "subtitle_stream " << (*i)->to_string () << "\n";
452         }
453
454         f << "frames_per_second " << _frames_per_second << "\n";
455         
456         _dirty = false;
457 }
458
459 /** Read state from our metadata file */
460 void
461 Film::read_metadata ()
462 {
463         boost::mutex::scoped_lock lm (_state_mutex);
464
465         _external_audio.clear ();
466         _content_audio_streams.clear ();
467         _subtitle_streams.clear ();
468
469         boost::optional<int> version;
470
471         /* Backward compatibility things */
472         boost::optional<int> audio_sample_rate;
473         boost::optional<int> audio_stream_index;
474         boost::optional<int> subtitle_stream_index;
475
476         ifstream f (file ("metadata").c_str());
477         if (!f.good()) {
478                 throw OpenFileError (file("metadata"));
479         }
480         
481         multimap<string, string> kv = read_key_value (f);
482
483         /* We need version before anything else */
484         multimap<string, string>::iterator v = kv.find ("version");
485         if (v != kv.end ()) {
486                 version = atoi (v->second.c_str());
487         }
488         
489         for (multimap<string, string>::const_iterator i = kv.begin(); i != kv.end(); ++i) {
490                 string const k = i->first;
491                 string const v = i->second;
492
493                 if (k == "audio_sample_rate") {
494                         audio_sample_rate = atoi (v.c_str());
495                 }
496
497                 /* User-specified stuff */
498                 if (k == "name") {
499                         _name = v;
500                 } else if (k == "use_dci_name") {
501                         _use_dci_name = (v == "1");
502                 } else if (k == "content") {
503                         _content = v;
504                 } else if (k == "trust_content_header") {
505                         _trust_content_header = (v == "1");
506                 } else if (k == "dcp_content_type") {
507                         _dcp_content_type = DCPContentType::from_pretty_name (v);
508                 } else if (k == "format") {
509                         _format = Format::from_metadata (v);
510                 } else if (k == "left_crop") {
511                         _crop.left = atoi (v.c_str ());
512                 } else if (k == "right_crop") {
513                         _crop.right = atoi (v.c_str ());
514                 } else if (k == "top_crop") {
515                         _crop.top = atoi (v.c_str ());
516                 } else if (k == "bottom_crop") {
517                         _crop.bottom = atoi (v.c_str ());
518                 } else if (k == "filter") {
519                         _filters.push_back (Filter::from_id (v));
520                 } else if (k == "scaler") {
521                         _scaler = Scaler::from_id (v);
522                 } else if (k == "dcp_trim_start") {
523                         _dcp_trim_start = atoi (v.c_str ());
524                 } else if (k == "dcp_trim_end") {
525                         _dcp_trim_end = atoi (v.c_str ());
526                 } else if (k == "dcp_ab") {
527                         _dcp_ab = (v == "1");
528                 } else if (k == "selected_content_audio_stream" || (!version && k == "selected_audio_stream")) {
529                         if (!version) {
530                                 audio_stream_index = atoi (v.c_str ());
531                         } else {
532                                 _content_audio_stream = audio_stream_factory (v, version);
533                         }
534                 } else if (k == "external_audio") {
535                         _external_audio.push_back (v);
536                 } else if (k == "use_content_audio") {
537                         _use_content_audio = (v == "1");
538                 } else if (k == "audio_gain") {
539                         _audio_gain = atof (v.c_str ());
540                 } else if (k == "audio_delay") {
541                         _audio_delay = atoi (v.c_str ());
542                 } else if (k == "still_duration") {
543                         _still_duration = atoi (v.c_str ());
544                 } else if (k == "selected_subtitle_stream") {
545                         if (!version) {
546                                 subtitle_stream_index = atoi (v.c_str ());
547                         } else {
548                                 _subtitle_stream = subtitle_stream_factory (v, version);
549                         }
550                 } else if (k == "with_subtitles") {
551                         _with_subtitles = (v == "1");
552                 } else if (k == "subtitle_offset") {
553                         _subtitle_offset = atoi (v.c_str ());
554                 } else if (k == "subtitle_scale") {
555                         _subtitle_scale = atof (v.c_str ());
556                 } else if (k == "encrypted") {
557                         _encrypted = (v == "1");
558                 } else if (k == "audio_language") {
559                         _audio_language = v;
560                 } else if (k == "subtitle_language") {
561                         _subtitle_language = v;
562                 } else if (k == "territory") {
563                         _territory = v;
564                 } else if (k == "rating") {
565                         _rating = v;
566                 } else if (k == "studio") {
567                         _studio = v;
568                 } else if (k == "facility") {
569                         _facility = v;
570                 } else if (k == "package_type") {
571                         _package_type = v;
572                 }
573                 
574                 /* Cached stuff */
575                 if (k == "width") {
576                         _size.width = atoi (v.c_str ());
577                 } else if (k == "height") {
578                         _size.height = atoi (v.c_str ());
579                 } else if (k == "length") {
580                         int const vv = atoi (v.c_str ());
581                         if (vv) {
582                                 _length = vv;
583                         }
584                 } else if (k == "content_digest") {
585                         _content_digest = v;
586                 } else if (k == "content_audio_stream" || (!version && k == "audio_stream")) {
587                         _content_audio_streams.push_back (audio_stream_factory (v, version));
588                 } else if (k == "external_audio_stream") {
589                         _external_audio_stream = audio_stream_factory (v, version);
590                 } else if (k == "subtitle_stream") {
591                         _subtitle_streams.push_back (subtitle_stream_factory (v, version));
592                 } else if (k == "frames_per_second") {
593                         _frames_per_second = atof (v.c_str ());
594                 }
595         }
596
597         if (!version) {
598                 if (audio_sample_rate) {
599                         /* version < 1 didn't specify sample rate in the audio streams, so fill it in here */
600                         for (vector<shared_ptr<AudioStream> >::iterator i = _content_audio_streams.begin(); i != _content_audio_streams.end(); ++i) {
601                                 (*i)->set_sample_rate (audio_sample_rate.get());
602                         }
603                 }
604
605                 /* also the selected stream was specified as an index */
606                 if (audio_stream_index && audio_stream_index.get() >= 0 && audio_stream_index.get() < (int) _content_audio_streams.size()) {
607                         _content_audio_stream = _content_audio_streams[audio_stream_index.get()];
608                 }
609
610                 /* similarly the subtitle */
611                 if (subtitle_stream_index && subtitle_stream_index.get() >= 0 && subtitle_stream_index.get() < (int) _subtitle_streams.size()) {
612                         _subtitle_stream = _subtitle_streams[subtitle_stream_index.get()];
613                 }
614         }
615                 
616         _dirty = false;
617 }
618
619 Size
620 Film::cropped_size (Size s) const
621 {
622         boost::mutex::scoped_lock lm (_state_mutex);
623         s.width -= _crop.left + _crop.right;
624         s.height -= _crop.top + _crop.bottom;
625         return s;
626 }
627
628 /** Given a directory name, return its full path within the Film's directory.
629  *  The directory (and its parents) will be created if they do not exist.
630  */
631 string
632 Film::dir (string d) const
633 {
634         boost::mutex::scoped_lock lm (_directory_mutex);
635         boost::filesystem::path p;
636         p /= _directory;
637         p /= d;
638         boost::filesystem::create_directories (p);
639         return p.string ();
640 }
641
642 /** Given a file or directory name, return its full path within the Film's directory.
643  *  _directory_mutex must not be locked on entry.
644  */
645 string
646 Film::file (string f) const
647 {
648         boost::mutex::scoped_lock lm (_directory_mutex);
649         boost::filesystem::path p;
650         p /= _directory;
651         p /= f;
652         return p.string ();
653 }
654
655 /** @return full path of the content (actual video) file
656  *  of the Film.
657  */
658 string
659 Film::content_path () const
660 {
661         boost::mutex::scoped_lock lm (_state_mutex);
662         if (boost::filesystem::path(_content).has_root_directory ()) {
663                 return _content;
664         }
665
666         return file (_content);
667 }
668
669 ContentType
670 Film::content_type () const
671 {
672         if (boost::filesystem::is_directory (_content)) {
673                 /* Directory of images, we assume */
674                 return VIDEO;
675         }
676
677         if (still_image_file (_content)) {
678                 return STILL;
679         }
680
681         return VIDEO;
682 }
683
684 /** @return The sampling rate that we will resample the audio to */
685 int
686 Film::target_audio_sample_rate () const
687 {
688         if (!audio_stream()) {
689                 return 0;
690         }
691         
692         /* Resample to a DCI-approved sample rate */
693         double t = dcp_audio_sample_rate (audio_stream()->sample_rate());
694
695         DCPFrameRate dfr = dcp_frame_rate (frames_per_second ());
696
697         /* Compensate for the fact that video will be rounded to the
698            nearest integer number of frames per second.
699         */
700         if (dfr.run_fast) {
701                 t *= _frames_per_second * dfr.skip / dfr.frames_per_second;
702         }
703
704         return rint (t);
705 }
706
707 boost::optional<int>
708 Film::dcp_length () const
709 {
710         if (content_type() == STILL) {
711                 return _still_duration * frames_per_second();
712         }
713         
714         if (!length()) {
715                 return boost::optional<int> ();
716         }
717
718         return length().get() - dcp_trim_start() - dcp_trim_end();
719 }
720
721 /** @return a DCI-compliant name for a DCP of this film */
722 string
723 Film::dci_name () const
724 {
725         stringstream d;
726
727         string fixed_name = to_upper_copy (name());
728         for (size_t i = 0; i < fixed_name.length(); ++i) {
729                 if (fixed_name[i] == ' ') {
730                         fixed_name[i] = '-';
731                 }
732         }
733
734         /* Spec is that the name part should be maximum 14 characters, as I understand it */
735         if (fixed_name.length() > 14) {
736                 fixed_name = fixed_name.substr (0, 14);
737         }
738
739         d << fixed_name << "_";
740
741         if (dcp_content_type()) {
742                 d << dcp_content_type()->dci_name() << "_";
743         }
744
745         if (format()) {
746                 d << format()->dci_name() << "_";
747         }
748
749         if (!audio_language().empty ()) {
750                 d << audio_language();
751                 if (!subtitle_language().empty() && with_subtitles()) {
752                         d << "-" << subtitle_language();
753                 } else {
754                         d << "-XX";
755                 }
756                         
757                 d << "_";
758         }
759
760         if (!territory().empty ()) {
761                 d << territory();
762                 if (!rating().empty ()) {
763                         d << "-" << rating();
764                 }
765                 d << "_";
766         }
767
768         switch (audio_channels()) {
769         case 1:
770                 d << "10_";
771                 break;
772         case 2:
773                 d << "20_";
774                 break;
775         case 6:
776                 d << "51_";
777                 break;
778         case 8:
779                 d << "71_";
780                 break;
781         }
782
783         d << "2K_";
784
785         if (!studio().empty ()) {
786                 d << studio() << "_";
787         }
788
789         d << boost::gregorian::to_iso_string (_dci_date) << "_";
790
791         if (!facility().empty ()) {
792                 d << facility() << "_";
793         }
794
795         if (!package_type().empty ()) {
796                 d << package_type();
797         }
798
799         return d.str ();
800 }
801
802 /** @return name to give the DCP */
803 string
804 Film::dcp_name () const
805 {
806         if (use_dci_name()) {
807                 return dci_name ();
808         }
809
810         return name();
811 }
812
813
814 void
815 Film::set_directory (string d)
816 {
817         boost::mutex::scoped_lock lm (_state_mutex);
818         _directory = d;
819         _dirty = true;
820 }
821
822 void
823 Film::set_name (string n)
824 {
825         {
826                 boost::mutex::scoped_lock lm (_state_mutex);
827                 _name = n;
828         }
829         signal_changed (NAME);
830 }
831
832 void
833 Film::set_use_dci_name (bool u)
834 {
835         {
836                 boost::mutex::scoped_lock lm (_state_mutex);
837                 _use_dci_name = u;
838         }
839         signal_changed (USE_DCI_NAME);
840 }
841
842 void
843 Film::set_content (string c)
844 {
845         string check = directory ();
846
847 #if BOOST_FILESYSTEM_VERSION == 3
848         boost::filesystem::path slash ("/");
849         string platform_slash = slash.make_preferred().string ();
850 #else
851 #ifdef DVDOMATIC_WINDOWS
852         string platform_slash = "\\";
853 #else
854         string platform_slash = "/";
855 #endif
856 #endif  
857
858         if (!ends_with (check, platform_slash)) {
859                 check += platform_slash;
860         }
861         
862         if (boost::filesystem::path(c).has_root_directory () && starts_with (c, check)) {
863                 c = c.substr (_directory.length() + 1);
864         }
865
866         string old_content;
867         
868         {
869                 boost::mutex::scoped_lock lm (_state_mutex);
870                 if (c == _content) {
871                         return;
872                 }
873
874                 old_content = _content;
875                 _content = c;
876         }
877
878         /* Reset streams here in case the new content doesn't have one or the other */
879         _content_audio_stream = shared_ptr<AudioStream> ();
880         _subtitle_stream = shared_ptr<SubtitleStream> ();
881
882         /* Start off using content audio */
883         set_use_content_audio (true);
884
885         /* Create a temporary decoder so that we can get information
886            about the content.
887         */
888
889         try {
890                 shared_ptr<DecodeOptions> o (new DecodeOptions);
891                 Decoders d = decoder_factory (shared_from_this(), o, 0);
892                 
893                 set_size (d.video->native_size ());
894                 set_frames_per_second (d.video->frames_per_second ());
895                 set_subtitle_streams (d.video->subtitle_streams ());
896                 if (d.audio) {
897                         set_content_audio_streams (d.audio->audio_streams ());
898                 }
899
900                 /* Start off with the first audio and subtitle streams */
901                 if (d.audio && !d.audio->audio_streams().empty()) {
902                         set_content_audio_stream (d.audio->audio_streams().front());
903                 }
904                 
905                 if (!d.video->subtitle_streams().empty()) {
906                         set_subtitle_stream (d.video->subtitle_streams().front());
907                 }
908                 
909                 {
910                         boost::mutex::scoped_lock lm (_state_mutex);
911                         _content = c;
912                 }
913                 
914                 signal_changed (CONTENT);
915                 
916                 examine_content ();
917
918         } catch (...) {
919
920                 boost::mutex::scoped_lock lm (_state_mutex);
921                 _content = old_content;
922                 throw;
923
924         }
925
926         /* Default format */
927         switch (content_type()) {
928         case STILL:
929                 set_format (Format::from_id ("var-185"));
930                 break;
931         case VIDEO:
932                 set_format (Format::from_id ("185"));
933                 break;
934         }
935
936         /* Still image DCPs must use external audio */
937         if (content_type() == STILL) {
938                 set_use_content_audio (false);
939         }
940 }
941
942 void
943 Film::set_trust_content_header (bool t)
944 {
945         {
946                 boost::mutex::scoped_lock lm (_state_mutex);
947                 _trust_content_header = t;
948         }
949         
950         signal_changed (TRUST_CONTENT_HEADER);
951
952         if (!_trust_content_header && !content().empty()) {
953                 /* We just said that we don't trust the content's header */
954                 examine_content ();
955         }
956 }
957                
958 void
959 Film::set_dcp_content_type (DCPContentType const * t)
960 {
961         {
962                 boost::mutex::scoped_lock lm (_state_mutex);
963                 _dcp_content_type = t;
964         }
965         signal_changed (DCP_CONTENT_TYPE);
966 }
967
968 void
969 Film::set_format (Format const * f)
970 {
971         {
972                 boost::mutex::scoped_lock lm (_state_mutex);
973                 _format = f;
974         }
975         signal_changed (FORMAT);
976 }
977
978 void
979 Film::set_crop (Crop c)
980 {
981         {
982                 boost::mutex::scoped_lock lm (_state_mutex);
983                 _crop = c;
984         }
985         signal_changed (CROP);
986 }
987
988 void
989 Film::set_left_crop (int c)
990 {
991         {
992                 boost::mutex::scoped_lock lm (_state_mutex);
993                 
994                 if (_crop.left == c) {
995                         return;
996                 }
997                 
998                 _crop.left = c;
999         }
1000         signal_changed (CROP);
1001 }
1002
1003 void
1004 Film::set_right_crop (int c)
1005 {
1006         {
1007                 boost::mutex::scoped_lock lm (_state_mutex);
1008                 if (_crop.right == c) {
1009                         return;
1010                 }
1011                 
1012                 _crop.right = c;
1013         }
1014         signal_changed (CROP);
1015 }
1016
1017 void
1018 Film::set_top_crop (int c)
1019 {
1020         {
1021                 boost::mutex::scoped_lock lm (_state_mutex);
1022                 if (_crop.top == c) {
1023                         return;
1024                 }
1025                 
1026                 _crop.top = c;
1027         }
1028         signal_changed (CROP);
1029 }
1030
1031 void
1032 Film::set_bottom_crop (int c)
1033 {
1034         {
1035                 boost::mutex::scoped_lock lm (_state_mutex);
1036                 if (_crop.bottom == c) {
1037                         return;
1038                 }
1039                 
1040                 _crop.bottom = c;
1041         }
1042         signal_changed (CROP);
1043 }
1044
1045 void
1046 Film::set_filters (vector<Filter const *> f)
1047 {
1048         {
1049                 boost::mutex::scoped_lock lm (_state_mutex);
1050                 _filters = f;
1051         }
1052         signal_changed (FILTERS);
1053 }
1054
1055 void
1056 Film::set_scaler (Scaler const * s)
1057 {
1058         {
1059                 boost::mutex::scoped_lock lm (_state_mutex);
1060                 _scaler = s;
1061         }
1062         signal_changed (SCALER);
1063 }
1064
1065 void
1066 Film::set_dcp_trim_start (int t)
1067 {
1068         {
1069                 boost::mutex::scoped_lock lm (_state_mutex);
1070                 _dcp_trim_start = t;
1071         }
1072         signal_changed (DCP_TRIM_START);
1073 }
1074
1075 void
1076 Film::set_dcp_trim_end (int t)
1077 {
1078         {
1079                 boost::mutex::scoped_lock lm (_state_mutex);
1080                 _dcp_trim_end = t;
1081         }
1082         signal_changed (DCP_TRIM_END);
1083 }
1084
1085 void
1086 Film::set_dcp_ab (bool a)
1087 {
1088         {
1089                 boost::mutex::scoped_lock lm (_state_mutex);
1090                 _dcp_ab = a;
1091         }
1092         signal_changed (DCP_AB);
1093 }
1094
1095 void
1096 Film::set_content_audio_stream (shared_ptr<AudioStream> s)
1097 {
1098         {
1099                 boost::mutex::scoped_lock lm (_state_mutex);
1100                 _content_audio_stream = s;
1101         }
1102         signal_changed (CONTENT_AUDIO_STREAM);
1103 }
1104
1105 void
1106 Film::set_external_audio (vector<string> a)
1107 {
1108         {
1109                 boost::mutex::scoped_lock lm (_state_mutex);
1110                 _external_audio = a;
1111         }
1112
1113         shared_ptr<DecodeOptions> o (new DecodeOptions);
1114         shared_ptr<ExternalAudioDecoder> decoder (new ExternalAudioDecoder (shared_from_this(), o, 0));
1115         if (decoder->audio_stream()) {
1116                 _external_audio_stream = decoder->audio_stream ();
1117         }
1118         
1119         signal_changed (EXTERNAL_AUDIO);
1120 }
1121
1122 void
1123 Film::set_use_content_audio (bool e)
1124 {
1125         {
1126                 boost::mutex::scoped_lock lm (_state_mutex);
1127                 _use_content_audio = e;
1128         }
1129
1130         signal_changed (USE_CONTENT_AUDIO);
1131 }
1132
1133 void
1134 Film::set_audio_gain (float g)
1135 {
1136         {
1137                 boost::mutex::scoped_lock lm (_state_mutex);
1138                 _audio_gain = g;
1139         }
1140         signal_changed (AUDIO_GAIN);
1141 }
1142
1143 void
1144 Film::set_audio_delay (int d)
1145 {
1146         {
1147                 boost::mutex::scoped_lock lm (_state_mutex);
1148                 _audio_delay = d;
1149         }
1150         signal_changed (AUDIO_DELAY);
1151 }
1152
1153 void
1154 Film::set_still_duration (int d)
1155 {
1156         {
1157                 boost::mutex::scoped_lock lm (_state_mutex);
1158                 _still_duration = d;
1159         }
1160         signal_changed (STILL_DURATION);
1161 }
1162
1163 void
1164 Film::set_subtitle_stream (shared_ptr<SubtitleStream> s)
1165 {
1166         {
1167                 boost::mutex::scoped_lock lm (_state_mutex);
1168                 _subtitle_stream = s;
1169         }
1170         signal_changed (SUBTITLE_STREAM);
1171 }
1172
1173 void
1174 Film::set_with_subtitles (bool w)
1175 {
1176         {
1177                 boost::mutex::scoped_lock lm (_state_mutex);
1178                 _with_subtitles = w;
1179         }
1180         signal_changed (WITH_SUBTITLES);
1181 }
1182
1183 void
1184 Film::set_subtitle_offset (int o)
1185 {
1186         {
1187                 boost::mutex::scoped_lock lm (_state_mutex);
1188                 _subtitle_offset = o;
1189         }
1190         signal_changed (SUBTITLE_OFFSET);
1191 }
1192
1193 void
1194 Film::set_subtitle_scale (float s)
1195 {
1196         {
1197                 boost::mutex::scoped_lock lm (_state_mutex);
1198                 _subtitle_scale = s;
1199         }
1200         signal_changed (SUBTITLE_SCALE);
1201 }
1202
1203 void
1204 Film::set_encrypted (bool e)
1205 {
1206         {
1207                 boost::mutex::scoped_lock lm (_state_mutex);
1208                 _encrypted = e;
1209         }
1210         signal_changed (ENCRYPTED);
1211 }
1212
1213 void
1214 Film::set_audio_language (string l)
1215 {
1216         {
1217                 boost::mutex::scoped_lock lm (_state_mutex);
1218                 _audio_language = l;
1219         }
1220         signal_changed (DCI_METADATA);
1221 }
1222
1223 void
1224 Film::set_subtitle_language (string l)
1225 {
1226         {
1227                 boost::mutex::scoped_lock lm (_state_mutex);
1228                 _subtitle_language = l;
1229         }
1230         signal_changed (DCI_METADATA);
1231 }
1232
1233 void
1234 Film::set_territory (string t)
1235 {
1236         {
1237                 boost::mutex::scoped_lock lm (_state_mutex);
1238                 _territory = t;
1239         }
1240         signal_changed (DCI_METADATA);
1241 }
1242
1243 void
1244 Film::set_rating (string r)
1245 {
1246         {
1247                 boost::mutex::scoped_lock lm (_state_mutex);
1248                 _rating = r;
1249         }
1250         signal_changed (DCI_METADATA);
1251 }
1252
1253 void
1254 Film::set_studio (string s)
1255 {
1256         {
1257                 boost::mutex::scoped_lock lm (_state_mutex);
1258                 _studio = s;
1259         }
1260         signal_changed (DCI_METADATA);
1261 }
1262
1263 void
1264 Film::set_facility (string f)
1265 {
1266         {
1267                 boost::mutex::scoped_lock lm (_state_mutex);
1268                 _facility = f;
1269         }
1270         signal_changed (DCI_METADATA);
1271 }
1272
1273 void
1274 Film::set_package_type (string p)
1275 {
1276         {
1277                 boost::mutex::scoped_lock lm (_state_mutex);
1278                 _package_type = p;
1279         }
1280         signal_changed (DCI_METADATA);
1281 }
1282
1283 void
1284 Film::set_size (Size s)
1285 {
1286         {
1287                 boost::mutex::scoped_lock lm (_state_mutex);
1288                 _size = s;
1289         }
1290         signal_changed (SIZE);
1291 }
1292
1293 void
1294 Film::set_length (SourceFrame l)
1295 {
1296         {
1297                 boost::mutex::scoped_lock lm (_state_mutex);
1298                 _length = l;
1299         }
1300         signal_changed (LENGTH);
1301 }
1302
1303 void
1304 Film::unset_length ()
1305 {
1306         {
1307                 boost::mutex::scoped_lock lm (_state_mutex);
1308                 _length = boost::none;
1309         }
1310         signal_changed (LENGTH);
1311 }       
1312
1313 void
1314 Film::set_content_digest (string d)
1315 {
1316         {
1317                 boost::mutex::scoped_lock lm (_state_mutex);
1318                 _content_digest = d;
1319         }
1320         _dirty = true;
1321 }
1322
1323 void
1324 Film::set_content_audio_streams (vector<shared_ptr<AudioStream> > s)
1325 {
1326         {
1327                 boost::mutex::scoped_lock lm (_state_mutex);
1328                 _content_audio_streams = s;
1329         }
1330         signal_changed (CONTENT_AUDIO_STREAMS);
1331 }
1332
1333 void
1334 Film::set_subtitle_streams (vector<shared_ptr<SubtitleStream> > s)
1335 {
1336         {
1337                 boost::mutex::scoped_lock lm (_state_mutex);
1338                 _subtitle_streams = s;
1339         }
1340         signal_changed (SUBTITLE_STREAMS);
1341 }
1342
1343 void
1344 Film::set_frames_per_second (float f)
1345 {
1346         {
1347                 boost::mutex::scoped_lock lm (_state_mutex);
1348                 _frames_per_second = f;
1349         }
1350         signal_changed (FRAMES_PER_SECOND);
1351 }
1352         
1353 void
1354 Film::signal_changed (Property p)
1355 {
1356         {
1357                 boost::mutex::scoped_lock lm (_state_mutex);
1358                 _dirty = true;
1359         }
1360
1361         if (ui_signaller) {
1362                 ui_signaller->emit (boost::bind (boost::ref (Changed), p));
1363         }
1364 }
1365
1366 int
1367 Film::audio_channels () const
1368 {
1369         shared_ptr<AudioStream> s = audio_stream ();
1370         if (!s) {
1371                 return 0;
1372         }
1373
1374         return s->channels ();
1375 }
1376
1377 void
1378 Film::set_dci_date_today ()
1379 {
1380         _dci_date = boost::gregorian::day_clock::local_day ();
1381 }
1382
1383 boost::shared_ptr<AudioStream>
1384 Film::audio_stream () const
1385 {
1386         if (use_content_audio()) {
1387                 return _content_audio_stream;
1388         }
1389
1390         return _external_audio_stream;
1391 }
1392
1393 void
1394 Film::make_kdms (
1395         list<shared_ptr<Screen> > screens,
1396         boost::posix_time::ptime from,
1397         boost::posix_time::ptime until,
1398         string directory
1399         ) const
1400 {
1401         string const cd = Config::instance()->crypt_chain_directory ();
1402         if (boost::filesystem::is_empty (cd)) {
1403                 libdcp::make_crypt_chain (cd);
1404         }
1405
1406         libdcp::CertificateChain chain;
1407
1408         {
1409                 boost::filesystem::path p (cd);
1410                 p /= "ca.self-signed.pem";
1411                 chain.add (shared_ptr<libdcp::Certificate> (new libdcp::Certificate (p.string ())));
1412         }
1413
1414         {
1415                 boost::filesystem::path p (cd);
1416                 p /= "intermediate.signed.pem";
1417                 chain.add (shared_ptr<libdcp::Certificate> (new libdcp::Certificate (p.string ())));
1418         }
1419
1420         {
1421                 boost::filesystem::path p (cd);
1422                 p /= "leaf.signed.pem";
1423                 chain.add (shared_ptr<libdcp::Certificate> (new libdcp::Certificate (p.string ())));
1424         }
1425
1426         boost::filesystem::path signer_key (cd);
1427         signer_key /= "leaf.key";
1428
1429         /* Find the DCP to make the KDM for */
1430         string const dir = this->directory ();
1431         list<string> dcps;
1432         for (boost::filesystem::directory_iterator i = boost::filesystem::directory_iterator(dir); i != boost::filesystem::directory_iterator(); ++i) {
1433                 if (boost::filesystem::is_directory (*i) && i->path().leaf() != "j2c" && i->path().leaf() != "wavs") {
1434                         dcps.push_back (i->path().string());
1435                 }
1436         }
1437
1438         if (dcps.empty()) {
1439                 throw KDMError ("Could not find DCP to make KDM for");
1440         } else if (dcps.size() > 1) {
1441                 throw KDMError ("More than one possible DCP to make KDM for");
1442         }
1443
1444         for (list<shared_ptr<Screen> >::iterator i = screens.begin(); i != screens.end(); ++i) {
1445
1446                 libdcp::DCP dcp (dcps.front ());
1447                 dcp.read ();
1448                 
1449                 /* XXX: single CPL only */
1450                 shared_ptr<xmlpp::Document> kdm = dcp.cpls().front()->make_kdm (chain, signer_key.string(), (*i)->certificate, from, until);
1451
1452                 boost::filesystem::path out = directory;
1453                 out /= "kdm.xml";
1454                 kdm->write_to_file_formatted (out.string());
1455         }
1456 }
1457