using boost::ends_with;
using boost::starts_with;
using boost::optional;
+using libdcp::Size;
-int const Film::state_version = 1;
+int const Film::state_version = 2;
/** Construct a Film object in a given directory, reading any metadata
* file that exists in that directory. An exception will be thrown if
, _dcp_content_type (0)
, _format (0)
, _scaler (Scaler::from_id ("bicubic"))
- , _dcp_trim_start (0)
- , _dcp_trim_end (0)
+ , _trim_start (0)
+ , _trim_end (0)
, _dcp_ab (false)
, _use_content_audio (true)
, _audio_gain (0)
, _crop (o._crop)
, _filters (o._filters)
, _scaler (o._scaler)
- , _dcp_trim_start (o._dcp_trim_start)
- , _dcp_trim_end (o._dcp_trim_end)
+ , _trim_start (o._trim_start)
+ , _trim_end (o._trim_end)
, _reel_size (o._reel_size)
, _dcp_ab (o._dcp_ab)
, _content_audio_stream (o._content_audio_stream)
, _package_type (o._package_type)
, _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)
}
log()->log (String::compose ("Content is %1; type %2", content_path(), (content_type() == STILL ? "still" : "video")));
- log()->log (String::compose ("Content length %1", length().get()));
+ if (length()) {
+ log()->log (String::compose ("Content length %1", length().get()));
+ }
log()->log (String::compose ("Content digest %1", content_digest()));
log()->log (String::compose ("%1 threads", Config::instance()->num_local_encoding_threads()));
log()->log (String::compose ("J2K bandwidth %1", j2k_bandwidth()));
throw MissingSettingError ("name");
}
- shared_ptr<EncodeOptions> oe (new EncodeOptions (j2k_dir(), ".j2c", dir ("wavs")));
- oe->out_size = format()->dcp_size ();
- oe->padding = format()->dcp_padding (shared_from_this ());
- if (dcp_length ()) {
- oe->video_range = make_pair (dcp_trim_start(), dcp_trim_start() + dcp_length().get());
- if (audio_stream()) {
- oe->audio_range = make_pair (
-
- video_frames_to_audio_frames (
- oe->video_range.get().first,
- dcp_audio_sample_rate (audio_stream()->sample_rate()),
- dcp_frame_rate (frames_per_second()).frames_per_second
- ),
-
- video_frames_to_audio_frames (
- oe->video_range.get().second,
- dcp_audio_sample_rate (audio_stream()->sample_rate()),
- dcp_frame_rate (frames_per_second()).frames_per_second
- )
- );
- }
-
- }
-
- oe->video_skip = dcp_frame_rate (frames_per_second()).skip;
-
- shared_ptr<DecodeOptions> od (new DecodeOptions);
- od->decode_subtitles = with_subtitles ();
+ DecodeOptions od;
+ od.decode_subtitles = with_subtitles ();
shared_ptr<Job> r;
if (transcode) {
if (dcp_ab()) {
- r = JobManager::instance()->add (shared_ptr<Job> (new ABTranscodeJob (shared_from_this(), od, oe, shared_ptr<Job> ())));
+ r = JobManager::instance()->add (shared_ptr<Job> (new ABTranscodeJob (shared_from_this(), od, shared_ptr<Job> ())));
} else {
- r = JobManager::instance()->add (shared_ptr<Job> (new TranscodeJob (shared_from_this(), od, oe, shared_ptr<Job> ())));
+ r = JobManager::instance()->add (shared_ptr<Job> (new TranscodeJob (shared_from_this(), od, shared_ptr<Job> ())));
}
}
- r = JobManager::instance()->add (shared_ptr<Job> (new CheckHashesJob (shared_from_this(), od, oe, r)));
- JobManager::instance()->add (shared_ptr<Job> (new MakeDCPJob (shared_from_this(), oe, r)));
+ r = JobManager::instance()->add (shared_ptr<Job> (new CheckHashesJob (shared_from_this(), od, r)));
+ JobManager::instance()->add (shared_ptr<Job> (new MakeDCPJob (shared_from_this(), r)));
}
/** Start a job to examine our content file */
f << "filter " << (*i)->id () << "\n";
}
f << "scaler " << _scaler->id () << "\n";
- f << "dcp_trim_start " << _dcp_trim_start << "\n";
- f << "dcp_trim_end " << _dcp_trim_end << "\n";
+ f << "trim_start " << _trim_start << "\n";
+ f << "trim_end " << _trim_end << "\n";
if (_reel_size) {
f << "reel_size " << _reel_size.get() << "\n";
}
f << "width " << _size.width << "\n";
f << "height " << _size.height << "\n";
f << "length " << _length.get_value_or(0) << "\n";
+ f << "dcp_intrinsic_duration " << _dcp_intrinsic_duration.get_value_or(0) << "\n";
f << "content_digest " << _content_digest << "\n";
for (vector<shared_ptr<AudioStream> >::const_iterator i = _content_audio_streams.begin(); i != _content_audio_streams.end(); ++i) {
_filters.push_back (Filter::from_id (v));
} else if (k == "scaler") {
_scaler = Scaler::from_id (v);
- } else if (k == "dcp_trim_start") {
- _dcp_trim_start = atoi (v.c_str ());
- } else if (k == "dcp_trim_end") {
- _dcp_trim_end = atoi (v.c_str ());
+ } else if ( ((!version || version < 2) && k == "trim_start") || k == "trim_start") {
+ _trim_start = atoi (v.c_str ());
+ } else if ( ((!version || version < 2) && k == "trim_end") || k == "trim_end") {
+ _trim_end = atoi (v.c_str ());
} else if (k == "reel_size") {
_reel_size = boost::lexical_cast<uint64_t> (v);
} else if (k == "dcp_ab") {
if (vv) {
_length = vv;
}
+ } else if (k == "dcp_intrinsic_duration") {
+ int const vv = atoi (v.c_str ());
+ if (vv) {
+ _dcp_intrinsic_duration = vv;
+ }
} else if (k == "content_digest") {
_content_digest = v;
} else if (k == "content_audio_stream" || (!version && k == "audio_stream")) {
/* Resample to a DCI-approved sample rate */
double t = dcp_audio_sample_rate (audio_stream()->sample_rate());
- DCPFrameRate dfr = dcp_frame_rate (frames_per_second ());
+ DCPFrameRate dfr (frames_per_second ());
- /* Compensate for the fact that video will be rounded to the
- nearest integer number of frames per second.
+ /* 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
+ look different in the DCP compared to the source (slower or faster).
+ skip/repeat doesn't come into effect here.
*/
- if (dfr.run_fast) {
- t *= _frames_per_second * dfr.skip / dfr.frames_per_second;
+
+ if (dfr.change_speed) {
+ t *= _frames_per_second * dfr.factor() / dfr.frames_per_second;
}
return rint (t);
}
-boost::optional<int>
-Film::dcp_length () const
+int
+Film::still_duration_in_frames () const
{
- if (content_type() == STILL) {
- return _still_duration * frames_per_second();
- }
-
- if (!length()) {
- return boost::optional<int> ();
- }
-
- return length().get() - dcp_trim_start() - dcp_trim_end();
+ return still_duration() * frames_per_second();
}
/** @return a DCI-compliant name for a DCP of this film */
*/
try {
- shared_ptr<DecodeOptions> o (new DecodeOptions);
- Decoders d = decoder_factory (shared_from_this(), o, 0);
+ Decoders d = decoder_factory (shared_from_this(), DecodeOptions(), 0);
set_size (d.video->native_size ());
set_frames_per_second (d.video->frames_per_second ());
}
void
-Film::set_dcp_trim_start (int t)
+Film::set_trim_start (int t)
{
{
boost::mutex::scoped_lock lm (_state_mutex);
- _dcp_trim_start = t;
+ _trim_start = t;
}
- signal_changed (DCP_TRIM_START);
+ signal_changed (TRIM_START);
}
void
-Film::set_dcp_trim_end (int t)
+Film::set_trim_end (int t)
{
{
boost::mutex::scoped_lock lm (_state_mutex);
- _dcp_trim_end = t;
+ _trim_end = t;
}
- signal_changed (DCP_TRIM_END);
+ signal_changed (TRIM_END);
}
void
_external_audio = a;
}
- shared_ptr<DecodeOptions> o (new DecodeOptions);
- shared_ptr<ExternalAudioDecoder> decoder (new ExternalAudioDecoder (shared_from_this(), o, 0));
+ shared_ptr<ExternalAudioDecoder> decoder (new ExternalAudioDecoder (shared_from_this(), DecodeOptions(), 0));
if (decoder->audio_stream()) {
_external_audio_stream = decoder->audio_stream ();
}
_length = boost::none;
}
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)
return _external_audio_stream;
}
+
+/** @param f DCP frame index.
+ * @param t true to return a temporary file path, otherwise a permanent one.
+ * @return The path to write this video frame to.
+ */
+string
+Film::frame_out_path (int f, bool t) const
+{
+ stringstream s;
+ s << j2k_dir() << "/";
+ s.width (8);
+ s << std::setfill('0') << f << ".j2c";
+
+ if (t) {
+ s << ".tmp";
+ }
+
+ return s.str ();
+}
+
+string
+Film::hash_out_path (int f, bool t) const
+{
+ return frame_out_path (f, t) + ".md5";
+}
+
+/** @param c Audio channel index.
+ * @param t true to return a temporary file path, otherwise a permanent one.
+ * @return The path to write this audio file to.
+ */
+string
+Film::multichannel_audio_out_path (int c, bool t) const
+{
+ stringstream s;
+ s << dir ("wavs") << "/" << (c + 1) << ".wav";
+ if (t) {
+ s << ".tmp";
+ }
+
+ return s.str ();
+}
+