File: mj2_to_metadata.c

package info (click to toggle)
gdcm 2.4.4-3%2Bdeb8u1
  • links: PTS, VCS
  • area: main
  • in suites: jessie
  • size: 32,912 kB
  • ctags: 52,166
  • sloc: cpp: 188,527; ansic: 124,526; xml: 41,799; sh: 7,162; python: 3,667; cs: 2,128; java: 1,344; lex: 1,290; tcl: 677; php: 128; makefile: 116
file content (312 lines) | stat: -rw-r--r-- 10,944 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
/* mj2_to_metadata.c */
/* Dump MJ2, JP2 metadata (partial so far) to xml file */
/* Contributed to Open JPEG by Glenn Pearson, contract software developer, U.S. National Library of Medicine.

The base code in this file was developed by the author as part of a video archiving
project for the U.S. National Library of Medicine, Bethesda, MD. 
It is the policy of NLM (and U.S. government) to not assert copyright.

A non-exclusive copy of this code has been contributed to the Open JPEG project.
Except for copyright, inclusion of the code within Open JPEG for distribution and use
can be bound by the Open JPEG open-source license and disclaimer, expressed elsewhere.
*/

#include "../libopenjpeg/opj_includes.h"
#include "mj2.h"

#include "mj2_to_metadata.h"
#include <string.h>
#include "getopt.h"

/* -------------------------------------------------------------------------- */

/**
sample error callback expecting a FILE* client object
*/
void error_callback(const char *msg, void *client_data) {
	FILE *stream = (FILE*)client_data;
	fprintf(stream, "[ERROR] %s", msg);
}
/**
sample warning callback expecting a FILE* client object
*/
void warning_callback(const char *msg, void *client_data) {
	FILE *stream = (FILE*)client_data;
	fprintf(stream, "[WARNING] %s", msg);
}
/**
sample debug callback expecting a FILE* client object
*/
void info_callback(const char *msg, void *client_data) {
	FILE *stream = (FILE*)client_data;
	fprintf(stream, "[INFO] %s", msg);
}

/* -------------------------------------------------------------------------- */



/* ------------- */

void help_display()
{
  /*             "1234567890123456789012345678901234567890123456789012345678901234567890123456789" */
  fprintf(stdout,"                Help for the 'mj2_to_metadata' Program\n");
  fprintf(stdout,"                ======================================\n");
  fprintf(stdout,"The -h option displays this information on screen.\n\n");
  
  fprintf(stdout,"mj2_to_metadata generates an XML file from a Motion JPEG 2000 file.\n");
  fprintf(stdout,"The generated XML shows the structural, but not (yet) curatorial,\n");
  fprintf(stdout,"metadata from the movie header and from the JPEG 2000 image and tile\n");
  fprintf(stdout,"headers of a sample frame.  Excluded: low-level packed-bits image data.\n\n");

  fprintf(stdout,"By Default\n");
  fprintf(stdout,"----------\n");
  fprintf(stdout,"The metadata includes the jp2 image and tile headers of the first frame.\n");
  fprintf(stdout,"\n");
  fprintf(stdout,"Metadata values are shown in 'raw' form (e.g., hexidecimal) as stored in the\n");
  fprintf(stdout,"file, and, if apt, in a 'derived' form that is more quickly grasped.\n");
  fprintf(stdout,"\n");
  fprintf(stdout,"Notes explaining the XML are embedded as terse comments.  These include\n");
  fprintf(stdout,"   meaning of non-obvious tag abbreviations;\n");
  fprintf(stdout,"   range and precision of valid values;\n");
  fprintf(stdout,"   interpretations of values, such as enumerations; and\n");
  fprintf(stdout,"   current implementation limitations.\n");
  fprintf(stdout,"\n");
  fprintf(stdout,"The sample-size and chunk-offset tables, each with 1 row per frame, are not reported.\n");
  fprintf(stdout,"\n");
  fprintf(stdout,"The file is self-contained and no verification (e.g., against a DTD) is requested.\n");
  fprintf(stdout,"\n");
  fprintf(stdout,"Required Parameters (except with -h)\n");
  fprintf(stdout,"------------------------------------\n");
  fprintf(stdout,"[Caution: file strings that contain spaces should be wrapped with quotes.]\n");
  fprintf(stdout,"-i input.mj2  : where 'input' is any source file name or path.\n");
  fprintf(stdout,"                MJ2 files created with 'frames_to_mj2' are supported so far.\n");
  fprintf(stdout,"                These are silent, single-track, 'MJ2 Simple Profile' videos.\n");
  fprintf(stdout,"-o output.xml : where 'output' is any destination file name or path.\n");
  fprintf(stdout,"\n");
  fprintf(stdout,"Optional Parameters\n");
  fprintf(stdout,"-------------------\n");
  fprintf(stdout,"-h            : Display this help information.\n");
  fprintf(stdout,"-n            : Suppress all mj2_to_metadata notes.\n");
  fprintf(stdout,"-t            : Include sample-size and chunk-offset tables.\n");
  fprintf(stdout,"-f n          : where n > 0.  Include jp2 header info for frame n [default=1].\n");
  fprintf(stdout,"-f 0          : No jp2 header info.\n");
  fprintf(stdout,"-r            : Suppress all 'raw' data for which a 'derived' form exists.\n");
  fprintf(stdout,"-d            : Suppress all 'derived' data.\n");
  fprintf(stdout,"                (If both -r and -d given, -r will be ignored.)\n");
  fprintf(stdout,"-v string     : Verify against the DTD file located by the string.\n");
  fprintf(stdout,"                Prepend quoted 'string' with either SYSTEM or PUBLIC keyword.\n");
  fprintf(stdout,"                Thus, for the distributed DTD placed in the same directory as\n");
  fprintf(stdout,"                the output file: -v \"SYSTEM mj2_to_metadata.dtd\"\n");
  fprintf(stdout,"                \"PUBLIC\" is used with an access protocol (e.g., http:) + URL.\n");
  /* More to come */
  fprintf(stdout,"\n");
  /*             "1234567890123456789012345678901234567890123456789012345678901234567890123456789" */
}

/* ------------- */

int main(int argc, char *argv[]) {

	opj_dinfo_t* dinfo; 
	opj_event_mgr_t event_mgr;		/* event manager */

  FILE *file, *xmlout;
/*  char xmloutname[50]; */
  opj_mj2_t *movie;

  char* infile = 0;
  char* outfile = 0;
  char* s, S1, S2, S3;
  int len;
  unsigned int sampleframe = 1; /* First frame */
  char* stringDTD = NULL;
  BOOL notes = TRUE;
  BOOL sampletables = FALSE;
  BOOL raw = TRUE;
  BOOL derived = TRUE;
	mj2_dparameters_t parameters;

  while (TRUE) {
	/* ':' after letter means it takes an argument */
    int c = getopt(argc, argv, "i:o:f:v:hntrd");
	/* FUTURE:  Reserve 'p' for pruning file (which will probably make -t redundant) */
    if (c == -1)
      break;
    switch (c) {
    case 'i':			/* IN file */
      infile = optarg;
      s = optarg;
      while (*s) { s++; } /* Run to filename end */
      s--;
      S3 = *s;
      s--;
      S2 = *s;
      s--;
      S1 = *s;
      
      if ((S1 == 'm' && S2 == 'j' && S3 == '2')
      || (S1 == 'M' && S2 == 'J' && S3 == '2')) {
       break;
      }
      fprintf(stderr, "Input file name must have .mj2 extension, not .%c%c%c.\n", S1, S2, S3);
      return 1;

      /* ----------------------------------------------------- */
    case 'o':			/* OUT file */
      outfile = optarg;
      while (*outfile) { outfile++; } /* Run to filename end */
      outfile--;
      S3 = *outfile;
      outfile--;
      S2 = *outfile;
      outfile--;
      S1 = *outfile;
      
      outfile = optarg;
      
      if ((S1 == 'x' && S2 == 'm' && S3 == 'l')
	  || (S1 == 'X' && S2 == 'M' && S3 == 'L'))
        break;
    
      fprintf(stderr,
	  "Output file name must have .xml extension, not .%c%c%c\n", S1, S2, S3);
	  return 1;

      /* ----------------------------------------------------- */
    case 'f':			/* Choose sample frame.  0 = none */
      sscanf(optarg, "%u", &sampleframe);
      break;

      /* ----------------------------------------------------- */
    case 'v':			/* Verification by DTD. */
      stringDTD = optarg;
	  /* We will not insist upon last 3 chars being "dtd", since non-file
	  access protocol may be used. */
	  if(strchr(stringDTD,'"') != NULL) {
        fprintf(stderr, "-D's string must not contain any embedded double-quote characters.\n");
	    return 1;
	  }

      if (strncmp(stringDTD,"PUBLIC ",7) == 0 || strncmp(stringDTD,"SYSTEM ",7) == 0)
        break;
    
      fprintf(stderr, "-D's string must start with \"PUBLIC \" or \"SYSTEM \"\n");
	  return 1;

    /* ----------------------------------------------------- */
    case 'n':			/* Suppress comments */
      notes = FALSE;
      break;

    /* ----------------------------------------------------- */
    case 't':			/* Show sample size and chunk offset tables */
      sampletables = TRUE;
      break;

    /* ----------------------------------------------------- */
    case 'h':			/* Display an help description */
      help_display();
      return 0;

    /* ----------------------------------------------------- */
    case 'r':			/* Suppress raw data */
      raw = FALSE;
      break;

    /* ----------------------------------------------------- */
    case 'd':			/* Suppress derived data */
      derived = FALSE;
      break;

   /* ----------------------------------------------------- */
    default:
      return 1;
    } /* switch */
  } /* while */

  if(!raw && !derived)
	  raw = TRUE; /* At least one of 'raw' and 'derived' must be true */

    /* Error messages */
  /* -------------- */
  if (!infile || !outfile) {
    fprintf(stderr,"Correct usage: mj2_to_metadata -i mj2-file -o xml-file (plus options)\n");
    return 1;
  }

/* was:
  if (argc != 3) {
    printf("Bad syntax: Usage: MJ2_to_metadata inputfile.mj2 outputfile.xml\n"); 
    printf("Example: MJ2_to_metadata foreman.mj2 foreman.xml\n");
    return 1;
  }
*/
  len = strlen(infile);
  if(infile[0] == ' ')
  {
    infile++; /* There may be a leading blank if user put space after -i */
  }
  
  file = fopen(infile, "rb"); /* was: argv[1] */
  
  if (!file) {
    fprintf(stderr, "Failed to open %s for reading.\n", infile); /* was: argv[1] */
    return 1;
  }

  len = strlen(outfile);
  if(outfile[0] == ' ')
  {
    outfile++; /* There may be a leading blank if user put space after -o */
  }

  // Checking output file
  xmlout = fopen(outfile, "w"); /* was: argv[2] */
  if (!xmlout) {
    fprintf(stderr, "Failed to open %s for writing.\n", outfile); /* was: argv[2] */
    return 1;
  }
  // Leave it open

	/*
	configure the event callbacks (not required)
	setting of each callback is optionnal
	*/
	memset(&event_mgr, 0, sizeof(opj_event_mgr_t));
	event_mgr.error_handler = error_callback;
	event_mgr.warning_handler = warning_callback;
	event_mgr.info_handler = info_callback;

	/* get a MJ2 decompressor handle */
	dinfo = mj2_create_decompress();

	/* catch events using our callbacks and give a local context */
	opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr);		

	/* setup the decoder decoding parameters using user parameters */
	movie = (opj_mj2_t*) dinfo->mj2_handle;
	mj2_setup_decoder(dinfo->mj2_handle, &parameters);

  if (mj2_read_struct(file, movie)) // Creating the movie structure
  {
    fclose(xmlout);
    return 1;
  }

  xml_write_init(notes, sampletables, raw, derived);
  xml_write_struct(file, xmlout, movie, sampleframe, stringDTD, &event_mgr);
  fclose(xmlout);

	fprintf(stderr,"Metadata correctly extracted to XML file \n");;	

	/* free remaining structures */
	if(dinfo) {
		mj2_destroy_decompress((opj_mj2_t*)dinfo->mj2_handle);
	}

  return 0;
}