update j2k_lib with new opj type
[openjpeg.git] / applications / mj2 / wrap_j2k_in_mj2.c
1 /*
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 
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
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.
15  *
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.
27  */
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32
33 #include "openjpeg.h"
34 #include "cio.h"
35 #include "j2k.h"
36 #include "jp2.h"
37 #include "mj2.h"
38
39 static int int_ceildiv(int a, int b) {
40         return (a + b - 1) / b;
41 }
42
43 /**
44 Size of memory first allocated for MOOV box
45 */
46 #define TEMP_BUF 10000 
47
48 #define ENUMCS_GRAY 16
49 #define ENUMCS_SRGB 17
50 #define ENUMCS_SYCC 18
51
52 #define J2K_CODESTREAM_MAGIC "\xff\x4f\xff\x51"
53
54 /* -------------------------------------------------------------------------- */
55
56 static int test_image(const char *fname, mj2_cparameters_t *cp)
57 {
58         FILE *reader;
59         opj_image_t *image;
60         unsigned char *src;
61         opj_dinfo_t *dinfo;
62         opj_cio_t *cio;
63         opj_dparameters_t dparameters;
64         int success;
65         long src_len;
66
67         success = 0;
68
69         if((reader = fopen(fname, "rb")) == NULL) return success;
70
71         fseek(reader, 0, SEEK_END);
72         src_len = ftell(reader);
73         fseek(reader, 0, SEEK_SET);
74         src = (unsigned char*) malloc(src_len);
75         fread(src, 1, src_len, reader);
76         fclose(reader);
77
78         if(memcmp(src, J2K_CODESTREAM_MAGIC, 4) != 0)
79    {
80         free(src); return success;
81    }
82         memset(&dparameters, 0, sizeof(opj_dparameters_t));
83
84         opj_set_default_decoder_parameters(&dparameters);
85
86         dinfo = opj_create_decompress(CODEC_J2K);
87
88         opj_setup_decoder(dinfo, &dparameters);
89
90         cio = opj_cio_open((opj_common_ptr)dinfo, src, src_len);
91
92         image = opj_decode(dinfo, cio);
93
94         free(src); cio->buffer = NULL;
95         opj_cio_close(cio);
96
97         if(image == NULL) goto fin;
98
99         cp->numcomps = image->numcomps;
100         cp->w = image->comps[0].w;
101         cp->h = image->comps[0].h;
102         cp->prec = image->comps[0].prec;
103
104         if(image->numcomps > 2 )
105    {
106         if((image->comps[0].dx == 1)
107         && (image->comps[1].dx == 2)
108         && (image->comps[2].dx == 2)
109         && (image->comps[0].dy == 1)
110         && (image->comps[1].dy == 2)
111         && (image->comps[2].dy == 2))// horizontal and vertical
112   {
113 //   Y420
114         cp->enumcs = ENUMCS_SYCC;
115         cp->CbCr_subsampling_dx = 2;
116         cp->CbCr_subsampling_dy = 2;
117   }
118         else
119         if((image->comps[0].dx == 1)
120         && (image->comps[1].dx == 2)
121         && (image->comps[2].dx == 2)
122         && (image->comps[0].dy == 1)
123         && (image->comps[1].dy == 1)
124         && (image->comps[2].dy == 1))// horizontal only
125   {
126 //   Y422
127         cp->enumcs = ENUMCS_SYCC;
128         cp->CbCr_subsampling_dx = 2;
129         cp->CbCr_subsampling_dy = 1;
130   }
131         else
132         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))
138   {
139 //   Y444 or RGB
140
141         if(image->color_space ==  CLRSPC_SRGB)
142  {
143         cp->enumcs = ENUMCS_SRGB;
144
145 //    cp->CbCr_subsampling_dx = 0;
146 //    cp->CbCr_subsampling_dy = 0;
147  }
148         else
149  {
150         cp->enumcs = ENUMCS_SYCC;
151
152         cp->CbCr_subsampling_dx = 1;
153         cp->CbCr_subsampling_dy = 1;
154  }
155   }
156         else
157   {
158         goto fin;
159   }
160    }
161         else
162    {
163         cp->enumcs = ENUMCS_GRAY;
164 //  cp->CbCr_subsampling_dx = 0;
165 //  cp->CbCr_subsampling_dy = 0;
166    }
167         if(image->icc_profile_buf)
168    {
169         cp->meth = 2;
170         free(image->icc_profile_buf); image->icc_profile_buf = NULL;
171    }
172         else cp->meth = 1;
173
174         success = 1;
175 fin:
176         if(dinfo)
177          opj_destroy_decompress(dinfo);
178
179         if(image)
180          opj_image_destroy(image);
181
182         return success;
183 }
184
185 /**
186 sample error callback expecting a FILE* client object
187 */
188 void error_callback(const char *msg, void *client_data) {
189         FILE *stream = (FILE*)client_data;
190         fprintf(stream, "[ERROR] %s", msg);
191 }
192 /**
193 sample warning callback expecting a FILE* client object
194 */
195 void warning_callback(const char *msg, void *client_data) {
196         FILE *stream = (FILE*)client_data;
197         fprintf(stream, "[WARNING] %s", msg);
198 }
199 /**
200 sample debug callback expecting a FILE* client object
201 */
202 void info_callback(const char *msg, void *client_data) {
203         FILE *stream = (FILE*)client_data;
204         fprintf(stream, "[INFO] %s", msg);
205 }
206
207 /* -------------------------------------------------------------------------- */
208
209
210
211 static void read_siz_marker(FILE *file, opj_image_t *image)
212 {
213   int len,i;
214   char buf, buf2[2];
215   unsigned char *siz_buffer;
216         opj_cio_t *cio;
217   
218   fseek(file, 0, SEEK_SET);
219   do {
220     fread(&buf,1,1, file);
221     if (buf==(char)0xff)
222       fread(&buf,1,1, file);
223   }
224   while (!(buf==(char)0x51));
225   
226   fread(buf2,2,1,file);         /* Lsiz                */
227   len = ((buf2[0])<<8) + buf2[1];
228   
229   siz_buffer = (unsigned char*) malloc(len * sizeof(unsigned char));
230   fread(siz_buffer,len, 1, file);
231         cio = opj_cio_open(NULL, siz_buffer, len);
232   
233   cio_read(cio, 2);                     /* Rsiz (capabilities) */
234   image->x1 = cio_read(cio, 4); /* Xsiz                */
235   image->y1 = cio_read(cio, 4); /* Ysiz                */
236   image->x0 = cio_read(cio, 4); /* X0siz               */
237   image->y0 = cio_read(cio, 4); /* Y0siz               */
238   cio_skip(cio, 16);                    /* XTsiz, YTsiz, XT0siz, YT0siz        */
239   
240   image->numcomps = cio_read(cio,2);    /* Csiz                */
241   image->comps =
242     (opj_image_comp_t *) malloc(image->numcomps * sizeof(opj_image_comp_t));
243         
244   for (i = 0; i < image->numcomps; i++) {
245     int tmp;
246     tmp = cio_read(cio,1);              /* Ssiz_i          */
247     image->comps[i].prec = (tmp & 0x7f) + 1;
248     image->comps[i].sgnd = tmp >> 7;
249     image->comps[i].dx = cio_read(cio,1);       /* XRsiz_i         */
250     image->comps[i].dy = cio_read(cio,1);       /* YRsiz_i         */
251     image->comps[i].resno_decoded = 0;  /* number of resolution decoded */
252     image->comps[i].factor = 0; /* reducing factor by component */
253   }
254   fseek(file, 0, SEEK_SET);
255         opj_cio_close(cio);
256   free(siz_buffer);
257 }
258
259 static void setparams(opj_mj2_t *movie, opj_image_t *image) {
260   int i, depth_0, depth, sign;
261   
262   movie->tk[0].w = int_ceildiv(image->x1 - image->x0, image->comps[0].dx);
263   movie->tk[0].h = int_ceildiv(image->y1 - image->y0, image->comps[0].dy);
264   mj2_init_stdmovie(movie);
265   
266   movie->tk[0].depth = image->comps[0].prec;
267         
268   if (image->numcomps==3) {
269     if ((image->comps[0].dx == 1) 
270         && (image->comps[1].dx == 1) 
271         && (image->comps[2].dx == 1)) 
272       movie->tk[0].CbCr_subsampling_dx = 1;
273     else 
274         if ((image->comps[0].dx == 1) 
275         && (image->comps[1].dx == 2) 
276         && (image->comps[2].dx == 2))
277       movie->tk[0].CbCr_subsampling_dx = 2;
278     else
279       fprintf(stderr,"Image component sizes are incoherent\n");
280     
281     if ((image->comps[0].dy == 1) 
282         && (image->comps[1].dy == 1) 
283         && (image->comps[2].dy == 1)) 
284       movie->tk[0].CbCr_subsampling_dy = 1;
285     else 
286         if ((image->comps[0].dy == 1) 
287         && (image->comps[1].dy == 2) 
288         && (image->comps[2].dy == 2))
289       movie->tk[0].CbCr_subsampling_dy = 2;
290     else
291       fprintf(stderr,"Image component sizes are incoherent\n");
292   }
293   
294   movie->tk[0].sample_rate = 25;
295   
296   movie->tk[0].jp2_struct.numcomps = image->numcomps;   // NC  
297         
298         /* Init Standard jp2 structure */
299         
300         movie->tk[0].jp2_struct.comps =
301     (opj_jp2_comps_t *) malloc(movie->tk[0].jp2_struct.numcomps * sizeof(opj_jp2_comps_t));
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(movie->tk[0].jp2_struct.numcl * sizeof(int));
308   movie->tk[0].jp2_struct.cl[0] = JP2_JP2;      /* CL0 : JP2  */
309   movie->tk[0].jp2_struct.C = 7;      /* C : Always 7*/
310   movie->tk[0].jp2_struct.UnkC = 0;      /* UnkC, colorspace specified in colr box*/
311   movie->tk[0].jp2_struct.IPR = 0;      /* IPR, no intellectual property*/
312   movie->tk[0].jp2_struct.w = int_ceildiv(image->x1 - image->x0, image->comps[0].dx);
313   movie->tk[0].jp2_struct.h = int_ceildiv(image->y1 - image->y0, image->comps[0].dy);
314   
315   depth_0 = image->comps[0].prec - 1;
316   sign = image->comps[0].sgnd;
317   movie->tk[0].jp2_struct.bpc = depth_0 + (sign << 7);
318   
319   for (i = 1; i < image->numcomps; i++) {
320     depth = image->comps[i].prec - 1;
321     sign = image->comps[i].sgnd;
322     if (depth_0 != depth)
323       movie->tk[0].jp2_struct.bpc = 255;
324   }
325   
326   for (i = 0; i < image->numcomps; i++)
327     movie->tk[0].jp2_struct.comps[i].bpcc =
328     image->comps[i].prec - 1 + (image->comps[i].sgnd << 7);
329   
330   if ((image->numcomps == 1 || image->numcomps == 3)
331     && (movie->tk[0].jp2_struct.bpc != 255))
332     movie->tk[0].jp2_struct.meth = 1;
333   else
334     movie->tk[0].jp2_struct.meth = 2;
335         
336     if (image->numcomps == 1)
337      movie->tk[0].jp2_struct.enumcs = 17;  // Grayscale
338   
339     else   
340         if ((image->comps[0].dx == 1) 
341         && (image->comps[1].dx == 1) 
342         && (image->comps[2].dx == 1) 
343     && (image->comps[0].dy == 1) 
344         && (image->comps[1].dy == 1) 
345         && (image->comps[2].dy == 1)) 
346      movie->tk[0].jp2_struct.enumcs = 16;    // RGB
347   
348     else   
349         if ((image->comps[0].dx == 1) 
350         && (image->comps[1].dx == 2) 
351         && (image->comps[2].dx == 2) 
352     && (image->comps[0].dy == 1) 
353         && (image->comps[1].dy == 2) 
354         && (image->comps[2].dy == 2)) 
355      movie->tk[0].jp2_struct.enumcs = 18;  // YUV
356   
357   else
358     movie->tk[0].jp2_struct.enumcs = 0; // Unkown profile */
359 }
360
361 int main(int argc, char *argv[]) {
362         opj_cinfo_t* cinfo; 
363         opj_event_mgr_t event_mgr;              /* event manager */  
364   unsigned int snum;
365   opj_mj2_t *movie;
366   mj2_sample_t *sample;
367   unsigned char* frame_codestream;
368   FILE *mj2file, *j2kfile;
369   char *j2kfilename;
370   unsigned char *buf;
371   int offset, mdat_initpos;
372   opj_image_t img;
373         opj_cio_t *cio;
374         mj2_cparameters_t parameters;
375         
376   if (argc != 3) {
377     printf("Usage: %s source_location mj2_filename\n",argv[0]);
378     printf("Example: %s input/input output.mj2\n",argv[0]);
379     return 1;
380   }
381   
382   mj2file = fopen(argv[2], "wb");
383   
384   if (!mj2file) {
385     fprintf(stderr, "failed to open %s for writing\n", argv[2]);
386     return 1;
387   }
388         memset(&img, 0, sizeof(opj_image_t));
389         /*
390         configure the event callbacks (not required)
391         setting of each callback is optionnal
392         */
393         memset(&event_mgr, 0, sizeof(opj_event_mgr_t));
394         event_mgr.error_handler = error_callback;
395         event_mgr.warning_handler = warning_callback;
396         event_mgr.info_handler = info_callback;
397
398         /* get a MJ2 decompressor handle */
399         cinfo = mj2_create_compress();
400
401         /* catch events using our callbacks and give a local context */
402         opj_set_event_mgr((opj_common_ptr)cinfo, &event_mgr, stderr);   
403         
404         /* setup the decoder encoding parameters using user parameters */
405         memset(&parameters, 0, sizeof(mj2_cparameters_t));
406         movie = (opj_mj2_t*) cinfo->mj2_handle;
407
408         j2kfilename = (char*)malloc(strlen(argv[1]) + 12);/* max. '%6d' */
409         sprintf(j2kfilename, "%s_00001.j2k",argv[1]);
410
411         if(test_image(j2kfilename, &parameters) == 0) goto fin;
412
413         parameters.frame_rate = 25; /* DEFAULT */
414
415         mj2_setup_encoder(movie, &parameters);
416
417   
418         /* Writing JP, FTYP and MDAT boxes 
419         Assuming that the JP and FTYP boxes won't be longer than 300 bytes */
420         
421   buf = (unsigned char*) malloc (300 * sizeof(unsigned char)); 
422   cio = opj_cio_open(movie->cinfo, buf, 300);
423   mj2_write_jp(cio);
424   mj2_write_ftyp(movie, cio);
425   mdat_initpos = cio_tell(cio);
426   cio_skip(cio, 4);
427   cio_write(cio,MJ2_MDAT, 4);   
428   fwrite(buf,cio_tell(cio),1,mj2file);
429   free(buf);
430         
431   // Insert each j2k codestream in a JP2C box  
432   snum=0;
433   offset = 0;  
434   while(1)
435   {
436     sample = &movie->tk[0].sample[snum];
437     sprintf(j2kfilename,"%s_%05d.j2k",argv[1],snum);
438     j2kfile = fopen(j2kfilename, "rb");
439     if (!j2kfile) {
440       if (snum==0) {  // Could not open a single codestream
441                                 fprintf(stderr, "failed to open %s for reading\n",j2kfilename);
442                                 return 1;
443       }
444       else {          // Tried to open a inexistant codestream
445                                 fprintf(stdout,"%d frames are being added to the MJ2 file\n",snum);
446                                 break;
447       }
448     }
449
450     // Calculating offset for samples and chunks
451     offset += cio_tell(cio);     
452     sample->offset = offset;
453     movie->tk[0].chunk[snum].offset = offset;  // There will be one sample per chunk
454     
455     // Calculating sample size
456     fseek(j2kfile,0,SEEK_END);  
457     sample->sample_size = ftell(j2kfile) + 8; // Sample size is codestream + JP2C box header
458     fseek(j2kfile,0,SEEK_SET);
459     
460     // Reading siz marker of j2k image for the first codestream
461     if (snum==0)              
462       read_siz_marker(j2kfile, &img);
463     
464     // Writing JP2C box header                      
465     frame_codestream = (unsigned char*) malloc (sample->sample_size+8); 
466                 cio = opj_cio_open(movie->cinfo, frame_codestream, sample->sample_size);    
467     cio_write(cio,sample->sample_size, 4);  // Sample size
468     cio_write(cio,JP2_JP2C, 4); // JP2C
469     
470     // Writing codestream from J2K file to MJ2 file
471     fread(frame_codestream+8,sample->sample_size-8,1,j2kfile);
472     fwrite(frame_codestream,sample->sample_size,1,mj2file);
473     cio_skip(cio, sample->sample_size-8);
474     
475     // Ending loop
476     fclose(j2kfile);
477     snum++;
478     mj2_sample_t * new_sample = (mj2_sample_t*)
479                 realloc(movie->tk[0].sample, (snum+1) * sizeof(mj2_sample_t));
480     mj2_chunk_t * new_chunk = (mj2_chunk_t*)
481                 realloc(movie->tk[0].chunk, (snum+1) * sizeof(mj2_chunk_t));
482     if (new_sample && new_chunk) {
483         movie->tk[0].sample = new_sample;
484         movie->tk[0].chunk = new_chunk;
485     } else {
486        fprintf(stderr, "Failed to allocate enough memory to read %s\n", j2kfilename);
487        return 1;
488     }
489     free(frame_codestream);
490   }
491   
492   // Writing the MDAT box length in header
493   offset += cio_tell(cio);
494   buf = (unsigned char*) malloc (4 * sizeof(unsigned char));
495         cio = opj_cio_open(movie->cinfo, buf, 4);
496   cio_write(cio,offset-mdat_initpos,4); 
497   fseek(mj2file,(long)mdat_initpos,SEEK_SET);
498   fwrite(buf,4,1,mj2file);
499   fseek(mj2file,0,SEEK_END);
500   free(buf);
501         
502   // Setting movie parameters
503   movie->tk[0].num_samples=snum;
504   movie->tk[0].num_chunks=snum;
505   setparams(movie, &img);
506         
507   // Writing MOOV box 
508         buf = (unsigned char*) malloc ((TEMP_BUF+snum*20) * sizeof(unsigned char));
509         cio = opj_cio_open(movie->cinfo, buf, (TEMP_BUF+snum*20));
510         mj2_write_moov(movie, cio);
511   fwrite(buf,cio_tell(cio),1,mj2file);
512         
513   // Ending program
514   free(img.comps);
515   opj_cio_close(cio);
516
517 fin:
518   fclose(mj2file);
519   mj2_destroy_compress(movie);
520   free(j2kfilename);
521
522   return 0;
523 }