Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4758 | right-hear | 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 |
||
30 | #include |
||
31 | #include |
||
32 | |||
33 | #include "openjpeg.h" |
||
34 | #include "../libopenjpeg/j2k.h" |
||
35 | #include "../libopenjpeg/jp2.h" |
||
36 | #include "../libopenjpeg/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 | unsigned 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 = (unsigned char*) malloc(len * sizeof(unsigned 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 | free(siz_buffer); |
||
123 | } |
||
124 | |||
125 | static void setparams(opj_mj2_t *movie, opj_image_t *image) { |
||
126 | int i, depth_0, depth, sign; |
||
127 | |||
128 | movie->tk[0].sample_rate = 25; |
||
129 | movie->tk[0].w = int_ceildiv(image->x1 - image->x0, image->comps[0].dx); |
||
130 | movie->tk[0].h = int_ceildiv(image->y1 - image->y0, image->comps[0].dy); |
||
131 | mj2_init_stdmovie(movie); |
||
132 | |||
133 | movie->tk[0].depth = image->comps[0].prec; |
||
134 | |||
135 | if (image->numcomps==3) { |
||
136 | if ((image->comps[0].dx == 1) |
||
137 | && (image->comps[1].dx == 1) |
||
138 | && (image->comps[2].dx == 1)) |
||
139 | movie->tk[0].CbCr_subsampling_dx = 1; |
||
140 | else |
||
141 | if ((image->comps[0].dx == 1) |
||
142 | && (image->comps[1].dx == 2) |
||
143 | && (image->comps[2].dx == 2)) |
||
144 | movie->tk[0].CbCr_subsampling_dx = 2; |
||
145 | else |
||
146 | fprintf(stderr,"Image component sizes are incoherent\n"); |
||
147 | |||
148 | if ((image->comps[0].dy == 1) |
||
149 | && (image->comps[1].dy == 1) |
||
150 | && (image->comps[2].dy == 1)) |
||
151 | movie->tk[0].CbCr_subsampling_dy = 1; |
||
152 | else |
||
153 | if ((image->comps[0].dy == 1) |
||
154 | && (image->comps[1].dy == 2) |
||
155 | && (image->comps[2].dy == 2)) |
||
156 | movie->tk[0].CbCr_subsampling_dy = 2; |
||
157 | else |
||
158 | fprintf(stderr,"Image component sizes are incoherent\n"); |
||
159 | } |
||
160 | |||
161 | movie->tk[0].sample_rate = 25; |
||
162 | |||
163 | movie->tk[0].jp2_struct.numcomps = image->numcomps; // NC |
||
164 | |||
165 | /* Init Standard jp2 structure */ |
||
166 | |||
167 | movie->tk[0].jp2_struct.comps = |
||
168 | (opj_jp2_comps_t *) malloc(movie->tk[0].jp2_struct.numcomps * sizeof(opj_jp2_comps_t)); |
||
169 | movie->tk[0].jp2_struct.precedence = 0; /* PRECEDENCE*/ |
||
170 | movie->tk[0].jp2_struct.approx = 0; /* APPROX*/ |
||
171 | movie->tk[0].jp2_struct.brand = JP2_JP2; /* BR */ |
||
172 | movie->tk[0].jp2_struct.minversion = 0; /* MinV */ |
||
173 | movie->tk[0].jp2_struct.numcl = 1; |
||
174 | movie->tk[0].jp2_struct.cl = (unsigned int *) malloc(movie->tk[0].jp2_struct.numcl * sizeof(int)); |
||
175 | movie->tk[0].jp2_struct.cl[0] = JP2_JP2; /* CL0 : JP2 */ |
||
176 | movie->tk[0].jp2_struct.C = 7; /* C : Always 7*/ |
||
177 | movie->tk[0].jp2_struct.UnkC = 0; /* UnkC, colorspace specified in colr box*/ |
||
178 | movie->tk[0].jp2_struct.IPR = 0; /* IPR, no intellectual property*/ |
||
179 | movie->tk[0].jp2_struct.w = int_ceildiv(image->x1 - image->x0, image->comps[0].dx); |
||
180 | movie->tk[0].jp2_struct.h = int_ceildiv(image->y1 - image->y0, image->comps[0].dy); |
||
181 | |||
182 | depth_0 = image->comps[0].prec - 1; |
||
183 | sign = image->comps[0].sgnd; |
||
184 | movie->tk[0].jp2_struct.bpc = depth_0 + (sign << 7); |
||
185 | |||
186 | for (i = 1; i < image->numcomps; i++) { |
||
187 | depth = image->comps[i].prec - 1; |
||
188 | sign = image->comps[i].sgnd; |
||
189 | if (depth_0 != depth) |
||
190 | movie->tk[0].jp2_struct.bpc = 255; |
||
191 | } |
||
192 | |||
193 | for (i = 0; i < image->numcomps; i++) |
||
194 | movie->tk[0].jp2_struct.comps[i].bpcc = |
||
195 | image->comps[i].prec - 1 + (image->comps[i].sgnd << 7); |
||
196 | |||
197 | if ((image->numcomps == 1 || image->numcomps == 3) |
||
198 | && (movie->tk[0].jp2_struct.bpc != 255)) |
||
199 | movie->tk[0].jp2_struct.meth = 1; |
||
200 | else |
||
201 | movie->tk[0].jp2_struct.meth = 2; |
||
202 | |||
203 | if (image->numcomps == 1) |
||
204 | movie->tk[0].jp2_struct.enumcs = 17; // Grayscale |
||
205 | |||
206 | else |
||
207 | if ((image->comps[0].dx == 1) |
||
208 | && (image->comps[1].dx == 1) |
||
209 | && (image->comps[2].dx == 1) |
||
210 | && (image->comps[0].dy == 1) |
||
211 | && (image->comps[1].dy == 1) |
||
212 | && (image->comps[2].dy == 1)) |
||
213 | movie->tk[0].jp2_struct.enumcs = 16; // RGB |
||
214 | |||
215 | else |
||
216 | if ((image->comps[0].dx == 1) |
||
217 | && (image->comps[1].dx == 2) |
||
218 | && (image->comps[2].dx == 2) |
||
219 | && (image->comps[0].dy == 1) |
||
220 | && (image->comps[1].dy == 2) |
||
221 | && (image->comps[2].dy == 2)) |
||
222 | movie->tk[0].jp2_struct.enumcs = 18; // YUV |
||
223 | |||
224 | else |
||
225 | movie->tk[0].jp2_struct.enumcs = 0; // Unkown profile */ |
||
226 | } |
||
227 | |||
228 | int main(int argc, char *argv[]) { |
||
229 | opj_cinfo_t* cinfo; |
||
230 | opj_event_mgr_t event_mgr; /* event manager */ |
||
231 | unsigned int snum; |
||
232 | opj_mj2_t *movie; |
||
233 | mj2_sample_t *sample; |
||
234 | unsigned char* frame_codestream; |
||
235 | FILE *mj2file, *j2kfile; |
||
236 | char j2kfilename[50]; |
||
237 | unsigned char *buf; |
||
238 | int offset, mdat_initpos; |
||
239 | opj_image_t img; |
||
240 | opj_cio_t *cio; |
||
241 | mj2_cparameters_t parameters; |
||
242 | |||
243 | if (argc != 3) { |
||
244 | printf("Usage: %s source_location mj2_filename\n",argv[0]); |
||
245 | printf("Example: %s input/input output.mj2\n",argv[0]); |
||
246 | return 1; |
||
247 | } |
||
248 | |||
249 | mj2file = fopen(argv[2], "wb"); |
||
250 | |||
251 | if (!mj2file) { |
||
252 | fprintf(stderr, "failed to open %s for writing\n", argv[2]); |
||
253 | return 1; |
||
254 | } |
||
255 | |||
256 | /* |
||
257 | configure the event callbacks (not required) |
||
258 | setting of each callback is optionnal |
||
259 | */ |
||
260 | memset(&event_mgr, 0, sizeof(opj_event_mgr_t)); |
||
261 | event_mgr.error_handler = error_callback; |
||
262 | event_mgr.warning_handler = warning_callback; |
||
263 | event_mgr.info_handler = info_callback; |
||
264 | |||
265 | /* get a MJ2 decompressor handle */ |
||
266 | cinfo = mj2_create_compress(); |
||
267 | |||
268 | /* catch events using our callbacks and give a local context */ |
||
269 | opj_set_event_mgr((opj_common_ptr)cinfo, &event_mgr, stderr); |
||
270 | |||
271 | /* setup the decoder encoding parameters using user parameters */ |
||
272 | movie = (opj_mj2_t*) cinfo->mj2_handle; |
||
273 | mj2_setup_encoder((opj_mj2_t*)cinfo->mj2_handle, ¶meters); |
||
274 | |||
275 | |||
276 | /* Writing JP, FTYP and MDAT boxes |
||
277 | Assuming that the JP and FTYP boxes won't be longer than 300 bytes */ |
||
278 | |||
279 | buf = (unsigned char*) malloc (300 * sizeof(unsigned char)); |
||
280 | cio = opj_cio_open(movie->cinfo, buf, 300); |
||
281 | mj2_write_jp(cio); |
||
282 | mj2_write_ftyp(movie, cio); |
||
283 | mdat_initpos = cio_tell(cio); |
||
284 | cio_skip(cio, 4); |
||
285 | cio_write(cio,MJ2_MDAT, 4); |
||
286 | fwrite(buf,cio_tell(cio),1,mj2file); |
||
287 | free(buf); |
||
288 | |||
289 | // Insert each j2k codestream in a JP2C box |
||
290 | snum=0; |
||
291 | offset = 0; |
||
292 | while(1) |
||
293 | { |
||
294 | sample = &movie->tk[0].sample[snum]; |
||
295 | sprintf(j2kfilename,"%s_%05d.j2k",argv[1],snum); |
||
296 | j2kfile = fopen(j2kfilename, "rb"); |
||
297 | if (!j2kfile) { |
||
298 | if (snum==0) { // Could not open a single codestream |
||
299 | fprintf(stderr, "failed to open %s for reading\n",j2kfilename); |
||
300 | return 1; |
||
301 | } |
||
302 | else { // Tried to open a inexistant codestream |
||
303 | fprintf(stdout,"%d frames are being added to the MJ2 file\n",snum); |
||
304 | break; |
||
305 | } |
||
306 | } |
||
307 | |||
308 | // Calculating offset for samples and chunks |
||
309 | offset += cio_tell(cio); |
||
310 | sample->offset = offset; |
||
311 | movie->tk[0].chunk[snum].offset = offset; // There will be one sample per chunk |
||
312 | |||
313 | // Calculating sample size |
||
314 | fseek(j2kfile,0,SEEK_END); |
||
315 | sample->sample_size = ftell(j2kfile) + 8; // Sample size is codestream + JP2C box header |
||
316 | fseek(j2kfile,0,SEEK_SET); |
||
317 | |||
318 | // Reading siz marker of j2k image for the first codestream |
||
319 | if (snum==0) |
||
320 | read_siz_marker(j2kfile, &img); |
||
321 | |||
322 | // Writing JP2C box header |
||
323 | frame_codestream = (unsigned char*) malloc (sample->sample_size+8); |
||
324 | cio = opj_cio_open(movie->cinfo, frame_codestream, sample->sample_size); |
||
325 | cio_write(cio,sample->sample_size, 4); // Sample size |
||
326 | cio_write(cio,JP2_JP2C, 4); // JP2C |
||
327 | |||
328 | // Writing codestream from J2K file to MJ2 file |
||
329 | fread(frame_codestream+8,sample->sample_size-8,1,j2kfile); |
||
330 | fwrite(frame_codestream,sample->sample_size,1,mj2file); |
||
331 | cio_skip(cio, sample->sample_size-8); |
||
332 | |||
333 | // Ending loop |
||
334 | fclose(j2kfile); |
||
335 | snum++; |
||
336 | movie->tk[0].sample = (mj2_sample_t*) |
||
337 | realloc(movie->tk[0].sample, (snum+1) * sizeof(mj2_sample_t)); |
||
338 | movie->tk[0].chunk = (mj2_chunk_t*) |
||
339 | realloc(movie->tk[0].chunk, (snum+1) * sizeof(mj2_chunk_t)); |
||
340 | free(frame_codestream); |
||
341 | } |
||
342 | |||
343 | // Writing the MDAT box length in header |
||
344 | offset += cio_tell(cio); |
||
345 | buf = (unsigned char*) malloc (4 * sizeof(unsigned char)); |
||
346 | cio = opj_cio_open(movie->cinfo, buf, 4); |
||
347 | cio_write(cio,offset-mdat_initpos,4); |
||
348 | fseek(mj2file,(long)mdat_initpos,SEEK_SET); |
||
349 | fwrite(buf,4,1,mj2file); |
||
350 | fseek(mj2file,0,SEEK_END); |
||
351 | free(buf); |
||
352 | |||
353 | // Setting movie parameters |
||
354 | movie->tk[0].num_samples=snum; |
||
355 | movie->tk[0].num_chunks=snum; |
||
356 | setparams(movie, &img); |
||
357 | |||
358 | // Writing MOOV box |
||
359 | buf = (unsigned char*) malloc ((TEMP_BUF+snum*20) * sizeof(unsigned char)); |
||
360 | cio = opj_cio_open(movie->cinfo, buf, (TEMP_BUF+snum*20)); |
||
361 | mj2_write_moov(movie, cio); |
||
362 | fwrite(buf,cio_tell(cio),1,mj2file); |
||
363 | |||
364 | // Ending program |
||
365 | fclose(mj2file); |
||
366 | free(img.comps); |
||
367 | opj_cio_close(cio); |
||
368 | mj2_destroy_compress(movie); |
||
369 | |||
370 | return 0; |
||
371 | }><>>>><>>8)><8)> |