45a91b1c942994c3196985e46a383f443893a620
[openjpeg.git] / mj2 / mj2_to_metadata.c
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.
4
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.
8
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.
12 */
13 #include <stdio.h>
14 #include <malloc.h>
15 #include <setjmp.h>
16
17 #include "mj2.h"
18 #include <openjpeg.h>
19
20 //MEMORY LEAK
21 #ifdef _DEBUG
22 #define _CRTDBG_MAP_ALLOC
23 #include <stdlib.h>  // Must be included first
24 #include <crtdbg.h>
25 #endif
26 //MEM
27
28 #include "mj2_to_metadata.h"
29 #include <string.h>
30 #ifndef DONT_HAVE_GETOPT
31 #include <getopt.h>
32 #else
33 #include "compat/getopt.h"
34 #endif
35
36 /* ------------- */
37
38 void help_display()
39 {
40   /*             "1234567890123456789012345678901234567890123456789012345678901234567890123456789" */
41   fprintf(stdout,"                Help for the 'mj2_to_metadata' Program\n");
42   fprintf(stdout,"                ======================================\n");
43   fprintf(stdout,"The -h option displays this information on screen.\n\n");
44   
45   fprintf(stdout,"mj2_to_metadata generates an XML file from a Motion JPEG 2000 file.\n");
46   fprintf(stdout,"The generated XML shows the structural, but not (yet) curatorial,\n");
47   fprintf(stdout,"metadata from the movie header and from the JPEG 2000 image and tile\n");
48   fprintf(stdout,"headers of a sample frame.  Excluded: low-level packed-bits image data.\n\n");
49
50   fprintf(stdout,"By Default\n");
51   fprintf(stdout,"----------\n");
52   fprintf(stdout,"The metadata includes the jp2 image and tile headers of the first frame.\n");
53   fprintf(stdout,"\n");
54   fprintf(stdout,"Metadata values are shown in 'raw' form (e.g., hexidecimal) as stored in the\n");
55   fprintf(stdout,"file, and, if apt, in a 'derived' form that is more quickly grasped.\n");
56   fprintf(stdout,"\n");
57   fprintf(stdout,"Notes explaining the XML are embedded as terse comments.  These include\n");
58   fprintf(stdout,"   meaning of non-obvious tag abbreviations;\n");
59   fprintf(stdout,"   range and precision of valid values;\n");
60   fprintf(stdout,"   interpretations of values, such as enumerations; and\n");
61   fprintf(stdout,"   current implementation limitations.\n");
62   fprintf(stdout,"\n");
63   fprintf(stdout,"The sample-size and chunk-offset tables, each with 1 row per frame, are not reported.\n");
64   fprintf(stdout,"\n");
65   fprintf(stdout,"The file is self-contained and no verification (e.g., against a DTD) is requested.\n");
66   fprintf(stdout,"\n");
67   fprintf(stdout,"Required Parameters (except with -h)\n");
68   fprintf(stdout,"------------------------------------\n");
69   fprintf(stdout,"[Caution: file strings that contain spaces should be wrapped with quotes.]\n");
70   fprintf(stdout,"-i input.mj2  : where 'input' is any source file name or path.\n");
71   fprintf(stdout,"                MJ2 files created with 'frames_to_mj2' are supported so far.\n");
72   fprintf(stdout,"                These are silent, single-track, 'MJ2 Simple Profile' videos.\n");
73   fprintf(stdout,"-o output.xml : where 'output' is any destination file name or path.\n");
74   fprintf(stdout,"\n");
75   fprintf(stdout,"Optional Parameters\n");
76   fprintf(stdout,"-------------------\n");
77   fprintf(stdout,"-h            : Display this help information.\n");
78   fprintf(stdout,"-n            : Suppress all mj2_to_metadata notes.\n");
79   fprintf(stdout,"-t            : Include sample-size and chunk-offset tables.\n");
80   fprintf(stdout,"-f n          : where n > 0.  Include jp2 header info for frame n [default=1].\n");
81   fprintf(stdout,"-f 0          : No jp2 header info.\n");
82   fprintf(stdout,"-r            : Suppress all 'raw' data for which a 'derived' form exists.\n");
83   fprintf(stdout,"-d            : Suppress all 'derived' data.\n");
84   fprintf(stdout,"                (If both -r and -d given, -r will be ignored.)\n");
85   fprintf(stdout,"-v string     : Verify against the DTD file located by the string.\n");
86   fprintf(stdout,"                Prepend quoted 'string' with either SYSTEM or PUBLIC keyword.\n");
87   fprintf(stdout,"                Thus, for the distributed DTD placed in the same directory as\n");
88   fprintf(stdout,"                the output file: -v \"SYSTEM mj2_to_metadata.dtd\"\n");
89   fprintf(stdout,"                \"PUBLIC\" is used with an access protocol (e.g., http:) + URL.\n");
90   /* More to come */
91   fprintf(stdout,"\n");
92   /*             "1234567890123456789012345678901234567890123456789012345678901234567890123456789" */
93 }
94
95 /* ------------- */
96
97 int main(int argc, char *argv[]) {
98
99   FILE *file, *xmlout;
100 /*  char xmloutname[50]; */
101   mj2_movie_t movie;
102
103   char* infile = 0;
104   char* outfile = 0;
105   char* s, S1, S2, S3;
106   int len;
107   unsigned int sampleframe = 1; /* First frame */
108   char* stringDTD = NULL;
109   BOOL notes = TRUE;
110   BOOL sampletables = FALSE;
111   BOOL raw = TRUE;
112   BOOL derived = TRUE;
113
114 #ifndef NO_PACKETS_DECODING
115   fprintf(stdout,"WARNING:  For best performance, define NO_PACKETS_DECODING in preprocessing.\n");
116 #endif
117
118   while (TRUE) {
119         /* ':' after letter means it takes an argument */
120     int c = getopt(argc, argv, "i:o:f:v:hntrd");
121         /* FUTURE:  Reserve 'p' for pruning file (which will probably make -t redundant) */
122     if (c == -1)
123       break;
124     switch (c) {
125     case 'i':                   /* IN file */
126       infile = optarg;
127       s = optarg;
128       while (*s) { s++; } /* Run to filename end */
129       s--;
130       S3 = *s;
131       s--;
132       S2 = *s;
133       s--;
134       S1 = *s;
135       
136       if ((S1 == 'm' && S2 == 'j' && S3 == '2')
137       || (S1 == 'M' && S2 == 'J' && S3 == '2')) {
138        break;
139       }
140       fprintf(stderr, "Input file name must have .mj2 extension, not .%c%c%c.\n", S1, S2, S3);
141       return 1;
142
143       /* ----------------------------------------------------- */
144     case 'o':                   /* OUT file */
145       outfile = optarg;
146       while (*outfile) { outfile++; } /* Run to filename end */
147       outfile--;
148       S3 = *outfile;
149       outfile--;
150       S2 = *outfile;
151       outfile--;
152       S1 = *outfile;
153       
154       outfile = optarg;
155       
156       if ((S1 == 'x' && S2 == 'm' && S3 == 'l')
157           || (S1 == 'X' && S2 == 'M' && S3 == 'L'))
158         break;
159     
160       fprintf(stderr,
161           "Output file name must have .xml extension, not .%c%c%c\n", S1, S2, S3);
162           return 1;
163
164       /* ----------------------------------------------------- */
165     case 'f':                   /* Choose sample frame.  0 = none */
166       sscanf(optarg, "%u", &sampleframe);
167       break;
168
169       /* ----------------------------------------------------- */
170     case 'v':                   /* Verification by DTD. */
171       stringDTD = optarg;
172           /* We will not insist upon last 3 chars being "dtd", since non-file
173           access protocol may be used. */
174           if(strchr(stringDTD,'"') != NULL) {
175         fprintf(stderr, "-D's string must not contain any embedded double-quote characters.\n");
176             return 1;
177           }
178
179       if (strncmp(stringDTD,"PUBLIC ",7) == 0 || strncmp(stringDTD,"SYSTEM ",7) == 0)
180         break;
181     
182       fprintf(stderr, "-D's string must start with \"PUBLIC \" or \"SYSTEM \"\n");
183           return 1;
184
185     /* ----------------------------------------------------- */
186     case 'n':                   /* Suppress comments */
187       notes = FALSE;
188       break;
189
190     /* ----------------------------------------------------- */
191     case 't':                   /* Show sample size and chunk offset tables */
192       sampletables = TRUE;
193       break;
194
195     /* ----------------------------------------------------- */
196     case 'h':                   /* Display an help description */
197       help_display();
198       return 0;
199
200     /* ----------------------------------------------------- */
201     case 'r':                   /* Suppress raw data */
202       raw = FALSE;
203       break;
204
205     /* ----------------------------------------------------- */
206     case 'd':                   /* Suppress derived data */
207       derived = FALSE;
208       break;
209
210    /* ----------------------------------------------------- */
211     default:
212       return 1;
213     } /* switch */
214   } /* while */
215
216   if(!raw && !derived)
217           raw = TRUE; /* At least one of 'raw' and 'derived' must be true */
218
219     /* Error messages */
220   /* -------------- */
221   if (!infile || !outfile) {
222     fprintf(stderr,"Correct usage: mj2_to_metadata -i mj2-file -o xml-file (plus options)\n");
223     return 1;
224   }
225
226 /* was:
227   if (argc != 3) {
228     printf("Bad syntax: Usage: MJ2_to_metadata inputfile.mj2 outputfile.xml\n"); 
229     printf("Example: MJ2_to_metadata foreman.mj2 foreman.xml\n");
230     return 1;
231   }
232 */
233   len = strlen(infile);
234   if(infile[0] == ' ')
235   {
236     infile++; /* There may be a leading blank if user put space after -i */
237   }
238   
239   file = fopen(infile, "rb"); /* was: argv[1] */
240   
241   if (!file) {
242     fprintf(stderr, "Failed to open %s for reading.\n", infile); /* was: argv[1] */
243     return 1;
244   }
245
246   len = strlen(outfile);
247   if(outfile[0] == ' ')
248   {
249     outfile++; /* There may be a leading blank if user put space after -o */
250   }
251
252   // Checking output file
253   xmlout = fopen(outfile, "w"); /* was: argv[2] */
254   if (!xmlout) {
255     fprintf(stderr, "Failed to open %s for writing.\n", outfile); /* was: argv[2] */
256     return 1;
257   }
258   // Leave it open
259
260   if (mj2_read_struct(file, &movie)) // Creating the movie structure
261   {
262     fclose(xmlout);
263     return 1;
264   }
265
266   xml_write_init(notes, sampletables, raw, derived);
267   xml_write_struct(file, xmlout, &movie, sampleframe, stringDTD);
268   fclose(xmlout);
269
270   mj2_memory_free(&movie);
271
272   //MEMORY LEAK
273   #ifdef _DEBUG
274     _CrtDumpMemoryLeaks();
275   #endif
276   //MEM
277
278   return 0;
279 }
280
281