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 "still_image_decoder.h"
26 #include "still_image_content.h"
27 #include "moving_image_decoder.h"
28 #include "moving_image_content.h"
29 #include "sndfile_decoder.h"
30 #include "sndfile_content.h"
31 #include "subtitle_content.h"
36 #include "resampler.h"
47 using boost::shared_ptr;
48 using boost::weak_ptr;
49 using boost::dynamic_pointer_cast;
54 Piece (shared_ptr<Content> c)
56 , video_position (c->position ())
57 , audio_position (c->position ())
62 Piece (shared_ptr<Content> c, shared_ptr<Decoder> d)
65 , video_position (c->position ())
66 , 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 (fit_ratio_within (_film->container()->ratio (), _film->full_frame ()));
133 Player::disable_video ()
139 Player::disable_audio ()
147 if (!_have_valid_pieces) {
149 _have_valid_pieces = true;
152 Time earliest_t = TIME_MAX;
153 shared_ptr<Piece> earliest;
159 for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
160 if ((*i)->decoder->done ()) {
164 shared_ptr<VideoDecoder> vd = dynamic_pointer_cast<VideoDecoder> ((*i)->decoder);
165 shared_ptr<AudioDecoder> ad = dynamic_pointer_cast<AudioDecoder> ((*i)->decoder);
168 if ((*i)->video_position < earliest_t) {
169 earliest_t = (*i)->video_position;
175 if (_audio && ad && ad->has_audio ()) {
176 if ((*i)->audio_position < earliest_t) {
177 earliest_t = (*i)->audio_position;
191 if (earliest_t > _video_position) {
194 if (earliest->repeating ()) {
195 earliest->repeat (this);
197 earliest->decoder->pass ();
203 if (earliest_t > _audio_position) {
204 emit_silence (_film->time_to_audio_frames (earliest_t - _audio_position));
206 earliest->decoder->pass ();
208 if (earliest->decoder->done()) {
209 shared_ptr<AudioContent> ac = dynamic_pointer_cast<AudioContent> (earliest->content);
211 shared_ptr<Resampler> re = resampler (ac, false);
213 shared_ptr<const AudioBuffers> b = re->flush ();
215 process_audio (earliest, b, ac->audio_length ());
224 Time audio_done_up_to = TIME_MAX;
225 for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
226 if (dynamic_pointer_cast<AudioDecoder> ((*i)->decoder)) {
227 audio_done_up_to = min (audio_done_up_to, (*i)->audio_position);
231 TimedAudioBuffers<Time> tb = _audio_merger.pull (audio_done_up_to);
232 Audio (tb.audio, tb.time);
233 _audio_position += _film->audio_frames_to_time (tb.audio->frames ());
239 /** @param extra Amount of extra time to add to the content frame's time (for repeat) */
241 Player::process_video (weak_ptr<Piece> weak_piece, shared_ptr<const Image> image, Eyes eyes, bool same, VideoContent::Frame frame, Time extra)
243 /* Keep a note of what came in so that we can repeat it if required */
244 _last_incoming_video.weak_piece = weak_piece;
245 _last_incoming_video.image = image;
246 _last_incoming_video.eyes = eyes;
247 _last_incoming_video.same = same;
248 _last_incoming_video.frame = frame;
249 _last_incoming_video.extra = extra;
251 shared_ptr<Piece> piece = weak_piece.lock ();
256 shared_ptr<VideoContent> content = dynamic_pointer_cast<VideoContent> (piece->content);
259 FrameRateConversion frc (content->video_frame_rate(), _film->video_frame_rate());
260 if (frc.skip && (frame % 2) == 1) {
264 Time const relative_time = (frame * frc.factor() * TIME_HZ / _film->video_frame_rate());
265 if (content->trimmed (relative_time)) {
269 /* Convert to RGB first, as FFmpeg doesn't seem to like handling YUV images with odd widths */
270 shared_ptr<Image> work_image = image->scale (image->size (), _film->scaler(), PIX_FMT_RGB24, true);
272 work_image = work_image->crop (content->crop(), true);
274 float const ratio = content->ratio() ? content->ratio()->ratio() : content->video_size_after_crop().ratio();
275 libdcp::Size image_size = fit_ratio_within (ratio, _video_container_size);
277 work_image = work_image->scale (image_size, _film->scaler(), PIX_FMT_RGB24, true);
279 Time time = content->position() + relative_time + extra - content->trim_start ();
281 if (_film->with_subtitles () && _out_subtitle.image && time >= _out_subtitle.from && time <= _out_subtitle.to) {
282 work_image->alpha_blend (_out_subtitle.image, _out_subtitle.position);
285 if (image_size != _video_container_size) {
286 assert (image_size.width <= _video_container_size.width);
287 assert (image_size.height <= _video_container_size.height);
288 shared_ptr<Image> im (new Image (PIX_FMT_RGB24, _video_container_size, true));
290 im->copy (work_image, Position<int> ((_video_container_size.width - image_size.width) / 2, (_video_container_size.height - image_size.height) / 2));
294 #ifdef DCPOMATIC_DEBUG
295 _last_video = piece->content;
298 Video (work_image, eyes, content->colour_conversion(), same, time);
300 time += TIME_HZ / _film->video_frame_rate();
301 _last_emit_was_black = false;
302 _video_position = piece->video_position = time;
304 if (frc.repeat > 1 && !piece->repeating ()) {
305 piece->set_repeat (_last_incoming_video, frc.repeat - 1);
310 Player::process_audio (weak_ptr<Piece> weak_piece, shared_ptr<const AudioBuffers> audio, AudioContent::Frame frame)
312 shared_ptr<Piece> piece = weak_piece.lock ();
317 shared_ptr<AudioContent> content = dynamic_pointer_cast<AudioContent> (piece->content);
321 if (content->audio_gain() != 0) {
322 shared_ptr<AudioBuffers> gain (new AudioBuffers (audio));
323 gain->apply_gain (content->audio_gain ());
328 if (content->content_audio_frame_rate() != content->output_audio_frame_rate()) {
329 shared_ptr<Resampler> r = resampler (content, true);
330 pair<shared_ptr<const AudioBuffers>, AudioContent::Frame> ro = r->run (audio, frame);
335 Time const relative_time = _film->audio_frames_to_time (frame);
337 if (content->trimmed (relative_time)) {
341 Time time = content->position() + (content->audio_delay() * TIME_HZ / 1000) + relative_time - content->trim_start ();
344 shared_ptr<AudioBuffers> dcp_mapped (new AudioBuffers (_film->audio_channels(), audio->frames()));
345 dcp_mapped->make_silent ();
346 list<pair<int, libdcp::Channel> > map = content->audio_mapping().content_to_dcp ();
347 for (list<pair<int, libdcp::Channel> >::iterator i = map.begin(); i != map.end(); ++i) {
348 if (i->first < audio->channels() && i->second < dcp_mapped->channels()) {
349 dcp_mapped->accumulate_channel (audio.get(), i->first, i->second);
355 /* We must cut off anything that comes before the start of all time */
357 int const frames = - time * _film->audio_frame_rate() / TIME_HZ;
358 if (frames >= audio->frames ()) {
362 shared_ptr<AudioBuffers> trimmed (new AudioBuffers (audio->channels(), audio->frames() - frames));
363 trimmed->copy_from (audio.get(), audio->frames() - frames, frames, 0);
369 _audio_merger.push (audio, time);
370 piece->audio_position += _film->audio_frames_to_time (audio->frames ());
376 TimedAudioBuffers<Time> tb = _audio_merger.flush ();
378 Audio (tb.audio, tb.time);
379 _audio_position += _film->audio_frames_to_time (tb.audio->frames ());
382 while (_video_position < _audio_position) {
386 while (_audio_position < _video_position) {
387 emit_silence (_film->time_to_audio_frames (_video_position - _audio_position));
392 /** Seek so that the next pass() will yield (approximately) the requested frame.
393 * Pass accurate = true to try harder to get close to the request.
394 * @return true on error
397 Player::seek (Time t, bool accurate)
399 if (!_have_valid_pieces) {
401 _have_valid_pieces = true;
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 Time s = t - vc->position ();
416 s = max (static_cast<Time> (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 (
424 vc->time_to_content_video_frames (s + vc->trim_start ()), accurate
427 (*i)->reset_repeat ();
430 _video_position = _audio_position = t;
432 /* XXX: don't seek audio because we don't need to... */
436 Player::setup_pieces ()
438 list<shared_ptr<Piece> > old_pieces = _pieces;
442 ContentList content = _playlist->content ();
443 sort (content.begin(), content.end(), ContentSorter ());
445 for (ContentList::iterator i = content.begin(); i != content.end(); ++i) {
447 shared_ptr<Piece> piece (new Piece (*i));
449 /* XXX: into content? */
451 shared_ptr<const FFmpegContent> fc = dynamic_pointer_cast<const FFmpegContent> (*i);
453 shared_ptr<FFmpegDecoder> fd (new FFmpegDecoder (_film, fc, _video, _audio));
455 fd->Video.connect (bind (&Player::process_video, this, weak_ptr<Piece> (piece), _1, _2, _3, _4, 0));
456 fd->Audio.connect (bind (&Player::process_audio, this, weak_ptr<Piece> (piece), _1, _2));
457 fd->Subtitle.connect (bind (&Player::process_subtitle, this, weak_ptr<Piece> (piece), _1, _2, _3, _4));
459 fd->seek (fc->time_to_content_video_frames (fc->trim_start ()), true);
463 shared_ptr<const StillImageContent> ic = dynamic_pointer_cast<const StillImageContent> (*i);
465 shared_ptr<StillImageDecoder> id;
467 /* See if we can re-use an old StillImageDecoder */
468 for (list<shared_ptr<Piece> >::const_iterator j = old_pieces.begin(); j != old_pieces.end(); ++j) {
469 shared_ptr<StillImageDecoder> imd = dynamic_pointer_cast<StillImageDecoder> ((*j)->decoder);
470 if (imd && imd->content() == ic) {
476 id.reset (new StillImageDecoder (_film, ic));
477 id->Video.connect (bind (&Player::process_video, this, weak_ptr<Piece> (piece), _1, _2, _3, _4, 0));
483 shared_ptr<const MovingImageContent> mc = dynamic_pointer_cast<const MovingImageContent> (*i);
485 shared_ptr<MovingImageDecoder> md;
488 md.reset (new MovingImageDecoder (_film, mc));
489 md->Video.connect (bind (&Player::process_video, this, weak_ptr<Piece> (piece), _1, _2, _3, _4, 0));
495 shared_ptr<const SndfileContent> sc = dynamic_pointer_cast<const SndfileContent> (*i);
497 shared_ptr<AudioDecoder> sd (new SndfileDecoder (_film, sc));
498 sd->Audio.connect (bind (&Player::process_audio, this, weak_ptr<Piece> (piece), _1, _2));
503 _pieces.push_back (piece);
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
520 _have_valid_pieces = false;
523 } else if (property == SubtitleContentProperty::SUBTITLE_OFFSET || property == SubtitleContentProperty::SUBTITLE_SCALE) {
529 property == VideoContentProperty::VIDEO_FRAME_TYPE || property == VideoContentProperty::VIDEO_CROP ||
530 property == VideoContentProperty::VIDEO_RATIO
535 } else if (property == ContentProperty::PATH) {
542 Player::playlist_changed ()
544 _have_valid_pieces = false;
549 Player::set_video_container_size (libdcp::Size s)
551 _video_container_size = s;
552 _black_frame.reset (new Image (PIX_FMT_RGB24, _video_container_size, true));
553 _black_frame->make_black ();
556 shared_ptr<Resampler>
557 Player::resampler (shared_ptr<AudioContent> c, bool create)
559 map<shared_ptr<AudioContent>, shared_ptr<Resampler> >::iterator i = _resamplers.find (c);
560 if (i != _resamplers.end ()) {
565 return shared_ptr<Resampler> ();
568 shared_ptr<Resampler> r (new Resampler (c->content_audio_frame_rate(), c->output_audio_frame_rate(), c->audio_channels()));
574 Player::emit_black ()
576 #ifdef DCPOMATIC_DEBUG
577 _last_video.reset ();
580 Video (_black_frame, EYES_BOTH, ColourConversion(), _last_emit_was_black, _video_position);
581 _video_position += _film->video_frames_to_time (1);
582 _last_emit_was_black = true;
586 Player::emit_silence (OutputAudioFrame most)
592 OutputAudioFrame N = min (most, _film->audio_frame_rate() / 2);
593 shared_ptr<AudioBuffers> silence (new AudioBuffers (_film->audio_channels(), N));
594 silence->make_silent ();
595 Audio (silence, _audio_position);
596 _audio_position += _film->audio_frames_to_time (N);
600 Player::film_changed (Film::Property p)
602 /* Here we should notice Film properties that affect our output, and
603 alert listeners that our output now would be different to how it was
604 last time we were run.
607 if (p == Film::SCALER || p == Film::WITH_SUBTITLES || p == Film::CONTAINER) {
613 Player::process_subtitle (weak_ptr<Piece> weak_piece, shared_ptr<Image> image, dcpomatic::Rect<double> rect, Time from, Time to)
615 _in_subtitle.piece = weak_piece;
616 _in_subtitle.image = image;
617 _in_subtitle.rect = rect;
618 _in_subtitle.from = from;
619 _in_subtitle.to = to;
625 Player::update_subtitle ()
627 shared_ptr<Piece> piece = _in_subtitle.piece.lock ();
632 if (!_in_subtitle.image) {
633 _out_subtitle.image.reset ();
637 shared_ptr<SubtitleContent> sc = dynamic_pointer_cast<SubtitleContent> (piece->content);
640 dcpomatic::Rect<double> in_rect = _in_subtitle.rect;
641 libdcp::Size scaled_size;
643 in_rect.y += sc->subtitle_offset ();
645 /* We will scale the subtitle up to fit _video_container_size, and also by the additional subtitle_scale */
646 scaled_size.width = in_rect.width * _video_container_size.width * sc->subtitle_scale ();
647 scaled_size.height = in_rect.height * _video_container_size.height * sc->subtitle_scale ();
649 /* Then we need a corrective translation, consisting of two parts:
651 * 1. that which is the result of the scaling of the subtitle by _video_container_size; this will be
652 * rect.x * _video_container_size.width and rect.y * _video_container_size.height.
654 * 2. that to shift the origin of the scale by subtitle_scale to the centre of the subtitle; this will be
655 * (width_before_subtitle_scale * (1 - subtitle_scale) / 2) and
656 * (height_before_subtitle_scale * (1 - subtitle_scale) / 2).
658 * Combining these two translations gives these expressions.
661 _out_subtitle.position.x = rint (_video_container_size.width * (in_rect.x + (in_rect.width * (1 - sc->subtitle_scale ()) / 2)));
662 _out_subtitle.position.y = rint (_video_container_size.height * (in_rect.y + (in_rect.height * (1 - sc->subtitle_scale ()) / 2)));
664 _out_subtitle.image = _in_subtitle.image->scale (
666 Scaler::from_id ("bicubic"),
667 _in_subtitle.image->pixel_format (),
670 _out_subtitle.from = _in_subtitle.from + piece->content->position ();
671 _out_subtitle.to = _in_subtitle.to + piece->content->position ();
674 /** Re-emit the last frame that was emitted, using current settings for crop, ratio, scaler and subtitles.
675 * @return false if this could not be done.
678 Player::repeat_last_video ()
680 if (!_last_incoming_video.image) {
685 _last_incoming_video.weak_piece,
686 _last_incoming_video.image,
687 _last_incoming_video.eyes,
688 _last_incoming_video.same,
689 _last_incoming_video.frame,
690 _last_incoming_video.extra