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"
34 #include "resampler.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)
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 /* XXX: don't know what to do with this */
119 shared_ptr<AudioContent> ac = dynamic_pointer_cast<AudioContent> ((*i)->content);
121 shared_ptr<Resampler> re = resampler (ac, false);
123 shared_ptr<const AudioBuffers> b = re->flush ();
125 process_audio (earliest, b, ac->audio_length ());
131 if (dec && dec->dcp_time < earliest_time) {
133 earliest_decoded = dec;
134 earliest_time = dec->dcp_time;
137 if (dynamic_pointer_cast<DecodedAudio> (dec) && dec->dcp_time < earliest_audio) {
138 earliest_audio = dec->dcp_time;
142 if (!earliest_piece) {
147 if (earliest_audio != TIME_MAX) {
148 TimedAudioBuffers<DCPTime> tb = _audio_merger.pull (earliest_audio);
149 Audio (tb.audio, tb.time);
150 _audio_position += _film->audio_frames_to_time (tb.audio->frames ());
153 /* Emit the earliest thing */
155 shared_ptr<DecodedVideo> dv = dynamic_pointer_cast<DecodedVideo> (earliest_decoded);
156 shared_ptr<DecodedAudio> da = dynamic_pointer_cast<DecodedAudio> (earliest_decoded);
157 shared_ptr<DecodedSubtitle> ds = dynamic_pointer_cast<DecodedSubtitle> (earliest_decoded);
160 if (!_just_did_inaccurate_seek && earliest_time > _video_position) {
161 /* XXX: if we're inside some content, repeat the last frame... otherwise emit black */
164 emit_video (earliest_piece, dv);
165 earliest_piece->decoder->get ();
168 if (!_just_did_inaccurate_seek && earliest_time > _audio_position) {
169 emit_silence (earliest_time - _audio_position);
171 emit_audio (earliest_piece, da);
172 earliest_piece->decoder->get ();
175 _in_subtitle.piece = earliest_piece;
176 _in_subtitle.subtitle = ds;
178 earliest_piece->decoder->get ();
181 _just_did_inaccurate_seek = false;
187 Player::emit_video (weak_ptr<Piece> weak_piece, shared_ptr<DecodedVideo> video)
189 /* Keep a note of what came in so that we can repeat it if required */
190 _last_incoming_video.weak_piece = weak_piece;
191 _last_incoming_video.video = video;
193 shared_ptr<Piece> piece = weak_piece.lock ();
198 shared_ptr<VideoContent> content = dynamic_pointer_cast<VideoContent> (piece->content);
201 FrameRateChange frc (content->video_frame_rate(), _film->video_frame_rate());
204 if (frc.skip && (frame % 2) == 1) {
209 if (content->trimmed (video->dcp_time - content->position ())) {
213 float const ratio = content->ratio() ? content->ratio()->ratio() : content->video_size_after_crop().ratio();
214 libdcp::Size const image_size = fit_ratio_within (ratio, _video_container_size);
216 shared_ptr<PlayerImage> pi (
221 _video_container_size,
227 _film->with_subtitles () &&
228 _out_subtitle.subtitle->image &&
229 video->dcp_time >= _out_subtitle.subtitle->dcp_time && video->dcp_time <= _out_subtitle.subtitle->dcp_time_to
232 Position<int> const container_offset (
233 (_video_container_size.width - image_size.width) / 2,
234 (_video_container_size.height - image_size.width) / 2
237 pi->set_subtitle (_out_subtitle.subtitle->image, _out_subtitle.position + container_offset);
240 #ifdef DCPOMATIC_DEBUG
241 _last_video = piece->content;
244 Video (pi, video->eyes, content->colour_conversion(), video->same, video->dcp_time);
246 _last_emit_was_black = false;
247 _video_position = rint (video->dcp_time + TIME_HZ / _film->video_frame_rate());
251 Player::emit_audio (weak_ptr<Piece> weak_piece, shared_ptr<DecodedAudio> audio)
253 shared_ptr<Piece> piece = weak_piece.lock ();
258 shared_ptr<AudioContent> content = dynamic_pointer_cast<AudioContent> (piece->content);
262 if (content->audio_gain() != 0) {
263 shared_ptr<AudioBuffers> gain (new AudioBuffers (audio->data));
264 gain->apply_gain (content->audio_gain ());
269 if (content->content_audio_frame_rate() != content->output_audio_frame_rate()) {
270 audio->data = resampler(content, true)->run (audio->data);
273 if (content->trimmed (audio->dcp_time - content->position ())) {
278 shared_ptr<AudioBuffers> dcp_mapped (new AudioBuffers (_film->audio_channels(), audio->data->frames()));
279 dcp_mapped->make_silent ();
280 list<pair<int, libdcp::Channel> > map = content->audio_mapping().content_to_dcp ();
281 for (list<pair<int, libdcp::Channel> >::iterator i = map.begin(); i != map.end(); ++i) {
282 if (i->first < audio->data->channels() && i->second < dcp_mapped->channels()) {
283 dcp_mapped->accumulate_channel (audio->data.get(), i->first, i->second);
287 audio->data = dcp_mapped;
290 audio->dcp_time += content->audio_delay() * TIME_HZ / 1000;
291 if (audio->dcp_time < 0) {
292 int const frames = - audio->dcp_time * _film->audio_frame_rate() / TIME_HZ;
293 if (frames >= audio->data->frames ()) {
297 shared_ptr<AudioBuffers> trimmed (new AudioBuffers (audio->data->channels(), audio->data->frames() - frames));
298 trimmed->copy_from (audio->data.get(), audio->data->frames() - frames, frames, 0);
300 audio->data = trimmed;
304 _audio_merger.push (audio->data, audio->dcp_time);
310 TimedAudioBuffers<DCPTime> tb = _audio_merger.flush ();
312 Audio (tb.audio, tb.time);
313 _audio_position += _film->audio_frames_to_time (tb.audio->frames ());
316 while (_video_position < _audio_position) {
320 while (_audio_position < _video_position) {
321 emit_silence (_video_position - _audio_position);
326 /** Seek so that the next pass() will yield (approximately) the requested frame.
327 * Pass accurate = true to try harder to get close to the request.
328 * @return true on error
331 Player::seek (DCPTime t, bool accurate)
333 if (!_have_valid_pieces) {
337 if (_pieces.empty ()) {
341 for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
342 /* s is the offset of t from the start position of this content */
343 DCPTime s = t - (*i)->content->position ();
344 s = max (static_cast<DCPTime> (0), s);
345 s = min ((*i)->content->length_after_trim(), s);
347 /* Convert this to the content time */
348 ContentTime ct = (s * (*i)->frc.speed_up) + (*i)->content->trim_start ();
350 /* And seek the decoder */
351 (*i)->decoder->seek (ct, accurate);
354 _video_position = _audio_position = t;
355 _audio_merger.clear (t);
358 /* We just did an inaccurate seek, so it's likely that the next thing seen
359 out of pass() will be a fair distance from _{video,audio}_position. Setting
360 this flag stops pass() from trying to fix that: we assume that if it
361 was an inaccurate seek then the caller does not care too much about
362 inserting black/silence to keep the time tidy.
364 _just_did_inaccurate_seek = true;
369 Player::setup_pieces ()
371 list<shared_ptr<Piece> > old_pieces = _pieces;
374 ContentList content = _playlist->content ();
376 for (ContentList::iterator i = content.begin(); i != content.end(); ++i) {
378 shared_ptr<Decoder> decoder;
379 optional<FrameRateChange> frc;
381 shared_ptr<const FFmpegContent> fc = dynamic_pointer_cast<const FFmpegContent> (*i);
383 decoder.reset (new FFmpegDecoder (_film, fc, _video, _audio));
384 frc = FrameRateChange (fc->video_frame_rate(), _film->video_frame_rate());
387 shared_ptr<const ImageContent> ic = dynamic_pointer_cast<const ImageContent> (*i);
389 /* See if we can re-use an old ImageDecoder */
390 for (list<shared_ptr<Piece> >::const_iterator j = old_pieces.begin(); j != old_pieces.end(); ++j) {
391 shared_ptr<ImageDecoder> imd = dynamic_pointer_cast<ImageDecoder> ((*j)->decoder);
392 if (imd && imd->content() == ic) {
398 decoder.reset (new ImageDecoder (_film, ic));
401 frc = FrameRateChange (ic->video_frame_rate(), _film->video_frame_rate());
404 shared_ptr<const SndfileContent> sc = dynamic_pointer_cast<const SndfileContent> (*i);
406 decoder.reset (new SndfileDecoder (_film, sc));
408 /* Working out the frc for this content is a bit tricky: what if it overlaps
409 two pieces of video content with different frame rates? For now, use
410 the one with the best overlap.
413 DCPTime best_overlap_t = 0;
414 shared_ptr<VideoContent> best_overlap;
415 for (ContentList::iterator j = content.begin(); j != content.end(); ++j) {
416 shared_ptr<VideoContent> vc = dynamic_pointer_cast<VideoContent> (*j);
421 DCPTime const overlap = max (vc->position(), sc->position()) - min (vc->end(), sc->end());
422 if (overlap > best_overlap_t) {
424 best_overlap_t = overlap;
429 frc = FrameRateChange (best_overlap->video_frame_rate(), _film->video_frame_rate ());
431 /* No video overlap; e.g. if the DCP is just audio */
432 frc = FrameRateChange (_film->video_frame_rate(), _film->video_frame_rate ());
436 decoder->seek ((*i)->trim_start (), true);
438 _pieces.push_back (shared_ptr<Piece> (new Piece (*i, decoder, frc.get ())));
441 _have_valid_pieces = true;
445 Player::content_changed (weak_ptr<Content> w, int property, bool frequent)
447 shared_ptr<Content> c = w.lock ();
453 property == ContentProperty::POSITION || property == ContentProperty::LENGTH ||
454 property == ContentProperty::TRIM_START || property == ContentProperty::TRIM_END
457 _have_valid_pieces = false;
460 } else if (property == SubtitleContentProperty::SUBTITLE_OFFSET || property == SubtitleContentProperty::SUBTITLE_SCALE) {
466 property == VideoContentProperty::VIDEO_FRAME_TYPE || property == VideoContentProperty::VIDEO_CROP ||
467 property == VideoContentProperty::VIDEO_RATIO
472 } else if (property == ContentProperty::PATH) {
479 Player::playlist_changed ()
481 _have_valid_pieces = false;
486 Player::set_video_container_size (libdcp::Size s)
488 _video_container_size = s;
490 shared_ptr<Image> im (new Image (PIX_FMT_RGB24, _video_container_size, true));
497 _video_container_size,
498 _video_container_size,
499 Scaler::from_id ("bicubic")
504 shared_ptr<Resampler>
505 Player::resampler (shared_ptr<AudioContent> c, bool create)
507 map<shared_ptr<AudioContent>, shared_ptr<Resampler> >::iterator i = _resamplers.find (c);
508 if (i != _resamplers.end ()) {
513 return shared_ptr<Resampler> ();
518 "Creating new resampler for %1 to %2 with %3 channels", c->content_audio_frame_rate(), c->output_audio_frame_rate(), c->audio_channels()
522 shared_ptr<Resampler> r (new Resampler (c->content_audio_frame_rate(), c->output_audio_frame_rate(), c->audio_channels()));
528 Player::emit_black ()
530 #ifdef DCPOMATIC_DEBUG
531 _last_video.reset ();
534 Video (_black_frame, EYES_BOTH, ColourConversion(), _last_emit_was_black, _video_position);
535 _video_position += _film->video_frames_to_time (1);
536 _last_emit_was_black = true;
540 Player::emit_silence (DCPTime most)
546 DCPTime t = min (most, TIME_HZ / 2);
547 shared_ptr<AudioBuffers> silence (new AudioBuffers (_film->audio_channels(), t * _film->audio_frame_rate() / TIME_HZ));
548 silence->make_silent ();
549 Audio (silence, _audio_position);
550 _audio_position += t;
554 Player::film_changed (Film::Property p)
556 /* Here we should notice Film properties that affect our output, and
557 alert listeners that our output now would be different to how it was
558 last time we were run.
561 if (p == Film::SCALER || p == Film::WITH_SUBTITLES || p == Film::CONTAINER) {
567 Player::update_subtitle ()
569 shared_ptr<Piece> piece = _in_subtitle.piece.lock ();
574 if (!_in_subtitle.subtitle->image) {
575 _out_subtitle.subtitle->image.reset ();
579 shared_ptr<SubtitleContent> sc = dynamic_pointer_cast<SubtitleContent> (piece->content);
582 dcpomatic::Rect<double> in_rect = _in_subtitle.subtitle->rect;
583 libdcp::Size scaled_size;
585 in_rect.y += sc->subtitle_offset ();
587 /* We will scale the subtitle up to fit _video_container_size, and also by the additional subtitle_scale */
588 scaled_size.width = in_rect.width * _video_container_size.width * sc->subtitle_scale ();
589 scaled_size.height = in_rect.height * _video_container_size.height * sc->subtitle_scale ();
591 /* Then we need a corrective translation, consisting of two parts:
593 * 1. that which is the result of the scaling of the subtitle by _video_container_size; this will be
594 * rect.x * _video_container_size.width and rect.y * _video_container_size.height.
596 * 2. that to shift the origin of the scale by subtitle_scale to the centre of the subtitle; this will be
597 * (width_before_subtitle_scale * (1 - subtitle_scale) / 2) and
598 * (height_before_subtitle_scale * (1 - subtitle_scale) / 2).
600 * Combining these two translations gives these expressions.
603 _out_subtitle.position.x = rint (_video_container_size.width * (in_rect.x + (in_rect.width * (1 - sc->subtitle_scale ()) / 2)));
604 _out_subtitle.position.y = rint (_video_container_size.height * (in_rect.y + (in_rect.height * (1 - sc->subtitle_scale ()) / 2)));
606 _out_subtitle.subtitle->image = _in_subtitle.subtitle->image->scale (
608 Scaler::from_id ("bicubic"),
609 _in_subtitle.subtitle->image->pixel_format (),
613 _out_subtitle.subtitle->dcp_time = _in_subtitle.subtitle->dcp_time;
614 _out_subtitle.subtitle->dcp_time = _in_subtitle.subtitle->dcp_time;
617 /** Re-emit the last frame that was emitted, using current settings for crop, ratio, scaler and subtitles.
618 * @return false if this could not be done.
621 Player::repeat_last_video ()
623 if (!_last_incoming_video.video || !_have_valid_pieces) {
628 _last_incoming_video.weak_piece,
629 _last_incoming_video.video
635 PlayerImage::PlayerImage (
636 shared_ptr<const Image> in,
638 libdcp::Size inter_size,
639 libdcp::Size out_size,
640 Scaler const * scaler
644 , _inter_size (inter_size)
645 , _out_size (out_size)
652 PlayerImage::set_subtitle (shared_ptr<const Image> image, Position<int> pos)
654 _subtitle_image = image;
655 _subtitle_position = pos;
659 PlayerImage::image ()
661 shared_ptr<Image> out = _in->crop_scale_window (_crop, _inter_size, _out_size, _scaler, PIX_FMT_RGB24, false);
663 Position<int> const container_offset ((_out_size.width - _inter_size.width) / 2, (_out_size.height - _inter_size.width) / 2);
665 if (_subtitle_image) {
666 out->alpha_blend (_subtitle_image, _subtitle_position);