dcpomatic_create should respond to --version on stdout, not stderr (#1686)
[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/version.h"
22 #include "lib/film.h"
23 #include "lib/util.h"
24 #include "lib/content_factory.h"
25 #include "lib/job_manager.h"
26 #include "lib/signal_manager.h"
27 #include "lib/job.h"
28 #include "lib/dcp_content_type.h"
29 #include "lib/ratio.h"
30 #include "lib/image_content.h"
31 #include "lib/video_content.h"
32 #include "lib/cross.h"
33 #include "lib/config.h"
34 #include "lib/dcp_content.h"
35 #include "lib/create_cli.h"
36 #include "lib/version.h"
37 #include "lib/dcpomatic_log.h"
38 #include <dcp/exceptions.h>
39 #include <libxml++/libxml++.h>
40 #include <boost/filesystem.hpp>
41 #include <boost/foreach.hpp>
42 #include <getopt.h>
43 #include <string>
44 #include <iostream>
45 #include <cstdlib>
46 #include <stdexcept>
47
48 using std::string;
49 using std::cout;
50 using std::cerr;
51 using std::list;
52 using std::exception;
53 using boost::shared_ptr;
54 using boost::dynamic_pointer_cast;
55 using boost::optional;
56
57 class SimpleSignalManager : public SignalManager
58 {
59 public:
60         /* Do nothing in this method so that UI events happen in our thread
61            when we call SignalManager::ui_idle().
62         */
63         void wake_ui () {}
64 };
65
66 int
67 main (int argc, char* argv[])
68 {
69         dcpomatic_setup_path_encoding ();
70         dcpomatic_setup ();
71
72         CreateCLI cc (argc, argv);
73         if (cc.error) {
74                 cerr << *cc.error << "\n";
75                 exit (1);
76         }
77
78         if (cc.version) {
79                 cout << "dcpomatic version " << dcpomatic_version << " " << dcpomatic_git_commit << "\n";
80                 exit (EXIT_SUCCESS);
81         }
82
83         if (cc.config_dir) {
84                 State::override_path = *cc.config_dir;
85         }
86
87         signal_manager = new SimpleSignalManager ();
88         JobManager* jm = JobManager::instance ();
89
90         try {
91                 shared_ptr<Film> film (new Film(cc.output_dir));
92                 dcpomatic_log = film->log ();
93                 dcpomatic_log->set_types (Config::instance()->log_types());
94                 if (cc.template_name) {
95                         film->use_template (cc.template_name.get());
96                 }
97                 film->set_name (cc.name);
98
99                 film->set_container (cc.container_ratio);
100                 film->set_dcp_content_type (cc.dcp_content_type);
101                 film->set_interop (cc.standard == dcp::INTEROP);
102                 film->set_use_isdcf_name (!cc.no_use_isdcf_name);
103                 film->set_signed (!cc.no_sign);
104                 film->set_encrypted (cc.encrypt);
105                 film->set_three_d (cc.threed);
106                 film->set_resolution (cc.fourk ? RESOLUTION_4K : RESOLUTION_2K);
107                 if (cc.j2k_bandwidth) {
108                         film->set_j2k_bandwidth (*cc.j2k_bandwidth);
109                 }
110
111                 BOOST_FOREACH (CreateCLI::Content i, cc.content) {
112                         boost::filesystem::path const can = boost::filesystem::canonical (i.path);
113                         list<shared_ptr<Content> > content;
114
115                         if (boost::filesystem::exists (can / "ASSETMAP") || (boost::filesystem::exists (can / "ASSETMAP.xml"))) {
116                                 content.push_back (shared_ptr<DCPContent>(new DCPContent(can)));
117                         } else {
118                                 /* I guess it's not a DCP */
119                                 content = content_factory (can);
120                         }
121
122                         BOOST_FOREACH (shared_ptr<Content> j, content) {
123                                 film->examine_and_add_content (j);
124                         }
125
126                         while (jm->work_to_do ()) {
127                                 dcpomatic_sleep (1);
128                         }
129
130                         while (signal_manager->ui_idle() > 0) {}
131
132                         BOOST_FOREACH (shared_ptr<Content> j, content) {
133                                 if (j->video) {
134                                         j->video->set_scale (VideoContentScale(cc.content_ratio));
135                                         j->video->set_frame_type (i.frame_type);
136                                 }
137                         }
138                 }
139
140                 if (cc.dcp_frame_rate) {
141                         film->set_video_frame_rate (*cc.dcp_frame_rate);
142                 }
143
144                 BOOST_FOREACH (shared_ptr<Content> i, film->content()) {
145                         shared_ptr<ImageContent> ic = dynamic_pointer_cast<ImageContent> (i);
146                         if (ic && ic->still()) {
147                                 ic->video->set_length (cc.still_length * 24);
148                         }
149                 }
150
151                 if (jm->errors ()) {
152                         BOOST_FOREACH (shared_ptr<Job> i, jm->get()) {
153                                 if (i->finished_in_error()) {
154                                         cerr << i->error_summary() << "\n"
155                                              << i->error_details() << "\n";
156                                 }
157                         }
158                         exit (EXIT_FAILURE);
159                 }
160
161                 if (cc.output_dir) {
162                         film->write_metadata ();
163                 } else {
164                         film->metadata()->write_to_stream_formatted(cout, "UTF-8");
165                 }
166         } catch (exception& e) {
167                 cerr << argv[0] << ": " << e.what() << "\n";
168                 exit (EXIT_FAILURE);
169         }
170
171         return 0;
172 }