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