8b4a0ea2a72098dea25560c6d389ad3f46105bbf
[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()) {
75                 cout << "      Picture ID:  " << reel->main_picture()->id() << "\n";
76                 if (reel->main_picture()->asset()) {
77                         cout << "      Picture:     "
78                              << reel->main_picture()->asset()->size().width
79                              << "x"
80                              << reel->main_picture()->asset()->size().height << "\n";
81                 }
82         }
83 }
84
85 static void
86 main_sound (shared_ptr<Reel> reel)
87 {
88         if (reel->main_sound()) {
89                 cout << "      Sound ID:    " << reel->main_sound()->id() << "\n";
90                 if (reel->main_sound()->asset()) {
91                         cout << "      Sound:       "
92                              << reel->main_sound()->asset()->channels()
93                              << " channels at "
94                              << reel->main_sound()->asset()->sampling_rate() << "Hz\n";
95                 }
96         }
97 }
98
99 static void
100 main_subtitle (shared_ptr<Reel> reel, bool list_subtitles)
101 {
102         if (!reel->main_subtitle()) {
103                 return;
104         }
105
106         cout << "      Subtitle ID: " << reel->main_subtitle()->id() << "\n";
107
108         list<SubtitleString> subs = reel->main_subtitle()->asset()->subtitles ();
109         cout << "      Subtitle:    " << subs.size() << " subtitles";
110         shared_ptr<InteropSubtitleAsset> iop = dynamic_pointer_cast<InteropSubtitleAsset> (reel->main_subtitle()->asset());
111         if (iop) {
112                 cout << " in " << iop->language() << "\n";
113         }
114         shared_ptr<SMPTESubtitleAsset> smpte = dynamic_pointer_cast<SMPTESubtitleAsset> (reel->main_subtitle()->asset());
115         if (smpte && smpte->language ()) {
116                 cout << " in " << smpte->language().get() << "\n";
117         }
118         if (list_subtitles) {
119                 BOOST_FOREACH (SubtitleString const& k, subs) {
120                         cout << k << "\n";
121                 }
122         }
123 }
124
125 int
126 main (int argc, char* argv[])
127 {
128         bool subtitles = false;
129         bool keep_going = false;
130         bool ignore_missing_assets = false;
131
132         int option_index = 0;
133         while (true) {
134                 static struct option long_options[] = {
135                         { "version", no_argument, 0, 'v' },
136                         { "help", no_argument, 0, 'h' },
137                         { "subtitles", no_argument, 0, 's' },
138                         { "keep-going", no_argument, 0, 'k' },
139                         { "ignore-missing-assets", no_argument, 0, 'A' },
140                         { 0, 0, 0, 0 }
141                 };
142
143                 int c = getopt_long (argc, argv, "vhskA", long_options, &option_index);
144
145                 if (c == -1) {
146                         break;
147                 }
148
149                 switch (c) {
150                 case 'v':
151                         cout << "libdcp version " << LIBDCP_VERSION << "\n";
152                         exit (EXIT_SUCCESS);
153                 case 'h':
154                         help (argv[0]);
155                         exit (EXIT_SUCCESS);
156                 case 's':
157                         subtitles = true;
158                         break;
159                 case 'k':
160                         keep_going = true;
161                         break;
162                 case 'A':
163                         ignore_missing_assets = true;
164                         break;
165                 }
166         }
167
168         if (argc <= optind || argc > (optind + 1)) {
169                 help (argv[0]);
170                 exit (EXIT_FAILURE);
171         }
172
173         if (!boost::filesystem::exists (argv[optind])) {
174                 cerr << argv[0] << ": DCP " << argv[optind] << " not found.\n";
175                 exit (EXIT_FAILURE);
176         }
177
178         DCP* dcp = 0;
179         DCP::ReadErrors errors;
180         try {
181                 dcp = new DCP (argv[optind]);
182                 dcp->read (keep_going, &errors);
183         } catch (FileError& e) {
184                 cerr << "Could not read DCP " << argv[optind] << "; " << e.what() << "\n";
185                 exit (EXIT_FAILURE);
186         } catch (DCPReadError& e) {
187                 cerr << "Could not read DCP " << argv[optind] << "; " << e.what() << "\n";
188                 exit (EXIT_FAILURE);
189         }
190
191         cout << "DCP: " << boost::filesystem::path(argv[optind]).string() << "\n";
192
193         dcp::filter_errors (errors, ignore_missing_assets);
194         for (DCP::ReadErrors::const_iterator i = errors.begin(); i != errors.end(); ++i) {
195                 cerr << "Error: " << (*i)->what() << "\n";
196         }
197
198         list<shared_ptr<CPL> > cpls = dcp->cpls ();
199
200         for (list<shared_ptr<CPL> >::iterator i = cpls.begin(); i != cpls.end(); ++i) {
201                 cout << "  CPL: " << (*i)->annotation_text() << "\n";
202
203                 list<shared_ptr<Reel> > reels = (*i)->reels ();
204
205                 int R = 1;
206                 for (list<shared_ptr<Reel> >::const_iterator j = reels.begin(); j != reels.end(); ++j) {
207                         cout << "    Reel " << R << "\n";
208
209                         try {
210                                 main_picture (*j);
211                         } catch (UnresolvedRefError& e) {
212                                 if (keep_going) {
213                                         if (!ignore_missing_assets) {
214                                                 cerr << e.what() << " (for main picture)\n";
215                                         }
216                                 } else {
217                                         throw;
218                                 }
219                         }
220
221                         try {
222                                 main_sound (*j);
223                         } catch (UnresolvedRefError& e) {
224                                 if (keep_going) {
225                                         if (!ignore_missing_assets) {
226                                                 cerr << e.what() << " (for main sound)\n";
227                                         }
228                                 } else {
229                                         throw;
230                                 }
231                         }
232
233                         try {
234                                 main_subtitle (*j, subtitles);
235                         } catch (UnresolvedRefError& e) {
236                                 if (keep_going) {
237                                         if (!ignore_missing_assets) {
238                                                 cerr << e.what() << " (for main subtitle)\n";
239                                         }
240                                 } else {
241                                         throw;
242                                 }
243                         }
244
245                         ++R;
246                 }
247         }
248
249         return 0;
250 }