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