*/
class FilmState;
-class EncodeOptions;
+class Film;
class ServerDescription;
class Scaler;
class Image;
class EncodedData
{
public:
- /** @param s Size of data, in bytes.
- /** @param d Data (will not be freed by this class, but may be by subclasses)
- * @param s libdcp::Size of data, in bytes.
-- */
- EncodedData (uint8_t* d, int s)
- : _data (d)
- , _size (s)
- {}
++ /** @param s Size of data, in bytes */
+ EncodedData (int s);
+
+ EncodedData (std::string f);
- virtual ~EncodedData () {}
+ virtual ~EncodedData ();
void send (boost::shared_ptr<Socket> socket);
- void write (boost::shared_ptr<const EncodeOptions>, SourceFrame);
+ void write (boost::shared_ptr<const Film>, int) const;
+ void write_hash (boost::shared_ptr<const Film>, int) const;
/** @return data */
uint8_t* data () const {
protected:
uint8_t* _data; ///< data
int _size; ///< data size in bytes
+
+private:
+ /* No copy construction */
+ EncodedData (EncodedData const &);
};
/** @class LocallyEncodedData
class LocallyEncodedData : public EncodedData
{
public:
- /** @param d Data (which will not be freed by this class)
- * @param s libdcp::Size of data, in bytes.
+ /** @param d Data (which will be copied by this class)
+ * @param s Size of data, in bytes.
*/
- LocallyEncodedData (uint8_t* d, int s)
- : EncodedData (d, s)
- {}
+ LocallyEncodedData (uint8_t* d, int s);
};
/** @class RemotelyEncodedData
{
public:
RemotelyEncodedData (int s);
- ~RemotelyEncodedData ();
};
/** @class DCPVideoFrame
public:
DCPVideoFrame (
boost::shared_ptr<const Image>, boost::shared_ptr<Subtitle>, libdcp::Size,
- int, int, float, Scaler const *, SourceFrame, float, std::string, int, int, Log *
+ int, int, float, Scaler const *, int, float, std::string, int, int, Log *
);
virtual ~DCPVideoFrame ();
boost::shared_ptr<EncodedData> encode_locally ();
boost::shared_ptr<EncodedData> encode_remotely (ServerDescription const *);
- SourceFrame frame () const {
+ int frame () const {
return _frame;
}
boost::shared_ptr<const Image> _input; ///< the input image
boost::shared_ptr<Subtitle> _subtitle; ///< any subtitle that should be on the image
- libdcp::Size _out_size; ///< the required size of the output, in pixels
+ libdcp::Size _out_size; ///< the required size of the output, in pixels
int _padding;
int _subtitle_offset;
float _subtitle_scale;
Scaler const * _scaler; ///< scaler to use
- SourceFrame _frame; ///< frame index within the Film's source
+ 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)
std::string _post_process; ///< FFmpeg post-processing string to use
int _colour_lut; ///< Colour look-up table to use
using boost::shared_ptr;
using boost::optional;
using boost::dynamic_pointer_cast;
+using libdcp::Size;
-FFmpegDecoder::FFmpegDecoder (shared_ptr<Film> f, shared_ptr<const DecodeOptions> o, Job* j)
+FFmpegDecoder::FFmpegDecoder (shared_ptr<Film> f, DecodeOptions o, Job* j)
: Decoder (f, o, j)
, VideoDecoder (f, o, j)
, AudioDecoder (f, o, j)
setup_audio ();
setup_subtitle ();
- if (!o->video_sync) {
+ if (!o.video_sync) {
_first_video = 0;
}
}
filter_and_emit_video (_frame);
}
- if (_audio_stream && _opt->decode_audio) {
+ if (_audio_stream && _opt.decode_audio) {
while (avcodec_decode_audio4 (_audio_codec_context, _frame, &frame_finished, &_packet) >= 0 && frame_finished) {
int const data_size = av_samples_get_buffer_size (
0, _audio_codec_context->channels, _frame->nb_samples, audio_sample_format (), 1
_film->log()->log (String::compose ("Used only %1 bytes of %2 in packet", r, _packet.size));
}
- if (_opt->video_sync) {
+ if (_opt.video_sync) {
out_with_sync ();
} else {
filter_and_emit_video (_frame);
}
}
- } else if (ffa && _packet.stream_index == ffa->id() && _opt->decode_audio) {
+ } else if (ffa && _packet.stream_index == ffa->id() && _opt.decode_audio) {
int frame_finished;
if (avcodec_decode_audio4 (_audio_codec_context, _frame, &frame_finished, &_packet) >= 0 && frame_finished) {
}
}
- } else if (_subtitle_stream && _packet.stream_index == _subtitle_stream->id() && _opt->decode_subtitles && _first_video) {
+ } else if (_subtitle_stream && _packet.stream_index == _subtitle_stream->id() && _opt.decode_subtitles && _first_video) {
int got_subtitle;
AVSubtitle sub;
return _audio_codec_context->sample_fmt;
}
- Size
+ libdcp::Size
FFmpegDecoder::native_size () const
{
- return Size (_video_codec_context->width, _video_codec_context->height);
+ return libdcp::Size (_video_codec_context->width, _video_codec_context->height);
}
PixelFormat
shared_ptr<FilterGraph> graph;
list<shared_ptr<FilterGraph> >::iterator i = _filter_graphs.begin();
- while (i != _filter_graphs.end() && !(*i)->can_process (Size (frame->width, frame->height), (AVPixelFormat) frame->format)) {
+ while (i != _filter_graphs.end() && !(*i)->can_process (libdcp::Size (frame->width, frame->height), (AVPixelFormat) frame->format)) {
++i;
}
if (i == _filter_graphs.end ()) {
- graph.reset (new FilterGraph (_film, this, Size (frame->width, frame->height), (AVPixelFormat) frame->format));
+ graph.reset (new FilterGraph (_film, this, libdcp::Size (frame->width, frame->height), (AVPixelFormat) frame->format));
_filter_graphs.push_back (graph);
_film->log()->log (String::compose ("New graph for %1x%2, pixel format %3", frame->width, frame->height, frame->format));
} else {
#include "ab_transcode_job.h"
#include "transcode_job.h"
#include "scp_dcp_job.h"
-#include "make_dcp_job.h"
#include "log.h"
#include "options.h"
#include "exceptions.h"
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)
, _external_audio (o._external_audio)
, _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)));
}
/** 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 << "dcp_ab " << (_dcp_ab ? "1" : "0") << "\n";
if (_content_audio_stream) {
f << "selected_content_audio_stream " << _content_audio_stream->to_string() << "\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") {
_dcp_ab = (v == "1");
} else if (k == "selected_content_audio_stream" || (!version && k == "selected_audio_stream")) {
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")) {
_dirty = false;
}
- Size
- Film::cropped_size (Size s) const
+ libdcp::Size
+ Film::cropped_size (libdcp::Size s) const
{
boost::mutex::scoped_lock lm (_state_mutex);
s.width -= _crop.left + _crop.right;
/* 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
- Film::set_reel_size (uint64_t s)
- {
- {
- boost::mutex::scoped_lock lm (_state_mutex);
- _reel_size = s;
- }
- signal_changed (REEL_SIZE);
- }
-
- void
- Film::unset_reel_size ()
- {
- {
- boost::mutex::scoped_lock lm (_state_mutex);
- _reel_size = boost::optional<uint64_t> ();
- }
- signal_changed (REEL_SIZE);
- }
-
void
Film::set_dcp_ab (bool a)
{
_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 ();
}
}
void
- Film::set_size (Size s)
+ Film::set_size (libdcp::Size s)
{
{
boost::mutex::scoped_lock lm (_state_mutex);
_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 ();
+}
+
std::string file (std::string f) const;
std::string dir (std::string d) const;
+ std::string frame_out_path (int f, bool t) const;
+ std::string hash_out_path (int f, bool t) const;
+ std::string multichannel_audio_out_path (int c, bool t) const;
+
std::string content_path () const;
ContentType content_type () const;
void read_metadata ();
libdcp::Size cropped_size (libdcp::Size) const;
- boost::optional<int> dcp_length () const;
std::string dci_name () const;
std::string dcp_name () const;
+ boost::optional<int> dcp_intrinsic_duration () const {
+ return _dcp_intrinsic_duration;
+ }
+
/** @return true if our state has changed since we last saved it */
bool dirty () const {
return _dirty;
CROP,
FILTERS,
SCALER,
- DCP_TRIM_START,
- DCP_TRIM_END,
+ TRIM_START,
+ TRIM_END,
- REEL_SIZE,
DCP_AB,
CONTENT_AUDIO_STREAM,
EXTERNAL_AUDIO,
DCI_METADATA,
SIZE,
LENGTH,
+ DCP_INTRINSIC_DURATION,
CONTENT_AUDIO_STREAMS,
SUBTITLE_STREAMS,
FRAMES_PER_SECOND,
return _scaler;
}
- SourceFrame dcp_trim_start () const {
+ int trim_start () const {
boost::mutex::scoped_lock lm (_state_mutex);
- return _dcp_trim_start;
+ return _trim_start;
}
- SourceFrame dcp_trim_end () const {
+ int trim_end () const {
boost::mutex::scoped_lock lm (_state_mutex);
- return _dcp_trim_end;
+ return _trim_end;
}
- boost::optional<uint64_t> reel_size () const {
- boost::mutex::scoped_lock lm (_state_mutex);
- return _reel_size;
- }
-
bool dcp_ab () const {
boost::mutex::scoped_lock lm (_state_mutex);
return _dcp_ab;
return _still_duration;
}
+ int still_duration_in_frames () const;
+
boost::shared_ptr<SubtitleStream> subtitle_stream () const {
boost::mutex::scoped_lock lm (_state_mutex);
return _subtitle_stream;
void set_bottom_crop (int);
void set_filters (std::vector<Filter const *>);
void set_scaler (Scaler const *);
- void set_dcp_trim_start (int);
- void set_dcp_trim_end (int);
+ void set_trim_start (int);
+ void set_trim_end (int);
- void set_reel_size (uint64_t);
- void unset_reel_size ();
void set_dcp_ab (bool);
void set_content_audio_stream (boost::shared_ptr<AudioStream>);
void set_external_audio (std::vector<std::string>);
void set_size (libdcp::Size);
void set_length (SourceFrame);
void unset_length ();
+ void set_dcp_intrinsic_duration (int);
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> >);
/** Scaler algorithm to use */
Scaler const * _scaler;
/** Frames to trim off the start of the DCP */
- int _dcp_trim_start;
+ int _trim_start;
/** Frames to trim off the end of the DCP */
- int _dcp_trim_end;
+ int _trim_end;
- /** Approximate target reel size in bytes; if not set, use a single reel */
- boost::optional<uint64_t> _reel_size;
/** true to create an A/B comparison DCP, where the left half of the image
is the video without any filters or post-processing, and the right half
has the specified filters and post-processing.
/* Data which are cached to speed things up */
- /** libdcp::Size, in pixels, of the source (ignoring cropping) */
+ /** Size, in pixels, of the source (ignoring cropping) */
libdcp::Size _size;
/** The length of the source, in video frames (as far as we know) */
boost::optional<SourceFrame> _length;
+ boost::optional<int> _dcp_intrinsic_duration;
/** MD5 digest of our content file */
std::string _content_digest;
/** The audio streams in our content */
using std::string;
using std::list;
using boost::shared_ptr;
+using libdcp::Size;
/** Construct a FilterGraph for the settings in a film.
* @param film Film.
* @param s Size of the images to process.
* @param p Pixel format of the images to process.
*/
- FilterGraph::FilterGraph (shared_ptr<Film> film, FFmpegDecoder* decoder, Size s, AVPixelFormat p)
+ FilterGraph::FilterGraph (shared_ptr<Film> film, FFmpegDecoder* decoder, libdcp::Size s, AVPixelFormat p)
: _buffer_src_context (0)
, _buffer_sink_context (0)
, _size (s)
* @return true if this chain can process images with `s' and `p', otherwise false.
*/
bool
- FilterGraph::can_process (Size s, AVPixelFormat p) const
+ FilterGraph::can_process (libdcp::Size s, AVPixelFormat p) const
{
return (_size == s && _pixel_format == p);
}
using std::stringstream;
using std::vector;
using boost::shared_ptr;
+using libdcp::Size;
vector<Format const *> Format::_formats;
void
Format::setup_formats ()
{
- _formats.push_back (new FixedFormat (119, Size (1285, 1080), "119", "1.19", "F"));
- _formats.push_back (new FixedFormat (133, Size (1436, 1080), "133", "1.33", "F"));
- _formats.push_back (new FixedFormat (138, Size (1485, 1080), "138", "1.375", "F"));
- _formats.push_back (new FixedFormat (133, Size (1998, 1080), "133-in-flat", "4:3 within Flat", "F"));
- _formats.push_back (new FixedFormat (137, Size (1480, 1080), "137", "Academy", "F"));
- _formats.push_back (new FixedFormat (166, Size (1793, 1080), "166", "1.66", "F"));
- _formats.push_back (new FixedFormat (166, Size (1998, 1080), "166-in-flat", "1.66 within Flat", "F"));
- _formats.push_back (new FixedFormat (178, Size (1998, 1080), "178-in-flat", "16:9 within Flat", "F"));
- _formats.push_back (new FixedFormat (178, Size (1920, 1080), "178", "16:9", "F"));
- _formats.push_back (new FixedFormat (185, Size (1998, 1080), "185", "Flat", "F"));
- _formats.push_back (new FixedFormat (239, Size (2048, 858), "239", "Scope", "S"));
- _formats.push_back (new VariableFormat (Size (1998, 1080), "var-185", "Flat", "F"));
- _formats.push_back (new VariableFormat (Size (2048, 858), "var-239", "Scope", "S"));
+ _formats.push_back (new FixedFormat (119, libdcp::Size (1285, 1080), "119", "1.19", "F"));
+ _formats.push_back (new FixedFormat (133, libdcp::Size (1436, 1080), "133", "1.33", "F"));
+ _formats.push_back (new FixedFormat (138, libdcp::Size (1485, 1080), "138", "1.375", "F"));
+ _formats.push_back (new FixedFormat (133, libdcp::Size (1998, 1080), "133-in-flat", "4:3 within Flat", "F"));
+ _formats.push_back (new FixedFormat (137, libdcp::Size (1480, 1080), "137", "Academy", "F"));
+ _formats.push_back (new FixedFormat (166, libdcp::Size (1793, 1080), "166", "1.66", "F"));
+ _formats.push_back (new FixedFormat (166, libdcp::Size (1998, 1080), "166-in-flat", "1.66 within Flat", "F"));
+ _formats.push_back (new FixedFormat (178, libdcp::Size (1998, 1080), "178-in-flat", "16:9 within Flat", "F"));
+ _formats.push_back (new FixedFormat (178, libdcp::Size (1920, 1080), "178", "16:9", "F"));
+ _formats.push_back (new FixedFormat (185, libdcp::Size (1998, 1080), "185", "Flat", "F"));
+ _formats.push_back (new FixedFormat (239, libdcp::Size (2048, 858), "239", "Scope", "S"));
+ _formats.push_back (new VariableFormat (libdcp::Size (1998, 1080), "var-185", "Flat", "F"));
+ _formats.push_back (new VariableFormat (libdcp::Size (2048, 858), "var-239", "Scope", "S"));
}
/** @param n Nickname.
* @param id ID (e.g. 185)
* @param n Nick name (e.g. Flat)
*/
- FixedFormat::FixedFormat (int r, Size dcp, string id, string n, string d)
+ FixedFormat::FixedFormat (int r, libdcp::Size dcp, string id, string n, string d)
: Format (dcp, id, n, d)
, _ratio (r)
{
return p;
}
- VariableFormat::VariableFormat (Size dcp, string id, string n, string d)
+ VariableFormat::VariableFormat (libdcp::Size dcp, string id, string n, string d)
: Format (dcp, id, n, d)
{
using namespace std;
using namespace boost;
+using libdcp::Size;
void
Image::swap (Image& other)
}
shared_ptr<Image>
- Image::scale (Size out_size, Scaler const * scaler, bool result_aligned) const
-Image::scale (libdcp::Size out_size, Scaler const * scaler, bool aligned) const
++Image::scale (libdcp::Size out_size, Scaler const * scaler, bool result_aligned) const
{
assert (scaler);
+ /* Empirical testing suggests that sws_scale() will crash if
+ the input image is not aligned.
+ */
+ assert (aligned ());
- shared_ptr<Image> scaled (new SimpleImage (pixel_format(), out_size, aligned));
+ shared_ptr<Image> scaled (new SimpleImage (pixel_format(), out_size, result_aligned));
struct SwsContext* scale_context = sws_getContext (
size().width, size().height, pixel_format(),
* @param scaler Scaler to use.
*/
shared_ptr<Image>
- Image::scale_and_convert_to_rgb (Size out_size, int padding, Scaler const * scaler, bool result_aligned) const
-Image::scale_and_convert_to_rgb (libdcp::Size out_size, int padding, Scaler const * scaler, bool aligned) const
++Image::scale_and_convert_to_rgb (libdcp::Size out_size, int padding, Scaler const * scaler, bool result_aligned) const
{
assert (scaler);
+ /* Empirical testing suggests that sws_scale() will crash if
+ the input image is not aligned.
+ */
+ assert (aligned ());
- Size content_size = out_size;
+ libdcp::Size content_size = out_size;
content_size.width -= (padding * 2);
- shared_ptr<Image> rgb (new SimpleImage (PIX_FMT_RGB24, content_size, aligned));
+ shared_ptr<Image> rgb (new SimpleImage (PIX_FMT_RGB24, content_size, result_aligned));
struct SwsContext* scale_context = sws_getContext (
size().width, size().height, pixel_format(),
scheme of things.
*/
if (padding > 0) {
- shared_ptr<Image> padded_rgb (new SimpleImage (PIX_FMT_RGB24, out_size, aligned));
+ shared_ptr<Image> padded_rgb (new SimpleImage (PIX_FMT_RGB24, out_size, result_aligned));
padded_rgb->make_black ();
/* XXX: we are cheating a bit here; we know the frame is RGB so we can
shared_ptr<Image>
Image::crop (Crop crop, bool aligned) const
{
- Size cropped_size = size ();
+ libdcp::Size cropped_size = size ();
cropped_size.width -= crop.left + crop.right;
cropped_size.height -= crop.top + crop.bottom;
{
switch (_pixel_format) {
case PIX_FMT_YUV420P:
- case PIX_FMT_YUV422P10LE:
case PIX_FMT_YUV422P:
memset (data()[0], 0, lines(0) * stride()[0]);
- memset (data()[1], 0x80, lines(1) * stride()[1]);
- memset (data()[2], 0x80, lines(2) * stride()[2]);
+ memset (data()[1], 0x7f, lines(1) * stride()[1]);
+ memset (data()[2], 0x7f, lines(2) * stride()[2]);
break;
+ case PIX_FMT_YUV422P10LE:
+ memset (data()[0], 0, lines(0) * stride()[0]);
+ for (int i = 1; i < 3; ++i) {
+ int16_t* p = reinterpret_cast<int16_t*> (data()[i]);
+ for (int y = 0; y < size().height; ++y) {
+ for (int x = 0; x < line_size()[i] / 2; ++x) {
+ p[x] = (1 << 9) - 1;
+ }
+ p += stride()[i] / 2;
+ }
+ }
+ break;
+
case PIX_FMT_RGB24:
memset (data()[0], 0, lines(0) * stride()[0]);
break;
return 0.5;
}
case PIX_FMT_YUV422P10LE:
- if (c == 1) {
+ if (c == 0) {
return 2;
} else {
return 1;
* @param p Pixel format.
* @param s Size in pixels.
*/
- SimpleImage::SimpleImage (AVPixelFormat p, Size s, bool aligned)
+ SimpleImage::SimpleImage (AVPixelFormat p, libdcp::Size s, bool aligned)
: Image (p)
, _size (s)
, _aligned (aligned)
return _stride;
}
- Size
+ libdcp::Size
SimpleImage::size () const
{
return _size;
}
+bool
+SimpleImage::aligned () const
+{
+ return _aligned;
+}
+
FilterBufferImage::FilterBufferImage (AVPixelFormat p, AVFilterBufferRef* b)
: Image (p)
, _buffer (b)
return _buffer->linesize;
}
- Size
+ libdcp::Size
FilterBufferImage::size () const
{
- return Size (_buffer->video->w, _buffer->video->h);
+ return libdcp::Size (_buffer->video->w, _buffer->video->h);
}
+bool
+FilterBufferImage::aligned () const
+{
+ /* XXX? */
+ return true;
+}
+
RGBPlusAlphaImage::RGBPlusAlphaImage (shared_ptr<const Image> im)
: SimpleImage (im->pixel_format(), im->size(), false)
{
using std::cout;
using boost::shared_ptr;
+using libdcp::Size;
ImageMagickDecoder::ImageMagickDecoder (
- boost::shared_ptr<Film> f, boost::shared_ptr<const DecodeOptions> o, Job* j)
+ boost::shared_ptr<Film> f, DecodeOptions o, Job* j)
: Decoder (f, o, j)
, VideoDecoder (f, o, j)
{
_iter = _files.begin ();
}
- Size
+ libdcp::Size
ImageMagickDecoder::native_size () const
{
if (_files.empty ()) {
/* Look at the first file and assume its size holds for all */
using namespace MagickCore;
Magick::Image* image = new Magick::Image (_film->content_path ());
- Size const s = Size (image->columns(), image->rows());
+ libdcp::Size const s = libdcp::Size (image->columns(), image->rows());
delete image;
return s;
ImageMagickDecoder::pass ()
{
if (_iter == _files.end()) {
- if (!_film->dcp_length() || video_frame() >= _film->dcp_length().get()) {
+ if (video_frame() >= _film->still_duration_in_frames()) {
return true;
}
Magick::Image* magick_image = new Magick::Image (_film->content_path ());
- Size size = native_size ();
+ libdcp::Size size = native_size ();
shared_ptr<Image> image (new SimpleImage (PIX_FMT_RGB24, size, false));
using namespace MagickCore;
delete magick_image;
- image = image->crop (_film->crop(), false);
+ image = image->crop (_film->crop(), true);
emit_video (image, 0);
using boost::algorithm::split;
using boost::thread;
using boost::bind;
+using libdcp::Size;
/** Create a server description from a string of metadata returned from as_metadata().
* @param v Metadata.
return -1;
}
- Size in_size (get_required_int (kv, "input_width"), get_required_int (kv, "input_height"));
+ libdcp::Size in_size (get_required_int (kv, "input_width"), get_required_int (kv, "input_height"));
int pixel_format_int = get_required_int (kv, "input_pixel_format");
- Size out_size (get_required_int (kv, "output_width"), get_required_int (kv, "output_height"));
+ libdcp::Size out_size (get_required_int (kv, "output_width"), get_required_int (kv, "output_height"));
int padding = get_required_int (kv, "padding");
int subtitle_offset = get_required_int (kv, "subtitle_offset");
float subtitle_scale = get_required_float (kv, "subtitle_scale");
int colour_lut_index = get_required_int (kv, "colour_lut");
int j2k_bandwidth = get_required_int (kv, "j2k_bandwidth");
Position subtitle_position (get_optional_int (kv, "subtitle_x"), get_optional_int (kv, "subtitle_y"));
- Size subtitle_size (get_optional_int (kv, "subtitle_width"), get_optional_int (kv, "subtitle_height"));
+ libdcp::Size subtitle_size (get_optional_int (kv, "subtitle_width"), get_optional_int (kv, "subtitle_height"));
/* This checks that colour_lut_index is within range */
colour_lut_index_to_name (colour_lut_index);
using namespace std;
using namespace boost;
+using libdcp::Size;
/** Construct a TimedSubtitle. This is a subtitle image, position,
* and a range of time over which it should be shown.
throw DecodeError ("non-bitmap subtitles not yet supported");
}
- shared_ptr<Image> image (new SimpleImage (PIX_FMT_RGBA, Size (rect->w, rect->h), true));
+ shared_ptr<Image> image (new SimpleImage (PIX_FMT_RGBA, libdcp::Size (rect->w, rect->h), true));
/* Start of the first line in the subtitle */
uint8_t* sub_p = rect->pict.data[0];
#include <iomanip>
#include <iostream>
#include <fstream>
+#include <climits>
#ifdef DVDOMATIC_POSIX
#include <execinfo.h>
#include <cxxabi.h>
#include "dcp_content_type.h"
#include "filter.h"
#include "sound_processor.h"
+#include "config.h"
using namespace std;
using namespace boost;
+using libdcp::Size;
thread::id ui_thread;
* @return FFmpeg crop filter string.
*/
string
- crop_string (Position start, Size size)
+ crop_string (Position start, libdcp::Size size)
{
stringstream s;
s << "crop=" << size.width << ":" << size.height << ":" << start.x << ":" << start.y;
return s.str ();
}
-/** @param fps Arbitrary frames-per-second value.
- * @return DCPFrameRate for this frames-per-second.
- */
-DCPFrameRate
-dcp_frame_rate (float fps)
+static bool about_equal (float a, float b)
+{
+ /* A film of F seconds at f FPS will be Ff frames;
+ Consider some delta FPS d, so if we run the same
+ film at (f + d) FPS it will last F(f + d) seconds.
+
+ Hence the difference in length over the length of the film will
+ be F(f + d) - Ff frames
+ = Ff + Fd - Ff frames
+ = Fd frames
+ = Fd/f seconds
+
+ So if we accept a difference of 1 frame, ie 1/f seconds, we can
+ say that
+
+ 1/f = Fd/f
+ ie 1 = Fd
+ ie d = 1/F
+
+ So for a 3hr film, ie F = 3 * 60 * 60 = 10800, the acceptable
+ FPS error is 1/F ~= 0.0001 ~= 10-e4
+ */
+
+ return (fabs (a - b) < 1e-4);
+}
+
+class FrameRateCandidate
{
- DCPFrameRate dfr;
+public:
+ FrameRateCandidate (float source_, int dcp_)
+ : source (source_)
+ , 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)
+{
+ list<int> const allowed_dcp_frame_rates = Config::instance()->allowed_dcp_frame_rates ();
+
+ /* Work out what rates we could manage, including those achieved by using skip / repeat. */
+ list<FrameRateCandidate> candidates;
- dfr.run_fast = (fps != rint (fps));
- dfr.frames_per_second = rint (fps);
- dfr.skip = 1;
+ /* Start with the ones without skip / repeat so they will get matched in preference to skipped/repeated ones */
+ for (list<int>::const_iterator i = allowed_dcp_frame_rates.begin(); i != allowed_dcp_frame_rates.end(); ++i) {
+ candidates.push_back (FrameRateCandidate (*i, *i));
+ }
+
+ /* Then the skip/repeat ones */
+ for (list<int>::const_iterator i = allowed_dcp_frame_rates.begin(); i != allowed_dcp_frame_rates.end(); ++i) {
+ candidates.push_back (FrameRateCandidate (float (*i) / 2, *i));
+ candidates.push_back (FrameRateCandidate (float (*i) * 2, *i));
+ }
+
+ /* Pick the best one, bailing early if we hit an exact match */
+ float error = numeric_limits<float>::max ();
+ boost::optional<FrameRateCandidate> best;
+ list<FrameRateCandidate>::iterator i = candidates.begin();
+ while (i != candidates.end()) {
+
+ if (about_equal (i->source, source_fps)) {
+ best = *i;
+ break;
+ }
+
+ float const e = fabs (i->source - source_fps);
+ if (e < error) {
+ error = e;
+ best = *i;
+ }
+
+ ++i;
+ }
- /* XXX: somewhat arbitrary */
- if (fps == 50) {
- dfr.frames_per_second = 25;
- dfr.skip = 2;
+ if (!best) {
+ throw EncodeError ("cannot find a suitable DCP frame rate for this source");
}
- return dfr;
+ frames_per_second = best->dcp;
+ skip = best->skip ();
+ repeat = best->repeat ();
+ change_speed = !about_equal (source_fps * factor(), frames_per_second);
}
/** @param An arbitrary sampling rate.
return f;
}
-
bool operator== (Crop const & a, Crop const & b)
{
return (a.left == b.left && a.right == b.right && a.top == b.top && a.bottom == b.bottom);
video_control (add_label_to_sizer (_film_sizer, _film_panel, "Trim frames"));
wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
video_control (add_label_to_sizer (s, _film_panel, "Start"));
- _dcp_trim_start = new wxSpinCtrl (_film_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1));
- s->Add (video_control (_dcp_trim_start));
+ _trim_start = new wxSpinCtrl (_film_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1));
+ s->Add (video_control (_trim_start));
video_control (add_label_to_sizer (s, _film_panel, "End"));
- _dcp_trim_end = new wxSpinCtrl (_film_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1));
- s->Add (video_control (_dcp_trim_end));
+ _trim_end = new wxSpinCtrl (_film_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1));
+ s->Add (video_control (_trim_end));
_film_sizer->Add (s);
}
- _multiple_reels = new wxCheckBox (_film_panel, wxID_ANY, wxT ("Make multiple reels"));
- _film_sizer->Add (_multiple_reels);
-
- {
- wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
- _reel_size = new wxSpinCtrl (_film_panel, wxID_ANY);
- s->Add (_reel_size);
- add_label_to_sizer (s, _film_panel, "Gb each");
- _film_sizer->Add (s);
- }
-
_dcp_ab = new wxCheckBox (_film_panel, wxID_ANY, wxT ("A/B"));
video_control (_dcp_ab);
_film_sizer->Add (_dcp_ab, 1);
for (vector<DCPContentType const *>::const_iterator i = ct.begin(); i != ct.end(); ++i) {
_dcp_content_type->Append (std_to_wx ((*i)->pretty_name ()));
}
-
- _reel_size->SetRange(1, 1000);
}
void
_dcp_content_type->Connect (wxID_ANY, wxEVT_COMMAND_COMBOBOX_SELECTED, wxCommandEventHandler (FilmEditor::dcp_content_type_changed), 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);
- _dcp_trim_start->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::dcp_trim_start_changed), 0, this);
- _dcp_trim_end->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::dcp_trim_end_changed), 0, this);
+ _trim_start->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::trim_start_changed), 0, this);
+ _trim_end->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::trim_end_changed), 0, this);
- _multiple_reels->Connect (wxID_ANY, wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler (FilmEditor::multiple_reels_toggled), 0, this);
- _reel_size->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::reel_size_changed), 0, this);
_with_subtitles->Connect (wxID_ANY, wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler (FilmEditor::with_subtitles_toggled), 0, this);
_subtitle_offset->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::subtitle_offset_changed), 0, this);
_subtitle_scale->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::subtitle_scale_changed), 0, this);
_right_crop->SetRange (0, 1024);
_bottom_crop->SetRange (0, 1024);
_still_duration->SetRange (1, 60 * 60);
- _dcp_trim_start->SetRange (0, 100);
- _dcp_trim_end->SetRange (0, 100);
+ _trim_start->SetRange (0, 100);
+ _trim_end->SetRange (0, 100);
_j2k_bandwidth->SetRange (50, 250);
}
_film->set_trust_content_header (_trust_content_header->GetValue ());
}
- void
- FilmEditor::multiple_reels_toggled (wxCommandEvent &)
- {
- if (!_film) {
- return;
- }
-
- if (_multiple_reels->GetValue()) {
- _film->set_reel_size (_reel_size->GetValue() * 1e9);
- } else {
- _film->unset_reel_size ();
- }
-
- setup_reel_control_sensitivity ();
- }
-
- void
- FilmEditor::reel_size_changed (wxCommandEvent &)
- {
- if (!_film) {
- return;
- }
-
- _film->set_reel_size (static_cast<uint64_t> (_reel_size->GetValue()) * 1e9);
- }
-
/** Called when the DCP A/B switch has been toggled */
void
FilmEditor::dcp_ab_toggled (wxCommandEvent &)
}
_length->SetLabel (std_to_wx (s.str ()));
if (_film->length()) {
- _dcp_trim_start->SetRange (0, _film->length().get());
- _dcp_trim_end->SetRange (0, _film->length().get());
+ _trim_start->SetRange (0, _film->length().get());
+ _trim_end->SetRange (0, _film->length().get());
}
break;
+ case Film::DCP_INTRINSIC_DURATION:
+ break;
case Film::DCP_CONTENT_TYPE:
checked_set (_dcp_content_type, DCPContentType::as_index (_film->dcp_content_type ()));
_dcp_name->SetLabel (std_to_wx (_film->dcp_name ()));
case Film::SCALER:
checked_set (_scaler, Scaler::as_index (_film->scaler ()));
break;
- case Film::DCP_TRIM_START:
- checked_set (_dcp_trim_start, _film->dcp_trim_start());
+ case Film::TRIM_START:
+ checked_set (_trim_start, _film->trim_start());
break;
- case Film::DCP_TRIM_END:
- checked_set (_dcp_trim_end, _film->dcp_trim_end());
+ case Film::TRIM_END:
+ checked_set (_trim_end, _film->trim_end());
break;
- case Film::REEL_SIZE:
- if (_film->reel_size()) {
- checked_set (_multiple_reels, true);
- checked_set (_reel_size, _film->reel_size().get() / 1e9);
- } else {
- checked_set (_multiple_reels, false);
- }
- setup_reel_control_sensitivity ();
- break;
case Film::AUDIO_GAIN:
checked_set (_audio_gain, _film->audio_gain ());
break;
film_changed (Film::CROP);
film_changed (Film::FILTERS);
film_changed (Film::SCALER);
- film_changed (Film::DCP_TRIM_START);
- film_changed (Film::DCP_TRIM_END);
+ film_changed (Film::TRIM_START);
+ film_changed (Film::TRIM_END);
- film_changed (Film::REEL_SIZE);
film_changed (Film::DCP_AB);
film_changed (Film::CONTENT_AUDIO_STREAM);
film_changed (Film::EXTERNAL_AUDIO);
_scaler->Enable (s);
_audio_stream->Enable (s);
_dcp_content_type->Enable (s);
- _dcp_trim_start->Enable (s);
- _dcp_trim_end->Enable (s);
+ _trim_start->Enable (s);
+ _trim_end->Enable (s);
- _multiple_reels->Enable (s);
- _reel_size->Enable (s);
_dcp_ab->Enable (s);
_colour_lut->Enable (s);
_j2k_bandwidth->Enable (s);
setup_subtitle_control_sensitivity ();
setup_audio_control_sensitivity ();
- setup_reel_control_sensitivity ();
}
/** Called when the `Edit filters' button has been clicked */
}
void
-FilmEditor::dcp_trim_start_changed (wxCommandEvent &)
+FilmEditor::trim_start_changed (wxCommandEvent &)
{
if (!_film) {
return;
}
- _film->set_dcp_trim_start (_dcp_trim_start->GetValue ());
+ _film->set_trim_start (_trim_start->GetValue ());
}
void
-FilmEditor::dcp_trim_end_changed (wxCommandEvent &)
+FilmEditor::trim_end_changed (wxCommandEvent &)
{
if (!_film) {
return;
}
- _film->set_dcp_trim_end (_dcp_trim_end->GetValue ());
+ _film->set_trim_end (_trim_end->GetValue ());
}
void
_film->set_external_audio (a);
}
-
- void
- FilmEditor::setup_reel_control_sensitivity ()
- {
- _reel_size->Enable (_multiple_reels->GetValue ());
- }
void content_changed (wxCommandEvent &);
void trust_content_header_changed (wxCommandEvent &);
void format_changed (wxCommandEvent &);
- void dcp_trim_start_changed (wxCommandEvent &);
- void dcp_trim_end_changed (wxCommandEvent &);
+ void trim_start_changed (wxCommandEvent &);
+ void trim_end_changed (wxCommandEvent &);
- void multiple_reels_toggled (wxCommandEvent &);
- void reel_size_changed (wxCommandEvent &);
void dcp_content_type_changed (wxCommandEvent &);
void dcp_ab_toggled (wxCommandEvent &);
void scaler_changed (wxCommandEvent &);
void setup_formats ();
void setup_subtitle_control_sensitivity ();
void setup_audio_control_sensitivity ();
- void setup_reel_control_sensitivity ();
void setup_streams ();
void setup_audio_details ();
/** The Film's duration for still sources */
wxSpinCtrl* _still_duration;
- wxSpinCtrl* _dcp_trim_start;
- wxSpinCtrl* _dcp_trim_end;
+ wxSpinCtrl* _trim_start;
+ wxSpinCtrl* _trim_end;
- wxCheckBox* _multiple_reels;
- wxSpinCtrl* _reel_size;
/** Selector to generate an A/B comparison DCP */
wxCheckBox* _dcp_ab;
using std::cout;
using std::list;
using boost::shared_ptr;
+using libdcp::Size;
FilmViewer::FilmViewer (shared_ptr<Film> f, wxWindow* p)
: wxPanel (p)
break;
case Film::CONTENT:
{
- shared_ptr<DecodeOptions> o (new DecodeOptions);
- o->decode_audio = false;
- o->decode_subtitles = true;
- o->video_sync = false;
+ DecodeOptions o;
+ o.decode_audio = false;
+ o.decode_subtitles = true;
+ o.video_sync = false;
_decoders = decoder_factory (_film, o, 0);
_decoders.video->Video.connect (bind (&FilmViewer::process_video, this, _1, _2, _3));
_decoders.video->OutputChanged.connect (boost::bind (&FilmViewer::decoder_changed, this));
return;
}
- Size old_size;
+ libdcp::Size old_size;
if (_display_frame) {
old_size = _display_frame->size();
}
/* Get a compacted image as we have to feed it to wxWidgets */
- _display_frame = _raw_frame->scale_and_convert_to_rgb (Size (_out_width, _out_height), 0, _film->scaler(), false);
+ _display_frame = _raw_frame->scale_and_convert_to_rgb (libdcp::Size (_out_width, _out_height), 0, _film->scaler(), false);
if (old_size != _display_frame->size()) {
_clear_required = true;