1 /* meta_out.c */
2 /* Dump MJ2, JP2 metadata (partial so far) to xml file */
3 /* Callable from mj2_to_metadata */
4 /* Contributed to Open JPEG by Glenn Pearson, contract software developer, U.S. National Library of Medicine.
5
6 The base code in this file was developed by the author as part of a video archiving
7 project for the U.S. National Library of Medicine, Bethesda, MD.
8 It is the policy of NLM (and U.S. government) to not assert copyright.
9
10 A non-exclusive copy of this code has been contributed to the Open JPEG project.
11 Except for copyright, inclusion of the code within Open JPEG for distribution and use
12 can be bound by the Open JPEG open-source license and disclaimer, expressed elsewhere.
13 */
14
15 #include <windows.h> /* for time functions */
16
17 #include "opj_includes.h"
18 #include "mj2.h"
19
20 #include <time.h>
21 #include "meta_out.h"
22
23 static BOOL notes = TRUE;
24 static BOOL sampletables = FALSE;
25 static BOOL raw = TRUE;
26 static BOOL derived = TRUE;
27
28 opj_tcp_t *j2k_default_tcp;
29
30 /* Forwards */
31 int xml_write_overall_header(FILE *file, FILE *xmlout, opj_mj2_t * movie, unsigned int sampleframe, opj_event_mgr_t *event_mgr);
32 int xml_write_moov(FILE *file, FILE *xmlout, opj_mj2_t * movie, unsigned int sampleframe, opj_event_mgr_t *event_mgr);
33
34 void uint_to_chars(unsigned int value, char* buf);
35
36 void xml_write_trak(FILE* file, FILE* xmlout, mj2_tk_t *track, unsigned int tnum, unsigned int sampleframe, opj_event_mgr_t *event_mgr);
37 void xml_write_tkhd(FILE* file, FILE* xmlout, mj2_tk_t *track, unsigned int tnum);
38 void xml_write_udta(FILE* file, FILE* xmlout, mj2_tk_t *track, unsigned int tnum);
39 void xml_write_mdia(FILE* file, FILE* xmlout, mj2_tk_t *track, unsigned int tnum);
40 void xml_write_stbl(FILE* file, FILE* xmlout, mj2_tk_t *track, unsigned int tnum);
41
42 void UnixTimeToFileTime(time_t t, LPFILETIME pft);
43 void UnixTimeToSystemTime(time_t t, LPSYSTEMTIME pst);
44 void xml_time_out(FILE* xmlout, time_t t);
45
46 void int16_to_3packedchars(short int value, char* buf);
47
48 void xml_write_moov_udta(FILE* xmlout, opj_mj2_t * movie);
49 void xml_write_free_and_skip(FILE* xmlout, opj_mj2_t * movie);
50 void xml_write_uuid(FILE* xmlout, opj_mj2_t * movie);
51
52 int xml_out_frame(FILE* file, FILE* xmlout, mj2_sample_t *sample, unsigned int snum, opj_event_mgr_t *event_mgr);
53
54 void xml_out_frame_siz(FILE* xmlout, opj_image_t *img, opj_cp_t *cp);
55 void xml_out_frame_cod(FILE* xmlout, opj_tcp_t *tcp);
56 void xml_out_frame_coc(FILE* xmlout, opj_tcp_t *tcp, int numcomps); /* opj_image_t *img); */
57 BOOL same_component_style(opj_tccp_t *tccp1, opj_tccp_t *tccp2);
58 void xml_out_frame_qcd(FILE* xmlout, opj_tcp_t *tcp);
59 void xml_out_frame_qcc(FILE* xmlout, opj_tcp_t *tcp, int numcomps); /* opj_image_t *img); */
60 BOOL same_component_quantization(opj_tccp_t *tccp1, opj_tccp_t *tccp2);
61 void xml_out_frame_rgn(FILE* xmlout, opj_tcp_t *tcp, int numcomps);/* opj_image_t *img);*/
62 void xml_out_frame_poc(FILE* xmlout, opj_tcp_t *tcp);
63 void xml_out_frame_ppm(FILE* xmlout, opj_cp_t *cp);
64 void xml_out_frame_ppt(FILE* xmlout, opj_tcp_t *tcp);
65 void xml_out_frame_tlm(FILE* xmlout); /* j2k_default_tcp is passed globally */ /* NO-OP. TLM NOT SAVED IN DATA STRUCTURE */
66 void xml_out_frame_plm(FILE* xmlout); /* j2k_default_tcp is passed globally */ /* NO-OP. PLM NOT SAVED IN DATA STRUCTURE. opt in main; can be used in conjunction with PLT */
67 void xml_out_frame_plt(FILE* xmlout, opj_tcp_t *tcp); /* NO-OP. PLM NOT SAVED IN DATA STRUCTURE. opt in main; can be used in conjunction with PLT */
68 void xml_out_frame_crg(FILE* xmlout); /* j2k_default_tcp is passed globally */ /* opt in main; */
69 void xml_out_frame_com(FILE* xmlout, opj_tcp_t *tcp); /* NO-OP. COM NOT SAVED IN DATA STRUCTURE */ /* opt in main; */
70 void xml_out_dump_hex(FILE* xmlout, char *data, int data_len, char* s);
71 void xml_out_dump_hex_and_ascii(FILE* xmlout, char *data, int data_len, char* s);
72 void xml_out_frame_jp2h(FILE* xmlout, opj_jp2_t *jp2_struct);
73 #ifdef NOTYET
74 /* Shown with cp, extended, as data structure... but it could be a new different one */
75 void xml_out_frame_jp2i(FILE* xmlout, opj_cp_t *cp);/* IntellectualProperty 'jp2i' (no restrictions on location) */
76 void xml_out_frame_xml(FILE* xmlout, opj_cp_t *cp); /* XML 'xml\040' (0x786d6c20). Can appear multiply */
77 void xml_out_frame_uuid(FILE* xmlout, opj_cp_t *cp); /* UUID 'uuid' (top level only) */
78 void xml_out_frame_uinf(FILE* xmlout, opj_cp_t *cp); /* UUIDInfo 'uinf', includes UUIDList 'ulst' and URL 'url\40' */
79 void xml_out_frame_unknown_type(FILE* xmlout, opj_cp_t *cp);
80 #endif
81
82
xml_write_init(BOOL n,BOOL t,BOOL r,BOOL d)83 void xml_write_init(BOOL n, BOOL t, BOOL r, BOOL d)
84 {
85 /* Init file globals */
86 notes = n;
87 sampletables = t;
88 raw = r;
89 derived = d;
90 }
91
xml_write_struct(FILE * file,FILE * xmlout,opj_mj2_t * movie,unsigned int sampleframe,char * stringDTD,opj_event_mgr_t * event_mgr)92 int xml_write_struct(FILE* file, FILE *xmlout, opj_mj2_t * movie, unsigned int sampleframe, char* stringDTD, opj_event_mgr_t *event_mgr) {
93
94 if(stringDTD != NULL)
95 {
96 fprintf(xmlout,"<?xml version=\"1.0\" standalone=\"no\"?>\n");
97 /* stringDTD is known to start with "SYSTEM " or "PUBLIC " */
98 /* typical: SYSTEM mj2_to_metadata.dtd */
99 stringDTD[6] = '\0'; /* Break into two strings at space, so quotes can be inserted. */
100 fprintf(xmlout,"<!DOCTYPE MJ2_File %s \"%s\">\n", stringDTD, stringDTD+7);
101 stringDTD[6] = ' '; /* restore for sake of debugger or memory allocator */
102 } else
103 fprintf(xmlout,"<?xml version=\"1.0\" standalone=\"yes\"?>\n");
104
105 fprintf(xmlout, "<MJ2_File>\n");
106 xml_write_overall_header(file, xmlout, movie, sampleframe, event_mgr);
107 fprintf(xmlout, "</MJ2_File>");
108 return 0;
109 }
110
111 /* ------------- */
112
xml_write_overall_header(FILE * file,FILE * xmlout,opj_mj2_t * movie,unsigned int sampleframe,opj_event_mgr_t * event_mgr)113 int xml_write_overall_header(FILE *file, FILE *xmlout, opj_mj2_t * movie, unsigned int sampleframe, opj_event_mgr_t *event_mgr)
114 {
115 int i;
116 char buf[5];
117 buf[4] = '\0';
118
119 fprintf(xmlout, " <JP2 BoxType=\"jP[space][space]\" Signature=\"0x0d0a870a\" />\n");
120 // Called after structure initialized by mj2_read_ftyp
121 fprintf(xmlout, " <FileType BoxType=\"ftyp\">\n");
122 uint_to_chars(movie->brand, buf);
123 fprintf(xmlout, " <Brand>%s</Brand>\n", buf); /* 4 character; BR */
124 fprintf(xmlout, " <MinorVersion>%u</MinorVersion>\n", movie->minversion); /* 4 char; MinV */
125 fprintf(xmlout, " <CompatibilityList Count=\"%d\">\n",movie->num_cl);
126 for (i = movie->num_cl - 1; i > -1; i--) /* read routine stored in reverse order, so let's undo damage */
127 {
128 uint_to_chars(movie->cl[i], buf);
129 fprintf(xmlout, " <CompatibleBrand>%s</CompatibleBrand>\n", buf); /*4 characters, each CLi */
130 }
131 fprintf(xmlout, " </CompatibilityList>\n");
132 fprintf(xmlout, " </FileType>\n");
133 xml_write_moov(file, xmlout, movie, sampleframe, event_mgr);
134 // To come? <mdat> // This is the container for media data that can also be accessed through track structures,
135 // so is redundant, and simply not of interest as metadata
136 // <moof> // Allows incremental build up of movie. Probably not in Simple Profile
137 xml_write_free_and_skip(xmlout, movie); /* NO OP so far */ /* May be a place where user squirrels metadata */
138 xml_write_uuid(xmlout, movie); /* NO OP so far */ /* May be a place where user squirrels metadata */
139 return 0;
140 }
141
142 /* ------------- */
143
xml_write_moov(FILE * file,FILE * xmlout,opj_mj2_t * movie,unsigned int sampleframe,opj_event_mgr_t * event_mgr)144 int xml_write_moov(FILE *file, FILE *xmlout, opj_mj2_t * movie, unsigned int sampleframe, opj_event_mgr_t *event_mgr)
145 {
146 unsigned int tnum;
147 mj2_tk_t *track;
148
149 fprintf(xmlout, " <MovieBox BoxType=\"moov\">\n");
150 fprintf(xmlout, " <MovieHeader BoxType=\"mvhd\">\n");
151 fprintf(xmlout, " <CreationTime>\n");
152 if(raw)
153 fprintf(xmlout, " <InSeconds>%u</InSeconds>\n", movie->creation_time);
154 if(notes)
155 fprintf(xmlout, " <!-- Seconds since start of Jan. 1, 1904 UTC (Greenwich) -->\n");
156 /* 2082844800 = seconds between 1/1/04 and 1/1/70 */
157 /* There's still a time zone offset problem not solved... but spec is ambigous as to whether stored time
158 should be local or UTC */
159 if(derived) {
160 fprintf(xmlout, " <AsLocalTime>");
161 xml_time_out(xmlout, movie->creation_time - 2082844800);
162 fprintf(xmlout,"</AsLocalTime>\n");
163 }
164 fprintf(xmlout, " </CreationTime>\n");
165 fprintf(xmlout, " <ModificationTime>\n");
166 if(raw)
167 fprintf(xmlout, " <InSeconds>%u</InSeconds>\n", movie->modification_time);
168 if(derived) {
169 fprintf(xmlout, " <AsLocalTime>");
170 xml_time_out(xmlout, movie->modification_time - 2082844800);
171 fprintf(xmlout,"</AsLocalTime>\n");
172 }
173 fprintf(xmlout, " </ModificationTime>\n");
174 fprintf(xmlout, " <Timescale>%d</Timescale>\n", movie->timescale);
175 if(notes)
176 fprintf(xmlout, " <!-- Timescale defines time units in one second -->\n");
177 fprintf(xmlout, " <Rate>\n"); /* Rate to play presentation (default = 0x00010000) */
178 if(notes) {
179 fprintf(xmlout, " <!-- Rate to play presentation is stored as fixed-point binary 16.16 value. Decimal value is approximation. -->\n");
180 fprintf(xmlout, " <!-- Rate is expressed relative to normal (default) value of 0x00010000 (1.0) -->\n");
181 }
182 if(raw)
183 fprintf(xmlout, " <AsHex>0x%08x</AsHex>\n", movie->rate);
184 if(derived)
185 fprintf(xmlout, " <AsDecimal>%12.6f</AsDecimal>\n", (double)movie->rate/(double)0x00010000);
186 fprintf(xmlout, " </Rate>\n");
187 fprintf(xmlout, " <Duration>\n");
188 if(raw)
189 fprintf(xmlout, " <InTimeUnits>%u</InTimeUnits>\n", movie->duration);
190 if(derived)
191 fprintf(xmlout, " <InSeconds>%12.3f</InSeconds>\n", (double)movie->duration/(double)movie->timescale); // Make this double later to get fractional seconds
192 fprintf(xmlout, " </Duration>\n");
193 #ifdef CURRENTSTRUCT
194 movie->volume = movie->volume << 8;
195 #endif
196 fprintf(xmlout, " <Volume>\n");
197 if(notes) {
198 fprintf(xmlout, " <!-- Audio volume stored as fixed-point binary 8.8 value. Decimal value is approximation. -->\n");
199 fprintf(xmlout, " <!-- Full, normal (default) value is 0x0100 (1.0) -->\n");
200 }
201 if(raw)
202 fprintf(xmlout, " <AsHex>0x%04x</AsHex>\n", movie->volume);
203 if(derived)
204 fprintf(xmlout, " <AsDecimal>%6.3f</AsDecimal>\n", (double)movie->volume/(double)0x0100);
205 fprintf(xmlout, " </Volume>\n");
206 #ifdef CURRENTSTRUCT
207 if(notes)
208 fprintf(xmlout, " <!-- Current m2j_to_metadata implementation always shows bits to right of decimal as zeroed. -->\n");
209 movie->volume = movie->volume >> 8;
210 #endif
211 /* Transformation matrix for video */
212 fprintf(xmlout, " <TransformationMatrix>\n");
213 if(notes) {
214 fprintf(xmlout, " <!-- 3 x 3 Video Transformation Matrix {a,b,u,c,d,v,x,y,w}. Required: u=0, v=0, w=1 -->\n");
215 fprintf(xmlout, " <!-- Maps decompressed point (p,q) to rendered point (ap + cq + x, bp + dq + y) -->\n");
216 fprintf(xmlout, " <!-- Stored as Fixed Point Hex: all are binary 16.16, except u,v,w are 2.30 -->\n");
217 fprintf(xmlout, " <!-- Unity = 0x00010000,0,0,0,0x00010000,0,0,0,0x40000000 -->\n");
218 }
219 fprintf(xmlout, " <TMa>0x%08x</TMa>\n", movie->trans_matrix[0]);
220 fprintf(xmlout, " <TMb>0x%08x</TMb>\n", movie->trans_matrix[1]);
221 fprintf(xmlout, " <TMu>0x%08x</TMu>\n", movie->trans_matrix[2]);
222 fprintf(xmlout, " <TMc>0x%08x</TMc>\n", movie->trans_matrix[3]);
223 fprintf(xmlout, " <TMd>0x%08x</TMd>\n", movie->trans_matrix[4]);
224 fprintf(xmlout, " <TMv>0x%08x</TMv>\n", movie->trans_matrix[5]);
225 fprintf(xmlout, " <TMx>0x%08x</TMx>\n", movie->trans_matrix[6]);
226 fprintf(xmlout, " <TMy>0x%08x</TMy>\n", movie->trans_matrix[7]);
227 fprintf(xmlout, " <TMw>0x%08x</TMw>\n", movie->trans_matrix[8]);
228 fprintf(xmlout, " </TransformationMatrix>\n");
229 fprintf(xmlout, " </MovieHeader>\n");
230
231 fprintf(xmlout, " <Statistics>\n");
232 fprintf(xmlout, " <TracksFound>\n");
233 fprintf(xmlout, " <Video>%d</Video>\n", movie->num_vtk);
234 fprintf(xmlout, " <Audio>%d</Audio>\n", movie->num_stk);
235 fprintf(xmlout, " <Hint>%d</Hint>\n", movie->num_htk);
236 if(notes)
237 fprintf(xmlout, " <!-- Hint tracks for streaming video are not part of MJ2, but are a defined extension. -->\n");
238 /* See Part 3 Amend 2 Section 4.2 for relation of MJ2 to Part 12 Sections 7 and 10 hints */
239 fprintf(xmlout, " </TracksFound>\n");
240 fprintf(xmlout, " </Statistics>\n");
241 /* Idea for the future: It would be possible to add code to verify that the file values:
242 1) are legal and self-consistent
243 2) comply with particular JP2 and/or MJ2 profiles.
244 This could be reported here as additional XML elements */
245
246 // Find first video track
247 tnum = 0;
248 while (movie->tk[tnum].track_type != 0)
249 tnum ++;
250
251 track = &(movie->tk[tnum]);
252 // For now, output info on first video track
253 xml_write_trak(file, xmlout, track, tnum, sampleframe, event_mgr);
254
255 // to come: <MovieExtends mvek> // possibly not in Simple Profile
256 xml_write_moov_udta(xmlout, movie); /* NO OP so far */ /* <UserDataBox udta> contains <CopyrightBox cprt> */
257 fprintf(xmlout, " </MovieBox>\n");
258 return 0;
259 }
260
261 /* --------------- */
262
uint_to_chars(unsigned int value,char * buf)263 void uint_to_chars(unsigned int value, char* buf)
264 {
265 /* buf is at least char[5] */
266 int i;
267 for (i = 3; i >= 0; i--)
268 {
269 buf[i] = (value & 0x000000ff);
270 value = (value >> 8);
271 }
272 buf[4] = '\0'; /* Precautionary */
273 }
274
275 /* ------------- */
276
277 /* WINDOWS SPECIFIC */
278
UnixTimeToFileTime(time_t t,LPFILETIME pft)279 void UnixTimeToFileTime(time_t t, LPFILETIME pft)
280 {
281 /* Windows specific. From MS Q167296 */
282 /* 'time_t' represents seconds since midnight January 1, 1970 UTC (coordinated universal time). */
283 /* 64-bit FILETIME structure represents the number of 100-nanosecond intervals since January 1, 1601 UTC (coordinate universal time). */
284 LONGLONG ll; /* LONGLONG is a 64-bit value. */
285 ll = Int32x32To64(t, 10000000) + 116444736000000000;
286 pft->dwLowDateTime = (DWORD)ll;
287 /* pft->dwLowDateTime = (DWORD)(0x00000000ffffffff & ll); */
288 pft->dwHighDateTime = (DWORD)(ll >> 32);
289 }
290 // Once the UNIX time is converted to a FILETIME structure,
291 // other Win32 time formats can be easily obtained by using Win32 functions such
292 // as FileTimeToSystemTime() and FileTimeToDosDateTime().
293
294 /* ------------- */
295
UnixTimeToSystemTime(time_t t,LPSYSTEMTIME pst)296 void UnixTimeToSystemTime(time_t t, LPSYSTEMTIME pst)
297 {
298 /* Windows specific */
299 FILETIME ft;
300 UnixTimeToFileTime(t, &ft);
301 FileTimeToLocalFileTime( &ft, &ft ); /* Adjust from UTC to local time zone */
302 FileTimeToSystemTime(&ft, pst);
303 }
304
305 /* ------------- */
306
xml_time_out(FILE * xmlout,time_t t)307 void xml_time_out(FILE* xmlout, time_t t)
308 {
309 /* Windows specific */
310 SYSTEMTIME st;
311 char szLocalDate[255], szLocalTime[255];
312 UnixTimeToSystemTime( t, &st );
313 GetDateFormat( LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, szLocalDate, 255 );
314 GetTimeFormat( LOCALE_USER_DEFAULT, 0, &st, NULL, szLocalTime, 255 );
315 fprintf(xmlout, "%s %s", szLocalDate, szLocalTime );
316 }
317
318 /* END WINDOWS SPECIFIC */
319
320 /* ------------- */
321
xml_write_moov_udta(FILE * xmlout,opj_mj2_t * movie)322 void xml_write_moov_udta(FILE* xmlout, opj_mj2_t * movie) {
323 /* Compare with xml_write_udta */
324 #ifdef NOTYET
325 /* NO-OP so far. Optional UserData 'udta' (zero or one in moov or each trak)
326 can contain multiple Copyright 'cprt' with different language codes */
327 /* There may be nested non-standard boxes within udta */
328 IMAGINE movie->udta, movie->copyright_count, movie->copyright_language[i] (array of 16bit ints), movie->copyright_notice[i] (array of buffers)
329 PROBABLY ALSO NEED movie->udta_len or special handler for non-standard boxes
330 char buf[5];
331 int i;
332
333 if(movie->udta != 1)
334 return; /* Not present */
335
336 fprintf(xmlout, " <UserData BoxType=\"udta\">\n");
337 for(i = 0; i < movie->copyright_count; i++) {
338 fprintf(xmlout, " <Copyright BoxType=\"cprt\"> Instance=\"%d\">\n", i+1);
339 int16_to_3packedchars((short int)movie->copyright_languages[i], buf);
340 fprintf(xmlout, " <Language>%s</Language>\n", buf); /* 3 chars */
341 fprintf(xmlout, " <Notice>%s</Notice>\n",movie->copyright_notices[i]);
342 fprintf(xmlout, " </Copyright>\n", i+1);
343 }
344 /* TO DO: Non-standard boxes */
345 fprintf(xmlout, " </UserData>\n");
346 #endif
347 }
348
xml_write_free_and_skip(FILE * xmlout,opj_mj2_t * movie)349 void xml_write_free_and_skip(FILE* xmlout, opj_mj2_t * movie) {
350 #ifdef NOTYET
351 /* NO-OP so far. There can be zero or more instances of free and/or skip
352 at the top level of the file. This may be a place where the user squirrel's metadata.
353 Let's assume unstructured, and do a dump */
354 IMAGINE movie->free_and_skip, movie->free_and_skip_count, movie->free_and_skip_content[i] (array of buffers),
355 movie->free_and_skip_len[i] (array of ints), movie->is_skip[i] (array of BOOL)
356 int i;
357
358 if(movie->free_and_skip != 1)
359 return; /* Not present */
360
361 for(i = 0; i < movie->free_and_skip_count; i++) {
362 if(movie->is_skip[i])
363 fprintf(xmlout, " <Skip BoxType=\"skip\">\n");
364 else
365 fprintf(xmlout, " <Free BoxType=\"free\">\n");
366
367 xml_out_dump_hex_and_ascii(xmlout, movie->free_and_skip_contents[i], movie->free_and_skip_len[i]);
368
369 if(movie->is_skip[i])
370 fprintf(xmlout, " </Skip>\n");
371 else
372 fprintf(xmlout, " </Free>\n");
373 }
374 #endif
375 }
376
xml_write_uuid(FILE * xmlout,opj_mj2_t * movie)377 void xml_write_uuid(FILE* xmlout, opj_mj2_t * movie) {
378 /* Univeral Unique IDs of 16 bytes. */
379 #ifdef NOTYET
380 /* NO-OP so far. There can be zero or more instances of private uuid boxes in a file.
381 This function supports the top level of the file, but uuid may be elsewhere [not yet supported].
382 This may be a place where the user squirrel's metadata. Let's assume unstructured, and do a dump */
383 IMAGINE movie->uuid, movie->uuid_count, movie->uuid_content[i] (array of buffers),
384 movie->uuid_len[i] (array of ints), movie->uuid_type[i] (array of 17-byte (16+null termination) buffers)
385 int i;
386
387 if(movie->uuid != 1)
388 return; /* Not present */
389
390 for(i = 0; i < movie->uuid_count; i++) {
391 fprintf(xmlout, " <PrivateExtension BoxType=\"uuid\" UUID=\"%s\">\n", movie->uuid_type[i]);
392 // See Part III section 5.2.1, 6.1, 6.2
393 xml_out_dump_hex_and_ascii(xmlout, movie->uuid_contents[i], movie->uuid_len[i]);
394 fprintf(xmlout, " </PrivateExtension>\n");
395 }
396 #endif
397 }
398
399 /* ------------- */
400
xml_write_trak(FILE * file,FILE * xmlout,mj2_tk_t * track,unsigned int tnum,unsigned int sampleframe,opj_event_mgr_t * event_mgr)401 void xml_write_trak(FILE* file, FILE* xmlout, mj2_tk_t *track, unsigned int tnum, unsigned int sampleframe, opj_event_mgr_t *event_mgr)
402 {
403 fprintf(xmlout, " <Track BoxType=\"trak\" Instance=\"%d\">\n", tnum);
404 xml_write_tkhd(file, xmlout, track, tnum);
405 // TO DO: TrackReferenceContainer 'tref' just used in hint track
406 // TO DO: EditListContainer 'edts', contains EditList 'elst' with media-time, segment-duration, media-rate
407 xml_write_mdia(file, xmlout, track, tnum);
408 xml_write_udta(file, xmlout, track, tnum); // NO-OP so far. Optional UserData 'udta', can contain multiple Copyright 'cprt'
409
410 if(track->track_type==0) { /* Only do for visual track */
411 /* sampleframe is from user option -f. 1 = first frame */
412 /* sampleframe of 0 is a user requests: no jp2 header */
413 /* Treat out-of-bounds values in the same way */
414 if(sampleframe > 0 && sampleframe <= track->num_samples)
415 {
416 mj2_sample_t *sample;
417 unsigned int snum;
418
419 snum = sampleframe-1;
420 // Someday maybe do a smart range scan... for (snum=0; snum < track->num_samples; snum++){
421 // fprintf(stdout,"Frame %d: ",snum+1);
422 sample = &track->sample[snum];
423 if(xml_out_frame(file, xmlout, sample, snum, event_mgr))
424 return; /* Not great error handling here */
425 }
426 }
427 fprintf(xmlout, " </Track>\n");
428 }
429
430 /* ------------- */
431
xml_write_tkhd(FILE * file,FILE * xmlout,mj2_tk_t * track,unsigned int tnum)432 void xml_write_tkhd(FILE* file, FILE* xmlout, mj2_tk_t *track, unsigned int tnum)
433 {
434 fprintf(xmlout, " <TrackHeader BoxType=\"tkhd\">\n");
435 if(notes) {
436 fprintf(xmlout, " <!-- Not shown here: CreationTime, ModificationTime, Duration. -->\n");
437 fprintf(xmlout, " <!-- These 3 fields are reported under MediaHeader below. When reading these 3, -->\n");
438 fprintf(xmlout, " <!-- m2j_to_metadata currently doesn't distinguish between TrackHeader and MediaHeader source. -->\n");
439 fprintf(xmlout, " <!-- If both found, value read from MediaHeader is used. -->\n");
440 }
441 fprintf(xmlout, " <TrackID>%u</TrackID>\n", track->track_ID);
442 if(track->track_type==0) /* For visual track */
443 {
444 fprintf(xmlout, " <TrackLayer>%d</TrackLayer>\n", track->layer);
445 if(notes)
446 fprintf(xmlout," <!-- front-to-back ordering of video tracks. 0 = normal, -1 is closer, etc. -->\n");
447 }
448 if(track->track_type!=0) /* volume irrelevant for visual track */
449 {
450 #ifdef CURRENTSTRUCT
451 track->volume = track->volume << 8;
452 #endif
453 fprintf(xmlout, " <Volume>\n");
454 if(notes) {
455 fprintf(xmlout," <!-- Track audio volume stored as fixed-point binary 8.8 value. Decimal value is approximation. -->\n");
456 fprintf(xmlout," <!-- Full, normal (default) value is 0x0100 (1.0) -->\n");
457 }
458 if(raw)
459 fprintf(xmlout," <AsHex>0x%04x</AsHex>\n", track->volume);
460 if(derived)
461 fprintf(xmlout," <AsDecimal>%6.3f</AsDecimal>\n", (double)track->volume/(double)0x0100);
462 fprintf(xmlout, " </Volume>\n");
463 #ifdef CURRENTSTRUCT
464 if(notes)
465 fprintf(xmlout, " <!-- Current m2j_to_metadata implementation always shows bits to right of decimal as zeroed. -->\n");
466 track->volume = track->volume >> 8;
467 #endif
468 }
469 if(track->track_type==0)
470 {
471 /* Transformation matrix for video */
472 fprintf(xmlout, " <TransformationMatrix>\n");
473 if(notes) {
474 fprintf(xmlout," <!-- Comments about matrix in MovieHeader apply here as well. -->\n");
475 fprintf(xmlout," <!-- This matrix is applied before MovieHeader one. -->\n");
476 }
477 fprintf(xmlout, " <TMa>0x%08x</TMa>\n", track->trans_matrix[0]);
478 fprintf(xmlout, " <TMb>0x%08x</TMb>\n", track->trans_matrix[1]);
479 fprintf(xmlout, " <TMu>0x%08x</TMu>\n", track->trans_matrix[2]);
480 fprintf(xmlout, " <TMc>0x%08x</TMc>\n", track->trans_matrix[3]);
481 fprintf(xmlout, " <TMd>0x%08x</TMd>\n", track->trans_matrix[4]);
482 fprintf(xmlout, " <TMv>0x%08x</TMv>\n", track->trans_matrix[5]);
483 fprintf(xmlout, " <TMx>0x%08x</TMx>\n", track->trans_matrix[6]);
484 fprintf(xmlout, " <TMy>0x%08x</TMy>\n", track->trans_matrix[7]);
485 fprintf(xmlout, " <TMw>0x%08x</TMw>\n", track->trans_matrix[8]);
486 fprintf(xmlout, " </TransformationMatrix>\n");
487 }
488 #ifdef CURRENTSTRUCT
489 track->w = track->w << 16;
490 track->h = track->h << 16;
491 #endif
492 if(notes) {
493 fprintf(xmlout, " <!-- Width and Height in pixels are for the presentation; frames will be scaled to this. -->\n");
494 fprintf(xmlout, " <!-- Both stored as fixed-point binary 16.16 values. Decimal values are approximations. -->\n");
495 }
496 fprintf(xmlout, " <Width>\n");
497 if(raw)
498 fprintf(xmlout, " <AsHex>0x%08x</AsHex>\n", track->w);
499 if(derived)
500 fprintf(xmlout, " <AsDecimal>%12.6f</AsDecimal>\n", (double)track->w/(double)0x00010000); /* Rate to play presentation (default = 0x00010000) */
501 fprintf(xmlout, " </Width>\n");
502 fprintf(xmlout, " <Height>\n");
503 if(raw)
504 fprintf(xmlout, " <AsHex>0x%08x</AsHex>\n", track->h);
505 if(derived)
506 fprintf(xmlout, " <AsDecimal>%12.6f</AsDecimal>\n", (double)track->h/(double)0x00010000); /* Rate to play presentation (default = 0x00010000) */
507 fprintf(xmlout, " </Height>\n");
508 #ifdef CURRENTSTRUCT
509 if(notes) {
510 fprintf(xmlout, " <!-- Current m2j_to_metadata implementation always shows bits to right of decimal as zeroed. -->\n");
511 fprintf(xmlout, " <!-- Also, width and height values shown here will actually be those read from track's <VisualSampleEntry> if given. -->\n");
512 }
513 track->w = track->w >> 16;
514 track->h = track->h >> 16;
515 #endif
516 fprintf(xmlout, " </TrackHeader>\n");
517 }
518
519 /* ------------- */
520
xml_write_udta(FILE * file,FILE * xmlout,mj2_tk_t * track,unsigned int tnum)521 void xml_write_udta(FILE* file, FILE* xmlout, mj2_tk_t *track, unsigned int tnum) {
522 /* NO-OP so far. Optional UserData 'udta' (zero or one in moov or each trak)
523 can contain multiple Copyright 'cprt' with different language codes */
524 /* There may be nested non-standard boxes within udta */
525 #ifdef NOTYET
526 IMAGINE track->udta, track->copyright_count, track->copyright_language[i] (array of 16bit ints), track->copyright_notice[i] (array of buffers)
527 PROBABLY ALSO NEED track->udta_len or special handler for non-standard boxes
528 char buf[5];
529 int i;
530
531 if(track->udta != 1)
532 return; /* Not present */
533
534 fprintf(xmlout, " <UserData BoxType=\"udta\">\n");
535 for(i = 0; i < track->copyright_count; i++) {
536 fprintf(xmlout, " <Copyright BoxType=\"cprt\"> Instance=\"%d\">\n", i+1);
537 int16_to_3packedchars((short int)track->copyright_languages[i], buf);
538 fprintf(xmlout, " <Language>%s</Language>\n", buf); /* 3 chars */
539 fprintf(xmlout, " <Notice>%s</Notice>\n",track->copyright_notices[i]);
540 fprintf(xmlout, " </Copyright>\n", i+1);
541 }
542 /* TO DO: Non-standard boxes */
543 fprintf(xmlout, " </UserData>\n");
544 #endif
545 }
546
547 /* ------------- */
548
xml_write_mdia(FILE * file,FILE * xmlout,mj2_tk_t * track,unsigned int tnum)549 void xml_write_mdia(FILE* file, FILE* xmlout, mj2_tk_t *track, unsigned int tnum)
550 {
551 char buf[5];
552 int i, k;
553 buf[4] = '\0';
554
555 fprintf(xmlout, " <Media BoxType=\"mdia\">\n");
556 fprintf(xmlout, " <MediaHeader BoxType=\"mdhd\">\n");
557 fprintf(xmlout, " <CreationTime>\n");
558 if(raw)
559 fprintf(xmlout, " <InSeconds>%u</InSeconds>\n", track->creation_time);
560 if(notes)
561 fprintf(xmlout, " <!-- Seconds since start of Jan. 1, 1904 UTC (Greenwich) -->\n");
562 /* 2082844800 = seconds between 1/1/04 and 1/1/70 */
563 /* There's still a time zone offset problem not solved... but spec is ambigous as to whether stored time
564 should be local or UTC */
565 if(derived) {
566 fprintf(xmlout, " <AsLocalTime>");
567 xml_time_out(xmlout, track->creation_time - 2082844800);
568 fprintf(xmlout,"</AsLocalTime>\n");
569 }
570 fprintf(xmlout, " </CreationTime>\n");
571 fprintf(xmlout, " <ModificationTime>\n");
572 if(raw)
573 fprintf(xmlout, " <InSeconds>%u</InSeconds>\n", track->modification_time);
574 if(derived) {
575 fprintf(xmlout, " <AsLocalTime>");
576 xml_time_out(xmlout, track->modification_time - 2082844800);
577 fprintf(xmlout,"</AsLocalTime>\n");
578 }
579 fprintf(xmlout, " </ModificationTime>\n");
580 fprintf(xmlout, " <Timescale>%d</Timescale>\n", track->timescale);
581 if(notes)
582 fprintf(xmlout, " <!-- Timescale defines time units in one second -->\n");
583 fprintf(xmlout, " <Duration>\n");
584 if(raw)
585 fprintf(xmlout, " <InTimeUnits>%u</InTimeUnits>\n", track->duration);
586 if(derived)
587 fprintf(xmlout, " <InSeconds>%12.3f</InSeconds>\n", (double)track->duration/(double)track->timescale); // Make this double later to get fractional seconds
588 fprintf(xmlout, " </Duration>\n");
589 int16_to_3packedchars((short int)track->language, buf);
590 fprintf(xmlout, " <Language>%s</Language>\n", buf); /* 3 chars */
591 fprintf(xmlout, " </MediaHeader>\n");
592 fprintf(xmlout, " <HandlerReference BoxType=\"hdlr\">\n");
593 switch(track->track_type)
594 {
595 case 0:
596 fprintf(xmlout, " <HandlerType Code=\"vide\">video media track</HandlerType>\n"); break;
597 case 1:
598 fprintf(xmlout, " <HandlerType Code=\"soun\">Sound</HandlerType>\n"); break;
599 case 2:
600 fprintf(xmlout, " <HandlerType Code=\"hint\">Hint</HandlerType>\n"); break;
601 }
602 if(notes) {
603 fprintf(xmlout, " <!-- String value shown is not actually read from file. -->\n");
604 fprintf(xmlout, " <!-- Shown value is one used for our encode. -->\n");
605 }
606 fprintf(xmlout, " </HandlerReference>\n");
607 fprintf(xmlout, " <MediaInfoContainer BoxType=\"minf\">\n");
608 switch(track->track_type)
609 {
610 case 0:
611 fprintf(xmlout, " <VideoMediaHeader BoxType=\"vmhd\">\n");
612 fprintf(xmlout, " <GraphicsMode>0x%02x</GraphicsMode>\n", track->graphicsmode);
613 if(notes) {
614 fprintf(xmlout," <!-- Enumerated values of graphics mode: -->\n");
615 fprintf(xmlout," <!-- 0x00 = copy (over existing image); -->\n");
616 fprintf(xmlout," <!-- 0x24 = transparent; 'blue-screen' this image using opcolor; -->\n");
617 fprintf(xmlout," <!-- 0x100 = alpha; alpha-blend this image -->\n");
618 /* fprintf(xmlout," <!-- 0x101 = whitealpha; alpha-blend this image, which has been blended with white; -->\n"); This was evidently dropped upon amendment */
619 fprintf(xmlout," <!-- 0x102 = pre-multiplied black alpha; image has been already been alpha-blended with black. -->\n");
620 fprintf(xmlout," <!-- 0x110 = component alpha; blend alpha channel(s) and color channels individually. -->\n");
621 }
622 fprintf(xmlout, " <Opcolor>\n");
623 fprintf(xmlout, " <Red>0x%02x</Red>\n", track->opcolor[0]);
624 fprintf(xmlout, " <Green>0x%02x</Green>\n",track->opcolor[1]);
625 fprintf(xmlout, " <Blue>0x%02x</Blue>\n",track->opcolor[2]);
626 fprintf(xmlout, " </Opcolor>\n");
627 fprintf(xmlout, " </VideoMediaHeader>\n");
628 break;
629 case 1:
630 fprintf(xmlout, " <SoundMediaHeader BoxType=\"smhd\">\n");
631 #ifdef CURRENTSTRUCT
632 track->balance = track->balance << 8;
633 #endif
634 fprintf(xmlout, " <Balance>\n");
635 if(notes) {
636 fprintf(xmlout," <!-- Track audio balance fixes mono track in stereo space. -->\n");
637 fprintf(xmlout," <!-- Stored as fixed-point binary 8.8 value. Decimal value is approximation. -->\n");
638 fprintf(xmlout," <!-- 0.0 = center, -1.0 = full left, 1.0 = full right -->\n");
639 }
640 if(raw)
641 fprintf(xmlout," <AsHex>0x%04x</AsHex>\n", track->balance);
642 if(derived)
643 fprintf(xmlout," <AsDecimal>%6.3f</AsDecimal>\n", (double)track->balance/(double)0x0100);
644 fprintf(xmlout, " </Balance>\n");
645 #ifdef CURRENTSTRUCT
646 if(notes)
647 fprintf(xmlout," <!-- Current m2j_to_metadata implementation always shows bits to right of decimal as zeroed. -->\n");
648 track->balance = track->balance >> 8;
649 #endif
650 fprintf(xmlout, " </SoundMediaHeader>\n");
651 break;
652 case 2:
653 fprintf(xmlout, " <HintMediaHeader BoxType=\"hmhd\">\n");
654 fprintf(xmlout, " <MaxPDU_Size>%d</MaxPDU_Size>\n", track->maxPDUsize);
655 if(notes)
656 fprintf(xmlout," <!-- Size in bytes of largest PDU in this hint stream. -->\n");
657 fprintf(xmlout, " <AvgPDU_Size>%d</AvgPDU_Size>\n", track->avgPDUsize);
658 if(notes)
659 fprintf(xmlout," <!-- Average size in bytes of a PDU over the entire presentation. -->\n");
660 fprintf(xmlout, " <MaxBitRate>%d</MaxBitRate>\n", track->maxbitrate);
661 if(notes)
662 fprintf(xmlout," <!-- Maximum rate in bits per second over any window of 1 second. -->\n");
663 fprintf(xmlout, " <AvgBitRate>%d</AvgBitRate>\n", track->avgbitrate);
664 if(notes)
665 fprintf(xmlout," <!-- Averate rate in bits per second over the entire presentation. -->\n");
666 fprintf(xmlout, " <SlidingAvgBit>%d</SlidingAvgBitRate>\n", track->slidingavgbitrate);
667 if(notes)
668 fprintf(xmlout," <!-- Maximum rate in bits per second over any window of one minute. -->\n");
669 fprintf(xmlout, " </HintMediaHeader>\n");
670 break;
671 }
672 fprintf(xmlout, " <DataInfo BoxType=\"dinf\">\n");
673 fprintf(xmlout, " <DataReference BoxType=\"dref\" URL_Count=\"%d\" URN_Count=\"%d\">\n", track->num_url, track->num_urn); // table w. flags, URLs, URNs
674 // Data structure does not distinguish between single URL, single URN, or DREF table or URLs & URNs.
675 // We could infer those, but for now just present everything as a DREF table.
676 if(notes)
677 fprintf(xmlout, " <!-- No entries here mean that file is self-contained, as required by Simple Profile. -->\n");
678 for(k = 0; k < track->num_url; k++) {
679 fprintf(xmlout, " <DataEntryUrlBox BoxType=\"url[space]\">\n"); // table w. flags, URLs, URNs
680 if(notes)
681 fprintf(xmlout," <!-- Only the first 16 bytes of URL location are recorded in mj2_to_metadata data structure. -->\n");
682 for(i = 0; i < 4; i++) {
683 uint_to_chars(track->url[track->num_url].location[i], buf);
684 fprintf(xmlout, " <Location>%s</Location>\n");
685 }
686 fprintf(xmlout, " </DataEntryUrlBox>\n"); // table w. flags, URLs, URNs
687 }
688 for(k = 0; k < track->num_urn; k++) {
689 fprintf(xmlout," <DataEntryUrnBox BoxType=\"urn[space]\">\n"); // table w. flags, URLs, URNs
690 // Only the first 16 bytes are recorded in the data structure currently.
691 if(notes)
692 fprintf(xmlout," <!-- Only the first 16 bytes each of URN name and optional location are recorded in mj2_to_metadata data structure. -->\n");
693 fprintf(xmlout, " <Name>");
694 for(i = 0; i < 4; i++) {
695 uint_to_chars(track->urn[track->num_urn].name[i], buf);
696 fprintf(xmlout,"%s", buf);
697 }
698 fprintf(xmlout, "</Name>\n");
699 fprintf(xmlout, " <Location>");
700 for(i = 0; i < 4; i++) {
701 uint_to_chars(track->urn[track->num_urn].location[i], buf);
702 fprintf(xmlout,"%s");
703 }
704 fprintf(xmlout, "</Location>\n");
705 fprintf(xmlout, " </DataEntryUrnBox>\n");
706 }
707 fprintf(xmlout, " </DataReference>\n");
708 fprintf(xmlout, " </DataInfo>\n");
709
710 xml_write_stbl(file, xmlout, track, tnum); /* SampleTable */
711
712 fprintf(xmlout, " </MediaInfoContainer>\n");
713 fprintf(xmlout, " </Media>\n");
714 }
715
716 /* ------------- */
717
xml_write_stbl(FILE * file,FILE * xmlout,mj2_tk_t * track,unsigned int tnum)718 void xml_write_stbl(FILE* file, FILE* xmlout, mj2_tk_t *track, unsigned int tnum)
719 {
720 char buf[5], buf33[33];
721 int i, len;
722 buf[4] = '\0';
723
724 fprintf(xmlout, " <SampleTable BoxType=\"stbl\">\n");
725 if(notes)
726 fprintf(xmlout, " <!-- What follows are specific instances of generic SampleDescription BoxType=\"stsd\" -->\n");
727 switch(track->track_type)
728 {
729 case 0:
730 // There could be multiple instances of this, but "entry_count" is just a local at read-time.
731 // And it's used wrong, too, as count of just visual type, when it's really all 3 types.
732 // This is referred to as "smj2" within mj2.c
733 fprintf(xmlout, " <VisualSampleEntry BoxType=\"mjp2\">\n");
734 if(notes) {
735 fprintf(xmlout, " <!-- If multiple instances of this box, only first is shown here. -->\n");
736 fprintf(xmlout, " <!-- Width and Height are in pixels. Unlike the Track Header, there is no fractional part. -->\n");
737 fprintf(xmlout, " <!-- In mj2_to_metadata implementation, the values are not represented separately from Track Header's values. -->\n");
738 }
739 /* No shifting required. If CURRENTSTRUCT gets changed, then may need to revisit treatment of these */
740 fprintf(xmlout, " <WidthAsInteger>%d</WidthAsInteger>\n", track->w);
741 fprintf(xmlout, " <HeightAsInteger>%d</HeightAsInteger>\n", track->h);
742 // Horizresolution and vertresolution don't require shifting, already stored right in CURRENTSTRUCT
743 if(notes) {
744 fprintf(xmlout, " <!-- Resolutions are in pixels per inch, for the highest-resolution component (typically luminance). -->\n");
745 fprintf(xmlout, " <!-- Both stored as fixed-point binary 16.16 values. Decimal values are approximations. -->\n");
746 fprintf(xmlout, " <!-- Typical value for both resolutions is 0x00480000 (72.0) -->\n");
747 }
748 fprintf(xmlout, " <HorizontalRes>\n");
749 if(raw)
750 fprintf(xmlout, " <AsHex>0x%08x</AsHex>\n", track->horizresolution);
751 if(derived)
752 fprintf(xmlout, " <AsDecimal>%12.6f</AsDecimal>\n", (double)track->horizresolution/(double)0x00010000); /* Rate to play presentation (default = 0x00010000) */
753 fprintf(xmlout, " </HorizontalRes>\n");
754 fprintf(xmlout, " <VerticalRes>\n");
755 if(raw)
756 fprintf(xmlout, " <AsHex>0x%08x</AsHex>\n", track->vertresolution);
757 if(derived)
758 fprintf(xmlout, " <AsDecimal>%12.6f</AsDecimal>\n", (double)track->vertresolution/(double)0x00010000); /* Rate to play presentation (default = 0x00010000) */
759 fprintf(xmlout, " </VerticalRes>\n");
760
761 buf33[0] = '\0';
762 for(i = 0; i < 8; i++) {
763 uint_to_chars((unsigned int)track->compressorname[i], buf);
764 strcat(buf33, buf); /* This loads up (4 * 8) + 1 chars, but trailing ones are usually junk */
765 }
766 len = (int)buf33[0]; /* First byte has string length in bytes. There may be garbage beyond it. */
767 buf33[len+1] = '\0'; /* Suppress it */
768 fprintf(xmlout, " <CompressorName>%s</CompressorName>\n", buf33+1); /* Start beyond first byte */
769 if(notes) {
770 fprintf(xmlout, " <!-- Compressor name for debugging. Standard restricts max length to 31 bytes. -->\n");
771 fprintf(xmlout, " <!-- Usually blank or \"Motion JPEG2000\" -->\n");
772 }
773 fprintf(xmlout, " <Depth>0x%02x</Depth>\n",track->depth);
774 if(notes) {
775 fprintf(xmlout, " <!-- Depth is: -->\n");
776 fprintf(xmlout, " <!-- 0x20: alpha channels present (color or grayscale) -->\n");
777 fprintf(xmlout, " <!-- 0x28: grayscale without alpha -->\n");
778 fprintf(xmlout, " <!-- 0x18: color without alpha -->\n");
779 }
780
781 xml_out_frame_jp2h(xmlout, &(track->jp2_struct)); /* JP2 Header */
782
783 /* Following subboxes are optional */
784 fprintf(xmlout, " <FieldCoding BoxType=\"fiel\">\n");
785 fprintf(xmlout, " <FieldCount>%d</FieldCount>\n", (unsigned int)track->fieldcount); /* uchar as 1 byte uint */
786 if(notes)
787 fprintf(xmlout, " <!-- Must be either 1 or 2 -->\n");
788 fprintf(xmlout, " <FieldOrder>%d</FieldOrder>\n", (unsigned int)track->fieldorder); /* uchar as 1 byte uint */
789 if(notes) {
790 fprintf(xmlout, " <!-- When FieldCount=2, FieldOrder means: -->\n");
791 fprintf(xmlout, " <!-- 0: Field coding unknown -->\n");
792 fprintf(xmlout, " <!-- 1: Field with topmost line is stored first in sample; fields are in temporal order -->\n");
793 fprintf(xmlout, " <!-- 6: Field with topmost line is stored second in sample; fields are in temporal order -->\n");
794 fprintf(xmlout, " <!-- Defaults: FieldCount=1, FieldOrder=0 if FieldCoding box not present -->\n");
795 fprintf(xmlout, " <!-- Current implementation doesn't retain whether box was actually present. -->\n");
796 }
797 fprintf(xmlout, " </FieldCoding>\n");
798
799 fprintf(xmlout, " <MJP2_Profile BoxType=\"jp2p\" Count=\"%d\">\n",track->num_br);
800 for (i = 0; i < track->num_br; i++) /* read routine stored in reverse order, so let's undo damage */
801 {
802 uint_to_chars(track->br[i], buf);
803 fprintf(xmlout, " <CompatibleBrand>%s</CompatibleBrand>\n", buf); /*4 characters, each CLi */
804 }
805 fprintf(xmlout, " </MJP2_Profile>\n");
806
807 fprintf(xmlout, " <MJP2_Prefix BoxType=\"jp2x\" Count=\"%d\">\n",track->num_jp2x);
808 for (i = 0; i < track->num_jp2x; i++)
809 { // We'll probably need better formatting than this
810 fprintf(xmlout, " <Data>0x%02x</Data>\n", track->jp2xdata[i]); /* Each entry is single byte */
811 }
812 fprintf(xmlout, " </MJP2_Prefix>\n");
813
814 fprintf(xmlout, " <MJP2_SubSampling BoxType=\"jsub\">\n"); /* These values are all 1 byte */
815 if(notes)
816 fprintf(xmlout, " <!-- Typical subsample value is 2 for 4:2:0 -->\n");
817 fprintf(xmlout, " <HorizontalSub>%d</HorizontalSub>\n", track->hsub);
818 fprintf(xmlout, " <VerticalSub>%d</VerticalSub>\n", track->vsub);
819 fprintf(xmlout, " <HorizontalOffset>%d</HorizontalOffset>\n", track->hoff);
820 fprintf(xmlout, " <VerticalOffset>%d</VerticalOffset>\n", track->voff);
821 if(notes) {
822 fprintf(xmlout, " <!-- Typical {horizontal, vertical} chroma offset values: -->\n");
823 fprintf(xmlout, " <!-- 4:2:2 format (CCIR601, H.262, MPEG2, MPEG4, recom. Exif): {0, 0} -->\n");
824 fprintf(xmlout, " <!-- 4:2:2 format (JFIF): {1, 0} -->\n");
825 fprintf(xmlout, " <!-- 4:2:0 format (H.262, MPEG2, MPEG4): {0, 1} -->\n");
826 fprintf(xmlout, " <!-- 4:2:0 format (MPEG1, H.261, JFIF, recom. Exif): {1, 1} -->\n");
827 }
828 fprintf(xmlout, " </MJP2_SubSampling>\n"); /* These values are all 1 byte */
829
830 fprintf(xmlout, " <MJP2_OriginalFormat BoxType=\"orfo\">\n"); /* Part III Appx. 2 */
831 fprintf(xmlout, " <OriginalFieldCount>%u</OriginalFieldCount>\n", (unsigned int)track->or_fieldcount); /* uchar as 1-byte uint */
832 if(notes)
833 fprintf(xmlout, " <!-- In original material before encoding. Must be either 1 or 2 -->\n");
834 fprintf(xmlout, " <OriginalFieldOrder>%u</OriginalFieldOrder>\n", (unsigned int)track->or_fieldorder); /* uchar as 1-byte uint */
835 if(notes) {
836 fprintf(xmlout, " <!-- When FieldCount=2, FieldOrder means: -->\n");
837 fprintf(xmlout, " <!-- 0: Field coding unknown -->\n");
838 fprintf(xmlout, " <!-- 11: Topmost line came from the earlier field; -->\n");
839 fprintf(xmlout, " <!-- 16: Topmost line came form the later field. -->\n");
840 fprintf(xmlout, " <!-- Defaults: FieldCount=1, FieldOrder=0 if FieldCoding box not present -->\n");
841 fprintf(xmlout, " <!-- Current implementation doesn't retain whether box was actually present. -->\n");
842 }
843 fprintf(xmlout, " </MJP2_OriginalFormat>\n");
844 fprintf(xmlout, " </VisualSampleEntry>\n");
845 break;
846 case 1: case 2:
847 if(notes)
848 fprintf(xmlout, " <!-- mj2_to_metadata's data structure doesn't record this currently. -->\n"); break;
849 }
850 fprintf(xmlout, " <TimeToSample BoxType=\"stts\">\n");
851 fprintf(xmlout, " <SampleStatistics>\n");
852 fprintf(xmlout, " <TotalSamples>%d</TotalSamples>\n", track->num_samples);
853 if(notes)
854 fprintf(xmlout, " <!-- For video, gives the total frames in the track, by summing all entries in the Sample Table -->\n");
855 fprintf(xmlout, " </SampleStatistics>\n");
856 fprintf(xmlout, " <SampleEntries EntryCount=\"%d\">\n", track->num_tts);
857 for (i = 0; i < track->num_tts; i++) {
858 fprintf(xmlout, " <Table Entry=\"%u\" SampleCount=\"%d\" SampleDelta=\"%u\" />\n",
859 i+1, track->tts[i].sample_count, track->tts[i].sample_delta);
860 }
861 fprintf(xmlout, " </SampleEntries>\n");
862 fprintf(xmlout, " </TimeToSample>\n");
863
864 fprintf(xmlout, " <SampleToChunk BoxType=\"stsc\" Count=\"%d\">\n", track->num_samplestochunk);
865 for (i = 0; i < track->num_samplestochunk; i++) {
866 fprintf(xmlout, " <FirstChunk>%u</FirstChunk>\n",track->sampletochunk[i].first_chunk); /* 4 bytes */
867 fprintf(xmlout, " <SamplesPerChunk>%u</SamplesPerChunk>\n",track->sampletochunk[i].samples_per_chunk); /* 4 bytes */
868 fprintf(xmlout, " <SampleDescrIndex>%u</SampleDescrIndex>\n",track->sampletochunk[i].sample_descr_idx); /* 4 bytes */
869 }
870 fprintf(xmlout, " </SampleToChunk>\n");
871 // After reading this info in, track->num_chunks is calculated and a decompressed table established internally.
872
873 fprintf(xmlout, " <SampleSize BoxType=\"stsz\">\n");
874 if(track->same_sample_size) {
875 // all values in track->sample[i].sample_size are equal. Grab the first one.
876 fprintf(xmlout, " <Sample_Size>%u</Sample_Size>\n", track->sample[0].sample_size);
877 if(notes) {
878 fprintf(xmlout, " <!-- Non-zero value means all samples have that size. -->\n");
879 fprintf(xmlout, " <!-- So <Sample_Count> (aka Entry_Count in std.) has no meaning, is suppressed from this output, and no table follows. -->\n");
880 }
881 } else {
882 fprintf(xmlout, " <Sample_Size>0</Sample_Size>\n");
883 if(notes)
884 if(sampletables)
885 fprintf(xmlout," <!-- Zero value means samples have different sizes, given in table next of length Sample_Count (aka Entry_Count in std). -->\n");
886 else
887 fprintf(xmlout," <!-- Zero value means samples have different sizes, given in table (not shown) of length Sample_Count (aka Entry_Count in std). -->\n");
888 fprintf(xmlout, " <Sample_Count>%u</Sample_Count>\n", track->num_samples);
889 if(sampletables)
890 for (i = 0; i < (int)track->num_samples; i++) {
891 fprintf(xmlout, " <EntrySize Num=\"%u\">%u</EntrySize>\n", i+1, track->sample[i].sample_size);
892 }
893 }
894 fprintf(xmlout, " </SampleSize>\n");
895
896 fprintf(xmlout, " <ChunkOffset BoxType=\"stco\">\n");
897 // Structure not yet - Variant ChunkLargeOffset 'co64'
898 fprintf(xmlout, " <EntryCount>%u</EntryCount>\n", track->num_chunks);
899 if(notes) {
900 fprintf(xmlout, " <!-- For this implementation, EntryCount shown is one calculated during file read of <SampleToChunk> data. -->\n");
901 fprintf(xmlout, " <!-- Implementation will report failure during file read of <ChunkOffset> data if read entry-count disagrees. -->\n");
902 }
903 if(sampletables)
904 for (i = 0; i < (int)track->num_chunks; i++)
905 fprintf(xmlout, " <Chunk_Offset Num=\"%d\">%u</Chunk_Offset>\n", i+1, track->chunk[i].offset);
906 fprintf(xmlout, " </ChunkOffset>\n");
907
908 fprintf(xmlout, " </SampleTable>\n");
909 }
910
911 /* ------------- */
912
xml_out_frame(FILE * file,FILE * xmlout,mj2_sample_t * sample,unsigned int snum,opj_event_mgr_t * event_mgr)913 int xml_out_frame(FILE* file, FILE* xmlout, mj2_sample_t *sample, unsigned int snum, opj_event_mgr_t *event_mgr)
914 {
915 opj_dparameters_t parameters; /* decompression parameters */
916 opj_image_t *img;
917 opj_cp_t *cp;
918 int i;
919 int numcomps;
920 unsigned char* frame_codestream;
921 opj_dinfo_t* dinfo = NULL; /* handle to a decompressor */
922 opj_cio_t *cio = NULL;
923 opj_j2k_t *j2k;
924
925 /* JPEG 2000 compressed image data */
926
927 /* get a decoder handle */
928 dinfo = opj_create_decompress(CODEC_J2K);
929
930 /* catch events using our callbacks and give a local context */
931 opj_set_event_mgr((opj_common_ptr)dinfo, event_mgr, stderr);
932
933 /* setup the decoder decoding parameters using the current image and user parameters */
934 parameters.cp_limit_decoding = DECODE_ALL_BUT_PACKETS;
935 opj_setup_decoder(dinfo, ¶meters);
936
937 frame_codestream = (unsigned char*) malloc (sample->sample_size-8); /* Skipping JP2C marker */
938 if(frame_codestream == NULL)
939 return 1;
940
941 fseek(file,sample->offset+8,SEEK_SET);
942 fread(frame_codestream,sample->sample_size-8,1, file); /* Assuming that jp and ftyp markers size do */
943
944 /* open a byte stream */
945 cio = opj_cio_open((opj_common_ptr)dinfo, frame_codestream, sample->sample_size-8);
946
947 /* Decode J2K to image: */
948 img = opj_decode(dinfo, cio);
949 if (!img) {
950 fprintf(stderr, "ERROR -> j2k_to_image: failed to decode image!\n");
951 opj_destroy_decompress(dinfo);
952 opj_cio_close(cio);
953 return 1;
954 }
955
956 j2k = (opj_j2k_t*)dinfo->j2k_handle;
957 j2k_default_tcp = j2k->default_tcp;
958 cp = j2k->cp;
959
960 numcomps = img->numcomps;
961 /* Alignments: " < To help maintain xml pretty-printing */
962 fprintf(xmlout, " <JP2_Frame Num=\"%d\">\n", snum+1);
963 fprintf(xmlout, " <MainHeader>\n");
964 /* There can be multiple codestreams; a particular image is entirely within a single codestream */
965 /* TO DO: A frame can be represented by two I-guess-contigious codestreams if its interleaved. */
966 fprintf(xmlout, " <StartOfCodestream Marker=\"SOC\" />\n");
967 /* "cp" stands for "coding parameter"; "tcp" is tile coding parameters, "tccp" is tile-component coding parameters */
968 xml_out_frame_siz(xmlout, img, cp); /* reqd in main */
969 xml_out_frame_cod(xmlout, j2k_default_tcp); /* reqd in main */
970 xml_out_frame_coc(xmlout, j2k_default_tcp, numcomps); /* opt in main, at most 1 per component */
971 xml_out_frame_qcd(xmlout, j2k_default_tcp); /* reqd in main */
972 xml_out_frame_qcc(xmlout, j2k_default_tcp, numcomps); /* opt in main, at most 1 per component */
973 xml_out_frame_rgn(xmlout, j2k_default_tcp, numcomps); /* opt, at most 1 per component */
974 xml_out_frame_poc(xmlout, j2k_default_tcp); /* opt (but reqd in main or tile for any progression order changes) */
975 /* Next four get j2k_default_tcp passed globally: */
976 #ifdef SUPPRESS_FOR_NOW
977 xml_out_frame_ppm(xmlout, cp); /* opt (but either PPM or PPT [distributed in tile headers] or codestream packet header reqd) */
978 #endif
979 xml_out_frame_tlm(xmlout); /* NO-OP. TLM NOT SAVED IN DATA STRUCTURE */ /* opt */
980 xml_out_frame_plm(xmlout); /* NO-OP. PLM NOT SAVED IN DATA STRUCTURE */ /* opt in main; can be used in conjunction with PLT */
981 xml_out_frame_crg(xmlout); /* NO-OP. CRG NOT SAVED IN DATA STRUCTURE */ /* opt in main; */
982 xml_out_frame_com(xmlout, j2k_default_tcp); /* NO-OP. COM NOT SAVED IN DATA STRUCTURE */ /* opt in main; */
983
984 fprintf(xmlout, " </MainHeader>\n");
985
986 /* TO DO: all the tile headers (sigh) */
987 fprintf(xmlout, " <TilePartHeaders Count=\"%d\">\n", cp->tileno_size); /* size of the vector tileno */
988 for(i = 0; i < cp->tileno_size; i++) { /* I think cp->tileno_size will be same number as (cp->tw * cp->th) or as global j2k_curtileno */
989 // Standard seems to use zero-based # for tile-part.
990 fprintf(xmlout, " <TilePartHeader Num=\"%d\" ID=\"%d\">\n", i, cp->tileno[i]); /* ID number of the tiles present in the codestream */
991 fprintf(xmlout, " <StartOfTilePart Marker=\"SOT\" />\n");
992 /* All markers in tile-part headers (between SOT and SOD) are optional, unless structure requires. */
993 if(i == 0) {
994 xml_out_frame_cod(xmlout, &(cp->tcps[i])); /* No more than 1 per tile */
995 xml_out_frame_coc(xmlout, &(cp->tcps[i]), numcomps); /* No more than 1 per component */
996 xml_out_frame_qcd(xmlout, &(cp->tcps[i])); /* No more than 1 per tile */
997 xml_out_frame_qcc(xmlout, &(cp->tcps[i]), numcomps); /* No more than 1 per component */
998 xml_out_frame_rgn(xmlout, &(cp->tcps[i]), numcomps); /* No more than 1 per component */
999 }
1000 xml_out_frame_poc(xmlout, &(cp->tcps[i])); /* Reqd only if any progression order changes different from main POC */
1001 #ifdef SUPPRESS_FOR_NOW
1002 xml_out_frame_ppt(xmlout, &(cp->tcps[i])); /* Either PPT [distributed in tile headers] or PPM or codestream packet header reqd. */
1003 #endif
1004 xml_out_frame_plt(xmlout, &(cp->tcps[i])); /* NO-OP. PLT NOT SAVED IN DATA STRUCTURE */ /* Can be used in conjunction with main's PLM */
1005 xml_out_frame_com(xmlout, &(cp->tcps[i])); /* NO-OP. COM NOT SAVED IN DATA STRUCTURE */
1006 /* opj_tcp_t * cp->tcps; "tile coding parameters" */
1007 /* Maybe not: fprintf(xmlout, " <>%d</>, cp->matrice[i]; */ /* Fixed layer */
1008 fprintf(xmlout, " <StartOfData Marker=\"SOD\" />\n");
1009 if(notes)
1010 fprintf(xmlout, " <!-- Tile-part bitstream, not shown, follows tile-part header and SOD marker. -->\n");
1011 fprintf(xmlout, " </TilePartHeader>\n");
1012 }
1013 fprintf(xmlout, " </TilePartHeaders>\n"); /* size of the vector tileno */
1014
1015 #ifdef NOTYET
1016 IMAGINE the cp object has data to support the following... but we could use an new different data structure instead
1017 /* I'm unclear if the span of the original fread(frame_codestream...) included the following items if they're trailing. */
1018 /* ALSO TO DO, BUT DATA STRUCTURE DOESN'T HANDLE YET: boxes (anywhere in file except before the Filetype box): */
1019 xml_out_frame_jp2i(xmlout, &cp); /* IntellectualProperty 'jp2i' (no restrictions on location) */
1020 xml_out_frame_xml(xmlout, &cp); /* XML 'xml\040' (0x786d6c20). Can appear multiply */
1021 xml_out_frame_uuid(xmlout, &cp); /* UUID 'uuid' (top level only) */
1022 xml_out_frame_uinf(xmlout, &cp); /* UUIDInfo 'uinf', includes UUIDList 'ulst' and URL 'url\40' */
1023 #endif
1024
1025 fprintf(xmlout, " </JP2_Frame>\n");
1026
1027 /* Extra commentary: */
1028 if(notes) {
1029 fprintf(xmlout, " <!-- Given the number and size of components, mj2_to_frame would try to convert this -->\n");
1030 if (((img->numcomps == 3) && (img->comps[0].dx == img->comps[1].dx / 2)
1031 && (img->comps[0].dx == img->comps[2].dx / 2 ) && (img->comps[0].dx == 1))
1032 || (img->numcomps == 1)) {
1033 fprintf(xmlout, " <!-- file to a YUV movie in the normal manner. -->\n");
1034 }
1035 else if ((img->numcomps == 3) &&
1036 (img->comps[0].dx == 1) && (img->comps[1].dx == 1)&&
1037 (img->comps[2].dx == 1)) {// If YUV 4:4:4 input --> to bmp
1038 fprintf(xmlout, " <!-- YUV 4:4:4 file to a series of .bmp files. -->\n");
1039 }
1040 else {
1041 fprintf(xmlout, " <!-- file whose image component dimension are unknown, to a series of .j2k files. -->\n");
1042 }
1043 }
1044
1045 opj_destroy_decompress(dinfo);
1046 opj_cio_close(cio);
1047 free(frame_codestream);
1048
1049 return 0;
1050 }
1051
1052 /* ------------- */
1053
int16_to_3packedchars(short int value,char * buf)1054 void int16_to_3packedchars(short int value, char* buf)
1055 {
1056 /* This is to retrieve the 3-letter ASCII language code */
1057 /* Each char is packed into 5 bits, as difference from 0x60 */
1058 int i;
1059 for (i = 2; i >= 0; i--)
1060 {
1061 buf[i] = (value & 0x001f) + 0x60;
1062 value = (value >>5);
1063 }
1064 buf[3] = '\0';
1065 }
1066
1067 /* ------------- */
1068
xml_out_frame_siz(FILE * xmlout,opj_image_t * img,opj_cp_t * cp)1069 void xml_out_frame_siz(FILE* xmlout, opj_image_t *img, opj_cp_t *cp)
1070 {
1071 opj_image_comp_t *comp;
1072 int i;
1073
1074 fprintf(xmlout, " <ImageAndFileSize Marker=\"SIZ\">\n");
1075 // This is similar to j2k.c's j2k_dump_image.
1076 // Not of interest: Lsiz, Rsiz
1077 fprintf(xmlout, " <Xsiz>%d</Xsiz>\n", img->x1);
1078 fprintf(xmlout, " <Ysiz>%d</Ysiz>\n", img->y1);
1079 if(notes)
1080 fprintf(xmlout, " <!-- Xsiz, Ysiz is the size of the reference grid. -->\n");
1081 fprintf(xmlout, " <XOsiz>%d</XOsiz>\n", img->x0);
1082 fprintf(xmlout, " <YOsiz>%d</YOsiz>\n", img->y0);
1083 if(notes)
1084 fprintf(xmlout, " <!-- XOsiz, YOsiz are offsets from grid origin to image origin. -->\n");
1085 fprintf(xmlout, " <XTsiz>%d</XTsiz>\n", cp->tdx);
1086 fprintf(xmlout, " <YTsiz>%d</YTsiz>\n", cp->tdy);
1087 if(notes)
1088 fprintf(xmlout, " <!-- XTsiz, YTsiz is the size of one tile with respect to the grid. -->\n");
1089 fprintf(xmlout, " <XTOsiz>%d</XTOsiz>\n", cp->tx0);
1090 fprintf(xmlout, " <YTOsiz>%d</YTOsiz>\n", cp->ty0);
1091 if(notes)
1092 fprintf(xmlout, " <!-- XTOsiz, YTOsiz are offsets from grid origin to first tile origin. -->\n");
1093 fprintf(xmlout, " <Csiz>%d</Csiz>\n", img->numcomps);
1094 if(notes) {
1095 fprintf(xmlout, " <!-- Csiz is the number of components in the image. -->\n");
1096 fprintf(xmlout, " <!-- For image components next: -->\n");
1097 fprintf(xmlout, " <!-- XRsiz, YRsiz denote pixel-sample-spacing on the grid, per Part I Annex B. -->\n");
1098 //fprintf(xmlout," <!-- XO, YO is offset of the component compared to the whole image. -->\n");
1099 fprintf(xmlout, " <!-- Bits per pixel (bpp) is the pixel depth. -->\n");
1100 fprintf(xmlout, " <!-- WidthOfData and HeightOfData are calculated values, e.g.: w = roundup((Xsiz - XOsiz)/ XRsiz) -->\n");
1101 }
1102
1103 for (i = 0; i < img->numcomps; i++) {/* image-components */
1104 comp = &(img->comps[i]);
1105 fprintf(xmlout, " <Component Num=\"%d\">\n", i+1);
1106 fprintf(xmlout, " <Ssiz>\n");
1107 if(raw)
1108 fprintf(xmlout," <AsHex>0x%02x</AsHex>\n", (comp->sgnd << 7) & (comp->prec - 1));
1109 if(derived) {
1110 fprintf(xmlout," <Signed>%d</Signed>\n", comp->sgnd);
1111 fprintf(xmlout," <PrecisionInBits>%d</PrecisionInBits>\n", comp->prec);
1112 }
1113 fprintf(xmlout, " </Ssiz>\n");
1114 fprintf(xmlout, " <XRsiz>%d</XRsiz>\n", comp->dx);
1115 fprintf(xmlout, " <YRsiz>%d</YRsiz>\n", comp->dy);
1116 fprintf(xmlout, " <WidthOfData>%d</WidthOfData>\n", comp->w);
1117 fprintf(xmlout, " <HeightOfData>%d</HeightOfData>\n", comp->h);
1118 /* Rest of these aren't calculated when SIZ is read:
1119 fprintf(xmlout, " <XO>%d</XO>\n", comp->x0);
1120 fprintf(xmlout, " <YO>%d</YO>\n", comp->y0);
1121 if(notes)
1122 fprintf(xmlout," <!-- XO, YO is offset of the component compared to the whole image. -->\n");
1123 fprintf(xmlout, " <BitsPerPixel>%d</BitsPerPixel>\n", comp->bpp);
1124 fprintf(xmlout, " <NumberOfDecodedResolution>%d</NumberOfDecodedResolution>\n", comp->resno_decoded); */
1125 // SUPPRESS: n/a to mj2_to_metadata. fprintf(xmlout," <Factor>%d</Factor\n", comp->factor);
1126 /* factor = number of division by 2 of the out image compare to the original size of image */
1127 // TO DO comp->data: int *data; /* image-component data */
1128
1129 fprintf(xmlout, " </Component>\n");
1130 }
1131 fprintf(xmlout, " </ImageAndFileSize>\n");
1132 }
1133
1134 /* ------------- */
1135
xml_out_frame_cod(FILE * xmlout,opj_tcp_t * tcp)1136 void xml_out_frame_cod(FILE* xmlout, opj_tcp_t *tcp)
1137 {
1138 /* Could be called with tcp = &j2k_default_tcp;
1139 /* Or, for tile-part header, with &j2k_cp->tcps[j2k_curtileno]
1140 /* Alignment for main:" < < < < To help maintain xml pretty-printing */
1141 /* Alignment for tile:" < < < To help maintain xml pretty-printing */
1142 opj_tccp_t *tccp;
1143 int i;
1144 char spaces[13] = " "; /* 12 spaces if tilepart*/
1145 char* s = spaces;
1146 if(tcp == j2k_default_tcp) {
1147 s++;s++; /* shorten s to 10 spaces if main */
1148 }
1149 tccp = &(tcp->tccps[0]);
1150
1151 fprintf(xmlout, "%s<CodingStyleDefault Marker=\"COD\">\n",s); /* Required in main header */
1152 /* Not retained or of interest: Lcod */
1153 fprintf(xmlout, "%s <Scod>0x%02x</Scod>\n", s, tcp->csty); /* 1 byte */
1154 if(notes) {
1155 fprintf(xmlout, "%s <!-- For Scod, specific bits mean (where bit 0 is lowest or rightmost): -->\n",s);
1156 fprintf(xmlout, "%s <!-- bit 0: Defines entropy coder precincts -->\n",s);
1157 fprintf(xmlout, "%s <!-- 0 = (PPx=15, PPy=15); 1 = precincts defined below. -->\n",s);
1158 fprintf(xmlout, "%s <!-- bit 1: 1 = SOP marker may be used; 0 = not. -->\n",s);
1159 fprintf(xmlout, "%s <!-- bit 2: 1 = EPH marker may be used; 0 = not. -->\n",s);
1160 }
1161 fprintf(xmlout, "%s <SGcod>\n",s);
1162 fprintf(xmlout, "%s <ProgressionOrder>%d</ProgressionOrder>\n", s, tcp->prg); /* 1 byte, SGcod (A) */
1163 if(notes) {
1164 fprintf(xmlout, "%s <!-- Defined Progression Order Values are: -->\n",s);
1165 fprintf(xmlout, "%s <!-- 0 = LRCP; 1 = RLCP; 2 = RPCL; 3 = PCRL; 4 = CPRL -->\n",s);
1166 fprintf(xmlout, "%s <!-- where L = \"layer\", R = \"resolution level\", C = \"component\", P = \"position\". -->\n",s);
1167 }
1168 fprintf(xmlout, "%s <NumberOfLayers>%d</NumberOfLayers>\n", s, tcp->numlayers); /* 2 bytes, SGcod (B) */
1169 fprintf(xmlout, "%s <MultipleComponentTransformation>%d</MultipleComponentTransformation>\n", s, tcp->mct); /* 1 byte, SGcod (C). More or less boolean */
1170 if(notes)
1171 fprintf(xmlout, "%s <!-- For MCT, 0 = none, 1 = transform first 3 components for efficiency, per Part I Annex G -->\n",s);
1172 fprintf(xmlout, "%s </SGcod>\n",s);
1173 /* This code will compile only if declaration of j2k_default_tcp is changed from static (to implicit extern) in j2k.c */
1174 fprintf(xmlout, "%s <SPcod>\n",s);
1175 /* Internal data structure tccp defines separate defaults for each component, but they all get the same values */
1176 /* So we only have to report the first component's values here. */
1177 /* Compare j2k_read_cox(...) */
1178 fprintf(xmlout, "%s <NumberOfDecompositionLevels>%d</NumberOfDecompositionLevels>\n", s, tccp->numresolutions - 1); /* 1 byte, SPcox (D) */
1179 fprintf(xmlout, "%s <CodeblockWidth>%d</CodeblockWidth>\n", s, tccp->cblkw - 2); /* 1 byte, SPcox (E) */
1180 fprintf(xmlout, "%s <CodeblockHeight>%d</CodeblockHeight>\n", s, tccp->cblkh - 2); /* 1 byte, SPcox (F) */
1181 if(notes) {
1182 fprintf(xmlout, "%s <!-- CBW and CBH are non-negative, and summed cannot exceed 8 -->\n",s);
1183 fprintf(xmlout, "%s <!-- Codeblock dimension is 2^(value + 2) -->\n", s);
1184 }
1185 fprintf(xmlout, "%s <CodeblockStyle>0x%02x</CodeblockStyle>\n", s, tccp->cblksty); /* 1 byte, SPcox (G) */
1186 if(notes) {
1187 fprintf(xmlout, "%s <!-- For CodeblockStyle, bits mean (with value 1=feature on, 0=off): -->\n",s);
1188 fprintf(xmlout, "%s <!-- bit 0: Selective arithmetic coding bypass. -->\n",s);
1189 fprintf(xmlout, "%s <!-- bit 1: Reset context probabilities on coding pass boundaries. -->\n",s);
1190 fprintf(xmlout, "%s <!-- bit 2: Termination on each coding pass. -->\n",s);
1191 fprintf(xmlout, "%s <!-- bit 3: Vertically causal context. -->\n",s);
1192 fprintf(xmlout, "%s <!-- bit 4: Predictable termination. -->\n",s);
1193 fprintf(xmlout, "%s <!-- bit 5: Segmentation symbols are used. -->\n",s);
1194 }
1195 fprintf(xmlout, "%s <Transformation>%d</Transformation>\n", s, tccp->qmfbid); /* 1 byte, SPcox (H) */
1196 if(notes)
1197 fprintf(xmlout, "%s <!-- For Transformation, 0=\"9-7 irreversible filter\", 1=\"5-3 reversible filter\" -->\n",s);
1198 if (tccp->csty & J2K_CP_CSTY_PRT) {
1199 fprintf(xmlout, "%s <PrecinctSize>\n",s); /* 1 byte, SPcox (I_i) */
1200 if(notes)
1201 fprintf(xmlout, "%s <!-- These are size exponents PPx and PPy. May be zero only for first level (aka N(L)LL subband)-->\n",s);
1202 for (i = 0; i < tccp->numresolutions; i++) {
1203 fprintf(xmlout, "%s <PrecinctHeightAndWidth ResolutionLevel=\"%d\">\n", s, i);
1204 if(raw)
1205 fprintf(xmlout,"%s <AsHex>0x%02x</AsHex>\n", s, (tccp->prch[i] << 4) | tccp->prcw[i]); /* packed into 1 byte, SPcox (G) */
1206 if(derived) {
1207 fprintf(xmlout,"%s <WidthAsDecimal>%d</WidthAsDecimal>\n", s, tccp->prcw[i]);
1208 fprintf(xmlout,"%s <HeightAsDecimal>%d</HeightAsDecimal>\n", s, tccp->prch[i]);
1209 }
1210 fprintf(xmlout, "%s </PrecinctHeightAndWidth>\n", s, i);
1211 }
1212 fprintf(xmlout, "%s </PrecinctSize>\n",s); /* 1 byte, SPcox (I_i) */
1213 }
1214 fprintf(xmlout, "%s </SPcod>\n",s);
1215 fprintf(xmlout, "%s</CodingStyleDefault>\n",s);
1216 }
1217
1218 /* ------------- */
1219
xml_out_frame_coc(FILE * xmlout,opj_tcp_t * tcp,int numcomps)1220 void xml_out_frame_coc(FILE* xmlout, opj_tcp_t *tcp, int numcomps) /* Optional in main & tile-part headers */
1221 {
1222 /* Uses global j2k_default_tcp */
1223 opj_tccp_t *tccp, *firstcomp_tccp;
1224 int i, compno;
1225 char spaces[13] = " "; /* 12 spaces if tilepart*/
1226 char* s = spaces;
1227 if(tcp == j2k_default_tcp) {
1228 s++;s++; /* shorten s to 10 spaces if main */
1229 }
1230
1231 firstcomp_tccp = &(tcp->tccps[0]);
1232 /* Internal data structure tccp defines separate defaults for each component, set from main */
1233 /* default, then selectively overwritten. */
1234 /* Compare j2k_read_cox(...) */
1235 /* We don't really know which was the default, and which were not */
1236 /* Let's pretend that [0] is the default and all others are not */
1237 if(notes) {
1238 fprintf(xmlout, "%s<!-- mj2_to_metadata implementation always reports component[0] as using default COD, -->\n", s);
1239 if(tcp == j2k_default_tcp)
1240 fprintf(xmlout, "%s<!-- and any other component, with main-header style values different from [0], as COC. -->\n", s);
1241 else
1242 fprintf(xmlout, "%s<!-- and any other component, with tile-part-header style values different from [0], as COC. -->\n", s);
1243 }
1244 for (compno = 1; compno < numcomps; compno++) /* spec says components are zero-based */
1245 {
1246 tccp = &tcp->tccps[compno];
1247 if(same_component_style(firstcomp_tccp, tccp))
1248 continue;
1249
1250 /* Alignments: " < < < < < To help maintain xml pretty-printing */
1251 fprintf(xmlout, "%s<CodingStyleComponent Marker=\"COC\">\n", s); /* Optional in main header, at most 1 per component */
1252 if(notes)
1253 fprintf(xmlout, "%s <!-- See Ccoc below for zero-based component number. -->\n", s);
1254 /* Overrides the main COD for the specific component */
1255 /* Not retained or of interest: Lcod */
1256 fprintf(xmlout, "%s <Scoc>0x%02x</Scoc>\n", s, tccp->csty); /* 1 byte */
1257 if(notes) {
1258 fprintf(xmlout, "%s <!-- Scoc defines entropy coder precincts: -->\n", s);
1259 fprintf(xmlout, "%s <!-- 0 = maximum, namely (PPx=15, PPy=15); 1 = precincts defined below. -->\n", s);
1260 }
1261 fprintf(xmlout, "%s <Ccoc>%d</Ccoc>\n", s, compno); /* 1 or 2 bytes */
1262 /* Unfortunately compo isn't retained in j2k_read_coc: compno = cio_read(j2k_img->numcomps <= 256 ? 1 : 2); /* Ccoc */
1263 /*if(j2k_img_numcomps <=256)
1264 component is 1 byte
1265 else
1266 compno is 2 byte */
1267
1268 /* This code will compile only if declaration of j2k_default_tcp is changed from static (to implicit extern) in j2k.c */
1269 fprintf(xmlout, "%s <SPcoc>\n", s);
1270 fprintf(xmlout, "%s <NumberOfDecompositionLevels>%d</NumberOfDecompositionLevels>\n", s, tccp->numresolutions - 1); /* 1 byte, SPcox (D) */
1271 fprintf(xmlout, "%s <CodeblockWidth>%d</CodeblockWidth>\n", s, tccp->cblkw - 2); /* 1 byte, SPcox (E) */
1272 fprintf(xmlout, "%s <CodeblockHeight>%d</CodeblockHeight>\n", s, tccp->cblkh - 2); /* 1 byte, SPcox (F) */
1273 if(notes) {
1274 fprintf(xmlout, "%s <!-- CBW and CBH are non-negative, and summed cannot exceed 8 -->\n", s);
1275 fprintf(xmlout, "%s <!-- Codeblock dimension is 2^(value + 2) -->\n", s);
1276 }
1277 fprintf(xmlout, "%s <CodeblockStyle>0x%02x</CodeblockStyle>\n", s, tccp->cblksty); /* 1 byte, SPcox (G) */
1278 if(notes) {
1279 fprintf(xmlout, "%s <!-- For CodeblockStyle, bits mean (with value 1=feature on, 0=off): -->\n", s);
1280 fprintf(xmlout, "%s <!-- bit 0: Selective arithmetic coding bypass. -->\n", s);
1281 fprintf(xmlout, "%s <!-- bit 1: Reset context probabilities on coding pass boundaries. -->\n", s);
1282 fprintf(xmlout, "%s <!-- bit 2: Termination on each coding pass. -->\n", s);
1283 fprintf(xmlout, "%s <!-- bit 3: Vertically causal context. -->\n", s);
1284 fprintf(xmlout, "%s <!-- bit 4: Predictable termination. -->\n", s);
1285 fprintf(xmlout, "%s <!-- bit 5: Segmentation symbols are used. -->\n", s);
1286 }
1287 fprintf(xmlout, "%s <Transformation>%d</Transformation>\n", s, tccp->qmfbid); /* 1 byte, SPcox (H) */
1288 if(notes)
1289 fprintf(xmlout, "%s <!-- For Transformation, 0=\"9-7 irreversible filter\", 1=\"5-3 reversible filter\" -->\n", s);
1290 if (tccp->csty & J2K_CP_CSTY_PRT) {
1291 fprintf(xmlout, "%s <PrecinctSize>\n", s); /* 1 byte, SPcox (I_i) */
1292 if(notes)
1293 fprintf(xmlout, "%s <!-- These are size exponents PPx and PPy. May be zero only for first level (aka N(L)LL subband)-->\n", s);
1294 for (i = 0; i < tccp->numresolutions-1; i++) { /* subtract 1 to get # of decomposition levels */
1295 fprintf(xmlout, "%s <PrecinctHeightAndWidth ResolutionLevel=\"%d\">\n", s, i);
1296 if(raw)
1297 fprintf(xmlout,"%s <AsHex>0x%02x</AsHex>\n", s, (tccp->prch[i] << 4) | tccp->prcw[i]); /* packed into 1 byte, SPcox (G) */
1298 if(derived) {
1299 fprintf(xmlout,"%s <WidthAsDecimal>%d</WidthAsDecimal>\n", s, tccp->prcw[i]);
1300 fprintf(xmlout,"%s <HeightAsDecimal>%d</HeightAsDecimal>\n", s, tccp->prch[i]);
1301 }
1302 fprintf(xmlout, "%s </PrecinctHeightAndWidth>\n", s, i);
1303 }
1304 fprintf(xmlout, "%s </PrecinctSize>\n", s); /* 1 byte, SPcox (I_i) */
1305 }
1306 fprintf(xmlout, "%s </SPcoc>\n", s);
1307 fprintf(xmlout, "%s</CodingStyleComponent>\n", s);
1308 }
1309 }
1310
1311 /* ------------- */
1312
same_component_style(opj_tccp_t * tccp1,opj_tccp_t * tccp2)1313 BOOL same_component_style(opj_tccp_t *tccp1, opj_tccp_t *tccp2)
1314 {
1315 int i;
1316
1317 if(tccp1->numresolutions != tccp2->numresolutions)
1318 return FALSE;
1319 if(tccp1->cblkw != tccp2->cblkw)
1320 return FALSE;
1321 if(tccp1->cblkh != tccp2->cblkh)
1322 return FALSE;
1323 if(tccp1->cblksty != tccp2->cblksty)
1324 return FALSE;
1325 if(tccp1->csty != tccp2->csty)
1326 return FALSE;
1327
1328 if (tccp1->csty & J2K_CP_CSTY_PRT) {
1329 for (i = 0; i < tccp1->numresolutions; i++) {
1330 if(tccp1->prcw[i] != tccp2->prcw[i] || tccp1->prch[i] != tccp2->prch[i])
1331 return FALSE;
1332 }
1333 }
1334 return TRUE;
1335 }
1336
1337 /* ------------- */
1338
xml_out_frame_qcd(FILE * xmlout,opj_tcp_t * tcp)1339 void xml_out_frame_qcd(FILE* xmlout, opj_tcp_t *tcp)
1340 {
1341 /* This code will compile only if declaration of j2k_default_tcp is changed from static (to implicit extern) in j2k.c */
1342 opj_tccp_t *tccp;
1343 int bandno, numbands;
1344 char spaces[13] = " "; /* 12 spaces if tilepart*/
1345 char* s = spaces;
1346 if(tcp == j2k_default_tcp) {
1347 s++;s++; /* shorten s to 10 spaces if main */
1348 }
1349
1350 /* Compare j2k_read_qcx */
1351 fprintf(xmlout, "%s<QuantizationDefault Marker=\"QCD\">\n", s); /* Required in main header, single occurrence */
1352 tccp = &(tcp->tccps[0]);
1353 /* Not retained or of interest: Lqcd */
1354 fprintf(xmlout, "%s <Sqcd>\n", s); /* 1 byte */
1355 if(notes)
1356 fprintf(xmlout, "%s <!-- Default quantization style for all components. -->\n", s);
1357 if(raw)
1358 fprintf(xmlout, "%s <AsHex>0x%02x</AsHex>\n", s, (tccp->numgbits) << 5 | tccp->qntsty);
1359 if(derived)
1360 fprintf(xmlout, "%s <QuantizationStyle>%d</QuantizationStyle>\n", s, tccp->qntsty);
1361 if(notes) {
1362 fprintf(xmlout, "%s <!-- Quantization style (in Sqcd's low 5 bits) may be: -->\n", s);
1363 fprintf(xmlout, "%s <!-- 0 = No quantization. SPqcd size = 8 bits-->\n", s);
1364 fprintf(xmlout, "%s <!-- 1 = Scalar derived (values signaled for N(L)LL subband only). Use Eq. E.5. SPqcd size = 16. -->\n", s);
1365 fprintf(xmlout, "%s <!-- 2 = Scalar expounded (values signaled for each subband). SPqcd size = 16. -->\n", s);
1366 }
1367 if(derived)
1368 fprintf(xmlout, "%s <NumberOfGuardBits>%d</NumberOfGuardBits>\n", s, tccp->numgbits);
1369 if(notes)
1370 fprintf(xmlout, "%s <!-- 0-7 guard bits allowed (stored in Sqcd's high 3 bits) -->\n", s);
1371 fprintf(xmlout, "%s </Sqcd>\n", s);
1372
1373 /* Problem: numbands in some cases is calculated from len, which is not retained or available here at this time */
1374 /* So we'll just dump all internal values */
1375 /* We could calculate it, but I'm having trouble believing the length equations in the standard */
1376
1377 fprintf(xmlout, "%s <SPqcd>\n", s);
1378 switch(tccp->qntsty) {
1379 case J2K_CCP_QNTSTY_NOQNT: /* no quantization */
1380 /* This is what standard says, but I don't believe it: len = 4 + (3*decomp); */
1381 numbands = J2K_MAXBANDS; /* should be: numbands = len - 1; */
1382 /* Better: IMAGINE numbands = tccp->stepsize_numbands; */
1383 /* Instead look for first zero exponent, quit there. Adequate? */
1384 fprintf(xmlout, "%s <ReversibleStepSizeValue>\n", s);
1385 if(notes) {
1386 fprintf(xmlout, "%s <!-- Current mj2_to_metadata implementation dumps entire internal table, -->\n", s);
1387 fprintf(xmlout, "%s <!-- until an exponent with zero value is reached. -->\n", s);
1388 fprintf(xmlout, "%s <!-- Exponent epsilon(b) of reversible dynamic range. -->\n", s);
1389 fprintf(xmlout, "%s <!-- Hex value is as stored, in high-order 5 bits. -->\n", s);
1390 }
1391 for (bandno = 0; bandno < numbands; bandno++) {
1392 if(tccp->stepsizes[bandno].expn == 0)
1393 break; /* Remove when we have real numbands */
1394 fprintf(xmlout, "%s <DynamicRangeExponent Subband=\"%d\">\n", s, bandno);
1395 if(raw)
1396 fprintf(xmlout,"%s <AsHex>0x%02x</AsHex>\n", s, tccp->stepsizes[bandno].expn << 3);
1397 if(derived)
1398 fprintf(xmlout,"%s <AsDecimal>%d</AsDecimal>\n", s, tccp->stepsizes[bandno].expn);
1399 fprintf(xmlout, "%s </DynamicRangeExponent>\n", s);
1400 }
1401 fprintf(xmlout, "%s </ReversibleStepSizeValue>\n", s);
1402 break;
1403 case J2K_CCP_QNTSTY_SIQNT: /* scalar quantization derived */
1404 /* This is what standard says. Should I believe it:: len = 5;
1405 /* numbands = 1; */
1406 fprintf(xmlout, "%s <QuantizationStepSizeValues>\n", s);
1407 if(notes)
1408 fprintf(xmlout, "%s <!-- For irreversible transformation only. See Part I Annex E Equation E.3 -->\n", s);
1409 fprintf(xmlout, "%s <QuantizationValues Subband=\"0\">\n", s);
1410 if(notes)
1411 fprintf(xmlout, "%s <!-- For N(L)LL subband: >\n", s);
1412 if(raw)
1413 fprintf(xmlout, "%s <AsHex>0x%02x</AsHex>\n", s, (tccp->stepsizes[0].expn << 11) | tccp->stepsizes[0].mant);
1414 if(derived) {
1415 fprintf(xmlout, "%s <Exponent>%d</Exponent>\n", s, tccp->stepsizes[0].expn);
1416 fprintf(xmlout, "%s <Mantissa>%d</Mantissa>\n", s, tccp->stepsizes[0].mant);
1417 }
1418 fprintf(xmlout, "%s </QuantizationValues>\n", s);
1419 if(notes) {
1420 fprintf(xmlout, "%s <!-- Exponents for subbands beyond 0 are not from header, but calculated per Eq. E.5 -->\n", s);
1421 fprintf(xmlout, "%s <!-- The mantissa for all subbands is the same, given by the value above. -->\n", s);
1422 fprintf(xmlout, "%s <!-- Current mj2_to_metadata implementation dumps entire internal table, -->\n", s);
1423 fprintf(xmlout, "%s <!-- until a subband with exponent of zero value is reached. -->\n", s);
1424 }
1425
1426 for (bandno = 1; bandno < J2K_MAXBANDS; bandno++) {
1427 if(tccp->stepsizes[bandno].expn == 0)
1428 break;
1429
1430 fprintf(xmlout, "%s <CalculatedExponent Subband=\"%d\">%d</CalculatedExponent>\n", s, bandno, tccp->stepsizes[bandno].expn);
1431 }
1432
1433 fprintf(xmlout, "%s </QuantizationStepSizeValues>\n", s);
1434 break;
1435
1436 default: /* J2K_CCP_QNTSTY_SEQNT */ /* scalar quantization expounded */
1437 /* This is what standard says, but should I believe it: len = 5 + 6*decomp; */
1438 numbands = J2K_MAXBANDS; /* should be: (len - 1) / 2;*/
1439 /* Better: IMAGINE numbands = tccp->stepsize_numbands; */
1440 fprintf(xmlout, "%s <QuantizationStepSizeValues>\n", s);
1441 if(notes) {
1442 fprintf(xmlout, "%s <!-- For irreversible transformation only. See Part I Annex E Equation E.3 -->\n", s);
1443 fprintf(xmlout, "%s <!-- Current mj2_to_metadata implementation dumps entire internal table, -->\n", s);
1444 fprintf(xmlout, "%s <!-- until a subband with mantissa and exponent of zero values is reached. -->\n", s);
1445 }
1446 for (bandno = 0; bandno < numbands; bandno++) {
1447 if(tccp->stepsizes[bandno].expn == 0 && tccp->stepsizes[bandno].mant == 0)
1448 break; /* Remove when we have real numbands */
1449
1450 fprintf(xmlout, "%s <QuantizationValues Subband=\"%d\">\n", s, bandno);
1451 if(raw)
1452 fprintf(xmlout,"%s <AsHex>0x%02x</AsHex>\n", s, (tccp->stepsizes[bandno].expn << 11) | tccp->stepsizes[bandno].mant);
1453 if(derived) {
1454 fprintf(xmlout,"%s <Exponent>%d</Exponent>\n", s, tccp->stepsizes[bandno].expn);
1455 fprintf(xmlout,"%s <Mantissa>%d</Mantissa>\n", s, tccp->stepsizes[bandno].mant);
1456 }
1457 fprintf(xmlout, "%s </QuantizationValues>\n", s);
1458 }
1459 fprintf(xmlout, "%s </QuantizationStepSizeValues>\n", s);
1460 break;
1461 } /* switch */
1462 fprintf(xmlout, "%s </SPqcd>\n", s);
1463 fprintf(xmlout, "%s</QuantizationDefault>\n", s);
1464
1465 /* Alignments: " < < < < < To help maintain xml pretty-printing */
1466 }
1467
1468 /* ------------- */
1469
xml_out_frame_qcc(FILE * xmlout,opj_tcp_t * tcp,int numcomps)1470 void xml_out_frame_qcc(FILE* xmlout, opj_tcp_t *tcp, int numcomps)
1471 {
1472 /* Uses global j2k_default_tcp */
1473 /* This code will compile only if declaration of j2k_default_tcp is changed from static (to implicit extern) in j2k.c */
1474 opj_tccp_t *tccp, *firstcomp_tccp;
1475 int bandno, numbands;
1476 int compno;
1477 char spaces[13] = " "; /* 12 spaces if tilepart*/
1478 char* s = spaces;
1479 if(tcp == j2k_default_tcp) {
1480 s++;s++; /* shorten s to 10 spaces if main */
1481 }
1482
1483 firstcomp_tccp = &(tcp->tccps[0]);
1484 /* Internal data structure tccp defines separate defaults for each component, set from main */
1485 /* default, then selectively overwritten. */
1486 /* Compare j2k_read_qcx(...) */
1487 /* We don't really know which was the default, and which were not */
1488 /* Let's pretend that [0] is the default and all others are not */
1489 if(notes) {
1490 fprintf(xmlout, "%s<!-- mj2_to_metadata implementation always reports component[0] as using default QCD, -->\n", s);
1491 if(tcp == j2k_default_tcp)
1492 fprintf(xmlout, "%s<!-- and any other component, with main-header quantization values different from [0], as QCC. -->\n", s);
1493 else
1494 fprintf(xmlout, "%s<!-- and any other component, with tile-part-header quantization values different from [0], as QCC. -->\n", s);
1495 }
1496 for (compno = 1; compno < numcomps; compno++) /* spec says components are zero-based */
1497 {
1498 tccp = &(tcp->tccps[compno]);
1499 if(same_component_quantization(firstcomp_tccp, tccp))
1500 continue;
1501
1502 /* Compare j2k_read_qcx */
1503 fprintf(xmlout, "%s<QuantizationComponent Marker=\"QCC\" Component=\"%d\">\n", s, compno); /* Required in main header, single occurrence */
1504 tccp = &j2k_default_tcp->tccps[0];
1505 /* Not retained or perhaps of interest: Lqcd It maybe can be calculated. */
1506 fprintf(xmlout, "%s <Sqcc>\n", s); /* 1 byte */
1507 if(notes)
1508 fprintf(xmlout, "%s <!-- Quantization style for this component. -->\n", s);
1509 if(raw)
1510 fprintf(xmlout, "%s <AsHex>0x%02x</AsHex>\n", s, (tccp->numgbits) << 5 | tccp->qntsty);
1511 if(derived)
1512 fprintf(xmlout, "%s <QuantizationStyle>%d</QuantizationStyle>\n", s, tccp->qntsty);
1513 if(notes) {
1514 fprintf(xmlout, "%s <!-- Quantization style (in Sqcc's low 5 bits) may be: -->\n", s);
1515 fprintf(xmlout, "%s <!-- 0 = No quantization. SPqcc size = 8 bits-->\n", s);
1516 fprintf(xmlout, "%s <!-- 1 = Scalar derived (values signaled for N(L)LL subband only). Use Eq. E.5. SPqcc size = 16. -->\n", s);
1517 fprintf(xmlout, "%s <!-- 2 = Scalar expounded (values signaled for each subband). SPqcc size = 16. -->\n", s);
1518 }
1519 if(derived)
1520 fprintf(xmlout, "%s <NumberOfGuardBits>%d</NumberOfGuardBits>\n", s, tccp->numgbits);
1521 if(notes)
1522 fprintf(xmlout, "%s <!-- 0-7 guard bits allowed (stored in Sqcc's high 3 bits) -->\n", s);
1523 fprintf(xmlout, "%s </Sqcc>\n", s);
1524
1525 /* Problem: numbands in some cases is calculated from len, which is not retained or available here at this time */
1526 /* So we'll just dump all internal values */
1527 fprintf(xmlout, "%s <SPqcc>\n", s);
1528 switch(tccp->qntsty) {
1529 case J2K_CCP_QNTSTY_NOQNT:
1530 numbands = J2K_MAXBANDS; /* should be: numbands = len - 1; */
1531 /* Better: IMAGINE numbands = tccp->stepsize_numbands; */
1532
1533 /* Instead look for first zero exponent, quit there. Adequate? */
1534 fprintf(xmlout, "%s <ReversibleStepSizeValue>\n", s);
1535 if(notes) {
1536 fprintf(xmlout, "%s <!-- Current mj2_to_metadata implementation dumps entire internal table, -->\n", s);
1537 fprintf(xmlout, "%s <!-- until an exponent with zero value is reached. -->\n", s);
1538 fprintf(xmlout, "%s <!-- Exponent epsilon(b) of reversible dynamic range. -->\n", s);
1539 fprintf(xmlout, "%s <!-- Hex value is as stored, in high-order 5 bits. -->\n", s);
1540 }
1541 for (bandno = 0; bandno < numbands; bandno++) {
1542 if(tccp->stepsizes[bandno].expn == 0)
1543 break; /* Remove this once we have real numbands */
1544 fprintf(xmlout, "%s <Exponent Subband=\"%d\">\n", s, bandno);
1545 if(raw)
1546 fprintf(xmlout,"%s <AsHex>0x%02x</AsHex>\n", s, tccp->stepsizes[bandno].expn << 3);
1547 if(derived)
1548 fprintf(xmlout,"%s <AsDecimal>%d</AsDecimal>\n", s, tccp->stepsizes[bandno].expn);
1549 fprintf(xmlout, "%s </Exponent>\n", s);
1550 }
1551 fprintf(xmlout, "%s </ReversibleStepSizeValue>\n", s);
1552 break;
1553 case J2K_CCP_QNTSTY_SIQNT:
1554 /* numbands = 1; */
1555 fprintf(xmlout, "%s <QuantizationStepSizeValues>\n", s);
1556 if(notes)
1557 fprintf(xmlout, "%s <!-- For irreversible transformation only. See Part I Annex E Equation E.3 -->\n", s);
1558 fprintf(xmlout, "%s <QuantizationValuesForSubband0>\n", s);
1559 if(notes)
1560 fprintf(xmlout, "%s <!-- For N(L)LL subband: >\n", s);
1561 if(raw)
1562 fprintf(xmlout, "%s <AsHex>0x%02x</AsHex>\n", s, (tccp->stepsizes[0].expn << 11) | tccp->stepsizes[0].mant);
1563 if(derived) {
1564 fprintf(xmlout, "%s <Exponent>%d</Exponent>\n", s, tccp->stepsizes[0].expn);
1565 fprintf(xmlout, "%s <Mantissa>%d</Mantissa>\n", s, tccp->stepsizes[0].mant);
1566 }
1567 fprintf(xmlout, "%s </QuantizationValuesForSubband0>\n", s);
1568 if(notes) {
1569 fprintf(xmlout, "%s <!-- Exponents for subbands beyond 0 are not from header, but calculated per Eq. E.5 -->\n", s);
1570 fprintf(xmlout, "%s <!-- The mantissa for all subbands is the same, given by the value above. -->\n", s);
1571 fprintf(xmlout, "%s <!-- Current mj2_to_metadata implementation dumps entire internal table, -->\n", s);
1572 fprintf(xmlout, "%s <!-- until a subband with exponent of zero value is reached. -->\n", s);
1573 }
1574
1575 for (bandno = 1; bandno < J2K_MAXBANDS; bandno++) {
1576 if(tccp->stepsizes[bandno].expn == 0)
1577 break;
1578
1579 fprintf(xmlout, "%s <CalculatedExponent Subband=\"%d\">%d</CalculatedExponent>\n", s, bandno, tccp->stepsizes[bandno].expn);
1580 }
1581 fprintf(xmlout, "%s </QuantizationStepSizeValues>\n", s);
1582 break;
1583
1584 default: /* J2K_CCP_QNTSTY_SEQNT */
1585 numbands = J2K_MAXBANDS; /* should be: (len - 1) / 2;*/
1586 /* Better: IMAGINE numbands = tccp->stepsize_numbands; */
1587 fprintf(xmlout, "%s <QuantizationStepSizeValues>\n", s);
1588 if(notes) {
1589 fprintf(xmlout, "%s <!-- For irreversible transformation only. See Part I Annex E Equation E.3 -->\n", s);
1590 fprintf(xmlout, "%s <!-- Current mj2_to_metadata implementation dumps entire internal table, -->\n", s);
1591 fprintf(xmlout, "%s <!-- until a subband with mantissa and exponent of zero values is reached. -->\n", s);
1592 }
1593 for (bandno = 0; bandno < numbands; bandno++) {
1594 if(tccp->stepsizes[bandno].expn == 0 && tccp->stepsizes[bandno].mant == 0)
1595 break; /* Remove this once we have real numbands count */
1596 fprintf(xmlout, "%s <QuantizationValues Subband=\"%d\">\n", s, bandno);
1597 if(raw)
1598 fprintf(xmlout,"%s <AsHex>0x%02x</AsHex>\n", s, (tccp->stepsizes[bandno].expn << 11) | tccp->stepsizes[bandno].mant);
1599 if(derived) {
1600 fprintf(xmlout,"%s <Exponent>%d</Exponent>\n", s, tccp->stepsizes[bandno].expn);
1601 fprintf(xmlout,"%s <Mantissa>%d</Mantissa>\n", s, tccp->stepsizes[bandno].mant);
1602 }
1603 fprintf(xmlout, "%s </QuantizationValues>\n", s);
1604 }
1605 fprintf(xmlout, "%s </QuantizationStepSizeValues>\n", s);
1606 break;
1607 } /* switch */
1608 fprintf(xmlout, "%s </SPqcc>\n", s);
1609 fprintf(xmlout, "%s</QuantizationComponent>\n", s);
1610 }
1611 /* Alignments: " < < < < < To help maintain xml pretty-printing */
1612 }
1613
1614 /* ------------- */
1615
same_component_quantization(opj_tccp_t * tccp1,opj_tccp_t * tccp2)1616 BOOL same_component_quantization(opj_tccp_t *tccp1, opj_tccp_t *tccp2)
1617 {
1618 int bandno, numbands;
1619
1620 if(tccp1->qntsty != tccp2->qntsty)
1621 return FALSE;
1622 if(tccp1->numgbits != tccp2->numgbits)
1623 return FALSE;
1624
1625 switch(tccp1->qntsty) {
1626 case J2K_CCP_QNTSTY_NOQNT:
1627 numbands = J2K_MAXBANDS; /* should be: numbands = len - 1; */
1628 /* Instead look for first zero exponent, quit there. Adequate? */
1629 for (bandno = 0; bandno < numbands; bandno++) {
1630 if(tccp1->stepsizes[bandno].expn == 0)
1631 break;
1632 if(tccp1->stepsizes[bandno].expn != tccp2->stepsizes[bandno].expn)
1633 return FALSE;
1634 }
1635 break;
1636 case J2K_CCP_QNTSTY_SIQNT:
1637 /* numbands = 1; */
1638 if(tccp1->stepsizes[0].expn != tccp2->stepsizes[0].expn || tccp1->stepsizes[0].mant != tccp2->stepsizes[0].mant)
1639 return FALSE;
1640 /* Don't need to check remainder, since they are calculated from [0] */
1641 break;
1642
1643 default: /* J2K_CCP_QNTSTY_SEQNT */
1644 numbands = J2K_MAXBANDS; /* should be: (len - 1) / 2;*/
1645 /* This comparison may cause us problems with trailing junk values. */
1646 for (bandno = 0; bandno < numbands; bandno++) {
1647 if(tccp1->stepsizes[bandno].expn != tccp2->stepsizes[bandno].expn || tccp1->stepsizes[bandno].mant != tccp2->stepsizes[bandno].mant);
1648 return FALSE;
1649 }
1650 break;
1651 } /* switch */
1652 return TRUE;
1653 }
1654
1655 /* ------------- */
1656
xml_out_frame_rgn(FILE * xmlout,opj_tcp_t * tcp,int numcomps)1657 void xml_out_frame_rgn(FILE* xmlout, opj_tcp_t *tcp, int numcomps)
1658 {
1659 int compno, SPrgn;
1660 /* MJ2 files can have regions of interest if hybridized with JPX Part II */
1661 char spaces[13] = " "; /* 12 spaces if tilepart*/
1662 char* s = spaces;
1663 if(tcp == j2k_default_tcp) {
1664 s++;s++; /* shorten s to 10 spaces if main */
1665 }
1666
1667 for(compno = 0; compno < numcomps; compno++) {
1668 SPrgn = tcp->tccps[compno].roishift; /* 1 byte; SPrgn */
1669 if(SPrgn == 0)
1670 continue; /* Yet another kludge */
1671
1672 fprintf(xmlout, "%s<RegionOfInterest Marker=\"RGN\">\n", s); /* Optional in main header, at most 1 per component */
1673 if(notes)
1674 fprintf(xmlout, "%s<!-- See Crgn below for zero-based component number. -->\n", s);
1675 /* Not retained or of interest: Lrgd */
1676 fprintf(xmlout, "%s <Srgn>0</Srgn>\n", s); /* 1 byte */
1677 if(notes)
1678 fprintf(xmlout, "%s <!-- Srgn is ROI style. Only style=0 defined: Implicit ROI (max. shift) -->\n", s);
1679 fprintf(xmlout, "%s <Crgn>%d</Crgn>\n", s, compno); /* 1 or 2 bytes */
1680 fprintf(xmlout, "%s <SPrgn>%d</SPrgn>\n", s, SPrgn); /* 1 byte */
1681 if(notes)
1682 fprintf(xmlout, "%s <!-- SPrgn is implicit ROI shift, i.e., binary shifting of ROI coefficients above background. -->\n", s);
1683 fprintf(xmlout, "</RegionOfInterest\n", s); /* Optional in main header, at most 1 per component */
1684 }
1685 }
1686
1687 /* ------------- */
1688
xml_out_frame_poc(FILE * xmlout,opj_tcp_t * tcp)1689 void xml_out_frame_poc(FILE* xmlout, opj_tcp_t *tcp) { /* Progression Order Change */
1690 /* Compare j2k_read_poc() */
1691 int i;
1692 opj_poc_t *poc;
1693 char spaces[13] = " "; /* 12 spaces if tilepart*/
1694 char* s = spaces;
1695 if(tcp == j2k_default_tcp) {
1696 s++;s++; /* shorten s to 10 spaces if main */
1697 }
1698
1699 if(tcp->POC != 1)
1700 return; /* Not present */
1701
1702 fprintf(xmlout, "%s<ProgressionOrderChange Marker=\"POC\">\n", s); /* Optional in main header, at most 1 per component */
1703 /* j2k_read_poc seems to allow accumulation of default pocs from multiple POC segments, but does
1704 the spec really allow that? */
1705 /* 2 bytes, not retained; Lpoc */
1706 /* I probably didn't get this dump precisely right. */
1707 for (i = 0; i < tcp->numpocs; i++) {
1708 poc = &tcp->pocs[i];
1709 fprintf(xmlout, "%s <Progression Num=\"%d\">\n", s, i+1);
1710 fprintf(xmlout, "%S <RSpoc>%d</RSpoc>\n", s, poc->resno0); /* 1 byte, RSpoc_i */
1711 if(notes)
1712 fprintf(xmlout,"%s <!-- Resolution level index (inclusive) for progression start. Range: 0 to 33 -->\n", s);
1713 fprintf(xmlout, "%s <CSpoc>%d</CSpoc>\n", s, poc->compno0);/* j2k_img->numcomps <= 256 ? 1 byte : 2 bytes; CSpoc_i */
1714 if(notes)
1715 fprintf(xmlout,"%s <!-- Component index (inclusive) for progression start. -->\n", s);
1716 fprintf(xmlout, "%s <LYEpoc>%d</LYEpoc>\n", s, poc->layno1); /* int_min(cio_read(2), tcp->numlayers); /* 2 bytes; LYEpoc_i */
1717 if(notes)
1718 fprintf(xmlout,"%s <!-- Layer index (exclusive) for progression end. -->\n", s);
1719 fprintf(xmlout, "%s <REpoc>%d</REpoc>\n", s, poc->resno1); /*int_min(cio_read(1), tccp->numresolutions); /* REpoc_i */
1720 if(notes)
1721 fprintf(xmlout,"%s <!-- Resolution level index (exclusive) for progression end. Range: RSpoc to 33 -->\n", s);
1722 fprintf(xmlout, "%s <CEpoc>%d</CEpoc>\n", s, poc->compno1); /* int_min(cio_read(j2k_img->numcomps <= 256 ? 1 : 2), j2k_img->numcomps); /* CEpoc_i */
1723 if(notes)
1724 fprintf(xmlout,"%s <!-- Component index (exclusive) for progression end. Minimum: CSpoc -->\n", s);
1725 fprintf(xmlout, "%s <Ppoc>%d</Ppoc>\n", s, poc->prg); /* 1 byte Ppoc_i */
1726 if(notes) {
1727 fprintf(xmlout,"%s <!-- Defined Progression Order Values are: -->\n", s);
1728 fprintf(xmlout,"%s <!-- 0 = LRCP; 1 = RLCP; 2 = RPCL; 3 = PCRL; 4 = CPRL -->\n", s);
1729 fprintf(xmlout,"%s <!-- where L = \"layer\", R = \"resolution level\", C = \"component\", P = \"position\". -->\n", s);
1730 }
1731 fprintf(xmlout, "%s </Progression>\n", s);
1732 }
1733 fprintf(xmlout, "%s</ProgressionOrderChange\n", s);
1734 }
1735
1736 /* ------------- */
1737
1738 #ifdef SUPPRESS_FOR_NOW
1739 /* Suppress PPM and PPT since we're not showing data from the third option, namely within the codestream, and
1740 that's evidently what frames_to_mj2 uses. And a hex dump isn't so useful anyway */
1741
xml_out_frame_ppm(FILE * xmlout,opj_cp_t * cp)1742 void xml_out_frame_ppm(FILE *xmlout, opj_cp_t *cp) { /* For main header, not tile-part (which uses PPT instead). */
1743 /* Either the PPM or PPT is required if the packet headers are not distributed in the bit stream */
1744 /* Use of PPM and PPT are mutually exclusive. */
1745 /* Compare j2k_read_ppm() */
1746 int j;
1747
1748 if(cp->ppm != 1)
1749 return; /* Not present */
1750 /* Main header uses indent of 10 spaces */
1751 fprintf(xmlout, " <PackedPacketHeadersMainHeader Marker=\"PPM\">\n"); /* Optional in main header, but if not, must be in PPT or codestream */
1752 /* 2 bytes Lppm not saved */
1753 if(notes) {
1754 fprintf(xmlout, " <!-- If there are multiple PPM marker segments in the main header, -->\n");
1755 fprintf(xmlout, " <!-- this mj2_to_metadata implementation will report them as a single consolidated PPM header. -->\n");
1756 fprintf(xmlout, " <!-- The implementation can't currently segregate by tile-part. -->\n");
1757 fprintf(xmlout, " <!-- TO DO? further map the packet headers to xml. -->\n");
1758 }
1759
1760 /* 1 byte, not retained ; Zppm is sequence # of this PPM header */
1761 /* 4 bytes, possibly overwritten multiple times in j2k_cp->ppm_previous: Nppm */
1762 /* Use j symbol for index instead of i, to make comparable with j2k_read_ppm */
1763 /* Not real clear whether to use ppm->store or ppm_len as upper bound */
1764 fprintf(xmlout, " <PackedData>\n");
1765 xml_out_dump_hex(xmlout, cp->ppm_data, cp->ppm_len);
1766 /* Dump packet headers 1 byte at a time: lppm[i][j] */
1767 fprintf(xmlout, " </PackedData>\n");
1768 fprintf(xmlout, " </PackedPacketHeadersMainHeader>\n"); /* Optional in main header, but if not, must be in PPT or codestream */
1769 }
1770
1771 /* ------------- */
1772
xml_out_frame_ppt(FILE * xmlout,opj_tcp_t * tcp)1773 void xml_out_frame_ppt(FILE *xmlout, opj_tcp_t *tcp) { /* For tile-part header, not main (which uses PPM instead). */
1774 /* Either the PPM or PPT is required if the packet headers are not distributed in the bit stream */
1775 /* Use of PPM and PPT are mutually exclusive. */
1776 /* Compare j2k_read_ppt() */
1777 int j;
1778
1779 if(tcp->ppt != 1)
1780 return; /* Not present */
1781
1782 /* Tile-part indents are 12 spaces */
1783 fprintf(xmlout, " <PackedPacketHeadersTilePartHeader Marker=\"PPT\">\n"); /* Optional in main header, but if not, must be in PPT or codestream */
1784 /* 2 bytes Lppm not saved */
1785 if(notes) {
1786 fprintf(xmlout, " <!-- If there are multiple PPT marker segments in the tile-part header, -->\n");
1787 fprintf(xmlout, " <!-- this mj2_to_metadata implementation will report them as a single consolidated PPT header. -->\n");
1788 fprintf(xmlout, " <!-- The implementation can't currently segregate by tile-part. -->\n");
1789 fprintf(xmlout, " <!-- TO DO? further map the packet headers to xml. -->\n");
1790 }
1791
1792 /* 1 byte, not retained ; Zppt is sequence # of this PPT header */
1793 /* 4 bytes, possibly overwritten multiple times in j2k_cp->ppt_previous: Nppt */
1794 /* Use j symbol for index instead of i, to make comparable with j2k_read_ppt */
1795 /* Not real clear whether to use ppt->store or ppt_len as upper bound */
1796 fprintf(xmlout, " <PackedData>\n");
1797 xml_out_dump_hex(xmlout, tcp->ppt_data, tcp->ppt_len);
1798 /* Dump packet headers 1 byte at a time: lppt[i][j] */
1799 fprintf(xmlout, " </PackedData>\n");
1800 fprintf(xmlout, " </PackedPacketHeadersTileHeader>\n"); /* Optional in tile-part header, but if not, must be in PPM or codestream */
1801 }
1802 #endif SUPPRESS_FOR_NOW
1803
1804 /* ------------- */
1805
xml_out_frame_tlm(FILE * xmlout)1806 void xml_out_frame_tlm(FILE* xmlout) { /* opt, main header only. May be multiple. */
1807 /* Compare j2k_read_tlm()... which doesn't retain anything! */
1808 /* Plan: Since this is only called from main header, not tilepart, use global j2k_default_tcp rather than parameter */
1809 /* Main header indents are 10 spaces */
1810 }
1811
1812 /* ------------- */
1813
xml_out_frame_plm(FILE * xmlout)1814 void xml_out_frame_plm(FILE* xmlout) { /* opt, main header only; can be used in conjunction with tile-part's PLT */
1815 /* NO-OP. PLM NOT SAVED IN DATA STRUCTURE */
1816 /* Compare j2k_read_plm()... which doesn't retain anything! */
1817 /* Plan: Since this is only called from main header, not tilepart, use global j2k_default_tcp rather than parameter */
1818 /* Main header indents are 10 spaces */
1819 }
1820
1821 /* ------------- */
1822
xml_out_frame_plt(FILE * xmlout,opj_tcp_t * tcp)1823 void xml_out_frame_plt(FILE* xmlout, opj_tcp_t *tcp) { /* opt, tile-part headers only; can be used in conjunction with main header's PLM */
1824 /* NO-OP. PLT NOT SAVED IN DATA STRUCTURE */
1825 /* Compare j2k_read_plt()... which doesn't retain anything! */
1826 /* Tile-part header indents are 12 spaces */
1827 }
1828
1829 /* ------------- */
1830
xml_out_frame_crg(FILE * xmlout)1831 void xml_out_frame_crg(FILE* xmlout) { /* NO-OP. CRG NOT SAVED IN DATA STRUCTURE */ /* opt, main header only; */
1832 /* Compare j2k_read_crg()... which doesn't retain anything! */
1833 /* Plan: Since this is only called from main header, not tilepart, use global j2k_default_tcp rather than parameter */
1834 #ifdef NOTYET
1835 THIS PSEUDOCODE IMAGINES THESE EXIST: j2k_default_tcp->crg, j2k_default_tcp->crg_i, j2k_default_tcp->crg_xcrg*, j2k_default_tcp->crg_ycrg*
1836 (POSSIBLY DON'T NEED crg_i, CAN GET NUMBER OR COMPONENTS FROM ELSEWHERE)
1837 if(j2k_default_tcp->crg != 1 || j2k_default_tcp->crg_i == 0)
1838 return; /* Not present */
1839
1840 /* Main header indents are 10 spaces */
1841 fprintf(xmlout, " <ComponentRegistration Marker=\"RG\" Count=\"%d\">\n", j2k_default_tcp->crg_i);
1842 if(notes) {
1843 fprintf(xmlout, " <!-- Fine tuning of registration of components with respect to each other, -->\n");
1844 fprintf(xmlout, " <!-- not required but potentially helpful for decoder. -->\n");
1845 fprintf(xmlout, " <!-- These supplementary fractional offsets are in units of 1/65536 of the horizontal -->\n");
1846 fprintf(xmlout, " <!-- or vertical separation (e.g., XRsiz[i] or YRsiz[i] for component i). -->\n");
1847 }
1848 /* This isn't the most compact form of table, but is OK when number of components is small, as is likely. */
1849 for (i = 0; i < j2k_default_tcp->crg_i; i++) {
1850 fprintf(xmlout, " <Component Num=\"%d\">\n", i+1);
1851 fprintf(xmlout, " <Xcrg>\n");
1852 if(raw)
1853 fprintf(xmlout," <AsNumerator>%d</AsNumerator>\n", j2k_default_tcp->crg_xcrg[i]);
1854 if(derived) {
1855 /* Calculate n * 100%/65536; 4 digits after decimal point is sufficiently accurate */
1856 fprintf(xmlout," <AsPercentage>%.4f</AsPercentage>\n", ((double)j2k_default_tcp->crg_xcrg[i])/655.36);
1857 /* We could do another calculation that include XRsiz[i]; maybe later. */
1858 }
1859 fprintf(xmlout, " </Xcrg>\n");
1860 fprintf(xmlout, " <Ycrg>\n");
1861 if(raw)
1862 fprintf(xmlout," <AsNumerator>%d</AsNumerator>\n", j2k_default_tcp->crg_ycrg[i]);
1863 if(derived) {
1864 fprintf(xmlout," <AsPercentage>%f</AsPercentage>\n", ((double)j2k_default_tcp->crg_ycrg[i])/655.36);
1865 }
1866 fprintf(xmlout, " </Ycrg>\n");
1867 fprintf(xmlout, " </Component>\n");
1868 }
1869
1870 fprintf(xmlout, " </ComponentRegistration>\n");
1871
1872 #endif
1873 }
1874
1875 /* ------------- */
1876
1877 /* Regrettably from a metadata point of view, j2k_read_com() skips over any comments in main header or tile-part-header */
1878 void xml_out_frame_com(FILE* xmlout, opj_tcp_t *tcp) { /* NO-OP. COM NOT SAVED IN DATA STRUCTURE */ /* opt in main or tile-part headers; */
1879 /* Compare j2k_read_com()... which doesn't retain anything! */
1880 #ifdef NOTYET
1881 char spaces[13] = " "; /* 12 spaces if tilepart*/
1882 char* s = spaces;
1883 if(tcp == &j2k_default_tcp) {
1884 s++;s++; /* shorten s to 10 spaces if main */
1885 }
1886 THIS PSEUDOCODE IMAGINES THESE EXIST: tcp->com, tcp->com_len, tcp->com_data array
1887 if(tcp->com != 1)
1888 return; /* Not present */
1889
1890 fprintf(xmlout, "%s<Comment Marker=\"COM\">\n", s); /* Optional in main or tile-part header */
1891 xml_out_dump_hex_and_ascii(tcp->com_data, tcp->com_len, s);
1892 fprintf(xmlout, "%s</Comment>\n", s);
1893 #endif
1894 }
1895
1896 void xml_out_dump_hex(FILE* xmlout, char *data, int data_len, char* s) {
1897 /* s is a string of spaces for indent */
1898 int i;
1899
1900 /* This is called when raw is true, or there is no appropriate derived form */
1901 fprintf(xmlout, "%s<AsHex>\n", s);
1902 fprintf(xmlout, "%s ", s); /* Inadequate for pretty printing */
1903 for (i = 0; i < data_len; i++) { /* Dump packet headers */
1904 fprintf(xmlout, "%02x", data[i]);
1905 }
1906 fprintf(xmlout, "%s</AsHex>\n", s);
1907 }
1908
1909 /* Define this as an even number: */
1910 #define BYTES_PER_DUMP_LINE 40
1911 /* Current total width for Hex and ASCII is : 11 spaces lead + (3 * BPDL) + 2 spaces + BPDL */
1912 void xml_out_dump_hex_and_ascii(FILE* xmlout, char *data, int data_len, char* s) {
1913 /* s is a string of spaces for indent */
1914 int i,j;
1915
1916 if(raw)
1917 xml_out_dump_hex(xmlout, data, data_len, s);
1918
1919 if(derived) {
1920 fprintf(xmlout, "%s<AsHexAndASCII>\n", s);
1921 for (i = 0; i < data_len; ) {
1922 fprintf(xmlout,"%s ", s); /* Additional leading space added in loop */
1923 /* First column: hex */
1924 for (j = 0; j < BYTES_PER_DUMP_LINE; j++) /* Dump bytes */
1925 fprintf(xmlout," %02x", data[i+j]);
1926 /* Space between columns... */ fprintf(xmlout, " ");
1927 /* Second column: ASCII */
1928 for (j = 0; j < BYTES_PER_DUMP_LINE; j++, i++) {
1929 if(isprint((int)data[i]) && i < data_len)
1930 fprintf(xmlout,"%c", data[i]);
1931 else
1932 fprintf(xmlout," ");
1933 }
1934 /* If we also wanted to output UCS-2 Unicode as a third column, then entire document
1935 must use fwprintf. Forget about it for now. As it stands, if data is UCS-2 format but still
1936 the ASCII set, then we'll be able to read every other byte as ASCII in column 2. If
1937 data is UTF-8 format but still ASCII, then we'll be able to read every byte as ASCII
1938 in column 2. */
1939 }
1940 fprintf(xmlout, "%s</AsHexAndASCII>\n", s);
1941 }
1942 }
1943
1944
1945 /* ------------- */
1946
1947 void xml_out_frame_jp2h(FILE* xmlout, opj_jp2_t *jp2_struct) { /* JP2 Header */
1948 /* Compare jp2_read_jp2h(opj_jp2_t * jp2_struct) */
1949 int i;
1950
1951 fprintf(xmlout, " <JP2Header BoxType=\"jp2h\">\n");
1952
1953 /* Compare jp2_read_ihdr(jp2_struct)) */
1954 fprintf(xmlout, " <ImageHeader BoxType=\"ihdr\">\n");
1955 fprintf(xmlout, " <HEIGHT>%d</HEIGHT>\n", jp2_struct->h); /* 4 bytes */
1956 fprintf(xmlout, " <WIDTH>%d</WIDTH>\n", jp2_struct->w); /* 4 bytes */
1957 if(notes)
1958 fprintf(xmlout, " <!-- HEIGHT here, if 2 fields per image, is of total deinterlaced height. -->\n");
1959 fprintf(xmlout, " <NC>%d</NC>\n", jp2_struct->numcomps); /* 2 bytes */
1960 if(notes)
1961 fprintf(xmlout, " <!-- NC is number of components -->\n"); /* 2 bytes */
1962 fprintf(xmlout, " <BPC>\n"); /* 1 byte */
1963 if(jp2_struct->bpc == 255) {
1964 fprintf(xmlout, " <AsHex>0x%02x</AsHex>\n", jp2_struct->bpc); /* 1 byte */
1965 if(notes)
1966 fprintf(xmlout, " <!-- BPC = 0xff means bits per pixel varies with component; see table below. -->\n");
1967 } else { /* Not 0xff */
1968 if(raw) {
1969 fprintf(xmlout, " <AsHex>0x%02x</AsHex>\n", jp2_struct->bpc); /* 1 byte */
1970 if(notes)
1971 fprintf(xmlout," <!-- BPC = 0xff means bits per pixel varies with component; see table below. -->\n");
1972 }
1973 if(derived) {
1974 fprintf(xmlout, " <BitsPerPixel>%d</BitsPerPixel>\n", jp2_struct->bpc & 0x7f);
1975 fprintf(xmlout, " <Signed>%d</Signed>\n", jp2_struct->bpc >> 7);
1976 }
1977 }
1978 fprintf(xmlout, " </BPC>\n");
1979 fprintf(xmlout, " <C>%d</C>\n", jp2_struct->C); /* 1 byte */
1980 if(notes)
1981 fprintf(xmlout, " <!-- C is compression type. Only \"7\" is allowed to date. -->\n"); /* 2 bytes */
1982 fprintf(xmlout, " <UnkC>%d</UnkC>\n", jp2_struct->UnkC); /* 1 byte */
1983 if(notes)
1984 fprintf(xmlout, " <!-- Colourspace Unknown. 1 = unknown, 0 = known (e.g., colourspace spec is accurate) -->\n"); /* 1 byte */
1985 fprintf(xmlout, " <IPR>%d</IPR>\n", jp2_struct->IPR); /* 1 byte */
1986 if(notes)
1987 fprintf(xmlout, " <!-- IPR is 1 if frame contains an Intellectual Property box; 0 otherwise. -->\n"); /* 2 bytes */
1988 fprintf(xmlout, " </ImageHeader>\n");
1989
1990 if (jp2_struct->bpc == 255)
1991 {
1992 fprintf(xmlout, " <BitsPerComponent BoxType=\"bpcc\">\n");
1993 if(notes)
1994 fprintf(xmlout, " <!-- Pixel depth (range 1 to 38) is low 7 bits of hex value + 1 -->\n");
1995 /* Bits per pixel varies with components */
1996 /* Compare jp2_read_bpcc(jp2_struct) */
1997 for (i = 0; i < (int)jp2_struct->numcomps; i++) {
1998 if(raw)
1999 fprintf(xmlout," <AsHex>0x%02x</AsHex>\n", jp2_struct->comps[i].bpcc); /* 1 byte */
2000 if(derived) {
2001 fprintf(xmlout," <BitsPerPixel>%d</BitsPerPixel>\n", (jp2_struct->comps[i].bpcc & 0x7f)+1);
2002 fprintf(xmlout," <Signed>%d</Signed>\n", jp2_struct->comps[i].bpcc >> 7);
2003 }
2004 }
2005 fprintf(xmlout, " </BitsPerComponent>\n");
2006 }
2007
2008 /* Compare jp2_read_colr(jp2_struct) */
2009 fprintf(xmlout, " <ColourSpecification BoxType=\"colr\">\n");
2010 fprintf(xmlout, " <METH>%d</METH>\n", jp2_struct->meth); /* 1 byte */
2011 if(notes) {
2012 fprintf(xmlout, " <!-- Valid values of specification method so far: -->\n");
2013 fprintf(xmlout, " <!-- 1 = Enumerated colourspace, in EnumCS field -->\n");
2014 fprintf(xmlout, " <!-- 2 = Restricted ICC Profile, in PROFILE field -->\n");
2015 }
2016 fprintf(xmlout, " <PREC>%d</PREC>\n", jp2_struct->precedence); /* 1 byte */
2017 if(notes)
2018 fprintf(xmlout, " <!-- 0 is only valid value of precedence so far. -->\n");
2019 fprintf(xmlout, " <APPROX>%d</APPROX>\n", jp2_struct->approx); /* 1 byte */
2020 if(notes)
2021 fprintf(xmlout, " <!-- 0 is only valid value of colourspace approximation so far. -->\n");
2022
2023 if (jp2_struct->meth == 1) {
2024 fprintf(xmlout, " <EnumCS>%d</EnumCS>\n", jp2_struct->enumcs); /* 4 bytes */
2025 if(notes) {
2026 fprintf(xmlout, " <!-- Valid values of enumerated MJ2 colourspace so far: -->\n");
2027 fprintf(xmlout, " <!-- 16: sRGB as defined by IEC 61966-2-1. -->\n");
2028 fprintf(xmlout, " <!-- 17: greyscale (related to sRGB). -->\n");
2029 fprintf(xmlout, " <!-- 18: sRGB YCC (from JPEG 2000 Part II). -->\n");
2030 fprintf(xmlout, " <!-- (Additional JPX values are defined in Part II). -->\n");
2031 }
2032 }
2033 else
2034 if(notes)
2035 fprintf(xmlout, " <!-- PROFILE is not handled by current OpenJPEG implementation. -->\n");
2036 /* only 1 byte is read and nothing stored */
2037 fprintf(xmlout, " </ColourSpecification>\n");
2038
2039 /* TO DO? No OpenJPEG support.
2040 Palette 'pclr'
2041 ComponentMapping 'cmap'
2042 ChannelDefinition 'cdef'
2043 Resolution 'res'
2044 */
2045 fprintf(xmlout, " </JP2Header>\n");
2046 }
2047 /* ------------- */
2048
2049 #ifdef NOTYET
2050 IMAGE these use cp structure, extended... but we could use a new data structure instead
2051 void xml_out_frame_jp2i(FILE* xmlout, opj_cp_t *cp) {
2052 /* IntellectualProperty 'jp2i' (no restrictions on location) */
2053 int i;
2054 IMAGE cp->jp2i, cp->jp2i_count, cp->jp2i_data (array of chars), cp->cp2i_len (array of ints)
2055 if(cp->jp2i != 1)
2056 return; /* Not present */
2057
2058 for(i = 0; i < cp->jp2i_count; i++)
2059 {
2060 fprintf(xmlout, " <IntellectualProperty BoxType=\"jp2i\">\n");
2061 /* I think this can be anything, including binary, so do a dump */
2062 /* Is it better to indent or not indent this content? Indent is better for reading, but
2063 worse for cut/paste. */
2064 xml_out_dump_hex_and_ascii(xmlout, cp->jp2i_data[i], cp->jp2i_len[i]);
2065 fprintf(xmlout, " </IntellectualProperty>\n");
2066 }
2067 }
2068
2069 void xml_out_frame_xml(FILE* xmlout, opj_cp_t *cp) {
2070 /* XML 'xml\040' (0x786d6c20). Can appear multiply, before or after jp2c codestreams */
2071 IMAGE cp->xml, cp->xml_count, cp->xml_data (array of chars)
2072 MAYBE WE DON'T NEED cp->xml_len (array of ints) IF WE ASSUME xml_data IS NULL-TERMINATED.
2073 ASSUME ASSUME EACH LINE IS ENDED BY \n.
2074 int i;
2075 if(cp->xml != 1)
2076 return; /* Not present */
2077
2078 for(i = 0; i < cp->xml_count; i++)
2079 {
2080 fprintf(xmlout, " <TextFormXML BoxType=\"xml[space]" Instance=\"%d\">\n", i+1);
2081 /* Is it better to indent or not indent this content? Indent is better for reading, but
2082 worse for cut/paste. Being lazy, didn't indent here. */
2083 fprintf(xmlout,cp->xml_data[i]); /* May be multiple lines */ /* Could check if this is well-formed */
2084 fprintf(xmlout, " </TextFormXML>\n");
2085 }
2086 }
2087
2088 void xml_out_frame_uuid(FILE* xmlout, opj_cp_t *cp) {
2089 /* UUID 'uuid' (top level only) */
2090 /* Part I 1.7.2 says: may appear multiply in JP2 file, anywhere except before File Type box */
2091 /* Part III 5.2.1 says: Private extensions shall be achieved through the 'uuid' type. */
2092 /* A UUID is a 16-byte value. There is a conventional string representation for it:
2093 "0x12345678-9ABC-DEF0-1234-567890ABCDEF". Let's assume that is what is stored in uuid_value */
2094
2095 /* Part III 6.1 Any other MJ2 box type could be alternatively written as a 'uuid' box, with value given
2096 as : 0xXXXXXXXX-0011-0010-8000-00AA00389B71, where the Xs are the boxtype in hex. However,
2097 such a file is "not compliant; systems may choose to read [such] objects ... as equivalent to the box of
2098 the same type, or not." Here, we choose not to. */
2099 int i;
2100 IMAGE cp->uuid, cp->uuid_count, cp->uuid_value (array of uuids... let's say fixed-length strings) cp->uuid_data (array of char buffers), cp->uuid_len (array of ints)
2101 if(cp->juuid != 1)
2102 return; /* Not present */
2103
2104 for(i = 0; i < cp->uuid_count; i++)
2105 {
2106 fprintf(xmlout, " <UniversalUniqueID BoxType=\"uuid\">
2107 fprintf(xmlout, " <UUID>%s</UUDI>\n", cp->uuid_value[i]);
2108 fprintf(xmlout, " <Data>\n");
2109 /* I think this can be anything, including binary, so do a dump */
2110 /* Is it better to indent or not indent this content? Indent is better for reading, but
2111 worse for cut/paste. */
2112 xml_out_dump_hex_and_ascii(xmlout, cp->uuid_data[i], cp->uuid_len[i]);
2113 fprintf(xmlout, " </Data>\n");
2114 fprintf(xmlout, " </UniversalUniqueID>\n");
2115 }
2116 }
2117
2118 void xml_out_frame_uinf(FILE* xmlout, opj_cp_t *cp) {
2119 /* UUIDInfo 'uinf', includes UUIDList 'ulst' and URL 'url\40' */
2120 /* Part I 1.7.3 says: may appear multiply in JP2 file, anywhere at the top level except before File Type box */
2121 /* So there may be multiple ulst's, and each can have multiple UUIDs listed (with a single URL) */
2122 /* This is not quite as vendor-specific as UUIDs, or at least is meant to be generally readable */
2123 /* Assume UUIDs stored in canonical string format */
2124 int i, j;
2125 IMAGE cp->uinf, cp->uinf_count, cp->uinf_ulst_nu (array of ints)
2126 cp->uinf_uuid (2 dimensional array of uuids... let's say fixed-length strings),
2127 cp->uinf_url (array of char buffers)
2128
2129 if(cp->uinf != 1)
2130 return; /* Not present */
2131
2132 for(i = 0; i < cp->uuid_count; i++)
2133 {
2134 fprintf(xmlout, " <UUIDInfo BoxType=\"uinf\">\n");
2135 fprintf(xmlout, " <UUIDList BoxType=\"ulst\" Count=\"%d\">\n",cp->cp->uinf_ulst_nu[i]);
2136 for(j = 0; j < cp->uinf_ulst_nu[i]; j++)
2137 fprintf(xmlout, " <ID Instance=\"%s\">%s</ID>\n", cp->uuif_uuid[i][j], j+1);
2138 fprintf(xmlout, " </UUIDList>\n");
2139 fprintf(xmlout, " <DataEntryURL>\n");
2140 /* Could add VERS and FLAG here */
2141 fprintf(xmlout, " <LOC>\n");
2142 fprintf(xmlout, " %s",cp->uinf_url[i]); /* Probably single line, so indent works */ /* In theory, could check if this is well-formed, or good live link */
2143 fprintf(xmlout, " </LOC>\n");
2144 fprintf(xmlout, " </DataEntryURL>\n");
2145 fprintf(xmlout, " </UUIDInfo>\n");
2146 }
2147 }
2148
2149 IMAGE these use cp structure, extended... but we could use a new data structure instead
2150 void xml_out_frame_unknown_type(FILE* xmlout, opj_cp_t *cp) {
2151 /* Part III 5.2.1 says "Type fields not defined here are reserved. Private extensions
2152 shall be acieved through the 'uuid' type." [This implies an unknown
2153 type would be an error, but then...] "Boxes not explicitly defined in this standard,
2154 or otherwise unrecognized by a reader, may be ignored."
2155 Also, it says "the following types are not and will not be used, or used only in
2156 their existing sense, in future versions of this specification, to avoid conflict
2157 with existing content using earlier pre-standard versions of this format:
2158 clip, crgn, matt, kmat, pnot, ctab, load, imap;
2159 track reference types tmcd, chap, sync,scpt, ssrc"
2160 [But good luck figuring out the mapping.]
2161 Part III Amend. 2 4.1 is stronger: "All these specifications [of this family, e.g.,
2162 JP2 Part I, ISO Base format (Part 12) leading to MP4, Quicktime, and possibly including
2163 MJ2] require that readers ignore objects that are unrecognizable to them".
2164 */
2165 int i;
2166 IMAGE cp->unknown_type, cp->unknown_type_count, cp->unknown_type_boxtype (array of buf[5]s), cp->unknown_type_data (array of chars), cp->unknown_type_len (array of ints)
2167 if(cp->unknown_type != 1)
2168 return; /* Not present */
2169
2170 for(i = 0; i < cp->unknown_type_count; i++)
2171 {
2172 fprintf(xmlout, " <UnknownType BoxType=\"%s\">\n", cp->unknown_type_boxtype[i]);
2173 /* Can be anything, including binary, so do a dump */
2174 /* Is it better to indent or not indent this content? Indent is better for reading, but
2175 worse for cut/paste. */
2176 xml_out_dump_hex_and_ascii(xmlout, cp->unknown_type_data[i], cp->unknown_type_len[i]);
2177 fprintf(xmlout, " </UnknownType>\n");
2178 }
2179 }
2180
2181 #endif
2182