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.
23 #include "ffmpeg_decoder.h"
24 #include "ffmpeg_content.h"
25 #include "image_decoder.h"
26 #include "image_content.h"
27 #include "sndfile_decoder.h"
28 #include "sndfile_content.h"
29 #include "subtitle_content.h"
44 using boost::shared_ptr;
45 using boost::weak_ptr;
46 using boost::dynamic_pointer_cast;
47 using boost::optional;
52 Piece (shared_ptr<Content> c, shared_ptr<Decoder> d, FrameRateChange f)
58 shared_ptr<Content> content;
59 shared_ptr<Decoder> decoder;
63 Player::Player (shared_ptr<const Film> f, shared_ptr<const Playlist> p)
68 , _have_valid_pieces (false)
71 , _audio_merger (f->audio_channels(), bind (&Film::time_to_audio_frames, f.get(), _1), bind (&Film::audio_frames_to_time, f.get(), _1))
72 , _last_emit_was_black (false)
73 , _just_did_inaccurate_seek (false)
74 , _approximate_size (false)
76 _playlist_changed_connection = _playlist->Changed.connect (bind (&Player::playlist_changed, this));
77 _playlist_content_changed_connection = _playlist->ContentChanged.connect (bind (&Player::content_changed, this, _1, _2, _3));
78 _film_changed_connection = _film->Changed.connect (bind (&Player::film_changed, this, _1));
79 set_video_container_size (fit_ratio_within (_film->container()->ratio (), _film->full_frame ()));
83 Player::disable_video ()
89 Player::disable_audio ()
97 if (!_have_valid_pieces) {
101 /* Interrogate all our pieces to find the one with the earliest decoded data */
103 shared_ptr<Piece> earliest_piece;
104 shared_ptr<Decoded> earliest_decoded;
105 DCPTime earliest_time = TIME_MAX;
106 DCPTime earliest_audio = TIME_MAX;
108 for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
110 shared_ptr<Decoded> dec = (*i)->decoder->peek ();
113 dec->set_dcp_times ((*i)->frc.speed_up, (*i)->content->position());
116 if (dec && dec->dcp_time < earliest_time) {
118 earliest_decoded = dec;
119 earliest_time = dec->dcp_time;
122 if (dynamic_pointer_cast<DecodedAudio> (dec) && dec->dcp_time < earliest_audio) {
123 earliest_audio = dec->dcp_time;
127 if (!earliest_piece) {
132 if (earliest_audio != TIME_MAX) {
133 TimedAudioBuffers<DCPTime> tb = _audio_merger.pull (earliest_audio);
134 Audio (tb.audio, tb.time);
135 /* This assumes that the audio_frames_to_time conversion is exact
136 so that there are no accumulated errors caused by rounding.
138 _audio_position += _film->audio_frames_to_time (tb.audio->frames ());
141 /* Emit the earliest thing */
143 shared_ptr<DecodedVideo> dv = dynamic_pointer_cast<DecodedVideo> (earliest_decoded);
144 shared_ptr<DecodedAudio> da = dynamic_pointer_cast<DecodedAudio> (earliest_decoded);
145 shared_ptr<DecodedSubtitle> ds = dynamic_pointer_cast<DecodedSubtitle> (earliest_decoded);
147 /* Will be set to false if we shouldn't consume the peeked DecodedThing */
150 /* This is the margin either side of _{video,audio}_position that we will accept
151 as a starting point for a frame consecutive to the previous.
153 DCPTime const margin = TIME_HZ / (2 * _film->video_frame_rate ());
157 if (_just_did_inaccurate_seek) {
159 /* Just emit; no subtlety */
160 emit_video (earliest_piece, dv);
161 step_video_position (dv);
163 } else if (dv->dcp_time - _video_position > margin) {
167 list<shared_ptr<Piece> >::iterator i = _pieces.begin();
168 while (i != _pieces.end() && ((*i)->content->position() >= _video_position || _video_position >= (*i)->content->end())) {
172 if (i == _pieces.end() || !_last_incoming_video.video || !_have_valid_pieces) {
173 /* We're outside all video content */
176 /* We're inside some video; repeat the frame */
177 _last_incoming_video.video->dcp_time = _video_position;
178 emit_video (_last_incoming_video.weak_piece, _last_incoming_video.video);
179 step_video_position (_last_incoming_video.video);
184 } else if (abs (dv->dcp_time - _video_position) < margin) {
186 emit_video (earliest_piece, dv);
187 step_video_position (dv);
189 /* Too far behind: skip */
192 } else if (da && _audio) {
194 if (_just_did_inaccurate_seek) {
195 /* Just emit; no subtlety */
196 emit_audio (earliest_piece, da);
197 } else if (da->dcp_time - _audio_position > margin) {
199 emit_silence (da->dcp_time - _audio_position);
201 } else if (abs (da->dcp_time - _audio_position) < margin) {
203 emit_audio (earliest_piece, da);
205 /* Too far behind: skip */
208 } else if (ds && _video) {
209 _in_subtitle.piece = earliest_piece;
210 _in_subtitle.subtitle = ds;
215 earliest_piece->decoder->consume ();
218 _just_did_inaccurate_seek = false;
224 Player::emit_video (weak_ptr<Piece> weak_piece, shared_ptr<DecodedVideo> video)
226 /* Keep a note of what came in so that we can repeat it if required */
227 _last_incoming_video.weak_piece = weak_piece;
228 _last_incoming_video.video = video;
230 shared_ptr<Piece> piece = weak_piece.lock ();
235 shared_ptr<VideoContent> content = dynamic_pointer_cast<VideoContent> (piece->content);
238 FrameRateChange frc (content->video_frame_rate(), _film->video_frame_rate());
240 float const ratio = content->ratio() ? content->ratio()->ratio() : content->video_size_after_crop().ratio();
241 libdcp::Size image_size = fit_ratio_within (ratio, _video_container_size);
242 if (_approximate_size) {
243 image_size.width &= ~3;
244 image_size.height &= ~3;
247 shared_ptr<PlayerImage> pi (
252 _video_container_size,
258 _film->with_subtitles () &&
259 _out_subtitle.image &&
260 video->dcp_time >= _out_subtitle.from && video->dcp_time <= _out_subtitle.to
263 Position<int> const container_offset (
264 (_video_container_size.width - image_size.width) / 2,
265 (_video_container_size.height - image_size.width) / 2
268 pi->set_subtitle (_out_subtitle.image, _out_subtitle.position + container_offset);
271 #ifdef DCPOMATIC_DEBUG
272 _last_video = piece->content;
275 Video (pi, video->eyes, content->colour_conversion(), video->same, video->dcp_time);
277 _last_emit_was_black = false;
281 Player::step_video_position (shared_ptr<DecodedVideo> video)
283 /* This is a bit of a hack; don't update _video_position if EYES_RIGHT is on its way */
284 if (video->eyes != EYES_LEFT) {
285 /* This assumes that the video_frames_to_time conversion is exact
286 so that there are no accumulated errors caused by rounding.
288 _video_position += _film->video_frames_to_time (1);
293 Player::emit_audio (weak_ptr<Piece> weak_piece, shared_ptr<DecodedAudio> audio)
295 shared_ptr<Piece> piece = weak_piece.lock ();
300 shared_ptr<AudioContent> content = dynamic_pointer_cast<AudioContent> (piece->content);
304 if (content->audio_gain() != 0) {
305 shared_ptr<AudioBuffers> gain (new AudioBuffers (audio->data));
306 gain->apply_gain (content->audio_gain ());
310 if (content->trimmed (audio->dcp_time - content->position ())) {
315 shared_ptr<AudioBuffers> dcp_mapped (new AudioBuffers (_film->audio_channels(), audio->data->frames()));
316 dcp_mapped->make_silent ();
317 list<pair<int, libdcp::Channel> > map = content->audio_mapping().content_to_dcp ();
318 for (list<pair<int, libdcp::Channel> >::iterator i = map.begin(); i != map.end(); ++i) {
319 if (i->first < audio->data->channels() && i->second < dcp_mapped->channels()) {
320 dcp_mapped->accumulate_channel (audio->data.get(), i->first, i->second);
324 audio->data = dcp_mapped;
327 audio->dcp_time += content->audio_delay() * TIME_HZ / 1000;
328 if (audio->dcp_time < 0) {
329 int const frames = - audio->dcp_time * _film->audio_frame_rate() / TIME_HZ;
330 if (frames >= audio->data->frames ()) {
334 shared_ptr<AudioBuffers> trimmed (new AudioBuffers (audio->data->channels(), audio->data->frames() - frames));
335 trimmed->copy_from (audio->data.get(), audio->data->frames() - frames, frames, 0);
337 audio->data = trimmed;
341 _audio_merger.push (audio->data, audio->dcp_time);
347 TimedAudioBuffers<DCPTime> tb = _audio_merger.flush ();
349 Audio (tb.audio, tb.time);
350 _audio_position += _film->audio_frames_to_time (tb.audio->frames ());
353 while (_video_position < _audio_position) {
357 while (_audio_position < _video_position) {
358 emit_silence (_video_position - _audio_position);
363 /** Seek so that the next pass() will yield (approximately) the requested frame.
364 * Pass accurate = true to try harder to get close to the request.
365 * @return true on error
368 Player::seek (DCPTime t, bool accurate)
370 if (!_have_valid_pieces) {
374 if (_pieces.empty ()) {
378 for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
379 /* s is the offset of t from the start position of this content */
380 DCPTime s = t - (*i)->content->position ();
381 s = max (static_cast<DCPTime> (0), s);
382 s = min ((*i)->content->length_after_trim(), s);
384 /* Convert this to the content time */
385 ContentTime ct = (s * (*i)->frc.speed_up) + (*i)->content->trim_start ();
387 /* And seek the decoder */
388 (*i)->decoder->seek (ct, accurate);
391 _video_position = time_round_up (t, TIME_HZ / _film->video_frame_rate());
392 _audio_position = time_round_up (t, TIME_HZ / _film->audio_frame_rate());
394 _audio_merger.clear (_audio_position);
397 /* We just did an inaccurate seek, so it's likely that the next thing seen
398 out of pass() will be a fair distance from _{video,audio}_position. Setting
399 this flag stops pass() from trying to fix that: we assume that if it
400 was an inaccurate seek then the caller does not care too much about
401 inserting black/silence to keep the time tidy.
403 _just_did_inaccurate_seek = true;
408 Player::setup_pieces ()
410 list<shared_ptr<Piece> > old_pieces = _pieces;
413 ContentList content = _playlist->content ();
415 for (ContentList::iterator i = content.begin(); i != content.end(); ++i) {
417 shared_ptr<Decoder> decoder;
418 optional<FrameRateChange> frc;
420 shared_ptr<const FFmpegContent> fc = dynamic_pointer_cast<const FFmpegContent> (*i);
422 decoder.reset (new FFmpegDecoder (_film, fc, _video, _audio));
423 frc = FrameRateChange (fc->video_frame_rate(), _film->video_frame_rate());
426 shared_ptr<const ImageContent> ic = dynamic_pointer_cast<const ImageContent> (*i);
428 /* See if we can re-use an old ImageDecoder */
429 for (list<shared_ptr<Piece> >::const_iterator j = old_pieces.begin(); j != old_pieces.end(); ++j) {
430 shared_ptr<ImageDecoder> imd = dynamic_pointer_cast<ImageDecoder> ((*j)->decoder);
431 if (imd && imd->content() == ic) {
437 decoder.reset (new ImageDecoder (_film, ic));
440 frc = FrameRateChange (ic->video_frame_rate(), _film->video_frame_rate());
443 shared_ptr<const SndfileContent> sc = dynamic_pointer_cast<const SndfileContent> (*i);
445 decoder.reset (new SndfileDecoder (_film, sc));
447 /* Working out the frc for this content is a bit tricky: what if it overlaps
448 two pieces of video content with different frame rates? For now, use
449 the one with the best overlap.
452 DCPTime best_overlap_t = 0;
453 shared_ptr<VideoContent> best_overlap;
454 for (ContentList::iterator j = content.begin(); j != content.end(); ++j) {
455 shared_ptr<VideoContent> vc = dynamic_pointer_cast<VideoContent> (*j);
460 DCPTime const overlap = max (vc->position(), sc->position()) - min (vc->end(), sc->end());
461 if (overlap > best_overlap_t) {
463 best_overlap_t = overlap;
468 frc = FrameRateChange (best_overlap->video_frame_rate(), _film->video_frame_rate ());
470 /* No video overlap; e.g. if the DCP is just audio */
471 frc = FrameRateChange (_film->video_frame_rate(), _film->video_frame_rate ());
475 decoder->seek ((*i)->trim_start (), true);
477 _pieces.push_back (shared_ptr<Piece> (new Piece (*i, decoder, frc.get ())));
480 _have_valid_pieces = true;
482 /* The Piece for the _last_incoming_video will no longer be valid */
483 _last_incoming_video.video.reset ();
485 _video_position = _audio_position = 0;
489 Player::content_changed (weak_ptr<Content> w, int property, bool frequent)
491 shared_ptr<Content> c = w.lock ();
497 property == ContentProperty::POSITION || property == ContentProperty::LENGTH ||
498 property == ContentProperty::TRIM_START || property == ContentProperty::TRIM_END ||
499 property == VideoContentProperty::VIDEO_FRAME_TYPE
502 _have_valid_pieces = false;
505 } else if (property == SubtitleContentProperty::SUBTITLE_OFFSET || property == SubtitleContentProperty::SUBTITLE_SCALE) {
510 } else if (property == VideoContentProperty::VIDEO_CROP || property == VideoContentProperty::VIDEO_RATIO) {
514 } else if (property == ContentProperty::PATH) {
521 Player::playlist_changed ()
523 _have_valid_pieces = false;
528 Player::set_video_container_size (libdcp::Size s)
530 _video_container_size = s;
532 shared_ptr<Image> im (new Image (PIX_FMT_RGB24, _video_container_size, true));
539 _video_container_size,
540 _video_container_size,
541 Scaler::from_id ("bicubic")
547 Player::emit_black ()
549 #ifdef DCPOMATIC_DEBUG
550 _last_video.reset ();
553 Video (_black_frame, EYES_BOTH, ColourConversion(), _last_emit_was_black, _video_position);
554 _video_position += _film->video_frames_to_time (1);
555 _last_emit_was_black = true;
559 Player::emit_silence (DCPTime most)
565 DCPTime t = min (most, TIME_HZ / 2);
566 shared_ptr<AudioBuffers> silence (new AudioBuffers (_film->audio_channels(), t * _film->audio_frame_rate() / TIME_HZ));
567 silence->make_silent ();
568 Audio (silence, _audio_position);
570 _audio_position += t;
574 Player::film_changed (Film::Property p)
576 /* Here we should notice Film properties that affect our output, and
577 alert listeners that our output now would be different to how it was
578 last time we were run.
581 if (p == Film::SCALER || p == Film::WITH_SUBTITLES || p == Film::CONTAINER) {
587 Player::update_subtitle ()
589 shared_ptr<Piece> piece = _in_subtitle.piece.lock ();
594 if (!_in_subtitle.subtitle->image) {
595 _out_subtitle.image.reset ();
599 shared_ptr<SubtitleContent> sc = dynamic_pointer_cast<SubtitleContent> (piece->content);
602 dcpomatic::Rect<double> in_rect = _in_subtitle.subtitle->rect;
603 libdcp::Size scaled_size;
605 in_rect.y += sc->subtitle_offset ();
607 /* We will scale the subtitle up to fit _video_container_size, and also by the additional subtitle_scale */
608 scaled_size.width = in_rect.width * _video_container_size.width * sc->subtitle_scale ();
609 scaled_size.height = in_rect.height * _video_container_size.height * sc->subtitle_scale ();
611 /* Then we need a corrective translation, consisting of two parts:
613 * 1. that which is the result of the scaling of the subtitle by _video_container_size; this will be
614 * rect.x * _video_container_size.width and rect.y * _video_container_size.height.
616 * 2. that to shift the origin of the scale by subtitle_scale to the centre of the subtitle; this will be
617 * (width_before_subtitle_scale * (1 - subtitle_scale) / 2) and
618 * (height_before_subtitle_scale * (1 - subtitle_scale) / 2).
620 * Combining these two translations gives these expressions.
623 _out_subtitle.position.x = rint (_video_container_size.width * (in_rect.x + (in_rect.width * (1 - sc->subtitle_scale ()) / 2)));
624 _out_subtitle.position.y = rint (_video_container_size.height * (in_rect.y + (in_rect.height * (1 - sc->subtitle_scale ()) / 2)));
626 _out_subtitle.image = _in_subtitle.subtitle->image->scale (
628 Scaler::from_id ("bicubic"),
633 _out_subtitle.from = _in_subtitle.subtitle->dcp_time;
634 _out_subtitle.to = _in_subtitle.subtitle->dcp_time_to;
637 /** Re-emit the last frame that was emitted, using current settings for crop, ratio, scaler and subtitles.
638 * @return false if this could not be done.
641 Player::repeat_last_video ()
643 if (!_last_incoming_video.video || !_have_valid_pieces) {
648 _last_incoming_video.weak_piece,
649 _last_incoming_video.video
656 Player::set_approximate_size ()
658 _approximate_size = true;
662 PlayerImage::PlayerImage (
663 shared_ptr<const Image> in,
665 libdcp::Size inter_size,
666 libdcp::Size out_size,
667 Scaler const * scaler
671 , _inter_size (inter_size)
672 , _out_size (out_size)
679 PlayerImage::set_subtitle (shared_ptr<const Image> image, Position<int> pos)
681 _subtitle_image = image;
682 _subtitle_position = pos;
686 PlayerImage::image (AVPixelFormat format, bool aligned)
688 shared_ptr<Image> out = _in->crop_scale_window (_crop, _inter_size, _out_size, _scaler, format, aligned);
690 Position<int> const container_offset ((_out_size.width - _inter_size.width) / 2, (_out_size.height - _inter_size.width) / 2);
692 if (_subtitle_image) {
693 out->alpha_blend (_subtitle_image, _subtitle_position);