X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;ds=sidebyside;f=src%2FAS_DCP.h;h=75ca97f76edafcc2da37d93b3e4c86049aaef577;hb=1c99be3b63bf3e86d985bea581bbac57d51e18ee;hp=b64c3a5c469f35da284c378220c1dce8b95089e2;hpb=30d642bd3b8474744dfbdcc2bdc46cdf827102c4;p=asdcplib.git diff --git a/src/AS_DCP.h b/src/AS_DCP.h index b64c3a5..75ca97f 100755 --- a/src/AS_DCP.h +++ b/src/AS_DCP.h @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2006, John Hurst +Copyright (c) 2003-2014, John Hurst All rights reserved. Redistribution and use in source and binary forms, with or without @@ -25,60 +25,74 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /*! \file AS_DCP.h - \version $Id$ + \version $Id$ \brief AS-DCP library, public interface -The asdcplib library is a set of wrapper objects that offer simplified -access to files conforming to the file formats proposed by the SMPTE -D-Cinema packaging working group DC28.20. The file format, labeled -AS-DCP, is described in series of separate documents which include but -may not be limited to: - - o AS-DCP Track File Specification - o AS-DCP Track File Essence Encryption Specification - o AS-DCP Operational Constraints Specification - o SMPTE 330M - UMID - o SMPTE 336M - KLV - o SMPTE 377M - MXF - o SMPTE 390M - OP-Atom - o SMPTE 379M - Generic Container - o SMPTE 381M - MPEG2 picture - o SMPTE XXXM - JPEG 2000 picture - o SMPTE 382M - WAV/PCM sound +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 a series of documents which includes 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 429-14:2008 Aux Data Track File + o SMPTE ST 330:2004 - UMID + o SMPTE ST 336:2001 - KLV + o SMPTE ST 377:2004 - MXF (old version, required) + 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) + 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 a plaintext MPEG2 Video Elementary Stream to a plaintext ASDCP file - o Write a plaintext MPEG2 Video Elementary Stream to a ciphertext ASDCP file - o Read a plaintext MPEG2 Video Elementary Stream from a plaintext ASDCP file - o Read a plaintext MPEG2 Video Elementary Stream from a ciphertext ASDCP file - o Read a ciphertext MPEG2 Video Elementary Stream from a ciphertext ASDCP file - o Write one or more plaintext JPEG 2000 codestreams to a plaintext ASDCP file - o Write one or more plaintext JPEG 2000 codestreams to a ciphertext ASDCP file - o Read one or more plaintext JPEG 2000 codestreams from a plaintext ASDCP file - o Read one or more plaintext JPEG 2000 codestreams from a ciphertext ASDCP file - o Read one or more ciphertext JPEG 2000 codestreams from a ciphertext ASDCP file - o Write one or more plaintext PCM audio streams to a plaintext ASDCP file - o Write one or more plaintext PCM audio streams to a ciphertext ASDCP file - o Read one or more plaintext PCM audio streams from a plaintext ASDCP file - o Read one or more plaintext PCM audio streams from a ciphertext ASDCP file - o Read one or more ciphertext PCM audio streams from a ciphertext ASDCP file - o Read header metadata from an ASDCP file - -This project depends upon the following library: - - OpenSSL http://www.openssl.org/ + o Write essence to a plaintext or ciphertext AS-DCP file: + 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 + Aux Data (frame-wrapped synchronous blob) + Proposed Dolby (TM) Atmos track file + 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__ +#ifndef _AS_DCP_H_ +#define _AS_DCP_H_ +#include +#include #include #include -#include #include +#include +#include +#include +#include //-------------------------------------------------------------------------------- // common integer types @@ -128,22 +142,12 @@ typedef unsigned int ui32_t; T(const T&); \ T& operator=(const T&) - //-------------------------------------------------------------------------------- // All library components are defined in the namespace ASDCP // namespace ASDCP { - // The version number consists of three segments: major, API minor, and - // implementation minor. Whenever a change is made to AS_DCP.h, the API minor - // version will increment. Changes made to the internal implementation will - // result in the incrementing of the implementation minor version. - - // For example, if asdcplib version 1.0.0 were modified to accomodate changes - // in file format, and if no changes were made to AS_DCP.h, the new version would be - // 1.0.1. If changes were also required in AS_DCP.h, the new version would be 1.1.1. - const ui32_t VERSION_MAJOR = 1; - const ui32_t VERSION_APIMINOR = 0; - const ui32_t VERSION_IMPMINOR = 4; + // + // The version number declaration and explanation have moved to ../configure.ac const char* Version(); // UUIDs are passed around as strings of UUIDlen bytes @@ -152,81 +156,45 @@ namespace ASDCP { // Encryption keys are passed around as strings of KeyLen bytes const ui32_t KeyLen = 16; - // Key IDs are really UUIDs, so it makes no sense to have this value - // // Encryption key IDs are passed around as strings of KeyIDlen bytes - // const ui32_t KeyIDlen = 16; - - - //--------------------------------------------------------------------------------- - // message logging - - // Error and debug messages will be delivered to an object having this interface. - // The default implementation sends only LOG_ERROR and LOG_WARN messages to stderr. - // To receive LOG_INFO or LOG_DEBUG messages, or to send messages somewhere other - // than stderr, implement this interface and register an instance of your new class - // by calling SetDefaultLogSink(). - class ILogSink - { - public: - enum LogType_t { LOG_ERROR, LOG_WARN, LOG_INFO, LOG_DEBUG }; - - virtual ~ILogSink() {} - virtual void Error(const char*, ...) = 0; // receives error messges - virtual void Warn(const char*, ...) = 0; // receives warning messges - virtual void Info(const char*, ...) = 0; // receives info messages - virtual void Debug(const char*, ...) = 0; // receives debug messages - virtual void Logf(LogType_t, const char*, ...) = 0; // log a formatted string with positional parameters - virtual void vLogf(LogType_t, const char*, va_list*) = 0; // log a formatted string with a va_list struct - }; - - // Sets the internal default sink to the given receiver. If the given value - // is zero, sets the default sink to the internally allocated stderr sink. - void SetDefaultLogSink(ILogSink* = 0); - - // Returns the internal default sink. - ILogSink& DefaultLogSink(); - //--------------------------------------------------------------------------------- // return values - // Each method or subroutine in this library that is not void or does not directly - // return a value will instead return a result code from this enumeration. - enum Result_t { - RESULT_FALSE = 1, // successful but negative - RESULT_OK = 0, // No errors detected - RESULT_FAIL = -1, // An undefined error was detected - RESULT_PTR = -2, // An unexpected NULL pointer was given - RESULT_NULL_STR = -3, // An unexpected empty string was given - RESULT_SMALLBUF = -4, // The given frame buffer is too small - RESULT_INIT = -5, // The object is not yet initialized - RESULT_NOT_FOUND = -6, // The requested file does not exist on the system - RESULT_NO_PERM = -7, // Insufficient privilege exists to perform the operation - RESULT_FILEOPEN = -8, // Failure opening file - RESULT_FORMAT = -9, // The file format is not proper OP-Atom/AS-DCP - RESULT_BADSEEK = -10, // An invalid file location was requested - RESULT_READFAIL = -11, // File read error - RESULT_WRITEFAIL = -12, // File write error - RESULT_RAW_ESS = -13, // Unknown raw essence file type - RESULT_RAW_FORMAT = -14, // Raw essence format invalid - RESULT_STATE = -15, // Object state error - RESULT_ENDOFFILE = -16, // Attempt to read past end of file - RESULT_CONFIG = -17, // Invalid configuration option detected - RESULT_RANGE = -18, // Frame number out of range - RESULT_CRYPT_CTX = -19, // AESEncContext required when writing to encrypted file - RESULT_LARGE_PTO = -20, // Plaintext offset exceeds frame buffer size - RESULT_ALLOC = -21, // Error allocating memory - RESULT_CAPEXTMEM = -22, // Cannot resize externally allocated memory - RESULT_CHECKFAIL = -23, // The check value did not decrypt correctly - RESULT_HMACFAIL = -24, // HMAC authentication failure - RESULT_HMAC_CTX = -25, // HMAC context required - RESULT_CRYPT_INIT = -26, // Error initializing block cipher context - RESULT_EMPTY_FB = -27, // Attempted to write an empty frame buffer - }; - - // Returns a pointer to an English language string describing the given result code. - // If the result code is not a valid member of the Result_t enum, the string - // "**UNKNOWN**" will be returned. - const char* GetResultString(Result_t); + 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 @@ -234,27 +202,43 @@ namespace ASDCP { // 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_UNKNOWN, // the file is not a supported AS-DCP of AS-02 essence container + + // + ESS_MPEG2_VES, // the file contains an MPEG-2 video elementary stream + + // d-cinema essence types + 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) + ESS_DCDATA_UNKNOWN, // the file contains one or more D-Cinema Data bytestreams + ESS_DCDATA_DOLBY_ATMOS, // the file contains one or more DolbyATMOS bytestreams + + // IMF essence types + ESS_AS02_JPEG_2000, // the file contains one or more JPEG 2000 codestreams + ESS_AS02_PCM_24b_48k, // the file contains one or more PCM audio pairs, clip wrapped + ESS_AS02_PCM_24b_96k, // the file contains one or more PCM audio pairs, clip wrapped + ESS_AS02_TIMED_TEXT, // the file contains a TTML document and zero or more resources + + ESS_ACES, // the file contains one ACES codestream + ESS_MAX }; - // 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); + Result_t EssenceType(const std::string& 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); + Result_t RawEssenceType(const std::string& filename, EssenceType_t& type); - // Locate the named object in the file header and dump it to the given stream. - // The default dump stream is stderr. - Result_t FindObject(const char* filename, const char* objname, FILE* = 0); + //--------------------------------------------------------------------------------- + // base types // A simple container for rational numbers. class Rational @@ -277,13 +261,56 @@ namespace ASDCP { 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; + } }; + // Encodes a rational number as a string having a single delimiter character between + // numerator and denominator. Retuns the buffer pointer to allow convenient in-line use. + const char* EncodeRational(const Rational&, char* str_buf, ui32_t buf_len, char delimiter = ' '); + + // Decodes a rational number havng a single non-digit delimiter character between + // the numerator and denominator. Returns false if the string does not contain + // the expected syntax. + bool DecodeRational(const char* str_rat, Rational&); + + // common edit rates, use these instead of hard coded constants - const Rational EditRate_24(24,1); - const Rational EditRate_23_98(24000,1001); - const Rational EditRate_48(48,1); - const Rational SampleRate_48k(48000,1); + 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); + + // Archival frame rates, see ST 428-21 + // 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_16 = Rational(16,1); + const Rational EditRate_18 = Rational(200,11); // 18.182 + const Rational EditRate_20 = Rational(20,1); + const Rational EditRate_22 = Rational(240,11); // 21.818 + // Non-reference counting container for internal member objects. // Please do not use this class for any other purpose. @@ -308,6 +335,79 @@ namespace ASDCP { 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, + LS_MAX + }; + + // + 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 @@ -332,7 +432,7 @@ namespace ASDCP { // 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. @@ -383,7 +483,7 @@ namespace ASDCP { // 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); + Result_t InitKey(const byte_t* key, LabelSet_t); // Reset internal state, allows repeated cycles of Update -> Finalize void Reset(); @@ -406,41 +506,6 @@ namespace ASDCP { Result_t TestHMACValue(const byte_t* buf) const; }; - //--------------------------------------------------------------------------------- - // WriterInfo class - encapsulates writer identification details used for - // OpenWrite() calls. Replace these values at runtime to identify your product. - // - 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 to be) encrypted - bool UsesHMAC; // true if HMAC exists or is to be calculated - std::string ProductVersion; - std::string CompanyName; - std::string ProductName; - - WriterInfo() : EncryptedEssence(false), UsesHMAC(false) { - 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 stream, stderr by default. - void WriterInfoDump(const WriterInfo&, FILE* = 0); - //--------------------------------------------------------------------------------- // frame buffer base class // @@ -521,6 +586,16 @@ namespace ASDCP { 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 to use these + class OP1aHeader; + class OPAtomIndexFooter; + class RIP; + }; //--------------------------------------------------------------------------------- // MPEG2 video elementary stream support @@ -552,24 +627,26 @@ namespace ASDCP { // 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; // + 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); @@ -595,7 +672,7 @@ namespace ASDCP { { Capacity(size); } - + virtual ~FrameBuffer() {} // Sets the MPEG frame type of the picture data in the frame buffer. @@ -646,7 +723,7 @@ namespace ASDCP { // 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; + Result_t OpenRead(const std::string& filename) const; // Fill a VideoDescriptor struct with the values from the file's header. // Returns RESULT_INIT if the file is not open. @@ -675,10 +752,16 @@ namespace ASDCP { MXFWriter(); virtual ~MXFWriter(); + // Warning: direct manipulation of MXF structures can interfere + // with the normal operation of the wrapper. Caveat emptor! + virtual MXF::OP1aHeader& OP1aHeader(); + virtual MXF::OPAtomIndexFooter& OPAtomIndexFooter(); + virtual MXF::RIP& RIP(); + // 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&, + Result_t OpenWrite(const std::string& filename, const WriterInfo&, const VideoDescriptor&, ui32_t HeaderSize = 16384); // Writes a frame of essence to the MXF file. If the optional AESEncContext @@ -702,9 +785,15 @@ namespace ASDCP { MXFReader(); virtual ~MXFReader(); + // Warning: direct manipulation of MXF structures can interfere + // with the normal operation of the wrapper. Caveat emptor! + virtual MXF::OP1aHeader& OP1aHeader(); + virtual MXF::OPAtomIndexFooter& OPAtomIndexFooter(); + virtual MXF::RIP& RIP(); + // Open the file for reading. The file must exist. Returns error if the // operation cannot be completed. - Result_t OpenRead(const char* filename) const; + Result_t OpenRead(const std::string& filename) const; // Returns RESULT_INIT if the file is not open. Result_t Close() const; @@ -726,6 +815,12 @@ namespace ASDCP { // out of range, or if optional decrypt or HAMC operations fail. Result_t ReadFrame(ui32_t frame_number, FrameBuffer&, AESDecContext* = 0, HMACContext* = 0) const; + // Using the index table read from the footer partition, lookup the frame number + // and return the offset into the file at which to read that frame of essence. + // Returns RESULT_INIT if the file is not open, and RESULT_RANGE if the frame number is + // out of range. + Result_t LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset, i8_t& temporalOffset, i8_t& keyFrameOffset) 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. @@ -746,22 +841,49 @@ namespace ASDCP { }; } // 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 + CF_CFG_6, // ST 377-4 (MCA) labels (see also ASDCP::MXF::decode_mca_string) + CF_MAXIMUM + }; + struct AudioDescriptor { - Rational SampleRate; // rate of frame wrapping + Rational EditRate; // rate of frame wrapping Rational AudioSamplingRate; // rate of audio sample - ui32_t Locked; // + 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 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); @@ -774,7 +896,7 @@ namespace ASDCP { // Returns number of samples per frame of data described by ADesc inline ui32_t CalcSamplesPerFrame(const AudioDescriptor& ADesc) { - double tmpd = ADesc.AudioSamplingRate.Quotient() / ADesc.SampleRate.Quotient(); + double tmpd = ADesc.AudioSamplingRate.Quotient() / ADesc.EditRate.Quotient(); return (ui32_t)ceil(tmpd); } @@ -791,7 +913,7 @@ namespace ASDCP { 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; }; @@ -813,7 +935,7 @@ namespace ASDCP { // 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; + Result_t OpenRead(const std::string& 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. @@ -825,6 +947,8 @@ namespace ASDCP { // 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; + + Result_t Seek(ui32_t frame_number) const; }; @@ -839,10 +963,16 @@ namespace ASDCP { MXFWriter(); virtual ~MXFWriter(); + // Warning: direct manipulation of MXF structures can interfere + // with the normal operation of the wrapper. Caveat emptor! + virtual MXF::OP1aHeader& OP1aHeader(); + virtual MXF::OPAtomIndexFooter& OPAtomIndexFooter(); + virtual MXF::RIP& RIP(); + // 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&, + Result_t OpenWrite(const std::string& filename, const WriterInfo&, const AudioDescriptor&, ui32_t HeaderSize = 16384); // Writes a frame of essence to the MXF file. If the optional AESEncContext @@ -866,9 +996,15 @@ namespace ASDCP { MXFReader(); virtual ~MXFReader(); + // Warning: direct manipulation of MXF structures can interfere + // with the normal operation of the wrapper. Caveat emptor! + virtual MXF::OP1aHeader& OP1aHeader(); + virtual MXF::OPAtomIndexFooter& OPAtomIndexFooter(); + virtual MXF::RIP& RIP(); + // Open the file for reading. The file must exist. Returns error if the // operation cannot be completed. - Result_t OpenRead(const char* filename) const; + Result_t OpenRead(const std::string& filename) const; // Returns RESULT_INIT if the file is not open. Result_t Close() const; @@ -890,25 +1026,64 @@ namespace ASDCP { // out of range, or if optional decrypt or HAMC operations fail. Result_t ReadFrame(ui32_t frame_number, FrameBuffer&, AESDecContext* = 0, HMACContext* = 0) const; + // Using the index table read from the footer partition, lookup the frame number + // and return the offset into the file at which to read that frame of essence. + // Returns RESULT_INIT if the file is not open, and RESULT_RANGE if the frame number is + // out of range. + Result_t LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset, i8_t& temporalOffset, i8_t& keyFrameOffset) 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 DefaultCodingDataLength = 64; + const ui32_t MaxPrecincts = 32; // ISO 15444-1 Annex A.6.1 + const ui32_t MaxDefaults = 256; // made up - struct ImageComponent +#pragma pack(1) + struct ImageComponent_t // ISO 15444-1 Annex A.5.1 { - byte_t Ssize; - byte_t XRsize; - byte_t YRsize; + 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; @@ -927,13 +1102,13 @@ namespace ASDCP { ui32_t XTOsize; ui32_t YTOsize; ui16_t Csize; - ImageComponent ImageComponents[MaxComponents]; - byte_t CodingStyle[DefaultCodingDataLength]; - ui32_t CodingStyleLength; - byte_t QuantDefault[DefaultCodingDataLength]; - ui32_t QuantDefaultLength; + 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); @@ -944,7 +1119,7 @@ namespace ASDCP { 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; }; @@ -968,13 +1143,17 @@ namespace ASDCP { // 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; + Result_t OpenReadFrame(const std::string& 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 { @@ -992,9 +1171,18 @@ namespace ASDCP { // 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 + // parser will check the metadata for each codestream and fail if a + // mismatch is detected. + Result_t OpenRead(const std::string& 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 char* filename, bool pedantic = false) const; + Result_t OpenRead(const std::list& 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. @@ -1024,10 +1212,16 @@ namespace ASDCP { MXFWriter(); virtual ~MXFWriter(); + // Warning: direct manipulation of MXF structures can interfere + // with the normal operation of the wrapper. Caveat emptor! + virtual MXF::OP1aHeader& OP1aHeader(); + virtual MXF::OPAtomIndexFooter& OPAtomIndexFooter(); + virtual MXF::RIP& RIP(); + // 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&, + Result_t OpenWrite(const std::string& filename, const WriterInfo&, const PictureDescriptor&, ui32_t HeaderSize = 16384); // Writes a frame of essence to the MXF file. If the optional AESEncContext @@ -1051,9 +1245,15 @@ namespace ASDCP { MXFReader(); virtual ~MXFReader(); + // Warning: direct manipulation of MXF structures can interfere + // with the normal operation of the wrapper. Caveat emptor! + virtual MXF::OP1aHeader& OP1aHeader(); + virtual MXF::OPAtomIndexFooter& OPAtomIndexFooter(); + virtual MXF::RIP& RIP(); + // Open the file for reading. The file must exist. Returns error if the // operation cannot be completed. - Result_t OpenRead(const char* filename) const; + Result_t OpenRead(const std::string& filename) const; // Returns RESULT_INIT if the file is not open. Result_t Close() const; @@ -1075,15 +1275,659 @@ namespace ASDCP { // out of range, or if optional decrypt or HAMC operations fail. Result_t ReadFrame(ui32_t frame_number, FrameBuffer&, AESDecContext* = 0, HMACContext* = 0) const; + // Using the index table read from the footer partition, lookup the frame number + // and return the offset into the file at which to read that frame of essence. + // Returns RESULT_INIT if the file is not open, and RESULT_FRAME if the frame number is + // out of range. + Result_t LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset, i8_t& temporalOffset, i8_t& keyFrameOffset) 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 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::OP1aHeader& OP1aHeader(); + virtual MXF::OPAtomIndexFooter& OPAtomIndexFooter(); + virtual MXF::RIP& RIP(); + + // 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 std::string& 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 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::OP1aHeader& OP1aHeader(); + virtual MXF::OPAtomIndexFooter& OPAtomIndexFooter(); + virtual MXF::RIP& RIP(); + + // Open the file for reading. The file must exist. Returns error if the + // operation cannot be completed. + Result_t OpenRead(const std::string& 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; + + // Using the index table read from the footer partition, lookup the frame number + // and return the offset into the file at which to read that frame of essence. + // Returns RESULT_INIT if the file is not open, and RESULT_FRAME if the frame number is + // out of range. + Result_t LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset, i8_t& temporalOffset, i8_t& keyFrameOffset) 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 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; + }; + + // An abstract base for a lookup service that returns the resource data + // identified by the given ancillary resource id. + // + class IResourceResolver + { + public: + virtual ~IResourceResolver() {} + virtual Result_t ResolveRID(const byte_t* uuid, FrameBuffer&) const = 0; // return data for RID + }; + + // Resolves resource references by testing the named directory for file names containing + // the respective UUID. + // + class LocalFilenameResolver : public ASDCP::TimedText::IResourceResolver + { + std::string m_Dirname; + ASDCP_NO_COPY_CONSTRUCT(LocalFilenameResolver); + + public: + LocalFilenameResolver(); + virtual ~LocalFilenameResolver(); + Result_t OpenRead(const std::string& dirname); + Result_t ResolveRID(const byte_t* uuid, FrameBuffer& FrameBuf) const; + }; + + // + class DCSubtitleParser + { + class h__SubtitleParser; + mem_ptr 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 std::string& 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 std::string& filename) 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 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::OP1aHeader& OP1aHeader(); + virtual MXF::OPAtomIndexFooter& OPAtomIndexFooter(); + virtual MXF::RIP& RIP(); + + // 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 std::string& 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 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::OP1aHeader& OP1aHeader(); + virtual MXF::OPAtomIndexFooter& OPAtomIndexFooter(); + virtual MXF::RIP& RIP(); + + // Open the file for reading. The file must exist. Returns error if the + // operation cannot be completed. + Result_t OpenRead(const std::string& 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 DCData + { + struct DCDataDescriptor + { + Rational EditRate; // Sample rate + ui32_t ContainerDuration; // number of frames + byte_t AssetID[UUIDlen]; // The UUID for the DCData track + byte_t DataEssenceCoding[UUIDlen]; // The coding for the data carried + }; + + // Print DCDataDescriptor to std::ostream + std::ostream& operator << (std::ostream& strm, const DCDataDescriptor& ddesc); + // Print debugging information to stream (stderr default) + void DCDataDescriptorDump(const DCDataDescriptor&, 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 DC Data file. The file is expected + // to contain exactly one complete frame of DC data essence as an unwrapped (raw) + // byte stream. + class BytestreamParser + { + class h__BytestreamParser; + mem_ptr m_Parser; + ASDCP_NO_COPY_CONSTRUCT(BytestreamParser); + + public: + BytestreamParser(); + virtual ~BytestreamParser(); + + // 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 std::string& filename, FrameBuffer&) const; + + // Fill a DCDataDescriptor struct with the values from the file's bytestream. + // Returns RESULT_INIT if the file is not open. + Result_t FillDCDataDescriptor(DCDataDescriptor&) const; + }; + + // An object which reads a sequence of files containing DC Data. + class SequenceParser + { + class h__SequenceParser; + mem_ptr 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 bytestream for exactly one frame. The files + // must be named such that the frames are in temporal order when sorted + // alphabetically by filename. + Result_t OpenRead(const std::string& filename) const; + + // Opens a file sequence for reading. The sequence is expected to contain one or + // more filenames, each naming a file containing the bytestream for exactly one + // frame. + Result_t OpenRead(const std::list& file_list) const; + + // Fill a DCDataDescriptor struct with default values. + // Returns RESULT_INIT if the directory is not open. + Result_t FillDCDataDescriptor(DCDataDescriptor&) 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 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::OP1aHeader& OP1aHeader(); + virtual MXF::OPAtomIndexFooter& OPAtomIndexFooter(); + virtual MXF::RIP& RIP(); + + // 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 std::string& filename, const WriterInfo&, + const DCDataDescriptor&, 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 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::OP1aHeader& OP1aHeader(); + virtual MXF::OPAtomIndexFooter& OPAtomIndexFooter(); + virtual MXF::RIP& RIP(); + + // Open the file for reading. The file must exist. Returns error if the + // operation cannot be completed. + Result_t OpenRead(const std::string& filename) const; + + // Returns RESULT_INIT if the file is not open. + Result_t Close() const; + + // Fill a DCDataDescriptor struct with the values from the file's header. + // Returns RESULT_INIT if the file is not open. + Result_t FillDCDataDescriptor(DCDataDescriptor&) 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; + + // Using the index table read from the footer partition, lookup the frame number + // and return the offset into the file at which to read that frame of essence. + // Returns RESULT_INIT if the file is not open, and RESULT_RANGE if the frame number is + // out of range. + Result_t LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset, i8_t& temporalOffset, i8_t& keyFrameOffset) const; + + // Print debugging information to stream + void DumpHeaderMetadata(FILE* = 0) const; + void DumpIndex(FILE* = 0) const; + }; + + } // namespace DCData + + //--------------------------------------------------------------------------------- + // + namespace ATMOS + { + struct AtmosDescriptor : public DCData::DCDataDescriptor + { + ui32_t FirstFrame; // Frame number of the frame to align with the FFOA of the picture track + ui16_t MaxChannelCount; // Max number of channels in bitstream + ui16_t MaxObjectCount; // Max number of objects in bitstream + byte_t AtmosID[UUIDlen]; // UUID of Atmos Project + ui8_t AtmosVersion; // ATMOS Coder Version used to create bitstream + }; + + // Print AtmosDescriptor to std::ostream + std::ostream& operator << (std::ostream& strm, const AtmosDescriptor& adesc); + // Print debugging information to stream (stderr default) + void AtmosDescriptorDump(const AtmosDescriptor&, FILE* = 0); + // Determine if a file is a raw atmos file + bool IsDolbyAtmos(const std::string& filename); + + // + class MXFWriter + { + + class h__Writer; + mem_ptr 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::OP1aHeader& OP1aHeader(); + virtual MXF::OPAtomIndexFooter& OPAtomIndexFooter(); + virtual MXF::RIP& RIP(); + + // 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 std::string& filename, const WriterInfo&, + const AtmosDescriptor&, 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 DCData::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 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::OP1aHeader& OP1aHeader(); + virtual MXF::OPAtomIndexFooter& OPAtomIndexFooter(); + virtual MXF::RIP& RIP(); + + // Open the file for reading. The file must exist. Returns error if the + // operation cannot be completed. + Result_t OpenRead(const std::string& filename) const; + + // Returns RESULT_INIT if the file is not open. + Result_t Close() const; + + // Fill an AtmosDescriptor struct with the values from the file's header. + // Returns RESULT_INIT if the file is not open. + Result_t FillAtmosDescriptor(AtmosDescriptor&) 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, DCData::FrameBuffer&, AESDecContext* = 0, HMACContext* = 0) const; + + // Using the index table read from the footer partition, lookup the frame number + // and return the offset into the file at which to read that frame of essence. + // Returns RESULT_INIT if the file is not open, and RESULT_RANGE if the frame number is + // out of range. + Result_t LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset, i8_t& temporalOffset, i8_t& keyFrameOffset) const; + + // Print debugging information to stream + void DumpHeaderMetadata(FILE* = 0) const; + void DumpIndex(FILE* = 0) const; + }; + + } // namespace ATMOS + + + } // namespace ASDCP -#endif // _AS_DCP_H__ +#endif // _AS_DCP_H_ // // end AS_DCP.h