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.
15 #include <windows.h> /* for time functions */
17 #include "opj_includes.h"
23 static BOOL notes = TRUE;
24 static BOOL sampletables = FALSE;
25 static BOOL raw = TRUE;
26 static BOOL derived = TRUE;
28 opj_tcp_t *j2k_default_tcp;
31 int xml_write_overall_header(FILE *file, FILE *xmlout, opj_mj2_t * movie,
32 unsigned int sampleframe, opj_event_mgr_t *event_mgr);
33 int xml_write_moov(FILE *file, FILE *xmlout, opj_mj2_t * movie,
34 unsigned int sampleframe, opj_event_mgr_t *event_mgr);
36 void uint_to_chars(unsigned int value, char* buf);
38 void xml_write_trak(FILE* file, FILE* xmlout, mj2_tk_t *track,
39 unsigned int tnum, unsigned int sampleframe, opj_event_mgr_t *event_mgr);
40 void xml_write_tkhd(FILE* file, FILE* xmlout, mj2_tk_t *track,
42 void xml_write_udta(FILE* file, FILE* xmlout, mj2_tk_t *track,
44 void xml_write_mdia(FILE* file, FILE* xmlout, mj2_tk_t *track,
46 void xml_write_stbl(FILE* file, FILE* xmlout, mj2_tk_t *track,
49 void UnixTimeToFileTime(time_t t, LPFILETIME pft);
50 void UnixTimeToSystemTime(time_t t, LPSYSTEMTIME pst);
51 void xml_time_out(FILE* xmlout, time_t t);
53 void int16_to_3packedchars(short int value, char* buf);
55 void xml_write_moov_udta(FILE* xmlout, opj_mj2_t * movie);
56 void xml_write_free_and_skip(FILE* xmlout, opj_mj2_t * movie);
57 void xml_write_uuid(FILE* xmlout, opj_mj2_t * movie);
59 int xml_out_frame(FILE* file, FILE* xmlout, mj2_sample_t *sample,
60 unsigned int snum, opj_event_mgr_t *event_mgr);
62 void xml_out_frame_siz(FILE* xmlout, opj_image_t *img, opj_cp_t *cp);
63 void xml_out_frame_cod(FILE* xmlout, opj_tcp_t *tcp);
64 void xml_out_frame_coc(FILE* xmlout, opj_tcp_t *tcp,
65 int numcomps); /* opj_image_t *img); */
66 BOOL same_component_style(opj_tccp_t *tccp1, opj_tccp_t *tccp2);
67 void xml_out_frame_qcd(FILE* xmlout, opj_tcp_t *tcp);
68 void xml_out_frame_qcc(FILE* xmlout, opj_tcp_t *tcp,
69 int numcomps); /* opj_image_t *img); */
70 BOOL same_component_quantization(opj_tccp_t *tccp1, opj_tccp_t *tccp2);
71 void xml_out_frame_rgn(FILE* xmlout, opj_tcp_t *tcp,
72 int numcomps);/* opj_image_t *img);*/
73 void xml_out_frame_poc(FILE* xmlout, opj_tcp_t *tcp);
74 void xml_out_frame_ppm(FILE* xmlout, opj_cp_t *cp);
75 void xml_out_frame_ppt(FILE* xmlout, opj_tcp_t *tcp);
76 void xml_out_frame_tlm(FILE*
77 xmlout); /* j2k_default_tcp is passed globally */ /* NO-OP. TLM NOT SAVED IN DATA STRUCTURE */
78 void xml_out_frame_plm(FILE*
79 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 */
80 void xml_out_frame_plt(FILE* xmlout,
81 opj_tcp_t *tcp); /* NO-OP. PLM NOT SAVED IN DATA STRUCTURE. opt in main; can be used in conjunction with PLT */
82 void xml_out_frame_crg(FILE*
83 xmlout); /* j2k_default_tcp is passed globally */ /* opt in main; */
84 void xml_out_frame_com(FILE* xmlout,
85 opj_tcp_t *tcp); /* NO-OP. COM NOT SAVED IN DATA STRUCTURE */ /* opt in main; */
86 void xml_out_dump_hex(FILE* xmlout, char *data, int data_len, char* s);
87 void xml_out_dump_hex_and_ascii(FILE* xmlout, char *data, int data_len,
89 void xml_out_frame_jp2h(FILE* xmlout, opj_jp2_t *jp2_struct);
91 /* Shown with cp, extended, as data structure... but it could be a new different one */
92 void xml_out_frame_jp2i(FILE* xmlout,
93 opj_cp_t *cp);/* IntellectualProperty 'jp2i' (no restrictions on location) */
94 void xml_out_frame_xml(FILE* xmlout,
95 opj_cp_t *cp); /* XML 'xml\040' (0x786d6c20). Can appear multiply */
96 void xml_out_frame_uuid(FILE* xmlout,
97 opj_cp_t *cp); /* UUID 'uuid' (top level only) */
98 void xml_out_frame_uinf(FILE* xmlout,
99 opj_cp_t *cp); /* UUIDInfo 'uinf', includes UUIDList 'ulst' and URL 'url\40' */
100 void xml_out_frame_unknown_type(FILE* xmlout, opj_cp_t *cp);
104 void xml_write_init(BOOL n, BOOL t, BOOL r, BOOL d)
106 /* Init file globals */
113 int xml_write_struct(FILE* file, FILE *xmlout, opj_mj2_t * movie,
114 unsigned int sampleframe, char* stringDTD, opj_event_mgr_t *event_mgr)
117 if (stringDTD != NULL) {
118 fprintf(xmlout, "<?xml version=\"1.0\" standalone=\"no\"?>\n");
119 /* stringDTD is known to start with "SYSTEM " or "PUBLIC " */
120 /* typical: SYSTEM mj2_to_metadata.dtd */
122 '\0'; /* Break into two strings at space, so quotes can be inserted. */
123 fprintf(xmlout, "<!DOCTYPE MJ2_File %s \"%s\">\n", stringDTD, stringDTD + 7);
124 stringDTD[6] = ' '; /* restore for sake of debugger or memory allocator */
126 fprintf(xmlout, "<?xml version=\"1.0\" standalone=\"yes\"?>\n");
129 fprintf(xmlout, "<MJ2_File>\n");
130 xml_write_overall_header(file, xmlout, movie, sampleframe, event_mgr);
131 fprintf(xmlout, "</MJ2_File>");
137 int xml_write_overall_header(FILE *file, FILE *xmlout, opj_mj2_t * movie,
138 unsigned int sampleframe, opj_event_mgr_t *event_mgr)
145 " <JP2 BoxType=\"jP[space][space]\" Signature=\"0x0d0a870a\" />\n");
146 // Called after structure initialized by mj2_read_ftyp
147 fprintf(xmlout, " <FileType BoxType=\"ftyp\">\n");
148 uint_to_chars(movie->brand, buf);
149 fprintf(xmlout, " <Brand>%s</Brand>\n",
150 buf); /* 4 character; BR */
151 fprintf(xmlout, " <MinorVersion>%u</MinorVersion>\n",
152 movie->minversion); /* 4 char; MinV */
153 fprintf(xmlout, " <CompatibilityList Count=\"%d\">\n", movie->num_cl);
154 for (i = movie->num_cl - 1; i > -1;
155 i--) { /* read routine stored in reverse order, so let's undo damage */
156 uint_to_chars(movie->cl[i], buf);
157 fprintf(xmlout, " <CompatibleBrand>%s</CompatibleBrand>\n",
158 buf); /*4 characters, each CLi */
160 fprintf(xmlout, " </CompatibilityList>\n");
161 fprintf(xmlout, " </FileType>\n");
162 xml_write_moov(file, xmlout, movie, sampleframe, event_mgr);
163 // To come? <mdat> // This is the container for media data that can also be accessed through track structures,
164 // so is redundant, and simply not of interest as metadata
165 // <moof> // Allows incremental build up of movie. Probably not in Simple Profile
166 xml_write_free_and_skip(xmlout,
167 movie); /* NO OP so far */ /* May be a place where user squirrels metadata */
168 xml_write_uuid(xmlout,
169 movie); /* NO OP so far */ /* May be a place where user squirrels metadata */
175 int xml_write_moov(FILE *file, FILE *xmlout, opj_mj2_t * movie,
176 unsigned int sampleframe, opj_event_mgr_t *event_mgr)
181 fprintf(xmlout, " <MovieBox BoxType=\"moov\">\n");
182 fprintf(xmlout, " <MovieHeader BoxType=\"mvhd\">\n");
183 fprintf(xmlout, " <CreationTime>\n");
185 fprintf(xmlout, " <InSeconds>%u</InSeconds>\n", movie->creation_time);
189 " <!-- Seconds since start of Jan. 1, 1904 UTC (Greenwich) -->\n");
191 /* 2082844800 = seconds between 1/1/04 and 1/1/70 */
192 /* There's still a time zone offset problem not solved... but spec is ambiguous as to whether stored time
193 should be local or UTC */
195 fprintf(xmlout, " <AsLocalTime>");
196 xml_time_out(xmlout, movie->creation_time - 2082844800);
197 fprintf(xmlout, "</AsLocalTime>\n");
199 fprintf(xmlout, " </CreationTime>\n");
200 fprintf(xmlout, " <ModificationTime>\n");
202 fprintf(xmlout, " <InSeconds>%u</InSeconds>\n",
203 movie->modification_time);
206 fprintf(xmlout, " <AsLocalTime>");
207 xml_time_out(xmlout, movie->modification_time - 2082844800);
208 fprintf(xmlout, "</AsLocalTime>\n");
210 fprintf(xmlout, " </ModificationTime>\n");
211 fprintf(xmlout, " <Timescale>%d</Timescale>\n", movie->timescale);
213 fprintf(xmlout, " <!-- Timescale defines time units in one second -->\n");
216 " <Rate>\n"); /* Rate to play presentation (default = 0x00010000) */
219 " <!-- Rate to play presentation is stored as fixed-point binary 16.16 value. Decimal value is approximation. -->\n");
221 " <!-- Rate is expressed relative to normal (default) value of 0x00010000 (1.0) -->\n");
224 fprintf(xmlout, " <AsHex>0x%08x</AsHex>\n", movie->rate);
227 fprintf(xmlout, " <AsDecimal>%12.6f</AsDecimal>\n",
228 (double)movie->rate / (double)0x00010000);
230 fprintf(xmlout, " </Rate>\n");
231 fprintf(xmlout, " <Duration>\n");
233 fprintf(xmlout, " <InTimeUnits>%u</InTimeUnits>\n", movie->duration);
236 fprintf(xmlout, " <InSeconds>%12.3f</InSeconds>\n",
237 (double)movie->duration / (double)
238 movie->timescale); // Make this double later to get fractional seconds
240 fprintf(xmlout, " </Duration>\n");
242 movie->volume = movie->volume << 8;
244 fprintf(xmlout, " <Volume>\n");
247 " <!-- Audio volume stored as fixed-point binary 8.8 value. Decimal value is approximation. -->\n");
249 " <!-- Full, normal (default) value is 0x0100 (1.0) -->\n");
252 fprintf(xmlout, " <AsHex>0x%04x</AsHex>\n", movie->volume);
255 fprintf(xmlout, " <AsDecimal>%6.3f</AsDecimal>\n",
256 (double)movie->volume / (double)0x0100);
258 fprintf(xmlout, " </Volume>\n");
262 " <!-- Current m2j_to_metadata implementation always shows bits to right of decimal as zeroed. -->\n");
264 movie->volume = movie->volume >> 8;
266 /* Transformation matrix for video */
267 fprintf(xmlout, " <TransformationMatrix>\n");
270 " <!-- 3 x 3 Video Transformation Matrix {a,b,u,c,d,v,x,y,w}. Required: u=0, v=0, w=1 -->\n");
272 " <!-- Maps decompressed point (p,q) to rendered point (ap + cq + x, bp + dq + y) -->\n");
274 " <!-- Stored as Fixed Point Hex: all are binary 16.16, except u,v,w are 2.30 -->\n");
276 " <!-- Unity = 0x00010000,0,0,0,0x00010000,0,0,0,0x40000000 -->\n");
278 fprintf(xmlout, " <TMa>0x%08x</TMa>\n", movie->trans_matrix[0]);
279 fprintf(xmlout, " <TMb>0x%08x</TMb>\n", movie->trans_matrix[1]);
280 fprintf(xmlout, " <TMu>0x%08x</TMu>\n", movie->trans_matrix[2]);
281 fprintf(xmlout, " <TMc>0x%08x</TMc>\n", movie->trans_matrix[3]);
282 fprintf(xmlout, " <TMd>0x%08x</TMd>\n", movie->trans_matrix[4]);
283 fprintf(xmlout, " <TMv>0x%08x</TMv>\n", movie->trans_matrix[5]);
284 fprintf(xmlout, " <TMx>0x%08x</TMx>\n", movie->trans_matrix[6]);
285 fprintf(xmlout, " <TMy>0x%08x</TMy>\n", movie->trans_matrix[7]);
286 fprintf(xmlout, " <TMw>0x%08x</TMw>\n", movie->trans_matrix[8]);
287 fprintf(xmlout, " </TransformationMatrix>\n");
288 fprintf(xmlout, " </MovieHeader>\n");
290 fprintf(xmlout, " <Statistics>\n");
291 fprintf(xmlout, " <TracksFound>\n");
292 fprintf(xmlout, " <Video>%d</Video>\n", movie->num_vtk);
293 fprintf(xmlout, " <Audio>%d</Audio>\n", movie->num_stk);
294 fprintf(xmlout, " <Hint>%d</Hint>\n", movie->num_htk);
297 " <!-- Hint tracks for streaming video are not part of MJ2, but are a defined extension. -->\n");
299 /* See Part 3 Amend 2 Section 4.2 for relation of MJ2 to Part 12 Sections 7 and 10 hints */
300 fprintf(xmlout, " </TracksFound>\n");
301 fprintf(xmlout, " </Statistics>\n");
302 /* Idea for the future: It would be possible to add code to verify that the file values:
303 1) are legal and self-consistent
304 2) comply with particular JP2 and/or MJ2 profiles.
305 This could be reported here as additional XML elements */
307 // Find first video track
309 while (movie->tk[tnum].track_type != 0) {
313 track = &(movie->tk[tnum]);
314 // For now, output info on first video track
315 xml_write_trak(file, xmlout, track, tnum, sampleframe, event_mgr);
317 // to come: <MovieExtends mvek> // possibly not in Simple Profile
318 xml_write_moov_udta(xmlout,
319 movie); /* NO OP so far */ /* <UserDataBox udta> contains <CopyrightBox cprt> */
320 fprintf(xmlout, " </MovieBox>\n");
324 /* --------------- */
326 void uint_to_chars(unsigned int value, char* buf)
328 /* buf is at least char[5] */
330 for (i = 3; i >= 0; i--) {
331 buf[i] = (value & 0x000000ff);
332 value = (value >> 8);
334 buf[4] = '\0'; /* Precautionary */
339 /* WINDOWS SPECIFIC */
341 void UnixTimeToFileTime(time_t t, LPFILETIME pft)
343 /* Windows specific. From MS Q167296 */
344 /* 'time_t' represents seconds since midnight January 1, 1970 UTC (coordinated universal time). */
345 /* 64-bit FILETIME structure represents the number of 100-nanosecond intervals since January 1, 1601 UTC (coordinate universal time). */
346 LONGLONG ll; /* LONGLONG is a 64-bit value. */
347 ll = Int32x32To64(t, 10000000) + 116444736000000000;
348 pft->dwLowDateTime = (DWORD)ll;
349 /* pft->dwLowDateTime = (DWORD)(0x00000000ffffffff & ll); */
350 pft->dwHighDateTime = (DWORD)(ll >> 32);
352 // Once the UNIX time is converted to a FILETIME structure,
353 // other Win32 time formats can be easily obtained by using Win32 functions such
354 // as FileTimeToSystemTime() and FileTimeToDosDateTime().
358 void UnixTimeToSystemTime(time_t t, LPSYSTEMTIME pst)
360 /* Windows specific */
362 UnixTimeToFileTime(t, &ft);
363 FileTimeToLocalFileTime(&ft, &ft); /* Adjust from UTC to local time zone */
364 FileTimeToSystemTime(&ft, pst);
369 void xml_time_out(FILE* xmlout, time_t t)
371 /* Windows specific */
373 char szLocalDate[255], szLocalTime[255];
374 UnixTimeToSystemTime(t, &st);
375 GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, szLocalDate, 255);
376 GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, szLocalTime, 255);
377 fprintf(xmlout, "%s %s", szLocalDate, szLocalTime);
380 /* END WINDOWS SPECIFIC */
384 void xml_write_moov_udta(FILE* xmlout, opj_mj2_t * movie)
386 /* Compare with xml_write_udta */
388 /* NO-OP so far. Optional UserData 'udta' (zero or one in moov or each trak)
389 can contain multiple Copyright 'cprt' with different language codes */
390 /* There may be nested non-standard boxes within udta */
391 IMAGINE movie->udta, movie->copyright_count,
392 movie->copyright_language[i](array of 16bit ints),
393 movie->copyright_notice[i](array of buffers)
394 PROBABLY ALSO NEED movie->udta_len or special handler for non - standard boxes
398 if (movie->udta != 1) {
399 return; /* Not present */
402 fprintf(xmlout, " <UserData BoxType=\"udta\">\n");
403 for (i = 0; i < movie->copyright_count; i++) {
404 fprintf(xmlout, " <Copyright BoxType=\"cprt\"> Instance=\"%d\">\n",
406 int16_to_3packedchars((short int)movie->copyright_languages[i], buf);
407 fprintf(xmlout, " <Language>%s</Language>\n", buf); /* 3 chars */
408 fprintf(xmlout, " <Notice>%s</Notice>\n", movie->copyright_notices[i]);
409 fprintf(xmlout, " </Copyright>\n", i + 1);
411 /* TO DO: Non-standard boxes */
412 fprintf(xmlout, " </UserData>\n");
416 void xml_write_free_and_skip(FILE* xmlout, opj_mj2_t * movie)
419 /* NO-OP so far. There can be zero or more instances of free and/or skip
420 at the top level of the file. This may be a place where the user squirrel's metadata.
421 Let's assume unstructured, and do a dump */
422 IMAGINE movie->free_and_skip, movie->free_and_skip_count,
423 movie->free_and_skip_content[i](array of buffers),
424 movie->free_and_skip_len[i](array of ints), movie->is_skip[i](array of BOOL)
427 if (movie->free_and_skip != 1) {
428 return; /* Not present */
431 for (i = 0; i < movie->free_and_skip_count; i++) {
432 if (movie->is_skip[i]) {
433 fprintf(xmlout, " <Skip BoxType=\"skip\">\n");
435 fprintf(xmlout, " <Free BoxType=\"free\">\n");
438 xml_out_dump_hex_and_ascii(xmlout, movie->free_and_skip_contents[i],
439 movie->free_and_skip_len[i]);
441 if (movie->is_skip[i]) {
442 fprintf(xmlout, " </Skip>\n");
444 fprintf(xmlout, " </Free>\n");
450 void xml_write_uuid(FILE* xmlout, opj_mj2_t * movie)
452 /* Universal Unique IDs of 16 bytes. */
454 /* NO-OP so far. There can be zero or more instances of private uuid boxes in a file.
455 This function supports the top level of the file, but uuid may be elsewhere [not yet supported].
456 This may be a place where the user squirrel's metadata. Let's assume unstructured, and do a dump */
457 IMAGINE movie->uuid, movie->uuid_count,
458 movie->uuid_content[i](array of buffers),
459 movie->uuid_len[i](array of ints),
460 movie->uuid_type[i](array of 17 - byte(16 + null termination) buffers)
463 if (movie->uuid != 1) {
464 return; /* Not present */
467 for (i = 0; i < movie->uuid_count; i++) {
468 fprintf(xmlout, " <PrivateExtension BoxType=\"uuid\" UUID=\"%s\">\n",
469 movie->uuid_type[i]);
470 // See Part III section 5.2.1, 6.1, 6.2
471 xml_out_dump_hex_and_ascii(xmlout, movie->uuid_contents[i], movie->uuid_len[i]);
472 fprintf(xmlout, " </PrivateExtension>\n");
479 void xml_write_trak(FILE* file, FILE* xmlout, mj2_tk_t *track,
480 unsigned int tnum, unsigned int sampleframe, opj_event_mgr_t *event_mgr)
482 fprintf(xmlout, " <Track BoxType=\"trak\" Instance=\"%d\">\n", tnum);
483 xml_write_tkhd(file, xmlout, track, tnum);
484 // TO DO: TrackReferenceContainer 'tref' just used in hint track
485 // TO DO: EditListContainer 'edts', contains EditList 'elst' with media-time, segment-duration, media-rate
486 xml_write_mdia(file, xmlout, track, tnum);
487 xml_write_udta(file, xmlout, track,
488 tnum); // NO-OP so far. Optional UserData 'udta', can contain multiple Copyright 'cprt'
490 if (track->track_type == 0) { /* Only do for visual track */
491 /* sampleframe is from user option -f. 1 = first frame */
492 /* sampleframe of 0 is a user requests: no jp2 header */
493 /* Treat out-of-bounds values in the same way */
494 if (sampleframe > 0 && sampleframe <= track->num_samples) {
495 mj2_sample_t *sample;
498 snum = sampleframe - 1;
499 // Someday maybe do a smart range scan... for (snum=0; snum < track->num_samples; snum++){
500 // fprintf(stdout,"Frame %d: ",snum+1);
501 sample = &track->sample[snum];
502 if (xml_out_frame(file, xmlout, sample, snum, event_mgr)) {
503 return; /* Not great error handling here */
507 fprintf(xmlout, " </Track>\n");
512 void xml_write_tkhd(FILE* file, FILE* xmlout, mj2_tk_t *track,
515 fprintf(xmlout, " <TrackHeader BoxType=\"tkhd\">\n");
518 " <!-- Not shown here: CreationTime, ModificationTime, Duration. -->\n");
520 " <!-- These 3 fields are reported under MediaHeader below. When reading these 3, -->\n");
522 " <!-- m2j_to_metadata currently doesn't distinguish between TrackHeader and MediaHeader source. -->\n");
524 " <!-- If both found, value read from MediaHeader is used. -->\n");
526 fprintf(xmlout, " <TrackID>%u</TrackID>\n", track->track_ID);
527 if (track->track_type == 0) { /* For visual track */
528 fprintf(xmlout, " <TrackLayer>%d</TrackLayer>\n", track->layer);
531 " <!-- front-to-back ordering of video tracks. 0 = normal, -1 is closer, etc. -->\n");
534 if (track->track_type != 0) { /* volume irrelevant for visual track */
536 track->volume = track->volume << 8;
538 fprintf(xmlout, " <Volume>\n");
541 " <!-- Track audio volume stored as fixed-point binary 8.8 value. Decimal value is approximation. -->\n");
543 " <!-- Full, normal (default) value is 0x0100 (1.0) -->\n");
546 fprintf(xmlout, " <AsHex>0x%04x</AsHex>\n", track->volume);
549 fprintf(xmlout, " <AsDecimal>%6.3f</AsDecimal>\n",
550 (double)track->volume / (double)0x0100);
552 fprintf(xmlout, " </Volume>\n");
556 " <!-- Current m2j_to_metadata implementation always shows bits to right of decimal as zeroed. -->\n");
558 track->volume = track->volume >> 8;
561 if (track->track_type == 0) {
562 /* Transformation matrix for video */
563 fprintf(xmlout, " <TransformationMatrix>\n");
566 " <!-- Comments about matrix in MovieHeader apply here as well. -->\n");
568 " <!-- This matrix is applied before MovieHeader one. -->\n");
570 fprintf(xmlout, " <TMa>0x%08x</TMa>\n", track->trans_matrix[0]);
571 fprintf(xmlout, " <TMb>0x%08x</TMb>\n", track->trans_matrix[1]);
572 fprintf(xmlout, " <TMu>0x%08x</TMu>\n", track->trans_matrix[2]);
573 fprintf(xmlout, " <TMc>0x%08x</TMc>\n", track->trans_matrix[3]);
574 fprintf(xmlout, " <TMd>0x%08x</TMd>\n", track->trans_matrix[4]);
575 fprintf(xmlout, " <TMv>0x%08x</TMv>\n", track->trans_matrix[5]);
576 fprintf(xmlout, " <TMx>0x%08x</TMx>\n", track->trans_matrix[6]);
577 fprintf(xmlout, " <TMy>0x%08x</TMy>\n", track->trans_matrix[7]);
578 fprintf(xmlout, " <TMw>0x%08x</TMw>\n", track->trans_matrix[8]);
579 fprintf(xmlout, " </TransformationMatrix>\n");
582 track->w = track->w << 16;
583 track->h = track->h << 16;
587 " <!-- Width and Height in pixels are for the presentation; frames will be scaled to this. -->\n");
589 " <!-- Both stored as fixed-point binary 16.16 values. Decimal values are approximations. -->\n");
591 fprintf(xmlout, " <Width>\n");
593 fprintf(xmlout, " <AsHex>0x%08x</AsHex>\n", track->w);
596 fprintf(xmlout, " <AsDecimal>%12.6f</AsDecimal>\n",
597 (double)track->w / (double)
598 0x00010000); /* Rate to play presentation (default = 0x00010000) */
600 fprintf(xmlout, " </Width>\n");
601 fprintf(xmlout, " <Height>\n");
603 fprintf(xmlout, " <AsHex>0x%08x</AsHex>\n", track->h);
606 fprintf(xmlout, " <AsDecimal>%12.6f</AsDecimal>\n",
607 (double)track->h / (double)
608 0x00010000); /* Rate to play presentation (default = 0x00010000) */
610 fprintf(xmlout, " </Height>\n");
614 " <!-- Current m2j_to_metadata implementation always shows bits to right of decimal as zeroed. -->\n");
616 " <!-- Also, width and height values shown here will actually be those read from track's <VisualSampleEntry> if given. -->\n");
618 track->w = track->w >> 16;
619 track->h = track->h >> 16;
621 fprintf(xmlout, " </TrackHeader>\n");
626 void xml_write_udta(FILE* file, FILE* xmlout, mj2_tk_t *track,
629 /* NO-OP so far. Optional UserData 'udta' (zero or one in moov or each trak)
630 can contain multiple Copyright 'cprt' with different language codes */
631 /* There may be nested non-standard boxes within udta */
633 IMAGINE track->udta, track->copyright_count,
634 track->copyright_language[i](array of 16bit ints),
635 track->copyright_notice[i](array of buffers)
636 PROBABLY ALSO NEED track->udta_len or special handler for non - standard boxes
640 if (track->udta != 1) {
641 return; /* Not present */
644 fprintf(xmlout, " <UserData BoxType=\"udta\">\n");
645 for (i = 0; i < track->copyright_count; i++) {
646 fprintf(xmlout, " <Copyright BoxType=\"cprt\"> Instance=\"%d\">\n",
648 int16_to_3packedchars((short int)track->copyright_languages[i], buf);
649 fprintf(xmlout, " <Language>%s</Language>\n", buf); /* 3 chars */
650 fprintf(xmlout, " <Notice>%s</Notice>\n",
651 track->copyright_notices[i]);
652 fprintf(xmlout, " </Copyright>\n", i + 1);
654 /* TO DO: Non-standard boxes */
655 fprintf(xmlout, " </UserData>\n");
661 void xml_write_mdia(FILE* file, FILE* xmlout, mj2_tk_t *track,
668 fprintf(xmlout, " <Media BoxType=\"mdia\">\n");
669 fprintf(xmlout, " <MediaHeader BoxType=\"mdhd\">\n");
670 fprintf(xmlout, " <CreationTime>\n");
672 fprintf(xmlout, " <InSeconds>%u</InSeconds>\n",
673 track->creation_time);
677 " <!-- Seconds since start of Jan. 1, 1904 UTC (Greenwich) -->\n");
679 /* 2082844800 = seconds between 1/1/04 and 1/1/70 */
680 /* There's still a time zone offset problem not solved... but spec is ambiguous as to whether stored time
681 should be local or UTC */
683 fprintf(xmlout, " <AsLocalTime>");
684 xml_time_out(xmlout, track->creation_time - 2082844800);
685 fprintf(xmlout, "</AsLocalTime>\n");
687 fprintf(xmlout, " </CreationTime>\n");
688 fprintf(xmlout, " <ModificationTime>\n");
690 fprintf(xmlout, " <InSeconds>%u</InSeconds>\n",
691 track->modification_time);
694 fprintf(xmlout, " <AsLocalTime>");
695 xml_time_out(xmlout, track->modification_time - 2082844800);
696 fprintf(xmlout, "</AsLocalTime>\n");
698 fprintf(xmlout, " </ModificationTime>\n");
699 fprintf(xmlout, " <Timescale>%d</Timescale>\n", track->timescale);
702 " <!-- Timescale defines time units in one second -->\n");
704 fprintf(xmlout, " <Duration>\n");
706 fprintf(xmlout, " <InTimeUnits>%u</InTimeUnits>\n",
710 fprintf(xmlout, " <InSeconds>%12.3f</InSeconds>\n",
711 (double)track->duration / (double)
712 track->timescale); // Make this double later to get fractional seconds
714 fprintf(xmlout, " </Duration>\n");
715 int16_to_3packedchars((short int)track->language, buf);
716 fprintf(xmlout, " <Language>%s</Language>\n", buf); /* 3 chars */
717 fprintf(xmlout, " </MediaHeader>\n");
718 fprintf(xmlout, " <HandlerReference BoxType=\"hdlr\">\n");
719 switch (track->track_type) {
722 " <HandlerType Code=\"vide\">video media track</HandlerType>\n");
725 fprintf(xmlout, " <HandlerType Code=\"soun\">Sound</HandlerType>\n");
728 fprintf(xmlout, " <HandlerType Code=\"hint\">Hint</HandlerType>\n");
733 " <!-- String value shown is not actually read from file. -->\n");
735 " <!-- Shown value is one used for our encode. -->\n");
737 fprintf(xmlout, " </HandlerReference>\n");
738 fprintf(xmlout, " <MediaInfoContainer BoxType=\"minf\">\n");
739 switch (track->track_type) {
741 fprintf(xmlout, " <VideoMediaHeader BoxType=\"vmhd\">\n");
742 fprintf(xmlout, " <GraphicsMode>0x%02x</GraphicsMode>\n",
743 track->graphicsmode);
745 fprintf(xmlout, " <!-- Enumerated values of graphics mode: -->\n");
746 fprintf(xmlout, " <!-- 0x00 = copy (over existing image); -->\n");
748 " <!-- 0x24 = transparent; 'blue-screen' this image using opcolor; -->\n");
750 " <!-- 0x100 = alpha; alpha-blend this image -->\n");
751 /* fprintf(xmlout," <!-- 0x101 = whitealpha; alpha-blend this image, which has been blended with white; -->\n"); This was evidently dropped upon amendment */
753 " <!-- 0x102 = pre-multiplied black alpha; image has been already been alpha-blended with black. -->\n");
755 " <!-- 0x110 = component alpha; blend alpha channel(s) and color channels individually. -->\n");
757 fprintf(xmlout, " <Opcolor>\n");
758 fprintf(xmlout, " <Red>0x%02x</Red>\n", track->opcolor[0]);
759 fprintf(xmlout, " <Green>0x%02x</Green>\n", track->opcolor[1]);
760 fprintf(xmlout, " <Blue>0x%02x</Blue>\n", track->opcolor[2]);
761 fprintf(xmlout, " </Opcolor>\n");
762 fprintf(xmlout, " </VideoMediaHeader>\n");
765 fprintf(xmlout, " <SoundMediaHeader BoxType=\"smhd\">\n");
767 track->balance = track->balance << 8;
769 fprintf(xmlout, " <Balance>\n");
772 " <!-- Track audio balance fixes mono track in stereo space. -->\n");
774 " <!-- Stored as fixed-point binary 8.8 value. Decimal value is approximation. -->\n");
776 " <!-- 0.0 = center, -1.0 = full left, 1.0 = full right -->\n");
779 fprintf(xmlout, " <AsHex>0x%04x</AsHex>\n", track->balance);
782 fprintf(xmlout, " <AsDecimal>%6.3f</AsDecimal>\n",
783 (double)track->balance / (double)0x0100);
785 fprintf(xmlout, " </Balance>\n");
789 " <!-- Current m2j_to_metadata implementation always shows bits to right of decimal as zeroed. -->\n");
791 track->balance = track->balance >> 8;
793 fprintf(xmlout, " </SoundMediaHeader>\n");
796 fprintf(xmlout, " <HintMediaHeader BoxType=\"hmhd\">\n");
797 fprintf(xmlout, " <MaxPDU_Size>%d</MaxPDU_Size>\n",
801 " <!-- Size in bytes of largest PDU in this hint stream. -->\n");
803 fprintf(xmlout, " <AvgPDU_Size>%d</AvgPDU_Size>\n",
807 " <!-- Average size in bytes of a PDU over the entire presentation. -->\n");
809 fprintf(xmlout, " <MaxBitRate>%d</MaxBitRate>\n",
813 " <!-- Maximum rate in bits per second over any window of 1 second. -->\n");
815 fprintf(xmlout, " <AvgBitRate>%d</AvgBitRate>\n",
819 " <!-- Averate rate in bits per second over the entire presentation. -->\n");
821 fprintf(xmlout, " <SlidingAvgBit>%d</SlidingAvgBitRate>\n",
822 track->slidingavgbitrate);
825 " <!-- Maximum rate in bits per second over any window of one minute. -->\n");
827 fprintf(xmlout, " </HintMediaHeader>\n");
830 fprintf(xmlout, " <DataInfo BoxType=\"dinf\">\n");
832 " <DataReference BoxType=\"dref\" URL_Count=\"%d\" URN_Count=\"%d\">\n",
833 track->num_url, track->num_urn); // table w. flags, URLs, URNs
834 // Data structure does not distinguish between single URL, single URN, or DREF table or URLs & URNs.
835 // We could infer those, but for now just present everything as a DREF table.
838 " <!-- No entries here mean that file is self-contained, as required by Simple Profile. -->\n");
840 for (k = 0; k < track->num_url; k++) {
842 " <DataEntryUrlBox BoxType=\"url[space]\">\n"); // table w. flags, URLs, URNs
845 " <!-- Only the first 16 bytes of URL location are recorded in mj2_to_metadata data structure. -->\n");
847 for (i = 0; i < 4; i++) {
848 uint_to_chars(track->url[track->num_url].location[i], buf);
849 fprintf(xmlout, " <Location>%s</Location>\n");
852 " </DataEntryUrlBox>\n"); // table w. flags, URLs, URNs
854 for (k = 0; k < track->num_urn; k++) {
856 " <DataEntryUrnBox BoxType=\"urn[space]\">\n"); // table w. flags, URLs, URNs
857 // Only the first 16 bytes are recorded in the data structure currently.
860 " <!-- Only the first 16 bytes each of URN name and optional location are recorded in mj2_to_metadata data structure. -->\n");
862 fprintf(xmlout, " <Name>");
863 for (i = 0; i < 4; i++) {
864 uint_to_chars(track->urn[track->num_urn].name[i], buf);
865 fprintf(xmlout, "%s", buf);
867 fprintf(xmlout, "</Name>\n");
868 fprintf(xmlout, " <Location>");
869 for (i = 0; i < 4; i++) {
870 uint_to_chars(track->urn[track->num_urn].location[i], buf);
871 fprintf(xmlout, "%s");
873 fprintf(xmlout, "</Location>\n");
874 fprintf(xmlout, " </DataEntryUrnBox>\n");
876 fprintf(xmlout, " </DataReference>\n");
877 fprintf(xmlout, " </DataInfo>\n");
879 xml_write_stbl(file, xmlout, track, tnum); /* SampleTable */
881 fprintf(xmlout, " </MediaInfoContainer>\n");
882 fprintf(xmlout, " </Media>\n");
887 void xml_write_stbl(FILE* file, FILE* xmlout, mj2_tk_t *track,
890 char buf[5], buf33[33];
894 fprintf(xmlout, " <SampleTable BoxType=\"stbl\">\n");
897 " <!-- What follows are specific instances of generic SampleDescription BoxType=\"stsd\" -->\n");
899 switch (track->track_type) {
901 // There could be multiple instances of this, but "entry_count" is just a local at read-time.
902 // And it's used wrong, too, as count of just visual type, when it's really all 3 types.
903 // This is referred to as "smj2" within mj2.c
904 fprintf(xmlout, " <VisualSampleEntry BoxType=\"mjp2\">\n");
907 " <!-- If multiple instances of this box, only first is shown here. -->\n");
909 " <!-- Width and Height are in pixels. Unlike the Track Header, there is no fractional part. -->\n");
911 " <!-- In mj2_to_metadata implementation, the values are not represented separately from Track Header's values. -->\n");
913 /* No shifting required. If CURRENTSTRUCT gets changed, then may need to revisit treatment of these */
914 fprintf(xmlout, " <WidthAsInteger>%d</WidthAsInteger>\n",
916 fprintf(xmlout, " <HeightAsInteger>%d</HeightAsInteger>\n",
918 // Horizresolution and vertresolution don't require shifting, already stored right in CURRENTSTRUCT
921 " <!-- Resolutions are in pixels per inch, for the highest-resolution component (typically luminance). -->\n");
923 " <!-- Both stored as fixed-point binary 16.16 values. Decimal values are approximations. -->\n");
925 " <!-- Typical value for both resolutions is 0x00480000 (72.0) -->\n");
927 fprintf(xmlout, " <HorizontalRes>\n");
929 fprintf(xmlout, " <AsHex>0x%08x</AsHex>\n",
930 track->horizresolution);
933 fprintf(xmlout, " <AsDecimal>%12.6f</AsDecimal>\n",
934 (double)track->horizresolution / (double)
935 0x00010000); /* Rate to play presentation (default = 0x00010000) */
937 fprintf(xmlout, " </HorizontalRes>\n");
938 fprintf(xmlout, " <VerticalRes>\n");
940 fprintf(xmlout, " <AsHex>0x%08x</AsHex>\n",
941 track->vertresolution);
944 fprintf(xmlout, " <AsDecimal>%12.6f</AsDecimal>\n",
945 (double)track->vertresolution / (double)
946 0x00010000); /* Rate to play presentation (default = 0x00010000) */
948 fprintf(xmlout, " </VerticalRes>\n");
951 for (i = 0; i < 8; i++) {
952 uint_to_chars((unsigned int)track->compressorname[i], buf);
954 buf); /* This loads up (4 * 8) + 1 chars, but trailing ones are usually junk */
957 buf33[0]; /* First byte has string length in bytes. There may be garbage beyond it. */
958 buf33[len + 1] = '\0'; /* Suppress it */
959 fprintf(xmlout, " <CompressorName>%s</CompressorName>\n",
960 buf33 + 1); /* Start beyond first byte */
963 " <!-- Compressor name for debugging. Standard restricts max length to 31 bytes. -->\n");
965 " <!-- Usually blank or \"Motion JPEG2000\" -->\n");
967 fprintf(xmlout, " <Depth>0x%02x</Depth>\n", track->depth);
969 fprintf(xmlout, " <!-- Depth is: -->\n");
971 " <!-- 0x20: alpha channels present (color or grayscale) -->\n");
972 fprintf(xmlout, " <!-- 0x28: grayscale without alpha -->\n");
973 fprintf(xmlout, " <!-- 0x18: color without alpha -->\n");
976 xml_out_frame_jp2h(xmlout, &(track->jp2_struct)); /* JP2 Header */
978 /* Following subboxes are optional */
979 fprintf(xmlout, " <FieldCoding BoxType=\"fiel\">\n");
980 fprintf(xmlout, " <FieldCount>%d</FieldCount>\n",
981 (unsigned int)track->fieldcount); /* uchar as 1 byte uint */
983 fprintf(xmlout, " <!-- Must be either 1 or 2 -->\n");
985 fprintf(xmlout, " <FieldOrder>%d</FieldOrder>\n",
986 (unsigned int)track->fieldorder); /* uchar as 1 byte uint */
989 " <!-- When FieldCount=2, FieldOrder means: -->\n");
990 fprintf(xmlout, " <!-- 0: Field coding unknown -->\n");
992 " <!-- 1: Field with topmost line is stored first in sample; fields are in temporal order -->\n");
994 " <!-- 6: Field with topmost line is stored second in sample; fields are in temporal order -->\n");
996 " <!-- Defaults: FieldCount=1, FieldOrder=0 if FieldCoding box not present -->\n");
998 " <!-- Current implementation doesn't retain whether box was actually present. -->\n");
1000 fprintf(xmlout, " </FieldCoding>\n");
1003 " <MJP2_Profile BoxType=\"jp2p\" Count=\"%d\">\n", track->num_br);
1004 for (i = 0; i < track->num_br;
1005 i++) { /* read routine stored in reverse order, so let's undo damage */
1006 uint_to_chars(track->br[i], buf);
1007 fprintf(xmlout, " <CompatibleBrand>%s</CompatibleBrand>\n",
1008 buf); /*4 characters, each CLi */
1010 fprintf(xmlout, " </MJP2_Profile>\n");
1013 " <MJP2_Prefix BoxType=\"jp2x\" Count=\"%d\">\n", track->num_jp2x);
1014 for (i = 0; i < track->num_jp2x; i++) {
1015 // We'll probably need better formatting than this
1016 fprintf(xmlout, " <Data>0x%02x</Data>\n",
1017 track->jp2xdata[i]); /* Each entry is single byte */
1019 fprintf(xmlout, " </MJP2_Prefix>\n");
1022 " <MJP2_SubSampling BoxType=\"jsub\">\n"); /* These values are all 1 byte */
1025 " <!-- Typical subsample value is 2 for 4:2:0 -->\n");
1027 fprintf(xmlout, " <HorizontalSub>%d</HorizontalSub>\n",
1029 fprintf(xmlout, " <VerticalSub>%d</VerticalSub>\n",
1031 fprintf(xmlout, " <HorizontalOffset>%d</HorizontalOffset>\n",
1033 fprintf(xmlout, " <VerticalOffset>%d</VerticalOffset>\n",
1037 " <!-- Typical {horizontal, vertical} chroma offset values: -->\n");
1039 " <!-- 4:2:2 format (CCIR601, H.262, MPEG2, MPEG4, recom. Exif): {0, 0} -->\n");
1041 " <!-- 4:2:2 format (JFIF): {1, 0} -->\n");
1043 " <!-- 4:2:0 format (H.262, MPEG2, MPEG4): {0, 1} -->\n");
1045 " <!-- 4:2:0 format (MPEG1, H.261, JFIF, recom. Exif): {1, 1} -->\n");
1048 " </MJP2_SubSampling>\n"); /* These values are all 1 byte */
1051 " <MJP2_OriginalFormat BoxType=\"orfo\">\n"); /* Part III Appx. 2 */
1053 " <OriginalFieldCount>%u</OriginalFieldCount>\n",
1054 (unsigned int)track->or_fieldcount); /* uchar as 1-byte uint */
1057 " <!-- In original material before encoding. Must be either 1 or 2 -->\n");
1060 " <OriginalFieldOrder>%u</OriginalFieldOrder>\n",
1061 (unsigned int)track->or_fieldorder); /* uchar as 1-byte uint */
1064 " <!-- When FieldCount=2, FieldOrder means: -->\n");
1065 fprintf(xmlout, " <!-- 0: Field coding unknown -->\n");
1067 " <!-- 11: Topmost line came from the earlier field; -->\n");
1069 " <!-- 16: Topmost line came form the later field. -->\n");
1071 " <!-- Defaults: FieldCount=1, FieldOrder=0 if FieldCoding box not present -->\n");
1073 " <!-- Current implementation doesn't retain whether box was actually present. -->\n");
1075 fprintf(xmlout, " </MJP2_OriginalFormat>\n");
1076 fprintf(xmlout, " </VisualSampleEntry>\n");
1082 " <!-- mj2_to_metadata's data structure doesn't record this currently. -->\n");
1086 fprintf(xmlout, " <TimeToSample BoxType=\"stts\">\n");
1087 fprintf(xmlout, " <SampleStatistics>\n");
1088 fprintf(xmlout, " <TotalSamples>%d</TotalSamples>\n",
1089 track->num_samples);
1092 " <!-- For video, gives the total frames in the track, by summing all entries in the Sample Table -->\n");
1094 fprintf(xmlout, " </SampleStatistics>\n");
1095 fprintf(xmlout, " <SampleEntries EntryCount=\"%d\">\n",
1097 for (i = 0; i < track->num_tts; i++) {
1099 " <Table Entry=\"%u\" SampleCount=\"%d\" SampleDelta=\"%u\" />\n",
1100 i + 1, track->tts[i].sample_count, track->tts[i].sample_delta);
1102 fprintf(xmlout, " </SampleEntries>\n");
1103 fprintf(xmlout, " </TimeToSample>\n");
1106 " <SampleToChunk BoxType=\"stsc\" Count=\"%d\">\n",
1107 track->num_samplestochunk);
1108 for (i = 0; i < track->num_samplestochunk; i++) {
1109 fprintf(xmlout, " <FirstChunk>%u</FirstChunk>\n",
1110 track->sampletochunk[i].first_chunk); /* 4 bytes */
1111 fprintf(xmlout, " <SamplesPerChunk>%u</SamplesPerChunk>\n",
1112 track->sampletochunk[i].samples_per_chunk); /* 4 bytes */
1113 fprintf(xmlout, " <SampleDescrIndex>%u</SampleDescrIndex>\n",
1114 track->sampletochunk[i].sample_descr_idx); /* 4 bytes */
1116 fprintf(xmlout, " </SampleToChunk>\n");
1117 // After reading this info in, track->num_chunks is calculated and a decompressed table established internally.
1119 fprintf(xmlout, " <SampleSize BoxType=\"stsz\">\n");
1120 if (track->same_sample_size) {
1121 // all values in track->sample[i].sample_size are equal. Grab the first one.
1122 fprintf(xmlout, " <Sample_Size>%u</Sample_Size>\n",
1123 track->sample[0].sample_size);
1126 " <!-- Non-zero value means all samples have that size. -->\n");
1128 " <!-- So <Sample_Count> (aka Entry_Count in std.) has no meaning, is suppressed from this output, and no table follows. -->\n");
1131 fprintf(xmlout, " <Sample_Size>0</Sample_Size>\n");
1135 " <!-- Zero value means samples have different sizes, given in table next of length Sample_Count (aka Entry_Count in std). -->\n");
1138 " <!-- Zero value means samples have different sizes, given in table (not shown) of length Sample_Count (aka Entry_Count in std). -->\n");
1140 fprintf(xmlout, " <Sample_Count>%u</Sample_Count>\n",
1141 track->num_samples);
1143 for (i = 0; i < (int)track->num_samples; i++) {
1144 fprintf(xmlout, " <EntrySize Num=\"%u\">%u</EntrySize>\n", i + 1,
1145 track->sample[i].sample_size);
1148 fprintf(xmlout, " </SampleSize>\n");
1150 fprintf(xmlout, " <ChunkOffset BoxType=\"stco\">\n");
1151 // Structure not yet - Variant ChunkLargeOffset 'co64'
1152 fprintf(xmlout, " <EntryCount>%u</EntryCount>\n",
1156 " <!-- For this implementation, EntryCount shown is one calculated during file read of <SampleToChunk> data. -->\n");
1158 " <!-- Implementation will report failure during file read of <ChunkOffset> data if read entry-count disagrees. -->\n");
1161 for (i = 0; i < (int)track->num_chunks; i++) {
1162 fprintf(xmlout, " <Chunk_Offset Num=\"%d\">%u</Chunk_Offset>\n",
1163 i + 1, track->chunk[i].offset);
1165 fprintf(xmlout, " </ChunkOffset>\n");
1167 fprintf(xmlout, " </SampleTable>\n");
1172 int xml_out_frame(FILE* file, FILE* xmlout, mj2_sample_t *sample,
1173 unsigned int snum, opj_event_mgr_t *event_mgr)
1175 opj_dparameters_t parameters; /* decompression parameters */
1180 unsigned char* frame_codestream;
1181 opj_dinfo_t* dinfo = NULL; /* handle to a decompressor */
1182 opj_cio_t *cio = NULL;
1185 /* JPEG 2000 compressed image data */
1187 /* get a decoder handle */
1188 dinfo = opj_create_decompress(CODEC_J2K);
1190 /* catch events using our callbacks and give a local context */
1191 opj_set_event_mgr((opj_common_ptr)dinfo, event_mgr, stderr);
1193 /* setup the decoder decoding parameters using the current image and user parameters */
1194 parameters.cp_limit_decoding = DECODE_ALL_BUT_PACKETS;
1195 opj_setup_decoder(dinfo, ¶meters);
1197 frame_codestream = (unsigned char*) malloc(sample->sample_size -
1198 8); /* Skipping JP2C marker */
1199 if (frame_codestream == NULL) {
1203 fseek(file, sample->offset + 8, SEEK_SET);
1204 fread(frame_codestream, sample->sample_size - 8, 1,
1205 file); /* Assuming that jp and ftyp markers size do */
1207 /* open a byte stream */
1208 cio = opj_cio_open((opj_common_ptr)dinfo, frame_codestream,
1209 sample->sample_size - 8);
1211 /* Decode J2K to image: */
1212 img = opj_decode(dinfo, cio);
1214 fprintf(stderr, "ERROR -> j2k_to_image: failed to decode image!\n");
1215 opj_destroy_decompress(dinfo);
1220 j2k = (opj_j2k_t*)dinfo->j2k_handle;
1221 j2k_default_tcp = j2k->default_tcp;
1224 numcomps = img->numcomps;
1225 /* Alignments: " < To help maintain xml pretty-printing */
1226 fprintf(xmlout, " <JP2_Frame Num=\"%d\">\n", snum + 1);
1227 fprintf(xmlout, " <MainHeader>\n");
1228 /* There can be multiple codestreams; a particular image is entirely within a single codestream */
1229 /* TO DO: A frame can be represented by two I-guess-contiguous codestreams if its interleaved. */
1230 fprintf(xmlout, " <StartOfCodestream Marker=\"SOC\" />\n");
1231 /* "cp" stands for "coding parameter"; "tcp" is tile coding parameters, "tccp" is tile-component coding parameters */
1232 xml_out_frame_siz(xmlout, img, cp); /* reqd in main */
1233 xml_out_frame_cod(xmlout, j2k_default_tcp); /* reqd in main */
1234 xml_out_frame_coc(xmlout, j2k_default_tcp,
1235 numcomps); /* opt in main, at most 1 per component */
1236 xml_out_frame_qcd(xmlout, j2k_default_tcp); /* reqd in main */
1237 xml_out_frame_qcc(xmlout, j2k_default_tcp,
1238 numcomps); /* opt in main, at most 1 per component */
1239 xml_out_frame_rgn(xmlout, j2k_default_tcp,
1240 numcomps); /* opt, at most 1 per component */
1241 xml_out_frame_poc(xmlout,
1242 j2k_default_tcp); /* opt (but reqd in main or tile for any progression order changes) */
1243 /* Next four get j2k_default_tcp passed globally: */
1244 #ifdef SUPPRESS_FOR_NOW
1245 xml_out_frame_ppm(xmlout,
1246 cp); /* opt (but either PPM or PPT [distributed in tile headers] or codestream packet header reqd) */
1249 xmlout); /* NO-OP. TLM NOT SAVED IN DATA STRUCTURE */ /* opt */
1251 xmlout); /* NO-OP. PLM NOT SAVED IN DATA STRUCTURE */ /* opt in main; can be used in conjunction with PLT */
1253 xmlout); /* NO-OP. CRG NOT SAVED IN DATA STRUCTURE */ /* opt in main; */
1254 xml_out_frame_com(xmlout,
1255 j2k_default_tcp); /* NO-OP. COM NOT SAVED IN DATA STRUCTURE */ /* opt in main; */
1257 fprintf(xmlout, " </MainHeader>\n");
1259 /* TO DO: all the tile headers (sigh) */
1260 fprintf(xmlout, " <TilePartHeaders Count=\"%d\">\n",
1261 cp->tileno_size); /* size of the vector tileno */
1262 for (i = 0; i < cp->tileno_size;
1263 i++) { /* I think cp->tileno_size will be same number as (cp->tw * cp->th) or as global j2k_curtileno */
1264 // Standard seems to use zero-based # for tile-part.
1265 fprintf(xmlout, " <TilePartHeader Num=\"%d\" ID=\"%d\">\n", i,
1266 cp->tileno[i]); /* ID number of the tiles present in the codestream */
1267 fprintf(xmlout, " <StartOfTilePart Marker=\"SOT\" />\n");
1268 /* All markers in tile-part headers (between SOT and SOD) are optional, unless structure requires. */
1270 xml_out_frame_cod(xmlout, &(cp->tcps[i])); /* No more than 1 per tile */
1271 xml_out_frame_coc(xmlout, &(cp->tcps[i]),
1272 numcomps); /* No more than 1 per component */
1273 xml_out_frame_qcd(xmlout, &(cp->tcps[i])); /* No more than 1 per tile */
1274 xml_out_frame_qcc(xmlout, &(cp->tcps[i]),
1275 numcomps); /* No more than 1 per component */
1276 xml_out_frame_rgn(xmlout, &(cp->tcps[i]),
1277 numcomps); /* No more than 1 per component */
1279 xml_out_frame_poc(xmlout,
1280 &(cp->tcps[i])); /* Reqd only if any progression order changes different from main POC */
1281 #ifdef SUPPRESS_FOR_NOW
1282 xml_out_frame_ppt(xmlout,
1283 &(cp->tcps[i])); /* Either PPT [distributed in tile headers] or PPM or codestream packet header reqd. */
1285 xml_out_frame_plt(xmlout,
1286 &(cp->tcps[i])); /* NO-OP. PLT NOT SAVED IN DATA STRUCTURE */ /* Can be used in conjunction with main's PLM */
1287 xml_out_frame_com(xmlout,
1288 &(cp->tcps[i])); /* NO-OP. COM NOT SAVED IN DATA STRUCTURE */
1289 /* opj_tcp_t * cp->tcps; "tile coding parameters" */
1290 /* Maybe not: fprintf(xmlout, " <>%d</>, cp->matrice[i]; */ /* Fixed layer */
1291 fprintf(xmlout, " <StartOfData Marker=\"SOD\" />\n");
1294 " <!-- Tile-part bitstream, not shown, follows tile-part header and SOD marker. -->\n");
1296 fprintf(xmlout, " </TilePartHeader>\n");
1299 " </TilePartHeaders>\n"); /* size of the vector tileno */
1302 IMAGINE the cp object has data to support the following... but we could use an
1303 new different data structure instead
1304 /* I'm unclear if the span of the original fread(frame_codestream...) included the following items if they're trailing. */
1305 /* ALSO TO DO, BUT DATA STRUCTURE DOESN'T HANDLE YET: boxes (anywhere in file except before the Filetype box): */
1306 xml_out_frame_jp2i(xmlout,
1307 &cp); /* IntellectualProperty 'jp2i' (no restrictions on location) */
1308 xml_out_frame_xml(xmlout,
1309 &cp); /* XML 'xml\040' (0x786d6c20). Can appear multiply */
1310 xml_out_frame_uuid(xmlout, &cp); /* UUID 'uuid' (top level only) */
1311 xml_out_frame_uinf(xmlout,
1312 &cp); /* UUIDInfo 'uinf', includes UUIDList 'ulst' and URL 'url\40' */
1315 fprintf(xmlout, " </JP2_Frame>\n");
1317 /* Extra commentary: */
1320 " <!-- Given the number and size of components, mj2_to_frame would try to convert this -->\n");
1321 if (((img->numcomps == 3) && (img->comps[0].dx == img->comps[1].dx / 2)
1322 && (img->comps[0].dx == img->comps[2].dx / 2) && (img->comps[0].dx == 1))
1323 || (img->numcomps == 1)) {
1324 fprintf(xmlout, " <!-- file to a YUV movie in the normal manner. -->\n");
1325 } else if ((img->numcomps == 3) &&
1326 (img->comps[0].dx == 1) && (img->comps[1].dx == 1) &&
1327 (img->comps[2].dx == 1)) {// If YUV 4:4:4 input --> to bmp
1328 fprintf(xmlout, " <!-- YUV 4:4:4 file to a series of .bmp files. -->\n");
1331 " <!-- file whose image component dimension are unknown, to a series of .j2k files. -->\n");
1335 opj_destroy_decompress(dinfo);
1337 free(frame_codestream);
1344 void int16_to_3packedchars(short int value, char* buf)
1346 /* This is to retrieve the 3-letter ASCII language code */
1347 /* Each char is packed into 5 bits, as difference from 0x60 */
1349 for (i = 2; i >= 0; i--) {
1350 buf[i] = (value & 0x001f) + 0x60;
1351 value = (value >> 5);
1358 void xml_out_frame_siz(FILE* xmlout, opj_image_t *img, opj_cp_t *cp)
1360 opj_image_comp_t *comp;
1363 fprintf(xmlout, " <ImageAndFileSize Marker=\"SIZ\">\n");
1364 // This is similar to j2k.c's j2k_dump_image.
1365 // Not of interest: Lsiz, Rsiz
1366 fprintf(xmlout, " <Xsiz>%d</Xsiz>\n", img->x1);
1367 fprintf(xmlout, " <Ysiz>%d</Ysiz>\n", img->y1);
1370 " <!-- Xsiz, Ysiz is the size of the reference grid. -->\n");
1372 fprintf(xmlout, " <XOsiz>%d</XOsiz>\n", img->x0);
1373 fprintf(xmlout, " <YOsiz>%d</YOsiz>\n", img->y0);
1376 " <!-- XOsiz, YOsiz are offsets from grid origin to image origin. -->\n");
1378 fprintf(xmlout, " <XTsiz>%d</XTsiz>\n", cp->tdx);
1379 fprintf(xmlout, " <YTsiz>%d</YTsiz>\n", cp->tdy);
1382 " <!-- XTsiz, YTsiz is the size of one tile with respect to the grid. -->\n");
1384 fprintf(xmlout, " <XTOsiz>%d</XTOsiz>\n", cp->tx0);
1385 fprintf(xmlout, " <YTOsiz>%d</YTOsiz>\n", cp->ty0);
1388 " <!-- XTOsiz, YTOsiz are offsets from grid origin to first tile origin. -->\n");
1390 fprintf(xmlout, " <Csiz>%d</Csiz>\n", img->numcomps);
1393 " <!-- Csiz is the number of components in the image. -->\n");
1394 fprintf(xmlout, " <!-- For image components next: -->\n");
1396 " <!-- XRsiz, YRsiz denote pixel-sample-spacing on the grid, per Part I Annex B. -->\n");
1397 //fprintf(xmlout," <!-- XO, YO is offset of the component compared to the whole image. -->\n");
1399 " <!-- Bits per pixel (bpp) is the pixel depth. -->\n");
1401 " <!-- WidthOfData and HeightOfData are calculated values, e.g.: w = roundup((Xsiz - XOsiz)/ XRsiz) -->\n");
1404 for (i = 0; i < img->numcomps; i++) {/* image-components */
1405 comp = &(img->comps[i]);
1406 fprintf(xmlout, " <Component Num=\"%d\">\n", i + 1);
1407 fprintf(xmlout, " <Ssiz>\n");
1409 fprintf(xmlout, " <AsHex>0x%02x</AsHex>\n",
1410 (comp->sgnd << 7) & (comp->prec - 1));
1413 fprintf(xmlout, " <Signed>%d</Signed>\n", comp->sgnd);
1414 fprintf(xmlout, " <PrecisionInBits>%d</PrecisionInBits>\n",
1417 fprintf(xmlout, " </Ssiz>\n");
1418 fprintf(xmlout, " <XRsiz>%d</XRsiz>\n", comp->dx);
1419 fprintf(xmlout, " <YRsiz>%d</YRsiz>\n", comp->dy);
1420 fprintf(xmlout, " <WidthOfData>%d</WidthOfData>\n", comp->w);
1421 fprintf(xmlout, " <HeightOfData>%d</HeightOfData>\n", comp->h);
1422 /* Rest of these aren't calculated when SIZ is read:
1423 fprintf(xmlout, " <XO>%d</XO>\n", comp->x0);
1424 fprintf(xmlout, " <YO>%d</YO>\n", comp->y0);
1426 fprintf(xmlout," <!-- XO, YO is offset of the component compared to the whole image. -->\n");
1427 fprintf(xmlout, " <BitsPerPixel>%d</BitsPerPixel>\n", comp->bpp);
1428 fprintf(xmlout, " <NumberOfDecodedResolution>%d</NumberOfDecodedResolution>\n", comp->resno_decoded); */
1429 // SUPPRESS: n/a to mj2_to_metadata. fprintf(xmlout," <Factor>%d</Factor\n", comp->factor);
1430 /* factor = number of division by 2 of the out image compare to the original size of image */
1431 // TO DO comp->data: int *data; /* image-component data */
1433 fprintf(xmlout, " </Component>\n");
1435 fprintf(xmlout, " </ImageAndFileSize>\n");
1440 void xml_out_frame_cod(FILE* xmlout, opj_tcp_t *tcp)
1442 /* Could be called with tcp = &j2k_default_tcp;
1443 /* Or, for tile-part header, with &j2k_cp->tcps[j2k_curtileno]
1444 /* Alignment for main:" < < < < To help maintain xml pretty-printing */
1445 /* Alignment for tile:" < < < To help maintain xml pretty-printing */
1448 char spaces[13] = " "; /* 12 spaces if tilepart*/
1450 if (tcp == j2k_default_tcp) {
1452 s++; /* shorten s to 10 spaces if main */
1454 tccp = &(tcp->tccps[0]);
1456 fprintf(xmlout, "%s<CodingStyleDefault Marker=\"COD\">\n",
1457 s); /* Required in main header */
1458 /* Not retained or of interest: Lcod */
1459 fprintf(xmlout, "%s <Scod>0x%02x</Scod>\n", s, tcp->csty); /* 1 byte */
1462 "%s <!-- For Scod, specific bits mean (where bit 0 is lowest or rightmost): -->\n",
1464 fprintf(xmlout, "%s <!-- bit 0: Defines entropy coder precincts -->\n", s);
1466 "%s <!-- 0 = (PPx=15, PPy=15); 1 = precincts defined below. -->\n", s);
1467 fprintf(xmlout, "%s <!-- bit 1: 1 = SOP marker may be used; 0 = not. -->\n",
1469 fprintf(xmlout, "%s <!-- bit 2: 1 = EPH marker may be used; 0 = not. -->\n",
1472 fprintf(xmlout, "%s <SGcod>\n", s);
1473 fprintf(xmlout, "%s <ProgressionOrder>%d</ProgressionOrder>\n", s,
1474 tcp->prg); /* 1 byte, SGcod (A) */
1476 fprintf(xmlout, "%s <!-- Defined Progression Order Values are: -->\n", s);
1478 "%s <!-- 0 = LRCP; 1 = RLCP; 2 = RPCL; 3 = PCRL; 4 = CPRL -->\n", s);
1480 "%s <!-- where L = \"layer\", R = \"resolution level\", C = \"component\", P = \"position\". -->\n",
1483 fprintf(xmlout, "%s <NumberOfLayers>%d</NumberOfLayers>\n", s,
1484 tcp->numlayers); /* 2 bytes, SGcod (B) */
1486 "%s <MultipleComponentTransformation>%d</MultipleComponentTransformation>\n",
1487 s, tcp->mct); /* 1 byte, SGcod (C). More or less boolean */
1490 "%s <!-- For MCT, 0 = none, 1 = transform first 3 components for efficiency, per Part I Annex G -->\n",
1493 fprintf(xmlout, "%s </SGcod>\n", s);
1494 /* This code will compile only if declaration of j2k_default_tcp is changed from static (to implicit extern) in j2k.c */
1495 fprintf(xmlout, "%s <SPcod>\n", s);
1496 /* Internal data structure tccp defines separate defaults for each component, but they all get the same values */
1497 /* So we only have to report the first component's values here. */
1498 /* Compare j2k_read_cox(...) */
1500 "%s <NumberOfDecompositionLevels>%d</NumberOfDecompositionLevels>\n", s,
1501 tccp->numresolutions - 1); /* 1 byte, SPcox (D) */
1502 fprintf(xmlout, "%s <CodeblockWidth>%d</CodeblockWidth>\n", s,
1503 tccp->cblkw - 2); /* 1 byte, SPcox (E) */
1504 fprintf(xmlout, "%s <CodeblockHeight>%d</CodeblockHeight>\n", s,
1505 tccp->cblkh - 2); /* 1 byte, SPcox (F) */
1508 "%s <!-- CBW and CBH are non-negative, and summed cannot exceed 8 -->\n", s);
1509 fprintf(xmlout, "%s <!-- Codeblock dimension is 2^(value + 2) -->\n", s);
1511 fprintf(xmlout, "%s <CodeblockStyle>0x%02x</CodeblockStyle>\n", s,
1512 tccp->cblksty); /* 1 byte, SPcox (G) */
1515 "%s <!-- For CodeblockStyle, bits mean (with value 1=feature on, 0=off): -->\n",
1518 "%s <!-- bit 0: Selective arithmetic coding bypass. -->\n", s);
1520 "%s <!-- bit 1: Reset context probabilities on coding pass boundaries. -->\n",
1522 fprintf(xmlout, "%s <!-- bit 2: Termination on each coding pass. -->\n",
1524 fprintf(xmlout, "%s <!-- bit 3: Vertically causal context. -->\n", s);
1525 fprintf(xmlout, "%s <!-- bit 4: Predictable termination. -->\n", s);
1526 fprintf(xmlout, "%s <!-- bit 5: Segmentation symbols are used. -->\n", s);
1528 fprintf(xmlout, "%s <Transformation>%d</Transformation>\n", s,
1529 tccp->qmfbid); /* 1 byte, SPcox (H) */
1532 "%s <!-- For Transformation, 0=\"9-7 irreversible filter\", 1=\"5-3 reversible filter\" -->\n",
1535 if (tccp->csty & J2K_CP_CSTY_PRT) {
1536 fprintf(xmlout, "%s <PrecinctSize>\n", s); /* 1 byte, SPcox (I_i) */
1539 "%s <!-- These are size exponents PPx and PPy. May be zero only for first level (aka N(L)LL subband)-->\n",
1542 for (i = 0; i < tccp->numresolutions; i++) {
1543 fprintf(xmlout, "%s <PrecinctHeightAndWidth ResolutionLevel=\"%d\">\n",
1546 fprintf(xmlout, "%s <AsHex>0x%02x</AsHex>\n", s,
1547 (tccp->prch[i] << 4) | tccp->prcw[i]); /* packed into 1 byte, SPcox (G) */
1550 fprintf(xmlout, "%s <WidthAsDecimal>%d</WidthAsDecimal>\n", s,
1552 fprintf(xmlout, "%s <HeightAsDecimal>%d</HeightAsDecimal>\n", s,
1555 fprintf(xmlout, "%s </PrecinctHeightAndWidth>\n", s, i);
1557 fprintf(xmlout, "%s </PrecinctSize>\n", s); /* 1 byte, SPcox (I_i) */
1559 fprintf(xmlout, "%s </SPcod>\n", s);
1560 fprintf(xmlout, "%s</CodingStyleDefault>\n", s);
1565 void xml_out_frame_coc(FILE* xmlout, opj_tcp_t *tcp,
1566 int numcomps) /* Optional in main & tile-part headers */
1568 /* Uses global j2k_default_tcp */
1569 opj_tccp_t *tccp, *firstcomp_tccp;
1571 char spaces[13] = " "; /* 12 spaces if tilepart*/
1573 if (tcp == j2k_default_tcp) {
1575 s++; /* shorten s to 10 spaces if main */
1578 firstcomp_tccp = &(tcp->tccps[0]);
1579 /* Internal data structure tccp defines separate defaults for each component, set from main */
1580 /* default, then selectively overwritten. */
1581 /* Compare j2k_read_cox(...) */
1582 /* We don't really know which was the default, and which were not */
1583 /* Let's pretend that [0] is the default and all others are not */
1586 "%s<!-- mj2_to_metadata implementation always reports component[0] as using default COD, -->\n",
1588 if (tcp == j2k_default_tcp) {
1590 "%s<!-- and any other component, with main-header style values different from [0], as COC. -->\n",
1594 "%s<!-- and any other component, with tile-part-header style values different from [0], as COC. -->\n",
1598 for (compno = 1; compno < numcomps;
1599 compno++) { /* spec says components are zero-based */
1600 tccp = &tcp->tccps[compno];
1601 if (same_component_style(firstcomp_tccp, tccp)) {
1605 /* Alignments: " < < < < < To help maintain xml pretty-printing */
1606 fprintf(xmlout, "%s<CodingStyleComponent Marker=\"COC\">\n",
1607 s); /* Optional in main header, at most 1 per component */
1610 "%s <!-- See Ccoc below for zero-based component number. -->\n", s);
1612 /* Overrides the main COD for the specific component */
1613 /* Not retained or of interest: Lcod */
1614 fprintf(xmlout, "%s <Scoc>0x%02x</Scoc>\n", s, tccp->csty); /* 1 byte */
1616 fprintf(xmlout, "%s <!-- Scoc defines entropy coder precincts: -->\n", s);
1618 "%s <!-- 0 = maximum, namely (PPx=15, PPy=15); 1 = precincts defined below. -->\n",
1621 fprintf(xmlout, "%s <Ccoc>%d</Ccoc>\n", s, compno); /* 1 or 2 bytes */
1622 /* Unfortunately compo isn't retained in j2k_read_coc: compno = cio_read(j2k_img->numcomps <= 256 ? 1 : 2); /* Ccoc */
1623 /*if(j2k_img_numcomps <=256)
1628 /* This code will compile only if declaration of j2k_default_tcp is changed from static (to implicit extern) in j2k.c */
1629 fprintf(xmlout, "%s <SPcoc>\n", s);
1631 "%s <NumberOfDecompositionLevels>%d</NumberOfDecompositionLevels>\n", s,
1632 tccp->numresolutions - 1); /* 1 byte, SPcox (D) */
1633 fprintf(xmlout, "%s <CodeblockWidth>%d</CodeblockWidth>\n", s,
1634 tccp->cblkw - 2); /* 1 byte, SPcox (E) */
1635 fprintf(xmlout, "%s <CodeblockHeight>%d</CodeblockHeight>\n", s,
1636 tccp->cblkh - 2); /* 1 byte, SPcox (F) */
1639 "%s <!-- CBW and CBH are non-negative, and summed cannot exceed 8 -->\n", s);
1640 fprintf(xmlout, "%s <!-- Codeblock dimension is 2^(value + 2) -->\n", s);
1642 fprintf(xmlout, "%s <CodeblockStyle>0x%02x</CodeblockStyle>\n", s,
1643 tccp->cblksty); /* 1 byte, SPcox (G) */
1646 "%s <!-- For CodeblockStyle, bits mean (with value 1=feature on, 0=off): -->\n",
1649 "%s <!-- bit 0: Selective arithmetic coding bypass. -->\n", s);
1651 "%s <!-- bit 1: Reset context probabilities on coding pass boundaries. -->\n",
1653 fprintf(xmlout, "%s <!-- bit 2: Termination on each coding pass. -->\n",
1655 fprintf(xmlout, "%s <!-- bit 3: Vertically causal context. -->\n", s);
1656 fprintf(xmlout, "%s <!-- bit 4: Predictable termination. -->\n", s);
1657 fprintf(xmlout, "%s <!-- bit 5: Segmentation symbols are used. -->\n", s);
1659 fprintf(xmlout, "%s <Transformation>%d</Transformation>\n", s,
1660 tccp->qmfbid); /* 1 byte, SPcox (H) */
1663 "%s <!-- For Transformation, 0=\"9-7 irreversible filter\", 1=\"5-3 reversible filter\" -->\n",
1666 if (tccp->csty & J2K_CP_CSTY_PRT) {
1667 fprintf(xmlout, "%s <PrecinctSize>\n", s); /* 1 byte, SPcox (I_i) */
1670 "%s <!-- These are size exponents PPx and PPy. May be zero only for first level (aka N(L)LL subband)-->\n",
1673 for (i = 0; i < tccp->numresolutions - 1;
1674 i++) { /* subtract 1 to get # of decomposition levels */
1675 fprintf(xmlout, "%s <PrecinctHeightAndWidth ResolutionLevel=\"%d\">\n",
1678 fprintf(xmlout, "%s <AsHex>0x%02x</AsHex>\n", s,
1679 (tccp->prch[i] << 4) | tccp->prcw[i]); /* packed into 1 byte, SPcox (G) */
1682 fprintf(xmlout, "%s <WidthAsDecimal>%d</WidthAsDecimal>\n", s,
1684 fprintf(xmlout, "%s <HeightAsDecimal>%d</HeightAsDecimal>\n", s,
1687 fprintf(xmlout, "%s </PrecinctHeightAndWidth>\n", s, i);
1689 fprintf(xmlout, "%s </PrecinctSize>\n", s); /* 1 byte, SPcox (I_i) */
1691 fprintf(xmlout, "%s </SPcoc>\n", s);
1692 fprintf(xmlout, "%s</CodingStyleComponent>\n", s);
1698 BOOL same_component_style(opj_tccp_t *tccp1, opj_tccp_t *tccp2)
1702 if (tccp1->numresolutions != tccp2->numresolutions) {
1705 if (tccp1->cblkw != tccp2->cblkw) {
1708 if (tccp1->cblkh != tccp2->cblkh) {
1711 if (tccp1->cblksty != tccp2->cblksty) {
1714 if (tccp1->csty != tccp2->csty) {
1718 if (tccp1->csty & J2K_CP_CSTY_PRT) {
1719 for (i = 0; i < tccp1->numresolutions; i++) {
1720 if (tccp1->prcw[i] != tccp2->prcw[i] || tccp1->prch[i] != tccp2->prch[i]) {
1730 void xml_out_frame_qcd(FILE* xmlout, opj_tcp_t *tcp)
1732 /* This code will compile only if declaration of j2k_default_tcp is changed from static (to implicit extern) in j2k.c */
1734 int bandno, numbands;
1735 char spaces[13] = " "; /* 12 spaces if tilepart*/
1737 if (tcp == j2k_default_tcp) {
1739 s++; /* shorten s to 10 spaces if main */
1742 /* Compare j2k_read_qcx */
1743 fprintf(xmlout, "%s<QuantizationDefault Marker=\"QCD\">\n",
1744 s); /* Required in main header, single occurrence */
1745 tccp = &(tcp->tccps[0]);
1746 /* Not retained or of interest: Lqcd */
1747 fprintf(xmlout, "%s <Sqcd>\n", s); /* 1 byte */
1750 "%s <!-- Default quantization style for all components. -->\n", s);
1753 fprintf(xmlout, "%s <AsHex>0x%02x</AsHex>\n", s,
1754 (tccp->numgbits) << 5 | tccp->qntsty);
1757 fprintf(xmlout, "%s <QuantizationStyle>%d</QuantizationStyle>\n", s,
1762 "%s <!-- Quantization style (in Sqcd's low 5 bits) may be: -->\n", s);
1763 fprintf(xmlout, "%s <!-- 0 = No quantization. SPqcd size = 8 bits-->\n",
1766 "%s <!-- 1 = Scalar derived (values signaled for N(L)LL subband only). Use Eq. E.5. SPqcd size = 16. -->\n",
1769 "%s <!-- 2 = Scalar expounded (values signaled for each subband). SPqcd size = 16. -->\n",
1773 fprintf(xmlout, "%s <NumberOfGuardBits>%d</NumberOfGuardBits>\n", s,
1778 "%s <!-- 0-7 guard bits allowed (stored in Sqcd's high 3 bits) -->\n", s);
1780 fprintf(xmlout, "%s </Sqcd>\n", s);
1782 /* Problem: numbands in some cases is calculated from len, which is not retained or available here at this time */
1783 /* So we'll just dump all internal values */
1784 /* We could calculate it, but I'm having trouble believing the length equations in the standard */
1786 fprintf(xmlout, "%s <SPqcd>\n", s);
1787 switch (tccp->qntsty) {
1788 case J2K_CCP_QNTSTY_NOQNT: /* no quantization */
1789 /* This is what standard says, but I don't believe it: len = 4 + (3*decomp); */
1790 numbands = J2K_MAXBANDS; /* should be: numbands = len - 1; */
1791 /* Better: IMAGINE numbands = tccp->stepsize_numbands; */
1792 /* Instead look for first zero exponent, quit there. Adequate? */
1793 fprintf(xmlout, "%s <ReversibleStepSizeValue>\n", s);
1796 "%s <!-- Current mj2_to_metadata implementation dumps entire internal table, -->\n",
1799 "%s <!-- until an exponent with zero value is reached. -->\n", s);
1801 "%s <!-- Exponent epsilon(b) of reversible dynamic range. -->\n", s);
1803 "%s <!-- Hex value is as stored, in high-order 5 bits. -->\n", s);
1805 for (bandno = 0; bandno < numbands; bandno++) {
1806 if (tccp->stepsizes[bandno].expn == 0) {
1807 break; /* Remove when we have real numbands */
1809 fprintf(xmlout, "%s <DynamicRangeExponent Subband=\"%d\">\n", s, bandno);
1811 fprintf(xmlout, "%s <AsHex>0x%02x</AsHex>\n", s,
1812 tccp->stepsizes[bandno].expn << 3);
1815 fprintf(xmlout, "%s <AsDecimal>%d</AsDecimal>\n", s,
1816 tccp->stepsizes[bandno].expn);
1818 fprintf(xmlout, "%s </DynamicRangeExponent>\n", s);
1820 fprintf(xmlout, "%s </ReversibleStepSizeValue>\n", s);
1822 case J2K_CCP_QNTSTY_SIQNT: /* scalar quantization derived */
1823 /* This is what standard says. Should I believe it:: len = 5;
1825 fprintf(xmlout, "%s <QuantizationStepSizeValues>\n", s);
1828 "%s <!-- For irreversible transformation only. See Part I Annex E Equation E.3 -->\n",
1831 fprintf(xmlout, "%s <QuantizationValues Subband=\"0\">\n", s);
1833 fprintf(xmlout, "%s <!-- For N(L)LL subband: >\n", s);
1836 fprintf(xmlout, "%s <AsHex>0x%02x</AsHex>\n", s,
1837 (tccp->stepsizes[0].expn << 11) | tccp->stepsizes[0].mant);
1840 fprintf(xmlout, "%s <Exponent>%d</Exponent>\n", s,
1841 tccp->stepsizes[0].expn);
1842 fprintf(xmlout, "%s <Mantissa>%d</Mantissa>\n", s,
1843 tccp->stepsizes[0].mant);
1845 fprintf(xmlout, "%s </QuantizationValues>\n", s);
1848 "%s <!-- Exponents for subbands beyond 0 are not from header, but calculated per Eq. E.5 -->\n",
1851 "%s <!-- The mantissa for all subbands is the same, given by the value above. -->\n",
1854 "%s <!-- Current mj2_to_metadata implementation dumps entire internal table, -->\n",
1857 "%s <!-- until a subband with exponent of zero value is reached. -->\n",
1861 for (bandno = 1; bandno < J2K_MAXBANDS; bandno++) {
1862 if (tccp->stepsizes[bandno].expn == 0) {
1867 "%s <CalculatedExponent Subband=\"%d\">%d</CalculatedExponent>\n", s,
1868 bandno, tccp->stepsizes[bandno].expn);
1871 fprintf(xmlout, "%s </QuantizationStepSizeValues>\n", s);
1874 default: /* J2K_CCP_QNTSTY_SEQNT */ /* scalar quantization expounded */
1875 /* This is what standard says, but should I believe it: len = 5 + 6*decomp; */
1876 numbands = J2K_MAXBANDS; /* should be: (len - 1) / 2;*/
1877 /* Better: IMAGINE numbands = tccp->stepsize_numbands; */
1878 fprintf(xmlout, "%s <QuantizationStepSizeValues>\n", s);
1881 "%s <!-- For irreversible transformation only. See Part I Annex E Equation E.3 -->\n",
1884 "%s <!-- Current mj2_to_metadata implementation dumps entire internal table, -->\n",
1887 "%s <!-- until a subband with mantissa and exponent of zero values is reached. -->\n",
1890 for (bandno = 0; bandno < numbands; bandno++) {
1891 if (tccp->stepsizes[bandno].expn == 0 && tccp->stepsizes[bandno].mant == 0) {
1892 break; /* Remove when we have real numbands */
1895 fprintf(xmlout, "%s <QuantizationValues Subband=\"%d\">\n", s, bandno);
1897 fprintf(xmlout, "%s <AsHex>0x%02x</AsHex>\n", s,
1898 (tccp->stepsizes[bandno].expn << 11) | tccp->stepsizes[bandno].mant);
1901 fprintf(xmlout, "%s <Exponent>%d</Exponent>\n", s,
1902 tccp->stepsizes[bandno].expn);
1903 fprintf(xmlout, "%s <Mantissa>%d</Mantissa>\n", s,
1904 tccp->stepsizes[bandno].mant);
1906 fprintf(xmlout, "%s </QuantizationValues>\n", s);
1908 fprintf(xmlout, "%s </QuantizationStepSizeValues>\n", s);
1911 fprintf(xmlout, "%s </SPqcd>\n", s);
1912 fprintf(xmlout, "%s</QuantizationDefault>\n", s);
1914 /* Alignments: " < < < < < To help maintain xml pretty-printing */
1919 void xml_out_frame_qcc(FILE* xmlout, opj_tcp_t *tcp, int numcomps)
1921 /* Uses global j2k_default_tcp */
1922 /* This code will compile only if declaration of j2k_default_tcp is changed from static (to implicit extern) in j2k.c */
1923 opj_tccp_t *tccp, *firstcomp_tccp;
1924 int bandno, numbands;
1926 char spaces[13] = " "; /* 12 spaces if tilepart*/
1928 if (tcp == j2k_default_tcp) {
1930 s++; /* shorten s to 10 spaces if main */
1933 firstcomp_tccp = &(tcp->tccps[0]);
1934 /* Internal data structure tccp defines separate defaults for each component, set from main */
1935 /* default, then selectively overwritten. */
1936 /* Compare j2k_read_qcx(...) */
1937 /* We don't really know which was the default, and which were not */
1938 /* Let's pretend that [0] is the default and all others are not */
1941 "%s<!-- mj2_to_metadata implementation always reports component[0] as using default QCD, -->\n",
1943 if (tcp == j2k_default_tcp) {
1945 "%s<!-- and any other component, with main-header quantization values different from [0], as QCC. -->\n",
1949 "%s<!-- and any other component, with tile-part-header quantization values different from [0], as QCC. -->\n",
1953 for (compno = 1; compno < numcomps;
1954 compno++) { /* spec says components are zero-based */
1955 tccp = &(tcp->tccps[compno]);
1956 if (same_component_quantization(firstcomp_tccp, tccp)) {
1960 /* Compare j2k_read_qcx */
1962 "%s<QuantizationComponent Marker=\"QCC\" Component=\"%d\">\n", s,
1963 compno); /* Required in main header, single occurrence */
1964 tccp = &j2k_default_tcp->tccps[0];
1965 /* Not retained or perhaps of interest: Lqcd It maybe can be calculated. */
1966 fprintf(xmlout, "%s <Sqcc>\n", s); /* 1 byte */
1968 fprintf(xmlout, "%s <!-- Quantization style for this component. -->\n", s);
1971 fprintf(xmlout, "%s <AsHex>0x%02x</AsHex>\n", s,
1972 (tccp->numgbits) << 5 | tccp->qntsty);
1975 fprintf(xmlout, "%s <QuantizationStyle>%d</QuantizationStyle>\n", s,
1980 "%s <!-- Quantization style (in Sqcc's low 5 bits) may be: -->\n", s);
1981 fprintf(xmlout, "%s <!-- 0 = No quantization. SPqcc size = 8 bits-->\n",
1984 "%s <!-- 1 = Scalar derived (values signaled for N(L)LL subband only). Use Eq. E.5. SPqcc size = 16. -->\n",
1987 "%s <!-- 2 = Scalar expounded (values signaled for each subband). SPqcc size = 16. -->\n",
1991 fprintf(xmlout, "%s <NumberOfGuardBits>%d</NumberOfGuardBits>\n", s,
1996 "%s <!-- 0-7 guard bits allowed (stored in Sqcc's high 3 bits) -->\n", s);
1998 fprintf(xmlout, "%s </Sqcc>\n", s);
2000 /* Problem: numbands in some cases is calculated from len, which is not retained or available here at this time */
2001 /* So we'll just dump all internal values */
2002 fprintf(xmlout, "%s <SPqcc>\n", s);
2003 switch (tccp->qntsty) {
2004 case J2K_CCP_QNTSTY_NOQNT:
2005 numbands = J2K_MAXBANDS; /* should be: numbands = len - 1; */
2006 /* Better: IMAGINE numbands = tccp->stepsize_numbands; */
2008 /* Instead look for first zero exponent, quit there. Adequate? */
2009 fprintf(xmlout, "%s <ReversibleStepSizeValue>\n", s);
2012 "%s <!-- Current mj2_to_metadata implementation dumps entire internal table, -->\n",
2015 "%s <!-- until an exponent with zero value is reached. -->\n", s);
2017 "%s <!-- Exponent epsilon(b) of reversible dynamic range. -->\n", s);
2019 "%s <!-- Hex value is as stored, in high-order 5 bits. -->\n", s);
2021 for (bandno = 0; bandno < numbands; bandno++) {
2022 if (tccp->stepsizes[bandno].expn == 0) {
2023 break; /* Remove this once we have real numbands */
2025 fprintf(xmlout, "%s <Exponent Subband=\"%d\">\n", s, bandno);
2027 fprintf(xmlout, "%s <AsHex>0x%02x</AsHex>\n", s,
2028 tccp->stepsizes[bandno].expn << 3);
2031 fprintf(xmlout, "%s <AsDecimal>%d</AsDecimal>\n", s,
2032 tccp->stepsizes[bandno].expn);
2034 fprintf(xmlout, "%s </Exponent>\n", s);
2036 fprintf(xmlout, "%s </ReversibleStepSizeValue>\n", s);
2038 case J2K_CCP_QNTSTY_SIQNT:
2040 fprintf(xmlout, "%s <QuantizationStepSizeValues>\n", s);
2043 "%s <!-- For irreversible transformation only. See Part I Annex E Equation E.3 -->\n",
2046 fprintf(xmlout, "%s <QuantizationValuesForSubband0>\n", s);
2048 fprintf(xmlout, "%s <!-- For N(L)LL subband: >\n", s);
2051 fprintf(xmlout, "%s <AsHex>0x%02x</AsHex>\n", s,
2052 (tccp->stepsizes[0].expn << 11) | tccp->stepsizes[0].mant);
2055 fprintf(xmlout, "%s <Exponent>%d</Exponent>\n", s,
2056 tccp->stepsizes[0].expn);
2057 fprintf(xmlout, "%s <Mantissa>%d</Mantissa>\n", s,
2058 tccp->stepsizes[0].mant);
2060 fprintf(xmlout, "%s </QuantizationValuesForSubband0>\n", s);
2063 "%s <!-- Exponents for subbands beyond 0 are not from header, but calculated per Eq. E.5 -->\n",
2066 "%s <!-- The mantissa for all subbands is the same, given by the value above. -->\n",
2069 "%s <!-- Current mj2_to_metadata implementation dumps entire internal table, -->\n",
2072 "%s <!-- until a subband with exponent of zero value is reached. -->\n",
2076 for (bandno = 1; bandno < J2K_MAXBANDS; bandno++) {
2077 if (tccp->stepsizes[bandno].expn == 0) {
2082 "%s <CalculatedExponent Subband=\"%d\">%d</CalculatedExponent>\n", s,
2083 bandno, tccp->stepsizes[bandno].expn);
2085 fprintf(xmlout, "%s </QuantizationStepSizeValues>\n", s);
2088 default: /* J2K_CCP_QNTSTY_SEQNT */
2089 numbands = J2K_MAXBANDS; /* should be: (len - 1) / 2;*/
2090 /* Better: IMAGINE numbands = tccp->stepsize_numbands; */
2091 fprintf(xmlout, "%s <QuantizationStepSizeValues>\n", s);
2094 "%s <!-- For irreversible transformation only. See Part I Annex E Equation E.3 -->\n",
2097 "%s <!-- Current mj2_to_metadata implementation dumps entire internal table, -->\n",
2100 "%s <!-- until a subband with mantissa and exponent of zero values is reached. -->\n",
2103 for (bandno = 0; bandno < numbands; bandno++) {
2104 if (tccp->stepsizes[bandno].expn == 0 && tccp->stepsizes[bandno].mant == 0) {
2105 break; /* Remove this once we have real numbands count */
2107 fprintf(xmlout, "%s <QuantizationValues Subband=\"%d\">\n", s, bandno);
2109 fprintf(xmlout, "%s <AsHex>0x%02x</AsHex>\n", s,
2110 (tccp->stepsizes[bandno].expn << 11) | tccp->stepsizes[bandno].mant);
2113 fprintf(xmlout, "%s <Exponent>%d</Exponent>\n", s,
2114 tccp->stepsizes[bandno].expn);
2115 fprintf(xmlout, "%s <Mantissa>%d</Mantissa>\n", s,
2116 tccp->stepsizes[bandno].mant);
2118 fprintf(xmlout, "%s </QuantizationValues>\n", s);
2120 fprintf(xmlout, "%s </QuantizationStepSizeValues>\n", s);
2123 fprintf(xmlout, "%s </SPqcc>\n", s);
2124 fprintf(xmlout, "%s</QuantizationComponent>\n", s);
2126 /* Alignments: " < < < < < To help maintain xml pretty-printing */
2131 BOOL same_component_quantization(opj_tccp_t *tccp1, opj_tccp_t *tccp2)
2133 int bandno, numbands;
2135 if (tccp1->qntsty != tccp2->qntsty) {
2138 if (tccp1->numgbits != tccp2->numgbits) {
2142 switch (tccp1->qntsty) {
2143 case J2K_CCP_QNTSTY_NOQNT:
2144 numbands = J2K_MAXBANDS; /* should be: numbands = len - 1; */
2145 /* Instead look for first zero exponent, quit there. Adequate? */
2146 for (bandno = 0; bandno < numbands; bandno++) {
2147 if (tccp1->stepsizes[bandno].expn == 0) {
2150 if (tccp1->stepsizes[bandno].expn != tccp2->stepsizes[bandno].expn) {
2155 case J2K_CCP_QNTSTY_SIQNT:
2157 if (tccp1->stepsizes[0].expn != tccp2->stepsizes[0].expn ||
2158 tccp1->stepsizes[0].mant != tccp2->stepsizes[0].mant) {
2161 /* Don't need to check remainder, since they are calculated from [0] */
2164 default: /* J2K_CCP_QNTSTY_SEQNT */
2165 numbands = J2K_MAXBANDS; /* should be: (len - 1) / 2;*/
2166 /* This comparison may cause us problems with trailing junk values. */
2167 for (bandno = 0; bandno < numbands; bandno++) {
2168 if (tccp1->stepsizes[bandno].expn != tccp2->stepsizes[bandno].expn ||
2169 tccp1->stepsizes[bandno].mant != tccp2->stepsizes[bandno].mant);
2179 void xml_out_frame_rgn(FILE* xmlout, opj_tcp_t *tcp, int numcomps)
2182 /* MJ2 files can have regions of interest if hybridized with JPX Part II */
2183 char spaces[13] = " "; /* 12 spaces if tilepart*/
2185 if (tcp == j2k_default_tcp) {
2187 s++; /* shorten s to 10 spaces if main */
2190 for (compno = 0; compno < numcomps; compno++) {
2191 SPrgn = tcp->tccps[compno].roishift; /* 1 byte; SPrgn */
2193 continue; /* Yet another kludge */
2196 fprintf(xmlout, "%s<RegionOfInterest Marker=\"RGN\">\n",
2197 s); /* Optional in main header, at most 1 per component */
2199 fprintf(xmlout, "%s<!-- See Crgn below for zero-based component number. -->\n",
2202 /* Not retained or of interest: Lrgd */
2203 fprintf(xmlout, "%s <Srgn>0</Srgn>\n", s); /* 1 byte */
2206 "%s <!-- Srgn is ROI style. Only style=0 defined: Implicit ROI (max. shift) -->\n",
2209 fprintf(xmlout, "%s <Crgn>%d</Crgn>\n", s, compno); /* 1 or 2 bytes */
2210 fprintf(xmlout, "%s <SPrgn>%d</SPrgn>\n", s, SPrgn); /* 1 byte */
2213 "%s <!-- SPrgn is implicit ROI shift, i.e., binary shifting of ROI coefficients above background. -->\n",
2216 fprintf(xmlout, "</RegionOfInterest\n",
2217 s); /* Optional in main header, at most 1 per component */
2223 void xml_out_frame_poc(FILE* xmlout,
2224 opj_tcp_t *tcp) /* Progression Order Change */
2226 /* Compare j2k_read_poc() */
2229 char spaces[13] = " "; /* 12 spaces if tilepart*/
2231 if (tcp == j2k_default_tcp) {
2233 s++; /* shorten s to 10 spaces if main */
2236 if (tcp->POC != 1) {
2237 return; /* Not present */
2240 fprintf(xmlout, "%s<ProgressionOrderChange Marker=\"POC\">\n",
2241 s); /* Optional in main header, at most 1 per component */
2242 /* j2k_read_poc seems to allow accumulation of default pocs from multiple POC segments, but does
2243 the spec really allow that? */
2244 /* 2 bytes, not retained; Lpoc */
2245 /* I probably didn't get this dump precisely right. */
2246 for (i = 0; i < tcp->numpocs; i++) {
2247 poc = &tcp->pocs[i];
2248 fprintf(xmlout, "%s <Progression Num=\"%d\">\n", s, i + 1);
2249 fprintf(xmlout, "%S <RSpoc>%d</RSpoc>\n", s,
2250 poc->resno0); /* 1 byte, RSpoc_i */
2253 "%s <!-- Resolution level index (inclusive) for progression start. Range: 0 to 33 -->\n",
2256 fprintf(xmlout, "%s <CSpoc>%d</CSpoc>\n", s,
2257 poc->compno0);/* j2k_img->numcomps <= 256 ? 1 byte : 2 bytes; CSpoc_i */
2260 "%s <!-- Component index (inclusive) for progression start. -->\n", s);
2262 fprintf(xmlout, "%s <LYEpoc>%d</LYEpoc>\n", s,
2263 poc->layno1); /* int_min(cio_read(2), tcp->numlayers); /* 2 bytes; LYEpoc_i */
2265 fprintf(xmlout, "%s <!-- Layer index (exclusive) for progression end. -->\n",
2268 fprintf(xmlout, "%s <REpoc>%d</REpoc>\n", s,
2269 poc->resno1); /*int_min(cio_read(1), tccp->numresolutions); /* REpoc_i */
2272 "%s <!-- Resolution level index (exclusive) for progression end. Range: RSpoc to 33 -->\n",
2275 fprintf(xmlout, "%s <CEpoc>%d</CEpoc>\n", s,
2276 poc->compno1); /* int_min(cio_read(j2k_img->numcomps <= 256 ? 1 : 2), j2k_img->numcomps); /* CEpoc_i */
2279 "%s <!-- Component index (exclusive) for progression end. Minimum: CSpoc -->\n",
2282 fprintf(xmlout, "%s <Ppoc>%d</Ppoc>\n", s, poc->prg); /* 1 byte Ppoc_i */
2284 fprintf(xmlout, "%s <!-- Defined Progression Order Values are: -->\n", s);
2286 "%s <!-- 0 = LRCP; 1 = RLCP; 2 = RPCL; 3 = PCRL; 4 = CPRL -->\n", s);
2288 "%s <!-- where L = \"layer\", R = \"resolution level\", C = \"component\", P = \"position\". -->\n",
2291 fprintf(xmlout, "%s </Progression>\n", s);
2293 fprintf(xmlout, "%s</ProgressionOrderChange\n", s);
2298 #ifdef SUPPRESS_FOR_NOW
2299 /* Suppress PPM and PPT since we're not showing data from the third option, namely within the codestream, and
2300 that's evidently what frames_to_mj2 uses. And a hex dump isn't so useful anyway */
2302 void xml_out_frame_ppm(FILE *xmlout,
2303 opj_cp_t *cp) /* For main header, not tile-part (which uses PPT instead). */
2305 /* Either the PPM or PPT is required if the packet headers are not distributed in the bit stream */
2306 /* Use of PPM and PPT are mutually exclusive. */
2307 /* Compare j2k_read_ppm() */
2311 return; /* Not present */
2313 /* Main header uses indent of 10 spaces */
2315 " <PackedPacketHeadersMainHeader Marker=\"PPM\">\n"); /* Optional in main header, but if not, must be in PPT or codestream */
2316 /* 2 bytes Lppm not saved */
2319 " <!-- If there are multiple PPM marker segments in the main header, -->\n");
2321 " <!-- this mj2_to_metadata implementation will report them as a single consolidated PPM header. -->\n");
2323 " <!-- The implementation can't currently segregate by tile-part. -->\n");
2325 " <!-- TO DO? further map the packet headers to xml. -->\n");
2328 /* 1 byte, not retained ; Zppm is sequence # of this PPM header */
2329 /* 4 bytes, possibly overwritten multiple times in j2k_cp->ppm_previous: Nppm */
2330 /* Use j symbol for index instead of i, to make comparable with j2k_read_ppm */
2331 /* Not real clear whether to use ppm->store or ppm_len as upper bound */
2332 fprintf(xmlout, " <PackedData>\n");
2333 xml_out_dump_hex(xmlout, cp->ppm_data, cp->ppm_len);
2334 /* Dump packet headers 1 byte at a time: lppm[i][j] */
2335 fprintf(xmlout, " </PackedData>\n");
2337 " </PackedPacketHeadersMainHeader>\n"); /* Optional in main header, but if not, must be in PPT or codestream */
2342 void xml_out_frame_ppt(FILE *xmlout,
2343 opj_tcp_t *tcp) /* For tile-part header, not main (which uses PPM instead). */
2345 /* Either the PPM or PPT is required if the packet headers are not distributed in the bit stream */
2346 /* Use of PPM and PPT are mutually exclusive. */
2347 /* Compare j2k_read_ppt() */
2350 if (tcp->ppt != 1) {
2351 return; /* Not present */
2354 /* Tile-part indents are 12 spaces */
2356 " <PackedPacketHeadersTilePartHeader Marker=\"PPT\">\n"); /* Optional in main header, but if not, must be in PPT or codestream */
2357 /* 2 bytes Lppm not saved */
2360 " <!-- If there are multiple PPT marker segments in the tile-part header, -->\n");
2362 " <!-- this mj2_to_metadata implementation will report them as a single consolidated PPT header. -->\n");
2364 " <!-- The implementation can't currently segregate by tile-part. -->\n");
2366 " <!-- TO DO? further map the packet headers to xml. -->\n");
2369 /* 1 byte, not retained ; Zppt is sequence # of this PPT header */
2370 /* 4 bytes, possibly overwritten multiple times in j2k_cp->ppt_previous: Nppt */
2371 /* Use j symbol for index instead of i, to make comparable with j2k_read_ppt */
2372 /* Not real clear whether to use ppt->store or ppt_len as upper bound */
2373 fprintf(xmlout, " <PackedData>\n");
2374 xml_out_dump_hex(xmlout, tcp->ppt_data, tcp->ppt_len);
2375 /* Dump packet headers 1 byte at a time: lppt[i][j] */
2376 fprintf(xmlout, " </PackedData>\n");
2378 " </PackedPacketHeadersTileHeader>\n"); /* Optional in tile-part header, but if not, must be in PPM or codestream */
2380 #endif SUPPRESS_FOR_NOW
2384 void xml_out_frame_tlm(FILE*
2385 xmlout) /* opt, main header only. May be multiple. */
2387 /* Compare j2k_read_tlm()... which doesn't retain anything! */
2388 /* Plan: Since this is only called from main header, not tilepart, use global j2k_default_tcp rather than parameter */
2389 /* Main header indents are 10 spaces */
2394 void xml_out_frame_plm(FILE*
2395 xmlout) /* opt, main header only; can be used in conjunction with tile-part's PLT */
2397 /* NO-OP. PLM NOT SAVED IN DATA STRUCTURE */
2398 /* Compare j2k_read_plm()... which doesn't retain anything! */
2399 /* Plan: Since this is only called from main header, not tilepart, use global j2k_default_tcp rather than parameter */
2400 /* Main header indents are 10 spaces */
2405 void xml_out_frame_plt(FILE* xmlout,
2406 opj_tcp_t *tcp) /* opt, tile-part headers only; can be used in conjunction with main header's PLM */
2408 /* NO-OP. PLT NOT SAVED IN DATA STRUCTURE */
2409 /* Compare j2k_read_plt()... which doesn't retain anything! */
2410 /* Tile-part header indents are 12 spaces */
2415 void xml_out_frame_crg(FILE* xmlout)
2417 /* NO-OP. CRG NOT SAVED IN DATA STRUCTURE */ /* opt, main header only; */
2418 /* Compare j2k_read_crg()... which doesn't retain anything! */
2419 /* Plan: Since this is only called from main header, not tilepart, use global j2k_default_tcp rather than parameter */
2421 THIS PSEUDOCODE IMAGINES THESE EXIST:
2422 j2k_default_tcp->crg, j2k_default_tcp->crg_i, j2k_default_tcp->crg_xcrg*,
2423 j2k_default_tcp->crg_ycrg*
2424 (POSSIBLY DON'T NEED crg_i, CAN GET NUMBER OR COMPONENTS FROM ELSEWHERE)
2425 if (j2k_default_tcp->crg != 1 || j2k_default_tcp->crg_i == 0)
2426 return; /* Not present */
2428 /* Main header indents are 10 spaces */
2430 " <ComponentRegistration Marker=\"RG\" Count=\"%d\">\n",
2431 j2k_default_tcp->crg_i);
2434 " <!-- Fine tuning of registration of components with respect to each other, -->\n");
2436 " <!-- not required but potentially helpful for decoder. -->\n");
2438 " <!-- These supplementary fractional offsets are in units of 1/65536 of the horizontal -->\n");
2440 " <!-- or vertical separation (e.g., XRsiz[i] or YRsiz[i] for component i). -->\n");
2442 /* This isn't the most compact form of table, but is OK when number of components is small, as is likely. */
2443 for (i = 0; i < j2k_default_tcp->crg_i; i++) {
2444 fprintf(xmlout, " <Component Num=\"%d\">\n", i + 1);
2445 fprintf(xmlout, " <Xcrg>\n");
2447 fprintf(xmlout, " <AsNumerator>%d</AsNumerator>\n",
2448 j2k_default_tcp->crg_xcrg[i]);
2451 /* Calculate n * 100%/65536; 4 digits after decimal point is sufficiently accurate */
2452 fprintf(xmlout, " <AsPercentage>%.4f</AsPercentage>\n",
2453 ((double)j2k_default_tcp->crg_xcrg[i]) / 655.36);
2454 /* We could do another calculation that include XRsiz[i]; maybe later. */
2456 fprintf(xmlout, " </Xcrg>\n");
2457 fprintf(xmlout, " <Ycrg>\n");
2459 fprintf(xmlout, " <AsNumerator>%d</AsNumerator>\n",
2460 j2k_default_tcp->crg_ycrg[i]);
2463 fprintf(xmlout, " <AsPercentage>%f</AsPercentage>\n",
2464 ((double)j2k_default_tcp->crg_ycrg[i]) / 655.36);
2466 fprintf(xmlout, " </Ycrg>\n");
2467 fprintf(xmlout, " </Component>\n");
2470 fprintf(xmlout, " </ComponentRegistration>\n");
2477 /* Regrettably from a metadata point of view, j2k_read_com() skips over any comments in main header or tile-part-header */
2478 void xml_out_frame_com(FILE* xmlout, opj_tcp_t *tcp)
2480 /* NO-OP. COM NOT SAVED IN DATA STRUCTURE */ /* opt in main or tile-part headers; */
2481 /* Compare j2k_read_com()... which doesn't retain anything! */
2483 char spaces[13] = " "; /* 12 spaces if tilepart*/
2485 if (tcp == &j2k_default_tcp) {
2487 s++; /* shorten s to 10 spaces if main */
2489 THIS PSEUDOCODE IMAGINES THESE EXIST:
2490 tcp->com, tcp->com_len, tcp->com_data array
2491 if (tcp->com != 1) {
2492 return; /* Not present */
2495 fprintf(xmlout, "%s<Comment Marker=\"COM\">\n",
2496 s); /* Optional in main or tile-part header */
2497 xml_out_dump_hex_and_ascii(tcp->com_data, tcp->com_len, s);
2498 fprintf(xmlout, "%s</Comment>\n", s);
2502 void xml_out_dump_hex(FILE* xmlout, char *data, int data_len, char* s)
2504 /* s is a string of spaces for indent */
2507 /* This is called when raw is true, or there is no appropriate derived form */
2508 fprintf(xmlout, "%s<AsHex>\n", s);
2509 fprintf(xmlout, "%s ", s); /* Inadequate for pretty printing */
2510 for (i = 0; i < data_len; i++) { /* Dump packet headers */
2511 fprintf(xmlout, "%02x", data[i]);
2513 fprintf(xmlout, "%s</AsHex>\n", s);
2516 /* Define this as an even number: */
2517 #define BYTES_PER_DUMP_LINE 40
2518 /* Current total width for Hex and ASCII is : 11 spaces lead + (3 * BPDL) + 2 spaces + BPDL */
2519 void xml_out_dump_hex_and_ascii(FILE* xmlout, char *data, int data_len,
2522 /* s is a string of spaces for indent */
2526 xml_out_dump_hex(xmlout, data, data_len, s);
2530 fprintf(xmlout, "%s<AsHexAndASCII>\n", s);
2531 for (i = 0; i < data_len;) {
2532 fprintf(xmlout, "%s ", s); /* Additional leading space added in loop */
2533 /* First column: hex */
2534 for (j = 0; j < BYTES_PER_DUMP_LINE; j++) { /* Dump bytes */
2535 fprintf(xmlout, " %02x", data[i + j]);
2537 /* Space between columns... */ fprintf(xmlout, " ");
2538 /* Second column: ASCII */
2539 for (j = 0; j < BYTES_PER_DUMP_LINE; j++, i++) {
2540 if (isprint((int)data[i]) && i < data_len) {
2541 fprintf(xmlout, "%c", data[i]);
2543 fprintf(xmlout, " ");
2546 /* If we also wanted to output UCS-2 Unicode as a third column, then entire document
2547 must use fwprintf. Forget about it for now. As it stands, if data is UCS-2 format but still
2548 the ASCII set, then we'll be able to read every other byte as ASCII in column 2. If
2549 data is UTF-8 format but still ASCII, then we'll be able to read every byte as ASCII
2552 fprintf(xmlout, "%s</AsHexAndASCII>\n", s);
2559 void xml_out_frame_jp2h(FILE* xmlout, opj_jp2_t *jp2_struct) /* JP2 Header */
2561 /* Compare jp2_read_jp2h(opj_jp2_t * jp2_struct) */
2564 fprintf(xmlout, " <JP2Header BoxType=\"jp2h\">\n");
2566 /* Compare jp2_read_ihdr(jp2_struct)) */
2567 fprintf(xmlout, " <ImageHeader BoxType=\"ihdr\">\n");
2568 fprintf(xmlout, " <HEIGHT>%d</HEIGHT>\n",
2569 jp2_struct->h); /* 4 bytes */
2570 fprintf(xmlout, " <WIDTH>%d</WIDTH>\n",
2571 jp2_struct->w); /* 4 bytes */
2574 " <!-- HEIGHT here, if 2 fields per image, is of total deinterlaced height. -->\n");
2576 fprintf(xmlout, " <NC>%d</NC>\n",
2577 jp2_struct->numcomps); /* 2 bytes */
2580 " <!-- NC is number of components -->\n"); /* 2 bytes */
2582 fprintf(xmlout, " <BPC>\n"); /* 1 byte */
2583 if (jp2_struct->bpc == 255) {
2584 fprintf(xmlout, " <AsHex>0x%02x</AsHex>\n",
2585 jp2_struct->bpc); /* 1 byte */
2588 " <!-- BPC = 0xff means bits per pixel varies with component; see table below. -->\n");
2590 } else { /* Not 0xff */
2592 fprintf(xmlout, " <AsHex>0x%02x</AsHex>\n",
2593 jp2_struct->bpc); /* 1 byte */
2596 " <!-- BPC = 0xff means bits per pixel varies with component; see table below. -->\n");
2600 fprintf(xmlout, " <BitsPerPixel>%d</BitsPerPixel>\n",
2601 jp2_struct->bpc & 0x7f);
2602 fprintf(xmlout, " <Signed>%d</Signed>\n",
2603 jp2_struct->bpc >> 7);
2606 fprintf(xmlout, " </BPC>\n");
2607 fprintf(xmlout, " <C>%d</C>\n",
2608 jp2_struct->C); /* 1 byte */
2611 " <!-- C is compression type. Only \"7\" is allowed to date. -->\n"); /* 2 bytes */
2613 fprintf(xmlout, " <UnkC>%d</UnkC>\n",
2614 jp2_struct->UnkC); /* 1 byte */
2617 " <!-- Colourspace Unknown. 1 = unknown, 0 = known (e.g., colourspace spec is accurate) -->\n"); /* 1 byte */
2619 fprintf(xmlout, " <IPR>%d</IPR>\n",
2620 jp2_struct->IPR); /* 1 byte */
2623 " <!-- IPR is 1 if frame contains an Intellectual Property box; 0 otherwise. -->\n"); /* 2 bytes */
2625 fprintf(xmlout, " </ImageHeader>\n");
2627 if (jp2_struct->bpc == 255) {
2628 fprintf(xmlout, " <BitsPerComponent BoxType=\"bpcc\">\n");
2631 " <!-- Pixel depth (range 1 to 38) is low 7 bits of hex value + 1 -->\n");
2633 /* Bits per pixel varies with components */
2634 /* Compare jp2_read_bpcc(jp2_struct) */
2635 for (i = 0; i < (int)jp2_struct->numcomps; i++) {
2637 fprintf(xmlout, " <AsHex>0x%02x</AsHex>\n",
2638 jp2_struct->comps[i].bpcc); /* 1 byte */
2641 fprintf(xmlout, " <BitsPerPixel>%d</BitsPerPixel>\n",
2642 (jp2_struct->comps[i].bpcc & 0x7f) + 1);
2643 fprintf(xmlout, " <Signed>%d</Signed>\n",
2644 jp2_struct->comps[i].bpcc >> 7);
2647 fprintf(xmlout, " </BitsPerComponent>\n");
2650 /* Compare jp2_read_colr(jp2_struct) */
2652 " <ColourSpecification BoxType=\"colr\">\n");
2653 fprintf(xmlout, " <METH>%d</METH>\n",
2654 jp2_struct->meth); /* 1 byte */
2657 " <!-- Valid values of specification method so far: -->\n");
2659 " <!-- 1 = Enumerated colourspace, in EnumCS field -->\n");
2661 " <!-- 2 = Restricted ICC Profile, in PROFILE field -->\n");
2663 fprintf(xmlout, " <PREC>%d</PREC>\n",
2664 jp2_struct->precedence); /* 1 byte */
2667 " <!-- 0 is only valid value of precedence so far. -->\n");
2669 fprintf(xmlout, " <APPROX>%d</APPROX>\n",
2670 jp2_struct->approx); /* 1 byte */
2673 " <!-- 0 is only valid value of colourspace approximation so far. -->\n");
2676 if (jp2_struct->meth == 1) {
2677 fprintf(xmlout, " <EnumCS>%d</EnumCS>\n",
2678 jp2_struct->enumcs); /* 4 bytes */
2681 " <!-- Valid values of enumerated MJ2 colourspace so far: -->\n");
2683 " <!-- 16: sRGB as defined by IEC 61966-2-1. -->\n");
2685 " <!-- 17: greyscale (related to sRGB). -->\n");
2687 " <!-- 18: sRGB YCC (from JPEG 2000 Part II). -->\n");
2689 " <!-- (Additional JPX values are defined in Part II). -->\n");
2693 " <!-- PROFILE is not handled by current OpenJPEG implementation. -->\n");
2695 /* only 1 byte is read and nothing stored */
2696 fprintf(xmlout, " </ColourSpecification>\n");
2698 /* TO DO? No OpenJPEG support.
2700 ComponentMapping 'cmap'
2701 ChannelDefinition 'cdef'
2704 fprintf(xmlout, " </JP2Header>\n");
2709 IMAGE these use cp structure,
2710 extended... but we could use a new data structure instead
2711 void xml_out_frame_jp2i(FILE* xmlout, opj_cp_t *cp)
2713 /* IntellectualProperty 'jp2i' (no restrictions on location) */
2715 IMAGE cp->jp2i, cp->jp2i_count, cp->jp2i_data(array of chars),
2716 cp->cp2i_len(array of ints)
2717 if (cp->jp2i != 1) {
2718 return; /* Not present */
2721 for (i = 0; i < cp->jp2i_count; i++) {
2722 fprintf(xmlout, " <IntellectualProperty BoxType=\"jp2i\">\n");
2723 /* I think this can be anything, including binary, so do a dump */
2724 /* Is it better to indent or not indent this content? Indent is better for reading, but
2725 worse for cut/paste. */
2726 xml_out_dump_hex_and_ascii(xmlout, cp->jp2i_data[i], cp->jp2i_len[i]);
2727 fprintf(xmlout, " </IntellectualProperty>\n");
2731 void xml_out_frame_xml(FILE* xmlout, opj_cp_t *cp)
2733 /* XML 'xml\040' (0x786d6c20). Can appear multiply, before or after jp2c codestreams */
2734 IMAGE cp->xml, cp->xml_count, cp->xml_data(array of chars)
2735 MAYBE WE DON'T NEED cp->xml_len (array of ints) IF WE ASSUME xml_data IS NULL-TERMINATED.
2736 ASSUME ASSUME EACH LINE IS ENDED BY \n.
2739 return; /* Not present */
2742 for (i = 0; i < cp->xml_count; i++) {
2743 fprintf(xmlout, " <TextFormXML BoxType=\"xml[space]" Instance =
2745 /* Is it better to indent or not indent this content? Indent is better for reading, but
2746 worse for cut/paste. Being lazy, didn't indent here. */
2748 cp->xml_data[i]); /* May be multiple lines */ /* Could check if this is well-formed */
2749 fprintf(xmlout, " </TextFormXML>\n");
2753 void xml_out_frame_uuid(FILE* xmlout, opj_cp_t *cp)
2755 /* UUID 'uuid' (top level only) */
2756 /* Part I 1.7.2 says: may appear multiply in JP2 file, anywhere except before File Type box */
2757 /* Part III 5.2.1 says: Private extensions shall be achieved through the 'uuid' type. */
2758 /* A UUID is a 16-byte value. There is a conventional string representation for it:
2759 "0x12345678-9ABC-DEF0-1234-567890ABCDEF". Let's assume that is what is stored in uuid_value */
2761 /* Part III 6.1 Any other MJ2 box type could be alternatively written as a 'uuid' box, with value given
2762 as : 0xXXXXXXXX-0011-0010-8000-00AA00389B71, where the Xs are the boxtype in hex. However,
2763 such a file is "not compliant; systems may choose to read [such] objects ... as equivalent to the box of
2764 the same type, or not." Here, we choose not to. */
2766 IMAGE cp->uuid, cp->uuid_count,
2767 cp->uuid_value(array of uuids...
2768 let's say fixed-length strings) cp->uuid_data (array of char buffers), cp->uuid_len (array of ints)
2770 return; /* Not present */
2772 for (i = 0; i < cp->uuid_count; i++) {
2773 fprintf(xmlout, " <UniversalUniqueID BoxType=\"uuid\">
2774 fprintf(xmlout, " <UUID>%s</UUDI>\n", cp->uuid_value[i]);
2775 fprintf(xmlout, " <Data>\n");
2776 /* I think this can be anything, including binary, so do a dump */
2777 /* Is it better to indent or not indent this content? Indent is better for reading, but
2778 worse for cut/paste. */
2779 xml_out_dump_hex_and_ascii(xmlout, cp->uuid_data[i], cp->uuid_len[i]);
2780 fprintf(xmlout, " </Data>\n");
2781 fprintf(xmlout, " </UniversalUniqueID>\n");
2785 void xml_out_frame_uinf(FILE* xmlout, opj_cp_t *cp)
2787 /* UUIDInfo 'uinf', includes UUIDList 'ulst' and URL 'url\40' */
2788 /* Part I 1.7.3 says: may appear multiply in JP2 file, anywhere at the top level except before File Type box */
2789 /* So there may be multiple ulst's, and each can have multiple UUIDs listed (with a single URL) */
2790 /* This is not quite as vendor-specific as UUIDs, or at least is meant to be generally readable */
2791 /* Assume UUIDs stored in canonical string format */
2793 IMAGE cp->uinf, cp->uinf_count, cp->uinf_ulst_nu(array of ints)
2794 cp->uinf_uuid(2 dimensional array of uuids... let's say fixed-length strings),
2795 cp->uinf_url(array of char buffers)
2798 return; /* Not present */
2800 for (i = 0; i < cp->uuid_count; i++) {
2801 fprintf(xmlout, " <UUIDInfo BoxType=\"uinf\">\n");
2802 fprintf(xmlout, " <UUIDList BoxType=\"ulst\" Count=\"%d\">\n",
2803 cp->cp->uinf_ulst_nu[i]);
2804 for (j = 0; j < cp->uinf_ulst_nu[i]; j++) {
2805 fprintf(xmlout, " <ID Instance=\"%s\">%s</ID>\n",
2806 cp->uuif_uuid[i][j], j + 1);
2808 fprintf(xmlout, " </UUIDList>\n");
2809 fprintf(xmlout, " <DataEntryURL>\n");
2810 /* Could add VERS and FLAG here */
2811 fprintf(xmlout, " <LOC>\n");
2812 fprintf(xmlout, " %s",
2813 cp->uinf_url[i]); /* Probably single line, so indent works */ /* In theory, could check if this is well-formed, or good live link */
2814 fprintf(xmlout, " </LOC>\n");
2815 fprintf(xmlout, " </DataEntryURL>\n");
2816 fprintf(xmlout, " </UUIDInfo>\n");
2820 IMAGE these use cp structure,
2821 extended... but we could use a new data structure instead
2822 void xml_out_frame_unknown_type(FILE* xmlout, opj_cp_t *cp)
2824 /* Part III 5.2.1 says "Type fields not defined here are reserved. Private extensions
2825 shall be acieved through the 'uuid' type." [This implies an unknown
2826 type would be an error, but then...] "Boxes not explicitly defined in this standard,
2827 or otherwise unrecognized by a reader, may be ignored."
2828 Also, it says "the following types are not and will not be used, or used only in
2829 their existing sense, in future versions of this specification, to avoid conflict
2830 with existing content using earlier pre-standard versions of this format:
2831 clip, crgn, matt, kmat, pnot, ctab, load, imap;
2832 track reference types tmcd, chap, sync,scpt, ssrc"
2833 [But good luck figuring out the mapping.]
2834 Part III Amend. 2 4.1 is stronger: "All these specifications [of this family, e.g.,
2835 JP2 Part I, ISO Base format (Part 12) leading to MP4, Quicktime, and possibly including
2836 MJ2] require that readers ignore objects that are unrecognizable to them".
2839 IMAGE cp->unknown_type, cp->unknown_type_count,
2840 cp->unknown_type_boxtype(array of buf[5]s),
2841 cp->unknown_type_data(array of chars), cp->unknown_type_len(array of ints)
2842 if (cp->unknown_type != 1) {
2843 return; /* Not present */
2846 for (i = 0; i < cp->unknown_type_count; i++) {
2847 fprintf(xmlout, " <UnknownType BoxType=\"%s\">\n",
2848 cp->unknown_type_boxtype[i]);
2849 /* Can be anything, including binary, so do a dump */
2850 /* Is it better to indent or not indent this content? Indent is better for reading, but
2851 worse for cut/paste. */
2852 xml_out_dump_hex_and_ascii(xmlout, cp->unknown_type_data[i],
2853 cp->unknown_type_len[i]);
2854 fprintf(xmlout, " </UnknownType>\n");