+2013-03-02 Carl Hetherington <cth@carlh.net>
+
+ * Add option to specify the DCP's frame
+ rate (part of #56).
+
+ * Add a description of what each video format
+ means to the UI.
+
2013-03-01 Carl Hetherington <cth@carlh.net>
* Version 0.76beta2 released.
if (_film_a->audio_stream()) {
shared_ptr<AudioStream> st = _film_a->audio_stream();
- _matcher.reset (new Matcher (_film_a->log(), st->sample_rate(), _film_a->frames_per_second()));
+ _matcher.reset (new Matcher (_film_a->log(), st->sample_rate(), _film_a->source_frame_rate()));
_delay_line.reset (new DelayLine (_film_a->log(), st->channels(), _film_a->audio_delay() * st->sample_rate() / 1000));
_gain.reset (new Gain (_film_a->log(), _film_a->audio_gain()));
}
decoders.audio->set_audio_stream (_film->audio_stream ());
decoders.audio->Audio.connect (bind (&AnalyseAudioJob::audio, this, _1));
- int64_t total_audio_frames = video_frames_to_audio_frames (_film->length().get(), _film->audio_stream()->sample_rate(), _film->frames_per_second());
+ int64_t total_audio_frames = video_frames_to_audio_frames (_film->length().get(), _film->audio_stream()->sample_rate(), _film->source_frame_rate());
_samples_per_point = total_audio_frames / _num_points;
_current.resize (_film->audio_stream()->channels ());
_allowed_dcp_frame_rates.push_back (24);
_allowed_dcp_frame_rates.push_back (25);
_allowed_dcp_frame_rates.push_back (30);
+ _allowed_dcp_frame_rates.push_back (48);
+ _allowed_dcp_frame_rates.push_back (50);
+ _allowed_dcp_frame_rates.push_back (60);
ifstream f (file().c_str ());
string line;
DCPVideoFrame::DCPVideoFrame (
shared_ptr<const Image> yuv, shared_ptr<Subtitle> sub,
Size out, int p, int subtitle_offset, float subtitle_scale,
- Scaler const * s, int f, float fps, string pp, int clut, int bw, Log* l
+ Scaler const * s, int f, int dcp_fps, string pp, int clut, int bw, Log* l
)
: _input (yuv)
, _subtitle (sub)
, _subtitle_scale (subtitle_scale)
, _scaler (s)
, _frame (f)
- , _frames_per_second (DCPFrameRate(fps).frames_per_second)
+ , _frames_per_second (dcp_fps)
, _post_process (pp)
, _colour_lut (clut)
, _j2k_bandwidth (bw)
public:
DCPVideoFrame (
boost::shared_ptr<const Image>, boost::shared_ptr<Subtitle>, libdcp::Size,
- int, int, float, Scaler const *, int, float, std::string, int, int, Log *
+ int, int, float, Scaler const *, int, int, std::string, int, int, Log *
);
virtual ~DCPVideoFrame ();
float _subtitle_scale;
Scaler const * _scaler; ///< scaler to use
int _frame; ///< frame index within the DCP's intrinsic duration
- int _frames_per_second; ///< Frames per second that we will use for the DCP (rounded)
+ int _frames_per_second; ///< Frames per second that we will use for the DCP
std::string _post_process; ///< FFmpeg post-processing string to use
int _colour_lut; ///< Colour look-up table to use
int _j2k_bandwidth; ///< J2K bandwidth to use
void
Encoder::process_video (shared_ptr<Image> image, bool same, boost::shared_ptr<Subtitle> sub)
{
- DCPFrameRate dfr (_film->frames_per_second ());
+ FrameRateConversion frc (_film->source_frame_rate(), _film->dcp_frame_rate());
- if (dfr.skip && (_video_frames_in % 2)) {
+ if (frc.skip && (_video_frames_in % 2)) {
++_video_frames_in;
return;
}
new DCPVideoFrame (
image, sub, _film->format()->dcp_size(), _film->format()->dcp_padding (_film),
_film->subtitle_offset(), _film->subtitle_scale(),
- _film->scaler(), _video_frames_out, _film->frames_per_second(), s.second,
+ _film->scaler(), _video_frames_out, _film->dcp_frame_rate(), s.second,
_film->colour_lut(), _film->j2k_bandwidth(),
_film->log()
)
++_video_frames_in;
++_video_frames_out;
- if (dfr.repeat) {
+ if (frc.repeat) {
_writer->repeat (_video_frames_out);
++_video_frames_out;
frame_done ();
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;
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
, _trust_content_header (true)
, _dcp_content_type (0)
, _format (0)
- , _scaler (Scaler::from_id (N_("bicubic")))
+ , _scaler (Scaler::from_id ("bicubic"))
, _trim_start (0)
, _trim_end (0)
, _dcp_ab (false)
, _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 ();
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;
}
}
read_metadata ();
}
- _log = new FileLog (file (N_("log")));
+ _log = new FileLog (file ("log"));
}
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_audio_streams (o._content_audio_streams)
, _external_audio_stream (o._external_audio_stream)
, _subtitle_streams (o._subtitle_streams)
- , _frames_per_second (o._frames_per_second)
+ , _source_frame_rate (o._source_frame_rate)
, _dirty (o._dirty)
{
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<int> (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<int> (colour_lut());
if (dcp_ab()) {
pair<string, string> 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 ();
Film::info_dir () const
{
boost::filesystem::path p;
- p /= N_("info");
+ p /= "info";
p /= video_state_identifier ();
return dir (p.string());
}
Film::video_mxf_dir () const
{
boost::filesystem::path p;
- return dir (N_("video"));
+ return dir ("video");
}
string
Film::video_mxf_filename () const
{
- return video_state_identifier() + N_(".mxf");
+ return video_state_identifier() + ".mxf";
}
string
{
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<string, int> 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"));
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<Filter const *>::const_iterator i = _filters.begin(); i != _filters.end(); ++i) {
- f << N_("filter ") << (*i)->id () << N_("\n");
+ f << "filter " << (*i)->id () << endl;
}
- 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 << "scaler " << _scaler->id () << endl;
+ f << "trim_start " << _trim_start << endl;
+ f << "trim_end " << _trim_end << endl;
+ 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<string>::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 << "dcp_intrinsic_duration " << _dcp_intrinsic_duration.get_value_or(0) << endl;
+ f << "content_digest " << _content_digest << endl;
for (vector<shared_ptr<AudioStream> >::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 " << _external_audio_stream->to_string() << endl;
for (vector<shared_ptr<SubtitleStream> >::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;
}
boost::optional<int> audio_stream_index;
boost::optional<int> 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<string, string> kv = read_key_value (f);
/* We need version before anything else */
- multimap<string, string>::iterator v = kv.find (N_("version"));
+ multimap<string, string>::iterator v = kv.find ("version");
if (v != kv.end ()) {
version = atoi (v->second.c_str());
}
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 == "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")) {
+ } else if (k == "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")) {
+ } else if (k == "external_audio_stream") {
_external_audio_stream = audio_stream_factory (v, version);
- } else if (k == N_("subtitle_stream")) {
+ } 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);
}
}
/* 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
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);
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 */
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.subtitle_language;
} else {
- d << N_("-XX");
+ d << "-XX";
}
- d << N_("_");
+ d << "_";
}
if (!dm.territory.empty ()) {
d << dm.territory;
if (!dm.rating.empty ()) {
- d << N_("-") << dm.rating;
+ d << "-" << dm.rating;
}
- d << N_("_");
+ d << "_";
}
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 ()) {
{
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)) {
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 ());
/* 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;
}
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)
{
}
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
stringstream s;
s.width (8);
- s << setfill('0') << f << N_(".md5");
+ s << setfill('0') << f << ".md5";
p /= s.str();
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();
DCP_INTRINSIC_DURATION,
CONTENT_AUDIO_STREAMS,
SUBTITLE_STREAMS,
- FRAMES_PER_SECOND,
+ SOURCE_FRAME_RATE,
+ DCP_FRAME_RATE
};
boost::mutex::scoped_lock lm (_state_mutex);
return _dci_metadata;
}
+
+ int dcp_frame_rate () const {
+ boost::mutex::scoped_lock lm (_state_mutex);
+ return _dcp_frame_rate;
+ }
libdcp::Size size () const {
boost::mutex::scoped_lock lm (_state_mutex);
return _subtitle_streams;
}
- float frames_per_second () const {
+ float source_frame_rate () const {
boost::mutex::scoped_lock lm (_state_mutex);
if (content_type() == STILL) {
return 24;
}
- return _frames_per_second;
+ return _source_frame_rate;
}
boost::shared_ptr<AudioStream> audio_stream () const;
void set_colour_lut (int);
void set_j2k_bandwidth (int);
void set_dci_metadata (DCIMetadata);
+ void set_dcp_frame_rate (int);
void set_size (libdcp::Size);
void set_length (SourceFrame);
void unset_length ();
void set_content_digest (std::string);
void set_content_audio_streams (std::vector<boost::shared_ptr<AudioStream> >);
void set_subtitle_streams (std::vector<boost::shared_ptr<SubtitleStream> >);
- void set_frames_per_second (float);
+ void set_source_frame_rate (float);
/** Emitted when some property has changed */
mutable boost::signals2::signal<void (Property)> Changed;
DCIMetadata _dci_metadata;
/** The date that we should use in a DCI name */
boost::gregorian::date _dci_date;
+ /** Frames per second to run our DCP at */
+ int _dcp_frame_rate;
/* Data which are cached to speed things up */
/** the subtitle streams that we can use */
std::vector<boost::shared_ptr<SubtitleStream> > _subtitle_streams;
/** Frames per second of the source */
- float _frames_per_second;
+ float _source_frame_rate;
/** true if our state has changed since we last saved it */
mutable bool _dirty;
Format::setup_formats ()
{
/// TRANSLATORS: these are film picture aspect ratios; "Academy" means 1.37, "Flat" 1.85 and "Scope" 2.39.
- _formats.push_back (new FixedFormat (119, libdcp::Size (1285, 1080), N_("119"), _("1.19"), N_("F")));
- _formats.push_back (new FixedFormat (133, libdcp::Size (1436, 1080), N_("133"), _("1.33"), N_("F")));
- _formats.push_back (new FixedFormat (138, libdcp::Size (1485, 1080), N_("138"), _("1.375"), N_("F")));
- _formats.push_back (new FixedFormat (133, libdcp::Size (1998, 1080), N_("133-in-flat"), _("4:3 within Flat"), N_("F")));
- _formats.push_back (new FixedFormat (137, libdcp::Size (1480, 1080), N_("137"), _("Academy"), N_("F")));
- _formats.push_back (new FixedFormat (166, libdcp::Size (1793, 1080), N_("166"), _("1.66"), N_("F")));
- _formats.push_back (new FixedFormat (166, libdcp::Size (1998, 1080), N_("166-in-flat"), _("1.66 within Flat"), N_("F")));
- _formats.push_back (new FixedFormat (178, libdcp::Size (1998, 1080), N_("178-in-flat"), _("16:9 within Flat"), N_("F")));
- _formats.push_back (new FixedFormat (178, libdcp::Size (1920, 1080), N_("178"), _("16:9"), N_("F")));
- _formats.push_back (new FixedFormat (185, libdcp::Size (1998, 1080), N_("185"), _("Flat"), N_("F")));
- _formats.push_back (new FixedFormat (239, libdcp::Size (2048, 858), N_("239"), _("Scope"), N_("S")));
- _formats.push_back (new VariableFormat (libdcp::Size (1998, 1080), N_("var-185"), _("Flat without stretch"), N_("F")));
- _formats.push_back (new VariableFormat (libdcp::Size (2048, 858), N_("var-239"), _("Scope without stretch"), N_("S")));
+ _formats.push_back (
+ new FixedFormat (119, libdcp::Size (1285, 1080), N_("119"), _("1.19"), N_("F"),
+ _("Source scaled to 1.19:1")
+ ));
+
+ _formats.push_back (
+ new FixedFormat (133, libdcp::Size (1436, 1080), N_("133"), _("1.33"), N_("F"),
+ _("Source scaled to 1.33:1")
+ ));
+
+ _formats.push_back (
+ new FixedFormat (138, libdcp::Size (1485, 1080), N_("138"), _("1.375"), N_("F"),
+ _("Source scaled to 1.375:1")
+ ));
+
+ _formats.push_back (
+ new FixedFormat (133, libdcp::Size (1998, 1080), N_("133-in-flat"), _("4:3 within Flat"), N_("F"),
+ _("Source scaled to 1.33:1 then pillarboxed to Flat")
+ ));
+
+ _formats.push_back (
+ new FixedFormat (137, libdcp::Size (1480, 1080), N_("137"), _("Academy"), N_("F"),
+ _("Source scaled to 1.37:1 (Academy ratio)")
+ ));
+
+ _formats.push_back (
+ new FixedFormat (166, libdcp::Size (1793, 1080), N_("166"), _("1.66"), N_("F"),
+ _("Source scaled to 1.66:1")
+ ));
+
+ _formats.push_back (
+ new FixedFormat (166, libdcp::Size (1998, 1080), N_("166-in-flat"), _("1.66 within Flat"), N_("F"),
+ _("Source scaled to 1.66:1 then pillarboxed to Flat")
+ ));
+
+ _formats.push_back (
+ new FixedFormat (178, libdcp::Size (1998, 1080), N_("178-in-flat"), _("16:9 within Flat"), N_("F"),
+ _("Source scaled to 1.78:1 then pillarboxed to Flat")
+ ));
+
+ _formats.push_back (
+ new FixedFormat (178, libdcp::Size (1920, 1080), N_("178"), _("16:9"), N_("F"),
+ _("Source scaled to 1.78:1")
+ ));
+
+ _formats.push_back (
+ new FixedFormat (185, libdcp::Size (1998, 1080), N_("185"), _("Flat"), N_("F"),
+ _("Source scaled to Flat (1.85:1)")
+ ));
+
+ _formats.push_back (
+ new FixedFormat (239, libdcp::Size (2048, 858), N_("239"), _("Scope"), N_("S"),
+ _("Source scaled to Scope (2.39:1)")
+ ));
+
+ _formats.push_back (
+ new VariableFormat (libdcp::Size (1998, 1080), N_("var-185"), _("Flat without stretch"), N_("F"),
+ _("Source scaled to fit Flat preserving its aspect ratio")
+ ));
+
+ _formats.push_back (
+ new VariableFormat (libdcp::Size (2048, 858), N_("var-239"), _("Scope without stretch"), N_("S"),
+ _("Source scaled to fit Scope preserving its aspect ratio")
+ ));
}
/** @param n Nickname.
* @param id ID (e.g. 185)
* @param n Nick name (e.g. Flat)
*/
-FixedFormat::FixedFormat (int r, libdcp::Size dcp, string id, string n, string d)
- : Format (dcp, id, n, d)
+FixedFormat::FixedFormat (int r, libdcp::Size dcp, string id, string n, string d, string e)
+ : Format (dcp, id, n, d, e)
, _ratio (r)
{
return static_cast<float> (_dcp_size.width) / _dcp_size.height;
}
-VariableFormat::VariableFormat (libdcp::Size dcp, string id, string n, string d)
- : Format (dcp, id, n, d)
+VariableFormat::VariableFormat (libdcp::Size dcp, string id, string n, string d, string e)
+ : Format (dcp, id, n, d, e)
{
}
class Format
{
public:
- Format (libdcp::Size dcp, std::string id, std::string n, std::string d)
+ Format (libdcp::Size dcp, std::string id, std::string n, std::string d, std::string e)
: _dcp_size (dcp)
, _id (id)
, _nickname (n)
, _dci_name (d)
+ , _description (e)
{}
/** @return the aspect ratio multiplied by 100
return _dci_name;
}
+ std::string description () const {
+ return _description;
+ }
+
std::string as_metadata () const;
static Format const * from_nickname (std::string n);
/** nickname (e.g. Flat, Scope) */
std::string _nickname;
std::string _dci_name;
+ std::string _description;
private:
/** all available formats */
class FixedFormat : public Format
{
public:
- FixedFormat (int, libdcp::Size, std::string, std::string, std::string);
+ FixedFormat (int, libdcp::Size, std::string, std::string, std::string, std::string);
int ratio_as_integer (boost::shared_ptr<const Film>) const {
return _ratio;
class VariableFormat : public Format
{
public:
- VariableFormat (libdcp::Size, std::string, std::string, std::string);
+ VariableFormat (libdcp::Size, std::string, std::string, std::string, std::string);
int ratio_as_integer (boost::shared_ptr<const Film> f) const;
float ratio_as_float (boost::shared_ptr<const Film> f) const;
/* Compute approximate proposed length here, as it's only here that we need it */
int length = _film->length().get();
- DCPFrameRate const dfr (_film->frames_per_second ());
- if (dfr.skip) {
+ FrameRateConversion const frc (_film->source_frame_rate(), _film->dcp_frame_rate());
+ if (frc.skip) {
length /= 2;
}
/* If we are repeating it shouldn't affect transcode time, so don't take it into account */
if (f->audio_stream()) {
shared_ptr<AudioStream> st = f->audio_stream();
- _matcher.reset (new Matcher (f->log(), st->sample_rate(), f->frames_per_second()));
+ _matcher.reset (new Matcher (f->log(), st->sample_rate(), f->source_frame_rate()));
_delay_line.reset (new DelayLine (f->log(), st->channels(), f->audio_delay() * st->sample_rate() / 1000));
_gain.reset (new Gain (f->log(), f->audio_gain()));
}
, dcp (dcp_)
{}
- bool skip () const {
- return !about_equal (source, dcp) && source > dcp;
- }
-
- bool repeat () const {
- return !about_equal (source, dcp) && source < dcp;
- }
-
float source;
int dcp;
};
-/** @param fps Arbitrary source frames-per-second value */
-/** XXX: this could be slow-ish */
-DCPFrameRate::DCPFrameRate (float source_fps)
+int
+best_dcp_frame_rate (float source_fps)
{
list<int> const allowed_dcp_frame_rates = Config::instance()->allowed_dcp_frame_rates ();
++i;
}
- if (!best) {
- throw EncodeError (_("cannot find a suitable DCP frame rate for this source"));
- }
-
- frames_per_second = best->dcp;
- skip = best->skip ();
- repeat = best->repeat ();
- change_speed = !about_equal (source_fps * factor(), frames_per_second);
+ assert (best);
+ return best->dcp;
}
/** @param An arbitrary sampling rate.
return _source_channels;
}
+
+FrameRateConversion::FrameRateConversion (float source, int dcp)
+ : skip (false)
+ , repeat (false)
+ , change_speed (false)
+{
+ if (fabs (source / 2.0 - dcp) < (fabs (source - dcp))) {
+ skip = true;
+ } else if (fabs (source * 2 - dcp) < fabs (source - dcp)) {
+ repeat = true;
+ }
+
+ change_speed = !about_equal (source * factor(), dcp);
+
+ if (!skip && !repeat && !change_speed) {
+ description = _("DCP and source have the same rate.\n");
+ } else {
+ if (skip) {
+ description = _("DCP will use every other frame of the source.\n");
+ } else if (repeat) {
+ description = _("Each source frame will be doubled in the DCP.\n");
+ }
+
+ if (change_speed) {
+ float const pc = (source * factor()) * 100 / dcp;
+ description += String::compose (_("DCP will run at %1%% of the source speed."), pc);
+ }
+ }
+}
typedef int SourceFrame;
-struct DCPFrameRate
+struct FrameRateConversion
{
- DCPFrameRate (float);
+ FrameRateConversion (float, int);
/** @return factor by which to multiply a source frame rate
to get the effective rate after any skip or repeat has happened.
return 1;
}
-
- /** frames per second for the DCP */
- int frames_per_second;
+
/** true to skip every other frame */
bool skip;
/** true to repeat every frame once */
bool repeat;
/** true if this DCP will run its video faster or slower than the source
- * without taking into account `repeat'.
+ * without taking into account `repeat' nor `skip'.
* (e.g. change_speed will be true if
* source is 29.97fps, DCP is 30fps
* source is 14.50fps, DCP is 30fps
* source is 12.50fps, DCP is 25fps)
*/
bool change_speed;
+
+ std::string description;
};
+int best_dcp_frame_rate (float);
+
enum ContentType {
STILL, ///< content is still images
VIDEO ///< content is a video
new libdcp::MonoPictureAsset (
_film->video_mxf_dir (),
_film->video_mxf_filename (),
- DCPFrameRate (_film->frames_per_second()).frames_per_second,
- _film->format()->dcp_size()
+ _film->dcp_frame_rate (),
+ _film->format()->dcp_size ()
)
);
new libdcp::SoundAsset (
_film->dir (_film->dcp_name()),
N_("audio.mxf"),
- DCPFrameRate (_film->frames_per_second()).frames_per_second,
+ _film->dcp_frame_rate (),
m.dcp_channels (),
dcp_audio_sample_rate (_film->audio_stream()->sample_rate())
)
}
libdcp::DCP dcp (_film->dir (_film->dcp_name()));
- DCPFrameRate dfr (_film->frames_per_second ());
shared_ptr<libdcp::CPL> cpl (
- new libdcp::CPL (_film->dir (_film->dcp_name()), _film->dcp_name(), _film->dcp_content_type()->libdcp_kind (), frames, dfr.frames_per_second)
+ new libdcp::CPL (
+ _film->dir (_film->dcp_name()),
+ _film->dcp_name(),
+ _film->dcp_content_type()->libdcp_kind (),
+ frames,
+ _film->dcp_frame_rate ()
+ )
);
dcp.add_cpl (cpl);
wxDouble db_label_height;
wxDouble db_label_descent;
wxDouble db_label_leading;
- gc->GetTextExtent ("-80dB", &_db_label_width, &db_label_height, &db_label_descent, &db_label_leading);
+ gc->GetTextExtent (wxT ("-80dB"), &_db_label_width, &db_label_height, &db_label_descent, &db_label_leading);
_db_label_width += 8;
_film_sizer = new wxBoxSizer (wxVERTICAL);
_film_panel->SetSizer (_film_sizer);
- wxFlexGridSizer* grid = new wxFlexGridSizer (2, 4, 4);
+ wxGridBagSizer* grid = new wxGridBagSizer (4, 4);
_film_sizer->Add (grid, 0, wxALL, 8);
- add_label_to_sizer (grid, _film_panel, _("Name"));
+ int r = 0;
+
+ add_label_to_grid_bag_sizer (grid, _film_panel, _("Name"), wxGBPosition (r, 0));
_name = new wxTextCtrl (_film_panel, wxID_ANY);
- grid->Add (_name, 1, wxEXPAND);
-
- add_label_to_sizer (grid, _film_panel, _("DCP Name"));
+ grid->Add (_name, wxGBPosition(r, 1));
+ ++r;
+
+ add_label_to_grid_bag_sizer (grid, _film_panel, _("DCP Name"), wxGBPosition (r, 0));
_dcp_name = new wxStaticText (_film_panel, wxID_ANY, wxT (""));
- grid->Add (_dcp_name, 0, wxALIGN_CENTER_VERTICAL | wxSHRINK);
+ grid->Add (_dcp_name, wxGBPosition(r, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
+ ++r;
_use_dci_name = new wxCheckBox (_film_panel, wxID_ANY, _("Use DCI name"));
- grid->Add (_use_dci_name, 1, wxEXPAND);
+ grid->Add (_use_dci_name, wxGBPosition (r, 0));
_edit_dci_button = new wxButton (_film_panel, wxID_ANY, _("Details..."));
- grid->Add (_edit_dci_button, 0);
+ grid->Add (_edit_dci_button, wxGBPosition (r, 1), wxDefaultSpan);
+ ++r;
- add_label_to_sizer (grid, _film_panel, _("Content"));
+ add_label_to_grid_bag_sizer (grid, _film_panel, _("Content"), wxGBPosition (r, 0));
_content = new wxFilePickerCtrl (_film_panel, wxID_ANY, wxT (""), _("Select Content File"), wxT("*.*"));
- grid->Add (_content, 1, wxEXPAND);
+ grid->Add (_content, wxGBPosition (r, 1), wxDefaultSpan, wxEXPAND);
+ ++r;
_trust_content_header = new wxCheckBox (_film_panel, wxID_ANY, _("Trust content's header"));
video_control (_trust_content_header);
- grid->Add (_trust_content_header, 1);
- grid->AddSpacer (0);
+ grid->Add (_trust_content_header, wxGBPosition (r, 0), wxGBSpan(1, 2));
+ ++r;
- add_label_to_sizer (grid, _film_panel, _("Content Type"));
+ add_label_to_grid_bag_sizer (grid, _film_panel, _("Content Type"), wxGBPosition (r, 0));
_dcp_content_type = new wxChoice (_film_panel, wxID_ANY);
- grid->Add (_dcp_content_type);
+ grid->Add (_dcp_content_type, wxGBPosition (r, 1));
+ ++r;
- video_control (add_label_to_sizer (grid, _film_panel, _("Original Frame Rate")));
- _frames_per_second = new wxStaticText (_film_panel, wxID_ANY, wxT (""));
- grid->Add (video_control (_frames_per_second), 1, wxALIGN_CENTER_VERTICAL);
+ video_control (add_label_to_grid_bag_sizer (grid, _film_panel, _("Original Frame Rate"), wxGBPosition (r, 0)));
+ _source_frame_rate = new wxStaticText (_film_panel, wxID_ANY, wxT (""));
+ grid->Add (video_control (_source_frame_rate), wxGBPosition (r, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
+ ++r;
+
+ {
+ add_label_to_grid_bag_sizer (grid, _film_panel, _("DCP Frame Rate"), wxGBPosition (r, 0));
+ wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
+ _dcp_frame_rate = new wxChoice (_film_panel, wxID_ANY);
+ s->Add (_dcp_frame_rate, 1, wxALIGN_CENTER_VERTICAL);
+ _best_dcp_frame_rate = new wxButton (_film_panel, wxID_ANY, _("Use best"));
+ s->Add (_best_dcp_frame_rate, 1, wxALIGN_CENTER_VERTICAL | wxALL | wxEXPAND, 6);
+ grid->Add (s, wxGBPosition (r, 1));
+ }
+ ++r;
+
+ _frame_rate_description = new wxStaticText (_film_panel, wxID_ANY, wxT (""), wxDefaultPosition, wxDefaultSize);
+ grid->Add (video_control (_frame_rate_description), wxGBPosition (r, 0), wxGBSpan (1, 2), wxEXPAND | wxALIGN_CENTER_VERTICAL | wxALL, 6);
+ wxFont font = _frame_rate_description->GetFont();
+ font.SetStyle(wxFONTSTYLE_ITALIC);
+ font.SetPointSize(font.GetPointSize() - 1);
+ _frame_rate_description->SetFont(font);
+ ++r;
- video_control (add_label_to_sizer (grid, _film_panel, _("Original Size")));
+ video_control (add_label_to_grid_bag_sizer (grid, _film_panel, _("Original Size"), wxGBPosition (r, 0)));
_original_size = new wxStaticText (_film_panel, wxID_ANY, wxT (""));
- grid->Add (video_control (_original_size), 1, wxALIGN_CENTER_VERTICAL);
+ grid->Add (video_control (_original_size), wxGBPosition (r, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
+ ++r;
- video_control (add_label_to_sizer (grid, _film_panel, _("Length")));
+ video_control (add_label_to_grid_bag_sizer (grid, _film_panel, _("Length"), wxGBPosition (r, 0)));
_length = new wxStaticText (_film_panel, wxID_ANY, wxT (""));
- grid->Add (video_control (_length), 1, wxALIGN_CENTER_VERTICAL);
+ grid->Add (video_control (_length), wxGBPosition (r, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
+ ++r;
{
- video_control (add_label_to_sizer (grid, _film_panel, _("Trim frames")));
+ video_control (add_label_to_grid_bag_sizer (grid, _film_panel, _("Trim frames"), wxGBPosition (r, 0)));
wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
video_control (add_label_to_sizer (s, _film_panel, _("Start")));
_trim_start = new wxSpinCtrl (_film_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1));
_trim_end = new wxSpinCtrl (_film_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1));
s->Add (video_control (_trim_end));
- grid->Add (s);
+ grid->Add (s, wxGBPosition (r, 1));
}
+ ++r;
_dcp_ab = new wxCheckBox (_film_panel, wxID_ANY, _("A/B"));
video_control (_dcp_ab);
- grid->Add (_dcp_ab, 1);
- grid->AddSpacer (0);
+ grid->Add (_dcp_ab, wxGBPosition (r, 0));
+ ++r;
/* STILL-only stuff */
{
- still_control (add_label_to_sizer (grid, _film_panel, _("Duration")));
+ still_control (add_label_to_grid_bag_sizer (grid, _film_panel, _("Duration"), wxGBPosition (r, 0)));
wxSizer* s = new wxBoxSizer (wxHORIZONTAL);
_still_duration = new wxSpinCtrl (_film_panel);
still_control (_still_duration);
s->Add (_still_duration, 1, wxEXPAND);
/// TRANSLATORS: `s' here is an abbreviation for seconds, the unit of time
still_control (add_label_to_sizer (s, _film_panel, _("s")));
- grid->Add (s);
+ grid->Add (s, wxGBPosition (r, 1));
}
+ ++r;
vector<DCPContentType const *> const ct = DCPContentType::all ();
for (vector<DCPContentType const *>::const_iterator i = ct.begin(); i != ct.end(); ++i) {
_dcp_content_type->Append (std_to_wx ((*i)->pretty_name ()));
}
+
+ list<int> const dfr = Config::instance()->allowed_dcp_frame_rates ();
+ for (list<int>::const_iterator i = dfr.begin(); i != dfr.end(); ++i) {
+ _dcp_frame_rate->Append (std_to_wx (boost::lexical_cast<string> (*i)));
+ }
}
void
_filters_button->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (FilmEditor::edit_filters_clicked), 0, this);
_scaler->Connect (wxID_ANY, wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler (FilmEditor::scaler_changed), 0, this);
_dcp_content_type->Connect (wxID_ANY, wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler (FilmEditor::dcp_content_type_changed), 0, this);
+ _dcp_frame_rate->Connect (wxID_ANY, wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler (FilmEditor::dcp_frame_rate_changed), 0, this);
+ _best_dcp_frame_rate->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (FilmEditor::best_dcp_frame_rate_clicked), 0, this);
_dcp_ab->Connect (wxID_ANY, wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler (FilmEditor::dcp_ab_toggled), 0, this);
_still_duration->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::still_duration_changed), 0, this);
_trim_start->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::trim_start_changed), 0, this);
_video_sizer = new wxBoxSizer (wxVERTICAL);
_video_panel->SetSizer (_video_sizer);
- wxFlexGridSizer* grid = new wxFlexGridSizer (2, 4, 4);
+ wxGridBagSizer* grid = new wxGridBagSizer (4, 4);
_video_sizer->Add (grid, 0, wxALL, 8);
- add_label_to_sizer (grid, _video_panel, _("Format"));
+ int r = 0;
+ add_label_to_grid_bag_sizer (grid, _video_panel, _("Format"), wxGBPosition (r, 0));
_format = new wxChoice (_video_panel, wxID_ANY);
- grid->Add (_format);
-
- add_label_to_sizer (grid, _video_panel, _("Left crop"));
+ grid->Add (_format, wxGBPosition (r, 1));
+ ++r;
+
+ _format_description = new wxStaticText (_video_panel, wxID_ANY, wxT (""), wxDefaultPosition, wxDefaultSize);
+ grid->Add (_format_description, wxGBPosition (r, 0), wxGBSpan (1, 2), wxEXPAND | wxALIGN_CENTER_VERTICAL | wxALL, 6);
+ wxFont font = _format_description->GetFont();
+ font.SetStyle(wxFONTSTYLE_ITALIC);
+ font.SetPointSize(font.GetPointSize() - 1);
+ _format_description->SetFont(font);
+ ++r;
+
+ add_label_to_grid_bag_sizer (grid, _video_panel, _("Left crop"), wxGBPosition (r, 0));
_left_crop = new wxSpinCtrl (_video_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1));
- grid->Add (_left_crop);
+ grid->Add (_left_crop, wxGBPosition (r, 1));
+ ++r;
- add_label_to_sizer (grid, _video_panel, _("Right crop"));
+ add_label_to_grid_bag_sizer (grid, _video_panel, _("Right crop"), wxGBPosition (r, 0));
_right_crop = new wxSpinCtrl (_video_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1));
- grid->Add (_right_crop);
+ grid->Add (_right_crop, wxGBPosition (r, 1));
+ ++r;
- add_label_to_sizer (grid, _video_panel, _("Top crop"));
+ add_label_to_grid_bag_sizer (grid, _video_panel, _("Top crop"), wxGBPosition (r, 0));
_top_crop = new wxSpinCtrl (_video_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1));
- grid->Add (_top_crop);
+ grid->Add (_top_crop, wxGBPosition (r, 1));
+ ++r;
- add_label_to_sizer (grid, _video_panel, _("Bottom crop"));
+ add_label_to_grid_bag_sizer (grid, _video_panel, _("Bottom crop"), wxGBPosition (r, 0));
_bottom_crop = new wxSpinCtrl (_video_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1));
- grid->Add (_bottom_crop);
+ grid->Add (_bottom_crop, wxGBPosition (r, 1));
+ ++r;
/* VIDEO-only stuff */
{
- video_control (add_label_to_sizer (grid, _video_panel, _("Filters")));
+ video_control (add_label_to_grid_bag_sizer (grid, _video_panel, _("Filters"), wxGBPosition (r, 0)));
wxSizer* s = new wxBoxSizer (wxHORIZONTAL);
_filters = new wxStaticText (_video_panel, wxID_ANY, _("None"));
video_control (_filters);
_filters_button = new wxButton (_video_panel, wxID_ANY, _("Edit..."));
video_control (_filters_button);
s->Add (_filters_button, 0);
- grid->Add (s, 1);
+ grid->Add (s, wxGBPosition (r, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
}
+ ++r;
- video_control (add_label_to_sizer (grid, _video_panel, _("Scaler")));
+ video_control (add_label_to_grid_bag_sizer (grid, _video_panel, _("Scaler"), wxGBPosition (r, 0)));
_scaler = new wxChoice (_video_panel, wxID_ANY);
- grid->Add (video_control (_scaler), 1);
+ grid->Add (video_control (_scaler), wxGBPosition (r, 1));
+ ++r;
vector<Scaler const *> const sc = Scaler::all ();
for (vector<Scaler const *>::const_iterator i = sc.begin(); i != sc.end(); ++i) {
_scaler->Append (std_to_wx ((*i)->name()));
}
- add_label_to_sizer (grid, _video_panel, _("Colour look-up table"));
+ add_label_to_grid_bag_sizer (grid, _video_panel, _("Colour look-up table"), wxGBPosition (r, 0));
_colour_lut = new wxChoice (_video_panel, wxID_ANY);
for (int i = 0; i < 2; ++i) {
_colour_lut->Append (std_to_wx (colour_lut_index_to_name (i)));
}
_colour_lut->SetSelection (0);
- grid->Add (_colour_lut, 1, wxEXPAND);
+ grid->Add (_colour_lut, wxGBPosition (r, 1), wxDefaultSpan, wxEXPAND);
+ ++r;
{
- add_label_to_sizer (grid, _video_panel, _("JPEG2000 bandwidth"));
+ add_label_to_grid_bag_sizer (grid, _video_panel, _("JPEG2000 bandwidth"), wxGBPosition (r, 0));
wxSizer* s = new wxBoxSizer (wxHORIZONTAL);
_j2k_bandwidth = new wxSpinCtrl (_video_panel, wxID_ANY);
s->Add (_j2k_bandwidth, 1);
add_label_to_sizer (s, _video_panel, _("MBps"));
- grid->Add (s, 1);
+ grid->Add (s, wxGBPosition (r, 1));
}
+ ++r;
_left_crop->SetRange (0, 1024);
_top_crop->SetRange (0, 1024);
}
_film->set_j2k_bandwidth (_j2k_bandwidth->GetValue() * 1e6);
-}
+}
+
+void
+FilmEditor::dcp_frame_rate_changed (wxCommandEvent &)
+{
+ if (!_film) {
+ return;
+ }
+
+ _film->set_dcp_frame_rate (
+ boost::lexical_cast<int> (
+ wx_to_std (_dcp_frame_rate->GetString (_dcp_frame_rate->GetSelection ()))
+ )
+ );
+}
/** Called when the metadata stored in the Film object has changed;
checked_set (_format, n);
}
setup_dcp_name ();
+
+ _format_description->SetLabel (std_to_wx (_film->format()->description ()));
break;
}
case Film::CROP:
checked_set (_name, _film->name());
setup_dcp_name ();
break;
- case Film::FRAMES_PER_SECOND:
- s << fixed << setprecision(2) << _film->frames_per_second();
- _frames_per_second->SetLabel (std_to_wx (s.str ()));
+ case Film::SOURCE_FRAME_RATE:
+ s << fixed << setprecision(2) << _film->source_frame_rate();
+ _source_frame_rate->SetLabel (std_to_wx (s.str ()));
break;
case Film::SIZE:
if (_film->size().width == 0 && _film->size().height == 0) {
}
break;
case Film::LENGTH:
- if (_film->frames_per_second() > 0 && _film->length()) {
- s << _film->length().get() << " " << _("frames") << "; " << seconds_to_hms (_film->length().get() / _film->frames_per_second());
+ if (_film->source_frame_rate() > 0 && _film->length()) {
+ s << _film->length().get() << " " << _("frames") << "; " << seconds_to_hms (_film->length().get() / _film->source_frame_rate());
} else if (_film->length()) {
s << _film->length().get() << " " << _("frames");
}
setup_audio_details ();
break;
}
+ case Film::DCP_FRAME_RATE:
+ for (unsigned int i = 0; i < _dcp_frame_rate->GetCount(); ++i) {
+ if (wx_to_std (_dcp_frame_rate->GetString(i)) == boost::lexical_cast<string> (_film->dcp_frame_rate())) {
+ if (_dcp_frame_rate->GetSelection() != int(i)) {
+ _dcp_frame_rate->SetSelection (i);
+ break;
+ }
+ }
+ }
+ _frame_rate_description->SetLabel (std_to_wx (FrameRateConversion (_film->source_frame_rate(), _film->dcp_frame_rate()).description));
+ _best_dcp_frame_rate->Enable (best_dcp_frame_rate (_film->source_frame_rate ()) != _film->dcp_frame_rate ());
}
}
film_changed (Film::LENGTH);
film_changed (Film::CONTENT_AUDIO_STREAMS);
film_changed (Film::SUBTITLE_STREAMS);
- film_changed (Film::FRAMES_PER_SECOND);
+ film_changed (Film::SOURCE_FRAME_RATE);
+ film_changed (Film::DCP_FRAME_RATE);
}
/** Updates the sensitivity of lots of widgets to a given value.
_scaler->Enable (s);
_audio_stream->Enable (s);
_dcp_content_type->Enable (s);
+ _dcp_frame_rate->Enable (s);
_trim_start->Enable (s);
_trim_end->Enable (s);
_dcp_ab->Enable (s);
_audio_dialog->Show ();
_audio_dialog->set_film (_film);
}
+
+void
+FilmEditor::best_dcp_frame_rate_clicked (wxCommandEvent &)
+{
+ if (!_film) {
+ return;
+ }
+
+ _film->set_dcp_frame_rate (best_dcp_frame_rate (_film->source_frame_rate ()));
+}
void subtitle_stream_changed (wxCommandEvent &);
void use_audio_changed (wxCommandEvent &);
void external_audio_changed (wxCommandEvent &);
+ void dcp_frame_rate_changed (wxCommandEvent &);
+ void best_dcp_frame_rate_clicked (wxCommandEvent &);
/* Handle changes to the model */
void film_changed (Film::Property);
wxButton* _edit_dci_button;
/** The Film's format */
wxChoice* _format;
+ wxStaticText* _format_description;
/** The Film's content file */
wxFilePickerCtrl* _content;
wxCheckBox* _trust_content_header;
wxSpinCtrl* _j2k_bandwidth;
/** The Film's DCP content type */
wxChoice* _dcp_content_type;
- /** The Film's frames per second */
- wxStaticText* _frames_per_second;
+ /** The Film's source frame rate */
+ wxStaticText* _source_frame_rate;
+ wxChoice* _dcp_frame_rate;
+ wxButton* _best_dcp_frame_rate;
+ wxStaticText* _frame_rate_description;
/** The Film's original size */
wxStaticText* _original_size;
/** The Film's length */
get_frame ();
if (_film->length()) {
- int const new_slider_position = 4096 * _decoders.video->last_source_time() / (_film->length().get() / _film->frames_per_second());
+ int const new_slider_position = 4096 * _decoders.video->last_source_time() / (_film->length().get() / _film->source_frame_rate());
if (new_slider_position != _slider->GetValue()) {
_slider->SetValue (new_slider_position);
}
return;
}
- if (_decoders.video->seek (_slider->GetValue() * _film->length().get() / (4096 * _film->frames_per_second()))) {
+ if (_decoders.video->seek (_slider->GetValue() * _film->length().get() / (4096 * _film->source_frame_rate()))) {
return;
}
}
if (_play_button->GetValue()) {
- _timer.Start (1000 / _film->frames_per_second());
+ _timer.Start (1000 / _film->source_frame_rate());
} else {
_timer.Stop ();
}
if (_film->length()) {
_frames->SetLabel (std_to_wx (lexical_cast<string> (_film->length().get())));
- double const disk = ((double) _film->j2k_bandwidth() / 8) * _film->length().get() / (_film->frames_per_second () * 1073741824);
+ FrameRateConversion frc (_film->source_frame_rate(), _film->dcp_frame_rate());
+ int const dcp_length = _film->length().get() * frc.factor();
+ double const disk = ((double) _film->j2k_bandwidth() / 8) * dcp_length / (_film->dcp_frame_rate() * 1073741824);
stringstream s;
s << fixed << setprecision (1) << disk << _("Gb");
_disk->SetLabel (std_to_wx (s.str ()));
return m;
}
+wxStaticText *
+add_label_to_grid_bag_sizer (wxGridBagSizer* s, wxWindow* p, wxString t, wxGBPosition pos, wxGBSpan span)
+{
+ wxStaticText* m = new wxStaticText (p, wxID_ANY, t);
+ s->Add (m, pos, span, wxALIGN_CENTER_VERTICAL | wxALL, 6);
+ return m;
+}
+
/** Pop up an error dialogue box.
* @param parent Parent.
* @param m Message.
*/
#include <wx/wx.h>
+#include <wx/gbsizer.h>
#include <boost/function.hpp>
#include <boost/thread.hpp>
class wxFilePickerCtrl;
class wxSpinCtrl;
+class wxGridBagSizer;
/** @file src/wx/wx_util.h
* @brief Some utility functions and classes.
extern void error_dialog (wxWindow *, wxString);
extern wxStaticText* add_label_to_sizer (wxSizer *, wxWindow *, wxString, int prop = 0);
+extern wxStaticText* add_label_to_grid_bag_sizer (wxGridBagSizer *, wxWindow *, wxString, wxGBPosition, wxGBSpan span = wxDefaultSpan);
extern std::string wx_to_std (wxString);
extern wxString std_to_wx (std::string);
-version 3
+version 4
name fred
use_dci_name 1
content
facility
package_type
dci_date 20130211
+dcp_frame_rate 0
width 0
height 0
length 0
dcp_intrinsic_duration 0
content_digest
external_audio_stream external 0 0
-frames_per_second 0
+source_frame_rate 0
BOOST_CHECK_EQUAL (JobManager::instance()->errors(), false);
}
-/* Test the constructor of DCPFrameRate */
-BOOST_AUTO_TEST_CASE (dcp_frame_rate_test)
+/* Test best_dcp_frame_rate and FrameRateConversion */
+BOOST_AUTO_TEST_CASE (best_dcp_frame_rate_test)
{
/* Run some tests with a limited range of allowed rates */
afr.push_back (30);
Config::instance()->set_allowed_dcp_frame_rates (afr);
- DCPFrameRate dfr = DCPFrameRate (60);
- BOOST_CHECK_EQUAL (dfr.frames_per_second, 30);
- BOOST_CHECK_EQUAL (dfr.skip, true);
- BOOST_CHECK_EQUAL (dfr.repeat, false);
- BOOST_CHECK_EQUAL (dfr.change_speed, false);
+ int best = best_dcp_frame_rate (60);
+ FrameRateConversion frc = FrameRateConversion (60, best);
+ BOOST_CHECK_EQUAL (best, 30);
+ BOOST_CHECK_EQUAL (frc.skip, true);
+ BOOST_CHECK_EQUAL (frc.repeat, false);
+ BOOST_CHECK_EQUAL (frc.change_speed, false);
- dfr = DCPFrameRate (50);
- BOOST_CHECK_EQUAL (dfr.frames_per_second, 25);
- BOOST_CHECK_EQUAL (dfr.skip, true);
- BOOST_CHECK_EQUAL (dfr.repeat, false);
- BOOST_CHECK_EQUAL (dfr.change_speed, false);
-
- dfr = DCPFrameRate (48);
- BOOST_CHECK_EQUAL (dfr.frames_per_second, 24);
- BOOST_CHECK_EQUAL (dfr.skip, true);
- BOOST_CHECK_EQUAL (dfr.repeat, false);
- BOOST_CHECK_EQUAL (dfr.change_speed, false);
+ best = best_dcp_frame_rate (50);
+ frc = FrameRateConversion (50, best);
+ BOOST_CHECK_EQUAL (best, 25);
+ BOOST_CHECK_EQUAL (frc.skip, true);
+ BOOST_CHECK_EQUAL (frc.repeat, false);
+ BOOST_CHECK_EQUAL (frc.change_speed, false);
+
+ best = best_dcp_frame_rate (48);
+ frc = FrameRateConversion (48, best);
+ BOOST_CHECK_EQUAL (best, 24);
+ BOOST_CHECK_EQUAL (frc.skip, true);
+ BOOST_CHECK_EQUAL (frc.repeat, false);
+ BOOST_CHECK_EQUAL (frc.change_speed, false);
- dfr = DCPFrameRate (30);
- BOOST_CHECK_EQUAL (dfr.skip, false);
- BOOST_CHECK_EQUAL (dfr.frames_per_second, 30);
- BOOST_CHECK_EQUAL (dfr.repeat, false);
- BOOST_CHECK_EQUAL (dfr.change_speed, false);
-
- dfr = DCPFrameRate (29.97);
- BOOST_CHECK_EQUAL (dfr.skip, false);
- BOOST_CHECK_EQUAL (dfr.frames_per_second, 30);
- BOOST_CHECK_EQUAL (dfr.repeat, false);
- BOOST_CHECK_EQUAL (dfr.change_speed, true);
+ best = best_dcp_frame_rate (30);
+ frc = FrameRateConversion (30, best);
+ BOOST_CHECK_EQUAL (best, 30);
+ BOOST_CHECK_EQUAL (frc.skip, false);
+ BOOST_CHECK_EQUAL (frc.repeat, false);
+ BOOST_CHECK_EQUAL (frc.change_speed, false);
+
+ best = best_dcp_frame_rate (29.97);
+ frc = FrameRateConversion (29.97, best);
+ BOOST_CHECK_EQUAL (best, 30);
+ BOOST_CHECK_EQUAL (frc.skip, false);
+ BOOST_CHECK_EQUAL (frc.repeat, false);
+ BOOST_CHECK_EQUAL (frc.change_speed, true);
- dfr = DCPFrameRate (25);
- BOOST_CHECK_EQUAL (dfr.skip, false);
- BOOST_CHECK_EQUAL (dfr.frames_per_second, 25);
- BOOST_CHECK_EQUAL (dfr.repeat, false);
- BOOST_CHECK_EQUAL (dfr.change_speed, false);
-
- dfr = DCPFrameRate (24);
- BOOST_CHECK_EQUAL (dfr.skip, false);
- BOOST_CHECK_EQUAL (dfr.frames_per_second, 24);
- BOOST_CHECK_EQUAL (dfr.repeat, false);
- BOOST_CHECK_EQUAL (dfr.change_speed, false);
-
- dfr = DCPFrameRate (14.5);
- BOOST_CHECK_EQUAL (dfr.skip, false);
- BOOST_CHECK_EQUAL (dfr.frames_per_second, 30);
- BOOST_CHECK_EQUAL (dfr.repeat, true);
- BOOST_CHECK_EQUAL (dfr.change_speed, true);
-
- dfr = DCPFrameRate (12.6);
- BOOST_CHECK_EQUAL (dfr.skip, false);
- BOOST_CHECK_EQUAL (dfr.frames_per_second, 25);
- BOOST_CHECK_EQUAL (dfr.repeat, true);
- BOOST_CHECK_EQUAL (dfr.change_speed, true);
-
- dfr = DCPFrameRate (12.4);
- BOOST_CHECK_EQUAL (dfr.skip, false);
- BOOST_CHECK_EQUAL (dfr.frames_per_second, 25);
- BOOST_CHECK_EQUAL (dfr.repeat, true);
- BOOST_CHECK_EQUAL (dfr.change_speed, true);
-
- dfr = DCPFrameRate (12);
- BOOST_CHECK_EQUAL (dfr.skip, false);
- BOOST_CHECK_EQUAL (dfr.frames_per_second, 24);
- BOOST_CHECK_EQUAL (dfr.repeat, true);
- BOOST_CHECK_EQUAL (dfr.change_speed, false);
+ best = best_dcp_frame_rate (25);
+ frc = FrameRateConversion (25, best);
+ BOOST_CHECK_EQUAL (best, 25);
+ BOOST_CHECK_EQUAL (frc.skip, false);
+ BOOST_CHECK_EQUAL (frc.repeat, false);
+ BOOST_CHECK_EQUAL (frc.change_speed, false);
+
+ best = best_dcp_frame_rate (24);
+ frc = FrameRateConversion (24, best);
+ BOOST_CHECK_EQUAL (best, 24);
+ BOOST_CHECK_EQUAL (frc.skip, false);
+ BOOST_CHECK_EQUAL (frc.repeat, false);
+ BOOST_CHECK_EQUAL (frc.change_speed, false);
+
+ best = best_dcp_frame_rate (14.5);
+ frc = FrameRateConversion (14.5, best);
+ BOOST_CHECK_EQUAL (best, 30);
+ BOOST_CHECK_EQUAL (frc.skip, false);
+ BOOST_CHECK_EQUAL (frc.repeat, true);
+ BOOST_CHECK_EQUAL (frc.change_speed, true);
+
+ best = best_dcp_frame_rate (12.6);
+ frc = FrameRateConversion (12.6, best);
+ BOOST_CHECK_EQUAL (best, 25);
+ BOOST_CHECK_EQUAL (frc.skip, false);
+ BOOST_CHECK_EQUAL (frc.repeat, true);
+ BOOST_CHECK_EQUAL (frc.change_speed, true);
+
+ best = best_dcp_frame_rate (12.4);
+ frc = FrameRateConversion (12.4, best);
+ BOOST_CHECK_EQUAL (best, 25);
+ BOOST_CHECK_EQUAL (frc.skip, false);
+ BOOST_CHECK_EQUAL (frc.repeat, true);
+ BOOST_CHECK_EQUAL (frc.change_speed, true);
+
+ best = best_dcp_frame_rate (12);
+ frc = FrameRateConversion (12, best);
+ BOOST_CHECK_EQUAL (best, 24);
+ BOOST_CHECK_EQUAL (frc.skip, false);
+ BOOST_CHECK_EQUAL (frc.repeat, true);
+ BOOST_CHECK_EQUAL (frc.change_speed, false);
/* Now add some more rates and see if it will use them
in preference to skip/repeat.
afr.push_back (60);
Config::instance()->set_allowed_dcp_frame_rates (afr);
- dfr = DCPFrameRate (60);
- BOOST_CHECK_EQUAL (dfr.frames_per_second, 60);
- BOOST_CHECK_EQUAL (dfr.skip, false);
- BOOST_CHECK_EQUAL (dfr.repeat, false);
- BOOST_CHECK_EQUAL (dfr.change_speed, false);
+ best = best_dcp_frame_rate (60);
+ frc = FrameRateConversion (60, best);
+ BOOST_CHECK_EQUAL (best, 60);
+ BOOST_CHECK_EQUAL (frc.skip, false);
+ BOOST_CHECK_EQUAL (frc.repeat, false);
+ BOOST_CHECK_EQUAL (frc.change_speed, false);
- dfr = DCPFrameRate (50);
- BOOST_CHECK_EQUAL (dfr.frames_per_second, 50);
- BOOST_CHECK_EQUAL (dfr.skip, false);
- BOOST_CHECK_EQUAL (dfr.repeat, false);
- BOOST_CHECK_EQUAL (dfr.change_speed, false);
-
- dfr = DCPFrameRate (48);
- BOOST_CHECK_EQUAL (dfr.frames_per_second, 48);
- BOOST_CHECK_EQUAL (dfr.skip, false);
- BOOST_CHECK_EQUAL (dfr.repeat, false);
- BOOST_CHECK_EQUAL (dfr.change_speed, false);
+ best = best_dcp_frame_rate (50);
+ frc = FrameRateConversion (50, best);
+ BOOST_CHECK_EQUAL (best, 50);
+ BOOST_CHECK_EQUAL (frc.skip, false);
+ BOOST_CHECK_EQUAL (frc.repeat, false);
+ BOOST_CHECK_EQUAL (frc.change_speed, false);
+
+ best = best_dcp_frame_rate (48);
+ frc = FrameRateConversion (48, best);
+ BOOST_CHECK_EQUAL (best, 48);
+ BOOST_CHECK_EQUAL (frc.skip, false);
+ BOOST_CHECK_EQUAL (frc.repeat, false);
+ BOOST_CHECK_EQUAL (frc.change_speed, false);
+
+ /* Check some out-there conversions (not the best) */
+
+ frc = FrameRateConversion (14.99, 24);
+ BOOST_CHECK_EQUAL (frc.skip, false);
+ BOOST_CHECK_EQUAL (frc.repeat, true);
+ BOOST_CHECK_EQUAL (frc.change_speed, true);
+
+ /* Check some conversions with limited DCP targets */
+
+ afr.clear ();
+ afr.push_back (24);
+ Config::instance()->set_allowed_dcp_frame_rates (afr);
+
+ best = best_dcp_frame_rate (25);
+ frc = FrameRateConversion (25, best);
+ BOOST_CHECK_EQUAL (best, 24);
+ BOOST_CHECK_EQUAL (frc.skip, false);
+ BOOST_CHECK_EQUAL (frc.repeat, false);
+ BOOST_CHECK_EQUAL (frc.change_speed, true);
}
BOOST_AUTO_TEST_CASE (audio_sampling_rate_test)
{
+ std::list<int> afr;
+ afr.push_back (24);
+ afr.push_back (25);
+ afr.push_back (30);
+ Config::instance()->set_allowed_dcp_frame_rates (afr);
+
shared_ptr<Film> f = new_test_film ("audio_sampling_rate_test");
- f->set_frames_per_second (24);
+ f->set_source_frame_rate (24);
+ f->set_dcp_frame_rate (24);
f->set_content_audio_stream (shared_ptr<AudioStream> (new FFmpegAudioStream ("a", 42, 48000, 0)));
BOOST_CHECK_EQUAL (f->target_audio_sample_rate(), 48000);
f->set_content_audio_stream (shared_ptr<AudioStream> (new FFmpegAudioStream ("a", 42, 80000, 0)));
BOOST_CHECK_EQUAL (f->target_audio_sample_rate(), 96000);
- f->set_frames_per_second (23.976);
+ f->set_source_frame_rate (23.976);
+ f->set_dcp_frame_rate (best_dcp_frame_rate (23.976));
f->set_content_audio_stream (shared_ptr<AudioStream> (new FFmpegAudioStream ("a", 42, 48000, 0)));
BOOST_CHECK_EQUAL (f->target_audio_sample_rate(), 47952);
- f->set_frames_per_second (29.97);
+ f->set_source_frame_rate (29.97);
+ f->set_dcp_frame_rate (best_dcp_frame_rate (29.97));
+ BOOST_CHECK_EQUAL (f->dcp_frame_rate (), 30);
f->set_content_audio_stream (shared_ptr<AudioStream> (new FFmpegAudioStream ("a", 42, 48000, 0)));
BOOST_CHECK_EQUAL (f->target_audio_sample_rate(), 47952);
+
+ f->set_source_frame_rate (25);
+ f->set_dcp_frame_rate (24);
+ f->set_content_audio_stream (shared_ptr<AudioStream> (new FFmpegAudioStream ("a", 42, 48000, 0)));
+ BOOST_CHECK_EQUAL (f->target_audio_sample_rate(), 50000);
+
+ f->set_source_frame_rate (25);
+ f->set_dcp_frame_rate (24);
+ f->set_content_audio_stream (shared_ptr<AudioStream> (new FFmpegAudioStream ("a", 42, 44100, 0)));
+ BOOST_CHECK_EQUAL (f->target_audio_sample_rate(), 50000);
+
+ /* Check some out-there conversions (not the best) */
+
+ f->set_source_frame_rate (14.99);
+ f->set_dcp_frame_rate (25);
+ f->set_content_audio_stream (shared_ptr<AudioStream> (new FFmpegAudioStream ("a", 42, 16000, 0)));
+ /* The FrameRateConversion within target_audio_sample_rate should choose to double-up
+ the 14.99 fps video to 30 and then run it slow at 25.
+ */
+ BOOST_CHECK_EQUAL (f->target_audio_sample_rate(), rint (48000 * 2 * 14.99 / 25));
}
class TestJob : public Job