2 Copyright (c) 2004-2009, John Hurst
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.
13 3. The name of the author may not be used to endorse or promote products
14 derived from this software without specific prior written permission.
16 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 /*! \file JP2K_Sequence_Parser.cpp
29 \brief AS-DCP library, JPEG 2000 codestream essence reader implementation
33 #include <KM_fileio.h>
41 using namespace ASDCP;
44 //------------------------------------------------------------------------------------------
46 class FileList : public std::list<std::string>
48 std::string m_DirName;
54 const FileList& operator=(const std::list<std::string>& pathlist) {
55 std::list<std::string>::const_iterator i;
56 for ( i = pathlist.begin(); i != pathlist.end(); i++ )
62 Result_t InitFromDirectory(const char* path)
64 char next_file[Kumu::MaxFilePath];
65 Kumu::DirScanner Scanner;
67 Result_t result = Scanner.Open(path);
69 if ( ASDCP_SUCCESS(result) )
73 while ( ASDCP_SUCCESS(Scanner.GetNext(next_file)) )
75 if ( next_file[0] == '.' ) // no hidden files or internal links
78 std::string Str(m_DirName);
91 //------------------------------------------------------------------------------------------
93 class ASDCP::JP2K::SequenceParser::h__SequenceParser
96 Rational m_PictureRate;
98 FileList::iterator m_CurrentFile;
99 CodestreamParser m_Parser;
104 ASDCP_NO_COPY_CONSTRUCT(h__SequenceParser);
107 PictureDescriptor m_PDesc;
109 h__SequenceParser() : m_FramesRead(0), m_Pedantic(false)
111 memset(&m_PDesc, 0, sizeof(m_PDesc));
112 m_PDesc.EditRate = Rational(24,1);
120 Result_t OpenRead(const char* filename, bool pedantic);
121 Result_t OpenRead(const std::list<std::string>& file_list, bool pedantic);
127 m_CurrentFile = m_FileList.begin();
131 Result_t ReadFrame(FrameBuffer&);
137 ASDCP::JP2K::SequenceParser::h__SequenceParser::OpenRead()
139 if ( m_FileList.empty() )
140 return RESULT_ENDOFFILE;
142 m_CurrentFile = m_FileList.begin();
143 CodestreamParser Parser;
144 FrameBuffer TmpBuffer;
146 Kumu::fsize_t file_size = Kumu::FileSize((*m_CurrentFile).c_str());
148 if ( file_size == 0 )
149 return RESULT_NOT_FOUND;
151 assert(file_size <= 0xFFFFFFFFL);
152 Result_t result = TmpBuffer.Capacity((ui32_t) file_size);
154 if ( ASDCP_SUCCESS(result) )
155 result = Parser.OpenReadFrame((*m_CurrentFile).c_str(), TmpBuffer);
157 if ( ASDCP_SUCCESS(result) )
158 result = Parser.FillPictureDescriptor(m_PDesc);
161 if ( ASDCP_SUCCESS(result) )
162 m_PDesc.ContainerDuration = m_FileList.size();
169 ASDCP::JP2K::SequenceParser::h__SequenceParser::OpenRead(const char* filename, bool pedantic)
171 ASDCP_TEST_NULL_STR(filename);
172 m_Pedantic = pedantic;
174 Result_t result = m_FileList.InitFromDirectory(filename);
176 if ( ASDCP_SUCCESS(result) )
185 ASDCP::JP2K::SequenceParser::h__SequenceParser::OpenRead(const std::list<std::string>& file_list, bool pedantic)
187 m_Pedantic = pedantic;
188 m_FileList = file_list;
195 operator==(const ASDCP::JP2K::ImageComponent_t& lhs, const ASDCP::JP2K::ImageComponent_t& rhs)
197 if ( lhs.Ssize != rhs.Ssize ) return false;
198 if ( lhs.XRsize != rhs.XRsize ) return false;
199 if ( lhs.YRsize != rhs.YRsize ) return false;
205 operator==(const ASDCP::JP2K::QuantizationDefault_t& lhs, const ASDCP::JP2K::QuantizationDefault_t& rhs)
207 if ( lhs.Sqcd != rhs.Sqcd ) return false;
208 if ( lhs.SPqcdLength != rhs.SPqcdLength ) return false;
210 for ( ui32_t i = 0; i < JP2K::MaxDefaults; i++ )
212 if ( lhs.SPqcd[i] != rhs.SPqcd[i] )
221 operator==(const ASDCP::JP2K::CodingStyleDefault_t& lhs, const ASDCP::JP2K::CodingStyleDefault_t& rhs)
223 if ( lhs.Scod != rhs.Scod ) return false;
226 if ( lhs.SGcod.ProgressionOrder != rhs.SGcod.ProgressionOrder ) return false;
227 if ( lhs.SGcod.MultiCompTransform != rhs.SGcod.MultiCompTransform ) return false;
229 for ( ui32_t i = 0; i < sizeof(ui16_t); i++ )
231 if ( lhs.SGcod.NumberOfLayers[i] != lhs.SGcod.NumberOfLayers[i] )
236 if ( lhs.SPcod.DecompositionLevels != rhs.SPcod.DecompositionLevels ) return false;
237 if ( lhs.SPcod.CodeblockWidth != rhs.SPcod.CodeblockWidth ) return false;
238 if ( lhs.SPcod.CodeblockHeight != rhs.SPcod.CodeblockHeight ) return false;
239 if ( lhs.SPcod.CodeblockStyle != rhs.SPcod.CodeblockStyle ) return false;
240 if ( lhs.SPcod.Transformation != rhs.SPcod.Transformation ) return false;
242 for ( ui32_t i = 0; i < JP2K::MaxPrecincts; i++ )
244 if ( lhs.SPcod.PrecinctSize[i] != rhs.SPcod.PrecinctSize[i] )
253 operator==(const ASDCP::JP2K::PictureDescriptor& lhs, const ASDCP::JP2K::PictureDescriptor& rhs)
255 if ( lhs.EditRate != rhs.EditRate ) return false;
256 // if ( lhs.ContainerDuration != rhs.ContainerDuration ) return false;
257 if ( lhs.SampleRate != rhs.SampleRate ) return false;
258 if ( lhs.StoredWidth != rhs.StoredWidth ) return false;
259 if ( lhs.StoredHeight != rhs.StoredHeight ) return false;
260 if ( lhs.AspectRatio != rhs.AspectRatio ) return false;
261 if ( lhs.Rsize != rhs.Rsize ) return false;
262 if ( lhs.Xsize != rhs.Xsize ) return false;
263 if ( lhs.Ysize != rhs.Ysize ) return false;
264 if ( lhs.XOsize != rhs.XOsize ) return false;
265 if ( lhs.YOsize != rhs.YOsize ) return false;
266 if ( lhs.XTsize != rhs.XTsize ) return false;
267 if ( lhs.YTsize != rhs.YTsize ) return false;
268 if ( lhs.XTOsize != rhs.XTOsize ) return false;
269 if ( lhs.YTOsize != rhs.YTOsize ) return false;
270 if ( lhs.Csize != rhs.Csize ) return false;
271 if ( ! ( lhs.CodingStyleDefault == rhs.CodingStyleDefault ) ) return false;
272 if ( ! ( lhs.QuantizationDefault == rhs.QuantizationDefault ) ) return false;
274 for ( ui32_t i = 0; i < JP2K::MaxComponents; i++ )
276 if ( ! ( lhs.ImageComponents[i] == rhs.ImageComponents[i] ) )
285 ASDCP::JP2K::SequenceParser::h__SequenceParser::ReadFrame(FrameBuffer& FB)
287 if ( m_CurrentFile == m_FileList.end() )
288 return RESULT_ENDOFFILE;
291 Result_t result = m_Parser.OpenReadFrame((*m_CurrentFile).c_str(), FB);
293 if ( ASDCP_SUCCESS(result) && m_Pedantic )
295 PictureDescriptor PDesc;
296 result = m_Parser.FillPictureDescriptor(PDesc);
298 if ( ASDCP_SUCCESS(result) && ! ( m_PDesc == PDesc ) )
300 Kumu::DefaultLogSink().Error("JPEG-2000 codestream parameters do not match at frame %d\n", m_FramesRead + 1);
301 result = RESULT_RAW_FORMAT;
305 if ( ASDCP_SUCCESS(result) )
307 FB.FrameNumber(m_FramesRead++);
315 //------------------------------------------------------------------------------------------
317 ASDCP::JP2K::SequenceParser::SequenceParser()
321 ASDCP::JP2K::SequenceParser::~SequenceParser()
325 // Opens the stream for reading, parses enough data to provide a complete
326 // set of stream metadata for the MXFWriter below.
328 ASDCP::JP2K::SequenceParser::OpenRead(const char* filename, bool pedantic) const
330 const_cast<ASDCP::JP2K::SequenceParser*>(this)->m_Parser = new h__SequenceParser;
332 Result_t result = m_Parser->OpenRead(filename, pedantic);
334 if ( ASDCP_FAILURE(result) )
335 const_cast<ASDCP::JP2K::SequenceParser*>(this)->m_Parser.release();
342 ASDCP::JP2K::SequenceParser::OpenRead(const std::list<std::string>& file_list, bool pedantic) const
344 const_cast<ASDCP::JP2K::SequenceParser*>(this)->m_Parser = new h__SequenceParser;
346 Result_t result = m_Parser->OpenRead(file_list, pedantic);
348 if ( ASDCP_FAILURE(result) )
349 const_cast<ASDCP::JP2K::SequenceParser*>(this)->m_Parser.release();
355 // Rewinds the stream to the beginning.
357 ASDCP::JP2K::SequenceParser::Reset() const
359 if ( m_Parser.empty() )
362 return m_Parser->Reset();
365 // Places a frame of data in the frame buffer. Fails if the buffer is too small
366 // or the stream is empty.
368 ASDCP::JP2K::SequenceParser::ReadFrame(FrameBuffer& FB) const
370 if ( m_Parser.empty() )
373 return m_Parser->ReadFrame(FB);
378 ASDCP::JP2K::SequenceParser::FillPictureDescriptor(PictureDescriptor& PDesc) const
380 if ( m_Parser.empty() )
383 PDesc = m_Parser->m_PDesc;
389 // end JP2K_Sequence_Parser.cpp