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