updated XCode project file
[openjpeg.git] / OPJViewer / source / imagmxf.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:        imagmxf.cpp\r
28 // Purpose:     wxImage MXF (Material eXchange Format) JPEG 2000 file format handler\r
29 // Author:      Giuseppe Baruffa - based on imagjpeg.cpp, Vaclav Slavik\r
30 // RCS-ID:      $Id: imagmxf.cpp,v 0.00 2007/11/19 17:00:00 MW Exp $\r
31 // Copyright:   (c) Giuseppe Baruffa\r
32 // Licence:     wxWindows licence\r
33 /////////////////////////////////////////////////////////////////////////////\r
34 \r
35 #ifdef USE_MXF\r
36 \r
37 #include "mxflib/mxflib.h"\r
38 using namespace mxflib;\r
39 \r
40 namespace\r
41 {\r
42         //! Structure holding information about the essence in each body stream\r
43         struct EssenceInfo\r
44         {\r
45                 UMIDPtr PackageID;\r
46                 PackagePtr Package;\r
47                 MDObjectPtr Descriptor;\r
48         };\r
49         //! Map of EssenceInfo structures indexed by BodySID\r
50         typedef std::map<UInt32, EssenceInfo> EssenceInfoMap;\r
51 \r
52         //! The map of essence info for this file\r
53         EssenceInfoMap EssenceLookup;\r
54 };\r
55 \r
56 //! Build an EssenceInfoMap for the essence in a given file\r
57 /*! \return True if al OK, else false\r
58  */\r
59 bool BuildEssenceInfo(MXFFilePtr &File, EssenceInfoMap &EssenceLookup);\r
60 \r
61 // For compilers that support precompilation, includes "wx.h".\r
62 #include "wx/wxprec.h"\r
63 \r
64 #ifdef __BORLANDC__\r
65     #pragma hdrstop\r
66 #endif\r
67 \r
68 #if wxUSE_IMAGE && wxUSE_LIBOPENJPEG\r
69 \r
70 #include "imagmxf.h"\r
71 \r
72 #ifndef WX_PRECOMP\r
73     #include "wx/log.h"\r
74     #include "wx/app.h"\r
75     #include "wx/intl.h"\r
76     #include "wx/bitmap.h"\r
77     #include "wx/module.h"\r
78 #endif\r
79 \r
80 \r
81 #include "libopenjpeg/openjpeg.h"\r
82 \r
83 \r
84 #include "wx/filefn.h"\r
85 #include "wx/wfstream.h"\r
86 \r
87 // ----------------------------------------------------------------------------\r
88 // types\r
89 // ----------------------------------------------------------------------------\r
90 \r
91 \r
92 //-----------------------------------------------------------------------------\r
93 // wxMXFHandler\r
94 //-----------------------------------------------------------------------------\r
95 \r
96 IMPLEMENT_DYNAMIC_CLASS(wxMXFHandler,wxImageHandler)\r
97 \r
98 #if wxUSE_STREAMS\r
99 \r
100 #include <stdarg.h>\r
101 #define MAX_MESSAGE_LEN 200\r
102 \r
103 //------------- MXF Manager\r
104 \r
105 // Debug and error messages\r
106 \r
107 //! Display a warning message\r
108 void mxflib::warning(const char *Fmt, ...)\r
109 {\r
110         char msg[MAX_MESSAGE_LEN];\r
111         va_list args;\r
112 \r
113         va_start(args, Fmt);\r
114         _vsnprintf(msg, MAX_MESSAGE_LEN, Fmt, args);\r
115         va_end(args);\r
116 \r
117         int message_len = strlen(msg) - 1;\r
118         if (msg[message_len] != '\n')\r
119                 message_len = MAX_MESSAGE_LEN;\r
120 #ifndef __WXGTK__ \r
121                 wxMutexGuiEnter();\r
122 #endif /* __WXGTK__ */\r
123         wxLogMessage(wxT("[WARNING_MXF] %.*s"), message_len, msg);\r
124 #ifndef __WXGTK__ \r
125     wxMutexGuiLeave();\r
126 #endif /* __WXGTK__ */\r
127 }\r
128 \r
129 //! Display an error message\r
130 void mxflib::error(const char *Fmt, ...)\r
131 {\r
132         char msg[MAX_MESSAGE_LEN];\r
133         va_list args;\r
134 \r
135         va_start(args, Fmt);\r
136         _vsnprintf(msg, MAX_MESSAGE_LEN, Fmt, args);\r
137         va_end(args);\r
138 \r
139         int message_len = strlen(msg) - 1;\r
140         if (msg[message_len] != '\n')\r
141                 message_len = MAX_MESSAGE_LEN;\r
142 #ifndef __WXGTK__ \r
143                 wxMutexGuiEnter();\r
144 #endif /* __WXGTK__ */\r
145         wxLogMessage(wxT("[ERROR_MXF] %.*s"), message_len, msg);\r
146 #ifndef __WXGTK__ \r
147     wxMutexGuiLeave();\r
148 #endif /* __WXGTK__ */\r
149 }\r
150 \r
151 //! Display an error message\r
152 void mxflib::debug(const char *Fmt, ...)\r
153 {\r
154         char msg[MAX_MESSAGE_LEN];\r
155         va_list args;\r
156 \r
157         va_start(args, Fmt);\r
158         _vsnprintf(msg, MAX_MESSAGE_LEN, Fmt, args);\r
159         va_end(args);\r
160 \r
161         int message_len = strlen(msg) - 1;\r
162         if (msg[message_len] != '\n')\r
163                 message_len = MAX_MESSAGE_LEN;\r
164 #ifndef __WXGTK__ \r
165                 wxMutexGuiEnter();\r
166 #endif /* __WXGTK__ */\r
167         wxLogMessage(wxT("[DEBUG_MXF] %.*s"), message_len, msg);\r
168 #ifndef __WXGTK__ \r
169     wxMutexGuiLeave();\r
170 #endif /* __WXGTK__ */\r
171 }\r
172 \r
173 \r
174 \r
175 //------------- JPEG 2000 Data Source Manager\r
176 \r
177 #define J2K_CFMT 0\r
178 #define JP2_CFMT 1\r
179 #define JPT_CFMT 2\r
180 #define MJ2_CFMT 3\r
181 #define PXM_DFMT 0\r
182 #define PGX_DFMT 1\r
183 #define BMP_DFMT 2\r
184 #define YUV_DFMT 3\r
185 \r
186 /* sample error callback expecting a FILE* client object */\r
187 void mxf_error_callback(const char *msg, void *client_data) {\r
188         int message_len = strlen(msg) - 1;\r
189         if (msg[message_len] != '\n')\r
190                 message_len = MAX_MESSAGE_LEN;\r
191 #ifndef __WXGTK__ \r
192                 wxMutexGuiEnter();\r
193 #endif /* __WXGTK__ */\r
194         wxLogMessage(wxT("[ERROR] %.*s"), message_len, msg);\r
195 #ifndef __WXGTK__ \r
196     wxMutexGuiLeave();\r
197 #endif /* __WXGTK__ */\r
198 }\r
199 \r
200 /* sample warning callback expecting a FILE* client object */\r
201 void mxf_warning_callback(const char *msg, void *client_data) {\r
202         int message_len = strlen(msg) - 1;\r
203         if (msg[message_len] != '\n')\r
204                 message_len = MAX_MESSAGE_LEN;\r
205 #ifndef __WXGTK__ \r
206                 wxMutexGuiEnter();\r
207 #endif /* __WXGTK__ */\r
208         wxLogMessage(wxT("[WARNING] %.*s"), message_len, msg);\r
209 #ifndef __WXGTK__ \r
210     wxMutexGuiLeave();\r
211 #endif /* __WXGTK__ */\r
212 }\r
213 \r
214 /* sample debug callback expecting no client object */\r
215 void mxf_info_callback(const char *msg, void *client_data) {\r
216         int message_len = strlen(msg) - 1;\r
217         if (msg[message_len] != '\n')\r
218                 message_len = MAX_MESSAGE_LEN;\r
219 #ifndef __WXGTK__ \r
220                 wxMutexGuiEnter();\r
221 #endif /* __WXGTK__ */\r
222         wxLogMessage(wxT("[INFO] %.*s"), message_len, msg);\r
223 #ifndef __WXGTK__ \r
224     wxMutexGuiLeave();\r
225 #endif /* __WXGTK__ */\r
226 }\r
227 \r
228 \r
229 /////////////////////////////////////////////////\r
230 /////////////////////////////////////////////////\r
231 \r
232 // load the mxf file format\r
233 bool wxMXFHandler::LoadFile(wxImage *image, wxInputStream& stream, bool verbose, int index)\r
234 {\r
235         opj_dparameters_t parameters;   /* decompression parameters */\r
236         opj_event_mgr_t event_mgr;              /* event manager */\r
237         opj_image_t *opjimage = NULL;\r
238         unsigned char *src = NULL;\r
239     unsigned char *ptr;\r
240         int file_length, j2k_point, j2k_len;\r
241         opj_codestream_info_t cstr_info;  /* Codestream information structure */\r
242         \r
243         // simply display the version of the library\r
244         wxLogMessage(wxT("Version of MXF: %s   "), wxString::FromAscii(LibraryVersion().c_str()));\r
245         //wxLogMessage(wxT("MXF file name: %s"), m_filename.GetFullPath());\r
246 \r
247         // open MXF file\r
248         MXFFilePtr TestFile = new MXFFile;\r
249         if (! TestFile->Open(m_filename.GetFullPath().c_str(), true))\r
250         {\r
251                 wxLogError(wxT("Could not find %s"), m_filename.GetFullPath().c_str());\r
252                 return false;\r
253         } else\r
254                 wxLogMessage(wxT("Found %s"), m_filename.GetFullPath().c_str());\r
255 \r
256         // Get the size\r
257         TestFile->SeekEnd();\r
258         wxLogMessage(wxT("Size is %d bytes"), TestFile->Tell());\r
259         TestFile->Seek(0);\r
260 \r
261         // essence information\r
262         //BuildEssenceInfo(TestFile, EssenceLookup);\r
263 \r
264         // close MXF file\r
265         TestFile->Close();\r
266 \r
267         return false;\r
268         \r
269         // destroy the image\r
270     image->Destroy();\r
271 \r
272         /* handle to a decompressor */\r
273         opj_dinfo_t* dinfo = NULL;      \r
274         opj_cio_t *cio = NULL;\r
275 \r
276         /* configure the event callbacks (not required) */\r
277         memset(&event_mgr, 0, sizeof(opj_event_mgr_t));\r
278         event_mgr.error_handler = mxf_error_callback;\r
279         event_mgr.warning_handler = mxf_warning_callback;\r
280         event_mgr.info_handler = mxf_info_callback;\r
281 \r
282         /* set decoding parameters to default values */\r
283         opj_set_default_decoder_parameters(&parameters);\r
284 \r
285         /* prepare parameters */\r
286         strncpy(parameters.infile, "", sizeof(parameters.infile)-1);\r
287         strncpy(parameters.outfile, "", sizeof(parameters.outfile)-1);\r
288         parameters.decod_format = J2K_CFMT;\r
289         parameters.cod_format = BMP_DFMT;\r
290         if (m_reducefactor)\r
291                 parameters.cp_reduce = m_reducefactor;\r
292         if (m_qualitylayers)\r
293                 parameters.cp_layer = m_qualitylayers;\r
294         /*if (n_components)\r
295                 parameters. = n_components;*/\r
296 \r
297         /* JPWL only */\r
298 #ifdef USE_JPWL\r
299         parameters.jpwl_exp_comps = m_expcomps;\r
300         parameters.jpwl_max_tiles = m_maxtiles;\r
301         parameters.jpwl_correct = m_enablejpwl;\r
302 #endif /* USE_JPWL */\r
303 \r
304         /* get a decoder handle */\r
305         dinfo = opj_create_decompress(CODEC_J2K);\r
306 \r
307         /* find length of the stream */\r
308         stream.SeekI(0, wxFromEnd);\r
309         file_length = (int) stream.TellI();\r
310 \r
311         /* search for the m_framenum codestream position and length  */\r
312         //jp2c_point = searchjp2c(stream, file_length, m_framenum);\r
313         //jp2c_len = searchjp2c(stream, file_length, m_framenum);\r
314         j2k_point = 0;\r
315         j2k_len = 10;\r
316 \r
317         // malloc memory source\r
318     src = (unsigned char *) malloc(j2k_len);\r
319 \r
320         // copy the jp2c\r
321         stream.SeekI(j2k_point, wxFromStart);\r
322         stream.Read(src, j2k_len);\r
323 \r
324         /* catch events using our callbacks and give a local context */\r
325         opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr);\r
326 \r
327         /* setup the decoder decoding parameters using user parameters */\r
328         opj_setup_decoder(dinfo, &parameters);\r
329 \r
330         /* open a byte stream */\r
331         cio = opj_cio_open((opj_common_ptr)dinfo, src, j2k_len);\r
332 \r
333         /* decode the stream and fill the image structure */\r
334         opjimage = opj_decode_with_info(dinfo, cio, &cstr_info);\r
335         if (!opjimage) {\r
336                 wxMutexGuiEnter();\r
337                 wxLogError(wxT("MXF: failed to decode image!"));\r
338                 wxMutexGuiLeave();\r
339                 opj_destroy_decompress(dinfo);\r
340                 opj_cio_close(cio);\r
341                 free(src);\r
342                 return false;\r
343         }\r
344 \r
345         /* close the byte stream */\r
346         opj_cio_close(cio);\r
347 \r
348         /* common rendering method */\r
349 #include "imagjpeg2000.cpp"\r
350 \r
351     wxMutexGuiEnter();\r
352     wxLogMessage(wxT("MXF: image loaded."));\r
353     wxMutexGuiLeave();\r
354 \r
355         /* close openjpeg structs */\r
356         opj_destroy_decompress(dinfo);\r
357         opj_image_destroy(opjimage);\r
358         free(src);\r
359 \r
360         if (!image->Ok())\r
361                 return false;\r
362         else\r
363                 return true;\r
364 \r
365 }\r
366 \r
367 // save the mxf file format\r
368 bool wxMXFHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbose )\r
369 {\r
370     wxLogError(wxT("MXF: Couldn't save movie -> not implemented."));\r
371     return false;\r
372 }\r
373 \r
374 #ifdef __VISUALC__\r
375     #pragma warning(default:4611)\r
376 #endif /* VC++ */\r
377 \r
378 // recognize the MXF JPEG 2000 starting box\r
379 bool wxMXFHandler::DoCanRead( wxInputStream& stream )\r
380 {\r
381     unsigned char hdr[4];\r
382 \r
383     if ( !stream.Read(hdr, WXSIZEOF(hdr)) )\r
384         return false;\r
385 \r
386     return (hdr[0] == 0x06 &&\r
387                         hdr[1] == 0x0E &&\r
388                         hdr[2] == 0x2B &&\r
389                         hdr[3] == 0x34);\r
390 }\r
391 \r
392 //! Build an EssenceInfoMap for the essence in a given file\r
393 /*! \return True if al OK, else false\r
394  */\r
395 bool BuildEssenceInfo(MXFFilePtr &File, EssenceInfoMap &EssenceLookup)\r
396 {\r
397         // Empty any old data\r
398         EssenceLookup.clear();\r
399 \r
400         // Get the master metadata set (or the header if we must)\r
401         PartitionPtr MasterPartition = File->ReadMasterPartition();\r
402         if(!MasterPartition)\r
403         {\r
404                 File->Seek(0);\r
405                 MasterPartition = File->ReadPartition();\r
406                 warning("File %s does not contain a cloased copy of header metadata - using the open copy in the file header\n", File->Name.c_str());\r
407         }\r
408 \r
409         if(!MasterPartition) \r
410         {\r
411                 error("Could not read header metadata from file %s\n", File->Name.c_str());\r
412                 return false;\r
413         }\r
414 \r
415         // Read and parse the metadata\r
416         MasterPartition->ReadMetadata();\r
417         MetadataPtr HMeta = MasterPartition->ParseMetadata();\r
418         \r
419         if(!HMeta) \r
420         {\r
421                 error("Could not read header metadata from file %s\n", File->Name.c_str());\r
422                 return false;\r
423         }\r
424 \r
425         /* Scan the Essence container data sets to get PackageID to BodySID mapping */\r
426         MDObjectPtr ECDSet = HMeta[ContentStorage_UL];\r
427         if(ECDSet) ECDSet = ECDSet->GetLink();\r
428         if(ECDSet) ECDSet = ECDSet[EssenceContainerDataBatch_UL];\r
429         if(!ECDSet)\r
430         {\r
431                 error("Header metadata in file %s does not contain an EssenceContainerData set\n", File->Name.c_str());\r
432                 return false;\r
433         }\r
434 \r
435         MDObject::iterator it = ECDSet->begin();\r
436         while(it != ECDSet->end())\r
437         {\r
438                 MDObjectPtr ThisECDSet = (*it).second->GetLink();\r
439                 MDObjectPtr PackageID;\r
440                 if(ThisECDSet) PackageID = ThisECDSet->Child(LinkedPackageUID_UL);\r
441                 if(PackageID)\r
442                 {\r
443                         EssenceInfo NewEI;\r
444                         NewEI.PackageID = new UMID(PackageID->PutData()->Data);\r
445 \r
446                         // Inset the basic essence info - but not if this is external essence (BodySID == 0)\r
447                         UInt32 BodySID = ThisECDSet->GetUInt(BodySID_UL);\r
448                         if(BodySID) EssenceLookup[BodySID] = NewEI;\r
449                 }\r
450                 it++;\r
451         }\r
452 \r
453         /* Now find the other items for the essence lookup map */\r
454         if(EssenceLookup.size())\r
455         {\r
456                 PackageList::iterator it = HMeta->Packages.begin();\r
457                 while(it != HMeta->Packages.end())\r
458                 {\r
459                         // Only Source Packages are of interest\r
460                         if((*it)->IsA(SourcePackage_UL))\r
461                         {\r
462                                 MDObjectPtr Descriptor = (*it)->Child(Descriptor_UL);\r
463                                 if(Descriptor) Descriptor = Descriptor->GetLink();\r
464 \r
465                                 if(Descriptor)\r
466                                 {\r
467                                         MDObjectPtr PackageID = (*it)->Child(PackageUID_UL);\r
468                                         if(PackageID)\r
469                                         {\r
470                                                 UMIDPtr TheID = new UMID(PackageID->PutData()->Data);\r
471                                                 \r
472                                                 /* Now do a lookup in the essence lookup map (it will need to be done the long way here */\r
473                                                 EssenceInfoMap::iterator EL_it = EssenceLookup.begin();\r
474                                                 while(EL_it != EssenceLookup.end())\r
475                                                 {\r
476                                                         if((*((*EL_it).second.PackageID)) == (*TheID))\r
477                                                         {\r
478                                                                 // If found, set the missing items and stop searching\r
479                                                                 (*EL_it).second.Package = (*it);\r
480                                                                 (*EL_it).second.Descriptor = Descriptor;\r
481                                                                 break;\r
482                                                         }\r
483                                                         EL_it++;\r
484                                                 }\r
485                                         }\r
486                                 }\r
487                         }\r
488 \r
489                         it++;\r
490                 }\r
491         }\r
492 \r
493         return true;\r
494 }\r
495 \r
496 \r
497 #endif   // wxUSE_STREAMS\r
498 \r
499 #endif   // wxUSE_LIBOPENJPEG\r
500 \r
501 #endif // USE_MXF\r
502 \r