2 * Copyright (c) 2007, Digital Signal Processing Laboratory, Universit� degli studi di Perugia (UPG), Italy
\r
3 * All rights reserved.
\r
5 * Redistribution and use in source and binary forms, with or without
\r
6 * modification, are permitted provided that the following conditions
\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
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
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
37 #include "mxflib/mxflib.h"
\r
38 using namespace mxflib;
\r
42 //! Structure holding information about the essence in each body stream
\r
47 MDObjectPtr Descriptor;
\r
49 //! Map of EssenceInfo structures indexed by BodySID
\r
50 typedef std::map<UInt32, EssenceInfo> EssenceInfoMap;
\r
52 //! The map of essence info for this file
\r
53 EssenceInfoMap EssenceLookup;
\r
56 //! Build an EssenceInfoMap for the essence in a given file
\r
57 /*! \return True if al OK, else false
\r
59 bool BuildEssenceInfo(MXFFilePtr &File, EssenceInfoMap &EssenceLookup);
\r
61 // For compilers that support precompilation, includes "wx.h".
\r
62 #include "wx/wxprec.h"
\r
68 #if wxUSE_IMAGE && wxUSE_LIBOPENJPEG
\r
70 #include "imagmxf.h"
\r
75 #include "wx/intl.h"
\r
76 #include "wx/bitmap.h"
\r
77 #include "wx/module.h"
\r
81 #include "libopenjpeg/openjpeg.h"
\r
84 #include "wx/filefn.h"
\r
85 #include "wx/wfstream.h"
\r
87 // ----------------------------------------------------------------------------
\r
89 // ----------------------------------------------------------------------------
\r
92 //-----------------------------------------------------------------------------
\r
94 //-----------------------------------------------------------------------------
\r
96 IMPLEMENT_DYNAMIC_CLASS(wxMXFHandler,wxImageHandler)
\r
100 #include <stdarg.h>
\r
101 #define MAX_MESSAGE_LEN 200
\r
103 //------------- MXF Manager
\r
105 // Debug and error messages
\r
107 //! Display a warning message
\r
108 void mxflib::warning(const char *Fmt, ...)
\r
110 char msg[MAX_MESSAGE_LEN];
\r
113 va_start(args, Fmt);
\r
114 _vsnprintf(msg, MAX_MESSAGE_LEN, Fmt, args);
\r
117 int message_len = strlen(msg) - 1;
\r
118 if (msg[message_len] != '\n')
\r
119 message_len = MAX_MESSAGE_LEN;
\r
122 #endif /* __WXGTK__ */
\r
123 wxLogMessage(wxT("[WARNING_MXF] %.*s"), message_len, msg);
\r
126 #endif /* __WXGTK__ */
\r
129 //! Display an error message
\r
130 void mxflib::error(const char *Fmt, ...)
\r
132 char msg[MAX_MESSAGE_LEN];
\r
135 va_start(args, Fmt);
\r
136 _vsnprintf(msg, MAX_MESSAGE_LEN, Fmt, args);
\r
139 int message_len = strlen(msg) - 1;
\r
140 if (msg[message_len] != '\n')
\r
141 message_len = MAX_MESSAGE_LEN;
\r
144 #endif /* __WXGTK__ */
\r
145 wxLogMessage(wxT("[ERROR_MXF] %.*s"), message_len, msg);
\r
148 #endif /* __WXGTK__ */
\r
151 //! Display an error message
\r
152 void mxflib::debug(const char *Fmt, ...)
\r
154 char msg[MAX_MESSAGE_LEN];
\r
157 va_start(args, Fmt);
\r
158 _vsnprintf(msg, MAX_MESSAGE_LEN, Fmt, args);
\r
161 int message_len = strlen(msg) - 1;
\r
162 if (msg[message_len] != '\n')
\r
163 message_len = MAX_MESSAGE_LEN;
\r
166 #endif /* __WXGTK__ */
\r
167 wxLogMessage(wxT("[DEBUG_MXF] %.*s"), message_len, msg);
\r
170 #endif /* __WXGTK__ */
\r
175 //------------- JPEG 2000 Data Source Manager
\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
193 #endif /* __WXGTK__ */
\r
194 wxLogMessage(wxT("[ERROR] %.*s"), message_len, msg);
\r
197 #endif /* __WXGTK__ */
\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
207 #endif /* __WXGTK__ */
\r
208 wxLogMessage(wxT("[WARNING] %.*s"), message_len, msg);
\r
211 #endif /* __WXGTK__ */
\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
221 #endif /* __WXGTK__ */
\r
222 wxLogMessage(wxT("[INFO] %.*s"), message_len, msg);
\r
225 #endif /* __WXGTK__ */
\r
229 /////////////////////////////////////////////////
\r
230 /////////////////////////////////////////////////
\r
232 // load the mxf file format
\r
233 bool wxMXFHandler::LoadFile(wxImage *image, wxInputStream& stream, bool verbose, int index)
\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
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
248 MXFFilePtr TestFile = new MXFFile;
\r
249 if (! TestFile->Open(m_filename.GetFullPath().c_str(), true))
\r
251 wxLogError(wxT("Could not find %s"), m_filename.GetFullPath().c_str());
\r
254 wxLogMessage(wxT("Found %s"), m_filename.GetFullPath().c_str());
\r
257 TestFile->SeekEnd();
\r
258 wxLogMessage(wxT("Size is %d bytes"), TestFile->Tell());
\r
261 // essence information
\r
262 //BuildEssenceInfo(TestFile, EssenceLookup);
\r
269 // destroy the image
\r
272 /* handle to a decompressor */
\r
273 opj_dinfo_t* dinfo = NULL;
\r
274 opj_cio_t *cio = NULL;
\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
282 /* set decoding parameters to default values */
\r
283 opj_set_default_decoder_parameters(¶meters);
\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
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
304 /* get a decoder handle */
\r
305 dinfo = opj_create_decompress(CODEC_J2K);
\r
307 /* find length of the stream */
\r
308 stream.SeekI(0, wxFromEnd);
\r
309 file_length = (int) stream.TellI();
\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
317 // malloc memory source
\r
318 src = (unsigned char *) malloc(j2k_len);
\r
321 stream.SeekI(j2k_point, wxFromStart);
\r
322 stream.Read(src, j2k_len);
\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
327 /* setup the decoder decoding parameters using user parameters */
\r
328 opj_setup_decoder(dinfo, ¶meters);
\r
330 /* open a byte stream */
\r
331 cio = opj_cio_open((opj_common_ptr)dinfo, src, j2k_len);
\r
333 /* decode the stream and fill the image structure */
\r
334 opjimage = opj_decode_with_info(dinfo, cio, &cstr_info);
\r
337 wxLogError(wxT("MXF: failed to decode image!"));
\r
339 opj_destroy_decompress(dinfo);
\r
340 opj_cio_close(cio);
\r
345 /* close the byte stream */
\r
346 opj_cio_close(cio);
\r
348 /* common rendering method */
\r
349 #include "imagjpeg2000.cpp"
\r
352 wxLogMessage(wxT("MXF: image loaded."));
\r
355 /* close openjpeg structs */
\r
356 opj_destroy_decompress(dinfo);
\r
357 opj_image_destroy(opjimage);
\r
367 // save the mxf file format
\r
368 bool wxMXFHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbose )
\r
370 wxLogError(wxT("MXF: Couldn't save movie -> not implemented."));
\r
375 #pragma warning(default:4611)
\r
378 // recognize the MXF JPEG 2000 starting box
\r
379 bool wxMXFHandler::DoCanRead( wxInputStream& stream )
\r
381 unsigned char hdr[4];
\r
383 if ( !stream.Read(hdr, WXSIZEOF(hdr)) )
\r
386 return (hdr[0] == 0x06 &&
\r
392 //! Build an EssenceInfoMap for the essence in a given file
\r
393 /*! \return True if al OK, else false
\r
395 bool BuildEssenceInfo(MXFFilePtr &File, EssenceInfoMap &EssenceLookup)
\r
397 // Empty any old data
\r
398 EssenceLookup.clear();
\r
400 // Get the master metadata set (or the header if we must)
\r
401 PartitionPtr MasterPartition = File->ReadMasterPartition();
\r
402 if(!MasterPartition)
\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
409 if(!MasterPartition)
\r
411 error("Could not read header metadata from file %s\n", File->Name.c_str());
\r
415 // Read and parse the metadata
\r
416 MasterPartition->ReadMetadata();
\r
417 MetadataPtr HMeta = MasterPartition->ParseMetadata();
\r
421 error("Could not read header metadata from file %s\n", File->Name.c_str());
\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
431 error("Header metadata in file %s does not contain an EssenceContainerData set\n", File->Name.c_str());
\r
435 MDObject::iterator it = ECDSet->begin();
\r
436 while(it != ECDSet->end())
\r
438 MDObjectPtr ThisECDSet = (*it).second->GetLink();
\r
439 MDObjectPtr PackageID;
\r
440 if(ThisECDSet) PackageID = ThisECDSet->Child(LinkedPackageUID_UL);
\r
444 NewEI.PackageID = new UMID(PackageID->PutData()->Data);
\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
453 /* Now find the other items for the essence lookup map */
\r
454 if(EssenceLookup.size())
\r
456 PackageList::iterator it = HMeta->Packages.begin();
\r
457 while(it != HMeta->Packages.end())
\r
459 // Only Source Packages are of interest
\r
460 if((*it)->IsA(SourcePackage_UL))
\r
462 MDObjectPtr Descriptor = (*it)->Child(Descriptor_UL);
\r
463 if(Descriptor) Descriptor = Descriptor->GetLink();
\r
467 MDObjectPtr PackageID = (*it)->Child(PackageUID_UL);
\r
470 UMIDPtr TheID = new UMID(PackageID->PutData()->Data);
\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
476 if((*((*EL_it).second.PackageID)) == (*TheID))
\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
497 #endif // wxUSE_STREAMS
\r
499 #endif // wxUSE_LIBOPENJPEG
\r