2 Copyright (C) 2013-2015 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.
22 #include "ffmpeg_decoder.h"
23 #include "audio_buffers.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"
30 #include "subrip_decoder.h"
31 #include "subrip_content.h"
32 #include "dcp_content.h"
35 #include "raw_image_proxy.h"
38 #include "render_subtitles.h"
40 #include "content_video.h"
41 #include "player_video.h"
42 #include "frame_rate_change.h"
43 #include "dcp_content.h"
44 #include "dcp_decoder.h"
45 #include "dcp_subtitle_content.h"
46 #include "dcp_subtitle_decoder.h"
47 #include "audio_processor.h"
50 #include <dcp/reel_sound_asset.h>
51 #include <dcp/reel_subtitle_asset.h>
52 #include <dcp/reel_picture_asset.h>
53 #include <boost/foreach.hpp>
60 #define LOG_GENERAL(...) _film->log()->log (String::compose (__VA_ARGS__), Log::TYPE_GENERAL);
72 using boost::shared_ptr;
73 using boost::weak_ptr;
74 using boost::dynamic_pointer_cast;
75 using boost::optional;
77 Player::Player (shared_ptr<const Film> film, shared_ptr<const Playlist> playlist)
79 , _playlist (playlist)
80 , _have_valid_pieces (false)
81 , _ignore_video (false)
82 , _ignore_audio (false)
83 , _always_burn_subtitles (false)
85 , _play_referenced (false)
87 _film_changed_connection = _film->Changed.connect (bind (&Player::film_changed, this, _1));
88 _playlist_changed_connection = _playlist->Changed.connect (bind (&Player::playlist_changed, this));
89 _playlist_content_changed_connection = _playlist->ContentChanged.connect (bind (&Player::playlist_content_changed, this, _1, _2, _3));
90 set_video_container_size (_film->frame_size ());
92 film_changed (Film::AUDIO_PROCESSOR);
96 Player::setup_pieces ()
98 list<shared_ptr<Piece> > old_pieces = _pieces;
101 BOOST_FOREACH (shared_ptr<Content> i, _playlist->content ()) {
103 if (!i->paths_valid ()) {
107 shared_ptr<Decoder> decoder;
108 optional<FrameRateChange> frc;
110 /* Work out a FrameRateChange for the best overlap video for this content, in case we need it below */
111 DCPTime best_overlap_t;
112 shared_ptr<VideoContent> best_overlap;
113 BOOST_FOREACH (shared_ptr<Content> j, _playlist->content ()) {
114 shared_ptr<VideoContent> vc = dynamic_pointer_cast<VideoContent> (j);
119 DCPTime const overlap = max (vc->position(), i->position()) - min (vc->end(), i->end());
120 if (overlap > best_overlap_t) {
122 best_overlap_t = overlap;
126 optional<FrameRateChange> best_overlap_frc;
128 best_overlap_frc = FrameRateChange (best_overlap->video_frame_rate(), _film->video_frame_rate ());
130 /* No video overlap; e.g. if the DCP is just audio */
131 best_overlap_frc = FrameRateChange (_film->video_frame_rate(), _film->video_frame_rate ());
135 shared_ptr<const FFmpegContent> fc = dynamic_pointer_cast<const FFmpegContent> (i);
137 decoder.reset (new FFmpegDecoder (fc, _film->log(), _fast));
138 frc = FrameRateChange (fc->video_frame_rate(), _film->video_frame_rate());
141 shared_ptr<const DCPContent> dc = dynamic_pointer_cast<const DCPContent> (i);
143 decoder.reset (new DCPDecoder (dc, _fast));
144 frc = FrameRateChange (dc->video_frame_rate(), _film->video_frame_rate());
148 shared_ptr<const ImageContent> ic = dynamic_pointer_cast<const ImageContent> (i);
150 /* See if we can re-use an old ImageDecoder */
151 for (list<shared_ptr<Piece> >::const_iterator j = old_pieces.begin(); j != old_pieces.end(); ++j) {
152 shared_ptr<ImageDecoder> imd = dynamic_pointer_cast<ImageDecoder> ((*j)->decoder);
153 if (imd && imd->content() == ic) {
159 decoder.reset (new ImageDecoder (ic));
162 frc = FrameRateChange (ic->video_frame_rate(), _film->video_frame_rate());
166 shared_ptr<const SndfileContent> sc = dynamic_pointer_cast<const SndfileContent> (i);
168 decoder.reset (new SndfileDecoder (sc, _fast));
169 frc = best_overlap_frc;
173 shared_ptr<const SubRipContent> rc = dynamic_pointer_cast<const SubRipContent> (i);
175 decoder.reset (new SubRipDecoder (rc));
176 frc = best_overlap_frc;
179 /* DCPSubtitleContent */
180 shared_ptr<const DCPSubtitleContent> dsc = dynamic_pointer_cast<const DCPSubtitleContent> (i);
182 decoder.reset (new DCPSubtitleDecoder (dsc));
183 frc = best_overlap_frc;
186 shared_ptr<VideoDecoder> vd = dynamic_pointer_cast<VideoDecoder> (decoder);
187 if (vd && _ignore_video) {
188 vd->set_ignore_video ();
191 shared_ptr<AudioDecoder> ad = dynamic_pointer_cast<AudioDecoder> (decoder);
192 if (ad && _ignore_audio) {
193 ad->set_ignore_audio ();
196 _pieces.push_back (shared_ptr<Piece> (new Piece (i, decoder, frc.get ())));
199 _have_valid_pieces = true;
203 Player::playlist_content_changed (weak_ptr<Content> w, int property, bool frequent)
205 shared_ptr<Content> c = w.lock ();
211 property == ContentProperty::POSITION ||
212 property == ContentProperty::LENGTH ||
213 property == ContentProperty::TRIM_START ||
214 property == ContentProperty::TRIM_END ||
215 property == ContentProperty::PATH ||
216 property == VideoContentProperty::VIDEO_FRAME_TYPE ||
217 property == DCPContentProperty::CAN_BE_PLAYED
220 _have_valid_pieces = false;
224 property == SubtitleContentProperty::USE_SUBTITLES ||
225 property == SubtitleContentProperty::SUBTITLE_X_OFFSET ||
226 property == SubtitleContentProperty::SUBTITLE_Y_OFFSET ||
227 property == SubtitleContentProperty::SUBTITLE_X_SCALE ||
228 property == SubtitleContentProperty::SUBTITLE_Y_SCALE ||
229 property == SubtitleContentProperty::FONTS ||
230 property == VideoContentProperty::VIDEO_CROP ||
231 property == VideoContentProperty::VIDEO_SCALE ||
232 property == VideoContentProperty::VIDEO_FRAME_RATE ||
233 property == VideoContentProperty::VIDEO_FADE_IN ||
234 property == VideoContentProperty::VIDEO_FADE_OUT ||
235 property == VideoContentProperty::COLOUR_CONVERSION
243 Player::set_video_container_size (dcp::Size s)
245 _video_container_size = s;
247 _black_image.reset (new Image (PIX_FMT_RGB24, _video_container_size, true));
248 _black_image->make_black ();
252 Player::playlist_changed ()
254 _have_valid_pieces = false;
259 Player::film_changed (Film::Property p)
261 /* Here we should notice Film properties that affect our output, and
262 alert listeners that our output now would be different to how it was
263 last time we were run.
266 if (p == Film::CONTAINER) {
268 } else if (p == Film::VIDEO_FRAME_RATE) {
269 /* Pieces contain a FrameRateChange which contains the DCP frame rate,
270 so we need new pieces here.
272 _have_valid_pieces = false;
274 } else if (p == Film::AUDIO_PROCESSOR) {
275 if (_film->audio_processor ()) {
276 _audio_processor = _film->audio_processor()->clone (_film->audio_frame_rate ());
282 Player::transform_image_subtitles (list<ImageSubtitle> subs) const
284 list<PositionImage> all;
286 for (list<ImageSubtitle>::const_iterator i = subs.begin(); i != subs.end(); ++i) {
291 /* We will scale the subtitle up to fit _video_container_size */
292 dcp::Size scaled_size (i->rectangle.width * _video_container_size.width, i->rectangle.height * _video_container_size.height);
294 /* Then we need a corrective translation, consisting of two parts:
296 * 1. that which is the result of the scaling of the subtitle by _video_container_size; this will be
297 * rect.x * _video_container_size.width and rect.y * _video_container_size.height.
299 * 2. that to shift the origin of the scale by subtitle_scale to the centre of the subtitle; this will be
300 * (width_before_subtitle_scale * (1 - subtitle_x_scale) / 2) and
301 * (height_before_subtitle_scale * (1 - subtitle_y_scale) / 2).
303 * Combining these two translations gives these expressions.
310 dcp::YUV_TO_RGB_REC601,
311 i->image->pixel_format (),
315 lrint (_video_container_size.width * i->rectangle.x),
316 lrint (_video_container_size.height * i->rectangle.y)
325 shared_ptr<PlayerVideo>
326 Player::black_player_video_frame (DCPTime time) const
328 return shared_ptr<PlayerVideo> (
330 shared_ptr<const ImageProxy> (new RawImageProxy (_black_image)),
334 _video_container_size,
335 _video_container_size,
338 PresetColourConversion::all().front().conversion
343 /** @return All PlayerVideos at the given time. There may be none if the content
344 * at `time' is a DCP which we are passing through (i.e. referring to by reference)
345 * or 2 if we have 3D.
347 list<shared_ptr<PlayerVideo> >
348 Player::get_video (DCPTime time, bool accurate)
350 if (!_have_valid_pieces) {
354 /* Find subtitles for possible burn-in */
356 PlayerSubtitles ps = get_subtitles (time, DCPTime::from_frames (1, _film->video_frame_rate ()), false, true);
358 list<PositionImage> sub_images;
360 /* Image subtitles */
361 list<PositionImage> c = transform_image_subtitles (ps.image);
362 copy (c.begin(), c.end(), back_inserter (sub_images));
364 /* Text subtitles (rendered to an image) */
365 if (!ps.text.empty ()) {
366 list<PositionImage> s = render_subtitles (ps.text, ps.fonts, _video_container_size);
367 copy (s.begin (), s.end (), back_inserter (sub_images));
370 optional<PositionImage> subtitles;
371 if (!sub_images.empty ()) {
372 subtitles = merge (sub_images);
375 /* Find pieces containing video which is happening now */
377 list<shared_ptr<Piece> > ov = overlaps<VideoContent> (
379 time + DCPTime::from_frames (1, _film->video_frame_rate ()) - DCPTime::delta()
382 list<shared_ptr<PlayerVideo> > pvf;
385 /* No video content at this time */
386 pvf.push_back (black_player_video_frame (time));
388 /* Some video content at this time */
389 shared_ptr<Piece> last = *(ov.rbegin ());
390 VideoFrameType const last_type = dynamic_pointer_cast<VideoContent> (last->content)->video_frame_type ();
392 /* Get video from appropriate piece(s) */
393 BOOST_FOREACH (shared_ptr<Piece> piece, ov) {
395 shared_ptr<VideoDecoder> decoder = dynamic_pointer_cast<VideoDecoder> (piece->decoder);
396 DCPOMATIC_ASSERT (decoder);
397 shared_ptr<VideoContent> video_content = dynamic_pointer_cast<VideoContent> (piece->content);
398 DCPOMATIC_ASSERT (video_content);
400 shared_ptr<DCPContent> dcp_content = dynamic_pointer_cast<DCPContent> (video_content);
401 if (dcp_content && dcp_content->reference_video () && !_play_referenced) {
406 /* always use the last video */
408 /* with a corresponding L/R eye if appropriate */
409 (last_type == VIDEO_FRAME_TYPE_3D_LEFT && video_content->video_frame_type() == VIDEO_FRAME_TYPE_3D_RIGHT) ||
410 (last_type == VIDEO_FRAME_TYPE_3D_RIGHT && video_content->video_frame_type() == VIDEO_FRAME_TYPE_3D_LEFT);
413 /* We want to use this piece */
414 list<ContentVideo> content_video = decoder->get_video (dcp_to_content_video (piece, time), accurate);
415 if (content_video.empty ()) {
416 pvf.push_back (black_player_video_frame (time));
418 dcp::Size image_size = video_content->scale().size (video_content, _video_container_size, _film->frame_size ());
420 for (list<ContentVideo>::const_iterator i = content_video.begin(); i != content_video.end(); ++i) {
422 shared_ptr<PlayerVideo> (
425 content_video_to_dcp (piece, i->frame),
426 video_content->crop (),
427 video_content->fade (i->frame),
429 _video_container_size,
432 video_content->colour_conversion ()
439 /* Discard unused video */
440 decoder->get_video (dcp_to_content_video (piece, time), accurate);
446 BOOST_FOREACH (shared_ptr<PlayerVideo> p, pvf) {
447 p->set_subtitle (subtitles.get ());
454 /** @return Audio data or 0 if the only audio data here is referenced DCP data */
455 shared_ptr<AudioBuffers>
456 Player::get_audio (DCPTime time, DCPTime length, bool accurate)
458 if (!_have_valid_pieces) {
462 Frame const length_frames = length.frames_round (_film->audio_frame_rate ());
464 shared_ptr<AudioBuffers> audio (new AudioBuffers (_film->audio_channels(), length_frames));
465 audio->make_silent ();
467 list<shared_ptr<Piece> > ov = overlaps<AudioContent> (time, time + length);
472 bool all_referenced = true;
473 BOOST_FOREACH (shared_ptr<Piece> i, ov) {
474 shared_ptr<AudioContent> audio_content = dynamic_pointer_cast<AudioContent> (i->content);
475 shared_ptr<DCPContent> dcp_content = dynamic_pointer_cast<DCPContent> (i->content);
476 if (audio_content && (!dcp_content || !dcp_content->reference_audio ())) {
477 /* There is audio content which is not from a DCP or not set to be referenced */
478 all_referenced = false;
482 if (all_referenced && !_play_referenced) {
483 return shared_ptr<AudioBuffers> ();
486 BOOST_FOREACH (shared_ptr<Piece> i, ov) {
488 shared_ptr<AudioContent> content = dynamic_pointer_cast<AudioContent> (i->content);
489 DCPOMATIC_ASSERT (content);
490 shared_ptr<AudioDecoder> decoder = dynamic_pointer_cast<AudioDecoder> (i->decoder);
491 DCPOMATIC_ASSERT (decoder);
493 /* The time that we should request from the content */
494 DCPTime request = time - DCPTime::from_seconds (content->audio_delay() / 1000.0);
495 Frame request_frames = length_frames;
497 if (request < DCPTime ()) {
498 /* We went off the start of the content, so we will need to offset
499 the stuff we get back.
502 request_frames += request.frames_round (_film->audio_frame_rate ());
503 if (request_frames < 0) {
506 request = DCPTime ();
509 Frame const content_frame = dcp_to_resampled_audio (i, request);
511 BOOST_FOREACH (AudioStreamPtr j, content->audio_streams ()) {
513 if (j->channels() == 0) {
514 /* Some content (e.g. DCPs) can have streams with no channels */
518 /* Audio from this piece's decoder stream (which might be more or less than what we asked for) */
519 ContentAudio all = decoder->get_audio (j, content_frame, request_frames, accurate);
522 if (content->audio_gain() != 0) {
523 shared_ptr<AudioBuffers> gain (new AudioBuffers (all.audio));
524 gain->apply_gain (content->audio_gain ());
529 shared_ptr<AudioBuffers> dcp_mapped (new AudioBuffers (_film->audio_channels(), all.audio->frames()));
530 dcp_mapped->make_silent ();
531 AudioMapping map = j->mapping ();
532 for (int i = 0; i < map.input_channels(); ++i) {
533 for (int j = 0; j < _film->audio_channels(); ++j) {
534 if (map.get (i, j) > 0) {
535 dcp_mapped->accumulate_channel (
545 if (_audio_processor) {
546 dcp_mapped = _audio_processor->run (dcp_mapped, _film->audio_channels ());
549 all.audio = dcp_mapped;
551 audio->accumulate_frames (
553 content_frame - all.frame,
554 offset.frames_round (_film->audio_frame_rate()),
555 min (Frame (all.audio->frames()), request_frames)
564 Player::dcp_to_content_video (shared_ptr<const Piece> piece, DCPTime t) const
566 shared_ptr<const VideoContent> vc = dynamic_pointer_cast<const VideoContent> (piece->content);
567 DCPTime s = t - piece->content->position ();
568 s = min (piece->content->length_after_trim(), s);
569 s = max (DCPTime(), s + DCPTime (piece->content->trim_start(), piece->frc));
571 /* It might seem more logical here to convert s to a ContentTime (using the FrameRateChange)
572 then convert that ContentTime to frames at the content's rate. However this fails for
573 situations like content at 29.9978733fps, DCP at 30fps. The accuracy of the Time type is not
574 enough to distinguish between the two with low values of time (e.g. 3200 in Time units).
576 Instead we convert the DCPTime using the DCP video rate then account for any skip/repeat.
578 return s.frames_floor (piece->frc.dcp) / piece->frc.factor ();
582 Player::content_video_to_dcp (shared_ptr<const Piece> piece, Frame f) const
584 shared_ptr<const VideoContent> vc = dynamic_pointer_cast<const VideoContent> (piece->content);
585 /* See comment in dcp_to_content_video */
586 DCPTime const d = DCPTime::from_frames (f * piece->frc.factor(), piece->frc.dcp) - DCPTime (piece->content->trim_start (), piece->frc);
587 return max (DCPTime (), d + piece->content->position ());
591 Player::dcp_to_resampled_audio (shared_ptr<const Piece> piece, DCPTime t) const
593 DCPTime s = t - piece->content->position ();
594 s = min (piece->content->length_after_trim(), s);
595 /* See notes in dcp_to_content_video */
596 return max (DCPTime (), DCPTime (piece->content->trim_start (), piece->frc) + s).frames_floor (_film->audio_frame_rate ());
600 Player::dcp_to_content_subtitle (shared_ptr<const Piece> piece, DCPTime t) const
602 DCPTime s = t - piece->content->position ();
603 s = min (piece->content->length_after_trim(), s);
604 return max (ContentTime (), ContentTime (s, piece->frc) + piece->content->trim_start());
607 /** @param burnt true to return only subtitles to be burnt, false to return only
608 * subtitles that should not be burnt. This parameter will be ignored if
609 * _always_burn_subtitles is true; in this case, all subtitles will be returned.
612 Player::get_subtitles (DCPTime time, DCPTime length, bool starting, bool burnt)
614 list<shared_ptr<Piece> > subs = overlaps<SubtitleContent> (time, time + length);
616 PlayerSubtitles ps (time, length);
618 for (list<shared_ptr<Piece> >::const_iterator j = subs.begin(); j != subs.end(); ++j) {
619 shared_ptr<SubtitleContent> subtitle_content = dynamic_pointer_cast<SubtitleContent> ((*j)->content);
620 if (!subtitle_content->use_subtitles () || (!_always_burn_subtitles && (burnt != subtitle_content->burn_subtitles ()))) {
624 shared_ptr<DCPContent> dcp_content = dynamic_pointer_cast<DCPContent> (subtitle_content);
625 if (dcp_content && dcp_content->reference_subtitle () && !_play_referenced) {
629 shared_ptr<SubtitleDecoder> subtitle_decoder = dynamic_pointer_cast<SubtitleDecoder> ((*j)->decoder);
630 ContentTime const from = dcp_to_content_subtitle (*j, time);
631 /* XXX: this video_frame_rate() should be the rate that the subtitle content has been prepared for */
632 ContentTime const to = from + ContentTime::from_frames (1, _film->video_frame_rate ());
634 list<ContentImageSubtitle> image = subtitle_decoder->get_image_subtitles (ContentTimePeriod (from, to), starting);
635 for (list<ContentImageSubtitle>::iterator i = image.begin(); i != image.end(); ++i) {
637 /* Apply content's subtitle offsets */
638 i->sub.rectangle.x += subtitle_content->subtitle_x_offset ();
639 i->sub.rectangle.y += subtitle_content->subtitle_y_offset ();
641 /* Apply content's subtitle scale */
642 i->sub.rectangle.width *= subtitle_content->subtitle_x_scale ();
643 i->sub.rectangle.height *= subtitle_content->subtitle_y_scale ();
645 /* Apply a corrective translation to keep the subtitle centred after that scale */
646 i->sub.rectangle.x -= i->sub.rectangle.width * (subtitle_content->subtitle_x_scale() - 1);
647 i->sub.rectangle.y -= i->sub.rectangle.height * (subtitle_content->subtitle_y_scale() - 1);
649 ps.image.push_back (i->sub);
652 list<ContentTextSubtitle> text = subtitle_decoder->get_text_subtitles (ContentTimePeriod (from, to), starting);
653 BOOST_FOREACH (ContentTextSubtitle& ts, text) {
654 BOOST_FOREACH (dcp::SubtitleString& s, ts.subs) {
655 s.set_h_position (s.h_position() + subtitle_content->subtitle_x_offset ());
656 s.set_v_position (s.v_position() + subtitle_content->subtitle_y_offset ());
657 float const xs = subtitle_content->subtitle_x_scale();
658 float const ys = subtitle_content->subtitle_y_scale();
659 float const average = s.size() * (xs + ys) / 2;
660 s.set_size (average);
661 if (fabs (1.0 - xs / ys) > dcp::ASPECT_ADJUST_EPSILON) {
662 s.set_aspect_adjust (xs / ys);
664 ps.text.push_back (s);
665 ps.add_fonts (subtitle_content->fonts ());
673 list<shared_ptr<Font> >
674 Player::get_subtitle_fonts ()
676 if (!_have_valid_pieces) {
680 list<shared_ptr<Font> > fonts;
681 BOOST_FOREACH (shared_ptr<Piece>& p, _pieces) {
682 shared_ptr<SubtitleContent> sc = dynamic_pointer_cast<SubtitleContent> (p->content);
684 /* XXX: things may go wrong if there are duplicate font IDs
685 with different font files.
687 list<shared_ptr<Font> > f = sc->fonts ();
688 copy (f.begin(), f.end(), back_inserter (fonts));
695 /** Set this player never to produce any video data */
697 Player::set_ignore_video ()
699 _ignore_video = true;
702 /** Set this player never to produce any audio data */
704 Player::set_ignore_audio ()
706 _ignore_audio = true;
709 /** Set whether or not this player should always burn text subtitles into the image,
710 * regardless of the content settings.
711 * @param burn true to always burn subtitles, false to obey content settings.
714 Player::set_always_burn_subtitles (bool burn)
716 _always_burn_subtitles = burn;
723 _have_valid_pieces = false;
727 Player::set_play_referenced ()
729 _play_referenced = true;
730 _have_valid_pieces = false;
733 list<shared_ptr<dcp::ReelAsset> >
734 Player::get_reel_assets ()
736 list<shared_ptr<dcp::ReelAsset> > a;
738 BOOST_FOREACH (shared_ptr<Content> i, _playlist->content ()) {
739 shared_ptr<DCPContent> j = dynamic_pointer_cast<DCPContent> (i);
743 /* XXX: hack hack hack */
744 DCPDecoder decoder (j, false);
745 if (j->reference_video ()) {
746 a.push_back (decoder.reels().front()->main_picture ());
748 if (j->reference_audio ()) {
749 a.push_back (decoder.reels().front()->main_sound ());
751 if (j->reference_subtitle ()) {
752 a.push_back (decoder.reels().front()->main_subtitle ());