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 /** DCPTime of the last video we emitted relative to the start of the DCP */
104 DCPTime video_position;
105 /** DCPTime of the last audio we emitted relative to the start of the DCP */
106 DCPTime audio_position;
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 DCPTime 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<DCPTime> 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<DCPTime> 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, DCPTime 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 FrameRateChange frc (content->video_frame_rate(), _film->video_frame_rate());
263 if (frc.skip && (frame % 2) == 1) {
267 DCPTime const relative_time = (frame * frc.factor() * TIME_HZ / _film->video_frame_rate());
268 if (content->trimmed (relative_time)) {
272 DCPTime 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 DCPTime const relative_time = _film->audio_frames_to_time (frame);
338 if (content->trimmed (relative_time)) {
342 DCPTime 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 ();
347 list<pair<int, libdcp::Channel> > map = content->audio_mapping().content_to_dcp ();
348 for (list<pair<int, libdcp::Channel> >::iterator i = map.begin(); i != map.end(); ++i) {
349 if (i->first < audio->channels() && i->second < dcp_mapped->channels()) {
350 dcp_mapped->accumulate_channel (audio.get(), i->first, i->second);
356 /* We must cut off anything that comes before the start of all time */
358 int const frames = - time * _film->audio_frame_rate() / TIME_HZ;
359 if (frames >= audio->frames ()) {
363 shared_ptr<AudioBuffers> trimmed (new AudioBuffers (audio->channels(), audio->frames() - frames));
364 trimmed->copy_from (audio.get(), audio->frames() - frames, frames, 0);
370 _audio_merger.push (audio, time);
371 piece->audio_position += _film->audio_frames_to_time (audio->frames ());
377 TimedAudioBuffers<DCPTime> tb = _audio_merger.flush ();
379 Audio (tb.audio, tb.time);
380 _audio_position += _film->audio_frames_to_time (tb.audio->frames ());
383 while (_video_position < _audio_position) {
387 while (_audio_position < _video_position) {
388 emit_silence (_film->time_to_audio_frames (_video_position - _audio_position));
393 /** Seek so that the next pass() will yield (approximately) the requested frame.
394 * Pass accurate = true to try harder to get close to the request.
395 * @return true on error
398 Player::seek (DCPTime t, bool accurate)
400 if (!_have_valid_pieces) {
404 if (_pieces.empty ()) {
408 for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
409 shared_ptr<VideoContent> vc = dynamic_pointer_cast<VideoContent> ((*i)->content);
414 /* s is the offset of t from the start position of this content */
415 DCPTime s = t - vc->position ();
416 s = max (static_cast<DCPTime> (0), s);
417 s = min (vc->length_after_trim(), s);
419 /* Hence set the piece positions to the `global' time */
420 (*i)->video_position = (*i)->audio_position = vc->position() + s;
422 /* And seek the decoder */
423 dynamic_pointer_cast<VideoDecoder>((*i)->decoder)->seek (s + vc->trim_start (), accurate);
424 (*i)->reset_repeat ();
427 _video_position = _audio_position = t;
428 _audio_merger.clear (t);
432 Player::setup_pieces ()
434 list<shared_ptr<Piece> > old_pieces = _pieces;
438 ContentList content = _playlist->content ();
439 sort (content.begin(), content.end(), ContentSorter ());
441 for (ContentList::iterator i = content.begin(); i != content.end(); ++i) {
443 shared_ptr<Piece> piece (new Piece (*i));
445 /* XXX: into content? */
447 shared_ptr<const FFmpegContent> fc = dynamic_pointer_cast<const FFmpegContent> (*i);
449 shared_ptr<FFmpegDecoder> fd (new FFmpegDecoder (_film, fc, _video, _audio));
451 fd->Video.connect (bind (&Player::process_video, this, weak_ptr<Piece> (piece), _1, _2, _3, _4, 0));
452 fd->Audio.connect (bind (&Player::process_audio, this, weak_ptr<Piece> (piece), _1, _2));
453 fd->Subtitle.connect (bind (&Player::process_subtitle, this, weak_ptr<Piece> (piece), _1, _2, _3, _4));
455 fd->seek (fc->trim_start (), true);
459 shared_ptr<const ImageContent> ic = dynamic_pointer_cast<const ImageContent> (*i);
461 bool reusing = false;
463 /* See if we can re-use an old ImageDecoder */
464 for (list<shared_ptr<Piece> >::const_iterator j = old_pieces.begin(); j != old_pieces.end(); ++j) {
465 shared_ptr<ImageDecoder> imd = dynamic_pointer_cast<ImageDecoder> ((*j)->decoder);
466 if (imd && imd->content() == ic) {
473 shared_ptr<ImageDecoder> id (new ImageDecoder (_film, ic));
474 id->Video.connect (bind (&Player::process_video, this, weak_ptr<Piece> (piece), _1, _2, _3, _4, 0));
479 shared_ptr<const SndfileContent> sc = dynamic_pointer_cast<const SndfileContent> (*i);
481 shared_ptr<AudioDecoder> sd (new SndfileDecoder (_film, sc));
482 sd->Audio.connect (bind (&Player::process_audio, this, weak_ptr<Piece> (piece), _1, _2));
487 _pieces.push_back (piece);
490 _have_valid_pieces = true;
494 Player::content_changed (weak_ptr<Content> w, int property, bool frequent)
496 shared_ptr<Content> c = w.lock ();
502 property == ContentProperty::POSITION || property == ContentProperty::LENGTH ||
503 property == ContentProperty::TRIM_START || property == ContentProperty::TRIM_END
506 _have_valid_pieces = false;
509 } else if (property == SubtitleContentProperty::SUBTITLE_OFFSET || property == SubtitleContentProperty::SUBTITLE_SCALE) {
515 property == VideoContentProperty::VIDEO_FRAME_TYPE || property == VideoContentProperty::VIDEO_CROP ||
516 property == VideoContentProperty::VIDEO_RATIO
521 } else if (property == ContentProperty::PATH) {
528 Player::playlist_changed ()
530 _have_valid_pieces = false;
535 Player::set_video_container_size (libdcp::Size s)
537 _video_container_size = s;
539 shared_ptr<Image> im (new Image (PIX_FMT_RGB24, _video_container_size, true));
546 _video_container_size,
547 _video_container_size,
548 Scaler::from_id ("bicubic")
553 shared_ptr<Resampler>
554 Player::resampler (shared_ptr<AudioContent> c, bool create)
556 map<shared_ptr<AudioContent>, shared_ptr<Resampler> >::iterator i = _resamplers.find (c);
557 if (i != _resamplers.end ()) {
562 return shared_ptr<Resampler> ();
567 "Creating new resampler for %1 to %2 with %3 channels", c->content_audio_frame_rate(), c->output_audio_frame_rate(), c->audio_channels()
571 shared_ptr<Resampler> r (new Resampler (c->content_audio_frame_rate(), c->output_audio_frame_rate(), c->audio_channels()));
577 Player::emit_black ()
579 #ifdef DCPOMATIC_DEBUG
580 _last_video.reset ();
583 Video (_black_frame, EYES_BOTH, ColourConversion(), _last_emit_was_black, _video_position);
584 _video_position += _film->video_frames_to_time (1);
585 _last_emit_was_black = true;
589 Player::emit_silence (OutputAudioFrame most)
595 OutputAudioFrame N = min (most, _film->audio_frame_rate() / 2);
596 shared_ptr<AudioBuffers> silence (new AudioBuffers (_film->audio_channels(), N));
597 silence->make_silent ();
598 Audio (silence, _audio_position);
599 _audio_position += _film->audio_frames_to_time (N);
603 Player::film_changed (Film::Property p)
605 /* Here we should notice Film properties that affect our output, and
606 alert listeners that our output now would be different to how it was
607 last time we were run.
610 if (p == Film::SCALER || p == Film::WITH_SUBTITLES || p == Film::CONTAINER) {
616 Player::process_subtitle (weak_ptr<Piece> weak_piece, shared_ptr<Image> image, dcpomatic::Rect<double> rect, DCPTime from, DCPTime to)
618 _in_subtitle.piece = weak_piece;
619 _in_subtitle.image = image;
620 _in_subtitle.rect = rect;
621 _in_subtitle.from = from;
622 _in_subtitle.to = to;
628 Player::update_subtitle ()
630 shared_ptr<Piece> piece = _in_subtitle.piece.lock ();
635 if (!_in_subtitle.image) {
636 _out_subtitle.image.reset ();
640 shared_ptr<SubtitleContent> sc = dynamic_pointer_cast<SubtitleContent> (piece->content);
643 dcpomatic::Rect<double> in_rect = _in_subtitle.rect;
644 libdcp::Size scaled_size;
646 in_rect.y += sc->subtitle_offset ();
648 /* We will scale the subtitle up to fit _video_container_size, and also by the additional subtitle_scale */
649 scaled_size.width = in_rect.width * _video_container_size.width * sc->subtitle_scale ();
650 scaled_size.height = in_rect.height * _video_container_size.height * sc->subtitle_scale ();
652 /* Then we need a corrective translation, consisting of two parts:
654 * 1. that which is the result of the scaling of the subtitle by _video_container_size; this will be
655 * rect.x * _video_container_size.width and rect.y * _video_container_size.height.
657 * 2. that to shift the origin of the scale by subtitle_scale to the centre of the subtitle; this will be
658 * (width_before_subtitle_scale * (1 - subtitle_scale) / 2) and
659 * (height_before_subtitle_scale * (1 - subtitle_scale) / 2).
661 * Combining these two translations gives these expressions.
664 _out_subtitle.position.x = rint (_video_container_size.width * (in_rect.x + (in_rect.width * (1 - sc->subtitle_scale ()) / 2)));
665 _out_subtitle.position.y = rint (_video_container_size.height * (in_rect.y + (in_rect.height * (1 - sc->subtitle_scale ()) / 2)));
667 _out_subtitle.image = _in_subtitle.image->scale (
669 Scaler::from_id ("bicubic"),
670 _in_subtitle.image->pixel_format (),
673 _out_subtitle.from = _in_subtitle.from + piece->content->position ();
674 _out_subtitle.to = _in_subtitle.to + piece->content->position ();
677 /** Re-emit the last frame that was emitted, using current settings for crop, ratio, scaler and subtitles.
678 * @return false if this could not be done.
681 Player::repeat_last_video ()
683 if (!_last_incoming_video.image || !_have_valid_pieces) {
688 _last_incoming_video.weak_piece,
689 _last_incoming_video.image,
690 _last_incoming_video.eyes,
691 _last_incoming_video.same,
692 _last_incoming_video.frame,
693 _last_incoming_video.extra
699 PlayerImage::PlayerImage (
700 shared_ptr<const Image> in,
702 libdcp::Size inter_size,
703 libdcp::Size out_size,
704 Scaler const * scaler
708 , _inter_size (inter_size)
709 , _out_size (out_size)
716 PlayerImage::set_subtitle (shared_ptr<const Image> image, Position<int> pos)
718 _subtitle_image = image;
719 _subtitle_position = pos;
723 PlayerImage::image ()
725 shared_ptr<Image> out = _in->crop_scale_window (_crop, _inter_size, _out_size, _scaler, PIX_FMT_RGB24, false);
727 Position<int> const container_offset ((_out_size.width - _inter_size.width) / 2, (_out_size.height - _inter_size.width) / 2);
729 if (_subtitle_image) {
730 out->alpha_blend (_subtitle_image, _subtitle_position);