diff options
| author | Carl Hetherington <cth@carlh.net> | 2012-10-24 18:14:10 +0100 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2012-10-24 18:14:10 +0100 |
| commit | bd8fa9a370f1739952c83107352baa08c79d095e (patch) | |
| tree | dafa3dae2db5439dc08e770fc4b09febac5f0374 /src/lib | |
| parent | 44b57d623dec97a3f9955082f0b8a7a8d27b7518 (diff) | |
Merge FilmState / Film.
Diffstat (limited to 'src/lib')
52 files changed, 1464 insertions, 1625 deletions
diff --git a/src/lib/ab_transcode_job.cc b/src/lib/ab_transcode_job.cc index cffb2cef1..9e453d85d 100644 --- a/src/lib/ab_transcode_job.cc +++ b/src/lib/ab_transcode_job.cc @@ -24,38 +24,36 @@ #include "format.h" #include "filter.h" #include "ab_transcoder.h" -#include "film_state.h" #include "encoder_factory.h" #include "config.h" using namespace std; using namespace boost; -/** @param s FilmState to compare (with filters and/or a non-bicubic scaler). +/** @param f Film to compare. * @param o Options. - * @Param l A log that we can write to. */ -ABTranscodeJob::ABTranscodeJob (shared_ptr<const FilmState> s, shared_ptr<const Options> o, Log* l, shared_ptr<Job> req) - : Job (s, l, req) +ABTranscodeJob::ABTranscodeJob (shared_ptr<Film> f, shared_ptr<const Options> o, shared_ptr<Job> req) + : Job (f, req) , _opt (o) { - _fs_b.reset (new FilmState (*_fs)); - _fs_b->set_scaler (Config::instance()->reference_scaler ()); - _fs_b->set_filters (Config::instance()->reference_filters ()); + _film_b.reset (new Film (*_film)); + _film_b->set_scaler (Config::instance()->reference_scaler ()); + _film_b->set_filters (Config::instance()->reference_filters ()); } string ABTranscodeJob::name () const { - return String::compose ("A/B transcode %1", _fs->name()); + return String::compose ("A/B transcode %1", _film->name()); } void ABTranscodeJob::run () { try { - /* _fs_b is the one with no filters */ - ABTranscoder w (_fs_b, _fs, _opt, this, _log, encoder_factory (_fs, _opt, _log)); + /* _film_b is the one with reference filters */ + ABTranscoder w (_film_b, _film, _opt, this, encoder_factory (_film, _opt)); w.go (); set_progress (1); set_state (FINISHED_OK); diff --git a/src/lib/ab_transcode_job.h b/src/lib/ab_transcode_job.h index 2485608e6..8331edf76 100644 --- a/src/lib/ab_transcode_job.h +++ b/src/lib/ab_transcode_job.h @@ -24,17 +24,19 @@ #include <boost/shared_ptr.hpp> #include "job.h" +class Film; + /** @class ABTranscodeJob * @brief Job to run a transcoder which produces output for A/B comparison of various settings. * - * The right half of the frame will be processed using the FilmState supplied; - * the left half will be processed using the same state but *without* filters - * and with the scaler set to SWS_BICUBIC. + * The right half of the frame will be processed using the Film supplied; + * the left half will be processed using the same state but with the reference + * filters and scaler. */ class ABTranscodeJob : public Job { public: - ABTranscodeJob (boost::shared_ptr<const FilmState> s, boost::shared_ptr<const Options> o, Log* l, boost::shared_ptr<Job> req); + ABTranscodeJob (boost::shared_ptr<Film> f, boost::shared_ptr<const Options> o, boost::shared_ptr<Job> req); std::string name () const; void run (); @@ -42,8 +44,6 @@ public: private: boost::shared_ptr<const Options> _opt; - /** Copy of our FilmState with filters removed and scaler set back to bicubic; - * this is the `reference' (left-half-frame) state. - */ - boost::shared_ptr<FilmState> _fs_b; + /** Copy of our Film using the reference filters and scaler */ + boost::shared_ptr<Film> _film_b; }; diff --git a/src/lib/ab_transcoder.cc b/src/lib/ab_transcoder.cc index 08938a282..4f0ce0a71 100644 --- a/src/lib/ab_transcoder.cc +++ b/src/lib/ab_transcoder.cc @@ -25,39 +25,36 @@ #include "decoder.h" #include "encoder.h" #include "job.h" -#include "film_state.h" #include "options.h" #include "image.h" #include "decoder_factory.h" /** @file src/ab_transcoder.cc - * @brief A transcoder which uses one FilmState for the left half of the screen, and a different one + * @brief A transcoder which uses one Film for the left half of the screen, and a different one * for the right half (to facilitate A/B comparisons of settings) */ using namespace std; using namespace boost; -/** @param a FilmState to use for the left half of the screen. - * @param b FilmState to use for the right half of the screen. +/** @param a Film to use for the left half of the screen. + * @param b Film to use for the right half of the screen. * @param o Options. * @param j Job that we are associated with. - * @param l Log. * @param e Encoder to use. */ ABTranscoder::ABTranscoder ( - shared_ptr<const FilmState> a, shared_ptr<const FilmState> b, shared_ptr<const Options> o, Job* j, Log* l, shared_ptr<Encoder> e) - : _fs_a (a) - , _fs_b (b) + shared_ptr<Film> a, shared_ptr<Film> b, shared_ptr<const Options> o, Job* j, shared_ptr<Encoder> e) + : _film_a (a) + , _film_b (b) , _opt (o) , _job (j) - , _log (l) , _encoder (e) , _last_frame (0) { - _da = decoder_factory (_fs_a, o, j, _log); - _db = decoder_factory (_fs_b, o, j, _log); + _da = decoder_factory (_film_a, o, j); + _db = decoder_factory (_film_b, o, j); _da->Video.connect (sigc::bind (sigc::mem_fun (*this, &ABTranscoder::process_video), 0)); _db->Video.connect (sigc::bind (sigc::mem_fun (*this, &ABTranscoder::process_video), 1)); @@ -112,10 +109,6 @@ ABTranscoder::go () bool const a = _da->pass (); bool const b = _db->pass (); - if (_job) { - _job->set_progress (float (_last_frame) / _fs_a->dcp_length()); - } - if (a && b) { break; } diff --git a/src/lib/ab_transcoder.h b/src/lib/ab_transcoder.h index 491205ef7..7bf5dd4a1 100644 --- a/src/lib/ab_transcoder.h +++ b/src/lib/ab_transcoder.h @@ -18,7 +18,7 @@ */ /** @file src/ab_transcoder.h - * @brief A transcoder which uses one FilmState for the left half of the screen, and a different one + * @brief A transcoder which uses one Film for the left half of the screen, and a different one * for the right half (to facilitate A/B comparisons of settings) */ @@ -28,25 +28,24 @@ class Job; class Encoder; class Decoder; -class FilmState; class Options; class Image; class Log; class Subtitle; +class Film; /** @class ABTranscoder - * @brief A transcoder which uses one FilmState for the left half of the screen, and a different one + * @brief A transcoder which uses one Film for the left half of the screen, and a different one * for the right half (to facilitate A/B comparisons of settings) */ class ABTranscoder { public: ABTranscoder ( - boost::shared_ptr<const FilmState> a, - boost::shared_ptr<const FilmState> b, + boost::shared_ptr<Film> a, + boost::shared_ptr<Film> b, boost::shared_ptr<const Options> o, Job* j, - Log* l, boost::shared_ptr<Encoder> e ); @@ -57,11 +56,10 @@ public: private: void process_video (boost::shared_ptr<Image>, int, boost::shared_ptr<Subtitle>, int); - boost::shared_ptr<const FilmState> _fs_a; - boost::shared_ptr<const FilmState> _fs_b; + boost::shared_ptr<Film> _film_a; + boost::shared_ptr<Film> _film_b; boost::shared_ptr<const Options> _opt; Job* _job; - Log* _log; boost::shared_ptr<Encoder> _encoder; boost::shared_ptr<Decoder> _da; boost::shared_ptr<Decoder> _db; diff --git a/src/lib/check_hashes_job.cc b/src/lib/check_hashes_job.cc index 478e4c91a..c6460ff60 100644 --- a/src/lib/check_hashes_job.cc +++ b/src/lib/check_hashes_job.cc @@ -21,18 +21,18 @@ #include <boost/lexical_cast.hpp> #include <boost/filesystem.hpp> #include "check_hashes_job.h" -#include "film_state.h" #include "options.h" #include "log.h" #include "job_manager.h" #include "ab_transcode_job.h" #include "transcode_job.h" +#include "film.h" using namespace std; using namespace boost; -CheckHashesJob::CheckHashesJob (shared_ptr<const FilmState> s, shared_ptr<const Options> o, Log* l, shared_ptr<Job> req) - : Job (s, l, req) +CheckHashesJob::CheckHashesJob (shared_ptr<Film> f, shared_ptr<const Options> o, shared_ptr<Job> req) + : Job (f, req) , _opt (o) , _bad (0) { @@ -42,7 +42,7 @@ CheckHashesJob::CheckHashesJob (shared_ptr<const FilmState> s, shared_ptr<const string CheckHashesJob::name () const { - return String::compose ("Check hashes of %1", _fs->name()); + return String::compose ("Check hashes of %1", _film->name()); } void @@ -50,18 +50,18 @@ CheckHashesJob::run () { _bad = 0; - int const N = _fs->dcp_length (); + int const N = _film->dcp_length (); for (int i = 0; i < N; ++i) { string const j2k_file = _opt->frame_out_path (i, false); string const hash_file = j2k_file + ".md5"; if (!filesystem::exists (j2k_file)) { - _log->log (String::compose ("Frame %1 has a missing J2K file.", i)); + _film->log()->log (String::compose ("Frame %1 has a missing J2K file.", i)); filesystem::remove (hash_file); ++_bad; } else if (!filesystem::exists (hash_file)) { - _log->log (String::compose ("Frame %1 has a missing hash file.", i)); + _film->log()->log (String::compose ("Frame %1 has a missing hash file.", i)); filesystem::remove (j2k_file); ++_bad; } else { @@ -69,27 +69,27 @@ CheckHashesJob::run () string hash; ref >> hash; if (hash != md5_digest (j2k_file)) { - _log->log (String::compose ("Frame %1 has wrong hash; deleting.", i)); + _film->log()->log (String::compose ("Frame %1 has wrong hash; deleting.", i)); filesystem::remove (j2k_file); filesystem::remove (hash_file); ++_bad; } } - set_progress (float (i) / _fs->length()); + set_progress (float (i) / _film->length()); } if (_bad) { shared_ptr<Job> tc; - if (_fs->dcp_ab()) { - tc.reset (new ABTranscodeJob (_fs, _opt, _log, shared_from_this())); + if (_film->dcp_ab()) { + tc.reset (new ABTranscodeJob (_film, _opt, shared_from_this())); } else { - tc.reset (new TranscodeJob (_fs, _opt, _log, shared_from_this())); + tc.reset (new TranscodeJob (_film, _opt, shared_from_this())); } JobManager::instance()->add_after (shared_from_this(), tc); - JobManager::instance()->add_after (tc, shared_ptr<Job> (new CheckHashesJob (_fs, _opt, _log, tc))); + JobManager::instance()->add_after (tc, shared_ptr<Job> (new CheckHashesJob (_film, _opt, tc))); } set_progress (1); diff --git a/src/lib/check_hashes_job.h b/src/lib/check_hashes_job.h index 7cf1789f6..e0ed6a64a 100644 --- a/src/lib/check_hashes_job.h +++ b/src/lib/check_hashes_job.h @@ -22,7 +22,7 @@ class CheckHashesJob : public Job { public: - CheckHashesJob (boost::shared_ptr<const FilmState> s, boost::shared_ptr<const Options> o, Log* l, boost::shared_ptr<Job> req); + CheckHashesJob (boost::shared_ptr<Film> f, boost::shared_ptr<const Options> o, boost::shared_ptr<Job> req); std::string name () const; void run (); diff --git a/src/lib/copy_from_dvd_job.cc b/src/lib/copy_from_dvd_job.cc index e08718072..c43723aa0 100644 --- a/src/lib/copy_from_dvd_job.cc +++ b/src/lib/copy_from_dvd_job.cc @@ -25,18 +25,17 @@ #include <boost/algorithm/string.hpp> #include <boost/filesystem.hpp> #include "copy_from_dvd_job.h" -#include "film_state.h" #include "dvd.h" #include "cross.h" +#include "film.h" using namespace std; using namespace boost; -/** @param fs FilmState for the film to write DVD data into. - * @param l Log that we can write to. +/** @param f Film to write DVD data into. */ -CopyFromDVDJob::CopyFromDVDJob (shared_ptr<const FilmState> fs, Log* l, shared_ptr<Job> req) - : Job (fs, l, req) +CopyFromDVDJob::CopyFromDVDJob (shared_ptr<Film> f, shared_ptr<Job> req) + : Job (f, req) { } @@ -51,7 +50,7 @@ void CopyFromDVDJob::run () { /* Remove any old DVD rips */ - filesystem::remove_all (_fs->dir ("dvd")); + filesystem::remove_all (_film->dir ("dvd")); string const dvd = find_dvd (); if (dvd.empty ()) { @@ -75,7 +74,7 @@ CopyFromDVDJob::run () } stringstream c; - c << "vobcopy -n " << longest_title << " -l -o \"" << _fs->dir ("dvd") << "\" 2>&1"; + c << "vobcopy -n " << longest_title << " -l -o \"" << _film->dir ("dvd") << "\" 2>&1"; FILE* f = popen (c.str().c_str(), "r"); if (f == 0) { diff --git a/src/lib/copy_from_dvd_job.h b/src/lib/copy_from_dvd_job.h index ce3837100..063e94358 100644 --- a/src/lib/copy_from_dvd_job.h +++ b/src/lib/copy_from_dvd_job.h @@ -29,7 +29,7 @@ class CopyFromDVDJob : public Job { public: - CopyFromDVDJob (boost::shared_ptr<const FilmState>, Log *, boost::shared_ptr<Job> req); + CopyFromDVDJob (boost::shared_ptr<Film>, boost::shared_ptr<Job> req); std::string name () const; void run (); diff --git a/src/lib/dcp_content_type.h b/src/lib/dcp_content_type.h index b703970a3..2b6e60a19 100644 --- a/src/lib/dcp_content_type.h +++ b/src/lib/dcp_content_type.h @@ -17,6 +17,9 @@ */ +#ifndef DVDOMATIC_DCP_CONTENT_TYPE_H +#define DVDOMATIC_DCP_CONTENT_TYPE_H + /** @file src/content_type.h * @brief A description of the type of content for a DCP (e.g. feature, trailer etc.) */ @@ -61,3 +64,4 @@ private: static std::vector<DCPContentType const *> _dcp_content_types; }; +#endif diff --git a/src/lib/dcp_video_frame.cc b/src/lib/dcp_video_frame.cc index 916a57bc8..4f84a8302 100644 --- a/src/lib/dcp_video_frame.cc +++ b/src/lib/dcp_video_frame.cc @@ -47,7 +47,6 @@ #include "dcp_video_frame.h" #include "lut.h" #include "config.h" -#include "film_state.h" #include "options.h" #include "exceptions.h" #include "server.h" diff --git a/src/lib/decoder.cc b/src/lib/decoder.cc index 045c1b818..9c339737a 100644 --- a/src/lib/decoder.cc +++ b/src/lib/decoder.cc @@ -38,7 +38,6 @@ extern "C" { #include "film.h" #include "format.h" #include "job.h" -#include "film_state.h" #include "options.h" #include "exceptions.h" #include "image.h" @@ -53,19 +52,17 @@ extern "C" { using namespace std; using namespace boost; -/** @param s FilmState of the Film. +/** @param f Film. * @param o Options. * @param j Job that we are running within, or 0 - * @param l Log to use. * @param minimal true to do the bare minimum of work; just run through the content. Useful for acquiring * accurate frame counts as quickly as possible. This generates no video or audio output. * @param ignore_length Ignore the content's claimed length when computing progress. */ -Decoder::Decoder (boost::shared_ptr<const FilmState> s, boost::shared_ptr<const Options> o, Job* j, Log* l, bool minimal, bool ignore_length) - : _fs (s) +Decoder::Decoder (boost::shared_ptr<Film> f, boost::shared_ptr<const Options> o, Job* j, bool minimal, bool ignore_length) + : _film (f) , _opt (o) , _job (j) - , _log (l) , _minimal (minimal) , _ignore_length (ignore_length) , _video_frame (0) @@ -76,7 +73,7 @@ Decoder::Decoder (boost::shared_ptr<const FilmState> s, boost::shared_ptr<const , _delay_in_bytes (0) , _audio_frames_processed (0) { - if (_opt->decode_video_frequency != 0 && _fs->length() == 0) { + if (_opt->decode_video_frequency != 0 && _film->length() == 0) { throw DecodeError ("cannot do a partial decode if length == 0"); } } @@ -90,7 +87,7 @@ Decoder::~Decoder () void Decoder::process_begin () { - _delay_in_bytes = _fs->audio_delay() * _fs->audio_sample_rate() * _fs->audio_channels() * bytes_per_audio_sample() / 1000; + _delay_in_bytes = _film->audio_delay() * _film->audio_sample_rate() * _film->audio_channels() * bytes_per_audio_sample() / 1000; delete _delay_line; _delay_line = new DelayLine (_delay_in_bytes); @@ -104,7 +101,7 @@ Decoder::process_end () if (_delay_in_bytes < 0) { uint8_t remainder[-_delay_in_bytes]; _delay_line->get_remaining (remainder); - _audio_frames_processed += _delay_in_bytes / (_fs->audio_channels() * bytes_per_audio_sample()); + _audio_frames_processed += _delay_in_bytes / (_film->audio_channels() * bytes_per_audio_sample()); emit_audio (remainder, -_delay_in_bytes); } @@ -112,28 +109,28 @@ Decoder::process_end () in to get it to the right length. */ - int64_t const video_length_in_audio_frames = ((int64_t) _fs->dcp_length() * _fs->audio_sample_rate() / _fs->frames_per_second()); + int64_t const video_length_in_audio_frames = ((int64_t) _film->dcp_length() * _film->audio_sample_rate() / _film->frames_per_second()); int64_t const audio_short_by_frames = video_length_in_audio_frames - _audio_frames_processed; _log->log ( String::compose ("DCP length is %1 (%2 audio frames); %3 frames of audio processed.", - _fs->dcp_length(), + _film->dcp_length(), video_length_in_audio_frames, _audio_frames_processed) ); if (audio_short_by_frames >= 0 && _opt->decode_audio) { - _log->log (String::compose ("DCP length is %1; %2 frames of audio processed.", _fs->dcp_length(), _audio_frames_processed)); + _log->log (String::compose ("DCP length is %1; %2 frames of audio processed.", _film->dcp_length(), _audio_frames_processed)); _log->log (String::compose ("Adding %1 frames of silence to the end.", audio_short_by_frames)); /* XXX: this is slightly questionable; does memset () give silence with all sample formats? */ - int64_t bytes = audio_short_by_frames * _fs->audio_channels() * bytes_per_audio_sample(); + int64_t bytes = audio_short_by_frames * _film->audio_channels() * bytes_per_audio_sample(); - int64_t const silence_size = 16 * 1024 * _fs->audio_channels() * bytes_per_audio_sample(); + int64_t const silence_size = 16 * 1024 * _film->audio_channels() * bytes_per_audio_sample(); uint8_t silence[silence_size]; memset (silence, 0, silence_size); @@ -157,7 +154,7 @@ Decoder::go () while (pass () == false) { if (_job && !_ignore_length) { - _job->set_progress (float (_video_frame) / _fs->dcp_length()); + _job->set_progress (float (_video_frame) / _film->dcp_length()); } } @@ -176,7 +173,7 @@ Decoder::pass () _have_setup_video_filters = true; } - if (!_ignore_length && _video_frame >= _fs->dcp_length()) { + if (!_ignore_length && _video_frame >= _film->dcp_length()) { return true; } @@ -184,7 +181,7 @@ Decoder::pass () } /** Called by subclasses to tell the world that some audio data is ready - * @param data Audio data, in FilmState::audio_sample_format. + * @param data Audio data, in Film::audio_sample_format. * @param size Number of bytes of data. */ void @@ -201,11 +198,11 @@ Decoder::emit_audio (uint8_t* data, int size) { /* Deinterleave and convert to float */ - assert ((size % (bytes_per_audio_sample() * _fs->audio_channels())) == 0); + assert ((size % (bytes_per_audio_sample() * _film->audio_channels())) == 0); int const total_samples = size / bytes_per_audio_sample(); - int const frames = total_samples / _fs->audio_channels(); - shared_ptr<AudioBuffers> audio (new AudioBuffers (_fs->audio_channels(), frames)); + int const frames = total_samples / _film->audio_channels(); + shared_ptr<AudioBuffers> audio (new AudioBuffers (_film->audio_channels(), frames)); switch (audio_sample_format()) { case AV_SAMPLE_FMT_S16: @@ -217,7 +214,7 @@ Decoder::emit_audio (uint8_t* data, int size) audio->data(channel)[sample] = float(*p++) / (1 << 15); ++channel; - if (channel == _fs->audio_channels()) { + if (channel == _film->audio_channels()) { channel = 0; ++sample; } @@ -234,7 +231,7 @@ Decoder::emit_audio (uint8_t* data, int size) audio->data(channel)[sample] = float(*p++) / (1 << 31); ++channel; - if (channel == _fs->audio_channels()) { + if (channel == _film->audio_channels()) { channel = 0; ++sample; } @@ -244,7 +241,7 @@ Decoder::emit_audio (uint8_t* data, int size) case AV_SAMPLE_FMT_FLTP: { float* p = reinterpret_cast<float*> (data); - for (int i = 0; i < _fs->audio_channels(); ++i) { + for (int i = 0; i < _film->audio_channels(); ++i) { memcpy (audio->data(i), p, frames * sizeof(float)); p += frames; } @@ -256,9 +253,9 @@ Decoder::emit_audio (uint8_t* data, int size) } /* Maybe apply gain */ - if (_fs->audio_gain() != 0) { - float const linear_gain = pow (10, _fs->audio_gain() / 20); - for (int i = 0; i < _fs->audio_channels(); ++i) { + if (_film->audio_gain() != 0) { + float const linear_gain = pow (10, _film->audio_gain() / 20); + for (int i = 0; i < _film->audio_channels(); ++i) { for (int j = 0; j < frames; ++j) { audio->data(i)[j] *= linear_gain; } @@ -283,11 +280,11 @@ Decoder::process_video (AVFrame* frame) return; } - /* Use FilmState::length here as our one may be wrong */ + /* Use Film::length here as our one may be wrong */ int gap = 0; if (_opt->decode_video_frequency != 0) { - gap = _fs->length() / _opt->decode_video_frequency; + gap = _film->length() / _opt->decode_video_frequency; } if (_opt->decode_video_frequency != 0 && gap != 0 && (_video_frame % gap) != 0) { @@ -352,7 +349,7 @@ Decoder::process_video (AVFrame* frame) } shared_ptr<Subtitle> sub; - if (_timed_subtitle && _timed_subtitle->displayed_at (double (last_video_frame()) / _fs->frames_per_second())) { + if (_timed_subtitle && _timed_subtitle->displayed_at (double (last_video_frame()) / _film->frames_per_second())) { sub = _timed_subtitle->subtitle (); } @@ -374,14 +371,14 @@ Decoder::setup_video_filters () Size size_after_crop; if (_opt->apply_crop) { - size_after_crop = _fs->cropped_size (native_size ()); - fs << crop_string (Position (_fs->crop().left, _fs->crop().top), size_after_crop); + size_after_crop = _film->cropped_size (native_size ()); + fs << crop_string (Position (_film->crop().left, _film->crop().top), size_after_crop); } else { size_after_crop = native_size (); fs << crop_string (Position (0, 0), size_after_crop); } - string filters = Filter::ffmpeg_strings (_fs->filters()).first; + string filters = Filter::ffmpeg_strings (_film->filters()).first; if (!filters.empty ()) { filters += ","; } @@ -465,7 +462,7 @@ Decoder::process_subtitle (shared_ptr<TimedSubtitle> s) if (_timed_subtitle && _opt->apply_crop) { Position const p = _timed_subtitle->subtitle()->position (); - _timed_subtitle->subtitle()->set_position (Position (p.x - _fs->crop().left, p.y - _fs->crop().top)); + _timed_subtitle->subtitle()->set_position (Position (p.x - _film->crop().left, p.y - _film->crop().top)); } } diff --git a/src/lib/decoder.h b/src/lib/decoder.h index f530de0eb..ed7eaeb17 100644 --- a/src/lib/decoder.h +++ b/src/lib/decoder.h @@ -33,13 +33,13 @@ #include "stream.h" class Job; -class FilmState; class Options; class Image; class Log; class DelayLine; class TimedSubtitle; class Subtitle; +class Film; /** @class Decoder. * @brief Parent class for decoders of content. @@ -51,7 +51,7 @@ class Subtitle; class Decoder { public: - Decoder (boost::shared_ptr<const FilmState>, boost::shared_ptr<const Options>, Job *, Log *, bool, bool); + Decoder (boost::shared_ptr<Film>, boost::shared_ptr<const Options>, Job *, bool, bool); virtual ~Decoder (); /* Methods to query our input video */ @@ -112,8 +112,8 @@ protected: int bytes_per_audio_sample () const; - /** our FilmState */ - boost::shared_ptr<const FilmState> _fs; + /** our Film */ + boost::shared_ptr<Film> _film; /** our options */ boost::shared_ptr<const Options> _opt; /** associated Job, or 0 */ diff --git a/src/lib/decoder_factory.cc b/src/lib/decoder_factory.cc index c03912094..56fb56296 100644 --- a/src/lib/decoder_factory.cc +++ b/src/lib/decoder_factory.cc @@ -25,27 +25,27 @@ #include "ffmpeg_decoder.h" #include "tiff_decoder.h" #include "imagemagick_decoder.h" -#include "film_state.h" +#include "film.h" using namespace std; using namespace boost; shared_ptr<Decoder> decoder_factory ( - shared_ptr<const FilmState> fs, shared_ptr<const Options> o, Job* j, Log* l, bool minimal = false, bool ignore_length = false + shared_ptr<Film> f, shared_ptr<const Options> o, Job* j, bool minimal = false, bool ignore_length = false ) { - if (filesystem::is_directory (fs->content_path ())) { + if (filesystem::is_directory (f->content_path ())) { /* Assume a directory contains TIFFs */ - return shared_ptr<Decoder> (new TIFFDecoder (fs, o, j, l, minimal, ignore_length)); + return shared_ptr<Decoder> (new TIFFDecoder (f, o, j, minimal, ignore_length)); } - if (fs->content_type() == STILL) { + if (f->content_type() == STILL) { /* Always ignore length of decodes of stills, since the decoder finishes very quickly and it's the encoder that takes the time. */ - return shared_ptr<Decoder> (new ImageMagickDecoder (fs, o, j, l, minimal, true)); + return shared_ptr<Decoder> (new ImageMagickDecoder (f, o, j, minimal, true)); } - return shared_ptr<Decoder> (new FFmpegDecoder (fs, o, j, l, minimal, ignore_length)); + return shared_ptr<Decoder> (new FFmpegDecoder (f, o, j, minimal, ignore_length)); } diff --git a/src/lib/decoder_factory.h b/src/lib/decoder_factory.h index 36c14951f..81dcec944 100644 --- a/src/lib/decoder_factory.h +++ b/src/lib/decoder_factory.h @@ -22,11 +22,11 @@ */ class Decoder; -class FilmState; +class Film; class Options; class Job; class Log; extern boost::shared_ptr<Decoder> decoder_factory ( - boost::shared_ptr<const FilmState>, boost::shared_ptr<const Options>, Job *, Log *, bool minimal = false, bool ignore_length = false + boost::shared_ptr<Film>, boost::shared_ptr<const Options>, Job *, bool minimal = false, bool ignore_length = false ); diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index 62ba922da..7352dcfb1 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -28,14 +28,12 @@ using namespace boost; int const Encoder::_history_size = 25; -/** @param s FilmState of the film that we are encoding. +/** @param f Film that we are encoding. * @param o Options. - * @param l Log. */ -Encoder::Encoder (shared_ptr<const FilmState> s, shared_ptr<const Options> o, Log* l) - : _fs (s) +Encoder::Encoder (shared_ptr<const Film> f, shared_ptr<const Options> o) + : _film (f) , _opt (o) - , _log (l) , _just_skipped (false) , _last_frame (0) { diff --git a/src/lib/encoder.h b/src/lib/encoder.h index 561e41901..4d741a92b 100644 --- a/src/lib/encoder.h +++ b/src/lib/encoder.h @@ -32,12 +32,11 @@ extern "C" { #include <libavutil/samplefmt.h> } -class FilmState; class Options; class Image; -class Log; class Subtitle; class AudioBuffers; +class Film; /** @class Encoder * @brief Parent class for classes which can encode video and audio frames. @@ -52,7 +51,7 @@ class AudioBuffers; class Encoder { public: - Encoder (boost::shared_ptr<const FilmState> s, boost::shared_ptr<const Options> o, Log* l); + Encoder (boost::shared_ptr<const Film> f, boost::shared_ptr<const Options> o); /** Called to indicate that a processing run is about to begin */ virtual void process_begin (int64_t audio_channel_layout) = 0; @@ -81,12 +80,10 @@ protected: void frame_done (int n); void frame_skipped (); - /** FilmState of the film that we are encoding */ - boost::shared_ptr<const FilmState> _fs; + /** Film that we are encoding */ + boost::shared_ptr<const Film> _film; /** Options */ boost::shared_ptr<const Options> _opt; - /** Log */ - Log* _log; /** Mutex for _time_history, _just_skipped and _last_frame */ mutable boost::mutex _history_mutex; diff --git a/src/lib/encoder_factory.cc b/src/lib/encoder_factory.cc index d16150fa6..df45535cf 100644 --- a/src/lib/encoder_factory.cc +++ b/src/lib/encoder_factory.cc @@ -24,17 +24,17 @@ #include <boost/filesystem.hpp> #include "j2k_wav_encoder.h" #include "j2k_still_encoder.h" -#include "film_state.h" +#include "film.h" using namespace std; using namespace boost; shared_ptr<Encoder> -encoder_factory (shared_ptr<const FilmState> fs, shared_ptr<const Options> o, Log* l) +encoder_factory (shared_ptr<const Film> f, shared_ptr<const Options> o) { - if (!filesystem::is_directory (fs->content_path()) && fs->content_type() == STILL) { - return shared_ptr<Encoder> (new J2KStillEncoder (fs, o, l)); + if (!filesystem::is_directory (f->content_path()) && f->content_type() == STILL) { + return shared_ptr<Encoder> (new J2KStillEncoder (f, o)); } - return shared_ptr<Encoder> (new J2KWAVEncoder (fs, o, l)); + return shared_ptr<Encoder> (new J2KWAVEncoder (f, o)); } diff --git a/src/lib/encoder_factory.h b/src/lib/encoder_factory.h index 2803de6f0..1bc4e18df 100644 --- a/src/lib/encoder_factory.h +++ b/src/lib/encoder_factory.h @@ -22,9 +22,9 @@ */ class Encoder; -class FilmState; class Options; class Job; class Log; +class Film; -extern boost::shared_ptr<Encoder> encoder_factory (boost::shared_ptr<const FilmState>, boost::shared_ptr<const Options>, Log *); +extern boost::shared_ptr<Encoder> encoder_factory (boost::shared_ptr<const Film>, boost::shared_ptr<const Options>); diff --git a/src/lib/examine_content_job.cc b/src/lib/examine_content_job.cc index f0fb29812..0187e1776 100644 --- a/src/lib/examine_content_job.cc +++ b/src/lib/examine_content_job.cc @@ -23,18 +23,18 @@ #include "examine_content_job.h" #include "options.h" -#include "film_state.h" #include "decoder_factory.h" #include "decoder.h" #include "imagemagick_encoder.h" #include "transcoder.h" #include "log.h" +#include "film.h" using namespace std; using namespace boost; -ExamineContentJob::ExamineContentJob (shared_ptr<const FilmState> fs, Log* l, shared_ptr<Job> req) - : Job (fs, l, req) +ExamineContentJob::ExamineContentJob (shared_ptr<Film> f, shared_ptr<Job> req) + : Job (f, req) { } @@ -46,18 +46,16 @@ ExamineContentJob::~ExamineContentJob () string ExamineContentJob::name () const { - if (_fs->name().empty ()) { + if (_film->name().empty ()) { return "Examine content"; } - return String::compose ("Examine content of %1", _fs->name()); + return String::compose ("Examine content of %1", _film->name()); } void ExamineContentJob::run () { - shared_ptr<FilmState> fs = _fs->state_copy (); - /* Decode the content to get an accurate length */ shared_ptr<Options> o (new Options ("", "", "")); @@ -66,12 +64,12 @@ ExamineContentJob::run () descend (0.5); - _decoder = decoder_factory (fs, o, this, _log, true, true); + _decoder = decoder_factory (_film, o, this, true, true); _decoder->go (); - fs->set_length (_decoder->last_video_frame ()); + _film->set_length (_decoder->last_video_frame ()); - _log->log (String::compose ("Video length is %1 frames", _decoder->last_video_frame())); + _film->log()->log (String::compose ("Video length is %1 frames", _decoder->last_video_frame())); ascend (); @@ -80,14 +78,14 @@ ExamineContentJob::run () descend (0.5); try { - o.reset (new Options (fs->dir ("thumbs"), ".png", "")); - o->out_size = fs->size (); + o.reset (new Options (_film->dir ("thumbs"), ".png", "")); + o->out_size = _film->size (); o->apply_crop = false; o->decode_audio = false; o->decode_video_frequency = 128; o->decode_subtitles = true; - shared_ptr<ImageMagickEncoder> e (new ImageMagickEncoder (fs, o, _log)); - Transcoder w (fs, o, this, _log, e); + shared_ptr<ImageMagickEncoder> e (new ImageMagickEncoder (_film, o)); + Transcoder w (_film, o, this, e); w.go (); } catch (std::exception& e) { diff --git a/src/lib/examine_content_job.h b/src/lib/examine_content_job.h index 3bbd673a8..098b9d132 100644 --- a/src/lib/examine_content_job.h +++ b/src/lib/examine_content_job.h @@ -31,7 +31,7 @@ class Decoder; class ExamineContentJob : public Job { public: - ExamineContentJob (boost::shared_ptr<const FilmState>, Log *, boost::shared_ptr<Job> req); + ExamineContentJob (boost::shared_ptr<Film>, boost::shared_ptr<Job> req); ~ExamineContentJob (); std::string name () const; diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc index 9891bb55b..30701797a 100644 --- a/src/lib/ffmpeg_decoder.cc +++ b/src/lib/ffmpeg_decoder.cc @@ -41,7 +41,6 @@ extern "C" { #include "transcoder.h" #include "job.h" #include "filter.h" -#include "film_state.h" #include "options.h" #include "exceptions.h" #include "image.h" @@ -53,8 +52,8 @@ extern "C" { using namespace std; using namespace boost; -FFmpegDecoder::FFmpegDecoder (boost::shared_ptr<const FilmState> s, boost::shared_ptr<const Options> o, Job* j, Log* l, bool minimal, bool ignore_length) - : Decoder (s, o, j, l, minimal, ignore_length) +FFmpegDecoder::FFmpegDecoder (boost::shared_ptr<Film> f, boost::shared_ptr<const Options> o, Job* j, bool minimal, bool ignore_length) + : Decoder (f, o, j, minimal, ignore_length) , _format_context (0) , _video_stream (-1) , _audio_stream (-1) @@ -98,8 +97,8 @@ FFmpegDecoder::setup_general () av_register_all (); - if ((r = avformat_open_input (&_format_context, _fs->content_path().c_str(), 0, 0)) != 0) { - throw OpenFileError (_fs->content_path ()); + if ((r = avformat_open_input (&_format_context, _film->content_path().c_str(), 0, 0)) != 0) { + throw OpenFileError (_film->content_path ()); } if (avformat_find_stream_info (_format_context, 0) < 0) { @@ -127,12 +126,12 @@ FFmpegDecoder::setup_general () /* Now override audio and subtitle streams with those from the Film, if it has any */ - if (_fs->audio_stream_index() != -1) { - _audio_stream = _fs->audio_stream().id(); + if (_film->audio_stream_index() != -1) { + _audio_stream = _film->audio_stream().id(); } - if (_fs->subtitle_stream_index() != -1) { - _subtitle_stream = _fs->subtitle_stream().id (); + if (_film->subtitle_stream_index() != -1) { + _subtitle_stream = _film->subtitle_stream().id (); } if (_video_stream < 0) { @@ -236,7 +235,7 @@ FFmpegDecoder::do_pass () 0, _audio_codec_context->channels, _frame->nb_samples, audio_sample_format (), 1 ); - assert (_audio_codec_context->channels == _fs->audio_channels()); + assert (_audio_codec_context->channels == _film->audio_channels()); process_audio (_frame->data[0], data_size); } } @@ -300,7 +299,7 @@ FFmpegDecoder::do_pass () 0, _audio_codec_context->channels, _frame->nb_samples, audio_sample_format (), 1 ); - assert (_audio_codec_context->channels == _fs->audio_channels()); + assert (_audio_codec_context->channels == _film->audio_channels()); process_audio (_frame->data[0], data_size); } diff --git a/src/lib/ffmpeg_decoder.h b/src/lib/ffmpeg_decoder.h index 26b5d6979..abcdfa0b2 100644 --- a/src/lib/ffmpeg_decoder.h +++ b/src/lib/ffmpeg_decoder.h @@ -42,7 +42,6 @@ struct AVBufferContext; struct AVCodec; struct AVStream; class Job; -class FilmState; class Options; class Image; class Log; @@ -53,7 +52,7 @@ class Log; class FFmpegDecoder : public Decoder { public: - FFmpegDecoder (boost::shared_ptr<const FilmState>, boost::shared_ptr<const Options>, Job *, Log *, bool, bool); + FFmpegDecoder (boost::shared_ptr<Film>, boost::shared_ptr<const Options>, Job *, bool, bool); ~FFmpegDecoder (); /* Methods to query our input video */ diff --git a/src/lib/film.cc b/src/lib/film.cc index aa0bfa211..7ce56138a 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -28,6 +28,7 @@ #include <boost/filesystem.hpp> #include <boost/algorithm/string.hpp> #include <boost/lexical_cast.hpp> +#include <boost/date_time.hpp> #include "film.h" #include "format.h" #include "imagemagick_encoder.h" @@ -41,7 +42,6 @@ #include "scp_dcp_job.h" #include "copy_from_dvd_job.h" #include "make_dcp_job.h" -#include "film_state.h" #include "log.h" #include "options.h" #include "exceptions.h" @@ -64,6 +64,26 @@ using namespace boost; */ Film::Film (string d, bool must_exist) + : _use_dci_name (false) + , _dcp_content_type (0) + , _format (0) + , _scaler (Scaler::from_id ("bicubic")) + , _dcp_frames (0) + , _dcp_trim_action (CUT) + , _dcp_ab (false) + , _audio_stream (-1) + , _audio_gain (0) + , _audio_delay (0) + , _still_duration (10) + , _subtitle_stream (-1) + , _with_subtitles (false) + , _subtitle_offset (0) + , _subtitle_scale (1) + , _length (0) + , _audio_sample_rate (0) + , _has_subtitles (false) + , _frames_per_second (0) + , _dirty (false) { /* Make state.directory a complete path without ..s (where possible) (Code swiped from Adam Bowen on stackoverflow) @@ -98,6 +118,49 @@ Film::Film (string d, bool must_exist) _log = new FileLog (file ("log")); } +Film::Film (Film const & o) + : _log (0) + , _directory (o._directory) + , _name (o._name) + , _use_dci_name (o._use_dci_name) + , _content (o._content) + , _dcp_content_type (o._dcp_content_type) + , _format (o._format) + , _crop (o._crop) + , _filters (o._filters) + , _scaler (o._scaler) + , _dcp_frames (o._dcp_frames) + , _dcp_trim_action (o._dcp_trim_action) + , _dcp_ab (o._dcp_ab) + , _audio_stream (o._audio_stream) + , _audio_gain (o._audio_gain) + , _audio_delay (o._audio_delay) + , _still_duration (o._still_duration) + , _subtitle_stream (o._subtitle_stream) + , _with_subtitles (o._with_subtitles) + , _subtitle_offset (o._subtitle_offset) + , _subtitle_scale (o._subtitle_scale) + , _audio_language (o._audio_language) + , _subtitle_language (o._subtitle_language) + , _territory (o._territory) + , _rating (o._rating) + , _studio (o._studio) + , _facility (o._facility) + , _package_type (o._package_type) + , _thumbs (o._thumbs) + , _size (o._size) + , _length (o._length) + , _audio_sample_rate (o._audio_sample_rate) + , _content_digest (o._content_digest) + , _has_subtitles (o._has_subtitles) + , _audio_streams (o._audio_streams) + , _subtitle_streams (o._subtitle_streams) + , _frames_per_second (o._frames_per_second) + , _dirty (o._dirty) +{ + +} + Film::~Film () { delete _log; @@ -174,7 +237,6 @@ Film::make_dcp (bool transcode) throw MissingSettingError ("name"); } - shared_ptr<const FilmState> fs = state_copy (); shared_ptr<Options> o (new Options (j2k_dir(), ".j2c", dir ("wavs"))); o->out_size = format()->dcp_size (); if (dcp_frames() == 0) { @@ -200,14 +262,14 @@ Film::make_dcp (bool transcode) if (transcode) { if (dcp_ab()) { - r = JobManager::instance()->add (shared_ptr<Job> (new ABTranscodeJob (fs, o, log(), shared_ptr<Job> ()))); + r = JobManager::instance()->add (shared_ptr<Job> (new ABTranscodeJob (shared_from_this(), o, shared_ptr<Job> ()))); } else { - r = JobManager::instance()->add (shared_ptr<Job> (new TranscodeJob (fs, o, log(), shared_ptr<Job> ()))); + r = JobManager::instance()->add (shared_ptr<Job> (new TranscodeJob (shared_from_this(), o, shared_ptr<Job> ()))); } } - r = JobManager::instance()->add (shared_ptr<Job> (new CheckHashesJob (fs, o, log(), r))); - JobManager::instance()->add (shared_ptr<Job> (new MakeDCPJob (fs, o, log(), r))); + r = JobManager::instance()->add (shared_ptr<Job> (new CheckHashesJob (shared_from_this(), o, r))); + JobManager::instance()->add (shared_ptr<Job> (new MakeDCPJob (shared_from_this(), o, r))); } void @@ -247,7 +309,7 @@ Film::examine_content () /* This call will recreate the directory */ dir ("thumbs"); - _examine_content_job.reset (new ExamineContentJob (state_copy (), log(), shared_ptr<Job> ())); + _examine_content_job.reset (new ExamineContentJob (shared_from_this(), shared_ptr<Job> ())); _examine_content_job->Finished.connect (sigc::mem_fun (*this, &Film::examine_content_post_gui)); JobManager::instance()->add (_examine_content_job); } @@ -298,14 +360,14 @@ Film::audio_files () const void Film::send_dcp_to_tms () { - shared_ptr<Job> j (new SCPDCPJob (state_copy (), log(), shared_ptr<Job> ())); + shared_ptr<Job> j (new SCPDCPJob (shared_from_this(), shared_ptr<Job> ())); JobManager::instance()->add (j); } void Film::copy_from_dvd () { - shared_ptr<Job> j (new CopyFromDVDJob (state_copy (), log(), shared_ptr<Job> ())); + shared_ptr<Job> j (new CopyFromDVDJob (shared_from_this(), shared_ptr<Job> ())); j->Finished.connect (sigc::mem_fun (*this, &Film::copy_from_dvd_post_gui)); JobManager::instance()->add (j); } @@ -358,9 +420,785 @@ Film::thumb_subtitle (int n) const return sub; } +/** Write state to our `metadata' file */ +void +Film::write_metadata () const +{ + filesystem::create_directories (directory()); + + string const m = file ("metadata"); + ofstream f (m.c_str ()); + if (!f.good ()) { + throw CreateFileError (m); + } + + /* User stuff */ + f << "name " << _name << "\n"; + f << "use_dci_name " << _use_dci_name << "\n"; + f << "content " << _content << "\n"; + if (_dcp_content_type) { + f << "dcp_content_type " << _dcp_content_type->pretty_name () << "\n"; + } + if (_format) { + f << "format " << _format->as_metadata () << "\n"; + } + f << "left_crop " << _crop.left << "\n"; + f << "right_crop " << _crop.right << "\n"; + f << "top_crop " << _crop.top << "\n"; + f << "bottom_crop " << _crop.bottom << "\n"; + for (vector<Filter const *>::const_iterator i = _filters.begin(); i != _filters.end(); ++i) { + f << "filter " << (*i)->id () << "\n"; + } + f << "scaler " << _scaler->id () << "\n"; + f << "dcp_frames " << _dcp_frames << "\n"; + + f << "dcp_trim_action "; + switch (_dcp_trim_action) { + case CUT: + f << "cut\n"; + break; + case BLACK_OUT: + f << "black_out\n"; + break; + } + + f << "dcp_ab " << (_dcp_ab ? "1" : "0") << "\n"; + f << "selected_audio_stream " << _audio_stream << "\n"; + f << "audio_gain " << _audio_gain << "\n"; + f << "audio_delay " << _audio_delay << "\n"; + f << "still_duration " << _still_duration << "\n"; + f << "selected_subtitle_stream " << _subtitle_stream << "\n"; + f << "with_subtitles " << _with_subtitles << "\n"; + f << "subtitle_offset " << _subtitle_offset << "\n"; + f << "subtitle_scale " << _subtitle_scale << "\n"; + f << "audio_language " << _audio_language << "\n"; + f << "subtitle_language " << _subtitle_language << "\n"; + f << "territory " << _territory << "\n"; + f << "rating " << _rating << "\n"; + f << "studio " << _studio << "\n"; + f << "facility " << _facility << "\n"; + f << "package_type " << _package_type << "\n"; + + /* Cached stuff; this is information about our content; we could + look it up each time, but that's slow. + */ + for (vector<int>::const_iterator i = _thumbs.begin(); i != _thumbs.end(); ++i) { + f << "thumb " << *i << "\n"; + } + f << "width " << _size.width << "\n"; + f << "height " << _size.height << "\n"; + f << "length " << _length << "\n"; + f << "audio_sample_rate " << _audio_sample_rate << "\n"; + f << "content_digest " << _content_digest << "\n"; + f << "has_subtitles " << _has_subtitles << "\n"; + + for (vector<AudioStream>::const_iterator i = _audio_streams.begin(); i != _audio_streams.end(); ++i) { + f << "audio_stream " << i->to_string () << "\n"; + } + + for (vector<SubtitleStream>::const_iterator i = _subtitle_streams.begin(); i != _subtitle_streams.end(); ++i) { + f << "subtitle_stream " << i->to_string () << "\n"; + } + + f << "frames_per_second " << _frames_per_second << "\n"; + + _dirty = false; +} + +/** Read state from our metadata file */ +void +Film::read_metadata () +{ + ifstream f (file("metadata").c_str()); + multimap<string, string> kv = read_key_value (f); + for (multimap<string, string>::const_iterator i = kv.begin(); i != kv.end(); ++i) { + string const k = i->first; + string const v = i->second; + + /* User-specified stuff */ + if (k == "name") { + _name = v; + } else if (k == "use_dci_name") { + _use_dci_name = (v == "1"); + } else if (k == "content") { + _content = v; + } else if (k == "dcp_content_type") { + _dcp_content_type = DCPContentType::from_pretty_name (v); + } else if (k == "format") { + _format = Format::from_metadata (v); + } else if (k == "left_crop") { + _crop.left = atoi (v.c_str ()); + } else if (k == "right_crop") { + _crop.right = atoi (v.c_str ()); + } else if (k == "top_crop") { + _crop.top = atoi (v.c_str ()); + } else if (k == "bottom_crop") { + _crop.bottom = atoi (v.c_str ()); + } else if (k == "filter") { + _filters.push_back (Filter::from_id (v)); + } else if (k == "scaler") { + _scaler = Scaler::from_id (v); + } else if (k == "dcp_frames") { + _dcp_frames = atoi (v.c_str ()); + } else if (k == "dcp_trim_action") { + if (v == "cut") { + _dcp_trim_action = CUT; + } else if (v == "black_out") { + _dcp_trim_action = BLACK_OUT; + } + } else if (k == "dcp_ab") { + _dcp_ab = (v == "1"); + } else if (k == "selected_audio_stream") { + _audio_stream = atoi (v.c_str ()); + } else if (k == "audio_gain") { + _audio_gain = atof (v.c_str ()); + } else if (k == "audio_delay") { + _audio_delay = atoi (v.c_str ()); + } else if (k == "still_duration") { + _still_duration = atoi (v.c_str ()); + } else if (k == "selected_subtitle_stream") { + _subtitle_stream = atoi (v.c_str ()); + } else if (k == "with_subtitles") { + _with_subtitles = (v == "1"); + } else if (k == "subtitle_offset") { + _subtitle_offset = atoi (v.c_str ()); + } else if (k == "subtitle_scale") { + _subtitle_scale = atof (v.c_str ()); + } else if (k == "audio_language") { + _audio_language = v; + } else if (k == "subtitle_language") { + _subtitle_language = v; + } else if (k == "territory") { + _territory = v; + } else if (k == "rating") { + _rating = v; + } else if (k == "studio") { + _studio = v; + } else if (k == "facility") { + _facility = v; + } else if (k == "package_type") { + _package_type = v; + } + + /* Cached stuff */ + if (k == "thumb") { + int const n = atoi (v.c_str ()); + /* Only add it to the list if it still exists */ + if (filesystem::exists (thumb_file_for_frame (n))) { + _thumbs.push_back (n); + } + } else if (k == "width") { + _size.width = atoi (v.c_str ()); + } else if (k == "height") { + _size.height = atoi (v.c_str ()); + } else if (k == "length") { + _length = atof (v.c_str ()); + } else if (k == "audio_sample_rate") { + _audio_sample_rate = atoi (v.c_str ()); + } else if (k == "content_digest") { + _content_digest = v; + } else if (k == "has_subtitles") { + _has_subtitles = (v == "1"); + } else if (k == "audio_stream") { + _audio_streams.push_back (AudioStream (v)); + } else if (k == "subtitle_stream") { + _subtitle_streams.push_back (SubtitleStream (v)); + } else if (k == "frames_per_second") { + _frames_per_second = atof (v.c_str ()); + } + } + + _dirty = false; +} + +/** @param n A thumb index. + * @return The path to the thumb's image file. + */ +string +Film::thumb_file (int n) const +{ + return thumb_file_for_frame (thumb_frame (n)); +} + +/** @param n A frame index within the Film. + * @return The path to the thumb's image file for this frame; + * we assume that it exists. + */ +string +Film::thumb_file_for_frame (int n) const +{ + return thumb_base_for_frame(n) + ".png"; +} + +string +Film::thumb_base (int n) const +{ + return thumb_base_for_frame (thumb_frame (n)); +} + +string +Film::thumb_base_for_frame (int n) const +{ + stringstream s; + s.width (8); + s << setfill('0') << n; + + filesystem::path p; + p /= dir ("thumbs"); + p /= s.str (); + + return p.string (); +} + + +/** @param n A thumb index. + * @return The frame within the Film that it is for. + */ +int +Film::thumb_frame (int n) const +{ + assert (n < int (_thumbs.size ())); + return _thumbs[n]; +} + +Size +Film::cropped_size (Size s) const +{ + s.width -= _crop.left + _crop.right; + s.height -= _crop.top + _crop.bottom; + return s; +} + +/** Given a directory name, return its full path within the Film's directory. + * The directory (and its parents) will be created if they do not exist. + */ +string +Film::dir (string d) const +{ + filesystem::path p; + p /= _directory; + p /= d; + filesystem::create_directories (p); + return p.string (); +} + +/** Given a file or directory name, return its full path within the Film's directory */ +string +Film::file (string f) const +{ + filesystem::path p; + p /= _directory; + p /= f; + return p.string (); +} + +/** @return full path of the content (actual video) file + * of the Film. + */ +string +Film::content_path () const +{ + if (filesystem::path(_content).has_root_directory ()) { + return _content; + } + + return file (_content); +} + +ContentType +Film::content_type () const +{ +#if BOOST_FILESYSTEM_VERSION == 3 + string ext = filesystem::path(_content).extension().string(); +#else + string ext = filesystem::path(_content).extension(); +#endif + + transform (ext.begin(), ext.end(), ext.begin(), ::tolower); + + if (ext == ".tif" || ext == ".tiff" || ext == ".jpg" || ext == ".jpeg" || ext == ".png") { + return STILL; + } + + return VIDEO; +} + +/** @return The sampling rate that we will resample the audio to */ +int +Film::target_audio_sample_rate () const +{ + /* Resample to a DCI-approved sample rate */ + double t = dcp_audio_sample_rate (_audio_sample_rate); + + /* Compensate for the fact that video will be rounded to the + nearest integer number of frames per second. + */ + if (rint (_frames_per_second) != _frames_per_second) { + t *= _frames_per_second / rint (_frames_per_second); + } + + return rint (t); +} + +int +Film::dcp_length () const +{ + if (_dcp_frames) { + return _dcp_frames; + } + + return _length; +} + +/** @return a DCI-compliant name for a DCP of this film */ +string +Film::dci_name () const +{ + stringstream d; + + string fixed_name = to_upper_copy (_name); + for (size_t i = 0; i < fixed_name.length(); ++i) { + if (fixed_name[i] == ' ') { + fixed_name[i] = '-'; + } + } + + /* Spec is that the name part should be maximum 14 characters, as I understand it */ + if (fixed_name.length() > 14) { + fixed_name = fixed_name.substr (0, 14); + } + + d << fixed_name << "_"; + + if (_dcp_content_type) { + d << _dcp_content_type->dci_name() << "_"; + } + + if (_format) { + d << _format->dci_name() << "_"; + } + + if (!_audio_language.empty ()) { + d << _audio_language; + if (!_subtitle_language.empty() && _with_subtitles) { + d << "-" << _subtitle_language; + } else { + d << "-XX"; + } + + d << "_"; + } + + if (!_territory.empty ()) { + d << _territory; + if (!_rating.empty ()) { + d << "-" << _rating; + } + d << "_"; + } + + switch (_audio_streams[_audio_stream].channels()) { + case 1: + d << "10_"; + break; + case 2: + d << "20_"; + break; + case 6: + d << "51_"; + break; + case 8: + d << "71_"; + break; + } + + d << "2K_"; + + if (!_studio.empty ()) { + d << _studio << "_"; + } + + gregorian::date today = gregorian::day_clock::local_day (); + d << gregorian::to_iso_string (today) << "_"; + + if (!_facility.empty ()) { + d << _facility << "_"; + } + + if (!_package_type.empty ()) { + d << _package_type; + } + + return d.str (); +} + +/** @return name to give the DCP */ +string +Film::dcp_name () const +{ + if (_use_dci_name) { + return dci_name (); + } + + return _name; +} + + +void +Film::set_directory (string d) +{ + _directory = d; + _dirty = true; +} + +void +Film::set_name (string n) +{ + _name = n; + signal_changed (NAME); +} + +void +Film::set_use_dci_name (bool u) +{ + _use_dci_name = u; + signal_changed (USE_DCI_NAME); +} + void Film::set_content (string c) { - FilmState::set_content (c); - examine_content (); + string check = _directory; + +#if BOOST_FILESYSTEM_VERSION == 3 + filesystem::path slash ("/"); + string platform_slash = slash.make_preferred().string (); +#else +#ifdef DVDOMATIC_WINDOWS + string platform_slash = "\\"; +#else + string platform_slash = "/"; +#endif +#endif + + if (!ends_with (check, platform_slash)) { + check += platform_slash; + } + + if (filesystem::path(c).has_root_directory () && starts_with (c, check)) { + c = c.substr (_directory.length() + 1); + } + + if (c == _content) { + return; + } + + /* Create a temporary decoder so that we can get information + about the content. + */ + + _content = c; + + shared_ptr<Options> o (new Options ("", "", "")); + o->out_size = Size (1024, 1024); + + shared_ptr<Decoder> d = decoder_factory (shared_from_this(), o, 0, 0); + + set_size (d->native_size ()); + set_frames_per_second (d->frames_per_second ()); + set_audio_sample_rate (d->audio_sample_rate ()); + set_has_subtitles (d->has_subtitles ()); + set_audio_streams (d->audio_streams ()); + set_subtitle_streams (d->subtitle_streams ()); + set_audio_stream (audio_streams().empty() ? -1 : 0); + set_subtitle_stream (subtitle_streams().empty() ? -1 : 0); + + signal_changed (CONTENT); + + set_content_digest (md5_digest (content_path ())); +} + +void +Film::set_dcp_content_type (DCPContentType const * t) +{ + _dcp_content_type = t; + signal_changed (DCP_CONTENT_TYPE); +} + +void +Film::set_format (Format const * f) +{ + _format = f; + signal_changed (FORMAT); +} + +void +Film::set_crop (Crop c) +{ + _crop = c; + signal_changed (CROP); +} + +void +Film::set_left_crop (int c) +{ + if (_crop.left == c) { + return; + } + + _crop.left = c; + signal_changed (CROP); +} + +void +Film::set_right_crop (int c) +{ + if (_crop.right == c) { + return; + } + + _crop.right = c; + signal_changed (CROP); +} + +void +Film::set_top_crop (int c) +{ + if (_crop.top == c) { + return; + } + + _crop.top = c; + signal_changed (CROP); +} + +void +Film::set_bottom_crop (int c) +{ + if (_crop.bottom == c) { + return; + } + + _crop.bottom = c; + signal_changed (CROP); +} + +void +Film::set_filters (vector<Filter const *> f) +{ + _filters = f; + signal_changed (FILTERS); +} + +void +Film::set_scaler (Scaler const * s) +{ + _scaler = s; + signal_changed (SCALER); +} + +void +Film::set_dcp_frames (int f) +{ + _dcp_frames = f; + signal_changed (DCP_FRAMES); +} + +void +Film::set_dcp_trim_action (TrimAction a) +{ + _dcp_trim_action = a; + signal_changed (DCP_TRIM_ACTION); +} + +void +Film::set_dcp_ab (bool a) +{ + _dcp_ab = a; + signal_changed (DCP_AB); +} + +void +Film::set_audio_stream (int s) +{ + _audio_stream = s; + signal_changed (AUDIO_STREAM); +} + +void +Film::set_audio_gain (float g) +{ + _audio_gain = g; + signal_changed (AUDIO_GAIN); +} + +void +Film::set_audio_delay (int d) +{ + _audio_delay = d; + signal_changed (AUDIO_DELAY); +} + +void +Film::set_still_duration (int d) +{ + _still_duration = d; + signal_changed (STILL_DURATION); +} + +void +Film::set_subtitle_stream (int s) +{ + _subtitle_stream = s; + signal_changed (SUBTITLE_STREAM); +} + +void +Film::set_with_subtitles (bool w) +{ + _with_subtitles = w; + signal_changed (WITH_SUBTITLES); +} + +void +Film::set_subtitle_offset (int o) +{ + _subtitle_offset = o; + signal_changed (SUBTITLE_OFFSET); +} + +void +Film::set_subtitle_scale (float s) +{ + _subtitle_scale = s; + signal_changed (SUBTITLE_SCALE); +} + +void +Film::set_audio_language (string l) +{ + _audio_language = l; + signal_changed (DCI_METADATA); +} + +void +Film::set_subtitle_language (string l) +{ + _subtitle_language = l; + signal_changed (DCI_METADATA); +} + +void +Film::set_territory (string t) +{ + _territory = t; + signal_changed (DCI_METADATA); +} + +void +Film::set_rating (string r) +{ + _rating = r; + signal_changed (DCI_METADATA); +} + +void +Film::set_studio (string s) +{ + _studio = s; + signal_changed (DCI_METADATA); +} + +void +Film::set_facility (string f) +{ + _facility = f; + signal_changed (DCI_METADATA); +} + +void +Film::set_package_type (string p) +{ + _package_type = p; + signal_changed (DCI_METADATA); +} + +void +Film::set_thumbs (vector<int> t) +{ + _thumbs = t; + signal_changed (THUMBS); +} + +void +Film::set_size (Size s) +{ + _size = s; + signal_changed (SIZE); +} + +void +Film::set_length (int l) +{ + _length = l; + signal_changed (LENGTH); +} + +void +Film::set_audio_sample_rate (int r) +{ + _audio_sample_rate = r; + signal_changed (AUDIO_SAMPLE_RATE); +} + +void +Film::set_content_digest (string d) +{ + _content_digest = d; + _dirty = true; +} + +void +Film::set_has_subtitles (bool s) +{ + _has_subtitles = s; + signal_changed (HAS_SUBTITLES); +} + +void +Film::set_audio_streams (vector<AudioStream> s) +{ + _audio_streams = s; + _dirty = true; +} + +void +Film::set_subtitle_streams (vector<SubtitleStream> s) +{ + _subtitle_streams = s; + _dirty = true; +} + +void +Film::set_frames_per_second (float f) +{ + _frames_per_second = f; + signal_changed (FRAMES_PER_SECOND); +} + +void +Film::signal_changed (Property p) +{ + _dirty = true; + Changed (p); +} + +int +Film::audio_channels () const +{ + if (_audio_stream == -1) { + return 0; + } + + return _audio_streams[_audio_stream].channels (); } diff --git a/src/lib/film.h b/src/lib/film.h index 59589b325..795be29d6 100644 --- a/src/lib/film.h +++ b/src/lib/film.h @@ -34,7 +34,9 @@ extern "C" { #include <libavcodec/avcodec.h> } #include "dcp_content_type.h" -#include "film_state.h" +#include "util.h" +#include "stream.h" +#include "trim_action.h" class Format; class Job; @@ -48,10 +50,11 @@ class ExamineContentJob; * A representation of a piece of video (with sound), including naming, * the source content file, and how it should be presented in a DCP. */ -class Film : public FilmState +class Film : public boost::enable_shared_from_this<Film> { public: Film (std::string d, bool must_exist = true); + Film (Film const &); ~Film (); std::string j2k_dir () const; @@ -75,15 +78,367 @@ public: int encoded_frames () const; - void set_content (std::string); + std::string file (std::string f) const; + std::string dir (std::string d) const; -private: + + + std::string content_path () const; + ContentType content_type () const; + + bool content_is_dvd () const; + + std::string thumb_file (int) const; + std::string thumb_base (int) const; + int thumb_frame (int) const; + + int target_audio_sample_rate () const; + + void write_metadata () const; + void read_metadata (); + + Size cropped_size (Size) const; + int dcp_length () const; + std::string dci_name () const; + std::string dcp_name () const; + + bool dirty () const { + return _dirty; + } + + int audio_channels () const; + + enum Property { + NONE, + NAME, + USE_DCI_NAME, + CONTENT, + DCP_CONTENT_TYPE, + FORMAT, + CROP, + FILTERS, + SCALER, + DCP_FRAMES, + DCP_TRIM_ACTION, + DCP_AB, + AUDIO_STREAM, + AUDIO_GAIN, + AUDIO_DELAY, + STILL_DURATION, + SUBTITLE_STREAM, + WITH_SUBTITLES, + SUBTITLE_OFFSET, + SUBTITLE_SCALE, + DCI_METADATA, + THUMBS, + SIZE, + LENGTH, + AUDIO_SAMPLE_RATE, + HAS_SUBTITLES, + AUDIO_STREAMS, + SUBTITLE_STREAMS, + FRAMES_PER_SECOND, + }; + + + /* GET */ + + std::string directory () const { + return _directory; + } + + std::string name () const { + return _name; + } + + bool use_dci_name () const { + return _use_dci_name; + } + + std::string content () const { + return _content; + } + + DCPContentType const * dcp_content_type () const { + return _dcp_content_type; + } + + Format const * format () const { + return _format; + } + + Crop crop () const { + return _crop; + } + + std::vector<Filter const *> filters () const { + return _filters; + } + + Scaler const * scaler () const { + return _scaler; + } + + int dcp_frames () const { + return _dcp_frames; + } + + TrimAction dcp_trim_action () const { + return _dcp_trim_action; + } + + bool dcp_ab () const { + return _dcp_ab; + } + + int audio_stream_index () const { + return _audio_stream; + } + + AudioStream audio_stream () const { + assert (_audio_stream < int (_audio_streams.size())); + return _audio_streams[_audio_stream]; + } + + float audio_gain () const { + return _audio_gain; + } + + int audio_delay () const { + return _audio_delay; + } + + int still_duration () const { + return _still_duration; + } + + int subtitle_stream_index () const { + return _subtitle_stream; + } + + SubtitleStream subtitle_stream () const { + assert (_subtitle_stream < int (_subtitle_streams.size())); + return _subtitle_streams[_subtitle_stream]; + } + + bool with_subtitles () const { + return _with_subtitles; + } + + int subtitle_offset () const { + return _subtitle_offset; + } + + float subtitle_scale () const { + return _subtitle_scale; + } + + std::string audio_language () const { + return _audio_language; + } + + std::string subtitle_language () const { + return _subtitle_language; + } + + std::string territory () const { + return _territory; + } + + std::string rating () const { + return _rating; + } + + std::string studio () const { + return _studio; + } + + std::string facility () const { + return _facility; + } + + std::string package_type () const { + return _package_type; + } + + std::vector<int> thumbs () const { + return _thumbs; + } + + Size size () const { + return _size; + } + + int length () const { + return _length; + } + + int audio_sample_rate () const { + return _audio_sample_rate; + } + + std::string content_digest () const { + return _content_digest; + } + + bool has_subtitles () const { + return _has_subtitles; + } + + std::vector<AudioStream> audio_streams () const { + return _audio_streams; + } + + std::vector<SubtitleStream> subtitle_streams () const { + return _subtitle_streams; + } + + float frames_per_second () const { + return _frames_per_second; + } + + + /* SET */ + + void set_directory (std::string); + void set_name (std::string); + void set_use_dci_name (bool); + virtual void set_content (std::string); + void set_dcp_content_type (DCPContentType const *); + void set_format (Format const *); + void set_crop (Crop); + void set_left_crop (int); + void set_right_crop (int); + void set_top_crop (int); + void set_bottom_crop (int); + void set_filters (std::vector<Filter const *>); + void set_scaler (Scaler const *); + void set_dcp_frames (int); + void set_dcp_trim_action (TrimAction); + void set_dcp_ab (bool); + void set_audio_stream (int); + void set_audio_gain (float); + void set_audio_delay (int); + void set_still_duration (int); + void set_subtitle_stream (int); + void set_with_subtitles (bool); + void set_subtitle_offset (int); + void set_subtitle_scale (float); + void set_audio_language (std::string); + void set_subtitle_language (std::string); + void set_territory (std::string); + void set_rating (std::string); + void set_studio (std::string); + void set_facility (std::string); + void set_package_type (std::string); + void set_thumbs (std::vector<int>); + void set_size (Size); + void set_length (int); + void set_audio_sample_rate (int); + void set_content_digest (std::string); + void set_has_subtitles (bool); + void set_audio_streams (std::vector<AudioStream>); + void set_subtitle_streams (std::vector<SubtitleStream>); + void set_frames_per_second (float); + + /** Emitted when some property has changed */ + mutable sigc::signal1<void, Property> Changed; + +private: /** Log to write to */ Log* _log; /** Any running ExamineContentJob, or 0 */ boost::shared_ptr<ExamineContentJob> _examine_content_job; + + std::string thumb_file_for_frame (int) const; + std::string thumb_base_for_frame (int) const; + void signal_changed (Property); + + /** Complete path to directory containing the film metadata; + * must not be relative. + */ + std::string _directory; + /** Name for DVD-o-matic */ + std::string _name; + /** True if a auto-generated DCI-compliant name should be used for our DCP */ + bool _use_dci_name; + /** File or directory containing content; may be relative to our directory + * or an absolute path. + */ + std::string _content; + /** The type of content that this Film represents (feature, trailer etc.) */ + DCPContentType const * _dcp_content_type; + /** The format to present this Film in (flat, scope, etc.) */ + Format const * _format; + /** The crop to apply to the source */ + Crop _crop; + /** Video filters that should be used when generating DCPs */ + std::vector<Filter const *> _filters; + /** Scaler algorithm to use */ + Scaler const * _scaler; + /** Number of frames to put in the DCP, or 0 for all */ + int _dcp_frames; + /** What to do with audio when trimming DCPs */ + TrimAction _dcp_trim_action; + /** true to create an A/B comparison DCP, where the left half of the image + is the video without any filters or post-processing, and the right half + has the specified filters and post-processing. + */ + bool _dcp_ab; + /** An index into our _audio_streams vector for the stream to use for audio, or -1 if there is none */ + int _audio_stream; + /** Gain to apply to audio in dB */ + float _audio_gain; + /** Delay to apply to audio (positive moves audio later) in milliseconds */ + int _audio_delay; + /** Duration to make still-sourced films (in seconds) */ + int _still_duration; + /** An index into our _subtitle_streams vector for the stream to use for subtitles, or -1 if there is none */ + int _subtitle_stream; + /** True if subtitles should be shown for this film */ + bool _with_subtitles; + /** y offset for placing subtitles, in source pixels; +ve is further down + the frame, -ve is further up. + */ + int _subtitle_offset; + /** scale factor to apply to subtitles */ + float _subtitle_scale; + + /* DCI naming stuff */ + std::string _audio_language; + std::string _subtitle_language; + std::string _territory; + std::string _rating; + std::string _studio; + std::string _facility; + std::string _package_type; + + /* Data which are cached to speed things up */ + + /** Vector of frame indices for each of our `thumbnails' */ + std::vector<int> _thumbs; + /** Size, in pixels, of the source (ignoring cropping) */ + Size _size; + /** Length of the source in frames */ + int _length; + /** Sample rate of the source audio, in Hz */ + int _audio_sample_rate; + /** MD5 digest of our content file */ + std::string _content_digest; + /** true if the source has subtitles */ + bool _has_subtitles; + /** the audio streams that the source has */ + std::vector<AudioStream> _audio_streams; + /** the subtitle streams that the source has */ + std::vector<SubtitleStream> _subtitle_streams; + /** Frames per second of the source */ + float _frames_per_second; + + mutable bool _dirty; + + friend class paths_test; }; #endif diff --git a/src/lib/film_state.cc b/src/lib/film_state.cc deleted file mode 100644 index 0ab38214d..000000000 --- a/src/lib/film_state.cc +++ /dev/null @@ -1,836 +0,0 @@ -/* - Copyright (C) 2012 Carl Hetherington <cth@carlh.net> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -/** @file src/film_state.cc - * @brief The state of a Film. This is separate from Film so that - * state can easily be copied and kept around for reference - * by long-running jobs. This avoids the jobs getting confused - * by the user changing Film settings during their run. - */ - -#include <fstream> -#include <string> -#include <iomanip> -#include <sstream> -#include <boost/filesystem.hpp> -#include <boost/date_time.hpp> -#include <boost/algorithm/string.hpp> -#include "film_state.h" -#include "scaler.h" -#include "filter.h" -#include "format.h" -#include "dcp_content_type.h" -#include "util.h" -#include "exceptions.h" -#include "options.h" -#include "decoder.h" -#include "decoder_factory.h" - -using namespace std; -using namespace boost; - -/** Write state to our `metadata' file */ -void -FilmState::write_metadata () const -{ - filesystem::create_directories (directory()); - - string const m = file ("metadata"); - ofstream f (m.c_str ()); - if (!f.good ()) { - throw CreateFileError (m); - } - - /* User stuff */ - f << "name " << _name << "\n"; - f << "use_dci_name " << _use_dci_name << "\n"; - f << "content " << _content << "\n"; - if (_dcp_content_type) { - f << "dcp_content_type " << _dcp_content_type->pretty_name () << "\n"; - } - if (_format) { - f << "format " << _format->as_metadata () << "\n"; - } - f << "left_crop " << _crop.left << "\n"; - f << "right_crop " << _crop.right << "\n"; - f << "top_crop " << _crop.top << "\n"; - f << "bottom_crop " << _crop.bottom << "\n"; - for (vector<Filter const *>::const_iterator i = _filters.begin(); i != _filters.end(); ++i) { - f << "filter " << (*i)->id () << "\n"; - } - f << "scaler " << _scaler->id () << "\n"; - f << "dcp_frames " << _dcp_frames << "\n"; - - f << "dcp_trim_action "; - switch (_dcp_trim_action) { - case CUT: - f << "cut\n"; - break; - case BLACK_OUT: - f << "black_out\n"; - break; - } - - f << "dcp_ab " << (_dcp_ab ? "1" : "0") << "\n"; - f << "selected_audio_stream " << _audio_stream << "\n"; - f << "audio_gain " << _audio_gain << "\n"; - f << "audio_delay " << _audio_delay << "\n"; - f << "still_duration " << _still_duration << "\n"; - f << "selected_subtitle_stream " << _subtitle_stream << "\n"; - f << "with_subtitles " << _with_subtitles << "\n"; - f << "subtitle_offset " << _subtitle_offset << "\n"; - f << "subtitle_scale " << _subtitle_scale << "\n"; - f << "audio_language " << _audio_language << "\n"; - f << "subtitle_language " << _subtitle_language << "\n"; - f << "territory " << _territory << "\n"; - f << "rating " << _rating << "\n"; - f << "studio " << _studio << "\n"; - f << "facility " << _facility << "\n"; - f << "package_type " << _package_type << "\n"; - - /* Cached stuff; this is information about our content; we could - look it up each time, but that's slow. - */ - for (vector<int>::const_iterator i = _thumbs.begin(); i != _thumbs.end(); ++i) { - f << "thumb " << *i << "\n"; - } - f << "width " << _size.width << "\n"; - f << "height " << _size.height << "\n"; - f << "length " << _length << "\n"; - f << "audio_sample_rate " << _audio_sample_rate << "\n"; - f << "content_digest " << _content_digest << "\n"; - f << "has_subtitles " << _has_subtitles << "\n"; - - for (vector<AudioStream>::const_iterator i = _audio_streams.begin(); i != _audio_streams.end(); ++i) { - f << "audio_stream " << i->to_string () << "\n"; - } - - for (vector<SubtitleStream>::const_iterator i = _subtitle_streams.begin(); i != _subtitle_streams.end(); ++i) { - f << "subtitle_stream " << i->to_string () << "\n"; - } - - f << "frames_per_second " << _frames_per_second << "\n"; - - _dirty = false; -} - -/** Read state from our metadata file */ -void -FilmState::read_metadata () -{ - ifstream f (file("metadata").c_str()); - multimap<string, string> kv = read_key_value (f); - for (multimap<string, string>::const_iterator i = kv.begin(); i != kv.end(); ++i) { - string const k = i->first; - string const v = i->second; - - /* User-specified stuff */ - if (k == "name") { - _name = v; - } else if (k == "use_dci_name") { - _use_dci_name = (v == "1"); - } else if (k == "content") { - _content = v; - } else if (k == "dcp_content_type") { - _dcp_content_type = DCPContentType::from_pretty_name (v); - } else if (k == "format") { - _format = Format::from_metadata (v); - } else if (k == "left_crop") { - _crop.left = atoi (v.c_str ()); - } else if (k == "right_crop") { - _crop.right = atoi (v.c_str ()); - } else if (k == "top_crop") { - _crop.top = atoi (v.c_str ()); - } else if (k == "bottom_crop") { - _crop.bottom = atoi (v.c_str ()); - } else if (k == "filter") { - _filters.push_back (Filter::from_id (v)); - } else if (k == "scaler") { - _scaler = Scaler::from_id (v); - } else if (k == "dcp_frames") { - _dcp_frames = atoi (v.c_str ()); - } else if (k == "dcp_trim_action") { - if (v == "cut") { - _dcp_trim_action = CUT; - } else if (v == "black_out") { - _dcp_trim_action = BLACK_OUT; - } - } else if (k == "dcp_ab") { - _dcp_ab = (v == "1"); - } else if (k == "selected_audio_stream") { - _audio_stream = atoi (v.c_str ()); - } else if (k == "audio_gain") { - _audio_gain = atof (v.c_str ()); - } else if (k == "audio_delay") { - _audio_delay = atoi (v.c_str ()); - } else if (k == "still_duration") { - _still_duration = atoi (v.c_str ()); - } else if (k == "selected_subtitle_stream") { - _subtitle_stream = atoi (v.c_str ()); - } else if (k == "with_subtitles") { - _with_subtitles = (v == "1"); - } else if (k == "subtitle_offset") { - _subtitle_offset = atoi (v.c_str ()); - } else if (k == "subtitle_scale") { - _subtitle_scale = atof (v.c_str ()); - } else if (k == "audio_language") { - _audio_language = v; - } else if (k == "subtitle_language") { - _subtitle_language = v; - } else if (k == "territory") { - _territory = v; - } else if (k == "rating") { - _rating = v; - } else if (k == "studio") { - _studio = v; - } else if (k == "facility") { - _facility = v; - } else if (k == "package_type") { - _package_type = v; - } - - /* Cached stuff */ - if (k == "thumb") { - int const n = atoi (v.c_str ()); - /* Only add it to the list if it still exists */ - if (filesystem::exists (thumb_file_for_frame (n))) { - _thumbs.push_back (n); - } - } else if (k == "width") { - _size.width = atoi (v.c_str ()); - } else if (k == "height") { - _size.height = atoi (v.c_str ()); - } else if (k == "length") { - _length = atof (v.c_str ()); - } else if (k == "audio_sample_rate") { - _audio_sample_rate = atoi (v.c_str ()); - } else if (k == "content_digest") { - _content_digest = v; - } else if (k == "has_subtitles") { - _has_subtitles = (v == "1"); - } else if (k == "audio_stream") { - _audio_streams.push_back (AudioStream (v)); - } else if (k == "subtitle_stream") { - _subtitle_streams.push_back (SubtitleStream (v)); - } else if (k == "frames_per_second") { - _frames_per_second = atof (v.c_str ()); - } - } - - _dirty = false; -} - -/** @param n A thumb index. - * @return The path to the thumb's image file. - */ -string -FilmState::thumb_file (int n) const -{ - return thumb_file_for_frame (thumb_frame (n)); -} - -/** @param n A frame index within the Film. - * @return The path to the thumb's image file for this frame; - * we assume that it exists. - */ -string -FilmState::thumb_file_for_frame (int n) const -{ - return thumb_base_for_frame(n) + ".png"; -} - -string -FilmState::thumb_base (int n) const -{ - return thumb_base_for_frame (thumb_frame (n)); -} - -string -FilmState::thumb_base_for_frame (int n) const -{ - stringstream s; - s.width (8); - s << setfill('0') << n; - - filesystem::path p; - p /= dir ("thumbs"); - p /= s.str (); - - return p.string (); -} - - -/** @param n A thumb index. - * @return The frame within the Film that it is for. - */ -int -FilmState::thumb_frame (int n) const -{ - assert (n < int (_thumbs.size ())); - return _thumbs[n]; -} - -Size -FilmState::cropped_size (Size s) const -{ - s.width -= _crop.left + _crop.right; - s.height -= _crop.top + _crop.bottom; - return s; -} - -/** Given a directory name, return its full path within the Film's directory. - * The directory (and its parents) will be created if they do not exist. - */ -string -FilmState::dir (string d) const -{ - filesystem::path p; - p /= _directory; - p /= d; - filesystem::create_directories (p); - return p.string (); -} - -/** Given a file or directory name, return its full path within the Film's directory */ -string -FilmState::file (string f) const -{ - filesystem::path p; - p /= _directory; - p /= f; - return p.string (); -} - -/** @return full path of the content (actual video) file - * of the Film. - */ -string -FilmState::content_path () const -{ - if (filesystem::path(_content).has_root_directory ()) { - return _content; - } - - return file (_content); -} - -ContentType -FilmState::content_type () const -{ -#if BOOST_FILESYSTEM_VERSION == 3 - string ext = filesystem::path(_content).extension().string(); -#else - string ext = filesystem::path(_content).extension(); -#endif - - transform (ext.begin(), ext.end(), ext.begin(), ::tolower); - - if (ext == ".tif" || ext == ".tiff" || ext == ".jpg" || ext == ".jpeg" || ext == ".png") { - return STILL; - } - - return VIDEO; -} - -/** @return The sampling rate that we will resample the audio to */ -int -FilmState::target_audio_sample_rate () const -{ - /* Resample to a DCI-approved sample rate */ - double t = dcp_audio_sample_rate (_audio_sample_rate); - - /* Compensate for the fact that video will be rounded to the - nearest integer number of frames per second. - */ - if (rint (_frames_per_second) != _frames_per_second) { - t *= _frames_per_second / rint (_frames_per_second); - } - - return rint (t); -} - -int -FilmState::dcp_length () const -{ - if (_dcp_frames) { - return _dcp_frames; - } - - return _length; -} - -/** @return a DCI-compliant name for a DCP of this film */ -string -FilmState::dci_name () const -{ - stringstream d; - - string fixed_name = to_upper_copy (_name); - for (size_t i = 0; i < fixed_name.length(); ++i) { - if (fixed_name[i] == ' ') { - fixed_name[i] = '-'; - } - } - - /* Spec is that the name part should be maximum 14 characters, as I understand it */ - if (fixed_name.length() > 14) { - fixed_name = fixed_name.substr (0, 14); - } - - d << fixed_name << "_"; - - if (_dcp_content_type) { - d << _dcp_content_type->dci_name() << "_"; - } - - if (_format) { - d << _format->dci_name() << "_"; - } - - if (!_audio_language.empty ()) { - d << _audio_language; - if (!_subtitle_language.empty() && _with_subtitles) { - d << "-" << _subtitle_language; - } else { - d << "-XX"; - } - - d << "_"; - } - - if (!_territory.empty ()) { - d << _territory; - if (!_rating.empty ()) { - d << "-" << _rating; - } - d << "_"; - } - - switch (_audio_streams[_audio_stream].channels()) { - case 1: - d << "10_"; - break; - case 2: - d << "20_"; - break; - case 6: - d << "51_"; - break; - case 8: - d << "71_"; - break; - } - - d << "2K_"; - - if (!_studio.empty ()) { - d << _studio << "_"; - } - - gregorian::date today = gregorian::day_clock::local_day (); - d << gregorian::to_iso_string (today) << "_"; - - if (!_facility.empty ()) { - d << _facility << "_"; - } - - if (!_package_type.empty ()) { - d << _package_type; - } - - return d.str (); -} - -/** @return name to give the DCP */ -string -FilmState::dcp_name () const -{ - if (_use_dci_name) { - return dci_name (); - } - - return _name; -} - - -void -FilmState::set_directory (string d) -{ - _directory = d; - _dirty = true; -} - -void -FilmState::set_name (string n) -{ - _name = n; - signal_changed (NAME); -} - -void -FilmState::set_use_dci_name (bool u) -{ - _use_dci_name = u; - signal_changed (USE_DCI_NAME); -} - -void -FilmState::set_content (string c) -{ - string check = _directory; - -#if BOOST_FILESYSTEM_VERSION == 3 - filesystem::path slash ("/"); - string platform_slash = slash.make_preferred().string (); -#else -#ifdef DVDOMATIC_WINDOWS - string platform_slash = "\\"; -#else - string platform_slash = "/"; -#endif -#endif - - if (!ends_with (check, platform_slash)) { - check += platform_slash; - } - - if (filesystem::path(c).has_root_directory () && starts_with (c, check)) { - c = c.substr (_directory.length() + 1); - } - - if (c == _content) { - return; - } - - /* Create a temporary decoder so that we can get information - about the content. - */ - - shared_ptr<FilmState> s = state_copy (); - s->_content = c; - shared_ptr<Options> o (new Options ("", "", "")); - o->out_size = Size (1024, 1024); - - shared_ptr<Decoder> d = decoder_factory (s, o, 0, 0); - - set_size (d->native_size ()); - set_frames_per_second (d->frames_per_second ()); - set_audio_sample_rate (d->audio_sample_rate ()); - set_has_subtitles (d->has_subtitles ()); - set_audio_streams (d->audio_streams ()); - set_subtitle_streams (d->subtitle_streams ()); - set_audio_stream (audio_streams().empty() ? -1 : 0); - set_subtitle_stream (subtitle_streams().empty() ? -1 : 0); - - _content = c; - signal_changed (CONTENT); - - set_content_digest (md5_digest (content_path ())); -} - -void -FilmState::set_dcp_content_type (DCPContentType const * t) -{ - _dcp_content_type = t; - signal_changed (DCP_CONTENT_TYPE); -} - -void -FilmState::set_format (Format const * f) -{ - _format = f; - signal_changed (FORMAT); -} - -void -FilmState::set_crop (Crop c) -{ - _crop = c; - signal_changed (CROP); -} - -void -FilmState::set_left_crop (int c) -{ - if (_crop.left == c) { - return; - } - - _crop.left = c; - signal_changed (CROP); -} - -void -FilmState::set_right_crop (int c) -{ - if (_crop.right == c) { - return; - } - - _crop.right = c; - signal_changed (CROP); -} - -void -FilmState::set_top_crop (int c) -{ - if (_crop.top == c) { - return; - } - - _crop.top = c; - signal_changed (CROP); -} - -void -FilmState::set_bottom_crop (int c) -{ - if (_crop.bottom == c) { - return; - } - - _crop.bottom = c; - signal_changed (CROP); -} - -void -FilmState::set_filters (vector<Filter const *> f) -{ - _filters = f; - signal_changed (FILTERS); -} - -void -FilmState::set_scaler (Scaler const * s) -{ - _scaler = s; - signal_changed (SCALER); -} - -void -FilmState::set_dcp_frames (int f) -{ - _dcp_frames = f; - signal_changed (DCP_FRAMES); -} - -void -FilmState::set_dcp_trim_action (TrimAction a) -{ - _dcp_trim_action = a; - signal_changed (DCP_TRIM_ACTION); -} - -void -FilmState::set_dcp_ab (bool a) -{ - _dcp_ab = a; - signal_changed (DCP_AB); -} - -void -FilmState::set_audio_stream (int s) -{ - _audio_stream = s; - signal_changed (AUDIO_STREAM); -} - -void -FilmState::set_audio_gain (float g) -{ - _audio_gain = g; - signal_changed (AUDIO_GAIN); -} - -void -FilmState::set_audio_delay (int d) -{ - _audio_delay = d; - signal_changed (AUDIO_DELAY); -} - -void -FilmState::set_still_duration (int d) -{ - _still_duration = d; - signal_changed (STILL_DURATION); -} - -void -FilmState::set_subtitle_stream (int s) -{ - _subtitle_stream = s; - signal_changed (SUBTITLE_STREAM); -} - -void -FilmState::set_with_subtitles (bool w) -{ - _with_subtitles = w; - signal_changed (WITH_SUBTITLES); -} - -void -FilmState::set_subtitle_offset (int o) -{ - _subtitle_offset = o; - signal_changed (SUBTITLE_OFFSET); -} - -void -FilmState::set_subtitle_scale (float s) -{ - _subtitle_scale = s; - signal_changed (SUBTITLE_SCALE); -} - -void -FilmState::set_audio_language (string l) -{ - _audio_language = l; - signal_changed (DCI_METADATA); -} - -void -FilmState::set_subtitle_language (string l) -{ - _subtitle_language = l; - signal_changed (DCI_METADATA); -} - -void -FilmState::set_territory (string t) -{ - _territory = t; - signal_changed (DCI_METADATA); -} - -void -FilmState::set_rating (string r) -{ - _rating = r; - signal_changed (DCI_METADATA); -} - -void -FilmState::set_studio (string s) -{ - _studio = s; - signal_changed (DCI_METADATA); -} - -void -FilmState::set_facility (string f) -{ - _facility = f; - signal_changed (DCI_METADATA); -} - -void -FilmState::set_package_type (string p) -{ - _package_type = p; - signal_changed (DCI_METADATA); -} - -void -FilmState::set_thumbs (vector<int> t) -{ - _thumbs = t; - signal_changed (THUMBS); -} - -void -FilmState::set_size (Size s) -{ - _size = s; - signal_changed (SIZE); -} - -void -FilmState::set_length (int l) -{ - _length = l; - signal_changed (LENGTH); -} - -void -FilmState::set_audio_sample_rate (int r) -{ - _audio_sample_rate = r; - signal_changed (AUDIO_SAMPLE_RATE); -} - -void -FilmState::set_content_digest (string d) -{ - _content_digest = d; - _dirty = true; -} - -void -FilmState::set_has_subtitles (bool s) -{ - _has_subtitles = s; - signal_changed (HAS_SUBTITLES); -} - -void -FilmState::set_audio_streams (vector<AudioStream> s) -{ - _audio_streams = s; - _dirty = true; -} - -void -FilmState::set_subtitle_streams (vector<SubtitleStream> s) -{ - _subtitle_streams = s; - _dirty = true; -} - -void -FilmState::set_frames_per_second (float f) -{ - _frames_per_second = f; - signal_changed (FRAMES_PER_SECOND); -} - -void -FilmState::signal_changed (Property p) -{ - _dirty = true; - Changed (p); -} - -shared_ptr<FilmState> -FilmState::state_copy () const -{ - return shared_ptr<FilmState> (new FilmState (*this)); -} - -int -FilmState::audio_channels () const -{ - if (_audio_stream == -1) { - return 0; - } - - return _audio_streams[_audio_stream].channels (); -} diff --git a/src/lib/film_state.h b/src/lib/film_state.h deleted file mode 100644 index 14a8f7eb5..000000000 --- a/src/lib/film_state.h +++ /dev/null @@ -1,480 +0,0 @@ -/* - Copyright (C) 2012 Carl Hetherington <cth@carlh.net> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -/** @file src/film_state.h - * @brief The state of a Film. This is separate from Film so that - * state can easily be copied and kept around for reference - * by long-running jobs. This avoids the jobs getting confused - * by the user changing Film settings during their run. - */ - -#ifndef DVDOMATIC_FILM_STATE_H -#define DVDOMATIC_FILM_STATE_H - -#include <sigc++/signal.h> -extern "C" { -#include <libavcodec/avcodec.h> -#include <libswscale/swscale.h> -} -#include "scaler.h" -#include "util.h" -#include "trim_action.h" -#include "stream.h" - -class Format; -class DCPContentType; -class Filter; - -/** @class FilmState - * @brief The state of a Film. - * - * This is separate from Film so that state can easily be copied and - * kept around for reference by long-running jobs. This avoids the - * jobs getting confused by the user changing Film settings during - * their run. - */ - -class FilmState -{ -public: - FilmState () - : _use_dci_name (false) - , _dcp_content_type (0) - , _format (0) - , _scaler (Scaler::from_id ("bicubic")) - , _dcp_frames (0) - , _dcp_trim_action (CUT) - , _dcp_ab (false) - , _audio_stream (-1) - , _audio_gain (0) - , _audio_delay (0) - , _still_duration (10) - , _subtitle_stream (-1) - , _with_subtitles (false) - , _subtitle_offset (0) - , _subtitle_scale (1) - , _length (0) - , _audio_sample_rate (0) - , _has_subtitles (false) - , _frames_per_second (0) - , _dirty (false) - {} - - FilmState (FilmState const & o) - : _directory (o._directory) - , _name (o._name) - , _use_dci_name (o._use_dci_name) - , _content (o._content) - , _dcp_content_type (o._dcp_content_type) - , _format (o._format) - , _crop (o._crop) - , _filters (o._filters) - , _scaler (o._scaler) - , _dcp_frames (o._dcp_frames) - , _dcp_trim_action (o._dcp_trim_action) - , _dcp_ab (o._dcp_ab) - , _audio_stream (o._audio_stream) - , _audio_gain (o._audio_gain) - , _audio_delay (o._audio_delay) - , _still_duration (o._still_duration) - , _subtitle_stream (o._subtitle_stream) - , _with_subtitles (o._with_subtitles) - , _subtitle_offset (o._subtitle_offset) - , _subtitle_scale (o._subtitle_scale) - , _audio_language (o._audio_language) - , _subtitle_language (o._subtitle_language) - , _territory (o._territory) - , _rating (o._rating) - , _studio (o._studio) - , _facility (o._facility) - , _package_type (o._package_type) - , _thumbs (o._thumbs) - , _size (o._size) - , _length (o._length) - , _audio_sample_rate (o._audio_sample_rate) - , _content_digest (o._content_digest) - , _has_subtitles (o._has_subtitles) - , _audio_streams (o._audio_streams) - , _subtitle_streams (o._subtitle_streams) - , _frames_per_second (o._frames_per_second) - , _dirty (o._dirty) - {} - - virtual ~FilmState () {} - - std::string file (std::string f) const; - std::string dir (std::string d) const; - - std::string content_path () const; - ContentType content_type () const; - - bool content_is_dvd () const; - - std::string thumb_file (int) const; - std::string thumb_base (int) const; - int thumb_frame (int) const; - - int target_audio_sample_rate () const; - - void write_metadata () const; - void read_metadata (); - - Size cropped_size (Size) const; - int dcp_length () const; - std::string dci_name () const; - - std::string dcp_name () const; - - boost::shared_ptr<FilmState> state_copy () const; - - bool dirty () const { - return _dirty; - } - - int audio_channels () const; - - enum Property { - NONE, - NAME, - USE_DCI_NAME, - CONTENT, - DCP_CONTENT_TYPE, - FORMAT, - CROP, - FILTERS, - SCALER, - DCP_FRAMES, - DCP_TRIM_ACTION, - DCP_AB, - AUDIO_STREAM, - AUDIO_GAIN, - AUDIO_DELAY, - STILL_DURATION, - SUBTITLE_STREAM, - WITH_SUBTITLES, - SUBTITLE_OFFSET, - SUBTITLE_SCALE, - DCI_METADATA, - THUMBS, - SIZE, - LENGTH, - AUDIO_SAMPLE_RATE, - HAS_SUBTITLES, - AUDIO_STREAMS, - SUBTITLE_STREAMS, - FRAMES_PER_SECOND, - }; - - - /* GET */ - - std::string directory () const { - return _directory; - } - - std::string name () const { - return _name; - } - - bool use_dci_name () const { - return _use_dci_name; - } - - std::string content () const { - return _content; - } - - DCPContentType const * dcp_content_type () const { - return _dcp_content_type; - } - - Format const * format () const { - return _format; - } - - Crop crop () const { - return _crop; - } - - std::vector<Filter const *> filters () const { - return _filters; - } - - Scaler const * scaler () const { - return _scaler; - } - - int dcp_frames () const { - return _dcp_frames; - } - - TrimAction dcp_trim_action () const { - return _dcp_trim_action; - } - - bool dcp_ab () const { - return _dcp_ab; - } - - int audio_stream_index () const { - return _audio_stream; - } - - AudioStream audio_stream () const { - assert (_audio_stream < int (_audio_streams.size())); - return _audio_streams[_audio_stream]; - } - - float audio_gain () const { - return _audio_gain; - } - - int audio_delay () const { - return _audio_delay; - } - - int still_duration () const { - return _still_duration; - } - - int subtitle_stream_index () const { - return _subtitle_stream; - } - - SubtitleStream subtitle_stream () const { - assert (_subtitle_stream < int (_subtitle_streams.size())); - return _subtitle_streams[_subtitle_stream]; - } - - bool with_subtitles () const { - return _with_subtitles; - } - - int subtitle_offset () const { - return _subtitle_offset; - } - - float subtitle_scale () const { - return _subtitle_scale; - } - - std::string audio_language () const { - return _audio_language; - } - - std::string subtitle_language () const { - return _subtitle_language; - } - - std::string territory () const { - return _territory; - } - - std::string rating () const { - return _rating; - } - - std::string studio () const { - return _studio; - } - - std::string facility () const { - return _facility; - } - - std::string package_type () const { - return _package_type; - } - - std::vector<int> thumbs () const { - return _thumbs; - } - - Size size () const { - return _size; - } - - int length () const { - return _length; - } - - int audio_sample_rate () const { - return _audio_sample_rate; - } - - std::string content_digest () const { - return _content_digest; - } - - bool has_subtitles () const { - return _has_subtitles; - } - - std::vector<AudioStream> audio_streams () const { - return _audio_streams; - } - - std::vector<SubtitleStream> subtitle_streams () const { - return _subtitle_streams; - } - - float frames_per_second () const { - return _frames_per_second; - } - - - /* SET */ - - void set_directory (std::string); - void set_name (std::string); - void set_use_dci_name (bool); - virtual void set_content (std::string); - void set_dcp_content_type (DCPContentType const *); - void set_format (Format const *); - void set_crop (Crop); - void set_left_crop (int); - void set_right_crop (int); - void set_top_crop (int); - void set_bottom_crop (int); - void set_filters (std::vector<Filter const *>); - void set_scaler (Scaler const *); - void set_dcp_frames (int); - void set_dcp_trim_action (TrimAction); - void set_dcp_ab (bool); - void set_audio_stream (int); - void set_audio_gain (float); - void set_audio_delay (int); - void set_still_duration (int); - void set_subtitle_stream (int); - void set_with_subtitles (bool); - void set_subtitle_offset (int); - void set_subtitle_scale (float); - void set_audio_language (std::string); - void set_subtitle_language (std::string); - void set_territory (std::string); - void set_rating (std::string); - void set_studio (std::string); - void set_facility (std::string); - void set_package_type (std::string); - void set_thumbs (std::vector<int>); - void set_size (Size); - void set_length (int); - void set_audio_channels (int); - void set_audio_sample_rate (int); - void set_content_digest (std::string); - void set_has_subtitles (bool); - void set_audio_streams (std::vector<AudioStream>); - void set_subtitle_streams (std::vector<SubtitleStream>); - void set_frames_per_second (float); - - /** Emitted when some property has changed */ - mutable sigc::signal1<void, Property> Changed; - -private: - - std::string thumb_file_for_frame (int) const; - std::string thumb_base_for_frame (int) const; - void signal_changed (Property); - - /** Complete path to directory containing the film metadata; - * must not be relative. - */ - std::string _directory; - /** Name for DVD-o-matic */ - std::string _name; - /** True if a auto-generated DCI-compliant name should be used for our DCP */ - bool _use_dci_name; - /** File or directory containing content; may be relative to our directory - * or an absolute path. - */ - std::string _content; - /** The type of content that this Film represents (feature, trailer etc.) */ - DCPContentType const * _dcp_content_type; - /** The format to present this Film in (flat, scope, etc.) */ - Format const * _format; - /** The crop to apply to the source */ - Crop _crop; - /** Video filters that should be used when generating DCPs */ - std::vector<Filter const *> _filters; - /** Scaler algorithm to use */ - Scaler const * _scaler; - /** Number of frames to put in the DCP, or 0 for all */ - int _dcp_frames; - /** What to do with audio when trimming DCPs */ - TrimAction _dcp_trim_action; - /** true to create an A/B comparison DCP, where the left half of the image - is the video without any filters or post-processing, and the right half - has the specified filters and post-processing. - */ - bool _dcp_ab; - /** An index into our _audio_streams vector for the stream to use for audio, or -1 if there is none */ - int _audio_stream; - /** Gain to apply to audio in dB */ - float _audio_gain; - /** Delay to apply to audio (positive moves audio later) in milliseconds */ - int _audio_delay; - /** Duration to make still-sourced films (in seconds) */ - int _still_duration; - /** An index into our _subtitle_streams vector for the stream to use for subtitles, or -1 if there is none */ - int _subtitle_stream; - /** True if subtitles should be shown for this film */ - bool _with_subtitles; - /** y offset for placing subtitles, in source pixels; +ve is further down - the frame, -ve is further up. - */ - int _subtitle_offset; - /** scale factor to apply to subtitles */ - float _subtitle_scale; - - /* DCI naming stuff */ - std::string _audio_language; - std::string _subtitle_language; - std::string _territory; - std::string _rating; - std::string _studio; - std::string _facility; - std::string _package_type; - - /* Data which are cached to speed things up */ - - /** Vector of frame indices for each of our `thumbnails' */ - std::vector<int> _thumbs; - /** Size, in pixels, of the source (ignoring cropping) */ - Size _size; - /** Length of the source in frames */ - int _length; - /** Sample rate of the source audio, in Hz */ - int _audio_sample_rate; - /** MD5 digest of our content file */ - std::string _content_digest; - /** true if the source has subtitles */ - bool _has_subtitles; - /** the audio streams that the source has */ - std::vector<AudioStream> _audio_streams; - /** the subtitle streams that the source has */ - std::vector<SubtitleStream> _subtitle_streams; - /** Frames per second of the source */ - float _frames_per_second; - - mutable bool _dirty; - - friend class paths_test; -}; - -#endif diff --git a/src/lib/imagemagick_decoder.cc b/src/lib/imagemagick_decoder.cc index 32c433d09..185fccd82 100644 --- a/src/lib/imagemagick_decoder.cc +++ b/src/lib/imagemagick_decoder.cc @@ -20,18 +20,18 @@ #include <iostream> #include <Magick++/Image.h> #include "imagemagick_decoder.h" -#include "film_state.h" #include "image.h" +#include "film.h" using namespace std; using namespace boost; ImageMagickDecoder::ImageMagickDecoder ( - boost::shared_ptr<const FilmState> s, boost::shared_ptr<const Options> o, Job* j, Log* l, bool minimal, bool ignore_length) - : Decoder (s, o, j, l, minimal, ignore_length) + boost::shared_ptr<Film> f, boost::shared_ptr<const Options> o, Job* j, bool minimal, bool ignore_length) + : Decoder (f, o, j, minimal, ignore_length) , _done (false) { - _magick_image = new Magick::Image (_fs->content_path ()); + _magick_image = new Magick::Image (_film->content_path ()); } Size diff --git a/src/lib/imagemagick_decoder.h b/src/lib/imagemagick_decoder.h index 3e58e645f..13b53b685 100644 --- a/src/lib/imagemagick_decoder.h +++ b/src/lib/imagemagick_decoder.h @@ -26,7 +26,7 @@ namespace Magick { class ImageMagickDecoder : public Decoder { public: - ImageMagickDecoder (boost::shared_ptr<const FilmState>, boost::shared_ptr<const Options>, Job *, Log *, bool, bool); + ImageMagickDecoder (boost::shared_ptr<Film>, boost::shared_ptr<const Options>, Job *, bool, bool); float frames_per_second () const { return static_frames_per_second (); diff --git a/src/lib/imagemagick_encoder.cc b/src/lib/imagemagick_encoder.cc index 082fd13e8..e86888c36 100644 --- a/src/lib/imagemagick_encoder.cc +++ b/src/lib/imagemagick_encoder.cc @@ -31,7 +31,6 @@ #include <Magick++/Image.h> #include "imagemagick_encoder.h" #include "film.h" -#include "film_state.h" #include "options.h" #include "exceptions.h" #include "image.h" @@ -40,12 +39,11 @@ using namespace std; using namespace boost; -/** @param s FilmState of the film that we are encoding. +/** @param f Film that we are encoding. * @param o Options. - * @param l Log. */ -ImageMagickEncoder::ImageMagickEncoder (shared_ptr<const FilmState> s, shared_ptr<const Options> o, Log* l) - : Encoder (s, o, l) +ImageMagickEncoder::ImageMagickEncoder (shared_ptr<const Film> f, shared_ptr<const Options> o) + : Encoder (f, o) { } @@ -53,7 +51,7 @@ ImageMagickEncoder::ImageMagickEncoder (shared_ptr<const FilmState> s, shared_pt void ImageMagickEncoder::process_video (shared_ptr<Image> image, int frame, shared_ptr<Subtitle> sub) { - shared_ptr<Image> scaled = image->scale_and_convert_to_rgb (_opt->out_size, _opt->padding, _fs->scaler()); + shared_ptr<Image> scaled = image->scale_and_convert_to_rgb (_opt->out_size, _opt->padding, _film->scaler()); shared_ptr<Image> compact (new CompactImage (scaled)); string tmp_file = _opt->frame_out_path (frame, true); @@ -63,8 +61,8 @@ ImageMagickEncoder::process_video (shared_ptr<Image> image, int frame, shared_pt filesystem::rename (tmp_file, _opt->frame_out_path (frame, false)); if (sub) { - float const x_scale = float (_opt->out_size.width) / _fs->size().width; - float const y_scale = float (_opt->out_size.height) / _fs->size().height; + float const x_scale = float (_opt->out_size.width) / _film->size().width; + float const y_scale = float (_opt->out_size.height) / _film->size().height; string tmp_metadata_file = _opt->frame_out_path (frame, false, ".sub"); ofstream metadata (tmp_metadata_file.c_str ()); @@ -72,7 +70,7 @@ ImageMagickEncoder::process_video (shared_ptr<Image> image, int frame, shared_pt Size new_size = sub->image()->size (); new_size.width *= x_scale; new_size.height *= y_scale; - shared_ptr<Image> scaled = sub->image()->scale (new_size, _fs->scaler()); + shared_ptr<Image> scaled = sub->image()->scale (new_size, _film->scaler()); shared_ptr<Image> compact (new CompactImage (scaled)); string tmp_sub_file = _opt->frame_out_path (frame, true, ".sub.png"); diff --git a/src/lib/imagemagick_encoder.h b/src/lib/imagemagick_encoder.h index 29767ed03..f5e97ccd8 100644 --- a/src/lib/imagemagick_encoder.h +++ b/src/lib/imagemagick_encoder.h @@ -34,7 +34,7 @@ class Log; class ImageMagickEncoder : public Encoder { public: - ImageMagickEncoder (boost::shared_ptr<const FilmState> s, boost::shared_ptr<const Options> o, Log* l); + ImageMagickEncoder (boost::shared_ptr<const Film> f, boost::shared_ptr<const Options> o); void process_begin (int64_t audio_channel_layout) {} void process_video (boost::shared_ptr<Image>, int, boost::shared_ptr<Subtitle>); diff --git a/src/lib/j2k_still_encoder.cc b/src/lib/j2k_still_encoder.cc index de2f1eb46..51946372f 100644 --- a/src/lib/j2k_still_encoder.cc +++ b/src/lib/j2k_still_encoder.cc @@ -30,19 +30,19 @@ #include <openjpeg.h> #include "j2k_still_encoder.h" #include "config.h" -#include "film_state.h" #include "options.h" #include "exceptions.h" #include "dcp_video_frame.h" #include "filter.h" #include "log.h" #include "imagemagick_decoder.h" +#include "film.h" using namespace std; using namespace boost; -J2KStillEncoder::J2KStillEncoder (shared_ptr<const FilmState> s, shared_ptr<const Options> o, Log* l) - : Encoder (s, o, l) +J2KStillEncoder::J2KStillEncoder (shared_ptr<const Film> f, shared_ptr<const Options> o) + : Encoder (f, o) { } @@ -50,11 +50,11 @@ J2KStillEncoder::J2KStillEncoder (shared_ptr<const FilmState> s, shared_ptr<cons void J2KStillEncoder::process_video (shared_ptr<Image> yuv, int frame, shared_ptr<Subtitle> sub) { - pair<string, string> const s = Filter::ffmpeg_strings (_fs->filters()); + pair<string, string> const s = Filter::ffmpeg_strings (_film->filters()); DCPVideoFrame* f = new DCPVideoFrame ( - yuv, sub, _opt->out_size, _opt->padding, _fs->subtitle_offset(), _fs->subtitle_scale(), _fs->scaler(), 0, _fs->frames_per_second(), s.second, + yuv, sub, _opt->out_size, _opt->padding, _film->subtitle_offset(), _film->subtitle_scale(), _film->scaler(), 0, _film->frames_per_second(), s.second, Config::instance()->colour_lut_index(), Config::instance()->j2k_bandwidth(), - _log + _film->log() ); if (!boost::filesystem::exists (_opt->frame_out_path (0, false))) { @@ -63,7 +63,7 @@ J2KStillEncoder::process_video (shared_ptr<Image> yuv, int frame, shared_ptr<Sub } string const real = _opt->frame_out_path (0, false); - for (int i = 1; i < (_fs->still_duration() * ImageMagickDecoder::static_frames_per_second()); ++i) { + for (int i = 1; i < (_film->still_duration() * ImageMagickDecoder::static_frames_per_second()); ++i) { if (!boost::filesystem::exists (_opt->frame_out_path (i, false))) { string const link = _opt->frame_out_path (i, false); #ifdef DVDOMATIC_POSIX diff --git a/src/lib/j2k_still_encoder.h b/src/lib/j2k_still_encoder.h index 928afe372..433c497a6 100644 --- a/src/lib/j2k_still_encoder.h +++ b/src/lib/j2k_still_encoder.h @@ -34,7 +34,7 @@ class Log; class J2KStillEncoder : public Encoder { public: - J2KStillEncoder (boost::shared_ptr<const FilmState>, boost::shared_ptr<const Options>, Log *); + J2KStillEncoder (boost::shared_ptr<const Film>, boost::shared_ptr<const Options>); void process_begin (int64_t audio_channel_layout) {} void process_video (boost::shared_ptr<Image>, int, boost::shared_ptr<Subtitle>); diff --git a/src/lib/j2k_wav_encoder.cc b/src/lib/j2k_wav_encoder.cc index c0c785d11..4dd9ce8b6 100644 --- a/src/lib/j2k_wav_encoder.cc +++ b/src/lib/j2k_wav_encoder.cc @@ -32,7 +32,6 @@ #include <openjpeg.h> #include "j2k_wav_encoder.h" #include "config.h" -#include "film_state.h" #include "options.h" #include "exceptions.h" #include "dcp_video_frame.h" @@ -40,12 +39,13 @@ #include "filter.h" #include "log.h" #include "cross.h" +#include "film.h" using namespace std; using namespace boost; -J2KWAVEncoder::J2KWAVEncoder (shared_ptr<const FilmState> s, shared_ptr<const Options> o, Log* l) - : Encoder (s, o, l) +J2KWAVEncoder::J2KWAVEncoder (shared_ptr<const Film> f, shared_ptr<const Options> o) + : Encoder (f, o) #ifdef HAVE_SWRESAMPLE , _swr_context (0) #endif @@ -55,9 +55,9 @@ J2KWAVEncoder::J2KWAVEncoder (shared_ptr<const FilmState> s, shared_ptr<const Op /* Create sound output files with .tmp suffixes; we will rename them if and when we complete. */ - for (int i = 0; i < _fs->audio_channels(); ++i) { + for (int i = 0; i < _film->audio_channels(); ++i) { SF_INFO sf_info; - sf_info.samplerate = dcp_audio_sample_rate (_fs->audio_sample_rate()); + sf_info.samplerate = dcp_audio_sample_rate (_film->audio_sample_rate()); /* We write mono files */ sf_info.channels = 1; sf_info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_24; @@ -117,14 +117,14 @@ J2KWAVEncoder::process_video (shared_ptr<Image> yuv, int frame, shared_ptr<Subti /* Only do the processing if we don't already have a file for this frame */ if (!boost::filesystem::exists (_opt->frame_out_path (frame, false))) { - pair<string, string> const s = Filter::ffmpeg_strings (_fs->filters()); + pair<string, string> const s = Filter::ffmpeg_strings (_film->filters()); TIMING ("adding to queue of %1", _queue.size ()); _queue.push_back (boost::shared_ptr<DCPVideoFrame> ( new DCPVideoFrame ( - yuv, sub, _opt->out_size, _opt->padding, _fs->subtitle_offset(), _fs->subtitle_scale(), - _fs->scaler(), frame, _fs->frames_per_second(), s.second, + yuv, sub, _opt->out_size, _opt->padding, _film->subtitle_offset(), _film->subtitle_scale(), + _film->scaler(), frame, _film->frames_per_second(), s.second, Config::instance()->colour_lut_index (), Config::instance()->j2k_bandwidth (), - _log + _film->log() ) )); @@ -157,7 +157,7 @@ J2KWAVEncoder::encoder_thread (ServerDescription* server) TIMING ("encoder thread %1 wakes with queue of %2", boost::this_thread::get_id(), _queue.size()); boost::shared_ptr<DCPVideoFrame> vf = _queue.front (); - _log->log (String::compose ("Encoder thread %1 pops frame %2 from queue", boost::this_thread::get_id(), vf->frame())); + _film->log()->log (String::compose ("Encoder thread %1 pops frame %2 from queue", boost::this_thread::get_id(), vf->frame())); _queue.pop_front (); lock.unlock (); @@ -169,7 +169,7 @@ J2KWAVEncoder::encoder_thread (ServerDescription* server) encoded = vf->encode_remotely (server); if (remote_backoff > 0) { - _log->log (String::compose ("%1 was lost, but now she is found; removing backoff", server->host_name ())); + _film->log()->log (String::compose ("%1 was lost, but now she is found; removing backoff", server->host_name ())); } /* This job succeeded, so remove any backoff */ @@ -180,7 +180,7 @@ J2KWAVEncoder::encoder_thread (ServerDescription* server) /* back off more */ remote_backoff += 10; } - _log->log ( + _film->log()->log ( String::compose ( "Remote encode of %1 on %2 failed (%3); thread sleeping for %4s", vf->frame(), server->host_name(), e.what(), remote_backoff) @@ -193,7 +193,7 @@ J2KWAVEncoder::encoder_thread (ServerDescription* server) encoded = vf->encode_locally (); TIMING ("encoder thread %1 finishes local encode of %2", boost::this_thread::get_id(), vf->frame()); } catch (std::exception& e) { - _log->log (String::compose ("Local encode failed (%1)", e.what ())); + _film->log()->log (String::compose ("Local encode failed (%1)", e.what ())); } } @@ -202,7 +202,9 @@ J2KWAVEncoder::encoder_thread (ServerDescription* server) frame_done (vf->frame ()); } else { lock.lock (); - _log->log (String::compose ("Encoder thread %1 pushes frame %2 back onto queue after failure", boost::this_thread::get_id(), vf->frame())); + _film->log()->log ( + String::compose ("Encoder thread %1 pushes frame %2 back onto queue after failure", boost::this_thread::get_id(), vf->frame()) + ); _queue.push_front (vf); lock.unlock (); } @@ -219,22 +221,22 @@ J2KWAVEncoder::encoder_thread (ServerDescription* server) void J2KWAVEncoder::process_begin (int64_t audio_channel_layout) { - if (_fs->audio_sample_rate() != _fs->target_audio_sample_rate()) { + if (_film->audio_sample_rate() != _film->target_audio_sample_rate()) { #ifdef HAVE_SWRESAMPLE stringstream s; - s << "Will resample audio from " << _fs->audio_sample_rate() << " to " << _fs->target_audio_sample_rate(); - _log->log (s.str ()); + s << "Will resample audio from " << _film->audio_sample_rate() << " to " << _film->target_audio_sample_rate(); + _film->log()->log (s.str ()); /* We will be using planar float data when we call the resampler */ _swr_context = swr_alloc_set_opts ( 0, audio_channel_layout, AV_SAMPLE_FMT_FLTP, - _fs->target_audio_sample_rate(), + _film->target_audio_sample_rate(), audio_channel_layout, AV_SAMPLE_FMT_FLTP, - _fs->audio_sample_rate(), + _film->audio_sample_rate(), 0, 0 ); @@ -266,11 +268,11 @@ J2KWAVEncoder::process_end () { boost::mutex::scoped_lock lock (_worker_mutex); - _log->log ("Clearing queue of " + lexical_cast<string> (_queue.size ())); + _film->log()->log ("Clearing queue of " + lexical_cast<string> (_queue.size ())); /* Keep waking workers until the queue is empty */ while (!_queue.empty ()) { - _log->log ("Waking with " + lexical_cast<string> (_queue.size ())); + _film->log()->log ("Waking with " + lexical_cast<string> (_queue.size ())); _worker_condition.notify_all (); _worker_condition.wait (lock); } @@ -279,7 +281,7 @@ J2KWAVEncoder::process_end () terminate_worker_threads (); - _log->log ("Mopping up " + lexical_cast<string> (_queue.size())); + _film->log()->log ("Mopping up " + lexical_cast<string> (_queue.size())); /* The following sequence of events can occur in the above code: 1. a remote worker takes the last image off the queue @@ -291,20 +293,20 @@ J2KWAVEncoder::process_end () */ for (list<shared_ptr<DCPVideoFrame> >::iterator i = _queue.begin(); i != _queue.end(); ++i) { - _log->log (String::compose ("Encode left-over frame %1", (*i)->frame ())); + _film->log()->log (String::compose ("Encode left-over frame %1", (*i)->frame ())); try { shared_ptr<EncodedData> e = (*i)->encode_locally (); e->write (_opt, (*i)->frame ()); frame_done ((*i)->frame ()); } catch (std::exception& e) { - _log->log (String::compose ("Local encode failed (%1)", e.what ())); + _film->log()->log (String::compose ("Local encode failed (%1)", e.what ())); } } #if HAVE_SWRESAMPLE if (_swr_context) { - shared_ptr<AudioBuffers> out (new AudioBuffers (_fs->audio_channels(), 256)); + shared_ptr<AudioBuffers> out (new AudioBuffers (_film->audio_channels(), 256)); while (1) { int const frames = swr_convert (_swr_context, (uint8_t **) out->data(), 256, 0, 0); @@ -324,16 +326,16 @@ J2KWAVEncoder::process_end () } #endif - int const dcp_sr = dcp_audio_sample_rate (_fs->audio_sample_rate ()); + int const dcp_sr = dcp_audio_sample_rate (_film->audio_sample_rate ()); int64_t const extra_audio_frames = dcp_sr - (_audio_frames_written % dcp_sr); - shared_ptr<AudioBuffers> silence (new AudioBuffers (_fs->audio_channels(), extra_audio_frames)); + shared_ptr<AudioBuffers> silence (new AudioBuffers (_film->audio_channels(), extra_audio_frames)); silence->make_silent (); write_audio (silence); close_sound_files (); /* Rename .wav.tmp files to .wav */ - for (int i = 0; i < _fs->audio_channels(); ++i) { + for (int i = 0; i < _film->audio_channels(); ++i) { if (boost::filesystem::exists (_opt->multichannel_audio_out_path (i, false))) { boost::filesystem::remove (_opt->multichannel_audio_out_path (i, false)); } @@ -351,9 +353,9 @@ J2KWAVEncoder::process_audio (shared_ptr<const AudioBuffers> audio) if (_swr_context) { /* Compute the resampled frames count and add 32 for luck */ - int const max_resampled_frames = ceil (audio->frames() * _fs->target_audio_sample_rate() / _fs->audio_sample_rate()) + 32; + int const max_resampled_frames = ceil (audio->frames() * _film->target_audio_sample_rate() / _film->audio_sample_rate()) + 32; - resampled.reset (new AudioBuffers (_fs->audio_channels(), max_resampled_frames)); + resampled.reset (new AudioBuffers (_film->audio_channels(), max_resampled_frames)); /* Resample audio */ int const resampled_frames = swr_convert ( @@ -377,7 +379,7 @@ J2KWAVEncoder::process_audio (shared_ptr<const AudioBuffers> audio) void J2KWAVEncoder::write_audio (shared_ptr<const AudioBuffers> audio) { - for (int i = 0; i < _fs->audio_channels(); ++i) { + for (int i = 0; i < _film->audio_channels(); ++i) { sf_write_float (_sound_files[i], audio->data(i), audio->frames()); } diff --git a/src/lib/j2k_wav_encoder.h b/src/lib/j2k_wav_encoder.h index 69d445b09..95a802b6e 100644 --- a/src/lib/j2k_wav_encoder.h +++ b/src/lib/j2k_wav_encoder.h @@ -47,7 +47,7 @@ class AudioBuffers; class J2KWAVEncoder : public Encoder { public: - J2KWAVEncoder (boost::shared_ptr<const FilmState>, boost::shared_ptr<const Options>, Log *); + J2KWAVEncoder (boost::shared_ptr<const Film>, boost::shared_ptr<const Options>); ~J2KWAVEncoder (); void process_begin (int64_t audio_channel_layout); diff --git a/src/lib/job.cc b/src/lib/job.cc index 68cdce3cd..f3d7deac0 100644 --- a/src/lib/job.cc +++ b/src/lib/job.cc @@ -30,20 +30,16 @@ using namespace std; using namespace boost; -/** @param s FilmState for the film that we are operating on. - * @param l A log that we can write to. +/** @param s Film that we are operating on. */ -Job::Job (shared_ptr<const FilmState> s, Log* l, shared_ptr<Job> req) - : _fs (s) - , _log (l) +Job::Job (shared_ptr<Film> f, shared_ptr<Job> req) + : _film (f) , _required (req) , _state (NEW) , _start_time (0) , _progress_unknown (false) , _ran_for (0) { - assert (_log); - descend (1); } diff --git a/src/lib/job.h b/src/lib/job.h index 6b2b69b9d..b608f5da2 100644 --- a/src/lib/job.h +++ b/src/lib/job.h @@ -29,8 +29,7 @@ #include <boost/enable_shared_from_this.hpp> #include <sigc++/sigc++.h> -class Log; -class FilmState; +class Film; class Options; /** @class Job @@ -39,7 +38,7 @@ class Options; class Job : public boost::enable_shared_from_this<Job> { public: - Job (boost::shared_ptr<const FilmState> s, Log* l, boost::shared_ptr<Job> req); + Job (boost::shared_ptr<Film> s, boost::shared_ptr<Job> req); /** @return user-readable name of this job */ virtual std::string name () const = 0; @@ -89,10 +88,8 @@ protected: void set_state (State); void set_error (std::string e); - /** FilmState for this job */ - boost::shared_ptr<const FilmState> _fs; - /** a log that this job can write to */ - Log* _log; + /** Film for this job */ + boost::shared_ptr<Film> _film; private: diff --git a/src/lib/make_dcp_job.cc b/src/lib/make_dcp_job.cc index fcfce4b07..5a16abc1e 100644 --- a/src/lib/make_dcp_job.cc +++ b/src/lib/make_dcp_job.cc @@ -30,21 +30,20 @@ extern "C" { #include <libavutil/pixdesc.h> } #include "make_dcp_job.h" -#include "film_state.h" #include "dcp_content_type.h" #include "exceptions.h" #include "options.h" #include "imagemagick_decoder.h" +#include "film.h" using namespace std; using namespace boost; -/** @param s FilmState of the Film we are making the DCP for. +/** @param f Film we are making the DCP for. * @param o Options. - * @param l Log. */ -MakeDCPJob::MakeDCPJob (shared_ptr<const FilmState> s, shared_ptr<const Options> o, Log* l, shared_ptr<Job> req) - : Job (s, l, req) +MakeDCPJob::MakeDCPJob (shared_ptr<Film> f, shared_ptr<const Options> o, shared_ptr<Job> req) + : Job (f, req) , _opt (o) { @@ -53,7 +52,7 @@ MakeDCPJob::MakeDCPJob (shared_ptr<const FilmState> s, shared_ptr<const Options> string MakeDCPJob::name () const { - return String::compose ("Make DCP for %1", _fs->name()); + return String::compose ("Make DCP for %1", _film->name()); } string @@ -71,26 +70,26 @@ MakeDCPJob::wav_path (libdcp::Channel c) const void MakeDCPJob::run () { - string const dcp_path = _fs->dir (_fs->dcp_name()); + string const dcp_path = _film->dir (_film->dcp_name()); /* Remove any old DCP */ filesystem::remove_all (dcp_path); int frames = 0; - switch (_fs->content_type ()) { + switch (_film->content_type ()) { case VIDEO: - frames = _fs->dcp_length (); + frames = _film->dcp_length (); break; case STILL: - frames = _fs->still_duration() * ImageMagickDecoder::static_frames_per_second (); + frames = _film->still_duration() * ImageMagickDecoder::static_frames_per_second (); break; } - libdcp::DCP dcp (_fs->dir (_fs->dcp_name())); + libdcp::DCP dcp (_film->dir (_film->dcp_name())); dcp.Progress.connect (sigc::mem_fun (*this, &MakeDCPJob::dcp_progress)); shared_ptr<libdcp::CPL> cpl ( - new libdcp::CPL (_fs->dir (_fs->dcp_name()), _fs->dcp_name(), _fs->dcp_content_type()->libdcp_kind (), frames, rint (_fs->frames_per_second())) + new libdcp::CPL (_film->dir (_film->dcp_name()), _film->dcp_name(), _film->dcp_content_type()->libdcp_kind (), frames, rint (_film->frames_per_second())) ); dcp.add_cpl (cpl); @@ -99,10 +98,10 @@ MakeDCPJob::run () shared_ptr<libdcp::MonoPictureAsset> pa ( new libdcp::MonoPictureAsset ( sigc::mem_fun (*this, &MakeDCPJob::j2c_path), - _fs->dir (_fs->dcp_name()), + _film->dir (_film->dcp_name()), "video.mxf", &dcp.Progress, - rint (_fs->frames_per_second()), + rint (_film->frames_per_second()), frames, _opt->out_size.width, _opt->out_size.height @@ -113,17 +112,17 @@ MakeDCPJob::run () shared_ptr<libdcp::SoundAsset> sa; - if (_fs->audio_channels() > 0) { + if (_film->audio_channels() > 0) { descend (0.1); sa.reset ( new libdcp::SoundAsset ( sigc::mem_fun (*this, &MakeDCPJob::wav_path), - _fs->dir (_fs->dcp_name()), + _film->dir (_film->dcp_name()), "audio.mxf", &dcp.Progress, - rint (_fs->frames_per_second()), + rint (_film->frames_per_second()), frames, - _fs->audio_channels() + _film->audio_channels() ) ); ascend (); diff --git a/src/lib/make_dcp_job.h b/src/lib/make_dcp_job.h index d430ac3ce..442bb55f5 100644 --- a/src/lib/make_dcp_job.h +++ b/src/lib/make_dcp_job.h @@ -29,7 +29,7 @@ class MakeDCPJob : public Job { public: - MakeDCPJob (boost::shared_ptr<const FilmState>, boost::shared_ptr<const Options>, Log *, boost::shared_ptr<Job> req); + MakeDCPJob (boost::shared_ptr<Film>, boost::shared_ptr<const Options>, boost::shared_ptr<Job> req); std::string name () const; void run (); diff --git a/src/lib/player.cc b/src/lib/player.cc index db69c66d1..67aba36f2 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -26,7 +26,6 @@ #include <boost/thread.hpp> #include <boost/algorithm/string.hpp> #include "player.h" -#include "film_state.h" #include "filter.h" #include "screen.h" #include "exceptions.h" diff --git a/src/lib/player_manager.cc b/src/lib/player_manager.cc index 74fd2383b..d22ef1064 100644 --- a/src/lib/player_manager.cc +++ b/src/lib/player_manager.cc @@ -19,7 +19,6 @@ #include "player_manager.h" #include "player.h" -#include "film_state.h" #include "screen.h" using namespace std; @@ -43,16 +42,16 @@ PlayerManager::instance () } void -PlayerManager::setup (shared_ptr<const FilmState> fs, shared_ptr<const Screen> sc) +PlayerManager::setup (shared_ptr<const Film> f, shared_ptr<const Screen> sc) { boost::mutex::scoped_lock lm (_players_mutex); _players.clear (); - _players.push_back (shared_ptr<Player> (new Player (fs, sc, Player::SPLIT_NONE))); + _players.push_back (shared_ptr<Player> (new Player (f, sc, Player::SPLIT_NONE))); } void -PlayerManager::setup (shared_ptr<const FilmState> fs_a, shared_ptr<const FilmState> fs_b, shared_ptr<const Screen> sc) +PlayerManager::setup (shared_ptr<const Film> fs_a, shared_ptr<const Film> fs_b, shared_ptr<const Screen> sc) { boost::mutex::scoped_lock lm (_players_mutex); diff --git a/src/lib/scp_dcp_job.cc b/src/lib/scp_dcp_job.cc index 3f400fca4..a455c72a2 100644 --- a/src/lib/scp_dcp_job.cc +++ b/src/lib/scp_dcp_job.cc @@ -27,11 +27,12 @@ #include <fcntl.h> #include <boost/filesystem.hpp> #include <libssh/libssh.h> +#include "compose.hpp" #include "scp_dcp_job.h" #include "exceptions.h" #include "config.h" #include "log.h" -#include "film_state.h" +#include "film.h" using namespace std; using namespace boost; @@ -91,8 +92,8 @@ public: }; -SCPDCPJob::SCPDCPJob (shared_ptr<const FilmState> s, Log* l, shared_ptr<Job> req) - : Job (s, l, req) +SCPDCPJob::SCPDCPJob (shared_ptr<Film> f, shared_ptr<Job> req) + : Job (f, req) , _status ("Waiting") { @@ -107,7 +108,7 @@ SCPDCPJob::name () const void SCPDCPJob::run () { - _log->log ("SCP DCP job starting"); + _film->log()->log ("SCP DCP job starting"); SSHSession ss; @@ -140,12 +141,12 @@ SCPDCPJob::run () throw NetworkError (String::compose ("Could not start SCP session (%1)", ssh_get_error (ss.session))); } - r = ssh_scp_push_directory (sc.scp, _fs->dcp_name().c_str(), S_IRWXU); + r = ssh_scp_push_directory (sc.scp, _film->dcp_name().c_str(), S_IRWXU); if (r != SSH_OK) { - throw NetworkError (String::compose ("Could not create remote directory %1 (%2)", _fs->dcp_name(), ssh_get_error (ss.session))); + throw NetworkError (String::compose ("Could not create remote directory %1 (%2)", _film->dcp_name(), ssh_get_error (ss.session))); } - string const dcp_dir = _fs->dir (_fs->dcp_name()); + string const dcp_dir = _film->dir (_film->dcp_name()); boost::uintmax_t bytes_to_transfer = 0; for (filesystem::directory_iterator i = filesystem::directory_iterator (dcp_dir); i != filesystem::directory_iterator(); ++i) { diff --git a/src/lib/scp_dcp_job.h b/src/lib/scp_dcp_job.h index b457fdf5b..5d0bfe7b4 100644 --- a/src/lib/scp_dcp_job.h +++ b/src/lib/scp_dcp_job.h @@ -26,7 +26,7 @@ class SCPDCPJob : public Job { public: - SCPDCPJob (boost::shared_ptr<const FilmState>, Log *, boost::shared_ptr<Job> req); + SCPDCPJob (boost::shared_ptr<Film>, boost::shared_ptr<Job> req); std::string name () const; void run (); diff --git a/src/lib/subtitle.cc b/src/lib/subtitle.cc index 37c372c20..282a2cde1 100644 --- a/src/lib/subtitle.cc +++ b/src/lib/subtitle.cc @@ -24,7 +24,6 @@ #include "subtitle.h" #include "image.h" #include "exceptions.h" -#include "film_state.h" using namespace std; using namespace boost; diff --git a/src/lib/tiff_decoder.cc b/src/lib/tiff_decoder.cc index 51c0b60d1..9058fcc2a 100644 --- a/src/lib/tiff_decoder.cc +++ b/src/lib/tiff_decoder.cc @@ -33,26 +33,25 @@ extern "C" { } #include "util.h" #include "tiff_decoder.h" -#include "film_state.h" #include "exceptions.h" #include "image.h" #include "options.h" +#include "film.h" using namespace std; using namespace boost; -/** @param fs FilmState of our Film. +/** @param f Our Film. * @param o Options. * @param j Job that we are associated with, or 0. - * @param l Log that we can write to. * @param minimal true to do the bare minimum of work; just run through the content. Useful for acquiring * accurate frame counts as quickly as possible. This generates no video or audio output. * @param ignore_length Ignore the content's claimed length when computing progress. */ -TIFFDecoder::TIFFDecoder (boost::shared_ptr<const FilmState> fs, boost::shared_ptr<const Options> o, Job* j, Log* l, bool minimal, bool ignore_length) - : Decoder (fs, o, j, l, minimal, ignore_length) +TIFFDecoder::TIFFDecoder (boost::shared_ptr<Film> f, boost::shared_ptr<const Options> o, Job* j, bool minimal, bool ignore_length) + : Decoder (f, o, j, minimal, ignore_length) { - string const dir = _fs->content_path (); + string const dir = _film->content_path (); if (!filesystem::is_directory (dir)) { throw DecodeError ("TIFF content must be in a directory"); @@ -186,8 +185,8 @@ string TIFFDecoder::file_path (string f) const { stringstream s; - s << _fs->content_path() << "/" << f; - return _fs->file (s.str ()); + s << _film->content_path() << "/" << f; + return _film->file (s.str ()); } PixelFormat @@ -199,7 +198,7 @@ TIFFDecoder::pixel_format () const int TIFFDecoder::time_base_numerator () const { - return rint (_fs->frames_per_second()); + return rint (_film->frames_per_second()); } diff --git a/src/lib/tiff_decoder.h b/src/lib/tiff_decoder.h index 07174889d..1c287ee06 100644 --- a/src/lib/tiff_decoder.h +++ b/src/lib/tiff_decoder.h @@ -35,7 +35,6 @@ class Job; class FilmState; class Options; class Image; -class Log; /** @class TIFFDecoder. * @brief A decoder which reads a numbered set of TIFF files, one per frame. @@ -43,7 +42,7 @@ class Log; class TIFFDecoder : public Decoder { public: - TIFFDecoder (boost::shared_ptr<const FilmState>, boost::shared_ptr<const Options>, Job *, Log *, bool, bool); + TIFFDecoder (boost::shared_ptr<Film>, boost::shared_ptr<const Options>, Job *, bool, bool); /* Methods to query our input video */ float frames_per_second () const; diff --git a/src/lib/transcode_job.cc b/src/lib/transcode_job.cc index fe34867b2..a4965ba44 100644 --- a/src/lib/transcode_job.cc +++ b/src/lib/transcode_job.cc @@ -28,19 +28,17 @@ #include "film.h" #include "format.h" #include "transcoder.h" -#include "film_state.h" #include "log.h" #include "encoder_factory.h" using namespace std; using namespace boost; -/** @param s FilmState to use. +/** @param s Film to use. * @param o Options. - * @param l A log that we can write to. */ -TranscodeJob::TranscodeJob (shared_ptr<const FilmState> s, shared_ptr<const Options> o, Log* l, shared_ptr<Job> req) - : Job (s, l, req) +TranscodeJob::TranscodeJob (shared_ptr<Film> f, shared_ptr<const Options> o, shared_ptr<Job> req) + : Job (f, req) , _opt (o) { @@ -49,7 +47,7 @@ TranscodeJob::TranscodeJob (shared_ptr<const FilmState> s, shared_ptr<const Opti string TranscodeJob::name () const { - return String::compose ("Transcode %1", _fs->name()); + return String::compose ("Transcode %1", _film->name()); } void @@ -57,21 +55,21 @@ TranscodeJob::run () { try { - _log->log ("Transcode job starting"); + _film->log()->log ("Transcode job starting"); - _encoder = encoder_factory (_fs, _opt, _log); - Transcoder w (_fs, _opt, this, _log, _encoder); + _encoder = encoder_factory (_film, _opt); + Transcoder w (_film, _opt, this, _encoder); w.go (); set_progress (1); set_state (FINISHED_OK); - _log->log ("Transcode job completed successfully"); + _film->log()->log ("Transcode job completed successfully"); } catch (std::exception& e) { set_progress (1); set_state (FINISHED_ERROR); - _log->log (String::compose ("Transcode job failed (%1)", e.what())); + _film->log()->log (String::compose ("Transcode job failed (%1)", e.what())); throw; } @@ -108,5 +106,5 @@ TranscodeJob::remaining_time () const return 0; } - return ((_fs->dcp_length() - _encoder->last_frame()) / fps); + return ((_film->dcp_length() - _encoder->last_frame()) / fps); } diff --git a/src/lib/transcode_job.h b/src/lib/transcode_job.h index d185cb65d..1decea070 100644 --- a/src/lib/transcode_job.h +++ b/src/lib/transcode_job.h @@ -32,7 +32,7 @@ class Encoder; class TranscodeJob : public Job { public: - TranscodeJob (boost::shared_ptr<const FilmState> s, boost::shared_ptr<const Options> o, Log* l, boost::shared_ptr<Job> req); + TranscodeJob (boost::shared_ptr<Film> f, boost::shared_ptr<const Options> o, boost::shared_ptr<Job> req); std::string name () const; void run (); diff --git a/src/lib/transcoder.cc b/src/lib/transcoder.cc index a809e55d2..8c02b7633 100644 --- a/src/lib/transcoder.cc +++ b/src/lib/transcoder.cc @@ -18,7 +18,7 @@ */ /** @file src/transcoder.cc - * @brief A class which takes a FilmState and some Options, then uses those to transcode a Film. + * @brief A class which takes a Film and some Options, then uses those to transcode the film. * * A decoder is selected according to the content type, and the encoder can be specified * as a parameter to the constructor. @@ -34,16 +34,15 @@ using namespace std; using namespace boost; /** Construct a transcoder using a Decoder that we create and a supplied Encoder. - * @param s FilmState of Film that we are transcoding. + * @param f Film that we are transcoding. * @param o Options. * @param j Job that we are running under, or 0. - * @param l Log that we can write to. * @param e Encoder to use. */ -Transcoder::Transcoder (shared_ptr<const FilmState> s, shared_ptr<const Options> o, Job* j, Log* l, shared_ptr<Encoder> e) +Transcoder::Transcoder (shared_ptr<Film> f, shared_ptr<const Options> o, Job* j, shared_ptr<Encoder> e) : _job (j) , _encoder (e) - , _decoder (decoder_factory (s, o, j, l)) + , _decoder (decoder_factory (f, o, j)) { assert (_encoder); diff --git a/src/lib/transcoder.h b/src/lib/transcoder.h index ad6530914..79ef89a18 100644 --- a/src/lib/transcoder.h +++ b/src/lib/transcoder.h @@ -40,7 +40,7 @@ class FilmState; class Transcoder { public: - Transcoder (boost::shared_ptr<const FilmState> s, boost::shared_ptr<const Options> o, Job* j, Log* l, boost::shared_ptr<Encoder> e); + Transcoder (boost::shared_ptr<Film> f, boost::shared_ptr<const Options> o, Job* j, boost::shared_ptr<Encoder> e); void go (); diff --git a/src/lib/util.cc b/src/lib/util.cc index 81dc72b3d..90b27f39a 100644 --- a/src/lib/util.cc +++ b/src/lib/util.cc @@ -57,7 +57,6 @@ extern "C" { #include "dcp_content_type.h" #include "filter.h" #include "screen.h" -#include "film_state.h" #include "sound_processor.h" #ifndef DVDOMATIC_DISABLE_PLAYER #include "player_manager.h" diff --git a/src/lib/util.h b/src/lib/util.h index 1d9984d9d..eb2af8381 100644 --- a/src/lib/util.h +++ b/src/lib/util.h @@ -36,7 +36,7 @@ extern "C" { #include "compose.hpp" #ifdef DVDOMATIC_DEBUG -#define TIMING(...) _log->microsecond_log (String::compose (__VA_ARGS__), Log::TIMING); +#define TIMING(...) _film->log()->microsecond_log (String::compose (__VA_ARGS__), Log::TIMING); #else #define TIMING(...) #endif diff --git a/src/lib/wscript b/src/lib/wscript index 04db716a4..af8b4b7d3 100644 --- a/src/lib/wscript +++ b/src/lib/wscript @@ -25,7 +25,6 @@ def build(bld): ffmpeg_compatibility.cc ffmpeg_decoder.cc film.cc - film_state.cc filter.cc format.cc image.cc |
