Trying to create export audio encoders with between 9 and 15 channels
[dcpomatic.git] / src / lib / dcp_encoder.cc
1 /*
2     Copyright (C) 2012-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 /** @file  src/dcp_encoder.cc
22  *  @brief A class which takes a Film and some Options, then uses those to encode the film into a DCP.
23  *
24  *  A decoder is selected according to the content type, and the encoder can be specified
25  *  as a parameter to the constructor.
26  */
27
28 #include "dcp_encoder.h"
29 #include "j2k_encoder.h"
30 #include "film.h"
31 #include "video_decoder.h"
32 #include "audio_decoder.h"
33 #include "player.h"
34 #include "job.h"
35 #include "writer.h"
36 #include "compose.hpp"
37 #include "referenced_reel_asset.h"
38 #include "text_content.h"
39 #include "player_video.h"
40 #include <boost/signals2.hpp>
41 #include <boost/foreach.hpp>
42 #include <iostream>
43
44 #include "i18n.h"
45
46 using std::string;
47 using std::cout;
48 using std::list;
49 using boost::shared_ptr;
50 using boost::weak_ptr;
51 using boost::dynamic_pointer_cast;
52 using boost::optional;
53 using namespace dcpomatic;
54
55 /** Construct a DCP encoder.
56  *  @param film Film that we are encoding.
57  *  @param job Job that this encoder is being used in.
58  */
59 DCPEncoder::DCPEncoder (shared_ptr<const Film> film, weak_ptr<Job> job)
60         : Encoder (film, job)
61         , _finishing (false)
62         , _non_burnt_subtitles (false)
63 {
64         _player_video_connection = _player->Video.connect (bind (&DCPEncoder::video, this, _1, _2));
65         _player_audio_connection = _player->Audio.connect (bind (&DCPEncoder::audio, this, _1, _2));
66         _player_text_connection = _player->Text.connect (bind (&DCPEncoder::text, this, _1, _2, _3, _4));
67         _player_atmos_connection = _player->Atmos.connect (bind (&DCPEncoder::atmos, this, _1, _2, _3));
68
69         BOOST_FOREACH (shared_ptr<const Content> c, film->content ()) {
70                 BOOST_FOREACH (shared_ptr<TextContent> i, c->text) {
71                         if (i->use() && !i->burn()) {
72                                 _non_burnt_subtitles = true;
73                         }
74                 }
75         }
76 }
77
78 DCPEncoder::~DCPEncoder ()
79 {
80         /* We must stop receiving more video data before we die */
81         _player_video_connection.release ();
82         _player_audio_connection.release ();
83         _player_text_connection.release ();
84         _player_atmos_connection.release ();
85 }
86
87 void
88 DCPEncoder::go ()
89 {
90         _writer.reset (new Writer (_film, _job));
91         _writer->start ();
92
93         _j2k_encoder.reset (new J2KEncoder (_film, _writer));
94         _j2k_encoder->begin ();
95
96         {
97                 shared_ptr<Job> job = _job.lock ();
98                 DCPOMATIC_ASSERT (job);
99                 job->sub (_("Encoding"));
100         }
101
102         if (_non_burnt_subtitles) {
103                 list<shared_ptr<Font> > fonts = _player->get_subtitle_fonts ();
104
105                 if (fonts.size() > 1 && _film->interop()) {
106                         /* Interop will ignore second and subsequent <LoadFont>s so don't even
107                            write them as they upset some validators.
108                         */
109                         shared_ptr<Font> first = fonts.front ();
110                         fonts.clear ();
111                         fonts.push_back (first);
112                 }
113
114                 _writer->write (fonts);
115         }
116
117         while (!_player->pass ()) {}
118
119         BOOST_FOREACH (ReferencedReelAsset i, _player->get_reel_assets ()) {
120                 _writer->write (i);
121         }
122
123         _finishing = true;
124         _j2k_encoder->end ();
125         _writer->finish ();
126 }
127
128 void
129 DCPEncoder::video (shared_ptr<PlayerVideo> data, DCPTime time)
130 {
131         if (!_film->three_d()) {
132                 if (data->eyes() == EYES_LEFT) {
133                         /* Use left-eye images for both eyes... */
134                         data->set_eyes (EYES_BOTH);
135                 } else if (data->eyes() == EYES_RIGHT) {
136                         /* ...and discard the right */
137                         return;
138                 }
139         }
140
141         _j2k_encoder->encode (data, time);
142 }
143
144 void
145 DCPEncoder::audio (shared_ptr<AudioBuffers> data, DCPTime time)
146 {
147         _writer->write (data, time);
148
149         shared_ptr<Job> job = _job.lock ();
150         DCPOMATIC_ASSERT (job);
151         job->set_progress (float(time.get()) / _film->length().get());
152 }
153
154 void
155 DCPEncoder::text (PlayerText data, TextType type, optional<DCPTextTrack> track, DCPTimePeriod period)
156 {
157         if (type == TEXT_CLOSED_CAPTION || _non_burnt_subtitles) {
158                 _writer->write (data, type, track, period);
159         }
160 }
161
162
163 void
164 DCPEncoder::atmos (shared_ptr<const dcp::AtmosFrame> data, DCPTime time, AtmosMetadata metadata)
165 {
166         _writer->write (data, time, metadata);
167 }
168
169
170 optional<float>
171 DCPEncoder::current_rate () const
172 {
173         if (!_j2k_encoder) {
174                 return optional<float>();
175         }
176
177         return _j2k_encoder->current_encoding_rate ();
178 }
179
180 Frame
181 DCPEncoder::frames_done () const
182 {
183         if (!_j2k_encoder) {
184                 return 0;
185         }
186
187         return _j2k_encoder->video_frames_enqueued ();
188 }