o Replaced WIN32 directory scanner with dirent_win.h
[asdcplib.git] / src / AS_02.h
1 /*
2 Copyright (c) 2011-2016, Robert Scheler, Heiko Sparenberg Fraunhofer IIS,
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 /*! \file    AS_02.h
30     \version $Id$       
31     \brief   AS-02 library, public interface
32
33 This module implements MXF AS-02 is a set of file access objects that
34 offer simplified access to files conforming to the standards published
35 by the SMPTE Media and Packaging Technology Committee 35PM. The file
36 format, labeled IMF Essence Component (AKA "AS-02" for historical
37 reasons), is described in the following document:
38
39  o SMPTE 2067-5:2013 IMF Essence Component
40
41 The following use cases are supported by the module:
42
43  o Write essence to a plaintext or ciphertext AS-02 file:
44      JPEG 2000 codestreams
45      PCM audio streams
46
47  o Read essence from a plaintext or ciphertext AS-02 file:
48      JPEG 2000 codestreams
49      PCM audio streams
50
51  o Read header metadata from an AS-02 file
52
53 NOTE: ciphertext support for clip-wrapped PCM is not yet complete.
54 */
55
56 #ifndef _AS_02_H_
57 #define _AS_02_H_
58
59 #include "Metadata.h"
60
61
62 namespace AS_02
63 {
64   using Kumu::Result_t;
65
66   KM_DECLARE_RESULT(AS02_FORMAT,        -116, "The file format is not proper OP-1a/AS-02.");
67
68   namespace MXF {
69     //
70     // reads distributed index tables and provides a uniform lookup with
71     // translated StreamOffest values (that is, StreamOffest is adjusted
72     // to the actual file position
73     class AS02IndexReader : public ASDCP::MXF::Partition
74     {
75       Kumu::ByteString m_IndexSegmentData;
76       ui32_t m_Duration;
77       ui32_t m_BytesPerEditUnit;
78
79       Result_t InitFromBuffer(const byte_t* p, ui32_t l, const ui64_t& body_offset, const ui64_t& essence_container_offset);
80
81       ASDCP_NO_COPY_CONSTRUCT(AS02IndexReader);
82       AS02IndexReader();
83           
84     public:
85       const ASDCP::Dictionary*&   m_Dict;
86       ASDCP::IPrimerLookup *m_Lookup;
87     
88       AS02IndexReader(const ASDCP::Dictionary*&);
89       virtual ~AS02IndexReader();
90     
91       Result_t InitFromFile(const Kumu::FileReader& reader, const ASDCP::MXF::RIP& rip, const bool has_header_essence);
92       ui32_t GetDuration() const;
93       void     Dump(FILE* = 0);
94       Result_t GetMDObjectByID(const Kumu::UUID&, ASDCP::MXF::InterchangeObject** = 0);
95       Result_t GetMDObjectByType(const byte_t*, ASDCP::MXF::InterchangeObject** = 0);
96       Result_t GetMDObjectsByType(const byte_t* ObjectID, std::list<ASDCP::MXF::InterchangeObject*>& ObjectList);
97       Result_t Lookup(ui32_t frame_num, ASDCP::MXF::IndexTableSegment::IndexEntry&) const;
98     };
99
100     
101     // Returns size in bytes of a single sample of data described by ADesc
102     inline ui32_t CalcSampleSize(const ASDCP::MXF::WaveAudioDescriptor& d)
103     {
104       return (d.QuantizationBits / 8) * d.ChannelCount;
105     }
106
107       // Returns number of samples per frame of data described by ADesc
108     inline ui32_t CalcSamplesPerFrame(const ASDCP::MXF::WaveAudioDescriptor& d, const ASDCP::Rational& edit_rate)
109     {
110       double tmpd = d.AudioSamplingRate.Quotient() / edit_rate.Quotient();
111       return (ui32_t)ceil(tmpd);
112     }
113
114     // Returns the size in bytes of a frame of data described by ADesc
115     inline ui32_t CalcFrameBufferSize(const ASDCP::MXF::WaveAudioDescriptor& d, const ASDCP::Rational& edit_rate)
116     {
117       return CalcSampleSize(d) * CalcSamplesPerFrame(d, edit_rate);
118     }
119
120     // Returns number of frames for data described by ADesc, given a duration in samples and an edit rate
121     inline ui32_t CalcFramesFromDurationInSamples(const ui32_t duration_samples, const ASDCP::MXF::WaveAudioDescriptor& d,
122                                                   const ASDCP::Rational& edit_rate)
123     {
124       ui32_t spf = CalcSamplesPerFrame(d, edit_rate);
125       ui32_t frames = duration_samples / spf;
126       
127       if ( duration_samples % spf != 0 )
128         {
129           ++frames;
130         }
131
132       return frames;
133     }
134
135   } // namespace MXF
136
137
138   // IMF App 2 edit rates not already exposed in namespace ASDCP
139   const ASDCP::Rational EditRate_29_97 = ASDCP::Rational(30000, 1001);
140   const ASDCP::Rational EditRate_59_94 = ASDCP::Rational(60000, 1001);
141
142   //---------------------------------------------------------------------------------
143   // Accessors in the MXFReader and MXFWriter classes below return these types to
144   // provide direct access to MXF metadata structures declared in MXF.h and Metadata.h
145
146   // See ST 2067-5 Sec. x.y.z
147   enum IndexStrategy_t
148   {
149     IS_LEAD,
150     IS_FOLLOW,
151     IS_FILE_SPECIFIC,
152     IS_MAX
153   };
154  
155   namespace JP2K
156   { 
157     //
158     class MXFWriter
159     {
160       class h__Writer;
161       ASDCP::mem_ptr<h__Writer> m_Writer;
162       ASDCP_NO_COPY_CONSTRUCT(MXFWriter);
163       
164     public:
165       MXFWriter();
166       virtual ~MXFWriter();
167
168       // Warning: direct manipulation of MXF structures can interfere
169       // with the normal operation of the wrapper.  Caveat emptor!
170       virtual ASDCP::MXF::OP1aHeader& OP1aHeader();
171       virtual ASDCP::MXF::RIP& RIP();
172
173       // Open the file for writing. The file must not exist. Returns error if
174       // the operation cannot be completed or if nonsensical data is discovered
175       // in the essence descriptor.
176       Result_t OpenWrite(const std::string& filename, const ASDCP::WriterInfo&,
177                          ASDCP::MXF::FileDescriptor* essence_descriptor,
178                          ASDCP::MXF::InterchangeObject_list_t& essence_sub_descriptor_list,
179                          const ASDCP::Rational& edit_rate, const ui32_t& header_size = 16384,
180                          const IndexStrategy_t& strategy = IS_FOLLOW, const ui32_t& partition_space = 10);
181
182       // Writes a frame of essence to the MXF file. If the optional AESEncContext
183       // argument is present, the essence is encrypted prior to writing.
184       // Fails if the file is not open, is finalized, or an operating system
185       // error occurs.
186       Result_t WriteFrame(const ASDCP::JP2K::FrameBuffer&, ASDCP::AESEncContext* = 0, ASDCP::HMACContext* = 0);
187
188       // Closes the MXF file, writing the index and revised header.
189       Result_t Finalize();
190     };
191
192     //
193     class MXFReader
194     {
195       class h__Reader;
196       ASDCP::mem_ptr<h__Reader> m_Reader;
197       ASDCP_NO_COPY_CONSTRUCT(MXFReader);
198
199     public:
200       MXFReader();
201       virtual ~MXFReader();
202
203       // Warning: direct manipulation of MXF structures can interfere
204       // with the normal operation of the wrapper.  Caveat emptor!
205       virtual ASDCP::MXF::OP1aHeader& OP1aHeader();
206       virtual AS_02::MXF::AS02IndexReader& AS02IndexReader();
207       virtual ASDCP::MXF::RIP& RIP();
208
209       // Open the file for reading. The file must exist. Returns error if the
210       // operation cannot be completed.
211       Result_t OpenRead(const std::string& filename) const;
212
213       // Returns RESULT_INIT if the file is not open.
214       Result_t Close() const;
215
216       // Fill a WriterInfo struct with the values from the file's header.
217       // Returns RESULT_INIT if the file is not open.
218       Result_t FillWriterInfo(ASDCP::WriterInfo&) const;
219
220       // Reads a frame of essence from the MXF file. If the optional AESEncContext
221       // argument is present, the essence is decrypted after reading. If the MXF
222       // file is encrypted and the AESDecContext argument is NULL, the frame buffer
223       // will contain the ciphertext frame data. If the HMACContext argument is
224       // not NULL, the HMAC will be calculated (if the file supports it).
225       // Returns RESULT_INIT if the file is not open, failure if the frame number is
226       // out of range, or if optional decrypt or HAMC operations fail.
227       Result_t ReadFrame(ui32_t frame_number, ASDCP::JP2K::FrameBuffer&, ASDCP::AESDecContext* = 0, ASDCP::HMACContext* = 0) const;
228
229       // Print debugging information to stream
230       void     DumpHeaderMetadata(FILE* = 0) const;
231       void     DumpIndex(FILE* = 0) const;
232     };
233     
234   } //namespace JP2K
235   
236
237   //---------------------------------------------------------------------------------
238   //
239   namespace PCM
240   {
241     // see AS_DCP.h for related data types
242
243     // An AS-02 PCM file is clip-wrapped, but the interface defined below mimics that used
244     // for frame-wrapped essence elsewhere in this library.  The concept of frame rate
245     // therefore is only relevant to these classes and is not reflected in or affected by
246     // the contents of the MXF file.  The frame rate that is set on the writer is only
247     // for compatibility with the existing parsers, samples are packed contiguously into
248     // the same clip-wrapped packet.  Similarly, the edit rate must be set when initializing
249     // the reader to signal the number of samples to be read by each call to ReadFrame();
250
251     //
252       class MXFWriter
253     {
254       class h__Writer;
255       ASDCP::mem_ptr<h__Writer> m_Writer;
256       ASDCP_NO_COPY_CONSTRUCT(MXFWriter);
257
258     public:
259       MXFWriter();
260       virtual ~MXFWriter();
261
262       // Warning: direct manipulation of MXF structures can interfere
263       // with the normal operation of the wrapper.  Caveat emptor!
264       virtual ASDCP::MXF::OP1aHeader& OP1aHeader();
265       virtual ASDCP::MXF::RIP& RIP();
266
267       // Open the file for writing. The file must not exist. Returns error if
268       // the operation cannot be completed or if nonsensical data is discovered
269       // in the essence descriptor.
270       Result_t OpenWrite(const std::string& filename, const ASDCP::WriterInfo&,
271                          ASDCP::MXF::FileDescriptor* essence_descriptor,
272                          ASDCP::MXF::InterchangeObject_list_t& essence_sub_descriptor_list,
273                          const ASDCP::Rational& edit_rate, ui32_t HeaderSize = 16384);
274
275       // Writes a frame of essence to the MXF file. If the optional AESEncContext
276       // argument is present, the essence is encrypted prior to writing.
277       // Fails if the file is not open, is finalized, or an operating system
278       // error occurs.
279       Result_t WriteFrame(const ASDCP::FrameBuffer&, ASDCP::AESEncContext* = 0, ASDCP::HMACContext* = 0);
280       
281       // Closes the MXF file, writing the index and revised header.
282       Result_t Finalize();
283     };
284
285     //
286     class MXFReader
287     {
288       class h__Reader;
289       ASDCP::mem_ptr<h__Reader> m_Reader;
290       ASDCP_NO_COPY_CONSTRUCT(MXFReader);
291
292     public:
293       MXFReader();
294       virtual ~MXFReader();
295
296       // Warning: direct manipulation of MXF structures can interfere
297       // with the normal operation of the wrapper.  Caveat emptor!
298       virtual ASDCP::MXF::OP1aHeader& OP1aHeader();
299       virtual AS_02::MXF::AS02IndexReader& AS02IndexReader();
300       virtual ASDCP::MXF::RIP& RIP();
301
302       // Open the file for reading. The file must exist. Returns error if the
303       // operation cannot be completed.
304       Result_t OpenRead(const std::string& filename, const ASDCP::Rational& EditRate) const;
305
306       // Returns RESULT_INIT if the file is not open.
307       Result_t Close() const;
308
309       // Fill a WriterInfo struct with the values from the file's header.
310       // Returns RESULT_INIT if the file is not open.
311       Result_t FillWriterInfo(ASDCP::WriterInfo&) const;
312
313       // Reads a frame of essence from the MXF file. If the optional AESEncContext
314       // argument is present, the essence is decrypted after reading. If the MXF
315       // file is encrypted and the AESDecContext argument is NULL, the frame buffer
316       // will contain the ciphertext frame data. If the HMACContext argument is
317       // not NULL, the HMAC will be calculated (if the file supports it).
318       // Returns RESULT_INIT if the file is not open, failure if the frame number is
319       // out of range, or if optional decrypt or HAMC operations fail.
320       Result_t ReadFrame(ui32_t frame_number, ASDCP::PCM::FrameBuffer&, ASDCP::AESDecContext* = 0, ASDCP::HMACContext* = 0) const;
321       
322       // Print debugging information to stream
323       void     DumpHeaderMetadata(FILE* = 0) const;
324       void     DumpIndex(FILE* = 0) const;
325     };
326   } // namespace PCM
327
328   //---------------------------------------------------------------------------------
329   //
330   namespace TimedText
331     {
332       using ASDCP::TimedText::TimedTextDescriptor;
333       using ASDCP::TimedText::TimedTextResourceDescriptor;
334       using ASDCP::TimedText::ResourceList_t;
335
336       //
337       class Type5UUIDFilenameResolver : public ASDCP::TimedText::IResourceResolver
338         {
339           typedef std::map<Kumu::UUID, std::string> ResourceMap;
340             
341           ResourceMap m_ResourceMap;
342           std::string m_Dirname;
343           KM_NO_COPY_CONSTRUCT(Type5UUIDFilenameResolver);
344
345         public:
346           Type5UUIDFilenameResolver();
347           virtual ~Type5UUIDFilenameResolver();
348           Result_t OpenRead(const std::string& dirname);
349           Result_t ResolveRID(const byte_t* uuid, ASDCP::TimedText::FrameBuffer& FrameBuf) const;
350         };
351       
352
353       // Generate UUID asset ID values from file contents
354       Kumu::UUID CreatePNGNameId(const std::string& image_name);
355       Kumu::UUID CreateFontNameId(const std::string& font_name);
356
357       //
358       class ST2052_TextParser
359         {
360           class h__TextParser;
361           ASDCP::mem_ptr<h__TextParser> m_Parser;
362           ASDCP_NO_COPY_CONSTRUCT(ST2052_TextParser);
363
364         public:
365           ST2052_TextParser();
366           virtual ~ST2052_TextParser();
367
368           // Opens an XML file for reading, parses data to provide a complete
369           // set of stream metadata for the MXFWriter below.
370           Result_t OpenRead(const std::string& filename, const std::string& profile_name) const;
371
372           // Parse an XML string 
373           Result_t OpenRead(const std::string& xml_doc, const std::string& filename,
374                             const std::string& profile_name) const;
375
376           // Fill a TimedTextDescriptor struct with the values from the file's contents.
377           // Returns RESULT_INIT if the file is not open.
378           Result_t FillTimedTextDescriptor(ASDCP::TimedText::TimedTextDescriptor&) const;
379
380           // Reads the complete Timed Text Resource into the given string.
381           Result_t ReadTimedTextResource(std::string&) const;
382
383           // Reads the Ancillary Resource having the given ID. Fails if the buffer
384           // is too small or the resource does not exist. The optional Resolver
385           // argument can be provided which will be used to retrieve the resource
386           // having a particulat UUID. If a Resolver is not supplied, the default
387           // internal resolver will return the contents of the file having the UUID
388           // as the filename. The filename must exist in the same directory as the
389           // XML file opened with OpenRead().
390           Result_t ReadAncillaryResource(const Kumu::UUID&, ASDCP::TimedText::FrameBuffer&,
391                                          const ASDCP::TimedText::IResourceResolver* Resolver = 0) const;
392         };
393
394       //
395       class MXFWriter
396         {
397           class h__Writer;
398           ASDCP::mem_ptr<h__Writer> m_Writer;
399           ASDCP_NO_COPY_CONSTRUCT(MXFWriter);
400
401         public:
402           MXFWriter();
403           virtual ~MXFWriter();
404
405           // Warning: direct manipulation of MXF structures can interfere
406           // with the normal operation of the wrapper.  Caveat emptor!
407           virtual ASDCP::MXF::OP1aHeader& OP1aHeader();
408           virtual ASDCP::MXF::RIP& RIP();
409
410           // Open the file for writing. The file must not exist. Returns error if
411           // the operation cannot be completed or if nonsensical data is discovered
412           // in the essence descriptor.
413           Result_t OpenWrite(const std::string& filename, const ASDCP::WriterInfo&,
414                              const ASDCP::TimedText::TimedTextDescriptor&, ui32_t HeaderSize = 16384);
415
416           // Writes the Timed-Text Resource to the MXF file. The file must be UTF-8
417           // encoded. If the optional AESEncContext argument is present, the essence
418           // is encrypted prior to writing. Fails if the file is not open, is finalized,
419           // or an operating system error occurs.
420           // This method may only be called once, and it must be called before any
421           // call to WriteAncillaryResource(). RESULT_STATE will be returned if these
422           // conditions are not met.
423           Result_t WriteTimedTextResource(const std::string& XMLDoc, ASDCP::AESEncContext* = 0, ASDCP::HMACContext* = 0);
424
425           // Writes an Ancillary Resource to the MXF file. If the optional AESEncContext
426           // argument is present, the essence is encrypted prior to writing.
427           // Fails if the file is not open, is finalized, or an operating system
428           // error occurs. RESULT_STATE will be returned if the method is called before
429           // WriteTimedTextResource()
430           Result_t WriteAncillaryResource(const ASDCP::TimedText::FrameBuffer&, ASDCP::AESEncContext* = 0, ASDCP::HMACContext* = 0);
431
432           // Closes the MXF file, writing the index and revised header.
433           Result_t Finalize();
434         };
435
436       //
437       class MXFReader
438         {
439           class h__Reader;
440           ASDCP::mem_ptr<h__Reader> m_Reader;
441           ASDCP_NO_COPY_CONSTRUCT(MXFReader);
442
443         public:
444           MXFReader();
445           virtual ~MXFReader();
446
447           // Warning: direct manipulation of MXF structures can interfere
448           // with the normal operation of the wrapper.  Caveat emptor!
449           virtual ASDCP::MXF::OP1aHeader& OP1aHeader();
450           virtual AS_02::MXF::AS02IndexReader& AS02IndexReader();
451           virtual ASDCP::MXF::RIP& RIP();
452
453           // Open the file for reading. The file must exist. Returns error if the
454           // operation cannot be completed.
455           Result_t OpenRead(const std::string& filename) const;
456
457           // Returns RESULT_INIT if the file is not open.
458           Result_t Close() const;
459
460           // Fill a TimedTextDescriptor struct with the values from the file's header.
461           // Returns RESULT_INIT if the file is not open.
462           Result_t FillTimedTextDescriptor(ASDCP::TimedText::TimedTextDescriptor&) const;
463
464           // Fill a WriterInfo struct with the values from the file's header.
465           // Returns RESULT_INIT if the file is not open.
466           Result_t FillWriterInfo(ASDCP::WriterInfo&) const;
467
468           // Reads the complete Timed Text Resource into the given string. Fails if the resource
469           // is encrypted and AESDecContext is NULL (use the following method to retrieve the
470           // raw ciphertet block).
471           Result_t ReadTimedTextResource(std::string&, ASDCP::AESDecContext* = 0, ASDCP::HMACContext* = 0) const;
472
473           // Reads the complete Timed Text Resource from the MXF file. If the optional AESEncContext
474           // argument is present, the resource is decrypted after reading. If the MXF
475           // file is encrypted and the AESDecContext argument is NULL, the frame buffer
476           // will contain the ciphertext frame data. If the HMACContext argument is
477           // not NULL, the HMAC will be calculated (if the file supports it).
478           // Returns RESULT_INIT if the file is not open, failure if the frame number is
479           // out of range, or if optional decrypt or HAMC operations fail.
480           Result_t ReadTimedTextResource(ASDCP::TimedText::FrameBuffer&, ASDCP::AESDecContext* = 0, ASDCP::HMACContext* = 0) const;
481
482           // Reads the timed-text resource having the given UUID from the MXF file. If the
483           // optional AESEncContext argument is present, the resource is decrypted after
484           // reading. If the MXF file is encrypted and the AESDecContext argument is NULL,
485           // the frame buffer will contain the ciphertext frame data. If the HMACContext
486           // argument is not NULL, the HMAC will be calculated (if the file supports it).
487           // Returns RESULT_INIT if the file is not open, failure if the frame number is
488           // out of range, or if optional decrypt or HAMC operations fail.
489           Result_t ReadAncillaryResource(const Kumu::UUID&, ASDCP::TimedText::FrameBuffer&, ASDCP::AESDecContext* = 0, ASDCP::HMACContext* = 0) const;
490
491           // Print debugging information to stream
492           void     DumpHeaderMetadata(FILE* = 0) const;
493           void     DumpIndex(FILE* = 0) const;
494         };
495     } // namespace TimedText
496
497
498
499 } // namespace AS_02
500
501 #endif // _AS_02_H_
502
503 //
504 // end AS_02.h
505 //