ABTranscoder::ABTranscoder (shared_ptr<Film> a, shared_ptr<Film> b, shared_ptr<Job> j)
: _film_a (a)
, _film_b (b)
- , _playlist_a (_film_a->playlist ())
- , _playlist_b (_film_b->playlist ())
+ , _player_a (_film_a->player ())
+ , _player_b (_film_b->player ())
, _job (j)
- , _encoder (new Encoder (_film_a, _playlist_a))
+ , _encoder (new Encoder (_film_a))
, _combiner (new Combiner (a->log()))
{
- if (_playlist_a->has_audio ()) {
- _matcher.reset (new Matcher (_film_a->log(), _playlist_a->audio_frame_rate(), _playlist_a->video_frame_rate()));
- _delay_line.reset (new DelayLine (_film_a->log(), _playlist_a->audio_channels(), _film_a->audio_delay() * _playlist_a->audio_frame_rate() / 1000));
+ if (_film_a->has_audio ()) {
+ _matcher.reset (new Matcher (_film_a->log(), _film_a->audio_frame_rate(), _film_a->video_frame_rate()));
+ _delay_line.reset (new DelayLine (_film_a->log(), _film_a->audio_channels(), _film_a->audio_delay() * _film_a->audio_frame_rate() / 1000));
_gain.reset (new Gain (_film_a->log(), _film_a->audio_gain()));
}
- _playlist_a->Video.connect (bind (&Combiner::process_video, _combiner, _1, _2, _3));
- _playlist_b->Video.connect (bind (&Combiner::process_video_b, _combiner, _1, _2, _3));
+ _player_a->Video.connect (bind (&Combiner::process_video, _combiner, _1, _2, _3));
+ _player_b->Video.connect (bind (&Combiner::process_video_b, _combiner, _1, _2, _3));
if (_matcher) {
_combiner->connect_video (_matcher);
}
if (_matcher && _delay_line) {
- _playlist_a->connect_audio (_delay_line);
+ _player_a->connect_audio (_delay_line);
_delay_line->connect_audio (_matcher);
_matcher->connect_audio (_gain);
_gain->connect_audio (_encoder);
bool done[2] = { false, false };
while (1) {
- done[0] = _playlist_a->pass ();
- done[1] = _playlist_b->pass ();
+ done[0] = _player_a->pass ();
+ done[1] = _player_b->pass ();
if (_job) {
- _playlist_a->set_progress (_job);
+ _player_a->set_progress (_job);
}
if (done[0] && done[1]) {
class DelayLine;
class Gain;
class Combiner;
-class Playlist;
+class Player;
/** @class ABTranscoder
* @brief A transcoder which uses one Film for the left half of the screen, and a different one
private:
boost::shared_ptr<Film> _film_a;
boost::shared_ptr<Film> _film_b;
- boost::shared_ptr<Playlist> _playlist_a;
- boost::shared_ptr<Playlist> _playlist_b;
+ boost::shared_ptr<Player> _player_a;
+ boost::shared_ptr<Player> _player_b;
boost::shared_ptr<Job> _job;
boost::shared_ptr<Encoder> _encoder;
boost::shared_ptr<Combiner> _combiner;
void
AnalyseAudioJob::run ()
{
- shared_ptr<Playlist> playlist = _film->playlist ();
- playlist->disable_video ();
+ shared_ptr<Player> player = _film->player ();
+ player->disable_video ();
- playlist->Audio.connect (bind (&AnalyseAudioJob::audio, this, _1));
+ player->Audio.connect (bind (&AnalyseAudioJob::audio, this, _1));
- _samples_per_point = max (int64_t (1), playlist->audio_length() / _num_points);
+ _samples_per_point = max (int64_t (1), _film->audio_length() / _num_points);
- _current.resize (playlist->audio_channels ());
- _analysis.reset (new AudioAnalysis (playlist->audio_channels()));
+ _current.resize (_film->audio_channels ());
+ _analysis.reset (new AudioAnalysis (_film->audio_channels()));
- while (!playlist->pass()) {
- set_progress (float (_done) / playlist->audio_length ());
+ while (!player->pass()) {
+ set_progress (float (_done) / _film->audio_length ());
}
_analysis->write (_film->audio_analysis_path ());
using boost::optional;
using boost::shared_ptr;
-AudioDecoder::AudioDecoder (shared_ptr<const Film> f, shared_ptr<AudioContent> c)
+AudioDecoder::AudioDecoder (shared_ptr<const Film> f)
: Decoder (f)
{
class AudioDecoder : public AudioSource, public virtual Decoder
{
public:
- AudioDecoder (boost::shared_ptr<const Film>, boost::shared_ptr<AudioContent>);
+ AudioDecoder (boost::shared_ptr<const Film>);
};
#endif
int const Encoder::_history_size = 25;
/** @param f Film that we are encoding */
-Encoder::Encoder (shared_ptr<Film> f, shared_ptr<Playlist> p)
+Encoder::Encoder (shared_ptr<Film> f)
: _film (f)
- , _playlist (p)
, _video_frames_in (0)
, _video_frames_out (0)
#ifdef HAVE_SWRESAMPLE
void
Encoder::process_begin ()
{
- if (_playlist->has_audio() && _playlist->audio_frame_rate() != _film->target_audio_sample_rate()) {
+ if (_film->has_audio() && _film->audio_frame_rate() != _film->target_audio_sample_rate()) {
#ifdef HAVE_SWRESAMPLE
stringstream s;
- s << String::compose (N_("Will resample audio from %1 to %2"), _playlist->audio_frame_rate(), _film->target_audio_sample_rate());
+ s << String::compose (N_("Will resample audio from %1 to %2"), _film->audio_frame_rate(), _film->target_audio_sample_rate());
_film->log()->log (s.str ());
/* We will be using planar float data when we call the resampler */
_swr_context = swr_alloc_set_opts (
0,
- _playlist->audio_channel_layout(),
+ _film->audio_channel_layout(),
AV_SAMPLE_FMT_FLTP,
_film->target_audio_sample_rate(),
- _playlist->audio_channel_layout(),
+ _film->audio_channel_layout(),
AV_SAMPLE_FMT_FLTP,
- _playlist->audio_frame_rate(),
+ _film->audio_frame_rate(),
0, 0
);
}
}
- _writer.reset (new Writer (_film, _playlist));
+ _writer.reset (new Writer (_film));
}
Encoder::process_end ()
{
#if HAVE_SWRESAMPLE
- if (_playlist->has_audio() && _playlist->audio_channels() && _swr_context) {
+ if (_film->has_audio() && _film->audio_channels() && _swr_context) {
- shared_ptr<AudioBuffers> out (new AudioBuffers (_playlist->audio_channels(), 256));
+ shared_ptr<AudioBuffers> out (new AudioBuffers (_film->audio_channels(), 256));
while (1) {
int const frames = swr_convert (_swr_context, (uint8_t **) out->data(), 256, 0, 0);
void
Encoder::process_video (shared_ptr<Image> image, bool same, boost::shared_ptr<Subtitle> sub)
{
- FrameRateConversion frc (_playlist->video_frame_rate(), _film->dcp_frame_rate());
+ FrameRateConversion frc (_film->video_frame_rate(), _film->dcp_frame_rate());
if (frc.skip && (_video_frames_in % 2)) {
++_video_frames_in;
TIMING ("adding to queue of %1", _queue.size ());
_queue.push_back (boost::shared_ptr<DCPVideoFrame> (
new DCPVideoFrame (
- image, sub, _film->format()->dcp_size(), _film->format()->dcp_padding (_playlist),
+ image, sub, _film->format()->dcp_size(), _film->format()->dcp_padding (_film),
_film->subtitle_offset(), _film->subtitle_scale(),
_film->scaler(), _video_frames_out, _film->dcp_frame_rate(), s.second,
_film->colour_lut(), _film->j2k_bandwidth(),
if (_swr_context) {
/* Compute the resampled frames count and add 32 for luck */
- int const max_resampled_frames = ceil ((int64_t) data->frames() * _film->target_audio_sample_rate() / _playlist->audio_frame_rate()) + 32;
+ int const max_resampled_frames = ceil ((int64_t) data->frames() * _film->target_audio_sample_rate() / _film->audio_frame_rate()) + 32;
- shared_ptr<AudioBuffers> resampled (new AudioBuffers (_playlist->audio_channels(), max_resampled_frames));
+ shared_ptr<AudioBuffers> resampled (new AudioBuffers (_film->audio_channels(), max_resampled_frames));
/* Resample audio */
int const resampled_frames = swr_convert (
void
Encoder::write_audio (shared_ptr<const AudioBuffers> data)
{
- AudioMapping m (_playlist->audio_channels ());
- if (m.dcp_channels() != _playlist->audio_channels()) {
+ AudioMapping m (_film->audio_channels ());
+ if (m.dcp_channels() != _film->audio_channels()) {
/* Remap (currently just for mono -> 5.1) */
class DCPVideoFrame;
class EncodedData;
class Writer;
-class Playlist;
/** @class Encoder
* @brief Encoder to J2K and WAV for DCP.
class Encoder : public VideoSink, public AudioSink
{
public:
- Encoder (boost::shared_ptr<Film> f, boost::shared_ptr<Playlist>);
+ Encoder (boost::shared_ptr<Film> f);
virtual ~Encoder ();
/** Called to indicate that a processing run is about to begin */
/** Film that we are encoding */
boost::shared_ptr<Film> _film;
- boost::shared_ptr<Playlist> _playlist;
/** Mutex for _time_history and _last_frame */
mutable boost::mutex _history_mutex;
using boost::dynamic_pointer_cast;
using libdcp::Size;
-FFmpegDecoder::FFmpegDecoder (shared_ptr<const Film> f, shared_ptr<FFmpegContent> c, bool video, bool audio, bool subtitles, bool video_sync)
+FFmpegDecoder::FFmpegDecoder (shared_ptr<const Film> f, shared_ptr<const FFmpegContent> c, bool video, bool audio, bool subtitles, bool video_sync)
: Decoder (f)
- , VideoDecoder (f, c)
- , AudioDecoder (f, c)
+ , VideoDecoder (f)
+ , AudioDecoder (f)
, _ffmpeg_content (c)
, _format_context (0)
, _video_stream (-1)
class FFmpegDecoder : public VideoDecoder, public AudioDecoder
{
public:
- FFmpegDecoder (boost::shared_ptr<const Film>, boost::shared_ptr<FFmpegContent>, bool video, bool audio, bool subtitles, bool video_sync);
+ FFmpegDecoder (boost::shared_ptr<const Film>, boost::shared_ptr<const FFmpegContent>, bool video, bool audio, bool subtitles, bool video_sync);
~FFmpegDecoder ();
float frames_per_second () const;
std::string stream_name (AVStream* s) const;
- boost::shared_ptr<FFmpegContent> _ffmpeg_content;
+ boost::shared_ptr<const FFmpegContent> _ffmpeg_content;
AVFormatContext* _format_context;
int _video_stream;
*/
Film::Film (string d, bool must_exist)
- : _use_dci_name (true)
+ : _playlist (new Playlist)
+ , _use_dci_name (true)
, _trust_content_headers (true)
, _dcp_content_type (0)
, _format (0)
: boost::enable_shared_from_this<Film> (o)
/* note: the copied film shares the original's log */
, _log (o._log)
+ , _playlist (new Playlist)
, _directory (o._directory)
, _name (o._name)
, _use_dci_name (o._use_dci_name)
, _dcp_frame_rate (o._dcp_frame_rate)
, _dirty (o._dirty)
{
-
+ _playlist->setup (_content);
}
Film::~Film ()
int
Film::target_audio_sample_rate () const
{
- /* XXX: how often is this method called? */
-
- boost::shared_ptr<Playlist> p = playlist ();
- if (p->has_audio ()) {
+ if (has_audio ()) {
return 0;
}
/* Resample to a DCI-approved sample rate */
- double t = dcp_audio_sample_rate (p->audio_frame_rate());
+ double t = dcp_audio_sample_rate (audio_frame_rate());
- FrameRateConversion frc (p->video_frame_rate(), dcp_frame_rate());
+ FrameRateConversion frc (video_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
*/
if (frc.change_speed) {
- t *= p->video_frame_rate() * frc.factor() / dcp_frame_rate();
+ t *= video_frame_rate() * frc.factor() / dcp_frame_rate();
}
return rint (t);
return true;
}
-shared_ptr<Playlist>
-Film::playlist () const
+shared_ptr<Player>
+Film::player () const
{
boost::mutex::scoped_lock lm (_state_mutex);
- return shared_ptr<Playlist> (new Playlist (shared_from_this (), _content));
+ return shared_ptr<Player> (new Player (shared_from_this (), _playlist));
}
void
{
boost::mutex::scoped_lock lm (_state_mutex);
_content.push_back (c);
+ _playlist->setup (_content);
}
signal_changed (CONTENT);
examine_content (c);
}
+
+ContentAudioFrame
+Film::audio_length () const
+{
+ return _playlist->audio_length ();
+}
+
+int
+Film::audio_channels () const
+{
+ return _playlist->audio_channels ();
+}
+
+int
+Film::audio_frame_rate () const
+{
+ return _playlist->audio_frame_rate ();
+}
+
+int64_t
+Film::audio_channel_layout () const
+{
+ return _playlist->audio_channel_layout ();
+}
+
+bool
+Film::has_audio () const
+{
+ return _playlist->has_audio ();
+}
+
+float
+Film::video_frame_rate () const
+{
+ return _playlist->video_frame_rate ();
+}
+
+libdcp::Size
+Film::video_size () const
+{
+ return _playlist->video_size ();
+}
+
+ContentVideoFrame
+Film::video_length () const
+{
+ return _playlist->video_length ();
+}
+
class AnalyseAudioJob;
class ExternalAudioStream;
class Content;
+class Player;
class Playlist;
/** @class Film
bool have_dcp () const;
- boost::shared_ptr<Playlist> playlist () const;
+ boost::shared_ptr<Player> player () const;
+
+ ContentAudioFrame audio_length () const;
+ int audio_channels () const;
+ int audio_frame_rate () const;
+ int64_t audio_channel_layout () const;
+ bool has_audio () const;
+
+ float video_frame_rate () const;
+ libdcp::Size video_size () const;
+ ContentVideoFrame video_length () const;
/** Identifiers for the parts of our state;
used for signalling changes.
void analyse_audio_finished ();
std::string video_state_identifier () const;
+ boost::shared_ptr<Playlist> _playlist;
+
/** Complete path to directory containing the film metadata;
* must not be relative.
*/
* (so there are dcp_padding() pixels on the left and dcp_padding() on the right)
*/
int
-Format::dcp_padding (shared_ptr<const Playlist> p) const
+Format::dcp_padding (shared_ptr<const Film> f) const
{
- int pad = rint ((_dcp_size.width - (_dcp_size.height * ratio_as_integer(p) / 100.0)) / 2.0);
+ int pad = rint ((_dcp_size.width - (_dcp_size.height * ratio_as_integer(f) / 100.0)) / 2.0);
/* This comes out -ve for Scope; bodge it */
if (pad < 0) {
}
int
-VariableFormat::ratio_as_integer (shared_ptr<const Playlist> p) const
+VariableFormat::ratio_as_integer (shared_ptr<const Film> f) const
{
- return rint (ratio_as_float (p) * 100);
+ return rint (ratio_as_float (f) * 100);
}
float
-VariableFormat::ratio_as_float (shared_ptr<const Playlist> p) const
+VariableFormat::ratio_as_float (shared_ptr<const Film> f) const
{
- return float (p->video_size().width) / p->video_size().height;
+ return float (f->video_size().width) / f->video_size().height;
}
/** @return A name to be presented to the user */
#include <vector>
#include "util.h"
-class Playlist;
+class Film;
class Format
{
/** @return the aspect ratio multiplied by 100
* (e.g. 239 for Cinemascope 2.39:1)
*/
- virtual int ratio_as_integer (boost::shared_ptr<const Playlist> f) const = 0;
+ virtual int ratio_as_integer (boost::shared_ptr<const Film> f) const = 0;
/** @return the ratio as a floating point number */
- virtual float ratio_as_float (boost::shared_ptr<const Playlist> f) const = 0;
+ virtual float ratio_as_float (boost::shared_ptr<const Film> f) const = 0;
/** @return the ratio of the container (including any padding) as a floating point number */
float container_ratio_as_float () const;
- int dcp_padding (boost::shared_ptr<const Playlist>) const;
+ int dcp_padding (boost::shared_ptr<const Film>) const;
/** @return size in pixels of the images that we should
* put in a DCP for this ratio. This size will not correspond
public:
FixedFormat (int, libdcp::Size, std::string, std::string, std::string, std::string);
- int ratio_as_integer (boost::shared_ptr<const Playlist>) const {
+ int ratio_as_integer (boost::shared_ptr<const Film>) const {
return _ratio;
}
- float ratio_as_float (boost::shared_ptr<const Playlist>) const {
+ float ratio_as_float (boost::shared_ptr<const Film>) const {
return _ratio / 100.0;
}
public:
VariableFormat (libdcp::Size, std::string, std::string, std::string, std::string);
- int ratio_as_integer (boost::shared_ptr<const Playlist> f) const;
- float ratio_as_float (boost::shared_ptr<const Playlist> f) const;
+ int ratio_as_integer (boost::shared_ptr<const Film> f) const;
+ float ratio_as_float (boost::shared_ptr<const Film> f) const;
std::string name () const;
};
using boost::shared_ptr;
using libdcp::Size;
-ImageMagickDecoder::ImageMagickDecoder (shared_ptr<const Film> f, shared_ptr<ImageMagickContent> c)
+ImageMagickDecoder::ImageMagickDecoder (shared_ptr<const Film> f, shared_ptr<const ImageMagickContent> c)
: Decoder (f)
- , VideoDecoder (f, c)
+ , VideoDecoder (f)
, _imagemagick_content (c)
, _position (0)
{
class ImageMagickDecoder : public VideoDecoder
{
public:
- ImageMagickDecoder (boost::shared_ptr<const Film>, boost::shared_ptr<ImageMagickContent>);
+ ImageMagickDecoder (boost::shared_ptr<const Film>, boost::shared_ptr<const ImageMagickContent>);
float frames_per_second () const {
/* We don't know */
private:
void film_changed (Film::Property);
- boost::shared_ptr<ImageMagickContent> _imagemagick_content;
+ boost::shared_ptr<const ImageMagickContent> _imagemagick_content;
ContentVideoFrame _position;
};
using boost::shared_ptr;
using boost::dynamic_pointer_cast;
-Playlist::Playlist (shared_ptr<const Film> f, list<shared_ptr<Content> > c)
- : _film (f)
- , _video_from (VIDEO_NONE)
+Playlist::Playlist ()
+ : _video_from (VIDEO_NONE)
, _audio_from (AUDIO_NONE)
- , _have_setup_decoders (false)
- , _ffmpeg_decoder_done (false)
- , _video_sync (true)
{
- for (list<shared_ptr<Content> >::const_iterator i = c.begin(); i != c.end(); ++i) {
+
+}
+
+void
+Playlist::setup (list<shared_ptr<Content> > content)
+{
+ _video_from = VIDEO_NONE;
+ _audio_from = AUDIO_NONE;
+
+ for (list<shared_ptr<Content> >::const_iterator i = content.begin(); i != content.end(); ++i) {
shared_ptr<FFmpegContent> fc = dynamic_pointer_cast<FFmpegContent> (*i);
if (fc) {
assert (!_ffmpeg);
case AUDIO_SNDFILE:
{
ContentAudioFrame l = 0;
- for (list<shared_ptr<SndfileContent> >::const_iterator i = _sndfile.begin(); i != _sndfile.end(); ++i) {
+ for (list<shared_ptr<const SndfileContent> >::const_iterator i = _sndfile.begin(); i != _sndfile.end(); ++i) {
l += (*i)->audio_length ();
}
return l;
case AUDIO_SNDFILE:
{
int c = 0;
- for (list<shared_ptr<SndfileContent> >::const_iterator i = _sndfile.begin(); i != _sndfile.end(); ++i) {
+ for (list<shared_ptr<const SndfileContent> >::const_iterator i = _sndfile.begin(); i != _sndfile.end(); ++i) {
c += (*i)->audio_channels ();
}
return c;
case VIDEO_IMAGEMAGICK:
{
ContentVideoFrame l = 0;
- for (list<shared_ptr<ImageMagickContent> >::const_iterator i = _imagemagick.begin(); i != _imagemagick.end(); ++i) {
+ for (list<shared_ptr<const ImageMagickContent> >::const_iterator i = _imagemagick.begin(); i != _imagemagick.end(); ++i) {
l += (*i)->video_length ();
}
return l;
{
return _audio_from != AUDIO_NONE;
}
+
+Player::Player (boost::shared_ptr<const Film> f, boost::shared_ptr<const Playlist> p)
+ : _film (f)
+ , _playlist (p)
+ , _video (true)
+ , _audio (true)
+ , _subtitles (true)
+ , _have_setup_decoders (false)
+ , _ffmpeg_decoder_done (false)
+ , _video_sync (true)
+{
+
+}
void
-Playlist::disable_video ()
+Player::disable_video ()
{
- _video_from = VIDEO_NONE;
+ _video = false;
}
void
-Playlist::disable_audio ()
+Player::disable_audio ()
{
- _audio_from = AUDIO_NONE;
+ _audio = false;
}
void
-Playlist::disable_subtitles ()
+Player::disable_subtitles ()
{
- /* XXX */
+ _subtitles = false;
}
bool
-Playlist::pass ()
+Player::pass ()
{
if (!_have_setup_decoders) {
setup_decoders ();
bool done = true;
- if (_video_from == VIDEO_FFMPEG || _audio_from == AUDIO_FFMPEG) {
+ if (_playlist->video_from() == Playlist::VIDEO_FFMPEG || _playlist->audio_from() == Playlist::AUDIO_FFMPEG) {
if (!_ffmpeg_decoder_done) {
if (_ffmpeg_decoder->pass ()) {
_ffmpeg_decoder_done = true;
}
}
- if (_video_from == VIDEO_IMAGEMAGICK) {
+ if (_playlist->video_from() == Playlist::VIDEO_IMAGEMAGICK) {
if (_imagemagick_decoder != _imagemagick_decoders.end ()) {
if ((*_imagemagick_decoder)->pass ()) {
_imagemagick_decoder++;
}
void
-Playlist::set_progress (shared_ptr<Job> job)
+Player::set_progress (shared_ptr<Job> job)
{
/* XXX */
}
void
-Playlist::process_video (shared_ptr<Image> i, bool same, shared_ptr<Subtitle> s)
+Player::process_video (shared_ptr<Image> i, bool same, shared_ptr<Subtitle> s)
{
Video (i, same, s);
}
void
-Playlist::process_audio (shared_ptr<AudioBuffers> b)
+Player::process_audio (shared_ptr<AudioBuffers> b)
{
Audio (b);
}
bool
-Playlist::seek (double t)
+Player::seek (double t)
{
bool r = false;
- switch (_video_from) {
- case VIDEO_NONE:
+ switch (_playlist->video_from()) {
+ case Playlist::VIDEO_NONE:
break;
- case VIDEO_FFMPEG:
+ case Playlist::VIDEO_FFMPEG:
if (_ffmpeg_decoder->seek (t)) {
r = true;
}
break;
- case VIDEO_IMAGEMAGICK:
+ case Playlist::VIDEO_IMAGEMAGICK:
if ((*_imagemagick_decoder)->seek (t)) {
r = true;
}
}
bool
-Playlist::seek_to_last ()
+Player::seek_to_last ()
{
bool r = false;
- switch (_video_from) {
- case VIDEO_NONE:
+ switch (_playlist->video_from ()) {
+ case Playlist::VIDEO_NONE:
break;
- case VIDEO_FFMPEG:
+ case Playlist::VIDEO_FFMPEG:
if (_ffmpeg_decoder->seek_to_last ()) {
r = true;
}
break;
- case VIDEO_IMAGEMAGICK:
+ case Playlist::VIDEO_IMAGEMAGICK:
if ((*_imagemagick_decoder)->seek_to_last ()) {
r = true;
}
}
void
-Playlist::setup_decoders ()
+Player::setup_decoders ()
{
- if (_video_from == VIDEO_FFMPEG || _audio_from == AUDIO_FFMPEG) {
+ if ((_video && _playlist->video_from() == Playlist::VIDEO_FFMPEG) || (_audio && _playlist->audio_from() == Playlist::AUDIO_FFMPEG)) {
_ffmpeg_decoder.reset (
new FFmpegDecoder (
- _film, _ffmpeg, _video_from == VIDEO_FFMPEG, _audio_from == AUDIO_FFMPEG, _film->with_subtitles(), _video_sync
+ _film,
+ _playlist->ffmpeg(),
+ _video && _playlist->video_from() == Playlist::VIDEO_FFMPEG,
+ _audio && _playlist->audio_from() == Playlist::AUDIO_FFMPEG,
+ _subtitles && _film->with_subtitles(),
+ _video_sync
)
);
}
- if (_video_from == VIDEO_FFMPEG) {
+ if (_video && _playlist->video_from() == Playlist::VIDEO_FFMPEG) {
_ffmpeg_decoder->connect_video (shared_from_this ());
}
- if (_audio_from == AUDIO_FFMPEG) {
+ if (_audio && _playlist->audio_from() == Playlist::AUDIO_FFMPEG) {
_ffmpeg_decoder->connect_audio (shared_from_this ());
}
- if (_video_from == VIDEO_IMAGEMAGICK) {
- for (list<shared_ptr<ImageMagickContent> >::iterator i = _imagemagick.begin(); i != _imagemagick.end(); ++i) {
+ if (_video && _playlist->video_from() == Playlist::VIDEO_IMAGEMAGICK) {
+ list<shared_ptr<const ImageMagickContent> > ic = _playlist->imagemagick ();
+ for (list<shared_ptr<const ImageMagickContent> >::iterator i = ic.begin(); i != ic.end(); ++i) {
shared_ptr<ImageMagickDecoder> d (new ImageMagickDecoder (_film, *i));
_imagemagick_decoders.push_back (d);
d->connect_video (shared_from_this ());
_imagemagick_decoder = _imagemagick_decoders.begin ();
}
- if (_audio_from == AUDIO_SNDFILE) {
- for (list<shared_ptr<SndfileContent> >::iterator i = _sndfile.begin(); i != _sndfile.end(); ++i) {
+ if (_audio && _playlist->audio_from() == Playlist::AUDIO_SNDFILE) {
+ list<shared_ptr<const SndfileContent> > sc = _playlist->sndfile ();
+ for (list<shared_ptr<const SndfileContent> >::iterator i = sc.begin(); i != sc.end(); ++i) {
shared_ptr<SndfileDecoder> d (new SndfileDecoder (_film, *i));
_sndfile_decoders.push_back (d);
d->connect_audio (shared_from_this ());
}
void
-Playlist::disable_video_sync ()
+Player::disable_video_sync ()
{
_video_sync = false;
}
+
+double
+Player::last_video_time () const
+{
+ switch (_playlist->video_from ()) {
+ case Playlist::VIDEO_NONE:
+ return 0;
+ case Playlist::VIDEO_FFMPEG:
+ return _ffmpeg_decoder->last_source_time ();
+ case Playlist::VIDEO_IMAGEMAGICK:
+ return (*_imagemagick_decoder)->last_source_time ();
+ }
+
+ return 0;
+}
class Job;
class Film;
-class Playlist : public VideoSource, public AudioSource, public VideoSink, public AudioSink, public boost::enable_shared_from_this<Playlist>
+class Playlist
{
public:
- Playlist (boost::shared_ptr<const Film>, std::list<boost::shared_ptr<Content> >);
+ Playlist ();
+
+ void setup (std::list<boost::shared_ptr<Content> >);
ContentAudioFrame audio_length () const;
int audio_channels () const;
libdcp::Size video_size () const;
ContentVideoFrame video_length () const;
+ enum VideoFrom {
+ VIDEO_NONE,
+ VIDEO_FFMPEG,
+ VIDEO_IMAGEMAGICK
+ };
+
+ enum AudioFrom {
+ AUDIO_NONE,
+ AUDIO_FFMPEG,
+ AUDIO_SNDFILE
+ };
+
+ VideoFrom video_from () const {
+ return _video_from;
+ }
+
+ AudioFrom audio_from () const {
+ return _audio_from;
+ }
+
+ boost::shared_ptr<const FFmpegContent> ffmpeg () const {
+ return _ffmpeg;
+ }
+
+ std::list<boost::shared_ptr<const ImageMagickContent> > imagemagick () const {
+ return _imagemagick;
+ }
+
+ std::list<boost::shared_ptr<const SndfileContent> > sndfile () const {
+ return _sndfile;
+ }
+
+private:
+ VideoFrom _video_from;
+ AudioFrom _audio_from;
+
+ boost::shared_ptr<const FFmpegContent> _ffmpeg;
+ std::list<boost::shared_ptr<const ImageMagickContent> > _imagemagick;
+ std::list<boost::shared_ptr<const SndfileContent> > _sndfile;
+};
+
+class Player : public VideoSource, public AudioSource, public VideoSink, public AudioSink, public boost::enable_shared_from_this<Player>
+{
+public:
+ Player (boost::shared_ptr<const Film>, boost::shared_ptr<const Playlist>);
+
void disable_video ();
void disable_audio ();
void disable_subtitles ();
bool seek (double);
bool seek_to_last ();
+ double last_video_time () const;
+
private:
void process_video (boost::shared_ptr<Image> i, bool same, boost::shared_ptr<Subtitle> s);
void process_audio (boost::shared_ptr<AudioBuffers>);
void setup_decoders ();
-
- boost::shared_ptr<const Film> _film;
- enum {
- VIDEO_NONE,
- VIDEO_FFMPEG,
- VIDEO_IMAGEMAGICK
- } _video_from;
+ boost::shared_ptr<const Film> _film;
+ boost::shared_ptr<const Playlist> _playlist;
+
+ bool _video;
+ bool _audio;
+ bool _subtitles;
- enum {
- AUDIO_NONE,
- AUDIO_FFMPEG,
- AUDIO_SNDFILE
- } _audio_from;
-
- boost::shared_ptr<FFmpegContent> _ffmpeg;
- std::list<boost::shared_ptr<ImageMagickContent> > _imagemagick;
- std::list<boost::shared_ptr<SndfileContent> > _sndfile;
-
bool _have_setup_decoders;
boost::shared_ptr<FFmpegDecoder> _ffmpeg_decoder;
bool _ffmpeg_decoder_done;
/* XXX */
-SndfileDecoder::SndfileDecoder (shared_ptr<const Film> f, shared_ptr<SndfileContent> c)
+SndfileDecoder::SndfileDecoder (shared_ptr<const Film> f, shared_ptr<const SndfileContent> c)
: Decoder (f)
- , AudioDecoder (f, c)
+ , AudioDecoder (f)
{
sf_count_t frames;
SNDFILE* sf = open_file (frames);
class SndfileDecoder : public AudioDecoder
{
public:
- SndfileDecoder (boost::shared_ptr<const Film>, boost::shared_ptr<SndfileContent>);
+ SndfileDecoder (boost::shared_ptr<const Film>, boost::shared_ptr<const SndfileContent>);
bool pass ();
SNDFILE* open_file (sf_count_t &);
void close_file (SNDFILE*);
- boost::shared_ptr<SndfileContent> _sndfile_content;
+ boost::shared_ptr<const SndfileContent> _sndfile_content;
};
*/
Transcoder::Transcoder (shared_ptr<Film> f, shared_ptr<Job> j)
: _job (j)
- , _playlist (f->playlist ())
- , _encoder (new Encoder (f, _playlist))
+ , _player (f->player ())
+ , _encoder (new Encoder (f))
{
- if (_playlist->has_audio ()) {
- _matcher.reset (new Matcher (f->log(), _playlist->audio_frame_rate(), _playlist->video_frame_rate()));
- _delay_line.reset (new DelayLine (f->log(), _playlist->audio_channels(), f->audio_delay() * _playlist->audio_frame_rate() / 1000));
+ if (f->has_audio ()) {
+ _matcher.reset (new Matcher (f->log(), f->audio_frame_rate(), f->video_frame_rate()));
+ _delay_line.reset (new DelayLine (f->log(), f->audio_channels(), f->audio_delay() * f->audio_frame_rate() / 1000));
_gain.reset (new Gain (f->log(), f->audio_gain()));
}
if (_matcher) {
- _playlist->connect_video (_matcher);
+ _player->connect_video (_matcher);
_matcher->connect_video (_encoder);
} else {
- _playlist->connect_video (_encoder);
+ _player->connect_video (_encoder);
}
- if (_matcher && _delay_line && _playlist->has_audio ()) {
- _playlist->connect_audio (_delay_line);
+ if (_matcher && _delay_line && f->has_audio ()) {
+ _player->connect_audio (_delay_line);
_delay_line->connect_audio (_matcher);
_matcher->connect_audio (_gain);
_gain->connect_audio (_encoder);
_encoder->process_begin ();
try {
while (1) {
- if (_playlist->pass ()) {
+ if (_player->pass ()) {
break;
}
- _playlist->set_progress (_job);
+ _player->set_progress (_job);
}
} catch (...) {
class VideoFilter;
class Gain;
class DelayLine;
-class Playlist;
+class Player;
/** @class Transcoder
*
protected:
/** A Job that is running this Transcoder, or 0 */
boost::shared_ptr<Job> _job;
- boost::shared_ptr<Playlist> _playlist;
+ boost::shared_ptr<Player> _player;
boost::shared_ptr<Encoder> _encoder;
boost::shared_ptr<Matcher> _matcher;
boost::shared_ptr<DelayLine> _delay_line;
using boost::shared_ptr;
using boost::optional;
-VideoDecoder::VideoDecoder (shared_ptr<const Film> f, shared_ptr<VideoContent> c)
+VideoDecoder::VideoDecoder (shared_ptr<const Film> f)
: Decoder (f)
, _video_frame (0)
, _last_source_time (0)
{
assert (j);
-#if 0
- XXX
- if (_film->length()) {
- j->set_progress (float (_video_frame) / _film->length().get());
+ if (_film->video_length()) {
+ j->set_progress (float (_video_frame) / _film->video_length());
}
-#endif
}
class VideoDecoder : public VideoSource, public virtual Decoder
{
public:
- VideoDecoder (boost::shared_ptr<const Film>, boost::shared_ptr<VideoContent>);
+ VideoDecoder (boost::shared_ptr<const Film>);
/** @return video frames per second, or 0 if unknown */
virtual float frames_per_second () const = 0;
int const Writer::_maximum_frames_in_memory = 8;
-Writer::Writer (shared_ptr<Film> f, shared_ptr<Playlist> p)
+Writer::Writer (shared_ptr<Film> f)
: _film (f)
- , _playlist (p)
, _first_nonexistant_frame (0)
, _thread (0)
, _finish (false)
_picture_asset_writer = _picture_asset->start_write (_first_nonexistant_frame > 0);
- AudioMapping m (_playlist->audio_channels ());
+ AudioMapping m (_film->audio_channels ());
if (m.dcp_channels() > 0) {
_sound_asset.reset (
N_("audio.mxf"),
_film->dcp_frame_rate (),
m.dcp_channels (),
- dcp_audio_sample_rate (_playlist->audio_frame_rate())
+ dcp_audio_sample_rate (_film->audio_frame_rate())
)
);
class Film;
class EncodedData;
class AudioBuffers;
-class Playlist;
namespace libdcp {
class MonoPictureAsset;
class Writer : public ExceptionStore
{
public:
- Writer (boost::shared_ptr<Film>, boost::shared_ptr<Playlist>);
+ Writer (boost::shared_ptr<Film>);
bool can_fake_write (int) const;
/** our Film */
boost::shared_ptr<Film> _film;
- boost::shared_ptr<Playlist> _playlist;
/** the first frame index that does not already exist in our MXF */
int _first_nonexistant_frame;
server = new ServerDescription (server_host, 1);
shared_ptr<Film> film (new Film (film_dir, true));
- shared_ptr<Playlist> playlist = film->playlist ();
- playlist->disable_audio ();
+ shared_ptr<Player> player = film->player ();
+ player->disable_audio ();
try {
- playlist->Video.connect (boost::bind (process_video, _1, _2, _3));
+ player->Video.connect (boost::bind (process_video, _1, _2, _3));
bool done = false;
while (!done) {
- done = playlist->pass ();
+ done = player->pass ();
}
} catch (std::exception& e) {
cerr << "Error: " << e.what() << "\n";
#include <boost/filesystem.hpp>
#include "lib/audio_analysis.h"
#include "lib/film.h"
-#include "lib/playlist.h"
#include "audio_dialog.h"
#include "audio_plot.h"
#include "wx_util.h"
_film_audio_analysis_succeeded_connection.disconnect ();
_film = f;
- _playlist = _film->playlist ();
try_to_load_analysis ();
setup_channels ();
void
AudioDialog::setup_channels ()
{
- if (!_playlist->has_audio()) {
+ if (!_film->has_audio()) {
return;
}
- AudioMapping m (_playlist->audio_channels ());
+ AudioMapping m (_film->audio_channels ());
for (int i = 0; i < MAX_AUDIO_CHANNELS; ++i) {
if (m.dcp_to_source(static_cast<libdcp::Channel>(i))) {
_plot->set_analysis (a);
- AudioMapping m (_playlist->audio_channels ());
+ AudioMapping m (_film->audio_channels ());
optional<libdcp::Channel> c = m.source_to_dcp (0);
if (c) {
_channel_checkbox[c.get()]->SetValue (true);
assert (c < MAX_AUDIO_CHANNELS);
- AudioMapping m (_playlist->audio_channels ());
+ AudioMapping m (_film->audio_channels ());
optional<int> s = m.dcp_to_source (static_cast<libdcp::Channel> (c));
if (s) {
_plot->set_channel_visible (s.get(), _channel_checkbox[c]->GetValue ());
_plot->set_gain (_film->audio_gain ());
break;
case Film::CONTENT:
- _playlist = _film->playlist ();
setup_channels ();
break;
default:
class AudioPlot;
class Film;
-class Playlist;
class AudioDialog : public wxDialog
{
void setup_channels ();
boost::shared_ptr<Film> _film;
- boost::shared_ptr<Playlist> _playlist;
AudioPlot* _plot;
wxCheckBox* _channel_checkbox[MAX_AUDIO_CHANNELS];
wxCheckBox* _type_checkbox[AudioPoint::COUNT];
break;
case Film::CONTENT:
{
- _playlist = _film->playlist ();
- _playlist->disable_audio ();
- _playlist->disable_subtitles ();
- _playlist->disable_video_sync ();
+ _player = _film->player ();
+ _player->disable_audio ();
+ _player->disable_subtitles ();
+ _player->disable_video_sync ();
- _playlist->Video.connect (bind (&FilmViewer::process_video, this, _1, _2, _3));
-// _playlist->OutputChanged.connect (boost::bind (&FilmViewer::decoder_changed, this));
+ _player->Video.connect (bind (&FilmViewer::process_video, this, _1, _2, _3));
+// _player->OutputChanged.connect (boost::bind (&FilmViewer::decoder_changed, this));
calculate_sizes ();
get_frame ();
_panel->Refresh ();
void
FilmViewer::decoder_changed ()
{
- if (!_playlist == 0 || _playlist->seek_to_last ()) {
+ if (!_player || _player->seek_to_last ()) {
return;
}
void
FilmViewer::timer (wxTimerEvent &)
{
- if (!_playlist) {
+ if (!_player) {
return;
}
get_frame ();
-// if (_playlist->video_length()) {
-// int const new_slider_position = 4096 * _playlist->last_source_time() / (_film->length().get() / _film->source_frame_rate());
-// if (new_slider_position != _slider->GetValue()) {
-// _slider->SetValue (new_slider_position);
-// }
-// }
+ if (_film->video_length()) {
+ int const new_slider_position = 4096 * _player->last_video_time() / (_film->video_length() / _film->video_frame_rate());
+ if (new_slider_position != _slider->GetValue()) {
+ _slider->SetValue (new_slider_position);
+ }
+ }
}
void
FilmViewer::slider_moved (wxScrollEvent &)
{
- if (!_film || !_playlist) {
+ if (!_film || !_player) {
return;
}
- if (_playlist->seek (_slider->GetValue() * _playlist->video_length() / (4096 * _playlist->video_frame_rate()))) {
+ if (_player->seek (_slider->GetValue() * _film->video_length() / (4096 * _film->video_frame_rate()))) {
return;
}
void
FilmViewer::calculate_sizes ()
{
- if (!_film || !_playlist) {
+ if (!_film || !_player) {
return;
}
*/
_display_frame_x = 0;
if (format) {
- _display_frame_x = static_cast<float> (format->dcp_padding (_playlist)) * _out_size.width / format->dcp_size().width;
+ _display_frame_x = static_cast<float> (format->dcp_padding (_film)) * _out_size.width / format->dcp_size().width;
}
_film_size = _out_size;
/* Clear our raw frame in case we don't get a new one */
_raw_frame.reset ();
- if (!_playlist) {
+ if (!_player) {
_display_frame.reset ();
return;
}
try {
_got_frame = false;
while (!_got_frame) {
- if (_playlist->pass ()) {
+ if (_player->pass ()) {
/* We didn't get a frame before the decoder gave up,
so clear our display frame.
*/
void active_jobs_changed (bool);
boost::shared_ptr<Film> _film;
- boost::shared_ptr<Playlist> _playlist;
+ boost::shared_ptr<Player> _player;
wxSizer* _v_sizer;
wxPanel* _panel;
if not conf.options.static:
conf.check_cfg(package = 'libdcp', atleast_version = '0.41', args = '--cflags --libs', uselib_store = 'DCP', mandatory = True)
+ conf.check_cfg(package = 'libcxml', atleast_version = '0.01', args = '--cflags --libs', uselib_store = 'CXML', mandatory = True)
conf.check_cfg(package = 'libavformat', args = '--cflags --libs', uselib_store = 'AVFORMAT', mandatory = True)
conf.check_cfg(package = 'libavfilter', args = '--cflags --libs', uselib_store = 'AVFILTER', mandatory = True)
conf.check_cfg(package = 'libavcodec', args = '--cflags --libs', uselib_store = 'AVCODEC', mandatory = True)
conf.env.HAVE_DCP = 1
conf.env.STLIB_DCP = ['dcp', 'asdcp-libdcp', 'kumu-libdcp']
conf.env.LIB_DCP = ['glibmm-2.4', 'xml++-2.6', 'ssl', 'crypto', 'bz2']
+ conf.env.HAVE_CXML = 1
+ conf.env.STLIB_CXML = ['cxml']
conf.env.HAVE_AVFORMAT = 1
conf.env.STLIB_AVFORMAT = ['avformat']
conf.env.HAVE_AVFILTER = 1