2a3adcd408ef32acdeacf506d7ebe744450be0ce
[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 boost::optional;
37 using namespace dcpomatic;
38
39
40 Piece::Piece (shared_ptr<Content> c, shared_ptr<Decoder> d, FrameRateChange f)
41         : _content (c)
42         , decoder (d)
43         , _frc (f)
44 {
45         if (_content->audio) {
46                 for (auto j: _content->audio->streams()) {
47                         _stream_last_push_end[j] = _content->position();
48                 }
49         }
50 }
51
52
53
54 void
55 Piece::update_pull_to (DCPTime& pull_to) const
56 {
57         if (done) {
58                 return;
59         }
60
61         for (auto const& i: _stream_last_push_end) {
62                 pull_to = std::min(pull_to, i.second);
63         }
64 }
65
66
67 void
68 Piece::set_last_push_end (AudioStreamPtr stream, DCPTime end)
69 {
70         DCPOMATIC_ASSERT (_stream_last_push_end.find(stream) != _stream_last_push_end.end());
71         _stream_last_push_end[stream] = end;
72 }
73
74
75 DCPTime
76 Piece::content_video_to_dcp (Frame f) const
77 {
78         /* See comment in resampled_audio_to_dcp */
79         auto const d = DCPTime::from_frames(f * _frc.factor(), _frc.dcp) - DCPTime(_content->trim_start(), _frc);
80         return d + _content->position();
81 }
82
83
84 DCPTime
85 Piece::resampled_audio_to_dcp (Frame f, shared_ptr<const Film> film) const
86 {
87         /* It might seem more logical here to convert s to a ContentTime (using the FrameRateChange)
88            then convert that ContentTime to frames at the content's rate.  However this fails for
89            situations like content at 29.9978733fps, DCP at 30fps.  The accuracy of the Time type is not
90            enough to distinguish between the two with low values of time (e.g. 3200 in Time units).
91
92            Instead we convert the DCPTime using the DCP video rate then account for any skip/repeat.
93         */
94         return DCPTime::from_frames(f, film->audio_frame_rate())
95                 - DCPTime(_content->trim_start(), _frc)
96                 + _content->position();
97 }
98
99
100 ContentTime
101 Piece::dcp_to_content_time (DCPTime t, shared_ptr<const Film> film) const
102 {
103         auto s = t - _content->position ();
104         s = min (_content->length_after_trim(film), s);
105         return max (ContentTime(), ContentTime(s, _frc) + _content->trim_start());
106 }
107
108
109 optional<DCPTime>
110 Piece::content_time_to_dcp (shared_ptr<const Content> content, ContentTime t) const
111 {
112         if (_content != content) {
113                 return {};
114         }
115
116         return max (DCPTime(), DCPTime(t - _content->trim_start(), _frc) + _content->position());
117 }
118
119
120 bool
121 Piece::use_video () const
122 {
123         return _content->video && _content->video->use();
124 }
125
126
127 VideoFrameType
128 Piece::video_frame_type () const
129 {
130         DCPOMATIC_ASSERT (_content->video);
131         return _content->video->frame_type ();
132 }
133
134
135 dcpomatic::DCPTime
136 Piece::position () const
137 {
138         return _content->position ();
139 }
140
141
142 dcpomatic::DCPTime
143 Piece::end (shared_ptr<const Film> film) const
144 {
145         return _content->end (film);
146 }
147
148
149 shared_ptr<PlayerVideo>
150 Piece::player_video (ContentVideo video, shared_ptr<const Film> film, dcp::Size container_size) const
151 {
152         return std::make_shared<PlayerVideo>(
153                 video.image,
154                 _content->video->crop (),
155                 _content->video->fade (film, video.frame),
156                 scale_for_display(_content->video->scaled_size(film->frame_size()), container_size, film->frame_size()),
157                 container_size,
158                 video.eyes,
159                 video.part,
160                 _content->video->colour_conversion(),
161                 _content->video->range(),
162                 _content,
163                 video.frame,
164                 false
165                 );
166 }
167
168
169 int
170 Piece::resampled_audio_frame_rate (shared_ptr<const Film> film) const
171 {
172         DCPOMATIC_ASSERT (_content->audio);
173         return _content->audio->resampled_frame_rate (film);
174 }
175
176
177 double
178 Piece::audio_gain () const
179 {
180         DCPOMATIC_ASSERT (_content->audio);
181         return _content->audio->gain();
182 }
183
184
185 shared_ptr<Decoder>
186 Piece::decoder_for (shared_ptr<Content> content) const
187 {
188         if (content == _content) {
189                 return decoder;
190         }
191
192         return {};
193 }
194
195
196 DCPTime
197 Piece::decoder_position () const
198 {
199         auto t = content_time_to_dcp(_content, std::max(decoder->position(), _content->trim_start()));
200         DCPOMATIC_ASSERT (t);
201         return *t;
202 }
203
204
205 void
206 Piece::pass ()
207 {
208         LOG_DEBUG_PLAYER ("Calling pass() on %1", _content->path(0));
209         done = decoder->pass();
210 }
211
212
213 bool
214 Piece::reference_dcp_audio () const
215 {
216         auto dcp = dynamic_pointer_cast<DCPContent>(_content);
217         return dcp && dcp->reference_audio();
218 }
219
220
221 bool
222 Piece::has_text () const
223 {
224         return !decoder->text.empty();
225 }
226