2 * Copyright (c) 2003-2004, Fran�ois-Olivier Devaux
3 * Copyright (c) 2003-2004, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
19 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE.
37 #define MJ2_JP 0x6a502020
38 #define MJ2_FTYP 0x66747970
39 #define MJ2_MJ2 0x6d6a7032
40 #define MJ2_MJ2S 0x6d6a3273
41 #define MJ2_MDAT 0x6d646174
42 #define MJ2_MOOV 0x6d6f6f76
43 #define MJ2_MVHD 0x6d766864
44 #define MJ2_TRAK 0x7472616b
45 #define MJ2_TKHD 0x746b6864
46 #define MJ2_MDIA 0x6d646961
47 #define MJ2_MDHD 0x6d646864
48 #define MJ2_MHDR 0x6d686472
49 #define MJ2_HDLR 0x68646C72
50 #define MJ2_MINF 0x6d696e66
51 #define MJ2_VMHD 0x766d6864
52 #define MJ2_SMHD 0x736d6864
53 #define MJ2_HMHD 0x686d6864
54 #define MJ2_DINF 0x64696e66
55 #define MJ2_DREF 0x64726566
56 #define MJ2_URL 0x75726c20
57 #define MJ2_URN 0x75726e20
58 #define MJ2_STBL 0x7374626c
59 #define MJ2_STSD 0x73747364
60 #define MJ2_STTS 0x73747473
61 #define MJ2_STSC 0x73747363
62 #define MJ2_STSZ 0x7374737A
63 #define MJ2_STCO 0x7374636f
64 #define MJ2_MOOF 0x6d6f6f66
65 #define MJ2_FREE 0x66726565
66 #define MJ2_SKIP 0x736b6970
67 #define MJ2_JP2C 0x6a703263
68 #define MJ2_FIEL 0x6669656c
69 #define MJ2_JP2P 0x6a703270
70 #define MJ2_JP2X 0x6a703278
71 #define MJ2_JSUB 0x6a737562
72 #define MJ2_ORFO 0x6f72666f
73 #define MJ2_MVEX 0x6d766578
74 #define MJ2_JP2 0x6a703220
75 #define MJ2_J2P0 0x4a325030
79 * Free movie structure memory
82 void mj2_memory_free(mj2_movie_t * movie)
87 if (movie->num_cl != 0)
90 for (i = 0; i < movie->num_vtk + movie->num_stk + movie->num_htk; i++) {
92 if (tk->name_size != 0)
94 if (tk->jp2_struct.comps != 0)
95 free(tk->jp2_struct.comps);
96 if (tk->jp2_struct.cl != 0)
97 free(tk->jp2_struct.cl);
100 if (tk->num_urn != 0)
104 if (tk->num_jp2x != 0)
106 if (tk->num_tts != 0)
108 if (tk->num_chunks != 0)
110 if (tk->num_samplestochunk != 0)
111 free(tk->sampletochunk);
112 if (tk->num_samples != 0)
125 int mj2_read_boxhdr(mj2_box_t * box)
127 box->init_pos = cio_tell();
128 box->length = cio_read(4);
129 box->type = cio_read(4);
130 if (box->length == 1) {
131 if (cio_read(4) != 0) {
132 fprintf(stderr, "Error: Cannot handle box sizes higher than 2^32\n");
135 box->length = cio_read(4);
136 if (box->length == 0)
137 box->length = cio_numbytesleft() + 12;
139 else if (box->length == 0) {
140 box->length = cio_numbytesleft() + 8;
147 * Initialisation of a Standard Video Track
148 * with one sample per chunk
151 int mj2_init_stdmovie(mj2_movie_t * movie)
156 movie->brand = MJ2_MJ2;
157 movie->minversion = 0;
160 (unsigned int *) malloc(movie->num_cl * sizeof(unsigned int));
162 movie->cl[0] = MJ2_MJ2;
163 movie->cl[1] = MJ2_MJ2S;
164 time(<ime); /* Time since 1/1/70 */
165 movie->creation_time = (unsigned int) ltime + 2082844800; /* Seconds between 1/1/04 and 1/1/70 */
166 movie->timescale = 1000;
168 movie->rate = 1 << 16; /* Rate to play presentation (default = 0x00010000) */
169 movie->volume = 1 << 8; /* Movie volume (default = 0x0100) */
170 movie->trans_matrix[0] = 0x00010000; /* Transformation matrix for video */
171 movie->trans_matrix[1] = 0; /* Unity is { 0x00010000,0,0,0,0x00010000,0,0,0,0x40000000 } */
172 movie->trans_matrix[2] = 0;
173 movie->trans_matrix[3] = 0;
174 movie->trans_matrix[4] = 0x00010000;
175 movie->trans_matrix[5] = 0;
176 movie->trans_matrix[6] = 0;
177 movie->trans_matrix[7] = 0;
178 movie->trans_matrix[8] = 0x40000000;
179 movie->next_tk_id = 1;
181 for (i = 0; i < movie->num_htk + movie->num_stk + movie->num_vtk; i++) {
182 mj2_tk_t *tk = &movie->tk[i];
184 tk->jp2_struct.comps = NULL;
185 tk->jp2_struct.cl = NULL;
187 if (tk->track_type == 0) {
188 if (tk->num_samples == 0)
194 tk->timescale = 1000; /* Timescale = 1 ms */
196 tk->chunk[0].num_samples = 1;
197 tk->chunk[0].sample_descr_idx = 1;
199 tk->same_sample_size = 0;
201 tk->num_samplestochunk = 1; /* One sample per chunk */
203 (mj2_sampletochunk_t *) malloc(tk->num_samplestochunk *
204 sizeof(mj2_sampletochunk_t));
205 tk->sampletochunk[0].first_chunk = 1;
206 tk->sampletochunk[0].samples_per_chunk = 1;
207 tk->sampletochunk[0].sample_descr_idx = 1;
209 for (j = 0; j < tk->num_samples; j++) {
210 if (tk->sample_rate == 0)
211 tk->sample_rate = 25;
212 tk->sample[j].sample_delta = tk->timescale / tk->sample_rate;
216 tk->tts = (mj2_tts_t *) malloc(tk->num_tts * sizeof(mj2_tts_t));
217 tk->tts[0].sample_count = tk->num_samples;
218 tk->tts[0].sample_delta = tk->timescale / tk->sample_rate;
220 tk->horizresolution = 0x00480000; /* Horizontal resolution (typically 72) */
221 tk->vertresolution = 0x00480000; /* Vertical resolution (typically 72) */
222 tk->compressorname[0] = 0x0f4d6f74; /* Compressor Name[]: Motion JPEG2000 */
223 tk->compressorname[1] = 0x696f6e20;
224 tk->compressorname[2] = 0x4a504547;
225 tk->compressorname[3] = 0x32303030;
226 tk->compressorname[4] = 0x00120000;
227 tk->compressorname[5] = 0;
228 tk->compressorname[6] = 0x00000042;
229 tk->compressorname[7] = 0x000000DC;
230 tk->num_url = 0; /* Number of URL */
231 tk->num_urn = 0; /* Number of URN */
232 tk->graphicsmode = 0; /* Graphicsmode */
233 tk->opcolor[0] = 0; /* OpColor */
234 tk->opcolor[1] = 0; /* OpColor */
235 tk->opcolor[2] = 0; /* OpColor */
236 tk->creation_time = movie->creation_time; /* Seconds between 1/1/04 and 1/1/70 */
237 tk->language = 0; /* Language (undefined) */
239 tk->volume = 1 << 8; /* Movie volume (default = 0x0100) */
240 tk->trans_matrix[0] = 0x00010000; /* Transformation matrix for track */
241 tk->trans_matrix[1] = 0; /* Unity is { 0x00010000,0,0,0,0x00010000,0,0,0,0x40000000 } */
242 tk->trans_matrix[2] = 0;
243 tk->trans_matrix[3] = 0;
244 tk->trans_matrix[4] = 0x00010000;
245 tk->trans_matrix[5] = 0;
246 tk->trans_matrix[6] = 0;
247 tk->trans_matrix[7] = 0;
248 tk->trans_matrix[8] = 0x40000000;
251 tk->or_fieldcount = 1;
252 tk->or_fieldorder = 0;
254 tk->br = (unsigned int *) malloc(tk->num_br * sizeof(unsigned int));
256 tk->br[1] = MJ2_J2P0;
258 tk->hsub = 2; /* 4:2:0 */
259 tk->vsub = 2; /* 4:2:0 */
262 tk->visual_w = tk->w << 16;
263 tk->visual_h = tk->h << 16;
274 * Time To Sample box Decompact
277 void mj2_tts_decompact(mj2_tk_t * tk)
281 for (i = 0; i < tk->num_tts; i++) {
282 tk->num_samples += tk->tts[i].sample_count;
286 (mj2_sample_t *) malloc(tk->num_samples * sizeof(mj2_sample_t));
288 for (i = 0; i < tk->num_tts; i++) {
289 for (j = 0; j < tk->tts[i].sample_count; j++) {
290 tk->sample[j].sample_delta = tk->tts[i].sample_delta;
296 * Sample To Chunk box Decompact
299 void mj2_stsc_decompact(mj2_tk_t * tk)
305 if (tk->num_samplestochunk == 1) {
307 (unsigned int) ceil((double) tk->num_samples /
308 (double) tk->sampletochunk[0].samples_per_chunk);
310 (mj2_chunk_t *) malloc(tk->num_chunks * sizeof(mj2_chunk_t));
311 for (k = 0; k < tk->num_chunks; k++) {
312 tk->chunk[k].num_samples = tk->sampletochunk[0].samples_per_chunk;
317 (mj2_chunk_t *) malloc(tk->num_samples * sizeof(mj2_chunk_t));
319 for (i = 0; i < tk->num_samplestochunk -1 ; i++) {
320 for (j = tk->sampletochunk[i].first_chunk - 1;
321 j < tk->sampletochunk[i + 1].first_chunk - 1; j++) {
322 tk->chunk[j].num_samples = tk->sampletochunk[i].samples_per_chunk;
324 sampleno += tk->chunk[j].num_samples;
327 tk->num_chunks += (int)(tk->num_samples - sampleno) / tk->sampletochunk[tk->num_samplestochunk - 1].samples_per_chunk;
328 for (k = tk->sampletochunk[tk->num_samplestochunk - 1].first_chunk - 1;
329 k < tk->num_chunks; k++) {
330 tk->chunk[k].num_samples =
331 tk->sampletochunk[tk->num_samplestochunk - 1].samples_per_chunk;
333 tk->chunk = realloc(tk->chunk, tk->num_chunks * sizeof(mj2_chunk_t));
340 * Chunk offset box Decompact
343 void mj2_stco_decompact(mj2_tk_t * tk)
348 int intra_chunk_offset;
350 for (i = 0; i < tk->num_chunks; i++) {
351 intra_chunk_offset = 0;
352 for (j = 0; j < tk->chunk[i].num_samples; j++) {
353 tk->sample[k].offset = intra_chunk_offset + tk->chunk[i].offset;
354 intra_chunk_offset += tk->sample[k].sample_size;
369 box.init_pos = cio_tell();
372 cio_write(MJ2_JP, 4); /* JP */
373 cio_write(0x0d0a870a, 4); /* 0x0d0a870a required in a JP box */
375 box.length = cio_tell() - box.init_pos;
376 cio_seek(box.init_pos);
377 cio_write(box.length, 4);
378 cio_seek(box.init_pos + box.length);
384 * JPEG 2000 signature
391 mj2_read_boxhdr(&box);
392 if (MJ2_JP != box.type) { /* Check Marker */
393 fprintf(stderr, "Error: Expected JP Marker\n");
396 if (0x0d0a870a != cio_read(4)) { /* read the 0x0d0a870a required in a JP box */
397 fprintf(stderr, "Error with JP Marker\n");
400 if (cio_tell() - box.init_pos != box.length) { /* Check box length */
401 fprintf(stderr, "Error with JP Box size \n");
414 void mj2_write_ftyp(mj2_movie_t * movie)
418 box.init_pos = cio_tell();
421 cio_write(MJ2_FTYP, 4); /* FTYP */
422 cio_write(movie->brand, 4); /* BR */
423 cio_write(movie->minversion, 4); /* MinV */
425 for (i = 0; i < movie->num_cl; i++)
426 cio_write(movie->cl[i], 4); /* CL */
428 box.length = cio_tell() - box.init_pos;
429 cio_seek(box.init_pos);
430 cio_write(box.length, 4); /* Length */
431 cio_seek(box.init_pos + box.length);
440 int mj2_read_ftyp(mj2_movie_t * movie)
445 mj2_read_boxhdr(&box); /* Box Size */
446 if (MJ2_FTYP != box.type) {
447 fprintf(stderr, "Error: Expected FTYP Marker\n");
451 movie->brand = cio_read(4); /* BR */
452 movie->minversion = cio_read(4); /* MinV */
453 movie->num_cl = (box.length - 16) / 4;
455 (unsigned int *) malloc(movie->num_cl * sizeof(unsigned int));
457 for (i = movie->num_cl - 1; i > -1; i--)
458 movie->cl[i] = cio_read(4); /* CLi */
460 if (cio_tell() - box.init_pos != box.length) {
461 fprintf(stderr, "Error with FTYP Box\n");
474 void mj2_write_stco(mj2_tk_t * tk)
479 box.init_pos = cio_tell();
481 cio_write(MJ2_STCO, 4); /* STCO */
483 cio_write(0, 4); /* Version = 0, flags = 0 */
485 cio_write(tk->num_chunks, 4); /* Entry Count */
487 for (i = 0; i < tk->num_chunks; i++) {
488 cio_write(tk->chunk[i].offset, 4); /* Entry offset */
491 box.length = cio_tell() - box.init_pos;
492 cio_seek(box.init_pos);
493 cio_write(box.length, 4); /* L */
494 cio_seek(box.init_pos + box.length);
503 int mj2_read_stco(mj2_tk_t * tk)
508 mj2_read_boxhdr(&box); /* Box Size */
509 if (MJ2_STCO != box.type) {
510 fprintf(stderr, "Error: Expected STCO Marker\n");
514 if (0 != cio_read(1)) { /* Version = 0 */
515 fprintf(stderr, "Error: Only Version 0 handled in STCO box\n");
519 if (0 != cio_read(3)) { /* Flags = 0 */
520 fprintf(stderr, "Error with flag in STCO box. Expected flag 0\n");
525 if (cio_read(4) != tk->num_chunks) {
527 "Error in STCO box: expecting same amount of entry-count as chunks \n");
529 for (i = 0; i < tk->num_chunks; i++) {
530 tk->chunk[i].offset = cio_read(4); /* Entry offset */
534 mj2_stco_decompact(tk);
537 if (cio_tell() - box.init_pos != box.length) {
538 fprintf(stderr, "Error with STCO Box size\n");
550 void mj2_write_stsz(mj2_tk_t * tk)
555 box.init_pos = cio_tell();
557 cio_write(MJ2_STSZ, 4); /* STSZ */
559 cio_write(0, 4); /* Version = 0, flags = 0 */
561 if (tk->same_sample_size == 1) { /* If they all have the same size */
562 cio_write(tk->sample[0].sample_size, 4); /* Size */
564 cio_write(1, 4); /* Entry count = 1 */
568 cio_write(0, 4); /* Sample Size = 0 becase they all have different sizes */
570 cio_write(tk->num_samples, 4); /* Sample Count */
572 for (i = 0; i < tk->num_samples; i++) {
573 cio_write(tk->sample[i].sample_size, 4);
577 box.length = cio_tell() - box.init_pos;
578 cio_seek(box.init_pos);
579 cio_write(box.length, 4); /* L */
580 cio_seek(box.init_pos + box.length);
589 int mj2_read_stsz(mj2_tk_t * tk)
595 mj2_read_boxhdr(&box); /* Box Size */
596 if (MJ2_STSZ != box.type) {
597 fprintf(stderr, "Error: Expected STSZ Marker\n");
602 if (0 != cio_read(1)) { /* Version = 0 */
603 fprintf(stderr, "Error: Only Version 0 handled in STSZ box\n");
607 if (0 != cio_read(3)) { /* Flags = 0 */
608 fprintf(stderr, "Error with flag in STSZ box. Expected flag 0\n");
612 sample_size = cio_read(4);
614 if (sample_size != 0) { /* Samples do have the same size */
615 tk->same_sample_size = 1;
616 for (i = 0; i < tk->num_samples; i++) {
617 tk->sample[i].sample_size = sample_size;
619 cio_skip(4); /* Sample count = 1 */
621 tk->same_sample_size = 0;
622 if (tk->num_samples != cio_read(4)) { /* Sample count */
624 "Error in STSZ box. Expected that sample-count is number of samples in track\n");
627 for (i = 0; i < tk->num_samples; i++) {
628 tk->sample[i].sample_size = cio_read(4); /* Sample Size */
631 if (cio_tell() - box.init_pos != box.length) {
632 fprintf(stderr, "Error with STSZ Box size\n");
646 void mj2_write_stsc(mj2_tk_t * tk)
651 box.init_pos = cio_tell();
653 cio_write(MJ2_STSC, 4); /* STSC */
655 cio_write(0, 4); /* Version = 0, flags = 0 */
657 cio_write(tk->num_samplestochunk, 4); /* Entry Count */
659 for (i = 0; i < tk->num_samplestochunk; i++) {
660 cio_write(tk->sampletochunk[i].first_chunk, 4); /* First Chunk */
661 cio_write(tk->sampletochunk[i].samples_per_chunk, 4); /* Samples per chunk */
662 cio_write(tk->sampletochunk[i].sample_descr_idx, 4); /* Samples description index */
666 box.length = cio_tell() - box.init_pos;
667 cio_seek(box.init_pos);
668 cio_write(box.length, 4); /* L */
669 cio_seek(box.init_pos + box.length);
678 int mj2_read_stsc(mj2_tk_t * tk)
683 mj2_read_boxhdr(&box); /* Box Size */
684 if (MJ2_STSC != box.type) {
685 fprintf(stderr, "Error: Expected STSC Marker\n");
690 if (0 != cio_read(1)) { /* Version = 0 */
691 fprintf(stderr, "Error: Only Version 0 handled in STSC box\n");
695 if (0 != cio_read(3)) { /* Flags = 0 */
696 fprintf(stderr, "Error with flag in STSC box. Expected flag 0\n");
700 tk->num_samplestochunk = cio_read(4);
703 (mj2_sampletochunk_t *) malloc(tk->num_samplestochunk *
704 sizeof(mj2_sampletochunk_t));
707 for (i = 0; i < tk->num_samplestochunk; i++) {
708 tk->sampletochunk[i].first_chunk = cio_read(4);
709 tk->sampletochunk[i].samples_per_chunk = cio_read(4);
710 tk->sampletochunk[i].sample_descr_idx = cio_read(4);
713 mj2_stsc_decompact(tk); /* decompact sample to chunk box */
716 if (cio_tell() - box.init_pos != box.length) {
717 fprintf(stderr, "Error with STSC Box size\n");
729 void mj2_write_stts(mj2_tk_t * tk)
735 box.init_pos = cio_tell();
737 cio_write(MJ2_STTS, 4); /* STTS */
739 cio_write(0, 4); /* Version = 0, flags = 0 */
741 cio_write(tk->num_tts, 4); /* entry_count */
742 for (i = 0; i < tk->num_tts; i++) {
743 cio_write(tk->tts[i].sample_count, 4); /* Sample-count */
744 cio_write(tk->tts[i].sample_delta, 4); /* Sample-Delta */
747 box.length = cio_tell() - box.init_pos;
748 cio_seek(box.init_pos);
749 cio_write(box.length, 4); /* L */
750 cio_seek(box.init_pos + box.length);
759 int mj2_read_stts(mj2_tk_t * tk)
765 mj2_read_boxhdr(&box);
766 if (MJ2_STTS != box.type) {
767 fprintf(stderr, "Error: Expected STTS Marker\n");
772 if (0 != cio_read(1)) { /* Version = 0 */
773 fprintf(stderr, "Error: Only Version 0 handled in STTS box\n");
777 if (0 != cio_read(3)) { /* Flags = 0 */
778 fprintf(stderr, "Error with flag in STTS box. Expected flag 0\n");
782 tk->num_tts = cio_read(4);
784 tk->tts = (mj2_tts_t *) malloc(tk->num_tts * sizeof(mj2_tts_t));
786 for (i = 0; i < tk->num_tts; i++) {
787 tk->tts[i].sample_count = cio_read(4);
788 tk->tts[i].sample_delta = cio_read(4);
791 mj2_tts_decompact(tk);
793 if (cio_tell() - box.init_pos != box.length) {
794 fprintf(stderr, "Error with STTS Box size\n");
806 void mj2_write_fiel(mj2_tk_t * tk)
811 box.init_pos = cio_tell();
813 cio_write(MJ2_FIEL, 4); /* STTS */
815 cio_write(tk->fieldcount, 1); /* Field count */
816 cio_write(tk->fieldorder, 1); /* Field order */
819 box.length = cio_tell() - box.init_pos;
820 cio_seek(box.init_pos);
821 cio_write(box.length, 4); /* L */
822 cio_seek(box.init_pos + box.length);
831 int mj2_read_fiel(mj2_tk_t * tk)
836 mj2_read_boxhdr(&box);
837 if (MJ2_FIEL != box.type) {
838 fprintf(stderr, "Error: Expected FIEL Marker\n");
843 tk->fieldcount = cio_read(1);
844 tk->fieldorder = cio_read(1);
846 if (cio_tell() - box.init_pos != box.length) {
847 fprintf(stderr, "Error with FIEL Box size\n");
856 * Original Format Box
859 void mj2_write_orfo(mj2_tk_t * tk)
863 box.init_pos = cio_tell();
865 cio_write(MJ2_ORFO, 4);
867 cio_write(tk->or_fieldcount, 1); /* Original Field count */
868 cio_write(tk->or_fieldorder, 1); /* Original Field order */
871 box.length = cio_tell() - box.init_pos;
872 cio_seek(box.init_pos);
873 cio_write(box.length, 4); /* L */
874 cio_seek(box.init_pos + box.length);
880 * Original Format Box
883 int mj2_read_orfo(mj2_tk_t * tk)
888 mj2_read_boxhdr(&box);
889 if (MJ2_ORFO != box.type) {
890 fprintf(stderr, "Error: Expected ORFO Marker\n");
895 tk->or_fieldcount = cio_read(1);
896 tk->or_fieldorder = cio_read(1);
898 if (cio_tell() - box.init_pos != box.length) {
899 fprintf(stderr, "Error with ORFO Box size\n");
911 void mj2_write_jp2p(mj2_tk_t * tk)
917 box.init_pos = cio_tell();
919 cio_write(MJ2_JP2P, 4);
921 cio_write(0, 4); /* Version 0, flags =0 */
923 for (i = 0; i < tk->num_br; i++) {
924 cio_write(tk->br[i], 4);
927 box.length = cio_tell() - box.init_pos;
928 cio_seek(box.init_pos);
929 cio_write(box.length, 4); /* L */
930 cio_seek(box.init_pos + box.length);
939 int mj2_read_jp2p(mj2_tk_t * tk)
945 mj2_read_boxhdr(&box);
946 if (MJ2_JP2P != box.type) {
947 fprintf(stderr, "Error: Expected JP2P Marker\n");
951 if (0 != cio_read(1)) { /* Version = 0 */
952 fprintf(stderr, "Error: Only Version 0 handled in JP2P box\n");
956 if (0 != cio_read(3)) { /* Flags = 0 */
957 fprintf(stderr, "Error with flag in JP2P box. Expected flag 0\n");
962 tk->num_br = (box.length - 12) / 4;
963 tk->br = (unsigned int *) malloc(tk->num_br * sizeof(unsigned int));
965 for (i = 0; i < tk->num_br; i++) {
966 tk->br[i] = cio_read(4);
969 if (cio_tell() - box.init_pos != box.length) {
970 fprintf(stderr, "Error with JP2P Box size\n");
982 void mj2_write_jp2x(mj2_tk_t * tk)
988 box.init_pos = cio_tell();
990 cio_write(MJ2_JP2X, 4);
992 for (i = 0; i < tk->num_jp2x; i++) {
993 cio_write(tk->jp2xdata[i], 1);
996 box.length = cio_tell() - box.init_pos;
997 cio_seek(box.init_pos);
998 cio_write(box.length, 4); /* L */
999 cio_seek(box.init_pos + box.length);
1008 int mj2_read_jp2x(mj2_tk_t * tk)
1014 mj2_read_boxhdr(&box);
1015 if (MJ2_JP2X != box.type) {
1016 fprintf(stderr, "Error: Expected JP2X Marker\n");
1021 tk->num_jp2x = (box.length - 8);
1023 (unsigned char *) malloc(tk->num_jp2x * sizeof(unsigned char));
1025 for (i = 0; i < tk->num_jp2x; i++) {
1026 tk->jp2xdata[i] = cio_read(1);
1029 if (cio_tell() - box.init_pos != box.length) {
1030 fprintf(stderr, "Error with JP2X Box size\n");
1037 * Write the JSUB box
1039 * MJP2 Subsampling Box
1042 void mj2_write_jsub(mj2_tk_t * tk)
1047 box.init_pos = cio_tell();
1049 cio_write(MJ2_JSUB, 4);
1051 cio_write(tk->hsub, 1);
1052 cio_write(tk->vsub, 1);
1053 cio_write(tk->hoff, 1);
1054 cio_write(tk->voff, 1);
1056 box.length = cio_tell() - box.init_pos;
1057 cio_seek(box.init_pos);
1058 cio_write(box.length, 4); /* L */
1059 cio_seek(box.init_pos + box.length);
1065 * MJP2 Subsampling Box
1068 int mj2_read_jsub(mj2_tk_t * tk)
1072 mj2_read_boxhdr(&box);
1073 if (MJ2_JSUB != box.type) {
1074 fprintf(stderr, "Error: Expected JSUB Marker\n");
1078 tk->hsub = cio_read(1);
1079 tk->vsub = cio_read(1);
1080 tk->hoff = cio_read(1);;
1081 tk->voff = cio_read(1);
1083 if (cio_tell() - box.init_pos != box.length) {
1084 fprintf(stderr, "Error with JSUB Box size\n");
1091 * Write the SMJ2 box
1093 * Visual Sample Entry Description
1096 void mj2_write_smj2(mj2_tk_t * tk)
1100 box.init_pos = cio_tell();
1102 cio_write(MJ2_MJ2, 4); /* MJ2 */
1104 cio_write(0, 4); /* Version = 0, flags = 0 */
1108 cio_write(0, 2); /* Pre-defined */
1110 cio_write(0, 2); /* Reserved */
1112 cio_write(0, 4); /* Pre-defined */
1113 cio_write(0, 4); /* Pre-defined */
1114 cio_write(0, 4); /* Pre-defined */
1116 cio_write(tk->w, 2); /* Width */
1117 cio_write(tk->h, 2); /* Height */
1119 cio_write(tk->horizresolution, 4); /* Horizontal resolution */
1120 cio_write(tk->vertresolution, 4); /* Vertical resolution */
1122 cio_write(0, 4); /* Reserved */
1124 cio_write(1, 2); /* Pre-defined = 1 */
1126 cio_write(tk->compressorname[0], 4); /* Compressor Name */
1127 cio_write(tk->compressorname[1], 4);
1128 cio_write(tk->compressorname[2], 4);
1129 cio_write(tk->compressorname[3], 4);
1130 cio_write(tk->compressorname[4], 4);
1131 cio_write(tk->compressorname[5], 4);
1132 cio_write(tk->compressorname[6], 4);
1133 cio_write(tk->compressorname[7], 4);
1135 cio_write(tk->depth, 2); /* Depth */
1137 cio_write(0xffff, 2); /* Pre-defined = -1 */
1139 jp2_write_jp2h(&tk->jp2_struct);
1143 if (tk->num_br != 0)
1145 if (tk->num_jp2x != 0)
1151 box.length = cio_tell() - box.init_pos;
1152 cio_seek(box.init_pos);
1153 cio_write(box.length, 4); /* L */
1154 cio_seek(box.init_pos + box.length);
1160 * Visual Sample Entry Description
1163 int mj2_read_smj2(j2k_image_t * img, mj2_tk_t * tk)
1169 mj2_read_boxhdr(&box);
1171 if (MJ2_MJ2 != box.type) {
1172 fprintf(stderr, "Error in SMJ2 box: Expected MJ2 Marker\n");
1176 if (0 != cio_read(1)) { /* Version = 0 */
1177 fprintf(stderr, "Error: Only Version 0 handled in MJP2 box\n");
1181 if (0 != cio_read(3)) { /* Flags = 0 */
1182 fprintf(stderr, "Error with flag in MJP2 box. Expected flag 0\n");
1188 cio_skip(2); /* Pre-defined */
1190 cio_skip(2); /* Reserved */
1192 cio_skip(4); /* Pre-defined */
1193 cio_skip(4); /* Pre-defined */
1194 cio_skip(4); /* Pre-defined */
1196 tk->w = cio_read(2); /* Width */
1197 tk->h = cio_read(2); /* Height */
1199 tk->horizresolution = cio_read(4); /* Horizontal resolution */
1200 tk->vertresolution = cio_read(4); /* Vertical resolution */
1202 cio_skip(4); /* Reserved */
1204 cio_skip(2); /* Pre-defined = 1 */
1206 tk->compressorname[0] = cio_read(4); /* Compressor Name */
1207 tk->compressorname[1] = cio_read(4);
1208 tk->compressorname[2] = cio_read(4);
1209 tk->compressorname[3] = cio_read(4);
1210 tk->compressorname[4] = cio_read(4);
1211 tk->compressorname[5] = cio_read(4);
1212 tk->compressorname[6] = cio_read(4);
1213 tk->compressorname[7] = cio_read(4);
1215 tk->depth = cio_read(2); /* Depth */
1217 /* Init std value */
1221 tk->or_fieldcount = 1;
1222 tk->or_fieldorder = 0;
1224 cio_skip(2); /* Pre-defined = -1 */
1226 if (jp2_read_jp2h(&tk->jp2_struct)) {
1227 fprintf(stderr, "Error with JP2H Box\n");
1231 tk->jp2_struct.comps = (jp2_comps_t *) malloc(tk->jp2_struct.numcomps * sizeof(jp2_comps_t));
1232 tk->jp2_struct.cl = (int *) malloc(sizeof(int));
1237 for (i = 0; cio_tell() - box.init_pos < box.length; i++) {
1238 mj2_read_boxhdr(&box2);
1239 cio_seek(box2.init_pos);
1240 switch (box2.type) {
1242 if (mj2_read_fiel(tk))
1247 if (mj2_read_jp2p(tk))
1252 if (mj2_read_jp2x(tk))
1257 if (mj2_read_jsub(tk))
1262 if (mj2_read_orfo(tk))
1267 fprintf(stderr, "Error with MJP2 Box size\n");
1278 * Write the STSD box
1280 * Sample Description
1283 void mj2_write_stsd(mj2_tk_t * tk)
1287 box.init_pos = cio_tell();
1289 cio_write(MJ2_STSD, 4); /* STSD */
1291 cio_write(0, 4); /* Version = 0, flags = 0 */
1293 cio_write(1, 4); /* entry_count = 1 (considering same JP2 headerboxes) */
1295 if (tk->track_type == 0) {
1297 } else if (tk->track_type == 1) {
1300 if (tk->track_type == 2) {
1305 box.length = cio_tell() - box.init_pos;
1306 cio_seek(box.init_pos);
1307 cio_write(box.length, 4); /* L */
1308 cio_seek(box.init_pos + box.length);
1314 * Sample Description
1317 int mj2_read_stsd(mj2_tk_t * tk, j2k_image_t * img)
1320 int entry_count, len_2skip;
1324 mj2_read_boxhdr(&box);
1326 if (MJ2_STSD != box.type) {
1327 fprintf(stderr, "Error: Expected STSD Marker\n");
1331 if (0 != cio_read(1)) { /* Version = 0 */
1332 fprintf(stderr, "Error: Only Version 0 handled in STSD box\n");
1336 if (0 != cio_read(3)) { /* Flags = 0 */
1337 fprintf(stderr, "Error with flag in STSD box. Expected flag 0\n");
1341 entry_count = cio_read(4);
1343 if (tk->track_type == 0) {
1344 for (i = 0; i < entry_count; i++) {
1345 if (mj2_read_smj2(img, tk))
1348 } else if (tk->track_type == 1) {
1349 len_2skip = cio_read(4); // Not implemented -> skipping box
1350 cio_skip(len_2skip - 4);
1351 } else if (tk->track_type == 2) {
1352 len_2skip = cio_read(4); // Not implemented -> skipping box
1353 cio_skip(len_2skip - 4);
1357 if (cio_tell() - box.init_pos != box.length) {
1358 fprintf(stderr, "Error with STSD Box size\n");
1365 * Write the STBL box
1367 * Sample table box box
1370 void mj2_write_stbl(mj2_tk_t * tk)
1374 box.init_pos = cio_tell();
1376 cio_write(MJ2_STBL, 4); /* STBL */
1384 box.length = cio_tell() - box.init_pos;
1385 cio_seek(box.init_pos);
1386 cio_write(box.length, 4); /* L */
1387 cio_seek(box.init_pos + box.length);
1393 * Sample table box box
1396 int mj2_read_stbl(mj2_tk_t * tk, j2k_image_t * img)
1400 mj2_read_boxhdr(&box);
1401 if (MJ2_STBL != box.type) {
1402 fprintf(stderr, "Error: Expected STBL Marker\n");
1406 if (mj2_read_stsd(tk, img))
1408 if (mj2_read_stts(tk))
1410 if (mj2_read_stsc(tk))
1412 if (mj2_read_stsz(tk))
1414 if (mj2_read_stco(tk))
1417 if (cio_tell() - box.init_pos != box.length) {
1418 fprintf(stderr, "Error with STBL Box size\n");
1430 void mj2_write_url(mj2_tk_t * tk, int url_num)
1434 box.init_pos = cio_tell();
1436 cio_write(MJ2_URL, 4); /* URL */
1439 cio_write(1, 4); /* Version = 0, flags = 1 because stored in same file */
1441 cio_write(0, 4); /* Version = 0, flags = 0 */
1442 cio_write(tk->url[url_num - 1].location[0], 4);
1443 cio_write(tk->url[url_num - 1].location[1], 4);
1444 cio_write(tk->url[url_num - 1].location[2], 4);
1445 cio_write(tk->url[url_num - 1].location[3], 4);
1448 box.length = cio_tell() - box.init_pos;
1449 cio_seek(box.init_pos);
1450 cio_write(box.length, 4); /* L */
1451 cio_seek(box.init_pos + box.length);
1460 int mj2_read_url(mj2_tk_t * tk, int urn_num)
1464 mj2_read_boxhdr(&box);
1465 if (MJ2_URL != box.type) {
1466 fprintf(stderr, "Error: Expected URL Marker\n");
1470 if (0 != cio_read(1)) { /* Version = 0 */
1471 fprintf(stderr, "Error: Only Version 0 handled in URL box\n");
1475 if (1 != cio_read(3)) { /* If flags = 1 --> media data in file */
1476 tk->url[urn_num].location[0] = cio_read(4);
1477 tk->url[urn_num].location[1] = cio_read(4);
1478 tk->url[urn_num].location[2] = cio_read(4);
1479 tk->url[urn_num].location[3] = cio_read(4);
1485 if (cio_tell() - box.init_pos != box.length) {
1486 fprintf(stderr, "Error with URL Box size\n");
1498 void mj2_write_urn(mj2_tk_t * tk, int urn_num)
1502 box.init_pos = cio_tell();
1504 cio_write(MJ2_URN, 4); /* URN */
1506 cio_write(0, 4); /* Version = 0, flags = 0 */
1508 cio_write(tk->urn[urn_num].name[0], 4);
1509 cio_write(tk->urn[urn_num].name[1], 4);
1510 cio_write(tk->urn[urn_num].name[2], 4);
1511 cio_write(tk->urn[urn_num].name[3], 4);
1512 cio_write(tk->urn[urn_num].location[0], 4);
1513 cio_write(tk->urn[urn_num].location[1], 4);
1514 cio_write(tk->urn[urn_num].location[2], 4);
1515 cio_write(tk->urn[urn_num].location[3], 4);
1517 box.length = cio_tell() - box.init_pos;
1518 cio_seek(box.init_pos);
1519 cio_write(box.length, 4); /* L */
1520 cio_seek(box.init_pos + box.length);
1529 int mj2_read_urn(mj2_tk_t * tk, int urn_num)
1534 mj2_read_boxhdr(&box);
1535 if (MJ2_URN != box.type) {
1536 fprintf(stderr, "Error: Expected URN Marker\n");
1540 if (0 != cio_read(1)) { /* Version = 0 */
1541 fprintf(stderr, "Error: Only Version 0 handled in URN box\n");
1545 if (1 != cio_read(3)) { /* If flags = 1 --> media data in file */
1546 tk->urn[urn_num].name[0] = cio_read(4);
1547 tk->urn[urn_num].name[1] = cio_read(4);
1548 tk->urn[urn_num].name[2] = cio_read(4);
1549 tk->urn[urn_num].name[3] = cio_read(4);
1550 tk->urn[urn_num].location[0] = cio_read(4);
1551 tk->urn[urn_num].location[1] = cio_read(4);
1552 tk->urn[urn_num].location[2] = cio_read(4);
1553 tk->urn[urn_num].location[3] = cio_read(4);
1557 if (cio_tell() - box.init_pos != box.length) {
1558 fprintf(stderr, "Error with URN Box size\n");
1566 * Write the DREF box
1568 * Data reference box
1571 void mj2_write_dref(mj2_tk_t * tk)
1576 box.init_pos = cio_tell();
1578 cio_write(MJ2_DREF, 4); /* DREF */
1580 cio_write(0, 4); /* Version = 0, flags = 0 */
1582 if (tk->num_url + tk->num_urn == 0) { /* Media data in same file */
1583 cio_write(1, 4); /* entry_count = 1 */
1584 mj2_write_url(tk, 0);
1586 cio_write(tk->num_url + tk->num_urn, 4); /* entry_count */
1588 for (i = 0; i < tk->num_url; i++)
1589 mj2_write_url(tk, i + 1);
1591 for (i = 0; i < tk->num_urn; i++)
1592 mj2_write_urn(tk, i);
1595 box.length = cio_tell() - box.init_pos;
1596 cio_seek(box.init_pos);
1597 cio_write(box.length, 4); /* L */
1598 cio_seek(box.init_pos + box.length);
1604 * Data reference box
1607 int mj2_read_dref(mj2_tk_t * tk)
1611 int entry_count, marker;
1614 mj2_read_boxhdr(&box);
1615 if (MJ2_DREF != box.type) {
1616 fprintf(stderr, "Error: Expected DREF Marker\n");
1620 if (0 != cio_read(1)) { /* Version = 0 */
1621 fprintf(stderr, "Error: Only Version 0 handled in DREF box\n");
1625 if (0 != cio_read(3)) { /* Flags = 0 */
1626 fprintf(stderr, "Error with flag in DREF box. Expected flag 0\n");
1630 entry_count = cio_read(4);
1634 for (i = 0; i < entry_count; i++) {
1636 marker = cio_read(4);
1637 if (marker == MJ2_URL) {
1640 if (mj2_read_url(tk, tk->num_url))
1642 } else if (marker == MJ2_URN) {
1645 if (mj2_read_urn(tk, tk->num_urn))
1648 fprintf(stderr, "Error with in DREF box. Expected URN or URL box\n");
1655 if (cio_tell() - box.init_pos != box.length) {
1656 fprintf(stderr, "Error with DREF Box size\n");
1663 * Write the DINF box
1665 * Data information box
1668 void mj2_write_dinf(mj2_tk_t * tk)
1672 box.init_pos = cio_tell();
1674 cio_write(MJ2_DINF, 4); /* DINF */
1678 box.length = cio_tell() - box.init_pos;
1679 cio_seek(box.init_pos);
1680 cio_write(box.length, 4); /* L */
1681 cio_seek(box.init_pos + box.length);
1687 * Data information box
1690 int mj2_read_dinf(mj2_tk_t * tk)
1694 mj2_read_boxhdr(&box);
1695 if (MJ2_DINF != box.type) {
1696 fprintf(stderr, "Error: Expected DINF Marker\n");
1700 if (mj2_read_dref(tk))
1703 if (cio_tell() - box.init_pos != box.length) {
1704 fprintf(stderr, "Error with DINF Box size\n");
1711 * Write the VMHD box
1713 * Video Media information box
1716 void mj2_write_vmhd(mj2_tk_t * tk)
1720 box.init_pos = cio_tell();
1722 cio_write(MJ2_VMHD, 4); /* VMHD */
1724 cio_write(1, 4); /* Version = 0, flags = 1 */
1726 cio_write(tk->graphicsmode, 2);
1727 cio_write(tk->opcolor[0], 2);
1728 cio_write(tk->opcolor[1], 2);
1729 cio_write(tk->opcolor[2], 2);
1731 box.length = cio_tell() - box.init_pos;
1732 cio_seek(box.init_pos);
1733 cio_write(box.length, 4); /* L */
1734 cio_seek(box.init_pos + box.length);
1740 * Video Media information box
1743 int mj2_read_vmhd(mj2_tk_t * tk)
1747 mj2_read_boxhdr(&box);
1748 if (MJ2_VMHD != box.type) {
1749 fprintf(stderr, "Error: Expected VMHD Marker\n");
1753 if (0 != cio_read(1)) { /* Version = 0 */
1754 fprintf(stderr, "Error: Only Version 0 handled in VMHD box\n");
1758 if (1 != cio_read(3)) { /* Flags = 1 */
1759 fprintf(stderr, "Error with flag in VMHD box. Expected flag 1\n");
1764 tk->graphicsmode = cio_read(2);
1765 tk->opcolor[0] = cio_read(2);
1766 tk->opcolor[1] = cio_read(2);
1767 tk->opcolor[2] = cio_read(2);
1769 if (cio_tell() - box.init_pos != box.length) {
1770 fprintf(stderr, "Error with VMHD Box size\n");
1777 * Write the SMHD box
1779 * Sound Media information box
1782 void mj2_write_smhd(mj2_tk_t * tk)
1786 box.init_pos = cio_tell();
1788 cio_write(MJ2_SMHD, 4); /* SMHD */
1790 cio_write(0, 4); /* Version = 0, flags = 0 */
1792 cio_write(tk->balance, 2);
1794 cio_write(0, 2); /* Reserved */
1796 box.length = cio_tell() - box.init_pos;
1797 cio_seek(box.init_pos);
1798 cio_write(box.length, 4); /* L */
1799 cio_seek(box.init_pos + box.length);
1805 * Sound Media information box
1808 int mj2_read_smhd(mj2_tk_t * tk)
1812 mj2_read_boxhdr(&box);
1813 if (MJ2_SMHD != box.type) {
1814 fprintf(stderr, "Error: Expected SMHD Marker\n");
1818 if (0 != cio_read(1)) { /* Version = 0 */
1819 fprintf(stderr, "Error: Only Version 0 handled in SMHD box\n");
1823 if (0 != cio_read(3)) { /* Flags = 0 */
1824 fprintf(stderr, "Error with flag in SMHD box. Expected flag 0\n");
1829 tk->balance = cio_read(2);
1831 cio_skip(2); /* Reserved */
1833 if (cio_tell() - box.init_pos != box.length) {
1834 fprintf(stderr, "Error with SMHD Box size\n");
1841 * Write the HMHD box
1843 * Hint Media information box
1846 void mj2_write_hmhd(mj2_tk_t * tk)
1850 box.init_pos = cio_tell();
1852 cio_write(MJ2_HMHD, 4); /* HMHD */
1854 cio_write(0, 4); /* Version = 0, flags = 0 */
1856 cio_write(tk->maxPDUsize, 2);
1857 cio_write(tk->avgPDUsize, 2);
1858 cio_write(tk->maxbitrate, 4);
1859 cio_write(tk->avgbitrate, 4);
1860 cio_write(tk->slidingavgbitrate, 4);
1862 box.length = cio_tell() - box.init_pos;
1863 cio_seek(box.init_pos);
1864 cio_write(box.length, 4); /* L */
1865 cio_seek(box.init_pos + box.length);
1871 * Hint Media information box
1874 int mj2_read_hmhd(mj2_tk_t * tk)
1878 mj2_read_boxhdr(&box);
1879 if (MJ2_HMHD != box.type) {
1880 fprintf(stderr, "Error: Expected HMHD Marker\n");
1884 if (0 != cio_read(1)) { /* Version = 0 */
1885 fprintf(stderr, "Error: Only Version 0 handled in HMHD box\n");
1889 if (0 != cio_read(3)) { /* Flags = 0 */
1890 fprintf(stderr, "Error with flag in HMHD box. Expected flag 0\n");
1895 tk->maxPDUsize = cio_read(2);
1896 tk->avgPDUsize = cio_read(2);
1897 tk->maxbitrate = cio_read(4);
1898 tk->avgbitrate = cio_read(4);
1899 tk->slidingavgbitrate = cio_read(4);
1901 if (cio_tell() - box.init_pos != box.length) {
1902 fprintf(stderr, "Error with HMHD Box size\n");
1909 * Write the MINF box
1911 * Media information box
1914 void mj2_write_minf(mj2_tk_t * tk)
1918 box.init_pos = cio_tell();
1920 cio_write(MJ2_MINF, 4); /* MINF */
1922 if (tk->track_type == 0) {
1924 } else if (tk->track_type == 1) {
1926 } else if (tk->track_type == 2) {
1933 box.length = cio_tell() - box.init_pos;
1934 cio_seek(box.init_pos);
1935 cio_write(box.length, 4); /* L */
1936 cio_seek(box.init_pos + box.length);
1942 * Media information box
1945 int mj2_read_minf(mj2_tk_t * tk, j2k_image_t * img)
1948 unsigned int box_type;
1951 mj2_read_boxhdr(&box);
1952 if (MJ2_MINF != box.type) {
1953 fprintf(stderr, "Error: Expected MINF Marker\n");
1958 box_type = cio_read(4);
1961 if (box_type == MJ2_VMHD) {
1962 if (mj2_read_vmhd(tk))
1964 } else if (box_type == MJ2_SMHD) {
1965 if (mj2_read_smhd(tk))
1967 } else if (box_type == MJ2_HMHD) {
1968 if (mj2_read_hmhd(tk))
1971 fprintf(stderr, "Error in MINF box expected vmhd, smhd or hmhd\n");
1975 if (mj2_read_dinf(tk))
1978 if (mj2_read_stbl(tk, img))
1981 if (cio_tell() - box.init_pos != box.length) {
1982 fprintf(stderr, "Error with MINF Box size\n");
1989 * Write the HDLR box
1991 * Handler reference box
1994 void mj2_write_hdlr(mj2_tk_t * tk)
1998 box.init_pos = cio_tell();
2000 cio_write(MJ2_HDLR, 4); /* HDLR */
2002 cio_write(0, 4); /* Version = 0, flags = 0 */
2004 cio_write(0, 4); /* Predefine */
2006 tk->name = 0; /* The track name is immediately determined by the track type */
2008 if (tk->track_type == 0) {
2009 tk->handler_type = 0x76696465; /* Handler type: vide */
2010 cio_write(tk->handler_type, 4);
2014 cio_write(0, 4); /* Reserved */
2016 cio_write(0x76696465, 4);
2017 cio_write(0x6F206d65, 4);
2018 cio_write(0x64696120, 4);
2019 cio_write(0x74726163, 4);
2020 cio_write(0x6b00, 2); /* String: video media track */
2021 } else if (tk->track_type == 1) {
2022 tk->handler_type = 0x736F756E; /* Handler type: soun */
2023 cio_write(tk->handler_type, 4);
2027 cio_write(0, 4); /* Reserved */
2029 cio_write(0x536F756E, 4);
2030 cio_write(0x6400, 2); /* String: Sound */
2031 } else if (tk->track_type == 2) {
2032 tk->handler_type = 0x68696E74; /* Handler type: hint */
2033 cio_write(tk->handler_type, 4);
2037 cio_write(0, 4); /* Reserved */
2039 cio_write(0x48696E74, 4);
2040 cio_write(0, 2); /* String: Hint */
2043 box.length = cio_tell() - box.init_pos;
2044 cio_seek(box.init_pos);
2045 cio_write(box.length, 4); /* L */
2046 cio_seek(box.init_pos + box.length);
2052 * Handler reference box
2055 int mj2_read_hdlr(mj2_tk_t * tk)
2060 mj2_read_boxhdr(&box);
2061 if (MJ2_HDLR != box.type) {
2062 fprintf(stderr, "Error: Expected HDLR Marker\n");
2067 if (0 != cio_read(1)) { /* Version = 0 */
2068 fprintf(stderr, "Error: Only Version 0 handled in HDLR box\n");
2072 if (0 != cio_read(3)) { /* Flags = 0 */
2073 fprintf(stderr, "Error with flag in HDLR box. Expected flag 0\n");
2077 cio_skip(4); /* Reserved */
2079 tk->handler_type = cio_read(4);
2080 cio_skip(12); /* Reserved */
2082 tk->name_size = box.length - 32;
2084 tk->name = (char *) malloc(tk->name_size * sizeof(char));
2085 for (i = 0; i < tk->name_size; i++) {
2086 tk->name[i] = cio_read(1); /* Name */
2089 if (cio_tell() - box.init_pos != box.length) {
2090 fprintf(stderr, "Error with HDLR Box size\n");
2097 * Write the MDHD box
2102 void mj2_write_mdhd(mj2_tk_t * tk)
2107 unsigned int modification_time;
2109 box.init_pos = cio_tell();
2111 cio_write(MJ2_MDHD, 4); /* MDHD */
2113 cio_write(0, 4); /* Version = 0, flags = 0 */
2115 cio_write(tk->creation_time, 4); /* Creation Time */
2117 time(<ime); /* Time since 1/1/70 */
2118 modification_time = ltime + 2082844800; /* Seoonds between 1/1/04 and 1/1/70 */
2120 cio_write(modification_time, 4); /* Modification Time */
2122 cio_write(tk->timescale, 4); /* Timescale */
2126 for (i = 0; i < tk->num_samples; i++)
2127 tk->duration += tk->sample[i].sample_delta;
2129 cio_write(tk->duration, 4); /* Duration */
2131 cio_write(tk->language, 2); /* Language */
2133 cio_write(0, 2); /* Predefined */
2135 box.length = cio_tell() - box.init_pos;
2136 cio_seek(box.init_pos);
2137 cio_write(box.length, 4); /* L */
2138 cio_seek(box.init_pos + box.length);
2147 int mj2_read_mdhd(mj2_tk_t * tk)
2151 mj2_read_boxhdr(&box);
2152 if (!(MJ2_MHDR == box.type || MJ2_MDHD == box.type)) { // Kakadu writes MHDR instead of MDHD
2153 fprintf(stderr, "Error: Expected MDHD Marker\n");
2157 if (0 != cio_read(1)) { /* Version = 0 */
2158 fprintf(stderr, "Error: Only Version 0 handled in MDHD box\n");
2162 if (0 != cio_read(3)) { /* Flags = 0 */
2163 fprintf(stderr, "Error with flag in MDHD box. Expected flag 0\n");
2168 tk->creation_time = cio_read(4); /* Creation Time */
2170 tk->modification_time = cio_read(4); /* Modification Time */
2172 tk->timescale = cio_read(4); /* Timescale */
2174 tk->duration = cio_read(4); /* Duration */
2176 tk->language = cio_read(2); /* Language */
2178 cio_skip(2); /* Predefined */
2180 if (cio_tell() - box.init_pos != box.length) {
2181 fprintf(stderr, "Error with MDHD Box size\n");
2188 * Write the MDIA box
2193 void mj2_write_mdia(mj2_tk_t * tk)
2197 box.init_pos = cio_tell();
2199 cio_write(MJ2_MDIA, 4); /* MDIA */
2205 box.length = cio_tell() - box.init_pos;
2206 cio_seek(box.init_pos);
2207 cio_write(box.length, 4); /* L */
2208 cio_seek(box.init_pos + box.length);
2217 int mj2_read_mdia(mj2_tk_t * tk, j2k_image_t * img)
2221 mj2_read_boxhdr(&box);
2222 if (MJ2_MDIA != box.type) {
2223 fprintf(stderr, "Error: Expected MDIA Marker\n");
2227 if (mj2_read_mdhd(tk))
2229 if (mj2_read_hdlr(tk))
2231 if (mj2_read_minf(tk, img))
2234 if (cio_tell() - box.init_pos != box.length) {
2235 fprintf(stderr, "Error with MDIA Box size\n");
2242 * Write the TKHD box
2247 void mj2_write_tkhd(mj2_tk_t * tk)
2253 box.init_pos = cio_tell();
2256 cio_write(MJ2_TKHD, 4); /* TKHD */
2258 cio_write(3, 4); /* Version=0, flags=3 */
2260 time(<ime); /* Time since 1/1/70 */
2261 tk->modification_time = ltime + 2082844800; /* Seoonds between 1/1/04 and 1/1/70 */
2263 cio_write(tk->creation_time, 4); /* Creation Time */
2265 cio_write(tk->modification_time, 4); /* Modification Time */
2267 cio_write(tk->track_ID, 4); /* Track ID */
2269 cio_write(0, 4); /* Reserved */
2273 for (i = 0; i < tk->num_samples; i++)
2274 tk->duration += tk->sample[i].sample_delta;
2276 cio_write(tk->duration, 4); /* Duration */
2278 cio_write(0, 4); /* Reserved */
2279 cio_write(0, 4); /* Reserved */
2281 cio_write(tk->layer, 2); /* Layer */
2283 cio_write(0, 2); /* Predefined */
2285 cio_write(tk->volume, 2); /* Volume */
2287 cio_write(0, 2); /* Reserved */
2289 cio_write(tk->trans_matrix[0], 4); /* Transformation matrix for track */
2290 cio_write(tk->trans_matrix[1], 4);
2291 cio_write(tk->trans_matrix[2], 4);
2292 cio_write(tk->trans_matrix[3], 4);
2293 cio_write(tk->trans_matrix[4], 4);
2294 cio_write(tk->trans_matrix[5], 4);
2295 cio_write(tk->trans_matrix[6], 4);
2296 cio_write(tk->trans_matrix[7], 4);
2297 cio_write(tk->trans_matrix[8], 4);
2299 cio_write(tk->visual_w, 4); /* Video Visual Width */
2301 cio_write(tk->visual_h, 4); /* Video Visual Height */
2303 box.length = cio_tell() - box.init_pos;
2304 cio_seek(box.init_pos);
2305 cio_write(box.length, 4); /* L */
2306 cio_seek(box.init_pos + box.length);
2315 int mj2_read_tkhd(mj2_tk_t * tk)
2321 mj2_read_boxhdr(&box);
2323 if (MJ2_TKHD != box.type) {
2324 fprintf(stderr, "Error: Expected TKHD Marker\n");
2328 if (0 != cio_read(1)) { /* Version = 0 */
2329 fprintf(stderr, "Error: Only Version 0 handled in TKHD box\n");
2335 if (!(flag == 1 || flag == 2 || flag == 3 || flag == 4)) { /* Flags = 1,2,3 or 4 */
2337 "Error with flag in TKHD box: Expected flag 1,2,3 or 4\n");
2341 tk->creation_time = cio_read(4); /* Creation Time */
2343 tk->modification_time = cio_read(4); /* Modification Time */
2345 tk->track_ID = cio_read(4); /* Track ID */
2347 cio_skip(4); /* Reserved */
2349 tk->duration = cio_read(4); /* Duration */
2351 cio_skip(8); /* Reserved */
2353 tk->layer = cio_read(2); /* Layer */
2355 cio_read(2); /* Predefined */
2357 tk->volume = cio_read(2); /* Volume */
2359 cio_skip(2); /* Reserved */
2361 tk->trans_matrix[0] = cio_read(4); /* Transformation matrix for track */
2362 tk->trans_matrix[1] = cio_read(4);
2363 tk->trans_matrix[2] = cio_read(4);
2364 tk->trans_matrix[3] = cio_read(4);
2365 tk->trans_matrix[4] = cio_read(4);
2366 tk->trans_matrix[5] = cio_read(4);
2367 tk->trans_matrix[6] = cio_read(4);
2368 tk->trans_matrix[7] = cio_read(4);
2369 tk->trans_matrix[8] = cio_read(4);
2371 tk->visual_w = cio_read(4); /* Video Visual Width */
2373 tk->visual_h = cio_read(4); /* Video Visual Height */
2375 if (cio_tell() - box.init_pos != box.length) {
2376 fprintf(stderr, "Error with TKHD Box size\n");
2383 * Write the TRAK box
2388 void mj2_write_trak(mj2_tk_t * tk)
2392 box.init_pos = cio_tell();
2395 cio_write(MJ2_TRAK, 4); /* TRAK */
2400 box.length = cio_tell() - box.init_pos;
2401 cio_seek(box.init_pos);
2402 cio_write(box.length, 4); /* L */
2403 cio_seek(box.init_pos + box.length);
2412 int mj2_read_trak(mj2_tk_t * tk, j2k_image_t * img)
2416 mj2_read_boxhdr(&box);
2417 if (MJ2_TRAK != box.type) {
2418 fprintf(stderr, "Error: Expected TRAK Marker\n");
2421 if (mj2_read_tkhd(tk))
2423 if (mj2_read_mdia(tk, img))
2425 if (cio_tell() - box.init_pos != box.length) {
2426 fprintf(stderr, "Error with TRAK Box\n");
2433 * Write the MVHD box
2438 void mj2_write_mvhd(mj2_movie_t * movie)
2446 box.init_pos = cio_tell();
2448 cio_write(MJ2_MVHD, 4); /* MVHD */
2450 cio_write(0, 4); /* Version = 0, flags = 0 */
2452 time(<ime); /* Time since 1/1/70 */
2453 movie->modification_time = ltime + 2082844800; /* Seoonds between 1/1/04 and 1/1/70 */
2455 cio_write(movie->creation_time, 4); /* Creation Time */
2457 cio_write(movie->modification_time, 4); /* Modification Time */
2459 cio_write(movie->timescale, 4); /* Timescale */
2461 movie->duration = 0;
2463 for (i = 0; i < (movie->num_stk + movie->num_htk + movie->num_vtk); i++) {
2464 mj2_tk_t *tk = &movie->tk[i];
2466 for (j = 0; j < tk->num_samples; j++) {
2467 movie->duration += tk->sample[j].sample_delta;
2471 cio_write(movie->duration, 4);
2473 cio_write(movie->rate, 4); /* Rate to play presentation */
2475 cio_write(movie->volume, 2); /* Volume */
2477 cio_write(0, 2); /* Reserved */
2478 cio_write(0, 4); /* Reserved */
2479 cio_write(0, 4); /* Reserved */
2481 cio_write(movie->trans_matrix[0], 4); /* Transformation matrix for video */
2482 cio_write(movie->trans_matrix[1], 4);
2483 cio_write(movie->trans_matrix[2], 4);
2484 cio_write(movie->trans_matrix[3], 4);
2485 cio_write(movie->trans_matrix[4], 4);
2486 cio_write(movie->trans_matrix[5], 4);
2487 cio_write(movie->trans_matrix[6], 4);
2488 cio_write(movie->trans_matrix[7], 4);
2489 cio_write(movie->trans_matrix[8], 4);
2491 cio_write(0, 4); /* Pre-defined */
2492 cio_write(0, 4); /* Pre-defined */
2493 cio_write(0, 4); /* Pre-defined */
2494 cio_write(0, 4); /* Pre-defined */
2495 cio_write(0, 4); /* Pre-defined */
2496 cio_write(0, 4); /* Pre-defined */
2499 for (i = 0; i < movie->num_htk + movie->num_stk + movie->num_vtk; i++) {
2500 if (max_tk_num < movie->tk[i].track_ID)
2501 max_tk_num = movie->tk[i].track_ID;
2504 movie->next_tk_id = max_tk_num + 1;
2506 cio_write(movie->next_tk_id, 4); /* ID of Next track to be added */
2508 box.length = cio_tell() - box.init_pos;
2509 cio_seek(box.init_pos);
2510 cio_write(box.length, 4); /* L */
2511 cio_seek(box.init_pos + box.length);
2520 int mj2_read_mvhd(mj2_movie_t * movie)
2524 mj2_read_boxhdr(&box);
2525 if (MJ2_MVHD != box.type) {
2526 fprintf(stderr, "Error: Expected MVHD Marker\n");
2531 if (0 != cio_read(4)) { /* Version = 0, flags = 0 */
2532 fprintf(stderr, "Error: Only Version 0 handled in MVHD box\n");
2535 movie->creation_time = cio_read(4); /* Creation Time */
2537 movie->modification_time = cio_read(4); /* Modification Time */
2539 movie->timescale = cio_read(4); /* Timescale */
2541 movie->duration = cio_read(4); /* Duration */
2543 movie->rate = cio_read(4); /* Rate to play presentation */
2545 movie->volume = cio_read(2); /* Volume */
2547 cio_skip(10); /* Reserved */
2549 movie->trans_matrix[0] = cio_read(4); /* Transformation matrix for video */
2550 movie->trans_matrix[1] = cio_read(4);
2551 movie->trans_matrix[2] = cio_read(4);
2552 movie->trans_matrix[3] = cio_read(4);
2553 movie->trans_matrix[4] = cio_read(4);
2554 movie->trans_matrix[5] = cio_read(4);
2555 movie->trans_matrix[6] = cio_read(4);
2556 movie->trans_matrix[7] = cio_read(4);
2557 movie->trans_matrix[8] = cio_read(4);
2559 cio_skip(24); /* Pre-defined */
2561 movie->next_tk_id = cio_read(4); /* ID of Next track to be added */
2563 if (cio_tell() - box.init_pos != box.length) {
2564 fprintf(stderr, "Error with MVHD Box Size\n");
2572 * Write the MOOV box
2577 void mj2_write_moov(mj2_movie_t * movie)
2582 box.init_pos = cio_tell();
2584 cio_write(MJ2_MOOV, 4); /* MOOV */
2586 mj2_write_mvhd(movie);
2588 for (i = 0; i < (movie->num_stk + movie->num_htk + movie->num_vtk); i++) {
2589 mj2_write_trak(&movie->tk[i]);
2592 box.length = cio_tell() - box.init_pos;
2593 cio_seek(box.init_pos);
2594 cio_write(box.length, 4); /* L */
2595 cio_seek(box.init_pos + box.length);
2605 int mj2_read_moov(mj2_movie_t * movie, j2k_image_t * img)
2611 mj2_read_boxhdr(&box);
2612 if (MJ2_MOOV != box.type) {
2613 fprintf(stderr, "Error: Expected MOOV Marker\n");
2619 if (mj2_read_mvhd(movie))
2624 (mj2_tk_t *) malloc((movie->next_tk_id - 1) * sizeof(mj2_tk_t));
2626 for (i = 0; cio_tell() - box.init_pos < box.length; i++) {
2627 mj2_read_boxhdr(&box2);
2628 if (box2.type == MJ2_TRAK) {
2629 cio_seek(box2.init_pos);
2630 if (mj2_read_trak(&movie->tk[i], img))
2633 if (movie->tk[i].track_type == 0) {
2635 } else if (movie->tk[i].track_type == 1) {
2637 } else if (movie->tk[i].track_type == 2) {
2640 } else if (box2.type == MJ2_MVEX) {
2641 cio_seek(box2.init_pos);
2642 cio_skip(box2.length);
2645 fprintf(stderr, "Error with MOOV Box: Expected TRAK or MVEX box\n");
2652 int mj2_read_struct(FILE *file, mj2_movie_t * movie) {
2663 src = (char*) malloc (300 * sizeof(char));
2664 fread(src,300,1, file); // Assuming that jp and ftyp markers size do
2665 // not exceed 300 bytes
2671 if (mj2_read_ftyp(movie))
2674 fsresult = fseek(file,cio_tell(),SEEK_SET);
2676 fprintf(stderr, "End of file reached while trying to read data after FTYP box\n" );
2680 foffset = cio_tell();
2684 fread(src,30,1,file);
2686 mj2_read_boxhdr(&box);
2688 while(box.type != MJ2_MOOV) {
2693 fsresult = fseek(file,foffset+box.length,SEEK_SET);
2695 fprintf(stderr, "End of file reached while trying to read MDAT box\n" );
2698 foffset += box.length;
2702 fsresult = fseek(file,foffset+box.length,SEEK_SET);
2704 fprintf(stderr, "End of file reached while trying to read MOOF box\n" );
2707 foffset += box.length;
2710 fsresult = fseek(file,foffset+box.length,SEEK_SET);
2712 fprintf(stderr, "End of file reached while trying to read FREE box\n" );
2715 foffset += box.length;
2718 fsresult = fseek(file,foffset+box.length,SEEK_SET);
2720 fprintf(stderr, "End of file reached while trying to read SKIP box\n" );
2723 foffset += box.length;
2726 fprintf(stderr, "Unknown box in MJ2 stream\n");
2727 fsresult = fseek(file,foffset+box.length,SEEK_SET);
2729 fprintf(stderr, "End of file reached while trying to read end of unknown box\n");
2732 foffset += box.length;
2735 fsresult = fread(src,8,1,file);
2736 if (fsresult != 1) {
2737 fprintf(stderr, "MOOV box not found in file\n");
2741 mj2_read_boxhdr(&box);
2744 fseek(file,foffset,SEEK_SET);
2745 src = realloc(src,box.length);
2746 fsresult = fread(src,box.length,1,file);
2747 if (fsresult != 1) {
2748 fprintf(stderr, "End of file reached while trying to read MOOV box\n");
2752 cio_init(src, box.length);
2754 if (mj2_read_moov(movie, &img))