2 Copyright (C) 2013-2021 Carl Hetherington <cth@carlh.net>
4 This file is part of DCP-o-matic.
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.
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.
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/>.
22 #include "audio_content.h"
24 #include "dcp_content.h"
25 #include "dcpomatic_log.h"
29 #include "player_video.h"
30 #include "video_content.h"
33 using std::dynamic_pointer_cast;
34 using std::make_shared;
35 using std::shared_ptr;
37 using boost::optional;
38 using namespace dcpomatic;
41 Piece::Piece (shared_ptr<Content> c, shared_ptr<Decoder> d, FrameRateChange f)
46 if (_content->audio) {
47 for (auto j: _content->audio->streams()) {
48 _stream_last_push_end[j] = _content->position();
56 Piece::update_pull_to (DCPTime& pull_to) const
62 for (auto const& i: _stream_last_push_end) {
63 pull_to = std::min(pull_to, i.second);
69 Piece::set_last_push_end (AudioStreamPtr stream, DCPTime end)
71 DCPOMATIC_ASSERT (_stream_last_push_end.find(stream) != _stream_last_push_end.end());
72 _stream_last_push_end[stream] = end;
77 Piece::content_video_to_dcp (Frame f) const
79 /* See comment in resampled_audio_to_dcp */
80 auto const d = DCPTime::from_frames(f * _frc.factor(), _frc.dcp) - DCPTime(_content->trim_start(), _frc);
81 return d + _content->position();
86 Piece::resampled_audio_to_dcp (Frame f, shared_ptr<const Film> film) const
88 /* It might seem more logical here to convert s to a ContentTime (using the FrameRateChange)
89 then convert that ContentTime to frames at the content's rate. However this fails for
90 situations like content at 29.9978733fps, DCP at 30fps. The accuracy of the Time type is not
91 enough to distinguish between the two with low values of time (e.g. 3200 in Time units).
93 Instead we convert the DCPTime using the DCP video rate then account for any skip/repeat.
95 return DCPTime::from_frames(f, film->audio_frame_rate())
96 - DCPTime(_content->trim_start(), _frc)
97 + _content->position();
102 Piece::dcp_to_content_time (DCPTime t, shared_ptr<const Film> film) const
104 auto s = t - _content->position ();
105 s = min (_content->length_after_trim(film), s);
106 return max (ContentTime(), ContentTime(s, _frc) + _content->trim_start());
111 Piece::content_time_to_dcp (shared_ptr<const Content> content, ContentTime t) const
113 if (_content != content) {
117 return max (DCPTime(), DCPTime(t - _content->trim_start(), _frc) + _content->position());
122 Piece::use_video () const
124 return _content->video && _content->video->use();
129 Piece::video_frame_type () const
131 DCPOMATIC_ASSERT (_content->video);
132 return _content->video->frame_type ();
137 Piece::position () const
139 return _content->position ();
144 Piece::end (shared_ptr<const Film> film) const
146 return _content->end (film);
150 shared_ptr<PlayerVideo>
151 Piece::player_video (ContentVideo video, shared_ptr<const Film> film, dcp::Size container_size) const
153 return std::make_shared<PlayerVideo>(
155 _content->video->crop (),
156 _content->video->fade (film, video.frame),
157 scale_for_display(_content->video->scaled_size(film->frame_size()), container_size, film->frame_size()),
161 _content->video->colour_conversion(),
162 _content->video->range(),
171 Piece::resampled_audio_frame_rate (shared_ptr<const Film> film) const
173 DCPOMATIC_ASSERT (_content->audio);
174 return _content->audio->resampled_frame_rate (film);
179 Piece::audio_gain () const
181 DCPOMATIC_ASSERT (_content->audio);
182 return _content->audio->gain();
187 Piece::decoder_for (shared_ptr<Content> content) const
189 if (content == _content) {
200 LOG_DEBUG_PLAYER ("Calling pass() on %1", _content->path(0));
201 _done = _decoder->pass();
206 Piece::reference_dcp_audio () const
208 auto dcp = dynamic_pointer_cast<DCPContent>(_content);
209 return dcp && dcp->reference_audio();
214 Piece::seek (shared_ptr<const Film> film, DCPTime time, bool accurate)
216 if (time < position()) {
217 /* Before; seek to the start of the content. Even if this request is for an inaccurate seek
218 we must seek this (following) content accurately, otherwise when we come to the end of the current
219 content we may not start right at the beginning of the next, causing a gap (if the next content has
220 been trimmed to a point between keyframes, or something).
222 _decoder->seek (dcp_to_content_time(position(), film), true);
224 } else if (position() <= time && time < end(film)) {
225 /* During; seek to position */
226 _decoder->seek (dcp_to_content_time(time, film), accurate);
229 /* After; this piece is done */
235 optional<dcpomatic::DCPTime>
236 Piece::decoder_before(shared_ptr<const Film> film, optional<dcpomatic::DCPTime> time)
242 auto t = content_time_to_dcp(_content, std::max(_decoder->position(), _content->trim_start()));
243 DCPOMATIC_ASSERT (t);
245 if (*t > end(film)) {
248 /* Given two choices at the same time, pick the one with texts so we see it before
251 if (!time || t < *time || (t == *time && !_decoder->text.empty())) {
259 vector<dcpomatic::FontData>
260 Piece::fonts () const
262 return _decoder->fonts();
267 Piece::ignore_video_at (DCPTime time) const
269 return _ignore_video && _ignore_video->contains(time);