Assorted tidying.
[dcpomatic.git] / src / lib / audio_decoder.cc
1 /*
2     Copyright (C) 2012-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_decoder.h"
23 #include "audio_buffers.h"
24 #include "audio_content.h"
25 #include "dcpomatic_log.h"
26 #include "log.h"
27 #include "resampler.h"
28 #include "compose.hpp"
29 #include <iostream>
30
31 #include "i18n.h"
32
33
34 using std::cout;
35 using std::shared_ptr;
36 using std::make_shared;
37 using boost::optional;
38 using namespace dcpomatic;
39
40
41 AudioDecoder::AudioDecoder (Decoder* parent, shared_ptr<const AudioContent> content, bool fast)
42         : DecoderPart (parent)
43         , _content (content)
44         , _fast (fast)
45 {
46         /* Set up _positions so that we have one for each stream */
47         for (auto i: content->streams ()) {
48                 _positions[i] = 0;
49         }
50 }
51
52
53 /** @param time_already_delayed true if the delay should not be added to time */
54 void
55 AudioDecoder::emit (shared_ptr<const Film> film, AudioStreamPtr stream, shared_ptr<const AudioBuffers> data, ContentTime time, bool time_already_delayed)
56 {
57         if (ignore ()) {
58                 return;
59         }
60
61         /* Amount of error we will tolerate on audio timestamps; see comment below.
62          * We'll use 1 24fps video frame at 48kHz as this seems to be roughly how
63          * ffplay does it.
64          */
65         static Frame const slack_frames = 48000 / 24;
66
67         int const resampled_rate = _content->resampled_frame_rate(film);
68         if (!time_already_delayed) {
69                 time += ContentTime::from_seconds (_content->delay() / 1000.0);
70         }
71
72         auto reset = false;
73         if (_positions[stream] == 0) {
74                 /* This is the first data we have received since initialisation or seek.  Set
75                    the position based on the ContentTime that was given.  After this first time
76                    we just count samples unless the timestamp is more than slack_frames away
77                    from where we think it should be.  This is because ContentTimes seem to be
78                    slightly unreliable from FFmpegDecoder (i.e. not sample accurate), but we still
79                    need to obey them sometimes otherwise we get sync problems such as #1833.
80                 */
81                 if (_content->delay() > 0) {
82                         /* Insert silence to give the delay */
83                         silence (_content->delay ());
84                 }
85                 reset = true;
86         } else if (std::abs(_positions[stream] - time.frames_round(resampled_rate)) > slack_frames) {
87                 reset = true;
88                 LOG_GENERAL (
89                         "Reset audio position: was %1, new data at %2, slack: %3 frames",
90                         _positions[stream],
91                         time.frames_round(resampled_rate),
92                         std::abs(_positions[stream] - time.frames_round(resampled_rate))
93                         );
94         }
95
96         if (reset) {
97                 _positions[stream] = time.frames_round (resampled_rate);
98         }
99
100         shared_ptr<Resampler> resampler;
101         auto i = _resamplers.find(stream);
102         if (i != _resamplers.end()) {
103                 resampler = i->second;
104         } else {
105                 if (stream->frame_rate() != resampled_rate) {
106                         LOG_GENERAL (
107                                 "Creating new resampler from %1 to %2 with %3 channels",
108                                 stream->frame_rate(),
109                                 resampled_rate,
110                                 stream->channels()
111                                 );
112
113                         resampler = make_shared<Resampler>(stream->frame_rate(), resampled_rate, stream->channels());
114                         if (_fast) {
115                                 resampler->set_fast ();
116                         }
117                         _resamplers[stream] = resampler;
118                 }
119         }
120
121         if (resampler) {
122                 auto ro = resampler->run (data);
123                 if (ro->frames() == 0) {
124                         return;
125                 }
126                 data = ro;
127         }
128
129         Data(stream, ContentAudio (data, _positions[stream]));
130         _positions[stream] += data->frames();
131 }
132
133
134 /** @return Time just after the last thing that was emitted from a given stream */
135 ContentTime
136 AudioDecoder::stream_position (shared_ptr<const Film> film, AudioStreamPtr stream) const
137 {
138         auto i = _positions.find (stream);
139         DCPOMATIC_ASSERT (i != _positions.end ());
140         return ContentTime::from_frames (i->second, _content->resampled_frame_rate(film));
141 }
142
143
144 boost::optional<ContentTime>
145 AudioDecoder::position (shared_ptr<const Film> film) const
146 {
147         optional<ContentTime> p;
148         for (auto i: _positions) {
149                 auto const ct = stream_position (film, i.first);
150                 if (!p || ct < *p) {
151                         p = ct;
152                 }
153         }
154
155         return p;
156 }
157
158
159 void
160 AudioDecoder::seek ()
161 {
162         for (auto i: _resamplers) {
163                 i.second->flush ();
164                 i.second->reset ();
165         }
166
167         for (auto& i: _positions) {
168                 i.second = 0;
169         }
170 }
171
172
173 void
174 AudioDecoder::flush ()
175 {
176         for (auto const& i: _resamplers) {
177                 auto ro = i.second->flush ();
178                 if (ro->frames() > 0) {
179                         Data (i.first, ContentAudio (ro, _positions[i.first]));
180                         _positions[i.first] += ro->frames();
181                 }
182         }
183
184         if (_content->delay() < 0) {
185                 /* Finish off with the gap caused by the delay */
186                 silence (-_content->delay ());
187         }
188 }
189
190
191 void
192 AudioDecoder::silence (int milliseconds)
193 {
194         for (auto i: _content->streams()) {
195                 int const samples = ContentTime::from_seconds(milliseconds / 1000.0).frames_round(i->frame_rate());
196                 auto silence = make_shared<AudioBuffers>(i->channels(), samples);
197                 silence->make_silent ();
198                 Data (i, ContentAudio (silence, _positions[i]));
199         }
200 }