#include "ab_transcode_job.h"
#include "transcode_job.h"
#include "film.h"
+#include "exceptions.h"
using std::string;
using std::stringstream;
{
_bad = 0;
- int const N = _film->dcp_length ();
+ if (!_film->dcp_length()) {
+ throw EncodeError ("cannot check hashes of a DCP with unknown length");
+ }
+
+ int const N = _film->dcp_length().get();
for (int i = 0; i < N; ++i) {
string const j2k_file = _opt->frame_out_path (i, false);
}
}
- set_progress (float (i) / _film->length());
+ set_progress (float (i) / N);
}
if (_bad) {
, _delay_in_bytes (0)
, _audio_frames_processed (0)
{
- if (_opt->decode_video_frequency != 0 && _film->length() == 0) {
- throw DecodeError ("cannot do a partial decode if length == 0");
+ if (_opt->decode_video_frequency != 0 && !_film->length()) {
+ throw DecodeError ("cannot do a partial decode if length is unknown");
}
}
in to get it to the right length.
*/
- int64_t const video_length_in_audio_frames = ((int64_t) _film->dcp_length() * audio_sample_rate() / frames_per_second());
+ int64_t const video_length_in_audio_frames = ((int64_t) last_video_frame() * audio_sample_rate() / 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.",
- _film->dcp_length(),
+ last_video_frame(),
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.", _film->dcp_length(), _audio_frames_processed));
+ _log->log (String::compose ("DCP length is %1; %2 frames of audio processed.", last_video_frame(), _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
{
process_begin ();
- if (_job && _ignore_length) {
+ if (_job && !_film->dcp_length()) {
_job->set_progress_unknown ();
}
while (pass () == false) {
- if (_job && !_ignore_length) {
- _job->set_progress (float (_video_frame) / _film->dcp_length());
+ if (_job && _film->dcp_length()) {
+ _job->set_progress (float (_video_frame) / _film->dcp_length().get());
}
}
int gap = 0;
if (_opt->decode_video_frequency != 0) {
- gap = _film->length() / _opt->decode_video_frequency;
+ gap = _film->length().get() / _opt->decode_video_frequency;
}
if (_opt->decode_video_frequency != 0 && gap != 0 && (_video_frame % gap) != 0) {
using std::ifstream;
using std::ofstream;
using std::setfill;
+using std::min;
using boost::shared_ptr;
using boost::lexical_cast;
using boost::to_upper_copy;
, _dcp_content_type (0)
, _format (0)
, _scaler (Scaler::from_id ("bicubic"))
- , _dcp_frames (0)
, _dcp_trim_action (CUT)
, _dcp_ab (false)
, _audio_stream (-1)
, _with_subtitles (false)
, _subtitle_offset (0)
, _subtitle_scale (1)
- , _length (0)
, _audio_sample_rate (0)
, _has_subtitles (false)
, _frames_per_second (0)
shared_ptr<Options> o (new Options (j2k_dir(), ".j2c", dir ("wavs")));
o->out_size = format()->dcp_size ();
- if (dcp_frames() == 0) {
+ if (!dcp_frames()) {
/* Decode the whole film, no blacking */
o->black_after = 0;
} else {
break;
case BLACK_OUT:
/* Decode the whole film, but black some frames out */
- o->black_after = dcp_frames ();
+ o->black_after = dcp_frames().get ();
}
}
f << "filter " << (*i)->id () << "\n";
}
f << "scaler " << _scaler->id () << "\n";
- f << "dcp_frames " << _dcp_frames << "\n";
+ f << "dcp_frames " << _dcp_frames.get_value_or(0) << "\n";
f << "dcp_trim_action ";
switch (_dcp_trim_action) {
}
f << "width " << _size.width << "\n";
f << "height " << _size.height << "\n";
- f << "length " << _length << "\n";
+ f << "length " << _length.get_value_or(0) << "\n";
f << "audio_sample_rate " << _audio_sample_rate << "\n";
f << "content_digest " << _content_digest << "\n";
f << "has_subtitles " << _has_subtitles << "\n";
} else if (k == "scaler") {
_scaler = Scaler::from_id (v);
} else if (k == "dcp_frames") {
- _dcp_frames = atoi (v.c_str ());
+ int const vv = atoi (v.c_str ());
+ if (vv) {
+ _dcp_frames = vv;
+ }
} else if (k == "dcp_trim_action") {
if (v == "cut") {
_dcp_trim_action = CUT;
} else if (k == "height") {
_size.height = atoi (v.c_str ());
} else if (k == "length") {
- _length = atof (v.c_str ());
+ int const vv = atoi (v.c_str ());
+ if (vv) {
+ _length = vv;
+ }
} else if (k == "audio_sample_rate") {
_audio_sample_rate = atoi (v.c_str ());
} else if (k == "content_digest") {
return rint (t);
}
-int
+boost::optional<int>
Film::dcp_length () const
{
+ if (!length()) {
+ return boost::optional<int> ();
+ }
+
if (dcp_frames()) {
- return dcp_frames();
+ return min (dcp_frames().get(), length().get());
}
return length();
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 ());
signal_changed (LENGTH);
}
+void
+Film::unset_length ()
+{
+ {
+ boost::mutex::scoped_lock lm (_state_mutex);
+ _length = boost::none;
+ }
+ signal_changed (LENGTH);
+}
+
void
Film::set_audio_sample_rate (int r)
{
void read_metadata ();
Size cropped_size (Size) const;
- int dcp_length () const;
+ boost::optional<int> dcp_length () const;
std::string dci_name () const;
std::string dcp_name () const;
return _scaler;
}
- int dcp_frames () const {
+ boost::optional<int> dcp_frames () const {
boost::mutex::scoped_lock lm (_state_mutex);
return _dcp_frames;
}
return _size;
}
- int length () const {
+ boost::optional<int> length () const {
boost::mutex::scoped_lock lm (_state_mutex);
return _length;
}
-
+
int audio_sample_rate () const {
boost::mutex::scoped_lock lm (_state_mutex);
return _audio_sample_rate;
void set_thumbs (std::vector<int>);
void set_size (Size);
void set_length (int);
+ void unset_length ();
void set_audio_sample_rate (int);
void set_content_digest (std::string);
void set_has_subtitles (bool);
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;
+ /** Maximum number of frames to put in the DCP, if applicable */
+ boost::optional<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
std::vector<int> _thumbs;
/** Size, in pixels, of the source (ignoring cropping) */
Size _size;
- /** Length of the source in frames */
- int _length;
+ /** Actual length of the source (in video frames) from examining it */
+ boost::optional<int> _length;
/** Sample rate of the source audio, in Hz */
int _audio_sample_rate;
/** MD5 digest of our content file */
void
MakeDCPJob::run ()
{
+ if (!_film->dcp_length()) {
+ throw EncodeError ("cannot make a DCP when the source length is not known");
+ }
+
string const dcp_path = _film->dir (_film->dcp_name());
/* Remove any old DCP */
int frames = 0;
switch (_film->content_type ()) {
case VIDEO:
- frames = _film->dcp_length ();
+ frames = _film->dcp_length().get();
break;
case STILL:
frames = _film->still_duration() * ImageMagickDecoder::static_frames_per_second ();
return 0;
}
- return ((_film->dcp_length() - _encoder->last_frame()) / fps);
+ /* We assume that dcp_length() is valid */
+ return ((_film->dcp_length().get() - _encoder->last_frame()) / fps);
}
table->Add (_black_out);
_n_frames->SetRange (1, INT_MAX - 1);
- if (_film->dcp_frames() > 0) {
+ if (_film->dcp_frames()) {
_whole->SetValue (false);
_first->SetValue (true);
- _n_frames->SetValue (_film->dcp_frames ());
+ _n_frames->SetValue (_film->dcp_frames().get());
} else {
_whole->SetValue (true);
_first->SetValue (false);
}
break;
case Film::LENGTH:
- if (_film->frames_per_second() > 0 && _film->length() > 0) {
- s << _film->length() << " frames; " << seconds_to_hms (_film->length() / _film->frames_per_second());
- } else if (_film->length() > 0) {
- s << _film->length() << " frames";
+ if (_film->frames_per_second() > 0 && _film->length()) {
+ s << _film->length().get() << " frames; " << seconds_to_hms (_film->length().get() / _film->frames_per_second());
+ } else if (_film->length()) {
+ s << _film->length().get() << " frames";
}
_length->SetLabel (std_to_wx (s.str ()));
break;
add_label_to_sizer (table, this, "Frames already encoded");
_encoded = new ThreadedStaticText (this, "counting...", boost::bind (&PropertiesDialog::frames_already_encoded, this));
table->Add (_encoded, 1, wxALIGN_CENTER_VERTICAL);
-
- _frames->SetLabel (std_to_wx (lexical_cast<string> (_film->length ())));
- double const disk = ((double) Config::instance()->j2k_bandwidth() / 8) * _film->length() / (_film->frames_per_second () * 1073741824);
- stringstream s;
- s << fixed << setprecision (1) << disk << "Gb";
- _disk_for_frames->SetLabel (std_to_wx (s.str ()));
- stringstream t;
- t << fixed << setprecision (1) << (disk * 2) << "Gb";
- _total_disk->SetLabel (std_to_wx (t.str ()));
+ if (_film->length()) {
+ _frames->SetLabel (std_to_wx (lexical_cast<string> (_film->length().get())));
+ double const disk = ((double) Config::instance()->j2k_bandwidth() / 8) * _film->length().get() / (_film->frames_per_second () * 1073741824);
+ stringstream s;
+ s << fixed << setprecision (1) << disk << "Gb";
+ _disk_for_frames->SetLabel (std_to_wx (s.str ()));
+ stringstream t;
+ t << fixed << setprecision (1) << (disk * 2) << "Gb";
+ _total_disk->SetLabel (std_to_wx (t.str ()));
+ } else {
+ _frames->SetLabel (_("unknown"));
+ _disk_for_frames->SetLabel (_("unknown"));
+ _total_disk->SetLabel (_("unknown"));
+ }
wxBoxSizer* overall_sizer = new wxBoxSizer (wxVERTICAL);
overall_sizer->Add (table, 0, wxALL, 6);
return "";
}
- if (_film->length()) {
- u << " (" << (_film->encoded_frames() * 100 / _film->length()) << "%)";
+ if (_film->dcp_length()) {
+ u << " (" << (_film->encoded_frames() * 100 / _film->dcp_length().get()) << "%)";
}
return u.str ();
}