Oops: commit piece.cc.
[dcpomatic.git] / src / lib / piece.cc
1 /*
2     Copyright (C) 2013-2020 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_stream.h"
23 #include "content.h"
24 #include "piece.h"
25 #include <boost/foreach.hpp>
26
27
28 using std::copy;
29 using std::list;
30 using boost::shared_ptr;
31
32
33 Piece::Piece (shared_ptr<Content> c, shared_ptr<Decoder> d, FrameRateChange f)
34         : _frc (f)
35         , _done (false)
36 {
37         _content.push_back (c);
38         _decoder.push_back (d);
39
40         if (c->audio) {
41                 BOOST_FOREACH (AudioStreamPtr i, c->audio->streams()) {
42                         _stream_last_push_end[i] = c->position();
43                 }
44         }
45 }
46
47
48 void
49 Piece::update_pull_to (DCPTime& pull_to) const
50 {
51         if (_done) {
52                 return;
53         }
54
55         for (map<AudioStreamPtr, DCPTime>::const_iterator i = _stream_last_push_end.begin(); i != _stream_last_push_end.end(); ++i) {
56                 if (i->second < pull_to) {
57                         pull_to = i->second;
58                 }
59         }
60 }
61
62
63 void
64 Piece::set_last_push_end (AudioStreamPtr stream, DCPTime end)
65 {
66         DCPOMATIC_ASSERT (_stream_last_push_end.find(stream) != _stream_last_push_end.end());
67         _stream_last_push_end[stream] = end;
68 }
69
70
71 DCPTime
72 Piece::position () const
73 {
74         return _content[0]->position();
75 }
76
77
78 DCPTime
79 Piece::end (shared_ptr<const Film> film) const
80 {
81         return _content[0]->end(film);
82 }
83
84
85 DCPTime
86 Piece::content_video_to_dcp (Frame f) 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
96         DCPTime const d = DCPTime::from_frames(f * _frc.factor(), _frc.dcp) - DCPTime(_content[0]->trim_start(), _frc);
97         return d + position();
98 }
99
100
101 DCPTime
102 Piece::resampled_audio_to_dcp (shared_ptr<const Film> film, Frame f) const
103 {
104         /* See comment in dcp_to_content_video */
105         return DCPTime::from_frames(f, film->audio_frame_rate()) - DCPTime(_content[0]->trim_start(), frc) + position();
106 }
107
108
109 ContentTime
110 Piece::dcp_to_content_time (shared_ptr<const Film> film, DCPTime t) const
111 {
112         DCPTime s = t - position();
113         s = min (_content[0]->length_after_trim(_film), s);
114         return max (ContentTime(), ContentTime(s, _frc) + _content[0]->trim_start());
115 }
116
117
118 DCPTime
119 Piece::content_time_to_dcp (ContentTime t) const
120 {
121         return max (DCPTime(), DCPTime(t - _content[0]->trim_start(), _frc) + position());
122 }
123
124
125 void
126 Piece::add_fonts (list<shared_ptr<Font> >& fonts) const
127 {
128         BOOST_FOREACH (shared_ptr<Content> i, _content) {
129                 BOOST_FOREACH (shared_ptr<TextContent> j, i->text) {
130                         /* XXX: things may go wrong if there are duplicate font IDs
131                            with different font files.
132                            */
133                         list<shared_ptr<Font> > f = j->fonts ();
134                         copy (f.begin(), f.end(), back_inserter(fonts));
135                 }
136         }
137 }
138
139
140 optional<DCPTime>
141 Piece::position (shared_ptr<const Film> film)
142 {
143         if (_done) {
144                 return optional<DCPTime>();
145         }
146
147         DCPTime const t = content_time_to_dcp (max(_decoder[0]->position(), _content[0]->trim_start()));
148         if (t > end(film)) {
149                 _done = true;
150                 return optional<DCPTime>();
151         }
152
153         return t;
154 }
155
156
157 bool
158 Piece::has_text () const
159 {
160         return !_decoder[0].text.empty();
161 }
162
163
164 void
165 Piece::pass () const
166 {
167         _done = _decoder[0]->pass();
168 }
169