stereoscopic JP2K writing
[asdcplib.git] / src / AS_DCP.h
1 /*
2 Copyright (c) 2003-2006, 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    AS_DCP.h
28     \version $Id$       
29     \brief   AS-DCP library, public interface
30
31 The asdcplib library is a set of wrapper objects that offer simplified
32 access to files conforming to the file formats proposed by the SMPTE
33 D-Cinema packaging working group DC28.20.  The file format, labeled
34 AS-DCP, is described in series of separate documents which include but
35 may not be limited to:
36
37  o MXF Interop Track File Specification
38  o MXF Interop Track File Essence Encryption Specification
39  o MXF Interop Operational Constraints Specification
40  o SMPTE 429-3-2006 Track File Specification
41  o SMPTE 429-4-2006 JPEG 2000 for D-Cinema
42  o SMPTE 429-5-200X Timed Text Track File
43  o SMPTE 429-6-2006 Essence Encryption Specification
44  o SMPTE 429-10-2006 Stereoscopic Image Track File
45  o SMPTE 330M - UMID
46  o SMPTE 336M - KLV
47  o SMPTE 377M - MXF
48  o SMPTE 390M - OP-Atom
49  o SMPTE 379M - Generic Container
50  o SMPTE 381M - MPEG2 picture
51  o SMPTE 422M - JPEG 2000 picture
52  o SMPTE 382M - WAV/PCM sound
53  o IETF RFC 2104 - HMAC/SHA1
54  o NIST FIPS 197 - AES (Rijndael)
55
56 The following use cases are supported by the library:
57
58  o Write a plaintext MPEG2 Video Elementary Stream to a plaintext ASDCP file
59  o Write a plaintext MPEG2 Video Elementary Stream to a ciphertext ASDCP file
60  o Read a plaintext MPEG2 Video Elementary Stream from a plaintext ASDCP file
61  o Read a plaintext MPEG2 Video Elementary Stream from a ciphertext ASDCP file
62  o Read a ciphertext MPEG2 Video Elementary Stream from a ciphertext ASDCP file
63  o Write one or more plaintext JPEG 2000 codestreams to a plaintext ASDCP file
64  o Write one or more plaintext JPEG 2000 codestreams to a ciphertext ASDCP file
65  o Read one or more plaintext JPEG 2000 codestreams from a plaintext ASDCP file
66  o Read one or more plaintext JPEG 2000 codestreams from a ciphertext ASDCP file
67  o Read one or more ciphertext JPEG 2000 codestreams from a ciphertext ASDCP file
68  o Write one or more plaintext PCM audio streams to a plaintext ASDCP file
69  o Write one or more plaintext PCM audio streams to a ciphertext ASDCP file
70  o Read one or more plaintext PCM audio streams from a plaintext ASDCP file
71  o Read one or more plaintext PCM audio streams from a ciphertext ASDCP file
72  o Read one or more ciphertext PCM audio streams from a ciphertext ASDCP file
73  o Read header metadata from an ASDCP file
74
75 This project depends upon the following library:
76  - OpenSSL http://www.openssl.org/
77
78 */
79
80 #ifndef _AS_DCP_H_
81 #define _AS_DCP_H_
82
83 #include <KM_error.h>
84 #include <stdio.h>
85 #include <stdarg.h>
86 #include <math.h>
87 #include <iostream>
88 #include <string>
89
90 //--------------------------------------------------------------------------------
91 // common integer types
92 // supply your own by defining ASDCP_NO_BASE_TYPES
93
94 #ifndef ASDCP_NO_BASE_TYPES
95 typedef unsigned char  byte_t;
96 typedef char           i8_t;
97 typedef unsigned char  ui8_t;
98 typedef short          i16_t;
99 typedef unsigned short ui16_t;
100 typedef int            i32_t;
101 typedef unsigned int   ui32_t;
102 #endif
103
104
105 //--------------------------------------------------------------------------------
106 // convenience macros
107
108 // Convenience macros for managing return values in predicates
109 #define ASDCP_SUCCESS(v) (((v) < 0) ? 0 : 1)
110 #define ASDCP_FAILURE(v) (((v) < 0) ? 1 : 0)
111
112
113 // Returns RESULT_PTR if the given argument is NULL.
114 // See Result_t below for an explanation of RESULT_* symbols.
115 #define ASDCP_TEST_NULL(p) \
116   if ( (p) == 0  ) { \
117     return ASDCP::RESULT_PTR; \
118   }
119
120 // Returns RESULT_PTR if the given argument is NULL. See Result_t
121 // below for an explanation of RESULT_* symbols. It then assumes
122 // that the argument is a pointer to a string and returns
123 // RESULT_NULL_STR if the first character is '\0'.
124 //
125 #define ASDCP_TEST_NULL_STR(p) \
126   ASDCP_TEST_NULL(p); \
127   if ( (p)[0] == '\0' ) { \
128     return ASDCP::RESULT_NULL_STR; \
129   }
130
131 // Produces copy constructor boilerplate. Allows convenient private
132 // declatarion of copy constructors to prevent the compiler from
133 // silently manufacturing default methods.
134 #define ASDCP_NO_COPY_CONSTRUCT(T)   \
135           T(const T&); \
136           T& operator=(const T&)
137
138 //--------------------------------------------------------------------------------
139 // All library components are defined in the namespace ASDCP
140 //
141 namespace ASDCP {
142   // The version number consists of three segments: major, API minor, and
143   // implementation minor. Whenever a change is made to AS_DCP.h, the API minor
144   // version will increment. Changes made to the internal implementation will
145   // result in the incrementing of the implementation minor version.
146
147   // For example, if asdcplib version 1.0.0 were modified to accomodate changes
148   // in file format, and if no changes were made to AS_DCP.h, the new version would be
149   // 1.0.1. If changes were also required in AS_DCP.h, the new version would be 1.1.1.
150   const ui32_t VERSION_MAJOR = 1;
151   const ui32_t VERSION_APIMINOR = 2;
152   const ui32_t VERSION_IMPMINOR = 16;
153   const char* Version();
154
155   // UUIDs are passed around as strings of UUIDlen bytes
156   const ui32_t UUIDlen = 16;
157
158   // Encryption keys are passed around as strings of KeyLen bytes
159   const ui32_t KeyLen = 16;
160
161   //---------------------------------------------------------------------------------
162   // return values
163
164   using Kumu::Result_t;
165
166   using Kumu::RESULT_FALSE;
167   using Kumu::RESULT_OK;
168   using Kumu::RESULT_FAIL;
169   using Kumu::RESULT_PTR;
170   using Kumu::RESULT_NULL_STR;
171   using Kumu::RESULT_ALLOC;
172   using Kumu::RESULT_PARAM;
173   using Kumu::RESULT_SMALLBUF;
174   using Kumu::RESULT_INIT;
175   using Kumu::RESULT_NOT_FOUND;
176   using Kumu::RESULT_NO_PERM;
177   using Kumu::RESULT_FILEOPEN;
178   using Kumu::RESULT_BADSEEK;
179   using Kumu::RESULT_READFAIL;
180   using Kumu::RESULT_WRITEFAIL;
181   using Kumu::RESULT_STATE;
182   using Kumu::RESULT_ENDOFFILE;
183   using Kumu::RESULT_CONFIG;
184
185   const Kumu::Result_t RESULT_FORMAT     (-101, "The file format is not proper OP-Atom/AS-DCP.");
186   const Kumu::Result_t RESULT_RAW_ESS    (-102, "Unknown raw essence file type.");
187   const Kumu::Result_t RESULT_RAW_FORMAT (-103, "Raw essence format invalid.");
188   const Kumu::Result_t RESULT_RANGE      (-104, "Frame number out of range.");
189   const Kumu::Result_t RESULT_CRYPT_CTX  (-105, "AESEncContext required when writing to encrypted file.");
190   const Kumu::Result_t RESULT_LARGE_PTO  (-106, "Plaintext offset exceeds frame buffer size.");
191   const Kumu::Result_t RESULT_CAPEXTMEM  (-107, "Cannot resize externally allocated memory.");
192   const Kumu::Result_t RESULT_CHECKFAIL  (-108, "The check value did not decrypt correctly.");
193   const Kumu::Result_t RESULT_HMACFAIL   (-109, "HMAC authentication failure.");
194   const Kumu::Result_t RESULT_HMAC_CTX   (-110, "HMAC context required.");
195   const Kumu::Result_t RESULT_CRYPT_INIT (-111, "Error initializing block cipher context.");
196   const Kumu::Result_t RESULT_EMPTY_FB   (-112, "Empty frame buffer.");
197   const Kumu::Result_t RESULT_KLV_CODING (-113, "KLV coding error.");
198   const Kumu::Result_t RESULT_SPHASE     (-114, "Stereoscopic phase mismatch.");
199
200   //---------------------------------------------------------------------------------
201   // file identification
202
203   // The file accessors in this library implement a bounded set of essence types.
204   // This list will be expanded when support for new types is added to the library.
205   enum EssenceType_t {
206     ESS_UNKNOWN,     // the file is not a supported AS-DCP essence container
207     ESS_MPEG2_VES,   // the file contains an MPEG video elementary stream
208     ESS_JPEG_2000,   // the file contains one or more JPEG 2000 codestreams
209     ESS_PCM_24b_48k, // the file contains one or more PCM audio pairs
210     ESS_PCM_24b_96k, // the file contains one or more PCM audio pairs
211     ESS_TIMED_TEXT,  // the file contains an XML timed text document and one or more resources
212     ESS_JPEG_2000_S, // the file contains one or more JPEG 2000 codestream pairs (stereoscopic)
213   };
214
215   // Determine the type of essence contained in the given MXF file. RESULT_OK
216   // is returned if the file is successfully opened and contains a valid MXF
217   // stream. If there is an error, the result code will indicate the reason.
218   Result_t EssenceType(const char* filename, EssenceType_t& type);
219
220   // Determine the type of essence contained in the given raw file. RESULT_OK
221   // is returned if the file is successfully opened and contains a known
222   // stream type. If there is an error, the result code will indicate the reason.
223   Result_t RawEssenceType(const char* filename, EssenceType_t& type);
224
225
226   //---------------------------------------------------------------------------------
227   // base types
228
229   // A simple container for rational numbers.
230   class Rational
231   {
232   public:
233     i32_t Numerator;
234     i32_t Denominator;
235
236     Rational() : Numerator(0), Denominator(0) {}
237     Rational(i32_t n, i32_t d) : Numerator(n), Denominator(d) {}
238
239     inline double Quotient() const {
240       return (double)Numerator / (double)Denominator;
241     }
242
243     inline bool operator==(const Rational& rhs) const {
244       return ( rhs.Numerator == Numerator && rhs.Denominator == Denominator );
245     }
246
247     inline bool operator!=(const Rational& rhs) const {
248       return ( rhs.Numerator != Numerator || rhs.Denominator != Denominator );
249     }
250   };
251
252   // common edit rates, use these instead of hard coded constants
253   const Rational EditRate_24(24,1);
254   const Rational EditRate_23_98(24000,1001); // Not a DCI-compliant value!
255   const Rational EditRate_48(48,1);
256   const Rational SampleRate_48k(48000,1);
257   const Rational SampleRate_96k(96000,1);
258
259   // Non-reference counting container for internal member objects.
260   // Please do not use this class for any other purpose.
261   template <class T>
262     class mem_ptr
263     {
264       T* m_p; // the thing we point to
265       mem_ptr(T&);
266
267     public:
268       mem_ptr() : m_p(0) {}
269       mem_ptr(T* p) : m_p(p) {}
270       ~mem_ptr() { delete m_p; }
271
272       inline T&   operator*()  const { return *m_p; }
273       inline T*   operator->() const { return m_p; }
274       inline      operator T*()const { return m_p; }
275       inline const mem_ptr<T>& operator=(T* p) { set(p); return *this; }
276       inline T*   set(T* p)          { delete m_p; m_p = p; return m_p; }
277       inline T*   get()        const { return m_p; }
278       inline void release()          { m_p = 0; }
279       inline bool empty()      const { return m_p == 0; }
280     };
281
282
283   //---------------------------------------------------------------------------------
284   // WriterInfo class - encapsulates writer identification details used for
285   // OpenWrite() calls.  Replace these values at runtime to identify your product.
286   //
287   // MXF files use SMPTE Universal Labels to identify data items. The set of Labels
288   // in a file is determined by the MXF Operational Pattern and any constraining
289   // documentation. There are currently two flavors of AS-DCP file in use: MXF Interop
290   // and SMPTE. The two differ only in the values of two labels:
291   //
292   //   OP Atom     / Interop : 06 0e 2b 34 04 01 01 01  0d 01 02 01 10 00 00 00
293   //   OP Atom     / SMPTE   : 06 0e 2b 34 04 01 01 02  0d 01 02 01 10 00 00 00
294   // and 
295   //   EKLV Packet / Interop : 06 0e 2b 34 02 04 01 07  0d 01 03 01 02 7e 01 00
296   //   EKLV Packet / SMPTE   : 06 0e 2b 34 02 04 01 01  0d 01 03 01 02 7e 01 00
297   //
298   // asdcplib will read any (otherwise valid) file which has any combination of the
299   // above values. When writing files, MXF Interop labels are used by default. To
300   // write a file containing SMPTE labels, replace the default label set value in
301   // the WriterInfo before calling OpenWrite()
302   //
303   enum LabelSet_t
304   {
305     LS_MXF_UNKNOWN,
306     LS_MXF_INTEROP,
307     LS_MXF_SMPTE
308   };
309
310   //
311   struct WriterInfo
312   {
313     byte_t      ProductUUID[UUIDlen];
314     byte_t      AssetUUID[UUIDlen];
315     byte_t      ContextID[UUIDlen];
316     byte_t      CryptographicKeyID[UUIDlen];
317     bool        EncryptedEssence; // true if essence data is (or is going to be) encrypted
318     bool        UsesHMAC;         // true if HMAC exists or is to be calculated
319     std::string ProductVersion;
320     std::string CompanyName;
321     std::string ProductName;
322     LabelSet_t  LabelSetType;
323
324     WriterInfo() : EncryptedEssence(false), UsesHMAC(false), LabelSetType(LS_MXF_INTEROP)
325     {
326       static byte_t default_ProductUUID_Data[UUIDlen] = {
327         0x43, 0x05, 0x9a, 0x1d, 0x04, 0x32, 0x41, 0x01,
328         0xb8, 0x3f, 0x73, 0x68, 0x15, 0xac, 0xf3, 0x1d };
329       
330       memcpy(ProductUUID, default_ProductUUID_Data, UUIDlen);
331       memset(AssetUUID, 0, UUIDlen);
332       memset(ContextID, 0, UUIDlen);
333       memset(CryptographicKeyID, 0, UUIDlen);
334
335       ProductVersion = "Unreleased ";
336       ProductVersion += Version();
337       CompanyName = "DCI";
338       ProductName = "asdcplib";
339     }
340   };
341
342   // Print WriterInfo to stream, stderr by default.
343   void WriterInfoDump(const WriterInfo&, FILE* = 0);
344
345   //---------------------------------------------------------------------------------
346   // cryptographic support
347
348   // The following classes define interfaces to Rijndael contexts having the following properties:
349   //  o 16 byte key
350   //  o CBC mode with 16 byte block size
351   const ui32_t CBC_KEY_SIZE = 16;
352   const ui32_t CBC_BLOCK_SIZE = 16;
353   const ui32_t HMAC_SIZE = 20;
354
355   //
356   class AESEncContext
357     {
358       class h__AESContext;
359       mem_ptr<h__AESContext> m_Context;
360       ASDCP_NO_COPY_CONSTRUCT(AESEncContext);
361
362     public:
363       AESEncContext();
364       ~AESEncContext();
365
366       // Initializes Rijndael CBC encryption context.
367       // Returns error if the key argument is NULL.
368       Result_t InitKey(const byte_t* key);
369       
370       // Initializes 16 byte CBC Initialization Vector. This operation may be performed
371       // any number of times for a given key.
372       // Returns error if the i_vec argument is NULL.
373       Result_t SetIVec(const byte_t* i_vec);
374       Result_t GetIVec(byte_t* i_vec) const;
375
376       // Encrypt a block of data. The block size must be a multiple of CBC_BLOCK_SIZE.
377       // Returns error if either argument is NULL.
378       Result_t EncryptBlock(const byte_t* pt_buf, byte_t* ct_buf, ui32_t block_size);
379     };
380
381   //
382   class AESDecContext
383     {
384       class h__AESContext;
385       mem_ptr<h__AESContext> m_Context;
386       ASDCP_NO_COPY_CONSTRUCT(AESDecContext);
387
388     public:
389       AESDecContext();
390       ~AESDecContext();
391
392       // Initializes Rijndael CBC decryption context.
393       // Returns error if the key argument is NULL.
394       Result_t InitKey(const byte_t* key);
395
396       // Initializes 16 byte CBC Initialization Vector. This operation may be performed
397       // any number of times for a given key.
398       // Returns error if the i_vec argument is NULL.
399       Result_t SetIVec(const byte_t* i_vec);
400
401       // Decrypt a block of data. The block size must be a multiple of CBC_BLOCK_SIZE.
402       // Returns error if either argument is NULL.
403       Result_t DecryptBlock(const byte_t* ct_buf, byte_t* pt_buf, ui32_t block_size);
404     };
405
406   //
407   class HMACContext
408     {
409       class h__HMACContext;
410       mem_ptr<h__HMACContext> m_Context;
411       ASDCP_NO_COPY_CONSTRUCT(HMACContext);
412
413     public:
414       HMACContext();
415       ~HMACContext();
416
417       // Initializes HMAC context. The key argument must point to a binary
418       // key that is CBC_KEY_SIZE bytes in length. Returns error if the key
419       // argument is NULL.
420       Result_t InitKey(const byte_t* key, LabelSet_t);
421
422       // Reset internal state, allows repeated cycles of Update -> Finalize
423       void Reset();
424
425       // Add data to the digest. Returns error if the key argument is NULL or
426       // if the digest has been finalized.
427       Result_t Update(const byte_t* buf, ui32_t buf_len);
428
429       // Finalize digest.  Returns error if the digest has already been finalized.
430       Result_t Finalize();
431
432       // Writes HMAC value to given buffer. buf must point to a writable area of
433       // memory that is at least HMAC_SIZE bytes in length. Returns error if the
434       // buf argument is NULL or if the digest has not been finalized.
435       Result_t GetHMACValue(byte_t* buf) const;
436
437       // Tests the given value against the finalized value in the object. buf must
438       // point to a readable area of memory that is at least HMAC_SIZE bytes in length.
439       // Returns error if the buf argument is NULL or if the values do ot match.
440       Result_t TestHMACValue(const byte_t* buf) const;
441     };
442
443   //---------------------------------------------------------------------------------
444   // frame buffer base class
445   //
446   // The supported essence types are stored using per-frame KLV packetization. The
447   // following class implements essence-neutral functionality for managing a buffer
448   // containing a frame of essence.
449
450   class FrameBuffer
451     {
452       ASDCP_NO_COPY_CONSTRUCT(FrameBuffer);
453
454     protected:
455       byte_t* m_Data;          // pointer to memory area containing frame data
456       ui32_t  m_Capacity;      // size of memory area pointed to by m_Data
457       bool    m_OwnMem;        // if false, m_Data points to externally allocated memory
458       ui32_t  m_Size;          // size of frame data in memory area pointed to by m_Data
459       ui32_t  m_FrameNumber;   // delivery-order frame number
460
461       // It is possible to read raw ciphertext from an encrypted AS-DCP file.
462       // After reading an encrypted AS-DCP file in raw mode, the frame buffer will
463       // contain the encrypted source value portion of the Encrypted Triplet, followed
464       // by the integrity pack, if it exists.
465       // The buffer will begin with the IV and CheckValue, followed by encrypted essence
466       // and optional integrity pack
467       // The SourceLength and PlaintextOffset values from the packet will be held in the
468       // following variables:
469       ui32_t  m_SourceLength;       // plaintext length (delivered plaintext+decrypted ciphertext)
470       ui32_t  m_PlaintextOffset;    // offset to first byte of ciphertext
471
472      public:
473       FrameBuffer();
474       virtual ~FrameBuffer();
475
476       // Instructs the object to use an externally allocated buffer. The external
477       // buffer will not be cleaned up by the frame buffer when it exits.
478       // Call with (0,0) to revert to internally allocated buffer.
479       // Returns error if the buf_addr argument is NULL and buf_size is non-zero.
480       Result_t SetData(byte_t* buf_addr, ui32_t buf_size);
481
482       // Sets the size of the internally allocate buffer. Returns RESULT_CAPEXTMEM
483       // if the object is using an externally allocated buffer via SetData();
484       // Resets content size to zero.
485       Result_t Capacity(ui32_t cap);
486
487       // returns the size of the buffer
488       inline ui32_t  Capacity() const { return m_Capacity; }
489
490       // returns a const pointer to the essence data
491       inline const byte_t* RoData() const { return m_Data; }
492
493       // returns a non-const pointer to the essence data
494       inline byte_t* Data() { return m_Data; }
495
496       // set the size of the buffer's contents
497       inline ui32_t  Size(ui32_t size) { return m_Size = size; }
498
499       // returns the size of the buffer's contents
500       inline ui32_t  Size() const { return m_Size; }
501
502       // Sets the absolute frame number of this frame in the file in delivery order.
503       inline void    FrameNumber(ui32_t num) { m_FrameNumber = num; }
504
505       // Returns the absolute frame number of this frame in the file in delivery order.
506       inline ui32_t  FrameNumber() const { return m_FrameNumber; }
507
508       // Sets the length of the plaintext essence data
509       inline void    SourceLength(ui32_t len) { m_SourceLength = len; }
510
511       // When this value is 0 (zero), the buffer contains only plaintext. When it is
512       // non-zero, the buffer contains raw ciphertext and the return value is the length
513       // of the original plaintext.
514       inline ui32_t  SourceLength() const { return m_SourceLength; }
515
516       // Sets the offset into the buffer at which encrypted data begins
517       inline void    PlaintextOffset(ui32_t ofst) { m_PlaintextOffset = ofst; }
518
519       // Returns offset into buffer of first byte of ciphertext.
520       inline ui32_t  PlaintextOffset() const { return m_PlaintextOffset; }
521     };
522
523
524   //---------------------------------------------------------------------------------
525   // MPEG2 video elementary stream support
526
527   //
528   namespace MPEG2
529     {
530       // MPEG picture coding type
531       enum FrameType_t {
532         FRAME_U = 0x00, // Unknown
533         FRAME_I = 0x01, // I-Frame
534         FRAME_P = 0x02, // P-Frame
535         FRAME_B = 0x03  // B-Frame
536       };
537
538       // convert FrameType_t to char
539       inline char FrameTypeChar(FrameType_t type)
540         {
541           switch ( type )
542             {
543             case FRAME_I: return 'I';
544             case FRAME_B: return 'B';
545             case FRAME_P: return 'P';
546             default: return 'U';
547             }
548         }
549
550       // Structure represents the metadata elements in the file header's
551       // MPEG2VideoDescriptor object.
552       struct VideoDescriptor
553         {
554           Rational EditRate;                // 
555           ui32_t   FrameRate;               // 
556           Rational SampleRate;              // 
557           ui8_t    FrameLayout;             // 
558           ui32_t   StoredWidth;             // 
559           ui32_t   StoredHeight;            // 
560           Rational AspectRatio;             // 
561           ui32_t   ComponentDepth;          // 
562           ui32_t   HorizontalSubsampling;   // 
563           ui32_t   VerticalSubsampling;     // 
564           ui8_t    ColorSiting;             // 
565           ui8_t    CodedContentType;        // 
566           bool     LowDelay;                // 
567           ui32_t   BitRate;                 // 
568           ui8_t    ProfileAndLevel;         // 
569           ui32_t   ContainerDuration;       // 
570       };
571
572       // Print VideoDescriptor to stream, stderr by default.
573       void VideoDescriptorDump(const VideoDescriptor&, FILE* = 0);
574
575       // A container for MPEG frame data.
576       class FrameBuffer : public ASDCP::FrameBuffer
577         {
578           ASDCP_NO_COPY_CONSTRUCT(FrameBuffer); // TODO: should have copy construct
579
580         protected:
581           FrameType_t m_FrameType;
582           ui8_t       m_TemporalOffset;
583           bool        m_ClosedGOP;
584           bool        m_GOPStart;
585
586         public:
587           FrameBuffer() :
588             m_FrameType(FRAME_U), m_TemporalOffset(0),
589             m_ClosedGOP(false), m_GOPStart(false) {}
590
591           FrameBuffer(ui32_t size) :
592             m_FrameType(FRAME_U), m_TemporalOffset(0),
593             m_ClosedGOP(false), m_GOPStart(false)
594             {
595               Capacity(size);
596             }
597             
598           virtual ~FrameBuffer() {}
599
600           // Sets the MPEG frame type of the picture data in the frame buffer.
601           inline void FrameType(FrameType_t type) { m_FrameType = type; }
602
603           // Returns the MPEG frame type of the picture data in the frame buffer.
604           inline FrameType_t FrameType() const { return m_FrameType; }
605
606           // Sets the MPEG temporal offset of the picture data in the frame buffer.
607           inline void TemporalOffset(ui8_t offset) { m_TemporalOffset = offset; }
608
609           // Returns the MPEG temporal offset of the picture data in the frame buffer.
610           inline ui8_t TemporalOffset() const { return m_TemporalOffset; }
611
612           // Sets the MPEG GOP 'start' attribute for the frame buffer.
613           inline void GOPStart(bool start) { m_GOPStart = start; }
614
615           // True if the frame in the buffer is the first in the GOP (in transport order)
616           inline bool GOPStart() const { return m_GOPStart; }
617
618           // Sets the MPEG GOP 'closed' attribute for the frame buffer.
619           inline void ClosedGOP(bool closed) { m_ClosedGOP = closed; }
620
621           // Returns true if the frame in the buffer is from a closed GOP, false if
622           // the frame is from an open GOP.  Always returns false unless GOPStart()
623           // returns true.
624           inline bool ClosedGOP() const { return m_ClosedGOP; }
625
626           // Print object state to stream, include n bytes of frame data if indicated.
627           // Default stream is stderr.
628           void    Dump(FILE* = 0, ui32_t dump_len = 0) const;
629         };
630
631
632       // An object which opens and reads an MPEG2 Video Elementary Stream file.  The call to
633       // OpenRead() reads metadata from the file and populates an internal VideoDescriptor object.
634       // Each subsequent call to ReadFrame() reads exactly one frame from the stream into the
635       // given FrameBuffer object.
636       class Parser
637         {
638           class h__Parser;
639           mem_ptr<h__Parser> m_Parser;
640           ASDCP_NO_COPY_CONSTRUCT(Parser);
641
642         public:
643           Parser();
644           virtual ~Parser();
645
646           // Opens the stream for reading, parses enough data to provide a complete
647           // set of stream metadata for the MXFWriter below.
648           Result_t OpenRead(const char* filename) const;
649
650           // Fill a VideoDescriptor struct with the values from the file's header.
651           // Returns RESULT_INIT if the file is not open.
652           Result_t FillVideoDescriptor(VideoDescriptor&) const;
653
654           // Rewind the stream to the beginning.
655           Result_t Reset() const;
656
657           // Reads the next sequential frame in the input file and places it in the
658           // frame buffer. Fails if the buffer is too small or the stream is empty.
659           // The frame buffer's PlaintextOffset parameter will be set to the first
660           // data byte of the first slice. Set this value to zero if you want
661           // encrypted headers.
662           Result_t ReadFrame(FrameBuffer&) const;
663         };
664
665       // A class which creates and writes MPEG frame data to an AS-DCP format MXF file.
666       // Not yet implemented
667       class MXFWriter
668         {
669           class h__Writer;
670           mem_ptr<h__Writer> m_Writer;
671           ASDCP_NO_COPY_CONSTRUCT(MXFWriter);
672
673         public:
674           MXFWriter();
675           virtual ~MXFWriter();
676
677           // Open the file for writing. The file must not exist. Returns error if
678           // the operation cannot be completed or if nonsensical data is discovered
679           // in the essence descriptor.
680           Result_t OpenWrite(const char* filename, const WriterInfo&,
681                              const VideoDescriptor&, ui32_t HeaderSize = 16384);
682
683           // Writes a frame of essence to the MXF file. If the optional AESEncContext
684           // argument is present, the essence is encrypted prior to writing.
685           // Fails if the file is not open, is finalized, or an operating system
686           // error occurs.
687           Result_t WriteFrame(const FrameBuffer&, AESEncContext* = 0, HMACContext* = 0);
688
689           // Closes the MXF file, writing the index and revised header.
690           Result_t Finalize();
691         };
692
693       // A class which reads MPEG frame data from an AS-DCP format MXF file.
694       class MXFReader
695         {
696           class h__Reader;
697           mem_ptr<h__Reader> m_Reader;
698           ASDCP_NO_COPY_CONSTRUCT(MXFReader);
699
700         public:
701           MXFReader();
702           virtual ~MXFReader();
703
704           // Open the file for reading. The file must exist. Returns error if the
705           // operation cannot be completed.
706           Result_t OpenRead(const char* filename) const;
707
708           // Returns RESULT_INIT if the file is not open.
709           Result_t Close() const;
710
711           // Fill a VideoDescriptor struct with the values from the file's header.
712           // Returns RESULT_INIT if the file is not open.
713           Result_t FillVideoDescriptor(VideoDescriptor&) const;
714
715           // Fill a WriterInfo struct with the values from the file's header.
716           // Returns RESULT_INIT if the file is not open.
717           Result_t FillWriterInfo(WriterInfo&) const;
718
719           // Reads a frame of essence from the MXF file. If the optional AESEncContext
720           // argument is present, the essence is decrypted after reading. If the MXF
721           // file is encrypted and the AESDecContext argument is NULL, the frame buffer
722           // will contain the ciphertext frame data. If the HMACContext argument is
723           // not NULL, the HMAC will be calculated (if the file supports it).
724           // Returns RESULT_INIT if the file is not open, failure if the frame number is
725           // out of range, or if optional decrypt or HAMC operations fail.
726           Result_t ReadFrame(ui32_t frame_number, FrameBuffer&, AESDecContext* = 0, HMACContext* = 0) const;
727
728           // Calculates the first frame in transport order of the GOP in which the requested
729           // frame is located.  Calls ReadFrame() to fetch the frame at the calculated position.
730           // Returns RESULT_INIT if the file is not open.
731           Result_t ReadFrameGOPStart(ui32_t frame_number, FrameBuffer&, AESDecContext* = 0, HMACContext* = 0) const;
732
733           // Calculates the first frame in transport order of the GOP in which the requested
734           // frame is located.  Sets key_frame_number to the number of the frame at the calculated position.
735           // Returns RESULT_INIT if the file is not open.
736           Result_t FindFrameGOPStart(ui32_t frame_number, ui32_t& key_frame_number) const;
737
738           // Returns the type of the frame at the given position.
739           // Returns RESULT_INIT if the file is not open or RESULT_RANGE if the index is out of range.
740           Result_t FrameType(ui32_t frame_number, FrameType_t&) const;
741
742           // Print debugging information to stream
743           void     DumpHeaderMetadata(FILE* = 0) const;
744           void     DumpIndex(FILE* = 0) const;
745         };
746     } // namespace MPEG2
747
748   //
749   namespace PCM
750     {
751       struct AudioDescriptor
752         {
753           Rational SampleRate;         // rate of frame wrapping
754           Rational AudioSamplingRate;  // rate of audio sample
755           ui32_t   Locked;             // 
756           ui32_t   ChannelCount;       // number of channels
757           ui32_t   QuantizationBits;   // number of bits per single-channel sample
758           ui32_t   BlockAlign;         // number of bytes ber sample, all channels
759           ui32_t   AvgBps;             // 
760           ui32_t   LinkedTrackID;      // 
761           ui32_t   ContainerDuration;  // number of frames
762       };
763
764       // Print debugging information to stream (stderr default)
765       void   AudioDescriptorDump(const AudioDescriptor&, FILE* = 0);
766
767       // Returns size in bytes of a single sample of data described by ADesc
768       inline ui32_t CalcSampleSize(const AudioDescriptor& ADesc)
769         {
770           return (ADesc.QuantizationBits / 8) * ADesc.ChannelCount;
771         }
772
773       // Returns number of samples per frame of data described by ADesc
774       inline ui32_t CalcSamplesPerFrame(const AudioDescriptor& ADesc)
775         {
776           double tmpd = ADesc.AudioSamplingRate.Quotient() / ADesc.SampleRate.Quotient();
777           return (ui32_t)ceil(tmpd);
778         }
779
780       // Returns the size in bytes of a frame of data described by ADesc
781       inline ui32_t CalcFrameBufferSize(const AudioDescriptor& ADesc)
782         {
783           return CalcSampleSize(ADesc) * CalcSamplesPerFrame(ADesc);
784         }
785
786       //
787       class FrameBuffer : public ASDCP::FrameBuffer
788         {
789         public:
790           FrameBuffer() {}
791           FrameBuffer(ui32_t size) { Capacity(size); }
792           virtual ~FrameBuffer() {}
793         
794           // Print debugging information to stream (stderr default)
795           void Dump(FILE* = 0, ui32_t dump_bytes = 0) const;
796         };
797
798       // An object which opens and reads a WAV file.  The call to OpenRead() reads metadata from
799       // the file and populates an internal AudioDescriptor object. Each subsequent call to
800       // ReadFrame() reads exactly one frame from the stream into the given FrameBuffer object.
801       // A "frame" is either 2000 or 2002 samples, depending upon the value of PictureRate.
802       class WAVParser
803         {
804           class h__WAVParser;
805           mem_ptr<h__WAVParser> m_Parser;
806           ASDCP_NO_COPY_CONSTRUCT(WAVParser);
807
808         public:
809           WAVParser();
810           virtual ~WAVParser();
811
812           // Opens the stream for reading, parses enough data to provide a complete
813           // set of stream metadata for the MXFWriter below. PictureRate controls
814           // ther frame rate for the MXF frame wrapping option.
815           Result_t OpenRead(const char* filename, const Rational& PictureRate) const;
816
817           // Fill an AudioDescriptor struct with the values from the file's header.
818           // Returns RESULT_INIT if the file is not open.
819           Result_t FillAudioDescriptor(AudioDescriptor&) const;
820
821           // Rewind the stream to the beginning.
822           Result_t Reset() const;
823
824           // Reads the next sequential frame in the input file and places it in the
825           // frame buffer. Fails if the buffer is too small or the stream is empty.
826           Result_t ReadFrame(FrameBuffer&) const;
827         };
828
829
830       //
831       class MXFWriter
832         {
833           class h__Writer;
834           mem_ptr<h__Writer> m_Writer;
835           ASDCP_NO_COPY_CONSTRUCT(MXFWriter);
836
837         public:
838           MXFWriter();
839           virtual ~MXFWriter();
840
841           // Open the file for writing. The file must not exist. Returns error if
842           // the operation cannot be completed or if nonsensical data is discovered
843           // in the essence descriptor.
844           Result_t OpenWrite(const char* filename, const WriterInfo&,
845                              const AudioDescriptor&, ui32_t HeaderSize = 16384);
846
847           // Writes a frame of essence to the MXF file. If the optional AESEncContext
848           // argument is present, the essence is encrypted prior to writing.
849           // Fails if the file is not open, is finalized, or an operating system
850           // error occurs.
851           Result_t WriteFrame(const FrameBuffer&, AESEncContext* = 0, HMACContext* = 0);
852
853           // Closes the MXF file, writing the index and revised header.
854           Result_t Finalize();
855         };
856
857       //
858       class MXFReader
859         {
860           class h__Reader;
861           mem_ptr<h__Reader> m_Reader;
862           ASDCP_NO_COPY_CONSTRUCT(MXFReader);
863
864         public:
865           MXFReader();
866           virtual ~MXFReader();
867
868           // Open the file for reading. The file must exist. Returns error if the
869           // operation cannot be completed.
870           Result_t OpenRead(const char* filename) const;
871
872           // Returns RESULT_INIT if the file is not open.
873           Result_t Close() const;
874
875           // Fill an AudioDescriptor struct with the values from the file's header.
876           // Returns RESULT_INIT if the file is not open.
877           Result_t FillAudioDescriptor(AudioDescriptor&) const;
878
879           // Fill a WriterInfo struct with the values from the file's header.
880           // Returns RESULT_INIT if the file is not open.
881           Result_t FillWriterInfo(WriterInfo&) const;
882
883           // Reads a frame of essence from the MXF file. If the optional AESEncContext
884           // argument is present, the essence is decrypted after reading. If the MXF
885           // file is encrypted and the AESDecContext argument is NULL, the frame buffer
886           // will contain the ciphertext frame data. If the HMACContext argument is
887           // not NULL, the HMAC will be calculated (if the file supports it).
888           // Returns RESULT_INIT if the file is not open, failure if the frame number is
889           // out of range, or if optional decrypt or HAMC operations fail.
890           Result_t ReadFrame(ui32_t frame_number, FrameBuffer&, AESDecContext* = 0, HMACContext* = 0) const;
891
892           // Print debugging information to stream
893           void     DumpHeaderMetadata(FILE* = 0) const;
894           void     DumpIndex(FILE* = 0) const;
895         };
896     } // namespace PCM
897
898   //
899   namespace JP2K
900     {
901       const ui32_t MaxComponents = 3;
902       const ui32_t DefaultCodingDataLength = 64;
903
904       struct ImageComponent
905       {
906         byte_t Ssize;
907         byte_t XRsize;
908         byte_t YRsize;
909       };
910
911       struct PictureDescriptor
912       {
913         Rational       EditRate;
914         ui32_t         ContainerDuration;
915         Rational       SampleRate;
916         ui32_t         StoredWidth;
917         ui32_t         StoredHeight;
918         Rational       AspectRatio;
919         ui16_t         Rsize;
920         ui32_t         Xsize;
921         ui32_t         Ysize;
922         ui32_t         XOsize;
923         ui32_t         YOsize;
924         ui32_t         XTsize;
925         ui32_t         YTsize;
926         ui32_t         XTOsize;
927         ui32_t         YTOsize;
928         ui16_t         Csize;
929         ImageComponent ImageComponents[MaxComponents];
930         byte_t         CodingStyle[DefaultCodingDataLength];
931         ui32_t         CodingStyleLength;
932         byte_t         QuantDefault[DefaultCodingDataLength];
933         ui32_t         QuantDefaultLength;
934       };
935
936       // Print debugging information to stream (stderr default)
937       void   PictureDescriptorDump(const PictureDescriptor&, FILE* = 0);
938
939       //
940       class FrameBuffer : public ASDCP::FrameBuffer
941         {
942         public:
943           FrameBuffer() {}
944           FrameBuffer(ui32_t size) { Capacity(size); }
945           virtual ~FrameBuffer() {}
946         
947           // Print debugging information to stream (stderr default)
948           void Dump(FILE* = 0, ui32_t dump_bytes = 0) const;
949         };
950
951
952       // An object which opens and reads a JPEG 2000 codestream file.  The file is expected
953       // to contain exactly one complete frame of picture essence as an unwrapped (raw)
954       // ISO/IEC 15444 codestream.
955       class CodestreamParser
956         {
957           class h__CodestreamParser;
958           mem_ptr<h__CodestreamParser> m_Parser;
959           ASDCP_NO_COPY_CONSTRUCT(CodestreamParser);
960
961         public:
962           CodestreamParser();
963           virtual ~CodestreamParser();
964
965           // Opens a file for reading, parses enough data to provide a complete
966           // set of stream metadata for the MXFWriter below.
967           // The frame buffer's PlaintextOffset parameter will be set to the first
968           // byte of the data segment. Set this value to zero if you want
969           // encrypted headers.
970           Result_t OpenReadFrame(const char* filename, FrameBuffer&) const;
971
972           // Fill a PictureDescriptor struct with the values from the file's codestream.
973           // Returns RESULT_INIT if the file is not open.
974           Result_t FillPictureDescriptor(PictureDescriptor&) const;
975         };
976
977       // An object which reads a sequence of files containing JPEG 2000 pictures.
978       class SequenceParser
979         {
980           class h__SequenceParser;
981           mem_ptr<h__SequenceParser> m_Parser;
982           ASDCP_NO_COPY_CONSTRUCT(SequenceParser);
983
984         public:
985           SequenceParser();
986           virtual ~SequenceParser();
987
988           // Opens a directory for reading.  The directory is expected to contain one or
989           // more files, each containing the codestream for exactly one picture. The
990           // files must be named such that the frames are in temporal order when sorted
991           // alphabetically by filename. The parser will automatically parse enough data
992           // from the first file to provide a complete set of stream metadata for the
993           // MXFWriter below.  If the "pedantic" parameter is given and is true, the
994           // parser will check the metadata for each codestream and fail if a 
995           // mismatch is detected.
996           Result_t OpenRead(const char* filename, bool pedantic = false) const;
997
998           // Fill a PictureDescriptor struct with the values from the first file's codestream.
999           // Returns RESULT_INIT if the directory is not open.
1000           Result_t FillPictureDescriptor(PictureDescriptor&) const;
1001
1002           // Rewind the directory to the beginning.
1003           Result_t Reset() const;
1004
1005           // Reads the next sequential frame in the directory and places it in the
1006           // frame buffer. Fails if the buffer is too small or the direcdtory
1007           // contains no more files.
1008           // The frame buffer's PlaintextOffset parameter will be set to the first
1009           // byte of the data segment. Set this value to zero if you want
1010           // encrypted headers.
1011           Result_t ReadFrame(FrameBuffer&) const;
1012         };
1013
1014
1015       //
1016       class MXFWriter
1017         {
1018           class h__Writer;
1019           mem_ptr<h__Writer> m_Writer;
1020           ASDCP_NO_COPY_CONSTRUCT(MXFWriter);
1021
1022         public:
1023           MXFWriter();
1024           virtual ~MXFWriter();
1025
1026           // Open the file for writing. The file must not exist. Returns error if
1027           // the operation cannot be completed or if nonsensical data is discovered
1028           // in the essence descriptor.
1029           Result_t OpenWrite(const char* filename, const WriterInfo&,
1030                              const PictureDescriptor&, ui32_t HeaderSize = 16384);
1031
1032           // Writes a frame of essence to the MXF file. If the optional AESEncContext
1033           // argument is present, the essence is encrypted prior to writing.
1034           // Fails if the file is not open, is finalized, or an operating system
1035           // error occurs.
1036           Result_t WriteFrame(const FrameBuffer&, AESEncContext* = 0, HMACContext* = 0);
1037
1038           // Closes the MXF file, writing the index and revised header.
1039           Result_t Finalize();
1040         };
1041
1042       //
1043       class MXFReader
1044         {
1045           class h__Reader;
1046           mem_ptr<h__Reader> m_Reader;
1047           ASDCP_NO_COPY_CONSTRUCT(MXFReader);
1048
1049         public:
1050           MXFReader();
1051           virtual ~MXFReader();
1052
1053           // Open the file for reading. The file must exist. Returns error if the
1054           // operation cannot be completed.
1055           Result_t OpenRead(const char* filename) const;
1056
1057           // Returns RESULT_INIT if the file is not open.
1058           Result_t Close() const;
1059
1060           // Fill an AudioDescriptor struct with the values from the file's header.
1061           // Returns RESULT_INIT if the file is not open.
1062           Result_t FillPictureDescriptor(PictureDescriptor&) const;
1063
1064           // Fill a WriterInfo struct with the values from the file's header.
1065           // Returns RESULT_INIT if the file is not open.
1066           Result_t FillWriterInfo(WriterInfo&) const;
1067
1068           // Reads a frame of essence from the MXF file. If the optional AESEncContext
1069           // argument is present, the essence is decrypted after reading. If the MXF
1070           // file is encrypted and the AESDecContext argument is NULL, the frame buffer
1071           // will contain the ciphertext frame data. If the HMACContext argument is
1072           // not NULL, the HMAC will be calculated (if the file supports it).
1073           // Returns RESULT_INIT if the file is not open, failure if the frame number is
1074           // out of range, or if optional decrypt or HAMC operations fail.
1075           Result_t ReadFrame(ui32_t frame_number, FrameBuffer&, AESDecContext* = 0, HMACContext* = 0) const;
1076
1077           // Print debugging information to stream
1078           void     DumpHeaderMetadata(FILE* = 0) const;
1079           void     DumpIndex(FILE* = 0) const;
1080         };
1081
1082
1083       // Stereoscopic Image support
1084       //
1085
1086       enum StereoscopicPhase_t
1087       {
1088         SP_LEFT,
1089         SP_RIGHT
1090       };
1091
1092
1093       class MXFSWriter
1094         {
1095           class h__SWriter;
1096           mem_ptr<h__SWriter> m_Writer;
1097           ASDCP_NO_COPY_CONSTRUCT(MXFSWriter);
1098
1099         public:
1100           MXFSWriter();
1101           virtual ~MXFSWriter();
1102
1103           // Open the file for writing. The file must not exist. Returns error if
1104           // the operation cannot be completed or if nonsensical data is discovered
1105           // in the essence descriptor.
1106           Result_t OpenWrite(const char* filename, const WriterInfo&,
1107                              const PictureDescriptor&, ui32_t HeaderSize = 16384);
1108
1109           // Writes a frame of essence to the MXF file. If the optional AESEncContext
1110           // argument is present, the essence is encrypted prior to writing.
1111           // Fails if the file is not open, is finalized, or an operating system
1112           // error occurs. Frames must be written in the proper phase (L-R-L-R),
1113           // RESULT_SPHASE will be returned if phase is reversed. The first frame
1114           // written must be left eye.
1115           Result_t WriteFrame(const FrameBuffer&, StereoscopicPhase_t phase,
1116                               AESEncContext* = 0, HMACContext* = 0);
1117
1118           // Closes the MXF file, writing the index and revised header.  Returns
1119           // RESULT_SPHASE if WriteFrame was called an odd number of times.
1120           Result_t Finalize();
1121         };
1122
1123       //
1124       class MXFSReader
1125         {
1126           class h__SReader;
1127           mem_ptr<h__SReader> m_Reader;
1128           ASDCP_NO_COPY_CONSTRUCT(MXFSReader);
1129
1130         public:
1131           MXFSReader();
1132           virtual ~MXFSReader();
1133
1134           // Open the file for reading. The file must exist. Returns error if the
1135           // operation cannot be completed.
1136           Result_t OpenRead(const char* filename) const;
1137
1138           // Returns RESULT_INIT if the file is not open.
1139           Result_t Close() const;
1140
1141           // Fill an AudioDescriptor struct with the values from the file's header.
1142           // Returns RESULT_INIT if the file is not open.
1143           Result_t FillPictureDescriptor(PictureDescriptor&) const;
1144
1145           // Fill a WriterInfo struct with the values from the file's header.
1146           // Returns RESULT_INIT if the file is not open.
1147           Result_t FillWriterInfo(WriterInfo&) const;
1148
1149           // Reads a frame of essence from the MXF file. If the optional AESEncContext
1150           // argument is present, the essence is decrypted after reading. If the MXF
1151           // file is encrypted and the AESDecContext argument is NULL, the frame buffer
1152           // will contain the ciphertext frame data. If the HMACContext argument is
1153           // not NULL, the HMAC will be calculated (if the file supports it).
1154           // Returns RESULT_INIT if the file is not open, failure if the frame number is
1155           // out of range, or if optional decrypt or HAMC operations fail.
1156           Result_t ReadFrame(ui32_t frame_number, StereoscopicPhase_t phase,
1157                              FrameBuffer&, AESDecContext* = 0, HMACContext* = 0) const;
1158
1159           // Print debugging information to stream
1160           void     DumpHeaderMetadata(FILE* = 0) const;
1161           void     DumpIndex(FILE* = 0) const;
1162         };
1163     } // namespace JP2K
1164 } // namespace ASDCP
1165
1166
1167 #endif // _AS_DCP_H_
1168
1169 //
1170 // end AS_DCP.h
1171 //