Allow specification of the CPL ID to use in a DCP with _create (#2302).
[dcpomatic.git] / src / tools / dcpomatic_create.cc
1 /*
2     Copyright (C) 2013-2019 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 #include "lib/audio_content.h"
22 #include "lib/config.h"
23 #include "lib/content_factory.h"
24 #include "lib/create_cli.h"
25 #include "lib/cross.h"
26 #include "lib/dcp_content.h"
27 #include "lib/dcp_content_type.h"
28 #include "lib/dcpomatic_log.h"
29 #include "lib/film.h"
30 #include "lib/image_content.h"
31 #include "lib/job.h"
32 #include "lib/job_manager.h"
33 #include "lib/ratio.h"
34 #include "lib/signal_manager.h"
35 #include "lib/util.h"
36 #include "lib/version.h"
37 #include "lib/version.h"
38 #include "lib/video_content.h"
39 #include <dcp/exceptions.h>
40 #include <libxml++/libxml++.h>
41 #include <boost/filesystem.hpp>
42 #include <getopt.h>
43 #include <cstdlib>
44 #include <iostream>
45 #include <stdexcept>
46 #include <string>
47
48
49 using std::cerr;
50 using std::cout;
51 using std::dynamic_pointer_cast;
52 using std::exception;
53 using std::list;
54 using std::make_shared;
55 using std::shared_ptr;
56 using std::string;
57 using std::vector;
58 using boost::optional;
59
60
61 class SimpleSignalManager : public SignalManager
62 {
63 public:
64         /* Do nothing in this method so that UI events happen in our thread
65            when we call SignalManager::ui_idle().
66         */
67         void wake_ui () override {}
68 };
69
70 int
71 main (int argc, char* argv[])
72 {
73         dcpomatic_setup_path_encoding ();
74         dcpomatic_setup ();
75
76         CreateCLI cc (argc, argv);
77         if (cc.error) {
78                 cerr << *cc.error << "\n";
79                 exit (1);
80         }
81
82         if (cc.version) {
83                 cout << "dcpomatic version " << dcpomatic_version << " " << dcpomatic_git_commit << "\n";
84                 exit (EXIT_SUCCESS);
85         }
86
87         if (cc.config_dir) {
88                 State::override_path = *cc.config_dir;
89         }
90
91         signal_manager = new SimpleSignalManager ();
92         auto jm = JobManager::instance ();
93
94         try {
95                 auto film = std::make_shared<Film>(cc.output_dir);
96                 dcpomatic_log = film->log ();
97                 dcpomatic_log->set_types (Config::instance()->log_types());
98                 if (cc.template_name) {
99                         film->use_template (cc.template_name.get());
100                 }
101                 film->set_name (cc.name);
102
103                 if (cc.container_ratio) {
104                         film->set_container (cc.container_ratio);
105                 }
106                 film->set_dcp_content_type (cc.dcp_content_type);
107                 film->set_interop (cc.standard == dcp::Standard::INTEROP);
108                 film->set_use_isdcf_name (!cc.no_use_isdcf_name);
109                 film->set_encrypted (cc.encrypt);
110                 film->set_three_d (cc.threed);
111                 if (cc.twok) {
112                         film->set_resolution (Resolution::TWO_K);
113                 }
114                 if (cc.fourk) {
115                         film->set_resolution (Resolution::FOUR_K);
116                 }
117                 if (cc.j2k_bandwidth) {
118                         film->set_j2k_bandwidth (*cc.j2k_bandwidth);
119                 }
120
121                 for (auto cli_content: cc.content) {
122                         auto const can = boost::filesystem::canonical (cli_content.path);
123                         vector<shared_ptr<Content>> film_content_list;
124
125                         if (boost::filesystem::exists (can / "ASSETMAP") || (boost::filesystem::exists (can / "ASSETMAP.xml"))) {
126                                 auto dcp = make_shared<DCPContent>(can);
127                                 film_content_list.push_back (dcp);
128                                 if (cli_content.kdm) {
129                                         dcp->add_kdm (dcp::EncryptedKDM(dcp::file_to_string(*cli_content.kdm)));
130                                 }
131                                 if (cli_content.cpl) {
132                                         dcp->set_cpl(*cli_content.cpl);
133                                 }
134                         } else {
135                                 /* I guess it's not a DCP */
136                                 film_content_list = content_factory (can);
137                         }
138
139                         for (auto film_content: film_content_list) {
140                                 film->examine_and_add_content (film_content);
141                         }
142
143                         while (jm->work_to_do ()) {
144                                 dcpomatic_sleep_seconds (1);
145                         }
146
147                         while (signal_manager->ui_idle() > 0) {}
148
149                         for (auto film_content: film_content_list) {
150                                 if (film_content->video) {
151                                         film_content->video->set_frame_type (cli_content.frame_type);
152                                 }
153                                 if (film_content->audio && cli_content.channel) {
154                                         for (auto stream: film_content->audio->streams()) {
155                                                 AudioMapping mapping(stream->channels(), film->audio_channels());
156                                                 for (int channel = 0; channel < stream->channels(); ++channel) {
157                                                         mapping.set(channel, *cli_content.channel, 1.0f);
158                                                 }
159                                                 stream->set_mapping (mapping);
160                                         }
161                                 }
162                                 if (film_content->audio && cli_content.gain) {
163                                         film_content->audio->set_gain (*cli_content.gain);
164                                 }
165                         }
166                 }
167
168                 if (cc.dcp_frame_rate) {
169                         film->set_video_frame_rate (*cc.dcp_frame_rate);
170                 }
171
172                 for (auto i: film->content()) {
173                         auto ic = dynamic_pointer_cast<ImageContent> (i);
174                         if (ic && ic->still()) {
175                                 ic->video->set_length (cc.still_length * 24);
176                         }
177                 }
178
179                 if (jm->errors ()) {
180                         for (auto i: jm->get()) {
181                                 if (i->finished_in_error()) {
182                                         cerr << i->error_summary() << "\n";
183                                         if (!i->error_details().empty()) {
184                                              cout << i->error_details() << "\n";
185                                         }
186                                 }
187                         }
188                         exit (EXIT_FAILURE);
189                 }
190
191                 if (cc.output_dir) {
192                         film->write_metadata ();
193                 } else {
194                         film->metadata()->write_to_stream_formatted(cout, "UTF-8");
195                 }
196         } catch (exception& e) {
197                 cerr << argv[0] << ": " << e.what() << "\n";
198                 exit (EXIT_FAILURE);
199         }
200
201         return 0;
202 }