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"
49 #include <boost/foreach.hpp>
55 #define LOG_GENERAL(...) _film->log()->log (String::compose (__VA_ARGS__), Log::TYPE_GENERAL);
67 using boost::shared_ptr;
68 using boost::weak_ptr;
69 using boost::dynamic_pointer_cast;
70 using boost::optional;
72 Player::Player (shared_ptr<const Film> film, shared_ptr<const Playlist> playlist)
74 , _playlist (playlist)
75 , _have_valid_pieces (false)
76 , _ignore_video (false)
77 , _ignore_audio (false)
78 , _always_burn_subtitles (false)
80 _film_changed_connection = _film->Changed.connect (bind (&Player::film_changed, this, _1));
81 _playlist_changed_connection = _playlist->Changed.connect (bind (&Player::playlist_changed, this));
82 _playlist_content_changed_connection = _playlist->ContentChanged.connect (bind (&Player::playlist_content_changed, this, _1, _2, _3));
83 set_video_container_size (_film->frame_size ());
85 film_changed (Film::AUDIO_PROCESSOR);
89 Player::setup_pieces ()
91 list<shared_ptr<Piece> > old_pieces = _pieces;
94 BOOST_FOREACH (shared_ptr<Content> i, _playlist->content ()) {
96 if (!i->paths_valid ()) {
100 shared_ptr<Decoder> decoder;
101 optional<FrameRateChange> frc;
103 /* Work out a FrameRateChange for the best overlap video for this content, in case we need it below */
104 DCPTime best_overlap_t;
105 shared_ptr<VideoContent> best_overlap;
106 BOOST_FOREACH (shared_ptr<Content> j, _playlist->content ()) {
107 shared_ptr<VideoContent> vc = dynamic_pointer_cast<VideoContent> (j);
112 DCPTime const overlap = max (vc->position(), i->position()) - min (vc->end(), i->end());
113 if (overlap > best_overlap_t) {
115 best_overlap_t = overlap;
119 optional<FrameRateChange> best_overlap_frc;
121 best_overlap_frc = FrameRateChange (best_overlap->video_frame_rate(), _film->video_frame_rate ());
123 /* No video overlap; e.g. if the DCP is just audio */
124 best_overlap_frc = FrameRateChange (_film->video_frame_rate(), _film->video_frame_rate ());
128 shared_ptr<const FFmpegContent> fc = dynamic_pointer_cast<const FFmpegContent> (i);
130 decoder.reset (new FFmpegDecoder (fc, _film->log()));
131 frc = FrameRateChange (fc->video_frame_rate(), _film->video_frame_rate());
134 shared_ptr<const DCPContent> dc = dynamic_pointer_cast<const DCPContent> (i);
136 decoder.reset (new DCPDecoder (dc));
137 frc = FrameRateChange (dc->video_frame_rate(), _film->video_frame_rate());
141 shared_ptr<const ImageContent> ic = dynamic_pointer_cast<const ImageContent> (i);
143 /* See if we can re-use an old ImageDecoder */
144 for (list<shared_ptr<Piece> >::const_iterator j = old_pieces.begin(); j != old_pieces.end(); ++j) {
145 shared_ptr<ImageDecoder> imd = dynamic_pointer_cast<ImageDecoder> ((*j)->decoder);
146 if (imd && imd->content() == ic) {
152 decoder.reset (new ImageDecoder (ic));
155 frc = FrameRateChange (ic->video_frame_rate(), _film->video_frame_rate());
159 shared_ptr<const SndfileContent> sc = dynamic_pointer_cast<const SndfileContent> (i);
161 decoder.reset (new SndfileDecoder (sc));
162 frc = best_overlap_frc;
166 shared_ptr<const SubRipContent> rc = dynamic_pointer_cast<const SubRipContent> (i);
168 decoder.reset (new SubRipDecoder (rc));
169 frc = best_overlap_frc;
172 /* DCPSubtitleContent */
173 shared_ptr<const DCPSubtitleContent> dsc = dynamic_pointer_cast<const DCPSubtitleContent> (i);
175 decoder.reset (new DCPSubtitleDecoder (dsc));
176 frc = best_overlap_frc;
179 shared_ptr<VideoDecoder> vd = dynamic_pointer_cast<VideoDecoder> (decoder);
180 if (vd && _ignore_video) {
181 vd->set_ignore_video ();
184 shared_ptr<AudioDecoder> ad = dynamic_pointer_cast<AudioDecoder> (decoder);
185 if (ad && _ignore_audio) {
186 ad->set_ignore_audio ();
189 _pieces.push_back (shared_ptr<Piece> (new Piece (i, decoder, frc.get ())));
192 _have_valid_pieces = true;
196 Player::playlist_content_changed (weak_ptr<Content> w, int property, bool frequent)
198 shared_ptr<Content> c = w.lock ();
204 property == ContentProperty::POSITION ||
205 property == ContentProperty::LENGTH ||
206 property == ContentProperty::TRIM_START ||
207 property == ContentProperty::TRIM_END ||
208 property == ContentProperty::PATH ||
209 property == VideoContentProperty::VIDEO_FRAME_TYPE ||
210 property == DCPContentProperty::CAN_BE_PLAYED
213 _have_valid_pieces = false;
217 property == SubtitleContentProperty::USE_SUBTITLES ||
218 property == SubtitleContentProperty::SUBTITLE_X_OFFSET ||
219 property == SubtitleContentProperty::SUBTITLE_Y_OFFSET ||
220 property == SubtitleContentProperty::SUBTITLE_X_SCALE ||
221 property == SubtitleContentProperty::SUBTITLE_Y_SCALE ||
222 property == SubtitleContentProperty::FONTS ||
223 property == VideoContentProperty::VIDEO_CROP ||
224 property == VideoContentProperty::VIDEO_SCALE ||
225 property == VideoContentProperty::VIDEO_FRAME_RATE ||
226 property == VideoContentProperty::VIDEO_FADE_IN ||
227 property == VideoContentProperty::VIDEO_FADE_OUT ||
228 property == VideoContentProperty::COLOUR_CONVERSION
236 Player::set_video_container_size (dcp::Size s)
238 _video_container_size = s;
240 _black_image.reset (new Image (PIX_FMT_RGB24, _video_container_size, true));
241 _black_image->make_black ();
245 Player::playlist_changed ()
247 _have_valid_pieces = false;
252 Player::film_changed (Film::Property p)
254 /* Here we should notice Film properties that affect our output, and
255 alert listeners that our output now would be different to how it was
256 last time we were run.
259 if (p == Film::CONTAINER || p == Film::VIDEO_FRAME_RATE) {
261 } else if (p == Film::AUDIO_PROCESSOR) {
262 if (_film->audio_processor ()) {
263 _audio_processor = _film->audio_processor()->clone (_film->audio_frame_rate ());
269 Player::transform_image_subtitles (list<ImageSubtitle> subs) const
271 list<PositionImage> all;
273 for (list<ImageSubtitle>::const_iterator i = subs.begin(); i != subs.end(); ++i) {
278 /* We will scale the subtitle up to fit _video_container_size */
279 dcp::Size scaled_size (i->rectangle.width * _video_container_size.width, i->rectangle.height * _video_container_size.height);
281 /* Then we need a corrective translation, consisting of two parts:
283 * 1. that which is the result of the scaling of the subtitle by _video_container_size; this will be
284 * rect.x * _video_container_size.width and rect.y * _video_container_size.height.
286 * 2. that to shift the origin of the scale by subtitle_scale to the centre of the subtitle; this will be
287 * (width_before_subtitle_scale * (1 - subtitle_x_scale) / 2) and
288 * (height_before_subtitle_scale * (1 - subtitle_y_scale) / 2).
290 * Combining these two translations gives these expressions.
297 dcp::YUV_TO_RGB_REC601,
298 i->image->pixel_format (),
302 lrint (_video_container_size.width * i->rectangle.x),
303 lrint (_video_container_size.height * i->rectangle.y)
312 shared_ptr<PlayerVideo>
313 Player::black_player_video_frame (DCPTime time) const
315 return shared_ptr<PlayerVideo> (
317 shared_ptr<const ImageProxy> (new RawImageProxy (_black_image)),
321 _video_container_size,
322 _video_container_size,
325 PresetColourConversion::all().front().conversion
330 /** @return All PlayerVideos at the given time (there may be two frames for 3D) */
331 list<shared_ptr<PlayerVideo> >
332 Player::get_video (DCPTime time, bool accurate)
334 if (!_have_valid_pieces) {
338 /* Find subtitles for possible burn-in */
340 PlayerSubtitles ps = get_subtitles (time, DCPTime::from_frames (1, _film->video_frame_rate ()), false, true);
342 list<PositionImage> sub_images;
344 /* Image subtitles */
345 list<PositionImage> c = transform_image_subtitles (ps.image);
346 copy (c.begin(), c.end(), back_inserter (sub_images));
348 /* Text subtitles (rendered to an image) */
349 if (!ps.text.empty ()) {
350 list<PositionImage> s = render_subtitles (ps.text, ps.fonts, _video_container_size);
351 copy (s.begin (), s.end (), back_inserter (sub_images));
354 optional<PositionImage> subtitles;
355 if (!sub_images.empty ()) {
356 subtitles = merge (sub_images);
359 /* Find pieces containing video which is happening now */
361 list<shared_ptr<Piece> > ov = overlaps<VideoContent> (
363 time + DCPTime::from_frames (1, _film->video_frame_rate ()) - DCPTime::delta()
366 list<shared_ptr<PlayerVideo> > pvf;
369 /* No video content at this time */
370 pvf.push_back (black_player_video_frame (time));
372 /* Some video content at this time */
373 shared_ptr<Piece> last = *(ov.rbegin ());
374 VideoFrameType const last_type = dynamic_pointer_cast<VideoContent> (last->content)->video_frame_type ();
376 /* Get video from appropriate piece(s) */
377 BOOST_FOREACH (shared_ptr<Piece> piece, ov) {
379 shared_ptr<VideoDecoder> decoder = dynamic_pointer_cast<VideoDecoder> (piece->decoder);
380 DCPOMATIC_ASSERT (decoder);
381 shared_ptr<VideoContent> video_content = dynamic_pointer_cast<VideoContent> (piece->content);
382 DCPOMATIC_ASSERT (video_content);
385 /* always use the last video */
387 /* with a corresponding L/R eye if appropriate */
388 (last_type == VIDEO_FRAME_TYPE_3D_LEFT && video_content->video_frame_type() == VIDEO_FRAME_TYPE_3D_RIGHT) ||
389 (last_type == VIDEO_FRAME_TYPE_3D_RIGHT && video_content->video_frame_type() == VIDEO_FRAME_TYPE_3D_LEFT);
392 /* We want to use this piece */
393 list<ContentVideo> content_video = decoder->get_video (dcp_to_content_video (piece, time), accurate);
394 if (content_video.empty ()) {
395 pvf.push_back (black_player_video_frame (time));
397 dcp::Size image_size = video_content->scale().size (video_content, _video_container_size, _film->frame_size ());
399 for (list<ContentVideo>::const_iterator i = content_video.begin(); i != content_video.end(); ++i) {
401 shared_ptr<PlayerVideo> (
404 content_video_to_dcp (piece, i->frame),
405 video_content->crop (),
406 video_content->fade (i->frame),
408 _video_container_size,
411 video_content->colour_conversion ()
418 /* Discard unused video */
419 decoder->get_video (dcp_to_content_video (piece, time), accurate);
425 BOOST_FOREACH (shared_ptr<PlayerVideo> p, pvf) {
426 p->set_subtitle (subtitles.get ());
433 shared_ptr<AudioBuffers>
434 Player::get_audio (DCPTime time, DCPTime length, bool accurate)
436 if (!_have_valid_pieces) {
440 Frame const length_frames = length.frames_round (_film->audio_frame_rate ());
442 shared_ptr<AudioBuffers> audio (new AudioBuffers (_film->audio_channels(), length_frames));
443 audio->make_silent ();
445 list<shared_ptr<Piece> > ov = overlaps<AudioContent> (time, time + length);
450 for (list<shared_ptr<Piece> >::iterator i = ov.begin(); i != ov.end(); ++i) {
452 shared_ptr<AudioContent> content = dynamic_pointer_cast<AudioContent> ((*i)->content);
453 DCPOMATIC_ASSERT (content);
454 shared_ptr<AudioDecoder> decoder = dynamic_pointer_cast<AudioDecoder> ((*i)->decoder);
455 DCPOMATIC_ASSERT (decoder);
457 /* The time that we should request from the content */
458 DCPTime request = time - DCPTime::from_seconds (content->audio_delay() / 1000.0);
459 Frame request_frames = length_frames;
461 if (request < DCPTime ()) {
462 /* We went off the start of the content, so we will need to offset
463 the stuff we get back.
466 request_frames += request.frames_round (_film->audio_frame_rate ());
467 if (request_frames < 0) {
470 request = DCPTime ();
473 Frame const content_frame = dcp_to_resampled_audio (*i, request);
475 BOOST_FOREACH (AudioStreamPtr j, content->audio_streams ()) {
477 if (j->channels() == 0) {
478 /* Some content (e.g. DCPs) can have streams with no channels */
482 /* Audio from this piece's decoder stream (which might be more or less than what we asked for) */
483 ContentAudio all = decoder->get_audio (j, content_frame, request_frames, accurate);
486 if (content->audio_gain() != 0) {
487 shared_ptr<AudioBuffers> gain (new AudioBuffers (all.audio));
488 gain->apply_gain (content->audio_gain ());
493 shared_ptr<AudioBuffers> dcp_mapped (new AudioBuffers (_film->audio_channels(), all.audio->frames()));
494 dcp_mapped->make_silent ();
495 AudioMapping map = j->mapping ();
496 for (int i = 0; i < map.input_channels(); ++i) {
497 for (int j = 0; j < _film->audio_channels(); ++j) {
498 if (map.get (i, j) > 0) {
499 dcp_mapped->accumulate_channel (
509 if (_audio_processor) {
510 dcp_mapped = _audio_processor->run (dcp_mapped);
513 all.audio = dcp_mapped;
515 audio->accumulate_frames (
517 content_frame - all.frame,
518 offset.frames_round (_film->audio_frame_rate()),
519 min (Frame (all.audio->frames()), request_frames)
528 Player::dcp_to_content_video (shared_ptr<const Piece> piece, DCPTime t) const
530 shared_ptr<const VideoContent> vc = dynamic_pointer_cast<const VideoContent> (piece->content);
531 DCPTime s = t - piece->content->position ();
532 s = min (piece->content->length_after_trim(), s);
533 s = max (DCPTime(), s + DCPTime (piece->content->trim_start(), piece->frc));
535 /* It might seem more logical here to convert s to a ContentTime (using the FrameRateChange)
536 then convert that ContentTime to frames at the content's rate. However this fails for
537 situations like content at 29.9978733fps, DCP at 30fps. The accuracy of the Time type is not
538 enough to distinguish between the two with low values of time (e.g. 3200 in Time units).
540 Instead we convert the DCPTime using the DCP video rate then account for any skip/repeat.
542 return s.frames_floor (piece->frc.dcp) / piece->frc.factor ();
546 Player::content_video_to_dcp (shared_ptr<const Piece> piece, Frame f) const
548 shared_ptr<const VideoContent> vc = dynamic_pointer_cast<const VideoContent> (piece->content);
549 /* See comment in dcp_to_content_video */
550 DCPTime const d = DCPTime::from_frames (f * piece->frc.factor(), piece->frc.dcp) - DCPTime (piece->content->trim_start (), piece->frc);
551 return max (DCPTime (), d + piece->content->position ());
555 Player::dcp_to_resampled_audio (shared_ptr<const Piece> piece, DCPTime t) const
557 DCPTime s = t - piece->content->position ();
558 s = min (piece->content->length_after_trim(), s);
559 /* See notes in dcp_to_content_video */
560 return max (DCPTime (), DCPTime (piece->content->trim_start (), piece->frc) + s).frames_floor (_film->audio_frame_rate ());
564 Player::dcp_to_content_subtitle (shared_ptr<const Piece> piece, DCPTime t) const
566 DCPTime s = t - piece->content->position ();
567 s = min (piece->content->length_after_trim(), s);
568 return max (ContentTime (), ContentTime (s, piece->frc) + piece->content->trim_start());
571 /** @param burnt true to return only subtitles to be burnt, false to return only
572 * subtitles that should not be burnt. This parameter will be ignored if
573 * _always_burn_subtitles is true; in this case, all subtitles will be returned.
576 Player::get_subtitles (DCPTime time, DCPTime length, bool starting, bool burnt)
578 list<shared_ptr<Piece> > subs = overlaps<SubtitleContent> (time, time + length);
580 PlayerSubtitles ps (time, length);
582 for (list<shared_ptr<Piece> >::const_iterator j = subs.begin(); j != subs.end(); ++j) {
583 shared_ptr<SubtitleContent> subtitle_content = dynamic_pointer_cast<SubtitleContent> ((*j)->content);
584 if (!subtitle_content->use_subtitles () || (!_always_burn_subtitles && (burnt != subtitle_content->burn_subtitles ()))) {
588 shared_ptr<SubtitleDecoder> subtitle_decoder = dynamic_pointer_cast<SubtitleDecoder> ((*j)->decoder);
589 ContentTime const from = dcp_to_content_subtitle (*j, time);
590 /* XXX: this video_frame_rate() should be the rate that the subtitle content has been prepared for */
591 ContentTime const to = from + ContentTime::from_frames (1, _film->video_frame_rate ());
593 list<ContentImageSubtitle> image = subtitle_decoder->get_image_subtitles (ContentTimePeriod (from, to), starting);
594 for (list<ContentImageSubtitle>::iterator i = image.begin(); i != image.end(); ++i) {
596 /* Apply content's subtitle offsets */
597 i->sub.rectangle.x += subtitle_content->subtitle_x_offset ();
598 i->sub.rectangle.y += subtitle_content->subtitle_y_offset ();
600 /* Apply content's subtitle scale */
601 i->sub.rectangle.width *= subtitle_content->subtitle_x_scale ();
602 i->sub.rectangle.height *= subtitle_content->subtitle_y_scale ();
604 /* Apply a corrective translation to keep the subtitle centred after that scale */
605 i->sub.rectangle.x -= i->sub.rectangle.width * (subtitle_content->subtitle_x_scale() - 1);
606 i->sub.rectangle.y -= i->sub.rectangle.height * (subtitle_content->subtitle_y_scale() - 1);
608 ps.image.push_back (i->sub);
611 list<ContentTextSubtitle> text = subtitle_decoder->get_text_subtitles (ContentTimePeriod (from, to), starting);
612 BOOST_FOREACH (ContentTextSubtitle& ts, text) {
613 BOOST_FOREACH (dcp::SubtitleString& s, ts.subs) {
614 s.set_h_position (s.h_position() + subtitle_content->subtitle_x_offset ());
615 s.set_v_position (s.v_position() + subtitle_content->subtitle_y_offset ());
616 float const xs = subtitle_content->subtitle_x_scale();
617 float const ys = subtitle_content->subtitle_y_scale();
618 float const average = s.size() * (xs + ys) / 2;
619 s.set_size (average);
620 if (fabs (1.0 - xs / ys) > dcp::ASPECT_ADJUST_EPSILON) {
621 s.set_aspect_adjust (xs / ys);
623 ps.text.push_back (s);
624 ps.add_fonts (subtitle_content->fonts ());
632 list<shared_ptr<Font> >
633 Player::get_subtitle_fonts ()
635 if (!_have_valid_pieces) {
639 list<shared_ptr<Font> > fonts;
640 BOOST_FOREACH (shared_ptr<Piece>& p, _pieces) {
641 shared_ptr<SubtitleContent> sc = dynamic_pointer_cast<SubtitleContent> (p->content);
643 /* XXX: things may go wrong if there are duplicate font IDs
644 with different font files.
646 list<shared_ptr<Font> > f = sc->fonts ();
647 copy (f.begin(), f.end(), back_inserter (fonts));
654 /** Set this player never to produce any video data */
656 Player::set_ignore_video ()
658 _ignore_video = true;
661 /** Set this player never to produce any audio data */
663 Player::set_ignore_audio ()
665 _ignore_audio = true;
668 /** Set whether or not this player should always burn text subtitles into the image,
669 * regardless of the content settings.
670 * @param burn true to always burn subtitles, false to obey content settings.
673 Player::set_always_burn_subtitles (bool burn)
675 _always_burn_subtitles = burn;