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<Image> work_image = image->crop_scale_window (content->crop(), image_size, _video_container_size, _film->scaler(), PIX_FMT_RGB24, false);
279 Position<int> const container_offset (
280 (_video_container_size.width - image_size.width) / 2,
281 (_video_container_size.height - image_size.width) / 2
284 if (_film->with_subtitles () && _out_subtitle.image && time >= _out_subtitle.from && time <= _out_subtitle.to) {
285 work_image->alpha_blend (_out_subtitle.image, _out_subtitle.position + container_offset);
288 #ifdef DCPOMATIC_DEBUG
289 _last_video = piece->content;
292 Video (work_image, eyes, content->colour_conversion(), same, time);
294 _last_emit_was_black = false;
295 _video_position = piece->video_position = (time + TIME_HZ / _film->video_frame_rate());
297 if (frc.repeat > 1 && !piece->repeating ()) {
298 piece->set_repeat (_last_incoming_video, frc.repeat - 1);
303 Player::process_audio (weak_ptr<Piece> weak_piece, shared_ptr<const AudioBuffers> audio, AudioContent::Frame frame)
305 shared_ptr<Piece> piece = weak_piece.lock ();
310 shared_ptr<AudioContent> content = dynamic_pointer_cast<AudioContent> (piece->content);
314 if (content->audio_gain() != 0) {
315 shared_ptr<AudioBuffers> gain (new AudioBuffers (audio));
316 gain->apply_gain (content->audio_gain ());
321 if (content->content_audio_frame_rate() != content->output_audio_frame_rate()) {
322 shared_ptr<Resampler> r = resampler (content, true);
323 pair<shared_ptr<const AudioBuffers>, AudioContent::Frame> ro = r->run (audio, frame);
328 Time const relative_time = _film->audio_frames_to_time (frame);
330 if (content->trimmed (relative_time)) {
334 Time time = content->position() + (content->audio_delay() * TIME_HZ / 1000) + relative_time - content->trim_start ();
337 shared_ptr<AudioBuffers> dcp_mapped (new AudioBuffers (_film->audio_channels(), audio->frames()));
338 dcp_mapped->make_silent ();
339 list<pair<int, libdcp::Channel> > map = content->audio_mapping().content_to_dcp ();
340 for (list<pair<int, libdcp::Channel> >::iterator i = map.begin(); i != map.end(); ++i) {
341 if (i->first < audio->channels() && i->second < dcp_mapped->channels()) {
342 dcp_mapped->accumulate_channel (audio.get(), i->first, i->second);
348 /* We must cut off anything that comes before the start of all time */
350 int const frames = - time * _film->audio_frame_rate() / TIME_HZ;
351 if (frames >= audio->frames ()) {
355 shared_ptr<AudioBuffers> trimmed (new AudioBuffers (audio->channels(), audio->frames() - frames));
356 trimmed->copy_from (audio.get(), audio->frames() - frames, frames, 0);
362 _audio_merger.push (audio, time);
363 piece->audio_position += _film->audio_frames_to_time (audio->frames ());
369 TimedAudioBuffers<Time> tb = _audio_merger.flush ();
371 Audio (tb.audio, tb.time);
372 _audio_position += _film->audio_frames_to_time (tb.audio->frames ());
375 while (_video_position < _audio_position) {
379 while (_audio_position < _video_position) {
380 emit_silence (_film->time_to_audio_frames (_video_position - _audio_position));
385 /** Seek so that the next pass() will yield (approximately) the requested frame.
386 * Pass accurate = true to try harder to get close to the request.
387 * @return true on error
390 Player::seek (Time t, bool accurate)
392 if (!_have_valid_pieces) {
394 _have_valid_pieces = true;
397 if (_pieces.empty ()) {
401 for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
402 shared_ptr<VideoContent> vc = dynamic_pointer_cast<VideoContent> ((*i)->content);
407 /* s is the offset of t from the start position of this content */
408 Time s = t - vc->position ();
409 s = max (static_cast<Time> (0), s);
410 s = min (vc->length_after_trim(), s);
412 /* Hence set the piece positions to the `global' time */
413 (*i)->video_position = (*i)->audio_position = vc->position() + s;
415 /* And seek the decoder */
416 dynamic_pointer_cast<VideoDecoder>((*i)->decoder)->seek (
417 vc->time_to_content_video_frames (s + vc->trim_start ()), accurate
420 (*i)->reset_repeat ();
423 _video_position = _audio_position = t;
425 /* XXX: don't seek audio because we don't need to... */
429 Player::setup_pieces ()
431 list<shared_ptr<Piece> > old_pieces = _pieces;
435 ContentList content = _playlist->content ();
436 sort (content.begin(), content.end(), ContentSorter ());
438 for (ContentList::iterator i = content.begin(); i != content.end(); ++i) {
440 shared_ptr<Piece> piece (new Piece (*i));
442 /* XXX: into content? */
444 shared_ptr<const FFmpegContent> fc = dynamic_pointer_cast<const FFmpegContent> (*i);
446 shared_ptr<FFmpegDecoder> fd (new FFmpegDecoder (_film, fc, _video, _audio));
448 fd->Video.connect (bind (&Player::process_video, this, weak_ptr<Piece> (piece), _1, _2, _3, _4, 0));
449 fd->Audio.connect (bind (&Player::process_audio, this, weak_ptr<Piece> (piece), _1, _2));
450 fd->Subtitle.connect (bind (&Player::process_subtitle, this, weak_ptr<Piece> (piece), _1, _2, _3, _4));
452 fd->seek (fc->time_to_content_video_frames (fc->trim_start ()), true);
456 shared_ptr<const ImageContent> ic = dynamic_pointer_cast<const ImageContent> (*i);
458 bool reusing = false;
460 /* See if we can re-use an old ImageDecoder */
461 for (list<shared_ptr<Piece> >::const_iterator j = old_pieces.begin(); j != old_pieces.end(); ++j) {
462 shared_ptr<ImageDecoder> imd = dynamic_pointer_cast<ImageDecoder> ((*j)->decoder);
463 if (imd && imd->content() == ic) {
470 shared_ptr<ImageDecoder> id (new ImageDecoder (_film, ic));
471 id->Video.connect (bind (&Player::process_video, this, weak_ptr<Piece> (piece), _1, _2, _3, _4, 0));
476 shared_ptr<const SndfileContent> sc = dynamic_pointer_cast<const SndfileContent> (*i);
478 shared_ptr<AudioDecoder> sd (new SndfileDecoder (_film, sc));
479 sd->Audio.connect (bind (&Player::process_audio, this, weak_ptr<Piece> (piece), _1, _2));
484 _pieces.push_back (piece);
489 Player::content_changed (weak_ptr<Content> w, int property, bool frequent)
491 shared_ptr<Content> c = w.lock ();
497 property == ContentProperty::POSITION || property == ContentProperty::LENGTH ||
498 property == ContentProperty::TRIM_START || property == ContentProperty::TRIM_END
501 _have_valid_pieces = false;
504 } else if (property == SubtitleContentProperty::SUBTITLE_OFFSET || property == SubtitleContentProperty::SUBTITLE_SCALE) {
510 property == VideoContentProperty::VIDEO_FRAME_TYPE || property == VideoContentProperty::VIDEO_CROP ||
511 property == VideoContentProperty::VIDEO_RATIO
516 } else if (property == ContentProperty::PATH) {
523 Player::playlist_changed ()
525 _have_valid_pieces = false;
530 Player::set_video_container_size (libdcp::Size s)
532 _video_container_size = s;
533 _black_frame.reset (new Image (PIX_FMT_RGB24, _video_container_size, true));
534 _black_frame->make_black ();
537 shared_ptr<Resampler>
538 Player::resampler (shared_ptr<AudioContent> c, bool create)
540 map<shared_ptr<AudioContent>, shared_ptr<Resampler> >::iterator i = _resamplers.find (c);
541 if (i != _resamplers.end ()) {
546 return shared_ptr<Resampler> ();
551 "Creating new resampler for %1 to %2 with %3 channels", c->content_audio_frame_rate(), c->output_audio_frame_rate(), c->audio_channels()
555 shared_ptr<Resampler> r (new Resampler (c->content_audio_frame_rate(), c->output_audio_frame_rate(), c->audio_channels()));
561 Player::emit_black ()
563 #ifdef DCPOMATIC_DEBUG
564 _last_video.reset ();
567 Video (_black_frame, EYES_BOTH, ColourConversion(), _last_emit_was_black, _video_position);
568 _video_position += _film->video_frames_to_time (1);
569 _last_emit_was_black = true;
573 Player::emit_silence (OutputAudioFrame most)
579 OutputAudioFrame N = min (most, _film->audio_frame_rate() / 2);
580 shared_ptr<AudioBuffers> silence (new AudioBuffers (_film->audio_channels(), N));
581 silence->make_silent ();
582 Audio (silence, _audio_position);
583 _audio_position += _film->audio_frames_to_time (N);
587 Player::film_changed (Film::Property p)
589 /* Here we should notice Film properties that affect our output, and
590 alert listeners that our output now would be different to how it was
591 last time we were run.
594 if (p == Film::SCALER || p == Film::WITH_SUBTITLES || p == Film::CONTAINER) {
600 Player::process_subtitle (weak_ptr<Piece> weak_piece, shared_ptr<Image> image, dcpomatic::Rect<double> rect, Time from, Time to)
602 _in_subtitle.piece = weak_piece;
603 _in_subtitle.image = image;
604 _in_subtitle.rect = rect;
605 _in_subtitle.from = from;
606 _in_subtitle.to = to;
612 Player::update_subtitle ()
614 shared_ptr<Piece> piece = _in_subtitle.piece.lock ();
619 if (!_in_subtitle.image) {
620 _out_subtitle.image.reset ();
624 shared_ptr<SubtitleContent> sc = dynamic_pointer_cast<SubtitleContent> (piece->content);
627 dcpomatic::Rect<double> in_rect = _in_subtitle.rect;
628 libdcp::Size scaled_size;
630 in_rect.y += sc->subtitle_offset ();
632 /* We will scale the subtitle up to fit _video_container_size, and also by the additional subtitle_scale */
633 scaled_size.width = in_rect.width * _video_container_size.width * sc->subtitle_scale ();
634 scaled_size.height = in_rect.height * _video_container_size.height * sc->subtitle_scale ();
636 /* Then we need a corrective translation, consisting of two parts:
638 * 1. that which is the result of the scaling of the subtitle by _video_container_size; this will be
639 * rect.x * _video_container_size.width and rect.y * _video_container_size.height.
641 * 2. that to shift the origin of the scale by subtitle_scale to the centre of the subtitle; this will be
642 * (width_before_subtitle_scale * (1 - subtitle_scale) / 2) and
643 * (height_before_subtitle_scale * (1 - subtitle_scale) / 2).
645 * Combining these two translations gives these expressions.
648 _out_subtitle.position.x = rint (_video_container_size.width * (in_rect.x + (in_rect.width * (1 - sc->subtitle_scale ()) / 2)));
649 _out_subtitle.position.y = rint (_video_container_size.height * (in_rect.y + (in_rect.height * (1 - sc->subtitle_scale ()) / 2)));
651 _out_subtitle.image = _in_subtitle.image->scale (
653 Scaler::from_id ("bicubic"),
654 _in_subtitle.image->pixel_format (),
657 _out_subtitle.from = _in_subtitle.from + piece->content->position ();
658 _out_subtitle.to = _in_subtitle.to + piece->content->position ();
661 /** Re-emit the last frame that was emitted, using current settings for crop, ratio, scaler and subtitles.
662 * @return false if this could not be done.
665 Player::repeat_last_video ()
667 if (!_last_incoming_video.image) {
672 _last_incoming_video.weak_piece,
673 _last_incoming_video.image,
674 _last_incoming_video.eyes,
675 _last_incoming_video.same,
676 _last_incoming_video.frame,
677 _last_incoming_video.extra