Merge pull request #20 from cinecert/htj2c
[asdcplib.git] / 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$
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 std::string& 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 std::string& 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 std::string& filename, bool pedantic)
172 {
173   m_Pedantic = pedantic;
174
175   Result_t result = m_FileList.InitFromDirectory(filename);
176
177   if ( ASDCP_SUCCESS(result) )
178     result = OpenRead();
179
180   return result;
181 }
182
183
184 //
185 ASDCP::Result_t
186 ASDCP::JP2K::SequenceParser::h__SequenceParser::OpenRead(const std::list<std::string>& file_list, bool pedantic)
187 {
188   m_Pedantic = pedantic;
189   m_FileList = file_list;
190   return OpenRead();
191 }
192
193
194 //
195 bool
196 operator==(const ASDCP::JP2K::ImageComponent_t& lhs, const ASDCP::JP2K::ImageComponent_t& rhs)
197 {
198   if ( lhs.Ssize != rhs.Ssize ) return false;
199   if ( lhs.XRsize != rhs.XRsize ) return false;
200   if ( lhs.YRsize != rhs.YRsize ) return false;
201   return true;
202 }
203
204 //
205 bool
206 operator==(const ASDCP::JP2K::QuantizationDefault_t& lhs, const ASDCP::JP2K::QuantizationDefault_t& rhs)
207 {
208   if ( lhs.Sqcd != rhs.Sqcd ) return false;
209   if ( lhs.SPqcdLength != rhs.SPqcdLength ) return false;
210   
211   for ( ui32_t i = 0; i < JP2K::MaxDefaults; i++ )
212     {
213       if ( lhs.SPqcd[i] != rhs.SPqcd[i]  )
214         return false;
215     }
216
217   return true;
218 }
219
220 //
221 bool
222 operator==(const ASDCP::JP2K::CodingStyleDefault_t& lhs, const ASDCP::JP2K::CodingStyleDefault_t& rhs)
223 {
224   if ( lhs.Scod != rhs.Scod ) return false;
225
226   // SGcod
227   if ( lhs.SGcod.ProgressionOrder != rhs.SGcod.ProgressionOrder ) return false;
228   if ( lhs.SGcod.MultiCompTransform != rhs.SGcod.MultiCompTransform ) return false;
229
230   for ( ui32_t i = 0; i < sizeof(ui16_t); i++ )
231     {
232       if ( lhs.SGcod.NumberOfLayers[i] != rhs.SGcod.NumberOfLayers[i]  )
233         return false;
234     }
235
236   // SPcod
237   if ( lhs.SPcod.DecompositionLevels != rhs.SPcod.DecompositionLevels ) return false;
238   if ( lhs.SPcod.CodeblockWidth != rhs.SPcod.CodeblockWidth ) return false;
239   if ( lhs.SPcod.CodeblockHeight != rhs.SPcod.CodeblockHeight ) return false;
240   if ( lhs.SPcod.CodeblockStyle != rhs.SPcod.CodeblockStyle ) return false;
241   if ( lhs.SPcod.Transformation != rhs.SPcod.Transformation ) return false;
242   
243   for ( ui32_t i = 0; i < JP2K::MaxPrecincts; i++ )
244     {
245       if ( lhs.SPcod.PrecinctSize[i] != rhs.SPcod.PrecinctSize[i]  )
246         return false;
247     }
248
249   return true;
250 }
251
252 //
253 bool
254 operator==(const ASDCP::JP2K::ExtendedCapabilities_t& lhs, const ASDCP::JP2K::ExtendedCapabilities_t& rhs)
255 {
256         if (lhs.N != rhs.N) return false;
257
258         if (lhs.N != JP2K::NoExtendedCapabilitiesSignaled) {
259
260                 if (lhs.Pcap != rhs.Pcap) return false;
261
262                 for (ui32_t i = 0; i < lhs.N; i++)
263                 {
264                         if (lhs.Ccap[i] != rhs.Ccap[i])
265                                 return false;
266                 }
267
268         }
269
270         return true;
271 }
272
273 //
274 bool
275 operator==(const ASDCP::JP2K::CorrespondingProfile_t& lhs, const ASDCP::JP2K::CorrespondingProfile_t& rhs)
276 {
277         if (lhs.N != rhs.N) return false;
278
279         for (ui32_t i = 0; i < lhs.N; i++)
280         {
281                 if (lhs.Pcpf[i] != rhs.Pcpf[i])
282                         return false;
283         }
284
285         return true;
286 }
287
288 //
289 bool
290 operator==(const ASDCP::JP2K::Profile_t& lhs, const ASDCP::JP2K::Profile_t& rhs)
291 {
292         if (lhs.N != rhs.N) return false;
293
294         for (ui32_t i = 0; i < lhs.N; i++)
295         {
296                 if (lhs.Pprf[i] != rhs.Pprf[i])
297                         return false;
298         }
299
300         return true;
301 }
302
303 //
304 bool
305 operator==(const ASDCP::JP2K::PictureDescriptor& lhs, const ASDCP::JP2K::PictureDescriptor& rhs)
306 {
307   if ( lhs.EditRate != rhs.EditRate ) return false;
308   //  if ( lhs.ContainerDuration != rhs.ContainerDuration ) return false;
309   if ( lhs.SampleRate != rhs.SampleRate ) return false;
310   if ( lhs.StoredWidth != rhs.StoredWidth ) return false;
311   if ( lhs.StoredHeight != rhs.StoredHeight ) return false;
312   if ( lhs.AspectRatio != rhs.AspectRatio ) return false;
313   if ( lhs.Rsize != rhs.Rsize ) return false;
314   if ( lhs.Xsize != rhs.Xsize ) return false;
315   if ( lhs.Ysize != rhs.Ysize ) return false;
316   if ( lhs.XOsize != rhs.XOsize ) return false;
317   if ( lhs.YOsize != rhs.YOsize ) return false;
318   if ( lhs.XTsize != rhs.XTsize ) return false;
319   if ( lhs.YTsize != rhs.YTsize ) return false;
320   if ( lhs.XTOsize != rhs.XTOsize ) return false;
321   if ( lhs.YTOsize != rhs.YTOsize ) return false;
322   if ( lhs.Csize != rhs.Csize ) return false;
323   if ( ! ( lhs.CodingStyleDefault == rhs.CodingStyleDefault ) ) return false;
324   if ( ! ( lhs.QuantizationDefault == rhs.QuantizationDefault ) ) return false;
325   if (!(lhs.Profile == rhs.Profile)) return false;
326   if (!(lhs.CorrespondingProfile == rhs.CorrespondingProfile)) return false;
327   if (!(lhs.ExtendedCapabilities == rhs.ExtendedCapabilities)) return false;
328   
329   for ( ui32_t i = 0; i < JP2K::MaxComponents; i++ )
330     {
331       if ( ! ( lhs.ImageComponents[i] == rhs.ImageComponents[i] ) )
332         return false;
333     }
334
335   return true;
336 }
337
338 //
339 ASDCP::Result_t
340 ASDCP::JP2K::SequenceParser::h__SequenceParser::ReadFrame(FrameBuffer& FB)
341 {
342   if ( m_CurrentFile == m_FileList.end() )
343     return RESULT_ENDOFFILE;
344
345   // open the file
346   Result_t result = m_Parser.OpenReadFrame((*m_CurrentFile).c_str(), FB);
347
348   if ( ASDCP_SUCCESS(result) && m_Pedantic )
349     {
350       PictureDescriptor PDesc;
351       result = m_Parser.FillPictureDescriptor(PDesc);
352
353       if ( ASDCP_SUCCESS(result) && ! ( m_PDesc == PDesc ) )
354         {
355           Kumu::DefaultLogSink().Error("JPEG-2000 codestream parameters do not match at frame %d\n", m_FramesRead + 1);
356           result = RESULT_RAW_FORMAT;
357         }
358     }
359
360   if ( ASDCP_SUCCESS(result) )
361     {
362       FB.FrameNumber(m_FramesRead++);
363       m_CurrentFile++;
364     }
365
366   return result;
367 }
368
369
370 //------------------------------------------------------------------------------------------
371
372 ASDCP::JP2K::SequenceParser::SequenceParser()
373 {
374 }
375
376 ASDCP::JP2K::SequenceParser::~SequenceParser()
377 {
378 }
379
380 // Opens the stream for reading, parses enough data to provide a complete
381 // set of stream metadata for the MXFWriter below.
382 ASDCP::Result_t
383 ASDCP::JP2K::SequenceParser::OpenRead(const std::string& filename, bool pedantic) const
384 {
385   const_cast<ASDCP::JP2K::SequenceParser*>(this)->m_Parser = new h__SequenceParser;
386
387   Result_t result = m_Parser->OpenRead(filename, pedantic);
388
389   if ( ASDCP_FAILURE(result) )
390     const_cast<ASDCP::JP2K::SequenceParser*>(this)->m_Parser.release();
391
392   return result;
393 }
394
395 //
396 Result_t
397 ASDCP::JP2K::SequenceParser::OpenRead(const std::list<std::string>& file_list, bool pedantic) const
398 {
399   const_cast<ASDCP::JP2K::SequenceParser*>(this)->m_Parser = new h__SequenceParser;
400
401   Result_t result = m_Parser->OpenRead(file_list, pedantic);
402
403   if ( ASDCP_FAILURE(result) )
404     const_cast<ASDCP::JP2K::SequenceParser*>(this)->m_Parser.release();
405
406   return result;
407 }
408
409
410 // Rewinds the stream to the beginning.
411 ASDCP::Result_t
412 ASDCP::JP2K::SequenceParser::Reset() const
413 {
414   if ( m_Parser.empty() )
415     return RESULT_INIT;
416
417   return m_Parser->Reset();
418 }
419
420 // Places a frame of data in the frame buffer. Fails if the buffer is too small
421 // or the stream is empty.
422 ASDCP::Result_t
423 ASDCP::JP2K::SequenceParser::ReadFrame(FrameBuffer& FB) const
424 {
425   if ( m_Parser.empty() )
426     return RESULT_INIT;
427
428   return m_Parser->ReadFrame(FB);
429 }
430
431 //
432 ASDCP::Result_t
433 ASDCP::JP2K::SequenceParser::FillPictureDescriptor(PictureDescriptor& PDesc) const
434 {
435   if ( m_Parser.empty() )
436     return RESULT_INIT;
437
438   PDesc = m_Parser->m_PDesc;
439   return RESULT_OK;
440 }
441
442
443 //
444 // end JP2K_Sequence_Parser.cpp
445 //