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;
52 Piece (shared_ptr<Content> c)
54 , video_position (c->position ())
55 , audio_position (c->position ())
60 Piece (shared_ptr<Content> c, shared_ptr<Decoder> d)
63 , video_position (c->position ())
64 , audio_position (c->position ())
67 /** Set this piece to repeat a video frame a given number of times */
68 void set_repeat (IncomingVideo video, int num)
77 repeat_video.image.reset ();
82 bool repeating () const
84 return repeat_done != repeat_to_do;
87 void repeat (Player* player)
89 player->process_video (
90 repeat_video.weak_piece,
95 (repeat_done + 1) * (TIME_HZ / player->_film->video_frame_rate ())
101 shared_ptr<Content> content;
102 shared_ptr<Decoder> decoder;
103 /** Time of the last video we emitted relative to the start of the DCP */
105 /** Time of the last audio we emitted relative to the start of the DCP */
108 IncomingVideo repeat_video;
113 Player::Player (shared_ptr<const Film> f, shared_ptr<const Playlist> p)
118 , _have_valid_pieces (false)
119 , _video_position (0)
120 , _audio_position (0)
121 , _audio_merger (f->audio_channels(), bind (&Film::time_to_audio_frames, f.get(), _1), bind (&Film::audio_frames_to_time, f.get(), _1))
122 , _last_emit_was_black (false)
124 _playlist_changed_connection = _playlist->Changed.connect (bind (&Player::playlist_changed, this));
125 _playlist_content_changed_connection = _playlist->ContentChanged.connect (bind (&Player::content_changed, this, _1, _2, _3));
126 _film_changed_connection = _film->Changed.connect (bind (&Player::film_changed, this, _1));
127 set_video_container_size (fit_ratio_within (_film->container()->ratio (), _film->full_frame ()));
131 Player::disable_video ()
137 Player::disable_audio ()
145 if (!_have_valid_pieces) {
149 Time earliest_t = TIME_MAX;
150 shared_ptr<Piece> earliest;
156 for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
157 if ((*i)->decoder->done ()) {
161 shared_ptr<VideoDecoder> vd = dynamic_pointer_cast<VideoDecoder> ((*i)->decoder);
162 shared_ptr<AudioDecoder> ad = dynamic_pointer_cast<AudioDecoder> ((*i)->decoder);
165 if ((*i)->video_position < earliest_t) {
166 earliest_t = (*i)->video_position;
172 if (_audio && ad && ad->has_audio ()) {
173 if ((*i)->audio_position < earliest_t) {
174 earliest_t = (*i)->audio_position;
188 if (earliest_t > _video_position) {
191 if (earliest->repeating ()) {
192 earliest->repeat (this);
194 earliest->decoder->pass ();
200 if (earliest_t > _audio_position) {
201 emit_silence (_film->time_to_audio_frames (earliest_t - _audio_position));
203 earliest->decoder->pass ();
205 if (earliest->decoder->done()) {
206 shared_ptr<AudioContent> ac = dynamic_pointer_cast<AudioContent> (earliest->content);
208 shared_ptr<Resampler> re = resampler (ac, false);
210 shared_ptr<const AudioBuffers> b = re->flush ();
212 process_audio (earliest, b, ac->audio_length ());
221 boost::optional<Time> audio_done_up_to;
222 for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
223 if ((*i)->decoder->done ()) {
227 if (dynamic_pointer_cast<AudioDecoder> ((*i)->decoder)) {
228 audio_done_up_to = min (audio_done_up_to.get_value_or (TIME_MAX), (*i)->audio_position);
232 if (audio_done_up_to) {
233 TimedAudioBuffers<Time> tb = _audio_merger.pull (audio_done_up_to.get ());
234 Audio (tb.audio, tb.time);
235 _audio_position += _film->audio_frames_to_time (tb.audio->frames ());
242 /** @param extra Amount of extra time to add to the content frame's time (for repeat) */
244 Player::process_video (weak_ptr<Piece> weak_piece, shared_ptr<const Image> image, Eyes eyes, bool same, VideoContent::Frame frame, Time extra)
246 /* Keep a note of what came in so that we can repeat it if required */
247 _last_incoming_video.weak_piece = weak_piece;
248 _last_incoming_video.image = image;
249 _last_incoming_video.eyes = eyes;
250 _last_incoming_video.same = same;
251 _last_incoming_video.frame = frame;
252 _last_incoming_video.extra = extra;
254 shared_ptr<Piece> piece = weak_piece.lock ();
259 shared_ptr<VideoContent> content = dynamic_pointer_cast<VideoContent> (piece->content);
262 FrameRateConversion frc (content->video_frame_rate(), _film->video_frame_rate());
263 if (frc.skip && (frame % 2) == 1) {
267 Time const relative_time = (frame * frc.factor() * TIME_HZ / _film->video_frame_rate());
268 if (content->trimmed (relative_time)) {
272 Time const time = content->position() + relative_time + extra - content->trim_start ();
273 float const ratio = content->ratio() ? content->ratio()->ratio() : content->video_size_after_crop().ratio();
274 libdcp::Size const image_size = fit_ratio_within (ratio, _video_container_size);
276 shared_ptr<PlayerImage> pi (
281 _video_container_size,
286 if (_film->with_subtitles () && _out_subtitle.image && time >= _out_subtitle.from && time <= _out_subtitle.to) {
288 Position<int> const container_offset (
289 (_video_container_size.width - image_size.width) / 2,
290 (_video_container_size.height - image_size.width) / 2
293 pi->set_subtitle (_out_subtitle.image, _out_subtitle.position + container_offset);
296 #ifdef DCPOMATIC_DEBUG
297 _last_video = piece->content;
300 Video (pi, eyes, content->colour_conversion(), same, time);
302 _last_emit_was_black = false;
303 _video_position = piece->video_position = (time + TIME_HZ / _film->video_frame_rate());
305 if (frc.repeat > 1 && !piece->repeating ()) {
306 piece->set_repeat (_last_incoming_video, frc.repeat - 1);
311 Player::process_audio (weak_ptr<Piece> weak_piece, shared_ptr<const AudioBuffers> audio, AudioContent::Frame frame)
313 shared_ptr<Piece> piece = weak_piece.lock ();
318 shared_ptr<AudioContent> content = dynamic_pointer_cast<AudioContent> (piece->content);
322 if (content->audio_gain() != 0) {
323 shared_ptr<AudioBuffers> gain (new AudioBuffers (audio));
324 gain->apply_gain (content->audio_gain ());
329 if (content->content_audio_frame_rate() != content->output_audio_frame_rate()) {
330 shared_ptr<Resampler> r = resampler (content, true);
331 pair<shared_ptr<const AudioBuffers>, AudioContent::Frame> ro = r->run (audio, frame);
336 Time const relative_time = _film->audio_frames_to_time (frame);
338 if (content->trimmed (relative_time)) {
342 Time time = content->position() + (content->audio_delay() * TIME_HZ / 1000) + relative_time - content->trim_start ();
345 shared_ptr<AudioBuffers> dcp_mapped (new AudioBuffers (_film->audio_channels(), audio->frames()));
346 dcp_mapped->make_silent ();
348 AudioMapping map = content->audio_mapping ();
349 for (int i = 0; i < map.content_channels(); ++i) {
350 for (int j = 0; j < _film->audio_channels(); ++j) {
351 if (map.get (i, static_cast<libdcp::Channel> (j)) > 0) {
352 dcp_mapped->accumulate_channel (
355 static_cast<libdcp::Channel> (j),
356 map.get (i, static_cast<libdcp::Channel> (j))
364 /* We must cut off anything that comes before the start of all time */
366 int const frames = - time * _film->audio_frame_rate() / TIME_HZ;
367 if (frames >= audio->frames ()) {
371 shared_ptr<AudioBuffers> trimmed (new AudioBuffers (audio->channels(), audio->frames() - frames));
372 trimmed->copy_from (audio.get(), audio->frames() - frames, frames, 0);
378 _audio_merger.push (audio, time);
379 piece->audio_position += _film->audio_frames_to_time (audio->frames ());
385 TimedAudioBuffers<Time> tb = _audio_merger.flush ();
386 if (_audio && tb.audio) {
387 Audio (tb.audio, tb.time);
388 _audio_position += _film->audio_frames_to_time (tb.audio->frames ());
391 while (_video && _video_position < _audio_position) {
395 while (_audio && _audio_position < _video_position) {
396 emit_silence (_film->time_to_audio_frames (_video_position - _audio_position));
401 /** Seek so that the next pass() will yield (approximately) the requested frame.
402 * Pass accurate = true to try harder to get close to the request.
403 * @return true on error
406 Player::seek (Time t, bool accurate)
408 if (!_have_valid_pieces) {
412 if (_pieces.empty ()) {
416 for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
417 shared_ptr<VideoContent> vc = dynamic_pointer_cast<VideoContent> ((*i)->content);
422 /* s is the offset of t from the start position of this content */
423 Time s = t - vc->position ();
424 s = max (static_cast<Time> (0), s);
425 s = min (vc->length_after_trim(), s);
427 /* Hence set the piece positions to the `global' time */
428 (*i)->video_position = (*i)->audio_position = vc->position() + s;
430 /* And seek the decoder */
431 dynamic_pointer_cast<VideoDecoder>((*i)->decoder)->seek (
432 vc->time_to_content_video_frames (s + vc->trim_start ()), accurate
435 (*i)->reset_repeat ();
438 _video_position = _audio_position = t;
440 /* XXX: don't seek audio because we don't need to... */
444 Player::setup_pieces ()
446 list<shared_ptr<Piece> > old_pieces = _pieces;
450 ContentList content = _playlist->content ();
451 sort (content.begin(), content.end(), ContentSorter ());
453 for (ContentList::iterator i = content.begin(); i != content.end(); ++i) {
455 shared_ptr<Piece> piece (new Piece (*i));
457 /* XXX: into content? */
459 shared_ptr<const FFmpegContent> fc = dynamic_pointer_cast<const FFmpegContent> (*i);
461 shared_ptr<FFmpegDecoder> fd (new FFmpegDecoder (_film, fc, _video, _audio));
463 fd->Video.connect (bind (&Player::process_video, this, weak_ptr<Piece> (piece), _1, _2, _3, _4, 0));
464 fd->Audio.connect (bind (&Player::process_audio, this, weak_ptr<Piece> (piece), _1, _2));
465 fd->Subtitle.connect (bind (&Player::process_subtitle, this, weak_ptr<Piece> (piece), _1, _2, _3, _4));
467 fd->seek (fc->time_to_content_video_frames (fc->trim_start ()), true);
471 shared_ptr<const ImageContent> ic = dynamic_pointer_cast<const ImageContent> (*i);
473 bool reusing = false;
475 /* See if we can re-use an old ImageDecoder */
476 for (list<shared_ptr<Piece> >::const_iterator j = old_pieces.begin(); j != old_pieces.end(); ++j) {
477 shared_ptr<ImageDecoder> imd = dynamic_pointer_cast<ImageDecoder> ((*j)->decoder);
478 if (imd && imd->content() == ic) {
485 shared_ptr<ImageDecoder> id (new ImageDecoder (_film, ic));
486 id->Video.connect (bind (&Player::process_video, this, weak_ptr<Piece> (piece), _1, _2, _3, _4, 0));
491 shared_ptr<const SndfileContent> sc = dynamic_pointer_cast<const SndfileContent> (*i);
493 shared_ptr<AudioDecoder> sd (new SndfileDecoder (_film, sc));
494 sd->Audio.connect (bind (&Player::process_audio, this, weak_ptr<Piece> (piece), _1, _2));
499 _pieces.push_back (piece);
502 _have_valid_pieces = true;
506 Player::content_changed (weak_ptr<Content> w, int property, bool frequent)
508 shared_ptr<Content> c = w.lock ();
514 property == ContentProperty::POSITION || property == ContentProperty::LENGTH ||
515 property == ContentProperty::TRIM_START || property == ContentProperty::TRIM_END ||
516 property == VideoContentProperty::VIDEO_FRAME_TYPE
519 _have_valid_pieces = false;
522 } else if (property == SubtitleContentProperty::SUBTITLE_OFFSET || property == SubtitleContentProperty::SUBTITLE_SCALE) {
528 property == VideoContentProperty::VIDEO_CROP || property == VideoContentProperty::VIDEO_RATIO ||
529 property == VideoContentProperty::VIDEO_FRAME_RATE
534 } else if (property == ContentProperty::PATH) {
541 Player::playlist_changed ()
543 _have_valid_pieces = false;
548 Player::set_video_container_size (libdcp::Size s)
550 _video_container_size = s;
552 shared_ptr<Image> im (new Image (PIX_FMT_RGB24, _video_container_size, true));
559 _video_container_size,
560 _video_container_size,
561 Scaler::from_id ("bicubic")
566 shared_ptr<Resampler>
567 Player::resampler (shared_ptr<AudioContent> c, bool create)
569 map<shared_ptr<AudioContent>, shared_ptr<Resampler> >::iterator i = _resamplers.find (c);
570 if (i != _resamplers.end ()) {
575 return shared_ptr<Resampler> ();
580 "Creating new resampler for %1 to %2 with %3 channels", c->content_audio_frame_rate(), c->output_audio_frame_rate(), c->audio_channels()
584 shared_ptr<Resampler> r (new Resampler (c->content_audio_frame_rate(), c->output_audio_frame_rate(), c->audio_channels()));
590 Player::emit_black ()
592 #ifdef DCPOMATIC_DEBUG
593 _last_video.reset ();
596 Video (_black_frame, EYES_BOTH, ColourConversion(), _last_emit_was_black, _video_position);
597 _video_position += _film->video_frames_to_time (1);
598 _last_emit_was_black = true;
602 Player::emit_silence (OutputAudioFrame most)
608 OutputAudioFrame N = min (most, _film->audio_frame_rate() / 2);
609 shared_ptr<AudioBuffers> silence (new AudioBuffers (_film->audio_channels(), N));
610 silence->make_silent ();
611 Audio (silence, _audio_position);
612 _audio_position += _film->audio_frames_to_time (N);
616 Player::film_changed (Film::Property p)
618 /* Here we should notice Film properties that affect our output, and
619 alert listeners that our output now would be different to how it was
620 last time we were run.
623 if (p == Film::SCALER || p == Film::WITH_SUBTITLES || p == Film::CONTAINER || p == Film::VIDEO_FRAME_RATE) {
629 Player::process_subtitle (weak_ptr<Piece> weak_piece, shared_ptr<Image> image, dcpomatic::Rect<double> rect, Time from, Time to)
631 _in_subtitle.piece = weak_piece;
632 _in_subtitle.image = image;
633 _in_subtitle.rect = rect;
634 _in_subtitle.from = from;
635 _in_subtitle.to = to;
641 Player::update_subtitle ()
643 shared_ptr<Piece> piece = _in_subtitle.piece.lock ();
648 if (!_in_subtitle.image) {
649 _out_subtitle.image.reset ();
653 shared_ptr<SubtitleContent> sc = dynamic_pointer_cast<SubtitleContent> (piece->content);
656 dcpomatic::Rect<double> in_rect = _in_subtitle.rect;
657 libdcp::Size scaled_size;
659 in_rect.y += sc->subtitle_offset ();
661 /* We will scale the subtitle up to fit _video_container_size, and also by the additional subtitle_scale */
662 scaled_size.width = in_rect.width * _video_container_size.width * sc->subtitle_scale ();
663 scaled_size.height = in_rect.height * _video_container_size.height * sc->subtitle_scale ();
665 /* Then we need a corrective translation, consisting of two parts:
667 * 1. that which is the result of the scaling of the subtitle by _video_container_size; this will be
668 * rect.x * _video_container_size.width and rect.y * _video_container_size.height.
670 * 2. that to shift the origin of the scale by subtitle_scale to the centre of the subtitle; this will be
671 * (width_before_subtitle_scale * (1 - subtitle_scale) / 2) and
672 * (height_before_subtitle_scale * (1 - subtitle_scale) / 2).
674 * Combining these two translations gives these expressions.
677 _out_subtitle.position.x = rint (_video_container_size.width * (in_rect.x + (in_rect.width * (1 - sc->subtitle_scale ()) / 2)));
678 _out_subtitle.position.y = rint (_video_container_size.height * (in_rect.y + (in_rect.height * (1 - sc->subtitle_scale ()) / 2)));
680 _out_subtitle.image = _in_subtitle.image->scale (
682 Scaler::from_id ("bicubic"),
683 _in_subtitle.image->pixel_format (),
686 _out_subtitle.from = _in_subtitle.from + piece->content->position ();
687 _out_subtitle.to = _in_subtitle.to + piece->content->position ();
690 /** Re-emit the last frame that was emitted, using current settings for crop, ratio, scaler and subtitles.
691 * @return false if this could not be done.
694 Player::repeat_last_video ()
696 if (!_last_incoming_video.image || !_have_valid_pieces) {
701 _last_incoming_video.weak_piece,
702 _last_incoming_video.image,
703 _last_incoming_video.eyes,
704 _last_incoming_video.same,
705 _last_incoming_video.frame,
706 _last_incoming_video.extra
712 PlayerImage::PlayerImage (
713 shared_ptr<const Image> in,
715 libdcp::Size inter_size,
716 libdcp::Size out_size,
717 Scaler const * scaler
721 , _inter_size (inter_size)
722 , _out_size (out_size)
729 PlayerImage::set_subtitle (shared_ptr<const Image> image, Position<int> pos)
731 _subtitle_image = image;
732 _subtitle_position = pos;
736 PlayerImage::image ()
738 shared_ptr<Image> out = _in->crop_scale_window (_crop, _inter_size, _out_size, _scaler, PIX_FMT_RGB24, false);
740 Position<int> const container_offset ((_out_size.width - _inter_size.width) / 2, (_out_size.height - _inter_size.width) / 2);
742 if (_subtitle_image) {
743 out->alpha_blend (_subtitle_image, _subtitle_position);