- set_video_container_size (fit_ratio_within (_film->container()->ratio (), _film->full_frame ()));
-}
-
-void
-Player::disable_video ()
-{
- _video = false;
-}
-
-void
-Player::disable_audio ()
-{
- _audio = false;
-}
-
-bool
-Player::pass ()
-{
- if (!_have_valid_pieces) {
- setup_pieces ();
- }
-
- Time earliest_t = TIME_MAX;
- shared_ptr<Piece> earliest;
- enum {
- VIDEO,
- AUDIO
- } type = VIDEO;
-
- for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
- if ((*i)->decoder->done ()) {
- continue;
- }
-
- shared_ptr<VideoDecoder> vd = dynamic_pointer_cast<VideoDecoder> ((*i)->decoder);
- shared_ptr<AudioDecoder> ad = dynamic_pointer_cast<AudioDecoder> ((*i)->decoder);
-
- if (_video && vd) {
- if ((*i)->video_position < earliest_t) {
- earliest_t = (*i)->video_position;
- earliest = *i;
- type = VIDEO;
- }
- }
-
- if (_audio && ad && ad->has_audio ()) {
- if ((*i)->audio_position < earliest_t) {
- earliest_t = (*i)->audio_position;
- earliest = *i;
- type = AUDIO;
- }
- }
- }
-
- if (!earliest) {
- flush ();
- return true;
- }
-
- switch (type) {
- case VIDEO:
- if (earliest_t > _video_position) {
- emit_black ();
- } else {
- if (earliest->repeating ()) {
- earliest->repeat (this);
- } else {
- earliest->decoder->pass ();
- }
- }
- break;
-
- case AUDIO:
- if (earliest_t > _audio_position) {
- emit_silence (_film->time_to_audio_frames (earliest_t - _audio_position));
- } else {
- earliest->decoder->pass ();
-
- if (earliest->decoder->done()) {
- shared_ptr<AudioContent> ac = dynamic_pointer_cast<AudioContent> (earliest->content);
- assert (ac);
- shared_ptr<Resampler> re = resampler (ac, false);
- if (re) {
- shared_ptr<const AudioBuffers> b = re->flush ();
- if (b->frames ()) {
- process_audio (earliest, b, ac->audio_length ());
- }
- }
- }
- }
- break;
- }
-
- if (_audio) {
- boost::optional<Time> audio_done_up_to;
- for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
- if ((*i)->decoder->done ()) {
- continue;
- }
-
- shared_ptr<AudioDecoder> ad = dynamic_pointer_cast<AudioDecoder> ((*i)->decoder);
- if (ad && ad->has_audio ()) {
- audio_done_up_to = min (audio_done_up_to.get_value_or (TIME_MAX), (*i)->audio_position);
- }
- }
-
- if (audio_done_up_to) {
- TimedAudioBuffers<Time> tb = _audio_merger.pull (audio_done_up_to.get ());
- Audio (tb.audio, tb.time);
- _audio_position += _film->audio_frames_to_time (tb.audio->frames ());
- }
- }
-
- return false;
-}
-
-/** @param extra Amount of extra time to add to the content frame's time (for repeat) */
-void
-Player::process_video (weak_ptr<Piece> weak_piece, shared_ptr<const Image> image, Eyes eyes, bool same, VideoContent::Frame frame, Time extra)
-{
- /* Keep a note of what came in so that we can repeat it if required */
- _last_incoming_video.weak_piece = weak_piece;
- _last_incoming_video.image = image;
- _last_incoming_video.eyes = eyes;
- _last_incoming_video.same = same;
- _last_incoming_video.frame = frame;
- _last_incoming_video.extra = extra;
-
- 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->video_frame_rate());
- if (frc.skip && (frame % 2) == 1) {
- return;
- }
-
- Time const relative_time = (frame * frc.factor() * TIME_HZ / _film->video_frame_rate());
- if (content->trimmed (relative_time)) {
- return;
- }
-
- Time const time = content->position() + relative_time + extra - content->trim_start ();
- libdcp::Size const image_size = content->scale().size (content, _video_container_size);
-
- shared_ptr<PlayerImage> pi (
- new PlayerImage (
- image,
- content->crop(),
- image_size,
- _video_container_size,
- _film->scaler()
- )
- );
-
- if (_film->with_subtitles () && _out_subtitle.image && time >= _out_subtitle.from && time <= _out_subtitle.to) {
-
- Position<int> const container_offset (
- (_video_container_size.width - image_size.width) / 2,
- (_video_container_size.height - image_size.width) / 2
- );
-
- pi->set_subtitle (_out_subtitle.image, _out_subtitle.position + container_offset);
- }
-
-
-#ifdef DCPOMATIC_DEBUG
- _last_video = piece->content;
-#endif
-
- Video (pi, eyes, content->colour_conversion(), same, time);
-
- _last_emit_was_black = false;
- _video_position = piece->video_position = (time + TIME_HZ / _film->video_frame_rate());
-
- if (frc.repeat > 1 && !piece->repeating ()) {
- piece->set_repeat (_last_incoming_video, frc.repeat - 1);
- }
-}
-
-void
-Player::process_audio (weak_ptr<Piece> weak_piece, shared_ptr<const AudioBuffers> audio, AudioContent::Frame frame)
-{
- shared_ptr<Piece> piece = weak_piece.lock ();
- if (!piece) {
- return;
- }
-
- shared_ptr<AudioContent> content = dynamic_pointer_cast<AudioContent> (piece->content);
- assert (content);
-
- /* Gain */
- if (content->audio_gain() != 0) {
- shared_ptr<AudioBuffers> gain (new AudioBuffers (audio));
- gain->apply_gain (content->audio_gain ());
- audio = gain;
- }
-
- /* Resample */
- if (content->content_audio_frame_rate() != content->output_audio_frame_rate()) {
- shared_ptr<Resampler> r = resampler (content, true);
- pair<shared_ptr<const AudioBuffers>, AudioContent::Frame> ro = r->run (audio, frame);
- audio = ro.first;
- frame = ro.second;
- }
-
- Time const relative_time = _film->audio_frames_to_time (frame);
-
- if (content->trimmed (relative_time)) {
- return;
- }
-
- Time time = content->position() + (content->audio_delay() * TIME_HZ / 1000) + relative_time - content->trim_start ();
-
- /* Remap channels */
- shared_ptr<AudioBuffers> dcp_mapped (new AudioBuffers (_film->audio_channels(), audio->frames()));
- dcp_mapped->make_silent ();
-
- AudioMapping map = content->audio_mapping ();
- for (int i = 0; i < map.content_channels(); ++i) {
- for (int j = 0; j < _film->audio_channels(); ++j) {
- if (map.get (i, static_cast<libdcp::Channel> (j)) > 0) {
- dcp_mapped->accumulate_channel (
- audio.get(),
- i,
- static_cast<libdcp::Channel> (j),
- map.get (i, static_cast<libdcp::Channel> (j))
- );
- }
- }
- }
-
- audio = dcp_mapped;
-
- /* We must cut off anything that comes before the start of all time */
- if (time < 0) {
- int const frames = - time * _film->audio_frame_rate() / TIME_HZ;
- if (frames >= audio->frames ()) {
- return;
- }
-
- shared_ptr<AudioBuffers> trimmed (new AudioBuffers (audio->channels(), audio->frames() - frames));
- trimmed->copy_from (audio.get(), audio->frames() - frames, frames, 0);
-
- audio = trimmed;
- time = 0;
- }
-
- _audio_merger.push (audio, time);
- piece->audio_position += _film->audio_frames_to_time (audio->frames ());
-}
-
-void
-Player::flush ()
-{
- TimedAudioBuffers<Time> tb = _audio_merger.flush ();
- if (_audio && tb.audio) {
- Audio (tb.audio, tb.time);
- _audio_position += _film->audio_frames_to_time (tb.audio->frames ());
- }
-
- while (_video && _video_position < _audio_position) {
- emit_black ();
- }
-
- while (_audio && _audio_position < _video_position) {
- emit_silence (_film->time_to_audio_frames (_video_position - _audio_position));
- }
-
-}
-
-/** Seek so that the next pass() will yield (approximately) the requested frame.
- * Pass accurate = true to try harder to get close to the request.
- * @return true on error
- */
-void
-Player::seek (Time t, bool accurate)
-{
- if (!_have_valid_pieces) {
- setup_pieces ();
- }
-
- if (_pieces.empty ()) {
- return;
- }
-
- for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
- shared_ptr<VideoContent> vc = dynamic_pointer_cast<VideoContent> ((*i)->content);
- if (!vc) {
- continue;
- }
-
- /* s is the offset of t from the start position of this content */
- Time s = t - vc->position ();
- s = max (static_cast<Time> (0), s);
- s = min (vc->length_after_trim(), s);
-
- /* Hence set the piece positions to the `global' time */
- (*i)->video_position = (*i)->audio_position = vc->position() + s;
-
- /* And seek the decoder */
- dynamic_pointer_cast<VideoDecoder>((*i)->decoder)->seek (
- vc->time_to_content_video_frames (s + vc->trim_start ()), accurate
- );
-
- (*i)->reset_repeat ();
- }
-
- _video_position = _audio_position = t;
-
- /* XXX: don't seek audio because we don't need to... */