More fixes to when to pull from the audio merger.
[dcpomatic.git] / src / lib / player.cc
1 /*
2     Copyright (C) 2013-2017 Carl Hetherington <cth@carlh.net>
3
4     This file is part of DCP-o-matic.
5
6     DCP-o-matic is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     DCP-o-matic is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
18
19 */
20
21 #include "player.h"
22 #include "film.h"
23 #include "audio_buffers.h"
24 #include "content_audio.h"
25 #include "dcp_content.h"
26 #include "job.h"
27 #include "image.h"
28 #include "raw_image_proxy.h"
29 #include "ratio.h"
30 #include "log.h"
31 #include "render_subtitles.h"
32 #include "config.h"
33 #include "content_video.h"
34 #include "player_video.h"
35 #include "frame_rate_change.h"
36 #include "audio_processor.h"
37 #include "playlist.h"
38 #include "referenced_reel_asset.h"
39 #include "decoder_factory.h"
40 #include "decoder.h"
41 #include "video_decoder.h"
42 #include "audio_decoder.h"
43 #include "subtitle_content.h"
44 #include "subtitle_decoder.h"
45 #include "ffmpeg_content.h"
46 #include "audio_content.h"
47 #include "content_subtitle.h"
48 #include "dcp_decoder.h"
49 #include "image_decoder.h"
50 #include "resampler.h"
51 #include "compose.hpp"
52 #include <dcp/reel.h>
53 #include <dcp/reel_sound_asset.h>
54 #include <dcp/reel_subtitle_asset.h>
55 #include <dcp/reel_picture_asset.h>
56 #include <boost/foreach.hpp>
57 #include <stdint.h>
58 #include <algorithm>
59 #include <iostream>
60
61 #include "i18n.h"
62
63 #define LOG_GENERAL(...) _film->log()->log (String::compose (__VA_ARGS__), LogEntry::TYPE_GENERAL);
64
65 using std::list;
66 using std::cout;
67 using std::min;
68 using std::max;
69 using std::min;
70 using std::vector;
71 using std::pair;
72 using std::map;
73 using std::make_pair;
74 using std::copy;
75 using boost::shared_ptr;
76 using boost::weak_ptr;
77 using boost::dynamic_pointer_cast;
78 using boost::optional;
79 using boost::scoped_ptr;
80
81 Player::Player (shared_ptr<const Film> film, shared_ptr<const Playlist> playlist)
82         : _film (film)
83         , _playlist (playlist)
84         , _have_valid_pieces (false)
85         , _ignore_video (false)
86         , _ignore_audio (false)
87         , _always_burn_subtitles (false)
88         , _fast (false)
89         , _play_referenced (false)
90         , _audio_merger (_film->audio_channels(), _film->audio_frame_rate())
91 {
92         _film_changed_connection = _film->Changed.connect (bind (&Player::film_changed, this, _1));
93         _playlist_changed_connection = _playlist->Changed.connect (bind (&Player::playlist_changed, this));
94         _playlist_content_changed_connection = _playlist->ContentChanged.connect (bind (&Player::playlist_content_changed, this, _1, _2, _3));
95         set_video_container_size (_film->frame_size ());
96
97         film_changed (Film::AUDIO_PROCESSOR);
98 }
99
100 void
101 Player::setup_pieces ()
102 {
103         _pieces.clear ();
104
105         BOOST_FOREACH (shared_ptr<Content> i, _playlist->content ()) {
106
107                 if (!i->paths_valid ()) {
108                         continue;
109                 }
110
111                 shared_ptr<Decoder> decoder = decoder_factory (i, _film->log());
112                 FrameRateChange frc (i->active_video_frame_rate(), _film->video_frame_rate());
113
114                 if (!decoder) {
115                         /* Not something that we can decode; e.g. Atmos content */
116                         continue;
117                 }
118
119                 if (decoder->video && _ignore_video) {
120                         decoder->video->set_ignore ();
121                 }
122
123                 if (decoder->audio && _ignore_audio) {
124                         decoder->audio->set_ignore ();
125                 }
126
127                 shared_ptr<DCPDecoder> dcp = dynamic_pointer_cast<DCPDecoder> (decoder);
128                 if (dcp && _play_referenced) {
129                         dcp->set_decode_referenced ();
130                 }
131
132                 shared_ptr<Piece> piece (new Piece (i, decoder, frc));
133                 _pieces.push_back (piece);
134
135                 if (decoder->video) {
136                         decoder->video->Data.connect (bind (&Player::video, this, weak_ptr<Piece> (piece), _1));
137                 }
138
139                 if (decoder->audio) {
140                         decoder->audio->Data.connect (bind (&Player::audio, this, weak_ptr<Piece> (piece), _1, _2));
141                 }
142
143                 if (decoder->subtitle) {
144                         decoder->subtitle->ImageData.connect (bind (&Player::image_subtitle, this, weak_ptr<Piece> (piece), _1));
145                         decoder->subtitle->TextData.connect (bind (&Player::text_subtitle, this, weak_ptr<Piece> (piece), _1));
146                 }
147         }
148
149         BOOST_FOREACH (shared_ptr<Piece> i, _pieces) {
150                 if (i->content->audio) {
151                         BOOST_FOREACH (AudioStreamPtr j, i->content->audio->streams()) {
152                                 _stream_states[j] = StreamState (i, i->content->position ());
153                         }
154                 }
155         }
156
157         _have_valid_pieces = true;
158 }
159
160 void
161 Player::playlist_content_changed (weak_ptr<Content> w, int property, bool frequent)
162 {
163         shared_ptr<Content> c = w.lock ();
164         if (!c) {
165                 return;
166         }
167
168         if (
169                 property == ContentProperty::POSITION ||
170                 property == ContentProperty::LENGTH ||
171                 property == ContentProperty::TRIM_START ||
172                 property == ContentProperty::TRIM_END ||
173                 property == ContentProperty::PATH ||
174                 property == VideoContentProperty::FRAME_TYPE ||
175                 property == DCPContentProperty::NEEDS_ASSETS ||
176                 property == DCPContentProperty::NEEDS_KDM ||
177                 property == SubtitleContentProperty::COLOUR ||
178                 property == SubtitleContentProperty::OUTLINE ||
179                 property == SubtitleContentProperty::SHADOW ||
180                 property == SubtitleContentProperty::EFFECT_COLOUR ||
181                 property == FFmpegContentProperty::SUBTITLE_STREAM ||
182                 property == VideoContentProperty::COLOUR_CONVERSION
183                 ) {
184
185                 _have_valid_pieces = false;
186                 Changed (frequent);
187
188         } else if (
189                 property == SubtitleContentProperty::LINE_SPACING ||
190                 property == SubtitleContentProperty::OUTLINE_WIDTH ||
191                 property == SubtitleContentProperty::Y_SCALE ||
192                 property == SubtitleContentProperty::FADE_IN ||
193                 property == SubtitleContentProperty::FADE_OUT ||
194                 property == ContentProperty::VIDEO_FRAME_RATE ||
195                 property == SubtitleContentProperty::USE ||
196                 property == SubtitleContentProperty::X_OFFSET ||
197                 property == SubtitleContentProperty::Y_OFFSET ||
198                 property == SubtitleContentProperty::X_SCALE ||
199                 property == SubtitleContentProperty::FONTS ||
200                 property == VideoContentProperty::CROP ||
201                 property == VideoContentProperty::SCALE ||
202                 property == VideoContentProperty::FADE_IN ||
203                 property == VideoContentProperty::FADE_OUT
204                 ) {
205
206                 Changed (frequent);
207         }
208 }
209
210 void
211 Player::set_video_container_size (dcp::Size s)
212 {
213         _video_container_size = s;
214
215         _black_image.reset (new Image (AV_PIX_FMT_RGB24, _video_container_size, true));
216         _black_image->make_black ();
217 }
218
219 void
220 Player::playlist_changed ()
221 {
222         _have_valid_pieces = false;
223         Changed (false);
224 }
225
226 void
227 Player::film_changed (Film::Property p)
228 {
229         /* Here we should notice Film properties that affect our output, and
230            alert listeners that our output now would be different to how it was
231            last time we were run.
232         */
233
234         if (p == Film::CONTAINER) {
235                 Changed (false);
236         } else if (p == Film::VIDEO_FRAME_RATE) {
237                 /* Pieces contain a FrameRateChange which contains the DCP frame rate,
238                    so we need new pieces here.
239                 */
240                 _have_valid_pieces = false;
241                 Changed (false);
242         } else if (p == Film::AUDIO_PROCESSOR) {
243                 if (_film->audio_processor ()) {
244                         _audio_processor = _film->audio_processor()->clone (_film->audio_frame_rate ());
245                 }
246         }
247 }
248
249 list<PositionImage>
250 Player::transform_image_subtitles (list<ImageSubtitle> subs) const
251 {
252         list<PositionImage> all;
253
254         for (list<ImageSubtitle>::const_iterator i = subs.begin(); i != subs.end(); ++i) {
255                 if (!i->image) {
256                         continue;
257                 }
258
259                 /* We will scale the subtitle up to fit _video_container_size */
260                 dcp::Size scaled_size (i->rectangle.width * _video_container_size.width, i->rectangle.height * _video_container_size.height);
261
262                 /* Then we need a corrective translation, consisting of two parts:
263                  *
264                  * 1.  that which is the result of the scaling of the subtitle by _video_container_size; this will be
265                  *     rect.x * _video_container_size.width and rect.y * _video_container_size.height.
266                  *
267                  * 2.  that to shift the origin of the scale by subtitle_scale to the centre of the subtitle; this will be
268                  *     (width_before_subtitle_scale * (1 - subtitle_x_scale) / 2) and
269                  *     (height_before_subtitle_scale * (1 - subtitle_y_scale) / 2).
270                  *
271                  * Combining these two translations gives these expressions.
272                  */
273
274                 all.push_back (
275                         PositionImage (
276                                 i->image->scale (
277                                         scaled_size,
278                                         dcp::YUV_TO_RGB_REC601,
279                                         i->image->pixel_format (),
280                                         true,
281                                         _fast
282                                         ),
283                                 Position<int> (
284                                         lrint (_video_container_size.width * i->rectangle.x),
285                                         lrint (_video_container_size.height * i->rectangle.y)
286                                         )
287                                 )
288                         );
289         }
290
291         return all;
292 }
293
294 shared_ptr<PlayerVideo>
295 Player::black_player_video_frame () const
296 {
297         return shared_ptr<PlayerVideo> (
298                 new PlayerVideo (
299                         shared_ptr<const ImageProxy> (new RawImageProxy (_black_image)),
300                         Crop (),
301                         optional<double> (),
302                         _video_container_size,
303                         _video_container_size,
304                         EYES_BOTH,
305                         PART_WHOLE,
306                         PresetColourConversion::all().front().conversion
307                 )
308         );
309 }
310
311 Frame
312 Player::dcp_to_content_video (shared_ptr<const Piece> piece, DCPTime t) const
313 {
314         DCPTime s = t - piece->content->position ();
315         s = min (piece->content->length_after_trim(), s);
316         s = max (DCPTime(), s + DCPTime (piece->content->trim_start(), piece->frc));
317
318         /* It might seem more logical here to convert s to a ContentTime (using the FrameRateChange)
319            then convert that ContentTime to frames at the content's rate.  However this fails for
320            situations like content at 29.9978733fps, DCP at 30fps.  The accuracy of the Time type is not
321            enough to distinguish between the two with low values of time (e.g. 3200 in Time units).
322
323            Instead we convert the DCPTime using the DCP video rate then account for any skip/repeat.
324         */
325         return s.frames_floor (piece->frc.dcp) / piece->frc.factor ();
326 }
327
328 DCPTime
329 Player::content_video_to_dcp (shared_ptr<const Piece> piece, Frame f) const
330 {
331         /* See comment in dcp_to_content_video */
332         DCPTime const d = DCPTime::from_frames (f * piece->frc.factor(), piece->frc.dcp) - DCPTime (piece->content->trim_start (), piece->frc);
333         return max (DCPTime (), d + piece->content->position ());
334 }
335
336 Frame
337 Player::dcp_to_resampled_audio (shared_ptr<const Piece> piece, DCPTime t) const
338 {
339         DCPTime s = t - piece->content->position ();
340         s = min (piece->content->length_after_trim(), s);
341         /* See notes in dcp_to_content_video */
342         return max (DCPTime (), DCPTime (piece->content->trim_start (), piece->frc) + s).frames_floor (_film->audio_frame_rate ());
343 }
344
345 DCPTime
346 Player::resampled_audio_to_dcp (shared_ptr<const Piece> piece, Frame f) const
347 {
348         /* See comment in dcp_to_content_video */
349         DCPTime const d = DCPTime::from_frames (f, _film->audio_frame_rate()) - DCPTime (piece->content->trim_start (), piece->frc);
350         return max (DCPTime (), d + piece->content->position ());
351 }
352
353 ContentTime
354 Player::dcp_to_content_time (shared_ptr<const Piece> piece, DCPTime t) const
355 {
356         DCPTime s = t - piece->content->position ();
357         s = min (piece->content->length_after_trim(), s);
358         return max (ContentTime (), ContentTime (s, piece->frc) + piece->content->trim_start());
359 }
360
361 DCPTime
362 Player::content_time_to_dcp (shared_ptr<const Piece> piece, ContentTime t) const
363 {
364         return max (DCPTime (), DCPTime (t - piece->content->trim_start(), piece->frc) + piece->content->position());
365 }
366
367 list<shared_ptr<Font> >
368 Player::get_subtitle_fonts ()
369 {
370         if (!_have_valid_pieces) {
371                 setup_pieces ();
372         }
373
374         list<shared_ptr<Font> > fonts;
375         BOOST_FOREACH (shared_ptr<Piece>& p, _pieces) {
376                 if (p->content->subtitle) {
377                         /* XXX: things may go wrong if there are duplicate font IDs
378                            with different font files.
379                         */
380                         list<shared_ptr<Font> > f = p->content->subtitle->fonts ();
381                         copy (f.begin(), f.end(), back_inserter (fonts));
382                 }
383         }
384
385         return fonts;
386 }
387
388 /** Set this player never to produce any video data */
389 void
390 Player::set_ignore_video ()
391 {
392         _ignore_video = true;
393 }
394
395 /** Set this player never to produce any audio data */
396 void
397 Player::set_ignore_audio ()
398 {
399         _ignore_audio = true;
400 }
401
402 /** Set whether or not this player should always burn text subtitles into the image,
403  *  regardless of the content settings.
404  *  @param burn true to always burn subtitles, false to obey content settings.
405  */
406 void
407 Player::set_always_burn_subtitles (bool burn)
408 {
409         _always_burn_subtitles = burn;
410 }
411
412 void
413 Player::set_fast ()
414 {
415         _fast = true;
416         _have_valid_pieces = false;
417 }
418
419 void
420 Player::set_play_referenced ()
421 {
422         _play_referenced = true;
423         _have_valid_pieces = false;
424 }
425
426 list<ReferencedReelAsset>
427 Player::get_reel_assets ()
428 {
429         list<ReferencedReelAsset> a;
430
431         BOOST_FOREACH (shared_ptr<Content> i, _playlist->content ()) {
432                 shared_ptr<DCPContent> j = dynamic_pointer_cast<DCPContent> (i);
433                 if (!j) {
434                         continue;
435                 }
436
437                 scoped_ptr<DCPDecoder> decoder;
438                 try {
439                         decoder.reset (new DCPDecoder (j, _film->log()));
440                 } catch (...) {
441                         return a;
442                 }
443
444                 int64_t offset = 0;
445                 BOOST_FOREACH (shared_ptr<dcp::Reel> k, decoder->reels()) {
446
447                         DCPOMATIC_ASSERT (j->video_frame_rate ());
448                         double const cfr = j->video_frame_rate().get();
449                         Frame const trim_start = j->trim_start().frames_round (cfr);
450                         Frame const trim_end = j->trim_end().frames_round (cfr);
451                         int const ffr = _film->video_frame_rate ();
452
453                         DCPTime const from = i->position() + DCPTime::from_frames (offset, _film->video_frame_rate());
454                         if (j->reference_video ()) {
455                                 shared_ptr<dcp::ReelAsset> ra = k->main_picture ();
456                                 DCPOMATIC_ASSERT (ra);
457                                 ra->set_entry_point (ra->entry_point() + trim_start);
458                                 ra->set_duration (ra->duration() - trim_start - trim_end);
459                                 a.push_back (
460                                         ReferencedReelAsset (ra, DCPTimePeriod (from, from + DCPTime::from_frames (ra->duration(), ffr)))
461                                         );
462                         }
463
464                         if (j->reference_audio ()) {
465                                 shared_ptr<dcp::ReelAsset> ra = k->main_sound ();
466                                 DCPOMATIC_ASSERT (ra);
467                                 ra->set_entry_point (ra->entry_point() + trim_start);
468                                 ra->set_duration (ra->duration() - trim_start - trim_end);
469                                 a.push_back (
470                                         ReferencedReelAsset (ra, DCPTimePeriod (from, from + DCPTime::from_frames (ra->duration(), ffr)))
471                                         );
472                         }
473
474                         if (j->reference_subtitle ()) {
475                                 shared_ptr<dcp::ReelAsset> ra = k->main_subtitle ();
476                                 DCPOMATIC_ASSERT (ra);
477                                 ra->set_entry_point (ra->entry_point() + trim_start);
478                                 ra->set_duration (ra->duration() - trim_start - trim_end);
479                                 a.push_back (
480                                         ReferencedReelAsset (ra, DCPTimePeriod (from, from + DCPTime::from_frames (ra->duration(), ffr)))
481                                         );
482                         }
483
484                         /* Assume that main picture duration is the length of the reel */
485                         offset += k->main_picture()->duration ();
486                 }
487         }
488
489         return a;
490 }
491
492 list<shared_ptr<Piece> >
493 Player::overlaps (DCPTime from, DCPTime to, boost::function<bool (Content *)> valid)
494 {
495         if (!_have_valid_pieces) {
496                 setup_pieces ();
497         }
498
499         list<shared_ptr<Piece> > overlaps;
500         BOOST_FOREACH (shared_ptr<Piece> i, _pieces) {
501                 if (valid (i->content.get ()) && i->content->position() < to && i->content->end() > from) {
502                         overlaps.push_back (i);
503                 }
504         }
505
506         return overlaps;
507 }
508
509 bool
510 Player::pass ()
511 {
512         if (!_have_valid_pieces) {
513                 setup_pieces ();
514         }
515
516         shared_ptr<Piece> earliest;
517         DCPTime earliest_content;
518
519         BOOST_FOREACH (shared_ptr<Piece> i, _pieces) {
520                 if (!i->done) {
521                         DCPTime const t = i->content->position() + DCPTime (i->decoder->position(), i->frc);
522                         if (!earliest || t < earliest_content) {
523                                 earliest_content = t;
524                                 earliest = i;
525                         }
526                 }
527         }
528
529         if (!earliest) {
530                 /* No more content; fill up to the length of our playlist with silent black */
531
532                 DCPTime const length = _playlist->length ();
533
534                 DCPTime const frame = DCPTime::from_frames (1, _film->video_frame_rate());
535                 DCPTime from;
536                 if (_last_time) {
537                         from = _last_time.get() + frame;
538                 }
539                 for (DCPTime i = from; i < length; i += frame) {
540                         Video (black_player_video_frame (), i);
541                 }
542
543                 DCPTime t = _last_audio_time;
544                 while (t < length) {
545                         DCPTime block = min (DCPTime::from_seconds (0.5), length - t);
546                         shared_ptr<AudioBuffers> silence (new AudioBuffers (_film->audio_channels(), block.frames_round(_film->audio_frame_rate())));
547                         silence->make_silent ();
548                         Audio (silence, t);
549                         t += block;
550                 }
551
552                 return true;
553         }
554
555         earliest->done = earliest->decoder->pass ();
556
557         /* Emit any audio that is ready */
558
559         DCPTime pull_from = _playlist->length ();
560         for (map<AudioStreamPtr, StreamState>::const_iterator i = _stream_states.begin(); i != _stream_states.end(); ++i) {
561                 if (!i->second.piece->done && i->second.last_push_end < pull_from) {
562                         pull_from = i->second.last_push_end;
563                 }
564         }
565
566 //      cout << "PULL " << to_string(pull_from) << "\n";
567         pair<shared_ptr<AudioBuffers>, DCPTime> audio = _audio_merger.pull (pull_from);
568         if (audio.first->frames() > 0) {
569                 DCPOMATIC_ASSERT (audio.second >= _last_audio_time);
570                 DCPTime t = _last_audio_time;
571                 while (t < audio.second) {
572                         /* Silence up to the time of this new audio */
573                         DCPTime block = min (DCPTime::from_seconds (0.5), audio.second - t);
574                         shared_ptr<AudioBuffers> silence (new AudioBuffers (_film->audio_channels(), block.frames_round(_film->audio_frame_rate())));
575                         silence->make_silent ();
576                         Audio (silence, t);
577                         t += block;
578                 }
579
580                 Audio (audio.first, audio.second);
581                 _last_audio_time = audio.second + DCPTime::from_frames(audio.first->frames(), _film->audio_frame_rate());
582         }
583
584         return false;
585 }
586
587 void
588 Player::video (weak_ptr<Piece> wp, ContentVideo video)
589 {
590         shared_ptr<Piece> piece = wp.lock ();
591         if (!piece) {
592                 return;
593         }
594
595         /* Time and period of the frame we will emit */
596         DCPTime const time = content_video_to_dcp (piece, video.frame);
597         DCPTimePeriod const period (time, time + DCPTime::from_frames (1, _film->video_frame_rate()));
598
599         /* Discard if it's outside the content's period */
600         if (time < piece->content->position() || time >= piece->content->end()) {
601                 return;
602         }
603
604         /* Get any subtitles */
605
606         optional<PositionImage> subtitles;
607
608         for (list<pair<PlayerSubtitles, DCPTimePeriod> >::const_iterator i = _subtitles.begin(); i != _subtitles.end(); ++i) {
609
610                 if (!i->second.overlap (period)) {
611                         continue;
612                 }
613
614                 list<PositionImage> sub_images;
615
616                 /* Image subtitles */
617                 list<PositionImage> c = transform_image_subtitles (i->first.image);
618                 copy (c.begin(), c.end(), back_inserter (sub_images));
619
620                 /* Text subtitles (rendered to an image) */
621                 if (!i->first.text.empty ()) {
622                         list<PositionImage> s = render_subtitles (i->first.text, i->first.fonts, _video_container_size, time);
623                         copy (s.begin (), s.end (), back_inserter (sub_images));
624                 }
625
626                 if (!sub_images.empty ()) {
627                         subtitles = merge (sub_images);
628                 }
629         }
630
631         /* Fill gaps */
632
633         if (_last_time) {
634                 /* XXX: this may not work for 3D */
635                 DCPTime const frame = DCPTime::from_frames (1, _film->video_frame_rate());
636                 for (DCPTime i = _last_time.get() + frame; i < time; i += frame) {
637                         if (_playlist->video_content_at(i) && _last_video) {
638                                 Video (shared_ptr<PlayerVideo> (new PlayerVideo (*_last_video)), i);
639                         } else {
640                                 Video (black_player_video_frame (), i);
641                         }
642                 }
643         }
644
645         _last_video.reset (
646                 new PlayerVideo (
647                         video.image,
648                         piece->content->video->crop (),
649                         piece->content->video->fade (video.frame),
650                         piece->content->video->scale().size (
651                                 piece->content->video, _video_container_size, _film->frame_size ()
652                                 ),
653                         _video_container_size,
654                         video.eyes,
655                         video.part,
656                         piece->content->video->colour_conversion ()
657                         )
658                 );
659
660         if (subtitles) {
661                 _last_video->set_subtitle (subtitles.get ());
662         }
663
664         _last_time = time;
665
666         Video (_last_video, *_last_time);
667
668         /* Discard any subtitles we no longer need */
669
670         for (list<pair<PlayerSubtitles, DCPTimePeriod> >::iterator i = _subtitles.begin (); i != _subtitles.end(); ) {
671                 list<pair<PlayerSubtitles, DCPTimePeriod> >::iterator tmp = i;
672                 ++tmp;
673
674                 if (i->second.to < time) {
675                         _subtitles.erase (i);
676                 }
677
678                 i = tmp;
679         }
680 }
681
682 void
683 Player::audio (weak_ptr<Piece> wp, AudioStreamPtr stream, ContentAudio content_audio)
684 {
685         shared_ptr<Piece> piece = wp.lock ();
686         if (!piece) {
687                 return;
688         }
689
690         shared_ptr<AudioContent> content = piece->content->audio;
691         DCPOMATIC_ASSERT (content);
692
693         /* Gain */
694         if (content->gain() != 0) {
695                 shared_ptr<AudioBuffers> gain (new AudioBuffers (content_audio.audio));
696                 gain->apply_gain (content->gain ());
697                 content_audio.audio = gain;
698         }
699
700         /* Resample */
701         if (stream->frame_rate() != content->resampled_frame_rate()) {
702                 shared_ptr<Resampler> r = resampler (content, stream, true);
703                 pair<shared_ptr<const AudioBuffers>, Frame> ro = r->run (content_audio.audio, content_audio.frame);
704                 content_audio.audio = ro.first;
705                 content_audio.frame = ro.second;
706         }
707
708         /* XXX: end-trimming used to be checked here */
709
710         /* Compute time in the DCP */
711         DCPTime time = resampled_audio_to_dcp (piece, content_audio.frame) + DCPTime::from_seconds (content->delay() / 1000.0);
712
713         /* Remove anything that comes before the start of the content */
714         if (time < piece->content->position()) {
715                 DCPTime const discard_time = piece->content->position() - time;
716                 Frame discard_frames = discard_time.frames_round(_film->audio_frame_rate());
717                 Frame remaining_frames = content_audio.audio->frames() - discard_frames;
718                 if (remaining_frames <= 0) {
719                         /* This audio is entirely discarded */
720                         return;
721                 }
722                 shared_ptr<AudioBuffers> cut (new AudioBuffers (content_audio.audio->channels(), remaining_frames));
723                 cut->copy_from (content_audio.audio.get(), remaining_frames, discard_frames, 0);
724                 content_audio.audio = cut;
725                 time += discard_time;
726         }
727
728         /* Remap channels */
729         shared_ptr<AudioBuffers> dcp_mapped (new AudioBuffers (_film->audio_channels(), content_audio.audio->frames()));
730         dcp_mapped->make_silent ();
731
732         AudioMapping map = stream->mapping ();
733         for (int i = 0; i < map.input_channels(); ++i) {
734                 for (int j = 0; j < dcp_mapped->channels(); ++j) {
735                         if (map.get (i, static_cast<dcp::Channel> (j)) > 0) {
736                                 dcp_mapped->accumulate_channel (
737                                         content_audio.audio.get(),
738                                         i,
739                                         static_cast<dcp::Channel> (j),
740                                         map.get (i, static_cast<dcp::Channel> (j))
741                                         );
742                         }
743                 }
744         }
745
746         content_audio.audio = dcp_mapped;
747
748         if (_audio_processor) {
749                 content_audio.audio = _audio_processor->run (content_audio.audio, _film->audio_channels ());
750         }
751
752 //      cout << "PUSH " << content_audio.audio->frames() << " @ " << to_string(time) << "\n";
753         _audio_merger.push (content_audio.audio, time);
754
755         DCPOMATIC_ASSERT (_stream_states.find (stream) != _stream_states.end ());
756         _stream_states[stream].last_push_end = time + DCPTime::from_frames (content_audio.audio->frames(), _film->audio_frame_rate());
757 }
758
759 void
760 Player::image_subtitle (weak_ptr<Piece> wp, ContentImageSubtitle subtitle)
761 {
762         shared_ptr<Piece> piece = wp.lock ();
763         if (!piece) {
764                 return;
765         }
766
767         /* Apply content's subtitle offsets */
768         subtitle.sub.rectangle.x += piece->content->subtitle->x_offset ();
769         subtitle.sub.rectangle.y += piece->content->subtitle->y_offset ();
770
771         /* Apply content's subtitle scale */
772         subtitle.sub.rectangle.width *= piece->content->subtitle->x_scale ();
773         subtitle.sub.rectangle.height *= piece->content->subtitle->y_scale ();
774
775         /* Apply a corrective translation to keep the subtitle centred after that scale */
776         subtitle.sub.rectangle.x -= subtitle.sub.rectangle.width * (piece->content->subtitle->x_scale() - 1);
777         subtitle.sub.rectangle.y -= subtitle.sub.rectangle.height * (piece->content->subtitle->y_scale() - 1);
778
779         PlayerSubtitles ps;
780         ps.image.push_back (subtitle.sub);
781         DCPTimePeriod period (content_time_to_dcp (piece, subtitle.period().from), content_time_to_dcp (piece, subtitle.period().to));
782
783         if (piece->content->subtitle->use() && (piece->content->subtitle->burn() || _always_burn_subtitles)) {
784                 _subtitles.push_back (make_pair (ps, period));
785         } else {
786                 Subtitle (ps, period);
787         }
788 }
789
790 void
791 Player::text_subtitle (weak_ptr<Piece> wp, ContentTextSubtitle subtitle)
792 {
793         shared_ptr<Piece> piece = wp.lock ();
794         if (!piece) {
795                 return;
796         }
797
798         PlayerSubtitles ps;
799         DCPTimePeriod const period (content_time_to_dcp (piece, subtitle.period().from), content_time_to_dcp (piece, subtitle.period().to));
800
801         BOOST_FOREACH (dcp::SubtitleString s, subtitle.subs) {
802                 s.set_h_position (s.h_position() + piece->content->subtitle->x_offset ());
803                 s.set_v_position (s.v_position() + piece->content->subtitle->y_offset ());
804                 float const xs = piece->content->subtitle->x_scale();
805                 float const ys = piece->content->subtitle->y_scale();
806                 float size = s.size();
807
808                 /* Adjust size to express the common part of the scaling;
809                    e.g. if xs = ys = 0.5 we scale size by 2.
810                 */
811                 if (xs > 1e-5 && ys > 1e-5) {
812                         size *= 1 / min (1 / xs, 1 / ys);
813                 }
814                 s.set_size (size);
815
816                 /* Then express aspect ratio changes */
817                 if (fabs (1.0 - xs / ys) > dcp::ASPECT_ADJUST_EPSILON) {
818                         s.set_aspect_adjust (xs / ys);
819                 }
820
821                 s.set_in (dcp::Time(period.from.seconds(), 1000));
822                 s.set_out (dcp::Time(period.to.seconds(), 1000));
823                 ps.text.push_back (SubtitleString (s, piece->content->subtitle->outline_width()));
824                 ps.add_fonts (piece->content->subtitle->fonts ());
825         }
826
827         if (piece->content->subtitle->use() && (piece->content->subtitle->burn() || _always_burn_subtitles)) {
828                 _subtitles.push_back (make_pair (ps, period));
829         } else {
830                 Subtitle (ps, period);
831         }
832 }
833
834 void
835 Player::seek (DCPTime time, bool accurate)
836 {
837         BOOST_FOREACH (shared_ptr<Piece> i, _pieces) {
838                 if (i->content->position() <= time && time < i->content->end()) {
839                         i->decoder->seek (dcp_to_content_time (i, time), accurate);
840                         i->done = false;
841                 }
842         }
843
844         if (accurate) {
845                 _last_time = time - DCPTime::from_frames (1, _film->video_frame_rate ());
846         } else {
847                 _last_time = optional<DCPTime> ();
848         }
849 }
850
851 shared_ptr<Resampler>
852 Player::resampler (shared_ptr<const AudioContent> content, AudioStreamPtr stream, bool create)
853 {
854         ResamplerMap::const_iterator i = _resamplers.find (make_pair (content, stream));
855         if (i != _resamplers.end ()) {
856                 return i->second;
857         }
858
859         if (!create) {
860                 return shared_ptr<Resampler> ();
861         }
862
863         LOG_GENERAL (
864                 "Creating new resampler from %1 to %2 with %3 channels",
865                 stream->frame_rate(),
866                 content->resampled_frame_rate(),
867                 stream->channels()
868                 );
869
870         shared_ptr<Resampler> r (
871                 new Resampler (stream->frame_rate(), content->resampled_frame_rate(), stream->channels())
872                 );
873
874         _resamplers[make_pair(content, stream)] = r;
875         return r;
876 }