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 _just_did_inaccurate_seek = false;
194 } else if (da && _audio) {
196 if (da->dcp_time - _audio_position > margin) {
198 emit_silence (da->dcp_time - _audio_position);
200 } else if (abs (da->dcp_time - _audio_position) < margin) {
202 emit_audio (earliest_piece, da);
204 /* Too far behind: skip */
207 } else if (ds && _video) {
208 _in_subtitle.piece = earliest_piece;
209 _in_subtitle.subtitle = ds;
214 earliest_piece->decoder->consume ();
221 Player::emit_video (weak_ptr<Piece> weak_piece, shared_ptr<DecodedVideo> video)
223 /* Keep a note of what came in so that we can repeat it if required */
224 _last_incoming_video.weak_piece = weak_piece;
225 _last_incoming_video.video = video;
227 shared_ptr<Piece> piece = weak_piece.lock ();
232 shared_ptr<VideoContent> content = dynamic_pointer_cast<VideoContent> (piece->content);
235 FrameRateChange frc (content->video_frame_rate(), _film->video_frame_rate());
237 float const ratio = content->ratio() ? content->ratio()->ratio() : content->video_size_after_crop().ratio();
238 libdcp::Size image_size = fit_ratio_within (ratio, _video_container_size);
239 if (_approximate_size) {
240 image_size.width &= ~3;
241 image_size.height &= ~3;
244 shared_ptr<PlayerImage> pi (
249 _video_container_size,
255 _film->with_subtitles () &&
256 _out_subtitle.image &&
257 video->dcp_time >= _out_subtitle.from && video->dcp_time <= _out_subtitle.to
260 Position<int> const container_offset (
261 (_video_container_size.width - image_size.width) / 2,
262 (_video_container_size.height - image_size.height) / 2
265 pi->set_subtitle (_out_subtitle.image, _out_subtitle.position + container_offset);
268 #ifdef DCPOMATIC_DEBUG
269 _last_video = piece->content;
272 Video (pi, video->eyes, content->colour_conversion(), video->same, video->dcp_time);
274 _last_emit_was_black = false;
278 Player::step_video_position (shared_ptr<DecodedVideo> video)
280 /* This is a bit of a hack; don't update _video_position if EYES_RIGHT is on its way */
281 if (video->eyes != EYES_LEFT) {
282 /* This assumes that the video_frames_to_time conversion is exact
283 so that there are no accumulated errors caused by rounding.
285 _video_position += _film->video_frames_to_time (1);
290 Player::emit_audio (weak_ptr<Piece> weak_piece, shared_ptr<DecodedAudio> audio)
292 shared_ptr<Piece> piece = weak_piece.lock ();
297 shared_ptr<AudioContent> content = dynamic_pointer_cast<AudioContent> (piece->content);
301 if (content->audio_gain() != 0) {
302 shared_ptr<AudioBuffers> gain (new AudioBuffers (audio->data));
303 gain->apply_gain (content->audio_gain ());
307 if (content->trimmed (audio->dcp_time - content->position ())) {
312 shared_ptr<AudioBuffers> dcp_mapped (new AudioBuffers (_film->audio_channels(), audio->data->frames()));
313 dcp_mapped->make_silent ();
314 list<pair<int, libdcp::Channel> > map = content->audio_mapping().content_to_dcp ();
315 for (list<pair<int, libdcp::Channel> >::iterator i = map.begin(); i != map.end(); ++i) {
316 if (i->first < audio->data->channels() && i->second < dcp_mapped->channels()) {
317 dcp_mapped->accumulate_channel (audio->data.get(), i->first, i->second);
321 audio->data = dcp_mapped;
324 audio->dcp_time += content->audio_delay() * TIME_HZ / 1000;
325 if (audio->dcp_time < 0) {
326 int const frames = - audio->dcp_time * _film->audio_frame_rate() / TIME_HZ;
327 if (frames >= audio->data->frames ()) {
331 shared_ptr<AudioBuffers> trimmed (new AudioBuffers (audio->data->channels(), audio->data->frames() - frames));
332 trimmed->copy_from (audio->data.get(), audio->data->frames() - frames, frames, 0);
334 audio->data = trimmed;
338 _audio_merger.push (audio->data, audio->dcp_time);
344 TimedAudioBuffers<DCPTime> tb = _audio_merger.flush ();
346 Audio (tb.audio, tb.time);
347 _audio_position += _film->audio_frames_to_time (tb.audio->frames ());
350 while (_video_position < _audio_position) {
354 while (_audio_position < _video_position) {
355 emit_silence (_video_position - _audio_position);
360 /** Seek so that the next pass() will yield (approximately) the requested frame.
361 * Pass accurate = true to try harder to get close to the request.
362 * @return true on error
365 Player::seek (DCPTime t, bool accurate)
367 if (!_have_valid_pieces) {
371 if (_pieces.empty ()) {
375 for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
376 /* s is the offset of t from the start position of this content */
377 DCPTime s = t - (*i)->content->position ();
378 s = max (static_cast<DCPTime> (0), s);
379 s = min ((*i)->content->length_after_trim(), s);
381 /* Convert this to the content time */
382 ContentTime ct = (s * (*i)->frc.speed_up) + (*i)->content->trim_start ();
384 /* And seek the decoder */
385 (*i)->decoder->seek (ct, accurate);
388 _video_position = time_round_up (t, TIME_HZ / _film->video_frame_rate());
389 _audio_position = time_round_up (t, TIME_HZ / _film->audio_frame_rate());
391 _audio_merger.clear (_audio_position);
394 /* We just did an inaccurate seek, so it's likely that the next thing seen
395 out of pass() will be a fair distance from _{video,audio}_position. Setting
396 this flag stops pass() from trying to fix that: we assume that if it
397 was an inaccurate seek then the caller does not care too much about
398 inserting black/silence to keep the time tidy.
400 _just_did_inaccurate_seek = true;
405 Player::setup_pieces ()
407 list<shared_ptr<Piece> > old_pieces = _pieces;
410 ContentList content = _playlist->content ();
412 for (ContentList::iterator i = content.begin(); i != content.end(); ++i) {
414 shared_ptr<Decoder> decoder;
415 optional<FrameRateChange> frc;
417 shared_ptr<const FFmpegContent> fc = dynamic_pointer_cast<const FFmpegContent> (*i);
419 decoder.reset (new FFmpegDecoder (_film, fc, _video, _audio));
420 frc = FrameRateChange (fc->video_frame_rate(), _film->video_frame_rate());
423 shared_ptr<const ImageContent> ic = dynamic_pointer_cast<const ImageContent> (*i);
425 /* See if we can re-use an old ImageDecoder */
426 for (list<shared_ptr<Piece> >::const_iterator j = old_pieces.begin(); j != old_pieces.end(); ++j) {
427 shared_ptr<ImageDecoder> imd = dynamic_pointer_cast<ImageDecoder> ((*j)->decoder);
428 if (imd && imd->content() == ic) {
434 decoder.reset (new ImageDecoder (_film, ic));
437 frc = FrameRateChange (ic->video_frame_rate(), _film->video_frame_rate());
440 shared_ptr<const SndfileContent> sc = dynamic_pointer_cast<const SndfileContent> (*i);
442 decoder.reset (new SndfileDecoder (_film, sc));
444 /* Working out the frc for this content is a bit tricky: what if it overlaps
445 two pieces of video content with different frame rates? For now, use
446 the one with the best overlap.
449 DCPTime best_overlap_t = 0;
450 shared_ptr<VideoContent> best_overlap;
451 for (ContentList::iterator j = content.begin(); j != content.end(); ++j) {
452 shared_ptr<VideoContent> vc = dynamic_pointer_cast<VideoContent> (*j);
457 DCPTime const overlap = max (vc->position(), sc->position()) - min (vc->end(), sc->end());
458 if (overlap > best_overlap_t) {
460 best_overlap_t = overlap;
465 frc = FrameRateChange (best_overlap->video_frame_rate(), _film->video_frame_rate ());
467 /* No video overlap; e.g. if the DCP is just audio */
468 frc = FrameRateChange (_film->video_frame_rate(), _film->video_frame_rate ());
472 decoder->seek ((*i)->trim_start (), true);
474 _pieces.push_back (shared_ptr<Piece> (new Piece (*i, decoder, frc.get ())));
477 _have_valid_pieces = true;
479 /* The Piece for the _last_incoming_video will no longer be valid */
480 _last_incoming_video.video.reset ();
482 _video_position = _audio_position = 0;
486 Player::content_changed (weak_ptr<Content> w, int property, bool frequent)
488 shared_ptr<Content> c = w.lock ();
494 property == ContentProperty::POSITION || property == ContentProperty::LENGTH ||
495 property == ContentProperty::TRIM_START || property == ContentProperty::TRIM_END ||
496 property == VideoContentProperty::VIDEO_FRAME_TYPE
499 _have_valid_pieces = false;
502 } else if (property == SubtitleContentProperty::SUBTITLE_OFFSET || property == SubtitleContentProperty::SUBTITLE_SCALE) {
507 } else if (property == VideoContentProperty::VIDEO_CROP || property == VideoContentProperty::VIDEO_RATIO) {
511 } else if (property == ContentProperty::PATH) {
518 Player::playlist_changed ()
520 _have_valid_pieces = false;
525 Player::set_video_container_size (libdcp::Size s)
527 _video_container_size = s;
529 shared_ptr<Image> im (new Image (PIX_FMT_RGB24, _video_container_size, true));
536 _video_container_size,
537 _video_container_size,
538 Scaler::from_id ("bicubic")
544 Player::emit_black ()
546 #ifdef DCPOMATIC_DEBUG
547 _last_video.reset ();
550 Video (_black_frame, EYES_BOTH, ColourConversion(), _last_emit_was_black, _video_position);
551 _video_position += _film->video_frames_to_time (1);
552 _last_emit_was_black = true;
556 Player::emit_silence (DCPTime most)
562 DCPTime t = min (most, TIME_HZ / 2);
563 shared_ptr<AudioBuffers> silence (new AudioBuffers (_film->audio_channels(), t * _film->audio_frame_rate() / TIME_HZ));
564 silence->make_silent ();
565 Audio (silence, _audio_position);
567 _audio_position += t;
571 Player::film_changed (Film::Property p)
573 /* Here we should notice Film properties that affect our output, and
574 alert listeners that our output now would be different to how it was
575 last time we were run.
578 if (p == Film::SCALER || p == Film::WITH_SUBTITLES || p == Film::CONTAINER) {
584 Player::update_subtitle ()
586 shared_ptr<Piece> piece = _in_subtitle.piece.lock ();
591 if (!_in_subtitle.subtitle->image) {
592 _out_subtitle.image.reset ();
596 shared_ptr<SubtitleContent> sc = dynamic_pointer_cast<SubtitleContent> (piece->content);
599 dcpomatic::Rect<double> in_rect = _in_subtitle.subtitle->rect;
600 libdcp::Size scaled_size;
602 in_rect.y += sc->subtitle_offset ();
604 /* We will scale the subtitle up to fit _video_container_size, and also by the additional subtitle_scale */
605 scaled_size.width = in_rect.width * _video_container_size.width * sc->subtitle_scale ();
606 scaled_size.height = in_rect.height * _video_container_size.height * sc->subtitle_scale ();
608 /* Then we need a corrective translation, consisting of two parts:
610 * 1. that which is the result of the scaling of the subtitle by _video_container_size; this will be
611 * rect.x * _video_container_size.width and rect.y * _video_container_size.height.
613 * 2. that to shift the origin of the scale by subtitle_scale to the centre of the subtitle; this will be
614 * (width_before_subtitle_scale * (1 - subtitle_scale) / 2) and
615 * (height_before_subtitle_scale * (1 - subtitle_scale) / 2).
617 * Combining these two translations gives these expressions.
620 _out_subtitle.position.x = rint (_video_container_size.width * (in_rect.x + (in_rect.width * (1 - sc->subtitle_scale ()) / 2)));
621 _out_subtitle.position.y = rint (_video_container_size.height * (in_rect.y + (in_rect.height * (1 - sc->subtitle_scale ()) / 2)));
623 _out_subtitle.image = _in_subtitle.subtitle->image->scale (
625 Scaler::from_id ("bicubic"),
630 _out_subtitle.from = _in_subtitle.subtitle->dcp_time;
631 _out_subtitle.to = _in_subtitle.subtitle->dcp_time_to;
634 /** Re-emit the last frame that was emitted, using current settings for crop, ratio, scaler and subtitles.
635 * @return false if this could not be done.
638 Player::repeat_last_video ()
640 if (!_last_incoming_video.video || !_have_valid_pieces) {
645 _last_incoming_video.weak_piece,
646 _last_incoming_video.video
653 Player::set_approximate_size ()
655 _approximate_size = true;
659 PlayerImage::PlayerImage (
660 shared_ptr<const Image> in,
662 libdcp::Size inter_size,
663 libdcp::Size out_size,
664 Scaler const * scaler
668 , _inter_size (inter_size)
669 , _out_size (out_size)
676 PlayerImage::set_subtitle (shared_ptr<const Image> image, Position<int> pos)
678 _subtitle_image = image;
679 _subtitle_position = pos;
683 PlayerImage::image (AVPixelFormat format, bool aligned)
685 shared_ptr<Image> out = _in->crop_scale_window (_crop, _inter_size, _out_size, _scaler, format, aligned);
687 Position<int> const container_offset ((_out_size.width - _inter_size.width) / 2, (_out_size.height - _inter_size.width) / 2);
689 if (_subtitle_image) {
690 out->alpha_blend (_subtitle_image, _subtitle_position);