Don't make _stream_states for unmapped audio, otherwise we wait for content
[dcpomatic.git] / src / lib / ffmpeg_encoder.cc
1 /*
2     Copyright (C) 2017-2018 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 "butler.h"
23 #include "cross.h"
24 #include "ffmpeg_encoder.h"
25 #include "film.h"
26 #include "image.h"
27 #include "job.h"
28 #include "log.h"
29 #include "player.h"
30 #include "player_video.h"
31 #include "compose.hpp"
32 #include <iostream>
33
34 #include "i18n.h"
35
36
37 using std::cout;
38 using std::list;
39 using std::make_shared;
40 using std::shared_ptr;
41 using std::string;
42 using std::weak_ptr;
43 using boost::bind;
44 using boost::optional;
45 using namespace dcpomatic;
46 #if BOOST_VERSION >= 106100
47 using namespace boost::placeholders;
48 #endif
49
50
51 FFmpegEncoder::FFmpegEncoder (
52         shared_ptr<const Film> film,
53         weak_ptr<Job> job,
54         boost::filesystem::path output,
55         ExportFormat format,
56         bool mixdown_to_stereo,
57         bool split_reels,
58         bool audio_stream_per_channel,
59         int x264_crf
60         )
61         : Encoder (film, job)
62         , _output_audio_channels(mixdown_to_stereo ? 2 : (_film->audio_channels() > 8 ? 16 : _film->audio_channels()))
63         , _history (200)
64         , _output (output)
65         , _format (format)
66         , _split_reels (split_reels)
67         , _audio_stream_per_channel (audio_stream_per_channel)
68         , _x264_crf (x264_crf)
69         , _butler(
70                 _film,
71                 _player,
72                 mixdown_to_stereo ? stereo_map() : many_channel_map(),
73                 _output_audio_channels,
74                 boost::bind(&PlayerVideo::force, FFmpegFileEncoder::pixel_format(format)),
75                 VideoRange::VIDEO,
76                 Image::Alignment::PADDED,
77                 false,
78                 false,
79                 Butler::Audio::ENABLED
80                 )
81 {
82         _player.set_always_burn_open_subtitles();
83         _player.set_play_referenced();
84 }
85
86
87 AudioMapping
88 FFmpegEncoder::stereo_map() const
89 {
90         auto map = AudioMapping(_film->audio_channels(), 2);
91         float const overall_gain = 2 / (4 + sqrt(2));
92         float const minus_3dB = 1 / sqrt(2);
93         switch (_film->audio_channels()) {
94         case 2:
95                 map.set(dcp::Channel::LEFT, 0, 1);
96                 map.set(dcp::Channel::RIGHT, 1, 1);
97                 break;
98         case 4:
99                 map.set(dcp::Channel::LEFT,   0, overall_gain);
100                 map.set(dcp::Channel::RIGHT,  1, overall_gain);
101                 map.set(dcp::Channel::CENTRE, 0, overall_gain * minus_3dB);
102                 map.set(dcp::Channel::CENTRE, 1, overall_gain * minus_3dB);
103                 map.set(dcp::Channel::LS,     0, overall_gain);
104                 break;
105         default:
106                 map.set(dcp::Channel::LEFT,   0, overall_gain);
107                 map.set(dcp::Channel::RIGHT,  1, overall_gain);
108                 map.set(dcp::Channel::CENTRE, 0, overall_gain * minus_3dB);
109                 map.set(dcp::Channel::CENTRE, 1, overall_gain * minus_3dB);
110                 map.set(dcp::Channel::LS,     0, overall_gain);
111                 map.set(dcp::Channel::RS,     1, overall_gain);
112                 break;
113         }
114         return map;
115 }
116
117
118 AudioMapping
119 FFmpegEncoder::many_channel_map() const
120 {
121         auto map = AudioMapping(_film->audio_channels(), _output_audio_channels);
122         for (int i = 0; i < _film->audio_channels(); ++i) {
123                 map.set(i, i, 1);
124         }
125         return map;
126 }
127
128
129 void
130 FFmpegEncoder::go ()
131 {
132         {
133                 auto job = _job.lock ();
134                 DCPOMATIC_ASSERT (job);
135                 job->sub (_("Encoding"));
136         }
137
138         Waker waker;
139
140         list<FileEncoderSet> file_encoders;
141
142         int const files = _split_reels ? _film->reels().size() : 1;
143         for (int i = 0; i < files; ++i) {
144
145                 boost::filesystem::path filename = _output;
146                 auto extension = dcp::filesystem::extension(filename);
147                 filename = dcp::filesystem::change_extension(filename, "");
148
149                 if (files > 1) {
150                         /// TRANSLATORS: _reel%1 here is to be added to an export filename to indicate
151                         /// which reel it is.  Preserve the %1; it will be replaced with the reel number.
152                         filename = filename.string() + String::compose(_("_reel%1"), i + 1);
153                 }
154
155                 file_encoders.push_back (
156                         FileEncoderSet (
157                                 _film->frame_size(),
158                                 _film->video_frame_rate(),
159                                 _film->audio_frame_rate(),
160                                 _output_audio_channels,
161                                 _format,
162                                 _audio_stream_per_channel,
163                                 _x264_crf,
164                                 _film->three_d(),
165                                 filename,
166                                 extension
167                                 )
168                         );
169         }
170
171         auto reel_periods = _film->reels ();
172         auto reel = reel_periods.begin ();
173         auto encoder = file_encoders.begin ();
174
175         auto const video_frame = DCPTime::from_frames (1, _film->video_frame_rate ());
176         int const audio_frames = video_frame.frames_round(_film->audio_frame_rate());
177         std::vector<float> interleaved(_output_audio_channels * audio_frames);
178         auto deinterleaved = make_shared<AudioBuffers>(_output_audio_channels, audio_frames);
179         int const gets_per_frame = _film->three_d() ? 2 : 1;
180         for (DCPTime time; time < _film->length(); time += video_frame) {
181
182                 if (file_encoders.size() > 1 && !reel->contains(time)) {
183                         /* Next reel and file */
184                         ++reel;
185                         ++encoder;
186                         DCPOMATIC_ASSERT (reel != reel_periods.end());
187                         DCPOMATIC_ASSERT (encoder != file_encoders.end());
188                 }
189
190                 for (int j = 0; j < gets_per_frame; ++j) {
191                         Butler::Error e;
192                         auto video = _butler.get_video(Butler::Behaviour::BLOCKING, &e);
193                         _butler.rethrow();
194                         if (video.first) {
195                                 auto fe = encoder->get(video.first->eyes());
196                                 if (fe) {
197                                         fe->video(video.first, video.second - reel->from);
198                                 }
199                         } else {
200                                 if (e.code != Butler::Error::Code::FINISHED) {
201                                         throw DecodeError(String::compose("Error during decoding: %1", e.summary()));
202                                 }
203                         }
204                 }
205
206                 _history.event ();
207
208                 {
209                         boost::mutex::scoped_lock lm (_mutex);
210                         _last_time = time;
211                 }
212
213                 auto job = _job.lock ();
214                 if (job) {
215                         job->set_progress(float(time.get()) / _film->length().get());
216                 }
217
218                 waker.nudge ();
219
220                 _butler.get_audio(Butler::Behaviour::BLOCKING, interleaved.data(), audio_frames);
221                 /* XXX: inefficient; butler interleaves and we deinterleave again */
222                 float* p = interleaved.data();
223                 for (int j = 0; j < audio_frames; ++j) {
224                         for (int k = 0; k < _output_audio_channels; ++k) {
225                                 deinterleaved->data(k)[j] = *p++;
226                         }
227                 }
228                 encoder->audio (deinterleaved);
229         }
230
231         for (auto i: file_encoders) {
232                 i.flush ();
233         }
234 }
235
236 optional<float>
237 FFmpegEncoder::current_rate () const
238 {
239         return _history.rate ();
240 }
241
242 Frame
243 FFmpegEncoder::frames_done () const
244 {
245         boost::mutex::scoped_lock lm (_mutex);
246         return _last_time.frames_round (_film->video_frame_rate ());
247 }
248
249 FFmpegEncoder::FileEncoderSet::FileEncoderSet (
250         dcp::Size video_frame_size,
251         int video_frame_rate,
252         int audio_frame_rate,
253         int channels,
254         ExportFormat format,
255         bool audio_stream_per_channel,
256         int x264_crf,
257         bool three_d,
258         boost::filesystem::path output,
259         string extension
260         )
261 {
262         if (three_d) {
263                 _encoders[Eyes::LEFT] = make_shared<FFmpegFileEncoder>(
264                         video_frame_size, video_frame_rate, audio_frame_rate, channels, format,
265                         // TRANSLATORS: L here is an abbreviation for "left", to indicate the left-eye part of a 3D export
266                         audio_stream_per_channel, x264_crf, String::compose("%1_%2%3", output.string(), _("L"), extension)
267                         );
268                 _encoders[Eyes::RIGHT] = make_shared<FFmpegFileEncoder>(
269                         video_frame_size, video_frame_rate, audio_frame_rate, channels, format,
270                         // TRANSLATORS: R here is an abbreviation for "right", to indicate the right-eye part of a 3D export
271                         audio_stream_per_channel, x264_crf, String::compose("%1_%2%3", output.string(), _("R"), extension)
272                         );
273         } else {
274                 _encoders[Eyes::BOTH] = make_shared<FFmpegFileEncoder>(
275                         video_frame_size, video_frame_rate, audio_frame_rate, channels, format,
276                         audio_stream_per_channel, x264_crf, String::compose("%1%2", output.string(), extension)
277                         );
278         }
279 }
280
281 shared_ptr<FFmpegFileEncoder>
282 FFmpegEncoder::FileEncoderSet::get (Eyes eyes) const
283 {
284         if (_encoders.size() == 1) {
285                 /* We are doing a 2D export... */
286                 if (eyes == Eyes::LEFT) {
287                         /* ...but we got some 3D data; put the left eye into the output... */
288                         eyes = Eyes::BOTH;
289                 } else if (eyes == Eyes::RIGHT) {
290                         /* ...and ignore the right eye.*/
291                         return {};
292                 }
293         }
294
295         auto i = _encoders.find (eyes);
296         DCPOMATIC_ASSERT (i != _encoders.end());
297         return i->second;
298 }
299
300 void
301 FFmpegEncoder::FileEncoderSet::flush ()
302 {
303         for (auto& i: _encoders) {
304                 i.second->flush ();
305         }
306 }
307
308 void
309 FFmpegEncoder::FileEncoderSet::audio (shared_ptr<AudioBuffers> a)
310 {
311         for (auto& i: _encoders) {
312                 i.second->audio (a);
313         }
314 }