Fix GPL boilerplate in tools/
[libdcp.git] / tools / dcpinfo.cc
1 /*
2     Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
3
4     This file is part of libdcp.
5
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.
10
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.
15
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/>.
18
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
23     including the two.
24
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.
32 */
33
34 #include "dcp.h"
35 #include "exceptions.h"
36 #include "reel.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 "cpl.h"
47 #include "common.h"
48 #include <getopt.h>
49 #include <boost/filesystem.hpp>
50 #include <boost/foreach.hpp>
51 #include <iostream>
52 #include <cstdlib>
53
54 using std::string;
55 using std::cerr;
56 using std::cout;
57 using std::list;
58 using boost::shared_ptr;
59 using boost::dynamic_pointer_cast;
60 using namespace dcp;
61
62 static void
63 help (string n)
64 {
65         cerr << "Syntax: " << n << " [options] <DCP>\n"
66              << "  -s, --subtitles              list all subtitles\n"
67              << "  -k, --keep-going             carry on in the event of errors, if possible\n"
68              << "      --ignore-missing-assets  ignore missing asset files\n";
69 }
70
71 static void
72 main_picture (shared_ptr<Reel> reel)
73 {
74         if (reel->main_picture() && reel->main_picture()->asset()) {
75                 cout << "      Picture:  "
76                      << reel->main_picture()->asset()->size().width
77                      << "x"
78                      << reel->main_picture()->asset()->size().height << "\n";
79         }
80 }
81
82 static void
83 main_sound (shared_ptr<Reel> reel)
84 {
85         if (reel->main_sound() && reel->main_sound()->asset()) {
86                 cout << "      Sound:    "
87                      << reel->main_sound()->asset()->channels()
88                      << " channels at "
89                      << reel->main_sound()->asset()->sampling_rate() << "Hz\n";
90         }
91 }
92
93 static void
94 main_subtitle (shared_ptr<Reel> reel, bool list_subtitles)
95 {
96         if (!reel->main_subtitle()) {
97                 return;
98         }
99
100         list<SubtitleString> subs = reel->main_subtitle()->asset()->subtitles ();
101         cout << "      Subtitle: " << subs.size() << " subtitles";
102         shared_ptr<InteropSubtitleAsset> iop = dynamic_pointer_cast<InteropSubtitleAsset> (reel->main_subtitle()->asset());
103         if (iop) {
104                 cout << " in " << iop->language() << "\n";
105         }
106         shared_ptr<SMPTESubtitleAsset> smpte = dynamic_pointer_cast<SMPTESubtitleAsset> (reel->main_subtitle()->asset());
107         if (smpte && smpte->language ()) {
108                 cout << " in " << smpte->language().get() << "\n";
109         }
110         if (list_subtitles) {
111                 BOOST_FOREACH (SubtitleString const& k, subs) {
112                         cout << k << "\n";
113                 }
114         }
115 }
116
117 int
118 main (int argc, char* argv[])
119 {
120         bool subtitles = false;
121         bool keep_going = false;
122         bool ignore_missing_assets = false;
123
124         int option_index = 0;
125         while (1) {
126                 static struct option long_options[] = {
127                         { "version", no_argument, 0, 'v' },
128                         { "help", no_argument, 0, 'h' },
129                         { "subtitles", no_argument, 0, 's' },
130                         { "keep-going", no_argument, 0, 'k' },
131                         { "ignore-missing-assets", no_argument, 0, 'A' },
132                         { 0, 0, 0, 0 }
133                 };
134
135                 int c = getopt_long (argc, argv, "vhskA", long_options, &option_index);
136
137                 if (c == -1) {
138                         break;
139                 }
140
141                 switch (c) {
142                 case 'v':
143                         cout << "dcpdiff version " << LIBDCP_VERSION << "\n";
144                         exit (EXIT_SUCCESS);
145                 case 'h':
146                         help (argv[0]);
147                         exit (EXIT_SUCCESS);
148                 case 's':
149                         subtitles = true;
150                         break;
151                 case 'k':
152                         keep_going = true;
153                         break;
154                 case 'A':
155                         ignore_missing_assets = true;
156                         break;
157                 }
158         }
159
160         if (argc <= optind || argc > (optind + 1)) {
161                 help (argv[0]);
162                 exit (EXIT_FAILURE);
163         }
164
165         if (!boost::filesystem::exists (argv[optind])) {
166                 cerr << argv[0] << ": DCP " << argv[optind] << " not found.\n";
167                 exit (EXIT_FAILURE);
168         }
169
170         DCP* dcp = 0;
171         DCP::ReadErrors errors;
172         try {
173                 dcp = new DCP (argv[optind]);
174                 dcp->read (keep_going, &errors);
175         } catch (FileError& e) {
176                 cerr << "Could not read DCP " << argv[optind] << "; " << e.what() << "\n";
177                 exit (EXIT_FAILURE);
178         } catch (DCPReadError& e) {
179                 cerr << "Could not read DCP " << argv[optind] << "; " << e.what() << "\n";
180                 exit (EXIT_FAILURE);
181         }
182
183         cout << "DCP: " << boost::filesystem::path(argv[optind]).filename().string() << "\n";
184
185         dcp::filter_errors (errors, ignore_missing_assets);
186         for (DCP::ReadErrors::const_iterator i = errors.begin(); i != errors.end(); ++i) {
187                 cerr << "Error: " << (*i)->what() << "\n";
188         }
189
190         list<shared_ptr<CPL> > cpls = dcp->cpls ();
191
192         for (list<shared_ptr<CPL> >::iterator i = cpls.begin(); i != cpls.end(); ++i) {
193                 cout << "  CPL: " << (*i)->annotation_text() << "\n";
194
195                 list<shared_ptr<Reel> > reels = (*i)->reels ();
196
197                 int R = 1;
198                 for (list<shared_ptr<Reel> >::const_iterator j = reels.begin(); j != reels.end(); ++j) {
199                         cout << "    Reel " << R << "\n";
200
201                         try {
202                                 main_picture (*j);
203                         } catch (UnresolvedRefError& e) {
204                                 if (keep_going) {
205                                         if (!ignore_missing_assets) {
206                                                 cerr << e.what() << " (for main picture)\n";
207                                         }
208                                 } else {
209                                         throw;
210                                 }
211                         }
212
213                         try {
214                                 main_sound (*j);
215                         } catch (UnresolvedRefError& e) {
216                                 if (keep_going) {
217                                         if (!ignore_missing_assets) {
218                                                 cerr << e.what() << " (for main sound)\n";
219                                         }
220                                 } else {
221                                         throw;
222                                 }
223                         }
224
225                         try {
226                                 main_subtitle (*j, subtitles);
227                         } catch (UnresolvedRefError& e) {
228                                 if (keep_going) {
229                                         if (!ignore_missing_assets) {
230                                                 cerr << e.what() << " (for main subtitle)\n";
231                                         }
232                                 } else {
233                                         throw;
234                                 }
235                         }
236
237                         ++R;
238                 }
239         }
240
241         return 0;
242 }