2 * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium
3 * Copyright (c) 2002-2007, Professor Benoit Macq
4 * Copyright (c) 2003-2007, Francois-Olivier Devaux
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
39 static int int_ceildiv(int a, int b) {
40 return (a + b - 1) / b;
44 Size of memory first allocated for MOOV box
46 #define TEMP_BUF 10000
48 #define J2K_CODESTREAM_MAGIC "\xff\x4f\xff\x51"
50 /* -------------------------------------------------------------------------- */
52 static int test_image(const char *fname, mj2_cparameters_t *cp)
59 opj_dparameters_t dparameters;
65 if((reader = fopen(fname, "rb")) == NULL) return success;
67 fseek(reader, 0, SEEK_END);
68 src_len = ftell(reader);
69 fseek(reader, 0, SEEK_SET);
70 src = (unsigned char*) malloc(src_len);
71 fread(src, 1, src_len, reader);
74 if(memcmp(src, J2K_CODESTREAM_MAGIC, 4) != 0)
76 free(src); return success;
78 memset(&dparameters, 0, sizeof(opj_dparameters_t));
80 opj_set_default_decoder_parameters(&dparameters);
82 dinfo = opj_create_decompress(CODEC_J2K);
84 opj_setup_decoder(dinfo, &dparameters);
86 cio = opj_cio_open((opj_common_ptr)dinfo, src, src_len);
88 image = opj_decode(dinfo, cio);
90 free(src); cio->buffer = NULL;
93 if(image == NULL) goto fin;
95 cp->numcomps = image->numcomps;
96 cp->w = image->comps[0].w;
97 cp->h = image->comps[0].h;
98 cp->prec = image->comps[0].prec;
100 if(image->numcomps > 2 )
102 if((image->comps[0].dx == 1)
103 && (image->comps[1].dx == 2)
104 && (image->comps[2].dx == 2)
105 && (image->comps[0].dy == 1)
106 && (image->comps[1].dy == 2)
107 && (image->comps[2].dy == 2))/* horizontal and vertical*/
110 cp->enumcs = ENUMCS_SYCC;
111 cp->CbCr_subsampling_dx = 2;
112 cp->CbCr_subsampling_dy = 2;
115 if((image->comps[0].dx == 1)
116 && (image->comps[1].dx == 2)
117 && (image->comps[2].dx == 2)
118 && (image->comps[0].dy == 1)
119 && (image->comps[1].dy == 1)
120 && (image->comps[2].dy == 1))/* horizontal only*/
123 cp->enumcs = ENUMCS_SYCC;
124 cp->CbCr_subsampling_dx = 2;
125 cp->CbCr_subsampling_dy = 1;
128 if((image->comps[0].dx == 1)
129 && (image->comps[1].dx == 1)
130 && (image->comps[2].dx == 1)
131 && (image->comps[0].dy == 1)
132 && (image->comps[1].dy == 1)
133 && (image->comps[2].dy == 1))
137 if(image->color_space == CLRSPC_SRGB)
139 cp->enumcs = ENUMCS_SRGB;
141 /* cp->CbCr_subsampling_dx = 0; */
142 /* cp->CbCr_subsampling_dy = 0; */
146 cp->enumcs = ENUMCS_SYCC;
148 cp->CbCr_subsampling_dx = 1;
149 cp->CbCr_subsampling_dy = 1;
159 cp->enumcs = ENUMCS_GRAY;
160 /* cp->CbCr_subsampling_dx = 0; */
161 /* cp->CbCr_subsampling_dy = 0; */
163 if(image->icc_profile_buf)
166 free(image->icc_profile_buf); image->icc_profile_buf = NULL;
173 opj_destroy_decompress(dinfo);
176 opj_image_destroy(image);
182 sample error callback expecting a FILE* client object
184 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) {
192 FILE *stream = (FILE*)client_data;
193 fprintf(stream, "[WARNING] %s", msg);
196 sample debug callback expecting a FILE* client object
198 static void info_callback(const char *msg, void *client_data) {
199 FILE *stream = (FILE*)client_data;
200 fprintf(stream, "[INFO] %s", msg);
203 /* -------------------------------------------------------------------------- */
207 static void read_siz_marker(FILE *file, opj_image_t *image)
211 unsigned char *siz_buffer;
214 fseek(file, 0, SEEK_SET);
216 fread(&buf,1,1, file);
218 fread(&buf,1,1, file);
220 while (!(buf==(char)0x51));
222 fread(buf2,2,1,file); /* Lsiz */
223 len = ((buf2[0])<<8) + buf2[1];
225 siz_buffer = (unsigned char*) malloc(len * sizeof(unsigned char));
226 fread(siz_buffer,len, 1, file);
227 cio = opj_cio_open(NULL, siz_buffer, len);
229 cio_read(cio, 2); /* Rsiz (capabilities) */
230 image->x1 = cio_read(cio, 4); /* Xsiz */
231 image->y1 = cio_read(cio, 4); /* Ysiz */
232 image->x0 = cio_read(cio, 4); /* X0siz */
233 image->y0 = cio_read(cio, 4); /* Y0siz */
234 cio_skip(cio, 16); /* XTsiz, YTsiz, XT0siz, YT0siz */
236 image->numcomps = cio_read(cio,2); /* Csiz */
238 (opj_image_comp_t *) malloc(image->numcomps * sizeof(opj_image_comp_t));
240 for (i = 0; i < image->numcomps; i++) {
242 tmp = cio_read(cio,1); /* Ssiz_i */
243 image->comps[i].prec = (tmp & 0x7f) + 1;
244 image->comps[i].sgnd = tmp >> 7;
245 image->comps[i].dx = cio_read(cio,1); /* XRsiz_i */
246 image->comps[i].dy = cio_read(cio,1); /* YRsiz_i */
247 image->comps[i].resno_decoded = 0; /* number of resolution decoded */
248 image->comps[i].factor = 0; /* reducing factor by component */
250 fseek(file, 0, SEEK_SET);
255 static void setparams(opj_mj2_t *movie, opj_image_t *image) {
256 int i, depth_0, depth, sign;
258 movie->tk[0].w = int_ceildiv(image->x1 - image->x0, image->comps[0].dx);
259 movie->tk[0].h = int_ceildiv(image->y1 - image->y0, image->comps[0].dy);
260 mj2_init_stdmovie(movie);
262 movie->tk[0].depth = image->comps[0].prec;
264 if (image->numcomps==3) {
265 if ((image->comps[0].dx == 1)
266 && (image->comps[1].dx == 1)
267 && (image->comps[2].dx == 1))
268 movie->tk[0].CbCr_subsampling_dx = 1;
270 if ((image->comps[0].dx == 1)
271 && (image->comps[1].dx == 2)
272 && (image->comps[2].dx == 2))
273 movie->tk[0].CbCr_subsampling_dx = 2;
275 fprintf(stderr,"Image component sizes are incoherent\n");
277 if ((image->comps[0].dy == 1)
278 && (image->comps[1].dy == 1)
279 && (image->comps[2].dy == 1))
280 movie->tk[0].CbCr_subsampling_dy = 1;
282 if ((image->comps[0].dy == 1)
283 && (image->comps[1].dy == 2)
284 && (image->comps[2].dy == 2))
285 movie->tk[0].CbCr_subsampling_dy = 2;
287 fprintf(stderr,"Image component sizes are incoherent\n");
290 movie->tk[0].sample_rate = 25;
292 movie->tk[0].jp2_struct.numcomps = image->numcomps; /* NC */
294 /* Init Standard jp2 structure */
296 movie->tk[0].jp2_struct.comps =
297 (opj_jp2_comps_t *) malloc(movie->tk[0].jp2_struct.numcomps * sizeof(opj_jp2_comps_t));
298 movie->tk[0].jp2_struct.precedence = 0; /* PRECEDENCE*/
299 movie->tk[0].jp2_struct.approx = 0; /* APPROX*/
300 movie->tk[0].jp2_struct.brand = JP2_JP2; /* BR */
301 movie->tk[0].jp2_struct.minversion = 0; /* MinV */
302 movie->tk[0].jp2_struct.numcl = 1;
303 movie->tk[0].jp2_struct.cl = (unsigned int *) malloc(movie->tk[0].jp2_struct.numcl * sizeof(int));
304 movie->tk[0].jp2_struct.cl[0] = JP2_JP2; /* CL0 : JP2 */
305 movie->tk[0].jp2_struct.C = 7; /* C : Always 7*/
306 movie->tk[0].jp2_struct.UnkC = 0; /* UnkC, colorspace specified in colr box*/
307 movie->tk[0].jp2_struct.IPR = 0; /* IPR, no intellectual property*/
308 movie->tk[0].jp2_struct.w = int_ceildiv(image->x1 - image->x0, image->comps[0].dx);
309 movie->tk[0].jp2_struct.h = int_ceildiv(image->y1 - image->y0, image->comps[0].dy);
311 depth_0 = image->comps[0].prec - 1;
312 sign = image->comps[0].sgnd;
313 movie->tk[0].jp2_struct.bpc = depth_0 + (sign << 7);
315 for (i = 1; i < image->numcomps; i++) {
316 depth = image->comps[i].prec - 1;
317 sign = image->comps[i].sgnd;
318 if (depth_0 != depth)
319 movie->tk[0].jp2_struct.bpc = 255;
322 for (i = 0; i < image->numcomps; i++)
323 movie->tk[0].jp2_struct.comps[i].bpcc =
324 image->comps[i].prec - 1 + (image->comps[i].sgnd << 7);
326 if ((image->numcomps == 1 || image->numcomps == 3)
327 && (movie->tk[0].jp2_struct.bpc != 255))
328 movie->tk[0].jp2_struct.meth = 1;
330 movie->tk[0].jp2_struct.meth = 2;
332 if (image->numcomps == 1)
333 movie->tk[0].jp2_struct.enumcs = 17; /* Grayscale */
336 if ((image->comps[0].dx == 1)
337 && (image->comps[1].dx == 1)
338 && (image->comps[2].dx == 1)
339 && (image->comps[0].dy == 1)
340 && (image->comps[1].dy == 1)
341 && (image->comps[2].dy == 1))
342 movie->tk[0].jp2_struct.enumcs = 16; /* RGB */
345 if ((image->comps[0].dx == 1)
346 && (image->comps[1].dx == 2)
347 && (image->comps[2].dx == 2)
348 && (image->comps[0].dy == 1)
349 && (image->comps[1].dy == 2)
350 && (image->comps[2].dy == 2))
351 movie->tk[0].jp2_struct.enumcs = 18; /* YUV */
354 movie->tk[0].jp2_struct.enumcs = 0; /* Unkown profile */
357 int main(int argc, char *argv[]) {
359 opj_event_mgr_t event_mgr; /* event manager */
362 mj2_sample_t *sample;
363 unsigned char* frame_codestream;
364 FILE *mj2file, *j2kfile;
367 int offset, mdat_initpos;
370 mj2_cparameters_t parameters;
373 printf("Usage: %s source_location mj2_filename\n",argv[0]);
374 printf("Example: %s input/input output.mj2\n",argv[0]);
378 mj2file = fopen(argv[2], "wb");
381 fprintf(stderr, "failed to open %s for writing\n", argv[2]);
384 memset(&img, 0, sizeof(opj_image_t));
386 configure the event callbacks (not required)
387 setting of each callback is optionnal
389 memset(&event_mgr, 0, sizeof(opj_event_mgr_t));
390 event_mgr.error_handler = error_callback;
391 event_mgr.warning_handler = warning_callback;
392 event_mgr.info_handler = info_callback;
394 /* get a MJ2 decompressor handle */
395 cinfo = mj2_create_compress();
397 /* catch events using our callbacks and give a local context */
398 opj_set_event_mgr((opj_common_ptr)cinfo, &event_mgr, stderr);
400 /* setup the decoder encoding parameters using user parameters */
401 memset(¶meters, 0, sizeof(mj2_cparameters_t));
402 movie = (opj_mj2_t*) cinfo->mj2_handle;
404 j2kfilename = (char*)malloc(strlen(argv[1]) + 12);/* max. '%6d' */
405 sprintf(j2kfilename, "%s_00001.j2k",argv[1]);
407 if(test_image(j2kfilename, ¶meters) == 0) goto fin;
409 parameters.frame_rate = 25; /* DEFAULT */
411 mj2_setup_encoder(movie, ¶meters);
414 /* Writing JP, FTYP and MDAT boxes
415 Assuming that the JP and FTYP boxes won't be longer than 300 bytes */
417 buf = (unsigned char*) malloc (300 * sizeof(unsigned char));
418 cio = opj_cio_open(movie->cinfo, buf, 300);
420 mj2_write_ftyp(movie, cio);
421 mdat_initpos = cio_tell(cio);
423 cio_write(cio,MJ2_MDAT, 4);
424 fwrite(buf,cio_tell(cio),1,mj2file);
427 /* Insert each j2k codestream in a JP2C box */
432 mj2_sample_t * new_sample;
433 mj2_chunk_t * new_chunk;
434 sample = &movie->tk[0].sample[snum];
435 sprintf(j2kfilename,"%s_%05d.j2k",argv[1],snum);
436 j2kfile = fopen(j2kfilename, "rb");
438 if (snum==0) { /* Could not open a single codestream */
439 fprintf(stderr, "failed to open %s for reading\n",j2kfilename);
442 else { /* Tried to open a inexistant codestream */
443 fprintf(stdout,"%d frames are being added to the MJ2 file\n",snum);
448 /* Calculating offset for samples and chunks */
449 offset += cio_tell(cio);
450 sample->offset = offset;
451 movie->tk[0].chunk[snum].offset = offset; /* There will be one sample per chunk */
453 /* Calculating sample size */
454 fseek(j2kfile,0,SEEK_END);
455 sample->sample_size = ftell(j2kfile) + 8; /* Sample size is codestream + JP2C box header */
456 fseek(j2kfile,0,SEEK_SET);
458 /* Reading siz marker of j2k image for the first codestream */
460 read_siz_marker(j2kfile, &img);
462 /* Writing JP2C box header */
463 frame_codestream = (unsigned char*) malloc (sample->sample_size+8);
464 cio = opj_cio_open(movie->cinfo, frame_codestream, sample->sample_size);
465 cio_write(cio,sample->sample_size, 4); /* Sample size */
466 cio_write(cio,JP2_JP2C, 4); /* JP2C */
468 /* Writing codestream from J2K file to MJ2 file */
469 fread(frame_codestream+8,sample->sample_size-8,1,j2kfile);
470 fwrite(frame_codestream,sample->sample_size,1,mj2file);
471 cio_skip(cio, sample->sample_size-8);
476 new_sample = (mj2_sample_t*)
477 realloc(movie->tk[0].sample, (snum+1) * sizeof(mj2_sample_t));
478 new_chunk = (mj2_chunk_t*)
479 realloc(movie->tk[0].chunk, (snum+1) * sizeof(mj2_chunk_t));
480 if (new_sample && new_chunk) {
481 movie->tk[0].sample = new_sample;
482 movie->tk[0].chunk = new_chunk;
484 fprintf(stderr, "Failed to allocate enough memory to read %s\n", j2kfilename);
487 free(frame_codestream);
490 /* Writing the MDAT box length in header */
491 offset += cio_tell(cio);
492 buf = (unsigned char*) malloc (4 * sizeof(unsigned char));
493 cio = opj_cio_open(movie->cinfo, buf, 4);
494 cio_write(cio,offset-mdat_initpos,4);
495 fseek(mj2file,(long)mdat_initpos,SEEK_SET);
496 fwrite(buf,4,1,mj2file);
497 fseek(mj2file,0,SEEK_END);
500 /* Setting movie parameters */
501 movie->tk[0].num_samples=snum;
502 movie->tk[0].num_chunks=snum;
503 setparams(movie, &img);
505 /* Writing MOOV box */
506 buf = (unsigned char*) malloc ((TEMP_BUF+snum*20) * sizeof(unsigned char));
507 cio = opj_cio_open(movie->cinfo, buf, (TEMP_BUF+snum*20));
508 mj2_write_moov(movie, cio);
509 fwrite(buf,cio_tell(cio),1,mj2file);
517 mj2_destroy_compress(movie);