[v2.0] Fixed MJ2 codec bugs (issues 23-24 on google code). Thanks to Winfried for...
[openjpeg.git] / 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 "j2k.h"
35 #include "jp2.h"
36 #include "cio.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
49 /* -------------------------------------------------------------------------- */
50
51 /**
52 sample error callback expecting a FILE* client object
53 */
54 void error_callback(const char *msg, void *client_data) {
55         FILE *stream = (FILE*)client_data;
56         fprintf(stream, "[ERROR] %s", msg);
57 }
58 /**
59 sample warning callback expecting a FILE* client object
60 */
61 void warning_callback(const char *msg, void *client_data) {
62         FILE *stream = (FILE*)client_data;
63         fprintf(stream, "[WARNING] %s", msg);
64 }
65 /**
66 sample debug callback expecting a FILE* client object
67 */
68 void info_callback(const char *msg, void *client_data) {
69         FILE *stream = (FILE*)client_data;
70         fprintf(stream, "[INFO] %s", msg);
71 }
72
73 /* -------------------------------------------------------------------------- */
74
75
76
77 static void read_siz_marker(FILE *file, opj_image_t *image)
78 {
79   int len,i;
80   char buf, buf2[2];
81   char *siz_buffer;
82         opj_cio_t *cio;
83   
84   fseek(file, 0, SEEK_SET);
85   do {
86     fread(&buf,1,1, file);
87     if (buf==(char)0xff)
88       fread(&buf,1,1, file);
89   }
90   while (!(buf==(char)0x51));
91   
92   fread(buf2,2,1,file);         /* Lsiz                */
93   len = ((buf2[0])<<8) + buf2[1];
94   
95   siz_buffer = (char*) malloc(len * sizeof(char));
96   fread(siz_buffer,len, 1, file);
97         cio = opj_cio_open(NULL, siz_buffer, len);
98   
99   cio_read(cio, 2);                     /* Rsiz (capabilities) */
100   image->x1 = cio_read(cio, 4); /* Xsiz                */
101   image->y1 = cio_read(cio, 4); /* Ysiz                */
102   image->x0 = cio_read(cio, 4); /* X0siz               */
103   image->y0 = cio_read(cio, 4); /* Y0siz               */
104   cio_skip(cio, 16);                    /* XTsiz, YTsiz, XT0siz, YT0siz        */
105   
106   image->numcomps = cio_read(cio,2);    /* Csiz                */
107   image->comps =
108     (opj_image_comp_t *) malloc(image->numcomps * sizeof(opj_image_comp_t));
109         
110   for (i = 0; i < image->numcomps; i++) {
111     int tmp;
112     tmp = cio_read(cio,1);              /* Ssiz_i          */
113     image->comps[i].prec = (tmp & 0x7f) + 1;
114     image->comps[i].sgnd = tmp >> 7;
115     image->comps[i].dx = cio_read(cio,1);       /* XRsiz_i         */
116     image->comps[i].dy = cio_read(cio,1);       /* YRsiz_i         */
117     image->comps[i].resno_decoded = 0;  /* number of resolution decoded */
118     image->comps[i].factor = 0; /* reducing factor by component */
119   }
120   fseek(file, 0, SEEK_SET);
121         opj_cio_close(cio);
122 }
123
124 static void setparams(opj_mj2_t *movie, opj_image_t *image) {
125   int i, depth_0, depth, sign;
126   
127   movie->tk[0].sample_rate = 25;
128   movie->tk[0].w = int_ceildiv(image->x1 - image->x0, image->comps[0].dx);
129   movie->tk[0].h = int_ceildiv(image->y1 - image->y0, image->comps[0].dy);
130   mj2_init_stdmovie(movie);
131   
132   movie->tk[0].depth = image->comps[0].prec;
133         
134   if (image->numcomps==3) {
135     if ((image->comps[0].dx == 1) 
136         && (image->comps[1].dx == 1) 
137         && (image->comps[2].dx == 1)) 
138       movie->tk[0].CbCr_subsampling_dx = 1;
139     else 
140         if ((image->comps[0].dx == 1) 
141         && (image->comps[1].dx == 2) 
142         && (image->comps[2].dx == 2))
143       movie->tk[0].CbCr_subsampling_dx = 2;
144     else
145       fprintf(stderr,"Image component sizes are incoherent\n");
146     
147     if ((image->comps[0].dy == 1) 
148         && (image->comps[1].dy == 1) 
149         && (image->comps[2].dy == 1)) 
150       movie->tk[0].CbCr_subsampling_dy = 1;
151     else 
152         if ((image->comps[0].dy == 1) 
153         && (image->comps[1].dy == 2) 
154         && (image->comps[2].dy == 2))
155       movie->tk[0].CbCr_subsampling_dy = 2;
156     else
157       fprintf(stderr,"Image component sizes are incoherent\n");
158   }
159   
160   movie->tk[0].sample_rate = 25;
161   
162   movie->tk[0].jp2_struct.numcomps = image->numcomps;   // NC  
163         
164         /* Init Standard jp2 structure */
165         
166         movie->tk[0].jp2_struct.comps =
167     (opj_jp2_comps_t *) malloc(movie->tk[0].jp2_struct.numcomps * sizeof(opj_jp2_comps_t));
168   movie->tk[0].jp2_struct.precedence = 0;   /* PRECEDENCE*/
169   movie->tk[0].jp2_struct.approx = 0;   /* APPROX*/
170   movie->tk[0].jp2_struct.brand = JP2_JP2;      /* BR         */
171   movie->tk[0].jp2_struct.minversion = 0;       /* MinV       */
172   movie->tk[0].jp2_struct.numcl = 1;
173   movie->tk[0].jp2_struct.cl = (unsigned int *) malloc(movie->tk[0].jp2_struct.numcl * sizeof(int));
174   movie->tk[0].jp2_struct.cl[0] = JP2_JP2;      /* CL0 : JP2  */
175   movie->tk[0].jp2_struct.C = 7;      /* C : Always 7*/
176   movie->tk[0].jp2_struct.UnkC = 0;      /* UnkC, colorspace specified in colr box*/
177   movie->tk[0].jp2_struct.IPR = 0;      /* IPR, no intellectual property*/
178   movie->tk[0].jp2_struct.w = int_ceildiv(image->x1 - image->x0, image->comps[0].dx);
179   movie->tk[0].jp2_struct.h = int_ceildiv(image->y1 - image->y0, image->comps[0].dy);
180   
181   depth_0 = image->comps[0].prec - 1;
182   sign = image->comps[0].sgnd;
183   movie->tk[0].jp2_struct.bpc = depth_0 + (sign << 7);
184   
185   for (i = 1; i < image->numcomps; i++) {
186     depth = image->comps[i].prec - 1;
187     sign = image->comps[i].sgnd;
188     if (depth_0 != depth)
189       movie->tk[0].jp2_struct.bpc = 255;
190   }
191   
192   for (i = 0; i < image->numcomps; i++)
193     movie->tk[0].jp2_struct.comps[i].bpcc =
194     image->comps[i].prec - 1 + (image->comps[i].sgnd << 7);
195   
196   if ((image->numcomps == 1 || image->numcomps == 3)
197     && (movie->tk[0].jp2_struct.bpc != 255))
198     movie->tk[0].jp2_struct.meth = 1;
199   else
200     movie->tk[0].jp2_struct.meth = 2;
201         
202     if (image->numcomps == 1)
203      movie->tk[0].jp2_struct.enumcs = 17;  // Grayscale
204   
205     else   
206         if ((image->comps[0].dx == 1) 
207         && (image->comps[1].dx == 1) 
208         && (image->comps[2].dx == 1) 
209     && (image->comps[0].dy == 1) 
210         && (image->comps[1].dy == 1) 
211         && (image->comps[2].dy == 1)) 
212      movie->tk[0].jp2_struct.enumcs = 16;    // RGB
213   
214     else   
215         if ((image->comps[0].dx == 1) 
216         && (image->comps[1].dx == 2) 
217         && (image->comps[2].dx == 2) 
218     && (image->comps[0].dy == 1) 
219         && (image->comps[1].dy == 2) 
220         && (image->comps[2].dy == 2)) 
221      movie->tk[0].jp2_struct.enumcs = 18;  // YUV
222   
223   else
224     movie->tk[0].jp2_struct.enumcs = 0; // Unkown profile */
225 }
226
227 int main(int argc, char *argv[]) {
228         opj_cinfo_t* cinfo; 
229         opj_event_mgr_t event_mgr;              /* event manager */  
230   unsigned int snum;
231   opj_mj2_t *movie;
232   mj2_sample_t *sample;
233   unsigned char* frame_codestream;
234   FILE *mj2file, *j2kfile;
235   char j2kfilename[50];
236   char *buf;
237   int offset, mdat_initpos;
238   opj_image_t img;
239         opj_cio_t *cio;
240         mj2_cparameters_t parameters;
241         
242   if (argc != 3) {
243     printf("Bad syntax: Usage: MJ2_Wrapper source_location mj2_filename\n");
244     printf("Example: MJ2_Wrapper input/input output.mj2\n");
245     return 1;
246   }
247   
248   mj2file = fopen(argv[2], "wb");
249   
250   if (!mj2file) {
251     fprintf(stderr, "failed to open %s for writing\n", argv[2]);
252     return 1;
253   }
254
255         /*
256         configure the event callbacks (not required)
257         setting of each callback is optionnal
258         */
259         memset(&event_mgr, 0, sizeof(opj_event_mgr_t));
260         event_mgr.error_handler = error_callback;
261         event_mgr.warning_handler = warning_callback;
262         event_mgr.info_handler = info_callback;
263
264         /* get a MJ2 decompressor handle */
265         cinfo = mj2_create_compress();
266
267         /* catch events using our callbacks and give a local context */
268         opj_set_event_mgr((opj_common_ptr)cinfo, &event_mgr, stderr);   
269         
270         /* setup the decoder encoding parameters using user parameters */
271         movie = (opj_mj2_t*) cinfo->mj2_handle;
272         mj2_setup_encoder(cinfo->mj2_handle, &parameters);
273
274   
275         /* Writing JP, FTYP and MDAT boxes 
276         Assuming that the JP and FTYP boxes won't be longer than 300 bytes */
277         
278   buf = (char*) malloc (300 * sizeof(char)); 
279   cio = opj_cio_open(movie->cinfo, buf, 300);
280   mj2_write_jp(cio);
281   mj2_write_ftyp(movie, cio);
282   mdat_initpos = cio_tell(cio);
283   cio_skip(cio, 4);
284   cio_write(cio,MJ2_MDAT, 4);   
285   fwrite(buf,cio_tell(cio),1,mj2file);
286   free(buf);
287         
288   // Insert each j2k codestream in a JP2C box  
289   snum=0;
290   offset = 0;  
291   while(1)
292   {
293     sample = &movie->tk[0].sample[snum];
294     sprintf(j2kfilename,"%s_%05d.j2k",argv[1],snum);
295     j2kfile = fopen(j2kfilename, "rb");
296     if (!j2kfile) {
297       if (snum==0) {  // Could not open a single codestream
298                                 fprintf(stderr, "failed to open %s for reading\n",j2kfilename);
299                                 return 1;
300       }
301       else {          // Tried to open a inexistant codestream
302                                 fprintf(stdout,"%d frames are being added to the MJ2 file\n",snum);
303                                 break;
304       }
305     }
306
307     // Calculating offset for samples and chunks
308     offset += cio_tell(cio);     
309     sample->offset = offset;
310     movie->tk[0].chunk[snum].offset = offset;  // There will be one sample per chunk
311     
312     // Calculating sample size
313     fseek(j2kfile,0,SEEK_END);  
314     sample->sample_size = ftell(j2kfile) + 8; // Sample size is codestream + JP2C box header
315     fseek(j2kfile,0,SEEK_SET);
316     
317     // Reading siz marker of j2k image for the first codestream
318     if (snum==0)              
319       read_siz_marker(j2kfile, &img);
320     
321     // Writing JP2C box header                      
322     frame_codestream = (unsigned char*) malloc (sample->sample_size+8); 
323                 cio = opj_cio_open(movie->cinfo, frame_codestream, sample->sample_size);    
324     cio_write(cio,sample->sample_size, 4);  // Sample size
325     cio_write(cio,JP2_JP2C, 4); // JP2C
326     
327     // Writing codestream from J2K file to MJ2 file
328     fread(frame_codestream+8,sample->sample_size-8,1,j2kfile);
329     fwrite(frame_codestream,sample->sample_size,1,mj2file);
330     cio_skip(cio, sample->sample_size-8);
331     
332     // Ending loop
333     fclose(j2kfile);
334     snum++;
335     movie->tk[0].sample = realloc(movie->tk[0].sample, (snum+1) * sizeof(mj2_sample_t));
336     movie->tk[0].chunk = realloc(movie->tk[0].chunk, (snum+1) * sizeof(mj2_chunk_t));
337     free(frame_codestream);
338   }
339   
340   // Writing the MDAT box length in header
341   offset += cio_tell(cio);
342   buf = (char*) malloc (4 * sizeof(char));
343         cio = opj_cio_open(movie->cinfo, buf, 4);
344   cio_write(cio,offset-mdat_initpos,4); 
345   fseek(mj2file,(long)mdat_initpos,SEEK_SET);
346   fwrite(buf,4,1,mj2file);
347   fseek(mj2file,0,SEEK_END);
348   free(buf);
349         
350   // Setting movie parameters
351   movie->tk[0].num_samples=snum;
352   movie->tk[0].num_chunks=snum;
353   setparams(movie, &img);
354         
355   // Writing MOOV box 
356         buf = (char*) malloc ((TEMP_BUF+snum*20) * sizeof(char));
357         cio = opj_cio_open(movie->cinfo, buf, (TEMP_BUF+snum*20));
358         mj2_write_moov(movie, cio);
359   fwrite(buf,cio_tell(cio),1,mj2file);
360         
361   // Ending program
362   fclose(mj2file);
363   free(img.comps);
364   opj_cio_close(cio);
365   mj2_destroy_compress(movie);
366         
367   return 0;
368 }