2 Copyright (C) 2012-2018 Carl Hetherington <cth@carlh.net>
4 This file is part of libdcp.
6 libdcp 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.
11 libdcp 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.
16 You should have received a copy of the GNU General Public License
17 along with libdcp. If not, see <http://www.gnu.org/licenses/>.
19 In addition, as a special exception, the copyright holders give
20 permission to link the code of portions of this program with the
21 OpenSSL library under certain conditions as described in each
22 individual source file, and distribute linked combinations
25 You must obey the GNU General Public License in all respects
26 for all of the code used other than OpenSSL. If you modify
27 file(s) with this exception, you may extend this exception to your
28 version of the file(s), but you are not obligated to do so. If you
29 do not wish to do so, delete this exception statement from your
30 version. If you delete this exception statement from all source
31 files in the program, then also delete it here.
35 #include "exceptions.h"
37 #include "sound_asset.h"
38 #include "picture_asset.h"
39 #include "subtitle_asset.h"
40 #include "reel_picture_asset.h"
41 #include "reel_sound_asset.h"
42 #include "reel_subtitle_asset.h"
43 #include "subtitle_string.h"
44 #include "interop_subtitle_asset.h"
45 #include "smpte_subtitle_asset.h"
46 #include "mono_picture_asset.h"
47 #include "encrypted_kdm.h"
48 #include "decrypted_kdm.h"
52 #include <boost/filesystem.hpp>
53 #include <boost/foreach.hpp>
66 using boost::shared_ptr;
67 using boost::dynamic_pointer_cast;
68 using boost::optional;
74 cerr << "Syntax: " << n << " [options] [<DCP>] [<CPL>]\n"
75 << " -s, --subtitles list all subtitles\n"
76 << " -p, --picture analyse picture\n"
77 << " -d, --decompress decompress picture when analysing (this is slow)\n"
78 << " -k, --keep-going carry on in the event of errors, if possible\n"
79 << " --kdm KDM to decrypt DCP\n"
80 << " --private-key private key for the certificate that the KDM is targeted at\n"
81 << " --ignore-missing-assets ignore missing asset files\n";
85 mbits_per_second (int size, Fraction frame_rate)
87 return size * 8 * frame_rate.as_float() / 1e6;
91 main_picture (shared_ptr<Reel> reel, bool analyse, bool decompress)
93 if (!reel->main_picture()) {
97 cout << " Picture ID: " << reel->main_picture()->id()
98 << " entry " << reel->main_picture()->entry_point()
99 << " duration " << reel->main_picture()->duration()
100 << " intrinsic " << reel->main_picture()->intrinsic_duration();
102 if (reel->main_picture()->asset_ref().resolved()) {
103 if (reel->main_picture()->asset()) {
104 cout << "\n Picture: "
105 << reel->main_picture()->asset()->size().width
107 << reel->main_picture()->asset()->size().height << "\n";
110 shared_ptr<MonoPictureAsset> ma = dynamic_pointer_cast<MonoPictureAsset>(reel->main_picture()->asset());
112 shared_ptr<MonoPictureAssetReader> reader = ma->start_read ();
113 pair<int, int> j2k_size_range (INT_MAX, 0);
114 for (int64_t i = 0; i < ma->intrinsic_duration(); ++i) {
115 shared_ptr<const MonoPictureFrame> frame = reader->get_frame (i);
116 printf("Frame %" PRId64 " J2K size %7d", i, frame->j2k_size());
117 j2k_size_range.first = min(j2k_size_range.first, frame->j2k_size());
118 j2k_size_range.second = max(j2k_size_range.second, frame->j2k_size());
123 printf(" decrypted OK");
124 } catch (exception& e) {
125 printf(" decryption FAILED");
133 "J2K size ranges from %d (%.1f Mbit/s) to %d (%.1f Mbit/s)\n",
134 j2k_size_range.first, mbits_per_second(j2k_size_range.first, ma->frame_rate()),
135 j2k_size_range.second, mbits_per_second(j2k_size_range.second, ma->frame_rate())
139 cout << " - not present in this DCP.\n";
144 main_sound (shared_ptr<Reel> reel)
146 if (reel->main_sound()) {
147 cout << " Sound ID: " << reel->main_sound()->id()
148 << " entry " << reel->main_picture()->entry_point()
149 << " duration " << reel->main_picture()->duration()
150 << " intrinsic " << reel->main_picture()->intrinsic_duration();
151 if (reel->main_sound()->asset_ref().resolved()) {
152 if (reel->main_sound()->asset()) {
154 << reel->main_sound()->asset()->channels()
156 << reel->main_sound()->asset()->sampling_rate() << "Hz\n";
159 cout << " - not present in this DCP.\n";
165 main_subtitle (shared_ptr<Reel> reel, bool list_subtitles)
167 if (!reel->main_subtitle()) {
171 cout << " Subtitle ID: " << reel->main_subtitle()->id();
173 if (reel->main_subtitle()->asset_ref().resolved()) {
174 list<SubtitleString> subs = reel->main_subtitle()->asset()->subtitles ();
175 cout << "\n Subtitle: " << subs.size() << " subtitles";
176 shared_ptr<InteropSubtitleAsset> iop = dynamic_pointer_cast<InteropSubtitleAsset> (reel->main_subtitle()->asset());
178 cout << " in " << iop->language() << "\n";
180 shared_ptr<SMPTESubtitleAsset> smpte = dynamic_pointer_cast<SMPTESubtitleAsset> (reel->main_subtitle()->asset());
181 if (smpte && smpte->language ()) {
182 cout << " in " << smpte->language().get() << "\n";
184 if (list_subtitles) {
185 BOOST_FOREACH (SubtitleString const& k, subs) {
190 cout << " - not present in this DCP.\n";
195 main (int argc, char* argv[])
197 bool subtitles = false;
198 bool keep_going = false;
199 bool picture = false;
200 bool decompress = false;
201 bool ignore_missing_assets = false;
202 optional<boost::filesystem::path> kdm;
203 optional<boost::filesystem::path> private_key;
205 int option_index = 0;
207 static struct option long_options[] = {
208 { "version", no_argument, 0, 'v' },
209 { "help", no_argument, 0, 'h' },
210 { "subtitles", no_argument, 0, 's' },
211 { "keep-going", no_argument, 0, 'k' },
212 { "picture", no_argument, 0, 'p' },
213 { "decompress", no_argument, 0, 'd' },
214 { "ignore-missing-assets", no_argument, 0, 'A' },
215 { "kdm", required_argument, 0, 'B' },
216 { "private-key", required_argument, 0, 'C' },
220 int c = getopt_long (argc, argv, "vhskpdAB:C:", long_options, &option_index);
228 cout << "libdcp version " << LIBDCP_VERSION << "\n";
246 ignore_missing_assets = true;
252 private_key = optarg;
257 if (argc <= optind || argc > (optind + 1)) {
262 if (!boost::filesystem::exists (argv[optind])) {
263 cerr << argv[0] << ": DCP or CPL " << argv[optind] << " not found.\n";
267 list<shared_ptr<CPL> > cpls;
268 if (boost::filesystem::is_directory(argv[optind])) {
270 DCP::ReadErrors errors;
272 dcp = new DCP (argv[optind]);
273 dcp->read (keep_going, &errors);
274 if (kdm && private_key) {
275 dcp->add(DecryptedKDM(EncryptedKDM(file_to_string(*kdm)), file_to_string(*private_key)));
277 } catch (FileError& e) {
278 cerr << "Could not read DCP " << argv[optind] << "; " << e.what() << "\n";
280 } catch (DCPReadError& e) {
281 cerr << "Could not read DCP " << argv[optind] << "; " << e.what() << "\n";
283 } catch (KDMDecryptionError& e) {
284 cerr << e.what() << "\n";
288 cout << "DCP: " << boost::filesystem::path(argv[optind]).string() << "\n";
290 dcp::filter_errors (errors, ignore_missing_assets);
291 for (DCP::ReadErrors::const_iterator i = errors.begin(); i != errors.end(); ++i) {
292 cerr << "Error: " << (*i)->what() << "\n";
297 cpls.push_back (shared_ptr<CPL>(new CPL(boost::filesystem::path(argv[optind]))));
299 ignore_missing_assets = true;
302 BOOST_FOREACH (shared_ptr<CPL> i, cpls) {
303 cout << " CPL: " << i->annotation_text() << "\n";
306 BOOST_FOREACH (shared_ptr<Reel> j, i->reels()) {
307 cout << " Reel " << R << "\n";
310 main_picture (j, picture, decompress);
311 } catch (UnresolvedRefError& e) {
313 if (!ignore_missing_assets) {
314 cerr << e.what() << " (for main picture)\n";
323 } catch (UnresolvedRefError& e) {
325 if (!ignore_missing_assets) {
326 cerr << e.what() << " (for main sound)\n";
334 main_subtitle (j, subtitles);
335 } catch (UnresolvedRefError& e) {
337 if (!ignore_missing_assets) {
338 cerr << e.what() << " (for main subtitle)\n";