1 /* mj2_to_metadata.c */
2 /* Dump MJ2, JP2 metadata (partial so far) to xml file */
3 /* Contributed to Open JPEG by Glenn Pearson, contract software developer, U.S. National Library of Medicine.
5 The base code in this file was developed by the author as part of a video archiving
6 project for the U.S. National Library of Medicine, Bethesda, MD.
7 It is the policy of NLM (and U.S. government) to not assert copyright.
9 A non-exclusive copy of this code has been contributed to the Open JPEG project.
10 Except for copyright, inclusion of the code within Open JPEG for distribution and use
11 can be bound by the Open JPEG open-source license and disclaimer, expressed elsewhere.
14 #include "opj_includes.h"
17 #include "mj2_to_metadata.h"
19 #include "opj_getopt.h"
21 /* -------------------------------------------------------------------------- */
24 sample error callback expecting a FILE* client object
26 void error_callback(const char *msg, void *client_data)
28 FILE *stream = (FILE*)client_data;
29 fprintf(stream, "[ERROR] %s", msg);
32 sample warning callback expecting a FILE* client object
34 void warning_callback(const char *msg, void *client_data)
36 FILE *stream = (FILE*)client_data;
37 fprintf(stream, "[WARNING] %s", msg);
40 sample debug callback expecting a FILE* client object
42 void info_callback(const char *msg, void *client_data)
44 FILE *stream = (FILE*)client_data;
45 fprintf(stream, "[INFO] %s", msg);
48 /* -------------------------------------------------------------------------- */
56 /* "1234567890123456789012345678901234567890123456789012345678901234567890123456789" */
57 fprintf(stdout, " Help for the 'mj2_to_metadata' Program\n");
58 fprintf(stdout, " ======================================\n");
59 fprintf(stdout, "The -h option displays this information on screen.\n\n");
62 "mj2_to_metadata generates an XML file from a Motion JPEG 2000 file.\n");
64 "The generated XML shows the structural, but not (yet) curatorial,\n");
66 "metadata from the movie header and from the JPEG 2000 image and tile\n");
68 "headers of a sample frame. Excluded: low-level packed-bits image data.\n\n");
70 fprintf(stdout, "By Default\n");
71 fprintf(stdout, "----------\n");
73 "The metadata includes the jp2 image and tile headers of the first frame.\n");
74 fprintf(stdout, "\n");
76 "Metadata values are shown in 'raw' form (e.g., hexadecimal) as stored in the\n");
78 "file, and, if apt, in a 'derived' form that is more quickly grasped.\n");
79 fprintf(stdout, "\n");
81 "Notes explaining the XML are embedded as terse comments. These include\n");
82 fprintf(stdout, " meaning of non-obvious tag abbreviations;\n");
83 fprintf(stdout, " range and precision of valid values;\n");
84 fprintf(stdout, " interpretations of values, such as enumerations; and\n");
85 fprintf(stdout, " current implementation limitations.\n");
86 fprintf(stdout, "\n");
88 "The sample-size and chunk-offset tables, each with 1 row per frame, are not reported.\n");
89 fprintf(stdout, "\n");
91 "The file is self-contained and no verification (e.g., against a DTD) is requested.\n");
92 fprintf(stdout, "\n");
93 fprintf(stdout, "Required Parameters (except with -h)\n");
94 fprintf(stdout, "------------------------------------\n");
96 "[Caution: file strings that contain spaces should be wrapped with quotes.]\n");
98 "-i input.mj2 : where 'input' is any source file name or path.\n");
100 " MJ2 files created with 'frames_to_mj2' are supported so far.\n");
102 " These are silent, single-track, 'MJ2 Simple Profile' videos.\n");
104 "-o output.xml : where 'output' is any destination file name or path.\n");
105 fprintf(stdout, "\n");
106 fprintf(stdout, "Optional Parameters\n");
107 fprintf(stdout, "-------------------\n");
108 fprintf(stdout, "-h : Display this help information.\n");
109 fprintf(stdout, "-n : Suppress all mj2_to_metadata notes.\n");
111 "-t : Include sample-size and chunk-offset tables.\n");
113 "-f n : where n > 0. Include jp2 header info for frame n [default=1].\n");
114 fprintf(stdout, "-f 0 : No jp2 header info.\n");
116 "-r : Suppress all 'raw' data for which a 'derived' form exists.\n");
117 fprintf(stdout, "-d : Suppress all 'derived' data.\n");
119 " (If both -r and -d given, -r will be ignored.)\n");
121 "-v string : Verify against the DTD file located by the string.\n");
123 " Prepend quoted 'string' with either SYSTEM or PUBLIC keyword.\n");
125 " Thus, for the distributed DTD placed in the same directory as\n");
127 " the output file: -v \"SYSTEM mj2_to_metadata.dtd\"\n");
129 " \"PUBLIC\" is used with an access protocol (e.g., http:) + URL.\n");
131 fprintf(stdout, "\n");
132 /* "1234567890123456789012345678901234567890123456789012345678901234567890123456789" */
137 int main(int argc, char *argv[])
141 opj_event_mgr_t event_mgr; /* event manager */
144 /* char xmloutname[50]; */
151 unsigned int sampleframe = 1; /* First frame */
152 char* stringDTD = NULL;
154 BOOL sampletables = FALSE;
157 mj2_dparameters_t parameters;
160 /* ':' after letter means it takes an argument */
161 int c = getopt(argc, argv, "i:o:f:v:hntrd");
162 /* FUTURE: Reserve 'p' for pruning file (which will probably make -t redundant) */
167 case 'i': /* IN file */
171 s++; /* Run to filename end */
180 if ((S1 == 'm' && S2 == 'j' && S3 == '2')
181 || (S1 == 'M' && S2 == 'J' && S3 == '2')) {
184 fprintf(stderr, "Input file name must have .mj2 extension, not .%c%c%c.\n", S1,
188 /* ----------------------------------------------------- */
189 case 'o': /* OUT file */
192 outfile++; /* Run to filename end */
203 if ((S1 == 'x' && S2 == 'm' && S3 == 'l')
204 || (S1 == 'X' && S2 == 'M' && S3 == 'L')) {
209 "Output file name must have .xml extension, not .%c%c%c\n", S1, S2, S3);
212 /* ----------------------------------------------------- */
213 case 'f': /* Choose sample frame. 0 = none */
214 sscanf(optarg, "%u", &sampleframe);
217 /* ----------------------------------------------------- */
218 case 'v': /* Verification by DTD. */
220 /* We will not insist upon last 3 chars being "dtd", since non-file
221 access protocol may be used. */
222 if (strchr(stringDTD, '"') != NULL) {
224 "-D's string must not contain any embedded double-quote characters.\n");
228 if (strncmp(stringDTD, "PUBLIC ", 7) == 0 ||
229 strncmp(stringDTD, "SYSTEM ", 7) == 0) {
233 fprintf(stderr, "-D's string must start with \"PUBLIC \" or \"SYSTEM \"\n");
236 /* ----------------------------------------------------- */
237 case 'n': /* Suppress comments */
241 /* ----------------------------------------------------- */
242 case 't': /* Show sample size and chunk offset tables */
246 /* ----------------------------------------------------- */
247 case 'h': /* Display an help description */
251 /* ----------------------------------------------------- */
252 case 'r': /* Suppress raw data */
256 /* ----------------------------------------------------- */
257 case 'd': /* Suppress derived data */
261 /* ----------------------------------------------------- */
267 if (!raw && !derived) {
268 raw = TRUE; /* At least one of 'raw' and 'derived' must be true */
273 if (!infile || !outfile) {
275 "Correct usage: mj2_to_metadata -i mj2-file -o xml-file (plus options)\n");
281 printf("Bad syntax: Usage: MJ2_to_metadata inputfile.mj2 outputfile.xml\n");
282 printf("Example: MJ2_to_metadata foreman.mj2 foreman.xml\n");
286 len = strlen(infile);
287 if (infile[0] == ' ') {
288 infile++; /* There may be a leading blank if user put space after -i */
291 file = fopen(infile, "rb"); /* was: argv[1] */
294 fprintf(stderr, "Failed to open %s for reading.\n", infile); /* was: argv[1] */
298 len = strlen(outfile);
299 if (outfile[0] == ' ') {
300 outfile++; /* There may be a leading blank if user put space after -o */
303 // Checking output file
304 xmlout = fopen(outfile, "w"); /* was: argv[2] */
306 fprintf(stderr, "Failed to open %s for writing.\n", outfile); /* was: argv[2] */
312 configure the event callbacks (not required)
313 setting of each callback is optionnal
315 memset(&event_mgr, 0, sizeof(opj_event_mgr_t));
316 event_mgr.error_handler = error_callback;
317 event_mgr.warning_handler = warning_callback;
318 event_mgr.info_handler = info_callback;
320 /* get a MJ2 decompressor handle */
321 dinfo = mj2_create_decompress();
323 /* catch events using our callbacks and give a local context */
324 opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr);
326 /* setup the decoder decoding parameters using user parameters */
327 movie = (opj_mj2_t*) dinfo->mj2_handle;
328 mj2_setup_decoder(dinfo->mj2_handle, ¶meters);
330 if (mj2_read_struct(file, movie)) { // Creating the movie structure
335 xml_write_init(notes, sampletables, raw, derived);
336 xml_write_struct(file, xmlout, movie, sampleframe, stringDTD, &event_mgr);
339 fprintf(stderr, "Metadata correctly extracted to XML file \n");;
341 /* free remaining structures */
343 mj2_destroy_decompress((opj_mj2_t*)dinfo->mj2_handle);