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 *xmlout, mj2_movie_t * movie);
44 void uint_to_chars(unsigned int value, char* buf);
46 void xml_write_trak(FILE *file, FILE *xmlout, mj2_tk_t *track, unsigned int tnum, unsigned int sampleframe);
47 void xml_write_tkhd(FILE* file, FILE* xmlout, mj2_tk_t *track, unsigned int tnum);
48 void xml_write_udta(FILE* file, FILE* xmlout, mj2_tk_t *track, unsigned int tnum);
49 void xml_write_mdia(FILE* file, FILE* xmlout, mj2_tk_t *track, unsigned int tnum);
50 void xml_write_stbl(FILE* file, FILE* xmlout, mj2_tk_t *track, unsigned int tnum);
52 void UnixTimeToFileTime(time_t t, LPFILETIME pft);
53 void UnixTimeToSystemTime(time_t t, LPSYSTEMTIME pst);
54 void xml_time_out(FILE* xmlout, time_t t);
56 void int16_to_3packedchars(short int value, char* buf);
58 void xml_write_moov_udta(FILE* xmlout, mj2_movie_t * movie);
59 void xml_write_free_and_skip(FILE* xmlout, mj2_movie_t * movie);
60 void xml_write_uuid(FILE* xmlout, mj2_movie_t * movie);
62 int xml_out_frame(FILE* file, FILE* xmlout, mj2_sample_t *sample, unsigned int snum);
64 void xml_out_frame_siz(FILE* xmlout, j2k_image_t *img, j2k_cp_t *cp);
65 void xml_out_frame_cod(FILE* xmlout, j2k_tcp_t *tcp);
66 void xml_out_frame_coc(FILE* xmlout, j2k_tcp_t *tcp, int numcomps); /* j2k_image_t *img); */
67 BOOL same_component_style(j2k_tccp_t *tccp1, j2k_tccp_t *tccp2);
68 void xml_out_frame_qcd(FILE* xmlout, j2k_tcp_t *tcp);
69 void xml_out_frame_qcc(FILE* xmlout, j2k_tcp_t *tcp, int numcomps); /* j2k_image_t *img); */
70 BOOL same_component_quantization(j2k_tccp_t *tccp1, j2k_tccp_t *tccp2);
71 void xml_out_frame_rgn(FILE* xmlout, j2k_tcp_t *tcp, int numcomps);/* j2k_image_t *img);*/
72 void xml_out_frame_poc(FILE* xmlout, j2k_tcp_t *tcp);
73 void xml_out_frame_ppm(FILE* xmlout, j2k_cp_t *cp);
74 void xml_out_frame_ppt(FILE* xmlout, j2k_tcp_t *tcp);
75 void xml_out_frame_tlm(FILE* xmlout); /* j2k_default_tcp is passed globally */ /* NO-OP. TLM NOT SAVED IN DATA STRUCTURE */
76 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 */
77 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 */
78 void xml_out_frame_crg(FILE* xmlout); /* j2k_default_tcp is passed globally */ /* opt in main; */
79 void xml_out_frame_com(FILE* xmlout, j2k_tcp_t *tcp); /* NO-OP. COM NOT SAVED IN DATA STRUCTURE */ /* opt in main; */
80 void xml_out_dump_hex(FILE* xmlout, char *data, int data_len);
81 void xml_out_dump_hex_and_ascii(FILE* xmlout, char *data, int data_len);
82 void xml_out_frame_jp2h(FILE* xmlout, jp2_struct_t *jp2_struct);
84 /* Shown with cp, extended, as data structure... but it could be a new different one */
85 void xml_out_frame_jp2i(FILE* xmlout, j2k_cp_t *cp);/* IntellectualProperty 'jp2i' (no restrictions on location) */
86 void xml_out_frame_xml(FILE* xmlout, j2k_cp_t *cp); /* XML 'xml\040' (0x786d6c20). Can appear multiply */
87 void xml_out_frame_uuid(FILE* xmlout, j2k_cp_t *cp); /* UUID 'uuid' (top level only) */
88 void xml_out_frame_uinf(FILE* xmlout, j2k_cp_t *cp); /* UUIDInfo 'uinf', includes UUIDList 'ulst' and URL 'url\40' */
89 void xml_out_frame_unknown_type(FILE* xmlout, j2k_cp_t *cp);
93 /* ------------------------------------------------------------------------------------------- */
95 void xml_write_init(BOOL n, BOOL t, BOOL r, BOOL d)
97 /* Init file globals */
104 int xml_write_struct(FILE* file, FILE *xmlout, mj2_movie_t * movie, unsigned int sampleframe, char* stringDTD) {
108 if(stringDTD != NULL)
110 fprintf(xmlout,"<?xml version=\"1.0\" standalone=\"no\"?>\n");
111 /* stringDTD is known to start with "SYSTEM " or "PUBLIC " */
112 /* typical: SYSTEM mj2_to_metadata.dtd */
113 stringDTD[6] = '\0'; /* Break into two strings at space, so quotes can be inserted. */
114 fprintf(xmlout,"<!DOCTYPE MJ2_File %s \"%s\">\n", stringDTD, stringDTD+7);
115 stringDTD[6] = ' '; /* restore for sake of debugger or memory allocator */
117 fprintf(xmlout,"<?xml version=\"1.0\" standalone=\"yes\"?>\n");
119 fprintf(xmlout, "<MJ2_File>\n");
120 xml_write_overall_header(xmlout, movie);
121 // Find first video track
123 while (movie->tk[tnum].track_type != 0)
126 track = &(movie->tk[tnum]);
128 // For now, output info on first video track
129 xml_write_trak(file, xmlout, track, tnum, sampleframe);
131 fprintf(xmlout, "</MJ2_File>");
137 int xml_write_overall_header(FILE *xmlout, mj2_movie_t * movie)
142 fprintf(xmlout, " <JP2 BoxType=\"jP[space][space]\" Signature=\"0x0d0a870a\" />\n");
143 // Called after structure initialized by mj2_read_ftyp
144 fprintf(xmlout, " <FileType BoxType=\"ftyp\">\n");
145 uint_to_chars(movie->brand, buf);
146 fprintf(xmlout, " <Brand>%s</Brand>\n", buf); /* 4 character; BR */
147 fprintf(xmlout, " <MinorVersion>%u</MinorVersion>\n", movie->minversion); /* 4 char; MinV */
148 fprintf(xmlout, " <CompatibilityList Count=\"%d\">\n",movie->num_cl);
149 for (i = movie->num_cl - 1; i > -1; i--) /* read routine stored in reverse order, so let's undo damage */
151 uint_to_chars(movie->cl[i], buf);
152 fprintf(xmlout, " <CompatibleBrand>%s</CompatibleBrand>\n", buf); /*4 characters, each CLi */
154 fprintf(xmlout, " </CompatibilityList>\n");
155 fprintf(xmlout, " </FileType>\n");
156 fprintf(xmlout, " <MovieBox BoxType=\"moov\">\n");
157 fprintf(xmlout, " <MovieHeader BoxType=\"mvhd\">\n");
158 fprintf(xmlout, " <CreationTime>\n");
160 fprintf(xmlout, " <InSeconds>%u</InSeconds>\n", movie->creation_time);
162 fprintf(xmlout, " <!-- Seconds since start of Jan. 1, 1904 UTC (Greenwich) -->\n");
163 /* 2082844800 = seconds between 1/1/04 and 1/1/70 */
164 /* There's still a time zone offset problem not solved... but spec is ambigous as to whether stored time
165 should be local or UTC */
167 fprintf(xmlout, " <AsLocalTime>");
168 xml_time_out(xmlout, movie->creation_time - 2082844800);
169 fprintf(xmlout,"</AsLocalTime>\n");
171 fprintf(xmlout, " </CreationTime>\n");
172 fprintf(xmlout, " <ModificationTime>\n");
174 fprintf(xmlout, " <InSeconds>%u</InSeconds>\n", movie->modification_time);
176 fprintf(xmlout, " <AsLocalTime>");
177 xml_time_out(xmlout, movie->modification_time - 2082844800);
178 fprintf(xmlout,"</AsLocalTime>\n");
180 fprintf(xmlout, " </ModificationTime>\n");
181 fprintf(xmlout, " <Timescale>%d</Timescale>\n", movie->timescale);
183 fprintf(xmlout, " <!-- Timescale defines time units in one second -->\n");
184 fprintf(xmlout, " <Rate>\n"); /* Rate to play presentation (default = 0x00010000) */
185 #define CURRENTSTRUCT
187 movie->rate = movie->rate << 16;
190 fprintf(xmlout, " <!-- Rate to play presentation is stored as fixed-point binary 16.16 value. Decimal value is approximation. -->\n");
191 fprintf(xmlout, " <!-- Rate is expressed relative to normal (default) value of 0x00010000 (1.0) -->\n");
194 fprintf(xmlout, " <AsHex>0x%08x</AsHex>\n", movie->rate);
196 fprintf(xmlout, " <AsDecimal>%12.6f</AsDecimal>\n", (double)movie->rate/(double)0x00010000);
199 fprintf(xmlout, " <!-- Current m2j_to_metadata implementation always shows bits to right of decimal as zeroed. -->\n");
200 movie->rate = movie->rate >> 16;
202 fprintf(xmlout, " </Rate>\n");
203 fprintf(xmlout, " <Duration>\n");
205 fprintf(xmlout, " <InTimeUnits>%u</InTimeUnits>\n", movie->duration);
207 fprintf(xmlout, " <InSeconds>%12.3f</InSeconds>\n", (double)movie->duration/(double)movie->timescale); // Make this double later to get fractional seconds
208 fprintf(xmlout, " </Duration>\n");
210 movie->volume = movie->volume << 8;
212 fprintf(xmlout, " <Volume>\n");
214 fprintf(xmlout, " <!-- Audio volume stored as fixed-point binary 8.8 value. Decimal value is approximation. -->\n");
215 fprintf(xmlout, " <!-- Full, normal (default) value is 0x0100 (1.0) -->\n");
218 fprintf(xmlout, " <AsHex>0x%04x</AsHex>\n", movie->volume);
220 fprintf(xmlout, " <AsDecimal>%6.3f</AsDecimal>\n", (double)movie->volume/(double)0x0100);
221 fprintf(xmlout, " </Volume>\n");
224 fprintf(xmlout, " <!-- Current m2j_to_metadata implementation always shows bits to right of decimal as zeroed. -->\n");
225 movie->volume = movie->volume >> 8;
227 /* Transformation matrix for video */
228 fprintf(xmlout, " <TransformationMatrix>\n");
230 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");
231 fprintf(xmlout, " <!-- Maps decompressed point (p,q) to rendered point (ap + cq + x, bp + dq + y) -->\n");
232 fprintf(xmlout, " <!-- Stored as Fixed Point Hex: all are binary 16.16, except u,v,w are 2.30 -->\n");
233 fprintf(xmlout, " <!-- Unity = 0x00010000,0,0,0,0x00010000,0,0,0,0x40000000 -->\n");
235 fprintf(xmlout, " <TMa>0x%08x</TMa>\n", movie->trans_matrix[0]);
236 fprintf(xmlout, " <TMb>0x%08x</TMb>\n", movie->trans_matrix[1]);
237 fprintf(xmlout, " <TMu>0x%08x</TMu>\n", movie->trans_matrix[2]);
238 fprintf(xmlout, " <TMc>0x%08x</TMc>\n", movie->trans_matrix[3]);
239 fprintf(xmlout, " <TMd>0x%08x</TMd>\n", movie->trans_matrix[4]);
240 fprintf(xmlout, " <TMv>0x%08x</TMv>\n", movie->trans_matrix[5]);
241 fprintf(xmlout, " <TMx>0x%08x</TMx>\n", movie->trans_matrix[6]);
242 fprintf(xmlout, " <TMy>0x%08x</TMy>\n", movie->trans_matrix[7]);
243 fprintf(xmlout, " <TMw>0x%08x</TMw>\n", movie->trans_matrix[8]);
244 fprintf(xmlout, " </TransformationMatrix>\n");
245 fprintf(xmlout, " </MovieHeader>\n");
246 // Done elsewhere: one or more <Track "trak">
247 // to come: <MovieExtends mvek> // possibly not in Simple Profile
248 xml_write_moov_udta(xmlout, movie); /* NO OP so far */ /* <UserDataBox udta> contains <CopyrightBox cprt> */
250 fprintf(xmlout, " </MovieBox>\n");
251 // To come? <mdat> // This is the container for media data that can also be accessed through track structures,
252 // so is redundant, and simply not of interest as metadata
253 // <moof> // Allows incremental build up of movie. Probably not in Simple Profile
254 xml_write_free_and_skip(xmlout, movie); /* NO OP so far */ /* May be a place where user squirrels metadata */
255 xml_write_uuid(xmlout, movie); /* NO OP so far */ /* May be a place where user squirrels metadata */
257 fprintf(xmlout, " <Statistics>\n");
258 fprintf(xmlout, " <TracksFound>\n");
259 fprintf(xmlout, " <Video>%d</Video>\n", movie->num_vtk);
260 fprintf(xmlout, " <Audio>%d</Audio>\n", movie->num_stk);
261 fprintf(xmlout, " <Hint>%d</Hint>\n", movie->num_htk);
263 fprintf(xmlout, " <!-- Hint tracks for streaming video are not part of MJ2, but are a defined extension. -->\n");
264 /* See Part 3 Amend 2 Section 4.2 for relation of MJ2 to Part 12 Sections 7 and 10 hints */
265 fprintf(xmlout, " </TracksFound>\n");
266 fprintf(xmlout, " </Statistics>\n");
267 /* Idea for the future: It would be possible to add code to verify that the file values:
268 1) are legal and self-consistent
269 2) comply with particular JP2 and/or MJ2 profiles.
270 This could be reported here as additional XML elements */
276 void uint_to_chars(unsigned int value, char* buf)
278 /* buf is at least char[5] */
280 for (i = 3; i >= 0; i--)
282 buf[i] = (value & 0x000000ff);
283 value = (value >> 8);
285 buf[4] = '\0'; /* Precautionary */
290 /* WINDOWS SPECIFIC */
292 void UnixTimeToFileTime(time_t t, LPFILETIME pft)
294 /* Windows specific. From MS Q167296 */
295 /* 'time_t' represents seconds since midnight January 1, 1970 UTC (coordinated universal time). */
296 /* 64-bit FILETIME structure represents the number of 100-nanosecond intervals since January 1, 1601 UTC (coordinate universal time). */
297 LONGLONG ll; /* LONGLONG is a 64-bit value. */
298 ll = Int32x32To64(t, 10000000) + 116444736000000000;
299 pft->dwLowDateTime = (DWORD)ll;
300 /* pft->dwLowDateTime = (DWORD)(0x00000000ffffffff & ll); */
301 pft->dwHighDateTime = (DWORD)(ll >> 32);
303 // Once the UNIX time is converted to a FILETIME structure,
304 // other Win32 time formats can be easily obtained by using Win32 functions such
305 // as FileTimeToSystemTime() and FileTimeToDosDateTime().
309 void UnixTimeToSystemTime(time_t t, LPSYSTEMTIME pst)
311 /* Windows specific */
313 UnixTimeToFileTime(t, &ft);
314 FileTimeToLocalFileTime( &ft, &ft ); /* Adjust from UTC to local time zone */
315 FileTimeToSystemTime(&ft, pst);
320 void xml_time_out(FILE* xmlout, time_t t)
322 /* Windows specific */
324 char szLocalDate[255], szLocalTime[255];
325 UnixTimeToSystemTime( t, &st );
326 GetDateFormat( LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, szLocalDate, 255 );
327 GetTimeFormat( LOCALE_USER_DEFAULT, 0, &st, NULL, szLocalTime, 255 );
328 fprintf(xmlout, "%s %s", szLocalDate, szLocalTime );
331 /* END WINDOWS SPECIFIC */
335 void xml_write_moov_udta(FILE* xmlout, mj2_movie_t * movie) {
336 /* Compare with xml_write_udta */
338 /* NO-OP so far. Optional UserData 'udta' (zero or one in moov or each trak)
339 can contain multiple Copyright 'cprt' with different language codes */
340 /* There may be nested non-standard boxes within udta */
341 IMAGINE movie->udta, movie->copyright_count, movie->copyright_language[i] (array of 16bit ints), movie->copyright_notice[i] (array of buffers)
342 PROBABLY ALSO NEED movie->udta_len or special handler for non-standard boxes
347 return; /* Not present */
349 fprintf(xmlout, " <UserData BoxType=\"udta\">\n");
350 for(i = 0; i < movie->copyright_count; i++) {
351 fprintf(xmlout, " <Copyright BoxType=\"cprt\"> Instance=\"%d\">\n", i+1);
352 int16_to_3packedchars((short int)movie->copyright_languages[i], buf);
353 fprintf(xmlout, " <Language>%s</Language>\n", buf); /* 3 chars */
354 fprintf(xmlout, " <Notice>%s</Notice>\n",movie->copyright_notices[i]);
355 fprintf(xmlout, " </Copyright>\n", i+1);
357 /* TO DO: Non-standard boxes */
358 fprintf(xmlout, " </UserData>\n");
362 void xml_write_free_and_skip(FILE* xmlout, mj2_movie_t * movie) {
364 /* NO-OP so far. There can be zero or more instances of free and/or skip
365 at the top level of the file. This may be a place where the user squirrel's metadata.
366 Let's assume unstructured, and do a dump */
367 IMAGINE movie->free_and_skip, movie->free_and_skip_count, movie->free_and_skip_content[i] (array of buffers),
368 movie->free_and_skip_len[i] (array of ints), movie->is_skip[i] (array of BOOL)
371 if(movie->free_and_skip != 1)
372 return; /* Not present */
374 for(i = 0; i < movie->free_and_skip_count; i++) {
375 if(movie->is_skip[i])
376 fprintf(xmlout, " <Skip BoxType=\"skip\">\n");
378 fprintf(xmlout, " <Free BoxType=\"free\">\n");
380 xml_out_dump_hex_and_ascii(xmlout, movie->free_and_skip_contents[i], movie->free_and_skip_len[i]);
382 if(movie->is_skip[i])
383 fprintf(xmlout, " </Skip>\n");
385 fprintf(xmlout, " </Free>\n");
390 void xml_write_uuid(FILE* xmlout, mj2_movie_t * movie) {
391 /* Univeral Unique IDs of 16 bytes. */
393 /* NO-OP so far. There can be zero or more instances of private uuid boxes in a file.
394 This function supports the top level of the file, but uuid may be elsewhere [not yet supported].
395 This may be a place where the user squirrel's metadata. Let's assume unstructured, and do a dump */
396 IMAGINE movie->uuid, movie->uuid_count, movie->uuid_content[i] (array of buffers),
397 movie->uuid_len[i] (array of ints), movie->uuid_type[i] (array of 17-byte (16+null termination) buffers)
401 return; /* Not present */
403 for(i = 0; i < movie->uuid_count; i++) {
404 fprintf(xmlout, " <PrivateExtension BoxType=\"uuid\" UUID=\"%s\">\n", movie->uuid_type[i]);
405 // See Part III section 5.2.1, 6.1, 6.2
406 xml_out_dump_hex_and_ascii(xmlout, movie->uuid_contents[i], movie->uuid_len[i]);
407 fprintf(xmlout, " </PrivateExtension>\n");
414 void xml_write_trak(FILE* file, FILE* xmlout, mj2_tk_t *track, unsigned int tnum, unsigned int sampleframe)
416 fprintf(xmlout, " <Track BoxType=\"trak\" Instance=\"%d\">\n", tnum);
417 xml_write_tkhd(file, xmlout, track, tnum);
418 // TO DO: TrackReferenceContainer 'tref' just used in hint track
419 // TO DO: EditListContainer 'edts', contains EditList 'elst' with media-time, segment-duration, media-rate
420 xml_write_mdia(file, xmlout, track, tnum);
421 xml_write_udta(file, xmlout, track, tnum); // NO-OP so far. Optional UserData 'udta', can contain multiple Copyright 'cprt'
423 if(track->track_type==0) { /* Only do for visual track */
424 /* sampleframe is from user option -f. 1 = first frame */
425 /* sampleframe of 0 is a user requests: no jp2 header */
426 /* Treat out-of-bounds values in the same way */
427 if(sampleframe > 0 && sampleframe <= track->num_samples)
429 mj2_sample_t *sample;
432 snum = sampleframe-1;
433 // Someday maybe do a smart range scan... for (snum=0; snum < track->num_samples; snum++){
434 // fprintf(stdout,"Frame %d: ",snum+1);
435 sample = &track->sample[snum];
436 if(xml_out_frame(file, xmlout, sample, snum))
437 return; /* Not great error handling here */
440 fprintf(xmlout, " </Track>\n");
445 void xml_write_tkhd(FILE* file, FILE* xmlout, mj2_tk_t *track, unsigned int tnum)
447 fprintf(xmlout, " <TrackHeader BoxType=\"tkhd\">\n");
449 fprintf(xmlout, " <!-- Not shown here: CreationTime, ModificationTime, Duration. -->\n");
450 fprintf(xmlout, " <!-- These 3 fields are reported under MediaHeader below. When reading these 3, -->\n");
451 fprintf(xmlout, " <!-- m2j_to_metadata currently doesn't distinguish between TrackHeader and MediaHeader source. -->\n");
452 fprintf(xmlout, " <!-- If both found, value read from MediaHeader is used. -->\n");
454 fprintf(xmlout, " <TrackID>%u</TrackID>\n", track->track_ID);
455 if(track->track_type==0) /* For visual track */
457 fprintf(xmlout, " <TrackLayer>%d</TrackLayer>\n", track->layer);
459 fprintf(xmlout," <!-- front-to-back ordering of video tracks. 0 = normal, -1 is closer, etc. -->\n");
461 if(track->track_type!=0) /* volume irrelevant for visual track */
464 track->volume = track->volume << 8;
466 fprintf(xmlout, " <Volume>\n");
468 fprintf(xmlout," <!-- Track audio volume stored as fixed-point binary 8.8 value. Decimal value is approximation. -->\n");
469 fprintf(xmlout," <!-- Full, normal (default) value is 0x0100 (1.0) -->\n");
472 fprintf(xmlout," <AsHex>0x%04x</AsHex>\n", track->volume);
474 fprintf(xmlout," <AsDecimal>%6.3f</AsDecimal>\n", (double)track->volume/(double)0x0100);
475 fprintf(xmlout, " </Volume>\n");
478 fprintf(xmlout, " <!-- Current m2j_to_metadata implementation always shows bits to right of decimal as zeroed. -->\n");
479 track->volume = track->volume >> 8;
482 if(track->track_type==0)
484 /* Transformation matrix for video */
485 fprintf(xmlout, " <TransformationMatrix>\n");
487 fprintf(xmlout," <!-- Comments about matrix in MovieHeader apply here as well. -->\n");
488 fprintf(xmlout," <!-- This matrix is applied before MovieHeader one. -->\n");
490 fprintf(xmlout, " <TMa>0x%08x</TMa>\n", track->trans_matrix[0]);
491 fprintf(xmlout, " <TMb>0x%08x</TMb>\n", track->trans_matrix[1]);
492 fprintf(xmlout, " <TMu>0x%08x</TMu>\n", track->trans_matrix[2]);
493 fprintf(xmlout, " <TMc>0x%08x</TMc>\n", track->trans_matrix[3]);
494 fprintf(xmlout, " <TMd>0x%08x</TMd>\n", track->trans_matrix[4]);
495 fprintf(xmlout, " <TMv>0x%08x</TMv>\n", track->trans_matrix[5]);
496 fprintf(xmlout, " <TMx>0x%08x</TMx>\n", track->trans_matrix[6]);
497 fprintf(xmlout, " <TMy>0x%08x</TMy>\n", track->trans_matrix[7]);
498 fprintf(xmlout, " <TMw>0x%08x</TMw>\n", track->trans_matrix[8]);
499 fprintf(xmlout, " </TransformationMatrix>\n");
502 track->w = track->w << 16;
503 track->h = track->h << 16;
506 fprintf(xmlout, " <!-- Width and Height in pixels are for the presentation; frames will be scaled to this. -->\n");
507 fprintf(xmlout, " <!-- Both stored as fixed-point binary 16.16 values. Decimal values are approximations. -->\n");
509 fprintf(xmlout, " <Width>\n");
511 fprintf(xmlout, " <AsHex>0x%08x</AsHex>\n", track->w);
513 fprintf(xmlout, " <AsDecimal>%12.6f</AsDecimal>\n", (double)track->w/(double)0x00010000); /* Rate to play presentation (default = 0x00010000) */
514 fprintf(xmlout, " </Width>\n");
515 fprintf(xmlout, " <Height>\n");
517 fprintf(xmlout, " <AsHex>0x%08x</AsHex>\n", track->h);
519 fprintf(xmlout, " <AsDecimal>%12.6f</AsDecimal>\n", (double)track->h/(double)0x00010000); /* Rate to play presentation (default = 0x00010000) */
520 fprintf(xmlout, " </Height>\n");
523 fprintf(xmlout, " <!-- Current m2j_to_metadata implementation always shows bits to right of decimal as zeroed. -->\n");
524 fprintf(xmlout, " <!-- Also, width and height values shown here will actually be those read from track's <VisualSampleEntry> if given. -->\n");
526 track->w = track->w >> 16;
527 track->h = track->h >> 16;
529 fprintf(xmlout, " </TrackHeader>\n");
534 void xml_write_udta(FILE* file, FILE* xmlout, mj2_tk_t *track, unsigned int tnum) {
535 /* NO-OP so far. Optional UserData 'udta' (zero or one in moov or each trak)
536 can contain multiple Copyright 'cprt' with different language codes */
537 /* There may be nested non-standard boxes within udta */
539 IMAGINE track->udta, track->copyright_count, track->copyright_language[i] (array of 16bit ints), track->copyright_notice[i] (array of buffers)
540 PROBABLY ALSO NEED track->udta_len or special handler for non-standard boxes
545 return; /* Not present */
547 fprintf(xmlout, " <UserData BoxType=\"udta\">\n");
548 for(i = 0; i < track->copyright_count; i++) {
549 fprintf(xmlout, " <Copyright BoxType=\"cprt\"> Instance=\"%d\">\n", i+1);
550 int16_to_3packedchars((short int)track->copyright_languages[i], buf);
551 fprintf(xmlout, " <Language>%s</Language>\n", buf); /* 3 chars */
552 fprintf(xmlout, " <Notice>%s</Notice>\n",track->copyright_notices[i]);
553 fprintf(xmlout, " </Copyright>\n", i+1);
555 /* TO DO: Non-standard boxes */
556 fprintf(xmlout, " </UserData>\n");
562 void xml_write_mdia(FILE* file, FILE* xmlout, mj2_tk_t *track, unsigned int tnum)
568 fprintf(xmlout, " <Media BoxType=\"mdia\">\n");
569 fprintf(xmlout, " <MediaHeader BoxType=\"mdhd\">\n");
570 fprintf(xmlout, " <CreationTime>\n");
572 fprintf(xmlout, " <InSeconds>%u</InSeconds>\n", track->creation_time);
574 fprintf(xmlout, " <!-- Seconds since start of Jan. 1, 1904 UTC (Greenwich) -->\n");
575 /* 2082844800 = seconds between 1/1/04 and 1/1/70 */
576 /* There's still a time zone offset problem not solved... but spec is ambigous as to whether stored time
577 should be local or UTC */
579 fprintf(xmlout, " <AsLocalTime>");
580 xml_time_out(xmlout, track->creation_time - 2082844800);
581 fprintf(xmlout,"</AsLocalTime>\n");
583 fprintf(xmlout, " </CreationTime>\n");
584 fprintf(xmlout, " <ModificationTime>\n");
586 fprintf(xmlout, " <InSeconds>%u</InSeconds>\n", track->modification_time);
588 fprintf(xmlout, " <AsLocalTime>");
589 xml_time_out(xmlout, track->modification_time - 2082844800);
590 fprintf(xmlout,"</AsLocalTime>\n");
592 fprintf(xmlout, " </ModificationTime>\n");
593 fprintf(xmlout, " <Timescale>%d</Timescale>\n", track->timescale);
595 fprintf(xmlout, " <!-- Timescale defines time units in one second -->\n");
596 fprintf(xmlout, " <Duration>\n");
598 fprintf(xmlout, " <InTimeUnits>%u</InTimeUnits>\n", track->duration);
600 fprintf(xmlout, " <InSeconds>%12.3f</InSeconds>\n", (double)track->duration/(double)track->timescale); // Make this double later to get fractional seconds
601 fprintf(xmlout, " </Duration>\n");
602 int16_to_3packedchars((short int)track->language, buf);
603 fprintf(xmlout, " <Language>%s</Language>\n", buf); /* 3 chars */
604 fprintf(xmlout, " </MediaHeader>\n");
605 fprintf(xmlout, " <HandlerReference BoxType=\"hdlr\">\n");
606 switch(track->track_type)
609 fprintf(xmlout, " <HandlerType Code=\"vide\">video media track</HandlerType>\n"); break;
611 fprintf(xmlout, " <HandlerType Code=\"soun\">Sound</HandlerType>\n"); break;
613 fprintf(xmlout, " <HandlerType Code=\"hint\">Hint</HandlerType>\n"); break;
616 fprintf(xmlout, " <!-- String value shown is not actually read from file. -->\n");
617 fprintf(xmlout, " <!-- Shown value is one used for our encode. -->\n");
619 fprintf(xmlout, " </HandlerReference>\n");
620 fprintf(xmlout, " <MediaInfoContainer BoxType=\"minf\">\n");
621 switch(track->track_type)
624 fprintf(xmlout, " <VideoMediaHeader BoxType=\"vmhd\">\n");
625 fprintf(xmlout, " <GraphicsMode>0x%02x</GraphicsMode>\n", track->graphicsmode);
627 fprintf(xmlout," <!-- Enumerated values of graphics mode: -->\n");
628 fprintf(xmlout," <!-- 0x00 = copy (over existing image); -->\n");
629 fprintf(xmlout," <!-- 0x24 = transparent; 'blue-screen' this image using opcolor; -->\n");
630 fprintf(xmlout," <!-- 0x100 = alpha; alpha-blend this image -->\n");
631 /* fprintf(xmlout," <!-- 0x101 = whitealpha; alpha-blend this image, which has been blended with white; -->\n"); This was evidently dropped upon amendment */
632 fprintf(xmlout," <!-- 0x102 = pre-multiplied black alpha; image has been already been alpha-blended with black. -->\n");
633 fprintf(xmlout," <!-- 0x110 = component alpha; blend alpha channel(s) and color channels individually. -->\n");
635 fprintf(xmlout, " <Opcolor>\n");
636 fprintf(xmlout, " <Red>0x%02x</Red>\n", track->opcolor[0]);
637 fprintf(xmlout, " <Green>0x%02x</Green>\n",track->opcolor[1]);
638 fprintf(xmlout, " <Blue>0x%02x</Blue>\n",track->opcolor[2]);
639 fprintf(xmlout, " </Opcolor>\n");
640 fprintf(xmlout, " </VideoMediaHeader>\n");
643 fprintf(xmlout, " <SoundMediaHeader BoxType=\"smhd\">\n");
645 track->balance = track->balance << 8;
647 fprintf(xmlout, " <Balance>\n");
649 fprintf(xmlout," <!-- Track audio balance fixes mono track in stereo space. -->\n");
650 fprintf(xmlout," <!-- Stored as fixed-point binary 8.8 value. Decimal value is approximation. -->\n");
651 fprintf(xmlout," <!-- 0.0 = center, -1.0 = full left, 1.0 = full right -->\n");
654 fprintf(xmlout," <AsHex>0x%04x</AsHex>\n", track->balance);
656 fprintf(xmlout," <AsDecimal>%6.3f</AsDecimal>\n", (double)track->balance/(double)0x0100);
657 fprintf(xmlout, " </Balance>\n");
660 fprintf(xmlout," <!-- Current m2j_to_metadata implementation always shows bits to right of decimal as zeroed. -->\n");
661 track->balance = track->balance >> 8;
663 fprintf(xmlout, " </SoundMediaHeader>\n");
666 fprintf(xmlout, " <HintMediaHeader BoxType=\"hmhd\">\n");
667 fprintf(xmlout, " <MaxPDU_Size>%d</MaxPDU_Size>\n", track->maxPDUsize);
669 fprintf(xmlout," <!-- Size in bytes of largest PDU in this hint stream. -->\n");
670 fprintf(xmlout, " <AvgPDU_Size>%d</AvgPDU_Size>\n", track->avgPDUsize);
672 fprintf(xmlout," <!-- Average size in bytes of a PDU over the entire presentation. -->\n");
673 fprintf(xmlout, " <MaxBitRate>%d</MaxBitRate>\n", track->maxbitrate);
675 fprintf(xmlout," <!-- Maximum rate in bits per second over any window of 1 second. -->\n");
676 fprintf(xmlout, " <AvgBitRate>%d</AvgBitRate>\n", track->avgbitrate);
678 fprintf(xmlout," <!-- Averate rate in bits per second over the entire presentation. -->\n");
679 fprintf(xmlout, " <SlidingAvgBit>%d</SlidingAvgBitRate>\n", track->slidingavgbitrate);
681 fprintf(xmlout," <!-- Maximum rate in bits per second over any window of one minute. -->\n");
682 fprintf(xmlout, " </HintMediaHeader>\n");
685 fprintf(xmlout, " <DataInfo BoxType=\"dinf\">\n");
686 fprintf(xmlout, " <DataReference BoxType=\"dref\" URL_Count=\"%d\" URN_Count=\"%d\">\n", track->num_url, track->num_urn); // table w. flags, URLs, URNs
687 // Data structure does not distinguish between single URL, single URN, or DREF table or URLs & URNs.
688 // We could infer those, but for now just present everything as a DREF table.
690 fprintf(xmlout, " <!-- No entries here mean that file is self-contained, as required by Simple Profile. -->\n");
691 for(k = 0; k < track->num_url; k++) {
692 fprintf(xmlout, " <DataEntryUrlBox BoxType=\"url[space]\">\n"); // table w. flags, URLs, URNs
694 fprintf(xmlout," <!-- Only the first 16 bytes of URL location are recorded in mj2_to_metadata data structure. -->\n");
695 for(i = 0; i < 4; i++) {
696 uint_to_chars(track->url[track->num_url].location[i], buf);
697 fprintf(xmlout, " <Location>%s</Location>\n");
699 fprintf(xmlout, " </DataEntryUrlBox>\n"); // table w. flags, URLs, URNs
701 for(k = 0; k < track->num_urn; k++) {
702 fprintf(xmlout," <DataEntryUrnBox BoxType=\"urn[space]\">\n"); // table w. flags, URLs, URNs
703 // Only the first 16 bytes are recorded in the data structure currently.
705 fprintf(xmlout," <!-- Only the first 16 bytes each of URN name and optional location are recorded in mj2_to_metadata data structure. -->\n");
706 fprintf(xmlout, " <Name>");
707 for(i = 0; i < 4; i++) {
708 uint_to_chars(track->urn[track->num_urn].name[i], buf);
709 fprintf(xmlout,"%s", buf);
711 fprintf(xmlout, "</Name>\n");
712 fprintf(xmlout, " <Location>");
713 for(i = 0; i < 4; i++) {
714 uint_to_chars(track->urn[track->num_urn].location[i], buf);
715 fprintf(xmlout,"%s");
717 fprintf(xmlout, "</Location>\n");
718 fprintf(xmlout, " </DataEntryUrnBox>\n");
720 fprintf(xmlout, " </DataReference>\n");
721 fprintf(xmlout, " </DataInfo>\n");
723 xml_write_stbl(file, xmlout, track, tnum); /* SampleTable */
725 fprintf(xmlout, " </MediaInfoContainer>\n");
726 fprintf(xmlout, " </Media>\n");
731 void xml_write_stbl(FILE* file, FILE* xmlout, mj2_tk_t *track, unsigned int tnum)
733 char buf[5], buf33[33];
737 fprintf(xmlout, " <SampleTable BoxType=\"stbl\">\n");
739 fprintf(xmlout, " <!-- What follows are specific instances of generic SampleDescription BoxType=\"stsd\" -->\n");
740 switch(track->track_type)
743 // There could be multiple instances of this, but "entry_count" is just a local at read-time.
744 // And it's used wrong, too, as count of just visual type, when it's really all 3 types.
745 // This is referred to as "smj2" within mj2.c
746 fprintf(xmlout, " <VisualSampleEntry BoxType=\"mjp2\">\n");
748 fprintf(xmlout, " <!-- If multiple instances of this box, only first is shown here. -->\n");
749 fprintf(xmlout, " <!-- Width and Height are in pixels. Unlike the Track Header, there is no fractional part. -->\n");
750 fprintf(xmlout, " <!-- In mj2_to_metadata implementation, the values are not represented separately from Track Header's values. -->\n");
752 /* No shifting required. If CURRENTSTRUCT gets changed, then may need to revisit treatment of these */
753 fprintf(xmlout, " <WidthAsInteger>%d</WidthAsInteger>\n", track->w);
754 fprintf(xmlout, " <HeightAsInteger>%d</HeightAsInteger>\n", track->h);
755 // Horizresolution and vertresolution don't require shifting, already stored right in CURRENTSTRUCT
757 fprintf(xmlout, " <!-- Resolutions are in pixels per inch, for the highest-resolution component (typically luminance). -->\n");
758 fprintf(xmlout, " <!-- Both stored as fixed-point binary 16.16 values. Decimal values are approximations. -->\n");
759 fprintf(xmlout, " <!-- Typical value for both resolutions is 0x00480000 (72.0) -->\n");
761 fprintf(xmlout, " <HorizontalRes>\n");
763 fprintf(xmlout, " <AsHex>0x%08x</AsHex>\n", track->horizresolution);
765 fprintf(xmlout, " <AsDecimal>%12.6f</AsDecimal>\n", (double)track->horizresolution/(double)0x00010000); /* Rate to play presentation (default = 0x00010000) */
766 fprintf(xmlout, " </HorizontalRes>\n");
767 fprintf(xmlout, " <VerticalRes>\n");
769 fprintf(xmlout, " <AsHex>0x%08x</AsHex>\n", track->vertresolution);
771 fprintf(xmlout, " <AsDecimal>%12.6f</AsDecimal>\n", (double)track->vertresolution/(double)0x00010000); /* Rate to play presentation (default = 0x00010000) */
772 fprintf(xmlout, " </VerticalRes>\n");
775 for(i = 0; i < 8; i++) {
776 uint_to_chars((unsigned int)track->compressorname[i], buf);
777 strcat(buf33, buf); /* This loads up (4 * 8) + 1 chars, but trailing ones are usually junk */
779 len = (int)buf33[0]; /* First byte has string length in bytes. There may be garbage beyond it. */
780 buf33[len+1] = '\0'; /* Suppress it */
781 fprintf(xmlout, " <CompressorName>%s</CompressorName>\n", buf33+1); /* Start beyond first byte */
783 fprintf(xmlout, " <!-- Compressor name for debugging. Standard restricts max length to 31 bytes. -->\n");
784 fprintf(xmlout, " <!-- Usually blank or \"Motion JPEG2000\" -->\n");
786 fprintf(xmlout, " <Depth>0x%02x</Depth>\n",track->depth);
788 fprintf(xmlout, " <!-- Depth is: -->\n");
789 fprintf(xmlout, " <!-- 0x20: alpha channels present (color or grayscale) -->\n");
790 fprintf(xmlout, " <!-- 0x28: grayscale without alpha -->\n");
791 fprintf(xmlout, " <!-- 0x18: color without alpha -->\n");
794 xml_out_frame_jp2h(xmlout, &(track->jp2_struct)); /* JP2 Header */
796 /* Following subboxes are optional */
797 fprintf(xmlout, " <FieldCoding BoxType=\"fiel\">\n");
798 fprintf(xmlout, " <FieldCount>%d</FieldCount>\n", (unsigned int)track->fieldcount); /* uchar as 1 byte uint */
800 fprintf(xmlout, " <!-- Must be either 1 or 2 -->\n");
801 fprintf(xmlout, " <FieldOrder>%d</FieldOrder>\n", (unsigned int)track->fieldorder); /* uchar as 1 byte uint */
803 fprintf(xmlout, " <!-- When FieldCount=2, FieldOrder means: -->\n");
804 fprintf(xmlout, " <!-- 0: Field coding unknown -->\n");
805 fprintf(xmlout, " <!-- 1: Field with topmost line is stored first in sample; fields are in temporal order -->\n");
806 fprintf(xmlout, " <!-- 6: Field with topmost line is stored second in sample; fields are in temporal order -->\n");
807 fprintf(xmlout, " <!-- Defaults: FieldCount=1, FieldOrder=0 if FieldCoding box not present -->\n");
808 fprintf(xmlout, " <!-- Current implementation doesn't retain whether box was actually present. -->\n");
810 fprintf(xmlout, " </FieldCoding>\n");
812 fprintf(xmlout, " <MJP2_Profile BoxType=\"jp2p\" Count=\"%d\">\n",track->num_br);
813 for (i = 0; i < track->num_br; i++) /* read routine stored in reverse order, so let's undo damage */
815 uint_to_chars(track->br[i], buf);
816 fprintf(xmlout, " <CompatibleBrand>%s</CompatibleBrand>\n", buf); /*4 characters, each CLi */
818 fprintf(xmlout, " </MJP2_Profile>\n");
820 fprintf(xmlout, " <MJP2_Prefix BoxType=\"jp2x\" Count=\"%d\">\n",track->num_jp2x);
821 for (i = 0; i < track->num_jp2x; i++)
822 { // We'll probably need better formatting than this
823 fprintf(xmlout, " <Data>0x%02x</Data>\n", track->jp2xdata[i]); /* Each entry is single byte */
825 fprintf(xmlout, " </MJP2_Prefix>\n");
827 fprintf(xmlout, " <MJP2_SubSampling BoxType=\"jsub\">\n"); /* These values are all 1 byte */
829 fprintf(xmlout, " <!-- Typical subsample value is 2 for 4:2:0 -->\n");
830 fprintf(xmlout, " <HorizontalSub>%d</HorizontalSub>\n", track->hsub);
831 fprintf(xmlout, " <VerticalSub>%d</VerticalSub>\n", track->vsub);
832 fprintf(xmlout, " <HorizontalOffset>%d</HorizontalOffset>\n", track->hoff);
833 fprintf(xmlout, " <VerticalOffset>%d</VerticalOffset>\n", track->voff);
835 fprintf(xmlout, " <!-- Typical {horizontal, vertical} chroma offset values: -->\n");
836 fprintf(xmlout, " <!-- 4:2:2 format (CCIR601, H.262, MPEG2, MPEG4, recom. Exif): {0, 0} -->\n");
837 fprintf(xmlout, " <!-- 4:2:2 format (JFIF): {1, 0} -->\n");
838 fprintf(xmlout, " <!-- 4:2:0 format (H.262, MPEG2, MPEG4): {0, 1} -->\n");
839 fprintf(xmlout, " <!-- 4:2:0 format (MPEG1, H.261, JFIF, recom. Exif): {1, 1} -->\n");
841 fprintf(xmlout, " </MJP2_SubSampling>\n"); /* These values are all 1 byte */
843 fprintf(xmlout, " <MJP2_OriginalFormat BoxType=\"orfo\">\n"); /* Part III Appx. 2 */
844 fprintf(xmlout, " <OriginalFieldCount>%u</OriginalFieldCount>\n", (unsigned int)track->or_fieldcount); /* uchar as 1-byte uint */
846 fprintf(xmlout, " <!-- In original material before encoding. Must be either 1 or 2 -->\n");
847 fprintf(xmlout, " <OriginalFieldOrder>%u</OriginalFieldOrder>\n", (unsigned int)track->or_fieldorder); /* uchar as 1-byte uint */
849 fprintf(xmlout, " <!-- When FieldCount=2, FieldOrder means: -->\n");
850 fprintf(xmlout, " <!-- 0: Field coding unknown -->\n");
851 fprintf(xmlout, " <!-- 11: Topmost line came from the earlier field; -->\n");
852 fprintf(xmlout, " <!-- 16: Topmost line came form the later field. -->\n");
853 fprintf(xmlout, " <!-- Defaults: FieldCount=1, FieldOrder=0 if FieldCoding box not present -->\n");
854 fprintf(xmlout, " <!-- Current implementation doesn't retain whether box was actually present. -->\n");
856 fprintf(xmlout, " </MJP2_OriginalFormat>\n");
857 fprintf(xmlout, " </VisualSampleEntry>\n");
861 fprintf(xmlout, " <!-- mj2_to_metadata's data structure doesn't record this currently. -->\n"); break;
863 fprintf(xmlout, " <TimeToSample BoxType=\"stts\">\n");
864 fprintf(xmlout, " <SampleStatistics>\n");
865 fprintf(xmlout, " <TotalSamples>%d</TotalSamples>\n", track->num_samples);
867 fprintf(xmlout, " <!-- For video, gives the total frames in the track, by summing all entries in the Sample Table -->\n");
868 fprintf(xmlout, " </SampleStatistics>\n");
869 fprintf(xmlout, " <SampleEntries EntryCount=\"%d\">\n", track->num_tts);
870 for (i = 0; i < track->num_tts; i++) {
871 fprintf(xmlout, " <Table Entry=\"%u\" SampleCount=\"%d\" SampleDelta=\"%u\" />\n",
872 i+1, track->tts[i].sample_count, track->tts[i].sample_delta);
874 fprintf(xmlout, " </SampleEntries>\n");
875 fprintf(xmlout, " </TimeToSample>\n");
877 fprintf(xmlout, " <SampleToChunk BoxType=\"stsc\" Count=\"%d\">\n", track->num_samplestochunk);
878 for (i = 0; i < track->num_samplestochunk; i++) {
879 fprintf(xmlout, " <FirstChunk>%u</FirstChunk>\n",track->sampletochunk[i].first_chunk); /* 4 bytes */
880 fprintf(xmlout, " <SamplesPerChunk>%u</SamplesPerChunk>\n",track->sampletochunk[i].samples_per_chunk); /* 4 bytes */
881 fprintf(xmlout, " <SampleDescrIndex>%u</SampleDescrIndex>\n",track->sampletochunk[i].sample_descr_idx); /* 4 bytes */
883 fprintf(xmlout, " </SampleToChunk>\n");
884 // After reading this info in, track->num_chunks is calculated and a decompressed table established internally.
886 fprintf(xmlout, " <SampleSize BoxType=\"stsz\">\n");
887 if(track->same_sample_size) {
888 // all values in track->sample[i].sample_size are equal. Grab the first one.
889 fprintf(xmlout, " <Sample_Size>%u</Sample_Size>\n", track->sample[0].sample_size);
891 fprintf(xmlout, " <!-- Non-zero value means all samples have that size. -->\n");
892 fprintf(xmlout, " <!-- So <Sample_Count> (aka Entry_Count in std.) has no meaning, is suppressed from this output, and no table follows. -->\n");
895 fprintf(xmlout, " <Sample_Size>0</Sample_Size>\n");
898 fprintf(xmlout," <!-- Zero value means samples have different sizes, given in table next of length Sample_Count (aka Entry_Count in std). -->\n");
900 fprintf(xmlout," <!-- Zero value means samples have different sizes, given in table (not shown) of length Sample_Count (aka Entry_Count in std). -->\n");
901 fprintf(xmlout, " <Sample_Count>%u</Sample_Count>\n", track->num_samples);
903 for (i = 0; i < (int)track->num_samples; i++) {
904 fprintf(xmlout, " <EntrySize Num=\"%u\">%u</EntrySize>\n", i+1, track->sample[i].sample_size);
907 fprintf(xmlout, " </SampleSize>\n");
909 fprintf(xmlout, " <ChunkOffset BoxType=\"stco\">\n");
910 // Structure not yet - Variant ChunkLargeOffset 'co64'
911 fprintf(xmlout, " <EntryCount>%u</EntryCount>\n", track->num_chunks);
913 fprintf(xmlout, " <!-- For this implementation, EntryCount shown is one calculated during file read of <SampleToChunk> data. -->\n");
914 fprintf(xmlout, " <!-- Implementation will report failure during file read of <ChunkOffset> data if read entry-count disagrees. -->\n");
917 for (i = 0; i < (int)track->num_chunks; i++)
918 fprintf(xmlout, " <Chunk_Offset Num=\"%d\">%u</Chunk_Offset>\n", i+1, track->chunk[i].offset);
919 fprintf(xmlout, " </ChunkOffset>\n");
921 fprintf(xmlout, " </SampleTable>\n");
926 int xml_out_frame(FILE* file, FILE* xmlout, mj2_sample_t *sample, unsigned int snum)
932 unsigned char* frame_codestream;
933 /* char xmloutname[50]; */
935 frame_codestream = (unsigned char*) malloc (sample->sample_size-8); /* Skipping JP2C marker */
936 if(frame_codestream == NULL)
939 fseek(file,sample->offset+8,SEEK_SET);
940 fread(frame_codestream,sample->sample_size-8,1, file); /* Assuming that jp and ftyp markers size do */
941 /* Decode J2K to image: */
942 if (!j2k_decode(frame_codestream, sample->sample_size-8, &img, &cp)) {
943 free(frame_codestream);
944 #ifndef NO_PACKETS_DECODING
945 for (i=0; i<img.numcomps; i++)
946 free(img.comps[i].data);
952 numcomps = img.numcomps;
953 /* Alignments: " < To help maintain xml pretty-printing */
954 fprintf(xmlout, " <JP2_Frame Num=\"%d\">\n", snum+1);
955 fprintf(xmlout, " <MainHeader>\n");
956 /* There can be multiple codestreams; a particular image is entirely within a single codestream */
957 /* TO DO: A frame can be represented by two I-guess-contigious codestreams if its interleaved. */
958 fprintf(xmlout, " <StartOfCodestream Marker=\"SOC\" />\n");
959 /* "cp" stands for "coding parameter"; "tcp" is tile coding parameters, "tccp" is tile-component coding parameters */
960 xml_out_frame_siz(xmlout, &img, &cp); /* reqd in main */
961 xml_out_frame_cod(xmlout, &j2k_default_tcp); /* reqd in main */
962 xml_out_frame_coc(xmlout, &j2k_default_tcp, numcomps); /* opt in main, at most 1 per component */
963 xml_out_frame_qcd(xmlout, &j2k_default_tcp); /* reqd in main */
964 xml_out_frame_qcc(xmlout, &j2k_default_tcp, numcomps); /* opt in main, at most 1 per component */
965 xml_out_frame_rgn(xmlout, &j2k_default_tcp, numcomps); /* opt, at most 1 per component */
966 xml_out_frame_poc(xmlout, &j2k_default_tcp); /* opt (but reqd in main or tile for any progression order changes) */
967 /* Next four get j2k_default_tcp passed globally: */
968 #ifdef SUPPRESS_FOR_NOW
969 xml_out_frame_ppm(xmlout, &cp); /* opt (but either PPM or PPT [distributed in tile headers] or codestream packet header reqd) */
971 xml_out_frame_tlm(xmlout); /* NO-OP. TLM NOT SAVED IN DATA STRUCTURE */ /* opt */
972 xml_out_frame_plm(xmlout); /* NO-OP. PLM NOT SAVED IN DATA STRUCTURE */ /* opt in main; can be used in conjunction with PLT */
973 xml_out_frame_crg(xmlout); /* NO-OP. CRG NOT SAVED IN DATA STRUCTURE */ /* opt in main; */
974 xml_out_frame_com(xmlout, &j2k_default_tcp); /* NO-OP. COM NOT SAVED IN DATA STRUCTURE */ /* opt in main; */
976 fprintf(xmlout, " </MainHeader>\n");
978 /* TO DO: all the tile headers (sigh) */
979 fprintf(xmlout, " <TilePartHeaders Count=\"%d\">\n", cp.tileno_size); /* size of the vector tileno */
980 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 */
981 // Standard seems to use zero-based # for tile-part.
982 fprintf(xmlout, " <TilePartHeader Num=\"%d\" ID=\"%d\">\n", i, cp.tileno[i]); /* ID number of the tiles present in the codestream */
983 fprintf(xmlout, " <StartOfTilePart Marker=\"SOT\" />\n");
984 /* All markers in tile-part headers (between SOT and SOD) are optional, unless structure requires. */
986 xml_out_frame_cod(xmlout, &(cp.tcps[i])); /* No more than 1 per tile */
987 xml_out_frame_coc(xmlout, &(cp.tcps[i]), numcomps); /* No more than 1 per component */
988 xml_out_frame_qcd(xmlout, &(cp.tcps[i])); /* No more than 1 per tile */
989 xml_out_frame_qcc(xmlout, &(cp.tcps[i]), numcomps); /* No more than 1 per component */
990 xml_out_frame_rgn(xmlout, &(cp.tcps[i]), numcomps); /* No more than 1 per component */
992 xml_out_frame_poc(xmlout, &(cp.tcps[i])); /* Reqd only if any progression order changes different from main POC */
993 #ifdef SUPPRESS_FOR_NOW
994 xml_out_frame_ppt(xmlout, &(cp.tcps[i])); /* Either PPT [distributed in tile headers] or PPM or codestream packet header reqd. */
996 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 */
997 xml_out_frame_com(xmlout, &(cp.tcps[i])); /* NO-OP. COM NOT SAVED IN DATA STRUCTURE */
998 /* j2k_tcp_t * cp.tcps; "tile coding parameters" */
999 /* Maybe not: fprintf(xmlout, " <>%d</>, cp.matrice[i]; */ /* Fixed layer */
1000 fprintf(xmlout, " <StartOfData Marker=\"SOD\" />\n");
1002 fprintf(xmlout, " <!-- Tile-part bitstream, not shown, follows tile-part header and SOD marker. -->\n");
1003 fprintf(xmlout, " </TilePartHeader>\n");
1005 fprintf(xmlout, " </TilePartHeaders>\n"); /* size of the vector tileno */
1008 IMAGINE the cp object has data to support the following... but we could use an new different data structure instead
1009 /* I'm unclear if the span of the original fread(frame_codestream...) included the following items if they're trailing. */
1010 /* ALSO TO DO, BUT DATA STRUCTURE DOESN'T HANDLE YET: boxes (anywhere in file except before the Filetype box): */
1011 xml_out_frame_jp2i(xmlout, &cp); /* IntellectualProperty 'jp2i' (no restrictions on location) */
1012 xml_out_frame_xml(xmlout, &cp); /* XML 'xml\040' (0x786d6c20). Can appear multiply */
1013 xml_out_frame_uuid(xmlout, &cp); /* UUID 'uuid' (top level only) */
1014 xml_out_frame_uinf(xmlout, &cp); /* UUIDInfo 'uinf', includes UUIDList 'ulst' and URL 'url\40' */
1017 fprintf(xmlout, " </JP2_Frame>\n");
1019 /* Extra commentary: */
1021 fprintf(xmlout, " <!-- Given the number and size of components, mj2_to_frame would try to convert this -->\n");
1022 if (((img.numcomps == 3) && (img.comps[0].dx == img.comps[1].dx / 2)
1023 && (img.comps[0].dx == img.comps[2].dx / 2 ) && (img.comps[0].dx == 1))
1024 || (img.numcomps == 1)) {
1025 fprintf(xmlout, " <!-- file to a YUV movie in the normal manner. -->\n");
1027 else if ((img.numcomps == 3) &&
1028 (img.comps[0].dx == 1) && (img.comps[1].dx == 1)&&
1029 (img.comps[2].dx == 1)) {// If YUV 4:4:4 input --> to bmp
1030 fprintf(xmlout, " <!-- YUV 4:4:4 file to a series of .bmp files. -->\n");
1033 fprintf(xmlout, " <!-- file whose image component dimension are unknown, to a series of .j2k files. -->\n");
1037 #ifndef NO_PACKETS_DECODING
1038 for (i=0; i<img.numcomps; i++)
1039 free(img.comps[i].data);
1042 free(frame_codestream);
1049 void int16_to_3packedchars(short int value, char* buf)
1051 /* This is to retrieve the 3-letter ASCII language code */
1052 /* Each char is packed into 5 bits, as difference from 0x60 */
1054 for (i = 2; i >= 0; i--)
1056 buf[i] = (value & 0x001f) + 0x60;
1057 value = (value >>5);
1064 void xml_out_frame_siz(FILE* xmlout, j2k_image_t *img, j2k_cp_t *cp)
1069 fprintf(xmlout, " <ImageAndFileSize Marker=\"SIZ\">\n");
1070 // This is similar to j2k.c's j2k_dump_image.
1071 // Not of interest: Lsiz, Rsiz
1072 fprintf(xmlout, " <Xsiz>%d</Xsiz>\n", img->x1);
1073 fprintf(xmlout, " <Ysiz>%d</Ysiz>\n", img->y1);
1075 fprintf(xmlout, " <!-- Xsiz, Ysiz is the size of the reference grid. -->\n");
1076 fprintf(xmlout, " <XOsiz>%d</XOsiz>\n", img->x0);
1077 fprintf(xmlout, " <YOsiz>%d</YOsiz>\n", img->y0);
1079 fprintf(xmlout, " <!-- XOsiz, YOsiz are offsets from grid origin to image origin. -->\n");
1080 fprintf(xmlout, " <XTsiz>%d</XTsiz>\n", cp->tdx);
1081 fprintf(xmlout, " <YTsiz>%d</YTsiz>\n", cp->tdy);
1083 fprintf(xmlout, " <!-- XTsiz, YTsiz is the size of one tile with respect to the grid. -->\n");
1084 fprintf(xmlout, " <XTOsiz>%d</XTOsiz>\n", cp->tx0);
1085 fprintf(xmlout, " <YTOsiz>%d</YTOsiz>\n", cp->ty0);
1087 fprintf(xmlout, " <!-- XTOsiz, YTOsiz are offsets from grid origin to first tile origin. -->\n");
1088 fprintf(xmlout, " <Csiz>%d</Csiz>\n", img->numcomps);
1090 fprintf(xmlout, " <!-- Csiz is the number of components in the image. -->\n");
1091 fprintf(xmlout, " <!-- For image components next: -->\n");
1092 fprintf(xmlout, " <!-- XRsiz, YRsiz denote pixel-sample-spacing on the grid, per Part I Annex B. -->\n");
1093 //fprintf(xmlout," <!-- XO, YO is offset of the component compared to the whole image. -->\n");
1094 fprintf(xmlout, " <!-- Bits per pixel (bpp) is the pixel depth. -->\n");
1095 fprintf(xmlout, " <!-- WidthOfData and HeightOfData are calculated values, e.g.: w = roundup((Xsiz - XOsiz)/ XRsiz) -->\n");
1098 for (i = 0; i < img->numcomps; i++) {/* image-components */
1099 comp = &(img->comps[i]);
1100 fprintf(xmlout, " <Component Num=\"%d\">\n", i+1);
1101 fprintf(xmlout, " <Ssiz>\n");
1103 fprintf(xmlout," <AsHex>0x%02x</AsHex>\n", (comp->sgnd << 7) & (comp->prec - 1));
1105 fprintf(xmlout," <Signed>%d</Signed>\n", comp->sgnd);
1106 fprintf(xmlout," <PrecisionInBits>%d</PrecisionInBits>\n", comp->prec);
1108 fprintf(xmlout, " </Ssiz>\n");
1109 fprintf(xmlout, " <XRsiz>%d</XRsiz>\n", comp->dx);
1110 fprintf(xmlout, " <YRsiz>%d</YRsiz>\n", comp->dy);
1111 fprintf(xmlout, " <WidthOfData>%d</WidthOfData>\n", comp->w);
1112 fprintf(xmlout, " <HeightOfData>%d</HeightOfData>\n", comp->h);
1113 /* Rest of these aren't calculated when SIZ is read:
1114 fprintf(xmlout, " <XO>%d</XO>\n", comp->x0);
1115 fprintf(xmlout, " <YO>%d</YO>\n", comp->y0);
1117 fprintf(xmlout," <!-- XO, YO is offset of the component compared to the whole image. -->\n");
1118 fprintf(xmlout, " <BitsPerPixel>%d</BitsPerPixel>\n", comp->bpp);
1119 fprintf(xmlout, " <NumberOfDecodedResolution>%d</NumberOfDecodedResolution>\n", comp->resno_decoded); */
1120 // SUPPRESS: n/a to mj2_to_metadata. fprintf(xmlout," <Factor>%d</Factor\n", comp->factor);
1121 /* factor = number of division by 2 of the out image compare to the original size of image */
1122 // TO DO comp->data: int *data; /* image-component data */
1124 fprintf(xmlout, " </Component>\n");
1126 fprintf(xmlout, " </ImageAndFileSize>\n");
1131 void xml_out_frame_cod(FILE* xmlout, j2k_tcp_t *tcp)
1133 /* Could be called with tcp = &j2k_default_tcp;
1134 /* Or, for tile-part header, with &j2k_cp->tcps[j2k_curtileno]
1135 /* Alignment for main:" < < < < To help maintain xml pretty-printing */
1136 /* Alignment for tile:" < < < To help maintain xml pretty-printing */
1139 char spaces[11] = " "; /* 10 spaces if tilepart*/
1141 if(tcp == &j2k_default_tcp) {
1142 s++;s++; /* shorten s to 8 spaces if main */
1144 tccp = &(tcp->tccps[0]);
1146 fprintf(xmlout, "%s<CodingStyleDefault Marker=\"COD\">\n",s); /* Required in main header */
1147 /* Not retained or of interest: Lcod */
1148 fprintf(xmlout, "%s <Scod>0x%02x</Scod>\n", s, tcp->csty); /* 1 byte */
1150 fprintf(xmlout, "%s <!-- For Scod, specific bits mean (where bit 0 is lowest or rightmost): -->\n",s);
1151 fprintf(xmlout, "%s <!-- bit 0: Defines entropy coder precincts -->\n",s);
1152 fprintf(xmlout, "%s <!-- 0 = (PPx=15, PPy=15); 1 = precincts defined below. -->\n",s);
1153 fprintf(xmlout, "%s <!-- bit 1: 1 = SOP marker may be used; 0 = not. -->\n",s);
1154 fprintf(xmlout, "%s <!-- bit 2: 1 = EPH marker may be used; 0 = not. -->\n",s);
1156 fprintf(xmlout, "%s <SGcod>\n",s);
1157 fprintf(xmlout, "%s <ProgressionOrder>%d</ProgressionOrder>\n", s, tcp->prg); /* 1 byte, SGcod (A) */
1159 fprintf(xmlout, "%s <!-- Defined Progression Order Values are: -->\n",s);
1160 fprintf(xmlout, "%s <!-- 0 = LRCP; 1 = RLCP; 2 = RPCL; 3 = PCRL; 4 = CPRL -->\n",s);
1161 fprintf(xmlout, "%s <!-- where L = \"layer\", R = \"resolution level\", C = \"component\", P = \"position\". -->\n",s);
1163 fprintf(xmlout, "%s <NumberOfLayers>%d</NumberOfLayers>\n", s, tcp->numlayers); /* 2 bytes, SGcod (B) */
1164 fprintf(xmlout, "%s <MultipleComponentTransformation>%d</MultipleComponentTransformation>\n", s, tcp->mct); /* 1 byte, SGcod (C). More or less boolean */
1166 fprintf(xmlout, "%s <!-- For MCT, 0 = none, 1 = transform first 3 components for efficiency, per Part I Annex G -->\n",s);
1167 fprintf(xmlout, "%s </SGcod>\n",s);
1168 /* This code will compile only if declaration of j2k_default_tcp is changed from static (to implicit extern) in j2k.c */
1169 fprintf(xmlout, "%s <SPcod>\n",s);
1170 /* Internal data structure tccp defines separate defaults for each component, but they all get the same values */
1171 /* So we only have to report the first component's values here. */
1172 /* Compare j2k_read_cox(...) */
1173 fprintf(xmlout, "%s <NumberOfDecompositionLevels>%d</NumberOfDecompositionLevels>\n", s, tccp->numresolutions - 1); /* 1 byte, SPcox (D) */
1174 fprintf(xmlout, "%s <CodeblockWidth>%d</CodeblockWidth>\n", s, tccp->cblkw - 2); /* 1 byte, SPcox (E) */
1175 fprintf(xmlout, "%s <CodeblockHeight>%d</CodeblockHeight>\n", s, tccp->cblkh - 2); /* 1 byte, SPcox (F) */
1177 fprintf(xmlout, "%s <!-- CBW and CBH are non-negative, and summed cannot exceed 8 -->\n",s);
1178 fprintf(xmlout, "%s <!-- Codeblock dimension is 2^(value + 2) -->\n", s);
1180 fprintf(xmlout, "%s <CodeblockStyle>0x%02x</CodeblockStyle>\n", s, tccp->cblksty); /* 1 byte, SPcox (G) */
1182 fprintf(xmlout, "%s <!-- For CodeblockStyle, bits mean (with value 1=feature on, 0=off): -->\n",s);
1183 fprintf(xmlout, "%s <!-- bit 0: Selective arithmetic coding bypass. -->\n",s);
1184 fprintf(xmlout, "%s <!-- bit 1: Reset context probabilities on coding pass boundaries. -->\n",s);
1185 fprintf(xmlout, "%s <!-- bit 2: Termination on each coding pass. -->\n",s);
1186 fprintf(xmlout, "%s <!-- bit 3: Vertically causal context. -->\n",s);
1187 fprintf(xmlout, "%s <!-- bit 4: Predictable termination. -->\n",s);
1188 fprintf(xmlout, "%s <!-- bit 5: Segmentation symbols are used. -->\n",s);
1190 fprintf(xmlout, "%s <Transformation>%d</Transformation>\n", s, tccp->qmfbid); /* 1 byte, SPcox (H) */
1192 fprintf(xmlout, "%s <!-- For Transformation, 0=\"9-7 irreversible filter\", 1=\"5-3 reversible filter\" -->\n",s);
1193 if (tccp->csty & J2K_CP_CSTY_PRT) {
1194 fprintf(xmlout, "%s <PrecinctSize>\n",s); /* 1 byte, SPcox (I_i) */
1196 fprintf(xmlout, "%s <!-- These are size exponents PPx and PPy. May be zero only for first level (aka N(L)LL subband)-->\n",s);
1197 for (i = 0; i < tccp->numresolutions; i++) {
1198 fprintf(xmlout, "%s <PrecinctHeightAndWidth ResolutionLevel=\"%d\">\n", s, i);
1200 fprintf(xmlout,"%s <AsHex>0x%02x</AsHex>\n", s, (tccp->prch[i] << 4) | tccp->prcw[i]); /* packed into 1 byte, SPcox (G) */
1202 fprintf(xmlout,"%s <WidthAsDecimal>%d</WidthAsDecimal>\n", s, tccp->prcw[i]);
1203 fprintf(xmlout,"%s <HeightAsDecimal>%d</HeightAsDecimal>\n", s, tccp->prch[i]);
1205 fprintf(xmlout, "%s </PrecinctHeightAndWidth>\n", s, i);
1207 fprintf(xmlout, "%s </PrecinctSize>\n",s); /* 1 byte, SPcox (I_i) */
1209 fprintf(xmlout, "%s </SPcod>\n",s);
1210 fprintf(xmlout, "%s</CodingStyleDefault>\n",s);
1215 void xml_out_frame_coc(FILE* xmlout, j2k_tcp_t *tcp, int numcomps)
1217 /* Uses global j2k_default_tcp */
1218 j2k_tccp_t *tccp, *firstcomp_tccp;
1221 firstcomp_tccp = &(tcp->tccps[0]);
1222 /* Internal data structure tccp defines separate defaults for each component, set from main */
1223 /* default, then selectively overwritten. */
1224 /* Compare j2k_read_cox(...) */
1225 /* We don't really know which was the default, and which were not */
1226 /* Let's pretend that [0] is the default and all others are not */
1228 fprintf(xmlout, " <!-- mj2_to_metadata implementation always reports component[0] as using default COD, -->\n");
1229 if(tcp == &j2k_default_tcp)
1230 fprintf(xmlout, " <!-- and any other component, with main-header style values different from [0], as COC. -->\n");
1232 fprintf(xmlout, " <!-- and any other component, with tile-part-header style values different from [0], as COC. -->\n");
1234 for (compno = 1; compno < numcomps; compno++) /* spec says components are zero-based */
1236 tccp = &tcp->tccps[compno];
1237 if(same_component_style(firstcomp_tccp, tccp))
1240 /* Alignments: " < < < < < To help maintain xml pretty-printing */
1241 fprintf(xmlout, " <CodingStyleComponent Marker=\"COC\">\n"); /* Optional in main header, at most 1 per component */
1243 fprintf(xmlout, " <!-- See Ccoc below for zero-based component number. -->\n");
1244 /* Overrides the main COD for the specific component */
1245 /* Not retained or of interest: Lcod */
1246 fprintf(xmlout, " <Scoc>0x%02x</Scoc>\n", tccp->csty); /* 1 byte */
1248 fprintf(xmlout, " <!-- Scoc defines entropy coder precincts: -->\n");
1249 fprintf(xmlout, " <!-- 0 = maximum, namely (PPx=15, PPy=15); 1 = precincts defined below. -->\n");
1251 fprintf(xmlout, " <Ccoc>%d</Ccoc>\n", compno); /* 1 or 2 bytes */
1252 /* Unfortunately compo isn't retained in j2k_read_coc: compno = cio_read(j2k_img->numcomps <= 256 ? 1 : 2); /* Ccoc */
1253 /*if(j2k_img_numcomps <=256)
1258 /* This code will compile only if declaration of j2k_default_tcp is changed from static (to implicit extern) in j2k.c */
1259 fprintf(xmlout, " <SPcoc>\n");
1260 fprintf(xmlout, " <NumberOfDecompositionLevels>%d</NumberOfDecompositionLevels>\n", tccp->numresolutions - 1); /* 1 byte, SPcox (D) */
1261 fprintf(xmlout, " <CodeblockWidth>%d</CodeblockWidth>\n", tccp->cblkw - 2); /* 1 byte, SPcox (E) */
1262 fprintf(xmlout, " <CodeblockHeight>%d</CodeblockHeight>\n", tccp->cblkh - 2); /* 1 byte, SPcox (F) */
1264 fprintf(xmlout, " <!-- CBW and CBH are non-negative, and summed cannot exceed 8 -->\n");
1265 fprintf(xmlout, " <!-- Codeblock dimension is 2^(value + 2) -->\n");
1267 fprintf(xmlout, " <CodeblockStyle>0x%02x</CodeblockStyle>\n", tccp->cblksty); /* 1 byte, SPcox (G) */
1269 fprintf(xmlout, " <!-- For CodeblockStyle, bits mean (with value 1=feature on, 0=off): -->\n");
1270 fprintf(xmlout, " <!-- bit 0: Selective arithmetic coding bypass. -->\n");
1271 fprintf(xmlout, " <!-- bit 1: Reset context probabilities on coding pass boundaries. -->\n");
1272 fprintf(xmlout, " <!-- bit 2: Termination on each coding pass. -->\n");
1273 fprintf(xmlout, " <!-- bit 3: Vertically causal context. -->\n");
1274 fprintf(xmlout, " <!-- bit 4: Predictable termination. -->\n");
1275 fprintf(xmlout, " <!-- bit 5: Segmentation symbols are used. -->\n");
1277 fprintf(xmlout, " <Transformation>%d</Transformation>\n", tccp->qmfbid); /* 1 byte, SPcox (H) */
1279 fprintf(xmlout, " <!-- For Transformation, 0=\"9-7 irreversible filter\", 1=\"5-3 reversible filter\" -->\n");
1280 if (tccp->csty & J2K_CP_CSTY_PRT) {
1281 fprintf(xmlout, " <PrecinctSize>\n"); /* 1 byte, SPcox (I_i) */
1283 fprintf(xmlout, " <!-- These are size exponents PPx and PPy. May be zero only for first level (aka N(L)LL subband)-->\n");
1284 for (i = 0; i < tccp->numresolutions-1; i++) { /* subtract 1 to get # of decomposition levels */
1285 fprintf(xmlout, " <PrecinctHeightAndWidth ResolutionLevel=\"%d\">\n", i);
1287 fprintf(xmlout," <AsHex>0x%02x</AsHex>\n", (tccp->prch[i] << 4) | tccp->prcw[i]); /* packed into 1 byte, SPcox (G) */
1289 fprintf(xmlout," <WidthAsDecimal>%d</WidthAsDecimal>\n", tccp->prcw[i]);
1290 fprintf(xmlout," <HeightAsDecimal>%d</HeightAsDecimal>\n", tccp->prch[i]);
1292 fprintf(xmlout, " </PrecinctHeightAndWidth>\n", i);
1294 fprintf(xmlout, " </PrecinctSize>\n"); /* 1 byte, SPcox (I_i) */
1296 fprintf(xmlout, " </SPcoc>\n");
1297 fprintf(xmlout, " </CodingStyleComponent>\n");
1303 BOOL same_component_style(j2k_tccp_t *tccp1, j2k_tccp_t *tccp2)
1307 if(tccp1->numresolutions != tccp2->numresolutions)
1309 if(tccp1->cblkw != tccp2->cblkw)
1311 if(tccp1->cblkh != tccp2->cblkh)
1313 if(tccp1->cblksty != tccp2->cblksty)
1315 if(tccp1->csty != tccp2->csty)
1318 if (tccp1->csty & J2K_CP_CSTY_PRT) {
1319 for (i = 0; i < tccp1->numresolutions; i++) {
1320 if(tccp1->prcw[i] != tccp2->prcw[i] || tccp1->prch[i] != tccp2->prch[i])
1329 void xml_out_frame_qcd(FILE* xmlout, j2k_tcp_t *tcp)
1331 /* This code will compile only if declaration of j2k_default_tcp is changed from static (to implicit extern) in j2k.c */
1333 int bandno, numbands;
1335 /* Compare j2k_read_qcx */
1336 fprintf(xmlout, " <QuantizationDefault Marker=\"QCD\">\n"); /* Required in main header, single occurrence */
1337 tccp = &(tcp->tccps[0]);
1338 /* Not retained or of interest: Lqcd */
1339 fprintf(xmlout, " <Sqcd>\n"); /* 1 byte */
1341 fprintf(xmlout, " <!-- Default quantization style for all components. -->\n");
1343 fprintf(xmlout, " <AsHex>0x%02x</AsHex>\n", (tccp->numgbits) << 5 | tccp->qntsty);
1345 fprintf(xmlout, " <QuantizationStyle>%d</QuantizationStyle>\n", tccp->qntsty);
1347 fprintf(xmlout, " <!-- Quantization style (in Sqcd's low 5 bits) may be: -->\n");
1348 fprintf(xmlout, " <!-- 0 = No quantization. SPqcd size = 8 bits-->\n");
1349 fprintf(xmlout, " <!-- 1 = Scalar derived (values signaled for N(L)LL subband only). Use Eq. E.5. SPqcd size = 16. -->\n");
1350 fprintf(xmlout, " <!-- 2 = Scalar expounded (values signaled for each subband). SPqcd size = 16. -->\n");
1353 fprintf(xmlout, " <NumberOfGuardBits>%d</NumberOfGuardBits>\n", tccp->numgbits);
1355 fprintf(xmlout, " <!-- 0-7 guard bits allowed (stored in Sqcd's high 3 bits) -->\n");
1356 fprintf(xmlout, " </Sqcd>\n");
1358 /* Problem: numbands in some cases is calculated from len, which is not retained or available here at this time */
1359 /* So we'll just dump all internal values */
1360 /* We could calculate it, but I'm having trouble believing the length equations in the standard */
1362 fprintf(xmlout, " <SPqcd>\n");
1363 switch(tccp->qntsty) {
1364 case J2K_CCP_QNTSTY_NOQNT: /* no quantization */
1365 /* This is what standard says, but I don't believe it: len = 4 + (3*decomp); */
1366 numbands = J2K_MAXBANDS; /* should be: numbands = len - 1; */
1367 /* Better: IMAGINE numbands = tccp->stepsize_numbands; */
1368 /* Instead look for first zero exponent, quit there. Adequate? */
1369 fprintf(xmlout, " <ReversibleStepSizeValue>\n");
1371 fprintf(xmlout, " <!-- Current mj2_to_metadata implementation dumps entire internal table, -->\n");
1372 fprintf(xmlout, " <!-- until an exponent with zero value is reached. -->\n");
1373 fprintf(xmlout, " <!-- Exponent epsilon(b) of reversible dynamic range. -->\n");
1374 fprintf(xmlout, " <!-- Hex value is as stored, in high-order 5 bits. -->\n");
1376 for (bandno = 0; bandno < numbands; bandno++) {
1377 if(tccp->stepsizes[bandno].expn == 0)
1378 break; /* Remove when we have real numbands */
1379 fprintf(xmlout, " <DynamicRangeExponent Subband=\"%d\">\n", bandno);
1381 fprintf(xmlout," <AsHex>0x%02x</AsHex>\n", tccp->stepsizes[bandno].expn << 3);
1383 fprintf(xmlout," <AsDecimal>%d</AsDecimal>\n", tccp->stepsizes[bandno].expn);
1384 fprintf(xmlout, " </DynamicRangeExponent>\n");
1386 fprintf(xmlout, " </ReversibleStepSizeValue>\n");
1388 case J2K_CCP_QNTSTY_SIQNT: /* scalar quantization derived */
1389 /* This is what standard says. Should I believe it:: len = 5;
1391 fprintf(xmlout, " <QuantizationStepSizeValues>\n");
1393 fprintf(xmlout, " <!-- For irreversible transformation only. See Part I Annex E Equation E.3 -->\n");
1394 fprintf(xmlout, " <QuantizationValues Subband=\"0\">\n");
1396 fprintf(xmlout, " <!-- For N(L)LL subband: >\n");
1398 fprintf(xmlout, " <AsHex>0x%02x</AsHex>\n", (tccp->stepsizes[0].expn << 11) | tccp->stepsizes[0].mant);
1400 fprintf(xmlout, " <Exponent>%d</Exponent>\n", tccp->stepsizes[0].expn);
1401 fprintf(xmlout, " <Mantissa>%d</Mantissa>\n", tccp->stepsizes[0].mant);
1403 fprintf(xmlout, " </QuantizationValues>\n");
1405 fprintf(xmlout, " <!-- Exponents for subbands beyond 0 are not from header, but calculated per Eq. E.5 -->\n");
1406 fprintf(xmlout, " <!-- The mantissa for all subbands is the same, given by the value above. -->\n");
1407 fprintf(xmlout, " <!-- Current mj2_to_metadata implementation dumps entire internal table, -->\n");
1408 fprintf(xmlout, " <!-- until a subband with exponent of zero value is reached. -->\n");
1411 for (bandno = 1; bandno < J2K_MAXBANDS; bandno++) {
1412 if(tccp->stepsizes[bandno].expn == 0)
1415 fprintf(xmlout, " <CalculatedExponent Subband=\"%d\">%d</CalculatedExponent>\n", bandno, tccp->stepsizes[bandno].expn);
1418 fprintf(xmlout, " </QuantizationStepSizeValues>\n");
1421 default: /* J2K_CCP_QNTSTY_SEQNT */ /* scalar quantization expounded */
1422 /* This is what standard says, but should I believe it: len = 5 + 6*decomp; */
1423 numbands = J2K_MAXBANDS; /* should be: (len - 1) / 2;*/
1424 /* Better: IMAGINE numbands = tccp->stepsize_numbands; */
1425 fprintf(xmlout, " <QuantizationStepSizeValues>\n");
1427 fprintf(xmlout, " <!-- For irreversible transformation only. See Part I Annex E Equation E.3 -->\n");
1428 fprintf(xmlout, " <!-- Current mj2_to_metadata implementation dumps entire internal table, -->\n");
1429 fprintf(xmlout, " <!-- until a subband with mantissa and exponent of zero values is reached. -->\n");
1431 for (bandno = 0; bandno < numbands; bandno++) {
1432 if(tccp->stepsizes[bandno].expn == 0 && tccp->stepsizes[bandno].mant == 0)
1433 break; /* Remove when we have real numbands */
1435 fprintf(xmlout, " <QuantizationValues Subband=\"%d\">\n", bandno);
1437 fprintf(xmlout," <AsHex>0x%02x</AsHex>\n", (tccp->stepsizes[bandno].expn << 11) | tccp->stepsizes[bandno].mant);
1439 fprintf(xmlout," <Exponent>%d</Exponent>\n", tccp->stepsizes[bandno].expn);
1440 fprintf(xmlout," <Mantissa>%d</Mantissa>\n", tccp->stepsizes[bandno].mant);
1442 fprintf(xmlout, " </QuantizationValues>\n");
1444 fprintf(xmlout, " </QuantizationStepSizeValues>\n");
1447 fprintf(xmlout, " </SPqcd>\n");
1448 fprintf(xmlout, " </QuantizationDefault>\n");
1450 /* Alignments: " < < < < < To help maintain xml pretty-printing */
1455 void xml_out_frame_qcc(FILE* xmlout, j2k_tcp_t *tcp, int numcomps)
1457 /* Uses global j2k_default_tcp */
1458 /* This code will compile only if declaration of j2k_default_tcp is changed from static (to implicit extern) in j2k.c */
1459 j2k_tccp_t *tccp, *firstcomp_tccp;
1460 int bandno, numbands;
1463 firstcomp_tccp = &(tcp->tccps[0]);
1464 /* Internal data structure tccp defines separate defaults for each component, set from main */
1465 /* default, then selectively overwritten. */
1466 /* Compare j2k_read_qcx(...) */
1467 /* We don't really know which was the default, and which were not */
1468 /* Let's pretend that [0] is the default and all others are not */
1470 fprintf(xmlout, " <!-- mj2_to_metadata implementation always reports component[0] as using default QCD, -->\n");
1471 if(tcp == &j2k_default_tcp)
1472 fprintf(xmlout, " <!-- and any other component, with main-header quantization values different from [0], as QCC. -->\n");
1474 fprintf(xmlout, " <!-- and any other component, with tile-part-header quantization values different from [0], as QCC. -->\n");
1476 for (compno = 1; compno < numcomps; compno++) /* spec says components are zero-based */
1478 tccp = &(tcp->tccps[compno]);
1479 if(same_component_quantization(firstcomp_tccp, tccp))
1482 /* Compare j2k_read_qcx */
1483 fprintf(xmlout, " <QuantizationComponent Marker=\"QCC\" Component=\"%d\">\n", compno); /* Required in main header, single occurrence */
1484 tccp = &j2k_default_tcp.tccps[0];
1485 /* Not retained or perhaps of interest: Lqcd It maybe can be calculated. */
1486 fprintf(xmlout, " <Sqcc>\n"); /* 1 byte */
1488 fprintf(xmlout, " <!-- Quantization style for this component. -->\n");
1490 fprintf(xmlout, " <AsHex>0x%02x</AsHex>\n", (tccp->numgbits) << 5 | tccp->qntsty);
1492 fprintf(xmlout, " <QuantizationStyle>%d</QuantizationStyle>\n", tccp->qntsty);
1494 fprintf(xmlout, " <!-- Quantization style (in Sqcc's low 5 bits) may be: -->\n");
1495 fprintf(xmlout, " <!-- 0 = No quantization. SPqcc size = 8 bits-->\n");
1496 fprintf(xmlout, " <!-- 1 = Scalar derived (values signaled for N(L)LL subband only). Use Eq. E.5. SPqcc size = 16. -->\n");
1497 fprintf(xmlout, " <!-- 2 = Scalar expounded (values signaled for each subband). SPqcc size = 16. -->\n");
1500 fprintf(xmlout, " <NumberOfGuardBits>%d</NumberOfGuardBits>\n", tccp->numgbits);
1502 fprintf(xmlout, " <!-- 0-7 guard bits allowed (stored in Sqcc's high 3 bits) -->\n");
1503 fprintf(xmlout, " </Sqcc>\n");
1505 /* Problem: numbands in some cases is calculated from len, which is not retained or available here at this time */
1506 /* So we'll just dump all internal values */
1507 fprintf(xmlout, " <SPqcc>\n");
1508 switch(tccp->qntsty) {
1509 case J2K_CCP_QNTSTY_NOQNT:
1510 numbands = J2K_MAXBANDS; /* should be: numbands = len - 1; */
1511 /* Better: IMAGINE numbands = tccp->stepsize_numbands; */
1513 /* Instead look for first zero exponent, quit there. Adequate? */
1514 fprintf(xmlout, " <ReversibleStepSizeValue>\n");
1516 fprintf(xmlout, " <!-- Current mj2_to_metadata implementation dumps entire internal table, -->\n");
1517 fprintf(xmlout, " <!-- until an exponent with zero value is reached. -->\n");
1518 fprintf(xmlout, " <!-- Exponent epsilon(b) of reversible dynamic range. -->\n");
1519 fprintf(xmlout, " <!-- Hex value is as stored, in high-order 5 bits. -->\n");
1521 for (bandno = 0; bandno < numbands; bandno++) {
1522 if(tccp->stepsizes[bandno].expn == 0)
1523 break; /* Remove this once we have real numbands */
1524 fprintf(xmlout, " <Exponent Subband=\"%d\">\n", bandno);
1526 fprintf(xmlout," <AsHex>0x%02x</AsHex>\n", tccp->stepsizes[bandno].expn << 3);
1528 fprintf(xmlout," <AsDecimal>%d</AsDecimal>\n", tccp->stepsizes[bandno].expn);
1529 fprintf(xmlout, " </Exponent>\n");
1531 fprintf(xmlout, " </ReversibleStepSizeValue>\n");
1533 case J2K_CCP_QNTSTY_SIQNT:
1535 fprintf(xmlout, " <QuantizationStepSizeValues>\n");
1537 fprintf(xmlout, " <!-- For irreversible transformation only. See Part I Annex E Equation E.3 -->\n");
1538 fprintf(xmlout, " <QuantizationValuesForSubband0>\n");
1540 fprintf(xmlout, " <!-- For N(L)LL subband: >\n");
1542 fprintf(xmlout, " <AsHex>0x%02x</AsHex>\n", (tccp->stepsizes[0].expn << 11) | tccp->stepsizes[0].mant);
1544 fprintf(xmlout, " <Exponent>%d</Exponent>\n", tccp->stepsizes[0].expn);
1545 fprintf(xmlout, " <Mantissa>%d</Mantissa>\n", tccp->stepsizes[0].mant);
1547 fprintf(xmlout, " </QuantizationValuesForSubband0>\n");
1549 fprintf(xmlout, " <!-- Exponents for subbands beyond 0 are not from header, but calculated per Eq. E.5 -->\n");
1550 fprintf(xmlout, " <!-- The mantissa for all subbands is the same, given by the value above. -->\n");
1551 fprintf(xmlout, " <!-- Current mj2_to_metadata implementation dumps entire internal table, -->\n");
1552 fprintf(xmlout, " <!-- until a subband with exponent of zero value is reached. -->\n");
1555 for (bandno = 1; bandno < J2K_MAXBANDS; bandno++) {
1556 if(tccp->stepsizes[bandno].expn == 0)
1559 fprintf(xmlout, " <CalculatedExponent Subband=\"%d\">%d</CalculatedExponent>\n", bandno, tccp->stepsizes[bandno].expn);
1561 fprintf(xmlout, " </QuantizationStepSizeValues>\n");
1564 default: /* J2K_CCP_QNTSTY_SEQNT */
1565 numbands = J2K_MAXBANDS; /* should be: (len - 1) / 2;*/
1566 /* Better: IMAGINE numbands = tccp->stepsize_numbands; */
1567 fprintf(xmlout, " <QuantizationStepSizeValues>\n");
1569 fprintf(xmlout, " <!-- For irreversible transformation only. See Part I Annex E Equation E.3 -->\n");
1570 fprintf(xmlout, " <!-- Current mj2_to_metadata implementation dumps entire internal table, -->\n");
1571 fprintf(xmlout, " <!-- until a subband with mantissa and exponent of zero values is reached. -->\n");
1573 for (bandno = 0; bandno < numbands; bandno++) {
1574 if(tccp->stepsizes[bandno].expn == 0 && tccp->stepsizes[bandno].mant == 0)
1575 break; /* Remove this once we have real numbands count */
1576 fprintf(xmlout, " <QuantizationValues Subband=\"%d\">\n", bandno);
1578 fprintf(xmlout," <AsHex>0x%02x</AsHex>\n", (tccp->stepsizes[bandno].expn << 11) | tccp->stepsizes[bandno].mant);
1580 fprintf(xmlout," <Exponent>%d</Exponent>\n", tccp->stepsizes[bandno].expn);
1581 fprintf(xmlout," <Mantissa>%d</Mantissa>\n", tccp->stepsizes[bandno].mant);
1583 fprintf(xmlout, " </QuantizationValues>\n");
1585 fprintf(xmlout, " </QuantizationStepSizeValues>\n");
1588 fprintf(xmlout, " </SPqcc>\n");
1589 fprintf(xmlout, " </QuantizationComponent>\n");
1591 /* Alignments: " < < < < < To help maintain xml pretty-printing */
1596 BOOL same_component_quantization(j2k_tccp_t *tccp1, j2k_tccp_t *tccp2)
1598 int bandno, numbands;
1600 if(tccp1->qntsty != tccp2->qntsty)
1602 if(tccp1->numgbits != tccp2->numgbits)
1605 switch(tccp1->qntsty) {
1606 case J2K_CCP_QNTSTY_NOQNT:
1607 numbands = J2K_MAXBANDS; /* should be: numbands = len - 1; */
1608 /* Instead look for first zero exponent, quit there. Adequate? */
1609 for (bandno = 0; bandno < numbands; bandno++) {
1610 if(tccp1->stepsizes[bandno].expn == 0)
1612 if(tccp1->stepsizes[bandno].expn != tccp2->stepsizes[bandno].expn)
1616 case J2K_CCP_QNTSTY_SIQNT:
1618 if(tccp1->stepsizes[0].expn != tccp2->stepsizes[0].expn || tccp1->stepsizes[0].mant != tccp2->stepsizes[0].mant)
1620 /* Don't need to check remainder, since they are calculated from [0] */
1623 default: /* J2K_CCP_QNTSTY_SEQNT */
1624 numbands = J2K_MAXBANDS; /* should be: (len - 1) / 2;*/
1625 /* This comparison may cause us problems with trailing junk values. */
1626 for (bandno = 0; bandno < numbands; bandno++) {
1627 if(tccp1->stepsizes[bandno].expn != tccp2->stepsizes[bandno].expn || tccp1->stepsizes[bandno].mant != tccp2->stepsizes[bandno].mant);
1637 void xml_out_frame_rgn(FILE* xmlout, j2k_tcp_t *tcp, int numcomps)
1640 /* Don't know if MJ2 files can have regions of interest. Assume yes. */
1641 for(compno = 0; compno < numcomps; compno++) {
1642 SPrgn = tcp->tccps[compno].roishift; /* 1 byte; SPrgn */
1644 continue; /* Yet another kludge */
1646 fprintf(xmlout, " <RegionOfInterest Marker=\"RGN\">\n"); /* Optional in main header, at most 1 per component */
1648 fprintf(xmlout, " <!-- See Crgn below for zero-based component number. -->\n");
1649 /* Not retained or of interest: Lrgd */
1650 fprintf(xmlout, " <Srgn>0</Srgn>\n"); /* 1 byte */
1652 fprintf(xmlout, " <!-- Srgn is ROI style. Only style=0 defined: Implicit ROI (max. shift) -->\n");
1653 fprintf(xmlout, " <Crgn>%d</Crgn>\n", compno); /* 1 or 2 bytes */
1654 fprintf(xmlout, " <SPrgn>%d</SPrgn>\n", SPrgn); /* 1 byte */
1656 fprintf(xmlout, " <!-- SPrgn is implicit ROI shift, i.e., binary shifting of ROI coefficients above background. -->\n");
1657 fprintf(xmlout, " </RegionOfInterest\n"); /* Optional in main header, at most 1 per component */
1663 void xml_out_frame_poc(FILE* xmlout, j2k_tcp_t *tcp) { /* Progression Order Change */
1664 /* Compare j2k_read_poc() */
1669 return; /* Not present */
1671 fprintf(xmlout, " <ProgressionOrderChange Marker=\"POC\">\n"); /* Optional in main header, at most 1 per component */
1672 /* j2k_read_poc seems to allow accumulation of default pocs from multiple POC segments, but does
1673 the spec really allow that? */
1674 /* 2 bytes, not retained; Lpoc */
1675 /* I probably didn't get this dump precisely right. */
1676 for (i = 0; i < tcp->numpocs; i++) {
1677 poc = &tcp->pocs[i];
1678 fprintf(xmlout, " <Progression Num=\"%d\">\n", i+1);
1679 fprintf(xmlout, " <RSpoc>%d</RSpoc>\n", poc->resno0); /* 1 byte, RSpoc_i */
1681 fprintf(xmlout," <!-- Resolution level index (inclusive) for progression start. Range: 0 to 33 -->\n");
1682 fprintf(xmlout, " <CSpoc>%d</CSpoc>\n", poc->compno0);/* j2k_img->numcomps <= 256 ? 1 byte : 2 bytes; CSpoc_i */
1684 fprintf(xmlout," <!-- Component index (inclusive) for progression start. -->\n");
1685 fprintf(xmlout, " <LYEpoc>%d</LYEpoc>\n", poc->layno1); /* int_min(cio_read(2), tcp->numlayers); /* 2 bytes; LYEpoc_i */
1687 fprintf(xmlout," <!-- Layer index (exclusive) for progression end. -->\n");
1688 fprintf(xmlout, " <REpoc>%d</REpoc>\n", poc->resno1); /*int_min(cio_read(1), tccp->numresolutions); /* REpoc_i */
1690 fprintf(xmlout," <!-- Resolution level index (exclusive) for progression end. Range: RSpoc to 33 -->\n");
1691 fprintf(xmlout, " <CEpoc>%d</CEpoc>\n", poc->compno1); /* int_min(cio_read(j2k_img->numcomps <= 256 ? 1 : 2), j2k_img->numcomps); /* CEpoc_i */
1693 fprintf(xmlout," <!-- Component index (exclusive) for progression end. Minimum: CSpoc -->\n");
1694 fprintf(xmlout, " <Ppoc>%d</Ppoc>\n", poc->prg); /* 1 byte Ppoc_i */
1696 fprintf(xmlout," <!-- Defined Progression Order Values are: -->\n");
1697 fprintf(xmlout," <!-- 0 = LRCP; 1 = RLCP; 2 = RPCL; 3 = PCRL; 4 = CPRL -->\n");
1698 fprintf(xmlout," <!-- where L = \"layer\", R = \"resolution level\", C = \"component\", P = \"position\". -->\n");
1700 fprintf(xmlout, " </Progression>\n");
1702 fprintf(xmlout, " </ProgressionOrderChange\n");
1707 #ifdef SUPPRESS_FOR_NOW
1708 /* Suppress PPM and PPT since we're not showing data from the third option, namely within the codestream, and
1709 that's evidently what frames_to_mj2 uses. And a hex dump isn't so useful anyway */
1711 void xml_out_frame_ppm(FILE *xmlout, j2k_cp_t *cp) { /* opt (but reqd in main or tile for any progression order changes) */
1712 /* Compare j2k_read_ppm() */
1716 return; /* Not present */
1718 fprintf(xmlout, " <PackedPacketHeadersMainHeader Marker=\"PPM\">\n"); /* Optional in main header, but if not, must be in PPT or codestream */
1719 /* 2 bytes Lppm not saved */
1721 fprintf(xmlout, " <!-- If there are multiple PPM marker segments in the main header, -->\n");
1722 fprintf(xmlout, " <!-- this mj2_to_metadata implementation will report them as a single consolidated PPM header. -->\n");
1723 fprintf(xmlout, " <!-- The implementation can't currently segregate by tile-part. -->\n");
1724 fprintf(xmlout, " <!-- TO DO? further map the packet headers to xml. -->\n");
1727 /* 1 byte, not retained ; Zppm is sequence # of this PPM header */
1728 /* 4 bytes, possibly overwritten multiple times in j2k_cp->ppm_previous: Nppm */
1729 /* Use j symbol for index instead of i, to make comparable with j2k_read_ppm */
1730 /* Not real clear whether to use ppm->store or ppm_len as upper bound */
1731 fprintf(xmlout, " <PackedData>\n");
1732 xml_out_dump_hex(xmlout, cp->ppm_data, cp->ppm_len);
1733 /* Dump packet headers 1 byte at a time: lppm[i][j] */
1734 fprintf(xmlout, " </PackedData>\n");
1735 fprintf(xmlout, " </PackedPacketHeadersMainHeader>\n"); /* Optional in main header, but if not, must be in PPT or codestream */
1740 void xml_out_frame_ppt(FILE *xmlout, j2k_tcp_t *tcp) { /* opt in tilepart header */
1741 /* Compare j2k_read_ppt() */
1745 return; /* Not present */
1747 fprintf(xmlout, " <PackedPacketHeadersTilePartHeader Marker=\"PPT\">\n"); /* Optional in main header, but if not, must be in PPT or codestream */
1748 /* 2 bytes Lppm not saved */
1750 fprintf(xmlout, " <!-- If there are multiple PPT marker segments in the tile-part header, -->\n");
1751 fprintf(xmlout, " <!-- this mj2_to_metadata implementation will report them as a single consolidated PPT header. -->\n");
1752 fprintf(xmlout, " <!-- The implementation can't currently segregate by tile-part. -->\n");
1753 fprintf(xmlout, " <!-- TO DO? further map the packet headers to xml. -->\n");
1756 /* 1 byte, not retained ; Zppt is sequence # of this PPT header */
1757 /* 4 bytes, possibly overwritten multiple times in j2k_cp->ppt_previous: Nppt */
1758 /* Use j symbol for index instead of i, to make comparable with j2k_read_ppt */
1759 /* Not real clear whether to use ppt->store or ppt_len as upper bound */
1760 fprintf(xmlout, " <PackedData>\n");
1761 xml_out_dump_hex(xmlout, tcp->ppt_data, tcp->ppt_len);
1762 /* Dump packet headers 1 byte at a time: lppt[i][j] */
1763 fprintf(xmlout, " </PackedData>\n");
1764 fprintf(xmlout, " </PackedPacketHeadersTileHeader>\n"); /* Optional in tile-part header, but if not, must be in PPM or codestream */
1766 #endif SUPPRESS_FOR_NOW
1770 void xml_out_frame_tlm(FILE* xmlout) { /* opt, main header only. May be multiple. */
1771 /* Compare j2k_read_tlm()... which doesn't retain anything! */
1772 /* Plan: Since this is only called from main header, not tilepart, use global j2k_default_tcp rather than parameter */
1777 void xml_out_frame_plm(FILE* xmlout) { /* opt in main; can be used in conjunction with PLT */
1778 /* NO-OP. PLM NOT SAVED IN DATA STRUCTURE */
1779 /* Compare j2k_read_plm()... which doesn't retain anything! */
1780 /* Plan: Since this is only called from main header, not tilepart, use global j2k_default_tcp rather than parameter */
1785 void xml_out_frame_plt(FILE* xmlout, j2k_tcp_t *tcp) { /* opt in main; can be used in conjunction with PLT */
1786 /* NO-OP. PLT NOT SAVED IN DATA STRUCTURE */
1787 /* Compare j2k_read_plt()... which doesn't retain anything! */
1792 void xml_out_frame_crg(FILE* xmlout) { /* NO-OP. CRG NOT SAVED IN DATA STRUCTURE */ /* opt in main; */
1793 /* Compare j2k_read_crg()... which doesn't retain anything! */
1794 /* Plan: Since this is only called from main header, not tilepart, use global j2k_default_tcp rather than parameter */
1796 THIS PSEUDOCODE IMAGINES THESE EXIST: j2k_default_tcp->crg, j2k_default_tcp->crg_i, j2k_default_tcp->crg_xcrg*, j2k_default_tcp->crg_ycrg*
1797 (POSSIBLY DON'T NEED crg_i, CAN GET NUMBER OR COMPONENTS FROM ELSEWHERE)
1798 if(j2k_default_tcp->crg != 1 || j2k_default_tcp->crg_i == 0)
1799 return; /* Not present */
1801 fprintf(xmlout, " <ComponentRegistration Marker=\"RG\" Count=\"%d\">\n", j2k_default_tcp->crg_i);
1803 fprintf(xmlout, " <!-- Fine tuning of registration of components with respect to each other, -->\n");
1804 fprintf(xmlout, " <!-- not required but potentially helpful for decoder. -->\n");
1805 fprintf(xmlout, " <!-- These supplementary fractional offsets are in units of 1/65536 of the horizontal -->\n");
1806 fprintf(xmlout, " <!-- or vertical separation (e.g., XRsiz[i] or YRsiz[i] for component i). -->\n");
1808 /* This isn't the most compact form of table, but is OK when number of components is small, as is likely. */
1809 for (i = 0; i < j2k_default_tcp->crg_i; i++) {
1810 fprintf(xmlout, " <Component Num=\"%d\">\n", i+1);
1811 fprintf(xmlout, " <Xcrg>\n");
1813 fprintf(xmlout," <AsNumerator>%d</AsNumerator>\n", j2k_default_tcp->crg_xcrg[i]);
1815 /* Calculate n * 100%/65536; 4 digits after decimal point is sufficiently accurate */
1816 fprintf(xmlout," <AsPercentage>%.4f</AsPercentage>\n", ((double)j2k_default_tcp->crg_xcrg[i])/655.36);
1817 /* We could do another calculation that include XRsiz[i]; maybe later. */
1819 fprintf(xmlout, " </Xcrg>\n");
1820 fprintf(xmlout, " <Ycrg>\n");
1822 fprintf(xmlout," <AsNumerator>%d</AsNumerator>\n", j2k_default_tcp->crg_ycrg[i]);
1824 fprintf(xmlout," <AsPercentage>%f</AsPercentage>\n", ((double)j2k_default_tcp->crg_ycrg[i])/655.36);
1826 fprintf(xmlout, " </Ycrg>\n");
1827 fprintf(xmlout, " </Component>\n");
1830 fprintf(xmlout, " </ComponentRegistration>\n");
1837 /* Regrettably from a metadata point of view, j2k_read_com() skips over any comments in main header or tile-part-header */
1838 void xml_out_frame_com(FILE* xmlout, j2k_tcp_t *tcp) { /* NO-OP. COM NOT SAVED IN DATA STRUCTURE */ /* opt in main; */
1839 /* Compare j2k_read_com()... which doesn't retain anything! */
1841 THIS PSEUDOCODE IMAGINES THESE EXIST: tcp->com, tcp->com_len, tcp->com_data array
1843 return; /* Not present */
1845 fprintf(xmlout, " <Comment Marker=\"COM\">\n"); /* Optional in main or tile-part header */
1846 xml_out_dump_hex_and_ascii(tcp->com_data, tcp->com_len);
1847 fprintf(xmlout, " </Comment>\n");
1851 void xml_out_dump_hex(FILE* xmlout, char *data, int data_len) {
1854 /* This is called when raw is true, or there is no appropriate derived form */
1855 fprintf(xmlout, " <AsHex>\n");
1856 fprintf(xmlout, " "); /* Inadequate for pretty printing */
1857 for (i = 0; i < data_len; i++) { /* Dump packet headers */
1858 fprintf(xmlout, "%02x", data[i]);
1860 fprintf(xmlout, " </AsHex>\n");
1863 /* Define this as an even number: */
1864 #define BYTES_PER_DUMP_LINE 40
1865 /* Current total width for Hex and ASCII is : 11 spaces lead + (3 * BPDL) + 2 spaces + BPDL */
1866 void xml_out_dump_hex_and_ascii(FILE* xmlout, char *data, int data_len) {
1870 xml_out_dump_hex(xmlout, data, data_len);
1873 fprintf(xmlout, " <AsHexAndASCII>\n");
1874 for (i = 0; i < data_len; ) {
1875 fprintf(xmlout," "); /* Additional leading space added in loop */
1876 /* First column: hex */
1877 for (j = 0; j < BYTES_PER_DUMP_LINE; j++) /* Dump bytes */
1878 fprintf(xmlout," %02x", data[i+j]);
1879 /* Space between columns... */ fprintf(xmlout, " ");
1880 /* Second column: ASCII */
1881 for (j = 0; j < BYTES_PER_DUMP_LINE; j++, i++) {
1882 if(isprint((int)data[i]) && i < data_len)
1883 fprintf(xmlout,"%c", data[i]);
1885 fprintf(xmlout," ");
1887 /* If we also wanted to output UCS-2 Unicode as a third column, then entire document
1888 must use fwprintf. Forget about it for now. As it stands, if data is UCS-2 format but still
1889 the ASCII set, then we'll be able to read every other byte as ASCII in column 2. If
1890 data is UTF-8 format but still ASCII, then we'll be able to read every byte as ASCII
1893 fprintf(xmlout, " </AsHexAndASCII>\n");
1900 void xml_out_frame_jp2h(FILE* xmlout, jp2_struct_t *jp2_struct) { /* JP2 Header */
1901 /* Compare jp2_read_jp2h(jp2_struct_t * jp2_struct) */
1904 fprintf(xmlout, " <JP2Header BoxType=\"jp2h\">\n");
1906 /* Compare jp2_read_ihdr(jp2_struct)) */
1907 fprintf(xmlout, " <ImageHeader BoxType=\"ihdr\">\n");
1908 fprintf(xmlout, " <HEIGHT>%d</HEIGHT>\n", jp2_struct->h); /* 4 bytes */
1909 fprintf(xmlout, " <WIDTH>%d</WIDTH>\n", jp2_struct->w); /* 4 bytes */
1911 fprintf(xmlout, " <!-- HEIGHT here, if 2 fields per image, is of total deinterlaced height. -->\n");
1912 fprintf(xmlout, " <NC>%d</NC>\n", jp2_struct->numcomps); /* 2 bytes */
1914 fprintf(xmlout, " <!-- NC is number of components -->\n"); /* 2 bytes */
1915 fprintf(xmlout, " <BPC>\n"); /* 1 byte */
1916 if(jp2_struct->bpc == 255) {
1917 fprintf(xmlout, " <AsHex>0x%02x</AsHex>\n", jp2_struct->bpc); /* 1 byte */
1919 fprintf(xmlout, " <!-- BPC = 0xff means bits per pixel varies with component; see table below. -->\n");
1920 } else { /* Not 0xff */
1922 fprintf(xmlout, " <AsHex>0x%02x</AsHex>\n", jp2_struct->bpc); /* 1 byte */
1924 fprintf(xmlout," <!-- BPC = 0xff means bits per pixel varies with component; see table below. -->\n");
1927 fprintf(xmlout, " <BitsPerPixel>%d</BitsPerPixel>\n", jp2_struct->bpc & 0x7f);
1928 fprintf(xmlout, " <Signed>%d</Signed>\n", jp2_struct->bpc >> 7);
1931 fprintf(xmlout, " </BPC>\n");
1932 fprintf(xmlout, " <C>%d</C>\n", jp2_struct->C); /* 1 byte */
1934 fprintf(xmlout, " <!-- C is compression type. Only \"7\" is allowed to date. -->\n"); /* 2 bytes */
1935 fprintf(xmlout, " <UnkC>%d</UnkC>\n", jp2_struct->UnkC); /* 1 byte */
1937 fprintf(xmlout, " <!-- Colourspace Unknown. 1 = unknown, 0 = known (e.g., colourspace spec is accurate) -->\n"); /* 1 byte */
1938 fprintf(xmlout, " <IPR>%d</IPR>\n", jp2_struct->IPR); /* 1 byte */
1940 fprintf(xmlout, " <!-- IPR is 1 if frame contains an Intellectual Property box; 0 otherwise. -->\n"); /* 2 bytes */
1941 fprintf(xmlout, " </ImageHeader>\n");
1943 if (jp2_struct->bpc == 255)
1945 fprintf(xmlout, " <BitsPerComponent BoxType=\"bpcc\">\n");
1947 fprintf(xmlout, " <!-- Pixel depth (range 1 to 38) is low 7 bits of hex value + 1 -->\n");
1948 /* Bits per pixel varies with components */
1949 /* Compare jp2_read_bpcc(jp2_struct) */
1950 for (i = 0; i < (int)jp2_struct->numcomps; i++) {
1952 fprintf(xmlout," <AsHex>0x%02x</AsHex>\n", jp2_struct->comps[i].bpcc); /* 1 byte */
1954 fprintf(xmlout," <BitsPerPixel>%d</BitsPerPixel>\n", (jp2_struct->comps[i].bpcc & 0x7f)+1);
1955 fprintf(xmlout," <Signed>%d</Signed>\n", jp2_struct->comps[i].bpcc >> 7);
1958 fprintf(xmlout, " </BitsPerComponent>\n");
1961 /* Compare jp2_read_colr(jp2_struct) */
1962 fprintf(xmlout, " <ColourSpecification BoxType=\"colr\">\n");
1963 fprintf(xmlout, " <METH>%d</METH>\n", jp2_struct->meth); /* 1 byte */
1965 fprintf(xmlout, " <!-- Valid values of specification method so far: -->\n");
1966 fprintf(xmlout, " <!-- 1 = Enumerated colourspace, in EnumCS field -->\n");
1967 fprintf(xmlout, " <!-- 2 = Restricted ICC Profile, in PROFILE field -->\n");
1969 fprintf(xmlout, " <PREC>%d</PREC>\n", jp2_struct->precedence); /* 1 byte */
1971 fprintf(xmlout, " <!-- 0 is only valid value of precedence so far. -->\n");
1972 fprintf(xmlout, " <APPROX>%d</APPROX>\n", jp2_struct->approx); /* 1 byte */
1974 fprintf(xmlout, " <!-- 0 is only valid value of colourspace approximation so far. -->\n");
1976 if (jp2_struct->meth == 1) {
1977 fprintf(xmlout, " <EnumCS>%d</EnumCS>\n", jp2_struct->enumcs); /* 4 bytes */
1979 fprintf(xmlout, " <!-- Valid values of enumerated MJ2 colourspace so far: -->\n");
1980 fprintf(xmlout, " <!-- 16: sRGB as defined by IEC 61966-2-1. -->\n");
1981 fprintf(xmlout, " <!-- 17: greyscale (related to sRGB). -->\n");
1982 fprintf(xmlout, " <!-- 18: sRGB YCC (from JPEG 2000 Part II). -->\n");
1983 fprintf(xmlout, " <!-- (Additional JPX values are defined in Part II). -->\n");
1988 fprintf(xmlout, " <!-- PROFILE is not handled by current OpenJPEG implementation. -->\n");
1989 /* only 1 byte is read and nothing stored */
1990 fprintf(xmlout, " </ColourSpecification>\n");
1992 /* TO DO? No OpenJPEG support.
1994 ComponentMapping 'cmap'
1995 ChannelDefinition 'cdef'
1998 fprintf(xmlout, " </JP2Header>\n");
2003 IMAGE these use cp structure, extended... but we could use a new data structure instead
2004 void xml_out_frame_jp2i(FILE* xmlout, j2k_cp_t *cp) {
2005 /* IntellectualProperty 'jp2i' (no restrictions on location) */
2007 IMAGE cp->jp2i, cp->jp2i_count, cp->jp2i_data (array of chars), cp->cp2i_len (array of ints)
2009 return; /* Not present */
2011 for(i = 0; i < cp->jp2i_count; i++)
2013 fprintf(xmlout, " <IntellectualProperty BoxType=\"jp2i\">\n");
2014 /* I think this can be anything, including binary, so do a dump */
2015 /* Is it better to indent or not indent this content? Indent is better for reading, but
2016 worse for cut/paste. */
2017 xml_out_dump_hex_and_ascii(xmlout, cp->jp2i_data[i], cp->jp2i_len[i]);
2018 fprintf(xmlout, " </IntellectualProperty>\n");
2022 void xml_out_frame_xml(FILE* xmlout, j2k_cp_t *cp) {
2023 /* XML 'xml\040' (0x786d6c20). Can appear multiply, before or after jp2c codestreams */
2024 IMAGE cp->xml, cp->xml_count, cp->xml_data (array of chars)
2025 MAYBE WE DON'T NEED cp->xml_len (array of ints) IF WE ASSUME xml_data IS NULL-TERMINATED.
2026 ASSUME ASSUME EACH LINE IS ENDED BY \n.
2029 return; /* Not present */
2031 for(i = 0; i < cp->xml_count; i++)
2033 fprintf(xmlout, " <VendorSpecificXML BoxType=\"xml[space]" Instance=\"%d\">\n", i+1);
2034 /* Is it better to indent or not indent this content? Indent is better for reading, but
2035 worse for cut/paste. Being lazy, didn't indent here. */
2036 fprintf(xmlout,cp->xml_data[i]); /* May be multiple lines */ /* Could check if this is well-formed */
2037 fprintf(xmlout, " </VendorSpecificXML>\n");
2041 void xml_out_frame_uuid(FILE* xmlout, j2k_cp_t *cp) {
2042 /* UUID 'uuid' (top level only) */
2043 /* Part I 1.7.2 says: may appear multiply in JP2 file, anywhere except before File Type box */
2044 /* Part III 5.2.1 says: Private extensions shall be achieved through the 'uuid' type. */
2045 /* A UUID is a 16-byte value. There is a conventional string representation for it:
2046 "0x12345678-9ABC-DEF0-1234-567890ABCDEF". Let's assume that is what is stored in uuid_value */
2048 /* Part III 6.1 Any other MJ2 box type could be alternatively written as a 'uuid' box, with value given
2049 as : 0xXXXXXXXX-0011-0010-8000-00AA00389B71, where the Xs are the boxtype in hex. However,
2050 such a file is "not compliant; systems may choose to read [such] objects ... as equivalent to the box of
2051 the same type, or not." Here, we choose not to. */
2053 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)
2055 return; /* Not present */
2057 for(i = 0; i < cp->uuid_count; i++)
2059 fprintf(xmlout, " <VendorSpecific BoxType=\"uuid\">
2060 fprintf(xmlout, " <UUID>%s</UUDI>\n", cp->uuid_value[i]);
2061 fprintf(xmlout, " <Data>\n");
2062 /* I think this can be anything, including binary, so do a dump */
2063 /* Is it better to indent or not indent this content? Indent is better for reading, but
2064 worse for cut/paste. */
2065 xml_out_dump_hex_and_ascii(xmlout, cp->uuid_data[i], cp->uuid_len[i]);
2066 fprintf(xmlout, " </Data>\n");
2067 fprintf(xmlout, " </IntellectualProperty>\n");
2071 void xml_out_frame_uinf(FILE* xmlout, j2k_cp_t *cp) {
2072 /* UUIDInfo 'uinf', includes UUIDList 'ulst' and URL 'url\40' */
2073 /* Part I 1.7.3 says: may appear multiply in JP2 file, anywhere at the top level except before File Type box */
2074 /* So there may be multiple ulst's, and each can have multiple UUIDs listed (with a single URL) */
2075 /* This is not quite as vendor-specific as UUIDs, or at least is meant to be generally readable */
2076 /* Assume UUIDs stored in canonical string format */
2078 IMAGE cp->uinf, cp->uinf_count, cp->uinf_ulst_nu (array of ints)
2079 cp->uinf_uuid (2 dimensional array of uuids... let's say fixed-length strings),
2080 cp->uinf_url (array of char buffers)
2083 return; /* Not present */
2085 for(i = 0; i < cp->uuid_count; i++)
2087 fprintf(xmlout, " <UUIDInfo BoxType=\"uinf\">\n");
2088 fprintf(xmlout, " <UUIDList BoxType=\"ulst\" Count=\"%d\">\n",cp->cp->uinf_ulst_nu[i]);
2089 for(j = 0; j < cp->uinf_ulst_nu[i]; j++)
2090 fprintf(xmlout, " <ID Instance=\"%s\">%s</ID>\n", cp->uuif_uuid[i][j], j+1);
2091 fprintf(xmlout, " </UUIDList>\n");
2092 fprintf(xmlout, " <DataEntryURL>\n");
2093 /* Could add VERS and FLAG here */
2094 fprintf(xmlout, " <LOC>\n");
2095 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 */
2096 fprintf(xmlout, " </LOC>\n");
2097 fprintf(xmlout, " </DataEntryURL>\n");
2098 fprintf(xmlout, " </UUIDInfo>\n");
2102 IMAGE these use cp structure, extended... but we could use a new data structure instead
2103 void xml_out_frame_unknown_type(FILE* xmlout, j2k_cp_t *cp) {
2104 /* Part III 5.2.1 says "Type fields not defined here are reserved. Private extensions
2105 shall be acieved through the 'uuid' type." [This implies an unknown
2106 type would be an error, but then...] "Boxes not explicitly defined in this standard,
2107 or otherwise unrecognized by a reader, may be ignored."
2108 Also, it says "the following types are not and will not be used, or used only in
2109 their existing sense, in future versions of this specification, to avoid conflict
2110 with existing content using earlier pre-standard versions of this format:
2111 clip, crgn, matt, kmat, pnot, ctab, load, imap;
2112 track reference types tmcd, chap, sync,scpt, ssrc"
2113 [But good luck figuring out the mapping.]
2114 Part III Amend. 2 4.1 is stronger: "All these specifications [of this family, e.g.,
2115 JP2 Part I, ISO Base format (Part 12) leading to MP4, Quicktime, and possibly including
2116 MJ2] require that readers ignore objects that are unrecognizable to them".
2119 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)
2120 if(cp->unknown_type != 1)
2121 return; /* Not present */
2123 for(i = 0; i < cp->unknown_type_count; i++)
2125 fprintf(xmlout, " <UnknownType BoxType=\"%s\">\n", cp->unknown_type_boxtype[i]);
2126 /* Can be anything, including binary, so do a dump */
2127 /* Is it better to indent or not indent this content? Indent is better for reading, but
2128 worse for cut/paste. */
2129 xml_out_dump_hex_and_ascii(xmlout, cp->unknown_type_data[i], cp->unknown_type_len[i]);
2130 fprintf(xmlout, " </UnknownType>\n");