Trying to create export audio encoders with between 9 and 15 channels
[dcpomatic.git] / src / lib / player.cc
index c09bcd9feb4fbae78297303d16e72aada60c85e1..f22ace1b90b1810b79b4759c7945c8d575f91693 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2013-2018 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2013-2020 Carl Hetherington <cth@carlh.net>
 
     This file is part of DCP-o-matic.
 
@@ -85,7 +85,7 @@ int const PlayerProperty::DCP_DECODE_REDUCTION = 704;
 Player::Player (shared_ptr<const Film> film, shared_ptr<const Playlist> playlist)
        : _film (film)
        , _playlist (playlist)
-       , _suspended (false)
+       , _suspended (0)
        , _ignore_video (false)
        , _ignore_audio (false)
        , _ignore_text (false)
@@ -237,19 +237,17 @@ void
 Player::playlist_content_change (ChangeType type, int property, bool frequent)
 {
        if (type == CHANGE_TYPE_PENDING) {
-               boost::mutex::scoped_lock lm (_mutex);
                /* The player content is probably about to change, so we can't carry on
                   until that has happened and we've rebuilt our pieces.  Stop pass()
                   and seek() from working until then.
                */
-               _suspended = true;
+               ++_suspended;
        } else if (type == CHANGE_TYPE_DONE) {
                /* A change in our content has gone through.  Re-build our pieces. */
                setup_pieces ();
-               _suspended = false;
+               --_suspended;
        } else if (type == CHANGE_TYPE_CANCELLED) {
-               boost::mutex::scoped_lock lm (_mutex);
-               _suspended = false;
+               --_suspended;
        }
 
        Change (type, property, frequent);
@@ -517,8 +515,8 @@ Player::get_reel_assets ()
                        int64_t const reel_duration = k->main_picture()->duration();
 
                        /* See doc/design/trim_reels.svg */
-                       Frame const reel_trim_start = min(reel_duration, max(0LL, trim_start - offset_from_start));
-                       Frame const reel_trim_end =   min(reel_duration, max(0LL, reel_duration - (offset_from_end - trim_end)));
+                       Frame const reel_trim_start = min(reel_duration, max(int64_t(0), trim_start - offset_from_start));
+                       Frame const reel_trim_end =   min(reel_duration, max(int64_t(0), reel_duration - (offset_from_end - trim_end)));
 
                        DCPTime const from = i->position() + DCPTime::from_frames (offset_from_start, _film->video_frame_rate());
                        if (j->reference_video ()) {
@@ -613,8 +611,18 @@ Player::pass ()
 
        switch (which) {
        case CONTENT:
+       {
                earliest_content->done = earliest_content->decoder->pass ();
+               shared_ptr<DCPContent> dcp = dynamic_pointer_cast<DCPContent>(earliest_content->content);
+               if (dcp && !_play_referenced && dcp->reference_audio()) {
+                       /* We are skipping some referenced DCP audio content, so we need to update _last_audio_time
+                          to `hide' the fact that no audio was emitted during the referenced DCP (though
+                          we need to behave as though it was).
+                       */
+                       _last_audio_time = dcp->end (_film);
+               }
                break;
+       }
        case BLACK:
                emit_video (black_player_video_frame(EYES_BOTH), _black.position());
                _black.set_position (_black.position() + one_video_frame());
@@ -625,8 +633,16 @@ Player::pass ()
                if (_last_audio_time) {
                        /* Sometimes the thing that happened last finishes fractionally before
                           or after this silence.  Bodge the start time of the silence to fix it.
+                          I think this is nothing to worry about since we will just add or
+                          remove a little silence at the end of some content.
                        */
-                       DCPOMATIC_ASSERT (labs(period.from.get() - _last_audio_time->get()) < 2);
+                       int64_t const error = labs(period.from.get() - _last_audio_time->get());
+                       /* Let's not worry about less than a frame at 24fps */
+                       int64_t const too_much_error = DCPTime::from_frames(1, 24).get();
+                       if (error >= too_much_error) {
+                               _film->log()->log(String::compose("Silence starting before or after last audio by %1", error), LogEntry::TYPE_ERROR);
+                       }
+                       DCPOMATIC_ASSERT (error < too_much_error);
                        period.from = *_last_audio_time;
                }
                if (period.duration() > one_video_frame()) {
@@ -842,10 +858,12 @@ Player::audio (weak_ptr<Piece> wp, AudioStreamPtr stream, ContentAudio content_a
        shared_ptr<AudioContent> content = piece->content->audio;
        DCPOMATIC_ASSERT (content);
 
+       int const rfr = content->resampled_frame_rate (_film);
+
        /* Compute time in the DCP */
        DCPTime time = resampled_audio_to_dcp (piece, content_audio.frame);
        /* And the end of this block in the DCP */
-       DCPTime end = time + DCPTime::from_frames(content_audio.audio->frames(), content->resampled_frame_rate(_film));
+       DCPTime end = time + DCPTime::from_frames(content_audio.audio->frames(), rfr);
 
        /* Remove anything that comes before the start or after the end of the content */
        if (time < piece->content->position()) {
@@ -860,7 +878,7 @@ Player::audio (weak_ptr<Piece> wp, AudioStreamPtr stream, ContentAudio content_a
                /* Discard it all */
                return;
        } else if (end > piece->content->end(_film)) {
-               Frame const remaining_frames = DCPTime(piece->content->end(_film) - time).frames_round(_film->audio_frame_rate());
+               Frame const remaining_frames = DCPTime(piece->content->end(_film) - time).frames_round(rfr);
                if (remaining_frames == 0) {
                        return;
                }
@@ -919,8 +937,15 @@ Player::bitmap_text_start (weak_ptr<Piece> wp, weak_ptr<const TextContent> wc, C
 
        PlayerText ps;
        shared_ptr<Image> image = subtitle.sub.image;
+
        /* We will scale the subtitle up to fit _video_container_size */
-       dcp::Size scaled_size (subtitle.sub.rectangle.width * _video_container_size.width, subtitle.sub.rectangle.height * _video_container_size.height);
+       int const width = subtitle.sub.rectangle.width * _video_container_size.width;
+       int const height = subtitle.sub.rectangle.height * _video_container_size.height;
+       if (width == 0 || height == 0) {
+               return;
+       }
+
+       dcp::Size scaled_size (width, height);
        ps.bitmap.push_back (BitmapText(image->scale(scaled_size, dcp::YUV_TO_RGB_REC601, image->pixel_format(), true, _fast), subtitle.sub.rectangle));
        DCPTime from (content_time_to_dcp (piece, subtitle.from()));