2 Copyright (c) 2004-2015, 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 PHDR_Sequence_Parser.cpp
29 \brief AS-DCP library, JPEG 2000 codestream essence reader implementation
32 #include <AS_02_PHDR.h>
33 #include <KM_fileio.h>
42 using namespace ASDCP;
45 //------------------------------------------------------------------------------------------
47 class FileList : public std::list<std::string>
49 std::string m_DirName;
55 const FileList& operator=(const std::list<std::string>& pathlist) {
56 std::list<std::string>::const_iterator i;
57 for ( i = pathlist.begin(); i != pathlist.end(); i++ )
63 Result_t InitFromDirectory(const std::string& path)
65 char next_file[Kumu::MaxFilePath];
66 Kumu::DirScanner Scanner;
68 Result_t result = Scanner.Open(path);
70 if ( ASDCP_SUCCESS(result) )
74 while ( ASDCP_SUCCESS(Scanner.GetNext(next_file)) )
76 if ( PathGetExtension(next_file) == "j2c" )
78 std::string path = PathJoin(m_DirName, next_file);
80 if ( ! Kumu::PathIsDirectory(path) )
92 //------------------------------------------------------------------------------------------
94 class AS_02::PHDR::SequenceParser::h__SequenceParser
97 Rational m_PictureRate;
99 FileList::iterator m_CurrentFile;
100 ASDCP::JP2K::CodestreamParser m_Parser;
105 ASDCP_NO_COPY_CONSTRUCT(h__SequenceParser);
108 ASDCP::JP2K::PictureDescriptor m_PDesc;
110 h__SequenceParser() : m_FramesRead(0), m_Pedantic(false)
112 memset(&m_PDesc, 0, sizeof(m_PDesc));
113 m_PDesc.EditRate = Rational(24,1);
121 Result_t OpenRead(const std::string& filename, bool pedantic);
122 Result_t OpenRead(const std::list<std::string>& file_list, bool pedantic);
128 m_CurrentFile = m_FileList.begin();
132 Result_t ReadFrame(FrameBuffer&);
138 AS_02::PHDR::SequenceParser::h__SequenceParser::OpenRead()
140 if ( m_FileList.empty() )
141 return RESULT_ENDOFFILE;
143 m_CurrentFile = m_FileList.begin();
144 ASDCP::JP2K::CodestreamParser Parser;
145 AS_02::PHDR::FrameBuffer TmpBuffer;
147 Kumu::fsize_t file_size = Kumu::FileSize(*m_CurrentFile);
149 if ( file_size == 0 )
150 return RESULT_NOT_FOUND;
152 assert(file_size <= 0xFFFFFFFFL);
153 Result_t result = TmpBuffer.Capacity((ui32_t) file_size);
155 if ( ASDCP_SUCCESS(result) )
156 result = Parser.OpenReadFrame(*m_CurrentFile, TmpBuffer);
158 if ( ASDCP_SUCCESS(result) )
159 result = Parser.FillPictureDescriptor(m_PDesc);
162 if ( ASDCP_SUCCESS(result) )
163 m_PDesc.ContainerDuration = m_FileList.size();
170 AS_02::PHDR::SequenceParser::h__SequenceParser::OpenRead(const std::string& filename, bool pedantic)
172 m_Pedantic = pedantic;
174 Result_t result = m_FileList.InitFromDirectory(filename);
176 if ( ASDCP_SUCCESS(result) )
185 AS_02::PHDR::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 AS_02::PHDR::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, FB);
292 std::string metadata_path = PathJoin(PathDirname(*m_CurrentFile), PathSetExtension(*m_CurrentFile, "xml"));
294 if ( KM_SUCCESS(result) )
296 result = ReadFileIntoString(metadata_path, FB.OpaqueMetadata);
298 if ( KM_FAILURE(result) )
300 DefaultLogSink().Error("%s: %s\n", metadata_path.c_str(), result.Label());
305 DefaultLogSink().Error("%s: %s\n", m_CurrentFile->c_str(), result.Label());
308 if ( KM_SUCCESS(result) && m_Pedantic )
310 ASDCP::JP2K::PictureDescriptor PDesc;
311 result = m_Parser.FillPictureDescriptor(PDesc);
313 if ( KM_SUCCESS(result) && ! ( m_PDesc == PDesc ) )
315 Kumu::DefaultLogSink().Error("JPEG-2000 codestream parameters do not match at frame %d\n", m_FramesRead + 1);
316 result = RESULT_RAW_FORMAT;
320 if ( KM_SUCCESS(result) )
322 FB.FrameNumber(m_FramesRead++);
330 //------------------------------------------------------------------------------------------
332 AS_02::PHDR::SequenceParser::SequenceParser()
336 AS_02::PHDR::SequenceParser::~SequenceParser()
340 // Opens the stream for reading, parses enough data to provide a complete
341 // set of stream metadata for the MXFWriter below.
343 AS_02::PHDR::SequenceParser::OpenRead(const std::string& filename, bool pedantic) const
345 const_cast<AS_02::PHDR::SequenceParser*>(this)->m_Parser = new h__SequenceParser;
347 Result_t result = m_Parser->OpenRead(filename, pedantic);
349 if ( ASDCP_FAILURE(result) )
350 const_cast<AS_02::PHDR::SequenceParser*>(this)->m_Parser.release();
357 AS_02::PHDR::SequenceParser::OpenRead(const std::list<std::string>& file_list, bool pedantic) const
359 const_cast<AS_02::PHDR::SequenceParser*>(this)->m_Parser = new h__SequenceParser;
361 Result_t result = m_Parser->OpenRead(file_list, pedantic);
363 if ( ASDCP_FAILURE(result) )
364 const_cast<AS_02::PHDR::SequenceParser*>(this)->m_Parser.release();
370 // Rewinds the stream to the beginning.
372 AS_02::PHDR::SequenceParser::Reset() const
374 if ( m_Parser.empty() )
377 return m_Parser->Reset();
380 // Places a frame of data in the frame buffer. Fails if the buffer is too small
381 // or the stream is empty.
383 AS_02::PHDR::SequenceParser::ReadFrame(AS_02::PHDR::FrameBuffer& FB) const
385 if ( m_Parser.empty() )
388 return m_Parser->ReadFrame(FB);
393 AS_02::PHDR::SequenceParser::FillPictureDescriptor(ASDCP::JP2K::PictureDescriptor& PDesc) const
395 if ( m_Parser.empty() )
398 PDesc = m_Parser->m_PDesc;
404 // end PHDR_Sequence_Parser.cpp