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) {
147 _have_valid_pieces = true;
150 Time earliest_t = TIME_MAX;
151 shared_ptr<Piece> earliest;
157 for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
158 if ((*i)->decoder->done ()) {
162 shared_ptr<VideoDecoder> vd = dynamic_pointer_cast<VideoDecoder> ((*i)->decoder);
163 shared_ptr<AudioDecoder> ad = dynamic_pointer_cast<AudioDecoder> ((*i)->decoder);
166 if ((*i)->video_position < earliest_t) {
167 earliest_t = (*i)->video_position;
173 if (_audio && ad && ad->has_audio ()) {
174 if ((*i)->audio_position < earliest_t) {
175 earliest_t = (*i)->audio_position;
189 if (earliest_t > _video_position) {
192 if (earliest->repeating ()) {
193 earliest->repeat (this);
195 earliest->decoder->pass ();
201 if (earliest_t > _audio_position) {
202 emit_silence (_film->time_to_audio_frames (earliest_t - _audio_position));
204 earliest->decoder->pass ();
206 if (earliest->decoder->done()) {
207 shared_ptr<AudioContent> ac = dynamic_pointer_cast<AudioContent> (earliest->content);
209 shared_ptr<Resampler> re = resampler (ac, false);
211 shared_ptr<const AudioBuffers> b = re->flush ();
213 process_audio (earliest, b, ac->audio_length ());
222 boost::optional<Time> audio_done_up_to;
223 for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
224 if ((*i)->decoder->done ()) {
228 if (dynamic_pointer_cast<AudioDecoder> ((*i)->decoder)) {
229 audio_done_up_to = min (audio_done_up_to.get_value_or (TIME_MAX), (*i)->audio_position);
233 if (audio_done_up_to) {
234 TimedAudioBuffers<Time> tb = _audio_merger.pull (audio_done_up_to.get ());
235 Audio (tb.audio, tb.time);
236 _audio_position += _film->audio_frames_to_time (tb.audio->frames ());
243 /** @param extra Amount of extra time to add to the content frame's time (for repeat) */
245 Player::process_video (weak_ptr<Piece> weak_piece, shared_ptr<const Image> image, Eyes eyes, bool same, VideoContent::Frame frame, Time extra)
247 /* Keep a note of what came in so that we can repeat it if required */
248 _last_incoming_video.weak_piece = weak_piece;
249 _last_incoming_video.image = image;
250 _last_incoming_video.eyes = eyes;
251 _last_incoming_video.same = same;
252 _last_incoming_video.frame = frame;
253 _last_incoming_video.extra = extra;
255 shared_ptr<Piece> piece = weak_piece.lock ();
260 shared_ptr<VideoContent> content = dynamic_pointer_cast<VideoContent> (piece->content);
263 FrameRateConversion frc (content->video_frame_rate(), _film->video_frame_rate());
264 if (frc.skip && (frame % 2) == 1) {
268 Time const relative_time = (frame * frc.factor() * TIME_HZ / _film->video_frame_rate());
269 if (content->trimmed (relative_time)) {
273 Time const time = content->position() + relative_time + extra - content->trim_start ();
274 float const ratio = content->ratio() ? content->ratio()->ratio() : content->video_size_after_crop().ratio();
275 libdcp::Size const image_size = fit_ratio_within (ratio, _video_container_size);
277 shared_ptr<PlayerImage> pi (
282 _video_container_size,
287 if (_film->with_subtitles () && _out_subtitle.image && time >= _out_subtitle.from && time <= _out_subtitle.to) {
289 Position<int> const container_offset (
290 (_video_container_size.width - image_size.width) / 2,
291 (_video_container_size.height - image_size.width) / 2
294 pi->set_subtitle (_out_subtitle.image, _out_subtitle.position + container_offset);
297 #ifdef DCPOMATIC_DEBUG
298 _last_video = piece->content;
301 Video (pi, eyes, content->colour_conversion(), same, time);
303 _last_emit_was_black = false;
304 _video_position = piece->video_position = (time + TIME_HZ / _film->video_frame_rate());
306 if (frc.repeat > 1 && !piece->repeating ()) {
307 piece->set_repeat (_last_incoming_video, frc.repeat - 1);
312 Player::process_audio (weak_ptr<Piece> weak_piece, shared_ptr<const AudioBuffers> audio, AudioContent::Frame frame)
314 shared_ptr<Piece> piece = weak_piece.lock ();
319 shared_ptr<AudioContent> content = dynamic_pointer_cast<AudioContent> (piece->content);
323 if (content->audio_gain() != 0) {
324 shared_ptr<AudioBuffers> gain (new AudioBuffers (audio));
325 gain->apply_gain (content->audio_gain ());
330 if (content->content_audio_frame_rate() != content->output_audio_frame_rate()) {
331 shared_ptr<Resampler> r = resampler (content, true);
332 pair<shared_ptr<const AudioBuffers>, AudioContent::Frame> ro = r->run (audio, frame);
337 Time const relative_time = _film->audio_frames_to_time (frame);
339 if (content->trimmed (relative_time)) {
343 Time time = content->position() + (content->audio_delay() * TIME_HZ / 1000) + relative_time - content->trim_start ();
346 shared_ptr<AudioBuffers> dcp_mapped (new AudioBuffers (_film->audio_channels(), audio->frames()));
347 dcp_mapped->make_silent ();
348 list<pair<int, libdcp::Channel> > map = content->audio_mapping().content_to_dcp ();
349 for (list<pair<int, libdcp::Channel> >::iterator i = map.begin(); i != map.end(); ++i) {
350 if (i->first < audio->channels() && i->second < dcp_mapped->channels()) {
351 dcp_mapped->accumulate_channel (audio.get(), i->first, i->second);
357 /* We must cut off anything that comes before the start of all time */
359 int const frames = - time * _film->audio_frame_rate() / TIME_HZ;
360 if (frames >= audio->frames ()) {
364 shared_ptr<AudioBuffers> trimmed (new AudioBuffers (audio->channels(), audio->frames() - frames));
365 trimmed->copy_from (audio.get(), audio->frames() - frames, frames, 0);
371 _audio_merger.push (audio, time);
372 piece->audio_position += _film->audio_frames_to_time (audio->frames ());
378 TimedAudioBuffers<Time> tb = _audio_merger.flush ();
380 Audio (tb.audio, tb.time);
381 _audio_position += _film->audio_frames_to_time (tb.audio->frames ());
384 while (_video_position < _audio_position) {
388 while (_audio_position < _video_position) {
389 emit_silence (_film->time_to_audio_frames (_video_position - _audio_position));
394 /** Seek so that the next pass() will yield (approximately) the requested frame.
395 * Pass accurate = true to try harder to get close to the request.
396 * @return true on error
399 Player::seek (Time t, bool accurate)
401 if (!_have_valid_pieces) {
403 _have_valid_pieces = true;
406 if (_pieces.empty ()) {
410 for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
411 shared_ptr<VideoContent> vc = dynamic_pointer_cast<VideoContent> ((*i)->content);
416 /* s is the offset of t from the start position of this content */
417 Time s = t - vc->position ();
418 s = max (static_cast<Time> (0), s);
419 s = min (vc->length_after_trim(), s);
421 /* Hence set the piece positions to the `global' time */
422 (*i)->video_position = (*i)->audio_position = vc->position() + s;
424 /* And seek the decoder */
425 dynamic_pointer_cast<VideoDecoder>((*i)->decoder)->seek (
426 vc->time_to_content_video_frames (s + vc->trim_start ()), accurate
429 (*i)->reset_repeat ();
432 _video_position = _audio_position = t;
434 /* XXX: don't seek audio because we don't need to... */
438 Player::setup_pieces ()
440 list<shared_ptr<Piece> > old_pieces = _pieces;
444 ContentList content = _playlist->content ();
445 sort (content.begin(), content.end(), ContentSorter ());
447 for (ContentList::iterator i = content.begin(); i != content.end(); ++i) {
449 shared_ptr<Piece> piece (new Piece (*i));
451 /* XXX: into content? */
453 shared_ptr<const FFmpegContent> fc = dynamic_pointer_cast<const FFmpegContent> (*i);
455 shared_ptr<FFmpegDecoder> fd (new FFmpegDecoder (_film, fc, _video, _audio));
457 fd->Video.connect (bind (&Player::process_video, this, weak_ptr<Piece> (piece), _1, _2, _3, _4, 0));
458 fd->Audio.connect (bind (&Player::process_audio, this, weak_ptr<Piece> (piece), _1, _2));
459 fd->Subtitle.connect (bind (&Player::process_subtitle, this, weak_ptr<Piece> (piece), _1, _2, _3, _4));
461 fd->seek (fc->time_to_content_video_frames (fc->trim_start ()), true);
465 shared_ptr<const ImageContent> ic = dynamic_pointer_cast<const ImageContent> (*i);
467 bool reusing = false;
469 /* See if we can re-use an old ImageDecoder */
470 for (list<shared_ptr<Piece> >::const_iterator j = old_pieces.begin(); j != old_pieces.end(); ++j) {
471 shared_ptr<ImageDecoder> imd = dynamic_pointer_cast<ImageDecoder> ((*j)->decoder);
472 if (imd && imd->content() == ic) {
479 shared_ptr<ImageDecoder> id (new ImageDecoder (_film, ic));
480 id->Video.connect (bind (&Player::process_video, this, weak_ptr<Piece> (piece), _1, _2, _3, _4, 0));
485 shared_ptr<const SndfileContent> sc = dynamic_pointer_cast<const SndfileContent> (*i);
487 shared_ptr<AudioDecoder> sd (new SndfileDecoder (_film, sc));
488 sd->Audio.connect (bind (&Player::process_audio, this, weak_ptr<Piece> (piece), _1, _2));
493 _pieces.push_back (piece);
498 Player::content_changed (weak_ptr<Content> w, int property, bool frequent)
500 shared_ptr<Content> c = w.lock ();
506 property == ContentProperty::POSITION || property == ContentProperty::LENGTH ||
507 property == ContentProperty::TRIM_START || property == ContentProperty::TRIM_END
510 _have_valid_pieces = false;
513 } else if (property == SubtitleContentProperty::SUBTITLE_OFFSET || property == SubtitleContentProperty::SUBTITLE_SCALE) {
519 property == VideoContentProperty::VIDEO_FRAME_TYPE || property == VideoContentProperty::VIDEO_CROP ||
520 property == VideoContentProperty::VIDEO_RATIO
525 } else if (property == ContentProperty::PATH) {
532 Player::playlist_changed ()
534 _have_valid_pieces = false;
539 Player::set_video_container_size (libdcp::Size s)
541 _video_container_size = s;
543 shared_ptr<Image> im (new Image (PIX_FMT_RGB24, _video_container_size, true));
550 _video_container_size,
551 _video_container_size,
552 Scaler::from_id ("bicubic")
557 shared_ptr<Resampler>
558 Player::resampler (shared_ptr<AudioContent> c, bool create)
560 map<shared_ptr<AudioContent>, shared_ptr<Resampler> >::iterator i = _resamplers.find (c);
561 if (i != _resamplers.end ()) {
566 return shared_ptr<Resampler> ();
571 "Creating new resampler for %1 to %2 with %3 channels", c->content_audio_frame_rate(), c->output_audio_frame_rate(), c->audio_channels()
575 shared_ptr<Resampler> r (new Resampler (c->content_audio_frame_rate(), c->output_audio_frame_rate(), c->audio_channels()));
581 Player::emit_black ()
583 #ifdef DCPOMATIC_DEBUG
584 _last_video.reset ();
587 Video (_black_frame, EYES_BOTH, ColourConversion(), _last_emit_was_black, _video_position);
588 _video_position += _film->video_frames_to_time (1);
589 _last_emit_was_black = true;
593 Player::emit_silence (OutputAudioFrame most)
599 OutputAudioFrame N = min (most, _film->audio_frame_rate() / 2);
600 shared_ptr<AudioBuffers> silence (new AudioBuffers (_film->audio_channels(), N));
601 silence->make_silent ();
602 Audio (silence, _audio_position);
603 _audio_position += _film->audio_frames_to_time (N);
607 Player::film_changed (Film::Property p)
609 /* Here we should notice Film properties that affect our output, and
610 alert listeners that our output now would be different to how it was
611 last time we were run.
614 if (p == Film::SCALER || p == Film::WITH_SUBTITLES || p == Film::CONTAINER) {
620 Player::process_subtitle (weak_ptr<Piece> weak_piece, shared_ptr<Image> image, dcpomatic::Rect<double> rect, Time from, Time to)
622 _in_subtitle.piece = weak_piece;
623 _in_subtitle.image = image;
624 _in_subtitle.rect = rect;
625 _in_subtitle.from = from;
626 _in_subtitle.to = to;
632 Player::update_subtitle ()
634 shared_ptr<Piece> piece = _in_subtitle.piece.lock ();
639 if (!_in_subtitle.image) {
640 _out_subtitle.image.reset ();
644 shared_ptr<SubtitleContent> sc = dynamic_pointer_cast<SubtitleContent> (piece->content);
647 dcpomatic::Rect<double> in_rect = _in_subtitle.rect;
648 libdcp::Size scaled_size;
650 in_rect.y += sc->subtitle_offset ();
652 /* We will scale the subtitle up to fit _video_container_size, and also by the additional subtitle_scale */
653 scaled_size.width = in_rect.width * _video_container_size.width * sc->subtitle_scale ();
654 scaled_size.height = in_rect.height * _video_container_size.height * sc->subtitle_scale ();
656 /* Then we need a corrective translation, consisting of two parts:
658 * 1. that which is the result of the scaling of the subtitle by _video_container_size; this will be
659 * rect.x * _video_container_size.width and rect.y * _video_container_size.height.
661 * 2. that to shift the origin of the scale by subtitle_scale to the centre of the subtitle; this will be
662 * (width_before_subtitle_scale * (1 - subtitle_scale) / 2) and
663 * (height_before_subtitle_scale * (1 - subtitle_scale) / 2).
665 * Combining these two translations gives these expressions.
668 _out_subtitle.position.x = rint (_video_container_size.width * (in_rect.x + (in_rect.width * (1 - sc->subtitle_scale ()) / 2)));
669 _out_subtitle.position.y = rint (_video_container_size.height * (in_rect.y + (in_rect.height * (1 - sc->subtitle_scale ()) / 2)));
671 _out_subtitle.image = _in_subtitle.image->scale (
673 Scaler::from_id ("bicubic"),
674 _in_subtitle.image->pixel_format (),
677 _out_subtitle.from = _in_subtitle.from + piece->content->position ();
678 _out_subtitle.to = _in_subtitle.to + piece->content->position ();
681 /** Re-emit the last frame that was emitted, using current settings for crop, ratio, scaler and subtitles.
682 * @return false if this could not be done.
685 Player::repeat_last_video ()
687 if (!_last_incoming_video.image) {
692 _last_incoming_video.weak_piece,
693 _last_incoming_video.image,
694 _last_incoming_video.eyes,
695 _last_incoming_video.same,
696 _last_incoming_video.frame,
697 _last_incoming_video.extra
703 PlayerImage::PlayerImage (
704 shared_ptr<const Image> in,
706 libdcp::Size inter_size,
707 libdcp::Size out_size,
708 Scaler const * scaler
712 , _inter_size (inter_size)
713 , _out_size (out_size)
720 PlayerImage::set_subtitle (shared_ptr<const Image> image, Position<int> pos)
722 _subtitle_image = image;
723 _subtitle_position = pos;
727 PlayerImage::image ()
729 shared_ptr<Image> out = _in->crop_scale_window (_crop, _inter_size, _out_size, _scaler, PIX_FMT_RGB24, false);
731 Position<int> const container_offset ((_out_size.width - _inter_size.width) / 2, (_out_size.height - _inter_size.width) / 2);
733 if (_subtitle_image) {
734 out->alpha_blend (_subtitle_image, _subtitle_position);