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.
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.
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.
23 #define _CRTDBG_MAP_ALLOC
24 #include <stdlib.h> // Must be included first
29 #include <windows.h> /* for time functions */
35 extern j2k_tcp_t j2k_default_tcp;
36 static BOOL notes = TRUE;
37 static BOOL sampletables = FALSE;
38 static BOOL raw = TRUE;
39 static BOOL derived = TRUE;
42 int xml_write_overall_header(FILE *file, FILE *xmlout, mj2_movie_t * movie, unsigned int sampleframe);
43 int xml_write_moov(FILE *file, FILE *xmlout, mj2_movie_t * movie, unsigned int sampleframe);
45 void uint_to_chars(unsigned int value, char* buf);
47 void xml_write_trak(FILE *file, FILE *xmlout, mj2_tk_t *track, unsigned int tnum, unsigned int sampleframe);
48 void xml_write_tkhd(FILE* file, FILE* xmlout, mj2_tk_t *track, unsigned int tnum);
49 void xml_write_udta(FILE* file, FILE* xmlout, mj2_tk_t *track, unsigned int tnum);
50 void xml_write_mdia(FILE* file, FILE* xmlout, mj2_tk_t *track, unsigned int tnum);
51 void xml_write_stbl(FILE* file, FILE* xmlout, mj2_tk_t *track, unsigned int tnum);
53 void UnixTimeToFileTime(time_t t, LPFILETIME pft);
54 void UnixTimeToSystemTime(time_t t, LPSYSTEMTIME pst);
55 void xml_time_out(FILE* xmlout, time_t t);
57 void int16_to_3packedchars(short int value, char* buf);
59 void xml_write_moov_udta(FILE* xmlout, mj2_movie_t * movie);
60 void xml_write_free_and_skip(FILE* xmlout, mj2_movie_t * movie);
61 void xml_write_uuid(FILE* xmlout, mj2_movie_t * movie);
63 int xml_out_frame(FILE* file, FILE* xmlout, mj2_sample_t *sample, unsigned int snum);
65 void xml_out_frame_siz(FILE* xmlout, j2k_image_t *img, j2k_cp_t *cp);
66 void xml_out_frame_cod(FILE* xmlout, j2k_tcp_t *tcp);
67 void xml_out_frame_coc(FILE* xmlout, j2k_tcp_t *tcp, int numcomps); /* j2k_image_t *img); */
68 BOOL same_component_style(j2k_tccp_t *tccp1, j2k_tccp_t *tccp2);
69 void xml_out_frame_qcd(FILE* xmlout, j2k_tcp_t *tcp);
70 void xml_out_frame_qcc(FILE* xmlout, j2k_tcp_t *tcp, int numcomps); /* j2k_image_t *img); */
71 BOOL same_component_quantization(j2k_tccp_t *tccp1, j2k_tccp_t *tccp2);
72 void xml_out_frame_rgn(FILE* xmlout, j2k_tcp_t *tcp, int numcomps);/* j2k_image_t *img);*/
73 void xml_out_frame_poc(FILE* xmlout, j2k_tcp_t *tcp);
74 void xml_out_frame_ppm(FILE* xmlout, j2k_cp_t *cp);
75 void xml_out_frame_ppt(FILE* xmlout, j2k_tcp_t *tcp);
76 void xml_out_frame_tlm(FILE* xmlout); /* j2k_default_tcp is passed globally */ /* NO-OP. TLM NOT SAVED IN DATA STRUCTURE */
77 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 */
78 void xml_out_frame_plt(FILE* xmlout, j2k_tcp_t *tcp); /* NO-OP. PLM NOT SAVED IN DATA STRUCTURE. opt in main; can be used in conjunction with PLT */
79 void xml_out_frame_crg(FILE* xmlout); /* j2k_default_tcp is passed globally */ /* opt in main; */
80 void xml_out_frame_com(FILE* xmlout, j2k_tcp_t *tcp); /* NO-OP. COM NOT SAVED IN DATA STRUCTURE */ /* opt in main; */
81 void xml_out_dump_hex(FILE* xmlout, char *data, int data_len, char* s);
82 void xml_out_dump_hex_and_ascii(FILE* xmlout, char *data, int data_len, char* s);
83 void xml_out_frame_jp2h(FILE* xmlout, jp2_struct_t *jp2_struct);
85 /* Shown with cp, extended, as data structure... but it could be a new different one */
86 void xml_out_frame_jp2i(FILE* xmlout, j2k_cp_t *cp);/* IntellectualProperty 'jp2i' (no restrictions on location) */
87 void xml_out_frame_xml(FILE* xmlout, j2k_cp_t *cp); /* XML 'xml\040' (0x786d6c20). Can appear multiply */
88 void xml_out_frame_uuid(FILE* xmlout, j2k_cp_t *cp); /* UUID 'uuid' (top level only) */
89 void xml_out_frame_uinf(FILE* xmlout, j2k_cp_t *cp); /* UUIDInfo 'uinf', includes UUIDList 'ulst' and URL 'url\40' */
90 void xml_out_frame_unknown_type(FILE* xmlout, j2k_cp_t *cp);
94 /* ------------------------------------------------------------------------------------------- */
96 void xml_write_init(BOOL n, BOOL t, BOOL r, BOOL d)
98 /* Init file globals */
105 int xml_write_struct(FILE* file, FILE *xmlout, mj2_movie_t * movie, unsigned int sampleframe, char* stringDTD) {
107 if(stringDTD != NULL)
109 fprintf(xmlout,"<?xml version=\"1.0\" standalone=\"no\"?>\n");
110 /* stringDTD is known to start with "SYSTEM " or "PUBLIC " */
111 /* typical: SYSTEM mj2_to_metadata.dtd */
112 stringDTD[6] = '\0'; /* Break into two strings at space, so quotes can be inserted. */
113 fprintf(xmlout,"<!DOCTYPE MJ2_File %s \"%s\">\n", stringDTD, stringDTD+7);
114 stringDTD[6] = ' '; /* restore for sake of debugger or memory allocator */
116 fprintf(xmlout,"<?xml version=\"1.0\" standalone=\"yes\"?>\n");
118 fprintf(xmlout, "<MJ2_File>\n");
119 xml_write_overall_header(file, xmlout, movie, sampleframe);
120 fprintf(xmlout, "</MJ2_File>");
126 int xml_write_overall_header(FILE *file, FILE *xmlout, mj2_movie_t * movie, unsigned int sampleframe)
132 fprintf(xmlout, " <JP2 BoxType=\"jP[space][space]\" Signature=\"0x0d0a870a\" />\n");
133 // Called after structure initialized by mj2_read_ftyp
134 fprintf(xmlout, " <FileType BoxType=\"ftyp\">\n");
135 uint_to_chars(movie->brand, buf);
136 fprintf(xmlout, " <Brand>%s</Brand>\n", buf); /* 4 character; BR */
137 fprintf(xmlout, " <MinorVersion>%u</MinorVersion>\n", movie->minversion); /* 4 char; MinV */
138 fprintf(xmlout, " <CompatibilityList Count=\"%d\">\n",movie->num_cl);
139 for (i = movie->num_cl - 1; i > -1; i--) /* read routine stored in reverse order, so let's undo damage */
141 uint_to_chars(movie->cl[i], buf);
142 fprintf(xmlout, " <CompatibleBrand>%s</CompatibleBrand>\n", buf); /*4 characters, each CLi */
144 fprintf(xmlout, " </CompatibilityList>\n");
145 fprintf(xmlout, " </FileType>\n");
146 xml_write_moov(file, xmlout, movie, sampleframe);
147 // To come? <mdat> // This is the container for media data that can also be accessed through track structures,
148 // so is redundant, and simply not of interest as metadata
149 // <moof> // Allows incremental build up of movie. Probably not in Simple Profile
150 xml_write_free_and_skip(xmlout, movie); /* NO OP so far */ /* May be a place where user squirrels metadata */
151 xml_write_uuid(xmlout, movie); /* NO OP so far */ /* May be a place where user squirrels metadata */
157 int xml_write_moov(FILE *file, FILE *xmlout, mj2_movie_t * movie, unsigned int sampleframe)
162 fprintf(xmlout, " <MovieBox BoxType=\"moov\">\n");
163 fprintf(xmlout, " <MovieHeader BoxType=\"mvhd\">\n");
164 fprintf(xmlout, " <CreationTime>\n");
166 fprintf(xmlout, " <InSeconds>%u</InSeconds>\n", movie->creation_time);
168 fprintf(xmlout, " <!-- Seconds since start of Jan. 1, 1904 UTC (Greenwich) -->\n");
169 /* 2082844800 = seconds between 1/1/04 and 1/1/70 */
170 /* There's still a time zone offset problem not solved... but spec is ambigous as to whether stored time
171 should be local or UTC */
173 fprintf(xmlout, " <AsLocalTime>");
174 xml_time_out(xmlout, movie->creation_time - 2082844800);
175 fprintf(xmlout,"</AsLocalTime>\n");
177 fprintf(xmlout, " </CreationTime>\n");
178 fprintf(xmlout, " <ModificationTime>\n");
180 fprintf(xmlout, " <InSeconds>%u</InSeconds>\n", movie->modification_time);
182 fprintf(xmlout, " <AsLocalTime>");
183 xml_time_out(xmlout, movie->modification_time - 2082844800);
184 fprintf(xmlout,"</AsLocalTime>\n");
186 fprintf(xmlout, " </ModificationTime>\n");
187 fprintf(xmlout, " <Timescale>%d</Timescale>\n", movie->timescale);
189 fprintf(xmlout, " <!-- Timescale defines time units in one second -->\n");
190 fprintf(xmlout, " <Rate>\n"); /* Rate to play presentation (default = 0x00010000) */
191 #define CURRENTSTRUCT
193 movie->rate = movie->rate << 16;
196 fprintf(xmlout, " <!-- Rate to play presentation is stored as fixed-point binary 16.16 value. Decimal value is approximation. -->\n");
197 fprintf(xmlout, " <!-- Rate is expressed relative to normal (default) value of 0x00010000 (1.0) -->\n");
200 fprintf(xmlout, " <AsHex>0x%08x</AsHex>\n", movie->rate);
202 fprintf(xmlout, " <AsDecimal>%12.6f</AsDecimal>\n", (double)movie->rate/(double)0x00010000);
205 fprintf(xmlout, " <!-- Current m2j_to_metadata implementation always shows bits to right of decimal as zeroed. -->\n");
206 movie->rate = movie->rate >> 16;
208 fprintf(xmlout, " </Rate>\n");
209 fprintf(xmlout, " <Duration>\n");
211 fprintf(xmlout, " <InTimeUnits>%u</InTimeUnits>\n", movie->duration);
213 fprintf(xmlout, " <InSeconds>%12.3f</InSeconds>\n", (double)movie->duration/(double)movie->timescale); // Make this double later to get fractional seconds
214 fprintf(xmlout, " </Duration>\n");
216 movie->volume = movie->volume << 8;
218 fprintf(xmlout, " <Volume>\n");
220 fprintf(xmlout, " <!-- Audio volume stored as fixed-point binary 8.8 value. Decimal value is approximation. -->\n");
221 fprintf(xmlout, " <!-- Full, normal (default) value is 0x0100 (1.0) -->\n");
224 fprintf(xmlout, " <AsHex>0x%04x</AsHex>\n", movie->volume);
226 fprintf(xmlout, " <AsDecimal>%6.3f</AsDecimal>\n", (double)movie->volume/(double)0x0100);
227 fprintf(xmlout, " </Volume>\n");
230 fprintf(xmlout, " <!-- Current m2j_to_metadata implementation always shows bits to right of decimal as zeroed. -->\n");
231 movie->volume = movie->volume >> 8;
233 /* Transformation matrix for video */
234 fprintf(xmlout, " <TransformationMatrix>\n");
236 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");
237 fprintf(xmlout, " <!-- Maps decompressed point (p,q) to rendered point (ap + cq + x, bp + dq + y) -->\n");
238 fprintf(xmlout, " <!-- Stored as Fixed Point Hex: all are binary 16.16, except u,v,w are 2.30 -->\n");
239 fprintf(xmlout, " <!-- Unity = 0x00010000,0,0,0,0x00010000,0,0,0,0x40000000 -->\n");
241 fprintf(xmlout, " <TMa>0x%08x</TMa>\n", movie->trans_matrix[0]);
242 fprintf(xmlout, " <TMb>0x%08x</TMb>\n", movie->trans_matrix[1]);
243 fprintf(xmlout, " <TMu>0x%08x</TMu>\n", movie->trans_matrix[2]);
244 fprintf(xmlout, " <TMc>0x%08x</TMc>\n", movie->trans_matrix[3]);
245 fprintf(xmlout, " <TMd>0x%08x</TMd>\n", movie->trans_matrix[4]);
246 fprintf(xmlout, " <TMv>0x%08x</TMv>\n", movie->trans_matrix[5]);
247 fprintf(xmlout, " <TMx>0x%08x</TMx>\n", movie->trans_matrix[6]);
248 fprintf(xmlout, " <TMy>0x%08x</TMy>\n", movie->trans_matrix[7]);
249 fprintf(xmlout, " <TMw>0x%08x</TMw>\n", movie->trans_matrix[8]);
250 fprintf(xmlout, " </TransformationMatrix>\n");
251 fprintf(xmlout, " </MovieHeader>\n");
253 fprintf(xmlout, " <Statistics>\n");
254 fprintf(xmlout, " <TracksFound>\n");
255 fprintf(xmlout, " <Video>%d</Video>\n", movie->num_vtk);
256 fprintf(xmlout, " <Audio>%d</Audio>\n", movie->num_stk);
257 fprintf(xmlout, " <Hint>%d</Hint>\n", movie->num_htk);
259 fprintf(xmlout, " <!-- Hint tracks for streaming video are not part of MJ2, but are a defined extension. -->\n");
260 /* See Part 3 Amend 2 Section 4.2 for relation of MJ2 to Part 12 Sections 7 and 10 hints */
261 fprintf(xmlout, " </TracksFound>\n");
262 fprintf(xmlout, " </Statistics>\n");
263 /* Idea for the future: It would be possible to add code to verify that the file values:
264 1) are legal and self-consistent
265 2) comply with particular JP2 and/or MJ2 profiles.
266 This could be reported here as additional XML elements */
268 // Find first video track
270 while (movie->tk[tnum].track_type != 0)
273 track = &(movie->tk[tnum]);
274 // For now, output info on first video track
275 xml_write_trak(file, xmlout, track, tnum, sampleframe);
277 // to come: <MovieExtends mvek> // possibly not in Simple Profile
278 xml_write_moov_udta(xmlout, movie); /* NO OP so far */ /* <UserDataBox udta> contains <CopyrightBox cprt> */
279 fprintf(xmlout, " </MovieBox>\n");
283 /* --------------- */
285 void uint_to_chars(unsigned int value, char* buf)
287 /* buf is at least char[5] */
289 for (i = 3; i >= 0; i--)
291 buf[i] = (value & 0x000000ff);
292 value = (value >> 8);
294 buf[4] = '\0'; /* Precautionary */
299 /* WINDOWS SPECIFIC */
301 void UnixTimeToFileTime(time_t t, LPFILETIME pft)
303 /* Windows specific. From MS Q167296 */
304 /* 'time_t' represents seconds since midnight January 1, 1970 UTC (coordinated universal time). */
305 /* 64-bit FILETIME structure represents the number of 100-nanosecond intervals since January 1, 1601 UTC (coordinate universal time). */
306 LONGLONG ll; /* LONGLONG is a 64-bit value. */
307 ll = Int32x32To64(t, 10000000) + 116444736000000000;
308 pft->dwLowDateTime = (DWORD)ll;
309 /* pft->dwLowDateTime = (DWORD)(0x00000000ffffffff & ll); */
310 pft->dwHighDateTime = (DWORD)(ll >> 32);
312 // Once the UNIX time is converted to a FILETIME structure,
313 // other Win32 time formats can be easily obtained by using Win32 functions such
314 // as FileTimeToSystemTime() and FileTimeToDosDateTime().
318 void UnixTimeToSystemTime(time_t t, LPSYSTEMTIME pst)
320 /* Windows specific */
322 UnixTimeToFileTime(t, &ft);
323 FileTimeToLocalFileTime( &ft, &ft ); /* Adjust from UTC to local time zone */
324 FileTimeToSystemTime(&ft, pst);
329 void xml_time_out(FILE* xmlout, time_t t)
331 /* Windows specific */
333 char szLocalDate[255], szLocalTime[255];
334 UnixTimeToSystemTime( t, &st );
335 GetDateFormat( LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, szLocalDate, 255 );
336 GetTimeFormat( LOCALE_USER_DEFAULT, 0, &st, NULL, szLocalTime, 255 );
337 fprintf(xmlout, "%s %s", szLocalDate, szLocalTime );
340 /* END WINDOWS SPECIFIC */
344 void xml_write_moov_udta(FILE* xmlout, mj2_movie_t * movie) {
345 /* Compare with xml_write_udta */
347 /* NO-OP so far. Optional UserData 'udta' (zero or one in moov or each trak)
348 can contain multiple Copyright 'cprt' with different language codes */
349 /* There may be nested non-standard boxes within udta */
350 IMAGINE movie->udta, movie->copyright_count, movie->copyright_language[i] (array of 16bit ints), movie->copyright_notice[i] (array of buffers)
351 PROBABLY ALSO NEED movie->udta_len or special handler for non-standard boxes
356 return; /* Not present */
358 fprintf(xmlout, " <UserData BoxType=\"udta\">\n");
359 for(i = 0; i < movie->copyright_count; i++) {
360 fprintf(xmlout, " <Copyright BoxType=\"cprt\"> Instance=\"%d\">\n", i+1);
361 int16_to_3packedchars((short int)movie->copyright_languages[i], buf);
362 fprintf(xmlout, " <Language>%s</Language>\n", buf); /* 3 chars */
363 fprintf(xmlout, " <Notice>%s</Notice>\n",movie->copyright_notices[i]);
364 fprintf(xmlout, " </Copyright>\n", i+1);
366 /* TO DO: Non-standard boxes */
367 fprintf(xmlout, " </UserData>\n");
371 void xml_write_free_and_skip(FILE* xmlout, mj2_movie_t * movie) {
373 /* NO-OP so far. There can be zero or more instances of free and/or skip
374 at the top level of the file. This may be a place where the user squirrel's metadata.
375 Let's assume unstructured, and do a dump */
376 IMAGINE movie->free_and_skip, movie->free_and_skip_count, movie->free_and_skip_content[i] (array of buffers),
377 movie->free_and_skip_len[i] (array of ints), movie->is_skip[i] (array of BOOL)
380 if(movie->free_and_skip != 1)
381 return; /* Not present */
383 for(i = 0; i < movie->free_and_skip_count; i++) {
384 if(movie->is_skip[i])
385 fprintf(xmlout, " <Skip BoxType=\"skip\">\n");
387 fprintf(xmlout, " <Free BoxType=\"free\">\n");
389 xml_out_dump_hex_and_ascii(xmlout, movie->free_and_skip_contents[i], movie->free_and_skip_len[i]);
391 if(movie->is_skip[i])
392 fprintf(xmlout, " </Skip>\n");
394 fprintf(xmlout, " </Free>\n");
399 void xml_write_uuid(FILE* xmlout, mj2_movie_t * movie) {
400 /* Univeral Unique IDs of 16 bytes. */
402 /* NO-OP so far. There can be zero or more instances of private uuid boxes in a file.
403 This function supports the top level of the file, but uuid may be elsewhere [not yet supported].
404 This may be a place where the user squirrel's metadata. Let's assume unstructured, and do a dump */
405 IMAGINE movie->uuid, movie->uuid_count, movie->uuid_content[i] (array of buffers),
406 movie->uuid_len[i] (array of ints), movie->uuid_type[i] (array of 17-byte (16+null termination) buffers)
410 return; /* Not present */
412 for(i = 0; i < movie->uuid_count; i++) {
413 fprintf(xmlout, " <PrivateExtension BoxType=\"uuid\" UUID=\"%s\">\n", movie->uuid_type[i]);
414 // See Part III section 5.2.1, 6.1, 6.2
415 xml_out_dump_hex_and_ascii(xmlout, movie->uuid_contents[i], movie->uuid_len[i]);
416 fprintf(xmlout, " </PrivateExtension>\n");
423 void xml_write_trak(FILE* file, FILE* xmlout, mj2_tk_t *track, unsigned int tnum, unsigned int sampleframe)
425 fprintf(xmlout, " <Track BoxType=\"trak\" Instance=\"%d\">\n", tnum);
426 xml_write_tkhd(file, xmlout, track, tnum);
427 // TO DO: TrackReferenceContainer 'tref' just used in hint track
428 // TO DO: EditListContainer 'edts', contains EditList 'elst' with media-time, segment-duration, media-rate
429 xml_write_mdia(file, xmlout, track, tnum);
430 xml_write_udta(file, xmlout, track, tnum); // NO-OP so far. Optional UserData 'udta', can contain multiple Copyright 'cprt'
432 if(track->track_type==0) { /* Only do for visual track */
433 /* sampleframe is from user option -f. 1 = first frame */
434 /* sampleframe of 0 is a user requests: no jp2 header */
435 /* Treat out-of-bounds values in the same way */
436 if(sampleframe > 0 && sampleframe <= track->num_samples)
438 mj2_sample_t *sample;
441 snum = sampleframe-1;
442 // Someday maybe do a smart range scan... for (snum=0; snum < track->num_samples; snum++){
443 // fprintf(stdout,"Frame %d: ",snum+1);
444 sample = &track->sample[snum];
445 if(xml_out_frame(file, xmlout, sample, snum))
446 return; /* Not great error handling here */
449 fprintf(xmlout, " </Track>\n");
454 void xml_write_tkhd(FILE* file, FILE* xmlout, mj2_tk_t *track, unsigned int tnum)
456 fprintf(xmlout, " <TrackHeader BoxType=\"tkhd\">\n");
458 fprintf(xmlout, " <!-- Not shown here: CreationTime, ModificationTime, Duration. -->\n");
459 fprintf(xmlout, " <!-- These 3 fields are reported under MediaHeader below. When reading these 3, -->\n");
460 fprintf(xmlout, " <!-- m2j_to_metadata currently doesn't distinguish between TrackHeader and MediaHeader source. -->\n");
461 fprintf(xmlout, " <!-- If both found, value read from MediaHeader is used. -->\n");
463 fprintf(xmlout, " <TrackID>%u</TrackID>\n", track->track_ID);
464 if(track->track_type==0) /* For visual track */
466 fprintf(xmlout, " <TrackLayer>%d</TrackLayer>\n", track->layer);
468 fprintf(xmlout," <!-- front-to-back ordering of video tracks. 0 = normal, -1 is closer, etc. -->\n");
470 if(track->track_type!=0) /* volume irrelevant for visual track */
473 track->volume = track->volume << 8;
475 fprintf(xmlout, " <Volume>\n");
477 fprintf(xmlout," <!-- Track audio volume stored as fixed-point binary 8.8 value. Decimal value is approximation. -->\n");
478 fprintf(xmlout," <!-- Full, normal (default) value is 0x0100 (1.0) -->\n");
481 fprintf(xmlout," <AsHex>0x%04x</AsHex>\n", track->volume);
483 fprintf(xmlout," <AsDecimal>%6.3f</AsDecimal>\n", (double)track->volume/(double)0x0100);
484 fprintf(xmlout, " </Volume>\n");
487 fprintf(xmlout, " <!-- Current m2j_to_metadata implementation always shows bits to right of decimal as zeroed. -->\n");
488 track->volume = track->volume >> 8;
491 if(track->track_type==0)
493 /* Transformation matrix for video */
494 fprintf(xmlout, " <TransformationMatrix>\n");
496 fprintf(xmlout," <!-- Comments about matrix in MovieHeader apply here as well. -->\n");
497 fprintf(xmlout," <!-- This matrix is applied before MovieHeader one. -->\n");
499 fprintf(xmlout, " <TMa>0x%08x</TMa>\n", track->trans_matrix[0]);
500 fprintf(xmlout, " <TMb>0x%08x</TMb>\n", track->trans_matrix[1]);
501 fprintf(xmlout, " <TMu>0x%08x</TMu>\n", track->trans_matrix[2]);
502 fprintf(xmlout, " <TMc>0x%08x</TMc>\n", track->trans_matrix[3]);
503 fprintf(xmlout, " <TMd>0x%08x</TMd>\n", track->trans_matrix[4]);
504 fprintf(xmlout, " <TMv>0x%08x</TMv>\n", track->trans_matrix[5]);
505 fprintf(xmlout, " <TMx>0x%08x</TMx>\n", track->trans_matrix[6]);
506 fprintf(xmlout, " <TMy>0x%08x</TMy>\n", track->trans_matrix[7]);
507 fprintf(xmlout, " <TMw>0x%08x</TMw>\n", track->trans_matrix[8]);
508 fprintf(xmlout, " </TransformationMatrix>\n");
511 track->w = track->w << 16;
512 track->h = track->h << 16;
515 fprintf(xmlout, " <!-- Width and Height in pixels are for the presentation; frames will be scaled to this. -->\n");
516 fprintf(xmlout, " <!-- Both stored as fixed-point binary 16.16 values. Decimal values are approximations. -->\n");
518 fprintf(xmlout, " <Width>\n");
520 fprintf(xmlout, " <AsHex>0x%08x</AsHex>\n", track->w);
522 fprintf(xmlout, " <AsDecimal>%12.6f</AsDecimal>\n", (double)track->w/(double)0x00010000); /* Rate to play presentation (default = 0x00010000) */
523 fprintf(xmlout, " </Width>\n");
524 fprintf(xmlout, " <Height>\n");
526 fprintf(xmlout, " <AsHex>0x%08x</AsHex>\n", track->h);
528 fprintf(xmlout, " <AsDecimal>%12.6f</AsDecimal>\n", (double)track->h/(double)0x00010000); /* Rate to play presentation (default = 0x00010000) */
529 fprintf(xmlout, " </Height>\n");
532 fprintf(xmlout, " <!-- Current m2j_to_metadata implementation always shows bits to right of decimal as zeroed. -->\n");
533 fprintf(xmlout, " <!-- Also, width and height values shown here will actually be those read from track's <VisualSampleEntry> if given. -->\n");
535 track->w = track->w >> 16;
536 track->h = track->h >> 16;
538 fprintf(xmlout, " </TrackHeader>\n");
543 void xml_write_udta(FILE* file, FILE* xmlout, mj2_tk_t *track, unsigned int tnum) {
544 /* NO-OP so far. Optional UserData 'udta' (zero or one in moov or each trak)
545 can contain multiple Copyright 'cprt' with different language codes */
546 /* There may be nested non-standard boxes within udta */
548 IMAGINE track->udta, track->copyright_count, track->copyright_language[i] (array of 16bit ints), track->copyright_notice[i] (array of buffers)
549 PROBABLY ALSO NEED track->udta_len or special handler for non-standard boxes
554 return; /* Not present */
556 fprintf(xmlout, " <UserData BoxType=\"udta\">\n");
557 for(i = 0; i < track->copyright_count; i++) {
558 fprintf(xmlout, " <Copyright BoxType=\"cprt\"> Instance=\"%d\">\n", i+1);
559 int16_to_3packedchars((short int)track->copyright_languages[i], buf);
560 fprintf(xmlout, " <Language>%s</Language>\n", buf); /* 3 chars */
561 fprintf(xmlout, " <Notice>%s</Notice>\n",track->copyright_notices[i]);
562 fprintf(xmlout, " </Copyright>\n", i+1);
564 /* TO DO: Non-standard boxes */
565 fprintf(xmlout, " </UserData>\n");
571 void xml_write_mdia(FILE* file, FILE* xmlout, mj2_tk_t *track, unsigned int tnum)
577 fprintf(xmlout, " <Media BoxType=\"mdia\">\n");
578 fprintf(xmlout, " <MediaHeader BoxType=\"mdhd\">\n");
579 fprintf(xmlout, " <CreationTime>\n");
581 fprintf(xmlout, " <InSeconds>%u</InSeconds>\n", track->creation_time);
583 fprintf(xmlout, " <!-- Seconds since start of Jan. 1, 1904 UTC (Greenwich) -->\n");
584 /* 2082844800 = seconds between 1/1/04 and 1/1/70 */
585 /* There's still a time zone offset problem not solved... but spec is ambigous as to whether stored time
586 should be local or UTC */
588 fprintf(xmlout, " <AsLocalTime>");
589 xml_time_out(xmlout, track->creation_time - 2082844800);
590 fprintf(xmlout,"</AsLocalTime>\n");
592 fprintf(xmlout, " </CreationTime>\n");
593 fprintf(xmlout, " <ModificationTime>\n");
595 fprintf(xmlout, " <InSeconds>%u</InSeconds>\n", track->modification_time);
597 fprintf(xmlout, " <AsLocalTime>");
598 xml_time_out(xmlout, track->modification_time - 2082844800);
599 fprintf(xmlout,"</AsLocalTime>\n");
601 fprintf(xmlout, " </ModificationTime>\n");
602 fprintf(xmlout, " <Timescale>%d</Timescale>\n", track->timescale);
604 fprintf(xmlout, " <!-- Timescale defines time units in one second -->\n");
605 fprintf(xmlout, " <Duration>\n");
607 fprintf(xmlout, " <InTimeUnits>%u</InTimeUnits>\n", track->duration);
609 fprintf(xmlout, " <InSeconds>%12.3f</InSeconds>\n", (double)track->duration/(double)track->timescale); // Make this double later to get fractional seconds
610 fprintf(xmlout, " </Duration>\n");
611 int16_to_3packedchars((short int)track->language, buf);
612 fprintf(xmlout, " <Language>%s</Language>\n", buf); /* 3 chars */
613 fprintf(xmlout, " </MediaHeader>\n");
614 fprintf(xmlout, " <HandlerReference BoxType=\"hdlr\">\n");
615 switch(track->track_type)
618 fprintf(xmlout, " <HandlerType Code=\"vide\">video media track</HandlerType>\n"); break;
620 fprintf(xmlout, " <HandlerType Code=\"soun\">Sound</HandlerType>\n"); break;
622 fprintf(xmlout, " <HandlerType Code=\"hint\">Hint</HandlerType>\n"); break;
625 fprintf(xmlout, " <!-- String value shown is not actually read from file. -->\n");
626 fprintf(xmlout, " <!-- Shown value is one used for our encode. -->\n");
628 fprintf(xmlout, " </HandlerReference>\n");
629 fprintf(xmlout, " <MediaInfoContainer BoxType=\"minf\">\n");
630 switch(track->track_type)
633 fprintf(xmlout, " <VideoMediaHeader BoxType=\"vmhd\">\n");
634 fprintf(xmlout, " <GraphicsMode>0x%02x</GraphicsMode>\n", track->graphicsmode);
636 fprintf(xmlout," <!-- Enumerated values of graphics mode: -->\n");
637 fprintf(xmlout," <!-- 0x00 = copy (over existing image); -->\n");
638 fprintf(xmlout," <!-- 0x24 = transparent; 'blue-screen' this image using opcolor; -->\n");
639 fprintf(xmlout," <!-- 0x100 = alpha; alpha-blend this image -->\n");
640 /* fprintf(xmlout," <!-- 0x101 = whitealpha; alpha-blend this image, which has been blended with white; -->\n"); This was evidently dropped upon amendment */
641 fprintf(xmlout," <!-- 0x102 = pre-multiplied black alpha; image has been already been alpha-blended with black. -->\n");
642 fprintf(xmlout," <!-- 0x110 = component alpha; blend alpha channel(s) and color channels individually. -->\n");
644 fprintf(xmlout, " <Opcolor>\n");
645 fprintf(xmlout, " <Red>0x%02x</Red>\n", track->opcolor[0]);
646 fprintf(xmlout, " <Green>0x%02x</Green>\n",track->opcolor[1]);
647 fprintf(xmlout, " <Blue>0x%02x</Blue>\n",track->opcolor[2]);
648 fprintf(xmlout, " </Opcolor>\n");
649 fprintf(xmlout, " </VideoMediaHeader>\n");
652 fprintf(xmlout, " <SoundMediaHeader BoxType=\"smhd\">\n");
654 track->balance = track->balance << 8;
656 fprintf(xmlout, " <Balance>\n");
658 fprintf(xmlout," <!-- Track audio balance fixes mono track in stereo space. -->\n");
659 fprintf(xmlout," <!-- Stored as fixed-point binary 8.8 value. Decimal value is approximation. -->\n");
660 fprintf(xmlout," <!-- 0.0 = center, -1.0 = full left, 1.0 = full right -->\n");
663 fprintf(xmlout," <AsHex>0x%04x</AsHex>\n", track->balance);
665 fprintf(xmlout," <AsDecimal>%6.3f</AsDecimal>\n", (double)track->balance/(double)0x0100);
666 fprintf(xmlout, " </Balance>\n");
669 fprintf(xmlout," <!-- Current m2j_to_metadata implementation always shows bits to right of decimal as zeroed. -->\n");
670 track->balance = track->balance >> 8;
672 fprintf(xmlout, " </SoundMediaHeader>\n");
675 fprintf(xmlout, " <HintMediaHeader BoxType=\"hmhd\">\n");
676 fprintf(xmlout, " <MaxPDU_Size>%d</MaxPDU_Size>\n", track->maxPDUsize);
678 fprintf(xmlout," <!-- Size in bytes of largest PDU in this hint stream. -->\n");
679 fprintf(xmlout, " <AvgPDU_Size>%d</AvgPDU_Size>\n", track->avgPDUsize);
681 fprintf(xmlout," <!-- Average size in bytes of a PDU over the entire presentation. -->\n");
682 fprintf(xmlout, " <MaxBitRate>%d</MaxBitRate>\n", track->maxbitrate);
684 fprintf(xmlout," <!-- Maximum rate in bits per second over any window of 1 second. -->\n");
685 fprintf(xmlout, " <AvgBitRate>%d</AvgBitRate>\n", track->avgbitrate);
687 fprintf(xmlout," <!-- Averate rate in bits per second over the entire presentation. -->\n");
688 fprintf(xmlout, " <SlidingAvgBit>%d</SlidingAvgBitRate>\n", track->slidingavgbitrate);
690 fprintf(xmlout," <!-- Maximum rate in bits per second over any window of one minute. -->\n");
691 fprintf(xmlout, " </HintMediaHeader>\n");
694 fprintf(xmlout, " <DataInfo BoxType=\"dinf\">\n");
695 fprintf(xmlout, " <DataReference BoxType=\"dref\" URL_Count=\"%d\" URN_Count=\"%d\">\n", track->num_url, track->num_urn); // table w. flags, URLs, URNs
696 // Data structure does not distinguish between single URL, single URN, or DREF table or URLs & URNs.
697 // We could infer those, but for now just present everything as a DREF table.
699 fprintf(xmlout, " <!-- No entries here mean that file is self-contained, as required by Simple Profile. -->\n");
700 for(k = 0; k < track->num_url; k++) {
701 fprintf(xmlout, " <DataEntryUrlBox BoxType=\"url[space]\">\n"); // table w. flags, URLs, URNs
703 fprintf(xmlout," <!-- Only the first 16 bytes of URL location are recorded in mj2_to_metadata data structure. -->\n");
704 for(i = 0; i < 4; i++) {
705 uint_to_chars(track->url[track->num_url].location[i], buf);
706 fprintf(xmlout, " <Location>%s</Location>\n");
708 fprintf(xmlout, " </DataEntryUrlBox>\n"); // table w. flags, URLs, URNs
710 for(k = 0; k < track->num_urn; k++) {
711 fprintf(xmlout," <DataEntryUrnBox BoxType=\"urn[space]\">\n"); // table w. flags, URLs, URNs
712 // Only the first 16 bytes are recorded in the data structure currently.
714 fprintf(xmlout," <!-- Only the first 16 bytes each of URN name and optional location are recorded in mj2_to_metadata data structure. -->\n");
715 fprintf(xmlout, " <Name>");
716 for(i = 0; i < 4; i++) {
717 uint_to_chars(track->urn[track->num_urn].name[i], buf);
718 fprintf(xmlout,"%s", buf);
720 fprintf(xmlout, "</Name>\n");
721 fprintf(xmlout, " <Location>");
722 for(i = 0; i < 4; i++) {
723 uint_to_chars(track->urn[track->num_urn].location[i], buf);
724 fprintf(xmlout,"%s");
726 fprintf(xmlout, "</Location>\n");
727 fprintf(xmlout, " </DataEntryUrnBox>\n");
729 fprintf(xmlout, " </DataReference>\n");
730 fprintf(xmlout, " </DataInfo>\n");
732 xml_write_stbl(file, xmlout, track, tnum); /* SampleTable */
734 fprintf(xmlout, " </MediaInfoContainer>\n");
735 fprintf(xmlout, " </Media>\n");
740 void xml_write_stbl(FILE* file, FILE* xmlout, mj2_tk_t *track, unsigned int tnum)
742 char buf[5], buf33[33];
746 fprintf(xmlout, " <SampleTable BoxType=\"stbl\">\n");
748 fprintf(xmlout, " <!-- What follows are specific instances of generic SampleDescription BoxType=\"stsd\" -->\n");
749 switch(track->track_type)
752 // There could be multiple instances of this, but "entry_count" is just a local at read-time.
753 // And it's used wrong, too, as count of just visual type, when it's really all 3 types.
754 // This is referred to as "smj2" within mj2.c
755 fprintf(xmlout, " <VisualSampleEntry BoxType=\"mjp2\">\n");
757 fprintf(xmlout, " <!-- If multiple instances of this box, only first is shown here. -->\n");
758 fprintf(xmlout, " <!-- Width and Height are in pixels. Unlike the Track Header, there is no fractional part. -->\n");
759 fprintf(xmlout, " <!-- In mj2_to_metadata implementation, the values are not represented separately from Track Header's values. -->\n");
761 /* No shifting required. If CURRENTSTRUCT gets changed, then may need to revisit treatment of these */
762 fprintf(xmlout, " <WidthAsInteger>%d</WidthAsInteger>\n", track->w);
763 fprintf(xmlout, " <HeightAsInteger>%d</HeightAsInteger>\n", track->h);
764 // Horizresolution and vertresolution don't require shifting, already stored right in CURRENTSTRUCT
766 fprintf(xmlout, " <!-- Resolutions are in pixels per inch, for the highest-resolution component (typically luminance). -->\n");
767 fprintf(xmlout, " <!-- Both stored as fixed-point binary 16.16 values. Decimal values are approximations. -->\n");
768 fprintf(xmlout, " <!-- Typical value for both resolutions is 0x00480000 (72.0) -->\n");
770 fprintf(xmlout, " <HorizontalRes>\n");
772 fprintf(xmlout, " <AsHex>0x%08x</AsHex>\n", track->horizresolution);
774 fprintf(xmlout, " <AsDecimal>%12.6f</AsDecimal>\n", (double)track->horizresolution/(double)0x00010000); /* Rate to play presentation (default = 0x00010000) */
775 fprintf(xmlout, " </HorizontalRes>\n");
776 fprintf(xmlout, " <VerticalRes>\n");
778 fprintf(xmlout, " <AsHex>0x%08x</AsHex>\n", track->vertresolution);
780 fprintf(xmlout, " <AsDecimal>%12.6f</AsDecimal>\n", (double)track->vertresolution/(double)0x00010000); /* Rate to play presentation (default = 0x00010000) */
781 fprintf(xmlout, " </VerticalRes>\n");
784 for(i = 0; i < 8; i++) {
785 uint_to_chars((unsigned int)track->compressorname[i], buf);
786 strcat(buf33, buf); /* This loads up (4 * 8) + 1 chars, but trailing ones are usually junk */
788 len = (int)buf33[0]; /* First byte has string length in bytes. There may be garbage beyond it. */
789 buf33[len+1] = '\0'; /* Suppress it */
790 fprintf(xmlout, " <CompressorName>%s</CompressorName>\n", buf33+1); /* Start beyond first byte */
792 fprintf(xmlout, " <!-- Compressor name for debugging. Standard restricts max length to 31 bytes. -->\n");
793 fprintf(xmlout, " <!-- Usually blank or \"Motion JPEG2000\" -->\n");
795 fprintf(xmlout, " <Depth>0x%02x</Depth>\n",track->depth);
797 fprintf(xmlout, " <!-- Depth is: -->\n");
798 fprintf(xmlout, " <!-- 0x20: alpha channels present (color or grayscale) -->\n");
799 fprintf(xmlout, " <!-- 0x28: grayscale without alpha -->\n");
800 fprintf(xmlout, " <!-- 0x18: color without alpha -->\n");
803 xml_out_frame_jp2h(xmlout, &(track->jp2_struct)); /* JP2 Header */
805 /* Following subboxes are optional */
806 fprintf(xmlout, " <FieldCoding BoxType=\"fiel\">\n");
807 fprintf(xmlout, " <FieldCount>%d</FieldCount>\n", (unsigned int)track->fieldcount); /* uchar as 1 byte uint */
809 fprintf(xmlout, " <!-- Must be either 1 or 2 -->\n");
810 fprintf(xmlout, " <FieldOrder>%d</FieldOrder>\n", (unsigned int)track->fieldorder); /* uchar as 1 byte uint */
812 fprintf(xmlout, " <!-- When FieldCount=2, FieldOrder means: -->\n");
813 fprintf(xmlout, " <!-- 0: Field coding unknown -->\n");
814 fprintf(xmlout, " <!-- 1: Field with topmost line is stored first in sample; fields are in temporal order -->\n");
815 fprintf(xmlout, " <!-- 6: Field with topmost line is stored second in sample; fields are in temporal order -->\n");
816 fprintf(xmlout, " <!-- Defaults: FieldCount=1, FieldOrder=0 if FieldCoding box not present -->\n");
817 fprintf(xmlout, " <!-- Current implementation doesn't retain whether box was actually present. -->\n");
819 fprintf(xmlout, " </FieldCoding>\n");
821 fprintf(xmlout, " <MJP2_Profile BoxType=\"jp2p\" Count=\"%d\">\n",track->num_br);
822 for (i = 0; i < track->num_br; i++) /* read routine stored in reverse order, so let's undo damage */
824 uint_to_chars(track->br[i], buf);
825 fprintf(xmlout, " <CompatibleBrand>%s</CompatibleBrand>\n", buf); /*4 characters, each CLi */
827 fprintf(xmlout, " </MJP2_Profile>\n");
829 fprintf(xmlout, " <MJP2_Prefix BoxType=\"jp2x\" Count=\"%d\">\n",track->num_jp2x);
830 for (i = 0; i < track->num_jp2x; i++)
831 { // We'll probably need better formatting than this
832 fprintf(xmlout, " <Data>0x%02x</Data>\n", track->jp2xdata[i]); /* Each entry is single byte */
834 fprintf(xmlout, " </MJP2_Prefix>\n");
836 fprintf(xmlout, " <MJP2_SubSampling BoxType=\"jsub\">\n"); /* These values are all 1 byte */
838 fprintf(xmlout, " <!-- Typical subsample value is 2 for 4:2:0 -->\n");
839 fprintf(xmlout, " <HorizontalSub>%d</HorizontalSub>\n", track->hsub);
840 fprintf(xmlout, " <VerticalSub>%d</VerticalSub>\n", track->vsub);
841 fprintf(xmlout, " <HorizontalOffset>%d</HorizontalOffset>\n", track->hoff);
842 fprintf(xmlout, " <VerticalOffset>%d</VerticalOffset>\n", track->voff);
844 fprintf(xmlout, " <!-- Typical {horizontal, vertical} chroma offset values: -->\n");
845 fprintf(xmlout, " <!-- 4:2:2 format (CCIR601, H.262, MPEG2, MPEG4, recom. Exif): {0, 0} -->\n");
846 fprintf(xmlout, " <!-- 4:2:2 format (JFIF): {1, 0} -->\n");
847 fprintf(xmlout, " <!-- 4:2:0 format (H.262, MPEG2, MPEG4): {0, 1} -->\n");
848 fprintf(xmlout, " <!-- 4:2:0 format (MPEG1, H.261, JFIF, recom. Exif): {1, 1} -->\n");
850 fprintf(xmlout, " </MJP2_SubSampling>\n"); /* These values are all 1 byte */
852 fprintf(xmlout, " <MJP2_OriginalFormat BoxType=\"orfo\">\n"); /* Part III Appx. 2 */
853 fprintf(xmlout, " <OriginalFieldCount>%u</OriginalFieldCount>\n", (unsigned int)track->or_fieldcount); /* uchar as 1-byte uint */
855 fprintf(xmlout, " <!-- In original material before encoding. Must be either 1 or 2 -->\n");
856 fprintf(xmlout, " <OriginalFieldOrder>%u</OriginalFieldOrder>\n", (unsigned int)track->or_fieldorder); /* uchar as 1-byte uint */
858 fprintf(xmlout, " <!-- When FieldCount=2, FieldOrder means: -->\n");
859 fprintf(xmlout, " <!-- 0: Field coding unknown -->\n");
860 fprintf(xmlout, " <!-- 11: Topmost line came from the earlier field; -->\n");
861 fprintf(xmlout, " <!-- 16: Topmost line came form the later field. -->\n");
862 fprintf(xmlout, " <!-- Defaults: FieldCount=1, FieldOrder=0 if FieldCoding box not present -->\n");
863 fprintf(xmlout, " <!-- Current implementation doesn't retain whether box was actually present. -->\n");
865 fprintf(xmlout, " </MJP2_OriginalFormat>\n");
866 fprintf(xmlout, " </VisualSampleEntry>\n");
870 fprintf(xmlout, " <!-- mj2_to_metadata's data structure doesn't record this currently. -->\n"); break;
872 fprintf(xmlout, " <TimeToSample BoxType=\"stts\">\n");
873 fprintf(xmlout, " <SampleStatistics>\n");
874 fprintf(xmlout, " <TotalSamples>%d</TotalSamples>\n", track->num_samples);
876 fprintf(xmlout, " <!-- For video, gives the total frames in the track, by summing all entries in the Sample Table -->\n");
877 fprintf(xmlout, " </SampleStatistics>\n");
878 fprintf(xmlout, " <SampleEntries EntryCount=\"%d\">\n", track->num_tts);
879 for (i = 0; i < track->num_tts; i++) {
880 fprintf(xmlout, " <Table Entry=\"%u\" SampleCount=\"%d\" SampleDelta=\"%u\" />\n",
881 i+1, track->tts[i].sample_count, track->tts[i].sample_delta);
883 fprintf(xmlout, " </SampleEntries>\n");
884 fprintf(xmlout, " </TimeToSample>\n");
886 fprintf(xmlout, " <SampleToChunk BoxType=\"stsc\" Count=\"%d\">\n", track->num_samplestochunk);
887 for (i = 0; i < track->num_samplestochunk; i++) {
888 fprintf(xmlout, " <FirstChunk>%u</FirstChunk>\n",track->sampletochunk[i].first_chunk); /* 4 bytes */
889 fprintf(xmlout, " <SamplesPerChunk>%u</SamplesPerChunk>\n",track->sampletochunk[i].samples_per_chunk); /* 4 bytes */
890 fprintf(xmlout, " <SampleDescrIndex>%u</SampleDescrIndex>\n",track->sampletochunk[i].sample_descr_idx); /* 4 bytes */
892 fprintf(xmlout, " </SampleToChunk>\n");
893 // After reading this info in, track->num_chunks is calculated and a decompressed table established internally.
895 fprintf(xmlout, " <SampleSize BoxType=\"stsz\">\n");
896 if(track->same_sample_size) {
897 // all values in track->sample[i].sample_size are equal. Grab the first one.
898 fprintf(xmlout, " <Sample_Size>%u</Sample_Size>\n", track->sample[0].sample_size);
900 fprintf(xmlout, " <!-- Non-zero value means all samples have that size. -->\n");
901 fprintf(xmlout, " <!-- So <Sample_Count> (aka Entry_Count in std.) has no meaning, is suppressed from this output, and no table follows. -->\n");
904 fprintf(xmlout, " <Sample_Size>0</Sample_Size>\n");
907 fprintf(xmlout," <!-- Zero value means samples have different sizes, given in table next of length Sample_Count (aka Entry_Count in std). -->\n");
909 fprintf(xmlout," <!-- Zero value means samples have different sizes, given in table (not shown) of length Sample_Count (aka Entry_Count in std). -->\n");
910 fprintf(xmlout, " <Sample_Count>%u</Sample_Count>\n", track->num_samples);
912 for (i = 0; i < (int)track->num_samples; i++) {
913 fprintf(xmlout, " <EntrySize Num=\"%u\">%u</EntrySize>\n", i+1, track->sample[i].sample_size);
916 fprintf(xmlout, " </SampleSize>\n");
918 fprintf(xmlout, " <ChunkOffset BoxType=\"stco\">\n");
919 // Structure not yet - Variant ChunkLargeOffset 'co64'
920 fprintf(xmlout, " <EntryCount>%u</EntryCount>\n", track->num_chunks);
922 fprintf(xmlout, " <!-- For this implementation, EntryCount shown is one calculated during file read of <SampleToChunk> data. -->\n");
923 fprintf(xmlout, " <!-- Implementation will report failure during file read of <ChunkOffset> data if read entry-count disagrees. -->\n");
926 for (i = 0; i < (int)track->num_chunks; i++)
927 fprintf(xmlout, " <Chunk_Offset Num=\"%d\">%u</Chunk_Offset>\n", i+1, track->chunk[i].offset);
928 fprintf(xmlout, " </ChunkOffset>\n");
930 fprintf(xmlout, " </SampleTable>\n");
935 int xml_out_frame(FILE* file, FILE* xmlout, mj2_sample_t *sample, unsigned int snum)
941 unsigned char* frame_codestream;
942 /* char xmloutname[50]; */
944 frame_codestream = (unsigned char*) malloc (sample->sample_size-8); /* Skipping JP2C marker */
945 if(frame_codestream == NULL)
948 fseek(file,sample->offset+8,SEEK_SET);
949 fread(frame_codestream,sample->sample_size-8,1, file); /* Assuming that jp and ftyp markers size do */
950 /* Decode J2K to image: */
951 if (!j2k_decode(frame_codestream, sample->sample_size-8, &img, &cp)) {
952 free(frame_codestream);
953 #ifndef NO_PACKETS_DECODING
954 for (i=0; i<img.numcomps; i++)
955 free(img.comps[i].data);
961 numcomps = img.numcomps;
962 /* Alignments: " < To help maintain xml pretty-printing */
963 fprintf(xmlout, " <JP2_Frame Num=\"%d\">\n", snum+1);
964 fprintf(xmlout, " <MainHeader>\n");
965 /* There can be multiple codestreams; a particular image is entirely within a single codestream */
966 /* TO DO: A frame can be represented by two I-guess-contigious codestreams if its interleaved. */
967 fprintf(xmlout, " <StartOfCodestream Marker=\"SOC\" />\n");
968 /* "cp" stands for "coding parameter"; "tcp" is tile coding parameters, "tccp" is tile-component coding parameters */
969 xml_out_frame_siz(xmlout, &img, &cp); /* reqd in main */
970 xml_out_frame_cod(xmlout, &j2k_default_tcp); /* reqd in main */
971 xml_out_frame_coc(xmlout, &j2k_default_tcp, numcomps); /* opt in main, at most 1 per component */
972 xml_out_frame_qcd(xmlout, &j2k_default_tcp); /* reqd in main */
973 xml_out_frame_qcc(xmlout, &j2k_default_tcp, numcomps); /* opt in main, at most 1 per component */
974 xml_out_frame_rgn(xmlout, &j2k_default_tcp, numcomps); /* opt, at most 1 per component */
975 xml_out_frame_poc(xmlout, &j2k_default_tcp); /* opt (but reqd in main or tile for any progression order changes) */
976 /* Next four get j2k_default_tcp passed globally: */
977 #ifdef SUPPRESS_FOR_NOW
978 xml_out_frame_ppm(xmlout, &cp); /* opt (but either PPM or PPT [distributed in tile headers] or codestream packet header reqd) */
980 xml_out_frame_tlm(xmlout); /* NO-OP. TLM NOT SAVED IN DATA STRUCTURE */ /* opt */
981 xml_out_frame_plm(xmlout); /* NO-OP. PLM NOT SAVED IN DATA STRUCTURE */ /* opt in main; can be used in conjunction with PLT */
982 xml_out_frame_crg(xmlout); /* NO-OP. CRG NOT SAVED IN DATA STRUCTURE */ /* opt in main; */
983 xml_out_frame_com(xmlout, &j2k_default_tcp); /* NO-OP. COM NOT SAVED IN DATA STRUCTURE */ /* opt in main; */
985 fprintf(xmlout, " </MainHeader>\n");
987 /* TO DO: all the tile headers (sigh) */
988 fprintf(xmlout, " <TilePartHeaders Count=\"%d\">\n", cp.tileno_size); /* size of the vector tileno */
989 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 */
990 // Standard seems to use zero-based # for tile-part.
991 fprintf(xmlout, " <TilePartHeader Num=\"%d\" ID=\"%d\">\n", i, cp.tileno[i]); /* ID number of the tiles present in the codestream */
992 fprintf(xmlout, " <StartOfTilePart Marker=\"SOT\" />\n");
993 /* All markers in tile-part headers (between SOT and SOD) are optional, unless structure requires. */
995 xml_out_frame_cod(xmlout, &(cp.tcps[i])); /* No more than 1 per tile */
996 xml_out_frame_coc(xmlout, &(cp.tcps[i]), numcomps); /* No more than 1 per component */
997 xml_out_frame_qcd(xmlout, &(cp.tcps[i])); /* No more than 1 per tile */
998 xml_out_frame_qcc(xmlout, &(cp.tcps[i]), numcomps); /* No more than 1 per component */
999 xml_out_frame_rgn(xmlout, &(cp.tcps[i]), numcomps); /* No more than 1 per component */
1001 xml_out_frame_poc(xmlout, &(cp.tcps[i])); /* Reqd only if any progression order changes different from main POC */
1002 #ifdef SUPPRESS_FOR_NOW
1003 xml_out_frame_ppt(xmlout, &(cp.tcps[i])); /* Either PPT [distributed in tile headers] or PPM or codestream packet header reqd. */
1005 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 */
1006 xml_out_frame_com(xmlout, &(cp.tcps[i])); /* NO-OP. COM NOT SAVED IN DATA STRUCTURE */
1007 /* j2k_tcp_t * cp.tcps; "tile coding parameters" */
1008 /* Maybe not: fprintf(xmlout, " <>%d</>, cp.matrice[i]; */ /* Fixed layer */
1009 fprintf(xmlout, " <StartOfData Marker=\"SOD\" />\n");
1011 fprintf(xmlout, " <!-- Tile-part bitstream, not shown, follows tile-part header and SOD marker. -->\n");
1012 fprintf(xmlout, " </TilePartHeader>\n");
1014 fprintf(xmlout, " </TilePartHeaders>\n"); /* size of the vector tileno */
1017 IMAGINE the cp object has data to support the following... but we could use an new different data structure instead
1018 /* I'm unclear if the span of the original fread(frame_codestream...) included the following items if they're trailing. */
1019 /* ALSO TO DO, BUT DATA STRUCTURE DOESN'T HANDLE YET: boxes (anywhere in file except before the Filetype box): */
1020 xml_out_frame_jp2i(xmlout, &cp); /* IntellectualProperty 'jp2i' (no restrictions on location) */
1021 xml_out_frame_xml(xmlout, &cp); /* XML 'xml\040' (0x786d6c20). Can appear multiply */
1022 xml_out_frame_uuid(xmlout, &cp); /* UUID 'uuid' (top level only) */
1023 xml_out_frame_uinf(xmlout, &cp); /* UUIDInfo 'uinf', includes UUIDList 'ulst' and URL 'url\40' */
1026 fprintf(xmlout, " </JP2_Frame>\n");
1028 /* Extra commentary: */
1030 fprintf(xmlout, " <!-- Given the number and size of components, mj2_to_frame would try to convert this -->\n");
1031 if (((img.numcomps == 3) && (img.comps[0].dx == img.comps[1].dx / 2)
1032 && (img.comps[0].dx == img.comps[2].dx / 2 ) && (img.comps[0].dx == 1))
1033 || (img.numcomps == 1)) {
1034 fprintf(xmlout, " <!-- file to a YUV movie in the normal manner. -->\n");
1036 else if ((img.numcomps == 3) &&
1037 (img.comps[0].dx == 1) && (img.comps[1].dx == 1)&&
1038 (img.comps[2].dx == 1)) {// If YUV 4:4:4 input --> to bmp
1039 fprintf(xmlout, " <!-- YUV 4:4:4 file to a series of .bmp files. -->\n");
1042 fprintf(xmlout, " <!-- file whose image component dimension are unknown, to a series of .j2k files. -->\n");
1046 #ifndef NO_PACKETS_DECODING
1047 for (i=0; i<img.numcomps; i++)
1048 free(img.comps[i].data);
1051 free(frame_codestream);
1058 void int16_to_3packedchars(short int value, char* buf)
1060 /* This is to retrieve the 3-letter ASCII language code */
1061 /* Each char is packed into 5 bits, as difference from 0x60 */
1063 for (i = 2; i >= 0; i--)
1065 buf[i] = (value & 0x001f) + 0x60;
1066 value = (value >>5);
1073 void xml_out_frame_siz(FILE* xmlout, j2k_image_t *img, j2k_cp_t *cp)
1078 fprintf(xmlout, " <ImageAndFileSize Marker=\"SIZ\">\n");
1079 // This is similar to j2k.c's j2k_dump_image.
1080 // Not of interest: Lsiz, Rsiz
1081 fprintf(xmlout, " <Xsiz>%d</Xsiz>\n", img->x1);
1082 fprintf(xmlout, " <Ysiz>%d</Ysiz>\n", img->y1);
1084 fprintf(xmlout, " <!-- Xsiz, Ysiz is the size of the reference grid. -->\n");
1085 fprintf(xmlout, " <XOsiz>%d</XOsiz>\n", img->x0);
1086 fprintf(xmlout, " <YOsiz>%d</YOsiz>\n", img->y0);
1088 fprintf(xmlout, " <!-- XOsiz, YOsiz are offsets from grid origin to image origin. -->\n");
1089 fprintf(xmlout, " <XTsiz>%d</XTsiz>\n", cp->tdx);
1090 fprintf(xmlout, " <YTsiz>%d</YTsiz>\n", cp->tdy);
1092 fprintf(xmlout, " <!-- XTsiz, YTsiz is the size of one tile with respect to the grid. -->\n");
1093 fprintf(xmlout, " <XTOsiz>%d</XTOsiz>\n", cp->tx0);
1094 fprintf(xmlout, " <YTOsiz>%d</YTOsiz>\n", cp->ty0);
1096 fprintf(xmlout, " <!-- XTOsiz, YTOsiz are offsets from grid origin to first tile origin. -->\n");
1097 fprintf(xmlout, " <Csiz>%d</Csiz>\n", img->numcomps);
1099 fprintf(xmlout, " <!-- Csiz is the number of components in the image. -->\n");
1100 fprintf(xmlout, " <!-- For image components next: -->\n");
1101 fprintf(xmlout, " <!-- XRsiz, YRsiz denote pixel-sample-spacing on the grid, per Part I Annex B. -->\n");
1102 //fprintf(xmlout," <!-- XO, YO is offset of the component compared to the whole image. -->\n");
1103 fprintf(xmlout, " <!-- Bits per pixel (bpp) is the pixel depth. -->\n");
1104 fprintf(xmlout, " <!-- WidthOfData and HeightOfData are calculated values, e.g.: w = roundup((Xsiz - XOsiz)/ XRsiz) -->\n");
1107 for (i = 0; i < img->numcomps; i++) {/* image-components */
1108 comp = &(img->comps[i]);
1109 fprintf(xmlout, " <Component Num=\"%d\">\n", i+1);
1110 fprintf(xmlout, " <Ssiz>\n");
1112 fprintf(xmlout," <AsHex>0x%02x</AsHex>\n", (comp->sgnd << 7) & (comp->prec - 1));
1114 fprintf(xmlout," <Signed>%d</Signed>\n", comp->sgnd);
1115 fprintf(xmlout," <PrecisionInBits>%d</PrecisionInBits>\n", comp->prec);
1117 fprintf(xmlout, " </Ssiz>\n");
1118 fprintf(xmlout, " <XRsiz>%d</XRsiz>\n", comp->dx);
1119 fprintf(xmlout, " <YRsiz>%d</YRsiz>\n", comp->dy);
1120 fprintf(xmlout, " <WidthOfData>%d</WidthOfData>\n", comp->w);
1121 fprintf(xmlout, " <HeightOfData>%d</HeightOfData>\n", comp->h);
1122 /* Rest of these aren't calculated when SIZ is read:
1123 fprintf(xmlout, " <XO>%d</XO>\n", comp->x0);
1124 fprintf(xmlout, " <YO>%d</YO>\n", comp->y0);
1126 fprintf(xmlout," <!-- XO, YO is offset of the component compared to the whole image. -->\n");
1127 fprintf(xmlout, " <BitsPerPixel>%d</BitsPerPixel>\n", comp->bpp);
1128 fprintf(xmlout, " <NumberOfDecodedResolution>%d</NumberOfDecodedResolution>\n", comp->resno_decoded); */
1129 // SUPPRESS: n/a to mj2_to_metadata. fprintf(xmlout," <Factor>%d</Factor\n", comp->factor);
1130 /* factor = number of division by 2 of the out image compare to the original size of image */
1131 // TO DO comp->data: int *data; /* image-component data */
1133 fprintf(xmlout, " </Component>\n");
1135 fprintf(xmlout, " </ImageAndFileSize>\n");
1140 void xml_out_frame_cod(FILE* xmlout, j2k_tcp_t *tcp)
1142 /* Could be called with tcp = &j2k_default_tcp;
1143 /* Or, for tile-part header, with &j2k_cp->tcps[j2k_curtileno]
1144 /* Alignment for main:" < < < < To help maintain xml pretty-printing */
1145 /* Alignment for tile:" < < < To help maintain xml pretty-printing */
1148 char spaces[13] = " "; /* 12 spaces if tilepart*/
1150 if(tcp == &j2k_default_tcp) {
1151 s++;s++; /* shorten s to 10 spaces if main */
1153 tccp = &(tcp->tccps[0]);
1155 fprintf(xmlout, "%s<CodingStyleDefault Marker=\"COD\">\n",s); /* Required in main header */
1156 /* Not retained or of interest: Lcod */
1157 fprintf(xmlout, "%s <Scod>0x%02x</Scod>\n", s, tcp->csty); /* 1 byte */
1159 fprintf(xmlout, "%s <!-- For Scod, specific bits mean (where bit 0 is lowest or rightmost): -->\n",s);
1160 fprintf(xmlout, "%s <!-- bit 0: Defines entropy coder precincts -->\n",s);
1161 fprintf(xmlout, "%s <!-- 0 = (PPx=15, PPy=15); 1 = precincts defined below. -->\n",s);
1162 fprintf(xmlout, "%s <!-- bit 1: 1 = SOP marker may be used; 0 = not. -->\n",s);
1163 fprintf(xmlout, "%s <!-- bit 2: 1 = EPH marker may be used; 0 = not. -->\n",s);
1165 fprintf(xmlout, "%s <SGcod>\n",s);
1166 fprintf(xmlout, "%s <ProgressionOrder>%d</ProgressionOrder>\n", s, tcp->prg); /* 1 byte, SGcod (A) */
1168 fprintf(xmlout, "%s <!-- Defined Progression Order Values are: -->\n",s);
1169 fprintf(xmlout, "%s <!-- 0 = LRCP; 1 = RLCP; 2 = RPCL; 3 = PCRL; 4 = CPRL -->\n",s);
1170 fprintf(xmlout, "%s <!-- where L = \"layer\", R = \"resolution level\", C = \"component\", P = \"position\". -->\n",s);
1172 fprintf(xmlout, "%s <NumberOfLayers>%d</NumberOfLayers>\n", s, tcp->numlayers); /* 2 bytes, SGcod (B) */
1173 fprintf(xmlout, "%s <MultipleComponentTransformation>%d</MultipleComponentTransformation>\n", s, tcp->mct); /* 1 byte, SGcod (C). More or less boolean */
1175 fprintf(xmlout, "%s <!-- For MCT, 0 = none, 1 = transform first 3 components for efficiency, per Part I Annex G -->\n",s);
1176 fprintf(xmlout, "%s </SGcod>\n",s);
1177 /* This code will compile only if declaration of j2k_default_tcp is changed from static (to implicit extern) in j2k.c */
1178 fprintf(xmlout, "%s <SPcod>\n",s);
1179 /* Internal data structure tccp defines separate defaults for each component, but they all get the same values */
1180 /* So we only have to report the first component's values here. */
1181 /* Compare j2k_read_cox(...) */
1182 fprintf(xmlout, "%s <NumberOfDecompositionLevels>%d</NumberOfDecompositionLevels>\n", s, tccp->numresolutions - 1); /* 1 byte, SPcox (D) */
1183 fprintf(xmlout, "%s <CodeblockWidth>%d</CodeblockWidth>\n", s, tccp->cblkw - 2); /* 1 byte, SPcox (E) */
1184 fprintf(xmlout, "%s <CodeblockHeight>%d</CodeblockHeight>\n", s, tccp->cblkh - 2); /* 1 byte, SPcox (F) */
1186 fprintf(xmlout, "%s <!-- CBW and CBH are non-negative, and summed cannot exceed 8 -->\n",s);
1187 fprintf(xmlout, "%s <!-- Codeblock dimension is 2^(value + 2) -->\n", s);
1189 fprintf(xmlout, "%s <CodeblockStyle>0x%02x</CodeblockStyle>\n", s, tccp->cblksty); /* 1 byte, SPcox (G) */
1191 fprintf(xmlout, "%s <!-- For CodeblockStyle, bits mean (with value 1=feature on, 0=off): -->\n",s);
1192 fprintf(xmlout, "%s <!-- bit 0: Selective arithmetic coding bypass. -->\n",s);
1193 fprintf(xmlout, "%s <!-- bit 1: Reset context probabilities on coding pass boundaries. -->\n",s);
1194 fprintf(xmlout, "%s <!-- bit 2: Termination on each coding pass. -->\n",s);
1195 fprintf(xmlout, "%s <!-- bit 3: Vertically causal context. -->\n",s);
1196 fprintf(xmlout, "%s <!-- bit 4: Predictable termination. -->\n",s);
1197 fprintf(xmlout, "%s <!-- bit 5: Segmentation symbols are used. -->\n",s);
1199 fprintf(xmlout, "%s <Transformation>%d</Transformation>\n", s, tccp->qmfbid); /* 1 byte, SPcox (H) */
1201 fprintf(xmlout, "%s <!-- For Transformation, 0=\"9-7 irreversible filter\", 1=\"5-3 reversible filter\" -->\n",s);
1202 if (tccp->csty & J2K_CP_CSTY_PRT) {
1203 fprintf(xmlout, "%s <PrecinctSize>\n",s); /* 1 byte, SPcox (I_i) */
1205 fprintf(xmlout, "%s <!-- These are size exponents PPx and PPy. May be zero only for first level (aka N(L)LL subband)-->\n",s);
1206 for (i = 0; i < tccp->numresolutions; i++) {
1207 fprintf(xmlout, "%s <PrecinctHeightAndWidth ResolutionLevel=\"%d\">\n", s, i);
1209 fprintf(xmlout,"%s <AsHex>0x%02x</AsHex>\n", s, (tccp->prch[i] << 4) | tccp->prcw[i]); /* packed into 1 byte, SPcox (G) */
1211 fprintf(xmlout,"%s <WidthAsDecimal>%d</WidthAsDecimal>\n", s, tccp->prcw[i]);
1212 fprintf(xmlout,"%s <HeightAsDecimal>%d</HeightAsDecimal>\n", s, tccp->prch[i]);
1214 fprintf(xmlout, "%s </PrecinctHeightAndWidth>\n", s, i);
1216 fprintf(xmlout, "%s </PrecinctSize>\n",s); /* 1 byte, SPcox (I_i) */
1218 fprintf(xmlout, "%s </SPcod>\n",s);
1219 fprintf(xmlout, "%s</CodingStyleDefault>\n",s);
1224 void xml_out_frame_coc(FILE* xmlout, j2k_tcp_t *tcp, int numcomps) /* Optional in main & tile-part headers */
1226 /* Uses global j2k_default_tcp */
1227 j2k_tccp_t *tccp, *firstcomp_tccp;
1229 char spaces[13] = " "; /* 12 spaces if tilepart*/
1231 if(tcp == &j2k_default_tcp) {
1232 s++;s++; /* shorten s to 10 spaces if main */
1235 firstcomp_tccp = &(tcp->tccps[0]);
1236 /* Internal data structure tccp defines separate defaults for each component, set from main */
1237 /* default, then selectively overwritten. */
1238 /* Compare j2k_read_cox(...) */
1239 /* We don't really know which was the default, and which were not */
1240 /* Let's pretend that [0] is the default and all others are not */
1242 fprintf(xmlout, "%s<!-- mj2_to_metadata implementation always reports component[0] as using default COD, -->\n", s);
1243 if(tcp == &j2k_default_tcp)
1244 fprintf(xmlout, "%s<!-- and any other component, with main-header style values different from [0], as COC. -->\n", s);
1246 fprintf(xmlout, "%s<!-- and any other component, with tile-part-header style values different from [0], as COC. -->\n", s);
1248 for (compno = 1; compno < numcomps; compno++) /* spec says components are zero-based */
1250 tccp = &tcp->tccps[compno];
1251 if(same_component_style(firstcomp_tccp, tccp))
1254 /* Alignments: " < < < < < To help maintain xml pretty-printing */
1255 fprintf(xmlout, "%s<CodingStyleComponent Marker=\"COC\">\n", s); /* Optional in main header, at most 1 per component */
1257 fprintf(xmlout, "%s <!-- See Ccoc below for zero-based component number. -->\n", s);
1258 /* Overrides the main COD for the specific component */
1259 /* Not retained or of interest: Lcod */
1260 fprintf(xmlout, "%s <Scoc>0x%02x</Scoc>\n", s, tccp->csty); /* 1 byte */
1262 fprintf(xmlout, "%s <!-- Scoc defines entropy coder precincts: -->\n", s);
1263 fprintf(xmlout, "%s <!-- 0 = maximum, namely (PPx=15, PPy=15); 1 = precincts defined below. -->\n", s);
1265 fprintf(xmlout, "%s <Ccoc>%d</Ccoc>\n", s, compno); /* 1 or 2 bytes */
1266 /* Unfortunately compo isn't retained in j2k_read_coc: compno = cio_read(j2k_img->numcomps <= 256 ? 1 : 2); /* Ccoc */
1267 /*if(j2k_img_numcomps <=256)
1272 /* This code will compile only if declaration of j2k_default_tcp is changed from static (to implicit extern) in j2k.c */
1273 fprintf(xmlout, "%s <SPcoc>\n", s);
1274 fprintf(xmlout, "%s <NumberOfDecompositionLevels>%d</NumberOfDecompositionLevels>\n", s, tccp->numresolutions - 1); /* 1 byte, SPcox (D) */
1275 fprintf(xmlout, "%s <CodeblockWidth>%d</CodeblockWidth>\n", s, tccp->cblkw - 2); /* 1 byte, SPcox (E) */
1276 fprintf(xmlout, "%s <CodeblockHeight>%d</CodeblockHeight>\n", s, tccp->cblkh - 2); /* 1 byte, SPcox (F) */
1278 fprintf(xmlout, "%s <!-- CBW and CBH are non-negative, and summed cannot exceed 8 -->\n", s);
1279 fprintf(xmlout, "%s <!-- Codeblock dimension is 2^(value + 2) -->\n", s);
1281 fprintf(xmlout, "%s <CodeblockStyle>0x%02x</CodeblockStyle>\n", s, tccp->cblksty); /* 1 byte, SPcox (G) */
1283 fprintf(xmlout, "%s <!-- For CodeblockStyle, bits mean (with value 1=feature on, 0=off): -->\n", s);
1284 fprintf(xmlout, "%s <!-- bit 0: Selective arithmetic coding bypass. -->\n", s);
1285 fprintf(xmlout, "%s <!-- bit 1: Reset context probabilities on coding pass boundaries. -->\n", s);
1286 fprintf(xmlout, "%s <!-- bit 2: Termination on each coding pass. -->\n", s);
1287 fprintf(xmlout, "%s <!-- bit 3: Vertically causal context. -->\n", s);
1288 fprintf(xmlout, "%s <!-- bit 4: Predictable termination. -->\n", s);
1289 fprintf(xmlout, "%s <!-- bit 5: Segmentation symbols are used. -->\n", s);
1291 fprintf(xmlout, "%s <Transformation>%d</Transformation>\n", s, tccp->qmfbid); /* 1 byte, SPcox (H) */
1293 fprintf(xmlout, "%s <!-- For Transformation, 0=\"9-7 irreversible filter\", 1=\"5-3 reversible filter\" -->\n", s);
1294 if (tccp->csty & J2K_CP_CSTY_PRT) {
1295 fprintf(xmlout, "%s <PrecinctSize>\n", s); /* 1 byte, SPcox (I_i) */
1297 fprintf(xmlout, "%s <!-- These are size exponents PPx and PPy. May be zero only for first level (aka N(L)LL subband)-->\n", s);
1298 for (i = 0; i < tccp->numresolutions-1; i++) { /* subtract 1 to get # of decomposition levels */
1299 fprintf(xmlout, "%s <PrecinctHeightAndWidth ResolutionLevel=\"%d\">\n", s, i);
1301 fprintf(xmlout,"%s <AsHex>0x%02x</AsHex>\n", s, (tccp->prch[i] << 4) | tccp->prcw[i]); /* packed into 1 byte, SPcox (G) */
1303 fprintf(xmlout,"%s <WidthAsDecimal>%d</WidthAsDecimal>\n", s, tccp->prcw[i]);
1304 fprintf(xmlout,"%s <HeightAsDecimal>%d</HeightAsDecimal>\n", s, tccp->prch[i]);
1306 fprintf(xmlout, "%s </PrecinctHeightAndWidth>\n", s, i);
1308 fprintf(xmlout, "%s </PrecinctSize>\n", s); /* 1 byte, SPcox (I_i) */
1310 fprintf(xmlout, "%s </SPcoc>\n", s);
1311 fprintf(xmlout, "%s</CodingStyleComponent>\n", s);
1317 BOOL same_component_style(j2k_tccp_t *tccp1, j2k_tccp_t *tccp2)
1321 if(tccp1->numresolutions != tccp2->numresolutions)
1323 if(tccp1->cblkw != tccp2->cblkw)
1325 if(tccp1->cblkh != tccp2->cblkh)
1327 if(tccp1->cblksty != tccp2->cblksty)
1329 if(tccp1->csty != tccp2->csty)
1332 if (tccp1->csty & J2K_CP_CSTY_PRT) {
1333 for (i = 0; i < tccp1->numresolutions; i++) {
1334 if(tccp1->prcw[i] != tccp2->prcw[i] || tccp1->prch[i] != tccp2->prch[i])
1343 void xml_out_frame_qcd(FILE* xmlout, j2k_tcp_t *tcp)
1345 /* This code will compile only if declaration of j2k_default_tcp is changed from static (to implicit extern) in j2k.c */
1347 int bandno, numbands;
1348 char spaces[13] = " "; /* 12 spaces if tilepart*/
1350 if(tcp == &j2k_default_tcp) {
1351 s++;s++; /* shorten s to 10 spaces if main */
1354 /* Compare j2k_read_qcx */
1355 fprintf(xmlout, "%s<QuantizationDefault Marker=\"QCD\">\n", s); /* Required in main header, single occurrence */
1356 tccp = &(tcp->tccps[0]);
1357 /* Not retained or of interest: Lqcd */
1358 fprintf(xmlout, "%s <Sqcd>\n", s); /* 1 byte */
1360 fprintf(xmlout, "%s <!-- Default quantization style for all components. -->\n", s);
1362 fprintf(xmlout, "%s <AsHex>0x%02x</AsHex>\n", s, (tccp->numgbits) << 5 | tccp->qntsty);
1364 fprintf(xmlout, "%s <QuantizationStyle>%d</QuantizationStyle>\n", s, tccp->qntsty);
1366 fprintf(xmlout, "%s <!-- Quantization style (in Sqcd's low 5 bits) may be: -->\n", s);
1367 fprintf(xmlout, "%s <!-- 0 = No quantization. SPqcd size = 8 bits-->\n", s);
1368 fprintf(xmlout, "%s <!-- 1 = Scalar derived (values signaled for N(L)LL subband only). Use Eq. E.5. SPqcd size = 16. -->\n", s);
1369 fprintf(xmlout, "%s <!-- 2 = Scalar expounded (values signaled for each subband). SPqcd size = 16. -->\n", s);
1372 fprintf(xmlout, "%s <NumberOfGuardBits>%d</NumberOfGuardBits>\n", s, tccp->numgbits);
1374 fprintf(xmlout, "%s <!-- 0-7 guard bits allowed (stored in Sqcd's high 3 bits) -->\n", s);
1375 fprintf(xmlout, "%s </Sqcd>\n", s);
1377 /* Problem: numbands in some cases is calculated from len, which is not retained or available here at this time */
1378 /* So we'll just dump all internal values */
1379 /* We could calculate it, but I'm having trouble believing the length equations in the standard */
1381 fprintf(xmlout, "%s <SPqcd>\n", s);
1382 switch(tccp->qntsty) {
1383 case J2K_CCP_QNTSTY_NOQNT: /* no quantization */
1384 /* This is what standard says, but I don't believe it: len = 4 + (3*decomp); */
1385 numbands = J2K_MAXBANDS; /* should be: numbands = len - 1; */
1386 /* Better: IMAGINE numbands = tccp->stepsize_numbands; */
1387 /* Instead look for first zero exponent, quit there. Adequate? */
1388 fprintf(xmlout, "%s <ReversibleStepSizeValue>\n", s);
1390 fprintf(xmlout, "%s <!-- Current mj2_to_metadata implementation dumps entire internal table, -->\n", s);
1391 fprintf(xmlout, "%s <!-- until an exponent with zero value is reached. -->\n", s);
1392 fprintf(xmlout, "%s <!-- Exponent epsilon(b) of reversible dynamic range. -->\n", s);
1393 fprintf(xmlout, "%s <!-- Hex value is as stored, in high-order 5 bits. -->\n", s);
1395 for (bandno = 0; bandno < numbands; bandno++) {
1396 if(tccp->stepsizes[bandno].expn == 0)
1397 break; /* Remove when we have real numbands */
1398 fprintf(xmlout, "%s <DynamicRangeExponent Subband=\"%d\">\n", s, bandno);
1400 fprintf(xmlout,"%s <AsHex>0x%02x</AsHex>\n", s, tccp->stepsizes[bandno].expn << 3);
1402 fprintf(xmlout,"%s <AsDecimal>%d</AsDecimal>\n", s, tccp->stepsizes[bandno].expn);
1403 fprintf(xmlout, "%s </DynamicRangeExponent>\n", s);
1405 fprintf(xmlout, "%s </ReversibleStepSizeValue>\n", s);
1407 case J2K_CCP_QNTSTY_SIQNT: /* scalar quantization derived */
1408 /* This is what standard says. Should I believe it:: len = 5;
1410 fprintf(xmlout, "%s <QuantizationStepSizeValues>\n", s);
1412 fprintf(xmlout, "%s <!-- For irreversible transformation only. See Part I Annex E Equation E.3 -->\n", s);
1413 fprintf(xmlout, "%s <QuantizationValues Subband=\"0\">\n", s);
1415 fprintf(xmlout, "%s <!-- For N(L)LL subband: >\n", s);
1417 fprintf(xmlout, "%s <AsHex>0x%02x</AsHex>\n", s, (tccp->stepsizes[0].expn << 11) | tccp->stepsizes[0].mant);
1419 fprintf(xmlout, "%s <Exponent>%d</Exponent>\n", s, tccp->stepsizes[0].expn);
1420 fprintf(xmlout, "%s <Mantissa>%d</Mantissa>\n", s, tccp->stepsizes[0].mant);
1422 fprintf(xmlout, "%s </QuantizationValues>\n", s);
1424 fprintf(xmlout, "%s <!-- Exponents for subbands beyond 0 are not from header, but calculated per Eq. E.5 -->\n", s);
1425 fprintf(xmlout, "%s <!-- The mantissa for all subbands is the same, given by the value above. -->\n", s);
1426 fprintf(xmlout, "%s <!-- Current mj2_to_metadata implementation dumps entire internal table, -->\n", s);
1427 fprintf(xmlout, "%s <!-- until a subband with exponent of zero value is reached. -->\n", s);
1430 for (bandno = 1; bandno < J2K_MAXBANDS; bandno++) {
1431 if(tccp->stepsizes[bandno].expn == 0)
1434 fprintf(xmlout, "%s <CalculatedExponent Subband=\"%d\">%d</CalculatedExponent>\n", s, bandno, tccp->stepsizes[bandno].expn);
1437 fprintf(xmlout, "%s </QuantizationStepSizeValues>\n", s);
1440 default: /* J2K_CCP_QNTSTY_SEQNT */ /* scalar quantization expounded */
1441 /* This is what standard says, but should I believe it: len = 5 + 6*decomp; */
1442 numbands = J2K_MAXBANDS; /* should be: (len - 1) / 2;*/
1443 /* Better: IMAGINE numbands = tccp->stepsize_numbands; */
1444 fprintf(xmlout, "%s <QuantizationStepSizeValues>\n", s);
1446 fprintf(xmlout, "%s <!-- For irreversible transformation only. See Part I Annex E Equation E.3 -->\n", s);
1447 fprintf(xmlout, "%s <!-- Current mj2_to_metadata implementation dumps entire internal table, -->\n", s);
1448 fprintf(xmlout, "%s <!-- until a subband with mantissa and exponent of zero values is reached. -->\n", s);
1450 for (bandno = 0; bandno < numbands; bandno++) {
1451 if(tccp->stepsizes[bandno].expn == 0 && tccp->stepsizes[bandno].mant == 0)
1452 break; /* Remove when we have real numbands */
1454 fprintf(xmlout, "%s <QuantizationValues Subband=\"%d\">\n", s, bandno);
1456 fprintf(xmlout,"%s <AsHex>0x%02x</AsHex>\n", s, (tccp->stepsizes[bandno].expn << 11) | tccp->stepsizes[bandno].mant);
1458 fprintf(xmlout,"%s <Exponent>%d</Exponent>\n", s, tccp->stepsizes[bandno].expn);
1459 fprintf(xmlout,"%s <Mantissa>%d</Mantissa>\n", s, tccp->stepsizes[bandno].mant);
1461 fprintf(xmlout, "%s </QuantizationValues>\n", s);
1463 fprintf(xmlout, "%s </QuantizationStepSizeValues>\n", s);
1466 fprintf(xmlout, "%s </SPqcd>\n", s);
1467 fprintf(xmlout, "%s</QuantizationDefault>\n", s);
1469 /* Alignments: " < < < < < To help maintain xml pretty-printing */
1474 void xml_out_frame_qcc(FILE* xmlout, j2k_tcp_t *tcp, int numcomps)
1476 /* Uses global j2k_default_tcp */
1477 /* This code will compile only if declaration of j2k_default_tcp is changed from static (to implicit extern) in j2k.c */
1478 j2k_tccp_t *tccp, *firstcomp_tccp;
1479 int bandno, numbands;
1481 char spaces[13] = " "; /* 12 spaces if tilepart*/
1483 if(tcp == &j2k_default_tcp) {
1484 s++;s++; /* shorten s to 10 spaces if main */
1487 firstcomp_tccp = &(tcp->tccps[0]);
1488 /* Internal data structure tccp defines separate defaults for each component, set from main */
1489 /* default, then selectively overwritten. */
1490 /* Compare j2k_read_qcx(...) */
1491 /* We don't really know which was the default, and which were not */
1492 /* Let's pretend that [0] is the default and all others are not */
1494 fprintf(xmlout, "%s<!-- mj2_to_metadata implementation always reports component[0] as using default QCD, -->\n", s);
1495 if(tcp == &j2k_default_tcp)
1496 fprintf(xmlout, "%s<!-- and any other component, with main-header quantization values different from [0], as QCC. -->\n", s);
1498 fprintf(xmlout, "%s<!-- and any other component, with tile-part-header quantization values different from [0], as QCC. -->\n", s);
1500 for (compno = 1; compno < numcomps; compno++) /* spec says components are zero-based */
1502 tccp = &(tcp->tccps[compno]);
1503 if(same_component_quantization(firstcomp_tccp, tccp))
1506 /* Compare j2k_read_qcx */
1507 fprintf(xmlout, "%s<QuantizationComponent Marker=\"QCC\" Component=\"%d\">\n", s, compno); /* Required in main header, single occurrence */
1508 tccp = &j2k_default_tcp.tccps[0];
1509 /* Not retained or perhaps of interest: Lqcd It maybe can be calculated. */
1510 fprintf(xmlout, "%s <Sqcc>\n", s); /* 1 byte */
1512 fprintf(xmlout, "%s <!-- Quantization style for this component. -->\n", s);
1514 fprintf(xmlout, "%s <AsHex>0x%02x</AsHex>\n", s, (tccp->numgbits) << 5 | tccp->qntsty);
1516 fprintf(xmlout, "%s <QuantizationStyle>%d</QuantizationStyle>\n", s, tccp->qntsty);
1518 fprintf(xmlout, "%s <!-- Quantization style (in Sqcc's low 5 bits) may be: -->\n", s);
1519 fprintf(xmlout, "%s <!-- 0 = No quantization. SPqcc size = 8 bits-->\n", s);
1520 fprintf(xmlout, "%s <!-- 1 = Scalar derived (values signaled for N(L)LL subband only). Use Eq. E.5. SPqcc size = 16. -->\n", s);
1521 fprintf(xmlout, "%s <!-- 2 = Scalar expounded (values signaled for each subband). SPqcc size = 16. -->\n", s);
1524 fprintf(xmlout, "%s <NumberOfGuardBits>%d</NumberOfGuardBits>\n", s, tccp->numgbits);
1526 fprintf(xmlout, "%s <!-- 0-7 guard bits allowed (stored in Sqcc's high 3 bits) -->\n", s);
1527 fprintf(xmlout, "%s </Sqcc>\n", s);
1529 /* Problem: numbands in some cases is calculated from len, which is not retained or available here at this time */
1530 /* So we'll just dump all internal values */
1531 fprintf(xmlout, "%s <SPqcc>\n", s);
1532 switch(tccp->qntsty) {
1533 case J2K_CCP_QNTSTY_NOQNT:
1534 numbands = J2K_MAXBANDS; /* should be: numbands = len - 1; */
1535 /* Better: IMAGINE numbands = tccp->stepsize_numbands; */
1537 /* Instead look for first zero exponent, quit there. Adequate? */
1538 fprintf(xmlout, "%s <ReversibleStepSizeValue>\n", s);
1540 fprintf(xmlout, "%s <!-- Current mj2_to_metadata implementation dumps entire internal table, -->\n", s);
1541 fprintf(xmlout, "%s <!-- until an exponent with zero value is reached. -->\n", s);
1542 fprintf(xmlout, "%s <!-- Exponent epsilon(b) of reversible dynamic range. -->\n", s);
1543 fprintf(xmlout, "%s <!-- Hex value is as stored, in high-order 5 bits. -->\n", s);
1545 for (bandno = 0; bandno < numbands; bandno++) {
1546 if(tccp->stepsizes[bandno].expn == 0)
1547 break; /* Remove this once we have real numbands */
1548 fprintf(xmlout, "%s <Exponent Subband=\"%d\">\n", s, bandno);
1550 fprintf(xmlout,"%s <AsHex>0x%02x</AsHex>\n", s, tccp->stepsizes[bandno].expn << 3);
1552 fprintf(xmlout,"%s <AsDecimal>%d</AsDecimal>\n", s, tccp->stepsizes[bandno].expn);
1553 fprintf(xmlout, "%s </Exponent>\n", s);
1555 fprintf(xmlout, "%s </ReversibleStepSizeValue>\n", s);
1557 case J2K_CCP_QNTSTY_SIQNT:
1559 fprintf(xmlout, "%s <QuantizationStepSizeValues>\n", s);
1561 fprintf(xmlout, "%s <!-- For irreversible transformation only. See Part I Annex E Equation E.3 -->\n", s);
1562 fprintf(xmlout, "%s <QuantizationValuesForSubband0>\n", s);
1564 fprintf(xmlout, "%s <!-- For N(L)LL subband: >\n", s);
1566 fprintf(xmlout, "%s <AsHex>0x%02x</AsHex>\n", s, (tccp->stepsizes[0].expn << 11) | tccp->stepsizes[0].mant);
1568 fprintf(xmlout, "%s <Exponent>%d</Exponent>\n", s, tccp->stepsizes[0].expn);
1569 fprintf(xmlout, "%s <Mantissa>%d</Mantissa>\n", s, tccp->stepsizes[0].mant);
1571 fprintf(xmlout, "%s </QuantizationValuesForSubband0>\n", s);
1573 fprintf(xmlout, "%s <!-- Exponents for subbands beyond 0 are not from header, but calculated per Eq. E.5 -->\n", s);
1574 fprintf(xmlout, "%s <!-- The mantissa for all subbands is the same, given by the value above. -->\n", s);
1575 fprintf(xmlout, "%s <!-- Current mj2_to_metadata implementation dumps entire internal table, -->\n", s);
1576 fprintf(xmlout, "%s <!-- until a subband with exponent of zero value is reached. -->\n", s);
1579 for (bandno = 1; bandno < J2K_MAXBANDS; bandno++) {
1580 if(tccp->stepsizes[bandno].expn == 0)
1583 fprintf(xmlout, "%s <CalculatedExponent Subband=\"%d\">%d</CalculatedExponent>\n", s, bandno, tccp->stepsizes[bandno].expn);
1585 fprintf(xmlout, "%s </QuantizationStepSizeValues>\n", s);
1588 default: /* J2K_CCP_QNTSTY_SEQNT */
1589 numbands = J2K_MAXBANDS; /* should be: (len - 1) / 2;*/
1590 /* Better: IMAGINE numbands = tccp->stepsize_numbands; */
1591 fprintf(xmlout, "%s <QuantizationStepSizeValues>\n", s);
1593 fprintf(xmlout, "%s <!-- For irreversible transformation only. See Part I Annex E Equation E.3 -->\n", s);
1594 fprintf(xmlout, "%s <!-- Current mj2_to_metadata implementation dumps entire internal table, -->\n", s);
1595 fprintf(xmlout, "%s <!-- until a subband with mantissa and exponent of zero values is reached. -->\n", s);
1597 for (bandno = 0; bandno < numbands; bandno++) {
1598 if(tccp->stepsizes[bandno].expn == 0 && tccp->stepsizes[bandno].mant == 0)
1599 break; /* Remove this once we have real numbands count */
1600 fprintf(xmlout, "%s <QuantizationValues Subband=\"%d\">\n", s, bandno);
1602 fprintf(xmlout,"%s <AsHex>0x%02x</AsHex>\n", s, (tccp->stepsizes[bandno].expn << 11) | tccp->stepsizes[bandno].mant);
1604 fprintf(xmlout,"%s <Exponent>%d</Exponent>\n", s, tccp->stepsizes[bandno].expn);
1605 fprintf(xmlout,"%s <Mantissa>%d</Mantissa>\n", s, tccp->stepsizes[bandno].mant);
1607 fprintf(xmlout, "%s </QuantizationValues>\n", s);
1609 fprintf(xmlout, "%s </QuantizationStepSizeValues>\n", s);
1612 fprintf(xmlout, "%s </SPqcc>\n", s);
1613 fprintf(xmlout, "%s</QuantizationComponent>\n", s);
1615 /* Alignments: " < < < < < To help maintain xml pretty-printing */
1620 BOOL same_component_quantization(j2k_tccp_t *tccp1, j2k_tccp_t *tccp2)
1622 int bandno, numbands;
1624 if(tccp1->qntsty != tccp2->qntsty)
1626 if(tccp1->numgbits != tccp2->numgbits)
1629 switch(tccp1->qntsty) {
1630 case J2K_CCP_QNTSTY_NOQNT:
1631 numbands = J2K_MAXBANDS; /* should be: numbands = len - 1; */
1632 /* Instead look for first zero exponent, quit there. Adequate? */
1633 for (bandno = 0; bandno < numbands; bandno++) {
1634 if(tccp1->stepsizes[bandno].expn == 0)
1636 if(tccp1->stepsizes[bandno].expn != tccp2->stepsizes[bandno].expn)
1640 case J2K_CCP_QNTSTY_SIQNT:
1642 if(tccp1->stepsizes[0].expn != tccp2->stepsizes[0].expn || tccp1->stepsizes[0].mant != tccp2->stepsizes[0].mant)
1644 /* Don't need to check remainder, since they are calculated from [0] */
1647 default: /* J2K_CCP_QNTSTY_SEQNT */
1648 numbands = J2K_MAXBANDS; /* should be: (len - 1) / 2;*/
1649 /* This comparison may cause us problems with trailing junk values. */
1650 for (bandno = 0; bandno < numbands; bandno++) {
1651 if(tccp1->stepsizes[bandno].expn != tccp2->stepsizes[bandno].expn || tccp1->stepsizes[bandno].mant != tccp2->stepsizes[bandno].mant);
1661 void xml_out_frame_rgn(FILE* xmlout, j2k_tcp_t *tcp, int numcomps)
1664 /* MJ2 files can have regions of interest if hybridized with JPX Part II */
1665 char spaces[13] = " "; /* 12 spaces if tilepart*/
1667 if(tcp == &j2k_default_tcp) {
1668 s++;s++; /* shorten s to 10 spaces if main */
1671 for(compno = 0; compno < numcomps; compno++) {
1672 SPrgn = tcp->tccps[compno].roishift; /* 1 byte; SPrgn */
1674 continue; /* Yet another kludge */
1676 fprintf(xmlout, "%s<RegionOfInterest Marker=\"RGN\">\n", s); /* Optional in main header, at most 1 per component */
1678 fprintf(xmlout, "%s<!-- See Crgn below for zero-based component number. -->\n", s);
1679 /* Not retained or of interest: Lrgd */
1680 fprintf(xmlout, "%s <Srgn>0</Srgn>\n", s); /* 1 byte */
1682 fprintf(xmlout, "%s <!-- Srgn is ROI style. Only style=0 defined: Implicit ROI (max. shift) -->\n", s);
1683 fprintf(xmlout, "%s <Crgn>%d</Crgn>\n", s, compno); /* 1 or 2 bytes */
1684 fprintf(xmlout, "%s <SPrgn>%d</SPrgn>\n", s, SPrgn); /* 1 byte */
1686 fprintf(xmlout, "%s <!-- SPrgn is implicit ROI shift, i.e., binary shifting of ROI coefficients above background. -->\n", s);
1687 fprintf(xmlout, "</RegionOfInterest\n", s); /* Optional in main header, at most 1 per component */
1693 void xml_out_frame_poc(FILE* xmlout, j2k_tcp_t *tcp) { /* Progression Order Change */
1694 /* Compare j2k_read_poc() */
1697 char spaces[13] = " "; /* 12 spaces if tilepart*/
1699 if(tcp == &j2k_default_tcp) {
1700 s++;s++; /* shorten s to 10 spaces if main */
1704 return; /* Not present */
1706 fprintf(xmlout, "%s<ProgressionOrderChange Marker=\"POC\">\n", s); /* Optional in main header, at most 1 per component */
1707 /* j2k_read_poc seems to allow accumulation of default pocs from multiple POC segments, but does
1708 the spec really allow that? */
1709 /* 2 bytes, not retained; Lpoc */
1710 /* I probably didn't get this dump precisely right. */
1711 for (i = 0; i < tcp->numpocs; i++) {
1712 poc = &tcp->pocs[i];
1713 fprintf(xmlout, "%s <Progression Num=\"%d\">\n", s, i+1);
1714 fprintf(xmlout, "%S <RSpoc>%d</RSpoc>\n", s, poc->resno0); /* 1 byte, RSpoc_i */
1716 fprintf(xmlout,"%s <!-- Resolution level index (inclusive) for progression start. Range: 0 to 33 -->\n", s);
1717 fprintf(xmlout, "%s <CSpoc>%d</CSpoc>\n", s, poc->compno0);/* j2k_img->numcomps <= 256 ? 1 byte : 2 bytes; CSpoc_i */
1719 fprintf(xmlout,"%s <!-- Component index (inclusive) for progression start. -->\n", s);
1720 fprintf(xmlout, "%s <LYEpoc>%d</LYEpoc>\n", s, poc->layno1); /* int_min(cio_read(2), tcp->numlayers); /* 2 bytes; LYEpoc_i */
1722 fprintf(xmlout,"%s <!-- Layer index (exclusive) for progression end. -->\n", s);
1723 fprintf(xmlout, "%s <REpoc>%d</REpoc>\n", s, poc->resno1); /*int_min(cio_read(1), tccp->numresolutions); /* REpoc_i */
1725 fprintf(xmlout,"%s <!-- Resolution level index (exclusive) for progression end. Range: RSpoc to 33 -->\n", s);
1726 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 */
1728 fprintf(xmlout,"%s <!-- Component index (exclusive) for progression end. Minimum: CSpoc -->\n", s);
1729 fprintf(xmlout, "%s <Ppoc>%d</Ppoc>\n", s, poc->prg); /* 1 byte Ppoc_i */
1731 fprintf(xmlout,"%s <!-- Defined Progression Order Values are: -->\n", s);
1732 fprintf(xmlout,"%s <!-- 0 = LRCP; 1 = RLCP; 2 = RPCL; 3 = PCRL; 4 = CPRL -->\n", s);
1733 fprintf(xmlout,"%s <!-- where L = \"layer\", R = \"resolution level\", C = \"component\", P = \"position\". -->\n", s);
1735 fprintf(xmlout, "%s </Progression>\n", s);
1737 fprintf(xmlout, "%s</ProgressionOrderChange\n", s);
1742 #ifdef SUPPRESS_FOR_NOW
1743 /* Suppress PPM and PPT since we're not showing data from the third option, namely within the codestream, and
1744 that's evidently what frames_to_mj2 uses. And a hex dump isn't so useful anyway */
1746 void xml_out_frame_ppm(FILE *xmlout, j2k_cp_t *cp) { /* For main header, not tile-part (which uses PPT instead). */
1747 /* Either the PPM or PPT is required if the packet headers are not distributed in the bit stream */
1748 /* Use of PPM and PPT are mutually exclusive. */
1749 /* Compare j2k_read_ppm() */
1753 return; /* Not present */
1754 /* Main header uses indent of 10 spaces */
1755 fprintf(xmlout, " <PackedPacketHeadersMainHeader Marker=\"PPM\">\n"); /* Optional in main header, but if not, must be in PPT or codestream */
1756 /* 2 bytes Lppm not saved */
1758 fprintf(xmlout, " <!-- If there are multiple PPM marker segments in the main header, -->\n");
1759 fprintf(xmlout, " <!-- this mj2_to_metadata implementation will report them as a single consolidated PPM header. -->\n");
1760 fprintf(xmlout, " <!-- The implementation can't currently segregate by tile-part. -->\n");
1761 fprintf(xmlout, " <!-- TO DO? further map the packet headers to xml. -->\n");
1764 /* 1 byte, not retained ; Zppm is sequence # of this PPM header */
1765 /* 4 bytes, possibly overwritten multiple times in j2k_cp->ppm_previous: Nppm */
1766 /* Use j symbol for index instead of i, to make comparable with j2k_read_ppm */
1767 /* Not real clear whether to use ppm->store or ppm_len as upper bound */
1768 fprintf(xmlout, " <PackedData>\n");
1769 xml_out_dump_hex(xmlout, cp->ppm_data, cp->ppm_len);
1770 /* Dump packet headers 1 byte at a time: lppm[i][j] */
1771 fprintf(xmlout, " </PackedData>\n");
1772 fprintf(xmlout, " </PackedPacketHeadersMainHeader>\n"); /* Optional in main header, but if not, must be in PPT or codestream */
1777 void xml_out_frame_ppt(FILE *xmlout, j2k_tcp_t *tcp) { /* For tile-part header, not main (which uses PPM instead). */
1778 /* Either the PPM or PPT is required if the packet headers are not distributed in the bit stream */
1779 /* Use of PPM and PPT are mutually exclusive. */
1780 /* Compare j2k_read_ppt() */
1784 return; /* Not present */
1786 /* Tile-part indents are 12 spaces */
1787 fprintf(xmlout, " <PackedPacketHeadersTilePartHeader Marker=\"PPT\">\n"); /* Optional in main header, but if not, must be in PPT or codestream */
1788 /* 2 bytes Lppm not saved */
1790 fprintf(xmlout, " <!-- If there are multiple PPT marker segments in the tile-part header, -->\n");
1791 fprintf(xmlout, " <!-- this mj2_to_metadata implementation will report them as a single consolidated PPT header. -->\n");
1792 fprintf(xmlout, " <!-- The implementation can't currently segregate by tile-part. -->\n");
1793 fprintf(xmlout, " <!-- TO DO? further map the packet headers to xml. -->\n");
1796 /* 1 byte, not retained ; Zppt is sequence # of this PPT header */
1797 /* 4 bytes, possibly overwritten multiple times in j2k_cp->ppt_previous: Nppt */
1798 /* Use j symbol for index instead of i, to make comparable with j2k_read_ppt */
1799 /* Not real clear whether to use ppt->store or ppt_len as upper bound */
1800 fprintf(xmlout, " <PackedData>\n");
1801 xml_out_dump_hex(xmlout, tcp->ppt_data, tcp->ppt_len);
1802 /* Dump packet headers 1 byte at a time: lppt[i][j] */
1803 fprintf(xmlout, " </PackedData>\n");
1804 fprintf(xmlout, " </PackedPacketHeadersTileHeader>\n"); /* Optional in tile-part header, but if not, must be in PPM or codestream */
1806 #endif SUPPRESS_FOR_NOW
1810 void xml_out_frame_tlm(FILE* xmlout) { /* opt, main header only. May be multiple. */
1811 /* Compare j2k_read_tlm()... which doesn't retain anything! */
1812 /* Plan: Since this is only called from main header, not tilepart, use global j2k_default_tcp rather than parameter */
1813 /* Main header indents are 10 spaces */
1818 void xml_out_frame_plm(FILE* xmlout) { /* opt, main header only; can be used in conjunction with tile-part's PLT */
1819 /* NO-OP. PLM NOT SAVED IN DATA STRUCTURE */
1820 /* Compare j2k_read_plm()... which doesn't retain anything! */
1821 /* Plan: Since this is only called from main header, not tilepart, use global j2k_default_tcp rather than parameter */
1822 /* Main header indents are 10 spaces */
1827 void xml_out_frame_plt(FILE* xmlout, j2k_tcp_t *tcp) { /* opt, tile-part headers only; can be used in conjunction with main header's PLM */
1828 /* NO-OP. PLT NOT SAVED IN DATA STRUCTURE */
1829 /* Compare j2k_read_plt()... which doesn't retain anything! */
1830 /* Tile-part header indents are 12 spaces */
1835 void xml_out_frame_crg(FILE* xmlout) { /* NO-OP. CRG NOT SAVED IN DATA STRUCTURE */ /* opt, main header only; */
1836 /* Compare j2k_read_crg()... which doesn't retain anything! */
1837 /* Plan: Since this is only called from main header, not tilepart, use global j2k_default_tcp rather than parameter */
1839 THIS PSEUDOCODE IMAGINES THESE EXIST: j2k_default_tcp->crg, j2k_default_tcp->crg_i, j2k_default_tcp->crg_xcrg*, j2k_default_tcp->crg_ycrg*
1840 (POSSIBLY DON'T NEED crg_i, CAN GET NUMBER OR COMPONENTS FROM ELSEWHERE)
1841 if(j2k_default_tcp->crg != 1 || j2k_default_tcp->crg_i == 0)
1842 return; /* Not present */
1844 /* Main header indents are 10 spaces */
1845 fprintf(xmlout, " <ComponentRegistration Marker=\"RG\" Count=\"%d\">\n", j2k_default_tcp->crg_i);
1847 fprintf(xmlout, " <!-- Fine tuning of registration of components with respect to each other, -->\n");
1848 fprintf(xmlout, " <!-- not required but potentially helpful for decoder. -->\n");
1849 fprintf(xmlout, " <!-- These supplementary fractional offsets are in units of 1/65536 of the horizontal -->\n");
1850 fprintf(xmlout, " <!-- or vertical separation (e.g., XRsiz[i] or YRsiz[i] for component i). -->\n");
1852 /* This isn't the most compact form of table, but is OK when number of components is small, as is likely. */
1853 for (i = 0; i < j2k_default_tcp->crg_i; i++) {
1854 fprintf(xmlout, " <Component Num=\"%d\">\n", i+1);
1855 fprintf(xmlout, " <Xcrg>\n");
1857 fprintf(xmlout," <AsNumerator>%d</AsNumerator>\n", j2k_default_tcp->crg_xcrg[i]);
1859 /* Calculate n * 100%/65536; 4 digits after decimal point is sufficiently accurate */
1860 fprintf(xmlout," <AsPercentage>%.4f</AsPercentage>\n", ((double)j2k_default_tcp->crg_xcrg[i])/655.36);
1861 /* We could do another calculation that include XRsiz[i]; maybe later. */
1863 fprintf(xmlout, " </Xcrg>\n");
1864 fprintf(xmlout, " <Ycrg>\n");
1866 fprintf(xmlout," <AsNumerator>%d</AsNumerator>\n", j2k_default_tcp->crg_ycrg[i]);
1868 fprintf(xmlout," <AsPercentage>%f</AsPercentage>\n", ((double)j2k_default_tcp->crg_ycrg[i])/655.36);
1870 fprintf(xmlout, " </Ycrg>\n");
1871 fprintf(xmlout, " </Component>\n");
1874 fprintf(xmlout, " </ComponentRegistration>\n");
1881 /* Regrettably from a metadata point of view, j2k_read_com() skips over any comments in main header or tile-part-header */
1882 void xml_out_frame_com(FILE* xmlout, j2k_tcp_t *tcp) { /* NO-OP. COM NOT SAVED IN DATA STRUCTURE */ /* opt in main or tile-part headers; */
1883 /* Compare j2k_read_com()... which doesn't retain anything! */
1885 char spaces[13] = " "; /* 12 spaces if tilepart*/
1887 if(tcp == &j2k_default_tcp) {
1888 s++;s++; /* shorten s to 10 spaces if main */
1890 THIS PSEUDOCODE IMAGINES THESE EXIST: tcp->com, tcp->com_len, tcp->com_data array
1892 return; /* Not present */
1894 fprintf(xmlout, "%s<Comment Marker=\"COM\">\n", s); /* Optional in main or tile-part header */
1895 xml_out_dump_hex_and_ascii(tcp->com_data, tcp->com_len, s);
1896 fprintf(xmlout, "%s</Comment>\n", s);
1900 void xml_out_dump_hex(FILE* xmlout, char *data, int data_len, char* s) {
1901 /* s is a string of spaces for indent */
1904 /* This is called when raw is true, or there is no appropriate derived form */
1905 fprintf(xmlout, "%s<AsHex>\n", s);
1906 fprintf(xmlout, "%s ", s); /* Inadequate for pretty printing */
1907 for (i = 0; i < data_len; i++) { /* Dump packet headers */
1908 fprintf(xmlout, "%02x", data[i]);
1910 fprintf(xmlout, "%s</AsHex>\n", s);
1913 /* Define this as an even number: */
1914 #define BYTES_PER_DUMP_LINE 40
1915 /* Current total width for Hex and ASCII is : 11 spaces lead + (3 * BPDL) + 2 spaces + BPDL */
1916 void xml_out_dump_hex_and_ascii(FILE* xmlout, char *data, int data_len, char* s) {
1917 /* s is a string of spaces for indent */
1921 xml_out_dump_hex(xmlout, data, data_len, s);
1924 fprintf(xmlout, "%s<AsHexAndASCII>\n", s);
1925 for (i = 0; i < data_len; ) {
1926 fprintf(xmlout,"%s ", s); /* Additional leading space added in loop */
1927 /* First column: hex */
1928 for (j = 0; j < BYTES_PER_DUMP_LINE; j++) /* Dump bytes */
1929 fprintf(xmlout," %02x", data[i+j]);
1930 /* Space between columns... */ fprintf(xmlout, " ");
1931 /* Second column: ASCII */
1932 for (j = 0; j < BYTES_PER_DUMP_LINE; j++, i++) {
1933 if(isprint((int)data[i]) && i < data_len)
1934 fprintf(xmlout,"%c", data[i]);
1936 fprintf(xmlout," ");
1938 /* If we also wanted to output UCS-2 Unicode as a third column, then entire document
1939 must use fwprintf. Forget about it for now. As it stands, if data is UCS-2 format but still
1940 the ASCII set, then we'll be able to read every other byte as ASCII in column 2. If
1941 data is UTF-8 format but still ASCII, then we'll be able to read every byte as ASCII
1944 fprintf(xmlout, "%s</AsHexAndASCII>\n", s);
1951 void xml_out_frame_jp2h(FILE* xmlout, jp2_struct_t *jp2_struct) { /* JP2 Header */
1952 /* Compare jp2_read_jp2h(jp2_struct_t * jp2_struct) */
1955 fprintf(xmlout, " <JP2Header BoxType=\"jp2h\">\n");
1957 /* Compare jp2_read_ihdr(jp2_struct)) */
1958 fprintf(xmlout, " <ImageHeader BoxType=\"ihdr\">\n");
1959 fprintf(xmlout, " <HEIGHT>%d</HEIGHT>\n", jp2_struct->h); /* 4 bytes */
1960 fprintf(xmlout, " <WIDTH>%d</WIDTH>\n", jp2_struct->w); /* 4 bytes */
1962 fprintf(xmlout, " <!-- HEIGHT here, if 2 fields per image, is of total deinterlaced height. -->\n");
1963 fprintf(xmlout, " <NC>%d</NC>\n", jp2_struct->numcomps); /* 2 bytes */
1965 fprintf(xmlout, " <!-- NC is number of components -->\n"); /* 2 bytes */
1966 fprintf(xmlout, " <BPC>\n"); /* 1 byte */
1967 if(jp2_struct->bpc == 255) {
1968 fprintf(xmlout, " <AsHex>0x%02x</AsHex>\n", jp2_struct->bpc); /* 1 byte */
1970 fprintf(xmlout, " <!-- BPC = 0xff means bits per pixel varies with component; see table below. -->\n");
1971 } else { /* Not 0xff */
1973 fprintf(xmlout, " <AsHex>0x%02x</AsHex>\n", jp2_struct->bpc); /* 1 byte */
1975 fprintf(xmlout," <!-- BPC = 0xff means bits per pixel varies with component; see table below. -->\n");
1978 fprintf(xmlout, " <BitsPerPixel>%d</BitsPerPixel>\n", jp2_struct->bpc & 0x7f);
1979 fprintf(xmlout, " <Signed>%d</Signed>\n", jp2_struct->bpc >> 7);
1982 fprintf(xmlout, " </BPC>\n");
1983 fprintf(xmlout, " <C>%d</C>\n", jp2_struct->C); /* 1 byte */
1985 fprintf(xmlout, " <!-- C is compression type. Only \"7\" is allowed to date. -->\n"); /* 2 bytes */
1986 fprintf(xmlout, " <UnkC>%d</UnkC>\n", jp2_struct->UnkC); /* 1 byte */
1988 fprintf(xmlout, " <!-- Colourspace Unknown. 1 = unknown, 0 = known (e.g., colourspace spec is accurate) -->\n"); /* 1 byte */
1989 fprintf(xmlout, " <IPR>%d</IPR>\n", jp2_struct->IPR); /* 1 byte */
1991 fprintf(xmlout, " <!-- IPR is 1 if frame contains an Intellectual Property box; 0 otherwise. -->\n"); /* 2 bytes */
1992 fprintf(xmlout, " </ImageHeader>\n");
1994 if (jp2_struct->bpc == 255)
1996 fprintf(xmlout, " <BitsPerComponent BoxType=\"bpcc\">\n");
1998 fprintf(xmlout, " <!-- Pixel depth (range 1 to 38) is low 7 bits of hex value + 1 -->\n");
1999 /* Bits per pixel varies with components */
2000 /* Compare jp2_read_bpcc(jp2_struct) */
2001 for (i = 0; i < (int)jp2_struct->numcomps; i++) {
2003 fprintf(xmlout," <AsHex>0x%02x</AsHex>\n", jp2_struct->comps[i].bpcc); /* 1 byte */
2005 fprintf(xmlout," <BitsPerPixel>%d</BitsPerPixel>\n", (jp2_struct->comps[i].bpcc & 0x7f)+1);
2006 fprintf(xmlout," <Signed>%d</Signed>\n", jp2_struct->comps[i].bpcc >> 7);
2009 fprintf(xmlout, " </BitsPerComponent>\n");
2012 /* Compare jp2_read_colr(jp2_struct) */
2013 fprintf(xmlout, " <ColourSpecification BoxType=\"colr\">\n");
2014 fprintf(xmlout, " <METH>%d</METH>\n", jp2_struct->meth); /* 1 byte */
2016 fprintf(xmlout, " <!-- Valid values of specification method so far: -->\n");
2017 fprintf(xmlout, " <!-- 1 = Enumerated colourspace, in EnumCS field -->\n");
2018 fprintf(xmlout, " <!-- 2 = Restricted ICC Profile, in PROFILE field -->\n");
2020 fprintf(xmlout, " <PREC>%d</PREC>\n", jp2_struct->precedence); /* 1 byte */
2022 fprintf(xmlout, " <!-- 0 is only valid value of precedence so far. -->\n");
2023 fprintf(xmlout, " <APPROX>%d</APPROX>\n", jp2_struct->approx); /* 1 byte */
2025 fprintf(xmlout, " <!-- 0 is only valid value of colourspace approximation so far. -->\n");
2027 if (jp2_struct->meth == 1) {
2028 fprintf(xmlout, " <EnumCS>%d</EnumCS>\n", jp2_struct->enumcs); /* 4 bytes */
2030 fprintf(xmlout, " <!-- Valid values of enumerated MJ2 colourspace so far: -->\n");
2031 fprintf(xmlout, " <!-- 16: sRGB as defined by IEC 61966-2-1. -->\n");
2032 fprintf(xmlout, " <!-- 17: greyscale (related to sRGB). -->\n");
2033 fprintf(xmlout, " <!-- 18: sRGB YCC (from JPEG 2000 Part II). -->\n");
2034 fprintf(xmlout, " <!-- (Additional JPX values are defined in Part II). -->\n");
2039 fprintf(xmlout, " <!-- PROFILE is not handled by current OpenJPEG implementation. -->\n");
2040 /* only 1 byte is read and nothing stored */
2041 fprintf(xmlout, " </ColourSpecification>\n");
2043 /* TO DO? No OpenJPEG support.
2045 ComponentMapping 'cmap'
2046 ChannelDefinition 'cdef'
2049 fprintf(xmlout, " </JP2Header>\n");
2054 IMAGE these use cp structure, extended... but we could use a new data structure instead
2055 void xml_out_frame_jp2i(FILE* xmlout, j2k_cp_t *cp) {
2056 /* IntellectualProperty 'jp2i' (no restrictions on location) */
2058 IMAGE cp->jp2i, cp->jp2i_count, cp->jp2i_data (array of chars), cp->cp2i_len (array of ints)
2060 return; /* Not present */
2062 for(i = 0; i < cp->jp2i_count; i++)
2064 fprintf(xmlout, " <IntellectualProperty BoxType=\"jp2i\">\n");
2065 /* I think this can be anything, including binary, so do a dump */
2066 /* Is it better to indent or not indent this content? Indent is better for reading, but
2067 worse for cut/paste. */
2068 xml_out_dump_hex_and_ascii(xmlout, cp->jp2i_data[i], cp->jp2i_len[i]);
2069 fprintf(xmlout, " </IntellectualProperty>\n");
2073 void xml_out_frame_xml(FILE* xmlout, j2k_cp_t *cp) {
2074 /* XML 'xml\040' (0x786d6c20). Can appear multiply, before or after jp2c codestreams */
2075 IMAGE cp->xml, cp->xml_count, cp->xml_data (array of chars)
2076 MAYBE WE DON'T NEED cp->xml_len (array of ints) IF WE ASSUME xml_data IS NULL-TERMINATED.
2077 ASSUME ASSUME EACH LINE IS ENDED BY \n.
2080 return; /* Not present */
2082 for(i = 0; i < cp->xml_count; i++)
2084 fprintf(xmlout, " <TextFormXML BoxType=\"xml[space]" Instance=\"%d\">\n", i+1);
2085 /* Is it better to indent or not indent this content? Indent is better for reading, but
2086 worse for cut/paste. Being lazy, didn't indent here. */
2087 fprintf(xmlout,cp->xml_data[i]); /* May be multiple lines */ /* Could check if this is well-formed */
2088 fprintf(xmlout, " </TextFormXML>\n");
2092 void xml_out_frame_uuid(FILE* xmlout, j2k_cp_t *cp) {
2093 /* UUID 'uuid' (top level only) */
2094 /* Part I 1.7.2 says: may appear multiply in JP2 file, anywhere except before File Type box */
2095 /* Part III 5.2.1 says: Private extensions shall be achieved through the 'uuid' type. */
2096 /* A UUID is a 16-byte value. There is a conventional string representation for it:
2097 "0x12345678-9ABC-DEF0-1234-567890ABCDEF". Let's assume that is what is stored in uuid_value */
2099 /* Part III 6.1 Any other MJ2 box type could be alternatively written as a 'uuid' box, with value given
2100 as : 0xXXXXXXXX-0011-0010-8000-00AA00389B71, where the Xs are the boxtype in hex. However,
2101 such a file is "not compliant; systems may choose to read [such] objects ... as equivalent to the box of
2102 the same type, or not." Here, we choose not to. */
2104 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)
2106 return; /* Not present */
2108 for(i = 0; i < cp->uuid_count; i++)
2110 fprintf(xmlout, " <UniversalUniqueID BoxType=\"uuid\">
2111 fprintf(xmlout, " <UUID>%s</UUDI>\n", cp->uuid_value[i]);
2112 fprintf(xmlout, " <Data>\n");
2113 /* I think this can be anything, including binary, so do a dump */
2114 /* Is it better to indent or not indent this content? Indent is better for reading, but
2115 worse for cut/paste. */
2116 xml_out_dump_hex_and_ascii(xmlout, cp->uuid_data[i], cp->uuid_len[i]);
2117 fprintf(xmlout, " </Data>\n");
2118 fprintf(xmlout, " </UniversalUniqueID>\n");
2122 void xml_out_frame_uinf(FILE* xmlout, j2k_cp_t *cp) {
2123 /* UUIDInfo 'uinf', includes UUIDList 'ulst' and URL 'url\40' */
2124 /* Part I 1.7.3 says: may appear multiply in JP2 file, anywhere at the top level except before File Type box */
2125 /* So there may be multiple ulst's, and each can have multiple UUIDs listed (with a single URL) */
2126 /* This is not quite as vendor-specific as UUIDs, or at least is meant to be generally readable */
2127 /* Assume UUIDs stored in canonical string format */
2129 IMAGE cp->uinf, cp->uinf_count, cp->uinf_ulst_nu (array of ints)
2130 cp->uinf_uuid (2 dimensional array of uuids... let's say fixed-length strings),
2131 cp->uinf_url (array of char buffers)
2134 return; /* Not present */
2136 for(i = 0; i < cp->uuid_count; i++)
2138 fprintf(xmlout, " <UUIDInfo BoxType=\"uinf\">\n");
2139 fprintf(xmlout, " <UUIDList BoxType=\"ulst\" Count=\"%d\">\n",cp->cp->uinf_ulst_nu[i]);
2140 for(j = 0; j < cp->uinf_ulst_nu[i]; j++)
2141 fprintf(xmlout, " <ID Instance=\"%s\">%s</ID>\n", cp->uuif_uuid[i][j], j+1);
2142 fprintf(xmlout, " </UUIDList>\n");
2143 fprintf(xmlout, " <DataEntryURL>\n");
2144 /* Could add VERS and FLAG here */
2145 fprintf(xmlout, " <LOC>\n");
2146 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 */
2147 fprintf(xmlout, " </LOC>\n");
2148 fprintf(xmlout, " </DataEntryURL>\n");
2149 fprintf(xmlout, " </UUIDInfo>\n");
2153 IMAGE these use cp structure, extended... but we could use a new data structure instead
2154 void xml_out_frame_unknown_type(FILE* xmlout, j2k_cp_t *cp) {
2155 /* Part III 5.2.1 says "Type fields not defined here are reserved. Private extensions
2156 shall be acieved through the 'uuid' type." [This implies an unknown
2157 type would be an error, but then...] "Boxes not explicitly defined in this standard,
2158 or otherwise unrecognized by a reader, may be ignored."
2159 Also, it says "the following types are not and will not be used, or used only in
2160 their existing sense, in future versions of this specification, to avoid conflict
2161 with existing content using earlier pre-standard versions of this format:
2162 clip, crgn, matt, kmat, pnot, ctab, load, imap;
2163 track reference types tmcd, chap, sync,scpt, ssrc"
2164 [But good luck figuring out the mapping.]
2165 Part III Amend. 2 4.1 is stronger: "All these specifications [of this family, e.g.,
2166 JP2 Part I, ISO Base format (Part 12) leading to MP4, Quicktime, and possibly including
2167 MJ2] require that readers ignore objects that are unrecognizable to them".
2170 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)
2171 if(cp->unknown_type != 1)
2172 return; /* Not present */
2174 for(i = 0; i < cp->unknown_type_count; i++)
2176 fprintf(xmlout, " <UnknownType BoxType=\"%s\">\n", cp->unknown_type_boxtype[i]);
2177 /* Can be anything, including binary, so do a dump */
2178 /* Is it better to indent or not indent this content? Indent is better for reading, but
2179 worse for cut/paste. */
2180 xml_out_dump_hex_and_ascii(xmlout, cp->unknown_type_data[i], cp->unknown_type_len[i]);
2181 fprintf(xmlout, " </UnknownType>\n");