Add call to parent constructor.
[asdcplib-cth.git] / src / PHDR_Sequence_Parser.cpp
1 /*
2 Copyright (c) 2004-2015, John Hurst
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 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.
15
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.
26 */
27 /*! \file    PHDR_Sequence_Parser.cpp
28     \version $Id: PHDR_Sequence_Parser.cpp,v 1.2 2015/01/22 21:05:58 jhurst Exp $
29     \brief   AS-DCP library, JPEG 2000 codestream essence reader implementation
30 */
31
32 #include <AS_02_PHDR.h>
33 #include <KM_fileio.h>
34 #include <KM_log.h>
35 #include <list>
36 #include <string>
37 #include <algorithm>
38 #include <string.h>
39 #include <assert.h>
40
41 using namespace Kumu;
42 using namespace ASDCP;
43
44
45 //------------------------------------------------------------------------------------------
46   
47 class FileList : public std::list<std::string>
48 {
49   std::string m_DirName;
50
51 public:
52   FileList() {}
53   ~FileList() {}
54
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++ )
58       push_back(*i);
59     return *this;
60   }
61
62   //
63   Result_t InitFromDirectory(const std::string& path)
64   {
65     char next_file[Kumu::MaxFilePath];
66     Kumu::DirScanner Scanner;
67
68     Result_t result = Scanner.Open(path);
69
70     if ( ASDCP_SUCCESS(result) )
71       {
72         m_DirName = path;
73
74         while ( ASDCP_SUCCESS(Scanner.GetNext(next_file)) )
75           {
76             if ( PathGetExtension(next_file) == "j2c" )
77               {
78                 std::string path = PathJoin(m_DirName, next_file);
79
80                 if ( ! Kumu::PathIsDirectory(path) )
81                   push_back(path);
82               }
83           }
84
85         sort();
86       }
87
88     return result;
89   }
90 };
91
92 //------------------------------------------------------------------------------------------
93
94 class AS_02::PHDR::SequenceParser::h__SequenceParser
95 {
96   ui32_t             m_FramesRead;
97   Rational           m_PictureRate;
98   FileList           m_FileList;
99   FileList::iterator m_CurrentFile;
100   ASDCP::JP2K::CodestreamParser   m_Parser;
101   bool               m_Pedantic;
102
103   Result_t OpenRead();
104
105   ASDCP_NO_COPY_CONSTRUCT(h__SequenceParser);
106
107 public:
108   ASDCP::JP2K::PictureDescriptor  m_PDesc;
109
110   h__SequenceParser() : m_FramesRead(0), m_Pedantic(false)
111   {
112     memset(&m_PDesc, 0, sizeof(m_PDesc));
113     m_PDesc.EditRate = Rational(24,1); 
114   }
115
116   ~h__SequenceParser()
117   {
118     Close();
119   }
120
121   Result_t OpenRead(const std::string& filename, bool pedantic);
122   Result_t OpenRead(const std::list<std::string>& file_list, bool pedantic);
123   void     Close() {}
124
125   Result_t Reset()
126   {
127     m_FramesRead = 0;
128     m_CurrentFile = m_FileList.begin();
129     return RESULT_OK;
130   }
131
132   Result_t ReadFrame(FrameBuffer&);
133 };
134
135
136 //
137 ASDCP::Result_t
138 AS_02::PHDR::SequenceParser::h__SequenceParser::OpenRead()
139 {
140   if ( m_FileList.empty() )
141     return RESULT_ENDOFFILE;
142
143   m_CurrentFile = m_FileList.begin();
144   ASDCP::JP2K::CodestreamParser Parser;
145   AS_02::PHDR::FrameBuffer TmpBuffer;
146
147   Kumu::fsize_t file_size = Kumu::FileSize(*m_CurrentFile);
148
149   if ( file_size == 0 )
150     return RESULT_NOT_FOUND;
151
152   assert(file_size <= 0xFFFFFFFFL);
153   Result_t result = TmpBuffer.Capacity((ui32_t) file_size);
154
155   if ( ASDCP_SUCCESS(result) )
156     result = Parser.OpenReadFrame(*m_CurrentFile, TmpBuffer);
157       
158   if ( ASDCP_SUCCESS(result) )
159     result = Parser.FillPictureDescriptor(m_PDesc);
160
161   // how big is it?
162   if ( ASDCP_SUCCESS(result) )
163     m_PDesc.ContainerDuration = m_FileList.size();
164
165   return result;
166 }
167
168 //
169 ASDCP::Result_t
170 AS_02::PHDR::SequenceParser::h__SequenceParser::OpenRead(const std::string& filename, bool pedantic)
171 {
172   m_Pedantic = pedantic;
173
174   Result_t result = m_FileList.InitFromDirectory(filename);
175
176   if ( ASDCP_SUCCESS(result) )
177     result = OpenRead();
178
179   return result;
180 }
181
182
183 //
184 ASDCP::Result_t
185 AS_02::PHDR::SequenceParser::h__SequenceParser::OpenRead(const std::list<std::string>& file_list, bool pedantic)
186 {
187   m_Pedantic = pedantic;
188   m_FileList = file_list;
189   return OpenRead();
190 }
191
192
193 //
194 bool
195 operator==(const ASDCP::JP2K::ImageComponent_t& lhs, const ASDCP::JP2K::ImageComponent_t& rhs)
196 {
197   if ( lhs.Ssize != rhs.Ssize ) return false;
198   if ( lhs.XRsize != rhs.XRsize ) return false;
199   if ( lhs.YRsize != rhs.YRsize ) return false;
200   return true;
201 }
202
203 //
204 bool
205 operator==(const ASDCP::JP2K::QuantizationDefault_t& lhs, const ASDCP::JP2K::QuantizationDefault_t& rhs)
206 {
207   if ( lhs.Sqcd != rhs.Sqcd ) return false;
208   if ( lhs.SPqcdLength != rhs.SPqcdLength ) return false;
209   
210   for ( ui32_t i = 0; i < JP2K::MaxDefaults; i++ )
211     {
212       if ( lhs.SPqcd[i] != rhs.SPqcd[i]  )
213         return false;
214     }
215
216   return true;
217 }
218
219 //
220 bool
221 operator==(const ASDCP::JP2K::CodingStyleDefault_t& lhs, const ASDCP::JP2K::CodingStyleDefault_t& rhs)
222 {
223   if ( lhs.Scod != rhs.Scod ) return false;
224
225   // SGcod
226   if ( lhs.SGcod.ProgressionOrder != rhs.SGcod.ProgressionOrder ) return false;
227   if ( lhs.SGcod.MultiCompTransform != rhs.SGcod.MultiCompTransform ) return false;
228
229   for ( ui32_t i = 0; i < sizeof(ui16_t); i++ )
230     {
231       if ( lhs.SGcod.NumberOfLayers[i] != lhs.SGcod.NumberOfLayers[i]  )
232         return false;
233     }
234
235   // SPcod
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;
241   
242   for ( ui32_t i = 0; i < JP2K::MaxPrecincts; i++ )
243     {
244       if ( lhs.SPcod.PrecinctSize[i] != rhs.SPcod.PrecinctSize[i]  )
245         return false;
246     }
247
248   return true;
249 }
250
251 //
252 bool
253 operator==(const ASDCP::JP2K::PictureDescriptor& lhs, const ASDCP::JP2K::PictureDescriptor& rhs)
254 {
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;
273   
274   for ( ui32_t i = 0; i < JP2K::MaxComponents; i++ )
275     {
276       if ( ! ( lhs.ImageComponents[i] == rhs.ImageComponents[i] ) )
277         return false;
278     }
279
280   return true;
281 }
282
283 //
284 ASDCP::Result_t
285 AS_02::PHDR::SequenceParser::h__SequenceParser::ReadFrame(FrameBuffer& FB)
286 {
287   if ( m_CurrentFile == m_FileList.end() )
288     return RESULT_ENDOFFILE;
289
290   // open the file
291   Result_t result = m_Parser.OpenReadFrame(*m_CurrentFile, FB);
292   std::string metadata_path = PathJoin(PathDirname(*m_CurrentFile), PathSetExtension(*m_CurrentFile, "xml"));
293
294   if ( KM_SUCCESS(result) )
295     {
296       result = ReadFileIntoString(metadata_path, FB.OpaqueMetadata);
297
298       if ( KM_FAILURE(result) )
299         {
300           DefaultLogSink().Error("%s: %s\n", metadata_path.c_str(), result.Label());
301         }
302     }
303   else
304     {
305       DefaultLogSink().Error("%s: %s\n", m_CurrentFile->c_str(), result.Label());
306     }
307
308   if ( KM_SUCCESS(result) && m_Pedantic )
309     {
310       ASDCP::JP2K::PictureDescriptor PDesc;
311       result = m_Parser.FillPictureDescriptor(PDesc);
312
313       if ( KM_SUCCESS(result) && ! ( m_PDesc == PDesc ) )
314         {
315           Kumu::DefaultLogSink().Error("JPEG-2000 codestream parameters do not match at frame %d\n", m_FramesRead + 1);
316           result = RESULT_RAW_FORMAT;
317         }
318     }
319
320   if ( KM_SUCCESS(result) )
321     {
322       FB.FrameNumber(m_FramesRead++);
323       m_CurrentFile++;
324     }
325
326   return result;
327 }
328
329
330 //------------------------------------------------------------------------------------------
331
332 AS_02::PHDR::SequenceParser::SequenceParser()
333 {
334 }
335
336 AS_02::PHDR::SequenceParser::~SequenceParser()
337 {
338 }
339
340 // Opens the stream for reading, parses enough data to provide a complete
341 // set of stream metadata for the MXFWriter below.
342 ASDCP::Result_t
343 AS_02::PHDR::SequenceParser::OpenRead(const std::string& filename, bool pedantic) const
344 {
345   const_cast<AS_02::PHDR::SequenceParser*>(this)->m_Parser = new h__SequenceParser;
346
347   Result_t result = m_Parser->OpenRead(filename, pedantic);
348
349   if ( ASDCP_FAILURE(result) )
350     const_cast<AS_02::PHDR::SequenceParser*>(this)->m_Parser.release();
351
352   return result;
353 }
354
355 //
356 Result_t
357 AS_02::PHDR::SequenceParser::OpenRead(const std::list<std::string>& file_list, bool pedantic) const
358 {
359   const_cast<AS_02::PHDR::SequenceParser*>(this)->m_Parser = new h__SequenceParser;
360
361   Result_t result = m_Parser->OpenRead(file_list, pedantic);
362
363   if ( ASDCP_FAILURE(result) )
364     const_cast<AS_02::PHDR::SequenceParser*>(this)->m_Parser.release();
365
366   return result;
367 }
368
369
370 // Rewinds the stream to the beginning.
371 ASDCP::Result_t
372 AS_02::PHDR::SequenceParser::Reset() const
373 {
374   if ( m_Parser.empty() )
375     return RESULT_INIT;
376
377   return m_Parser->Reset();
378 }
379
380 // Places a frame of data in the frame buffer. Fails if the buffer is too small
381 // or the stream is empty.
382 ASDCP::Result_t
383 AS_02::PHDR::SequenceParser::ReadFrame(AS_02::PHDR::FrameBuffer& FB) const
384 {
385   if ( m_Parser.empty() )
386     return RESULT_INIT;
387
388   return m_Parser->ReadFrame(FB);
389 }
390
391 //
392 ASDCP::Result_t
393 AS_02::PHDR::SequenceParser::FillPictureDescriptor(ASDCP::JP2K::PictureDescriptor& PDesc) const
394 {
395   if ( m_Parser.empty() )
396     return RESULT_INIT;
397
398   PDesc = m_Parser->m_PDesc;
399   return RESULT_OK;
400 }
401
402
403 //
404 // end PHDR_Sequence_Parser.cpp
405 //