summaryrefslogtreecommitdiff
path: root/asdcplib/src/AS_DCP.h
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2012-07-16 19:25:13 +0100
committerCarl Hetherington <cth@carlh.net>2012-07-16 19:25:13 +0100
commitec1097e8426461b854b38e7b14bc73995c365e0a (patch)
tree19c8e41ff4061f48ba23524bc8e38f5398c1f21a /asdcplib/src/AS_DCP.h
parent7d48446b5efdf795df1ce22d6d9ed3ebe85d3381 (diff)
asdcplib 1.9.45
Diffstat (limited to 'asdcplib/src/AS_DCP.h')
-rwxr-xr-xasdcplib/src/AS_DCP.h1556
1 files changed, 1556 insertions, 0 deletions
diff --git a/asdcplib/src/AS_DCP.h b/asdcplib/src/AS_DCP.h
new file mode 100755
index 00000000..b227c063
--- /dev/null
+++ b/asdcplib/src/AS_DCP.h
@@ -0,0 +1,1556 @@
+/*
+Copyright (c) 2003-2012, John Hurst
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*! \file AS_DCP.h
+ \version $Id: AS_DCP.h,v 1.43 2012/02/02 01:58:43 jhurst Exp $
+ \brief AS-DCP library, public interface
+
+The asdcplib library is a set of file access objects that offer simplified
+access to files conforming to the standards published by the SMPTE
+D-Cinema Technology Committee 21DC. The file format, labeled AS-DCP,
+is described in series of separate documents which include but may not
+be be limited to:
+
+ o SMPTE ST 429-2:2011 DCP Operational Constraints
+ o SMPTE ST 429-3:2006 Sound and Picture Track File
+ o SMPTE ST 429-4:2006 MXF JPEG 2000 Application
+ o SMPTE ST 429-5:2009 Timed Text Track File
+ o SMPTE ST 429-6:2006 MXF Track File Essence Encryption
+ o SMPTE ST 429-10:2008 Stereoscopic Picture Track File
+ o SMPTE ST 330:2004 - UMID
+ o SMPTE ST 336:2001 - KLV
+ o SMPTE ST 377-1:2011 - MXF
+ o SMPTE ST 377-4:2012 - MXF Multichannel Audio Labeling Framework
+ o SMPTE ST 390:2011 - MXF OP-Atom
+ o SMPTE ST 379-1:2009 - MXF Generic Container (GC)
+ o SMPTE ST 381-1:2005 - MPEG2 picture in GC
+ o SMPTE ST 422:2006 - JPEG 2000 picture in GC
+ o SMPTE ST 382:2007 - WAV/PCM sound in GC
+ o IETF RFC 2104 - HMAC/SHA1
+ o NIST FIPS 197 - AES (Rijndael) (via OpenSSL)
+
+ o MXF Interop Track File Specification
+ o MXF Interop Track File Essence Encryption Specification
+ o MXF Interop Operational Constraints Specification
+ - Note: the MXF Interop documents are not formally published.
+ Contact the asdcplib support address to get copies.
+
+The following use cases are supported by the library:
+
+ o Write essence to a plaintext or ciphertext AS-DCP file:
+ MPEG2 Video Elementary Stream
+ JPEG 2000 codestreams
+ JPEG 2000 stereoscopic codestream pairs
+ PCM audio streams
+ SMPTE 429-7 Timed Text XML with font and image resources
+
+ o Read essence from a plaintext or ciphertext AS-DCP file:
+ MPEG2 Video Elementary Stream
+ JPEG 2000 codestreams
+ JPEG 2000 stereoscopic codestream pairs
+ PCM audio streams
+ SMPTE 429-7 Timed Text XML with font and image resources
+
+ o Read header metadata from an AS-DCP file
+
+This project depends upon the following libraries:
+ - OpenSSL http://www.openssl.org/
+ - Expat http://expat.sourceforge.net/ or
+ Xerces-C http://xerces.apache.org/xerces-c/
+ An XML library is not needed if you don't need support for SMPTE ST 429-5:2009.
+*/
+
+#ifndef _AS_DCP_H_
+#define _AS_DCP_H_
+
+#include <KM_error.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <math.h>
+#include <iosfwd>
+#include <string>
+#include <cstring>
+#include <list>
+
+//--------------------------------------------------------------------------------
+// common integer types
+// supply your own by defining ASDCP_NO_BASE_TYPES
+
+#ifndef ASDCP_NO_BASE_TYPES
+typedef unsigned char byte_t;
+typedef char i8_t;
+typedef unsigned char ui8_t;
+typedef short i16_t;
+typedef unsigned short ui16_t;
+typedef int i32_t;
+typedef unsigned int ui32_t;
+#endif
+
+
+//--------------------------------------------------------------------------------
+// convenience macros
+
+// Convenience macros for managing return values in predicates
+#define ASDCP_SUCCESS(v) (((v) < 0) ? 0 : 1)
+#define ASDCP_FAILURE(v) (((v) < 0) ? 1 : 0)
+
+
+// Returns RESULT_PTR if the given argument is NULL.
+// See Result_t below for an explanation of RESULT_* symbols.
+#define ASDCP_TEST_NULL(p) \
+ if ( (p) == 0 ) { \
+ return ASDCP::RESULT_PTR; \
+ }
+
+// Returns RESULT_PTR if the given argument is NULL. See Result_t
+// below for an explanation of RESULT_* symbols. It then assumes
+// that the argument is a pointer to a string and returns
+// RESULT_NULL_STR if the first character is '\0'.
+//
+#define ASDCP_TEST_NULL_STR(p) \
+ ASDCP_TEST_NULL(p); \
+ if ( (p)[0] == '\0' ) { \
+ return ASDCP::RESULT_NULL_STR; \
+ }
+
+// Produces copy constructor boilerplate. Allows convenient private
+// declatarion of copy constructors to prevent the compiler from
+// silently manufacturing default methods.
+#define ASDCP_NO_COPY_CONSTRUCT(T) \
+ T(const T&); \
+ T& operator=(const T&)
+
+//--------------------------------------------------------------------------------
+// All library components are defined in the namespace ASDCP
+//
+namespace ASDCP {
+ //
+ // The version number declaration and explanation have moved to ../configure.ac
+ const char* Version();
+
+ // UUIDs are passed around as strings of UUIDlen bytes
+ const ui32_t UUIDlen = 16;
+
+ // Encryption keys are passed around as strings of KeyLen bytes
+ const ui32_t KeyLen = 16;
+
+ //---------------------------------------------------------------------------------
+ // return values
+
+ using Kumu::Result_t;
+
+ using Kumu::RESULT_FALSE;
+ using Kumu::RESULT_OK;
+ using Kumu::RESULT_FAIL;
+ using Kumu::RESULT_PTR;
+ using Kumu::RESULT_NULL_STR;
+ using Kumu::RESULT_ALLOC;
+ using Kumu::RESULT_PARAM;
+ using Kumu::RESULT_SMALLBUF;
+ using Kumu::RESULT_INIT;
+ using Kumu::RESULT_NOT_FOUND;
+ using Kumu::RESULT_NO_PERM;
+ using Kumu::RESULT_FILEOPEN;
+ using Kumu::RESULT_BADSEEK;
+ using Kumu::RESULT_READFAIL;
+ using Kumu::RESULT_WRITEFAIL;
+ using Kumu::RESULT_STATE;
+ using Kumu::RESULT_ENDOFFILE;
+ using Kumu::RESULT_CONFIG;
+
+ KM_DECLARE_RESULT(FORMAT, -101, "The file format is not proper OP-Atom/AS-DCP.");
+ KM_DECLARE_RESULT(RAW_ESS, -102, "Unknown raw essence file type.");
+ KM_DECLARE_RESULT(RAW_FORMAT, -103, "Raw essence format invalid.");
+ KM_DECLARE_RESULT(RANGE, -104, "Frame number out of range.");
+ KM_DECLARE_RESULT(CRYPT_CTX, -105, "AESEncContext required when writing to encrypted file.");
+ KM_DECLARE_RESULT(LARGE_PTO, -106, "Plaintext offset exceeds frame buffer size.");
+ KM_DECLARE_RESULT(CAPEXTMEM, -107, "Cannot resize externally allocated memory.");
+ KM_DECLARE_RESULT(CHECKFAIL, -108, "The check value did not decrypt correctly.");
+ KM_DECLARE_RESULT(HMACFAIL, -109, "HMAC authentication failure.");
+ KM_DECLARE_RESULT(HMAC_CTX, -110, "HMAC context required.");
+ KM_DECLARE_RESULT(CRYPT_INIT, -111, "Error initializing block cipher context.");
+ KM_DECLARE_RESULT(EMPTY_FB, -112, "Empty frame buffer.");
+ KM_DECLARE_RESULT(KLV_CODING, -113, "KLV coding error.");
+ KM_DECLARE_RESULT(SPHASE, -114, "Stereoscopic phase mismatch.");
+ KM_DECLARE_RESULT(SFORMAT, -115, "Rate mismatch, file may contain stereoscopic essence.");
+
+ //---------------------------------------------------------------------------------
+ // file identification
+
+ // The file accessors in this library implement a bounded set of essence types.
+ // This list will be expanded when support for new types is added to the library.
+ enum EssenceType_t {
+ ESS_UNKNOWN, // the file is not a supported AS-DCP essence container
+ ESS_MPEG2_VES, // the file contains an MPEG video elementary stream
+ ESS_JPEG_2000, // the file contains one or more JPEG 2000 codestreams
+ ESS_PCM_24b_48k, // the file contains one or more PCM audio pairs
+ ESS_PCM_24b_96k, // the file contains one or more PCM audio pairs
+ ESS_TIMED_TEXT, // the file contains an XML timed text document and one or more resources
+ ESS_JPEG_2000_S, // the file contains one or more JPEG 2000 codestream pairs (stereoscopic)
+ };
+
+ // Determine the type of essence contained in the given MXF file. RESULT_OK
+ // is returned if the file is successfully opened and contains a valid MXF
+ // stream. If there is an error, the result code will indicate the reason.
+ Result_t EssenceType(const char* filename, EssenceType_t& type);
+
+ // Determine the type of essence contained in the given raw file. RESULT_OK
+ // is returned if the file is successfully opened and contains a known
+ // stream type. If there is an error, the result code will indicate the reason.
+ Result_t RawEssenceType(const char* filename, EssenceType_t& type);
+
+
+ //---------------------------------------------------------------------------------
+ // base types
+
+ // A simple container for rational numbers.
+ class Rational
+ {
+ public:
+ i32_t Numerator;
+ i32_t Denominator;
+
+ Rational() : Numerator(0), Denominator(0) {}
+ Rational(i32_t n, i32_t d) : Numerator(n), Denominator(d) {}
+
+ inline double Quotient() const {
+ return (double)Numerator / (double)Denominator;
+ }
+
+ inline bool operator==(const Rational& rhs) const {
+ return ( rhs.Numerator == Numerator && rhs.Denominator == Denominator );
+ }
+
+ inline bool operator!=(const Rational& rhs) const {
+ return ( rhs.Numerator != Numerator || rhs.Denominator != Denominator );
+ }
+
+ inline bool operator<(const Rational& rhs) {
+ if ( Numerator < rhs.Numerator ) return true;
+ if ( Numerator == rhs.Numerator && Denominator < rhs.Denominator ) return true;
+ return false;
+ }
+
+ inline bool operator>(const Rational& rhs) {
+ if ( Numerator > rhs.Numerator ) return true;
+ if ( Numerator == rhs.Numerator && Denominator > rhs.Denominator ) return true;
+ return false;
+ }
+ };
+
+ // common edit rates, use these instead of hard coded constants
+ const Rational EditRate_24 = Rational(24,1);
+ const Rational EditRate_23_98 = Rational(24000,1001); // Not a DCI-compliant value!
+ const Rational EditRate_48 = Rational(48,1);
+ const Rational SampleRate_48k = Rational(48000,1);
+ const Rational SampleRate_96k = Rational(96000,1);
+
+ // Additional frame rates, see ST 428-11, ST 429-13
+ // These rates are new and not supported by all systems. Do not assume that
+ // a package made using one of these rates will work just anywhere!
+ const Rational EditRate_25 = Rational(25,1);
+ const Rational EditRate_30 = Rational(30,1);
+ const Rational EditRate_50 = Rational(50,1);
+ const Rational EditRate_60 = Rational(60,1);
+ const Rational EditRate_96 = Rational(96,1);
+ const Rational EditRate_100 = Rational(100,1);
+ const Rational EditRate_120 = Rational(120,1);
+
+ // Non-reference counting container for internal member objects.
+ // Please do not use this class for any other purpose.
+ template <class T>
+ class mem_ptr
+ {
+ T* m_p; // the thing we point to
+ mem_ptr(T&);
+
+ public:
+ mem_ptr() : m_p(0) {}
+ mem_ptr(T* p) : m_p(p) {}
+ ~mem_ptr() { delete m_p; }
+
+ inline T& operator*() const { return *m_p; }
+ inline T* operator->() const { return m_p; }
+ inline operator T*()const { return m_p; }
+ inline const mem_ptr<T>& operator=(T* p) { set(p); return *this; }
+ inline T* set(T* p) { delete m_p; m_p = p; return m_p; }
+ inline T* get() const { return m_p; }
+ inline void release() { m_p = 0; }
+ inline bool empty() const { return m_p == 0; }
+ };
+
+
+ //---------------------------------------------------------------------------------
+ // WriterInfo class - encapsulates writer identification details used for
+ // OpenWrite() calls. Replace these values at runtime to identify your product.
+ //
+ // MXF files use SMPTE Universal Labels to identify data items. The set of Labels
+ // in a file is determined by the MXF Operational Pattern and any constraining
+ // documentation. There are currently two flavors of AS-DCP file in use: MXF Interop
+ // (AKA JPEG Interop) and SMPTE. The two differ in the values of three labels:
+ //
+ // OPAtom
+ // Interop : 06 0e 2b 34 04 01 01 01 0d 01 02 01 10 00 00 00
+ // SMPTE : 06 0e 2b 34 04 01 01 02 0d 01 02 01 10 00 00 00
+ //
+ // EKLV Packet:
+ // Interop : 06 0e 2b 34 02 04 01 07 0d 01 03 01 02 7e 01 00
+ // SMPTE : 06 0e 2b 34 02 04 01 01 0d 01 03 01 02 7e 01 00
+ //
+ // GenericDescriptor/SubDescriptors:
+ // Interop : 06 0e 2b 34 01 01 01 02 06 01 01 04 06 10 00 00
+ // SMPTE : 06 0e 2b 34 01 01 01 09 06 01 01 04 06 10 00 00
+ //
+ // asdcplib will read any (otherwise valid) file which has any combination of the
+ // above values. When writing files, MXF Interop labels are used by default. To
+ // write a file containing SMPTE labels, replace the default label set value in
+ // the WriterInfo before calling OpenWrite()
+ //
+ //
+ enum LabelSet_t
+ {
+ LS_MXF_UNKNOWN,
+ LS_MXF_INTEROP,
+ LS_MXF_SMPTE
+ };
+
+ //
+ struct WriterInfo
+ {
+ byte_t ProductUUID[UUIDlen];
+ byte_t AssetUUID[UUIDlen];
+ byte_t ContextID[UUIDlen];
+ byte_t CryptographicKeyID[UUIDlen];
+ bool EncryptedEssence; // true if essence data is (or is going to be) encrypted
+ bool UsesHMAC; // true if HMAC exists or is to be calculated
+ std::string ProductVersion;
+ std::string CompanyName;
+ std::string ProductName;
+ LabelSet_t LabelSetType;
+
+ WriterInfo() : EncryptedEssence(false), UsesHMAC(false), LabelSetType(LS_MXF_INTEROP)
+ {
+ static byte_t default_ProductUUID_Data[UUIDlen] = {
+ 0x43, 0x05, 0x9a, 0x1d, 0x04, 0x32, 0x41, 0x01,
+ 0xb8, 0x3f, 0x73, 0x68, 0x15, 0xac, 0xf3, 0x1d };
+
+ memcpy(ProductUUID, default_ProductUUID_Data, UUIDlen);
+ memset(AssetUUID, 0, UUIDlen);
+ memset(ContextID, 0, UUIDlen);
+ memset(CryptographicKeyID, 0, UUIDlen);
+
+ ProductVersion = "Unreleased ";
+ ProductVersion += Version();
+ CompanyName = "DCI";
+ ProductName = "asdcplib";
+ }
+ };
+
+ // Print WriterInfo to std::ostream
+ std::ostream& operator << (std::ostream& strm, const WriterInfo& winfo);
+ // Print WriterInfo to stream, stderr by default.
+ void WriterInfoDump(const WriterInfo&, FILE* = 0);
+
+ //---------------------------------------------------------------------------------
+ // cryptographic support
+
+ // The following classes define interfaces to Rijndael contexts having the following properties:
+ // o 16 byte key
+ // o CBC mode with 16 byte block size
+ const ui32_t CBC_KEY_SIZE = 16;
+ const ui32_t CBC_BLOCK_SIZE = 16;
+ const ui32_t HMAC_SIZE = 20;
+
+ //
+ class AESEncContext
+ {
+ class h__AESContext;
+ mem_ptr<h__AESContext> m_Context;
+ ASDCP_NO_COPY_CONSTRUCT(AESEncContext);
+
+ public:
+ AESEncContext();
+ ~AESEncContext();
+
+ // Initializes Rijndael CBC encryption context.
+ // Returns error if the key argument is NULL.
+ Result_t InitKey(const byte_t* key);
+
+ // Initializes 16 byte CBC Initialization Vector. This operation may be performed
+ // any number of times for a given key.
+ // Returns error if the i_vec argument is NULL.
+ Result_t SetIVec(const byte_t* i_vec);
+ Result_t GetIVec(byte_t* i_vec) const;
+
+ // Encrypt a block of data. The block size must be a multiple of CBC_BLOCK_SIZE.
+ // Returns error if either argument is NULL.
+ Result_t EncryptBlock(const byte_t* pt_buf, byte_t* ct_buf, ui32_t block_size);
+ };
+
+ //
+ class AESDecContext
+ {
+ class h__AESContext;
+ mem_ptr<h__AESContext> m_Context;
+ ASDCP_NO_COPY_CONSTRUCT(AESDecContext);
+
+ public:
+ AESDecContext();
+ ~AESDecContext();
+
+ // Initializes Rijndael CBC decryption context.
+ // Returns error if the key argument is NULL.
+ Result_t InitKey(const byte_t* key);
+
+ // Initializes 16 byte CBC Initialization Vector. This operation may be performed
+ // any number of times for a given key.
+ // Returns error if the i_vec argument is NULL.
+ Result_t SetIVec(const byte_t* i_vec);
+
+ // Decrypt a block of data. The block size must be a multiple of CBC_BLOCK_SIZE.
+ // Returns error if either argument is NULL.
+ Result_t DecryptBlock(const byte_t* ct_buf, byte_t* pt_buf, ui32_t block_size);
+ };
+
+ //
+ class HMACContext
+ {
+ class h__HMACContext;
+ mem_ptr<h__HMACContext> m_Context;
+ ASDCP_NO_COPY_CONSTRUCT(HMACContext);
+
+ public:
+ HMACContext();
+ ~HMACContext();
+
+ // Initializes HMAC context. The key argument must point to a binary
+ // key that is CBC_KEY_SIZE bytes in length. Returns error if the key
+ // argument is NULL.
+ Result_t InitKey(const byte_t* key, LabelSet_t);
+
+ // Reset internal state, allows repeated cycles of Update -> Finalize
+ void Reset();
+
+ // Add data to the digest. Returns error if the key argument is NULL or
+ // if the digest has been finalized.
+ Result_t Update(const byte_t* buf, ui32_t buf_len);
+
+ // Finalize digest. Returns error if the digest has already been finalized.
+ Result_t Finalize();
+
+ // Writes HMAC value to given buffer. buf must point to a writable area of
+ // memory that is at least HMAC_SIZE bytes in length. Returns error if the
+ // buf argument is NULL or if the digest has not been finalized.
+ Result_t GetHMACValue(byte_t* buf) const;
+
+ // Tests the given value against the finalized value in the object. buf must
+ // point to a readable area of memory that is at least HMAC_SIZE bytes in length.
+ // Returns error if the buf argument is NULL or if the values do ot match.
+ Result_t TestHMACValue(const byte_t* buf) const;
+ };
+
+ //---------------------------------------------------------------------------------
+ // frame buffer base class
+ //
+ // The supported essence types are stored using per-frame KLV packetization. The
+ // following class implements essence-neutral functionality for managing a buffer
+ // containing a frame of essence.
+
+ class FrameBuffer
+ {
+ ASDCP_NO_COPY_CONSTRUCT(FrameBuffer);
+
+ protected:
+ byte_t* m_Data; // pointer to memory area containing frame data
+ ui32_t m_Capacity; // size of memory area pointed to by m_Data
+ bool m_OwnMem; // if false, m_Data points to externally allocated memory
+ ui32_t m_Size; // size of frame data in memory area pointed to by m_Data
+ ui32_t m_FrameNumber; // delivery-order frame number
+
+ // It is possible to read raw ciphertext from an encrypted AS-DCP file.
+ // After reading an encrypted AS-DCP file in raw mode, the frame buffer will
+ // contain the encrypted source value portion of the Encrypted Triplet, followed
+ // by the integrity pack, if it exists.
+ // The buffer will begin with the IV and CheckValue, followed by encrypted essence
+ // and optional integrity pack
+ // The SourceLength and PlaintextOffset values from the packet will be held in the
+ // following variables:
+ ui32_t m_SourceLength; // plaintext length (delivered plaintext+decrypted ciphertext)
+ ui32_t m_PlaintextOffset; // offset to first byte of ciphertext
+
+ public:
+ FrameBuffer();
+ virtual ~FrameBuffer();
+
+ // Instructs the object to use an externally allocated buffer. The external
+ // buffer will not be cleaned up by the frame buffer when it exits.
+ // Call with (0,0) to revert to internally allocated buffer.
+ // Returns error if the buf_addr argument is NULL and buf_size is non-zero.
+ Result_t SetData(byte_t* buf_addr, ui32_t buf_size);
+
+ // Sets the size of the internally allocate buffer. Returns RESULT_CAPEXTMEM
+ // if the object is using an externally allocated buffer via SetData();
+ // Resets content size to zero.
+ Result_t Capacity(ui32_t cap);
+
+ // returns the size of the buffer
+ inline ui32_t Capacity() const { return m_Capacity; }
+
+ // returns a const pointer to the essence data
+ inline const byte_t* RoData() const { return m_Data; }
+
+ // returns a non-const pointer to the essence data
+ inline byte_t* Data() { return m_Data; }
+
+ // set the size of the buffer's contents
+ inline ui32_t Size(ui32_t size) { return m_Size = size; }
+
+ // returns the size of the buffer's contents
+ inline ui32_t Size() const { return m_Size; }
+
+ // Sets the absolute frame number of this frame in the file in delivery order.
+ inline void FrameNumber(ui32_t num) { m_FrameNumber = num; }
+
+ // Returns the absolute frame number of this frame in the file in delivery order.
+ inline ui32_t FrameNumber() const { return m_FrameNumber; }
+
+ // Sets the length of the plaintext essence data
+ inline void SourceLength(ui32_t len) { m_SourceLength = len; }
+
+ // When this value is 0 (zero), the buffer contains only plaintext. When it is
+ // non-zero, the buffer contains raw ciphertext and the return value is the length
+ // of the original plaintext.
+ inline ui32_t SourceLength() const { return m_SourceLength; }
+
+ // Sets the offset into the buffer at which encrypted data begins
+ inline void PlaintextOffset(ui32_t ofst) { m_PlaintextOffset = ofst; }
+
+ // Returns offset into buffer of first byte of ciphertext.
+ inline ui32_t PlaintextOffset() const { return m_PlaintextOffset; }
+ };
+
+ //---------------------------------------------------------------------------------
+ // Accessors in the MXFReader and MXFWriter classes below return these types to
+ // provide direct access to MXF metadata structures declared in MXF.h and Metadata.h
+
+ namespace MXF {
+ // #include<Metadata.h> to use these
+ class OPAtomHeader;
+ class OPAtomIndexFooter;
+ };
+
+ //---------------------------------------------------------------------------------
+ // MPEG2 video elementary stream support
+
+ //
+ namespace MPEG2
+ {
+ // MPEG picture coding type
+ enum FrameType_t {
+ FRAME_U = 0x00, // Unknown
+ FRAME_I = 0x01, // I-Frame
+ FRAME_P = 0x02, // P-Frame
+ FRAME_B = 0x03 // B-Frame
+ };
+
+ // convert FrameType_t to char
+ inline char FrameTypeChar(FrameType_t type)
+ {
+ switch ( type )
+ {
+ case FRAME_I: return 'I';
+ case FRAME_B: return 'B';
+ case FRAME_P: return 'P';
+ default: return 'U';
+ }
+ }
+
+ // Structure represents the metadata elements in the file header's
+ // MPEG2VideoDescriptor object.
+ struct VideoDescriptor
+ {
+ Rational EditRate; //
+ ui32_t FrameRate; //
+ Rational SampleRate; //
+ ui8_t FrameLayout; //
+ ui32_t StoredWidth; //
+ ui32_t StoredHeight; //
+ Rational AspectRatio; //
+ ui32_t ComponentDepth; //
+ ui32_t HorizontalSubsampling; //
+ ui32_t VerticalSubsampling; //
+ ui8_t ColorSiting; //
+ ui8_t CodedContentType; //
+ bool LowDelay; //
+ ui32_t BitRate; //
+ ui8_t ProfileAndLevel; //
+ ui32_t ContainerDuration; //
+ };
+
+ // Print VideoDescriptor to std::ostream
+ std::ostream& operator << (std::ostream& strm, const VideoDescriptor& vdesc);
+ // Print VideoDescriptor to stream, stderr by default.
+ void VideoDescriptorDump(const VideoDescriptor&, FILE* = 0);
+
+ // A container for MPEG frame data.
+ class FrameBuffer : public ASDCP::FrameBuffer
+ {
+ ASDCP_NO_COPY_CONSTRUCT(FrameBuffer); // TODO: should have copy construct
+
+ protected:
+ FrameType_t m_FrameType;
+ ui8_t m_TemporalOffset;
+ bool m_ClosedGOP;
+ bool m_GOPStart;
+
+ public:
+ FrameBuffer() :
+ m_FrameType(FRAME_U), m_TemporalOffset(0),
+ m_ClosedGOP(false), m_GOPStart(false) {}
+
+ FrameBuffer(ui32_t size) :
+ m_FrameType(FRAME_U), m_TemporalOffset(0),
+ m_ClosedGOP(false), m_GOPStart(false)
+ {
+ Capacity(size);
+ }
+
+ virtual ~FrameBuffer() {}
+
+ // Sets the MPEG frame type of the picture data in the frame buffer.
+ inline void FrameType(FrameType_t type) { m_FrameType = type; }
+
+ // Returns the MPEG frame type of the picture data in the frame buffer.
+ inline FrameType_t FrameType() const { return m_FrameType; }
+
+ // Sets the MPEG temporal offset of the picture data in the frame buffer.
+ inline void TemporalOffset(ui8_t offset) { m_TemporalOffset = offset; }
+
+ // Returns the MPEG temporal offset of the picture data in the frame buffer.
+ inline ui8_t TemporalOffset() const { return m_TemporalOffset; }
+
+ // Sets the MPEG GOP 'start' attribute for the frame buffer.
+ inline void GOPStart(bool start) { m_GOPStart = start; }
+
+ // True if the frame in the buffer is the first in the GOP (in transport order)
+ inline bool GOPStart() const { return m_GOPStart; }
+
+ // Sets the MPEG GOP 'closed' attribute for the frame buffer.
+ inline void ClosedGOP(bool closed) { m_ClosedGOP = closed; }
+
+ // Returns true if the frame in the buffer is from a closed GOP, false if
+ // the frame is from an open GOP. Always returns false unless GOPStart()
+ // returns true.
+ inline bool ClosedGOP() const { return m_ClosedGOP; }
+
+ // Print object state to stream, include n bytes of frame data if indicated.
+ // Default stream is stderr.
+ void Dump(FILE* = 0, ui32_t dump_len = 0) const;
+ };
+
+
+ // An object which opens and reads an MPEG2 Video Elementary Stream file. The call to
+ // OpenRead() reads metadata from the file and populates an internal VideoDescriptor object.
+ // Each subsequent call to ReadFrame() reads exactly one frame from the stream into the
+ // given FrameBuffer object.
+ class Parser
+ {
+ class h__Parser;
+ mem_ptr<h__Parser> m_Parser;
+ ASDCP_NO_COPY_CONSTRUCT(Parser);
+
+ public:
+ Parser();
+ virtual ~Parser();
+
+ // Opens the stream for reading, parses enough data to provide a complete
+ // set of stream metadata for the MXFWriter below.
+ Result_t OpenRead(const char* filename) const;
+
+ // Fill a VideoDescriptor struct with the values from the file's header.
+ // Returns RESULT_INIT if the file is not open.
+ Result_t FillVideoDescriptor(VideoDescriptor&) const;
+
+ // Rewind the stream to the beginning.
+ Result_t Reset() const;
+
+ // Reads the next sequential frame in the input file and places it in the
+ // frame buffer. Fails if the buffer is too small or the stream is empty.
+ // The frame buffer's PlaintextOffset parameter will be set to the first
+ // data byte of the first slice. Set this value to zero if you want
+ // encrypted headers.
+ Result_t ReadFrame(FrameBuffer&) const;
+ };
+
+ // A class which creates and writes MPEG frame data to an AS-DCP format MXF file.
+ // Not yet implemented
+ class MXFWriter
+ {
+ class h__Writer;
+ mem_ptr<h__Writer> m_Writer;
+ ASDCP_NO_COPY_CONSTRUCT(MXFWriter);
+
+ public:
+ MXFWriter();
+ virtual ~MXFWriter();
+
+ // Warning: direct manipulation of MXF structures can interfere
+ // with the normal operation of the wrapper. Caveat emptor!
+ virtual MXF::OPAtomHeader& OPAtomHeader();
+ virtual MXF::OPAtomIndexFooter& OPAtomIndexFooter();
+
+ // Open the file for writing. The file must not exist. Returns error if
+ // the operation cannot be completed or if nonsensical data is discovered
+ // in the essence descriptor.
+ Result_t OpenWrite(const char* filename, const WriterInfo&,
+ const VideoDescriptor&, ui32_t HeaderSize = 16384);
+
+ // Writes a frame of essence to the MXF file. If the optional AESEncContext
+ // argument is present, the essence is encrypted prior to writing.
+ // Fails if the file is not open, is finalized, or an operating system
+ // error occurs.
+ Result_t WriteFrame(const FrameBuffer&, AESEncContext* = 0, HMACContext* = 0);
+
+ // Closes the MXF file, writing the index and revised header.
+ Result_t Finalize();
+ };
+
+ // A class which reads MPEG frame data from an AS-DCP format MXF file.
+ class MXFReader
+ {
+ class h__Reader;
+ mem_ptr<h__Reader> m_Reader;
+ ASDCP_NO_COPY_CONSTRUCT(MXFReader);
+
+ public:
+ MXFReader();
+ virtual ~MXFReader();
+
+ // Warning: direct manipulation of MXF structures can interfere
+ // with the normal operation of the wrapper. Caveat emptor!
+ virtual MXF::OPAtomHeader& OPAtomHeader();
+ virtual MXF::OPAtomIndexFooter& OPAtomIndexFooter();
+
+ // Open the file for reading. The file must exist. Returns error if the
+ // operation cannot be completed.
+ Result_t OpenRead(const char* filename) const;
+
+ // Returns RESULT_INIT if the file is not open.
+ Result_t Close() const;
+
+ // Fill a VideoDescriptor struct with the values from the file's header.
+ // Returns RESULT_INIT if the file is not open.
+ Result_t FillVideoDescriptor(VideoDescriptor&) const;
+
+ // Fill a WriterInfo struct with the values from the file's header.
+ // Returns RESULT_INIT if the file is not open.
+ Result_t FillWriterInfo(WriterInfo&) const;
+
+ // Reads a frame of essence from the MXF file. If the optional AESEncContext
+ // argument is present, the essence is decrypted after reading. If the MXF
+ // file is encrypted and the AESDecContext argument is NULL, the frame buffer
+ // will contain the ciphertext frame data. If the HMACContext argument is
+ // not NULL, the HMAC will be calculated (if the file supports it).
+ // Returns RESULT_INIT if the file is not open, failure if the frame number is
+ // out of range, or if optional decrypt or HAMC operations fail.
+ Result_t ReadFrame(ui32_t frame_number, FrameBuffer&, AESDecContext* = 0, HMACContext* = 0) const;
+
+ // Calculates the first frame in transport order of the GOP in which the requested
+ // frame is located. Calls ReadFrame() to fetch the frame at the calculated position.
+ // Returns RESULT_INIT if the file is not open.
+ Result_t ReadFrameGOPStart(ui32_t frame_number, FrameBuffer&, AESDecContext* = 0, HMACContext* = 0) const;
+
+ // Calculates the first frame in transport order of the GOP in which the requested
+ // frame is located. Sets key_frame_number to the number of the frame at the calculated position.
+ // Returns RESULT_INIT if the file is not open.
+ Result_t FindFrameGOPStart(ui32_t frame_number, ui32_t& key_frame_number) const;
+
+ // Returns the type of the frame at the given position.
+ // Returns RESULT_INIT if the file is not open or RESULT_RANGE if the index is out of range.
+ Result_t FrameType(ui32_t frame_number, FrameType_t&) const;
+
+ // Print debugging information to stream
+ void DumpHeaderMetadata(FILE* = 0) const;
+ void DumpIndex(FILE* = 0) const;
+ };
+ } // namespace MPEG2
+
+ //---------------------------------------------------------------------------------
+ //
+
+
+
+ namespace PCM
+ {
+ // The default value of the ChannelFormat element of the AudioDescriptor struct
+ // is CF_NONE. If the value is set to one of the other ChannelFormat_t enum
+ // values, the file's Wave Audio Descriptor will contain a Channel Assignment
+ // element.
+ //
+ // The channel format should be one of (CF_CFG_1, CF_CFG_2, or CF_CFG_3) for
+ // SMPTE 429-2 files. It should normally be CF_NONE for JPEG Interop files, but
+ // the 429-2 may also be used.
+ //
+ enum ChannelFormat_t {
+ CF_NONE,
+ CF_CFG_1, // 5.1 with optional HI/VI
+ CF_CFG_2, // 6.1 (5.1 + center surround) with optional HI/VI
+ CF_CFG_3, // 7.1 (SDDS) with optional HI/VI
+ CF_CFG_4, // Wild Track Format
+ CF_CFG_5, // 7.1 DS with optional HI/VI
+ };
+
+ struct AudioDescriptor
+ {
+ Rational EditRate; // rate of frame wrapping
+ Rational AudioSamplingRate; // rate of audio sample
+ ui32_t Locked; //
+ ui32_t ChannelCount; // number of channels
+ ui32_t QuantizationBits; // number of bits per single-channel sample
+ ui32_t BlockAlign; // number of bytes ber sample, all channels
+ ui32_t AvgBps; //
+ ui32_t LinkedTrackID; //
+ ui32_t ContainerDuration; // number of frames
+ ChannelFormat_t ChannelFormat; // audio channel arrangement
+ };
+
+ // Print AudioDescriptor to std::ostream
+ std::ostream& operator << (std::ostream& strm, const AudioDescriptor& adesc);
+ // Print debugging information to stream (stderr default)
+ void AudioDescriptorDump(const AudioDescriptor&, FILE* = 0);
+
+ // Returns size in bytes of a single sample of data described by ADesc
+ inline ui32_t CalcSampleSize(const AudioDescriptor& ADesc)
+ {
+ return (ADesc.QuantizationBits / 8) * ADesc.ChannelCount;
+ }
+
+ // Returns number of samples per frame of data described by ADesc
+ inline ui32_t CalcSamplesPerFrame(const AudioDescriptor& ADesc)
+ {
+ double tmpd = ADesc.AudioSamplingRate.Quotient() / ADesc.EditRate.Quotient();
+ return (ui32_t)ceil(tmpd);
+ }
+
+ // Returns the size in bytes of a frame of data described by ADesc
+ inline ui32_t CalcFrameBufferSize(const AudioDescriptor& ADesc)
+ {
+ return CalcSampleSize(ADesc) * CalcSamplesPerFrame(ADesc);
+ }
+
+ //
+ class FrameBuffer : public ASDCP::FrameBuffer
+ {
+ public:
+ FrameBuffer() {}
+ FrameBuffer(ui32_t size) { Capacity(size); }
+ virtual ~FrameBuffer() {}
+
+ // Print debugging information to stream (stderr default)
+ void Dump(FILE* = 0, ui32_t dump_bytes = 0) const;
+ };
+
+ // An object which opens and reads a WAV file. The call to OpenRead() reads metadata from
+ // the file and populates an internal AudioDescriptor object. Each subsequent call to
+ // ReadFrame() reads exactly one frame from the stream into the given FrameBuffer object.
+ // A "frame" is either 2000 or 2002 samples, depending upon the value of PictureRate.
+ class WAVParser
+ {
+ class h__WAVParser;
+ mem_ptr<h__WAVParser> m_Parser;
+ ASDCP_NO_COPY_CONSTRUCT(WAVParser);
+
+ public:
+ WAVParser();
+ virtual ~WAVParser();
+
+ // Opens the stream for reading, parses enough data to provide a complete
+ // set of stream metadata for the MXFWriter below. PictureRate controls
+ // ther frame rate for the MXF frame wrapping option.
+ Result_t OpenRead(const char* filename, const Rational& PictureRate) const;
+
+ // Fill an AudioDescriptor struct with the values from the file's header.
+ // Returns RESULT_INIT if the file is not open.
+ Result_t FillAudioDescriptor(AudioDescriptor&) const;
+
+ // Rewind the stream to the beginning.
+ Result_t Reset() const;
+
+ // Reads the next sequential frame in the input file and places it in the
+ // frame buffer. Fails if the buffer is too small or the stream is empty.
+ Result_t ReadFrame(FrameBuffer&) const;
+ };
+
+
+ //
+ class MXFWriter
+ {
+ class h__Writer;
+ mem_ptr<h__Writer> m_Writer;
+ ASDCP_NO_COPY_CONSTRUCT(MXFWriter);
+
+ public:
+ MXFWriter();
+ virtual ~MXFWriter();
+
+ // Warning: direct manipulation of MXF structures can interfere
+ // with the normal operation of the wrapper. Caveat emptor!
+ virtual MXF::OPAtomHeader& OPAtomHeader();
+ virtual MXF::OPAtomIndexFooter& OPAtomIndexFooter();
+
+ // Open the file for writing. The file must not exist. Returns error if
+ // the operation cannot be completed or if nonsensical data is discovered
+ // in the essence descriptor.
+ Result_t OpenWrite(const char* filename, const WriterInfo&,
+ const AudioDescriptor&, ui32_t HeaderSize = 16384);
+
+ // Writes a frame of essence to the MXF file. If the optional AESEncContext
+ // argument is present, the essence is encrypted prior to writing.
+ // Fails if the file is not open, is finalized, or an operating system
+ // error occurs.
+ Result_t WriteFrame(const FrameBuffer&, AESEncContext* = 0, HMACContext* = 0);
+
+ // Closes the MXF file, writing the index and revised header.
+ Result_t Finalize();
+ };
+
+ //
+ class MXFReader
+ {
+ class h__Reader;
+ mem_ptr<h__Reader> m_Reader;
+ ASDCP_NO_COPY_CONSTRUCT(MXFReader);
+
+ public:
+ MXFReader();
+ virtual ~MXFReader();
+
+ // Warning: direct manipulation of MXF structures can interfere
+ // with the normal operation of the wrapper. Caveat emptor!
+ virtual MXF::OPAtomHeader& OPAtomHeader();
+ virtual MXF::OPAtomIndexFooter& OPAtomIndexFooter();
+
+ // Open the file for reading. The file must exist. Returns error if the
+ // operation cannot be completed.
+ Result_t OpenRead(const char* filename) const;
+
+ // Returns RESULT_INIT if the file is not open.
+ Result_t Close() const;
+
+ // Fill an AudioDescriptor struct with the values from the file's header.
+ // Returns RESULT_INIT if the file is not open.
+ Result_t FillAudioDescriptor(AudioDescriptor&) const;
+
+ // Fill a WriterInfo struct with the values from the file's header.
+ // Returns RESULT_INIT if the file is not open.
+ Result_t FillWriterInfo(WriterInfo&) const;
+
+ // Reads a frame of essence from the MXF file. If the optional AESEncContext
+ // argument is present, the essence is decrypted after reading. If the MXF
+ // file is encrypted and the AESDecContext argument is NULL, the frame buffer
+ // will contain the ciphertext frame data. If the HMACContext argument is
+ // not NULL, the HMAC will be calculated (if the file supports it).
+ // Returns RESULT_INIT if the file is not open, failure if the frame number is
+ // out of range, or if optional decrypt or HAMC operations fail.
+ Result_t ReadFrame(ui32_t frame_number, FrameBuffer&, AESDecContext* = 0, HMACContext* = 0) const;
+
+ // Print debugging information to stream
+ void DumpHeaderMetadata(FILE* = 0) const;
+ void DumpIndex(FILE* = 0) const;
+ };
+ } // namespace PCM
+
+ //---------------------------------------------------------------------------------
+ //
+ namespace JP2K
+ {
+ const ui32_t MaxComponents = 3;
+ const ui32_t MaxPrecincts = 32; // ISO 15444-1 Annex A.6.1
+ const ui32_t MaxDefaults = 256; // made up
+
+#pragma pack(1)
+ struct ImageComponent_t // ISO 15444-1 Annex A.5.1
+ {
+ ui8_t Ssize;
+ ui8_t XRsize;
+ ui8_t YRsize;
+ };
+
+ struct CodingStyleDefault_t // ISO 15444-1 Annex A.6.1
+ {
+ ui8_t Scod;
+
+ struct
+ {
+ ui8_t ProgressionOrder;
+ ui8_t NumberOfLayers[sizeof(ui16_t)];
+ ui8_t MultiCompTransform;
+ } SGcod;
+
+ struct
+ {
+ ui8_t DecompositionLevels;
+ ui8_t CodeblockWidth;
+ ui8_t CodeblockHeight;
+ ui8_t CodeblockStyle;
+ ui8_t Transformation;
+ ui8_t PrecinctSize[MaxPrecincts];
+ } SPcod;
+ };
+
+ struct QuantizationDefault_t // ISO 15444-1 Annex A.6.4
+ {
+ ui8_t Sqcd;
+ ui8_t SPqcd[MaxDefaults];
+ ui8_t SPqcdLength;
+ };
+#pragma pack()
+
+ struct PictureDescriptor
+ {
+ Rational EditRate;
+ ui32_t ContainerDuration;
+ Rational SampleRate;
+ ui32_t StoredWidth;
+ ui32_t StoredHeight;
+ Rational AspectRatio;
+ ui16_t Rsize;
+ ui32_t Xsize;
+ ui32_t Ysize;
+ ui32_t XOsize;
+ ui32_t YOsize;
+ ui32_t XTsize;
+ ui32_t YTsize;
+ ui32_t XTOsize;
+ ui32_t YTOsize;
+ ui16_t Csize;
+ ImageComponent_t ImageComponents[MaxComponents];
+ CodingStyleDefault_t CodingStyleDefault;
+ QuantizationDefault_t QuantizationDefault;
+ };
+
+ // Print debugging information to std::ostream
+ std::ostream& operator << (std::ostream& strm, const PictureDescriptor& pdesc);
+ // Print debugging information to stream (stderr default)
+ void PictureDescriptorDump(const PictureDescriptor&, FILE* = 0);
+
+ //
+ class FrameBuffer : public ASDCP::FrameBuffer
+ {
+ public:
+ FrameBuffer() {}
+ FrameBuffer(ui32_t size) { Capacity(size); }
+ virtual ~FrameBuffer() {}
+
+ // Print debugging information to stream (stderr default)
+ void Dump(FILE* = 0, ui32_t dump_bytes = 0) const;
+ };
+
+
+ // An object which opens and reads a JPEG 2000 codestream file. The file is expected
+ // to contain exactly one complete frame of picture essence as an unwrapped (raw)
+ // ISO/IEC 15444 codestream.
+ class CodestreamParser
+ {
+ class h__CodestreamParser;
+ mem_ptr<h__CodestreamParser> m_Parser;
+ ASDCP_NO_COPY_CONSTRUCT(CodestreamParser);
+
+ public:
+ CodestreamParser();
+ virtual ~CodestreamParser();
+
+ // Opens a file for reading, parses enough data to provide a complete
+ // set of stream metadata for the MXFWriter below.
+ // The frame buffer's PlaintextOffset parameter will be set to the first
+ // byte of the data segment. Set this value to zero if you want
+ // encrypted headers.
+ Result_t OpenReadFrame(const char* filename, FrameBuffer&) const;
+
+ // Fill a PictureDescriptor struct with the values from the file's codestream.
+ // Returns RESULT_INIT if the file is not open.
+ Result_t FillPictureDescriptor(PictureDescriptor&) const;
+ };
+
+ // Parses the data in the frame buffer to fill in the picture descriptor. Copies
+ // the offset of the image data into start_of_data. Returns error if the parser fails.
+ Result_t ParseMetadataIntoDesc(const FrameBuffer&, PictureDescriptor&, byte_t* start_of_data = 0);
+
+ // An object which reads a sequence of files containing JPEG 2000 pictures.
+ class SequenceParser
+ {
+ class h__SequenceParser;
+ mem_ptr<h__SequenceParser> m_Parser;
+ ASDCP_NO_COPY_CONSTRUCT(SequenceParser);
+
+ public:
+ SequenceParser();
+ virtual ~SequenceParser();
+
+ // Opens a directory for reading. The directory is expected to contain one or
+ // more files, each containing the codestream for exactly one picture. The
+ // files must be named such that the frames are in temporal order when sorted
+ // alphabetically by filename. The parser will automatically parse enough data
+ // from the first file to provide a complete set of stream metadata for the
+ // MXFWriter below. If the "pedantic" parameter is given and is true, the
+ // parser will check the metadata for each codestream and fail if a
+ // mismatch is detected.
+ Result_t OpenRead(const char* filename, bool pedantic = false) const;
+
+ // Opens a file sequence for reading. The sequence is expected to contain one or
+ // more filenames, each naming a file containing the codestream for exactly one
+ // picture. The parser will automatically parse enough data
+ // from the first file to provide a complete set of stream metadata for the
+ // MXFWriter below. If the "pedantic" parameter is given and is true, the
+ // parser will check the metadata for each codestream and fail if a
+ // mismatch is detected.
+ Result_t OpenRead(const std::list<std::string>& file_list, bool pedantic = false) const;
+
+ // Fill a PictureDescriptor struct with the values from the first file's codestream.
+ // Returns RESULT_INIT if the directory is not open.
+ Result_t FillPictureDescriptor(PictureDescriptor&) const;
+
+ // Rewind the directory to the beginning.
+ Result_t Reset() const;
+
+ // Reads the next sequential frame in the directory and places it in the
+ // frame buffer. Fails if the buffer is too small or the direcdtory
+ // contains no more files.
+ // The frame buffer's PlaintextOffset parameter will be set to the first
+ // byte of the data segment. Set this value to zero if you want
+ // encrypted headers.
+ Result_t ReadFrame(FrameBuffer&) const;
+ };
+
+
+ //
+ class MXFWriter
+ {
+ class h__Writer;
+ mem_ptr<h__Writer> m_Writer;
+ ASDCP_NO_COPY_CONSTRUCT(MXFWriter);
+
+ public:
+ MXFWriter();
+ virtual ~MXFWriter();
+
+ // Warning: direct manipulation of MXF structures can interfere
+ // with the normal operation of the wrapper. Caveat emptor!
+ virtual MXF::OPAtomHeader& OPAtomHeader();
+ virtual MXF::OPAtomIndexFooter& OPAtomIndexFooter();
+
+ // Open the file for writing. The file must not exist. Returns error if
+ // the operation cannot be completed or if nonsensical data is discovered
+ // in the essence descriptor.
+ Result_t OpenWrite(const char* filename, const WriterInfo&,
+ const PictureDescriptor&, ui32_t HeaderSize = 16384);
+
+ // Writes a frame of essence to the MXF file. If the optional AESEncContext
+ // argument is present, the essence is encrypted prior to writing.
+ // Fails if the file is not open, is finalized, or an operating system
+ // error occurs.
+ Result_t WriteFrame(const FrameBuffer&, AESEncContext* = 0, HMACContext* = 0);
+
+ // Closes the MXF file, writing the index and revised header.
+ Result_t Finalize();
+ };
+
+ //
+ class MXFReader
+ {
+ class h__Reader;
+ mem_ptr<h__Reader> m_Reader;
+ ASDCP_NO_COPY_CONSTRUCT(MXFReader);
+
+ public:
+ MXFReader();
+ virtual ~MXFReader();
+
+ // Warning: direct manipulation of MXF structures can interfere
+ // with the normal operation of the wrapper. Caveat emptor!
+ virtual MXF::OPAtomHeader& OPAtomHeader();
+ virtual MXF::OPAtomIndexFooter& OPAtomIndexFooter();
+
+ // Open the file for reading. The file must exist. Returns error if the
+ // operation cannot be completed.
+ Result_t OpenRead(const char* filename) const;
+
+ // Returns RESULT_INIT if the file is not open.
+ Result_t Close() const;
+
+ // Fill an AudioDescriptor struct with the values from the file's header.
+ // Returns RESULT_INIT if the file is not open.
+ Result_t FillPictureDescriptor(PictureDescriptor&) const;
+
+ // Fill a WriterInfo struct with the values from the file's header.
+ // Returns RESULT_INIT if the file is not open.
+ Result_t FillWriterInfo(WriterInfo&) const;
+
+ // Reads a frame of essence from the MXF file. If the optional AESEncContext
+ // argument is present, the essence is decrypted after reading. If the MXF
+ // file is encrypted and the AESDecContext argument is NULL, the frame buffer
+ // will contain the ciphertext frame data. If the HMACContext argument is
+ // not NULL, the HMAC will be calculated (if the file supports it).
+ // Returns RESULT_INIT if the file is not open, failure if the frame number is
+ // out of range, or if optional decrypt or HAMC operations fail.
+ Result_t ReadFrame(ui32_t frame_number, FrameBuffer&, AESDecContext* = 0, HMACContext* = 0) const;
+
+ // Print debugging information to stream
+ void DumpHeaderMetadata(FILE* = 0) const;
+ void DumpIndex(FILE* = 0) const;
+ };
+
+
+ // Stereoscopic Image support
+ //
+
+ enum StereoscopicPhase_t
+ {
+ SP_LEFT,
+ SP_RIGHT
+ };
+
+ struct SFrameBuffer
+ {
+ JP2K::FrameBuffer Left;
+ JP2K::FrameBuffer Right;
+
+ SFrameBuffer(ui32_t size) {
+ Left.Capacity(size);
+ Right.Capacity(size);
+ }
+ };
+
+ class MXFSWriter
+ {
+ class h__SWriter;
+ mem_ptr<h__SWriter> m_Writer;
+ ASDCP_NO_COPY_CONSTRUCT(MXFSWriter);
+
+ public:
+ MXFSWriter();
+ virtual ~MXFSWriter();
+
+ // Warning: direct manipulation of MXF structures can interfere
+ // with the normal operation of the wrapper. Caveat emptor!
+ virtual MXF::OPAtomHeader& OPAtomHeader();
+ virtual MXF::OPAtomIndexFooter& OPAtomIndexFooter();
+
+ // Open the file for writing. The file must not exist. Returns error if
+ // the operation cannot be completed or if nonsensical data is discovered
+ // in the essence descriptor.
+ Result_t OpenWrite(const char* filename, const WriterInfo&,
+ const PictureDescriptor&, ui32_t HeaderSize = 16384);
+
+ // Writes a pair of frames of essence to the MXF file. If the optional AESEncContext
+ // argument is present, the essence is encrypted prior to writing.
+ // Fails if the file is not open, is finalized, or an operating system
+ // error occurs.
+ Result_t WriteFrame(const SFrameBuffer&, AESEncContext* = 0, HMACContext* = 0);
+
+ // Writes a frame of essence to the MXF file. If the optional AESEncContext
+ // argument is present, the essence is encrypted prior to writing.
+ // Fails if the file is not open, is finalized, or an operating system
+ // error occurs. Frames must be written in the proper phase (L-R-L-R),
+ // RESULT_SPHASE will be returned if phase is reversed. The first frame
+ // written must be left eye.
+ Result_t WriteFrame(const FrameBuffer&, StereoscopicPhase_t phase,
+ AESEncContext* = 0, HMACContext* = 0);
+
+ // Closes the MXF file, writing the index and revised header. Returns
+ // RESULT_SPHASE if WriteFrame was called an odd number of times.
+ Result_t Finalize();
+ };
+
+ //
+ class MXFSReader
+ {
+ class h__SReader;
+ mem_ptr<h__SReader> m_Reader;
+ ASDCP_NO_COPY_CONSTRUCT(MXFSReader);
+
+ public:
+ MXFSReader();
+ virtual ~MXFSReader();
+
+ // Warning: direct manipulation of MXF structures can interfere
+ // with the normal operation of the wrapper. Caveat emptor!
+ virtual MXF::OPAtomHeader& OPAtomHeader();
+ virtual MXF::OPAtomIndexFooter& OPAtomIndexFooter();
+
+ // Open the file for reading. The file must exist. Returns error if the
+ // operation cannot be completed.
+ Result_t OpenRead(const char* filename) const;
+
+ // Returns RESULT_INIT if the file is not open.
+ Result_t Close() const;
+
+ // Fill an AudioDescriptor struct with the values from the file's header.
+ // Returns RESULT_INIT if the file is not open.
+ Result_t FillPictureDescriptor(PictureDescriptor&) const;
+
+ // Fill a WriterInfo struct with the values from the file's header.
+ // Returns RESULT_INIT if the file is not open.
+ Result_t FillWriterInfo(WriterInfo&) const;
+
+ // Reads a pair of frames of essence from the MXF file. If the optional AESEncContext
+ // argument is present, the essence is decrypted after reading. If the MXF
+ // file is encrypted and the AESDecContext argument is NULL, the frame buffer
+ // will contain the ciphertext frame data. If the HMACContext argument is
+ // not NULL, the HMAC will be calculated (if the file supports it).
+ // Returns RESULT_INIT if the file is not open, failure if the frame number is
+ // out of range, or if optional decrypt or HAMC operations fail.
+ Result_t ReadFrame(ui32_t frame_number, SFrameBuffer&, AESDecContext* = 0, HMACContext* = 0) const;
+
+ // Reads a frame of essence from the MXF file. If the optional AESEncContext
+ // argument is present, the essence is decrypted after reading. If the MXF
+ // file is encrypted and the AESDecContext argument is NULL, the frame buffer
+ // will contain the ciphertext frame data. If the HMACContext argument is
+ // not NULL, the HMAC will be calculated (if the file supports it).
+ // Returns RESULT_INIT if the file is not open, failure if the frame number is
+ // out of range, or if optional decrypt or HAMC operations fail.
+ Result_t ReadFrame(ui32_t frame_number, StereoscopicPhase_t phase,
+ FrameBuffer&, AESDecContext* = 0, HMACContext* = 0) const;
+
+ // Print debugging information to stream
+ void DumpHeaderMetadata(FILE* = 0) const;
+ void DumpIndex(FILE* = 0) const;
+ };
+ } // namespace JP2K
+
+ //---------------------------------------------------------------------------------
+ //
+ namespace TimedText
+ {
+ enum MIMEType_t { MT_BIN, MT_PNG, MT_OPENTYPE };
+
+ struct TimedTextResourceDescriptor
+ {
+ byte_t ResourceID[UUIDlen];
+ MIMEType_t Type;
+
+ TimedTextResourceDescriptor() : Type(MT_BIN) {}
+ };
+
+ typedef std::list<TimedTextResourceDescriptor> ResourceList_t;
+
+ struct TimedTextDescriptor
+ {
+ Rational EditRate; //
+ ui32_t ContainerDuration;
+ byte_t AssetID[UUIDlen];
+ std::string NamespaceName;
+ std::string EncodingName;
+ ResourceList_t ResourceList;
+
+ TimedTextDescriptor() : ContainerDuration(0), EncodingName("UTF-8") {} // D-Cinema format is always UTF-8
+ };
+
+ // Print debugging information to std::ostream
+ std::ostream& operator << (std::ostream& strm, const TimedTextDescriptor& tinfo);
+ // Print debugging information to stream (stderr default)
+ void DescriptorDump(const TimedTextDescriptor&, FILE* = 0);
+
+ //
+ class FrameBuffer : public ASDCP::FrameBuffer
+ {
+ ASDCP_NO_COPY_CONSTRUCT(FrameBuffer); // TODO: should have copy construct
+
+ protected:
+ byte_t m_AssetID[UUIDlen];
+ std::string m_MIMEType;
+
+ public:
+ FrameBuffer() { memset(m_AssetID, 0, UUIDlen); }
+ FrameBuffer(ui32_t size) { Capacity(size); memset(m_AssetID, 0, UUIDlen); }
+ virtual ~FrameBuffer() {}
+
+ inline const byte_t* AssetID() const { return m_AssetID; }
+ inline void AssetID(const byte_t* buf) { memcpy(m_AssetID, buf, UUIDlen); }
+ inline const char* MIMEType() const { return m_MIMEType.c_str(); }
+ inline void MIMEType(const std::string& s) { m_MIMEType = s; }
+
+ // Print debugging information to stream (stderr default)
+ void Dump(FILE* = 0, ui32_t dump_bytes = 0) const;
+ };
+
+ //
+ class IResourceResolver
+ {
+ public:
+ virtual ~IResourceResolver() {}
+ virtual Result_t ResolveRID(const byte_t* uuid, FrameBuffer&) const = 0; // return data for RID
+ };
+
+ //
+ class DCSubtitleParser
+ {
+ class h__SubtitleParser;
+ mem_ptr<h__SubtitleParser> m_Parser;
+ ASDCP_NO_COPY_CONSTRUCT(DCSubtitleParser);
+
+ public:
+ DCSubtitleParser();
+ virtual ~DCSubtitleParser();
+
+ // Opens an XML file for reading, parses data to provide a complete
+ // set of stream metadata for the MXFWriter below.
+ Result_t OpenRead(const char* filename) const;
+
+ // Parses an XML document to provide a complete set of stream metadata
+ // for the MXFWriter below. The optional filename argument is used to
+ // initialize the default resource resolver (see ReadAncillaryResource).
+ Result_t OpenRead(const std::string& xml_doc, const char* filename = 0) const;
+
+ // Fill a TimedTextDescriptor struct with the values from the file's contents.
+ // Returns RESULT_INIT if the file is not open.
+ Result_t FillTimedTextDescriptor(TimedTextDescriptor&) const;
+
+ // Reads the complete Timed Text Resource into the given string.
+ Result_t ReadTimedTextResource(std::string&) const;
+
+ // Reads the Ancillary Resource having the given ID. Fails if the buffer
+ // is too small or the resource does not exist. The optional Resolver
+ // argument can be provided which will be used to retrieve the resource
+ // having a particulat UUID. If a Resolver is not supplied, the default
+ // internal resolver will return the contents of the file having the UUID
+ // as the filename. The filename must exist in the same directory as the
+ // XML file opened with OpenRead().
+ Result_t ReadAncillaryResource(const byte_t* uuid, FrameBuffer&,
+ const IResourceResolver* Resolver = 0) const;
+ };
+
+ //
+ class MXFWriter
+ {
+ class h__Writer;
+ mem_ptr<h__Writer> m_Writer;
+ ASDCP_NO_COPY_CONSTRUCT(MXFWriter);
+
+ public:
+ MXFWriter();
+ virtual ~MXFWriter();
+
+ // Warning: direct manipulation of MXF structures can interfere
+ // with the normal operation of the wrapper. Caveat emptor!
+ virtual MXF::OPAtomHeader& OPAtomHeader();
+ virtual MXF::OPAtomIndexFooter& OPAtomIndexFooter();
+
+ // Open the file for writing. The file must not exist. Returns error if
+ // the operation cannot be completed or if nonsensical data is discovered
+ // in the essence descriptor.
+ Result_t OpenWrite(const char* filename, const WriterInfo&,
+ const TimedTextDescriptor&, ui32_t HeaderSize = 16384);
+
+ // Writes the Timed-Text Resource to the MXF file. The file must be UTF-8
+ // encoded. If the optional AESEncContext argument is present, the essence
+ // is encrypted prior to writing. Fails if the file is not open, is finalized,
+ // or an operating system error occurs.
+ // This method may only be called once, and it must be called before any
+ // call to WriteAncillaryResource(). RESULT_STATE will be returned if these
+ // conditions are not met.
+ Result_t WriteTimedTextResource(const std::string& XMLDoc, AESEncContext* = 0, HMACContext* = 0);
+
+ // Writes an Ancillary Resource to the MXF file. If the optional AESEncContext
+ // argument is present, the essence is encrypted prior to writing.
+ // Fails if the file is not open, is finalized, or an operating system
+ // error occurs. RESULT_STATE will be returned if the method is called before
+ // WriteTimedTextResource()
+ Result_t WriteAncillaryResource(const FrameBuffer&, AESEncContext* = 0, HMACContext* = 0);
+
+ // Closes the MXF file, writing the index and revised header.
+ Result_t Finalize();
+ };
+
+ //
+ class MXFReader
+ {
+ class h__Reader;
+ mem_ptr<h__Reader> m_Reader;
+ ASDCP_NO_COPY_CONSTRUCT(MXFReader);
+
+ public:
+ MXFReader();
+ virtual ~MXFReader();
+
+ // Warning: direct manipulation of MXF structures can interfere
+ // with the normal operation of the wrapper. Caveat emptor!
+ virtual MXF::OPAtomHeader& OPAtomHeader();
+ virtual MXF::OPAtomIndexFooter& OPAtomIndexFooter();
+
+ // Open the file for reading. The file must exist. Returns error if the
+ // operation cannot be completed.
+ Result_t OpenRead(const char* filename) const;
+
+ // Returns RESULT_INIT if the file is not open.
+ Result_t Close() const;
+
+ // Fill a TimedTextDescriptor struct with the values from the file's header.
+ // Returns RESULT_INIT if the file is not open.
+ Result_t FillTimedTextDescriptor(TimedTextDescriptor&) const;
+
+ // Fill a WriterInfo struct with the values from the file's header.
+ // Returns RESULT_INIT if the file is not open.
+ Result_t FillWriterInfo(WriterInfo&) const;
+
+ // Reads the complete Timed Text Resource into the given string. Fails if the resource
+ // is encrypted and AESDecContext is NULL (use the following method to retrieve the
+ // raw ciphertet block).
+ Result_t ReadTimedTextResource(std::string&, AESDecContext* = 0, HMACContext* = 0) const;
+
+ // Reads the complete Timed Text Resource from the MXF file. If the optional AESEncContext
+ // argument is present, the resource is decrypted after reading. If the MXF
+ // file is encrypted and the AESDecContext argument is NULL, the frame buffer
+ // will contain the ciphertext frame data. If the HMACContext argument is
+ // not NULL, the HMAC will be calculated (if the file supports it).
+ // Returns RESULT_INIT if the file is not open, failure if the frame number is
+ // out of range, or if optional decrypt or HAMC operations fail.
+ Result_t ReadTimedTextResource(FrameBuffer&, AESDecContext* = 0, HMACContext* = 0) const;
+
+ // Reads the timed-text resource having the given UUID from the MXF file. If the
+ // optional AESEncContext argument is present, the resource is decrypted after
+ // reading. If the MXF file is encrypted and the AESDecContext argument is NULL,
+ // the frame buffer will contain the ciphertext frame data. If the HMACContext
+ // argument is not NULL, the HMAC will be calculated (if the file supports it).
+ // Returns RESULT_INIT if the file is not open, failure if the frame number is
+ // out of range, or if optional decrypt or HAMC operations fail.
+ Result_t ReadAncillaryResource(const byte_t* uuid, FrameBuffer&, AESDecContext* = 0, HMACContext* = 0) const;
+
+ // Print debugging information to stream
+ void DumpHeaderMetadata(FILE* = 0) const;
+ void DumpIndex(FILE* = 0) const;
+ };
+ } // namespace TimedText
+
+
+} // namespace ASDCP
+
+
+#endif // _AS_DCP_H_
+
+//
+// end AS_DCP.h
+//