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.
36 #include "mj2_convert.h"
38 #define MJ2_JP 0x6a502020
39 #define MJ2_FTYP 0x66747970
40 #define MJ2_MJ2 0x6d6a7032
41 #define MJ2_MJ2S 0x6d6a3273
42 #define MJ2_MDAT 0x6d646174
43 #define MJ2_MOOV 0x6d6f6f76
44 #define MJ2_MVHD 0x6d766864
45 #define MJ2_TRAK 0x7472616b
46 #define MJ2_TKHD 0x746b6864
47 #define MJ2_MDIA 0x6d646961
48 #define MJ2_MDHD 0x6d646864
49 #define MJ2_MHDR 0x6d686472
50 #define MJ2_HDLR 0x68646C72
51 #define MJ2_MINF 0x6d696e66
52 #define MJ2_VMHD 0x766d6864
53 #define MJ2_SMHD 0x736d6864
54 #define MJ2_HMHD 0x686d6864
55 #define MJ2_DINF 0x64696e66
56 #define MJ2_DREF 0x64726566
57 #define MJ2_URL 0x75726c20
58 #define MJ2_URN 0x75726e20
59 #define MJ2_STBL 0x7374626c
60 #define MJ2_STSD 0x73747364
61 #define MJ2_STTS 0x73747473
62 #define MJ2_STSC 0x73747363
63 #define MJ2_STSZ 0x7374737A
64 #define MJ2_STCO 0x7374636f
65 #define MJ2_MOOF 0x6d6f6f66
66 #define MJ2_FREE 0x66726565
67 #define MJ2_SKIP 0x736b6970
68 #define MJ2_JP2C 0x6a703263
69 #define MJ2_FIEL 0x6669656c
70 #define MJ2_JP2P 0x6a703270
71 #define MJ2_JP2X 0x6a703278
72 #define MJ2_JSUB 0x6a737562
73 #define MJ2_ORFO 0x6f72666f
74 #define MJ2_MVEX 0x6d766578
75 #define MJ2_JP2 0x6a703220
76 #define MJ2_J2P0 0x4a325030
80 * Free movie structure memory
83 void mj2_memory_free(mj2_movie_t * movie)
88 if (movie->num_cl != 0)
91 for (i = 0; i < movie->num_vtk + movie->num_stk + movie->num_htk; i++) {
93 if (tk->name_size != 0)
101 if (tk->num_jp2x != 0)
103 if (tk->num_tts != 0)
105 if (tk->num_chunks != 0)
107 if (tk->num_samplestochunk != 0)
108 free(tk->sampletochunk);
109 if (tk->num_samples != 0)
122 int mj2_read_boxhdr(mj2_box_t * box)
124 box->init_pos = cio_tell();
125 box->length = cio_read(4);
126 box->type = cio_read(4);
127 if (box->length == 1) {
128 if (cio_read(4) != 0) {
129 fprintf(stderr, "Error: Cannot handle box sizes higher than 2^32\n");
132 box->length = cio_read(4);
139 * Initialisation of a Standard Video Track
140 * with one sample per chunk
143 int mj2_init_stdmovie(mj2_movie_t * movie)
148 movie->brand = MJ2_MJ2;
149 movie->minversion = 0;
152 (unsigned int *) malloc(movie->num_cl * sizeof(unsigned int));
154 movie->cl[0] = MJ2_MJ2;
155 movie->cl[1] = MJ2_MJ2S;
156 time(<ime); /* Time since 1/1/70 */
157 movie->creation_time = (unsigned int) ltime + 2082844800; /* Seconds between 1/1/04 and 1/1/70 */
158 movie->timescale = 1000;
160 movie->rate = 1; /* Rate to play presentation (default = 0x00010000) */
161 movie->volume = 1; /* Movie volume (default = 0x0100) */
162 movie->trans_matrix[0] = 0x00010000; /* Transformation matrix for video */
163 movie->trans_matrix[1] = 0; /* Unity is { 0x00010000,0,0,0,0x00010000,0,0,0,0x40000000 } */
164 movie->trans_matrix[2] = 0;
165 movie->trans_matrix[3] = 0;
166 movie->trans_matrix[4] = 0x00010000;
167 movie->trans_matrix[5] = 0;
168 movie->trans_matrix[6] = 0;
169 movie->trans_matrix[7] = 0;
170 movie->trans_matrix[8] = 0x40000000;
174 for (i = 0; i < movie->num_htk + movie->num_stk + movie->num_vtk; i++) {
175 mj2_tk_t *tk = &movie->tk[i];
176 if (tk->track_type == 0) {
177 tk->num_samples = yuv_num_frames(tk);
179 if (tk->num_samples == 0)
185 tk->timescale = 1000; /* Timescale = 1 ms */
188 (mj2_sample_t *) malloc(tk->num_samples * sizeof(mj2_sample_t));
189 tk->num_chunks = tk->num_samples;
191 (mj2_chunk_t *) malloc(tk->num_chunks * sizeof(mj2_chunk_t));
192 tk->chunk[0].num_samples = 1;
193 tk->chunk[0].sample_descr_idx = 1;
195 tk->same_sample_size = 0;
197 tk->num_samplestochunk = 1; /* One sample per chunk */
199 (mj2_sampletochunk_t *) malloc(tk->num_samplestochunk *
200 sizeof(mj2_sampletochunk_t));
201 tk->sampletochunk[0].first_chunk = 1;
202 tk->sampletochunk[0].samples_per_chunk = 1;
203 tk->sampletochunk[0].sample_descr_idx = 1;
205 for (j = 0; j < tk->num_samples; j++)
206 tk->sample[j].sample_delta = tk->timescale / tk->sample_rate;
209 tk->tts = (mj2_tts_t *) malloc(tk->num_tts * sizeof(mj2_tts_t));
210 tk->tts[0].sample_count = tk->num_samples;
211 tk->tts[0].sample_delta = tk->timescale / tk->sample_rate;
213 tk->horizresolution = 0x00480000; /* Horizontal resolution (typically 72) */
214 tk->vertresolution = 0x00480000; /* Vertical resolution (typically 72) */
215 tk->compressorname[0] = 0x0f4d6f74; /* Compressor Name[]: Motion JPEG2000 */
216 tk->compressorname[1] = 0x696f6e20;
217 tk->compressorname[2] = 0x4a504547;
218 tk->compressorname[3] = 0x32303030;
219 tk->compressorname[4] = 0x00120000;
220 tk->compressorname[5] = 0;
221 tk->compressorname[6] = 0x00000042;
222 tk->compressorname[7] = 0x000000DC;
223 tk->num_url = 0; /* Number of URL */
224 tk->num_urn = 0; /* Number of URN */
225 tk->graphicsmode = 0; /* Graphicsmode */
226 tk->opcolor[0] = 0; /* OpColor */
227 tk->opcolor[1] = 0; /* OpColor */
228 tk->opcolor[2] = 0; /* OpColor */
229 tk->creation_time = movie->creation_time; /* Seconds between 1/1/04 and 1/1/70 */
230 tk->language = 0; /* Language (undefined) */
233 tk->trans_matrix[0] = 0x00010000; /* Transformation matrix for track */
234 tk->trans_matrix[1] = 0; /* Unity is { 0x00010000,0,0,0,0x00010000,0,0,0,0x40000000 } */
235 tk->trans_matrix[2] = 0;
236 tk->trans_matrix[3] = 0;
237 tk->trans_matrix[4] = 0x00010000;
238 tk->trans_matrix[5] = 0;
239 tk->trans_matrix[6] = 0;
240 tk->trans_matrix[7] = 0;
241 tk->trans_matrix[8] = 0x40000000;
244 tk->or_fieldcount = 1;
245 tk->or_fieldorder = 0;
247 tk->br = (unsigned int *) malloc(tk->num_br * sizeof(unsigned int));
249 tk->br[1] = MJ2_J2P0;
251 tk->hsub = 2; /* 4:2:0 */
252 tk->vsub = 2; /* 4:2:0 */
261 * Time To Sample box Decompact
264 void mj2_tts_decompact(mj2_tk_t * tk)
268 for (i = 0; i < tk->num_tts; i++) {
269 tk->num_samples += tk->tts[i].sample_count;
273 (mj2_sample_t *) malloc(tk->num_samples * sizeof(mj2_sample_t));
275 for (i = 0; i < tk->num_tts; i++) {
276 for (j = 0; j < tk->tts[i].sample_count; j++) {
277 tk->sample[j].sample_delta = tk->tts[i].sample_delta;
283 * Sample To Chunk box Decompact
286 void mj2_stsc_decompact(mj2_tk_t * tk)
292 if (tk->num_samplestochunk == 1) {
294 (unsigned int) ceil((double) tk->num_samples /
295 (double) tk->sampletochunk[0].samples_per_chunk);
297 (mj2_chunk_t *) malloc(tk->num_chunks * sizeof(mj2_chunk_t));
298 for (k = 0; k < tk->num_chunks; k++) {
299 tk->chunk[k].num_samples = tk->sampletochunk[0].samples_per_chunk;
304 (mj2_chunk_t *) malloc(tk->num_samples * sizeof(mj2_chunk_t));
306 for (i = 0; i < tk->num_samplestochunk -1 ; i++) {
307 for (j = tk->sampletochunk[i].first_chunk - 1;
308 j < tk->sampletochunk[i + 1].first_chunk - 1; j++) {
309 tk->chunk[j].num_samples = tk->sampletochunk[i].samples_per_chunk;
311 sampleno += tk->chunk[j].num_samples;
314 tk->num_chunks += (int)(tk->num_samples - sampleno) / tk->sampletochunk[tk->num_samplestochunk - 1].samples_per_chunk;
315 for (k = tk->sampletochunk[tk->num_samplestochunk - 1].first_chunk - 1;
316 k < tk->num_chunks; k++) {
317 tk->chunk[k].num_samples =
318 tk->sampletochunk[tk->num_samplestochunk - 1].samples_per_chunk;
320 tk->chunk = realloc(tk->chunk, tk->num_chunks * sizeof(mj2_chunk_t));
327 * Chunk offset box Decompact
330 void mj2_stco_decompact(mj2_tk_t * tk)
335 int intra_chunk_offset;
337 for (i = 0; i < tk->num_chunks; i++) {
338 intra_chunk_offset = 0;
339 for (j = 0; j < tk->chunk[i].num_samples; j++) {
340 tk->sample[k].offset = intra_chunk_offset + tk->chunk[i].offset;
341 intra_chunk_offset += tk->sample[k].sample_size;
356 box.init_pos = cio_tell();
359 cio_write(MJ2_JP, 4); /* JP */
360 cio_write(0x0d0a870a, 4); /* 0x0d0a870a required in a JP box */
362 box.length = cio_tell() - box.init_pos;
363 cio_seek(box.init_pos);
364 cio_write(box.length, 4);
365 cio_seek(box.init_pos + box.length);
371 * JPEG 2000 signature
378 mj2_read_boxhdr(&box);
379 if (MJ2_JP != box.type) { /* Check Marker */
380 fprintf(stderr, "Error: Expected JP Marker\n");
383 if (0x0d0a870a != cio_read(4)) { /* read the 0x0d0a870a required in a JP box */
384 fprintf(stderr, "Error with JP Marker\n");
387 if (cio_tell() - box.init_pos != box.length) { /* Check box length */
388 fprintf(stderr, "Error with JP Box size \n");
401 void mj2_write_ftyp(mj2_movie_t * movie)
405 box.init_pos = cio_tell();
408 cio_write(MJ2_FTYP, 4); /* FTYP */
409 cio_write(movie->brand, 4); /* BR */
410 cio_write(movie->minversion, 4); /* MinV */
412 for (i = 0; i < movie->num_cl; i++)
413 cio_write(movie->cl[i], 4); /* CL */
415 box.length = cio_tell() - box.init_pos;
416 cio_seek(box.init_pos);
417 cio_write(box.length, 4); /* Length */
418 cio_seek(box.init_pos + box.length);
427 int mj2_read_ftyp(mj2_movie_t * movie)
432 mj2_read_boxhdr(&box); /* Box Size */
433 if (MJ2_FTYP != box.type) {
434 fprintf(stderr, "Error: Expected FTYP Marker\n");
438 movie->brand = cio_read(4); /* BR */
439 movie->minversion = cio_read(4); /* MinV */
440 movie->num_cl = (box.length - 16) / 4;
442 (unsigned int *) malloc(movie->num_cl * sizeof(unsigned int));
444 for (i = movie->num_cl - 1; i > -1; i--)
445 movie->cl[i] = cio_read(4); /* CLi */
447 if (cio_tell() - box.init_pos != box.length) {
448 fprintf(stderr, "Error with FTYP Box\n");
460 int mj2_write_mdat(FILE * outfile, mj2_movie_t * movie, j2k_image_t * img,
461 j2k_cp_t * cp, char *outbuf, char *index)
463 unsigned char box_len_ptr;
468 int pos_correction = 0;
471 box.init_pos = cio_tell();
473 cio_write(MJ2_MDAT, 4); /* MDAT */
475 for (i = 0; i < movie->num_stk + movie->num_htk + movie->num_vtk; i++) {
476 if (movie->tk[i].track_type != 0) {
477 fprintf(stderr, "Unable to write sound or hint tracks\n");
484 fprintf(stderr, "Video Track number %d\n", i + 1);
487 fwrite(outbuf, 1, len, outfile);
488 pos_correction = cio_tell() + pos_correction;
491 /* Copy the first tile coding parameters (tcp) to cp_init */
494 (j2k_tcp_t *) malloc(cp->tw * cp->th * sizeof(j2k_tcp_t));
495 for (tileno = 0; tileno < cp->tw * cp->th; tileno++) {
496 for (l = 0; l < cp->tcps[tileno].numlayers; l++) {
497 cp_init.tcps[tileno].rates[l] = cp->tcps[tileno].rates[l];
498 //tileno = cp->tcps[tileno].rates[l];
503 for (j = 0; j < tk->num_samples; j++) {
504 outbuf = (char *) malloc(cp->tdx * cp->tdy * cp->th * cp->tw * 2);
505 cio_init(outbuf, cp->tdx * cp->tdy * cp->th * cp->tw * 2);
507 fprintf(stderr, "Frame number %d/%d: \n", j + 1, tk->num_samples);
510 if (!yuvtoimage(tk, img, j)) {
511 fprintf(stderr, "Error with frame number %d in YUV file\n", j);
515 len = jp2_write_jp2c(img, cp, outbuf, index);
517 for (m = 0; m < img->numcomps; m++) {
518 free(img->comps[m].data);
521 tk->sample[j].sample_size = len;
523 tk->sample[j].offset = pos_correction;
524 tk->chunk[j].offset = pos_correction; /* There is one sample per chunk */
526 fwrite(outbuf, 1, len, outfile);
528 pos_correction = cio_tell() + pos_correction;
532 /* Copy the cp_init parameters to cp->tcps */
534 for (tileno = 0; tileno < cp->tw * cp->th; tileno++) {
535 for (k = 0; k < cp->tcps[tileno].numlayers; k++) {
536 cp->tcps[tileno].rates[k] = cp_init.tcps[tileno].rates[k];
542 box.length = pos_correction - box.init_pos;
544 fseek(outfile, box.init_pos, SEEK_SET);
546 cio_init(&box_len_ptr, 4); /* Init a cio to write box length variable in a little endian way */
547 cio_write(box.length, 4);
549 fwrite(&box_len_ptr, 4, 1, outfile);
551 fseek(outfile, box.init_pos + box.length, SEEK_SET);
563 int mj2_read_mdat(mj2_movie_t * movie, unsigned char *src, char *outfile)
567 int jp2c_cio_len, jp2c_len, pos_correction = 0;
573 mj2_read_boxhdr(&box);
574 if (MJ2_MDAT != box.type) {
575 fprintf(stderr, "Error: Expected MDAT Marker\n");
579 pos_correction = cio_tell() - box.init_pos;
581 f = fopen(outfile, "w"); /* Erase content of file if it already exists */
584 for (track_nb = 0; track_nb < movie->next_tk_id - 1; track_nb++) {
585 if (movie->tk[track_nb].imagefile != NULL) {
586 fprintf(stderr, "%s", movie->tk[track_nb].imagefile);
588 f = fopen(movie->tk[track_nb].imagefile, "w"); // Erase content of file if it already exists
594 track_nb < movie->num_htk + movie->num_stk + movie->num_vtk;
596 mj2_tk_t *tk = &movie->tk[track_nb];
597 if (tk->track_type != 0) {
598 cio_seek(box.init_pos);
599 cio_skip(box.length);
601 fprintf(stderr, "Track %d: Width=%d Height=%d\n", track_nb,
603 fprintf(stderr, "%d Samples\n", tk->num_samples);
605 if (tk->imagefile == NULL) {
606 tk->imagefile = outfile;
609 for (i = 0; i < tk->num_samples; i++) {
611 mj2_sample_t *sample = &tk->sample[i];
616 fprintf(stderr, "Frame %d / %d: \n", i+1, tk->num_samples);
618 cio_init(src + sample->offset, 8);
620 jp2c_cio_len = cio_tell();
621 jp2c_len = cio_read(4);
624 if (MJ2_JP2C != cio_read(4)) {
625 fprintf(stderr, "Error: Expected JP2C Marker\n");
629 pos = src + sample->offset + 8;
631 cio_seek(sample->offset + 8);
633 if (!j2k_decode(pos, sample->sample_size, &img, &cp))
636 if (imagetoyuv(&img, &cp, tk->imagefile))
641 for (compno=0; compno < img.numcomps; compno++)
642 free(img.comps[compno].data);
645 if (cio_tell() + 8 != jp2c_len) {
646 fprintf(stderr, "Error with JP2C Box Size\n");
654 cio_seek(box.init_pos);
655 cio_skip(box.length); /* Go back to box end */
666 void mj2_write_stco(mj2_tk_t * tk)
671 box.init_pos = cio_tell();
673 cio_write(MJ2_STCO, 4); /* STCO */
675 cio_write(0, 4); /* Version = 0, flags = 0 */
677 cio_write(tk->num_chunks, 4); /* Entry Count */
679 for (i = 0; i < tk->num_chunks; i++) {
680 cio_write(tk->chunk[i].offset, 4); /* Entry offset */
683 box.length = cio_tell() - box.init_pos;
684 cio_seek(box.init_pos);
685 cio_write(box.length, 4); /* L */
686 cio_seek(box.init_pos + box.length);
695 int mj2_read_stco(mj2_tk_t * tk)
700 mj2_read_boxhdr(&box); /* Box Size */
701 if (MJ2_STCO != box.type) {
702 fprintf(stderr, "Error: Expected STCO Marker\n");
706 if (0 != cio_read(1)) { /* Version = 0 */
707 fprintf(stderr, "Error: Only Version 0 handled in STCO box\n");
711 if (0 != cio_read(3)) { /* Flags = 0 */
712 fprintf(stderr, "Error with flag in STCO box. Expected flag 0\n");
717 if (cio_read(4) != tk->num_chunks) {
719 "Error in STCO box: expecting same amount of entry-count as chunks \n");
721 for (i = 0; i < tk->num_chunks; i++) {
722 tk->chunk[i].offset = cio_read(4); /* Entry offset */
726 mj2_stco_decompact(tk);
729 if (cio_tell() - box.init_pos != box.length) {
730 fprintf(stderr, "Error with STCO Box size\n");
742 void mj2_write_stsz(mj2_tk_t * tk)
747 box.init_pos = cio_tell();
749 cio_write(MJ2_STSZ, 4); /* STSZ */
751 cio_write(0, 4); /* Version = 0, flags = 0 */
753 if (tk->same_sample_size == 1) { /* If they all have the same size */
754 cio_write(tk->sample[0].sample_size, 4); /* Size */
756 cio_write(1, 4); /* Entry count = 1 */
760 cio_write(0, 4); /* Sample Size = 0 becase they all have different sizes */
762 cio_write(tk->num_samples, 4); /* Sample Count */
764 for (i = 0; i < tk->num_samples; i++) {
765 cio_write(tk->sample[i].sample_size, 4);
769 box.length = cio_tell() - box.init_pos;
770 cio_seek(box.init_pos);
771 cio_write(box.length, 4); /* L */
772 cio_seek(box.init_pos + box.length);
781 int mj2_read_stsz(mj2_tk_t * tk)
787 mj2_read_boxhdr(&box); /* Box Size */
788 if (MJ2_STSZ != box.type) {
789 fprintf(stderr, "Error: Expected STSZ Marker\n");
794 if (0 != cio_read(1)) { /* Version = 0 */
795 fprintf(stderr, "Error: Only Version 0 handled in STSZ box\n");
799 if (0 != cio_read(3)) { /* Flags = 0 */
800 fprintf(stderr, "Error with flag in STSZ box. Expected flag 0\n");
804 sample_size = cio_read(4);
806 if (sample_size != 0) { /* Samples do have the same size */
807 tk->same_sample_size = 1;
808 for (i = 0; i < tk->num_samples; i++) {
809 tk->sample[i].sample_size = sample_size;
811 cio_skip(4); /* Sample count = 1 */
813 tk->same_sample_size = 0;
814 if (tk->num_samples != cio_read(4)) { /* Sample count */
816 "Error in STSZ box. Expected that sample-count is number of samples in track\n");
819 for (i = 0; i < tk->num_samples; i++) {
820 tk->sample[i].sample_size = cio_read(4); /* Sample Size */
823 if (cio_tell() - box.init_pos != box.length) {
824 fprintf(stderr, "Error with STSZ Box size\n");
838 void mj2_write_stsc(mj2_tk_t * tk)
843 box.init_pos = cio_tell();
845 cio_write(MJ2_STSC, 4); /* STSC */
847 cio_write(0, 4); /* Version = 0, flags = 0 */
849 cio_write(tk->num_samplestochunk, 4); /* Entry Count */
851 for (i = 0; i < tk->num_samplestochunk; i++) {
852 cio_write(tk->sampletochunk[i].first_chunk, 4); /* First Chunk */
853 cio_write(tk->sampletochunk[i].samples_per_chunk, 4); /* Samples per chunk */
854 cio_write(tk->sampletochunk[i].sample_descr_idx, 4); /* Samples description index */
858 box.length = cio_tell() - box.init_pos;
859 cio_seek(box.init_pos);
860 cio_write(box.length, 4); /* L */
861 cio_seek(box.init_pos + box.length);
870 int mj2_read_stsc(mj2_tk_t * tk)
875 mj2_read_boxhdr(&box); /* Box Size */
876 if (MJ2_STSC != box.type) {
877 fprintf(stderr, "Error: Expected STSC Marker\n");
882 if (0 != cio_read(1)) { /* Version = 0 */
883 fprintf(stderr, "Error: Only Version 0 handled in STSC box\n");
887 if (0 != cio_read(3)) { /* Flags = 0 */
888 fprintf(stderr, "Error with flag in STSC box. Expected flag 0\n");
892 tk->num_samplestochunk = cio_read(4);
895 (mj2_sampletochunk_t *) malloc(tk->num_samplestochunk *
896 sizeof(mj2_sampletochunk_t));
899 for (i = 0; i < tk->num_samplestochunk; i++) {
900 tk->sampletochunk[i].first_chunk = cio_read(4);
901 tk->sampletochunk[i].samples_per_chunk = cio_read(4);
902 tk->sampletochunk[i].sample_descr_idx = cio_read(4);
905 mj2_stsc_decompact(tk); /* decompact sample to chunk box */
908 if (cio_tell() - box.init_pos != box.length) {
909 fprintf(stderr, "Error with STSC Box size\n");
921 void mj2_write_stts(mj2_tk_t * tk)
927 box.init_pos = cio_tell();
929 cio_write(MJ2_STTS, 4); /* STTS */
931 cio_write(0, 4); /* Version = 0, flags = 0 */
933 cio_write(tk->num_tts, 4); /* entry_count */
934 for (i = 0; i < tk->num_tts; i++) {
935 cio_write(tk->tts[i].sample_count, 4); /* Sample-count */
936 cio_write(tk->tts[i].sample_delta, 4); /* Sample-Delta */
939 box.length = cio_tell() - box.init_pos;
940 cio_seek(box.init_pos);
941 cio_write(box.length, 4); /* L */
942 cio_seek(box.init_pos + box.length);
951 int mj2_read_stts(mj2_tk_t * tk)
957 mj2_read_boxhdr(&box);
958 if (MJ2_STTS != box.type) {
959 fprintf(stderr, "Error: Expected STTS Marker\n");
964 if (0 != cio_read(1)) { /* Version = 0 */
965 fprintf(stderr, "Error: Only Version 0 handled in STTS box\n");
969 if (0 != cio_read(3)) { /* Flags = 0 */
970 fprintf(stderr, "Error with flag in STTS box. Expected flag 0\n");
974 tk->num_tts = cio_read(4);
976 tk->tts = (mj2_tts_t *) malloc(tk->num_tts * sizeof(mj2_tts_t));
978 for (i = 0; i < tk->num_tts; i++) {
979 tk->tts[i].sample_count = cio_read(4);
980 tk->tts[i].sample_delta = cio_read(4);
983 mj2_tts_decompact(tk);
985 if (cio_tell() - box.init_pos != box.length) {
986 fprintf(stderr, "Error with STTS Box size\n");
998 void mj2_write_fiel(mj2_tk_t * tk)
1003 box.init_pos = cio_tell();
1005 cio_write(MJ2_FIEL, 4); /* STTS */
1007 cio_write(tk->fieldcount, 1); /* Field count */
1008 cio_write(tk->fieldorder, 1); /* Field order */
1011 box.length = cio_tell() - box.init_pos;
1012 cio_seek(box.init_pos);
1013 cio_write(box.length, 4); /* L */
1014 cio_seek(box.init_pos + box.length);
1023 int mj2_read_fiel(mj2_tk_t * tk)
1028 mj2_read_boxhdr(&box);
1029 if (MJ2_FIEL != box.type) {
1030 fprintf(stderr, "Error: Expected FIEL Marker\n");
1035 tk->fieldcount = cio_read(1);
1036 tk->fieldorder = cio_read(1);
1038 if (cio_tell() - box.init_pos != box.length) {
1039 fprintf(stderr, "Error with FIEL Box size\n");
1046 * Write the ORFO box
1048 * Original Format Box
1051 void mj2_write_orfo(mj2_tk_t * tk)
1055 box.init_pos = cio_tell();
1057 cio_write(MJ2_ORFO, 4);
1059 cio_write(tk->or_fieldcount, 1); /* Original Field count */
1060 cio_write(tk->or_fieldorder, 1); /* Original Field order */
1063 box.length = cio_tell() - box.init_pos;
1064 cio_seek(box.init_pos);
1065 cio_write(box.length, 4); /* L */
1066 cio_seek(box.init_pos + box.length);
1072 * Original Format Box
1075 int mj2_read_orfo(mj2_tk_t * tk)
1080 mj2_read_boxhdr(&box);
1081 if (MJ2_ORFO != box.type) {
1082 fprintf(stderr, "Error: Expected ORFO Marker\n");
1087 tk->or_fieldcount = cio_read(1);
1088 tk->or_fieldorder = cio_read(1);
1090 if (cio_tell() - box.init_pos != box.length) {
1091 fprintf(stderr, "Error with ORFO Box size\n");
1098 * Write the JP2P box
1103 void mj2_write_jp2p(mj2_tk_t * tk)
1109 box.init_pos = cio_tell();
1111 cio_write(MJ2_JP2P, 4);
1113 cio_write(0, 4); /* Version 0, flags =0 */
1115 for (i = 0; i < tk->num_br; i++) {
1116 cio_write(tk->br[i], 4);
1119 box.length = cio_tell() - box.init_pos;
1120 cio_seek(box.init_pos);
1121 cio_write(box.length, 4); /* L */
1122 cio_seek(box.init_pos + box.length);
1131 int mj2_read_jp2p(mj2_tk_t * tk)
1137 mj2_read_boxhdr(&box);
1138 if (MJ2_JP2P != box.type) {
1139 fprintf(stderr, "Error: Expected JP2P Marker\n");
1143 if (0 != cio_read(1)) { /* Version = 0 */
1144 fprintf(stderr, "Error: Only Version 0 handled in JP2P box\n");
1148 if (0 != cio_read(3)) { /* Flags = 0 */
1149 fprintf(stderr, "Error with flag in JP2P box. Expected flag 0\n");
1154 tk->num_br = (box.length - 12) / 4;
1155 tk->br = (unsigned int *) malloc(tk->num_br * sizeof(unsigned int));
1157 for (i = 0; i < tk->num_br; i++) {
1158 tk->br[i] = cio_read(4);
1161 if (cio_tell() - box.init_pos != box.length) {
1162 fprintf(stderr, "Error with JP2P Box size\n");
1169 * Write the JP2X box
1174 void mj2_write_jp2x(mj2_tk_t * tk)
1180 box.init_pos = cio_tell();
1182 cio_write(MJ2_JP2X, 4);
1184 for (i = 0; i < tk->num_jp2x; i++) {
1185 cio_write(tk->jp2xdata[i], 1);
1188 box.length = cio_tell() - box.init_pos;
1189 cio_seek(box.init_pos);
1190 cio_write(box.length, 4); /* L */
1191 cio_seek(box.init_pos + box.length);
1200 int mj2_read_jp2x(mj2_tk_t * tk)
1206 mj2_read_boxhdr(&box);
1207 if (MJ2_JP2X != box.type) {
1208 fprintf(stderr, "Error: Expected JP2X Marker\n");
1213 tk->num_jp2x = (box.length - 8);
1215 (unsigned char *) malloc(tk->num_jp2x * sizeof(unsigned char));
1217 for (i = 0; i < tk->num_jp2x; i++) {
1218 tk->jp2xdata[i] = cio_read(1);
1221 if (cio_tell() - box.init_pos != box.length) {
1222 fprintf(stderr, "Error with JP2X Box size\n");
1229 * Write the JSUB box
1231 * MJP2 Subsampling Box
1234 void mj2_write_jsub(mj2_tk_t * tk)
1239 box.init_pos = cio_tell();
1241 cio_write(MJ2_JSUB, 4);
1243 cio_write(tk->hsub, 1);
1244 cio_write(tk->vsub, 1);
1245 cio_write(tk->hoff, 1);
1246 cio_write(tk->voff, 1);
1248 box.length = cio_tell() - box.init_pos;
1249 cio_seek(box.init_pos);
1250 cio_write(box.length, 4); /* L */
1251 cio_seek(box.init_pos + box.length);
1257 * MJP2 Subsampling Box
1260 int mj2_read_jsub(mj2_tk_t * tk)
1264 mj2_read_boxhdr(&box);
1265 if (MJ2_JSUB != box.type) {
1266 fprintf(stderr, "Error: Expected JSUB Marker\n");
1270 tk->hsub = cio_read(1);
1271 tk->vsub = cio_read(1);
1272 tk->hoff = cio_read(1);;
1273 tk->voff = cio_read(1);
1275 if (cio_tell() - box.init_pos != box.length) {
1276 fprintf(stderr, "Error with JSUB Box size\n");
1283 * Write the SMJ2 box
1285 * Visual Sample Entry Description
1288 void mj2_write_smj2(j2k_image_t * img, mj2_tk_t * tk)
1293 box.init_pos = cio_tell();
1295 cio_write(MJ2_MJ2, 4); /* MJ2 */
1297 cio_write(0, 4); /* Version = 0, flags = 0 */
1301 cio_write(0, 2); /* Pre-defined */
1303 cio_write(0, 2); /* Reserved */
1305 cio_write(0, 4); /* Pre-defined */
1306 cio_write(0, 4); /* Pre-defined */
1307 cio_write(0, 4); /* Pre-defined */
1309 cio_write(tk->w, 2); /* Width */
1310 cio_write(tk->h, 2); /* Height */
1312 cio_write(tk->horizresolution, 4); /* Horizontal resolution */
1313 cio_write(tk->vertresolution, 4); /* Vertical resolution */
1315 cio_write(0, 4); /* Reserved */
1317 cio_write(1, 2); /* Pre-defined = 1 */
1319 cio_write(tk->compressorname[0], 4); /* Compressor Name */
1320 cio_write(tk->compressorname[1], 4);
1321 cio_write(tk->compressorname[2], 4);
1322 cio_write(tk->compressorname[3], 4);
1323 cio_write(tk->compressorname[4], 4);
1324 cio_write(tk->compressorname[5], 4);
1325 cio_write(tk->compressorname[6], 4);
1326 cio_write(tk->compressorname[7], 4);
1330 for (i = 0; i < img->numcomps; i++)
1331 tk->depth += img->comps[i].bpp;
1333 cio_write(tk->depth, 2); /* Depth */
1335 cio_write(0xffff, 2); /* Pre-defined = -1 */
1337 jp2_init_stdjp2(&tk->jp2_struct, img);
1339 jp2_write_jp2h(&tk->jp2_struct);
1343 if (tk->num_br != 0)
1345 if (tk->num_jp2x != 0)
1351 box.length = cio_tell() - box.init_pos;
1352 cio_seek(box.init_pos);
1353 cio_write(box.length, 4); /* L */
1354 cio_seek(box.init_pos + box.length);
1360 * Visual Sample Entry Description
1363 int mj2_read_smj2(j2k_image_t * img, mj2_tk_t * tk)
1369 mj2_read_boxhdr(&box);
1371 if (MJ2_MJ2 != box.type) {
1372 fprintf(stderr, "Error in SMJ2 box: Expected MJ2 Marker\n");
1376 if (0 != cio_read(1)) { /* Version = 0 */
1377 fprintf(stderr, "Error: Only Version 0 handled in MJP2 box\n");
1381 if (0 != cio_read(3)) { /* Flags = 0 */
1382 fprintf(stderr, "Error with flag in MJP2 box. Expected flag 0\n");
1388 cio_skip(2); /* Pre-defined */
1390 cio_skip(2); /* Reserved */
1392 cio_skip(4); /* Pre-defined */
1393 cio_skip(4); /* Pre-defined */
1394 cio_skip(4); /* Pre-defined */
1396 tk->w = cio_read(2); /* Width */
1397 tk->h = cio_read(2); /* Height */
1399 tk->horizresolution = cio_read(4); /* Horizontal resolution */
1400 tk->vertresolution = cio_read(4); /* Vertical resolution */
1402 cio_skip(4); /* Reserved */
1404 cio_skip(2); /* Pre-defined = 1 */
1406 tk->compressorname[0] = cio_read(4); /* Compressor Name */
1407 tk->compressorname[1] = cio_read(4);
1408 tk->compressorname[2] = cio_read(4);
1409 tk->compressorname[3] = cio_read(4);
1410 tk->compressorname[4] = cio_read(4);
1411 tk->compressorname[5] = cio_read(4);
1412 tk->compressorname[6] = cio_read(4);
1413 tk->compressorname[7] = cio_read(4);
1415 tk->depth = cio_read(2); /* Depth */
1417 /* Init std value */
1421 tk->or_fieldcount = 1;
1422 tk->or_fieldorder = 0;
1424 cio_skip(2); /* Pre-defined = -1 */
1426 if (jp2_read_jp2h(&tk->jp2_struct)) {
1427 fprintf(stderr, "Error with JP2H Box\n");
1431 for (i = 0; cio_tell() - box.init_pos < box.length; i++) {
1432 mj2_read_boxhdr(&box2);
1433 cio_seek(box2.init_pos);
1434 switch (box2.type) {
1436 if (mj2_read_fiel(tk))
1441 if (mj2_read_jp2p(tk))
1446 if (mj2_read_jp2x(tk))
1451 if (mj2_read_jsub(tk))
1456 if (mj2_read_orfo(tk))
1461 fprintf(stderr, "Error with MJP2 Box size\n");
1472 * Write the STSD box
1474 * Sample Description
1477 void mj2_write_stsd(mj2_tk_t * tk, j2k_image_t * img)
1481 box.init_pos = cio_tell();
1483 cio_write(MJ2_STSD, 4); /* STSD */
1485 cio_write(0, 4); /* Version = 0, flags = 0 */
1487 cio_write(1, 4); /* entry_count = 1 (considering same JP2 headerboxes) */
1489 if (tk->track_type == 0) {
1490 mj2_write_smj2(img, tk);
1491 } else if (tk->track_type == 1) {
1494 if (tk->track_type == 2) {
1499 box.length = cio_tell() - box.init_pos;
1500 cio_seek(box.init_pos);
1501 cio_write(box.length, 4); /* L */
1502 cio_seek(box.init_pos + box.length);
1508 * Sample Description
1511 int mj2_read_stsd(mj2_tk_t * tk, j2k_image_t * img)
1514 int entry_count, len_2skip;
1518 mj2_read_boxhdr(&box);
1520 if (MJ2_STSD != box.type) {
1521 fprintf(stderr, "Error: Expected STSD Marker\n");
1525 if (0 != cio_read(1)) { /* Version = 0 */
1526 fprintf(stderr, "Error: Only Version 0 handled in STSD box\n");
1530 if (0 != cio_read(3)) { /* Flags = 0 */
1531 fprintf(stderr, "Error with flag in STSD box. Expected flag 0\n");
1535 entry_count = cio_read(4);
1537 if (tk->track_type == 0) {
1538 for (i = 0; i < entry_count; i++) {
1539 if (mj2_read_smj2(img, tk))
1542 } else if (tk->track_type == 1) {
1543 len_2skip = cio_read(4); // Not implemented -> skipping box
1544 cio_skip(len_2skip - 4);
1545 } else if (tk->track_type == 2) {
1546 len_2skip = cio_read(4); // Not implemented -> skipping box
1547 cio_skip(len_2skip - 4);
1551 if (cio_tell() - box.init_pos != box.length) {
1552 fprintf(stderr, "Error with STSD Box size\n");
1559 * Write the STBL box
1561 * Sample table box box
1564 void mj2_write_stbl(mj2_tk_t * tk, j2k_image_t * img)
1568 box.init_pos = cio_tell();
1570 cio_write(MJ2_STBL, 4); /* STBL */
1572 mj2_write_stsd(tk, img);
1578 box.length = cio_tell() - box.init_pos;
1579 cio_seek(box.init_pos);
1580 cio_write(box.length, 4); /* L */
1581 cio_seek(box.init_pos + box.length);
1587 * Sample table box box
1590 int mj2_read_stbl(mj2_tk_t * tk, j2k_image_t * img)
1594 mj2_read_boxhdr(&box);
1595 if (MJ2_STBL != box.type) {
1596 fprintf(stderr, "Error: Expected STBL Marker\n");
1600 if (mj2_read_stsd(tk, img))
1602 if (mj2_read_stts(tk))
1604 if (mj2_read_stsc(tk))
1606 if (mj2_read_stsz(tk))
1608 if (mj2_read_stco(tk))
1611 if (cio_tell() - box.init_pos != box.length) {
1612 fprintf(stderr, "Error with STBL Box size\n");
1624 void mj2_write_url(mj2_tk_t * tk, int url_num)
1628 box.init_pos = cio_tell();
1630 cio_write(MJ2_URL, 4); /* URL */
1633 cio_write(1, 4); /* Version = 0, flags = 1 because stored in same file */
1635 cio_write(0, 4); /* Version = 0, flags = 0 */
1636 cio_write(tk->url[url_num - 1].location[0], 4);
1637 cio_write(tk->url[url_num - 1].location[1], 4);
1638 cio_write(tk->url[url_num - 1].location[2], 4);
1639 cio_write(tk->url[url_num - 1].location[3], 4);
1642 box.length = cio_tell() - box.init_pos;
1643 cio_seek(box.init_pos);
1644 cio_write(box.length, 4); /* L */
1645 cio_seek(box.init_pos + box.length);
1654 int mj2_read_url(mj2_tk_t * tk, int urn_num)
1658 mj2_read_boxhdr(&box);
1659 if (MJ2_URL != box.type) {
1660 fprintf(stderr, "Error: Expected URL Marker\n");
1664 if (0 != cio_read(1)) { /* Version = 0 */
1665 fprintf(stderr, "Error: Only Version 0 handled in URL box\n");
1669 if (1 != cio_read(3)) { /* If flags = 1 --> media data in file */
1670 tk->url[urn_num].location[0] = cio_read(4);
1671 tk->url[urn_num].location[1] = cio_read(4);
1672 tk->url[urn_num].location[2] = cio_read(4);
1673 tk->url[urn_num].location[3] = cio_read(4);
1679 if (cio_tell() - box.init_pos != box.length) {
1680 fprintf(stderr, "Error with URL Box size\n");
1692 void mj2_write_urn(mj2_tk_t * tk, int urn_num)
1696 box.init_pos = cio_tell();
1698 cio_write(MJ2_URN, 4); /* URN */
1700 cio_write(0, 4); /* Version = 0, flags = 0 */
1702 cio_write(tk->urn[urn_num].name[0], 4);
1703 cio_write(tk->urn[urn_num].name[1], 4);
1704 cio_write(tk->urn[urn_num].name[2], 4);
1705 cio_write(tk->urn[urn_num].name[3], 4);
1706 cio_write(tk->urn[urn_num].location[0], 4);
1707 cio_write(tk->urn[urn_num].location[1], 4);
1708 cio_write(tk->urn[urn_num].location[2], 4);
1709 cio_write(tk->urn[urn_num].location[3], 4);
1711 box.length = cio_tell() - box.init_pos;
1712 cio_seek(box.init_pos);
1713 cio_write(box.length, 4); /* L */
1714 cio_seek(box.init_pos + box.length);
1723 int mj2_read_urn(mj2_tk_t * tk, int urn_num)
1728 mj2_read_boxhdr(&box);
1729 if (MJ2_URN != box.type) {
1730 fprintf(stderr, "Error: Expected URN Marker\n");
1734 if (0 != cio_read(1)) { /* Version = 0 */
1735 fprintf(stderr, "Error: Only Version 0 handled in URN box\n");
1739 if (1 != cio_read(3)) { /* If flags = 1 --> media data in file */
1740 tk->urn[urn_num].name[0] = cio_read(4);
1741 tk->urn[urn_num].name[1] = cio_read(4);
1742 tk->urn[urn_num].name[2] = cio_read(4);
1743 tk->urn[urn_num].name[3] = cio_read(4);
1744 tk->urn[urn_num].location[0] = cio_read(4);
1745 tk->urn[urn_num].location[1] = cio_read(4);
1746 tk->urn[urn_num].location[2] = cio_read(4);
1747 tk->urn[urn_num].location[3] = cio_read(4);
1751 if (cio_tell() - box.init_pos != box.length) {
1752 fprintf(stderr, "Error with URN Box size\n");
1760 * Write the DREF box
1762 * Data reference box
1765 void mj2_write_dref(mj2_tk_t * tk)
1770 box.init_pos = cio_tell();
1772 cio_write(MJ2_DREF, 4); /* DREF */
1774 cio_write(0, 4); /* Version = 0, flags = 0 */
1776 if (tk->num_url + tk->num_urn == 0) { /* Media data in same file */
1777 cio_write(1, 4); /* entry_count = 1 */
1778 mj2_write_url(tk, 0);
1780 cio_write(tk->num_url + tk->num_urn, 4); /* entry_count */
1782 for (i = 0; i < tk->num_url; i++)
1783 mj2_write_url(tk, i + 1);
1785 for (i = 0; i < tk->num_urn; i++)
1786 mj2_write_urn(tk, i);
1789 box.length = cio_tell() - box.init_pos;
1790 cio_seek(box.init_pos);
1791 cio_write(box.length, 4); /* L */
1792 cio_seek(box.init_pos + box.length);
1798 * Data reference box
1801 int mj2_read_dref(mj2_tk_t * tk)
1805 int entry_count, marker;
1808 mj2_read_boxhdr(&box);
1809 if (MJ2_DREF != box.type) {
1810 fprintf(stderr, "Error: Expected DREF Marker\n");
1814 if (0 != cio_read(1)) { /* Version = 0 */
1815 fprintf(stderr, "Error: Only Version 0 handled in DREF box\n");
1819 if (0 != cio_read(3)) { /* Flags = 0 */
1820 fprintf(stderr, "Error with flag in DREF box. Expected flag 0\n");
1824 entry_count = cio_read(4);
1828 for (i = 0; i < entry_count; i++) {
1830 marker = cio_read(4);
1831 if (marker == MJ2_URL) {
1834 if (mj2_read_url(tk, tk->num_url))
1836 } else if (marker == MJ2_URN) {
1839 if (mj2_read_urn(tk, tk->num_urn))
1842 fprintf(stderr, "Error with in DREF box. Expected URN or URL box\n");
1849 if (cio_tell() - box.init_pos != box.length) {
1850 fprintf(stderr, "Error with DREF Box size\n");
1857 * Write the DINF box
1859 * Data information box
1862 void mj2_write_dinf(mj2_tk_t * tk)
1866 box.init_pos = cio_tell();
1868 cio_write(MJ2_DINF, 4); /* DINF */
1872 box.length = cio_tell() - box.init_pos;
1873 cio_seek(box.init_pos);
1874 cio_write(box.length, 4); /* L */
1875 cio_seek(box.init_pos + box.length);
1881 * Data information box
1884 int mj2_read_dinf(mj2_tk_t * tk)
1888 mj2_read_boxhdr(&box);
1889 if (MJ2_DINF != box.type) {
1890 fprintf(stderr, "Error: Expected DINF Marker\n");
1894 if (mj2_read_dref(tk))
1897 if (cio_tell() - box.init_pos != box.length) {
1898 fprintf(stderr, "Error with DINF Box size\n");
1905 * Write the VMHD box
1907 * Video Media information box
1910 void mj2_write_vmhd(mj2_tk_t * tk)
1914 box.init_pos = cio_tell();
1916 cio_write(MJ2_VMHD, 4); /* VMHD */
1918 cio_write(1, 4); /* Version = 0, flags = 1 */
1920 cio_write(tk->graphicsmode, 2);
1921 cio_write(tk->opcolor[0], 2);
1922 cio_write(tk->opcolor[1], 2);
1923 cio_write(tk->opcolor[2], 2);
1925 box.length = cio_tell() - box.init_pos;
1926 cio_seek(box.init_pos);
1927 cio_write(box.length, 4); /* L */
1928 cio_seek(box.init_pos + box.length);
1934 * Video Media information box
1937 int mj2_read_vmhd(mj2_tk_t * tk)
1941 mj2_read_boxhdr(&box);
1942 if (MJ2_VMHD != box.type) {
1943 fprintf(stderr, "Error: Expected VMHD Marker\n");
1947 if (0 != cio_read(1)) { /* Version = 0 */
1948 fprintf(stderr, "Error: Only Version 0 handled in VMHD box\n");
1952 if (1 != cio_read(3)) { /* Flags = 1 */
1953 fprintf(stderr, "Error with flag in VMHD box. Expected flag 1\n");
1958 tk->graphicsmode = cio_read(2);
1959 tk->opcolor[0] = cio_read(2);
1960 tk->opcolor[1] = cio_read(2);
1961 tk->opcolor[2] = cio_read(2);
1963 if (cio_tell() - box.init_pos != box.length) {
1964 fprintf(stderr, "Error with VMHD Box size\n");
1971 * Write the SMHD box
1973 * Sound Media information box
1976 void mj2_write_smhd(mj2_tk_t * tk)
1980 box.init_pos = cio_tell();
1982 cio_write(MJ2_SMHD, 4); /* SMHD */
1984 cio_write(0, 4); /* Version = 0, flags = 0 */
1986 cio_write(tk->balance << 8, 2);
1988 cio_write(0, 2); /* Reserved */
1990 box.length = cio_tell() - box.init_pos;
1991 cio_seek(box.init_pos);
1992 cio_write(box.length, 4); /* L */
1993 cio_seek(box.init_pos + box.length);
1999 * Sound Media information box
2002 int mj2_read_smhd(mj2_tk_t * tk)
2006 mj2_read_boxhdr(&box);
2007 if (MJ2_SMHD != box.type) {
2008 fprintf(stderr, "Error: Expected SMHD Marker\n");
2012 if (0 != cio_read(1)) { /* Version = 0 */
2013 fprintf(stderr, "Error: Only Version 0 handled in VMHD box\n");
2017 if (0 != cio_read(3)) { /* Flags = 0 */
2018 fprintf(stderr, "Error with flag in VMHD box. Expected flag 0\n");
2023 tk->balance = cio_read(2) >> 8;
2025 cio_skip(2); /* Reserved */
2027 if (cio_tell() - box.init_pos != box.length) {
2028 fprintf(stderr, "Error with SMHD Box size\n");
2035 * Write the HMHD box
2037 * Hint Media information box
2040 void mj2_write_hmhd(mj2_tk_t * tk)
2044 box.init_pos = cio_tell();
2046 cio_write(MJ2_HMHD, 4); /* HMHD */
2048 cio_write(0, 4); /* Version = 0, flags = 0 */
2050 cio_write(tk->maxPDUsize, 2);
2051 cio_write(tk->avgPDUsize, 2);
2052 cio_write(tk->maxbitrate, 4);
2053 cio_write(tk->avgbitrate, 4);
2054 cio_write(tk->slidingavgbitrate, 4);
2056 box.length = cio_tell() - box.init_pos;
2057 cio_seek(box.init_pos);
2058 cio_write(box.length, 4); /* L */
2059 cio_seek(box.init_pos + box.length);
2065 * Hint Media information box
2068 int mj2_read_hmhd(mj2_tk_t * tk)
2072 mj2_read_boxhdr(&box);
2073 if (MJ2_HMHD != box.type) {
2074 fprintf(stderr, "Error: Expected HMHD Marker\n");
2078 if (0 != cio_read(1)) { /* Version = 0 */
2079 fprintf(stderr, "Error: Only Version 0 handled in VMHD box\n");
2083 if (0 != cio_read(3)) { /* Flags = 0 */
2084 fprintf(stderr, "Error with flag in VMHD box. Expected flag 0\n");
2089 tk->maxPDUsize = cio_read(2);
2090 tk->avgPDUsize = cio_read(2);
2091 tk->maxbitrate = cio_read(4);
2092 tk->avgbitrate = cio_read(4);
2093 tk->slidingavgbitrate = cio_read(4);
2095 if (cio_tell() - box.init_pos != box.length) {
2096 fprintf(stderr, "Error with HMHD Box size\n");
2103 * Write the MINF box
2105 * Media information box
2108 void mj2_write_minf(mj2_tk_t * tk, j2k_image_t * img)
2112 box.init_pos = cio_tell();
2114 cio_write(MJ2_MINF, 4); /* MINF */
2116 if (tk->track_type == 0) {
2118 } else if (tk->track_type == 1) {
2120 } else if (tk->track_type == 2) {
2125 mj2_write_stbl(tk, img);
2127 box.length = cio_tell() - box.init_pos;
2128 cio_seek(box.init_pos);
2129 cio_write(box.length, 4); /* L */
2130 cio_seek(box.init_pos + box.length);
2136 * Media information box
2139 int mj2_read_minf(mj2_tk_t * tk, j2k_image_t * img)
2142 unsigned int box_type;
2145 mj2_read_boxhdr(&box);
2146 if (MJ2_MINF != box.type) {
2147 fprintf(stderr, "Error: Expected MINF Marker\n");
2152 box_type = cio_read(4);
2155 if (box_type == MJ2_VMHD) {
2156 if (mj2_read_vmhd(tk))
2158 } else if (box_type == MJ2_SMHD) {
2159 if (mj2_read_smhd(tk))
2161 } else if (box_type == MJ2_HMHD) {
2162 if (mj2_read_hmhd(tk))
2165 fprintf(stderr, "Error in MINF box expected vmhd, smhd or hmhd\n");
2169 if (mj2_read_dinf(tk))
2172 if (mj2_read_stbl(tk, img))
2175 if (cio_tell() - box.init_pos != box.length) {
2176 fprintf(stderr, "Error with MINF Box size\n");
2183 * Write the HDLR box
2185 * Handler reference box
2188 void mj2_write_hdlr(mj2_tk_t * tk)
2192 box.init_pos = cio_tell();
2194 cio_write(MJ2_HDLR, 4); /* HDLR */
2196 cio_write(0, 4); /* Version = 0, flags = 0 */
2198 cio_write(0, 4); /* Predefine */
2200 tk->name = 0; /* The track name is immediately determined by the track type */
2202 if (tk->track_type == 0) {
2203 tk->handler_type = 0x76696465; /* Handler type: vide */
2204 cio_write(tk->handler_type, 4);
2208 cio_write(0, 4); /* Reserved */
2210 cio_write(0x76696465, 4);
2211 cio_write(0x6F206d65, 4);
2212 cio_write(0x64696120, 4);
2213 cio_write(0x74726163, 4);
2214 cio_write(0x6b00, 2); /* String: video media track */
2215 } else if (tk->track_type == 1) {
2216 tk->handler_type = 0x736F756E; /* Handler type: soun */
2217 cio_write(tk->handler_type, 4);
2221 cio_write(0, 4); /* Reserved */
2223 cio_write(0x536F756E, 4);
2224 cio_write(0x6400, 2); /* String: Sound */
2225 } else if (tk->track_type == 2) {
2226 tk->handler_type = 0x68696E74; /* Handler type: hint */
2227 cio_write(tk->handler_type, 4);
2231 cio_write(0, 4); /* Reserved */
2233 cio_write(0x48696E74, 4);
2234 cio_write(0, 2); /* String: Hint */
2237 box.length = cio_tell() - box.init_pos;
2238 cio_seek(box.init_pos);
2239 cio_write(box.length, 4); /* L */
2240 cio_seek(box.init_pos + box.length);
2246 * Handler reference box
2249 int mj2_read_hdlr(mj2_tk_t * tk)
2254 mj2_read_boxhdr(&box);
2255 if (MJ2_HDLR != box.type) {
2256 fprintf(stderr, "Error: Expected HDLR Marker\n");
2261 if (0 != cio_read(1)) { /* Version = 0 */
2262 fprintf(stderr, "Error: Only Version 0 handled in VMHD box\n");
2266 if (0 != cio_read(3)) { /* Flags = 0 */
2267 fprintf(stderr, "Error with flag in VMHD box. Expected flag 0\n");
2271 cio_skip(4); /* Reserved */
2273 tk->handler_type = cio_read(4);
2274 cio_skip(12); /* Reserved */
2276 tk->name_size = box.length - 32;
2278 tk->name = (char *) malloc(tk->name_size * sizeof(char));
2279 for (i = 0; i < tk->name_size; i++) {
2280 tk->name[i] = cio_read(1); /* Name */
2283 if (cio_tell() - box.init_pos != box.length) {
2284 fprintf(stderr, "Error with HDLR Box size\n");
2291 * Write the MDHD box
2296 void mj2_write_mdhd(mj2_tk_t * tk)
2301 unsigned int modification_time;
2303 box.init_pos = cio_tell();
2305 cio_write(MJ2_MDHD, 4); /* MDHD */
2307 cio_write(0, 4); /* Version = 0, flags = 0 */
2309 cio_write(tk->creation_time, 4); /* Creation Time */
2311 time(<ime); /* Time since 1/1/70 */
2312 modification_time = ltime + 2082844800; /* Seoonds between 1/1/04 and 1/1/70 */
2314 cio_write(modification_time, 4); /* Modification Time */
2316 cio_write(tk->timescale, 4); /* Timescale */
2320 for (i = 0; i < tk->num_samples; i++)
2321 tk->duration += tk->sample[i].sample_delta;
2323 cio_write(tk->duration, 4); /* Duration */
2325 cio_write(tk->language, 2); /* Language */
2327 cio_write(0, 2); /* Predefined */
2329 box.length = cio_tell() - box.init_pos;
2330 cio_seek(box.init_pos);
2331 cio_write(box.length, 4); /* L */
2332 cio_seek(box.init_pos + box.length);
2341 int mj2_read_mdhd(mj2_tk_t * tk)
2345 mj2_read_boxhdr(&box);
2346 if (!(MJ2_MHDR == box.type || MJ2_MDHD == box.type)) { // Kakadu writes MHDR instead of MDHD
2347 fprintf(stderr, "Error: Expected MDHD Marker\n");
2351 if (0 != cio_read(1)) { /* Version = 0 */
2352 fprintf(stderr, "Error: Only Version 0 handled in MDHD box\n");
2356 if (0 != cio_read(3)) { /* Flags = 0 */
2357 fprintf(stderr, "Error with flag in MDHD box. Expected flag 0\n");
2362 tk->creation_time = cio_read(4); /* Creation Time */
2364 tk->modification_time = cio_read(4); /* Modification Time */
2366 tk->timescale = cio_read(4); /* Timescale */
2368 tk->duration = cio_read(4); /* Duration */
2370 tk->language = cio_read(2); /* Language */
2372 cio_skip(2); /* Predefined */
2374 if (cio_tell() - box.init_pos != box.length) {
2375 fprintf(stderr, "Error with MDHD Box size\n");
2382 * Write the MDIA box
2387 void mj2_write_mdia(mj2_tk_t * tk, j2k_image_t * img)
2391 box.init_pos = cio_tell();
2393 cio_write(MJ2_MDIA, 4); /* MDIA */
2397 mj2_write_minf(tk, img);
2399 box.length = cio_tell() - box.init_pos;
2400 cio_seek(box.init_pos);
2401 cio_write(box.length, 4); /* L */
2402 cio_seek(box.init_pos + box.length);
2411 int mj2_read_mdia(mj2_tk_t * tk, j2k_image_t * img)
2415 mj2_read_boxhdr(&box);
2416 if (MJ2_MDIA != box.type) {
2417 fprintf(stderr, "Error: Expected MDIA Marker\n");
2421 if (mj2_read_mdhd(tk))
2423 if (mj2_read_hdlr(tk))
2425 if (mj2_read_minf(tk, img))
2428 if (cio_tell() - box.init_pos != box.length) {
2429 fprintf(stderr, "Error with MDIA Box size\n");
2436 * Write the TKHD box
2441 void mj2_write_tkhd(mj2_tk_t * tk)
2447 box.init_pos = cio_tell();
2450 cio_write(MJ2_TKHD, 4); /* TKHD */
2452 cio_write(3, 4); /* Version=0, flags=3 */
2454 time(<ime); /* Time since 1/1/70 */
2455 tk->modification_time = ltime + 2082844800; /* Seoonds between 1/1/04 and 1/1/70 */
2457 cio_write(tk->creation_time, 4); /* Creation Time */
2459 cio_write(tk->modification_time, 4); /* Modification Time */
2461 cio_write(tk->track_ID, 4); /* Track ID */
2463 cio_write(0, 4); /* Reserved */
2467 for (i = 0; i < tk->num_samples; i++)
2468 tk->duration += tk->sample[i].sample_delta;
2470 cio_write(tk->duration, 4); /* Duration */
2472 cio_write(0, 4); /* Reserved */
2473 cio_write(0, 4); /* Reserved */
2475 cio_write(tk->layer, 2); /* Layer */
2477 cio_write(0, 2); /* Predefined */
2479 cio_write(tk->volume << 8, 2); /* Volume */
2481 cio_write(0, 2); /* Reserved */
2483 cio_write(tk->trans_matrix[0], 4); /* Transformation matrix for track */
2484 cio_write(tk->trans_matrix[1], 4);
2485 cio_write(tk->trans_matrix[2], 4);
2486 cio_write(tk->trans_matrix[3], 4);
2487 cio_write(tk->trans_matrix[4], 4);
2488 cio_write(tk->trans_matrix[5], 4);
2489 cio_write(tk->trans_matrix[6], 4);
2490 cio_write(tk->trans_matrix[7], 4);
2491 cio_write(tk->trans_matrix[8], 4);
2493 cio_write(tk->w << 16, 4); /* Video Width */
2495 cio_write(tk->h << 16, 4); /* Video Height */
2497 box.length = cio_tell() - box.init_pos;
2498 cio_seek(box.init_pos);
2499 cio_write(box.length, 4); /* L */
2500 cio_seek(box.init_pos + box.length);
2509 int mj2_read_tkhd(mj2_tk_t * tk)
2515 mj2_read_boxhdr(&box);
2517 if (MJ2_TKHD != box.type) {
2518 fprintf(stderr, "Error: Expected TKHD Marker\n");
2522 if (0 != cio_read(1)) { /* Version = 0 */
2523 fprintf(stderr, "Error: Only Version 0 handled in TKHD box\n");
2529 if (!(flag == 1 || flag == 2 || flag == 3 || flag == 4)) { /* Flags = 1,2,3 or 4 */
2531 "Error with flag in TKHD box: Expected flag 1,2,3 or 4\n");
2535 tk->creation_time = cio_read(4); /* Creation Time */
2537 tk->modification_time = cio_read(4); /* Modification Time */
2539 tk->track_ID = cio_read(4); /* Track ID */
2541 cio_skip(4); /* Reserved */
2543 tk->duration = cio_read(4); /* Duration */
2545 cio_skip(8); /* Reserved */
2547 tk->layer = cio_read(2); /* Layer */
2549 cio_read(2); /* Predefined */
2551 tk->volume = cio_read(2) >> 8; /* Volume */
2553 cio_skip(2); /* Reserved */
2555 tk->trans_matrix[0] = cio_read(4); /* Transformation matrix for track */
2556 tk->trans_matrix[1] = cio_read(4);
2557 tk->trans_matrix[2] = cio_read(4);
2558 tk->trans_matrix[3] = cio_read(4);
2559 tk->trans_matrix[4] = cio_read(4);
2560 tk->trans_matrix[5] = cio_read(4);
2561 tk->trans_matrix[6] = cio_read(4);
2562 tk->trans_matrix[7] = cio_read(4);
2563 tk->trans_matrix[8] = cio_read(4);
2565 tk->w = cio_read(4) >> 16; /* Video Width */
2567 tk->h = cio_read(4) >> 16; /* Video Height */
2569 if (cio_tell() - box.init_pos != box.length) {
2570 fprintf(stderr, "Error with TKHD Box size\n");
2577 * Write the TRAK box
2582 void mj2_write_trak(mj2_tk_t * tk, j2k_image_t * img)
2586 box.init_pos = cio_tell();
2589 cio_write(MJ2_TRAK, 4); /* TRAK */
2592 mj2_write_mdia(tk, img);
2594 box.length = cio_tell() - box.init_pos;
2595 cio_seek(box.init_pos);
2596 cio_write(box.length, 4); /* L */
2597 cio_seek(box.init_pos + box.length);
2606 int mj2_read_trak(mj2_tk_t * tk, j2k_image_t * img)
2610 mj2_read_boxhdr(&box);
2611 if (MJ2_TRAK != box.type) {
2612 fprintf(stderr, "Error: Expected TRAK Marker\n");
2615 if (mj2_read_tkhd(tk))
2617 if (mj2_read_mdia(tk, img))
2619 if (cio_tell() - box.init_pos != box.length) {
2620 fprintf(stderr, "Error with TRAK Box\n");
2627 * Write the MVHD box
2632 void mj2_write_mvhd(mj2_movie_t * movie)
2640 box.init_pos = cio_tell();
2642 cio_write(MJ2_MVHD, 4); /* MVHD */
2644 cio_write(0, 4); /* Version = 0, flags = 0 */
2646 time(<ime); /* Time since 1/1/70 */
2647 movie->modification_time = ltime + 2082844800; /* Seoonds between 1/1/04 and 1/1/70 */
2649 cio_write(movie->creation_time, 4); /* Creation Time */
2651 cio_write(movie->modification_time, 4); /* Modification Time */
2653 cio_write(movie->timescale, 4); /* Timescale */
2655 movie->duration = 0;
2657 for (i = 0; i < (movie->num_stk + movie->num_htk + movie->num_vtk); i++) {
2658 mj2_tk_t *tk = &movie->tk[i];
2660 for (j = 0; j < tk->num_samples; j++) {
2661 movie->duration += tk->sample[j].sample_delta;
2665 cio_write(movie->duration, 4);
2667 cio_write(movie->rate << 16, 4); /* Rate to play presentation */
2669 cio_write(movie->volume << 8, 2); /* Volume */
2671 cio_write(0, 2); /* Reserved */
2672 cio_write(0, 4); /* Reserved */
2673 cio_write(0, 4); /* Reserved */
2675 cio_write(movie->trans_matrix[0], 4); /* Transformation matrix for video */
2676 cio_write(movie->trans_matrix[1], 4);
2677 cio_write(movie->trans_matrix[2], 4);
2678 cio_write(movie->trans_matrix[3], 4);
2679 cio_write(movie->trans_matrix[4], 4);
2680 cio_write(movie->trans_matrix[5], 4);
2681 cio_write(movie->trans_matrix[6], 4);
2682 cio_write(movie->trans_matrix[7], 4);
2683 cio_write(movie->trans_matrix[8], 4);
2685 cio_write(0, 4); /* Pre-defined */
2686 cio_write(0, 4); /* Pre-defined */
2687 cio_write(0, 4); /* Pre-defined */
2688 cio_write(0, 4); /* Pre-defined */
2689 cio_write(0, 4); /* Pre-defined */
2690 cio_write(0, 4); /* Pre-defined */
2693 for (i = 0; i < movie->num_htk + movie->num_stk + movie->num_vtk; i++) {
2694 if (max_tk_num < movie->tk[i].track_ID)
2695 max_tk_num = movie->tk[i].track_ID;
2698 movie->next_tk_id = max_tk_num + 1;
2700 cio_write(movie->next_tk_id, 4); /* ID of Next track to be added */
2702 box.length = cio_tell() - box.init_pos;
2703 cio_seek(box.init_pos);
2704 cio_write(box.length, 4); /* L */
2705 cio_seek(box.init_pos + box.length);
2714 int mj2_read_mvhd(mj2_movie_t * movie)
2718 mj2_read_boxhdr(&box);
2719 if (MJ2_MVHD != box.type) {
2720 fprintf(stderr, "Error: Expected MVHD Marker\n");
2725 if (0 != cio_read(4)) { /* Version = 0, flags = 0 */
2726 fprintf(stderr, "Error: Only Version 0 handled\n");
2729 movie->creation_time = cio_read(4); /* Creation Time */
2731 movie->modification_time = cio_read(4); /* Modification Time */
2733 movie->timescale = cio_read(4); /* Timescale */
2735 movie->duration = cio_read(4); /* Duration */
2737 movie->rate = cio_read(4) >> 16; /* Rate to play presentation */
2739 movie->volume = cio_read(2) >> 8; /* Volume */
2741 cio_skip(10); /* Reserved */
2743 movie->trans_matrix[0] = cio_read(4); /* Transformation matrix for video */
2744 movie->trans_matrix[1] = cio_read(4);
2745 movie->trans_matrix[2] = cio_read(4);
2746 movie->trans_matrix[3] = cio_read(4);
2747 movie->trans_matrix[4] = cio_read(4);
2748 movie->trans_matrix[5] = cio_read(4);
2749 movie->trans_matrix[6] = cio_read(4);
2750 movie->trans_matrix[7] = cio_read(4);
2751 movie->trans_matrix[8] = cio_read(4);
2753 cio_skip(24); /* Pre-defined */
2755 movie->next_tk_id = cio_read(4); /* ID of Next track to be added */
2757 if (cio_tell() - box.init_pos != box.length) {
2758 fprintf(stderr, "Error with MVHD Box Size\n");
2766 * Write the MOOV box
2771 void mj2_write_moov(mj2_movie_t * movie, j2k_image_t * img)
2776 box.init_pos = cio_tell();
2778 cio_write(MJ2_MOOV, 4); /* MOOV */
2780 mj2_write_mvhd(movie);
2782 for (i = 0; i < (movie->num_stk + movie->num_htk + movie->num_vtk); i++) {
2783 mj2_write_trak(&movie->tk[i], img);
2786 box.length = cio_tell() - box.init_pos;
2787 cio_seek(box.init_pos);
2788 cio_write(box.length, 4); /* L */
2789 cio_seek(box.init_pos + box.length);
2799 int mj2_read_moov(mj2_movie_t * movie, j2k_image_t * img)
2805 mj2_read_boxhdr(&box);
2806 if (MJ2_MOOV != box.type) {
2807 fprintf(stderr, "Error: Expected MOOV Marker\n");
2813 if (mj2_read_mvhd(movie))
2818 (mj2_tk_t *) malloc((movie->next_tk_id - 1) * sizeof(mj2_tk_t));
2820 for (i=0; i < (unsigned int)movie->next_tk_id - 1; i++)
2821 movie->tk[i].imagefile = NULL;
2823 for (i = 0; cio_tell() - box.init_pos < box.length; i++) {
2824 mj2_read_boxhdr(&box2);
2825 if (box2.type == MJ2_TRAK) {
2826 cio_seek(box2.init_pos);
2827 if (mj2_read_trak(&movie->tk[i], img))
2830 if (movie->tk[i].track_type == 0) {
2832 } else if (movie->tk[i].track_type == 1) {
2834 } else if (movie->tk[i].track_type == 2) {
2837 } else if (box2.type == MJ2_MVEX) {
2838 cio_seek(box2.init_pos);
2839 cio_skip(box2.length);
2842 fprintf(stderr, "Error with MOOV Box: Expected TRAK or MVEX box\n");
2850 int mj2_encode(mj2_movie_t * movie, j2k_cp_t * cp, char *index)
2860 outbuf = (char *) malloc(cp->tdx * cp->tdy * 2);
2861 cio_init(outbuf, cp->tdx * cp->tdy * 2);
2863 outfile = fopen(movie->mj2file, "wb");
2865 fprintf(stderr, "failed to open %s for writing\n", movie->mj2file);
2870 mj2_write_ftyp(movie);
2872 if (mj2_write_mdat(outfile, movie, &img, cp, outbuf, index)) {
2873 fprintf(stderr, "Error writing tracks\n\n");
2877 outbuf = (char *) malloc(cp->tdx * cp->tdy * 2);
2878 cio_init(outbuf, cp->tdx * cp->tdy * 2);
2880 mj2_write_moov(movie, &img);
2883 fwrite(outbuf, 1, len, outfile);
2887 for (i = 0; i < movie->tk[0].jp2_struct.numcomps; i++) {
2889 sprintf(tmp, "Compo%d", i);
2890 if (remove(tmp) == -1) {
2891 fprintf(stderr, "failed to kill %s file !\n", tmp);
2902 int mj2_decode(unsigned char *src, int len, mj2_movie_t * movie,
2903 j2k_cp_t * cp, char *outfile)
2905 unsigned int MDATbox_pos = 0;
2906 unsigned int MOOVboxend_pos = 0;
2914 if (mj2_read_ftyp(movie))
2918 for (; cio_numbytesleft() > 0;) {
2919 mj2_read_boxhdr(&box);
2922 cio_seek(box.init_pos);
2923 if (MOOVboxend_pos == 0) {
2924 MDATbox_pos = box.init_pos;
2925 cio_skip(box.length); /* The MDAT box is only read while the MOOV box is decoded */
2927 if (mj2_read_mdat(movie, src, outfile))
2933 cio_seek(box.init_pos);
2934 if (mj2_read_moov(movie, &img))
2936 MOOVboxend_pos = cio_tell();
2937 if (MDATbox_pos != 0) {
2938 cio_seek(MDATbox_pos); /* After MOOV box, read the MDAT box */
2940 if (mj2_read_mdat(movie, src, outfile))
2943 cio_seek(MOOVboxend_pos);
2948 cio_seek(box.init_pos);
2949 cio_skip(box.length);
2952 cio_seek(box.init_pos);
2953 cio_skip(box.length);
2956 cio_seek(box.init_pos);
2957 cio_skip(box.length);
2960 fprintf(stderr, "Unknown box\n");