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