[trunk] Import commit 87b08a096bb8ad61f9dbe4811e208d9c9d7fe63b from ghostpdl
[openjpeg.git] / src / bin / mj2 / opj_mj2_wrap.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 J2K_CODESTREAM_MAGIC "\xff\x4f\xff\x51"
49
50 /* -------------------------------------------------------------------------- */
51
52 static int test_image(const char *fname, mj2_cparameters_t *cp)
53 {
54         FILE *reader;
55         opj_image_t *image;
56         unsigned char *src;
57         opj_dinfo_t *dinfo;
58         opj_cio_t *cio;
59         opj_dparameters_t dparameters;
60         int success;
61         long src_len;
62
63         success = 0;
64
65         if((reader = fopen(fname, "rb")) == NULL) return success;
66
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);
72         fclose(reader);
73
74         if(memcmp(src, J2K_CODESTREAM_MAGIC, 4) != 0)
75    {
76         free(src); return success;
77    }
78         memset(&dparameters, 0, sizeof(opj_dparameters_t));
79
80         opj_set_default_decoder_parameters(&dparameters);
81
82         dinfo = opj_create_decompress(CODEC_J2K);
83
84         opj_setup_decoder(dinfo, &dparameters);
85
86         cio = opj_cio_open((opj_common_ptr)dinfo, src, src_len);
87
88         image = opj_decode(dinfo, cio);
89
90         free(src); cio->buffer = NULL;
91         opj_cio_close(cio);
92
93         if(image == NULL) goto fin;
94
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;
99
100         if(image->numcomps > 2 )
101    {
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*/
108   {
109 /*   Y420*/
110         cp->enumcs = ENUMCS_SYCC;
111         cp->CbCr_subsampling_dx = 2;
112         cp->CbCr_subsampling_dy = 2;
113   }
114         else
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*/
121   {
122 /*   Y422*/
123         cp->enumcs = ENUMCS_SYCC;
124         cp->CbCr_subsampling_dx = 2;
125         cp->CbCr_subsampling_dy = 1;
126   }
127         else
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))
134   {
135 /*   Y444 or RGB */
136
137         if(image->color_space ==  CLRSPC_SRGB)
138  {
139         cp->enumcs = ENUMCS_SRGB;
140
141 /*    cp->CbCr_subsampling_dx = 0; */
142 /*    cp->CbCr_subsampling_dy = 0; */
143  }
144         else
145  {
146         cp->enumcs = ENUMCS_SYCC;
147
148         cp->CbCr_subsampling_dx = 1;
149         cp->CbCr_subsampling_dy = 1;
150  }
151   }
152         else
153   {
154         goto fin;
155   }
156    }
157         else
158    {
159         cp->enumcs = ENUMCS_GRAY;
160 /*  cp->CbCr_subsampling_dx = 0; */
161 /*  cp->CbCr_subsampling_dy = 0; */
162    }
163         if(image->icc_profile_buf)
164    {
165         cp->meth = 2;
166         free(image->icc_profile_buf); image->icc_profile_buf = NULL;
167    }
168         else cp->meth = 1;
169
170         success = 1;
171 fin:
172         if(dinfo)
173          opj_destroy_decompress(dinfo);
174
175         if(image)
176          opj_image_destroy(image);
177
178         return success;
179 }
180
181 /**
182 sample error callback expecting a FILE* client object
183 */
184 static void error_callback(const char *msg, void *client_data) {
185         FILE *stream = (FILE*)client_data;
186         fprintf(stream, "[ERROR] %s", msg);
187 }
188 /**
189 sample warning callback expecting a FILE* client object
190 */
191 static void warning_callback(const char *msg, void *client_data) {
192         FILE *stream = (FILE*)client_data;
193         fprintf(stream, "[WARNING] %s", msg);
194 }
195 /**
196 sample debug callback expecting a FILE* client object
197 */
198 static void info_callback(const char *msg, void *client_data) {
199         FILE *stream = (FILE*)client_data;
200         fprintf(stream, "[INFO] %s", msg);
201 }
202
203 /* -------------------------------------------------------------------------- */
204
205
206
207 static void read_siz_marker(FILE *file, opj_image_t *image)
208 {
209   int len,i;
210   char buf, buf2[2];
211   unsigned char *siz_buffer;
212         opj_cio_t *cio;
213   
214   fseek(file, 0, SEEK_SET);
215   do {
216     fread(&buf,1,1, file);
217     if (buf==(char)0xff)
218       fread(&buf,1,1, file);
219   }
220   while (!(buf==(char)0x51));
221   
222   fread(buf2,2,1,file);         /* Lsiz                */
223   len = ((buf2[0])<<8) + buf2[1];
224   
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);
228   
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        */
235   
236   image->numcomps = cio_read(cio,2);    /* Csiz                */
237   image->comps =
238     (opj_image_comp_t *) malloc(image->numcomps * sizeof(opj_image_comp_t));
239         
240   for (i = 0; i < image->numcomps; i++) {
241     int tmp;
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 */
249   }
250   fseek(file, 0, SEEK_SET);
251         opj_cio_close(cio);
252   free(siz_buffer);
253 }
254
255 static void setparams(opj_mj2_t *movie, opj_image_t *image) {
256   int i, depth_0, depth, sign;
257   
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);
261   
262   movie->tk[0].depth = image->comps[0].prec;
263         
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;
269     else 
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;
274     else
275       fprintf(stderr,"Image component sizes are incoherent\n");
276     
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;
281     else 
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;
286     else
287       fprintf(stderr,"Image component sizes are incoherent\n");
288   }
289   
290   movie->tk[0].sample_rate = 25;
291   
292   movie->tk[0].jp2_struct.numcomps = image->numcomps;   /* NC */
293         
294         /* Init Standard jp2 structure */
295         
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);
310   
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);
314   
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;
320   }
321   
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);
325   
326   if ((image->numcomps == 1 || image->numcomps == 3)
327     && (movie->tk[0].jp2_struct.bpc != 255))
328     movie->tk[0].jp2_struct.meth = 1;
329   else
330     movie->tk[0].jp2_struct.meth = 2;
331         
332     if (image->numcomps == 1)
333      movie->tk[0].jp2_struct.enumcs = 17;  /* Grayscale */
334   
335     else   
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 */
343   
344     else   
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 */
352   
353   else
354     movie->tk[0].jp2_struct.enumcs = 0; /* Unkown profile */
355 }
356
357 int main(int argc, char *argv[]) {
358         opj_cinfo_t* cinfo; 
359         opj_event_mgr_t event_mgr;              /* event manager */  
360   unsigned int snum;
361   opj_mj2_t *movie;
362   mj2_sample_t *sample;
363   unsigned char* frame_codestream;
364   FILE *mj2file, *j2kfile;
365   char *j2kfilename;
366   unsigned char *buf;
367   int offset, mdat_initpos;
368   opj_image_t img;
369         opj_cio_t *cio;
370         mj2_cparameters_t parameters;
371         
372   if (argc != 3) {
373     printf("Usage: %s source_location mj2_filename\n",argv[0]);
374     printf("Example: %s input/input output.mj2\n",argv[0]);
375     return 1;
376   }
377   
378   mj2file = fopen(argv[2], "wb");
379   
380   if (!mj2file) {
381     fprintf(stderr, "failed to open %s for writing\n", argv[2]);
382     return 1;
383   }
384         memset(&img, 0, sizeof(opj_image_t));
385         /*
386         configure the event callbacks (not required)
387         setting of each callback is optionnal
388         */
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;
393
394         /* get a MJ2 decompressor handle */
395         cinfo = mj2_create_compress();
396
397         /* catch events using our callbacks and give a local context */
398         opj_set_event_mgr((opj_common_ptr)cinfo, &event_mgr, stderr);   
399         
400         /* setup the decoder encoding parameters using user parameters */
401         memset(&parameters, 0, sizeof(mj2_cparameters_t));
402         movie = (opj_mj2_t*) cinfo->mj2_handle;
403
404         j2kfilename = (char*)malloc(strlen(argv[1]) + 12);/* max. '%6d' */
405         sprintf(j2kfilename, "%s_00001.j2k",argv[1]);
406
407         if(test_image(j2kfilename, &parameters) == 0) goto fin;
408
409         parameters.frame_rate = 25; /* DEFAULT */
410
411         mj2_setup_encoder(movie, &parameters);
412
413   
414         /* Writing JP, FTYP and MDAT boxes 
415         Assuming that the JP and FTYP boxes won't be longer than 300 bytes */
416         
417   buf = (unsigned char*) malloc (300 * sizeof(unsigned char)); 
418   cio = opj_cio_open(movie->cinfo, buf, 300);
419   mj2_write_jp(cio);
420   mj2_write_ftyp(movie, cio);
421   mdat_initpos = cio_tell(cio);
422   cio_skip(cio, 4);
423   cio_write(cio,MJ2_MDAT, 4);   
424   fwrite(buf,cio_tell(cio),1,mj2file);
425   free(buf);
426         
427   /* Insert each j2k codestream in a JP2C box */
428   snum=0;
429   offset = 0;  
430   while(1)
431   {
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");
437     if (!j2kfile) {
438       if (snum==0) {  /* Could not open a single codestream */
439                                 fprintf(stderr, "failed to open %s for reading\n",j2kfilename);
440                                 return 1;
441       }
442       else {          /* Tried to open a inexistant codestream */
443                                 fprintf(stdout,"%d frames are being added to the MJ2 file\n",snum);
444                                 break;
445       }
446     }
447
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 */
452     
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);
457     
458     /* Reading siz marker of j2k image for the first codestream */
459     if (snum==0)              
460       read_siz_marker(j2kfile, &img);
461     
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 */
467     
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);
472     
473     /* Ending loop */
474     fclose(j2kfile);
475     snum++;
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;
483     } else {
484        fprintf(stderr, "Failed to allocate enough memory to read %s\n", j2kfilename);
485        return 1;
486     }
487     free(frame_codestream);
488   }
489   
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);
498   free(buf);
499         
500   /* Setting movie parameters */
501   movie->tk[0].num_samples=snum;
502   movie->tk[0].num_chunks=snum;
503   setparams(movie, &img);
504         
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);
510         
511   /* Ending program */
512   free(img.comps);
513   opj_cio_close(cio);
514
515 fin:
516   fclose(mj2file);
517   mj2_destroy_compress(movie);
518   free(j2kfilename);
519
520   return 0;
521 }