Make Piece::ignore_video private.
[dcpomatic.git] / src / lib / piece.cc
1 /*
2     Copyright (C) 2013-2021 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
22 #include "audio_content.h"
23 #include "content.h"
24 #include "dcp_content.h"
25 #include "dcpomatic_log.h"
26 #include "decoder.h"
27 #include "film.h"
28 #include "piece.h"
29 #include "player_video.h"
30 #include "video_content.h"
31
32
33 using std::dynamic_pointer_cast;
34 using std::make_shared;
35 using std::shared_ptr;
36 using std::vector;
37 using boost::optional;
38 using namespace dcpomatic;
39
40
41 Piece::Piece (shared_ptr<Content> c, shared_ptr<Decoder> d, FrameRateChange f)
42         : _content (c)
43         , _decoder (d)
44         , _frc (f)
45 {
46         if (_content->audio) {
47                 for (auto j: _content->audio->streams()) {
48                         _stream_last_push_end[j] = _content->position();
49                 }
50         }
51 }
52
53
54
55 void
56 Piece::update_pull_to (DCPTime& pull_to) const
57 {
58         if (_done) {
59                 return;
60         }
61
62         for (auto const& i: _stream_last_push_end) {
63                 pull_to = std::min(pull_to, i.second);
64         }
65 }
66
67
68 void
69 Piece::set_last_push_end (AudioStreamPtr stream, DCPTime end)
70 {
71         DCPOMATIC_ASSERT (_stream_last_push_end.find(stream) != _stream_last_push_end.end());
72         _stream_last_push_end[stream] = end;
73 }
74
75
76 DCPTime
77 Piece::content_video_to_dcp (Frame f) const
78 {
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();
82 }
83
84
85 DCPTime
86 Piece::resampled_audio_to_dcp (Frame f, shared_ptr<const Film> film) const
87 {
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).
92
93            Instead we convert the DCPTime using the DCP video rate then account for any skip/repeat.
94         */
95         return DCPTime::from_frames(f, film->audio_frame_rate())
96                 - DCPTime(_content->trim_start(), _frc)
97                 + _content->position();
98 }
99
100
101 ContentTime
102 Piece::dcp_to_content_time (DCPTime t, shared_ptr<const Film> film) const
103 {
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());
107 }
108
109
110 optional<DCPTime>
111 Piece::content_time_to_dcp (shared_ptr<const Content> content, ContentTime t) const
112 {
113         if (_content != content) {
114                 return {};
115         }
116
117         return max (DCPTime(), DCPTime(t - _content->trim_start(), _frc) + _content->position());
118 }
119
120
121 bool
122 Piece::use_video () const
123 {
124         return _content->video && _content->video->use();
125 }
126
127
128 VideoFrameType
129 Piece::video_frame_type () const
130 {
131         DCPOMATIC_ASSERT (_content->video);
132         return _content->video->frame_type ();
133 }
134
135
136 dcpomatic::DCPTime
137 Piece::position () const
138 {
139         return _content->position ();
140 }
141
142
143 dcpomatic::DCPTime
144 Piece::end (shared_ptr<const Film> film) const
145 {
146         return _content->end (film);
147 }
148
149
150 shared_ptr<PlayerVideo>
151 Piece::player_video (ContentVideo video, shared_ptr<const Film> film, dcp::Size container_size) const
152 {
153         return std::make_shared<PlayerVideo>(
154                 video.image,
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()),
158                 container_size,
159                 video.eyes,
160                 video.part,
161                 _content->video->colour_conversion(),
162                 _content->video->range(),
163                 _content,
164                 video.frame,
165                 false
166                 );
167 }
168
169
170 int
171 Piece::resampled_audio_frame_rate (shared_ptr<const Film> film) const
172 {
173         DCPOMATIC_ASSERT (_content->audio);
174         return _content->audio->resampled_frame_rate (film);
175 }
176
177
178 double
179 Piece::audio_gain () const
180 {
181         DCPOMATIC_ASSERT (_content->audio);
182         return _content->audio->gain();
183 }
184
185
186 shared_ptr<Decoder>
187 Piece::decoder_for (shared_ptr<Content> content) const
188 {
189         if (content == _content) {
190                 return _decoder;
191         }
192
193         return {};
194 }
195
196
197 void
198 Piece::pass ()
199 {
200         LOG_DEBUG_PLAYER ("Calling pass() on %1", _content->path(0));
201         _done = _decoder->pass();
202 }
203
204
205 bool
206 Piece::reference_dcp_audio () const
207 {
208         auto dcp = dynamic_pointer_cast<DCPContent>(_content);
209         return dcp && dcp->reference_audio();
210 }
211
212
213 void
214 Piece::seek (shared_ptr<const Film> film, DCPTime time, bool accurate)
215 {
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).
221                    */
222                 _decoder->seek (dcp_to_content_time(position(), film), true);
223                 _done = false;
224         } else if (position() <= time && time < end(film)) {
225                 /* During; seek to position */
226                 _decoder->seek (dcp_to_content_time(time, film), accurate);
227                 _done = false;
228         } else {
229                 /* After; this piece is done */
230                 _done = true;
231         }
232 }
233
234
235 optional<dcpomatic::DCPTime>
236 Piece::decoder_before(shared_ptr<const Film> film, optional<dcpomatic::DCPTime> time)
237 {
238         if (_done) {
239                 return {};
240         }
241
242         auto t = content_time_to_dcp(_content, std::max(_decoder->position(), _content->trim_start()));
243         DCPOMATIC_ASSERT (t);
244
245         if (*t > end(film)) {
246                 _done = true;
247         } else {
248                 /* Given two choices at the same time, pick the one with texts so we see it before
249                    the video.
250                    */
251                 if (!time || t < *time || (t == *time && !_decoder->text.empty())) {
252                         return t;
253                 }
254         }
255
256         return {};
257 }
258
259 vector<dcpomatic::FontData>
260 Piece::fonts () const
261 {
262         return _decoder->fonts();
263 }
264
265
266 bool
267 Piece::ignore_video_at (DCPTime time) const
268 {
269         return _ignore_video && _ignore_video->contains(time);
270 }
271