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);
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 ();
349 AudioMapping map = content->audio_mapping ();
350 for (int i = 0; i < map.content_channels(); ++i) {
351 for (int j = 0; j < _film->audio_channels(); ++j) {
352 if (map.get (i, static_cast<libdcp::Channel> (j)) > 0) {
353 dcp_mapped->accumulate_channel (
356 static_cast<libdcp::Channel> (j),
357 map.get (i, static_cast<libdcp::Channel> (j))
365 /* We must cut off anything that comes before the start of all time */
367 int const frames = - time * _film->audio_frame_rate() / TIME_HZ;
368 if (frames >= audio->frames ()) {
372 shared_ptr<AudioBuffers> trimmed (new AudioBuffers (audio->channels(), audio->frames() - frames));
373 trimmed->copy_from (audio.get(), audio->frames() - frames, frames, 0);
379 _audio_merger.push (audio, time);
380 piece->audio_position += _film->audio_frames_to_time (audio->frames ());
386 TimedAudioBuffers<Time> tb = _audio_merger.flush ();
387 if (_audio && tb.audio) {
388 Audio (tb.audio, tb.time);
389 _audio_position += _film->audio_frames_to_time (tb.audio->frames ());
392 while (_video && _video_position < _audio_position) {
396 while (_audio && _audio_position < _video_position) {
397 emit_silence (_film->time_to_audio_frames (_video_position - _audio_position));
402 /** Seek so that the next pass() will yield (approximately) the requested frame.
403 * Pass accurate = true to try harder to get close to the request.
404 * @return true on error
407 Player::seek (Time t, bool accurate)
409 if (!_have_valid_pieces) {
413 if (_pieces.empty ()) {
417 for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
418 shared_ptr<VideoContent> vc = dynamic_pointer_cast<VideoContent> ((*i)->content);
423 /* s is the offset of t from the start position of this content */
424 Time s = t - vc->position ();
425 s = max (static_cast<Time> (0), s);
426 s = min (vc->length_after_trim(), s);
428 /* Hence set the piece positions to the `global' time */
429 (*i)->video_position = (*i)->audio_position = vc->position() + s;
431 /* And seek the decoder */
432 dynamic_pointer_cast<VideoDecoder>((*i)->decoder)->seek (
433 vc->time_to_content_video_frames (s + vc->trim_start ()), accurate
436 (*i)->reset_repeat ();
439 _video_position = _audio_position = t;
441 /* XXX: don't seek audio because we don't need to... */
445 Player::setup_pieces ()
447 list<shared_ptr<Piece> > old_pieces = _pieces;
451 ContentList content = _playlist->content ();
452 sort (content.begin(), content.end(), ContentSorter ());
454 for (ContentList::iterator i = content.begin(); i != content.end(); ++i) {
456 shared_ptr<Piece> piece (new Piece (*i));
458 /* XXX: into content? */
460 shared_ptr<const FFmpegContent> fc = dynamic_pointer_cast<const FFmpegContent> (*i);
462 shared_ptr<FFmpegDecoder> fd (new FFmpegDecoder (_film, fc, _video, _audio));
464 fd->Video.connect (bind (&Player::process_video, this, weak_ptr<Piece> (piece), _1, _2, _3, _4, 0));
465 fd->Audio.connect (bind (&Player::process_audio, this, weak_ptr<Piece> (piece), _1, _2));
466 fd->Subtitle.connect (bind (&Player::process_subtitle, this, weak_ptr<Piece> (piece), _1, _2, _3, _4));
468 fd->seek (fc->time_to_content_video_frames (fc->trim_start ()), true);
472 shared_ptr<const ImageContent> ic = dynamic_pointer_cast<const ImageContent> (*i);
474 bool reusing = false;
476 /* See if we can re-use an old ImageDecoder */
477 for (list<shared_ptr<Piece> >::const_iterator j = old_pieces.begin(); j != old_pieces.end(); ++j) {
478 shared_ptr<ImageDecoder> imd = dynamic_pointer_cast<ImageDecoder> ((*j)->decoder);
479 if (imd && imd->content() == ic) {
486 shared_ptr<ImageDecoder> id (new ImageDecoder (_film, ic));
487 id->Video.connect (bind (&Player::process_video, this, weak_ptr<Piece> (piece), _1, _2, _3, _4, 0));
492 shared_ptr<const SndfileContent> sc = dynamic_pointer_cast<const SndfileContent> (*i);
494 shared_ptr<AudioDecoder> sd (new SndfileDecoder (_film, sc));
495 sd->Audio.connect (bind (&Player::process_audio, this, weak_ptr<Piece> (piece), _1, _2));
500 _pieces.push_back (piece);
503 _have_valid_pieces = true;
507 Player::content_changed (weak_ptr<Content> w, int property, bool frequent)
509 shared_ptr<Content> c = w.lock ();
515 property == ContentProperty::POSITION || property == ContentProperty::LENGTH ||
516 property == ContentProperty::TRIM_START || property == ContentProperty::TRIM_END ||
517 property == VideoContentProperty::VIDEO_FRAME_TYPE
520 _have_valid_pieces = false;
523 } else if (property == SubtitleContentProperty::SUBTITLE_OFFSET || property == SubtitleContentProperty::SUBTITLE_SCALE) {
529 property == VideoContentProperty::VIDEO_CROP || property == VideoContentProperty::VIDEO_RATIO ||
530 property == VideoContentProperty::VIDEO_FRAME_RATE
535 } else if (property == ContentProperty::PATH) {
542 Player::playlist_changed ()
544 _have_valid_pieces = false;
549 Player::set_video_container_size (libdcp::Size s)
551 _video_container_size = s;
553 shared_ptr<Image> im (new Image (PIX_FMT_RGB24, _video_container_size, true));
560 _video_container_size,
561 _video_container_size,
562 Scaler::from_id ("bicubic")
567 shared_ptr<Resampler>
568 Player::resampler (shared_ptr<AudioContent> c, bool create)
570 map<shared_ptr<AudioContent>, shared_ptr<Resampler> >::iterator i = _resamplers.find (c);
571 if (i != _resamplers.end ()) {
576 return shared_ptr<Resampler> ();
581 "Creating new resampler for %1 to %2 with %3 channels", c->content_audio_frame_rate(), c->output_audio_frame_rate(), c->audio_channels()
585 shared_ptr<Resampler> r (new Resampler (c->content_audio_frame_rate(), c->output_audio_frame_rate(), c->audio_channels()));
591 Player::emit_black ()
593 #ifdef DCPOMATIC_DEBUG
594 _last_video.reset ();
597 Video (_black_frame, EYES_BOTH, ColourConversion(), _last_emit_was_black, _video_position);
598 _video_position += _film->video_frames_to_time (1);
599 _last_emit_was_black = true;
603 Player::emit_silence (OutputAudioFrame most)
609 OutputAudioFrame N = min (most, _film->audio_frame_rate() / 2);
610 shared_ptr<AudioBuffers> silence (new AudioBuffers (_film->audio_channels(), N));
611 silence->make_silent ();
612 Audio (silence, _audio_position);
613 _audio_position += _film->audio_frames_to_time (N);
617 Player::film_changed (Film::Property p)
619 /* Here we should notice Film properties that affect our output, and
620 alert listeners that our output now would be different to how it was
621 last time we were run.
624 if (p == Film::SCALER || p == Film::WITH_SUBTITLES || p == Film::CONTAINER || p == Film::VIDEO_FRAME_RATE) {
630 Player::process_subtitle (weak_ptr<Piece> weak_piece, shared_ptr<Image> image, dcpomatic::Rect<double> rect, Time from, Time to)
632 _in_subtitle.piece = weak_piece;
633 _in_subtitle.image = image;
634 _in_subtitle.rect = rect;
635 _in_subtitle.from = from;
636 _in_subtitle.to = to;
642 Player::update_subtitle ()
644 shared_ptr<Piece> piece = _in_subtitle.piece.lock ();
649 if (!_in_subtitle.image) {
650 _out_subtitle.image.reset ();
654 shared_ptr<SubtitleContent> sc = dynamic_pointer_cast<SubtitleContent> (piece->content);
657 dcpomatic::Rect<double> in_rect = _in_subtitle.rect;
658 libdcp::Size scaled_size;
660 in_rect.y += sc->subtitle_offset ();
662 /* We will scale the subtitle up to fit _video_container_size, and also by the additional subtitle_scale */
663 scaled_size.width = in_rect.width * _video_container_size.width * sc->subtitle_scale ();
664 scaled_size.height = in_rect.height * _video_container_size.height * sc->subtitle_scale ();
666 /* Then we need a corrective translation, consisting of two parts:
668 * 1. that which is the result of the scaling of the subtitle by _video_container_size; this will be
669 * rect.x * _video_container_size.width and rect.y * _video_container_size.height.
671 * 2. that to shift the origin of the scale by subtitle_scale to the centre of the subtitle; this will be
672 * (width_before_subtitle_scale * (1 - subtitle_scale) / 2) and
673 * (height_before_subtitle_scale * (1 - subtitle_scale) / 2).
675 * Combining these two translations gives these expressions.
678 _out_subtitle.position.x = rint (_video_container_size.width * (in_rect.x + (in_rect.width * (1 - sc->subtitle_scale ()) / 2)));
679 _out_subtitle.position.y = rint (_video_container_size.height * (in_rect.y + (in_rect.height * (1 - sc->subtitle_scale ()) / 2)));
681 _out_subtitle.image = _in_subtitle.image->scale (
683 Scaler::from_id ("bicubic"),
684 _in_subtitle.image->pixel_format (),
689 Time from = _in_subtitle.from;
690 Time to = _in_subtitle.to;
691 shared_ptr<VideoContent> vc = dynamic_pointer_cast<VideoContent> (piece->content);
693 from = rint (from * vc->video_frame_rate() / _film->video_frame_rate());
694 to = rint (to * vc->video_frame_rate() / _film->video_frame_rate());
697 _out_subtitle.from = from * piece->content->position ();
698 _out_subtitle.to = to + piece->content->position ();
701 /** Re-emit the last frame that was emitted, using current settings for crop, ratio, scaler and subtitles.
702 * @return false if this could not be done.
705 Player::repeat_last_video ()
707 if (!_last_incoming_video.image || !_have_valid_pieces) {
712 _last_incoming_video.weak_piece,
713 _last_incoming_video.image,
714 _last_incoming_video.eyes,
715 _last_incoming_video.same,
716 _last_incoming_video.frame,
717 _last_incoming_video.extra
723 PlayerImage::PlayerImage (
724 shared_ptr<const Image> in,
726 libdcp::Size inter_size,
727 libdcp::Size out_size,
728 Scaler const * scaler
732 , _inter_size (inter_size)
733 , _out_size (out_size)
740 PlayerImage::set_subtitle (shared_ptr<const Image> image, Position<int> pos)
742 _subtitle_image = image;
743 _subtitle_position = pos;
747 PlayerImage::image ()
749 shared_ptr<Image> out = _in->crop_scale_window (_crop, _inter_size, _out_size, _scaler, PIX_FMT_RGB24, false);
751 Position<int> const container_offset ((_out_size.width - _inter_size.width) / 2, (_out_size.height - _inter_size.width) / 2);
753 if (_subtitle_image) {
754 out->alpha_blend (_subtitle_image, _subtitle_position);