2 * The copyright in this software is being made available under the 2-clauses
3 * BSD License, included below. This software may be subject to other third
4 * party and contributor rights, including patent rights, and no such rights
5 * are granted under this license.
7 * Copyright (c) 2002-2014, Universite catholique de Louvain (UCL), Belgium
8 * Copyright (c) 2002-2014, Professor Benoit Macq
9 * Copyright (c) 2003-2007, Francois-Olivier Devaux
10 * All rights reserved.
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
44 static int int_ceildiv(int a, int b)
46 return (a + b - 1) / b;
50 Size of memory first allocated for MOOV box
52 #define TEMP_BUF 10000
54 #define J2K_CODESTREAM_MAGIC "\xff\x4f\xff\x51"
56 /* -------------------------------------------------------------------------- */
58 static int test_image(const char *fname, mj2_cparameters_t *cp)
65 opj_dparameters_t dparameters;
71 if ((reader = fopen(fname, "rb")) == NULL) {
75 fseek(reader, 0, SEEK_END);
76 src_len = ftell(reader);
77 fseek(reader, 0, SEEK_SET);
78 src = (unsigned char*) malloc(src_len);
79 fread(src, 1, src_len, reader);
82 if (memcmp(src, J2K_CODESTREAM_MAGIC, 4) != 0) {
86 memset(&dparameters, 0, sizeof(opj_dparameters_t));
88 opj_set_default_decoder_parameters(&dparameters);
90 dinfo = opj_create_decompress(CODEC_J2K);
92 opj_setup_decoder(dinfo, &dparameters);
94 cio = opj_cio_open((opj_common_ptr)dinfo, src, src_len);
96 image = opj_decode(dinfo, cio);
106 cp->numcomps = image->numcomps;
107 cp->w = image->comps[0].w;
108 cp->h = image->comps[0].h;
109 cp->prec = image->comps[0].prec;
111 if (image->numcomps > 2) {
112 if ((image->comps[0].dx == 1)
113 && (image->comps[1].dx == 2)
114 && (image->comps[2].dx == 2)
115 && (image->comps[0].dy == 1)
116 && (image->comps[1].dy == 2)
117 && (image->comps[2].dy == 2)) { /* horizontal and vertical*/
119 cp->enumcs = ENUMCS_SYCC;
120 cp->CbCr_subsampling_dx = 2;
121 cp->CbCr_subsampling_dy = 2;
122 } else if ((image->comps[0].dx == 1)
123 && (image->comps[1].dx == 2)
124 && (image->comps[2].dx == 2)
125 && (image->comps[0].dy == 1)
126 && (image->comps[1].dy == 1)
127 && (image->comps[2].dy == 1)) { /* horizontal only*/
129 cp->enumcs = ENUMCS_SYCC;
130 cp->CbCr_subsampling_dx = 2;
131 cp->CbCr_subsampling_dy = 1;
132 } else if ((image->comps[0].dx == 1)
133 && (image->comps[1].dx == 1)
134 && (image->comps[2].dx == 1)
135 && (image->comps[0].dy == 1)
136 && (image->comps[1].dy == 1)
137 && (image->comps[2].dy == 1)) {
140 if (image->color_space == CLRSPC_SRGB) {
141 cp->enumcs = ENUMCS_SRGB;
143 /* cp->CbCr_subsampling_dx = 0; */
144 /* cp->CbCr_subsampling_dy = 0; */
146 cp->enumcs = ENUMCS_SYCC;
148 cp->CbCr_subsampling_dx = 1;
149 cp->CbCr_subsampling_dy = 1;
155 cp->enumcs = ENUMCS_GRAY;
156 /* cp->CbCr_subsampling_dx = 0; */
157 /* cp->CbCr_subsampling_dy = 0; */
159 if (image->icc_profile_buf) {
161 free(image->icc_profile_buf);
162 image->icc_profile_buf = NULL;
170 opj_destroy_decompress(dinfo);
174 opj_image_destroy(image);
181 sample error callback expecting a FILE* client object
183 static void error_callback(const char *msg, void *client_data)
185 FILE *stream = (FILE*)client_data;
186 fprintf(stream, "[ERROR] %s", msg);
189 sample warning callback expecting a FILE* client object
191 static void warning_callback(const char *msg, void *client_data)
193 FILE *stream = (FILE*)client_data;
194 fprintf(stream, "[WARNING] %s", msg);
197 sample debug callback expecting a FILE* client object
199 static void info_callback(const char *msg, void *client_data)
201 FILE *stream = (FILE*)client_data;
202 fprintf(stream, "[INFO] %s", msg);
205 /* -------------------------------------------------------------------------- */
209 static void read_siz_marker(FILE *file, opj_image_t *image)
213 unsigned char *siz_buffer;
216 fseek(file, 0, SEEK_SET);
218 fread(&buf, 1, 1, file);
219 if (buf == (char)0xff) {
220 fread(&buf, 1, 1, file);
222 } while (!(buf == (char)0x51));
224 fread(buf2, 2, 1, file); /* Lsiz */
225 len = ((buf2[0]) << 8) + buf2[1];
227 siz_buffer = (unsigned char*) malloc(len * sizeof(unsigned char));
228 fread(siz_buffer, len, 1, file);
229 cio = opj_cio_open(NULL, siz_buffer, len);
231 cio_read(cio, 2); /* Rsiz (capabilities) */
232 image->x1 = cio_read(cio, 4); /* Xsiz */
233 image->y1 = cio_read(cio, 4); /* Ysiz */
234 image->x0 = cio_read(cio, 4); /* X0siz */
235 image->y0 = cio_read(cio, 4); /* Y0siz */
236 cio_skip(cio, 16); /* XTsiz, YTsiz, XT0siz, YT0siz */
238 image->numcomps = cio_read(cio, 2); /* Csiz */
240 (opj_image_comp_t *) malloc(image->numcomps * sizeof(opj_image_comp_t));
242 for (i = 0; i < image->numcomps; i++) {
244 tmp = cio_read(cio, 1); /* Ssiz_i */
245 image->comps[i].prec = (tmp & 0x7f) + 1;
246 image->comps[i].sgnd = tmp >> 7;
247 image->comps[i].dx = cio_read(cio, 1); /* XRsiz_i */
248 image->comps[i].dy = cio_read(cio, 1); /* YRsiz_i */
249 image->comps[i].resno_decoded = 0; /* number of resolution decoded */
250 image->comps[i].factor = 0; /* reducing factor by component */
252 fseek(file, 0, SEEK_SET);
257 static void setparams(opj_mj2_t *movie, opj_image_t *image)
259 int i, depth_0, depth, sign;
261 movie->tk[0].w = int_ceildiv(image->x1 - image->x0, image->comps[0].dx);
262 movie->tk[0].h = int_ceildiv(image->y1 - image->y0, image->comps[0].dy);
263 mj2_init_stdmovie(movie);
265 movie->tk[0].depth = image->comps[0].prec;
267 if (image->numcomps == 3) {
268 if ((image->comps[0].dx == 1)
269 && (image->comps[1].dx == 1)
270 && (image->comps[2].dx == 1)) {
271 movie->tk[0].CbCr_subsampling_dx = 1;
272 } else if ((image->comps[0].dx == 1)
273 && (image->comps[1].dx == 2)
274 && (image->comps[2].dx == 2)) {
275 movie->tk[0].CbCr_subsampling_dx = 2;
277 fprintf(stderr, "Image component sizes are incoherent\n");
280 if ((image->comps[0].dy == 1)
281 && (image->comps[1].dy == 1)
282 && (image->comps[2].dy == 1)) {
283 movie->tk[0].CbCr_subsampling_dy = 1;
284 } else if ((image->comps[0].dy == 1)
285 && (image->comps[1].dy == 2)
286 && (image->comps[2].dy == 2)) {
287 movie->tk[0].CbCr_subsampling_dy = 2;
289 fprintf(stderr, "Image component sizes are incoherent\n");
293 movie->tk[0].sample_rate = 25;
295 movie->tk[0].jp2_struct.numcomps = image->numcomps; /* NC */
297 /* Init Standard jp2 structure */
299 movie->tk[0].jp2_struct.comps =
300 (opj_jp2_comps_t *) malloc(movie->tk[0].jp2_struct.numcomps * sizeof(
302 movie->tk[0].jp2_struct.precedence = 0; /* PRECEDENCE*/
303 movie->tk[0].jp2_struct.approx = 0; /* APPROX*/
304 movie->tk[0].jp2_struct.brand = JP2_JP2; /* BR */
305 movie->tk[0].jp2_struct.minversion = 0; /* MinV */
306 movie->tk[0].jp2_struct.numcl = 1;
307 movie->tk[0].jp2_struct.cl = (unsigned int *) malloc(
308 movie->tk[0].jp2_struct.numcl * sizeof(int));
309 movie->tk[0].jp2_struct.cl[0] = JP2_JP2; /* CL0 : JP2 */
310 movie->tk[0].jp2_struct.C = 7; /* C : Always 7*/
311 movie->tk[0].jp2_struct.UnkC =
312 0; /* UnkC, colorspace specified in colr box*/
313 movie->tk[0].jp2_struct.IPR = 0; /* IPR, no intellectual property*/
314 movie->tk[0].jp2_struct.w = int_ceildiv(image->x1 - image->x0,
316 movie->tk[0].jp2_struct.h = int_ceildiv(image->y1 - image->y0,
319 depth_0 = image->comps[0].prec - 1;
320 sign = image->comps[0].sgnd;
321 movie->tk[0].jp2_struct.bpc = depth_0 + (sign << 7);
323 for (i = 1; i < image->numcomps; i++) {
324 depth = image->comps[i].prec - 1;
325 sign = image->comps[i].sgnd;
326 if (depth_0 != depth) {
327 movie->tk[0].jp2_struct.bpc = 255;
331 for (i = 0; i < image->numcomps; i++)
332 movie->tk[0].jp2_struct.comps[i].bpcc =
333 image->comps[i].prec - 1 + (image->comps[i].sgnd << 7);
335 if ((image->numcomps == 1 || image->numcomps == 3)
336 && (movie->tk[0].jp2_struct.bpc != 255)) {
337 movie->tk[0].jp2_struct.meth = 1;
339 movie->tk[0].jp2_struct.meth = 2;
342 if (image->numcomps == 1) {
343 movie->tk[0].jp2_struct.enumcs = 17; /* Grayscale */
346 else if ((image->comps[0].dx == 1)
347 && (image->comps[1].dx == 1)
348 && (image->comps[2].dx == 1)
349 && (image->comps[0].dy == 1)
350 && (image->comps[1].dy == 1)
351 && (image->comps[2].dy == 1)) {
352 movie->tk[0].jp2_struct.enumcs = 16; /* RGB */
355 else if ((image->comps[0].dx == 1)
356 && (image->comps[1].dx == 2)
357 && (image->comps[2].dx == 2)
358 && (image->comps[0].dy == 1)
359 && (image->comps[1].dy == 2)
360 && (image->comps[2].dy == 2)) {
361 movie->tk[0].jp2_struct.enumcs = 18; /* YUV */
365 movie->tk[0].jp2_struct.enumcs = 0; /* Unknown profile */
369 int main(int argc, char *argv[])
372 opj_event_mgr_t event_mgr; /* event manager */
375 mj2_sample_t *sample;
376 unsigned char* frame_codestream;
377 FILE *mj2file, *j2kfile;
380 int offset, mdat_initpos;
383 mj2_cparameters_t parameters;
386 printf("Usage: %s source_location mj2_filename\n", argv[0]);
387 printf("Example: %s input/input output.mj2\n", argv[0]);
391 mj2file = fopen(argv[2], "wb");
394 fprintf(stderr, "failed to open %s for writing\n", argv[2]);
397 memset(&img, 0, sizeof(opj_image_t));
399 configure the event callbacks (not required)
400 setting of each callback is optionnal
402 memset(&event_mgr, 0, sizeof(opj_event_mgr_t));
403 event_mgr.error_handler = error_callback;
404 event_mgr.warning_handler = warning_callback;
405 event_mgr.info_handler = info_callback;
407 /* get a MJ2 decompressor handle */
408 cinfo = mj2_create_compress();
410 /* catch events using our callbacks and give a local context */
411 opj_set_event_mgr((opj_common_ptr)cinfo, &event_mgr, stderr);
413 /* setup the decoder encoding parameters using user parameters */
414 memset(¶meters, 0, sizeof(mj2_cparameters_t));
415 movie = (opj_mj2_t*) cinfo->mj2_handle;
417 j2kfilename = (char*)malloc(strlen(argv[1]) + 12);/* max. '%6d' */
418 sprintf(j2kfilename, "%s_00001.j2k", argv[1]);
420 if (test_image(j2kfilename, ¶meters) == 0) {
424 parameters.frame_rate = 25; /* DEFAULT */
426 mj2_setup_encoder(movie, ¶meters);
429 /* Writing JP, FTYP and MDAT boxes
430 Assuming that the JP and FTYP boxes won't be longer than 300 bytes */
432 buf = (unsigned char*) malloc(300 * sizeof(unsigned char));
433 cio = opj_cio_open(movie->cinfo, buf, 300);
435 mj2_write_ftyp(movie, cio);
436 mdat_initpos = cio_tell(cio);
438 cio_write(cio, MJ2_MDAT, 4);
439 fwrite(buf, cio_tell(cio), 1, mj2file);
442 /* Insert each j2k codestream in a JP2C box */
446 mj2_sample_t * new_sample;
447 mj2_chunk_t * new_chunk;
448 sample = &movie->tk[0].sample[snum];
449 sprintf(j2kfilename, "%s_%05d.j2k", argv[1], snum);
450 j2kfile = fopen(j2kfilename, "rb");
452 if (snum == 0) { /* Could not open a single codestream */
453 fprintf(stderr, "failed to open %s for reading\n", j2kfilename);
455 } else { /* Tried to open a inexistant codestream */
456 fprintf(stdout, "%d frames are being added to the MJ2 file\n", snum);
461 /* Calculating offset for samples and chunks */
462 offset += cio_tell(cio);
463 sample->offset = offset;
464 movie->tk[0].chunk[snum].offset =
465 offset; /* There will be one sample per chunk */
467 /* Calculating sample size */
468 fseek(j2kfile, 0, SEEK_END);
469 sample->sample_size = ftell(j2kfile) +
470 8; /* Sample size is codestream + JP2C box header */
471 fseek(j2kfile, 0, SEEK_SET);
473 /* Reading siz marker of j2k image for the first codestream */
475 read_siz_marker(j2kfile, &img);
478 /* Writing JP2C box header */
479 frame_codestream = (unsigned char*) malloc(sample->sample_size + 8);
480 cio = opj_cio_open(movie->cinfo, frame_codestream, sample->sample_size);
481 cio_write(cio, sample->sample_size, 4); /* Sample size */
482 cio_write(cio, JP2_JP2C, 4); /* JP2C */
484 /* Writing codestream from J2K file to MJ2 file */
485 fread(frame_codestream + 8, sample->sample_size - 8, 1, j2kfile);
486 fwrite(frame_codestream, sample->sample_size, 1, mj2file);
487 cio_skip(cio, sample->sample_size - 8);
492 new_sample = (mj2_sample_t*)
493 realloc(movie->tk[0].sample, (snum + 1) * sizeof(mj2_sample_t));
494 new_chunk = (mj2_chunk_t*)
495 realloc(movie->tk[0].chunk, (snum + 1) * sizeof(mj2_chunk_t));
496 if (new_sample && new_chunk) {
497 movie->tk[0].sample = new_sample;
498 movie->tk[0].chunk = new_chunk;
500 fprintf(stderr, "Failed to allocate enough memory to read %s\n", j2kfilename);
503 free(frame_codestream);
506 /* Writing the MDAT box length in header */
507 offset += cio_tell(cio);
508 buf = (unsigned char*) malloc(4 * sizeof(unsigned char));
509 cio = opj_cio_open(movie->cinfo, buf, 4);
510 cio_write(cio, offset - mdat_initpos, 4);
511 fseek(mj2file, (long)mdat_initpos, SEEK_SET);
512 fwrite(buf, 4, 1, mj2file);
513 fseek(mj2file, 0, SEEK_END);
516 /* Setting movie parameters */
517 movie->tk[0].num_samples = snum;
518 movie->tk[0].num_chunks = snum;
519 setparams(movie, &img);
521 /* Writing MOOV box */
522 buf = (unsigned char*) malloc((TEMP_BUF + snum * 20) * sizeof(unsigned char));
523 cio = opj_cio_open(movie->cinfo, buf, (TEMP_BUF + snum * 20));
524 mj2_write_moov(movie, cio);
525 fwrite(buf, cio_tell(cio), 1, mj2file);
533 mj2_destroy_compress(movie);