diff options
Diffstat (limited to 'src/lib/player.cc')
| -rw-r--r-- | src/lib/player.cc | 159 |
1 files changed, 116 insertions, 43 deletions
diff --git a/src/lib/player.cc b/src/lib/player.cc index cd1c54d5b..79f1c3b97 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -32,12 +32,16 @@ #include "null_content.h" #include "black_decoder.h" #include "silence_decoder.h" +#include "ratio.h" +#include "resampler.h" using std::list; using std::cout; using std::min; using std::max; using std::vector; +using std::pair; +using std::map; using boost::shared_ptr; using boost::weak_ptr; using boost::dynamic_pointer_cast; @@ -49,10 +53,12 @@ struct Piece Piece (shared_ptr<Content> c, shared_ptr<Decoder> d) : content (c) , decoder (d) + , last_emission (0) {} shared_ptr<Content> content; shared_ptr<Decoder> decoder; + Time last_emission; }; @@ -125,13 +131,8 @@ Player::pass () continue; } - if (!_audio && dynamic_pointer_cast<AudioDecoder> ((*i)->decoder) && !dynamic_pointer_cast<VideoDecoder> ((*i)->decoder)) { - continue; - } - - Time const t = (*i)->content->start() + (*i)->decoder->position(); - if (t < earliest_t) { - earliest_t = t; + if ((*i)->last_emission < earliest_t) { + earliest_t = (*i)->last_emission; earliest = *i; } } @@ -142,39 +143,106 @@ Player::pass () } earliest->decoder->pass (); - _position = earliest->content->start() + earliest->decoder->position (); + _position = earliest->last_emission; return false; } void -Player::process_video (weak_ptr<Content> weak_content, shared_ptr<const Image> image, bool same, Time time) +Player::process_video (weak_ptr<Piece> weak_piece, shared_ptr<const Image> image, bool same, VideoContent::Frame frame) { - shared_ptr<Content> content = weak_content.lock (); - if (!content) { + shared_ptr<Piece> piece = weak_piece.lock (); + if (!piece) { + return; + } + + shared_ptr<VideoContent> content = dynamic_pointer_cast<VideoContent> (piece->content); + assert (content); + + FrameRateConversion frc (content->video_frame_rate(), _film->dcp_video_frame_rate()); + if (frc.skip && (frame % 2) == 1) { return; } + + image = image->crop (content->crop(), true); + + libdcp::Size const container_size = _video_container_size.get_value_or (_film->container()->size (_film->full_frame ())); + libdcp::Size const image_size = content->ratio()->size (container_size); - time += content->start (); + image = image->scale_and_convert_to_rgb (image_size, _film->scaler(), true); + +#if 0 + if (film->with_subtitles ()) { + shared_ptr<Subtitle> sub; + if (_timed_subtitle && _timed_subtitle->displayed_at (t)) { + sub = _timed_subtitle->subtitle (); + } + + if (sub) { + dcpomatic::Rect const tx = subtitle_transformed_area ( + float (image_size.width) / content->video_size().width, + float (image_size.height) / content->video_size().height, + sub->area(), film->subtitle_offset(), film->subtitle_scale() + ); + + shared_ptr<Image> im = sub->image()->scale (tx.size(), film->scaler(), true); + image->alpha_blend (im, tx.position()); + } + } +#endif + + if (image_size != container_size) { + assert (image_size.width <= container_size.width); + assert (image_size.height <= container_size.height); + shared_ptr<Image> im (new SimpleImage (PIX_FMT_RGB24, container_size, true)); + im->make_black (); + im->copy (image, Position ((container_size.width - image_size.width) / 2, (container_size.height - image_size.height) / 2)); + image = im; + } + + Time time = content->start() + (frame * frc.factor() * TIME_HZ / _film->dcp_video_frame_rate()); Video (image, same, time); + + if (frc.repeat) { + time += TIME_HZ / _film->dcp_video_frame_rate(); + Video (image, true, time); + } + + piece->last_emission = min (piece->last_emission, time); } void -Player::process_audio (weak_ptr<Content> weak_content, shared_ptr<const AudioBuffers> audio, Time time) +Player::process_audio (weak_ptr<Piece> weak_piece, shared_ptr<const AudioBuffers> audio, AudioContent::Frame frame) { - shared_ptr<Content> content = weak_content.lock (); - if (!content) { + shared_ptr<Piece> piece = weak_piece.lock (); + if (!piece) { return; } - + + shared_ptr<AudioContent> content = dynamic_pointer_cast<AudioContent> (piece->content); + assert (content); + + if (content->content_audio_frame_rate() != content->output_audio_frame_rate()) { + audio = resampler(content)->run (audio); + } + + /* Remap channels */ + shared_ptr<AudioBuffers> dcp_mapped (new AudioBuffers (_film->dcp_audio_channels(), audio->frames())); + dcp_mapped->make_silent (); + list<pair<int, libdcp::Channel> > map = content->audio_mapping().content_to_dcp (); + for (list<pair<int, libdcp::Channel> >::iterator i = map.begin(); i != map.end(); ++i) { + dcp_mapped->accumulate_channel (audio.get(), i->first, i->second); + } + /* The time of this audio may indicate that some of our buffered audio is not going to be added to any more, so it can be emitted. */ - time += content->start (); + Time const time = content->start() + (frame * TIME_HZ / _film->dcp_audio_frame_rate()); + piece->last_emission = min (piece->last_emission, time); - cout << "Player gets " << audio->frames() << " @ " << time << " cf " << _next_audio << "\n"; + cout << "Player gets " << dcp_mapped->frames() << " @ " << time << " cf " << _next_audio << "\n"; if (time > _next_audio) { /* We can emit some audio from our buffers */ @@ -224,10 +292,18 @@ Player::seek (Time t) } for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) { - Time s = t - (*i)->content->start (); + shared_ptr<VideoContent> vc = dynamic_pointer_cast<VideoContent> ((*i)->content); + if (!vc) { + continue; + } + + Time s = t - vc->start (); s = max (static_cast<Time> (0), s); - s = min ((*i)->content->length(), s); - (*i)->decoder->seek (s); + s = min (vc->length(), s); + + FrameRateConversion frc (vc->video_frame_rate(), _film->dcp_video_frame_rate()); + VideoContent::Frame f = s * _film->dcp_video_frame_rate() / (frc.factor() * TIME_HZ); + dynamic_pointer_cast<VideoDecoder>((*i)->decoder)->seek (f); } /* XXX: don't seek audio because we don't need to... */ @@ -241,19 +317,14 @@ Player::seek_back () } void -Player::seek_forward () -{ - -} - -void Player::add_black_piece (Time s, Time len) { shared_ptr<NullContent> nc (new NullContent (_film, s, len)); nc->set_ratio (_film->container ()); shared_ptr<BlackDecoder> bd (new BlackDecoder (_film, nc)); - bd->Video.connect (bind (&Player::process_video, this, nc, _1, _2, _3)); - _pieces.push_back (shared_ptr<Piece> (new Piece (nc, bd))); + shared_ptr<Piece> p (new Piece (nc, bd)); + _pieces.push_back (p); + bd->Video.connect (bind (&Player::process_video, this, p, _1, _2, _3)); } void @@ -261,8 +332,9 @@ Player::add_silent_piece (Time s, Time len) { shared_ptr<NullContent> nc (new NullContent (_film, s, len)); shared_ptr<SilenceDecoder> sd (new SilenceDecoder (_film, nc)); - sd->Audio.connect (bind (&Player::process_audio, this, nc, _1, _2)); - _pieces.push_back (shared_ptr<Piece> (new Piece (nc, sd))); + shared_ptr<Piece> p (new Piece (nc, sd)); + _pieces.push_back (p); + sd->Audio.connect (bind (&Player::process_audio, this, p, _1, _2)); } @@ -279,7 +351,7 @@ Player::setup_pieces () for (Playlist::ContentList::iterator i = content.begin(); i != content.end(); ++i) { shared_ptr<Decoder> decoder; - + /* XXX: into content? */ shared_ptr<const FFmpegContent> fc = dynamic_pointer_cast<const FFmpegContent> (*i); @@ -288,9 +360,6 @@ Player::setup_pieces () fd->Video.connect (bind (&Player::process_video, this, *i, _1, _2, _3)); fd->Audio.connect (bind (&Player::process_audio, this, *i, _1, _2)); - if (_video_container_size) { - fd->set_video_container_size (_video_container_size.get ()); - } decoder = fd; } @@ -310,9 +379,6 @@ Player::setup_pieces () if (!id) { id.reset (new ImageMagickDecoder (_film, ic)); id->Video.connect (bind (&Player::process_video, this, *i, _1, _2, _3)); - if (_video_container_size) { - id->set_video_container_size (_video_container_size.get ()); - } } decoder = id; @@ -390,10 +456,17 @@ void Player::set_video_container_size (libdcp::Size s) { _video_container_size = s; - for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) { - shared_ptr<VideoDecoder> vd = dynamic_pointer_cast<VideoDecoder> ((*i)->decoder); - if (vd) { - vd->set_video_container_size (s); - } +} + +shared_ptr<Resampler> +Player::resampler (shared_ptr<AudioContent> c) +{ + map<shared_ptr<AudioContent>, shared_ptr<Resampler> >::iterator i = _resamplers.find (c); + if (i != _resamplers.end ()) { + return i->second; } + + shared_ptr<Resampler> r (new Resampler (c->content_audio_frame_rate(), c->output_audio_frame_rate(), c->audio_channels())); + _resamplers[c] = r; + return r; } |
