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 (_film->frame_size ());
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 libdcp::Size const image_size = content->scale().size (content, _video_container_size, _film->frame_size ());
278 shared_ptr<PlayerImage> pi (
283 _video_container_size,
288 if (_film->with_subtitles () && _out_subtitle.image && time >= _out_subtitle.from && time <= _out_subtitle.to) {
290 Position<int> const container_offset (
291 (_video_container_size.width - image_size.width) / 2,
292 (_video_container_size.height - image_size.width) / 2
295 pi->set_subtitle (_out_subtitle.image, _out_subtitle.position + container_offset);
299 #ifdef DCPOMATIC_DEBUG
300 _last_video = piece->content;
303 Video (pi, eyes, content->colour_conversion(), same, time);
305 _last_emit_was_black = false;
306 _video_position = piece->video_position = (time + TIME_HZ / _film->video_frame_rate());
308 if (frc.repeat > 1 && !piece->repeating ()) {
309 piece->set_repeat (_last_incoming_video, frc.repeat - 1);
314 Player::process_audio (weak_ptr<Piece> weak_piece, shared_ptr<const AudioBuffers> audio, AudioContent::Frame frame)
316 shared_ptr<Piece> piece = weak_piece.lock ();
321 shared_ptr<AudioContent> content = dynamic_pointer_cast<AudioContent> (piece->content);
325 if (content->audio_gain() != 0) {
326 shared_ptr<AudioBuffers> gain (new AudioBuffers (audio));
327 gain->apply_gain (content->audio_gain ());
332 if (content->content_audio_frame_rate() != content->output_audio_frame_rate()) {
333 shared_ptr<Resampler> r = resampler (content, true);
334 pair<shared_ptr<const AudioBuffers>, AudioContent::Frame> ro = r->run (audio, frame);
339 Time const relative_time = _film->audio_frames_to_time (frame);
341 if (content->trimmed (relative_time)) {
345 Time time = content->position() + (content->audio_delay() * TIME_HZ / 1000) + relative_time - content->trim_start ();
348 shared_ptr<AudioBuffers> dcp_mapped (new AudioBuffers (_film->audio_channels(), audio->frames()));
349 dcp_mapped->make_silent ();
351 AudioMapping map = content->audio_mapping ();
352 for (int i = 0; i < map.content_channels(); ++i) {
353 for (int j = 0; j < _film->audio_channels(); ++j) {
354 if (map.get (i, static_cast<libdcp::Channel> (j)) > 0) {
355 dcp_mapped->accumulate_channel (
358 static_cast<libdcp::Channel> (j),
359 map.get (i, static_cast<libdcp::Channel> (j))
367 /* We must cut off anything that comes before the start of all time */
369 int const frames = - time * _film->audio_frame_rate() / TIME_HZ;
370 if (frames >= audio->frames ()) {
374 shared_ptr<AudioBuffers> trimmed (new AudioBuffers (audio->channels(), audio->frames() - frames));
375 trimmed->copy_from (audio.get(), audio->frames() - frames, frames, 0);
381 _audio_merger.push (audio, time);
382 piece->audio_position += _film->audio_frames_to_time (audio->frames ());
388 TimedAudioBuffers<Time> tb = _audio_merger.flush ();
389 if (_audio && tb.audio) {
390 Audio (tb.audio, tb.time);
391 _audio_position += _film->audio_frames_to_time (tb.audio->frames ());
394 while (_video && _video_position < _audio_position) {
398 while (_audio && _audio_position < _video_position) {
399 emit_silence (_film->time_to_audio_frames (_video_position - _audio_position));
404 /** Seek so that the next pass() will yield (approximately) the requested frame.
405 * Pass accurate = true to try harder to get close to the request.
406 * @return true on error
409 Player::seek (Time t, bool accurate)
411 if (!_have_valid_pieces) {
415 if (_pieces.empty ()) {
419 for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
420 shared_ptr<VideoContent> vc = dynamic_pointer_cast<VideoContent> ((*i)->content);
425 /* s is the offset of t from the start position of this content */
426 Time s = t - vc->position ();
427 s = max (static_cast<Time> (0), s);
428 s = min (vc->length_after_trim(), s);
430 /* Hence set the piece positions to the `global' time */
431 (*i)->video_position = (*i)->audio_position = vc->position() + s;
433 /* And seek the decoder */
434 dynamic_pointer_cast<VideoDecoder>((*i)->decoder)->seek (
435 vc->time_to_content_video_frames (s + vc->trim_start ()), accurate
438 (*i)->reset_repeat ();
441 _video_position = _audio_position = t;
443 /* XXX: don't seek audio because we don't need to... */
447 Player::setup_pieces ()
449 list<shared_ptr<Piece> > old_pieces = _pieces;
453 ContentList content = _playlist->content ();
454 sort (content.begin(), content.end(), ContentSorter ());
456 for (ContentList::iterator i = content.begin(); i != content.end(); ++i) {
458 if (!(*i)->paths_valid ()) {
462 shared_ptr<Piece> piece (new Piece (*i));
464 /* XXX: into content? */
466 shared_ptr<const FFmpegContent> fc = dynamic_pointer_cast<const FFmpegContent> (*i);
468 shared_ptr<FFmpegDecoder> fd (new FFmpegDecoder (_film, fc, _video, _audio));
470 fd->Video.connect (bind (&Player::process_video, this, weak_ptr<Piece> (piece), _1, _2, _3, _4, 0));
471 fd->Audio.connect (bind (&Player::process_audio, this, weak_ptr<Piece> (piece), _1, _2));
472 fd->Subtitle.connect (bind (&Player::process_subtitle, this, weak_ptr<Piece> (piece), _1, _2, _3, _4));
474 fd->seek (fc->time_to_content_video_frames (fc->trim_start ()), true);
478 shared_ptr<const ImageContent> ic = dynamic_pointer_cast<const ImageContent> (*i);
480 bool reusing = false;
482 /* See if we can re-use an old ImageDecoder */
483 for (list<shared_ptr<Piece> >::const_iterator j = old_pieces.begin(); j != old_pieces.end(); ++j) {
484 shared_ptr<ImageDecoder> imd = dynamic_pointer_cast<ImageDecoder> ((*j)->decoder);
485 if (imd && imd->content() == ic) {
492 shared_ptr<ImageDecoder> id (new ImageDecoder (_film, ic));
493 id->Video.connect (bind (&Player::process_video, this, weak_ptr<Piece> (piece), _1, _2, _3, _4, 0));
498 shared_ptr<const SndfileContent> sc = dynamic_pointer_cast<const SndfileContent> (*i);
500 shared_ptr<AudioDecoder> sd (new SndfileDecoder (_film, sc));
501 sd->Audio.connect (bind (&Player::process_audio, this, weak_ptr<Piece> (piece), _1, _2));
506 _pieces.push_back (piece);
509 _have_valid_pieces = true;
513 Player::content_changed (weak_ptr<Content> w, int property, bool frequent)
515 shared_ptr<Content> c = w.lock ();
521 property == ContentProperty::POSITION || property == ContentProperty::LENGTH ||
522 property == ContentProperty::TRIM_START || property == ContentProperty::TRIM_END ||
523 property == VideoContentProperty::VIDEO_FRAME_TYPE
526 _have_valid_pieces = false;
530 property == SubtitleContentProperty::SUBTITLE_X_OFFSET ||
531 property == SubtitleContentProperty::SUBTITLE_Y_OFFSET ||
532 property == SubtitleContentProperty::SUBTITLE_SCALE
539 property == VideoContentProperty::VIDEO_CROP || property == VideoContentProperty::VIDEO_SCALE ||
540 property == VideoContentProperty::VIDEO_FRAME_RATE
545 } else if (property == ContentProperty::PATH) {
547 _have_valid_pieces = false;
553 Player::playlist_changed ()
555 _have_valid_pieces = false;
560 Player::set_video_container_size (libdcp::Size s)
562 _video_container_size = s;
564 shared_ptr<Image> im (new Image (PIX_FMT_RGB24, _video_container_size, true));
571 _video_container_size,
572 _video_container_size,
573 Scaler::from_id ("bicubic")
578 shared_ptr<Resampler>
579 Player::resampler (shared_ptr<AudioContent> c, bool create)
581 map<shared_ptr<AudioContent>, shared_ptr<Resampler> >::iterator i = _resamplers.find (c);
582 if (i != _resamplers.end ()) {
587 return shared_ptr<Resampler> ();
592 "Creating new resampler for %1 to %2 with %3 channels", c->content_audio_frame_rate(), c->output_audio_frame_rate(), c->audio_channels()
596 shared_ptr<Resampler> r (new Resampler (c->content_audio_frame_rate(), c->output_audio_frame_rate(), c->audio_channels()));
602 Player::emit_black ()
604 #ifdef DCPOMATIC_DEBUG
605 _last_video.reset ();
608 Video (_black_frame, EYES_BOTH, ColourConversion(), _last_emit_was_black, _video_position);
609 _video_position += _film->video_frames_to_time (1);
610 _last_emit_was_black = true;
614 Player::emit_silence (OutputAudioFrame most)
620 OutputAudioFrame N = min (most, _film->audio_frame_rate() / 2);
621 shared_ptr<AudioBuffers> silence (new AudioBuffers (_film->audio_channels(), N));
622 silence->make_silent ();
623 Audio (silence, _audio_position);
624 _audio_position += _film->audio_frames_to_time (N);
628 Player::film_changed (Film::Property p)
630 /* Here we should notice Film properties that affect our output, and
631 alert listeners that our output now would be different to how it was
632 last time we were run.
635 if (p == Film::SCALER || p == Film::WITH_SUBTITLES || p == Film::CONTAINER || p == Film::VIDEO_FRAME_RATE) {
641 Player::process_subtitle (weak_ptr<Piece> weak_piece, shared_ptr<Image> image, dcpomatic::Rect<double> rect, Time from, Time to)
643 _in_subtitle.piece = weak_piece;
644 _in_subtitle.image = image;
645 _in_subtitle.rect = rect;
646 _in_subtitle.from = from;
647 _in_subtitle.to = to;
653 Player::update_subtitle ()
655 shared_ptr<Piece> piece = _in_subtitle.piece.lock ();
660 if (!_in_subtitle.image) {
661 _out_subtitle.image.reset ();
665 shared_ptr<SubtitleContent> sc = dynamic_pointer_cast<SubtitleContent> (piece->content);
668 dcpomatic::Rect<double> in_rect = _in_subtitle.rect;
669 libdcp::Size scaled_size;
671 in_rect.x += sc->subtitle_x_offset ();
672 in_rect.y += sc->subtitle_y_offset ();
674 /* We will scale the subtitle up to fit _video_container_size, and also by the additional subtitle_scale */
675 scaled_size.width = in_rect.width * _video_container_size.width * sc->subtitle_scale ();
676 scaled_size.height = in_rect.height * _video_container_size.height * sc->subtitle_scale ();
678 /* Then we need a corrective translation, consisting of two parts:
680 * 1. that which is the result of the scaling of the subtitle by _video_container_size; this will be
681 * rect.x * _video_container_size.width and rect.y * _video_container_size.height.
683 * 2. that to shift the origin of the scale by subtitle_scale to the centre of the subtitle; this will be
684 * (width_before_subtitle_scale * (1 - subtitle_scale) / 2) and
685 * (height_before_subtitle_scale * (1 - subtitle_scale) / 2).
687 * Combining these two translations gives these expressions.
690 _out_subtitle.position.x = rint (_video_container_size.width * (in_rect.x + (in_rect.width * (1 - sc->subtitle_scale ()) / 2)));
691 _out_subtitle.position.y = rint (_video_container_size.height * (in_rect.y + (in_rect.height * (1 - sc->subtitle_scale ()) / 2)));
693 _out_subtitle.image = _in_subtitle.image->scale (
695 Scaler::from_id ("bicubic"),
696 _in_subtitle.image->pixel_format (),
701 Time from = _in_subtitle.from;
702 Time to = _in_subtitle.to;
703 shared_ptr<VideoContent> vc = dynamic_pointer_cast<VideoContent> (piece->content);
705 from = rint (from * vc->video_frame_rate() / _film->video_frame_rate());
706 to = rint (to * vc->video_frame_rate() / _film->video_frame_rate());
709 _out_subtitle.from = from + piece->content->position ();
710 _out_subtitle.to = to + piece->content->position ();
713 /** Re-emit the last frame that was emitted, using current settings for crop, ratio, scaler and subtitles.
714 * @return false if this could not be done.
717 Player::repeat_last_video ()
719 if (!_last_incoming_video.image || !_have_valid_pieces) {
724 _last_incoming_video.weak_piece,
725 _last_incoming_video.image,
726 _last_incoming_video.eyes,
727 _last_incoming_video.same,
728 _last_incoming_video.frame,
729 _last_incoming_video.extra
735 PlayerImage::PlayerImage (
736 shared_ptr<const Image> in,
738 libdcp::Size inter_size,
739 libdcp::Size out_size,
740 Scaler const * scaler
744 , _inter_size (inter_size)
745 , _out_size (out_size)
752 PlayerImage::set_subtitle (shared_ptr<const Image> image, Position<int> pos)
754 _subtitle_image = image;
755 _subtitle_position = pos;
759 PlayerImage::image ()
761 shared_ptr<Image> out = _in->crop_scale_window (_crop, _inter_size, _out_size, _scaler, PIX_FMT_RGB24, false);
763 Position<int> const container_offset ((_out_size.width - _inter_size.width) / 2, (_out_size.height - _inter_size.width) / 2);
765 if (_subtitle_image) {
766 out->alpha_blend (_subtitle_image, _subtitle_position);