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