Bump patch version post tag.
[asdcplib.git] / src / ACES_Sequence_Parser.cpp
1 /*
2 Copyright (c) 2018, Bjoern Stresing, Patrick Bichiou, Wolfgang Ruppel,
3 John Hurst
4
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
9 are met:
10 1. Redistributions of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in the
14 documentation and/or other materials provided with the distribution.
15 3. The name of the author may not be used to endorse or promote products
16 derived from this software without specific prior written permission.
17
18 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 #include "AS_02_ACES.h"
31 #include <KM_fileio.h>
32 #include <assert.h>
33 #include <KM_log.h>
34
35
36 using Kumu::DefaultLogSink;
37
38
39 class FileList : public std::list<std::string>
40 {
41   std::string m_DirName;
42
43 public:
44   FileList() {}
45   ~FileList() {}
46
47   const FileList& operator=(const std::list<std::string>& pathlist)
48   {
49     std::list<std::string>::const_iterator i;
50     for(i = pathlist.begin(); i != pathlist.end(); i++)
51       push_back(*i);
52     return *this;
53   }
54
55   //
56   ASDCP::Result_t InitFromDirectory(const std::string& path)
57   {
58     char next_file[Kumu::MaxFilePath];
59     Kumu::DirScanner Scanner;
60
61     ASDCP::Result_t result = Scanner.Open(path);
62
63     if(ASDCP_SUCCESS(result))
64     {
65       m_DirName = path;
66
67       while(ASDCP_SUCCESS(Scanner.GetNext(next_file)))
68       {
69         if(next_file[0] == '.') // no hidden files or internal links
70           continue;
71
72         std::string Str(m_DirName);
73         Str += "/";
74         Str += next_file;
75
76         if(!Kumu::PathIsDirectory(Str))
77           push_back(Str);
78       }
79
80       sort();
81     }
82
83     return result;
84   }
85 };
86
87
88 class AS_02::ACES::SequenceParser::h__SequenceParser
89 {
90   ui32_t             m_FramesRead;
91   ASDCP::Rational    m_PictureRate;
92   FileList           m_FileList;
93   FileList::iterator m_CurrentFile;
94   CodestreamParser   m_Parser;
95   bool               m_Pedantic;
96
97   Result_t OpenRead();
98
99   ASDCP_NO_COPY_CONSTRUCT(h__SequenceParser);
100
101 public:
102   PictureDescriptor  m_PDesc;
103   ResourceList_t   m_ResourceList_t;
104
105   h__SequenceParser() : m_FramesRead(0), m_Pedantic(false)
106   {
107     memset(&m_PDesc, 0, sizeof(m_PDesc));
108     m_PDesc.EditRate = ASDCP::Rational(24, 1);
109   }
110
111   ~h__SequenceParser()
112   {
113     Close();
114   }
115
116   Result_t OpenRead(const std::string& filename, bool pedantic);
117   Result_t OpenRead(const std::list<std::string>& file_list, bool pedantic);
118   // Opens a files sequence for reading. The sequence is expected to contain one or more
119   // PNG or TIFF files which will be added as Ancillary Data.
120   Result_t OpenTargetFrameSequenceRead(const std::list<std::string> &target_frame_file_list);
121
122   void     Close() {}
123
124   Result_t Reset()
125   {
126     m_FramesRead = 0;
127     m_CurrentFile = m_FileList.begin();
128     return RESULT_OK;
129   }
130
131   Result_t ReadFrame(FrameBuffer&);
132 };
133
134 AS_02::Result_t AS_02::ACES::SequenceParser::h__SequenceParser::OpenRead()
135 {
136
137   if(m_FileList.empty())
138     return RESULT_ENDOFFILE;
139
140   m_CurrentFile = m_FileList.begin();
141   CodestreamParser Parser;
142   FrameBuffer TmpBuffer;
143
144   Kumu::fsize_t file_size = Kumu::FileSize((*m_CurrentFile).c_str());
145
146   if(file_size == 0)
147     return RESULT_NOT_FOUND;
148
149   assert(file_size <= 0xFFFFFFFFL);
150   Result_t result = TmpBuffer.Capacity((ui32_t)file_size);
151   if(ASDCP_SUCCESS(result))
152     result = Parser.OpenReadFrame((*m_CurrentFile).c_str(), TmpBuffer);
153
154   if(ASDCP_SUCCESS(result))
155     result = Parser.FillPictureDescriptor(m_PDesc);
156
157   // how big is it?
158   if(ASDCP_SUCCESS(result))
159     m_PDesc.ContainerDuration = m_FileList.size();
160
161   return result;
162 }
163
164 AS_02::Result_t AS_02::ACES::SequenceParser::h__SequenceParser::OpenRead(const std::string& filename, bool pedantic)
165 {
166
167   m_Pedantic = pedantic;
168
169   Result_t result = m_FileList.InitFromDirectory(filename);
170
171   if(ASDCP_SUCCESS(result))
172     result = OpenRead();
173
174   return result;
175 }
176
177 AS_02::Result_t AS_02::ACES::SequenceParser::h__SequenceParser::OpenRead(const std::list<std::string>& file_list, bool pedantic)
178 {
179
180   m_Pedantic = pedantic;
181   m_FileList = file_list;
182   return OpenRead();
183 }
184
185 AS_02::Result_t AS_02::ACES::SequenceParser::h__SequenceParser::OpenTargetFrameSequenceRead(const std::list<std::string> &target_frame_file_list)
186 {
187   AS_02::Result_t result = AS_02::RESULT_OK;
188   std::list<std::string>::const_iterator i;
189   byte_t read_buffer[16];
190
191   for (i = target_frame_file_list.begin(); i != target_frame_file_list.end(); i++)
192   {
193       std::string abs_filename = Kumu::PathMakeAbsolute(*i);
194         Kumu::FileReader reader;
195         result = reader.OpenRead(abs_filename);
196
197         if ( KM_SUCCESS(result) )
198         {
199           result = reader.Read(read_buffer, 16);
200           reader.Close();
201         }
202         if ( KM_SUCCESS(result) )
203         {
204       // is it PNG or TIFF?
205         MIMEType_t media_type = MT_UNDEF;
206         if ( memcmp(read_buffer, PNGMagic, sizeof(PNGMagic)) == 0) media_type = MT_PNG;
207         if ( memcmp(read_buffer, TIFFMagicLE, sizeof(TIFFMagicLE)) == 0) media_type = MT_TIFF;
208         if ( memcmp(read_buffer, TIFFMagicBE, sizeof(TIFFMagicBE)) == 0) media_type = MT_TIFF;
209         if (media_type != MT_UNDEF)
210         {
211           AS_02::ACES::AncillaryResourceDescriptor resource_descriptor;
212           Kumu::UUID asset_id;
213           result = CreateTargetFrameAssetId(asset_id, abs_filename);
214           memcpy(&resource_descriptor.ResourceID, asset_id.Value(), Kumu::UUID_Length);
215           resource_descriptor.Type = media_type;
216           resource_descriptor.filePath = *i;
217           if ( KM_SUCCESS(result) ) m_ResourceList_t.push_back(resource_descriptor);
218
219         }
220     }
221    }
222   return result;
223 }
224
225
226 AS_02::Result_t AS_02::ACES::SequenceParser::h__SequenceParser::ReadFrame(FrameBuffer& FB)
227 {
228
229   if(m_CurrentFile == m_FileList.end())
230     return RESULT_ENDOFFILE;
231
232   // open the file
233   Result_t result = m_Parser.OpenReadFrame((*m_CurrentFile).c_str(), FB);
234
235   if(ASDCP_SUCCESS(result) && m_Pedantic)
236   {
237     PictureDescriptor PDesc;
238     result = m_Parser.FillPictureDescriptor(PDesc);
239
240     if(ASDCP_SUCCESS(result) && !(m_PDesc == PDesc))
241     {
242       Kumu::DefaultLogSink().Error("ACES codestream parameters do not match at frame %d\n", m_FramesRead + 1);
243       result = ASDCP::RESULT_RAW_FORMAT;
244     }
245   }
246
247   if(ASDCP_SUCCESS(result))
248   {
249     FB.FrameNumber(m_FramesRead++);
250     m_CurrentFile++;
251   }
252
253   return result;
254 }
255
256 //------------------------------------------------------------------------------
257
258
259 AS_02::ACES::SequenceParser::SequenceParser() {}
260
261 AS_02::ACES::SequenceParser::~SequenceParser() {}
262
263 // Opens the stream for reading, parses enough data to provide a complete
264 // set of stream metadata for the MXFWriter below.
265 AS_02::Result_t AS_02::ACES::SequenceParser::OpenRead(const std::string &directory, bool pedantic /*= false*/, const std::list<std::string> &target_frame_file_list /* = std::list<std::string>()*/) const
266 {
267
268   const_cast<AS_02::ACES::SequenceParser*>(this)->m_Parser = new h__SequenceParser;
269
270   Result_t result = m_Parser->OpenRead(directory, pedantic);
271
272   if(ASDCP_SUCCESS(result))
273     if (target_frame_file_list.size() > 0 ) result = m_Parser->OpenTargetFrameSequenceRead(target_frame_file_list);
274
275   if(ASDCP_FAILURE(result))
276     const_cast<AS_02::ACES::SequenceParser*>(this)->m_Parser.release();
277
278   return result;
279 }
280
281 AS_02::Result_t AS_02::ACES::SequenceParser::OpenRead(const std::list<std::string> &file_list, bool pedantic /*= false*/, const std::list<std::string> &target_frame_file_list /* = std::list<std::string>()*/) const
282 {
283
284   const_cast<AS_02::ACES::SequenceParser*>(this)->m_Parser = new h__SequenceParser;
285
286   Result_t result = m_Parser->OpenRead(file_list, pedantic);
287
288   if(ASDCP_SUCCESS(result))
289     if (target_frame_file_list.size() > 0 ) result = m_Parser->OpenTargetFrameSequenceRead(target_frame_file_list);
290
291   if(ASDCP_FAILURE(result))
292     const_cast<AS_02::ACES::SequenceParser*>(this)->m_Parser.release();
293
294   return result;
295 }
296
297 AS_02::Result_t AS_02::ACES::SequenceParser::FillPictureDescriptor(PictureDescriptor &PDesc) const
298 {
299
300   if(m_Parser.empty())
301     return RESULT_INIT;
302
303   PDesc = m_Parser->m_PDesc;
304   return RESULT_OK;
305 }
306
307 AS_02::Result_t AS_02::ACES::SequenceParser::FillResourceList(ResourceList_t &rResourceList_t) const
308 {
309
310   if(m_Parser.empty())
311     return RESULT_INIT;
312
313   rResourceList_t = m_Parser->m_ResourceList_t;
314   return RESULT_OK;
315 }
316
317 AS_02::Result_t AS_02::ACES::SequenceParser::Reset() const
318 {
319
320   if(m_Parser.empty())
321     return RESULT_INIT;
322
323   return m_Parser->Reset();
324 }
325
326 AS_02::Result_t AS_02::ACES::SequenceParser::ReadFrame(FrameBuffer &FB) const
327 {
328
329   if(m_Parser.empty())
330     return RESULT_INIT;
331
332   return m_Parser->ReadFrame(FB);
333 }
334
335 AS_02::Result_t AS_02::ACES::SequenceParser::ReadAncillaryResource(const std::string &filename, FrameBuffer &FB) const
336 {
337   if ( m_Parser.empty() )
338   return RESULT_INIT;
339   Kumu::FileReader reader;
340   Result_t result = Kumu::RESULT_OK;
341   result = reader.OpenRead(filename);
342   if (KM_SUCCESS(result))
343   {
344     FB.Capacity(reader.Size());
345     ui32_t read_count;
346     result = reader.Read(FB.Data(), reader.Size(), &read_count);
347     FB.Size(read_count);
348     if (read_count <  reader.Size()) result = Kumu::RESULT_FAIL;
349   }
350   return result;
351 }