Bug with mj2_read_struct fixed (problem when reading MJ2 files starting with the...
[openjpeg.git] / mj2 / wrap_j2k_in_mj2.c
1 #include <stdio.h>
2 #include <malloc.h>
3 #include <setjmp.h>
4 #include <string.h>
5
6 #include "mj2.h"
7 #include <cio.h>
8 #include <j2k.h>
9 #include <int.h>
10
11 #define MJ2_MJ2   0x6d6a7032
12 #define MJ2_MJ2S  0x6d6a3273
13 #define JP2_JP2C  0x6a703263
14 #define MJ2_MDAT  0x6d646174
15
16 //MEMORY LEAK
17 #ifdef _DEBUG
18 #define _CRTDBG_MAP_ALLOC
19 #include <stdlib.h>  // Must be included first
20 #include <crtdbg.h>
21 #endif
22 //MEM
23
24 jmp_buf j2k_error;
25
26 void j2k_read_siz_marker(FILE *file, j2k_image_t *j2k_img)
27 {
28   int len,i;
29   char buf, buf2[2];
30   char *siz_buffer;
31   
32   fseek(file, 0, SEEK_SET);
33   do {
34     fread(&buf,1,1, file);
35     if (buf==(char)0xff)
36       fread(&buf,1,1, file);
37   }
38   while (!(buf==(char)0x51));
39   
40   fread(buf2,2,1,file);         /* Lsiz                */
41   len = ((buf2[0])<<8) + buf2[1];
42   
43   siz_buffer = (char*) malloc(len * sizeof(char));
44   fread(siz_buffer,len, 1, file);
45   cio_init(siz_buffer,len);
46   
47   cio_read(2);                  /* Rsiz (capabilities) */
48   j2k_img->x1 = cio_read(4);    /* Xsiz                */
49   j2k_img->y1 = cio_read(4);    /* Ysiz                */
50   j2k_img->x0 = cio_read(4);    /* X0siz               */
51   j2k_img->y0 = cio_read(4);    /* Y0siz               */
52   cio_skip(16);                 /* XTsiz, YTsiz, XT0siz, YT0siz        */
53   
54   j2k_img->numcomps = cio_read(2);      /* Csiz                */
55   j2k_img->comps =
56     (j2k_comp_t *) malloc(j2k_img->numcomps * sizeof(j2k_comp_t));
57   for (i = 0; i < j2k_img->numcomps; i++) {
58     int tmp;
59     tmp = cio_read(1);          /* Ssiz_i          */
60     j2k_img->comps[i].prec = (tmp & 0x7f) + 1;
61     j2k_img->comps[i].sgnd = tmp >> 7;
62     j2k_img->comps[i].dx = cio_read(1); /* XRsiz_i         */
63     j2k_img->comps[i].dy = cio_read(1); /* YRsiz_i         */
64     j2k_img->comps[i].resno_decoded = 0;        /* number of resolution decoded */
65     j2k_img->comps[i].factor = 0;       /* reducing factor by component */
66   }
67   free(siz_buffer);
68   fseek(file, 0, SEEK_SET);
69 }
70
71 void setparams(mj2_movie_t *movie, j2k_image_t *img) {
72   int i, depth_0, depth, sign;
73   
74   movie->tk[0].sample_rate = 25;
75   movie->tk[0].w = int_ceildiv(img->x1 - img->x0, img->comps[0].dx);
76   movie->tk[0].h = int_ceildiv(img->y1 - img->y0, img->comps[0].dy);
77   mj2_init_stdmovie(movie);
78   
79   movie->tk[0].depth = img->comps[0].prec;
80
81   if (img->numcomps==3) {
82     if ((img->comps[0].dx == 1) && (img->comps[1].dx == 1) && (img->comps[1].dx == 1)) 
83       movie->tk[0].CbCr_subsampling_dx = 1;
84     else if ((img->comps[0].dx == 1) && (img->comps[1].dx == 2) && (img->comps[1].dx == 2))
85       movie->tk[0].CbCr_subsampling_dx = 2;
86     else
87       fprintf(stderr,"Image component sizes are incoherent\n");
88     
89     if ((img->comps[0].dy == 1) && (img->comps[1].dy == 1) && (img->comps[1].dy == 1)) 
90       movie->tk[0].CbCr_subsampling_dy = 1;
91     else if ((img->comps[0].dy == 1) && (img->comps[1].dy == 2) && (img->comps[1].dy == 2))
92       movie->tk[0].CbCr_subsampling_dy = 2;
93     else
94       fprintf(stderr,"Image component sizes are incoherent\n");
95   }
96   
97   movie->tk[0].sample_rate = 25;
98   
99   movie->tk[0].jp2_struct.numcomps = img->numcomps;     // NC  
100   jp2_init_stdjp2(&movie->tk[0].jp2_struct);
101   
102   movie->tk[0].jp2_struct.w = int_ceildiv(img->x1 - img->x0, img->comps[0].dx);
103   movie->tk[0].jp2_struct.h = int_ceildiv(img->y1 - img->y0, img->comps[0].dy);
104   
105   depth_0 = img->comps[0].prec - 1;
106   sign = img->comps[0].sgnd;
107   movie->tk[0].jp2_struct.bpc = depth_0 + (sign << 7);
108   
109   for (i = 1; i < img->numcomps; i++) {
110     depth = img->comps[i].prec - 1;
111     sign = img->comps[i].sgnd;
112     if (depth_0 != depth)
113       movie->tk[0].jp2_struct.bpc = 255;
114   }
115   
116   for (i = 0; i < img->numcomps; i++)
117     movie->tk[0].jp2_struct.comps[i].bpcc =
118     img->comps[i].prec - 1 + (img->comps[i].sgnd << 7);
119   
120   if ((img->numcomps == 1 || img->numcomps == 3)
121     && (movie->tk[0].jp2_struct.bpc != 255))
122     movie->tk[0].jp2_struct.meth = 1;
123   else
124     movie->tk[0].jp2_struct.meth = 2;
125     
126   if (img->numcomps == 1)
127     movie->tk[0].jp2_struct.enumcs = 17;  // Grayscale
128   
129   else   if ((img->comps[0].dx == 1) && (img->comps[1].dx == 1) && (img->comps[1].dx == 1) &&
130     (img->comps[0].dy == 1) && (img->comps[1].dy == 1) && (img->comps[1].dy == 1)) 
131     movie->tk[0].jp2_struct.enumcs = 16;    // RGB
132   
133   else   if ((img->comps[0].dx == 1) && (img->comps[1].dx == 2) && (img->comps[1].dx == 2) &&
134     (img->comps[0].dy == 1) && (img->comps[1].dy == 2) && (img->comps[1].dy == 2)) 
135     movie->tk[0].jp2_struct.enumcs = 18;  // YUV
136   
137   else
138     movie->tk[0].jp2_struct.enumcs = 0; // Unkown profile */
139 }
140
141 int main(int argc, char *argv[]) {
142   
143   unsigned int snum;
144   mj2_movie_t movie;
145   mj2_sample_t *sample;
146   unsigned char* frame_codestream;
147   FILE *mj2file, *j2kfile;
148   char j2kfilename[50];
149   char *buf;
150   int offset, mdat_initpos;
151   j2k_image_t img;
152   int pos, i;
153   
154   if (argc != 3) {
155     printf("Bad syntax: Usage: MJ2_Wrapper source_location mj2_filename\n");
156     printf("Example: MJ2_Wrapper input/input output.mj2\n");
157     return 1;
158   }
159   
160   mj2file = fopen(argv[2], "wb");
161   
162   if (!mj2file) {
163     fprintf(stderr, "failed to open %s for writing\n", argv[2]);
164     return 1;
165   }
166   
167   // Initialing the movie (parameters used in the JP and FTYP boxes  
168   movie.num_htk = 0;      // No hint tracks
169   movie.num_stk = 0;      // No sound tracks
170   movie.num_vtk = 1;      // One video track  
171   movie.tk = (mj2_tk_t*) malloc (sizeof(mj2_tk_t)); //Memory allocation for the video track
172   movie.tk[0].sample = (mj2_sample_t*) malloc (sizeof(mj2_sample_t));
173   movie.tk[0].chunk = (mj2_chunk_t *) malloc(sizeof(mj2_chunk_t));  
174   movie.tk[0].track_type = 0;     // Video track
175   movie.tk[0].track_ID = 1;       // Track ID = 1 
176   movie.brand = MJ2_MJ2;  // One brand: MJ2
177   movie.num_cl = 2;       // Two compatible brands: MJ2 and MJ2S
178   movie.cl = (unsigned int *) malloc(movie.num_cl * sizeof(unsigned int));
179   movie.cl[0] = MJ2_MJ2;
180   movie.cl[1] = MJ2_MJ2S;
181   movie.minversion = 0;   // Minimum version: 0
182   
183   // Writing JP, FTYP and MDAT boxes 
184   buf = (char*) malloc (300 * sizeof(char)); // Assuming that the JP and FTYP
185                                              // boxes won't be longer than 300 bytes
186   cio_init(buf , 300);
187   mj2_write_jp();
188   mj2_write_ftyp(&movie);
189   mdat_initpos = cio_tell();
190   cio_skip(4);
191   cio_write(MJ2_MDAT, 4);       
192   fwrite(buf,cio_tell(),1,mj2file);
193   free(buf);
194     
195   // Insert each j2k codestream in a JP2C box  
196   snum=0;
197   offset = 0;  
198   while(1)
199   {
200     sample = &movie.tk[0].sample[snum];
201     sprintf(j2kfilename,"%s_%d.j2k",argv[1],snum);
202     j2kfile = fopen(j2kfilename, "rb");
203     if (!j2kfile) {
204       if (snum==0) {  // Could not open a single codestream
205         fprintf(stderr, "failed to open %s for reading\n",j2kfilename);
206         return 1;
207       }
208       else {          // Tried to open a inexistant codestream
209         fprintf(stdout,"%d frames created\n",snum);
210         break;
211       }
212     }
213     // Calculating offset for samples and chunks
214     offset += cio_tell();     
215     sample->offset = offset;
216     movie.tk[0].chunk[snum].offset = offset;  // There will be one sample per chunk
217     
218     // Calculating sample size
219     fseek(j2kfile,0,SEEK_END);  
220     sample->sample_size = ftell(j2kfile) + 8; // Sample size is codestream + JP2C box header
221     fseek(j2kfile,0,SEEK_SET);
222     
223     // Reading siz marker of j2k image for the first codestream
224     if (snum==0)              
225       j2k_read_siz_marker(j2kfile, &img);
226     
227     // Writing JP2C box header                      
228     frame_codestream = (unsigned char*) malloc (sample->sample_size+8); 
229     cio_init(frame_codestream, sample->sample_size);
230     cio_write(sample->sample_size, 4);  // Sample size
231     cio_write(JP2_JP2C, 4);     // JP2C
232     
233     // Writing codestream from J2K file to MJ2 file
234     fread(frame_codestream+8,sample->sample_size-8,1,j2kfile);
235     fwrite(frame_codestream,sample->sample_size,1,mj2file);
236     cio_skip(sample->sample_size-8);
237     
238     // Ending loop
239     fclose(j2kfile);
240     snum++;
241     movie.tk[0].sample = realloc(movie.tk[0].sample, (snum+1) * sizeof(mj2_sample_t));
242     movie.tk[0].chunk = realloc(movie.tk[0].chunk, (snum+1) * sizeof(mj2_chunk_t));
243     free(frame_codestream);
244   }
245   
246   // Writing the MDAT box length in header
247   offset += cio_tell();
248   buf = (char*) malloc (4 * sizeof(char));
249   cio_init(buf,4);
250   cio_write(offset-mdat_initpos,4); // Write MDAT length in MDAT box header
251   fseek(mj2file,(long)mdat_initpos,SEEK_SET);
252   fwrite(buf,4,1,mj2file);
253   fseek(mj2file,0,SEEK_END);
254   free(buf);
255
256   // Setting movie parameters
257   movie.tk[0].num_samples=snum;
258   movie.tk[0].num_chunks=snum;
259   setparams(&movie, &img);
260
261   // Writing MOOV box 
262   i=1;
263   buf = (char*) malloc (10000 * sizeof(char));
264   cio_init(buf , i*10000);
265   if (setjmp(j2k_error)) {
266     i++;
267     realloc(buf,i*10000* sizeof(char));
268     pos = cio_tell();
269     cio_init(buf , i*10000);
270     cio_seek(pos);
271   }
272   mj2_write_moov(&movie);
273   fwrite(buf,cio_tell(),1,mj2file);
274
275   // Ending program
276   fclose(mj2file);
277   free(img.comps);
278   free(buf);
279   mj2_memory_free(&movie);
280
281
282   //MEMORY LEAK
283   #ifdef _DEBUG
284     _CrtDumpMemoryLeaks();
285   #endif
286   //MEM
287
288   return 0;
289 }