X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;ds=sidebyside;f=src%2Flib%2Ffilm.cc;h=0ca3746044291ff62de38ba8d130873a86b5001c;hb=1f4a21c0da3a917a5ff7743a577cc0f210fa86d8;hp=c119f1515fb469dadb0abc709674f5076e5eb5e7;hpb=0d3f5aae5b99832b7c5d55f32f5bccb365caa3fd;p=dcpomatic.git diff --git a/src/lib/film.cc b/src/lib/film.cc index c119f1515..0ca374604 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -50,7 +50,8 @@ #include "ui_signaller.h" #include "video_decoder.h" #include "audio_decoder.h" -#include "external_audio_decoder.h" +#include "sndfile_decoder.h" +#include "analyse_audio_job.h" #include "i18n.h" @@ -65,6 +66,7 @@ using std::ofstream; using std::setfill; using std::min; using std::make_pair; +using std::endl; using boost::shared_ptr; using boost::lexical_cast; using boost::to_upper_copy; @@ -73,7 +75,7 @@ using boost::starts_with; using boost::optional; using libdcp::Size; -int const Film::state_version = 3; +int const Film::state_version = 4; /** Construct a Film object in a given directory, reading any metadata * file that exists in that directory. An exception will be thrown if @@ -86,11 +88,12 @@ int const Film::state_version = 3; Film::Film (string d, bool must_exist) : _use_dci_name (true) , _trust_content_header (true) - , _dcp_content_type (0) - , _format (0) - , _scaler (Scaler::from_id (N_("bicubic"))) + , _dcp_content_type (Config::instance()->default_dcp_content_type ()) + , _format (Config::instance()->default_format ()) + , _scaler (Scaler::from_id ("bicubic")) , _trim_start (0) , _trim_end (0) + , _trim_type (CPL) , _dcp_ab (false) , _use_content_audio (true) , _audio_gain (0) @@ -102,7 +105,8 @@ Film::Film (string d, bool must_exist) , _colour_lut (0) , _j2k_bandwidth (200000000) , _dci_metadata (Config::instance()->default_dci_metadata ()) - , _frames_per_second (0) + , _dcp_frame_rate (0) + , _source_frame_rate (0) , _dirty (false) { set_dci_date_today (); @@ -114,13 +118,13 @@ Film::Film (string d, bool must_exist) boost::filesystem::path p (boost::filesystem::system_complete (d)); boost::filesystem::path result; for (boost::filesystem::path::iterator i = p.begin(); i != p.end(); ++i) { - if (*i == N_("..")) { - if (boost::filesystem::is_symlink (result) || result.filename() == N_("..")) { + if (*i == "..") { + if (boost::filesystem::is_symlink (result) || result.filename() == "..") { result /= *i; } else { result = result.parent_path (); } - } else if (*i != N_(".")) { + } else if (*i != ".") { result /= *i; } } @@ -135,18 +139,21 @@ Film::Film (string d, bool must_exist) } } - _external_audio_stream = ExternalAudioStream::create (); + _sndfile_stream = SndfileStream::create (); if (must_exist) { read_metadata (); + } else { + write_metadata (); } - _log = new FileLog (file (N_("log"))); + _log.reset (new FileLog (file ("log"))); } Film::Film (Film const & o) : boost::enable_shared_from_this (o) - , _log (0) + /* note: the copied film shares the original's log */ + , _log (o._log) , _directory (o._directory) , _name (o._name) , _use_dci_name (o._use_dci_name) @@ -159,6 +166,7 @@ Film::Film (Film const & o) , _scaler (o._scaler) , _trim_start (o._trim_start) , _trim_end (o._trim_end) + , _trim_type (o._trim_type) , _dcp_ab (o._dcp_ab) , _content_audio_stream (o._content_audio_stream) , _external_audio (o._external_audio) @@ -174,43 +182,45 @@ Film::Film (Film const & o) , _j2k_bandwidth (o._j2k_bandwidth) , _dci_metadata (o._dci_metadata) , _dci_date (o._dci_date) + , _dcp_frame_rate (o._dcp_frame_rate) , _size (o._size) , _length (o._length) - , _dcp_intrinsic_duration (o._dcp_intrinsic_duration) , _content_digest (o._content_digest) , _content_audio_streams (o._content_audio_streams) - , _external_audio_stream (o._external_audio_stream) + , _sndfile_stream (o._sndfile_stream) , _subtitle_streams (o._subtitle_streams) - , _frames_per_second (o._frames_per_second) + , _source_frame_rate (o._source_frame_rate) , _dirty (o._dirty) { - + } Film::~Film () { - delete _log; + } string Film::video_state_identifier () const { assert (format ()); + LocaleGuard lg; pair f = Filter::ffmpeg_strings (filters()); stringstream s; s << format()->id() - << N_("_") << content_digest() - << N_("_") << crop().left << N_("_") << crop().right << N_("_") << crop().top << N_("_") << crop().bottom - << N_("_") << f.first << N_("_") << f.second - << N_("_") << scaler()->id() - << N_("_") << j2k_bandwidth() - << N_("_") << boost::lexical_cast (colour_lut()); + << "_" << content_digest() + << "_" << crop().left << "_" << crop().right << "_" << crop().top << "_" << crop().bottom + << "_" << _dcp_frame_rate + << "_" << f.first << "_" << f.second + << "_" << scaler()->id() + << "_" << j2k_bandwidth() + << "_" << boost::lexical_cast (colour_lut()); if (dcp_ab()) { pair fa = Filter::ffmpeg_strings (Config::instance()->reference_filters()); - s << N_("ab_") << Config::instance()->reference_scaler()->id() << N_("_") << fa.first << N_("_") << fa.second; + s << "ab_" << Config::instance()->reference_scaler()->id() << "_" << fa.first << "_" << fa.second; } return s.str (); @@ -221,22 +231,59 @@ string Film::info_dir () const { boost::filesystem::path p; - p /= N_("info"); + p /= "info"; p /= video_state_identifier (); return dir (p.string()); } string -Film::video_mxf_dir () const +Film::internal_video_mxf_dir () const { boost::filesystem::path p; - return dir (N_("video")); + return dir ("video"); +} + +string +Film::internal_video_mxf_filename () const +{ + return video_state_identifier() + ".mxf"; +} + +string +Film::dcp_video_mxf_filename () const +{ + return filename_safe_name() + "_video.mxf"; } string -Film::video_mxf_filename () const +Film::dcp_audio_mxf_filename () const { - return video_state_identifier() + N_(".mxf"); + return filename_safe_name() + "_audio.mxf"; +} + +string +Film::filename_safe_name () const +{ + string const n = name (); + string o; + for (size_t i = 0; i < n.length(); ++i) { + if (isalnum (n[i])) { + o += n[i]; + } else { + o += "_"; + } + } + + return o; +} + +string +Film::audio_analysis_path () const +{ + boost::filesystem::path p; + p /= "analysis"; + p /= content_digest(); + return file (p.string ()); } /** Add suitable Jobs to the JobManager to create a DCP for this Film */ @@ -245,37 +292,38 @@ Film::make_dcp () { set_dci_date_today (); - if (dcp_name().find (N_("/")) != string::npos) { + if (dcp_name().find ("/") != string::npos) { throw BadSettingError (_("name"), _("cannot contain slashes")); } - log()->log (String::compose (N_("DVD-o-matic %1 git %2 using %3"), dvdomatic_version, dvdomatic_git_commit, dependency_version_summary())); + log()->log (String::compose ("DVD-o-matic %1 git %2 using %3", dvdomatic_version, dvdomatic_git_commit, dependency_version_summary())); { char buffer[128]; gethostname (buffer, sizeof (buffer)); - log()->log (String::compose (N_("Starting to make DCP on %1"), buffer)); + log()->log (String::compose ("Starting to make DCP on %1", buffer)); } - log()->log (String::compose (N_("Content is %1; type %2"), content_path(), (content_type() == STILL ? _("still") : _("video")))); + log()->log (String::compose ("Content is %1; type %2", content_path(), (content_type() == STILL ? _("still") : _("video")))); if (length()) { - log()->log (String::compose (N_("Content length %1"), length().get())); + log()->log (String::compose ("Content length %1", length().get())); } - log()->log (String::compose (N_("Content digest %1"), content_digest())); - log()->log (String::compose (N_("%1 threads"), Config::instance()->num_local_encoding_threads())); - log()->log (String::compose (N_("J2K bandwidth %1"), j2k_bandwidth())); + log()->log (String::compose ("Content digest %1", content_digest())); + log()->log (String::compose ("Content at %1 fps, DCP at %2 fps", source_frame_rate(), dcp_frame_rate())); + log()->log (String::compose ("%1 threads", Config::instance()->num_local_encoding_threads())); + log()->log (String::compose ("J2K bandwidth %1", j2k_bandwidth())); #ifdef DVDOMATIC_DEBUG - log()->log (N_("DVD-o-matic built in debug mode.")); + log()->log ("DVD-o-matic built in debug mode."); #else - log()->log (N_("DVD-o-matic built in optimised mode.")); + log()->log ("DVD-o-matic built in optimised mode."); #endif #ifdef LIBDCP_DEBUG - log()->log (N_("libdcp built in debug mode.")); + log()->log ("libdcp built in debug mode."); #else - log()->log (N_("libdcp built in optimised mode.")); + log()->log ("libdcp built in optimised mode."); #endif pair const c = cpu_info (); - log()->log (String::compose (N_("CPU: %1, %2 processors"), c.first, c.second)); + log()->log (String::compose ("CPU: %1, %2 processors", c.first, c.second)); if (format() == 0) { throw MissingSettingError (_("format")); @@ -305,6 +353,19 @@ Film::make_dcp () } } +/** Start a job to analyse the audio of our content file */ +void +Film::analyse_audio () +{ + if (_analyse_audio_job) { + return; + } + + _analyse_audio_job.reset (new AnalyseAudioJob (shared_from_this())); + _analyse_audio_job->Finished.connect (bind (&Film::analyse_audio_finished, this)); + JobManager::instance()->add (_analyse_audio_job); +} + /** Start a job to examine our content file */ void Film::examine_content () @@ -318,6 +379,18 @@ Film::examine_content () JobManager::instance()->add (_examine_content_job); } +void +Film::analyse_audio_finished () +{ + ensure_ui_thread (); + + if (_analyse_audio_job->finished_ok ()) { + AudioAnalysisSucceeded (); + } + + _analyse_audio_job.reset (); +} + void Film::examine_content_finished () { @@ -356,76 +429,85 @@ void Film::write_metadata () const { boost::mutex::scoped_lock lm (_state_mutex); + LocaleGuard lg; boost::filesystem::create_directories (directory()); - string const m = file (N_("metadata")); + string const m = file ("metadata"); ofstream f (m.c_str ()); if (!f.good ()) { throw CreateFileError (m); } - f << N_("version ") << state_version << N_("\n"); + f << "version " << state_version << endl; /* User stuff */ - f << N_("name ") << _name << N_("\n"); - f << N_("use_dci_name ") << _use_dci_name << N_("\n"); - f << N_("content ") << _content << N_("\n"); - f << N_("trust_content_header ") << (_trust_content_header ? N_("1") : N_("0")) << N_("\n"); + f << "name " << _name << endl; + f << "use_dci_name " << _use_dci_name << endl; + f << "content " << _content << endl; + f << "trust_content_header " << (_trust_content_header ? "1" : "0") << endl; if (_dcp_content_type) { - f << N_("dcp_content_type ") << _dcp_content_type->dci_name () << N_("\n"); + f << "dcp_content_type " << _dcp_content_type->dci_name () << endl; } if (_format) { - f << N_("format ") << _format->as_metadata () << N_("\n"); + f << "format " << _format->as_metadata () << endl; } - f << N_("left_crop ") << _crop.left << N_("\n"); - f << N_("right_crop ") << _crop.right << N_("\n"); - f << N_("top_crop ") << _crop.top << N_("\n"); - f << N_("bottom_crop ") << _crop.bottom << N_("\n"); + f << "left_crop " << _crop.left << endl; + f << "right_crop " << _crop.right << endl; + f << "top_crop " << _crop.top << endl; + f << "bottom_crop " << _crop.bottom << endl; for (vector::const_iterator i = _filters.begin(); i != _filters.end(); ++i) { - f << N_("filter ") << (*i)->id () << N_("\n"); + f << "filter " << (*i)->id () << endl; + } + f << "scaler " << _scaler->id () << endl; + f << "trim_start " << _trim_start << endl; + f << "trim_end " << _trim_end << endl; + switch (_trim_type) { + case CPL: + f << "trim_type cpl\n"; + break; + case ENCODE: + f << "trim_type encode\n"; + break; } - f << N_("scaler ") << _scaler->id () << N_("\n"); - f << N_("trim_start ") << _trim_start << N_("\n"); - f << N_("trim_end ") << _trim_end << N_("\n"); - f << N_("dcp_ab ") << (_dcp_ab ? N_("1") : N_("0")) << N_("\n"); + f << "dcp_ab " << (_dcp_ab ? "1" : "0") << endl; if (_content_audio_stream) { - f << N_("selected_content_audio_stream ") << _content_audio_stream->to_string() << N_("\n"); + f << "selected_content_audio_stream " << _content_audio_stream->to_string() << endl; } for (vector::const_iterator i = _external_audio.begin(); i != _external_audio.end(); ++i) { - f << N_("external_audio ") << *i << N_("\n"); + f << "external_audio " << *i << endl; } - f << N_("use_content_audio ") << (_use_content_audio ? N_("1") : N_("0")) << N_("\n"); - f << N_("audio_gain ") << _audio_gain << N_("\n"); - f << N_("audio_delay ") << _audio_delay << N_("\n"); - f << N_("still_duration ") << _still_duration << N_("\n"); + f << "use_content_audio " << (_use_content_audio ? "1" : "0") << endl; + f << "audio_gain " << _audio_gain << endl; + f << "audio_delay " << _audio_delay << endl; + f << "still_duration " << _still_duration << endl; if (_subtitle_stream) { - f << N_("selected_subtitle_stream ") << _subtitle_stream->to_string() << N_("\n"); + f << "selected_subtitle_stream " << _subtitle_stream->to_string() << endl; } - f << N_("with_subtitles ") << _with_subtitles << N_("\n"); - f << N_("subtitle_offset ") << _subtitle_offset << N_("\n"); - f << N_("subtitle_scale ") << _subtitle_scale << N_("\n"); - f << N_("colour_lut ") << _colour_lut << N_("\n"); - f << N_("j2k_bandwidth ") << _j2k_bandwidth << N_("\n"); + f << "with_subtitles " << _with_subtitles << endl; + f << "subtitle_offset " << _subtitle_offset << endl; + f << "subtitle_scale " << _subtitle_scale << endl; + f << "colour_lut " << _colour_lut << endl; + f << "j2k_bandwidth " << _j2k_bandwidth << endl; _dci_metadata.write (f); - f << N_("dci_date ") << boost::gregorian::to_iso_string (_dci_date) << N_("\n"); - f << N_("width ") << _size.width << N_("\n"); - f << N_("height ") << _size.height << N_("\n"); - f << N_("length ") << _length.get_value_or(0) << N_("\n"); - f << N_("dcp_intrinsic_duration ") << _dcp_intrinsic_duration.get_value_or(0) << N_("\n"); - f << N_("content_digest ") << _content_digest << N_("\n"); + f << "dci_date " << boost::gregorian::to_iso_string (_dci_date) << endl; + f << "dcp_frame_rate " << _dcp_frame_rate << endl; + f << "width " << _size.width << endl; + f << "height " << _size.height << endl; + f << "length " << _length.get_value_or(0) << endl; + f << "content_digest " << _content_digest << endl; for (vector >::const_iterator i = _content_audio_streams.begin(); i != _content_audio_streams.end(); ++i) { - f << N_("content_audio_stream ") << (*i)->to_string () << N_("\n"); + f << "content_audio_stream " << (*i)->to_string () << endl; } - f << N_("external_audio_stream ") << _external_audio_stream->to_string() << N_("\n"); + f << "external_audio_stream " << _sndfile_stream->to_string() << endl; for (vector >::const_iterator i = _subtitle_streams.begin(); i != _subtitle_streams.end(); ++i) { - f << N_("subtitle_stream ") << (*i)->to_string () << N_("\n"); + f << "subtitle_stream " << (*i)->to_string () << endl; } - f << N_("frames_per_second ") << _frames_per_second << N_("\n"); + f << "source_frame_rate " << _source_frame_rate << endl; _dirty = false; } @@ -435,6 +517,7 @@ void Film::read_metadata () { boost::mutex::scoped_lock lm (_state_mutex); + LocaleGuard lg; _external_audio.clear (); _content_audio_streams.clear (); @@ -447,15 +530,15 @@ Film::read_metadata () boost::optional audio_stream_index; boost::optional subtitle_stream_index; - ifstream f (file (N_("metadata")).c_str()); + ifstream f (file ("metadata").c_str()); if (!f.good()) { - throw OpenFileError (file (N_("metadata"))); + throw OpenFileError (file ("metadata")); } multimap kv = read_key_value (f); /* We need version before anything else */ - multimap::iterator v = kv.find (N_("version")); + multimap::iterator v = kv.find ("version"); if (v != kv.end ()) { version = atoi (v->second.c_str()); } @@ -464,108 +547,115 @@ Film::read_metadata () string const k = i->first; string const v = i->second; - if (k == N_("audio_sample_rate")) { + if (k == "audio_sample_rate") { audio_sample_rate = atoi (v.c_str()); } /* User-specified stuff */ - if (k == N_("name")) { + if (k == "name") { _name = v; - } else if (k == N_("use_dci_name")) { - _use_dci_name = (v == N_("1")); - } else if (k == N_("content")) { + } else if (k == "use_dci_name") { + _use_dci_name = (v == "1"); + } else if (k == "content") { _content = v; - } else if (k == N_("trust_content_header")) { - _trust_content_header = (v == N_("1")); - } else if (k == N_("dcp_content_type")) { + } else if (k == "trust_content_header") { + _trust_content_header = (v == "1"); + } else if (k == "dcp_content_type") { if (version < 3) { _dcp_content_type = DCPContentType::from_pretty_name (v); } else { _dcp_content_type = DCPContentType::from_dci_name (v); } - } else if (k == N_("format")) { + } else if (k == "format") { _format = Format::from_metadata (v); - } else if (k == N_("left_crop")) { + } else if (k == "left_crop") { _crop.left = atoi (v.c_str ()); - } else if (k == N_("right_crop")) { + } else if (k == "right_crop") { _crop.right = atoi (v.c_str ()); - } else if (k == N_("top_crop")) { + } else if (k == "top_crop") { _crop.top = atoi (v.c_str ()); - } else if (k == N_("bottom_crop")) { + } else if (k == "bottom_crop") { _crop.bottom = atoi (v.c_str ()); - } else if (k == N_("filter")) { + } else if (k == "filter") { _filters.push_back (Filter::from_id (v)); - } else if (k == N_("scaler")) { + } else if (k == "scaler") { _scaler = Scaler::from_id (v); - } else if ( ((!version || version < 2) && k == N_("dcp_trim_start")) || k == N_("trim_start")) { + } else if ( ((!version || version < 2) && k == "dcp_trim_start") || k == "trim_start") { _trim_start = atoi (v.c_str ()); - } else if ( ((!version || version < 2) && k == N_("dcp_trim_end")) || k == N_("trim_end")) { + } else if ( ((!version || version < 2) && k == "dcp_trim_end") || k == "trim_end") { _trim_end = atoi (v.c_str ()); - } else if (k == N_("dcp_ab")) { - _dcp_ab = (v == N_("1")); - } else if (k == N_("selected_content_audio_stream") || (!version && k == N_("selected_audio_stream"))) { + } else if (k == "trim_type") { + if (v == "cpl") { + _trim_type = CPL; + } else if (v == "encode") { + _trim_type = ENCODE; + } + } else if (k == "dcp_ab") { + _dcp_ab = (v == "1"); + } else if (k == "selected_content_audio_stream" || (!version && k == "selected_audio_stream")) { if (!version) { audio_stream_index = atoi (v.c_str ()); } else { _content_audio_stream = audio_stream_factory (v, version); } - } else if (k == N_("external_audio")) { + } else if (k == "external_audio") { _external_audio.push_back (v); - } else if (k == N_("use_content_audio")) { - _use_content_audio = (v == N_("1")); - } else if (k == N_("audio_gain")) { + } else if (k == "use_content_audio") { + _use_content_audio = (v == "1"); + } else if (k == "audio_gain") { _audio_gain = atof (v.c_str ()); - } else if (k == N_("audio_delay")) { + } else if (k == "audio_delay") { _audio_delay = atoi (v.c_str ()); - } else if (k == N_("still_duration")) { + } else if (k == "still_duration") { _still_duration = atoi (v.c_str ()); - } else if (k == N_("selected_subtitle_stream")) { + } else if (k == "selected_subtitle_stream") { if (!version) { subtitle_stream_index = atoi (v.c_str ()); } else { _subtitle_stream = subtitle_stream_factory (v, version); } - } else if (k == N_("with_subtitles")) { - _with_subtitles = (v == N_("1")); - } else if (k == N_("subtitle_offset")) { + } else if (k == "with_subtitles") { + _with_subtitles = (v == "1"); + } else if (k == "subtitle_offset") { _subtitle_offset = atoi (v.c_str ()); - } else if (k == N_("subtitle_scale")) { + } else if (k == "subtitle_scale") { _subtitle_scale = atof (v.c_str ()); - } else if (k == N_("colour_lut")) { + } else if (k == "colour_lut") { _colour_lut = atoi (v.c_str ()); - } else if (k == N_("j2k_bandwidth")) { + } else if (k == "j2k_bandwidth") { _j2k_bandwidth = atoi (v.c_str ()); - } else if (k == N_("dci_date")) { + } else if (k == "dci_date") { _dci_date = boost::gregorian::from_undelimited_string (v); + } else if (k == "dcp_frame_rate") { + _dcp_frame_rate = atoi (v.c_str ()); } _dci_metadata.read (k, v); /* Cached stuff */ - if (k == N_("width")) { + if (k == "width") { _size.width = atoi (v.c_str ()); - } else if (k == N_("height")) { + } else if (k == "height") { _size.height = atoi (v.c_str ()); - } else if (k == N_("length")) { + } else if (k == "length") { int const vv = atoi (v.c_str ()); if (vv) { _length = vv; } - } else if (k == N_("dcp_intrinsic_duration")) { - int const vv = atoi (v.c_str ()); - if (vv) { - _dcp_intrinsic_duration = vv; - } - } else if (k == N_("content_digest")) { + } else if (k == "content_digest") { _content_digest = v; - } else if (k == N_("content_audio_stream") || (!version && k == N_("audio_stream"))) { + } else if (k == "content_audio_stream" || (!version && k == "audio_stream")) { _content_audio_streams.push_back (audio_stream_factory (v, version)); - } else if (k == N_("external_audio_stream")) { - _external_audio_stream = audio_stream_factory (v, version); - } else if (k == N_("subtitle_stream")) { + } else if (k == "external_audio_stream") { + _sndfile_stream = audio_stream_factory (v, version); + } else if (k == "subtitle_stream") { _subtitle_streams.push_back (subtitle_stream_factory (v, version)); - } else if (k == N_("frames_per_second")) { - _frames_per_second = atof (v.c_str ()); + } else if (k == "source_frame_rate") { + _source_frame_rate = atof (v.c_str ()); + } else if (version < 4 && k == "frames_per_second") { + _source_frame_rate = atof (v.c_str ()); + /* Fill in what would have been used for DCP frame rate by the older version */ + _dcp_frame_rate = best_dcp_frame_rate (_source_frame_rate); } } @@ -675,7 +765,7 @@ Film::target_audio_sample_rate () const /* Resample to a DCI-approved sample rate */ double t = dcp_audio_sample_rate (audio_stream()->sample_rate()); - DCPFrameRate dfr (frames_per_second ()); + FrameRateConversion frc (source_frame_rate(), dcp_frame_rate()); /* Compensate if the DCP is being run at a different frame rate to the source; that is, if the video is run such that it will @@ -683,8 +773,8 @@ Film::target_audio_sample_rate () const skip/repeat doesn't come into effect here. */ - if (dfr.change_speed) { - t *= _frames_per_second * dfr.factor() / dfr.frames_per_second; + if (frc.change_speed) { + t *= source_frame_rate() * frc.factor() / dcp_frame_rate(); } return rint (t); @@ -693,7 +783,7 @@ Film::target_audio_sample_rate () const int Film::still_duration_in_frames () const { - return still_duration() * frames_per_second(); + return still_duration() * source_frame_rate(); } /** @return a DCI-compliant name for a DCP of this film */ @@ -714,70 +804,67 @@ Film::dci_name (bool if_created_now) const fixed_name = fixed_name.substr (0, 14); } - d << fixed_name << N_("_"); + d << fixed_name; if (dcp_content_type()) { - d << dcp_content_type()->dci_name() << N_("_"); + d << "_" << dcp_content_type()->dci_name(); } if (format()) { - d << format()->dci_name() << N_("_"); + d << "_" << format()->dci_name(); } DCIMetadata const dm = dci_metadata (); if (!dm.audio_language.empty ()) { - d << dm.audio_language; - if (!dm.subtitle_language.empty() && with_subtitles()) { - d << N_("-") << dm.subtitle_language; + d << "_" << dm.audio_language; + if (!dm.subtitle_language.empty()) { + d << "-" << dm.subtitle_language; } else { - d << N_("-XX"); + d << "-XX"; } - - d << N_("_"); } if (!dm.territory.empty ()) { - d << dm.territory; + d << "_" << dm.territory; if (!dm.rating.empty ()) { - d << N_("-") << dm.rating; + d << "-" << dm.rating; } - d << N_("_"); } switch (audio_channels()) { case 1: - d << N_("10_"); + d << "_10"; break; case 2: - d << N_("20_"); + d << "_20"; break; case 6: - d << N_("51_"); + d << "_51"; break; case 8: - d << N_("71_"); + d << "_71"; break; } - d << N_("2K_"); + d << "_2K"; if (!dm.studio.empty ()) { - d << dm.studio << N_("_"); + d << "_" << dm.studio; } if (if_created_now) { - d << boost::gregorian::to_iso_string (boost::gregorian::day_clock::local_day ()) << N_("_"); + d << "_" << boost::gregorian::to_iso_string (boost::gregorian::day_clock::local_day ()); } else { - d << boost::gregorian::to_iso_string (_dci_date) << N_("_"); + d << "_" << boost::gregorian::to_iso_string (_dci_date); } if (!dm.facility.empty ()) { - d << dm.facility << N_("_"); + d << "_" << dm.facility; } if (!dm.package_type.empty ()) { - d << dm.package_type; + d << "_" << dm.package_type; } return d.str (); @@ -828,7 +915,7 @@ Film::set_content (string c) { string check = directory (); - boost::filesystem::path slash (N_("/")); + boost::filesystem::path slash ("/"); string platform_slash = slash.make_preferred().string (); if (!ends_with (check, platform_slash)) { @@ -866,12 +953,20 @@ Film::set_content (string c) Decoders d = decoder_factory (shared_from_this(), DecodeOptions()); set_size (d.video->native_size ()); - set_frames_per_second (d.video->frames_per_second ()); + set_source_frame_rate (d.video->frames_per_second ()); + set_dcp_frame_rate (best_dcp_frame_rate (source_frame_rate ())); set_subtitle_streams (d.video->subtitle_streams ()); if (d.audio) { set_content_audio_streams (d.audio->audio_streams ()); } + { + boost::mutex::scoped_lock lm (_state_mutex); + _content = c; + } + + signal_changed (CONTENT); + /* Start off with the first audio and subtitle streams */ if (d.audio && !d.audio->audio_streams().empty()) { set_content_audio_stream (d.audio->audio_streams().front()); @@ -881,13 +976,6 @@ Film::set_content (string c) set_subtitle_stream (d.video->subtitle_streams().front()); } - { - boost::mutex::scoped_lock lm (_state_mutex); - _content = c; - } - - signal_changed (CONTENT); - examine_content (); } catch (...) { @@ -901,10 +989,10 @@ Film::set_content (string c) /* Default format */ switch (content_type()) { case STILL: - set_format (Format::from_id (N_("var-185"))); + set_format (Format::from_id ("var-185")); break; case VIDEO: - set_format (Format::from_id (N_("185"))); + set_format (Format::from_id ("185")); break; } @@ -1057,6 +1145,16 @@ Film::set_trim_end (int t) signal_changed (TRIM_END); } +void +Film::set_trim_type (TrimType t) +{ + { + boost::mutex::scoped_lock lm (_state_mutex); + _trim_type = t; + } + signal_changed (TRIM_TYPE); +} + void Film::set_dcp_ab (bool a) { @@ -1085,9 +1183,9 @@ Film::set_external_audio (vector a) _external_audio = a; } - shared_ptr decoder (new ExternalAudioDecoder (shared_from_this(), DecodeOptions())); + shared_ptr decoder (new SndfileDecoder (shared_from_this(), DecodeOptions())); if (decoder->audio_stream()) { - _external_audio_stream = decoder->audio_stream (); + _sndfile_stream = decoder->audio_stream (); } signal_changed (EXTERNAL_AUDIO); @@ -1204,6 +1302,17 @@ Film::set_dci_metadata (DCIMetadata m) signal_changed (DCI_METADATA); } + +void +Film::set_dcp_frame_rate (int f) +{ + { + boost::mutex::scoped_lock lm (_state_mutex); + _dcp_frame_rate = f; + } + signal_changed (DCP_FRAME_RATE); +} + void Film::set_size (libdcp::Size s) { @@ -1234,16 +1343,6 @@ Film::unset_length () signal_changed (LENGTH); } -void -Film::set_dcp_intrinsic_duration (int d) -{ - { - boost::mutex::scoped_lock lm (_state_mutex); - _dcp_intrinsic_duration = d; - } - signal_changed (DCP_INTRINSIC_DURATION); -} - void Film::set_content_digest (string d) { @@ -1275,13 +1374,13 @@ Film::set_subtitle_streams (vector > s) } void -Film::set_frames_per_second (float f) +Film::set_source_frame_rate (float f) { { boost::mutex::scoped_lock lm (_state_mutex); - _frames_per_second = f; + _source_frame_rate = f; } - signal_changed (FRAMES_PER_SECOND); + signal_changed (SOURCE_FRAME_RATE); } void @@ -1321,7 +1420,7 @@ Film::audio_stream () const return _content_audio_stream; } - return _external_audio_stream; + return _sndfile_stream; } string @@ -1332,7 +1431,7 @@ Film::info_path (int f) const stringstream s; s.width (8); - s << setfill('0') << f << N_(".md5"); + s << setfill('0') << f << ".md5"; p /= s.str(); @@ -1346,15 +1445,15 @@ string Film::j2c_path (int f, bool t) const { boost::filesystem::path p; - p /= N_("j2c"); + p /= "j2c"; p /= video_state_identifier (); stringstream s; s.width (8); - s << setfill('0') << f << N_(".j2c"); + s << setfill('0') << f << ".j2c"; if (t) { - s << N_(".tmp"); + s << ".tmp"; } p /= s.str(); @@ -1378,3 +1477,21 @@ Film::have_dcp () const return true; } + +bool +Film::has_audio () const +{ + if (use_content_audio()) { + return audio_stream(); + } + + vector const e = external_audio (); + for (vector::const_iterator i = e.begin(); i != e.end(); ++i) { + if (!i->empty ()) { + return true; + } + } + + return false; +} +