2 Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "ffmpeg_decoder.h"
25 #include "ffmpeg_content.h"
26 #include "image_decoder.h"
27 #include "image_content.h"
28 #include "sndfile_decoder.h"
29 #include "sndfile_content.h"
30 #include "subtitle_content.h"
45 using boost::shared_ptr;
46 using boost::weak_ptr;
47 using boost::dynamic_pointer_cast;
48 using boost::optional;
53 Piece (shared_ptr<Content> c, shared_ptr<Decoder> d, FrameRateChange f)
59 shared_ptr<Content> content;
60 shared_ptr<Decoder> decoder;
64 Player::Player (shared_ptr<const Film> f, shared_ptr<const Playlist> p)
69 , _have_valid_pieces (false)
72 , _audio_merger (f->audio_channels(), bind (&Film::time_to_audio_frames, f.get(), _1), bind (&Film::audio_frames_to_time, f.get(), _1))
73 , _last_emit_was_black (false)
74 , _just_did_inaccurate_seek (false)
75 , _approximate_size (false)
77 _playlist_changed_connection = _playlist->Changed.connect (bind (&Player::playlist_changed, this));
78 _playlist_content_changed_connection = _playlist->ContentChanged.connect (bind (&Player::content_changed, this, _1, _2, _3));
79 _film_changed_connection = _film->Changed.connect (bind (&Player::film_changed, this, _1));
80 set_video_container_size (fit_ratio_within (_film->container()->ratio (), _film->full_frame ()));
84 Player::disable_video ()
90 Player::disable_audio ()
98 if (!_have_valid_pieces) {
102 /* Interrogate all our pieces to find the one with the earliest decoded data */
104 shared_ptr<Piece> earliest_piece;
105 shared_ptr<Decoded> earliest_decoded;
106 DCPTime earliest_time = TIME_MAX;
107 DCPTime earliest_audio = TIME_MAX;
109 for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
111 DCPTime const offset = (*i)->content->position() - (*i)->content->trim_start();
114 shared_ptr<Decoded> dec;
116 dec = (*i)->decoder->peek ();
118 /* Decoder has nothing else to give us */
122 dec->set_dcp_times ((*i)->frc.speed_up, offset);
123 DCPTime const t = dec->dcp_time - offset;
124 if (t >= (*i)->content->full_length() - (*i)->content->trim_end ()) {
125 /* In the end-trimmed part; decoder has nothing eles to give us */
128 } else if (t >= (*i)->content->trim_start ()) {
129 /* Within the un-trimmed part; everything's ok */
132 /* Within the start-trimmed part; get something else */
133 (*i)->decoder->consume ();
141 if (dec->dcp_time < earliest_time) {
143 earliest_decoded = dec;
144 earliest_time = dec->dcp_time;
147 if (dynamic_pointer_cast<DecodedAudio> (dec) && dec->dcp_time < earliest_audio) {
148 earliest_audio = dec->dcp_time;
152 if (!earliest_piece) {
157 if (earliest_audio != TIME_MAX) {
158 TimedAudioBuffers<DCPTime> tb = _audio_merger.pull (max (int64_t (0), earliest_audio));
159 Audio (tb.audio, tb.time);
160 /* This assumes that the audio_frames_to_time conversion is exact
161 so that there are no accumulated errors caused by rounding.
163 _audio_position += _film->audio_frames_to_time (tb.audio->frames ());
166 /* Emit the earliest thing */
168 shared_ptr<DecodedVideo> dv = dynamic_pointer_cast<DecodedVideo> (earliest_decoded);
169 shared_ptr<DecodedAudio> da = dynamic_pointer_cast<DecodedAudio> (earliest_decoded);
170 shared_ptr<DecodedSubtitle> ds = dynamic_pointer_cast<DecodedSubtitle> (earliest_decoded);
172 /* Will be set to false if we shouldn't consume the peeked DecodedThing */
175 /* This is the margin either side of _{video,audio}_position that we will accept
176 as a starting point for a frame consecutive to the previous.
178 DCPTime const margin = TIME_HZ / (2 * _film->video_frame_rate ());
182 if (_just_did_inaccurate_seek) {
184 /* Just emit; no subtlety */
185 emit_video (earliest_piece, dv);
186 step_video_position (dv);
188 } else if (dv->dcp_time - _video_position > margin) {
192 list<shared_ptr<Piece> >::iterator i = _pieces.begin();
193 while (i != _pieces.end() && ((*i)->content->position() >= _video_position || _video_position >= (*i)->content->end())) {
197 if (i == _pieces.end() || !_last_incoming_video.video || !_have_valid_pieces) {
198 /* We're outside all video content */
201 /* We're inside some video; repeat the frame */
202 _last_incoming_video.video->dcp_time = _video_position;
203 emit_video (_last_incoming_video.weak_piece, _last_incoming_video.video);
204 step_video_position (_last_incoming_video.video);
209 } else if (abs (dv->dcp_time - _video_position) < margin) {
211 emit_video (earliest_piece, dv);
212 step_video_position (dv);
214 /* Too far behind: skip */
217 _just_did_inaccurate_seek = false;
219 } else if (da && _audio) {
221 if (da->dcp_time - _audio_position > margin) {
223 emit_silence (da->dcp_time - _audio_position);
225 } else if (abs (da->dcp_time - _audio_position) < margin) {
227 emit_audio (earliest_piece, da);
229 /* Too far behind: skip */
232 } else if (ds && _video) {
233 _in_subtitle.piece = earliest_piece;
234 _in_subtitle.subtitle = ds;
239 earliest_piece->decoder->consume ();
246 Player::emit_video (weak_ptr<Piece> weak_piece, shared_ptr<DecodedVideo> video)
248 /* Keep a note of what came in so that we can repeat it if required */
249 _last_incoming_video.weak_piece = weak_piece;
250 _last_incoming_video.video = video;
252 shared_ptr<Piece> piece = weak_piece.lock ();
257 shared_ptr<VideoContent> content = dynamic_pointer_cast<VideoContent> (piece->content);
260 FrameRateChange frc (content->video_frame_rate(), _film->video_frame_rate());
262 float const ratio = content->ratio() ? content->ratio()->ratio() : content->video_size_after_crop().ratio();
263 libdcp::Size image_size = fit_ratio_within (ratio, _video_container_size);
264 if (_approximate_size) {
265 image_size.width &= ~3;
266 image_size.height &= ~3;
269 shared_ptr<PlayerImage> pi (
274 _video_container_size,
280 _film->with_subtitles () &&
281 _out_subtitle.image &&
282 video->dcp_time >= _out_subtitle.from && video->dcp_time <= _out_subtitle.to
285 Position<int> const container_offset (
286 (_video_container_size.width - image_size.width) / 2,
287 (_video_container_size.height - image_size.height) / 2
290 pi->set_subtitle (_out_subtitle.image, _out_subtitle.position + container_offset);
293 #ifdef DCPOMATIC_DEBUG
294 _last_video = piece->content;
297 Video (pi, video->eyes, content->colour_conversion(), video->same, video->dcp_time);
299 _last_emit_was_black = false;
303 Player::step_video_position (shared_ptr<DecodedVideo> video)
305 /* This is a bit of a hack; don't update _video_position if EYES_RIGHT is on its way */
306 if (video->eyes != EYES_LEFT) {
307 /* This assumes that the video_frames_to_time conversion is exact
308 so that there are no accumulated errors caused by rounding.
310 _video_position += _film->video_frames_to_time (1);
315 Player::emit_audio (weak_ptr<Piece> weak_piece, shared_ptr<DecodedAudio> audio)
317 shared_ptr<Piece> piece = weak_piece.lock ();
322 shared_ptr<AudioContent> content = dynamic_pointer_cast<AudioContent> (piece->content);
326 if (content->audio_gain() != 0) {
327 shared_ptr<AudioBuffers> gain (new AudioBuffers (audio->data));
328 gain->apply_gain (content->audio_gain ());
333 shared_ptr<AudioBuffers> dcp_mapped (new AudioBuffers (_film->audio_channels(), audio->data->frames()));
334 dcp_mapped->make_silent ();
335 list<pair<int, libdcp::Channel> > map = content->audio_mapping().content_to_dcp ();
336 for (list<pair<int, libdcp::Channel> >::iterator i = map.begin(); i != map.end(); ++i) {
337 if (i->first < audio->data->channels() && i->second < dcp_mapped->channels()) {
338 dcp_mapped->accumulate_channel (audio->data.get(), i->first, i->second);
342 audio->data = dcp_mapped;
345 audio->dcp_time += content->audio_delay() * TIME_HZ / 1000;
346 if (audio->dcp_time < 0) {
347 int const frames = - audio->dcp_time * _film->audio_frame_rate() / TIME_HZ;
348 if (frames >= audio->data->frames ()) {
352 shared_ptr<AudioBuffers> trimmed (new AudioBuffers (audio->data->channels(), audio->data->frames() - frames));
353 trimmed->copy_from (audio->data.get(), audio->data->frames() - frames, frames, 0);
355 audio->data = trimmed;
359 _audio_merger.push (audio->data, audio->dcp_time);
365 TimedAudioBuffers<DCPTime> tb = _audio_merger.flush ();
366 if (_audio && tb.audio) {
367 Audio (tb.audio, tb.time);
368 _audio_position += _film->audio_frames_to_time (tb.audio->frames ());
371 while (_video && _video_position < _audio_position) {
375 while (_audio && _audio_position < _video_position) {
376 emit_silence (_video_position - _audio_position);
381 /** Seek so that the next pass() will yield (approximately) the requested frame.
382 * Pass accurate = true to try harder to get close to the request.
383 * @return true on error
386 Player::seek (DCPTime t, bool accurate)
388 if (!_have_valid_pieces) {
392 if (_pieces.empty ()) {
396 for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
397 /* s is the offset of t from the start position of this content */
398 DCPTime s = t - (*i)->content->position ();
399 s = max (static_cast<DCPTime> (0), s);
400 s = min ((*i)->content->length_after_trim(), s);
402 /* Convert this to the content time */
403 ContentTime ct = (s + (*i)->content->trim_start()) * (*i)->frc.speed_up;
405 /* And seek the decoder */
406 (*i)->decoder->seek (ct, accurate);
409 _video_position = time_round_up (t, TIME_HZ / _film->video_frame_rate());
410 _audio_position = time_round_up (t, TIME_HZ / _film->audio_frame_rate());
412 _audio_merger.clear (_audio_position);
415 /* We just did an inaccurate seek, so it's likely that the next thing seen
416 out of pass() will be a fair distance from _{video,audio}_position. Setting
417 this flag stops pass() from trying to fix that: we assume that if it
418 was an inaccurate seek then the caller does not care too much about
419 inserting black/silence to keep the time tidy.
421 _just_did_inaccurate_seek = true;
426 Player::setup_pieces ()
428 list<shared_ptr<Piece> > old_pieces = _pieces;
431 ContentList content = _playlist->content ();
433 for (ContentList::iterator i = content.begin(); i != content.end(); ++i) {
435 shared_ptr<Decoder> decoder;
436 optional<FrameRateChange> frc;
438 shared_ptr<const FFmpegContent> fc = dynamic_pointer_cast<const FFmpegContent> (*i);
440 decoder.reset (new FFmpegDecoder (_film, fc, _video, _audio));
441 frc = FrameRateChange (fc->video_frame_rate(), _film->video_frame_rate());
444 shared_ptr<const ImageContent> ic = dynamic_pointer_cast<const ImageContent> (*i);
446 /* See if we can re-use an old ImageDecoder */
447 for (list<shared_ptr<Piece> >::const_iterator j = old_pieces.begin(); j != old_pieces.end(); ++j) {
448 shared_ptr<ImageDecoder> imd = dynamic_pointer_cast<ImageDecoder> ((*j)->decoder);
449 if (imd && imd->content() == ic) {
455 decoder.reset (new ImageDecoder (_film, ic));
458 frc = FrameRateChange (ic->video_frame_rate(), _film->video_frame_rate());
461 shared_ptr<const SndfileContent> sc = dynamic_pointer_cast<const SndfileContent> (*i);
463 decoder.reset (new SndfileDecoder (_film, sc));
465 /* Working out the frc for this content is a bit tricky: what if it overlaps
466 two pieces of video content with different frame rates? For now, use
467 the one with the best overlap.
470 DCPTime best_overlap_t = 0;
471 shared_ptr<VideoContent> best_overlap;
472 for (ContentList::iterator j = content.begin(); j != content.end(); ++j) {
473 shared_ptr<VideoContent> vc = dynamic_pointer_cast<VideoContent> (*j);
478 DCPTime const overlap = max (vc->position(), sc->position()) - min (vc->end(), sc->end());
479 if (overlap > best_overlap_t) {
481 best_overlap_t = overlap;
486 frc = FrameRateChange (best_overlap->video_frame_rate(), _film->video_frame_rate ());
488 /* No video overlap; e.g. if the DCP is just audio */
489 frc = FrameRateChange (_film->video_frame_rate(), _film->video_frame_rate ());
493 ContentTime st = (*i)->trim_start() * frc->speed_up;
494 decoder->seek (st, true);
496 _pieces.push_back (shared_ptr<Piece> (new Piece (*i, decoder, frc.get ())));
499 _have_valid_pieces = true;
501 /* The Piece for the _last_incoming_video will no longer be valid */
502 _last_incoming_video.video.reset ();
504 _video_position = _audio_position = 0;
508 Player::content_changed (weak_ptr<Content> w, int property, bool frequent)
510 shared_ptr<Content> c = w.lock ();
516 property == ContentProperty::POSITION || property == ContentProperty::LENGTH ||
517 property == ContentProperty::TRIM_START || property == ContentProperty::TRIM_END ||
518 property == VideoContentProperty::VIDEO_FRAME_TYPE
521 _have_valid_pieces = false;
524 } else if (property == SubtitleContentProperty::SUBTITLE_OFFSET || property == SubtitleContentProperty::SUBTITLE_SCALE) {
529 } else if (property == VideoContentProperty::VIDEO_CROP || property == VideoContentProperty::VIDEO_RATIO) {
533 } else if (property == ContentProperty::PATH) {
540 Player::playlist_changed ()
542 _have_valid_pieces = false;
547 Player::set_video_container_size (libdcp::Size s)
549 _video_container_size = s;
551 shared_ptr<Image> im (new Image (PIX_FMT_RGB24, _video_container_size, true));
558 _video_container_size,
559 _video_container_size,
560 Scaler::from_id ("bicubic")
566 Player::emit_black ()
568 #ifdef DCPOMATIC_DEBUG
569 _last_video.reset ();
572 Video (_black_frame, EYES_BOTH, ColourConversion(), _last_emit_was_black, _video_position);
573 _video_position += _film->video_frames_to_time (1);
574 _last_emit_was_black = true;
578 Player::emit_silence (DCPTime most)
584 DCPTime t = min (most, TIME_HZ / 2);
585 shared_ptr<AudioBuffers> silence (new AudioBuffers (_film->audio_channels(), t * _film->audio_frame_rate() / TIME_HZ));
586 silence->make_silent ();
587 Audio (silence, _audio_position);
589 _audio_position += t;
593 Player::film_changed (Film::Property p)
595 /* Here we should notice Film properties that affect our output, and
596 alert listeners that our output now would be different to how it was
597 last time we were run.
600 if (p == Film::SCALER || p == Film::WITH_SUBTITLES || p == Film::CONTAINER) {
606 Player::update_subtitle ()
608 shared_ptr<Piece> piece = _in_subtitle.piece.lock ();
613 if (!_in_subtitle.subtitle->image) {
614 _out_subtitle.image.reset ();
618 shared_ptr<SubtitleContent> sc = dynamic_pointer_cast<SubtitleContent> (piece->content);
621 dcpomatic::Rect<double> in_rect = _in_subtitle.subtitle->rect;
622 libdcp::Size scaled_size;
624 in_rect.y += sc->subtitle_offset ();
626 /* We will scale the subtitle up to fit _video_container_size, and also by the additional subtitle_scale */
627 scaled_size.width = in_rect.width * _video_container_size.width * sc->subtitle_scale ();
628 scaled_size.height = in_rect.height * _video_container_size.height * sc->subtitle_scale ();
630 /* Then we need a corrective translation, consisting of two parts:
632 * 1. that which is the result of the scaling of the subtitle by _video_container_size; this will be
633 * rect.x * _video_container_size.width and rect.y * _video_container_size.height.
635 * 2. that to shift the origin of the scale by subtitle_scale to the centre of the subtitle; this will be
636 * (width_before_subtitle_scale * (1 - subtitle_scale) / 2) and
637 * (height_before_subtitle_scale * (1 - subtitle_scale) / 2).
639 * Combining these two translations gives these expressions.
642 _out_subtitle.position.x = rint (_video_container_size.width * (in_rect.x + (in_rect.width * (1 - sc->subtitle_scale ()) / 2)));
643 _out_subtitle.position.y = rint (_video_container_size.height * (in_rect.y + (in_rect.height * (1 - sc->subtitle_scale ()) / 2)));
645 _out_subtitle.image = _in_subtitle.subtitle->image->scale (
647 Scaler::from_id ("bicubic"),
652 _out_subtitle.from = _in_subtitle.subtitle->dcp_time;
653 _out_subtitle.to = _in_subtitle.subtitle->dcp_time_to;
656 /** Re-emit the last frame that was emitted, using current settings for crop, ratio, scaler and subtitles.
657 * @return false if this could not be done.
660 Player::repeat_last_video ()
662 if (!_last_incoming_video.video || !_have_valid_pieces) {
667 _last_incoming_video.weak_piece,
668 _last_incoming_video.video
675 Player::set_approximate_size ()
677 _approximate_size = true;
681 PlayerImage::PlayerImage (
682 shared_ptr<const Image> in,
684 libdcp::Size inter_size,
685 libdcp::Size out_size,
686 Scaler const * scaler
690 , _inter_size (inter_size)
691 , _out_size (out_size)
698 PlayerImage::set_subtitle (shared_ptr<const Image> image, Position<int> pos)
700 _subtitle_image = image;
701 _subtitle_position = pos;
705 PlayerImage::image (AVPixelFormat format, bool aligned)
707 shared_ptr<Image> out = _in->crop_scale_window (_crop, _inter_size, _out_size, _scaler, format, aligned);
709 Position<int> const container_offset ((_out_size.width - _inter_size.width) / 2, (_out_size.height - _inter_size.width) / 2);
711 if (_subtitle_image) {
712 out->alpha_blend (_subtitle_image, _subtitle_position);