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;
525 property == SubtitleContentProperty::SUBTITLE_X_OFFSET ||
526 property == SubtitleContentProperty::SUBTITLE_Y_OFFSET ||
527 property == SubtitleContentProperty::SUBTITLE_SCALE
534 property == VideoContentProperty::VIDEO_CROP || property == VideoContentProperty::VIDEO_RATIO ||
535 property == VideoContentProperty::VIDEO_FRAME_RATE
540 } else if (property == ContentProperty::PATH) {
547 Player::playlist_changed ()
549 _have_valid_pieces = false;
554 Player::set_video_container_size (libdcp::Size s)
556 _video_container_size = s;
558 shared_ptr<Image> im (new Image (PIX_FMT_RGB24, _video_container_size, true));
565 _video_container_size,
566 _video_container_size,
567 Scaler::from_id ("bicubic")
572 shared_ptr<Resampler>
573 Player::resampler (shared_ptr<AudioContent> c, bool create)
575 map<shared_ptr<AudioContent>, shared_ptr<Resampler> >::iterator i = _resamplers.find (c);
576 if (i != _resamplers.end ()) {
581 return shared_ptr<Resampler> ();
586 "Creating new resampler for %1 to %2 with %3 channels", c->content_audio_frame_rate(), c->output_audio_frame_rate(), c->audio_channels()
590 shared_ptr<Resampler> r (new Resampler (c->content_audio_frame_rate(), c->output_audio_frame_rate(), c->audio_channels()));
596 Player::emit_black ()
598 #ifdef DCPOMATIC_DEBUG
599 _last_video.reset ();
602 Video (_black_frame, EYES_BOTH, ColourConversion(), _last_emit_was_black, _video_position);
603 _video_position += _film->video_frames_to_time (1);
604 _last_emit_was_black = true;
608 Player::emit_silence (OutputAudioFrame most)
614 OutputAudioFrame N = min (most, _film->audio_frame_rate() / 2);
615 shared_ptr<AudioBuffers> silence (new AudioBuffers (_film->audio_channels(), N));
616 silence->make_silent ();
617 Audio (silence, _audio_position);
618 _audio_position += _film->audio_frames_to_time (N);
622 Player::film_changed (Film::Property p)
624 /* Here we should notice Film properties that affect our output, and
625 alert listeners that our output now would be different to how it was
626 last time we were run.
629 if (p == Film::SCALER || p == Film::WITH_SUBTITLES || p == Film::CONTAINER || p == Film::VIDEO_FRAME_RATE) {
635 Player::process_subtitle (weak_ptr<Piece> weak_piece, shared_ptr<Image> image, dcpomatic::Rect<double> rect, Time from, Time to)
637 _in_subtitle.piece = weak_piece;
638 _in_subtitle.image = image;
639 _in_subtitle.rect = rect;
640 _in_subtitle.from = from;
641 _in_subtitle.to = to;
647 Player::update_subtitle ()
649 shared_ptr<Piece> piece = _in_subtitle.piece.lock ();
654 if (!_in_subtitle.image) {
655 _out_subtitle.image.reset ();
659 shared_ptr<SubtitleContent> sc = dynamic_pointer_cast<SubtitleContent> (piece->content);
662 dcpomatic::Rect<double> in_rect = _in_subtitle.rect;
663 libdcp::Size scaled_size;
665 in_rect.x += sc->subtitle_x_offset ();
666 in_rect.y += sc->subtitle_y_offset ();
668 /* We will scale the subtitle up to fit _video_container_size, and also by the additional subtitle_scale */
669 scaled_size.width = in_rect.width * _video_container_size.width * sc->subtitle_scale ();
670 scaled_size.height = in_rect.height * _video_container_size.height * sc->subtitle_scale ();
672 /* Then we need a corrective translation, consisting of two parts:
674 * 1. that which is the result of the scaling of the subtitle by _video_container_size; this will be
675 * rect.x * _video_container_size.width and rect.y * _video_container_size.height.
677 * 2. that to shift the origin of the scale by subtitle_scale to the centre of the subtitle; this will be
678 * (width_before_subtitle_scale * (1 - subtitle_scale) / 2) and
679 * (height_before_subtitle_scale * (1 - subtitle_scale) / 2).
681 * Combining these two translations gives these expressions.
684 _out_subtitle.position.x = rint (_video_container_size.width * (in_rect.x + (in_rect.width * (1 - sc->subtitle_scale ()) / 2)));
685 _out_subtitle.position.y = rint (_video_container_size.height * (in_rect.y + (in_rect.height * (1 - sc->subtitle_scale ()) / 2)));
687 _out_subtitle.image = _in_subtitle.image->scale (
689 Scaler::from_id ("bicubic"),
690 _in_subtitle.image->pixel_format (),
695 Time from = _in_subtitle.from;
696 Time to = _in_subtitle.to;
697 shared_ptr<VideoContent> vc = dynamic_pointer_cast<VideoContent> (piece->content);
699 from = rint (from * vc->video_frame_rate() / _film->video_frame_rate());
700 to = rint (to * vc->video_frame_rate() / _film->video_frame_rate());
703 _out_subtitle.from = from + piece->content->position ();
704 _out_subtitle.to = to + piece->content->position ();
707 /** Re-emit the last frame that was emitted, using current settings for crop, ratio, scaler and subtitles.
708 * @return false if this could not be done.
711 Player::repeat_last_video ()
713 if (!_last_incoming_video.image || !_have_valid_pieces) {
718 _last_incoming_video.weak_piece,
719 _last_incoming_video.image,
720 _last_incoming_video.eyes,
721 _last_incoming_video.same,
722 _last_incoming_video.frame,
723 _last_incoming_video.extra
729 PlayerImage::PlayerImage (
730 shared_ptr<const Image> in,
732 libdcp::Size inter_size,
733 libdcp::Size out_size,
734 Scaler const * scaler
738 , _inter_size (inter_size)
739 , _out_size (out_size)
746 PlayerImage::set_subtitle (shared_ptr<const Image> image, Position<int> pos)
748 _subtitle_image = image;
749 _subtitle_position = pos;
753 PlayerImage::image ()
755 shared_ptr<Image> out = _in->crop_scale_window (_crop, _inter_size, _out_size, _scaler, PIX_FMT_RGB24, false);
757 Position<int> const container_offset ((_out_size.width - _inter_size.width) / 2, (_out_size.height - _inter_size.width) / 2);
759 if (_subtitle_image) {
760 out->alpha_blend (_subtitle_image, _subtitle_position);