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