Fixed a copy-and-paste type assignment error (bool instead of int) in the JPWL sectio...
[openjpeg.git] / OPJViewer / source / imagmj2.cpp
1 /*\r
2  * Copyright (c) 2007, Digital Signal Processing Laboratory, Universit� degli studi di Perugia (UPG), Italy\r
3  * All rights reserved.\r
4  *\r
5  * Redistribution and use in source and binary forms, with or without\r
6  * modification, are permitted provided that the following conditions\r
7  * are met:\r
8  * 1. Redistributions of source code must retain the above copyright\r
9  *    notice, this list of conditions and the following disclaimer.\r
10  * 2. Redistributions in binary form must reproduce the above copyright\r
11  *    notice, this list of conditions and the following disclaimer in the\r
12  *    documentation and/or other materials provided with the distribution.\r
13  *\r
14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'\r
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\r
18  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r
19  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r
20  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
21  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
22  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r
23  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
24  * POSSIBILITY OF SUCH DAMAGE.\r
25  */\r
26 /////////////////////////////////////////////////////////////////////////////\r
27 // Name:        imagmj2.cpp\r
28 // Purpose:     wxImage Motion JPEG 2000 file format handler\r
29 // Author:      Giuseppe Baruffa - based on imagjpeg.cpp, Vaclav Slavik\r
30 // RCS-ID:      $Id: imagmj2.cpp,v 0.00 2007/02/18 23:59:00 MW Exp $\r
31 // Copyright:   (c) Giuseppe Baruffa\r
32 // Licence:     wxWindows licence\r
33 /////////////////////////////////////////////////////////////////////////////\r
34 \r
35 // For compilers that support precompilation, includes "wx.h".\r
36 #include "wx/wxprec.h"\r
37 \r
38 #ifdef __BORLANDC__\r
39     #pragma hdrstop\r
40 #endif\r
41 \r
42 #if wxUSE_IMAGE && wxUSE_LIBOPENJPEG\r
43 \r
44 #include "imagmj2.h"\r
45 \r
46 #ifndef WX_PRECOMP\r
47     #include "wx/log.h"\r
48     #include "wx/app.h"\r
49     #include "wx/intl.h"\r
50     #include "wx/bitmap.h"\r
51     #include "wx/module.h"\r
52 #endif\r
53 \r
54 \r
55 #include "libopenjpeg/openjpeg.h"\r
56 \r
57 \r
58 #include "wx/filefn.h"\r
59 #include "wx/wfstream.h"\r
60 \r
61 // ----------------------------------------------------------------------------\r
62 // types\r
63 // ----------------------------------------------------------------------------\r
64 \r
65 \r
66 //-----------------------------------------------------------------------------\r
67 // wxMJ2Handler\r
68 //-----------------------------------------------------------------------------\r
69 \r
70 IMPLEMENT_DYNAMIC_CLASS(wxMJ2Handler,wxImageHandler)\r
71 \r
72 #if wxUSE_STREAMS\r
73 \r
74 //------------- JPEG 2000 Data Source Manager\r
75 \r
76 #define J2K_CFMT 0\r
77 #define JP2_CFMT 1\r
78 #define JPT_CFMT 2\r
79 #define MJ2_CFMT 3\r
80 #define PXM_DFMT 0\r
81 #define PGX_DFMT 1\r
82 #define BMP_DFMT 2\r
83 #define YUV_DFMT 3\r
84 \r
85 #define MAX_MESSAGE_LEN 200\r
86 \r
87 /* sample error callback expecting a FILE* client object */\r
88 void mj2_error_callback(const char *msg, void *client_data) {\r
89         char m_msg[MAX_MESSAGE_LEN];\r
90         int message_len = strlen(msg) - 1;\r
91         if (msg[message_len] != '\n')\r
92                 message_len = MAX_MESSAGE_LEN;\r
93         sprintf(m_msg, "[ERROR] %.*s", message_len, msg);\r
94     wxMutexGuiEnter();\r
95         wxLogMessage(m_msg);\r
96     wxMutexGuiLeave();\r
97 }\r
98 /* sample warning callback expecting a FILE* client object */\r
99 void mj2_warning_callback(const char *msg, void *client_data) {\r
100         char m_msg[MAX_MESSAGE_LEN];\r
101         int message_len = strlen(msg) - 1;\r
102         if (msg[message_len] != '\n')\r
103                 message_len = MAX_MESSAGE_LEN;\r
104         sprintf(m_msg, "[WARNING] %.*s", message_len, msg);\r
105     wxMutexGuiEnter();\r
106         wxLogMessage(m_msg);\r
107     wxMutexGuiLeave();\r
108 }\r
109 /* sample debug callback expecting no client object */\r
110 void mj2_info_callback(const char *msg, void *client_data) {\r
111         char m_msg[MAX_MESSAGE_LEN];\r
112         int message_len = strlen(msg) - 1;\r
113         if (msg[message_len] != '\n')\r
114                 message_len = MAX_MESSAGE_LEN;\r
115         sprintf(m_msg, "[INFO] %.*s", message_len, msg);\r
116     wxMutexGuiEnter();\r
117         wxLogMessage(m_msg);\r
118     wxMutexGuiLeave();\r
119 }\r
120 \r
121 /* macro functions */\r
122 /* From little endian to big endian, 2 and 4 bytes */\r
123 #define BYTE_SWAP2(X)   ((X & 0x00FF) << 8) | ((X & 0xFF00) >> 8)\r
124 #define BYTE_SWAP4(X)   ((X & 0x000000FF) << 24) | ((X & 0x0000FF00) << 8) | ((X & 0x00FF0000) >> 8) | ((X & 0xFF000000) >> 24)\r
125 #define BYTE_SWAP8(X)   ((X & 0x00000000000000FF) << 56) | ((X & 0x000000000000FF00) << 40) | \\r
126                         ((X & 0x0000000000FF0000) << 24) | ((X & 0x00000000FF000000) << 8) | \\r
127                                                 ((X & 0x000000FF00000000) >> 8)  | ((X & 0x0000FF0000000000) >> 24) | \\r
128                                                 ((X & 0x00FF000000000000) >> 40) | ((X & 0xFF00000000000000) >> 56)\r
129 \r
130 /* From codestream to int values */\r
131 #define STREAM_TO_UINT32(C, P)  (((unsigned long int) (C)[(P) + 0] << 24) + \\r
132                                                                 ((unsigned long int) (C)[(P) + 1] << 16) + \\r
133                                                                 ((unsigned long int) (C)[(P) + 2] << 8) + \\r
134                                                                 ((unsigned long int) (C)[(P) + 3] << 0))\r
135 \r
136 #define STREAM_TO_UINT16(C, P)  (((unsigned long int) (C)[(P) + 0] << 8) + \\r
137                                                                 ((unsigned long int) (C)[(P) + 1] << 0))\r
138 \r
139 /* defines */\r
140 #define SHORT_DESCR_LEN        32\r
141 #define LONG_DESCR_LEN         256\r
142 \r
143 /* enumeration for file formats */\r
144 #define J2FILENUM              4\r
145 typedef enum {\r
146 \r
147         JP2_FILE,\r
148         J2K_FILE,\r
149                 MJ2_FILE,\r
150                 UNK_FILE\r
151 \r
152 } my_j2filetype;\r
153 \r
154 /* enumeration for the box types */\r
155 #define J2BOXNUM                23\r
156 typedef enum {\r
157 \r
158                         FILE_BOX,\r
159                         JP_BOX,\r
160                         FTYP_BOX,\r
161                         JP2H_BOX,\r
162                         IHDR_BOX,\r
163                         COLR_BOX,\r
164                         JP2C_BOX,\r
165                         JP2I_BOX,\r
166                         XML_BOX,\r
167                         UUID_BOX,\r
168                         UINF_BOX,\r
169                         MOOV_BOX,\r
170                         MVHD_BOX,\r
171                         TRAK_BOX,\r
172                         TKHD_BOX,\r
173                         MDIA_BOX,\r
174                         MINF_BOX,\r
175                         STBL_BOX,\r
176                         STSD_BOX,\r
177                         MJP2_BOX,\r
178                         MDAT_BOX,\r
179                         ANY_BOX,\r
180                         UNK_BOX\r
181 \r
182 } my_j2boxtype;\r
183 \r
184 /* jp2 family box signatures */\r
185 #define FILE_SIGN           ""\r
186 #define JP_SIGN             "jP\040\040"\r
187 #define FTYP_SIGN           "ftyp"\r
188 #define JP2H_SIGN           "jp2h"\r
189 #define IHDR_SIGN           "ihdr"\r
190 #define COLR_SIGN           "colr"\r
191 #define JP2C_SIGN           "jp2c"\r
192 #define JP2I_SIGN           "jp2i"\r
193 #define XML_SIGN            "xml\040"\r
194 #define UUID_SIGN           "uuid"\r
195 #define UINF_SIGN           "uinf"\r
196 #define MOOV_SIGN           "moov"\r
197 #define MVHD_SIGN           "mvhd"\r
198 #define TRAK_SIGN           "trak"\r
199 #define TKHD_SIGN           "tkhd"\r
200 #define MDIA_SIGN           "mdia"\r
201 #define MINF_SIGN           "minf"\r
202 #define STBL_SIGN           "stbl"\r
203 #define STSD_SIGN           "stsd"\r
204 #define MJP2_SIGN           "mjp2"\r
205 #define MDAT_SIGN           "mdat"\r
206 #define ANY_SIGN                        ""\r
207 #define UNK_SIGN            ""\r
208 \r
209 /* the box structure itself */\r
210 struct my_boxdef {\r
211 \r
212         char                  value[5];                 /* hexadecimal value/string*/\r
213                 char                  name[SHORT_DESCR_LEN];    /* short description       */\r
214                 char                  descr[LONG_DESCR_LEN];    /* long  description       */\r
215                 int                   sbox;                     /* is it a superbox?       */\r
216                 int                   req[J2FILENUM];           /* mandatory box           */\r
217                 my_j2boxtype             ins;                      /* contained in box...     */\r
218 \r
219 };\r
220 \r
221 /* the possible boxes */\r
222 struct my_boxdef j2box[] =\r
223 {\r
224 /* sign */      {FILE_SIGN,\r
225 /* short */     "placeholder for nothing",\r
226 /* long */      "Nothing to say",\r
227 /* sbox */      0,\r
228 /* req */       {1, 1, 1},\r
229 /* ins */       FILE_BOX},\r
230 \r
231 /* sign */      {JP_SIGN,\r
232 /* short */     "JPEG 2000 Signature box",\r
233 /* long */      "This box uniquely identifies the file as being part of the JPEG 2000 family of files",\r
234 /* sbox */      0,\r
235 /* req */       {1, 1, 1},\r
236 /* ins */       FILE_BOX},\r
237 \r
238 /* sign */      {FTYP_SIGN,\r
239 /* short */     "File Type box",\r
240 /* long */      "This box specifies file type, version and compatibility information, including specifying if this file "\r
241                         "is a conforming JP2 file or if it can be read by a conforming JP2 reader",\r
242 /* sbox */      0,\r
243 /* req */       {1, 1, 1},\r
244 /* ins */       FILE_BOX},\r
245 \r
246 /* sign */      {JP2H_SIGN,\r
247 /* short */     "JP2 Header box",\r
248 /* long */      "This box contains a series of boxes that contain header-type information about the file",\r
249 /* sbox */      1,\r
250 /* req */       {1, 1, 1},\r
251 /* ins */       FILE_BOX},\r
252 \r
253 /* sign */      {IHDR_SIGN,\r
254 /* short */     "Image Header box",\r
255 /* long */      "This box specifies the size of the image and other related fields",\r
256 /* sbox */      0,\r
257 /* req */       {1, 1, 1},\r
258 /* ins */       JP2H_BOX},\r
259 \r
260 /* sign */      {COLR_SIGN,\r
261 /* short */     "Colour Specification box",\r
262 /* long */      "This box specifies the colourspace of the image",\r
263 /* sbox */      0,\r
264 /* req */       {1, 1, 1},\r
265 /* ins */       JP2H_BOX},\r
266 \r
267 /* sign */      {JP2C_SIGN,\r
268 /* short */     "Contiguous Codestream box",\r
269 /* long */      "This box contains the codestream as defined by Annex A",\r
270 /* sbox */      0,\r
271 /* req */       {1, 1, 1},\r
272 /* ins */       FILE_BOX},\r
273 \r
274 /* sign */      {JP2I_SIGN,\r
275 /* short */     "Intellectual Property box",\r
276 /* long */      "This box contains intellectual property information about the image",\r
277 /* sbox */      0,\r
278 /* req */       {0, 0, 0},\r
279 /* ins */       FILE_BOX},\r
280 \r
281 /* sign */      {XML_SIGN,\r
282 /* short */     "XML box",\r
283 /* long */      "This box provides a tool by which vendors can add XML formatted information to a JP2 file",\r
284 /* sbox */      0,\r
285 /* req */       {0, 0, 0},\r
286 /* ins */       FILE_BOX},\r
287 \r
288 /* sign */      {UUID_SIGN,\r
289 /* short */     "UUID box",\r
290 /* long */      "This box provides a tool by which vendors can add additional information to a file "\r
291                         "without risking conflict with other vendors",\r
292 /* sbox */      0,\r
293 /* req */       {0, 0, 0},\r
294 /* ins */       FILE_BOX},\r
295 \r
296 /* sign */      {UINF_SIGN,\r
297 /* short */     "UUID Info box",\r
298 /* long */      "This box provides a tool by which a vendor may provide access to additional information associated with a UUID",\r
299 /* sbox */      0,\r
300 /* req */       {0, 0, 0},\r
301 /* ins */       FILE_BOX},\r
302 \r
303 /* sign */      {MOOV_SIGN,\r
304 /* short */     "Movie box",\r
305 /* long */      "This box contains the media data. In video tracks, this box would contain JPEG2000 video frames",\r
306 /* sbox */      1,\r
307 /* req */       {1, 1, 1},\r
308 /* ins */       FILE_BOX},\r
309 \r
310 /* sign */      {MVHD_SIGN,\r
311 /* short */     "Movie Header box",\r
312 /* long */      "This box defines overall information which is media-independent, and relevant to the entire presentation "\r
313                         "considered as a whole",\r
314 /* sbox */      0,\r
315 /* req */       {1, 1, 1},\r
316 /* ins */       MOOV_BOX},\r
317 \r
318 /* sign */      {TRAK_SIGN,\r
319 /* short */     "Track box",\r
320 /* long */      "This is a container box for a single track of a presentation. A presentation may consist of one or more tracks",\r
321 /* sbox */      1,\r
322 /* req */       {1, 1, 1},\r
323 /* ins */       MOOV_BOX},\r
324 \r
325 /* sign */      {TKHD_SIGN,\r
326 /* short */     "Track Header box",\r
327 /* long */      "This box specifies the characteristics of a single track. Exactly one Track Header Box is contained in a track",\r
328 /* sbox */      0,\r
329 /* req */       {1, 1, 1},\r
330 /* ins */       TRAK_BOX},\r
331 \r
332 /* sign */      {MDIA_SIGN,\r
333 /* short */     "Media box",\r
334 /* long */      "The media declaration container contains all the objects which declare information about the media data "\r
335                         "within a track",\r
336 /* sbox */      1,\r
337 /* req */       {1, 1, 1},\r
338 /* ins */       TRAK_BOX},\r
339 \r
340 /* sign */      {MINF_SIGN,\r
341 /* short */     "Media Information box",\r
342 /* long */      "This box contains all the objects which declare characteristic information of the media in the track",\r
343 /* sbox */      1,\r
344 /* req */       {1, 1, 1},\r
345 /* ins */       MDIA_BOX},\r
346 \r
347 /* sign */      {STBL_SIGN,\r
348 /* short */     "Sample Table box",\r
349 /* long */      "The sample table contains all the time and data indexing of the media samples in a track",\r
350 /* sbox */      1,\r
351 /* req */       {1, 1, 1},\r
352 /* ins */       MINF_BOX},\r
353 \r
354 /* sign */      {STSD_SIGN,\r
355 /* short */     "Sample Description box",\r
356 /* long */      "The sample description table gives detailed information about the coding type used, and any initialization "\r
357                         "information needed for that coding",\r
358 /* sbox */      0,\r
359 /* req */       {1, 1, 1},\r
360 /* ins */       MINF_BOX},\r
361 \r
362 /* sign */      {MJP2_SIGN,\r
363 /* short */     "MJP2 Sample Description box",\r
364 /* long */      "The MJP2 sample description table gives detailed information about the coding type used, and any initialization "\r
365                         "information needed for that coding",\r
366 /* sbox */      0,\r
367 /* req */       {1, 1, 1},\r
368 /* ins */       MINF_BOX},\r
369 \r
370 /* sign */      {MDAT_SIGN,\r
371 /* short */     "Media Data box",\r
372 /* long */      "The meta-data for a presentation is stored in the single Movie Box which occurs at the top-level of a file",\r
373 /* sbox */      1,\r
374 /* req */       {1, 1, 1},\r
375 /* ins */       FILE_BOX},\r
376 \r
377 /* sign */      {ANY_SIGN,\r
378 /* short */     "Any box",\r
379 /* long */      "All the existing boxes",\r
380 /* sbox */      0,\r
381 /* req */       {0, 0, 0},\r
382 /* ins */       FILE_BOX},\r
383 \r
384 /* sign */      {UNK_SIGN,\r
385 /* short */     "Unknown Type box",\r
386 /* long */      "The signature is not recognised to be that of an existing box",\r
387 /* sbox */      0,\r
388 /* req */       {0, 0, 0},\r
389 /* ins */       ANY_BOX}\r
390 \r
391 };\r
392 \r
393 /* declaration */\r
394 int\r
395 my_box_handler_function(my_j2boxtype boxtype, wxInputStream& stream, unsigned long int filepoint, unsigned long int filelimit, int level,\r
396                                          char *scansign, unsigned long int *scanpoint);\r
397 \r
398 /* internal mini-search for a box signature */\r
399 int\r
400 my_jpeg2000parse(wxInputStream& stream, unsigned long int filepoint, unsigned long int filelimit, int level,\r
401                           char *scansign, unsigned long int *scanpoint)\r
402 {\r
403         unsigned long int       LBox = 0x00000000;\r
404         int                     LBox_read;\r
405         char                    TBox[5] = "\0\0\0\0";\r
406         int                     TBox_read;\r
407         __int64                 XLBox = 0x0000000000000000;\r
408         int                     XLBox_read;\r
409         unsigned long int       box_length = 0;\r
410         int                     last_box = 0, box_num = 0;\r
411         int                     box_type = ANY_BOX;\r
412         unsigned char           onebyte[1], twobytes[2], fourbytes[4];\r
413         int                     box_number = 0;\r
414 \r
415         /* cycle all over the file */\r
416         box_num = 0;\r
417         last_box = 0;\r
418         while (!last_box) {\r
419 \r
420                 /* do not exceed file limit */\r
421                 if (filepoint >= filelimit)\r
422                         return (0);\r
423 \r
424                 /* seek on file */\r
425                 if (stream.SeekI(filepoint, wxFromStart) == wxInvalidOffset)\r
426                         return (-1);\r
427 \r
428                 /* read the mandatory LBox, 4 bytes */\r
429                 if (!stream.Read(fourbytes, 4)) {\r
430                         (wxT("Problem reading LBox from the file (file ended?)"));\r
431                         return -1;\r
432                 };\r
433                 LBox = STREAM_TO_UINT32(fourbytes, 0);\r
434 \r
435                 /* read the mandatory TBox, 4 bytes */\r
436                 if (!stream.Read(TBox, 4)) {\r
437                         wxLogError(wxT("Problem reading TBox from the file (file ended?)"));\r
438                         return -1;\r
439                 };\r
440 \r
441                 /* look if scansign is got */\r
442                 if ((scansign != NULL) && (memcmp(TBox, scansign, 4) == 0)) {\r
443                         /* hack/exploit */\r
444                         // stop as soon as you find the level-th codebox\r
445                         if (box_number == level) {\r
446                                 memcpy(scansign, "    ", 4);\r
447                                 *scanpoint = filepoint;\r
448                                 return (0);\r
449                         } else\r
450                                 box_number++;\r
451 \r
452                 };\r
453 \r
454 \r
455                 /* determine the box type */\r
456                 for (box_type = JP_BOX; box_type < UNK_BOX; box_type++)\r
457                         if (memcmp(TBox, j2box[box_type].value, 4) == 0)\r
458                                 break;  \r
459 \r
460                 /* read the optional XLBox, 8 bytes */\r
461                 if (LBox == 1) {\r
462 \r
463                         if (!stream.Read(&XLBox, 8)) {\r
464                                 wxLogError(wxT("Problem reading XLBox from the file (file ended?)"));\r
465                                 return -1;\r
466                         };\r
467                         box_length = (unsigned long int) BYTE_SWAP8(XLBox);\r
468 \r
469                 } else if (LBox == 0x00000000) {\r
470 \r
471                         /* last box in file */\r
472                         last_box = 1; \r
473                         box_length = filelimit - filepoint;\r
474 \r
475                 } else\r
476 \r
477                         box_length = LBox;\r
478 \r
479 \r
480                 /* go deep in the box */\r
481                 my_box_handler_function((my_j2boxtype) box_type, stream, (LBox == 1) ? (filepoint + 16) : (filepoint + 8), filepoint + box_length, level,\r
482                         scansign, scanpoint);\r
483 \r
484                 /* if it's a superbox go inside it */\r
485                 if (j2box[box_type].sbox)\r
486                         my_jpeg2000parse(stream, (LBox == 1) ? (filepoint + 16) : (filepoint + 8), filepoint + box_length,\r
487                                 level, scansign, scanpoint);\r
488 \r
489                 /* increment box number and filepoint*/\r
490                 box_num++;\r
491                 filepoint += box_length;\r
492 \r
493         };\r
494 \r
495         /* all good */\r
496         return (0);\r
497 }\r
498 \r
499 // search first contiguos codestream box in an mj2 file\r
500 unsigned long int\r
501 searchfirstjp2c(wxInputStream& stream, unsigned long int fsize)\r
502 {\r
503         char scansign[] = "jp2c";\r
504         unsigned long int scanpoint = 0L;\r
505 \r
506         wxLogMessage("MJ2: searching jp2c box... ");\r
507 \r
508         /* do the parsing */\r
509         if (my_jpeg2000parse(stream, 0, fsize, 0, scansign, &scanpoint) < 0)            \r
510                 wxLogMessage("MJ2: Unrecoverable error during file parsing: stopping");\r
511 \r
512         if (strcmp(scansign, "    "))\r
513                 wxLogMessage("MJ2: not found");\r
514         else {\r
515 \r
516                 wxLogMessage(wxString::Format("MJ2: found at byte %d", scanpoint));\r
517 \r
518         };\r
519 \r
520 \r
521         return (scanpoint);\r
522 }\r
523 \r
524 // search the jp2h box in the file\r
525 unsigned long int\r
526 searchjpegheaderbox(wxInputStream& stream, unsigned long int fsize)\r
527 {\r
528         char scansign[] = "jp2h";\r
529         unsigned long int scanpoint = 0L;\r
530 \r
531         wxLogMessage("MJ2: searching jp2h box... ");\r
532 \r
533         /* do the parsing */\r
534         if (my_jpeg2000parse(stream, 0, fsize, 0, scansign, &scanpoint) < 0)            \r
535                 wxLogMessage("Unrecoverable error during file parsing: stopping");\r
536 \r
537         if (strcmp(scansign, "    "))\r
538                 wxLogMessage("MJ2: not found");\r
539         else\r
540                 wxLogMessage(wxString::Format("MJ2: found at byte %d", scanpoint));\r
541 \r
542         return (scanpoint);\r
543 }\r
544 \r
545 /* handling functions */\r
546 #define ITEM_PER_ROW    10\r
547 \r
548 /* Box handler function */\r
549 int\r
550 my_box_handler_function(my_j2boxtype boxtype, wxInputStream& stream, unsigned long int filepoint, unsigned long int filelimit, int level,\r
551                                          char *scansign, unsigned long int *scanpoint)\r
552 {\r
553         switch (boxtype) {\r
554 \r
555                         /* Sample Description box */\r
556         case (STSD_BOX):\r
557                 my_jpeg2000parse(stream, filepoint + 8, filelimit, level, scansign, scanpoint);\r
558                 break;\r
559 \r
560                         /* MJP2 Sample Description box */\r
561         case (MJP2_BOX):\r
562                 my_jpeg2000parse(stream, filepoint + 78, filelimit, level, scansign, scanpoint);\r
563                 break;\r
564                 \r
565         /* not yet implemented */\r
566         default:\r
567                 break;\r
568 \r
569         };\r
570 \r
571         return (0);\r
572 }\r
573 \r
574 // the jP and ftyp parts of the header\r
575 #define my_jPheadSIZE   32\r
576 unsigned char my_jPhead[my_jPheadSIZE] = {\r
577                 0x00, 0x00, 0x00, 0x0C,  'j',  'P',  ' ',  ' ',\r
578                 0x0D, 0x0A, 0x87, 0x0A, 0x00, 0x00, 0x00, 0x14,\r
579                  'f',  't',  'y',  'p',  'j',  'p',  '2',  ' ',\r
580                 0x00, 0x00, 0x00, 0x00,  'j',  'p',  '2',  ' '                  \r
581 };\r
582 \r
583 /////////////////////////////////////////////////\r
584 /////////////////////////////////////////////////\r
585 \r
586 // load the mj2 file format\r
587 bool wxMJ2Handler::LoadFile(wxImage *image, wxInputStream& stream, bool verbose, int index)\r
588 {\r
589         opj_dparameters_t parameters;   /* decompression parameters */\r
590         opj_event_mgr_t event_mgr;              /* event manager */\r
591         opj_image_t *opjimage = NULL;\r
592         unsigned char *src = NULL;\r
593     unsigned char *ptr;\r
594         int file_length, jp2c_point, jp2h_point;\r
595         unsigned long int jp2hboxlen, jp2cboxlen;\r
596 \r
597         // destroy the image\r
598     image->Destroy();\r
599 \r
600         /* handle to a decompressor */\r
601         opj_dinfo_t* dinfo = NULL;      \r
602         opj_cio_t *cio = NULL;\r
603 \r
604         /* configure the event callbacks (not required) */\r
605         memset(&event_mgr, 0, sizeof(opj_event_mgr_t));\r
606         event_mgr.error_handler = mj2_error_callback;\r
607         event_mgr.warning_handler = mj2_warning_callback;\r
608         event_mgr.info_handler = mj2_info_callback;\r
609 \r
610         /* set decoding parameters to default values */\r
611         opj_set_default_decoder_parameters(&parameters);\r
612 \r
613         /* prepare parameters */\r
614         strncpy(parameters.infile, "", sizeof(parameters.infile)-1);\r
615         strncpy(parameters.outfile, "", sizeof(parameters.outfile)-1);\r
616         parameters.decod_format = JP2_CFMT;\r
617         parameters.cod_format = BMP_DFMT;\r
618 \r
619         /* get a decoder handle */\r
620         dinfo = opj_create_decompress(CODEC_JP2);\r
621 \r
622         /* find length of the stream */\r
623         stream.SeekI(0, wxFromEnd);\r
624         file_length = (int) stream.TellI();\r
625 \r
626         /* search for the first codestream box and the movie header box  */\r
627         jp2c_point = searchfirstjp2c(stream, file_length);\r
628         jp2h_point = searchjpegheaderbox(stream, file_length);\r
629 \r
630         // read the jp2h box and store it\r
631         stream.SeekI(jp2h_point, wxFromStart);\r
632         stream.Read(&jp2hboxlen, sizeof(unsigned long int));\r
633         jp2hboxlen = BYTE_SWAP4(jp2hboxlen);\r
634 \r
635         // read the jp2c box and store it\r
636         stream.SeekI(jp2c_point, wxFromStart);\r
637         stream.Read(&jp2cboxlen, sizeof(unsigned long int));\r
638         jp2cboxlen = BYTE_SWAP4(jp2cboxlen);\r
639 \r
640         // malloc memory source\r
641     src = (unsigned char *) malloc(my_jPheadSIZE + jp2hboxlen + jp2cboxlen);\r
642 \r
643         // copy the jP and ftyp\r
644         memcpy(src, my_jPhead, my_jPheadSIZE);\r
645 \r
646         // copy the jp2h\r
647         stream.SeekI(jp2h_point, wxFromStart);\r
648         stream.Read(&src[my_jPheadSIZE], jp2hboxlen);\r
649 \r
650         // copy the jp2c\r
651         stream.SeekI(jp2c_point, wxFromStart);\r
652         stream.Read(&src[my_jPheadSIZE + jp2hboxlen], jp2cboxlen);\r
653 \r
654         /* catch events using our callbacks and give a local context */\r
655         opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr);\r
656 \r
657         /* setup the decoder decoding parameters using user parameters */\r
658         opj_setup_decoder(dinfo, &parameters);\r
659 \r
660         /* open a byte stream */\r
661         cio = opj_cio_open((opj_common_ptr)dinfo, src, my_jPheadSIZE + jp2hboxlen + jp2cboxlen);\r
662 \r
663         /* decode the stream and fill the image structure */\r
664         opjimage = opj_decode(dinfo, cio);\r
665         if (!opjimage) {\r
666                 wxMutexGuiEnter();\r
667                 wxLogError("MJ2: failed to decode image!");\r
668                 wxMutexGuiLeave();\r
669                 opj_destroy_decompress(dinfo);\r
670                 opj_cio_close(cio);\r
671                 free(src);\r
672                 return false;\r
673         }\r
674 \r
675         /* close the byte stream */\r
676         opj_cio_close(cio);\r
677 \r
678         // check image size\r
679         if ((opjimage->numcomps != 1) && (opjimage->numcomps != 3)) {\r
680                 wxMutexGuiEnter();\r
681                 wxLogError("MJ2: weird number of components");\r
682                 wxMutexGuiLeave();\r
683                 opj_destroy_decompress(dinfo);\r
684                 free(src);\r
685                 return false;\r
686         }\r
687 \r
688         // prepare image size\r
689     image->Create(opjimage->comps[0].w, opjimage->comps[0].h, true );\r
690 \r
691         // access image raw data\r
692     image->SetMask( false );\r
693     ptr = image->GetData();\r
694 \r
695         // RGB color picture\r
696         // does not handle comps. subsampling,\r
697         // so simply render the first component\r
698         if (opjimage->numcomps == 3) {\r
699                 int row, col;\r
700                 int *r = opjimage->comps[0].data;\r
701                 /*\r
702                 int *g = opjimage->comps[1].data;\r
703                 int *b = opjimage->comps[2].data;\r
704                 */\r
705                 for (row = 0; row < opjimage->comps[0].h; row++) {\r
706                         for (col = 0; col < opjimage->comps[0].w; col++) {\r
707                                 \r
708                                 /*\r
709                                 *(ptr++) = *(r++);\r
710                                 *(ptr++) = *(g++);\r
711                                 *(ptr++) = *(b++);\r
712                                 */\r
713                                 *(ptr++) = *(r);\r
714                                 *(ptr++) = *(r);\r
715                                 *(ptr++) = *(r++);\r
716 \r
717                         }\r
718                 }\r
719         }\r
720 \r
721         // B/W picture\r
722         if (opjimage->numcomps == 1) {\r
723                 int row, col;\r
724                 int *y = opjimage->comps[0].data;\r
725                 for (row = 0; row < opjimage->comps[0].h; row++) {\r
726                         for (col = 0; col < opjimage->comps[0].w; col++) {\r
727                                 \r
728                                 *(ptr++) = *(y);\r
729                                 *(ptr++) = *(y);\r
730                                 *(ptr++) = *(y++);\r
731 \r
732                         }\r
733                 }\r
734         }\r
735 \r
736     wxMutexGuiEnter();\r
737     wxLogMessage(wxT("MJ2: image loaded."));\r
738     wxMutexGuiLeave();\r
739 \r
740         /* close openjpeg structs */\r
741         opj_destroy_decompress(dinfo);\r
742         opj_image_destroy(opjimage);\r
743         free(src);\r
744 \r
745         if (!image->Ok())\r
746                 return false;\r
747         else\r
748                 return true;\r
749 \r
750 }\r
751 \r
752 // save the mj2 file format\r
753 bool wxMJ2Handler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbose )\r
754 {\r
755     wxLogError(wxT("MJ2: Couldn't save movie -> not implemented."));\r
756     return false;\r
757 }\r
758 \r
759 #ifdef __VISUALC__\r
760     #pragma warning(default:4611)\r
761 #endif /* VC++ */\r
762 \r
763 // recognize the Motion JPEG 2000 starting box\r
764 bool wxMJ2Handler::DoCanRead( wxInputStream& stream )\r
765 {\r
766     unsigned char hdr[24];\r
767 \r
768     if ( !stream.Read(hdr, WXSIZEOF(hdr)) )\r
769         return false;\r
770 \r
771     return (hdr[0] == 0x00 &&\r
772                         hdr[1] == 0x00 &&\r
773                         hdr[2] == 0x00 &&\r
774                         hdr[3] == 0x0C &&\r
775                         hdr[4] == 0x6A &&\r
776                         hdr[5] == 0x50 &&\r
777                         hdr[6] == 0x20 &&\r
778                         hdr[7] == 0x20 &&\r
779                         hdr[20] == 0x6D &&\r
780                         hdr[21] == 0x6A &&\r
781                         hdr[22] == 0x70 &&\r
782                         hdr[23] == 0x32);\r
783 }\r
784 \r
785 #endif   // wxUSE_STREAMS\r
786 \r
787 #endif   // wxUSE_LIBOPENJPEG\r