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.
29 #include "opj_includes.h"
33 Size of memory first allocated for MOOV box
35 #define TEMP_BUF 10000
38 /* -------------------------------------------------------------------------- */
41 sample error callback expecting a FILE* client object
43 void error_callback(const char *msg, void *client_data) {
44 FILE *stream = (FILE*)client_data;
45 fprintf(stream, "[ERROR] %s", msg);
48 sample warning callback expecting a FILE* client object
50 void warning_callback(const char *msg, void *client_data) {
51 FILE *stream = (FILE*)client_data;
52 fprintf(stream, "[WARNING] %s", msg);
55 sample debug callback expecting a FILE* client object
57 void info_callback(const char *msg, void *client_data) {
58 FILE *stream = (FILE*)client_data;
59 fprintf(stream, "[INFO] %s", msg);
62 /* -------------------------------------------------------------------------- */
66 static void read_siz_marker(FILE *file, opj_image_t *image)
73 fseek(file, 0, SEEK_SET);
75 fread(&buf,1,1, file);
77 fread(&buf,1,1, file);
79 while (!(buf==(char)0x51));
81 fread(buf2,2,1,file); /* Lsiz */
82 len = ((buf2[0])<<8) + buf2[1];
84 siz_buffer = (char*) malloc(len * sizeof(char));
85 fread(siz_buffer,len, 1, file);
86 cio = opj_cio_open(NULL, siz_buffer, len);
88 cio_read(cio, 2); /* Rsiz (capabilities) */
89 image->x1 = cio_read(cio, 4); /* Xsiz */
90 image->y1 = cio_read(cio, 4); /* Ysiz */
91 image->x0 = cio_read(cio, 4); /* X0siz */
92 image->y0 = cio_read(cio, 4); /* Y0siz */
93 cio_skip(cio, 16); /* XTsiz, YTsiz, XT0siz, YT0siz */
95 image->numcomps = cio_read(cio,2); /* Csiz */
97 (opj_image_comp_t *) malloc(image->numcomps * sizeof(opj_image_comp_t));
99 for (i = 0; i < image->numcomps; i++) {
101 tmp = cio_read(cio,1); /* Ssiz_i */
102 image->comps[i].prec = (tmp & 0x7f) + 1;
103 image->comps[i].sgnd = tmp >> 7;
104 image->comps[i].dx = cio_read(cio,1); /* XRsiz_i */
105 image->comps[i].dy = cio_read(cio,1); /* YRsiz_i */
106 image->comps[i].resno_decoded = 0; /* number of resolution decoded */
107 image->comps[i].factor = 0; /* reducing factor by component */
109 fseek(file, 0, SEEK_SET);
113 static void setparams(opj_mj2_t *movie, opj_image_t *image) {
114 int i, depth_0, depth, sign;
116 movie->tk[0].sample_rate = 25;
117 movie->tk[0].w = int_ceildiv(image->x1 - image->x0, image->comps[0].dx);
118 movie->tk[0].h = int_ceildiv(image->y1 - image->y0, image->comps[0].dy);
119 mj2_init_stdmovie(movie);
121 movie->tk[0].depth = image->comps[0].prec;
123 if (image->numcomps==3) {
124 if ((image->comps[0].dx == 1) && (image->comps[1].dx == 1) && (image->comps[1].dx == 1))
125 movie->tk[0].CbCr_subsampling_dx = 1;
126 else if ((image->comps[0].dx == 1) && (image->comps[1].dx == 2) && (image->comps[1].dx == 2))
127 movie->tk[0].CbCr_subsampling_dx = 2;
129 fprintf(stderr,"Image component sizes are incoherent\n");
131 if ((image->comps[0].dy == 1) && (image->comps[1].dy == 1) && (image->comps[1].dy == 1))
132 movie->tk[0].CbCr_subsampling_dy = 1;
133 else if ((image->comps[0].dy == 1) && (image->comps[1].dy == 2) && (image->comps[1].dy == 2))
134 movie->tk[0].CbCr_subsampling_dy = 2;
136 fprintf(stderr,"Image component sizes are incoherent\n");
139 movie->tk[0].sample_rate = 25;
141 movie->tk[0].jp2_struct.numcomps = image->numcomps; // NC
143 /* Init Standard jp2 structure */
145 movie->tk[0].jp2_struct.comps =
146 (opj_jp2_comps_t *) malloc(movie->tk[0].jp2_struct.numcomps * sizeof(opj_jp2_comps_t));
147 movie->tk[0].jp2_struct.precedence = 0; /* PRECEDENCE*/
148 movie->tk[0].jp2_struct.approx = 0; /* APPROX*/
149 movie->tk[0].jp2_struct.brand = JP2_JP2; /* BR */
150 movie->tk[0].jp2_struct.minversion = 0; /* MinV */
151 movie->tk[0].jp2_struct.numcl = 1;
152 movie->tk[0].jp2_struct.cl = (unsigned int *) malloc(movie->tk[0].jp2_struct.numcl * sizeof(int));
153 movie->tk[0].jp2_struct.cl[0] = JP2_JP2; /* CL0 : JP2 */
154 movie->tk[0].jp2_struct.C = 7; /* C : Always 7*/
155 movie->tk[0].jp2_struct.UnkC = 0; /* UnkC, colorspace specified in colr box*/
156 movie->tk[0].jp2_struct.IPR = 0; /* IPR, no intellectual property*/
157 movie->tk[0].jp2_struct.w = int_ceildiv(image->x1 - image->x0, image->comps[0].dx);
158 movie->tk[0].jp2_struct.h = int_ceildiv(image->y1 - image->y0, image->comps[0].dy);
160 depth_0 = image->comps[0].prec - 1;
161 sign = image->comps[0].sgnd;
162 movie->tk[0].jp2_struct.bpc = depth_0 + (sign << 7);
164 for (i = 1; i < image->numcomps; i++) {
165 depth = image->comps[i].prec - 1;
166 sign = image->comps[i].sgnd;
167 if (depth_0 != depth)
168 movie->tk[0].jp2_struct.bpc = 255;
171 for (i = 0; i < image->numcomps; i++)
172 movie->tk[0].jp2_struct.comps[i].bpcc =
173 image->comps[i].prec - 1 + (image->comps[i].sgnd << 7);
175 if ((image->numcomps == 1 || image->numcomps == 3)
176 && (movie->tk[0].jp2_struct.bpc != 255))
177 movie->tk[0].jp2_struct.meth = 1;
179 movie->tk[0].jp2_struct.meth = 2;
181 if (image->numcomps == 1)
182 movie->tk[0].jp2_struct.enumcs = 17; // Grayscale
184 else if ((image->comps[0].dx == 1) && (image->comps[1].dx == 1) && (image->comps[1].dx == 1) &&
185 (image->comps[0].dy == 1) && (image->comps[1].dy == 1) && (image->comps[1].dy == 1))
186 movie->tk[0].jp2_struct.enumcs = 16; // RGB
188 else if ((image->comps[0].dx == 1) && (image->comps[1].dx == 2) && (image->comps[1].dx == 2) &&
189 (image->comps[0].dy == 1) && (image->comps[1].dy == 2) && (image->comps[1].dy == 2))
190 movie->tk[0].jp2_struct.enumcs = 18; // YUV
193 movie->tk[0].jp2_struct.enumcs = 0; // Unkown profile */
196 int main(int argc, char *argv[]) {
198 opj_event_mgr_t event_mgr; /* event manager */
201 mj2_sample_t *sample;
202 unsigned char* frame_codestream;
203 FILE *mj2file, *j2kfile;
204 char j2kfilename[50];
206 int offset, mdat_initpos;
209 mj2_cparameters_t parameters;
212 printf("Bad syntax: Usage: MJ2_Wrapper source_location mj2_filename\n");
213 printf("Example: MJ2_Wrapper input/input output.mj2\n");
217 mj2file = fopen(argv[2], "wb");
220 fprintf(stderr, "failed to open %s for writing\n", argv[2]);
225 configure the event callbacks (not required)
226 setting of each callback is optionnal
228 memset(&event_mgr, 0, sizeof(opj_event_mgr_t));
229 event_mgr.error_handler = error_callback;
230 event_mgr.warning_handler = warning_callback;
231 event_mgr.info_handler = info_callback;
233 /* get a MJ2 decompressor handle */
234 cinfo = mj2_create_compress();
236 /* catch events using our callbacks and give a local context */
237 opj_set_event_mgr((opj_common_ptr)cinfo, &event_mgr, stderr);
239 /* setup the decoder encoding parameters using user parameters */
240 movie = (opj_mj2_t*) cinfo->mj2_handle;
241 mj2_setup_encoder(cinfo->mj2_handle, ¶meters);
244 /* Writing JP, FTYP and MDAT boxes
245 Assuming that the JP and FTYP boxes won't be longer than 300 bytes */
247 buf = (char*) malloc (300 * sizeof(char));
248 cio = opj_cio_open(movie->cinfo, buf, 300);
250 mj2_write_ftyp(movie, cio);
251 mdat_initpos = cio_tell(cio);
253 cio_write(cio,MJ2_MDAT, 4);
254 fwrite(buf,cio_tell(cio),1,mj2file);
257 // Insert each j2k codestream in a JP2C box
262 sample = &movie->tk[0].sample[snum];
263 sprintf(j2kfilename,"%s_%05d.j2k",argv[1],snum);
264 j2kfile = fopen(j2kfilename, "rb");
266 if (snum==0) { // Could not open a single codestream
267 fprintf(stderr, "failed to open %s for reading\n",j2kfilename);
270 else { // Tried to open a inexistant codestream
271 fprintf(stdout,"%d frames are being added to the MJ2 file\n",snum);
276 // Calculating offset for samples and chunks
277 offset += cio_tell(cio);
278 sample->offset = offset;
279 movie->tk[0].chunk[snum].offset = offset; // There will be one sample per chunk
281 // Calculating sample size
282 fseek(j2kfile,0,SEEK_END);
283 sample->sample_size = ftell(j2kfile) + 8; // Sample size is codestream + JP2C box header
284 fseek(j2kfile,0,SEEK_SET);
286 // Reading siz marker of j2k image for the first codestream
288 read_siz_marker(j2kfile, &img);
290 // Writing JP2C box header
291 frame_codestream = (unsigned char*) malloc (sample->sample_size+8);
292 cio = opj_cio_open(movie->cinfo, frame_codestream, sample->sample_size);
293 cio_write(cio,sample->sample_size, 4); // Sample size
294 cio_write(cio,JP2_JP2C, 4); // JP2C
296 // Writing codestream from J2K file to MJ2 file
297 fread(frame_codestream+8,sample->sample_size-8,1,j2kfile);
298 fwrite(frame_codestream,sample->sample_size,1,mj2file);
299 cio_skip(cio, sample->sample_size-8);
304 movie->tk[0].sample = realloc(movie->tk[0].sample, (snum+1) * sizeof(mj2_sample_t));
305 movie->tk[0].chunk = realloc(movie->tk[0].chunk, (snum+1) * sizeof(mj2_chunk_t));
306 free(frame_codestream);
309 // Writing the MDAT box length in header
310 offset += cio_tell(cio);
311 buf = (char*) malloc (4 * sizeof(char));
312 cio = opj_cio_open(movie->cinfo, buf, 4);
313 cio_write(cio,offset-mdat_initpos,4);
314 fseek(mj2file,(long)mdat_initpos,SEEK_SET);
315 fwrite(buf,4,1,mj2file);
316 fseek(mj2file,0,SEEK_END);
319 // Setting movie parameters
320 movie->tk[0].num_samples=snum;
321 movie->tk[0].num_chunks=snum;
322 setparams(movie, &img);
325 buf = (char*) malloc ((TEMP_BUF+snum*20) * sizeof(char));
326 cio = opj_cio_open(movie->cinfo, buf, (TEMP_BUF+snum*20));
327 mj2_write_moov(movie, cio);
328 fwrite(buf,cio_tell(cio),1,mj2file);
334 mj2_destroy_compress(movie);