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 shared_ptr<AudioDecoder> ad = dynamic_pointer_cast<AudioDecoder> ((*i)->decoder);
228 if (ad && ad->has_audio ()) {
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);
298 #ifdef DCPOMATIC_DEBUG
299 _last_video = piece->content;
302 Video (pi, eyes, content->colour_conversion(), same, time);
304 _last_emit_was_black = false;
305 _video_position = piece->video_position = (time + TIME_HZ / _film->video_frame_rate());
307 if (frc.repeat > 1 && !piece->repeating ()) {
308 piece->set_repeat (_last_incoming_video, frc.repeat - 1);
313 Player::process_audio (weak_ptr<Piece> weak_piece, shared_ptr<const AudioBuffers> audio, AudioContent::Frame frame)
315 shared_ptr<Piece> piece = weak_piece.lock ();
320 shared_ptr<AudioContent> content = dynamic_pointer_cast<AudioContent> (piece->content);
324 if (content->audio_gain() != 0) {
325 shared_ptr<AudioBuffers> gain (new AudioBuffers (audio));
326 gain->apply_gain (content->audio_gain ());
331 if (content->content_audio_frame_rate() != content->output_audio_frame_rate()) {
332 shared_ptr<Resampler> r = resampler (content, true);
333 pair<shared_ptr<const AudioBuffers>, AudioContent::Frame> ro = r->run (audio, frame);
338 Time const relative_time = _film->audio_frames_to_time (frame);
340 if (content->trimmed (relative_time)) {
344 Time time = content->position() + (content->audio_delay() * TIME_HZ / 1000) + relative_time - content->trim_start ();
347 shared_ptr<AudioBuffers> dcp_mapped (new AudioBuffers (_film->audio_channels(), audio->frames()));
348 dcp_mapped->make_silent ();
350 AudioMapping map = content->audio_mapping ();
351 for (int i = 0; i < map.content_channels(); ++i) {
352 for (int j = 0; j < _film->audio_channels(); ++j) {
353 if (map.get (i, static_cast<libdcp::Channel> (j)) > 0) {
354 dcp_mapped->accumulate_channel (
357 static_cast<libdcp::Channel> (j),
358 map.get (i, static_cast<libdcp::Channel> (j))
366 /* We must cut off anything that comes before the start of all time */
368 int const frames = - time * _film->audio_frame_rate() / TIME_HZ;
369 if (frames >= audio->frames ()) {
373 shared_ptr<AudioBuffers> trimmed (new AudioBuffers (audio->channels(), audio->frames() - frames));
374 trimmed->copy_from (audio.get(), audio->frames() - frames, frames, 0);
380 _audio_merger.push (audio, time);
381 piece->audio_position += _film->audio_frames_to_time (audio->frames ());
387 TimedAudioBuffers<Time> tb = _audio_merger.flush ();
388 if (_audio && tb.audio) {
389 Audio (tb.audio, tb.time);
390 _audio_position += _film->audio_frames_to_time (tb.audio->frames ());
393 while (_video && _video_position < _audio_position) {
397 while (_audio && _audio_position < _video_position) {
398 emit_silence (_film->time_to_audio_frames (_video_position - _audio_position));
403 /** Seek so that the next pass() will yield (approximately) the requested frame.
404 * Pass accurate = true to try harder to get close to the request.
405 * @return true on error
408 Player::seek (Time t, bool accurate)
410 if (!_have_valid_pieces) {
414 if (_pieces.empty ()) {
418 for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
419 shared_ptr<VideoContent> vc = dynamic_pointer_cast<VideoContent> ((*i)->content);
424 /* s is the offset of t from the start position of this content */
425 Time s = t - vc->position ();
426 s = max (static_cast<Time> (0), s);
427 s = min (vc->length_after_trim(), s);
429 /* Hence set the piece positions to the `global' time */
430 (*i)->video_position = (*i)->audio_position = vc->position() + s;
432 /* And seek the decoder */
433 dynamic_pointer_cast<VideoDecoder>((*i)->decoder)->seek (
434 vc->time_to_content_video_frames (s + vc->trim_start ()), accurate
437 (*i)->reset_repeat ();
440 _video_position = _audio_position = t;
442 /* XXX: don't seek audio because we don't need to... */
446 Player::setup_pieces ()
448 list<shared_ptr<Piece> > old_pieces = _pieces;
452 ContentList content = _playlist->content ();
453 sort (content.begin(), content.end(), ContentSorter ());
455 for (ContentList::iterator i = content.begin(); i != content.end(); ++i) {
457 shared_ptr<Piece> piece (new Piece (*i));
459 /* XXX: into content? */
461 shared_ptr<const FFmpegContent> fc = dynamic_pointer_cast<const FFmpegContent> (*i);
463 shared_ptr<FFmpegDecoder> fd (new FFmpegDecoder (_film, fc, _video, _audio));
465 fd->Video.connect (bind (&Player::process_video, this, weak_ptr<Piece> (piece), _1, _2, _3, _4, 0));
466 fd->Audio.connect (bind (&Player::process_audio, this, weak_ptr<Piece> (piece), _1, _2));
467 fd->Subtitle.connect (bind (&Player::process_subtitle, this, weak_ptr<Piece> (piece), _1, _2, _3, _4));
469 fd->seek (fc->time_to_content_video_frames (fc->trim_start ()), true);
473 shared_ptr<const ImageContent> ic = dynamic_pointer_cast<const ImageContent> (*i);
475 bool reusing = false;
477 /* See if we can re-use an old ImageDecoder */
478 for (list<shared_ptr<Piece> >::const_iterator j = old_pieces.begin(); j != old_pieces.end(); ++j) {
479 shared_ptr<ImageDecoder> imd = dynamic_pointer_cast<ImageDecoder> ((*j)->decoder);
480 if (imd && imd->content() == ic) {
487 shared_ptr<ImageDecoder> id (new ImageDecoder (_film, ic));
488 id->Video.connect (bind (&Player::process_video, this, weak_ptr<Piece> (piece), _1, _2, _3, _4, 0));
493 shared_ptr<const SndfileContent> sc = dynamic_pointer_cast<const SndfileContent> (*i);
495 shared_ptr<AudioDecoder> sd (new SndfileDecoder (_film, sc));
496 sd->Audio.connect (bind (&Player::process_audio, this, weak_ptr<Piece> (piece), _1, _2));
501 _pieces.push_back (piece);
504 _have_valid_pieces = true;
508 Player::content_changed (weak_ptr<Content> w, int property, bool frequent)
510 shared_ptr<Content> c = w.lock ();
516 property == ContentProperty::POSITION || property == ContentProperty::LENGTH ||
517 property == ContentProperty::TRIM_START || property == ContentProperty::TRIM_END ||
518 property == VideoContentProperty::VIDEO_FRAME_TYPE
521 _have_valid_pieces = false;
524 } else if (property == SubtitleContentProperty::SUBTITLE_OFFSET || property == SubtitleContentProperty::SUBTITLE_SCALE) {
530 property == VideoContentProperty::VIDEO_CROP || property == VideoContentProperty::VIDEO_RATIO ||
531 property == VideoContentProperty::VIDEO_FRAME_RATE
536 } else if (property == ContentProperty::PATH) {
543 Player::playlist_changed ()
545 _have_valid_pieces = false;
550 Player::set_video_container_size (libdcp::Size s)
552 _video_container_size = s;
554 shared_ptr<Image> im (new Image (PIX_FMT_RGB24, _video_container_size, true));
561 _video_container_size,
562 _video_container_size,
563 Scaler::from_id ("bicubic")
568 shared_ptr<Resampler>
569 Player::resampler (shared_ptr<AudioContent> c, bool create)
571 map<shared_ptr<AudioContent>, shared_ptr<Resampler> >::iterator i = _resamplers.find (c);
572 if (i != _resamplers.end ()) {
577 return shared_ptr<Resampler> ();
582 "Creating new resampler for %1 to %2 with %3 channels", c->content_audio_frame_rate(), c->output_audio_frame_rate(), c->audio_channels()
586 shared_ptr<Resampler> r (new Resampler (c->content_audio_frame_rate(), c->output_audio_frame_rate(), c->audio_channels()));
592 Player::emit_black ()
594 #ifdef DCPOMATIC_DEBUG
595 _last_video.reset ();
598 Video (_black_frame, EYES_BOTH, ColourConversion(), _last_emit_was_black, _video_position);
599 _video_position += _film->video_frames_to_time (1);
600 _last_emit_was_black = true;
604 Player::emit_silence (OutputAudioFrame most)
610 OutputAudioFrame N = min (most, _film->audio_frame_rate() / 2);
611 shared_ptr<AudioBuffers> silence (new AudioBuffers (_film->audio_channels(), N));
612 silence->make_silent ();
613 Audio (silence, _audio_position);
614 _audio_position += _film->audio_frames_to_time (N);
618 Player::film_changed (Film::Property p)
620 /* Here we should notice Film properties that affect our output, and
621 alert listeners that our output now would be different to how it was
622 last time we were run.
625 if (p == Film::SCALER || p == Film::WITH_SUBTITLES || p == Film::CONTAINER || p == Film::VIDEO_FRAME_RATE) {
631 Player::process_subtitle (weak_ptr<Piece> weak_piece, shared_ptr<Image> image, dcpomatic::Rect<double> rect, Time from, Time to)
633 _in_subtitle.piece = weak_piece;
634 _in_subtitle.image = image;
635 _in_subtitle.rect = rect;
636 _in_subtitle.from = from;
637 _in_subtitle.to = to;
643 Player::update_subtitle ()
645 shared_ptr<Piece> piece = _in_subtitle.piece.lock ();
650 if (!_in_subtitle.image) {
651 _out_subtitle.image.reset ();
655 shared_ptr<SubtitleContent> sc = dynamic_pointer_cast<SubtitleContent> (piece->content);
658 dcpomatic::Rect<double> in_rect = _in_subtitle.rect;
659 libdcp::Size scaled_size;
661 in_rect.y += sc->subtitle_offset ();
663 /* We will scale the subtitle up to fit _video_container_size, and also by the additional subtitle_scale */
664 scaled_size.width = in_rect.width * _video_container_size.width * sc->subtitle_scale ();
665 scaled_size.height = in_rect.height * _video_container_size.height * sc->subtitle_scale ();
667 /* Then we need a corrective translation, consisting of two parts:
669 * 1. that which is the result of the scaling of the subtitle by _video_container_size; this will be
670 * rect.x * _video_container_size.width and rect.y * _video_container_size.height.
672 * 2. that to shift the origin of the scale by subtitle_scale to the centre of the subtitle; this will be
673 * (width_before_subtitle_scale * (1 - subtitle_scale) / 2) and
674 * (height_before_subtitle_scale * (1 - subtitle_scale) / 2).
676 * Combining these two translations gives these expressions.
679 _out_subtitle.position.x = rint (_video_container_size.width * (in_rect.x + (in_rect.width * (1 - sc->subtitle_scale ()) / 2)));
680 _out_subtitle.position.y = rint (_video_container_size.height * (in_rect.y + (in_rect.height * (1 - sc->subtitle_scale ()) / 2)));
682 _out_subtitle.image = _in_subtitle.image->scale (
684 Scaler::from_id ("bicubic"),
685 _in_subtitle.image->pixel_format (),
690 Time from = _in_subtitle.from;
691 Time to = _in_subtitle.to;
692 shared_ptr<VideoContent> vc = dynamic_pointer_cast<VideoContent> (piece->content);
694 from = rint (from * vc->video_frame_rate() / _film->video_frame_rate());
695 to = rint (to * vc->video_frame_rate() / _film->video_frame_rate());
698 _out_subtitle.from = from * piece->content->position ();
699 _out_subtitle.to = to + piece->content->position ();
702 /** Re-emit the last frame that was emitted, using current settings for crop, ratio, scaler and subtitles.
703 * @return false if this could not be done.
706 Player::repeat_last_video ()
708 if (!_last_incoming_video.image || !_have_valid_pieces) {
713 _last_incoming_video.weak_piece,
714 _last_incoming_video.image,
715 _last_incoming_video.eyes,
716 _last_incoming_video.same,
717 _last_incoming_video.frame,
718 _last_incoming_video.extra
724 PlayerImage::PlayerImage (
725 shared_ptr<const Image> in,
727 libdcp::Size inter_size,
728 libdcp::Size out_size,
729 Scaler const * scaler
733 , _inter_size (inter_size)
734 , _out_size (out_size)
741 PlayerImage::set_subtitle (shared_ptr<const Image> image, Position<int> pos)
743 _subtitle_image = image;
744 _subtitle_position = pos;
748 PlayerImage::image ()
750 shared_ptr<Image> out = _in->crop_scale_window (_crop, _inter_size, _out_size, _scaler, PIX_FMT_RGB24, false);
752 Position<int> const container_offset ((_out_size.width - _inter_size.width) / 2, (_out_size.height - _inter_size.width) / 2);
754 if (_subtitle_image) {
755 out->alpha_blend (_subtitle_image, _subtitle_position);