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 (_film->video_frame_rate(), _film->audio_frame_rate(), (*i)->frc, 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 else 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 */
200 _statistics.video.black++;
202 /* We're inside some video; repeat the frame */
203 _last_incoming_video.video->dcp_time = _video_position;
204 emit_video (_last_incoming_video.weak_piece, _last_incoming_video.video);
205 step_video_position (_last_incoming_video.video);
206 _statistics.video.repeat++;
211 } else if (abs (dv->dcp_time - _video_position) < margin) {
213 emit_video (earliest_piece, dv);
214 step_video_position (dv);
215 _statistics.video.good++;
217 /* Too far behind: skip */
218 _statistics.video.skip++;
221 _just_did_inaccurate_seek = false;
223 } else if (da && _audio) {
225 if (da->dcp_time - _audio_position > margin) {
227 emit_silence (da->dcp_time - _audio_position);
229 _statistics.audio.silence += (da->dcp_time - _audio_position);
230 } else if (abs (da->dcp_time - _audio_position) < margin) {
232 emit_audio (earliest_piece, da);
233 _statistics.audio.good += da->data->frames();
235 /* Too far behind: skip */
236 _statistics.audio.skip += da->data->frames();
239 } else if (ds && _video) {
240 _in_subtitle.piece = earliest_piece;
241 _in_subtitle.subtitle = ds;
246 earliest_piece->decoder->consume ();
253 Player::emit_video (weak_ptr<Piece> weak_piece, shared_ptr<DecodedVideo> video)
255 /* Keep a note of what came in so that we can repeat it if required */
256 _last_incoming_video.weak_piece = weak_piece;
257 _last_incoming_video.video = video;
259 shared_ptr<Piece> piece = weak_piece.lock ();
264 shared_ptr<VideoContent> content = dynamic_pointer_cast<VideoContent> (piece->content);
267 FrameRateChange frc (content->video_frame_rate(), _film->video_frame_rate());
269 float const ratio = content->ratio() ? content->ratio()->ratio() : content->video_size_after_crop().ratio();
270 libdcp::Size image_size = fit_ratio_within (ratio, _video_container_size);
271 if (_approximate_size) {
272 image_size.width &= ~3;
273 image_size.height &= ~3;
276 shared_ptr<PlayerImage> pi (
281 _video_container_size,
287 _film->with_subtitles () &&
288 _out_subtitle.image &&
289 video->dcp_time >= _out_subtitle.from && video->dcp_time <= _out_subtitle.to
292 Position<int> const container_offset (
293 (_video_container_size.width - image_size.width) / 2,
294 (_video_container_size.height - image_size.height) / 2
297 pi->set_subtitle (_out_subtitle.image, _out_subtitle.position + container_offset);
300 #ifdef DCPOMATIC_DEBUG
301 _last_video = piece->content;
304 Video (pi, video->eyes, content->colour_conversion(), video->same, video->dcp_time);
306 _last_emit_was_black = false;
310 Player::step_video_position (shared_ptr<DecodedVideo> video)
312 /* This is a bit of a hack; don't update _video_position if EYES_RIGHT is on its way */
313 if (video->eyes != EYES_LEFT) {
314 /* This assumes that the video_frames_to_time conversion is exact
315 so that there are no accumulated errors caused by rounding.
317 _video_position += _film->video_frames_to_time (1);
322 Player::emit_audio (weak_ptr<Piece> weak_piece, shared_ptr<DecodedAudio> audio)
324 shared_ptr<Piece> piece = weak_piece.lock ();
329 shared_ptr<AudioContent> content = dynamic_pointer_cast<AudioContent> (piece->content);
333 if (content->audio_gain() != 0) {
334 shared_ptr<AudioBuffers> gain (new AudioBuffers (audio->data));
335 gain->apply_gain (content->audio_gain ());
340 shared_ptr<AudioBuffers> dcp_mapped (new AudioBuffers (_film->audio_channels(), audio->data->frames()));
341 dcp_mapped->make_silent ();
342 list<pair<int, libdcp::Channel> > map = content->audio_mapping().content_to_dcp ();
343 for (list<pair<int, libdcp::Channel> >::iterator i = map.begin(); i != map.end(); ++i) {
344 if (i->first < audio->data->channels() && i->second < dcp_mapped->channels()) {
345 dcp_mapped->accumulate_channel (audio->data.get(), i->first, i->second);
349 audio->data = dcp_mapped;
352 audio->dcp_time += content->audio_delay() * TIME_HZ / 1000;
353 if (audio->dcp_time < 0) {
354 int const frames = - audio->dcp_time * _film->audio_frame_rate() / TIME_HZ;
355 if (frames >= audio->data->frames ()) {
359 shared_ptr<AudioBuffers> trimmed (new AudioBuffers (audio->data->channels(), audio->data->frames() - frames));
360 trimmed->copy_from (audio->data.get(), audio->data->frames() - frames, frames, 0);
362 audio->data = trimmed;
366 _audio_merger.push (audio->data, audio->dcp_time);
372 TimedAudioBuffers<DCPTime> tb = _audio_merger.flush ();
373 if (_audio && tb.audio) {
374 Audio (tb.audio, tb.time);
375 _audio_position += _film->audio_frames_to_time (tb.audio->frames ());
378 while (_video && _video_position < _audio_position) {
382 while (_audio && _audio_position < _video_position) {
383 emit_silence (_video_position - _audio_position);
388 /** Seek so that the next pass() will yield (approximately) the requested frame.
389 * Pass accurate = true to try harder to get close to the request.
390 * @return true on error
393 Player::seek (DCPTime t, bool accurate)
395 if (!_have_valid_pieces) {
399 if (_pieces.empty ()) {
403 for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
404 /* s is the offset of t from the start position of this content */
405 DCPTime s = t - (*i)->content->position ();
406 s = max (static_cast<DCPTime> (0), s);
407 s = min ((*i)->content->length_after_trim(), s);
409 /* Convert this to the content time */
410 ContentTime ct = (s + (*i)->content->trim_start()) * (*i)->frc.speed_up;
412 /* And seek the decoder */
413 (*i)->decoder->seek (ct, accurate);
416 _video_position = time_round_up (t, TIME_HZ / _film->video_frame_rate());
417 _audio_position = time_round_up (t, TIME_HZ / _film->audio_frame_rate());
419 _audio_merger.clear (_audio_position);
422 /* We just did an inaccurate seek, so it's likely that the next thing seen
423 out of pass() will be a fair distance from _{video,audio}_position. Setting
424 this flag stops pass() from trying to fix that: we assume that if it
425 was an inaccurate seek then the caller does not care too much about
426 inserting black/silence to keep the time tidy.
428 _just_did_inaccurate_seek = true;
433 Player::setup_pieces ()
435 list<shared_ptr<Piece> > old_pieces = _pieces;
438 ContentList content = _playlist->content ();
440 for (ContentList::iterator i = content.begin(); i != content.end(); ++i) {
442 shared_ptr<Decoder> decoder;
443 optional<FrameRateChange> frc;
445 shared_ptr<const FFmpegContent> fc = dynamic_pointer_cast<const FFmpegContent> (*i);
447 decoder.reset (new FFmpegDecoder (_film, fc, _video, _audio));
448 frc = FrameRateChange (fc->video_frame_rate(), _film->video_frame_rate());
451 shared_ptr<const ImageContent> ic = dynamic_pointer_cast<const ImageContent> (*i);
453 /* See if we can re-use an old ImageDecoder */
454 for (list<shared_ptr<Piece> >::const_iterator j = old_pieces.begin(); j != old_pieces.end(); ++j) {
455 shared_ptr<ImageDecoder> imd = dynamic_pointer_cast<ImageDecoder> ((*j)->decoder);
456 if (imd && imd->content() == ic) {
462 decoder.reset (new ImageDecoder (_film, ic));
465 frc = FrameRateChange (ic->video_frame_rate(), _film->video_frame_rate());
468 shared_ptr<const SndfileContent> sc = dynamic_pointer_cast<const SndfileContent> (*i);
470 decoder.reset (new SndfileDecoder (_film, sc));
472 /* Working out the frc for this content is a bit tricky: what if it overlaps
473 two pieces of video content with different frame rates? For now, use
474 the one with the best overlap.
477 DCPTime best_overlap_t = 0;
478 shared_ptr<VideoContent> best_overlap;
479 for (ContentList::iterator j = content.begin(); j != content.end(); ++j) {
480 shared_ptr<VideoContent> vc = dynamic_pointer_cast<VideoContent> (*j);
485 DCPTime const overlap = max (vc->position(), sc->position()) - min (vc->end(), sc->end());
486 if (overlap > best_overlap_t) {
488 best_overlap_t = overlap;
493 frc = FrameRateChange (best_overlap->video_frame_rate(), _film->video_frame_rate ());
495 /* No video overlap; e.g. if the DCP is just audio */
496 frc = FrameRateChange (_film->video_frame_rate(), _film->video_frame_rate ());
500 ContentTime st = (*i)->trim_start() * frc->speed_up;
501 decoder->seek (st, true);
503 _pieces.push_back (shared_ptr<Piece> (new Piece (*i, decoder, frc.get ())));
506 _have_valid_pieces = true;
508 /* The Piece for the _last_incoming_video will no longer be valid */
509 _last_incoming_video.video.reset ();
511 _video_position = _audio_position = 0;
515 Player::content_changed (weak_ptr<Content> w, int property, bool frequent)
517 shared_ptr<Content> c = w.lock ();
523 property == ContentProperty::POSITION || property == ContentProperty::LENGTH ||
524 property == ContentProperty::TRIM_START || property == ContentProperty::TRIM_END ||
525 property == VideoContentProperty::VIDEO_FRAME_TYPE
528 _have_valid_pieces = false;
531 } else if (property == SubtitleContentProperty::SUBTITLE_OFFSET || property == SubtitleContentProperty::SUBTITLE_SCALE) {
536 } else if (property == VideoContentProperty::VIDEO_CROP || property == VideoContentProperty::VIDEO_RATIO) {
540 } else if (property == ContentProperty::PATH) {
547 Player::playlist_changed ()
549 _have_valid_pieces = false;
554 Player::set_video_container_size (libdcp::Size s)
556 _video_container_size = s;
558 shared_ptr<Image> im (new Image (PIX_FMT_RGB24, _video_container_size, true));
565 _video_container_size,
566 _video_container_size,
567 Scaler::from_id ("bicubic")
573 Player::emit_black ()
575 #ifdef DCPOMATIC_DEBUG
576 _last_video.reset ();
579 Video (_black_frame, EYES_BOTH, ColourConversion(), _last_emit_was_black, _video_position);
580 _video_position += _film->video_frames_to_time (1);
581 _last_emit_was_black = true;
585 Player::emit_silence (DCPTime most)
591 DCPTime t = min (most, TIME_HZ / 2);
592 shared_ptr<AudioBuffers> silence (new AudioBuffers (_film->audio_channels(), t * _film->audio_frame_rate() / TIME_HZ));
593 silence->make_silent ();
594 Audio (silence, _audio_position);
596 _audio_position += t;
600 Player::film_changed (Film::Property p)
602 /* Here we should notice Film properties that affect our output, and
603 alert listeners that our output now would be different to how it was
604 last time we were run.
607 if (p == Film::SCALER || p == Film::WITH_SUBTITLES || p == Film::CONTAINER) {
613 Player::update_subtitle ()
615 shared_ptr<Piece> piece = _in_subtitle.piece.lock ();
620 if (!_in_subtitle.subtitle->image) {
621 _out_subtitle.image.reset ();
625 shared_ptr<SubtitleContent> sc = dynamic_pointer_cast<SubtitleContent> (piece->content);
628 dcpomatic::Rect<double> in_rect = _in_subtitle.subtitle->rect;
629 libdcp::Size scaled_size;
631 in_rect.y += sc->subtitle_offset ();
633 /* We will scale the subtitle up to fit _video_container_size, and also by the additional subtitle_scale */
634 scaled_size.width = in_rect.width * _video_container_size.width * sc->subtitle_scale ();
635 scaled_size.height = in_rect.height * _video_container_size.height * sc->subtitle_scale ();
637 /* Then we need a corrective translation, consisting of two parts:
639 * 1. that which is the result of the scaling of the subtitle by _video_container_size; this will be
640 * rect.x * _video_container_size.width and rect.y * _video_container_size.height.
642 * 2. that to shift the origin of the scale by subtitle_scale to the centre of the subtitle; this will be
643 * (width_before_subtitle_scale * (1 - subtitle_scale) / 2) and
644 * (height_before_subtitle_scale * (1 - subtitle_scale) / 2).
646 * Combining these two translations gives these expressions.
649 _out_subtitle.position.x = rint (_video_container_size.width * (in_rect.x + (in_rect.width * (1 - sc->subtitle_scale ()) / 2)));
650 _out_subtitle.position.y = rint (_video_container_size.height * (in_rect.y + (in_rect.height * (1 - sc->subtitle_scale ()) / 2)));
652 _out_subtitle.image = _in_subtitle.subtitle->image->scale (
654 Scaler::from_id ("bicubic"),
659 _out_subtitle.from = _in_subtitle.subtitle->dcp_time;
660 _out_subtitle.to = _in_subtitle.subtitle->dcp_time_to;
663 /** Re-emit the last frame that was emitted, using current settings for crop, ratio, scaler and subtitles.
664 * @return false if this could not be done.
667 Player::repeat_last_video ()
669 if (!_last_incoming_video.video || !_have_valid_pieces) {
674 _last_incoming_video.weak_piece,
675 _last_incoming_video.video
682 Player::set_approximate_size ()
684 _approximate_size = true;
688 PlayerImage::PlayerImage (
689 shared_ptr<const Image> in,
691 libdcp::Size inter_size,
692 libdcp::Size out_size,
693 Scaler const * scaler
697 , _inter_size (inter_size)
698 , _out_size (out_size)
705 PlayerImage::set_subtitle (shared_ptr<const Image> image, Position<int> pos)
707 _subtitle_image = image;
708 _subtitle_position = pos;
712 PlayerImage::image (AVPixelFormat format, bool aligned)
714 shared_ptr<Image> out = _in->crop_scale_window (_crop, _inter_size, _out_size, _scaler, format, aligned);
716 Position<int> const container_offset ((_out_size.width - _inter_size.width) / 2, (_out_size.height - _inter_size.width) / 2);
718 if (_subtitle_image) {
719 out->alpha_blend (_subtitle_image, _subtitle_position);
726 PlayerStatistics::dump (shared_ptr<Log> log) const
728 log->log (String::compose ("Video: %1 good %2 skipped %3 black %4 repeat", video.good, video.skip, video.black, video.repeat));
729 log->log (String::compose ("Audio: %1 good %2 skipped %3 silence", audio.good, audio.skip, audio.silence));
732 PlayerStatistics const &
733 Player::statistics () const