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 ())
69 /** Set this piece to repeat a video frame a given number of times */
70 void set_repeat (IncomingVideo video, int num)
79 repeat_video.image.reset ();
84 bool repeating () const
86 return repeat_done != repeat_to_do;
89 void repeat (Player* player)
91 player->process_video (
92 repeat_video.weak_piece,
97 (repeat_done + 1) * (TIME_HZ / player->_film->video_frame_rate ())
103 shared_ptr<Content> content;
104 shared_ptr<Decoder> decoder;
105 /** Time of the last video we emitted relative to the start of the DCP */
107 /** Time of the last audio we emitted relative to the start of the DCP */
110 IncomingVideo repeat_video;
115 Player::Player (shared_ptr<const Film> f, shared_ptr<const Playlist> p)
120 , _have_valid_pieces (false)
121 , _video_position (0)
122 , _audio_position (0)
123 , _audio_merger (f->audio_channels(), bind (&Film::time_to_audio_frames, f.get(), _1), bind (&Film::audio_frames_to_time, f.get(), _1))
124 , _last_emit_was_black (false)
126 _playlist_changed_connection = _playlist->Changed.connect (bind (&Player::playlist_changed, this));
127 _playlist_content_changed_connection = _playlist->ContentChanged.connect (bind (&Player::content_changed, this, _1, _2, _3));
128 _film_changed_connection = _film->Changed.connect (bind (&Player::film_changed, this, _1));
129 set_video_container_size (fit_ratio_within (_film->container()->ratio (), _film->full_frame ()));
133 Player::disable_video ()
139 Player::disable_audio ()
147 if (!_have_valid_pieces) {
151 Time earliest_t = TIME_MAX;
152 shared_ptr<Piece> earliest;
158 for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
159 if ((*i)->decoder->done ()) {
163 shared_ptr<VideoDecoder> vd = dynamic_pointer_cast<VideoDecoder> ((*i)->decoder);
164 shared_ptr<AudioDecoder> ad = dynamic_pointer_cast<AudioDecoder> ((*i)->decoder);
167 if ((*i)->video_position < earliest_t) {
168 earliest_t = (*i)->video_position;
174 if (_audio && ad && ad->has_audio ()) {
175 if ((*i)->audio_position < earliest_t) {
176 earliest_t = (*i)->audio_position;
190 if (earliest_t > _video_position) {
193 if (earliest->repeating ()) {
194 earliest->repeat (this);
196 earliest->decoder->pass ();
202 if (earliest_t > _audio_position) {
203 emit_silence (_film->time_to_audio_frames (earliest_t - _audio_position));
205 earliest->decoder->pass ();
207 if (earliest->decoder->done()) {
208 shared_ptr<AudioContent> ac = dynamic_pointer_cast<AudioContent> (earliest->content);
210 shared_ptr<Resampler> re = resampler (ac, false);
212 shared_ptr<const AudioBuffers> b = re->flush ();
214 process_audio (earliest, b, ac->audio_length ());
223 boost::optional<Time> audio_done_up_to;
224 for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
225 if ((*i)->decoder->done ()) {
229 shared_ptr<AudioDecoder> ad = dynamic_pointer_cast<AudioDecoder> ((*i)->decoder);
230 if (ad && ad->has_audio ()) {
231 audio_done_up_to = min (audio_done_up_to.get_value_or (TIME_MAX), (*i)->audio_position);
235 if (audio_done_up_to) {
236 TimedAudioBuffers<Time> tb = _audio_merger.pull (audio_done_up_to.get ());
237 Audio (tb.audio, tb.time);
238 _audio_position += _film->audio_frames_to_time (tb.audio->frames ());
245 /** @param extra Amount of extra time to add to the content frame's time (for repeat) */
247 Player::process_video (weak_ptr<Piece> weak_piece, shared_ptr<const Image> image, Eyes eyes, bool same, VideoContent::Frame frame, Time extra)
249 /* Keep a note of what came in so that we can repeat it if required */
250 _last_incoming_video.weak_piece = weak_piece;
251 _last_incoming_video.image = image;
252 _last_incoming_video.eyes = eyes;
253 _last_incoming_video.same = same;
254 _last_incoming_video.frame = frame;
255 _last_incoming_video.extra = extra;
257 shared_ptr<Piece> piece = weak_piece.lock ();
262 shared_ptr<VideoContent> content = dynamic_pointer_cast<VideoContent> (piece->content);
265 FrameRateConversion frc (content->video_frame_rate(), _film->video_frame_rate());
266 if (frc.skip && (frame % 2) == 1) {
270 Time const relative_time = (frame * frc.factor() * TIME_HZ / _film->video_frame_rate());
271 if (content->trimmed (relative_time)) {
275 Time const time = content->position() + relative_time + extra - content->trim_start ();
276 float const ratio = content->ratio() ? content->ratio()->ratio() : content->video_size_after_crop().ratio();
277 libdcp::Size const image_size = fit_ratio_within (ratio, _video_container_size);
279 shared_ptr<PlayerImage> pi (
284 _video_container_size,
289 if (_film->with_subtitles () && _out_subtitle.image && time >= _out_subtitle.from && time <= _out_subtitle.to) {
291 Position<int> const container_offset (
292 (_video_container_size.width - image_size.width) / 2,
293 (_video_container_size.height - image_size.width) / 2
296 pi->set_subtitle (_out_subtitle.image, _out_subtitle.position + container_offset);
300 #ifdef DCPOMATIC_DEBUG
301 _last_video = piece->content;
304 Video (pi, eyes, content->colour_conversion(), same, time);
306 _last_emit_was_black = false;
307 _video_position = piece->video_position = (time + TIME_HZ / _film->video_frame_rate());
309 if (frc.repeat > 1 && !piece->repeating ()) {
310 piece->set_repeat (_last_incoming_video, frc.repeat - 1);
315 Player::process_audio (weak_ptr<Piece> weak_piece, shared_ptr<const AudioBuffers> audio, AudioContent::Frame frame)
317 shared_ptr<Piece> piece = weak_piece.lock ();
322 shared_ptr<AudioContent> content = dynamic_pointer_cast<AudioContent> (piece->content);
326 if (content->audio_gain() != 0) {
327 shared_ptr<AudioBuffers> gain (new AudioBuffers (audio));
328 gain->apply_gain (content->audio_gain ());
333 if (content->content_audio_frame_rate() != content->output_audio_frame_rate()) {
334 shared_ptr<Resampler> r = resampler (content, true);
335 pair<shared_ptr<const AudioBuffers>, AudioContent::Frame> ro = r->run (audio, frame);
340 Time const relative_time = _film->audio_frames_to_time (frame);
342 if (content->trimmed (relative_time)) {
346 Time time = content->position() + (content->audio_delay() * TIME_HZ / 1000) + relative_time - content->trim_start ();
349 shared_ptr<AudioBuffers> dcp_mapped (new AudioBuffers (_film->audio_channels(), audio->frames()));
350 dcp_mapped->make_silent ();
352 AudioMapping map = content->audio_mapping ();
353 for (int i = 0; i < map.content_channels(); ++i) {
354 for (int j = 0; j < _film->audio_channels(); ++j) {
355 if (map.get (i, static_cast<libdcp::Channel> (j)) > 0) {
356 dcp_mapped->accumulate_channel (
359 static_cast<libdcp::Channel> (j),
360 map.get (i, static_cast<libdcp::Channel> (j))
368 /* We must cut off anything that comes before the start of all time */
370 int const frames = - time * _film->audio_frame_rate() / TIME_HZ;
371 if (frames >= audio->frames ()) {
375 shared_ptr<AudioBuffers> trimmed (new AudioBuffers (audio->channels(), audio->frames() - frames));
376 trimmed->copy_from (audio.get(), audio->frames() - frames, frames, 0);
382 _audio_merger.push (audio, time);
383 piece->audio_position += _film->audio_frames_to_time (audio->frames ());
389 TimedAudioBuffers<Time> tb = _audio_merger.flush ();
390 if (_audio && tb.audio) {
391 Audio (tb.audio, tb.time);
392 _audio_position += _film->audio_frames_to_time (tb.audio->frames ());
395 while (_video && _video_position < _audio_position) {
399 while (_audio && _audio_position < _video_position) {
400 emit_silence (_film->time_to_audio_frames (_video_position - _audio_position));
405 /** Seek so that the next pass() will yield (approximately) the requested frame.
406 * Pass accurate = true to try harder to get close to the request.
407 * @return true on error
410 Player::seek (Time t, bool accurate)
412 if (!_have_valid_pieces) {
416 if (_pieces.empty ()) {
420 for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
421 shared_ptr<VideoContent> vc = dynamic_pointer_cast<VideoContent> ((*i)->content);
426 /* s is the offset of t from the start position of this content */
427 Time s = t - vc->position ();
428 s = max (static_cast<Time> (0), s);
429 s = min (vc->length_after_trim(), s);
431 /* Hence set the piece positions to the `global' time */
432 (*i)->video_position = (*i)->audio_position = vc->position() + s;
434 /* And seek the decoder */
435 dynamic_pointer_cast<VideoDecoder>((*i)->decoder)->seek (
436 vc->time_to_content_video_frames (s + vc->trim_start ()), accurate
439 (*i)->reset_repeat ();
442 _video_position = _audio_position = t;
444 /* XXX: don't seek audio because we don't need to... */
448 Player::setup_pieces ()
450 list<shared_ptr<Piece> > old_pieces = _pieces;
454 ContentList content = _playlist->content ();
455 sort (content.begin(), content.end(), ContentSorter ());
457 for (ContentList::iterator i = content.begin(); i != content.end(); ++i) {
459 if (!(*i)->paths_valid ()) {
463 shared_ptr<Piece> piece (new Piece (*i));
465 /* XXX: into content? */
467 shared_ptr<const FFmpegContent> fc = dynamic_pointer_cast<const FFmpegContent> (*i);
469 shared_ptr<FFmpegDecoder> fd (new FFmpegDecoder (_film, fc, _video, _audio));
471 fd->Video.connect (bind (&Player::process_video, this, weak_ptr<Piece> (piece), _1, _2, _3, _4, 0));
472 fd->Audio.connect (bind (&Player::process_audio, this, weak_ptr<Piece> (piece), _1, _2));
473 fd->Subtitle.connect (bind (&Player::process_subtitle, this, weak_ptr<Piece> (piece), _1, _2, _3, _4));
475 fd->seek (fc->time_to_content_video_frames (fc->trim_start ()), true);
479 shared_ptr<const ImageContent> ic = dynamic_pointer_cast<const ImageContent> (*i);
481 bool reusing = false;
483 /* See if we can re-use an old ImageDecoder */
484 for (list<shared_ptr<Piece> >::const_iterator j = old_pieces.begin(); j != old_pieces.end(); ++j) {
485 shared_ptr<ImageDecoder> imd = dynamic_pointer_cast<ImageDecoder> ((*j)->decoder);
486 if (imd && imd->content() == ic) {
493 shared_ptr<ImageDecoder> id (new ImageDecoder (_film, ic));
494 id->Video.connect (bind (&Player::process_video, this, weak_ptr<Piece> (piece), _1, _2, _3, _4, 0));
499 shared_ptr<const SndfileContent> sc = dynamic_pointer_cast<const SndfileContent> (*i);
501 shared_ptr<AudioDecoder> sd (new SndfileDecoder (_film, sc));
502 sd->Audio.connect (bind (&Player::process_audio, this, weak_ptr<Piece> (piece), _1, _2));
507 _pieces.push_back (piece);
510 _have_valid_pieces = true;
514 Player::content_changed (weak_ptr<Content> w, int property, bool frequent)
516 shared_ptr<Content> c = w.lock ();
522 property == ContentProperty::POSITION || property == ContentProperty::LENGTH ||
523 property == ContentProperty::TRIM_START || property == ContentProperty::TRIM_END ||
524 property == VideoContentProperty::VIDEO_FRAME_TYPE
527 _have_valid_pieces = false;
531 property == SubtitleContentProperty::SUBTITLE_X_OFFSET ||
532 property == SubtitleContentProperty::SUBTITLE_Y_OFFSET ||
533 property == SubtitleContentProperty::SUBTITLE_SCALE
540 property == VideoContentProperty::VIDEO_CROP || property == VideoContentProperty::VIDEO_RATIO ||
541 property == VideoContentProperty::VIDEO_FRAME_RATE
546 } else if (property == ContentProperty::PATH) {
548 _have_valid_pieces = false;
554 Player::playlist_changed ()
556 _have_valid_pieces = false;
561 Player::set_video_container_size (libdcp::Size s)
563 _video_container_size = s;
565 shared_ptr<Image> im (new Image (PIX_FMT_RGB24, _video_container_size, true));
572 _video_container_size,
573 _video_container_size,
574 Scaler::from_id ("bicubic")
579 shared_ptr<Resampler>
580 Player::resampler (shared_ptr<AudioContent> c, bool create)
582 map<shared_ptr<AudioContent>, shared_ptr<Resampler> >::iterator i = _resamplers.find (c);
583 if (i != _resamplers.end ()) {
588 return shared_ptr<Resampler> ();
593 "Creating new resampler for %1 to %2 with %3 channels", c->content_audio_frame_rate(), c->output_audio_frame_rate(), c->audio_channels()
597 shared_ptr<Resampler> r (new Resampler (c->content_audio_frame_rate(), c->output_audio_frame_rate(), c->audio_channels()));
603 Player::emit_black ()
605 #ifdef DCPOMATIC_DEBUG
606 _last_video.reset ();
609 Video (_black_frame, EYES_BOTH, ColourConversion(), _last_emit_was_black, _video_position);
610 _video_position += _film->video_frames_to_time (1);
611 _last_emit_was_black = true;
615 Player::emit_silence (OutputAudioFrame most)
621 OutputAudioFrame N = min (most, _film->audio_frame_rate() / 2);
622 shared_ptr<AudioBuffers> silence (new AudioBuffers (_film->audio_channels(), N));
623 silence->make_silent ();
624 Audio (silence, _audio_position);
625 _audio_position += _film->audio_frames_to_time (N);
629 Player::film_changed (Film::Property p)
631 /* Here we should notice Film properties that affect our output, and
632 alert listeners that our output now would be different to how it was
633 last time we were run.
636 if (p == Film::SCALER || p == Film::WITH_SUBTITLES || p == Film::CONTAINER || p == Film::VIDEO_FRAME_RATE) {
642 Player::process_subtitle (weak_ptr<Piece> weak_piece, shared_ptr<Image> image, dcpomatic::Rect<double> rect, Time from, Time to)
644 _in_subtitle.piece = weak_piece;
645 _in_subtitle.image = image;
646 _in_subtitle.rect = rect;
647 _in_subtitle.from = from;
648 _in_subtitle.to = to;
654 Player::update_subtitle ()
656 shared_ptr<Piece> piece = _in_subtitle.piece.lock ();
661 if (!_in_subtitle.image) {
662 _out_subtitle.image.reset ();
666 shared_ptr<SubtitleContent> sc = dynamic_pointer_cast<SubtitleContent> (piece->content);
669 dcpomatic::Rect<double> in_rect = _in_subtitle.rect;
670 libdcp::Size scaled_size;
672 in_rect.x += sc->subtitle_x_offset ();
673 in_rect.y += sc->subtitle_y_offset ();
675 /* We will scale the subtitle up to fit _video_container_size, and also by the additional subtitle_scale */
676 scaled_size.width = in_rect.width * _video_container_size.width * sc->subtitle_scale ();
677 scaled_size.height = in_rect.height * _video_container_size.height * sc->subtitle_scale ();
679 /* Then we need a corrective translation, consisting of two parts:
681 * 1. that which is the result of the scaling of the subtitle by _video_container_size; this will be
682 * rect.x * _video_container_size.width and rect.y * _video_container_size.height.
684 * 2. that to shift the origin of the scale by subtitle_scale to the centre of the subtitle; this will be
685 * (width_before_subtitle_scale * (1 - subtitle_scale) / 2) and
686 * (height_before_subtitle_scale * (1 - subtitle_scale) / 2).
688 * Combining these two translations gives these expressions.
691 _out_subtitle.position.x = rint (_video_container_size.width * (in_rect.x + (in_rect.width * (1 - sc->subtitle_scale ()) / 2)));
692 _out_subtitle.position.y = rint (_video_container_size.height * (in_rect.y + (in_rect.height * (1 - sc->subtitle_scale ()) / 2)));
694 _out_subtitle.image = _in_subtitle.image->scale (
696 Scaler::from_id ("bicubic"),
697 _in_subtitle.image->pixel_format (),
702 Time from = _in_subtitle.from;
703 Time to = _in_subtitle.to;
704 shared_ptr<VideoContent> vc = dynamic_pointer_cast<VideoContent> (piece->content);
706 from = rint (from * vc->video_frame_rate() / _film->video_frame_rate());
707 to = rint (to * vc->video_frame_rate() / _film->video_frame_rate());
710 _out_subtitle.from = from + piece->content->position ();
711 _out_subtitle.to = to + piece->content->position ();
714 /** Re-emit the last frame that was emitted, using current settings for crop, ratio, scaler and subtitles.
715 * @return false if this could not be done.
718 Player::repeat_last_video ()
720 if (!_last_incoming_video.image || !_have_valid_pieces) {
725 _last_incoming_video.weak_piece,
726 _last_incoming_video.image,
727 _last_incoming_video.eyes,
728 _last_incoming_video.same,
729 _last_incoming_video.frame,
730 _last_incoming_video.extra
736 PlayerImage::PlayerImage (
737 shared_ptr<const Image> in,
739 libdcp::Size inter_size,
740 libdcp::Size out_size,
741 Scaler const * scaler
745 , _inter_size (inter_size)
746 , _out_size (out_size)
753 PlayerImage::set_subtitle (shared_ptr<const Image> image, Position<int> pos)
755 _subtitle_image = image;
756 _subtitle_position = pos;
760 PlayerImage::image ()
762 shared_ptr<Image> out = _in->crop_scale_window (_crop, _inter_size, _out_size, _scaler, PIX_FMT_RGB24, false);
764 Position<int> const container_offset ((_out_size.width - _inter_size.width) / 2, (_out_size.height - _inter_size.width) / 2);
766 if (_subtitle_image) {
767 out->alpha_blend (_subtitle_image, _subtitle_position);