diff options
| author | Carl Hetherington <cth@carlh.net> | 2015-01-14 17:39:32 +0000 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2015-01-20 11:20:25 +0000 |
| commit | 3f630fb8334238ab8a58fbe1a0f513ae2c00de80 (patch) | |
| tree | 4b773b91029d6374bfd4f2194053d3e249d597cd /asdcplib/src | |
| parent | 49cafda01b3e07c47e3b20dd5ee91e1426446aea (diff) | |
Simplify time representation; better in-tree DCP subtitle parser.
Diffstat (limited to 'asdcplib/src')
84 files changed, 39081 insertions, 0 deletions
diff --git a/asdcplib/src/AS_DCP.cpp b/asdcplib/src/AS_DCP.cpp new file mode 100755 index 0000000..0ae9a1f --- /dev/null +++ b/asdcplib/src/AS_DCP.cpp @@ -0,0 +1,124 @@ +/* +Copyright (c) 2004-2009, 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.cpp + \version $Id: AS_DCP.cpp,v 1.6 2009/04/09 19:16:49 msheby Exp $ + \brief AS-DCP library, misc classes and subroutines +*/ + +#include "AS_DCP_internal.h" +#include <assert.h> + +const char* +ASDCP::Version() +{ + return PACKAGE_VERSION; +} + + +//------------------------------------------------------------------------------------------ +// +// frame buffer base class implementation + +ASDCP::FrameBuffer::FrameBuffer() : + m_Data(0), m_Capacity(0), m_OwnMem(false), m_Size(0), + m_FrameNumber(0), m_SourceLength(0), m_PlaintextOffset(0) +{ +} + +ASDCP::FrameBuffer::~FrameBuffer() +{ + if ( m_OwnMem && m_Data != 0 ) + free(m_Data); +} + +// Instructs the object to use an externally allocated buffer. The external +// buffer will not be cleaned up by the frame buffer when it is destroyed. +// Call with (0,0) to revert to internally allocated buffer. +// Returns error if the buf_addr argument is NULL and either buf_size is +// non-zero or internally allocated memory is in use. +ASDCP::Result_t +ASDCP::FrameBuffer::SetData(byte_t* buf_addr, ui32_t buf_size) +{ + // if buf_addr is null and we have an external memory reference, + // drop the reference and place the object in the initialized- + // but-no-buffer-allocated state + if ( buf_addr == 0 ) + { + if ( buf_size > 0 || m_OwnMem ) + return RESULT_PTR; + + m_OwnMem = false; + m_Capacity = m_Size = 0; + m_Data = 0; + return RESULT_OK; + } + + if ( m_OwnMem && m_Data != 0 ) + free(m_Data); + + m_OwnMem = false; + m_Capacity = buf_size; + m_Data = buf_addr; + m_Size = 0; + + return RESULT_OK; +} + +// 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. +ASDCP::Result_t +ASDCP::FrameBuffer::Capacity(ui32_t cap_size) +{ + if ( ! m_OwnMem && m_Data != 0 ) + return RESULT_CAPEXTMEM; // cannot resize external memory + + if ( m_Capacity < cap_size ) + { + if ( m_Data != 0 ) + { + assert(m_OwnMem); + free(m_Data); + } + + m_Data = (byte_t*)malloc(cap_size); + + if ( m_Data == 0 ) + return RESULT_ALLOC; + + m_Capacity = cap_size; + m_OwnMem = true; + m_Size = 0; + } + + return RESULT_OK; +} + + +// +// end AS_DCP.cpp +// diff --git a/asdcplib/src/AS_DCP.h b/asdcplib/src/AS_DCP.h new file mode 100755 index 0000000..eb2ce6e --- /dev/null +++ b/asdcplib/src/AS_DCP.h @@ -0,0 +1,1570 @@ +/* +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 <KM_platform.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; + + Result_t OpenReadFrame(const unsigned char * data, unsigned int size, 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 unless overwrite is true. 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, bool overwrite); + + // Writes a frame of essence to the MXF file. If the optional AESEncContext + // argument is present, the essence is encrypted prior to writing. + // A MD5 hash of the data that we write is written to hash if it is not 0 + // Fails if the file is not open, is finalized, or an operating system + // error occurs. + Result_t WriteFrame(const FrameBuffer&, AESEncContext* = 0, HMACContext* = 0, std::string* hash = 0); + + Result_t FakeWriteFrame(int size); + + // Closes the MXF file, writing the index and revised header. + Result_t Finalize(); + + // Return the current file offset in the MXF file that we are writing + ui64_t Tell() const; + }; + + // + 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 unless overwrite is true. 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, bool overwrite); + + // 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, std::string* hash = 0); + + Result_t FakeWriteFrame(int size, StereoscopicPhase_t phase); + + // 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(); + + // Return the current file offset in the MXF file that we are writing + ui64_t Tell() const; + }; + + // + 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 +// diff --git a/asdcplib/src/AS_DCP_AES.cpp b/asdcplib/src/AS_DCP_AES.cpp new file mode 100755 index 0000000..bb2a400 --- /dev/null +++ b/asdcplib/src/AS_DCP_AES.cpp @@ -0,0 +1,446 @@ +/* +Copyright (c) 2004-2009, 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_AES.h + \version $Id: AS_DCP_AES.cpp,v 1.13 2009/10/15 17:31:27 jhurst Exp $ + \brief AS-DCP library, AES wrapper +*/ + + +#include <assert.h> +#include <AS_DCP.h> +#include <KM_log.h> +#include <KM_prng.h> +using Kumu::DefaultLogSink; + +using namespace ASDCP; +const int KEY_SIZE_BITS = 128; + +#include <openssl/aes.h> +#include <openssl/sha.h> +#include <openssl/bn.h> +#include <openssl/err.h> + + +void +print_ssl_error() +{ + char err_buf[256]; + unsigned long errval = ERR_get_error(); + DefaultLogSink().Error("OpenSSL: %s\n", ERR_error_string(errval, err_buf)); +} + +//------------------------------------------------------------------------------------------ + +class ASDCP::AESEncContext::h__AESContext : public AES_KEY +{ +public: + byte_t m_IVec[CBC_BLOCK_SIZE]; +}; + + +ASDCP::AESEncContext::AESEncContext() {} +ASDCP::AESEncContext::~AESEncContext() {} + +// Initializes Rijndael CBC encryption context. +// Returns error if the key argument is NULL. +ASDCP::Result_t +ASDCP::AESEncContext::InitKey(const byte_t* key) +{ + KM_TEST_NULL_L(key); + + if ( m_Context ) + return RESULT_INIT; + + m_Context = new h__AESContext; + + if ( AES_set_encrypt_key(key, KEY_SIZE_BITS, m_Context) ) + { + print_ssl_error(); + return RESULT_CRYPT_INIT; + } + + return RESULT_OK; +} + + +// Set the value of the 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. +ASDCP::Result_t +ASDCP::AESEncContext::SetIVec(const byte_t* i_vec) +{ + KM_TEST_NULL_L(i_vec); + + if ( ! m_Context ) + return RESULT_INIT; + + memcpy(m_Context->m_IVec, i_vec, CBC_BLOCK_SIZE); + return RESULT_OK; +} + + +// Retrieve the value of the 16 byte CBC Initialization Vector. +// Returns error if the i_vec argument is NULL. +ASDCP::Result_t +ASDCP::AESEncContext::GetIVec(byte_t* i_vec) const +{ + KM_TEST_NULL_L(i_vec); + + if ( ! m_Context ) + return RESULT_INIT; + + memcpy(i_vec, m_Context->m_IVec, CBC_BLOCK_SIZE); + return RESULT_OK; +} + + +// Encrypt a 16 byte block of data. +// Returns error if either argument is NULL. +ASDCP::Result_t +ASDCP::AESEncContext::EncryptBlock(const byte_t* pt_buf, byte_t* ct_buf, ui32_t block_size) +{ + KM_TEST_NULL_L(pt_buf); + KM_TEST_NULL_L(ct_buf); + assert(block_size > 0); + assert( block_size % CBC_BLOCK_SIZE == 0 ); + + if ( m_Context.empty() ) + return RESULT_INIT; + + h__AESContext* Ctx = m_Context; + byte_t tmp_buf[CBC_BLOCK_SIZE]; + const byte_t* in_p = pt_buf; + byte_t* out_p = ct_buf; + + while ( block_size ) + { + // xor with the previous block + for ( ui32_t i = 0; i < CBC_BLOCK_SIZE; i++ ) + tmp_buf[i] = in_p[i] ^ Ctx->m_IVec[i]; + + AES_encrypt(tmp_buf, Ctx->m_IVec, Ctx); + memcpy(out_p, Ctx->m_IVec, CBC_BLOCK_SIZE); + + in_p += CBC_BLOCK_SIZE; + out_p += CBC_BLOCK_SIZE; + block_size -= CBC_BLOCK_SIZE; + } + + return RESULT_OK; +} + + +//------------------------------------------------------------------------------------------ + +class ASDCP::AESDecContext::h__AESContext : public AES_KEY +{ +public: + byte_t m_IVec[CBC_BLOCK_SIZE]; +}; + +ASDCP::AESDecContext::AESDecContext() {} +ASDCP::AESDecContext::~AESDecContext() {} + + +// Initializes Rijndael CBC decryption context. +// Returns error if the key argument is NULL. +ASDCP::Result_t +ASDCP::AESDecContext::InitKey(const byte_t* key) +{ + KM_TEST_NULL_L(key); + + if ( m_Context ) + return RESULT_INIT; + + m_Context = new h__AESContext; + + if ( AES_set_decrypt_key(key, KEY_SIZE_BITS, m_Context) ) + { + print_ssl_error(); + return RESULT_CRYPT_INIT; + } + + return RESULT_OK; +} + +// 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. +ASDCP::Result_t +ASDCP::AESDecContext::SetIVec(const byte_t* i_vec) +{ + KM_TEST_NULL_L(i_vec); + + if ( ! m_Context ) + return RESULT_INIT; + + memcpy(m_Context->m_IVec, i_vec, CBC_BLOCK_SIZE); + return RESULT_OK; +} + +// Decrypt a 16 byte block of data. +// Returns error if either argument is NULL. +ASDCP::Result_t +ASDCP::AESDecContext::DecryptBlock(const byte_t* ct_buf, byte_t* pt_buf, ui32_t block_size) +{ + KM_TEST_NULL_L(ct_buf); + KM_TEST_NULL_L(pt_buf); + assert(block_size > 0); + assert( block_size % CBC_BLOCK_SIZE == 0 ); + + if ( m_Context.empty() ) + return RESULT_INIT; + + register h__AESContext* Ctx = m_Context; + + const byte_t* in_p = ct_buf; + byte_t* out_p = pt_buf; + + while ( block_size ) + { + AES_decrypt(in_p, out_p, Ctx); + + for ( ui32_t i = 0; i < CBC_BLOCK_SIZE; i++ ) + out_p[i] ^= Ctx->m_IVec[i]; + + memcpy(Ctx->m_IVec, in_p, CBC_BLOCK_SIZE); + + in_p += CBC_BLOCK_SIZE; + out_p += CBC_BLOCK_SIZE; + block_size -= CBC_BLOCK_SIZE; + } + + return RESULT_OK; +} + +//------------------------------------------------------------------------------------------ + +static const ui32_t B_len = 64; // rfc 2104, Sec. 2 + +static byte_t const ipad_const = 0x36; +static byte_t const opad_const = 0x5c; + +class HMACContext::h__HMACContext +{ + SHA_CTX m_SHA; + byte_t m_key[KeyLen]; + ASDCP_NO_COPY_CONSTRUCT(h__HMACContext); + +public: + byte_t m_SHAValue[HMAC_SIZE]; + bool m_Final; + + h__HMACContext() : m_Final(false) {} + ~h__HMACContext() {} + + // SMPTE 429.6 MIC key generation + void SetKey(const byte_t* key) + { + byte_t rng_buf[SHA_DIGEST_LENGTH*2]; + Kumu::Gen_FIPS_186_Value(key, KeyLen, rng_buf, SHA_DIGEST_LENGTH*2); + + // rng_buf contains two rounds, x0 and x1 (each 160 bits). + // Use x1 per SMPTE 430-6-2006 Sec. 7.10 + memcpy(m_key, rng_buf+SHA_DIGEST_LENGTH, KeyLen); + Reset(); + } + + // MXF Interop MIC key generation + void SetInteropKey(const byte_t* key) + { + static byte_t key_nonce[KeyLen] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff }; + byte_t sha_buf[SHA_DIGEST_LENGTH]; + + // 7.10: MICKey = trunc( SHA1 ( key, key_nonce ) ) + SHA_CTX SHA; + SHA1_Init(&SHA); + SHA1_Update(&SHA, key, KeyLen); + SHA1_Update(&SHA, key_nonce, KeyLen); + SHA1_Final(sha_buf, &SHA); + memcpy(m_key, sha_buf, KeyLen); + Reset(); + } + + // + void + Reset() + { + byte_t xor_buf[B_len]; + memset(xor_buf, 0, B_len); + memcpy(xor_buf, m_key, KeyLen); + + memset(m_SHAValue, 0, HMAC_SIZE); + m_Final = false; + SHA1_Init(&m_SHA); + + // H(K XOR opad, H(K XOR ipad, text)) + // ^^^^^^^^^^ + for ( ui32_t i = 0; i < B_len; i++ ) + xor_buf[i] ^= ipad_const; + + SHA1_Update(&m_SHA, xor_buf, B_len); + } + + // + void + Update(const byte_t* buf, ui32_t buf_len) + { + // H(K XOR opad, H(K XOR ipad, text)) + // ^^^^ + SHA1_Update(&m_SHA, buf, buf_len); + } + + // + void + Finalize() + { + SHA_CTX SHA; + SHA1_Init(&SHA); + + byte_t xor_buf[B_len]; + memset(xor_buf, 0, B_len); + memcpy(xor_buf, m_key, KeyLen); + + SHA1_Init(&SHA); + + // H(K XOR opad, H(K XOR ipad, text)) + // ^^^^^^^^^^ + for ( ui32_t i = 0; i < B_len; i++ ) + xor_buf[i] ^= opad_const; + + SHA1_Update(&SHA, xor_buf, B_len); + + // H(K XOR opad, H(K XOR ipad, text)) + // ^ + SHA1_Final(m_SHAValue, &m_SHA); + SHA1_Update(&SHA, m_SHAValue, HMAC_SIZE); + + // H(K XOR opad, H(K XOR ipad, text)) + // ^ + SHA1_Final(m_SHAValue, &SHA); + m_Final = true; + } +}; + + +HMACContext::HMACContext() +{ +} + +HMACContext::~HMACContext() +{ +} + + +// +Result_t +HMACContext::InitKey(const byte_t* key, LabelSet_t SetType) +{ + KM_TEST_NULL_L(key); + + m_Context = new h__HMACContext; + + switch ( SetType ) + { + case LS_MXF_INTEROP: m_Context->SetInteropKey(key); break; + case LS_MXF_SMPTE: m_Context->SetKey(key); break; + default: + m_Context = 0; + return RESULT_INIT; + } + + return RESULT_OK; +} + + +// +void +HMACContext::Reset() +{ + if ( ! m_Context.empty() ) + m_Context->Reset(); +} + + +// +Result_t +HMACContext::Update(const byte_t* buf, ui32_t buf_len) +{ + KM_TEST_NULL_L(buf); + + if ( m_Context.empty() || m_Context->m_Final ) + return RESULT_INIT; + + m_Context->Update(buf, buf_len); + return RESULT_OK; +} + + +// +Result_t +HMACContext::Finalize() +{ + if ( m_Context.empty() || m_Context->m_Final ) + return RESULT_INIT; + + m_Context->Finalize(); + return RESULT_OK; +} + + +// +Result_t +HMACContext::GetHMACValue(byte_t* buf) const +{ + KM_TEST_NULL_L(buf); + + if ( m_Context.empty() || ! m_Context->m_Final ) + return RESULT_INIT; + + memcpy(buf, m_Context->m_SHAValue, HMAC_SIZE); + return RESULT_OK; +} + + +// +Result_t +HMACContext::TestHMACValue(const byte_t* buf) const +{ + KM_TEST_NULL_L(buf); + + if ( m_Context.empty() || ! m_Context->m_Final ) + return RESULT_INIT; + + return ( memcmp(buf, m_Context->m_SHAValue, HMAC_SIZE) == 0 ) ? RESULT_OK : RESULT_HMACFAIL; +} + + + +// +// end AS_DCP_AES.cpp +// diff --git a/asdcplib/src/AS_DCP_JP2K.cpp b/asdcplib/src/AS_DCP_JP2K.cpp new file mode 100755 index 0000000..05166d6 --- /dev/null +++ b/asdcplib/src/AS_DCP_JP2K.cpp @@ -0,0 +1,1384 @@ +/* -*- c-basic-offset: 2; -*- */ + +/* +Copyright (c) 2004-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_JP2k.cpp + \version $Id: AS_DCP_JP2K.cpp,v 1.54 2012/02/07 18:54:24 jhurst Exp $ + \brief AS-DCP library, JPEG 2000 essence reader and writer implementation +*/ + +#include "AS_DCP_internal.h" +#include <iostream> +#include <iomanip> + +using std::cout; +using namespace ASDCP::JP2K; +using Kumu::GenRandomValue; + +//------------------------------------------------------------------------------------------ + +static std::string JP2K_PACKAGE_LABEL = "File Package: SMPTE 429-4 frame wrapping of JPEG 2000 codestreams"; +static std::string JP2K_S_PACKAGE_LABEL = "File Package: SMPTE 429-10 frame wrapping of stereoscopic JPEG 2000 codestreams"; +static std::string PICT_DEF_LABEL = "Picture Track"; + +int s_exp_lookup[16] = { 0, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024,2048, 4096, 8192, 16384, 32768 }; + +// +std::ostream& +ASDCP::JP2K::operator << (std::ostream& strm, const PictureDescriptor& PDesc) +{ + strm << " AspectRatio: " << PDesc.AspectRatio.Numerator << "/" << PDesc.AspectRatio.Denominator << std::endl; + strm << " EditRate: " << PDesc.EditRate.Numerator << "/" << PDesc.EditRate.Denominator << std::endl; + strm << " SampleRate: " << PDesc.SampleRate.Numerator << "/" << PDesc.SampleRate.Denominator << std::endl; + strm << " StoredWidth: " << (unsigned) PDesc.StoredWidth << std::endl; + strm << " StoredHeight: " << (unsigned) PDesc.StoredHeight << std::endl; + strm << " Rsize: " << (unsigned) PDesc.Rsize << std::endl; + strm << " Xsize: " << (unsigned) PDesc.Xsize << std::endl; + strm << " Ysize: " << (unsigned) PDesc.Ysize << std::endl; + strm << " XOsize: " << (unsigned) PDesc.XOsize << std::endl; + strm << " YOsize: " << (unsigned) PDesc.YOsize << std::endl; + strm << " XTsize: " << (unsigned) PDesc.XTsize << std::endl; + strm << " YTsize: " << (unsigned) PDesc.YTsize << std::endl; + strm << " XTOsize: " << (unsigned) PDesc.XTOsize << std::endl; + strm << " YTOsize: " << (unsigned) PDesc.YTOsize << std::endl; + strm << " ContainerDuration: " << (unsigned) PDesc.ContainerDuration << std::endl; + + strm << "-- JPEG 2000 Metadata --" << std::endl; + strm << " ImageComponents:" << std::endl; + strm << " bits h-sep v-sep" << std::endl; + + ui32_t i; + for ( i = 0; i < PDesc.Csize; i++ ) + { + strm << " " << std::setw(4) << PDesc.ImageComponents[i].Ssize + 1 /* See ISO 15444-1, Table A11, for the origin of '+1' */ + << " " << std::setw(5) << PDesc.ImageComponents[i].XRsize + << " " << std::setw(5) << PDesc.ImageComponents[i].YRsize + << std::endl; + } + + strm << " Scod: " << (short) PDesc.CodingStyleDefault.Scod << std::endl; + strm << " ProgressionOrder: " << (short) PDesc.CodingStyleDefault.SGcod.ProgressionOrder << std::endl; + strm << " NumberOfLayers: " << (short) KM_i16_BE(Kumu::cp2i<ui16_t>(PDesc.CodingStyleDefault.SGcod.NumberOfLayers)) << std::endl; + strm << " MultiCompTransform: " << (short) PDesc.CodingStyleDefault.SGcod.MultiCompTransform << std::endl; + strm << "DecompositionLevels: " << (short) PDesc.CodingStyleDefault.SPcod.DecompositionLevels << std::endl; + strm << " CodeblockWidth: " << (short) PDesc.CodingStyleDefault.SPcod.CodeblockWidth << std::endl; + strm << " CodeblockHeight: " << (short) PDesc.CodingStyleDefault.SPcod.CodeblockHeight << std::endl; + strm << " CodeblockStyle: " << (short) PDesc.CodingStyleDefault.SPcod.CodeblockStyle << std::endl; + strm << " Transformation: " << (short) PDesc.CodingStyleDefault.SPcod.Transformation << std::endl; + + + ui32_t precinct_set_size = 0; + + for ( i = 0; PDesc.CodingStyleDefault.SPcod.PrecinctSize[i] != 0 && i < MaxPrecincts; i++ ) + precinct_set_size++; + + strm << " Precincts: " << (short) precinct_set_size << std::endl; + strm << "precinct dimensions:" << std::endl; + + for ( i = 0; i < precinct_set_size; i++ ) + strm << " " << i + 1 << ": " << s_exp_lookup[PDesc.CodingStyleDefault.SPcod.PrecinctSize[i]&0x0f] << " x " + << s_exp_lookup[(PDesc.CodingStyleDefault.SPcod.PrecinctSize[i]>>4)&0x0f] << std::endl; + + strm << " Sqcd: " << (short) PDesc.QuantizationDefault.Sqcd << std::endl; + + char tmp_buf[MaxDefaults*2]; + strm << " SPqcd: " << Kumu::bin2hex(PDesc.QuantizationDefault.SPqcd, PDesc.QuantizationDefault.SPqcdLength, tmp_buf, MaxDefaults*2) + << std::endl; + + return strm; +} + +// +void +ASDCP::JP2K::PictureDescriptorDump(const PictureDescriptor& PDesc, FILE* stream) +{ + if ( stream == 0 ) + stream = stderr; + + fprintf(stream, "\ + AspectRatio: %d/%d\n\ + EditRate: %d/%d\n\ + SampleRate: %d/%d\n\ + StoredWidth: %u\n\ + StoredHeight: %u\n\ + Rsize: %u\n\ + Xsize: %u\n\ + Ysize: %u\n\ + XOsize: %u\n\ + YOsize: %u\n\ + XTsize: %u\n\ + YTsize: %u\n\ + XTOsize: %u\n\ + YTOsize: %u\n\ + ContainerDuration: %u\n", + PDesc.AspectRatio.Numerator, PDesc.AspectRatio.Denominator, + PDesc.EditRate.Numerator, PDesc.EditRate.Denominator, + PDesc.SampleRate.Numerator, PDesc.SampleRate.Denominator, + PDesc.StoredWidth, + PDesc.StoredHeight, + PDesc.Rsize, + PDesc.Xsize, + PDesc.Ysize, + PDesc.XOsize, + PDesc.YOsize, + PDesc.XTsize, + PDesc.YTsize, + PDesc.XTOsize, + PDesc.YTOsize, + PDesc.ContainerDuration + ); + + fprintf(stream, "-- JPEG 2000 Metadata --\n"); + fprintf(stream, " ImageComponents:\n"); + fprintf(stream, " bits h-sep v-sep\n"); + + ui32_t i; + for ( i = 0; i < PDesc.Csize; i++ ) + { + fprintf(stream, " %4d %5d %5d\n", + PDesc.ImageComponents[i].Ssize + 1, // See ISO 15444-1, Table A11, for the origin of '+1' + PDesc.ImageComponents[i].XRsize, + PDesc.ImageComponents[i].YRsize + ); + } + + fprintf(stream, " Scod: %hd\n", PDesc.CodingStyleDefault.Scod); + fprintf(stream, " ProgressionOrder: %hd\n", PDesc.CodingStyleDefault.SGcod.ProgressionOrder); + fprintf(stream, " NumberOfLayers: %hd\n", + KM_i16_BE(Kumu::cp2i<ui16_t>(PDesc.CodingStyleDefault.SGcod.NumberOfLayers))); + + fprintf(stream, " MultiCompTransform: %hd\n", PDesc.CodingStyleDefault.SGcod.MultiCompTransform); + fprintf(stream, "DecompositionLevels: %hd\n", PDesc.CodingStyleDefault.SPcod.DecompositionLevels); + fprintf(stream, " CodeblockWidth: %hd\n", PDesc.CodingStyleDefault.SPcod.CodeblockWidth); + fprintf(stream, " CodeblockHeight: %hd\n", PDesc.CodingStyleDefault.SPcod.CodeblockHeight); + fprintf(stream, " CodeblockStyle: %hd\n", PDesc.CodingStyleDefault.SPcod.CodeblockStyle); + fprintf(stream, " Transformation: %hd\n", PDesc.CodingStyleDefault.SPcod.Transformation); + + + ui32_t precinct_set_size = 0; + + for ( i = 0; PDesc.CodingStyleDefault.SPcod.PrecinctSize[i] != 0 && i < MaxPrecincts; i++ ) + precinct_set_size++; + + fprintf(stream, " Precincts: %hd\n", precinct_set_size); + fprintf(stream, "precinct dimensions:\n"); + + for ( i = 0; i < precinct_set_size; i++ ) + fprintf(stream, " %d: %d x %d\n", i + 1, + s_exp_lookup[PDesc.CodingStyleDefault.SPcod.PrecinctSize[i]&0x0f], + s_exp_lookup[(PDesc.CodingStyleDefault.SPcod.PrecinctSize[i]>>4)&0x0f] + ); + + fprintf(stream, " Sqcd: %hd\n", PDesc.QuantizationDefault.Sqcd); + + char tmp_buf[MaxDefaults*2]; + fprintf(stream, " SPqcd: %s\n", + Kumu::bin2hex(PDesc.QuantizationDefault.SPqcd, PDesc.QuantizationDefault.SPqcdLength, + tmp_buf, MaxDefaults*2) + ); +} + + +//------------------------------------------------------------------------------------------ +// +// hidden, internal implementation of JPEG 2000 reader + + +class lh__Reader : public ASDCP::h__Reader +{ + RGBAEssenceDescriptor* m_EssenceDescriptor; + JPEG2000PictureSubDescriptor* m_EssenceSubDescriptor; + ASDCP::Rational m_EditRate; + ASDCP::Rational m_SampleRate; + EssenceType_t m_Format; + + ASDCP_NO_COPY_CONSTRUCT(lh__Reader); + +public: + PictureDescriptor m_PDesc; // codestream parameter list + + lh__Reader(const Dictionary& d) : + ASDCP::h__Reader(d), m_EssenceDescriptor(0), m_EssenceSubDescriptor(0), m_Format(ESS_UNKNOWN) {} + Result_t OpenRead(const char*, EssenceType_t); + Result_t ReadFrame(ui32_t, JP2K::FrameBuffer&, AESDecContext*, HMACContext*); + Result_t MD_to_JP2K_PDesc(JP2K::PictureDescriptor& PDesc); +}; + +// +ASDCP::Result_t +lh__Reader::MD_to_JP2K_PDesc(JP2K::PictureDescriptor& PDesc) +{ + memset(&PDesc, 0, sizeof(PDesc)); + MXF::RGBAEssenceDescriptor* PDescObj = (MXF::RGBAEssenceDescriptor*)m_EssenceDescriptor; + + PDesc.EditRate = m_EditRate; + PDesc.SampleRate = m_SampleRate; + assert(PDescObj->ContainerDuration <= 0xFFFFFFFFL); + PDesc.ContainerDuration = (ui32_t) PDescObj->ContainerDuration; + PDesc.StoredWidth = PDescObj->StoredWidth; + PDesc.StoredHeight = PDescObj->StoredHeight; + PDesc.AspectRatio = PDescObj->AspectRatio; + + if ( m_EssenceSubDescriptor != 0 ) + { + PDesc.Rsize = m_EssenceSubDescriptor->Rsize; + PDesc.Xsize = m_EssenceSubDescriptor->Xsize; + PDesc.Ysize = m_EssenceSubDescriptor->Ysize; + PDesc.XOsize = m_EssenceSubDescriptor->XOsize; + PDesc.YOsize = m_EssenceSubDescriptor->YOsize; + PDesc.XTsize = m_EssenceSubDescriptor->XTsize; + PDesc.YTsize = m_EssenceSubDescriptor->YTsize; + PDesc.XTOsize = m_EssenceSubDescriptor->XTOsize; + PDesc.YTOsize = m_EssenceSubDescriptor->YTOsize; + PDesc.Csize = m_EssenceSubDescriptor->Csize; + + // PictureComponentSizing + ui32_t tmp_size = m_EssenceSubDescriptor->PictureComponentSizing.Length(); + + if ( tmp_size == 17 ) // ( 2 * sizeof(ui32_t) ) + 3 components * 3 byte each + memcpy(&PDesc.ImageComponents, m_EssenceSubDescriptor->PictureComponentSizing.RoData() + 8, tmp_size - 8); + + else + DefaultLogSink().Error("Unexpected PictureComponentSizing size: %u, should be 17\n", tmp_size); + + // CodingStyleDefault + memset(&PDesc.CodingStyleDefault, 0, sizeof(CodingStyleDefault_t)); + memcpy(&PDesc.CodingStyleDefault, + m_EssenceSubDescriptor->CodingStyleDefault.RoData(), + m_EssenceSubDescriptor->CodingStyleDefault.Length()); + + // QuantizationDefault + memset(&PDesc.QuantizationDefault, 0, sizeof(QuantizationDefault_t)); + memcpy(&PDesc.QuantizationDefault, + m_EssenceSubDescriptor->QuantizationDefault.RoData(), + m_EssenceSubDescriptor->QuantizationDefault.Length()); + + PDesc.QuantizationDefault.SPqcdLength = m_EssenceSubDescriptor->QuantizationDefault.Length() - 1; + } + + return RESULT_OK; +} + +// +// +ASDCP::Result_t +lh__Reader::OpenRead(const char* filename, EssenceType_t type) +{ + Result_t result = OpenMXFRead(filename); + + if( ASDCP_SUCCESS(result) ) + { + InterchangeObject* tmp_iobj = 0; + m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(RGBAEssenceDescriptor), &tmp_iobj); + m_EssenceDescriptor = static_cast<RGBAEssenceDescriptor*>(tmp_iobj); + + m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(JPEG2000PictureSubDescriptor), &tmp_iobj); + m_EssenceSubDescriptor = static_cast<JPEG2000PictureSubDescriptor*>(tmp_iobj); + + std::list<InterchangeObject*> ObjectList; + m_HeaderPart.GetMDObjectsByType(OBJ_TYPE_ARGS(Track), ObjectList); + + if ( ObjectList.empty() ) + { + DefaultLogSink().Error("MXF Metadata contains no Track Sets.\n"); + return RESULT_FORMAT; + } + + m_EditRate = ((Track*)ObjectList.front())->EditRate; + m_SampleRate = m_EssenceDescriptor->SampleRate; + + if ( type == ASDCP::ESS_JPEG_2000 ) + { + if ( m_EditRate != m_SampleRate ) + { + DefaultLogSink().Warn("EditRate and SampleRate do not match (%.03f, %.03f).\n", + m_EditRate.Quotient(), m_SampleRate.Quotient()); + + if ( (m_EditRate == EditRate_24 && m_SampleRate == EditRate_48) || + (m_EditRate == EditRate_25 && m_SampleRate == EditRate_50) || + (m_EditRate == EditRate_30 && m_SampleRate == EditRate_60) || + (m_EditRate == EditRate_48 && m_SampleRate == EditRate_96) || + (m_EditRate == EditRate_50 && m_SampleRate == EditRate_100) || + (m_EditRate == EditRate_60 && m_SampleRate == EditRate_120) ) + { + DefaultLogSink().Debug("File may contain JPEG Interop stereoscopic images.\n"); + return RESULT_SFORMAT; + } + + return RESULT_FORMAT; + } + } + else if ( type == ASDCP::ESS_JPEG_2000_S ) + { + if ( m_EditRate == EditRate_24 ) + { + if ( m_SampleRate != EditRate_48 ) + { + DefaultLogSink().Error("EditRate and SampleRate not correct for 24/48 stereoscopic essence.\n"); + return RESULT_FORMAT; + } + } + else if ( m_EditRate == EditRate_25 ) + { + if ( m_SampleRate != EditRate_50 ) + { + DefaultLogSink().Error("EditRate and SampleRate not correct for 25/50 stereoscopic essence.\n"); + return RESULT_FORMAT; + } + } + else if ( m_EditRate == EditRate_30 ) + { + if ( m_SampleRate != EditRate_60 ) + { + DefaultLogSink().Error("EditRate and SampleRate not correct for 30/60 stereoscopic essence.\n"); + return RESULT_FORMAT; + } + } + else if ( m_EditRate == EditRate_48 ) + { + if ( m_SampleRate != EditRate_96 ) + { + DefaultLogSink().Error("EditRate and SampleRate not correct for 48/96 stereoscopic essence.\n"); + return RESULT_FORMAT; + } + } + else if ( m_EditRate == EditRate_50 ) + { + if ( m_SampleRate != EditRate_100 ) + { + DefaultLogSink().Error("EditRate and SampleRate not correct for 50/100 stereoscopic essence.\n"); + return RESULT_FORMAT; + } + } + else if ( m_EditRate == EditRate_60 ) + { + if ( m_SampleRate != EditRate_120 ) + { + DefaultLogSink().Error("EditRate and SampleRate not correct for 60/120 stereoscopic essence.\n"); + return RESULT_FORMAT; + } + } + else + { + DefaultLogSink().Error("EditRate not correct for stereoscopic essence: %d/%d.\n", + m_EditRate.Numerator, m_EditRate.Denominator); + return RESULT_FORMAT; + } + } + else + { + DefaultLogSink().Error("'type' argument unexpected: %x\n", type); + return RESULT_STATE; + } + + result = MD_to_JP2K_PDesc(m_PDesc); + } + + if( ASDCP_SUCCESS(result) ) + result = InitMXFIndex(); + + if( ASDCP_SUCCESS(result) ) + result = InitInfo(); + + return result; +} + +// +// +ASDCP::Result_t +lh__Reader::ReadFrame(ui32_t FrameNum, JP2K::FrameBuffer& FrameBuf, + AESDecContext* Ctx, HMACContext* HMAC) +{ + if ( ! m_File.IsOpen() ) + return RESULT_INIT; + + assert(m_Dict); + return ReadEKLVFrame(FrameNum, FrameBuf, m_Dict->ul(MDD_JPEG2000Essence), Ctx, HMAC); +} + + +// +class ASDCP::JP2K::MXFReader::h__Reader : public lh__Reader +{ + ASDCP_NO_COPY_CONSTRUCT(h__Reader); + h__Reader(); + +public: + h__Reader(const Dictionary& d) : lh__Reader(d) {} +}; + + + +//------------------------------------------------------------------------------------------ + + +// +void +ASDCP::JP2K::FrameBuffer::Dump(FILE* stream, ui32_t dump_len) const +{ + if ( stream == 0 ) + stream = stderr; + + fprintf(stream, "Frame: %06u, %7u bytes", m_FrameNumber, m_Size); + + fputc('\n', stream); + + if ( dump_len > 0 ) + Kumu::hexdump(m_Data, dump_len, stream); +} + + +//------------------------------------------------------------------------------------------ + +ASDCP::JP2K::MXFReader::MXFReader() +{ + m_Reader = new h__Reader(DefaultCompositeDict()); +} + + +ASDCP::JP2K::MXFReader::~MXFReader() +{ +} + +// Warning: direct manipulation of MXF structures can interfere +// with the normal operation of the wrapper. Caveat emptor! +// +ASDCP::MXF::OPAtomHeader& +ASDCP::JP2K::MXFReader::OPAtomHeader() +{ + if ( m_Reader.empty() ) + { + assert(g_OPAtomHeader); + return *g_OPAtomHeader; + } + + return m_Reader->m_HeaderPart; +} + +// Warning: direct manipulation of MXF structures can interfere +// with the normal operation of the wrapper. Caveat emptor! +// +ASDCP::MXF::OPAtomIndexFooter& +ASDCP::JP2K::MXFReader::OPAtomIndexFooter() +{ + if ( m_Reader.empty() ) + { + assert(g_OPAtomIndexFooter); + return *g_OPAtomIndexFooter; + } + + return m_Reader->m_FooterPart; +} + +// Open the file for reading. The file must exist. Returns error if the +// operation cannot be completed. +ASDCP::Result_t +ASDCP::JP2K::MXFReader::OpenRead(const char* filename) const +{ + return m_Reader->OpenRead(filename, ASDCP::ESS_JPEG_2000); +} + +// +ASDCP::Result_t +ASDCP::JP2K::MXFReader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf, + AESDecContext* Ctx, HMACContext* HMAC) const +{ + if ( m_Reader && m_Reader->m_File.IsOpen() ) + return m_Reader->ReadFrame(FrameNum, FrameBuf, Ctx, HMAC); + + return RESULT_INIT; +} + + +// Fill the struct with the values from the file's header. +// Returns RESULT_INIT if the file is not open. +ASDCP::Result_t +ASDCP::JP2K::MXFReader::FillPictureDescriptor(PictureDescriptor& PDesc) const +{ + if ( m_Reader && m_Reader->m_File.IsOpen() ) + { + PDesc = m_Reader->m_PDesc; + return RESULT_OK; + } + + return RESULT_INIT; +} + + +// Fill the struct with the values from the file's header. +// Returns RESULT_INIT if the file is not open. +ASDCP::Result_t +ASDCP::JP2K::MXFReader::FillWriterInfo(WriterInfo& Info) const +{ + if ( m_Reader && m_Reader->m_File.IsOpen() ) + { + Info = m_Reader->m_Info; + return RESULT_OK; + } + + return RESULT_INIT; +} + +// +void +ASDCP::JP2K::MXFReader::DumpHeaderMetadata(FILE* stream) const +{ + if ( m_Reader->m_File.IsOpen() ) + m_Reader->m_HeaderPart.Dump(stream); +} + + +// +void +ASDCP::JP2K::MXFReader::DumpIndex(FILE* stream) const +{ + if ( m_Reader->m_File.IsOpen() ) + m_Reader->m_FooterPart.Dump(stream); +} + +// +ASDCP::Result_t +ASDCP::JP2K::MXFReader::Close() const +{ + if ( m_Reader && m_Reader->m_File.IsOpen() ) + { + m_Reader->Close(); + return RESULT_OK; + } + + return RESULT_INIT; +} + + +//------------------------------------------------------------------------------------------ + + +class ASDCP::JP2K::MXFSReader::h__SReader : public lh__Reader +{ + ui32_t m_StereoFrameReady; + +public: + h__SReader(const Dictionary& d) : lh__Reader(d), m_StereoFrameReady(0xffffffff) {} + + // + Result_t ReadFrame(ui32_t FrameNum, StereoscopicPhase_t phase, FrameBuffer& FrameBuf, + AESDecContext* Ctx, HMACContext* HMAC) + { + // look up frame index node + IndexTableSegment::IndexEntry TmpEntry; + + if ( ASDCP_FAILURE(m_FooterPart.Lookup(FrameNum, TmpEntry)) ) + { + DefaultLogSink().Error("Frame value out of range: %u\n", FrameNum); + return RESULT_RANGE; + } + + // get frame position + Kumu::fpos_t FilePosition = m_EssenceStart + TmpEntry.StreamOffset; + Result_t result = RESULT_OK; + + if ( phase == SP_LEFT ) + { + if ( FilePosition != m_LastPosition ) + { + m_LastPosition = FilePosition; + result = m_File.Seek(FilePosition); + } + + // the call to ReadEKLVPacket() will leave the file on an R frame + m_StereoFrameReady = FrameNum; + } + else if ( phase == SP_RIGHT ) + { + if ( m_StereoFrameReady != FrameNum ) + { + // the file is not already positioned, we must do some work + // seek to the companion SP_LEFT frame and read the frame's key and length + if ( FilePosition != m_LastPosition ) + { + m_LastPosition = FilePosition; + result = m_File.Seek(FilePosition); + } + + KLReader Reader; + result = Reader.ReadKLFromFile(m_File); + + if ( ASDCP_SUCCESS(result) ) + { + // skip over the companion SP_LEFT frame + Kumu::fpos_t new_pos = FilePosition + SMPTE_UL_LENGTH + Reader.KLLength() + Reader.Length(); + result = m_File.Seek(new_pos); + } + } + + // the call to ReadEKLVPacket() will leave the file not on an R frame + m_StereoFrameReady = 0xffffffff; + } + else + { + DefaultLogSink().Error("Unexpected stereoscopic phase value: %u\n", phase); + return RESULT_STATE; + } + + if( ASDCP_SUCCESS(result) ) + { + ui32_t SequenceNum = FrameNum * 2; + SequenceNum += ( phase == SP_RIGHT ) ? 2 : 1; + assert(m_Dict); + result = ReadEKLVPacket(FrameNum, SequenceNum, FrameBuf, m_Dict->ul(MDD_JPEG2000Essence), Ctx, HMAC); + } + + return result; + } +}; + + + +ASDCP::JP2K::MXFSReader::MXFSReader() +{ + m_Reader = new h__SReader(DefaultCompositeDict()); +} + + +ASDCP::JP2K::MXFSReader::~MXFSReader() +{ +} + +// Warning: direct manipulation of MXF structures can interfere +// with the normal operation of the wrapper. Caveat emptor! +// +ASDCP::MXF::OPAtomHeader& +ASDCP::JP2K::MXFSReader::OPAtomHeader() +{ + if ( m_Reader.empty() ) + { + assert(g_OPAtomHeader); + return *g_OPAtomHeader; + } + + return m_Reader->m_HeaderPart; +} + +// Warning: direct manipulation of MXF structures can interfere +// with the normal operation of the wrapper. Caveat emptor! +// +ASDCP::MXF::OPAtomIndexFooter& +ASDCP::JP2K::MXFSReader::OPAtomIndexFooter() +{ + if ( m_Reader.empty() ) + { + assert(g_OPAtomIndexFooter); + return *g_OPAtomIndexFooter; + } + + return m_Reader->m_FooterPart; +} + +// Open the file for reading. The file must exist. Returns error if the +// operation cannot be completed. +ASDCP::Result_t +ASDCP::JP2K::MXFSReader::OpenRead(const char* filename) const +{ + return m_Reader->OpenRead(filename, ASDCP::ESS_JPEG_2000_S); +} + +// +ASDCP::Result_t +ASDCP::JP2K::MXFSReader::ReadFrame(ui32_t FrameNum, SFrameBuffer& FrameBuf, AESDecContext* Ctx, HMACContext* HMAC) const +{ + Result_t result = RESULT_INIT; + + if ( m_Reader && m_Reader->m_File.IsOpen() ) + { + result = m_Reader->ReadFrame(FrameNum, SP_LEFT, FrameBuf.Left, Ctx, HMAC); + + if ( ASDCP_SUCCESS(result) ) + result = m_Reader->ReadFrame(FrameNum, SP_RIGHT, FrameBuf.Right, Ctx, HMAC); + } + + return result; +} + +// +ASDCP::Result_t +ASDCP::JP2K::MXFSReader::ReadFrame(ui32_t FrameNum, StereoscopicPhase_t phase, FrameBuffer& FrameBuf, + AESDecContext* Ctx, HMACContext* HMAC) const +{ + if ( m_Reader && m_Reader->m_File.IsOpen() ) + return m_Reader->ReadFrame(FrameNum, phase, FrameBuf, Ctx, HMAC); + + return RESULT_INIT; +} + +// Fill the struct with the values from the file's header. +// Returns RESULT_INIT if the file is not open. +ASDCP::Result_t +ASDCP::JP2K::MXFSReader::FillPictureDescriptor(PictureDescriptor& PDesc) const +{ + if ( m_Reader && m_Reader->m_File.IsOpen() ) + { + PDesc = m_Reader->m_PDesc; + return RESULT_OK; + } + + return RESULT_INIT; +} + + +// Fill the struct with the values from the file's header. +// Returns RESULT_INIT if the file is not open. +ASDCP::Result_t +ASDCP::JP2K::MXFSReader::FillWriterInfo(WriterInfo& Info) const +{ + if ( m_Reader && m_Reader->m_File.IsOpen() ) + { + Info = m_Reader->m_Info; + return RESULT_OK; + } + + return RESULT_INIT; +} + +// +void +ASDCP::JP2K::MXFSReader::DumpHeaderMetadata(FILE* stream) const +{ + if ( m_Reader->m_File.IsOpen() ) + m_Reader->m_HeaderPart.Dump(stream); +} + + +// +void +ASDCP::JP2K::MXFSReader::DumpIndex(FILE* stream) const +{ + if ( m_Reader->m_File.IsOpen() ) + m_Reader->m_FooterPart.Dump(stream); +} + +// +ASDCP::Result_t +ASDCP::JP2K::MXFSReader::Close() const +{ + if ( m_Reader && m_Reader->m_File.IsOpen() ) + { + m_Reader->Close(); + return RESULT_OK; + } + + return RESULT_INIT; +} + + +//------------------------------------------------------------------------------------------ + + +// +class lh__Writer : public ASDCP::h__Writer +{ + ASDCP_NO_COPY_CONSTRUCT(lh__Writer); + lh__Writer(); + + JPEG2000PictureSubDescriptor* m_EssenceSubDescriptor; + +public: + PictureDescriptor m_PDesc; + byte_t m_EssenceUL[SMPTE_UL_LENGTH]; + + lh__Writer(const Dictionary& d) : ASDCP::h__Writer(d), m_EssenceSubDescriptor(0) { + memset(m_EssenceUL, 0, SMPTE_UL_LENGTH); + } + + ~lh__Writer(){} + + Result_t OpenWrite(const char*, EssenceType_t type, ui32_t HeaderSize, bool); + Result_t SetSourceStream(const PictureDescriptor&, const std::string& label, + ASDCP::Rational LocalEditRate = ASDCP::Rational(0,0)); + Result_t WriteFrame(const JP2K::FrameBuffer&, bool add_index, AESEncContext*, HMACContext*, std::string* hash = 0); + Result_t FakeWriteFrame(int size, bool add_index); + Result_t Finalize(); + Result_t JP2K_PDesc_to_MD(JP2K::PictureDescriptor& PDesc); +}; + +const int VideoLineMapSize = 16; // See SMPTE 377M D.2.1 +const int PixelLayoutSize = 8*2; // See SMPTE 377M D.2.3 +static const byte_t s_PixelLayoutXYZ[PixelLayoutSize] = { 0xd8, 0x0c, 0xd9, 0x0c, 0xda, 0x0c, 0x00 }; + +// +ASDCP::Result_t +lh__Writer::JP2K_PDesc_to_MD(JP2K::PictureDescriptor& PDesc) +{ + assert(m_EssenceDescriptor); + assert(m_EssenceSubDescriptor); + MXF::RGBAEssenceDescriptor* PDescObj = (MXF::RGBAEssenceDescriptor*)m_EssenceDescriptor; + + PDescObj->ContainerDuration = PDesc.ContainerDuration; + PDescObj->SampleRate = PDesc.EditRate; + PDescObj->FrameLayout = 0; + PDescObj->StoredWidth = PDesc.StoredWidth; + PDescObj->StoredHeight = PDesc.StoredHeight; + PDescObj->AspectRatio = PDesc.AspectRatio; + + // if ( m_Info.LabelSetType == LS_MXF_SMPTE ) + // { + // PictureEssenceCoding UL = + // Video Line Map ui32_t[VideoLineMapSize] = { 2, 4, 0, 0 } + // CaptureGamma UL = + // ComponentMaxRef ui32_t = 4095 + // ComponentMinRef ui32_t = 0 + // PixelLayout byte_t[PixelLayoutSize] = s_PixelLayoutXYZ + // } + + assert(m_Dict); + if ( PDesc.StoredWidth < 2049 ) + { + PDescObj->PictureEssenceCoding.Set(m_Dict->ul(MDD_JP2KEssenceCompression_2K)); + m_EssenceSubDescriptor->Rsize = 3; + } + else + { + PDescObj->PictureEssenceCoding.Set(m_Dict->ul(MDD_JP2KEssenceCompression_4K)); + m_EssenceSubDescriptor->Rsize = 4; + } + + m_EssenceSubDescriptor->Xsize = PDesc.Xsize; + m_EssenceSubDescriptor->Ysize = PDesc.Ysize; + m_EssenceSubDescriptor->XOsize = PDesc.XOsize; + m_EssenceSubDescriptor->YOsize = PDesc.YOsize; + m_EssenceSubDescriptor->XTsize = PDesc.XTsize; + m_EssenceSubDescriptor->YTsize = PDesc.YTsize; + m_EssenceSubDescriptor->XTOsize = PDesc.XTOsize; + m_EssenceSubDescriptor->YTOsize = PDesc.YTOsize; + m_EssenceSubDescriptor->Csize = PDesc.Csize; + + const ui32_t tmp_buffer_len = 1024; + byte_t tmp_buffer[tmp_buffer_len]; + + ui32_t* tmp_buffer_ui32 = (ui32_t*) tmp_buffer; + *tmp_buffer_ui32 = KM_i32_BE(MaxComponents); // three components + + *(ui32_t*)(tmp_buffer+4) = KM_i32_BE(sizeof(ASDCP::JP2K::ImageComponent_t)); + memcpy(tmp_buffer + 8, &PDesc.ImageComponents, sizeof(ASDCP::JP2K::ImageComponent_t) * MaxComponents); + + const ui32_t pcomp_size = (sizeof(int) * 2) + (sizeof(ASDCP::JP2K::ImageComponent_t) * MaxComponents); + memcpy(m_EssenceSubDescriptor->PictureComponentSizing.Data(), tmp_buffer, pcomp_size); + m_EssenceSubDescriptor->PictureComponentSizing.Length(pcomp_size); + + ui32_t precinct_set_size = 0, i; + for ( i = 0; PDesc.CodingStyleDefault.SPcod.PrecinctSize[i] != 0 && i < MaxPrecincts; i++ ) + precinct_set_size++; + + ui32_t csd_size = sizeof(CodingStyleDefault_t) - MaxPrecincts + precinct_set_size; + memcpy(m_EssenceSubDescriptor->CodingStyleDefault.Data(), &PDesc.CodingStyleDefault, csd_size); + m_EssenceSubDescriptor->CodingStyleDefault.Length(csd_size); + + ui32_t qdflt_size = PDesc.QuantizationDefault.SPqcdLength + 1; + memcpy(m_EssenceSubDescriptor->QuantizationDefault.Data(), &PDesc.QuantizationDefault, qdflt_size); + m_EssenceSubDescriptor->QuantizationDefault.Length(qdflt_size); + + return RESULT_OK; +} + + +// Open the file for writing. The file must not exist unless overwrite is true. Returns error if +// the operation cannot be completed. +ASDCP::Result_t +lh__Writer::OpenWrite(const char* filename, EssenceType_t type, ui32_t HeaderSize, bool overwrite) +{ + if ( ! m_State.Test_BEGIN() ) + return RESULT_STATE; + + Result_t result = RESULT_OK; + if (overwrite) { + result = m_File.OpenModify(filename); + m_File.Seek(0); + } else { + result = m_File.OpenWrite(filename); + } + + if ( ASDCP_SUCCESS(result) ) + { + m_HeaderSize = HeaderSize; + RGBAEssenceDescriptor* tmp_rgba = new RGBAEssenceDescriptor(m_Dict); + tmp_rgba->ComponentMaxRef = 4095; + tmp_rgba->ComponentMinRef = 0; + + m_EssenceDescriptor = tmp_rgba; + m_EssenceSubDescriptor = new JPEG2000PictureSubDescriptor(m_Dict); + m_EssenceSubDescriptorList.push_back((InterchangeObject*)m_EssenceSubDescriptor); + + GenRandomValue(m_EssenceSubDescriptor->InstanceUID); + m_EssenceDescriptor->SubDescriptors.push_back(m_EssenceSubDescriptor->InstanceUID); + + if ( type == ASDCP::ESS_JPEG_2000_S && m_Info.LabelSetType == LS_MXF_SMPTE ) + { + InterchangeObject* StereoSubDesc = new StereoscopicPictureSubDescriptor(m_Dict); + m_EssenceSubDescriptorList.push_back(StereoSubDesc); + GenRandomValue(StereoSubDesc->InstanceUID); + m_EssenceDescriptor->SubDescriptors.push_back(StereoSubDesc->InstanceUID); + } + + result = m_State.Goto_INIT(); + } + + return result; +} + +// Automatically sets the MXF file's metadata from the first jpeg codestream stream. +ASDCP::Result_t +lh__Writer::SetSourceStream(const PictureDescriptor& PDesc, const std::string& label, ASDCP::Rational LocalEditRate) +{ + assert(m_Dict); + if ( ! m_State.Test_INIT() ) + return RESULT_STATE; + + if ( LocalEditRate == ASDCP::Rational(0,0) ) + LocalEditRate = PDesc.EditRate; + + m_PDesc = PDesc; + Result_t result = JP2K_PDesc_to_MD(m_PDesc); + + if ( ASDCP_SUCCESS(result) ) + { + memcpy(m_EssenceUL, m_Dict->ul(MDD_JPEG2000Essence), SMPTE_UL_LENGTH); + m_EssenceUL[SMPTE_UL_LENGTH-1] = 1; // first (and only) essence container + result = m_State.Goto_READY(); + } + + if ( ASDCP_SUCCESS(result) ) + { + ui32_t TCFrameRate = ( m_PDesc.EditRate == EditRate_23_98 ) ? 24 : m_PDesc.EditRate.Numerator; + + result = WriteMXFHeader(label, UL(m_Dict->ul(MDD_JPEG_2000Wrapping)), + PICT_DEF_LABEL, UL(m_EssenceUL), UL(m_Dict->ul(MDD_PictureDataDef)), + LocalEditRate, TCFrameRate); + } + + return result; +} + +// 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. +// +ASDCP::Result_t +lh__Writer::WriteFrame(const JP2K::FrameBuffer& FrameBuf, bool add_index, + AESEncContext* Ctx, HMACContext* HMAC, std::string* hash) +{ + Result_t result = RESULT_OK; + + if ( m_State.Test_READY() ) + result = m_State.Goto_RUNNING(); // first time through + + ui64_t StreamOffset = m_StreamOffset; + + if ( ASDCP_SUCCESS(result) ) + result = WriteEKLVPacket(FrameBuf, m_EssenceUL, Ctx, HMAC, hash); + + if ( ASDCP_SUCCESS(result) && add_index ) + { + IndexTableSegment::IndexEntry Entry; + Entry.StreamOffset = StreamOffset; + m_FooterPart.PushIndexEntry(Entry); + } + + m_FramesWritten++; + return result; +} + +Result_t +lh__Writer::FakeWriteFrame(int size, bool add_index) +{ + Result_t result = RESULT_OK; + + if ( m_State.Test_READY() ) + result = m_State.Goto_RUNNING(); + + ui64_t StreamOffset = m_StreamOffset; + + if ( ASDCP_SUCCESS(result) ) + result = FakeWriteEKLVPacket(size); + + if ( ASDCP_SUCCESS(result) && add_index ) + { + IndexTableSegment::IndexEntry Entry; + Entry.StreamOffset = StreamOffset; + m_FooterPart.PushIndexEntry(Entry); + } + + m_FramesWritten++; + return result; +} + + +// Closes the MXF file, writing the index and other closing information. +// +ASDCP::Result_t +lh__Writer::Finalize() +{ + if ( ! m_State.Test_RUNNING() ) + return RESULT_STATE; + + m_State.Goto_FINAL(); + + return WriteMXFFooter(); +} + + +// +class ASDCP::JP2K::MXFWriter::h__Writer : public lh__Writer +{ + ASDCP_NO_COPY_CONSTRUCT(h__Writer); + h__Writer(); + +public: + h__Writer(const Dictionary& d) : lh__Writer(d) {} +}; + + +//------------------------------------------------------------------------------------------ + + + +ASDCP::JP2K::MXFWriter::MXFWriter() +{ +} + +ASDCP::JP2K::MXFWriter::~MXFWriter() +{ +} + +// Warning: direct manipulation of MXF structures can interfere +// with the normal operation of the wrapper. Caveat emptor! +// +ASDCP::MXF::OPAtomHeader& +ASDCP::JP2K::MXFWriter::OPAtomHeader() +{ + if ( m_Writer.empty() ) + { + assert(g_OPAtomHeader); + return *g_OPAtomHeader; + } + + return m_Writer->m_HeaderPart; +} + +// Warning: direct manipulation of MXF structures can interfere +// with the normal operation of the wrapper. Caveat emptor! +// +ASDCP::MXF::OPAtomIndexFooter& +ASDCP::JP2K::MXFWriter::OPAtomIndexFooter() +{ + if ( m_Writer.empty() ) + { + assert(g_OPAtomIndexFooter); + return *g_OPAtomIndexFooter; + } + + return m_Writer->m_FooterPart; +} + +// Open the file for writing. The file must not exist unless overwrite is true. Returns error if +// the operation cannot be completed. +ASDCP::Result_t +ASDCP::JP2K::MXFWriter::OpenWrite(const char* filename, const WriterInfo& Info, + const PictureDescriptor& PDesc, ui32_t HeaderSize, bool overwrite) +{ + if ( Info.LabelSetType == LS_MXF_SMPTE ) + m_Writer = new h__Writer(DefaultSMPTEDict()); + else + m_Writer = new h__Writer(DefaultInteropDict()); + + m_Writer->m_Info = Info; + + Result_t result = m_Writer->OpenWrite(filename, ASDCP::ESS_JPEG_2000, HeaderSize, overwrite); + + if ( ASDCP_SUCCESS(result) ) + result = m_Writer->SetSourceStream(PDesc, JP2K_PACKAGE_LABEL); + + if ( ASDCP_FAILURE(result) ) + m_Writer.release(); + + return result; +} + + +// 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. +ASDCP::Result_t +ASDCP::JP2K::MXFWriter::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC, std::string* hash) +{ + if ( m_Writer.empty() ) + return RESULT_INIT; + + return m_Writer->WriteFrame(FrameBuf, true, Ctx, HMAC, hash); +} + +ASDCP::Result_t +ASDCP::JP2K::MXFWriter::FakeWriteFrame(int size) +{ + if ( m_Writer.empty() ) + return RESULT_INIT; + + return m_Writer->FakeWriteFrame(size, true); +} + +// Closes the MXF file, writing the index and other closing information. +ASDCP::Result_t +ASDCP::JP2K::MXFWriter::Finalize() +{ + if ( m_Writer.empty() ) + return RESULT_INIT; + + return m_Writer->Finalize(); +} + +ui64_t +ASDCP::JP2K::MXFWriter::Tell() const +{ + return m_Writer->m_File.Tell(); +} + + +//------------------------------------------------------------------------------------------ +// + +// +class ASDCP::JP2K::MXFSWriter::h__SWriter : public lh__Writer +{ + ASDCP_NO_COPY_CONSTRUCT(h__SWriter); + h__SWriter(); + StereoscopicPhase_t m_NextPhase; + +public: + h__SWriter(const Dictionary& d) : lh__Writer(d), m_NextPhase(SP_LEFT) {} + + // + Result_t WriteFrame(const FrameBuffer& FrameBuf, StereoscopicPhase_t phase, + AESEncContext* Ctx, HMACContext* HMAC, std::string* hash) + { + if ( m_NextPhase != phase ) + return RESULT_SPHASE; + + if ( phase == SP_LEFT ) + { + m_NextPhase = SP_RIGHT; + return lh__Writer::WriteFrame(FrameBuf, true, Ctx, HMAC, hash); + } + + m_NextPhase = SP_LEFT; + return lh__Writer::WriteFrame(FrameBuf, false, Ctx, HMAC, hash); + } + + Result_t FakeWriteFrame(int size, StereoscopicPhase_t phase) + { + if (m_NextPhase != phase) + { + return RESULT_SPHASE; + } + + if (phase == SP_LEFT) + { + m_NextPhase = SP_RIGHT; + return lh__Writer::FakeWriteFrame(size, true); + } + + m_NextPhase = SP_LEFT; + return lh__Writer::FakeWriteFrame(size, false); + } + + // + Result_t Finalize() + { + if ( m_NextPhase != SP_LEFT ) + return RESULT_SPHASE; + + assert( m_FramesWritten % 2 == 0 ); + m_FramesWritten /= 2; + return lh__Writer::Finalize(); + } +}; + + +// +ASDCP::JP2K::MXFSWriter::MXFSWriter() +{ +} + +ASDCP::JP2K::MXFSWriter::~MXFSWriter() +{ +} + +// Warning: direct manipulation of MXF structures can interfere +// with the normal operation of the wrapper. Caveat emptor! +// +ASDCP::MXF::OPAtomHeader& +ASDCP::JP2K::MXFSWriter::OPAtomHeader() +{ + if ( m_Writer.empty() ) + { + assert(g_OPAtomHeader); + return *g_OPAtomHeader; + } + + return m_Writer->m_HeaderPart; +} + +// Warning: direct manipulation of MXF structures can interfere +// with the normal operation of the wrapper. Caveat emptor! +// +ASDCP::MXF::OPAtomIndexFooter& +ASDCP::JP2K::MXFSWriter::OPAtomIndexFooter() +{ + if ( m_Writer.empty() ) + { + assert(g_OPAtomIndexFooter); + return *g_OPAtomIndexFooter; + } + + return m_Writer->m_FooterPart; +} + +// Open the file for writing. The file must not exist. Returns error if +// the operation cannot be completed. +ASDCP::Result_t +ASDCP::JP2K::MXFSWriter::OpenWrite(const char* filename, const WriterInfo& Info, + const PictureDescriptor& PDesc, ui32_t HeaderSize, bool overwrite) +{ + if ( Info.LabelSetType == LS_MXF_SMPTE ) + m_Writer = new h__SWriter(DefaultSMPTEDict()); + else + m_Writer = new h__SWriter(DefaultInteropDict()); + + if ( PDesc.EditRate != ASDCP::EditRate_24 + && PDesc.EditRate != ASDCP::EditRate_25 + && PDesc.EditRate != ASDCP::EditRate_30 + && PDesc.EditRate != ASDCP::EditRate_48 + && PDesc.EditRate != ASDCP::EditRate_50 + && PDesc.EditRate != ASDCP::EditRate_60 ) + { + DefaultLogSink().Error("Stereoscopic wrapping requires 24, 25, 30, 48, 50 or 60 fps input streams.\n"); + return RESULT_FORMAT; + } + + if ( PDesc.StoredWidth > 2048 ) + DefaultLogSink().Warn("Wrapping non-standard 4K stereoscopic content. I hope you know what you are doing!\n"); + + m_Writer->m_Info = Info; + + Result_t result = m_Writer->OpenWrite(filename, ASDCP::ESS_JPEG_2000_S, HeaderSize, overwrite); + + if ( ASDCP_SUCCESS(result) ) + { + PictureDescriptor TmpPDesc = PDesc; + + if ( PDesc.EditRate == ASDCP::EditRate_24 ) + TmpPDesc.EditRate = ASDCP::EditRate_48; + + else if ( PDesc.EditRate == ASDCP::EditRate_25 ) + TmpPDesc.EditRate = ASDCP::EditRate_50; + + else if ( PDesc.EditRate == ASDCP::EditRate_30 ) + TmpPDesc.EditRate = ASDCP::EditRate_60; + + else if ( PDesc.EditRate == ASDCP::EditRate_48 ) + TmpPDesc.EditRate = ASDCP::EditRate_96; + + else if ( PDesc.EditRate == ASDCP::EditRate_50 ) + TmpPDesc.EditRate = ASDCP::EditRate_100; + + else if ( PDesc.EditRate == ASDCP::EditRate_60 ) + TmpPDesc.EditRate = ASDCP::EditRate_120; + + result = m_Writer->SetSourceStream(TmpPDesc, JP2K_S_PACKAGE_LABEL, PDesc.EditRate); + } + + if ( ASDCP_FAILURE(result) ) + m_Writer.release(); + + return result; +} + +ASDCP::Result_t +ASDCP::JP2K::MXFSWriter::WriteFrame(const SFrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC) +{ + if ( m_Writer.empty() ) + return RESULT_INIT; + + Result_t result = m_Writer->WriteFrame(FrameBuf.Left, SP_LEFT, Ctx, HMAC, 0); + + if ( ASDCP_SUCCESS(result) ) + result = m_Writer->WriteFrame(FrameBuf.Right, SP_RIGHT, Ctx, HMAC, 0); + + return result; +} + +// 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. +ASDCP::Result_t +ASDCP::JP2K::MXFSWriter::WriteFrame(const FrameBuffer& FrameBuf, StereoscopicPhase_t phase, + AESEncContext* Ctx, HMACContext* HMAC, std::string* hash) +{ + if ( m_Writer.empty() ) + return RESULT_INIT; + + return m_Writer->WriteFrame(FrameBuf, phase, Ctx, HMAC, hash); +} + +ASDCP::Result_t +ASDCP::JP2K::MXFSWriter::FakeWriteFrame(int size, StereoscopicPhase_t phase) +{ + if ( m_Writer.empty() ) + return RESULT_INIT; + + return m_Writer->FakeWriteFrame(size, phase); +} + +// Closes the MXF file, writing the index and other closing information. +ASDCP::Result_t +ASDCP::JP2K::MXFSWriter::Finalize() +{ + if ( m_Writer.empty() ) + return RESULT_INIT; + + return m_Writer->Finalize(); +} + +ui64_t +ASDCP::JP2K::MXFSWriter::Tell() const +{ + return m_Writer->m_File.Tell(); +} + +// +// end AS_DCP_JP2K.cpp +// diff --git a/asdcplib/src/AS_DCP_MPEG2.cpp b/asdcplib/src/AS_DCP_MPEG2.cpp new file mode 100755 index 0000000..bc64c1e --- /dev/null +++ b/asdcplib/src/AS_DCP_MPEG2.cpp @@ -0,0 +1,727 @@ +/* +Copyright (c) 2004-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_MPEG2.cpp + \version $Id: AS_DCP_MPEG2.cpp,v 1.34 2012/02/07 18:54:24 jhurst Exp $ + \brief AS-DCP library, MPEG2 essence reader and writer implementation +*/ + +#include "AS_DCP_internal.h" +#include <iostream> +#include <iomanip> + + +//------------------------------------------------------------------------------------------ + +static std::string MPEG_PACKAGE_LABEL = "File Package: SMPTE 381M frame wrapping of MPEG2 video elementary stream"; +static std::string PICT_DEF_LABEL = "Picture Track"; + +// +ASDCP::Result_t +MD_to_MPEG2_VDesc(MXF::MPEG2VideoDescriptor* VDescObj, MPEG2::VideoDescriptor& VDesc) +{ + ASDCP_TEST_NULL(VDescObj); + + VDesc.SampleRate = VDescObj->SampleRate; + VDesc.EditRate = VDescObj->SampleRate; + VDesc.FrameRate = VDescObj->SampleRate.Numerator; + assert(VDescObj->ContainerDuration <= 0xFFFFFFFFL); + VDesc.ContainerDuration = (ui32_t) VDescObj->ContainerDuration; + + VDesc.FrameLayout = VDescObj->FrameLayout; + VDesc.StoredWidth = VDescObj->StoredWidth; + VDesc.StoredHeight = VDescObj->StoredHeight; + VDesc.AspectRatio = VDescObj->AspectRatio; + + VDesc.ComponentDepth = VDescObj->ComponentDepth; + VDesc.HorizontalSubsampling = VDescObj->HorizontalSubsampling; + VDesc.VerticalSubsampling = VDescObj->VerticalSubsampling; + VDesc.ColorSiting = VDescObj->ColorSiting; + VDesc.CodedContentType = VDescObj->CodedContentType; + + VDesc.LowDelay = VDescObj->LowDelay == 0 ? false : true; + VDesc.BitRate = VDescObj->BitRate; + VDesc.ProfileAndLevel = VDescObj->ProfileAndLevel; + return RESULT_OK; +} + + +// +ASDCP::Result_t +MPEG2_VDesc_to_MD(MPEG2::VideoDescriptor& VDesc, MXF::MPEG2VideoDescriptor* VDescObj) +{ + ASDCP_TEST_NULL(VDescObj); + + VDescObj->SampleRate = VDesc.SampleRate; + VDescObj->ContainerDuration = VDesc.ContainerDuration; + + VDescObj->FrameLayout = VDesc.FrameLayout; + VDescObj->StoredWidth = VDesc.StoredWidth; + VDescObj->StoredHeight = VDesc.StoredHeight; + VDescObj->AspectRatio = VDesc.AspectRatio; + + VDescObj->ComponentDepth = VDesc.ComponentDepth; + VDescObj->HorizontalSubsampling = VDesc.HorizontalSubsampling; + VDescObj->VerticalSubsampling = VDesc.VerticalSubsampling; + VDescObj->ColorSiting = VDesc.ColorSiting; + VDescObj->CodedContentType = VDesc.CodedContentType; + + VDescObj->LowDelay = VDesc.LowDelay ? 1 : 0; + VDescObj->BitRate = VDesc.BitRate; + VDescObj->ProfileAndLevel = VDesc.ProfileAndLevel; + return RESULT_OK; +} + +// +std::ostream& +ASDCP::MPEG2::operator << (std::ostream& strm, const VideoDescriptor& VDesc) +{ + strm << " SampleRate: " << VDesc.SampleRate.Numerator << "/" << VDesc.SampleRate.Denominator << std::endl; + strm << " FrameLayout: " << (unsigned) VDesc.FrameLayout << std::endl; + strm << " StoredWidth: " << (unsigned) VDesc.StoredWidth << std::endl; + strm << " StoredHeight: " << (unsigned) VDesc.StoredHeight << std::endl; + strm << " AspectRatio: " << VDesc.AspectRatio.Numerator << "/" << VDesc.AspectRatio.Denominator << std::endl; + strm << " ComponentDepth: " << (unsigned) VDesc.ComponentDepth << std::endl; + strm << " HorizontalSubsmpl: " << (unsigned) VDesc.HorizontalSubsampling << std::endl; + strm << " VerticalSubsmpl: " << (unsigned) VDesc.VerticalSubsampling << std::endl; + strm << " ColorSiting: " << (unsigned) VDesc.ColorSiting << std::endl; + strm << " CodedContentType: " << (unsigned) VDesc.CodedContentType << std::endl; + strm << " LowDelay: " << (unsigned) VDesc.LowDelay << std::endl; + strm << " BitRate: " << (unsigned) VDesc.BitRate << std::endl; + strm << " ProfileAndLevel: " << (unsigned) VDesc.ProfileAndLevel << std::endl; + strm << " ContainerDuration: " << (unsigned) VDesc.ContainerDuration << std::endl; + + return strm; +} + +// +void +ASDCP::MPEG2::VideoDescriptorDump(const VideoDescriptor& VDesc, FILE* stream) +{ + if ( stream == 0 ) + stream = stderr; + + fprintf(stream, "\ + SampleRate: %d/%d\n\ + FrameLayout: %u\n\ + StoredWidth: %u\n\ + StoredHeight: %u\n\ + AspectRatio: %d/%d\n\ + ComponentDepth: %u\n\ + HorizontalSubsmpl: %u\n\ + VerticalSubsmpl: %u\n\ + ColorSiting: %u\n\ + CodedContentType: %u\n\ + LowDelay: %u\n\ + BitRate: %u\n\ + ProfileAndLevel: %u\n\ + ContainerDuration: %u\n", + VDesc.SampleRate.Numerator ,VDesc.SampleRate.Denominator, + VDesc.FrameLayout, + VDesc.StoredWidth, + VDesc.StoredHeight, + VDesc.AspectRatio.Numerator ,VDesc.AspectRatio.Denominator, + VDesc.ComponentDepth, + VDesc.HorizontalSubsampling, + VDesc.VerticalSubsampling, + VDesc.ColorSiting, + VDesc.CodedContentType, + VDesc.LowDelay, + VDesc.BitRate, + VDesc.ProfileAndLevel, + VDesc.ContainerDuration + ); +} + +//------------------------------------------------------------------------------------------ +// +// hidden, internal implementation of MPEG2 reader + +class ASDCP::MPEG2::MXFReader::h__Reader : public ASDCP::h__Reader +{ + ASDCP_NO_COPY_CONSTRUCT(h__Reader); + h__Reader(); + +public: + VideoDescriptor m_VDesc; // video parameter list + + h__Reader(const Dictionary& d) : ASDCP::h__Reader(d) {} + ~h__Reader() {} + Result_t OpenRead(const char*); + Result_t ReadFrame(ui32_t, FrameBuffer&, AESDecContext*, HMACContext*); + Result_t ReadFrameGOPStart(ui32_t, FrameBuffer&, AESDecContext*, HMACContext*); + Result_t FindFrameGOPStart(ui32_t, ui32_t&); + Result_t FrameType(ui32_t FrameNum, FrameType_t& type); +}; + + +// +// +ASDCP::Result_t +ASDCP::MPEG2::MXFReader::h__Reader::OpenRead(const char* filename) +{ + Result_t result = OpenMXFRead(filename); + + if( ASDCP_SUCCESS(result) ) + { + InterchangeObject* Object; + if ( ASDCP_SUCCESS(m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(MPEG2VideoDescriptor), &Object)) ) + { + assert(Object); + result = MD_to_MPEG2_VDesc((MXF::MPEG2VideoDescriptor*)Object, m_VDesc); + } + } + + if( ASDCP_SUCCESS(result) ) + result = InitMXFIndex(); + + if( ASDCP_SUCCESS(result) ) + result = InitInfo(); + + return result; +} + + +// +// +ASDCP::Result_t +ASDCP::MPEG2::MXFReader::h__Reader::ReadFrameGOPStart(ui32_t FrameNum, FrameBuffer& FrameBuf, + AESDecContext* Ctx, HMACContext* HMAC) +{ + ui32_t KeyFrameNum; + + Result_t result = FindFrameGOPStart(FrameNum, KeyFrameNum); + + if ( ASDCP_SUCCESS(result) ) + result = ReadFrame(KeyFrameNum, FrameBuf, Ctx, HMAC); + + return result; +} + + +// +// +ASDCP::Result_t +ASDCP::MPEG2::MXFReader::h__Reader::FindFrameGOPStart(ui32_t FrameNum, ui32_t& KeyFrameNum) +{ + KeyFrameNum = 0; + + if ( ! m_File.IsOpen() ) + return RESULT_INIT; + + // look up frame index node + IndexTableSegment::IndexEntry TmpEntry; + + if ( ASDCP_FAILURE(m_FooterPart.Lookup(FrameNum, TmpEntry)) ) + { + DefaultLogSink().Error("Frame value out of range: %u\n", FrameNum); + return RESULT_RANGE; + } + + KeyFrameNum = FrameNum - TmpEntry.KeyFrameOffset; + + return RESULT_OK; +} + +// +ASDCP::Result_t +ASDCP::MPEG2::MXFReader::h__Reader::FrameType(ui32_t FrameNum, FrameType_t& type) +{ + if ( ! m_File.IsOpen() ) + return RESULT_INIT; + + // look up frame index node + IndexTableSegment::IndexEntry TmpEntry; + + if ( ASDCP_FAILURE(m_FooterPart.Lookup(FrameNum, TmpEntry)) ) + { + DefaultLogSink().Error("Frame value out of range: %u\n", FrameNum); + return RESULT_RANGE; + } + + type = ( (TmpEntry.Flags & 0x0f) == 3 ) ? FRAME_B : ( (TmpEntry.Flags & 0x0f) == 2 ) ? FRAME_P : FRAME_I; + return RESULT_OK; +} + + +// +// +ASDCP::Result_t +ASDCP::MPEG2::MXFReader::h__Reader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf, + AESDecContext* Ctx, HMACContext* HMAC) +{ + assert(m_Dict); + if ( ! m_File.IsOpen() ) + return RESULT_INIT; + + Result_t result = ReadEKLVFrame(FrameNum, FrameBuf, m_Dict->ul(MDD_MPEG2Essence), Ctx, HMAC); + + if ( ASDCP_FAILURE(result) ) + return result; + + IndexTableSegment::IndexEntry TmpEntry; + m_FooterPart.Lookup(FrameNum, TmpEntry); + + switch ( ( TmpEntry.Flags >> 4 ) & 0x03 ) + { + case 0: FrameBuf.FrameType(FRAME_I); break; + case 2: FrameBuf.FrameType(FRAME_P); break; + case 3: FrameBuf.FrameType(FRAME_B); break; + default: FrameBuf.FrameType(FRAME_U); + } + + FrameBuf.TemporalOffset(TmpEntry.TemporalOffset); + FrameBuf.GOPStart(TmpEntry.Flags & 0x40 ? true : false); + FrameBuf.ClosedGOP(TmpEntry.Flags & 0x80 ? true : false); + + return RESULT_OK; +} + +//------------------------------------------------------------------------------------------ + + +// +void +ASDCP::MPEG2::FrameBuffer::Dump(FILE* stream, ui32_t dump_len) const +{ + if ( stream == 0 ) + stream = stderr; + + fprintf(stream, "Frame: %06u, %c%-2hu, %7u bytes", + m_FrameNumber, FrameTypeChar(m_FrameType), m_TemporalOffset, m_Size); + + if ( m_GOPStart ) + fprintf(stream, " (start %s GOP)", ( m_ClosedGOP ? "closed" : "open")); + + fputc('\n', stream); + + if ( dump_len > 0 ) + Kumu::hexdump(m_Data, dump_len, stream); +} + + +//------------------------------------------------------------------------------------------ + +ASDCP::MPEG2::MXFReader::MXFReader() +{ + m_Reader = new h__Reader(DefaultCompositeDict()); +} + + +ASDCP::MPEG2::MXFReader::~MXFReader() +{ +} + +// Warning: direct manipulation of MXF structures can interfere +// with the normal operation of the wrapper. Caveat emptor! +// +ASDCP::MXF::OPAtomHeader& +ASDCP::MPEG2::MXFReader::OPAtomHeader() +{ + if ( m_Reader.empty() ) + { + assert(g_OPAtomHeader); + return *g_OPAtomHeader; + } + + return m_Reader->m_HeaderPart; +} + +// Warning: direct manipulation of MXF structures can interfere +// with the normal operation of the wrapper. Caveat emptor! +// +ASDCP::MXF::OPAtomIndexFooter& +ASDCP::MPEG2::MXFReader::OPAtomIndexFooter() +{ + if ( m_Reader.empty() ) + { + assert(g_OPAtomIndexFooter); + return *g_OPAtomIndexFooter; + } + + return m_Reader->m_FooterPart; +} + +// Open the file for reading. The file must exist. Returns error if the +// operation cannot be completed. +ASDCP::Result_t +ASDCP::MPEG2::MXFReader::OpenRead(const char* filename) const +{ + return m_Reader->OpenRead(filename); +} + +// +ASDCP::Result_t +ASDCP::MPEG2::MXFReader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf, + AESDecContext* Ctx, HMACContext* HMAC) const +{ + if ( m_Reader && m_Reader->m_File.IsOpen() ) + return m_Reader->ReadFrame(FrameNum, FrameBuf, Ctx, HMAC); + + return RESULT_INIT; +} + + +// +ASDCP::Result_t +ASDCP::MPEG2::MXFReader::ReadFrameGOPStart(ui32_t FrameNum, FrameBuffer& FrameBuf, + AESDecContext* Ctx, HMACContext* HMAC) const +{ + if ( m_Reader && m_Reader->m_File.IsOpen() ) + return m_Reader->ReadFrameGOPStart(FrameNum, FrameBuf, Ctx, HMAC); + + return RESULT_INIT; +} + + +// +ASDCP::Result_t +ASDCP::MPEG2::MXFReader::FindFrameGOPStart(ui32_t FrameNum, ui32_t& KeyFrameNum) const +{ + if ( m_Reader && m_Reader->m_File.IsOpen() ) + return m_Reader->FindFrameGOPStart(FrameNum, KeyFrameNum); + + return RESULT_INIT; +} + + +// Fill the struct with the values from the file's header. +// Returns RESULT_INIT if the file is not open. +ASDCP::Result_t +ASDCP::MPEG2::MXFReader::FillVideoDescriptor(VideoDescriptor& VDesc) const +{ + if ( m_Reader && m_Reader->m_File.IsOpen() ) + { + VDesc = m_Reader->m_VDesc; + return RESULT_OK; + } + + return RESULT_INIT; +} + + +// Fill the struct with the values from the file's header. +// Returns RESULT_INIT if the file is not open. +ASDCP::Result_t +ASDCP::MPEG2::MXFReader::FillWriterInfo(WriterInfo& Info) const +{ + if ( m_Reader && m_Reader->m_File.IsOpen() ) + { + Info = m_Reader->m_Info; + return RESULT_OK; + } + + return RESULT_INIT; +} + +// +void +ASDCP::MPEG2::MXFReader::DumpHeaderMetadata(FILE* stream) const +{ + if ( m_Reader->m_File.IsOpen() ) + m_Reader->m_HeaderPart.Dump(stream); +} + + +// +void +ASDCP::MPEG2::MXFReader::DumpIndex(FILE* stream) const +{ + if ( m_Reader->m_File.IsOpen() ) + m_Reader->m_FooterPart.Dump(stream); +} + +// +ASDCP::Result_t +ASDCP::MPEG2::MXFReader::Close() const +{ + if ( m_Reader && m_Reader->m_File.IsOpen() ) + { + m_Reader->Close(); + return RESULT_OK; + } + + return RESULT_INIT; +} + +// +ASDCP::Result_t +ASDCP::MPEG2::MXFReader::FrameType(ui32_t FrameNum, FrameType_t& type) const +{ + if ( ! m_Reader ) + return RESULT_INIT; + + return m_Reader->FrameType(FrameNum, type); +} + + +//------------------------------------------------------------------------------------------ + +// +class ASDCP::MPEG2::MXFWriter::h__Writer : public ASDCP::h__Writer +{ + ASDCP_NO_COPY_CONSTRUCT(h__Writer); + h__Writer(); + +public: + VideoDescriptor m_VDesc; + ui32_t m_GOPOffset; + byte_t m_EssenceUL[SMPTE_UL_LENGTH]; + + h__Writer(const Dictionary& d) : ASDCP::h__Writer(d), m_GOPOffset(0) { + memset(m_EssenceUL, 0, SMPTE_UL_LENGTH); + } + + ~h__Writer(){} + + Result_t OpenWrite(const char*, ui32_t HeaderSize); + Result_t SetSourceStream(const VideoDescriptor&); + Result_t WriteFrame(const FrameBuffer&, AESEncContext* = 0, HMACContext* = 0); + Result_t Finalize(); +}; + + +// Open the file for writing. The file must not exist. Returns error if +// the operation cannot be completed. +ASDCP::Result_t +ASDCP::MPEG2::MXFWriter::h__Writer::OpenWrite(const char* filename, ui32_t HeaderSize) +{ + if ( ! m_State.Test_BEGIN() ) + return RESULT_STATE; + + Result_t result = m_File.OpenWrite(filename); + + if ( ASDCP_SUCCESS(result) ) + { + m_HeaderSize = HeaderSize; + m_EssenceDescriptor = new MPEG2VideoDescriptor(m_Dict); + result = m_State.Goto_INIT(); + } + + return result; +} + +// Automatically sets the MXF file's metadata from the MPEG stream. +ASDCP::Result_t +ASDCP::MPEG2::MXFWriter::h__Writer::SetSourceStream(const VideoDescriptor& VDesc) +{ + assert(m_Dict); + if ( ! m_State.Test_INIT() ) + return RESULT_STATE; + + m_VDesc = VDesc; + Result_t result = MPEG2_VDesc_to_MD(m_VDesc, (MPEG2VideoDescriptor*)m_EssenceDescriptor); + + if ( ASDCP_SUCCESS(result) ) + { + memcpy(m_EssenceUL, m_Dict->ul(MDD_MPEG2Essence), SMPTE_UL_LENGTH); + m_EssenceUL[SMPTE_UL_LENGTH-1] = 1; // first (and only) essence container + result = m_State.Goto_READY(); + } + + if ( ASDCP_SUCCESS(result) ) + { + ui32_t TCFrameRate = ( m_VDesc.EditRate == EditRate_23_98 ) ? 24 : m_VDesc.EditRate.Numerator; + + result = WriteMXFHeader(MPEG_PACKAGE_LABEL, UL(m_Dict->ul(MDD_MPEG2_VESWrapping)), + PICT_DEF_LABEL, UL(m_EssenceUL), UL(m_Dict->ul(MDD_PictureDataDef)), + m_VDesc.EditRate, TCFrameRate); + } + + return result; +} + +// 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. +// +ASDCP::Result_t +ASDCP::MPEG2::MXFWriter::h__Writer::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx, + HMACContext* HMAC) +{ + Result_t result = RESULT_OK; + + if ( m_State.Test_READY() ) + result = m_State.Goto_RUNNING(); // first time through, get the body location + + IndexTableSegment::IndexEntry Entry; + Entry.StreamOffset = m_StreamOffset; + + if ( ASDCP_SUCCESS(result) ) + result = WriteEKLVPacket(FrameBuf, m_EssenceUL, Ctx, HMAC); + + if ( ASDCP_FAILURE(result) ) + return result; + + // create mxflib flags + int Flags = 0; + + switch ( FrameBuf.FrameType() ) + { + case FRAME_I: Flags = 0x00; break; + case FRAME_P: Flags = 0x22; break; + case FRAME_B: Flags = 0x33; break; + /* Keep gcc quiet */ + case FRAME_U: break; + } + + if ( FrameBuf.GOPStart() ) + { + m_GOPOffset = 0; + Flags |= 0x40; + + if ( FrameBuf.ClosedGOP() ) + Flags |= 0x80; + } + + // update the index manager + Entry.TemporalOffset = - FrameBuf.TemporalOffset(); + Entry.KeyFrameOffset = 0 - m_GOPOffset; + Entry.Flags = Flags; + /* + fprintf(stderr, "to: %4hd ko: %4hd c1: %4hd c2: %4hd fl: 0x%02x\n", + Entry.TemporalOffset, Entry.KeyFrameOffset, + m_GOPOffset + Entry.TemporalOffset, + Entry.KeyFrameOffset - Entry.TemporalOffset, + Entry.Flags); + */ + m_FooterPart.PushIndexEntry(Entry); + m_FramesWritten++; + m_GOPOffset++; + + return RESULT_OK; +} + + +// Closes the MXF file, writing the index and other closing information. +// +ASDCP::Result_t +ASDCP::MPEG2::MXFWriter::h__Writer::Finalize() +{ + if ( ! m_State.Test_RUNNING() ) + return RESULT_STATE; + + m_State.Goto_FINAL(); + + return WriteMXFFooter(); +} + + +//------------------------------------------------------------------------------------------ + + + +ASDCP::MPEG2::MXFWriter::MXFWriter() +{ +} + +ASDCP::MPEG2::MXFWriter::~MXFWriter() +{ +} + +// Warning: direct manipulation of MXF structures can interfere +// with the normal operation of the wrapper. Caveat emptor! +// +ASDCP::MXF::OPAtomHeader& +ASDCP::MPEG2::MXFWriter::OPAtomHeader() +{ + if ( m_Writer.empty() ) + { + assert(g_OPAtomHeader); + return *g_OPAtomHeader; + } + + return m_Writer->m_HeaderPart; +} + +// Warning: direct manipulation of MXF structures can interfere +// with the normal operation of the wrapper. Caveat emptor! +// +ASDCP::MXF::OPAtomIndexFooter& +ASDCP::MPEG2::MXFWriter::OPAtomIndexFooter() +{ + if ( m_Writer.empty() ) + { + assert(g_OPAtomIndexFooter); + return *g_OPAtomIndexFooter; + } + + return m_Writer->m_FooterPart; +} + +// Open the file for writing. The file must not exist. Returns error if +// the operation cannot be completed. +ASDCP::Result_t +ASDCP::MPEG2::MXFWriter::OpenWrite(const char* filename, const WriterInfo& Info, + const VideoDescriptor& VDesc, ui32_t HeaderSize) +{ + if ( Info.LabelSetType == LS_MXF_SMPTE ) + m_Writer = new h__Writer(DefaultSMPTEDict()); + else + m_Writer = new h__Writer(DefaultInteropDict()); + + m_Writer->m_Info = Info; + + Result_t result = m_Writer->OpenWrite(filename, HeaderSize); + + if ( ASDCP_SUCCESS(result) ) + result = m_Writer->SetSourceStream(VDesc); + + if ( ASDCP_FAILURE(result) ) + m_Writer.release(); + + return result; +} + + +// 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. +ASDCP::Result_t +ASDCP::MPEG2::MXFWriter::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC) +{ + if ( m_Writer.empty() ) + return RESULT_INIT; + + return m_Writer->WriteFrame(FrameBuf, Ctx, HMAC); +} + +// Closes the MXF file, writing the index and other closing information. +ASDCP::Result_t +ASDCP::MPEG2::MXFWriter::Finalize() +{ + if ( m_Writer.empty() ) + return RESULT_INIT; + + return m_Writer->Finalize(); +} + + +// +// end AS_DCP_MPEG2.cpp +// diff --git a/asdcplib/src/AS_DCP_MXF.cpp b/asdcplib/src/AS_DCP_MXF.cpp new file mode 100755 index 0000000..da5232f --- /dev/null +++ b/asdcplib/src/AS_DCP_MXF.cpp @@ -0,0 +1,542 @@ +/* +Copyright (c) 2004-2009, 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_MXF.cpp + \version $Id: AS_DCP_MXF.cpp,v 1.31 2009/08/04 18:43:10 jhurst Exp $ + \brief AS-DCP library, misc classes and subroutines +*/ + +#include <KM_fileio.h> +#include <KM_xml.h> +#include "AS_DCP_internal.h" +#include "JP2K.h" +#include "MPEG.h" +#include "Wav.h" +#include <iostream> +#include <iomanip> + + +//------------------------------------------------------------------------------------------ +// misc subroutines + + +// +std::ostream& +ASDCP::operator << (std::ostream& strm, const WriterInfo& Info) +{ + char str_buf[40]; + + strm << " ProductUUID: " << UUID(Info.ProductUUID).EncodeHex(str_buf, 40) << std::endl; + strm << " ProductVersion: " << Info.ProductVersion << std::endl; + strm << " CompanyName: " << Info.CompanyName << std::endl; + strm << " ProductName: " << Info.ProductName << std::endl; + strm << " EncryptedEssence: " << (Info.EncryptedEssence ? "Yes" : "No") << std::endl; + + if ( Info.EncryptedEssence ) + { + strm << " HMAC: " << (Info.UsesHMAC ? "Yes" : "No") << std::endl; + strm << " ContextID: " << UUID(Info.ContextID).EncodeHex(str_buf, 40) << std::endl; + strm << "CryptographicKeyID: " << UUID(Info.CryptographicKeyID).EncodeHex(str_buf, 40) << std::endl; + } + + strm << " AssetUUID: " << UUID(Info.AssetUUID).EncodeHex(str_buf, 40) << std::endl; + strm << " Label Set Type: " << (Info.LabelSetType == LS_MXF_SMPTE ? "SMPTE" : + (Info.LabelSetType == LS_MXF_INTEROP ? "MXF Interop" : + "Unknown")) << std::endl; + return strm; +} + +// +void +ASDCP::WriterInfoDump(const WriterInfo& Info, FILE* stream) +{ + if ( stream == 0 ) + stream = stderr; + + char str_buf[40]; + + fprintf(stream," ProductUUID: %s\n", UUID(Info.ProductUUID).EncodeHex(str_buf, 40)); + fprintf(stream,"\ + ProductVersion: %s\n\ + CompanyName: %s\n\ + ProductName: %s\n\ + EncryptedEssence: %s\n", + Info.ProductVersion.c_str(), + Info.CompanyName.c_str(), + Info.ProductName.c_str(), + ( Info.EncryptedEssence ? "Yes" : "No" ) + ); + + if ( Info.EncryptedEssence ) + { + fprintf(stream, " HMAC: %s\n", ( Info.UsesHMAC ? "Yes" : "No")); + fprintf(stream, " ContextID: %s\n", UUID(Info.ContextID).EncodeHex(str_buf, 40)); + fprintf(stream, "CryptographicKeyID: %s\n", UUID(Info.CryptographicKeyID).EncodeHex(str_buf, 40)); + } + + fprintf(stream," AssetUUID: %s\n", UUID(Info.AssetUUID).EncodeHex(str_buf, 40)); + fprintf(stream," Label Set Type: %s\n", ( Info.LabelSetType == LS_MXF_SMPTE ? "SMPTE" : + ( Info.LabelSetType == LS_MXF_INTEROP ? "MXF Interop" : + "Unknown" ) )); +} + +// +Result_t +ASDCP::MD_to_WriterInfo(Identification* InfoObj, WriterInfo& Info) +{ + ASDCP_TEST_NULL(InfoObj); + char tmp_str[IdentBufferLen]; + + Info.ProductName = "Unknown Product"; + Info.ProductVersion = "Unknown Version"; + Info.CompanyName = "Unknown Company"; + memset(Info.ProductUUID, 0, UUIDlen); + + InfoObj->ProductName.EncodeString(tmp_str, IdentBufferLen); + if ( *tmp_str ) Info.ProductName = tmp_str; + + InfoObj->VersionString.EncodeString(tmp_str, IdentBufferLen); + if ( *tmp_str ) Info.ProductVersion = tmp_str; + + InfoObj->CompanyName.EncodeString(tmp_str, IdentBufferLen); + if ( *tmp_str ) Info.CompanyName = tmp_str; + + memcpy(Info.ProductUUID, InfoObj->ProductUID.Value(), UUIDlen); + + return RESULT_OK; +} + + +// +Result_t +ASDCP::MD_to_CryptoInfo(CryptographicContext* InfoObj, WriterInfo& Info, const Dictionary& Dict) +{ + ASDCP_TEST_NULL(InfoObj); + + Info.EncryptedEssence = true; + memcpy(Info.ContextID, InfoObj->ContextID.Value(), UUIDlen); + memcpy(Info.CryptographicKeyID, InfoObj->CryptographicKeyID.Value(), UUIDlen); + + UL MIC_SHA1(Dict.ul(MDD_MICAlgorithm_HMAC_SHA1)); + UL MIC_NONE(Dict.ul(MDD_MICAlgorithm_NONE)); + + if ( InfoObj->MICAlgorithm == MIC_SHA1 ) + Info.UsesHMAC = true; + + else if ( InfoObj->MICAlgorithm == MIC_NONE ) + Info.UsesHMAC = false; + + else + { + DefaultLogSink().Error("Unexpected MICAlgorithm UL.\n"); + return RESULT_FORMAT; + } + + return RESULT_OK; +} + +// +// +ASDCP::Result_t +ASDCP::EssenceType(const char* filename, EssenceType_t& type) +{ + const Dictionary* m_Dict = &DefaultCompositeDict(); + assert(m_Dict); + + ASDCP_TEST_NULL_STR(filename); + Kumu::FileReader Reader; + OPAtomHeader TestHeader(m_Dict); + + Result_t result = Reader.OpenRead(filename); + + if ( ASDCP_SUCCESS(result) ) + result = TestHeader.InitFromFile(Reader); // test UL and OP + + if ( ASDCP_SUCCESS(result) ) + { + type = ESS_UNKNOWN; + if ( ASDCP_SUCCESS(TestHeader.GetMDObjectByType(OBJ_TYPE_ARGS(RGBAEssenceDescriptor))) ) + { + if ( ASDCP_SUCCESS(TestHeader.GetMDObjectByType(OBJ_TYPE_ARGS(StereoscopicPictureSubDescriptor))) ) + type = ESS_JPEG_2000_S; + else + type = ESS_JPEG_2000; + } + else if ( ASDCP_SUCCESS(TestHeader.GetMDObjectByType(OBJ_TYPE_ARGS(WaveAudioDescriptor))) ) + type = ESS_PCM_24b_48k; + else if ( ASDCP_SUCCESS(TestHeader.GetMDObjectByType(OBJ_TYPE_ARGS(MPEG2VideoDescriptor))) ) + type = ESS_MPEG2_VES; + else if ( ASDCP_SUCCESS(TestHeader.GetMDObjectByType(OBJ_TYPE_ARGS(TimedTextDescriptor))) ) + type = ESS_TIMED_TEXT; + } + + return result; +} + +// +ASDCP::Result_t +ASDCP::RawEssenceType(const char* filename, EssenceType_t& type) +{ + ASDCP_TEST_NULL_STR(filename); + type = ESS_UNKNOWN; + ASDCP::FrameBuffer FB; + Kumu::FileReader Reader; + ASDCP::Wav::SimpleWaveHeader WavHeader; + ASDCP::AIFF::SimpleAIFFHeader AIFFHeader; + Kumu::XMLElement TmpElement("Tmp"); + + ui32_t data_offset; + ui32_t read_count; + Result_t result = FB.Capacity(Wav::MaxWavHeader); // using Wav max because everything else is much smaller + + if ( Kumu::PathIsFile(filename) ) + { + result = Reader.OpenRead(filename); + + if ( ASDCP_SUCCESS(result) ) + { + result = Reader.Read(FB.Data(), FB.Capacity(), &read_count); + Reader.Close(); + } + + if ( ASDCP_SUCCESS(result) ) + { + const byte_t* p = FB.RoData(); + FB.Size(read_count); + + ui32_t i = 0; + while ( p[i] == 0 ) i++; + + if ( i > 1 && p[i] == 1 && (p[i+1] == ASDCP::MPEG2::SEQ_START || p[i+1] == ASDCP::MPEG2::PIC_START) ) + { + type = ESS_MPEG2_VES; + } + else if ( memcmp(FB.RoData(), ASDCP::JP2K::Magic, sizeof(ASDCP::JP2K::Magic)) == 0 ) + { + type = ESS_JPEG_2000; + } + else if ( ASDCP_SUCCESS(WavHeader.ReadFromBuffer(FB.RoData(), read_count, &data_offset)) ) + { + switch ( WavHeader.samplespersec ) + { + case 48000: type = ESS_PCM_24b_48k; break; + case 96000: type = ESS_PCM_24b_96k; break; + default: + return RESULT_FORMAT; + } + } + else if ( ASDCP_SUCCESS(AIFFHeader.ReadFromBuffer(FB.RoData(), read_count, &data_offset)) ) + { + type = ESS_PCM_24b_48k; + } + else if ( Kumu::StringIsXML((const char*)FB.RoData(), FB.Size()) ) + { + type = ESS_TIMED_TEXT; + } + } + } + else if ( Kumu::PathIsDirectory(filename) ) + { + char next_file[Kumu::MaxFilePath]; + Kumu::DirScanner Scanner; + Result_t result = Scanner.Open(filename); + + if ( ASDCP_SUCCESS(result) ) + { + while ( ASDCP_SUCCESS(Scanner.GetNext(next_file)) ) + { + if ( next_file[0] == '.' ) // no hidden files or internal links + continue; + + std::string Str(filename); + Str += "/"; + Str += next_file; + result = Reader.OpenRead(Str.c_str()); + + if ( ASDCP_SUCCESS(result) ) + { + result = Reader.Read(FB.Data(), FB.Capacity(), &read_count); + Reader.Close(); + } + + if ( ASDCP_SUCCESS(result) ) + { + if ( memcmp(FB.RoData(), ASDCP::JP2K::Magic, sizeof(ASDCP::JP2K::Magic)) == 0 ) + { + type = ESS_JPEG_2000; + } + else if ( ASDCP_SUCCESS(WavHeader.ReadFromBuffer(FB.RoData(), read_count, &data_offset)) ) + { + switch ( WavHeader.samplespersec ) + { + case 48000: type = ESS_PCM_24b_48k; break; + case 96000: type = ESS_PCM_24b_96k; break; + default: + return RESULT_FORMAT; + } + } + } + + break; + } + } + } + + return result; +} + +// +Result_t +ASDCP::EncryptFrameBuffer(const ASDCP::FrameBuffer& FBin, ASDCP::FrameBuffer& FBout, AESEncContext* Ctx) +{ + ASDCP_TEST_NULL(Ctx); + FBout.Size(0); + + // size the buffer + Result_t result = FBout.Capacity(calc_esv_length(FBin.Size(), FBin.PlaintextOffset())); + + // write the IV + byte_t* p = FBout.Data(); + + // write the IV to the frame buffer + Ctx->GetIVec(p); + p += CBC_BLOCK_SIZE; + + + // encrypt the check value to the frame buffer + if ( ASDCP_SUCCESS(result) ) + { + result = Ctx->EncryptBlock(ESV_CheckValue, p, CBC_BLOCK_SIZE); + p += CBC_BLOCK_SIZE; + } + + // write optional plaintext region + if ( FBin.PlaintextOffset() > 0 ) + { + assert(FBin.PlaintextOffset() <= FBin.Size()); + memcpy(p, FBin.RoData(), FBin.PlaintextOffset()); + p += FBin.PlaintextOffset(); + } + + ui32_t ct_size = FBin.Size() - FBin.PlaintextOffset(); + ui32_t diff = ct_size % CBC_BLOCK_SIZE; + ui32_t block_size = ct_size - diff; + assert((block_size % CBC_BLOCK_SIZE) == 0); + + // encrypt the ciphertext region essence data + if ( ASDCP_SUCCESS(result) ) + { + result = Ctx->EncryptBlock(FBin.RoData() + FBin.PlaintextOffset(), p, block_size); + p += block_size; + } + + // construct and encrypt the padding + if ( ASDCP_SUCCESS(result) ) + { + byte_t the_last_block[CBC_BLOCK_SIZE]; + + if ( diff > 0 ) + memcpy(the_last_block, FBin.RoData() + FBin.PlaintextOffset() + block_size, diff); + + for (ui32_t i = 0; diff < CBC_BLOCK_SIZE; diff++, i++ ) + the_last_block[diff] = i; + + result = Ctx->EncryptBlock(the_last_block, p, CBC_BLOCK_SIZE); + } + + if ( ASDCP_SUCCESS(result) ) + FBout.Size(calc_esv_length(FBin.Size(), FBin.PlaintextOffset())); + + return result; +} + +// +Result_t +ASDCP::DecryptFrameBuffer(const ASDCP::FrameBuffer& FBin, ASDCP::FrameBuffer& FBout, AESDecContext* Ctx) +{ + ASDCP_TEST_NULL(Ctx); + assert(FBout.Capacity() >= FBin.SourceLength()); + + ui32_t ct_size = FBin.SourceLength() - FBin.PlaintextOffset(); + ui32_t diff = ct_size % CBC_BLOCK_SIZE; + ui32_t block_size = ct_size - diff; + assert(block_size); + assert((block_size % CBC_BLOCK_SIZE) == 0); + + const byte_t* buf = FBin.RoData(); + + // get ivec + Ctx->SetIVec(buf); + buf += CBC_BLOCK_SIZE; + + // decrypt and test check value + byte_t CheckValue[CBC_BLOCK_SIZE]; + Result_t result = Ctx->DecryptBlock(buf, CheckValue, CBC_BLOCK_SIZE); + buf += CBC_BLOCK_SIZE; + + if ( memcmp(CheckValue, ESV_CheckValue, CBC_BLOCK_SIZE) != 0 ) + return RESULT_CHECKFAIL; + + // copy plaintext region + if ( FBin.PlaintextOffset() > 0 ) + { + memcpy(FBout.Data(), buf, FBin.PlaintextOffset()); + buf += FBin.PlaintextOffset(); + } + + // decrypt all but last block + if ( ASDCP_SUCCESS(result) ) + { + result = Ctx->DecryptBlock(buf, FBout.Data() + FBin.PlaintextOffset(), block_size); + buf += block_size; + } + + // decrypt last block + if ( ASDCP_SUCCESS(result) ) + { + byte_t the_last_block[CBC_BLOCK_SIZE]; + result = Ctx->DecryptBlock(buf, the_last_block, CBC_BLOCK_SIZE); + + if ( the_last_block[diff] != 0 ) + { + DefaultLogSink().Error("Unexpected non-zero padding value.\n"); + return RESULT_FORMAT; + } + + if ( diff > 0 ) + memcpy(FBout.Data() + FBin.PlaintextOffset() + block_size, the_last_block, diff); + } + + if ( ASDCP_SUCCESS(result) ) + FBout.Size(FBin.SourceLength()); + + return result; +} + + +// +Result_t +ASDCP::IntegrityPack::CalcValues(const ASDCP::FrameBuffer& FB, byte_t* AssetID, + ui32_t sequence, HMACContext* HMAC) +{ + ASDCP_TEST_NULL(AssetID); + ASDCP_TEST_NULL(HMAC); + byte_t* p = Data; + HMAC->Reset(); + + static byte_t ber_4[MXF_BER_LENGTH] = {0x83, 0, 0, 0}; + + // update HMAC with essence data + HMAC->Update(FB.RoData(), FB.Size()); + + // track file ID length + memcpy(p, ber_4, MXF_BER_LENGTH); + *(p+3) = UUIDlen;; + p += MXF_BER_LENGTH; + + // track file ID + memcpy(p, AssetID, UUIDlen); + p += UUIDlen; + + // sequence length + memcpy(p, ber_4, MXF_BER_LENGTH); + *(p+3) = sizeof(ui64_t); + p += MXF_BER_LENGTH; + + // sequence number + Kumu::i2p<ui64_t>(KM_i64_BE(sequence), p); + p += sizeof(ui64_t); + + // HMAC length + memcpy(p, ber_4, MXF_BER_LENGTH); + *(p+3) = HMAC_SIZE; + p += MXF_BER_LENGTH; + + // update HMAC with intpack values + HMAC->Update(Data, klv_intpack_size - HMAC_SIZE); + + // finish & write HMAC + HMAC->Finalize(); + HMAC->GetHMACValue(p); + + assert(p + HMAC_SIZE == Data + klv_intpack_size); + + return RESULT_OK; +} + + +Result_t +ASDCP::IntegrityPack::TestValues(const ASDCP::FrameBuffer& FB, byte_t* AssetID, + ui32_t sequence, HMACContext* HMAC) +{ + ASDCP_TEST_NULL(AssetID); + ASDCP_TEST_NULL(HMAC); + + // find the start of the intpack + byte_t* p = (byte_t*)FB.RoData() + ( FB.Size() - klv_intpack_size ); + + // test the AssetID length + if ( ! Kumu::read_test_BER(&p, UUIDlen) ) + return RESULT_HMACFAIL; + + // test the AssetID + if ( memcmp(p, AssetID, UUIDlen) != 0 ) + { + DefaultLogSink().Error("IntegrityPack failure: AssetID mismatch.\n"); + return RESULT_HMACFAIL; + } + p += UUIDlen; + + // test the sequence length + if ( ! Kumu::read_test_BER(&p, sizeof(ui64_t)) ) + return RESULT_HMACFAIL; + + ui32_t test_sequence = (ui32_t)KM_i64_BE(Kumu::cp2i<ui64_t>(p)); + + // test the sequence value + if ( test_sequence != sequence ) + { + DefaultLogSink().Error("IntegrityPack failure: sequence is %u, expecting %u.\n", test_sequence, sequence); + return RESULT_HMACFAIL; + } + + p += sizeof(ui64_t); + + // test the HMAC length + if ( ! Kumu::read_test_BER(&p, HMAC_SIZE) ) + return RESULT_HMACFAIL; + + // test the HMAC + HMAC->Reset(); + HMAC->Update(FB.RoData(), FB.Size() - HMAC_SIZE); + HMAC->Finalize(); + + return HMAC->TestHMACValue(p); +} + +// +// end AS_DCP_MXF.cpp +// diff --git a/asdcplib/src/AS_DCP_PCM.cpp b/asdcplib/src/AS_DCP_PCM.cpp new file mode 100755 index 0000000..385d903 --- /dev/null +++ b/asdcplib/src/AS_DCP_PCM.cpp @@ -0,0 +1,671 @@ +/* +Copyright (c) 2004-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_PCM.cpp + \version $Id: AS_DCP_PCM.cpp,v 1.36 2012/02/07 18:54:25 jhurst Exp $ + \brief AS-DCP library, PCM essence reader and writer implementation +*/ + +#include "AS_DCP_internal.h" +#include <map> +#include <iostream> +#include <iomanip> + +//------------------------------------------------------------------------------------------ + +static std::string PCM_PACKAGE_LABEL = "File Package: SMPTE 382M frame wrapping of wave audio"; +static std::string SOUND_DEF_LABEL = "Sound Track"; + +// +Result_t +PCM_ADesc_to_MD(PCM::AudioDescriptor& ADesc, MXF::WaveAudioDescriptor* ADescObj) +{ + ASDCP_TEST_NULL(ADescObj); + ADescObj->SampleRate = ADesc.EditRate; + ADescObj->AudioSamplingRate = ADesc.AudioSamplingRate; + ADescObj->Locked = ADesc.Locked; + ADescObj->ChannelCount = ADesc.ChannelCount; + ADescObj->QuantizationBits = ADesc.QuantizationBits; + ADescObj->BlockAlign = ADesc.BlockAlign; + ADescObj->AvgBps = ADesc.AvgBps; + ADescObj->LinkedTrackID = ADesc.LinkedTrackID; + ADescObj->ContainerDuration = ADesc.ContainerDuration; + + ADescObj->ChannelAssignment.Reset(); + + switch ( ADesc.ChannelFormat ) + { + case PCM::CF_CFG_1: + ADescObj->ChannelAssignment = DefaultSMPTEDict().Type(MDD_DCAudioChannelCfg_1_5p1).ul; + break; + + case PCM::CF_CFG_2: + ADescObj->ChannelAssignment = DefaultSMPTEDict().Type(MDD_DCAudioChannelCfg_2_6p1).ul; + break; + + case PCM::CF_CFG_3: + ADescObj->ChannelAssignment = DefaultSMPTEDict().Type(MDD_DCAudioChannelCfg_3_7p1).ul; + break; + + case PCM::CF_CFG_4: + ADescObj->ChannelAssignment = DefaultSMPTEDict().Type(MDD_DCAudioChannelCfg_4_WTF).ul; + break; + + case PCM::CF_CFG_5: + ADescObj->ChannelAssignment = DefaultSMPTEDict().Type(MDD_DCAudioChannelCfg_5_7p1_DS).ul; + break; + + case PCM::CF_NONE: + /* Keep gcc quiet */ + break; + } + + return RESULT_OK; +} + +// +ASDCP::Result_t +MD_to_PCM_ADesc(MXF::WaveAudioDescriptor* ADescObj, PCM::AudioDescriptor& ADesc) +{ + ASDCP_TEST_NULL(ADescObj); + ADesc.EditRate = ADescObj->SampleRate; + ADesc.AudioSamplingRate = ADescObj->AudioSamplingRate; + ADesc.Locked = ADescObj->Locked; + ADesc.ChannelCount = ADescObj->ChannelCount; + ADesc.QuantizationBits = ADescObj->QuantizationBits; + ADesc.BlockAlign = ADescObj->BlockAlign; + ADesc.AvgBps = ADescObj->AvgBps; + ADesc.LinkedTrackID = ADescObj->LinkedTrackID; + assert(ADescObj->ContainerDuration <= 0xFFFFFFFFL); + ADesc.ContainerDuration = (ui32_t) ADescObj->ContainerDuration; + + ADesc.ChannelFormat = PCM::CF_NONE; + + if ( ADescObj->ChannelAssignment.HasValue() ) + { + if ( ADescObj->ChannelAssignment == DefaultSMPTEDict().Type(MDD_DCAudioChannelCfg_1_5p1).ul ) + ADesc.ChannelFormat = PCM::CF_CFG_1; + + else if ( ADescObj->ChannelAssignment == DefaultSMPTEDict().Type(MDD_DCAudioChannelCfg_2_6p1).ul ) + ADesc.ChannelFormat = PCM::CF_CFG_2; + + else if ( ADescObj->ChannelAssignment == DefaultSMPTEDict().Type(MDD_DCAudioChannelCfg_3_7p1).ul ) + ADesc.ChannelFormat = PCM::CF_CFG_3; + + else if ( ADescObj->ChannelAssignment == DefaultSMPTEDict().Type(MDD_DCAudioChannelCfg_4_WTF).ul ) + ADesc.ChannelFormat = PCM::CF_CFG_4; + + else if ( ADescObj->ChannelAssignment == DefaultSMPTEDict().Type(MDD_DCAudioChannelCfg_5_7p1_DS).ul ) + ADesc.ChannelFormat = PCM::CF_CFG_5; + } + + return RESULT_OK; +} + +// +std::ostream& +ASDCP::PCM::operator << (std::ostream& strm, const AudioDescriptor& ADesc) +{ + strm << " SampleRate: " << ADesc.EditRate.Numerator << "/" << ADesc.EditRate.Denominator << std::endl; + strm << " AudioSamplingRate: " << ADesc.AudioSamplingRate.Numerator << "/" << ADesc.AudioSamplingRate.Denominator << std::endl; + strm << " Locked: " << (unsigned) ADesc.Locked << std::endl; + strm << " ChannelCount: " << (unsigned) ADesc.ChannelCount << std::endl; + strm << " QuantizationBits: " << (unsigned) ADesc.QuantizationBits << std::endl; + strm << " BlockAlign: " << (unsigned) ADesc.BlockAlign << std::endl; + strm << " AvgBps: " << (unsigned) ADesc.AvgBps << std::endl; + strm << " LinkedTrackID: " << (unsigned) ADesc.LinkedTrackID << std::endl; + strm << " ContainerDuration: " << (unsigned) ADesc.ContainerDuration << std::endl; + + return strm; +} + +// +void +ASDCP::PCM::AudioDescriptorDump(const AudioDescriptor& ADesc, FILE* stream) +{ + if ( stream == 0 ) + stream = stderr; + + fprintf(stream, "\ + EditRate: %d/%d\n\ + AudioSamplingRate: %d/%d\n\ + Locked: %u\n\ + ChannelCount: %u\n\ + QuantizationBits: %u\n\ + BlockAlign: %u\n\ + AvgBps: %u\n\ + LinkedTrackID: %u\n\ + ContainerDuration: %u\n", + ADesc.EditRate.Numerator, ADesc.EditRate.Denominator, + ADesc.AudioSamplingRate.Numerator, ADesc.AudioSamplingRate.Denominator, + ADesc.Locked, + ADesc.ChannelCount, + ADesc.QuantizationBits, + ADesc.BlockAlign, + ADesc.AvgBps, + ADesc.LinkedTrackID, + ADesc.ContainerDuration + ); +} + + +// +// +static ui32_t +calc_CBR_frame_size(ASDCP::WriterInfo& Info, const ASDCP::PCM::AudioDescriptor& ADesc) +{ + ui32_t CBR_frame_size = 0; + + if ( Info.EncryptedEssence ) + { + CBR_frame_size = + SMPTE_UL_LENGTH + + MXF_BER_LENGTH + + klv_cryptinfo_size + + calc_esv_length(ASDCP::PCM::CalcFrameBufferSize(ADesc), 0) + + ( Info.UsesHMAC ? klv_intpack_size : (MXF_BER_LENGTH * 3) ); + } + else + { + CBR_frame_size = ASDCP::PCM::CalcFrameBufferSize(ADesc) + SMPTE_UL_LENGTH + MXF_BER_LENGTH; + } + + return CBR_frame_size; +} + + +//------------------------------------------------------------------------------------------ + + +class ASDCP::PCM::MXFReader::h__Reader : public ASDCP::h__Reader +{ + ASDCP_NO_COPY_CONSTRUCT(h__Reader); + h__Reader(); + +public: + AudioDescriptor m_ADesc; + + h__Reader(const Dictionary& d) : ASDCP::h__Reader(d) {} + ~h__Reader() {} + Result_t OpenRead(const char*); + Result_t ReadFrame(ui32_t, FrameBuffer&, AESDecContext*, HMACContext*); +}; + + +// +// +ASDCP::Result_t +ASDCP::PCM::MXFReader::h__Reader::OpenRead(const char* filename) +{ + Result_t result = OpenMXFRead(filename); + + if( ASDCP_SUCCESS(result) ) + { + InterchangeObject* Object; + if ( ASDCP_SUCCESS(m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(WaveAudioDescriptor), &Object)) ) + { + assert(Object); + result = MD_to_PCM_ADesc((MXF::WaveAudioDescriptor*)Object, m_ADesc); + } + } + + /* This check has been removed so that DCP-o-matic can use any edit rate + it wants. + */ +#if 0 + // check for sample/frame rate sanity + if ( ASDCP_SUCCESS(result) + && m_ADesc.EditRate != EditRate_24 + && m_ADesc.EditRate != EditRate_25 + && m_ADesc.EditRate != EditRate_30 + && m_ADesc.EditRate != EditRate_48 + && m_ADesc.EditRate != EditRate_50 + && m_ADesc.EditRate != EditRate_60 + && m_ADesc.EditRate != EditRate_96 + && m_ADesc.EditRate != EditRate_100 + && m_ADesc.EditRate != EditRate_120 + && m_ADesc.EditRate != EditRate_23_98 ) + { + DefaultLogSink().Error("PCM file EditRate is not a supported value: %d/%d\n", // lu + m_ADesc.EditRate.Numerator, m_ADesc.EditRate.Denominator); + + // oh, they gave us the audio sampling rate instead, assume 24/1 + if ( m_ADesc.EditRate == SampleRate_48k ) + { + DefaultLogSink().Warn("adjusting EditRate to 24/1\n"); + m_ADesc.EditRate = EditRate_24; + } + else + { + // or we just drop the hammer + return RESULT_FORMAT; + } + } +#endif + + if( ASDCP_SUCCESS(result) ) + result = InitMXFIndex(); + + if( ASDCP_SUCCESS(result) ) + result = InitInfo(); + + // TODO: test file for sane CBR index BytesPerEditUnit + + return result; +} + + +// +// +ASDCP::Result_t +ASDCP::PCM::MXFReader::h__Reader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf, + AESDecContext* Ctx, HMACContext* HMAC) +{ + if ( ! m_File.IsOpen() ) + return RESULT_INIT; + + assert(m_Dict); + return ReadEKLVFrame(FrameNum, FrameBuf, m_Dict->ul(MDD_WAVEssence), Ctx, HMAC); +} + +//------------------------------------------------------------------------------------------ + + +// +void +ASDCP::PCM::FrameBuffer::Dump(FILE* stream, ui32_t dump_len) const +{ + if ( stream == 0 ) + stream = stderr; + + fprintf(stream, "Frame: %06u, %7u bytes\n", + m_FrameNumber, m_Size); + + if ( dump_len ) + Kumu::hexdump(m_Data, dump_len, stream); +} + +//------------------------------------------------------------------------------------------ + +ASDCP::PCM::MXFReader::MXFReader() +{ + m_Reader = new h__Reader(DefaultCompositeDict()); +} + + +ASDCP::PCM::MXFReader::~MXFReader() +{ + if ( m_Reader && m_Reader->m_File.IsOpen() ) + m_Reader->Close(); +} + +// Warning: direct manipulation of MXF structures can interfere +// with the normal operation of the wrapper. Caveat emptor! +// +ASDCP::MXF::OPAtomHeader& +ASDCP::PCM::MXFReader::OPAtomHeader() +{ + if ( m_Reader.empty() ) + { + assert(g_OPAtomHeader); + return *g_OPAtomHeader; + } + + return m_Reader->m_HeaderPart; +} + +// Warning: direct manipulation of MXF structures can interfere +// with the normal operation of the wrapper. Caveat emptor! +// +ASDCP::MXF::OPAtomIndexFooter& +ASDCP::PCM::MXFReader::OPAtomIndexFooter() +{ + if ( m_Reader.empty() ) + { + assert(g_OPAtomIndexFooter); + return *g_OPAtomIndexFooter; + } + + return m_Reader->m_FooterPart; +} + +// Open the file for reading. The file must exist. Returns error if the +// operation cannot be completed. +ASDCP::Result_t +ASDCP::PCM::MXFReader::OpenRead(const char* filename) const +{ + return m_Reader->OpenRead(filename); +} + +// 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. +ASDCP::Result_t +ASDCP::PCM::MXFReader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf, + AESDecContext* Ctx, HMACContext* HMAC) const +{ + if ( m_Reader && m_Reader->m_File.IsOpen() ) + return m_Reader->ReadFrame(FrameNum, FrameBuf, Ctx, HMAC); + + return RESULT_INIT; +} + + +// Fill the struct with the values from the file's header. +// Returns RESULT_INIT if the file is not open. +ASDCP::Result_t +ASDCP::PCM::MXFReader::FillAudioDescriptor(AudioDescriptor& ADesc) const +{ + if ( m_Reader && m_Reader->m_File.IsOpen() ) + { + ADesc = m_Reader->m_ADesc; + return RESULT_OK; + } + + return RESULT_INIT; +} + +// Fill the struct with the values from the file's header. +// Returns RESULT_INIT if the file is not open. +ASDCP::Result_t +ASDCP::PCM::MXFReader::FillWriterInfo(WriterInfo& Info) const +{ + if ( m_Reader && m_Reader->m_File.IsOpen() ) + { + Info = m_Reader->m_Info; + return RESULT_OK; + } + + return RESULT_INIT; +} + +// +void +ASDCP::PCM::MXFReader::DumpHeaderMetadata(FILE* stream) const +{ + if ( m_Reader && m_Reader->m_File.IsOpen() ) + m_Reader->m_HeaderPart.Dump(stream); +} + + +// +void +ASDCP::PCM::MXFReader::DumpIndex(FILE* stream) const +{ + if ( m_Reader->m_File.IsOpen() ) + m_Reader->m_FooterPart.Dump(stream); +} + +// +ASDCP::Result_t +ASDCP::PCM::MXFReader::Close() const +{ + if ( m_Reader && m_Reader->m_File.IsOpen() ) + { + m_Reader->Close(); + return RESULT_OK; + } + + return RESULT_INIT; +} + + +//------------------------------------------------------------------------------------------ + +// +class ASDCP::PCM::MXFWriter::h__Writer : public ASDCP::h__Writer +{ + ASDCP_NO_COPY_CONSTRUCT(h__Writer); + h__Writer(); + +public: + AudioDescriptor m_ADesc; + byte_t m_EssenceUL[SMPTE_UL_LENGTH]; + + h__Writer(const Dictionary& d) : ASDCP::h__Writer(d) { + memset(m_EssenceUL, 0, SMPTE_UL_LENGTH); + } + + ~h__Writer(){} + + Result_t OpenWrite(const char*, ui32_t HeaderSize); + Result_t SetSourceStream(const AudioDescriptor&); + Result_t WriteFrame(const FrameBuffer&, AESEncContext* = 0, HMACContext* = 0); + Result_t Finalize(); +}; + + + +// Open the file for writing. The file must not exist. Returns error if +// the operation cannot be completed. +ASDCP::Result_t +ASDCP::PCM::MXFWriter::h__Writer::OpenWrite(const char* filename, ui32_t HeaderSize) +{ + if ( ! m_State.Test_BEGIN() ) + return RESULT_STATE; + + Result_t result = m_File.OpenWrite(filename); + + if ( ASDCP_SUCCESS(result) ) + { + m_HeaderSize = HeaderSize; + m_EssenceDescriptor = new WaveAudioDescriptor(m_Dict); + result = m_State.Goto_INIT(); + } + + return result; +} + + +// Automatically sets the MXF file's metadata from the WAV parser info. +ASDCP::Result_t +ASDCP::PCM::MXFWriter::h__Writer::SetSourceStream(const AudioDescriptor& ADesc) +{ + if ( ! m_State.Test_INIT() ) + return RESULT_STATE; + +#if 0 + /* This check has been removed so that DCP-o-matic can use anye dit rate + it wants. + */ + if ( ADesc.EditRate != EditRate_24 + && ADesc.EditRate != EditRate_25 + && ADesc.EditRate != EditRate_30 + && ADesc.EditRate != EditRate_48 + && ADesc.EditRate != EditRate_50 + && ADesc.EditRate != EditRate_60 + && ADesc.EditRate != EditRate_96 + && ADesc.EditRate != EditRate_100 + && ADesc.EditRate != EditRate_120 + && ADesc.EditRate != EditRate_23_98 ) + { + DefaultLogSink().Error("AudioDescriptor.EditRate is not a supported value: %d/%d\n", + ADesc.EditRate.Numerator, ADesc.EditRate.Denominator); + return RESULT_RAW_FORMAT; + } +#endif + + if ( ADesc.AudioSamplingRate != SampleRate_48k && ADesc.AudioSamplingRate != SampleRate_96k ) + { + DefaultLogSink().Error("AudioDescriptor.AudioSamplingRate is not 48000/1 or 96000/1: %d/%d\n", + ADesc.AudioSamplingRate.Numerator, ADesc.AudioSamplingRate.Denominator); + return RESULT_RAW_FORMAT; + } + + assert(m_Dict); + m_ADesc = ADesc; + + Result_t result = PCM_ADesc_to_MD(m_ADesc, (WaveAudioDescriptor*)m_EssenceDescriptor); + + if ( ASDCP_SUCCESS(result) ) + { + memcpy(m_EssenceUL, m_Dict->ul(MDD_WAVEssence), SMPTE_UL_LENGTH); + m_EssenceUL[SMPTE_UL_LENGTH-1] = 1; // first (and only) essence container + result = m_State.Goto_READY(); + } + + if ( ASDCP_SUCCESS(result) ) + { + ui32_t TCFrameRate = ( m_ADesc.EditRate == EditRate_23_98 ) ? 24 : m_ADesc.EditRate.Numerator; + + result = WriteMXFHeader(PCM_PACKAGE_LABEL, UL(m_Dict->ul(MDD_WAVWrapping)), + SOUND_DEF_LABEL, UL(m_EssenceUL), UL(m_Dict->ul(MDD_SoundDataDef)), + m_ADesc.EditRate, TCFrameRate, calc_CBR_frame_size(m_Info, m_ADesc)); + } + + return result; +} + + +// +// +ASDCP::Result_t +ASDCP::PCM::MXFWriter::h__Writer::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx, + HMACContext* HMAC) +{ + Result_t result = RESULT_OK; + + if ( m_State.Test_READY() ) + result = m_State.Goto_RUNNING(); // first time through + + if ( ASDCP_SUCCESS(result) ) + result = WriteEKLVPacket(FrameBuf, m_EssenceUL, Ctx, HMAC); + + if ( ASDCP_SUCCESS(result) ) + m_FramesWritten++; + + return result; +} + +// Closes the MXF file, writing the index and other closing information. +// +ASDCP::Result_t +ASDCP::PCM::MXFWriter::h__Writer::Finalize() +{ + if ( ! m_State.Test_RUNNING() ) + return RESULT_STATE; + + m_State.Goto_FINAL(); + + return WriteMXFFooter(); +} + + +//------------------------------------------------------------------------------------------ +// + + + +ASDCP::PCM::MXFWriter::MXFWriter() +{ +} + +ASDCP::PCM::MXFWriter::~MXFWriter() +{ +} + +// Warning: direct manipulation of MXF structures can interfere +// with the normal operation of the wrapper. Caveat emptor! +// +ASDCP::MXF::OPAtomHeader& +ASDCP::PCM::MXFWriter::OPAtomHeader() +{ + if ( m_Writer.empty() ) + { + assert(g_OPAtomHeader); + return *g_OPAtomHeader; + } + + return m_Writer->m_HeaderPart; +} + +// Warning: direct manipulation of MXF structures can interfere +// with the normal operation of the wrapper. Caveat emptor! +// +ASDCP::MXF::OPAtomIndexFooter& +ASDCP::PCM::MXFWriter::OPAtomIndexFooter() +{ + if ( m_Writer.empty() ) + { + assert(g_OPAtomIndexFooter); + return *g_OPAtomIndexFooter; + } + + return m_Writer->m_FooterPart; +} + +// Open the file for writing. The file must not exist. Returns error if +// the operation cannot be completed. +ASDCP::Result_t +ASDCP::PCM::MXFWriter::OpenWrite(const char* filename, const WriterInfo& Info, + const AudioDescriptor& ADesc, ui32_t HeaderSize) +{ + if ( Info.LabelSetType == LS_MXF_SMPTE ) + m_Writer = new h__Writer(DefaultSMPTEDict()); + else + m_Writer = new h__Writer(DefaultInteropDict()); + + m_Writer->m_Info = Info; + + Result_t result = m_Writer->OpenWrite(filename, HeaderSize); + + if ( ASDCP_SUCCESS(result) ) + result = m_Writer->SetSourceStream(ADesc); + + if ( ASDCP_FAILURE(result) ) + m_Writer.release(); + + return result; +} + +// 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. +ASDCP::Result_t +ASDCP::PCM::MXFWriter::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC) +{ + if ( m_Writer.empty() ) + return RESULT_INIT; + + return m_Writer->WriteFrame(FrameBuf, Ctx, HMAC); +} + +// Closes the MXF file, writing the index and other closing information. +ASDCP::Result_t +ASDCP::PCM::MXFWriter::Finalize() +{ + if ( m_Writer.empty() ) + return RESULT_INIT; + + return m_Writer->Finalize(); +} + +// +// end AS_DCP_PCM.cpp +// + diff --git a/asdcplib/src/AS_DCP_TimedText.cpp b/asdcplib/src/AS_DCP_TimedText.cpp new file mode 100644 index 0000000..98ecce1 --- /dev/null +++ b/asdcplib/src/AS_DCP_TimedText.cpp @@ -0,0 +1,770 @@ +/* +Copyright (c) 2008-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_TimedText.cpp + \version $Id: AS_DCP_TimedText.cpp,v 1.26 2012/02/07 18:54:25 jhurst Exp $ + \brief AS-DCP library, PCM essence reader and writer implementation +*/ + + +#include "AS_DCP_internal.h" +#include "KM_xml.h" +#include <iostream> +#include <iomanip> + +using Kumu::GenRandomValue; + +static std::string TIMED_TEXT_PACKAGE_LABEL = "File Package: SMPTE 429-5 clip wrapping of D-Cinema Timed Text data"; +static std::string TIMED_TEXT_DEF_LABEL = "Timed Text Track"; + + +//------------------------------------------------------------------------------------------ + +const char* +MIME2str(TimedText::MIMEType_t m) +{ + if ( m == TimedText::MT_PNG ) + return "image/png"; + + else if ( m == TimedText::MT_OPENTYPE ) + return "application/x-font-opentype"; + + return "application/octet-stream"; +} + +// +std::ostream& +ASDCP::TimedText::operator << (std::ostream& strm, const TimedTextDescriptor& TDesc) +{ + UUID TmpID(TDesc.AssetID); + char buf[64]; + + strm << " EditRate: " << (unsigned) TDesc.EditRate.Numerator << "/" << (unsigned) TDesc.EditRate.Denominator << std::endl; + strm << "ContainerDuration: " << (unsigned) TDesc.ContainerDuration << std::endl; + strm << " AssetID: " << TmpID.EncodeHex(buf, 64) << std::endl; + strm << " NamespaceName: " << TDesc.NamespaceName << std::endl; + strm << " ResourceCount: " << (unsigned long) TDesc.ResourceList.size() << std::endl; + + TimedText::ResourceList_t::const_iterator ri; + for ( ri = TDesc.ResourceList.begin() ; ri != TDesc.ResourceList.end(); ri++ ) + { + TmpID.Set((*ri).ResourceID); + strm << " " << TmpID.EncodeHex(buf, 64) << ": " << MIME2str((*ri).Type) << std::endl; + } + + return strm; +} + +// +void +ASDCP::TimedText::DescriptorDump(ASDCP::TimedText::TimedTextDescriptor const& TDesc, FILE* stream) +{ + if ( stream == 0 ) + stream = stderr; + + UUID TmpID(TDesc.AssetID); + char buf[64]; + + fprintf(stream, " EditRate: %u/%u\n", TDesc.EditRate.Numerator, TDesc.EditRate.Denominator); + fprintf(stream, "ContainerDuration: %u\n", TDesc.ContainerDuration); + fprintf(stream, " AssetID: %s\n", TmpID.EncodeHex(buf, 64)); + fprintf(stream, " NamespaceName: %s\n", TDesc.NamespaceName.c_str()); + fprintf(stream, " ResourceCount: %zu\n", TDesc.ResourceList.size()); + + TimedText::ResourceList_t::const_iterator ri; + for ( ri = TDesc.ResourceList.begin() ; ri != TDesc.ResourceList.end(); ri++ ) + { + TmpID.Set((*ri).ResourceID); + fprintf(stream, " %s: %s\n", + TmpID.EncodeHex(buf, 64), + MIME2str((*ri).Type)); + } +} + +// +void +ASDCP::TimedText::FrameBuffer::Dump(FILE* stream, ui32_t dump_len) const +{ + if ( stream == 0 ) + stream = stderr; + + UUID TmpID(m_AssetID); + char buf[64]; + fprintf(stream, "%s | %s | %u\n", TmpID.EncodeHex(buf, 64), m_MIMEType.c_str(), Size()); + + if ( dump_len > 0 ) + Kumu::hexdump(m_Data, dump_len, stream); +} + +//------------------------------------------------------------------------------------------ + +typedef std::map<UUID, UUID> ResourceMap_t; + +class ASDCP::TimedText::MXFReader::h__Reader : public ASDCP::h__Reader +{ + MXF::TimedTextDescriptor* m_EssenceDescriptor; + ResourceMap_t m_ResourceMap; + + ASDCP_NO_COPY_CONSTRUCT(h__Reader); + +public: + TimedTextDescriptor m_TDesc; + + h__Reader(const Dictionary& d) : ASDCP::h__Reader(d), m_EssenceDescriptor(0) { + memset(&m_TDesc.AssetID, 0, UUIDlen); + } + + Result_t OpenRead(const char*); + Result_t MD_to_TimedText_TDesc(TimedText::TimedTextDescriptor& TDesc); + Result_t ReadTimedTextResource(FrameBuffer& FrameBuf, AESDecContext* Ctx, HMACContext* HMAC); + Result_t ReadAncillaryResource(const byte_t*, FrameBuffer& FrameBuf, AESDecContext* Ctx, HMACContext* HMAC); +}; + +// +ASDCP::Result_t +ASDCP::TimedText::MXFReader::h__Reader::MD_to_TimedText_TDesc(TimedText::TimedTextDescriptor& TDesc) +{ + assert(m_EssenceDescriptor); + memset(&m_TDesc.AssetID, 0, UUIDlen); + MXF::TimedTextDescriptor* TDescObj = (MXF::TimedTextDescriptor*)m_EssenceDescriptor; + + TDesc.EditRate = TDescObj->SampleRate; + assert(TDescObj->ContainerDuration <= 0xFFFFFFFFL); + TDesc.ContainerDuration = (ui32_t) TDescObj->ContainerDuration; + memcpy(TDesc.AssetID, TDescObj->ResourceID.Value(), UUIDlen); + TDesc.NamespaceName = TDescObj->NamespaceURI; + TDesc.EncodingName = TDescObj->UCSEncoding; + + Batch<UUID>::const_iterator sdi = TDescObj->SubDescriptors.begin(); + TimedTextResourceSubDescriptor* DescObject = 0; + Result_t result = RESULT_OK; + + for ( ; sdi != TDescObj->SubDescriptors.end() && KM_SUCCESS(result); sdi++ ) + { + InterchangeObject* tmp_iobj = 0; + result = m_HeaderPart.GetMDObjectByID(*sdi, &tmp_iobj); + DescObject = static_cast<TimedTextResourceSubDescriptor*>(tmp_iobj); + + if ( KM_SUCCESS(result) ) + { + TimedTextResourceDescriptor TmpResource; + memcpy(TmpResource.ResourceID, DescObject->AncillaryResourceID.Value(), UUIDlen); + + if ( DescObject->MIMEMediaType.find("application/x-font-opentype") != std::string::npos + || DescObject->MIMEMediaType.find("application/x-opentype") != std::string::npos + || DescObject->MIMEMediaType.find("font/opentype") != std::string::npos ) + TmpResource.Type = MT_OPENTYPE; + + else if ( DescObject->MIMEMediaType.find("image/png") != std::string::npos ) + TmpResource.Type = MT_PNG; + + else + TmpResource.Type = MT_BIN; + + TDesc.ResourceList.push_back(TmpResource); + m_ResourceMap.insert(ResourceMap_t::value_type(DescObject->AncillaryResourceID, *sdi)); + } + else + { + DefaultLogSink().Error("Broken sub-descriptor link\n"); + return RESULT_FORMAT; + } + } + + return result; +} + +// +ASDCP::Result_t +ASDCP::TimedText::MXFReader::h__Reader::OpenRead(char const* filename) +{ + Result_t result = OpenMXFRead(filename); + + if( ASDCP_SUCCESS(result) ) + { + if ( m_EssenceDescriptor == 0 ) + { + InterchangeObject* tmp_iobj = 0; + result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(TimedTextDescriptor), &tmp_iobj); + m_EssenceDescriptor = static_cast<MXF::TimedTextDescriptor*>(tmp_iobj); + } + + if( ASDCP_SUCCESS(result) ) + result = MD_to_TimedText_TDesc(m_TDesc); + } + + if( ASDCP_SUCCESS(result) ) + result = InitMXFIndex(); + + if( ASDCP_SUCCESS(result) ) + result = InitInfo(); + + return result; +} + +// +ASDCP::Result_t +ASDCP::TimedText::MXFReader::h__Reader::ReadTimedTextResource(FrameBuffer& FrameBuf, + AESDecContext* Ctx, HMACContext* HMAC) +{ + if ( ! m_File.IsOpen() ) + return RESULT_INIT; + + assert(m_Dict); + Result_t result = ReadEKLVFrame(0, FrameBuf, m_Dict->ul(MDD_TimedTextEssence), Ctx, HMAC); + + if( ASDCP_SUCCESS(result) ) + { + FrameBuf.AssetID(m_TDesc.AssetID); + FrameBuf.MIMEType("text/xml"); + } + + return result; +} + +// +ASDCP::Result_t +ASDCP::TimedText::MXFReader::h__Reader::ReadAncillaryResource(const byte_t* uuid, FrameBuffer& FrameBuf, + AESDecContext* Ctx, HMACContext* HMAC) +{ + KM_TEST_NULL_L(uuid); + UUID RID(uuid); + + ResourceMap_t::const_iterator ri = m_ResourceMap.find(RID); + if ( ri == m_ResourceMap.end() ) + { + char buf[64]; + DefaultLogSink().Error("No such resource: %s\n", RID.EncodeHex(buf, 64)); + return RESULT_RANGE; + } + + TimedTextResourceSubDescriptor* DescObject = 0; + // get the subdescriptor + InterchangeObject* tmp_iobj = 0; + Result_t result = m_HeaderPart.GetMDObjectByID((*ri).second, &tmp_iobj); + DescObject = static_cast<TimedTextResourceSubDescriptor*>(tmp_iobj); + + if ( KM_SUCCESS(result) ) + { + Array<RIP::Pair>::const_iterator pi; + RIP::Pair TmpPair; + ui32_t sequence = 1; + + // Look up the partition start in the RIP using the SID. + // Count the sequence length in because this is the sequence + // value needed to complete the HMAC. + for ( pi = m_HeaderPart.m_RIP.PairArray.begin(); pi != m_HeaderPart.m_RIP.PairArray.end(); pi++, sequence++ ) + { + if ( (*pi).BodySID == DescObject->EssenceStreamID ) + { + TmpPair = *pi; + break; + } + } + + if ( TmpPair.ByteOffset == 0 ) + { + DefaultLogSink().Error("Body SID not found in RIP set: %d\n", DescObject->EssenceStreamID); + return RESULT_FORMAT; + } + + if ( KM_SUCCESS(result) ) + { + FrameBuf.AssetID(uuid); + FrameBuf.MIMEType(DescObject->MIMEMediaType); + + // seek tp the start of the partition + if ( (Kumu::fpos_t)TmpPair.ByteOffset != m_LastPosition ) + { + m_LastPosition = TmpPair.ByteOffset; + result = m_File.Seek(TmpPair.ByteOffset); + } + + // read the partition header + MXF::Partition GSPart(m_Dict); + result = GSPart.InitFromFile(m_File); + + if( ASDCP_SUCCESS(result) ) + { + // check the SID + if ( DescObject->EssenceStreamID != GSPart.BodySID ) + { + char buf[64]; + DefaultLogSink().Error("Generic stream partition body differs: %s\n", RID.EncodeHex(buf, 64)); + return RESULT_FORMAT; + } + + // read the essence packet + assert(m_Dict); + if( ASDCP_SUCCESS(result) ) + result = ReadEKLVPacket(0, 1, FrameBuf, m_Dict->ul(MDD_GenericStream_DataElement), Ctx, HMAC); + } + } + } + + return result; +} + + +//------------------------------------------------------------------------------------------ + +ASDCP::TimedText::MXFReader::MXFReader() +{ + m_Reader = new h__Reader(DefaultSMPTEDict()); +} + + +ASDCP::TimedText::MXFReader::~MXFReader() +{ +} + +// Warning: direct manipulation of MXF structures can interfere +// with the normal operation of the wrapper. Caveat emptor! +// +ASDCP::MXF::OPAtomHeader& +ASDCP::TimedText::MXFReader::OPAtomHeader() +{ + if ( m_Reader.empty() ) + { + assert(g_OPAtomHeader); + return *g_OPAtomHeader; + } + + return m_Reader->m_HeaderPart; +} + +// Warning: direct manipulation of MXF structures can interfere +// with the normal operation of the wrapper. Caveat emptor! +// +ASDCP::MXF::OPAtomIndexFooter& +ASDCP::TimedText::MXFReader::OPAtomIndexFooter() +{ + if ( m_Reader.empty() ) + { + assert(g_OPAtomIndexFooter); + return *g_OPAtomIndexFooter; + } + + return m_Reader->m_FooterPart; +} + +// Open the file for reading. The file must exist. Returns error if the +// operation cannot be completed. +ASDCP::Result_t +ASDCP::TimedText::MXFReader::OpenRead(const char* filename) const +{ + return m_Reader->OpenRead(filename); +} + +// Fill the struct with the values from the file's header. +// Returns RESULT_INIT if the file is not open. +ASDCP::Result_t +ASDCP::TimedText::MXFReader::FillTimedTextDescriptor(TimedText::TimedTextDescriptor& TDesc) const +{ + if ( m_Reader && m_Reader->m_File.IsOpen() ) + { + TDesc = m_Reader->m_TDesc; + return RESULT_OK; + } + + return RESULT_INIT; +} + +// Fill the struct with the values from the file's header. +// Returns RESULT_INIT if the file is not open. +ASDCP::Result_t +ASDCP::TimedText::MXFReader::FillWriterInfo(WriterInfo& Info) const +{ + if ( m_Reader && m_Reader->m_File.IsOpen() ) + { + Info = m_Reader->m_Info; + return RESULT_OK; + } + + return RESULT_INIT; +} + +// +ASDCP::Result_t +ASDCP::TimedText::MXFReader::ReadTimedTextResource(std::string& s, AESDecContext* Ctx, HMACContext* HMAC) const +{ + FrameBuffer FrameBuf(2*Kumu::Megabyte); + + Result_t result = ReadTimedTextResource(FrameBuf, Ctx, HMAC); + + if ( ASDCP_SUCCESS(result) ) + s.assign((char*)FrameBuf.Data(), FrameBuf.Size()); + + return result; +} + +// +ASDCP::Result_t +ASDCP::TimedText::MXFReader::ReadTimedTextResource(FrameBuffer& FrameBuf, + AESDecContext* Ctx, HMACContext* HMAC) const +{ + if ( m_Reader && m_Reader->m_File.IsOpen() ) + return m_Reader->ReadTimedTextResource(FrameBuf, Ctx, HMAC); + + return RESULT_INIT; +} + +// +ASDCP::Result_t +ASDCP::TimedText::MXFReader::ReadAncillaryResource(const byte_t* uuid, FrameBuffer& FrameBuf, + AESDecContext* Ctx, HMACContext* HMAC) const +{ + if ( m_Reader && m_Reader->m_File.IsOpen() ) + return m_Reader->ReadAncillaryResource(uuid, FrameBuf, Ctx, HMAC); + + return RESULT_INIT; +} + + +// +void +ASDCP::TimedText::MXFReader::DumpHeaderMetadata(FILE* stream) const +{ + if ( m_Reader->m_File.IsOpen() ) + m_Reader->m_HeaderPart.Dump(stream); +} + + +// +void +ASDCP::TimedText::MXFReader::DumpIndex(FILE* stream) const +{ + if ( m_Reader->m_File.IsOpen() ) + m_Reader->m_FooterPart.Dump(stream); +} + +// +ASDCP::Result_t +ASDCP::TimedText::MXFReader::Close() const +{ + if ( m_Reader && m_Reader->m_File.IsOpen() ) + { + m_Reader->Close(); + return RESULT_OK; + } + + return RESULT_INIT; +} + + +//------------------------------------------------------------------------------------------ + + +// +class ASDCP::TimedText::MXFWriter::h__Writer : public ASDCP::h__Writer +{ + ASDCP_NO_COPY_CONSTRUCT(h__Writer); + h__Writer(); + +public: + TimedTextDescriptor m_TDesc; + byte_t m_EssenceUL[SMPTE_UL_LENGTH]; + ui32_t m_EssenceStreamID; + + h__Writer(const Dictionary& d) : ASDCP::h__Writer(d), m_EssenceStreamID(10) { + memset(m_EssenceUL, 0, SMPTE_UL_LENGTH); + } + + ~h__Writer(){} + + Result_t OpenWrite(const char*, ui32_t HeaderSize); + Result_t SetSourceStream(const TimedTextDescriptor&); + Result_t WriteTimedTextResource(const std::string& XMLDoc, AESEncContext* = 0, HMACContext* = 0); + Result_t WriteAncillaryResource(const FrameBuffer&, AESEncContext* = 0, HMACContext* = 0); + Result_t Finalize(); + Result_t TimedText_TDesc_to_MD(TimedText::TimedTextDescriptor& TDesc); +}; + +// +ASDCP::Result_t +ASDCP::TimedText::MXFWriter::h__Writer::TimedText_TDesc_to_MD(TimedText::TimedTextDescriptor& TDesc) +{ + assert(m_EssenceDescriptor); + MXF::TimedTextDescriptor* TDescObj = (MXF::TimedTextDescriptor*)m_EssenceDescriptor; + + TDescObj->SampleRate = TDesc.EditRate; + TDescObj->ContainerDuration = TDesc.ContainerDuration; + TDescObj->ResourceID.Set(TDesc.AssetID); + TDescObj->NamespaceURI = TDesc.NamespaceName; + TDescObj->UCSEncoding = TDesc.EncodingName; + + return RESULT_OK; +} + +// +ASDCP::Result_t +ASDCP::TimedText::MXFWriter::h__Writer::OpenWrite(char const* filename, ui32_t HeaderSize) +{ + if ( ! m_State.Test_BEGIN() ) + return RESULT_STATE; + + Result_t result = m_File.OpenWrite(filename); + + if ( ASDCP_SUCCESS(result) ) + { + m_HeaderSize = HeaderSize; + m_EssenceDescriptor = new MXF::TimedTextDescriptor(m_Dict); + result = m_State.Goto_INIT(); + } + + return result; +} + +// +ASDCP::Result_t +ASDCP::TimedText::MXFWriter::h__Writer::SetSourceStream(ASDCP::TimedText::TimedTextDescriptor const& TDesc) +{ + if ( ! m_State.Test_INIT() ) + return RESULT_STATE; + + m_TDesc = TDesc; + ResourceList_t::const_iterator ri; + Result_t result = TimedText_TDesc_to_MD(m_TDesc); + + for ( ri = m_TDesc.ResourceList.begin() ; ri != m_TDesc.ResourceList.end() && ASDCP_SUCCESS(result); ri++ ) + { + TimedTextResourceSubDescriptor* resourceSubdescriptor = new TimedTextResourceSubDescriptor(m_Dict); + GenRandomValue(resourceSubdescriptor->InstanceUID); + resourceSubdescriptor->AncillaryResourceID.Set((*ri).ResourceID); + resourceSubdescriptor->MIMEMediaType = MIME2str((*ri).Type); + resourceSubdescriptor->EssenceStreamID = m_EssenceStreamID++; + m_EssenceSubDescriptorList.push_back((FileDescriptor*)resourceSubdescriptor); + m_EssenceDescriptor->SubDescriptors.push_back(resourceSubdescriptor->InstanceUID); + } + + m_EssenceStreamID = 10; + assert(m_Dict); + + if ( ASDCP_SUCCESS(result) ) + { + InitHeader(); + AddDMSegment(m_TDesc.EditRate, 24, TIMED_TEXT_DEF_LABEL, + UL(m_Dict->ul(MDD_PictureDataDef)), TIMED_TEXT_PACKAGE_LABEL); + + AddEssenceDescriptor(UL(m_Dict->ul(MDD_TimedTextWrapping))); + + result = m_HeaderPart.WriteToFile(m_File, m_HeaderSize); + + if ( KM_SUCCESS(result) ) + result = CreateBodyPart(m_TDesc.EditRate); + } + + if ( ASDCP_SUCCESS(result) ) + { + memcpy(m_EssenceUL, m_Dict->ul(MDD_TimedTextEssence), SMPTE_UL_LENGTH); + m_EssenceUL[SMPTE_UL_LENGTH-1] = 1; // first (and only) essence container + result = m_State.Goto_READY(); + } + + return result; +} + +// +ASDCP::Result_t +ASDCP::TimedText::MXFWriter::h__Writer::WriteTimedTextResource(const std::string& XMLDoc, + ASDCP::AESEncContext* Ctx, ASDCP::HMACContext* HMAC) +{ + Result_t result = m_State.Goto_RUNNING(); + + if ( ASDCP_SUCCESS(result) ) + { + // TODO: make sure it's XML + + ui32_t str_size = XMLDoc.size(); + FrameBuffer FrameBuf(str_size); + + memcpy(FrameBuf.Data(), XMLDoc.c_str(), str_size); + FrameBuf.Size(str_size); + + IndexTableSegment::IndexEntry Entry; + Entry.StreamOffset = m_StreamOffset; + + if ( ASDCP_SUCCESS(result) ) + result = WriteEKLVPacket(FrameBuf, m_EssenceUL, Ctx, HMAC); + + if ( ASDCP_SUCCESS(result) ) + { + m_FooterPart.PushIndexEntry(Entry); + m_FramesWritten++; + } + } + + return result; +} + + +// +ASDCP::Result_t +ASDCP::TimedText::MXFWriter::h__Writer::WriteAncillaryResource(const ASDCP::TimedText::FrameBuffer& FrameBuf, + ASDCP::AESEncContext* Ctx, ASDCP::HMACContext* HMAC) +{ + if ( ! m_State.Test_RUNNING() ) + return RESULT_STATE; + + Kumu::fpos_t here = m_File.Tell(); + assert(m_Dict); + + // create generic stream partition header + static UL GenericStream_DataElement(m_Dict->ul(MDD_GenericStream_DataElement)); + MXF::Partition GSPart(m_Dict); + + GSPart.ThisPartition = here; + GSPart.PreviousPartition = m_HeaderPart.m_RIP.PairArray.back().ByteOffset; + GSPart.BodySID = m_EssenceStreamID; + GSPart.OperationalPattern = m_HeaderPart.OperationalPattern; + + m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(m_EssenceStreamID++, here)); + GSPart.EssenceContainers.push_back(UL(m_Dict->ul(MDD_TimedTextEssence))); + UL TmpUL(m_Dict->ul(MDD_GenericStreamPartition)); + Result_t result = GSPart.WriteToFile(m_File, TmpUL); + + if ( ASDCP_SUCCESS(result) ) + result = WriteEKLVPacket(FrameBuf, GenericStream_DataElement.Value(), Ctx, HMAC); + + m_FramesWritten++; + return result; +} + +// +ASDCP::Result_t +ASDCP::TimedText::MXFWriter::h__Writer::Finalize() +{ + if ( ! m_State.Test_RUNNING() ) + return RESULT_STATE; + + m_FramesWritten = m_TDesc.ContainerDuration; + m_State.Goto_FINAL(); + + return WriteMXFFooter(); +} + + +//------------------------------------------------------------------------------------------ + +ASDCP::TimedText::MXFWriter::MXFWriter() +{ +} + +ASDCP::TimedText::MXFWriter::~MXFWriter() +{ +} + +// Warning: direct manipulation of MXF structures can interfere +// with the normal operation of the wrapper. Caveat emptor! +// +ASDCP::MXF::OPAtomHeader& +ASDCP::TimedText::MXFWriter::OPAtomHeader() +{ + if ( m_Writer.empty() ) + { + assert(g_OPAtomHeader); + return *g_OPAtomHeader; + } + + return m_Writer->m_HeaderPart; +} + +// Warning: direct manipulation of MXF structures can interfere +// with the normal operation of the wrapper. Caveat emptor! +// +ASDCP::MXF::OPAtomIndexFooter& +ASDCP::TimedText::MXFWriter::OPAtomIndexFooter() +{ + if ( m_Writer.empty() ) + { + assert(g_OPAtomIndexFooter); + return *g_OPAtomIndexFooter; + } + + return m_Writer->m_FooterPart; +} + +// Open the file for writing. The file must not exist. Returns error if +// the operation cannot be completed. +ASDCP::Result_t +ASDCP::TimedText::MXFWriter::OpenWrite(const char* filename, const WriterInfo& Info, + const TimedTextDescriptor& TDesc, ui32_t HeaderSize) +{ + if ( Info.LabelSetType != LS_MXF_SMPTE ) + { + DefaultLogSink().Error("Timed Text support requires LS_MXF_SMPTE\n"); + return RESULT_FORMAT; + } + + m_Writer = new h__Writer(DefaultSMPTEDict()); + m_Writer->m_Info = Info; + + Result_t result = m_Writer->OpenWrite(filename, HeaderSize); + + if ( ASDCP_SUCCESS(result) ) + result = m_Writer->SetSourceStream(TDesc); + + if ( ASDCP_FAILURE(result) ) + m_Writer.release(); + + return result; +} + +// +ASDCP::Result_t +ASDCP::TimedText::MXFWriter::WriteTimedTextResource(const std::string& XMLDoc, AESEncContext* Ctx, HMACContext* HMAC) +{ + if ( m_Writer.empty() ) + return RESULT_INIT; + + return m_Writer->WriteTimedTextResource(XMLDoc, Ctx, HMAC); +} + +// +ASDCP::Result_t +ASDCP::TimedText::MXFWriter::WriteAncillaryResource(const FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC) +{ + if ( m_Writer.empty() ) + return RESULT_INIT; + + return m_Writer->WriteAncillaryResource(FrameBuf, Ctx, HMAC); +} + +// Closes the MXF file, writing the index and other closing information. +ASDCP::Result_t +ASDCP::TimedText::MXFWriter::Finalize() +{ + if ( m_Writer.empty() ) + return RESULT_INIT; + + return m_Writer->Finalize(); +} + + + +// +// end AS_DCP_timedText.cpp +// diff --git a/asdcplib/src/AS_DCP_internal.h b/asdcplib/src/AS_DCP_internal.h new file mode 100755 index 0000000..73106a2 --- /dev/null +++ b/asdcplib/src/AS_DCP_internal.h @@ -0,0 +1,274 @@ +/* +Copyright (c) 2004-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_internal.h + \version $Id: AS_DCP_internal.h,v 1.27 2012/02/07 18:54:25 jhurst Exp $ + \brief AS-DCP library, non-public common elements +*/ + +#ifndef _AS_DCP_INTERNAL_H_ +#define _AS_DCP_INTERNAL_H_ + +#include <KM_platform.h> +#include <KM_util.h> +#include <KM_log.h> +#include "Metadata.h" + +using Kumu::DefaultLogSink; +// using namespace std; +using namespace ASDCP; +using namespace ASDCP::MXF; + +#ifdef DEFAULT_MD_DECL +ASDCP::MXF::OPAtomHeader *g_OPAtomHeader; +ASDCP::MXF::OPAtomIndexFooter *g_OPAtomIndexFooter; +#else +extern MXF::OPAtomHeader *g_OPAtomHeader; +extern MXF::OPAtomIndexFooter *g_OPAtomIndexFooter; +#endif + + +namespace ASDCP +{ + void default_md_object_init(); + + + // constant values used to calculate KLV and EKLV packet sizes + static const ui32_t klv_cryptinfo_size = + MXF_BER_LENGTH + + UUIDlen /* ContextID */ + + MXF_BER_LENGTH + + sizeof(ui64_t) /* PlaintextOffset */ + + MXF_BER_LENGTH + + SMPTE_UL_LENGTH /* SourceKey */ + + MXF_BER_LENGTH + + sizeof(ui64_t) /* SourceLength */ + + MXF_BER_LENGTH /* ESV length */ ; + + static const ui32_t klv_intpack_size = + MXF_BER_LENGTH + + UUIDlen /* TrackFileID */ + + MXF_BER_LENGTH + + sizeof(ui64_t) /* SequenceNumber */ + + MXF_BER_LENGTH + + 20; /* HMAC length*/ + + // calculate size of encrypted essence with IV, CheckValue, and padding + inline ui32_t + calc_esv_length(ui32_t source_length, ui32_t plaintext_offset) + { + ui32_t ct_size = source_length - plaintext_offset; + ui32_t diff = ct_size % CBC_BLOCK_SIZE; + ui32_t block_size = ct_size - diff; + return plaintext_offset + block_size + (CBC_BLOCK_SIZE * 3); + } + + // the check value for EKLV packets + // CHUKCHUKCHUKCHUK + static const byte_t ESV_CheckValue[CBC_BLOCK_SIZE] = + { 0x43, 0x48, 0x55, 0x4b, 0x43, 0x48, 0x55, 0x4b, + 0x43, 0x48, 0x55, 0x4b, 0x43, 0x48, 0x55, 0x4b }; + + //------------------------------------------------------------------------------------------ + // + + Result_t MD_to_WriterInfo(MXF::Identification*, WriterInfo&); + Result_t MD_to_CryptoInfo(MXF::CryptographicContext*, WriterInfo&, const Dictionary&); + Result_t EncryptFrameBuffer(const ASDCP::FrameBuffer&, ASDCP::FrameBuffer&, AESEncContext*); + Result_t DecryptFrameBuffer(const ASDCP::FrameBuffer&, ASDCP::FrameBuffer&, AESDecContext*); + + // + class KLReader : public ASDCP::KLVPacket + { + ASDCP_NO_COPY_CONSTRUCT(KLReader); + byte_t m_KeyBuf[SMPTE_UL_LENGTH*2]; + + public: + KLReader() {} + ~KLReader() {} + + inline byte_t* Key() { return m_KeyBuf; } + inline ui64_t Length() { return m_ValueLength; } + inline ui64_t KLLength() { return m_KLLength; } + + Result_t ReadKLFromFile(Kumu::FileReader& Reader); + }; + + // + class h__Reader + { + ASDCP_NO_COPY_CONSTRUCT(h__Reader); + h__Reader(); + + public: + const Dictionary* m_Dict; + Kumu::FileReader m_File; + OPAtomHeader m_HeaderPart; + Partition m_BodyPart; + OPAtomIndexFooter m_FooterPart; + ui64_t m_EssenceStart; + WriterInfo m_Info; + ASDCP::FrameBuffer m_CtFrameBuf; + Kumu::fpos_t m_LastPosition; + + h__Reader(const Dictionary&); + virtual ~h__Reader(); + + Result_t InitInfo(); + Result_t OpenMXFRead(const char* filename); + Result_t InitMXFIndex(); + + // positions file before reading + Result_t ReadEKLVFrame(ui32_t FrameNum, ASDCP::FrameBuffer& FrameBuf, + const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC); + + // reads from current position + Result_t ReadEKLVPacket(ui32_t FrameNum, ui32_t SequenceNum, ASDCP::FrameBuffer& FrameBuf, + const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC); + void Close(); + }; + + + // state machine for mxf writer + enum WriterState_t { + ST_BEGIN, // waiting for Open() + ST_INIT, // waiting for SetSourceStream() + ST_READY, // ready to write frames + ST_RUNNING, // one or more frames written + ST_FINAL, // index written, file closed + }; + + // implementation of h__WriterState class Goto_* methods +#define Goto_body(s1,s2) if ( m_State != (s1) ) \ + return RESULT_STATE; \ + m_State = (s2); \ + return RESULT_OK + // + class h__WriterState + { + ASDCP_NO_COPY_CONSTRUCT(h__WriterState); + + public: + WriterState_t m_State; + h__WriterState() : m_State(ST_BEGIN) {} + ~h__WriterState() {} + + inline bool Test_BEGIN() { return m_State == ST_BEGIN; } + inline bool Test_INIT() { return m_State == ST_INIT; } + inline bool Test_READY() { return m_State == ST_READY;} + inline bool Test_RUNNING() { return m_State == ST_RUNNING; } + inline bool Test_FINAL() { return m_State == ST_FINAL; } + inline Result_t Goto_INIT() { Goto_body(ST_BEGIN, ST_INIT); } + inline Result_t Goto_READY() { Goto_body(ST_INIT, ST_READY); } + inline Result_t Goto_RUNNING() { Goto_body(ST_READY, ST_RUNNING); } + inline Result_t Goto_FINAL() { Goto_body(ST_RUNNING, ST_FINAL); } + }; + + typedef std::list<ui64_t*> DurationElementList_t; + + // + class h__Writer + { + ASDCP_NO_COPY_CONSTRUCT(h__Writer); + h__Writer(); + + public: + const Dictionary* m_Dict; + Kumu::FileWriter m_File; + ui32_t m_HeaderSize; + OPAtomHeader m_HeaderPart; + Partition m_BodyPart; + OPAtomIndexFooter m_FooterPart; + ui64_t m_EssenceStart; + + MaterialPackage* m_MaterialPackage; + SourcePackage* m_FilePackage; + + FileDescriptor* m_EssenceDescriptor; + std::list<InterchangeObject*> m_EssenceSubDescriptorList; + + ui32_t m_FramesWritten; + ui64_t m_StreamOffset; + ASDCP::FrameBuffer m_CtFrameBuf; + h__WriterState m_State; + WriterInfo m_Info; + DurationElementList_t m_DurationUpdateList; + + h__Writer(const Dictionary&); + virtual ~h__Writer(); + + void InitHeader(); + void AddSourceClip(const MXF::Rational& EditRate, ui32_t TCFrameRate, + const std::string& TrackName, const UL& EssenceUL, + const UL& DataDefinition, const std::string& PackageLabel); + void AddDMSegment(const MXF::Rational& EditRate, ui32_t TCFrameRate, + const std::string& TrackName, const UL& DataDefinition, + const std::string& PackageLabel); + void AddEssenceDescriptor(const UL& WrappingUL); + Result_t CreateBodyPart(const MXF::Rational& EditRate, ui32_t BytesPerEditUnit = 0); + + // all the above for a single source clip + Result_t WriteMXFHeader(const std::string& PackageLabel, const UL& WrappingUL, + const std::string& TrackName, const UL& EssenceUL, + const UL& DataDefinition, const MXF::Rational& EditRate, + ui32_t TCFrameRate, ui32_t BytesPerEditUnit = 0); + + Result_t WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf, + const byte_t* EssenceUL, AESEncContext* Ctx, HMACContext* HMAC, std::string* hash = 0); + + Result_t FakeWriteEKLVPacket(int size); + + Result_t WriteMXFFooter(); + + }; + + + // helper class for calculating Integrity Packs, used by WriteEKLVPacket() below. + // + class IntegrityPack + { + public: + byte_t Data[klv_intpack_size]; + + IntegrityPack() { + memset(Data, 0, klv_intpack_size); + } + + ~IntegrityPack() {} + + Result_t CalcValues(const ASDCP::FrameBuffer&, byte_t* AssetID, ui32_t sequence, HMACContext* HMAC); + Result_t TestValues(const ASDCP::FrameBuffer&, byte_t* AssetID, ui32_t sequence, HMACContext* HMAC); + }; + + +} // namespace ASDCP + +#endif // _AS_DCP_INTERNAL_H_ + + +// +// end AS_DCP_internal.h +// diff --git a/asdcplib/src/Dict.cpp b/asdcplib/src/Dict.cpp new file mode 100755 index 0000000..c046aa7 --- /dev/null +++ b/asdcplib/src/Dict.cpp @@ -0,0 +1,321 @@ +/* +Copyright (c) 2006-2009, 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 Dict.cpp + \version $Id: Dict.cpp,v 1.15 2012/02/08 02:59:21 jhurst Exp $ + \brief MXF dictionary +*/ + + +#include "KM_mutex.h" +#include "KM_log.h" +#include "KLV.h" +#include "MDD.cpp" + +//------------------------------------------------------------------------------------------ + +// The composite dict is the union of the SMPTE and Interop dicts +// +static ASDCP::Dictionary s_CompositeDict; +static Kumu::Mutex s_CompositeDictLock; +static bool s_CompositeDictInit = false; + +// +const ASDCP::Dictionary& +ASDCP::DefaultCompositeDict() +{ + if ( ! s_CompositeDictInit ) + { + Kumu::AutoMutex AL(s_CompositeDictLock); + + if ( ! s_CompositeDictInit ) + { + s_CompositeDict.Init(); + s_CompositeDictInit = true; + } + } + + return s_CompositeDict; +} + +// +// +static ASDCP::Dictionary s_InteropDict; +static Kumu::Mutex s_InteropDictLock; +static bool s_InteropDictInit = false; + +// +const ASDCP::Dictionary& +ASDCP::DefaultInteropDict() +{ + if ( ! s_InteropDictInit ) + { + Kumu::AutoMutex AL(s_InteropDictLock); + + if ( ! s_InteropDictInit ) + { + s_InteropDict.Init(); + + s_InteropDict.DeleteEntry(MDD_MXFInterop_OPAtom); + s_InteropDict.DeleteEntry(MDD_MXFInterop_CryptEssence); + s_InteropDict.DeleteEntry(MDD_MXFInterop_GenericDescriptor_SubDescriptors); + + s_InteropDict.AddEntry(s_MDD_Table[MDD_MXFInterop_OPAtom], MDD_OPAtom); + s_InteropDict.AddEntry(s_MDD_Table[MDD_MXFInterop_CryptEssence], MDD_CryptEssence); + s_InteropDict.AddEntry(s_MDD_Table[MDD_MXFInterop_GenericDescriptor_SubDescriptors], + MDD_GenericDescriptor_SubDescriptors); + + s_InteropDictInit = true; + } + } + + return s_InteropDict; +} + +// +// +static ASDCP::Dictionary s_SMPTEDict; +static Kumu::Mutex s_SMPTEDictLock; +static bool s_SMPTEDictInit = false; + +// +const ASDCP::Dictionary& +ASDCP::DefaultSMPTEDict() +{ + if ( ! s_SMPTEDictInit ) + { + Kumu::AutoMutex AL(s_SMPTEDictLock); + + if ( ! s_SMPTEDictInit ) + { + s_SMPTEDict.Init(); + + s_SMPTEDict.DeleteEntry(MDD_MXFInterop_OPAtom); + s_SMPTEDict.DeleteEntry(MDD_MXFInterop_CryptEssence); + s_SMPTEDict.DeleteEntry(MDD_MXFInterop_GenericDescriptor_SubDescriptors); + + s_SMPTEDictInit = true; + } + } + + return s_SMPTEDict; +} + +// +const ASDCP::MDDEntry& +ASDCP::MXFInterop_OPAtom_Entry() { + return s_MDD_Table[MDD_MXFInterop_OPAtom]; +} + +// +const ASDCP::MDDEntry& +ASDCP::SMPTE_390_OPAtom_Entry() { + return s_MDD_Table[MDD_OPAtom]; +} + + +//------------------------------------------------------------------------------------------ +// + +ASDCP::Dictionary::Dictionary() {} +ASDCP::Dictionary::~Dictionary() {} + +// +void +ASDCP::Dictionary::Init() +{ + m_md_lookup.clear(); + memset(m_MDD_Table, 0, sizeof(m_MDD_Table)); + + for ( ui32_t x = 0; x < (ui32_t)ASDCP::MDD_Max; x++ ) + { + if ( x == MDD_PartitionMetadata_IndexSID_DEPRECATED // 30 + || x == MDD_PartitionMetadata_BodySID_DEPRECATED // 32 + || x == MDD_PartitionMetadata_EssenceContainers_DEPRECATED // 34 + || x == MDD_IndexTableSegmentBase_IndexSID_DEPRECATED // 56 + || x == MDD_IndexTableSegmentBase_BodySID_DEPRECATED // 57 + || x == MDD_PartitionArray_RandomIndexMetadata_BodySID_DEPRECATED // 73 + || x == MDD_Preface_EssenceContainers_DEPRECATED // 85 + || x == MDD_EssenceContainerData_IndexSID_DEPRECATED // 103 + || x == MDD_EssenceContainerData_BodySID_DEPRECATED // 104 + || x == MDD_DMSegment_DataDefinition_DEPRECATED // 266 + || x == MDD_DMSegment_Duration_DEPRECATED // 267 + || x == MDD_PartitionMetadata_OperationalPattern_DEPRECATED // 33 + || x == MDD_Preface_OperationalPattern_DEPRECATED // 84 + || x == MDD_TimedTextResourceSubDescriptor_EssenceStreamID_DEPRECATED // 264 + ) + continue; + + AddEntry(s_MDD_Table[x], x); + } +} + +// +bool +ASDCP::Dictionary::AddEntry(const MDDEntry& Entry, ui32_t index) +{ + if ( index >= (ui32_t)MDD_Max ) + { + Kumu::DefaultLogSink().Warn("UL Dictionary: index exceeds maximum: %d\n", index); + return false; + } + + bool result = true; + // is this index already there? + std::map<ui32_t, ASDCP::UL>::iterator rii = m_md_rev_lookup.find(index); + + if ( rii != m_md_rev_lookup.end() ) + { + DeleteEntry(index); + result = false; + } + + UL TmpUL(Entry.ul); + +#ifdef MDD_AUTHORING_MODE + char buf[64]; + std::map<ASDCP::UL, ui32_t>::iterator ii = m_md_lookup.find(TmpUL); + if ( ii != m_md_lookup.end() ) + { + fprintf(stderr, "DUPE! %s (%02x, %02x) %s | (%02x, %02x) %s\n", + TmpUL.EncodeString(buf, 64), + m_MDD_Table[ii->second].tag.a, m_MDD_Table[ii->second].tag.b, + m_MDD_Table[ii->second].name, + Entry.tag.a, Entry.tag.b, Entry.name); + } +#endif + + m_md_lookup.insert(std::map<UL, ui32_t>::value_type(TmpUL, index)); + m_md_rev_lookup.insert(std::map<ui32_t, UL>::value_type(index, TmpUL)); + m_md_sym_lookup.insert(std::map<std::string, ui32_t>::value_type(Entry.name, index)); + m_MDD_Table[index] = Entry; + + return result; +} + +// +bool +ASDCP::Dictionary::DeleteEntry(ui32_t index) +{ + std::map<ui32_t, ASDCP::UL>::iterator rii = m_md_rev_lookup.find(index); + if ( rii != m_md_rev_lookup.end() ) + { + std::map<ASDCP::UL, ui32_t>::iterator ii = m_md_lookup.find(rii->second); + assert(ii != m_md_lookup.end()); + + MDDEntry NilEntry; + memset(&NilEntry, 0, sizeof(NilEntry)); + + m_md_lookup.erase(ii); + m_md_rev_lookup.erase(rii); + m_MDD_Table[index] = NilEntry; + return true; + } + + return false; +} + +// +const ASDCP::MDDEntry& +ASDCP::Dictionary::Type(MDD_t type_id) const +{ + assert(m_MDD_Table[0].name[0]); + std::map<ui32_t, ASDCP::UL>::const_iterator rii = m_md_rev_lookup.find(type_id); + + if ( rii == m_md_rev_lookup.end() ) + Kumu::DefaultLogSink().Warn("UL Dictionary: unknown UL type_id: %d\n", type_id); + + return m_MDD_Table[type_id]; +} + +// +const ASDCP::MDDEntry* +ASDCP::Dictionary::FindUL(const byte_t* ul_buf) const +{ + assert(m_MDD_Table[0].name[0]); + std::map<UL, ui32_t>::const_iterator i = m_md_lookup.find(UL(ul_buf)); + + if ( i == m_md_lookup.end() ) + { + byte_t tmp_ul[SMPTE_UL_LENGTH]; + memcpy(tmp_ul, ul_buf, SMPTE_UL_LENGTH); + tmp_ul[SMPTE_UL_LENGTH-1] = 0; + + i = m_md_lookup.find(UL(tmp_ul)); + + if ( i == m_md_lookup.end() ) + { + char buf[64]; + UL TmpUL(ul_buf); + Kumu::DefaultLogSink().Warn("UL Dictionary: unknown UL: %s\n", TmpUL.EncodeString(buf, 64)); + return 0; + } + } + + return &m_MDD_Table[i->second]; +} + +// +const ASDCP::MDDEntry* +ASDCP::Dictionary::FindSymbol(const std::string& str) const +{ + assert(m_MDD_Table[0].name[0]); + std::map<std::string, ui32_t>::const_iterator i = m_md_sym_lookup.find(str); + + if ( i == m_md_sym_lookup.end() ) + { + Kumu::DefaultLogSink().Warn("UL Dictionary: unknown symbol: %s\n", str.c_str()); + return 0; + } + + return &m_MDD_Table[i->second]; +} + +// +void +ASDCP::Dictionary::Dump(FILE* stream) const +{ + if ( stream == 0 ) + stream = stderr; + + MDD_t di = (MDD_t)0; + char str_buf[64]; + + while ( di < MDD_Max ) + { + if ( m_MDD_Table[di].name != 0 ) + { + UL TmpUL(m_MDD_Table[di].ul); + fprintf(stream, "%s: %s\n", TmpUL.EncodeString(str_buf, 64), m_MDD_Table[di].name); + } + + di = (MDD_t)(di + 1); + } +} + +// +// end Dict.cpp +// diff --git a/asdcplib/src/Index.cpp b/asdcplib/src/Index.cpp new file mode 100755 index 0000000..702b185 --- /dev/null +++ b/asdcplib/src/Index.cpp @@ -0,0 +1,243 @@ +/* +Copyright (c) 2005-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 Index.cpp + \version $Id: Index.cpp,v 1.21 2012/02/03 19:49:56 jhurst Exp $ + \brief MXF index segment objects +*/ + +#include "MXF.h" +const ui32_t kl_length = ASDCP::SMPTE_UL_LENGTH + ASDCP::MXF_BER_LENGTH; + + +// +ASDCP::MXF::IndexTableSegment::IndexTableSegment(const Dictionary*& d) : + InterchangeObject(d), m_Dict(d), + IndexStartPosition(0), IndexDuration(0), EditUnitByteCount(0), + IndexSID(129), BodySID(1), SliceCount(0), PosTableCount(0) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_IndexTableSegment); +} + +// +ASDCP::MXF::IndexTableSegment::~IndexTableSegment() +{ +} + +// +void +ASDCP::MXF::IndexTableSegment::Copy(const IndexTableSegment& rhs) +{ + InterchangeObject::Copy(rhs); + IndexEditRate = rhs.IndexEditRate; + IndexStartPosition = rhs.IndexStartPosition; + IndexDuration = rhs.IndexDuration; + EditUnitByteCount = rhs.EditUnitByteCount; + IndexSID = rhs.IndexSID; + BodySID = rhs.BodySID; + SliceCount = rhs.SliceCount; + PosTableCount = rhs.PosTableCount; + DeltaEntryArray = rhs.DeltaEntryArray; + IndexEntryArray = rhs.IndexEntryArray; +} + +// +ASDCP::Result_t +ASDCP::MXF::IndexTableSegment::InitFromTLVSet(TLVReader& TLVSet) +{ + Result_t result = InterchangeObject::InitFromTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(IndexTableSegmentBase, IndexEditRate)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi64(OBJ_READ_ARGS(IndexTableSegmentBase, IndexStartPosition)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi64(OBJ_READ_ARGS(IndexTableSegmentBase, IndexDuration)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(IndexTableSegmentBase, EditUnitByteCount)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(IndexTableSegmentBase, IndexSID)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(EssenceContainerData, BodySID)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi8(OBJ_READ_ARGS(IndexTableSegmentBase, SliceCount)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi8(OBJ_READ_ARGS(IndexTableSegmentBase, PosTableCount)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(IndexTableSegment, DeltaEntryArray)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(IndexTableSegment, IndexEntryArray)); + return result; +} + +// +ASDCP::Result_t +ASDCP::MXF::IndexTableSegment::WriteToTLVSet(TLVWriter& TLVSet) +{ + Result_t result = InterchangeObject::WriteToTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(IndexTableSegmentBase, IndexEditRate)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi64(OBJ_WRITE_ARGS(IndexTableSegmentBase, IndexStartPosition)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi64(OBJ_WRITE_ARGS(IndexTableSegmentBase, IndexDuration)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(IndexTableSegmentBase, EditUnitByteCount)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(IndexTableSegmentBase, IndexSID)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(EssenceContainerData, BodySID)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi8(OBJ_WRITE_ARGS(IndexTableSegmentBase, SliceCount)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi8(OBJ_WRITE_ARGS(IndexTableSegmentBase, PosTableCount)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(IndexTableSegment, DeltaEntryArray)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(IndexTableSegment, IndexEntryArray)); + return result; +} + +// +ASDCP::Result_t +ASDCP::MXF::IndexTableSegment::InitFromBuffer(const byte_t* p, ui32_t l) +{ + return InterchangeObject::InitFromBuffer(p, l); +} + +// +ASDCP::Result_t +ASDCP::MXF::IndexTableSegment::WriteToBuffer(ASDCP::FrameBuffer& Buffer) +{ + return InterchangeObject::WriteToBuffer(Buffer); +} + +// +void +ASDCP::MXF::IndexTableSegment::Dump(FILE* stream) +{ + char identbuf[IdentBufferLen]; + + if ( stream == 0 ) + stream = stderr; + + InterchangeObject::Dump(stream); + fprintf(stream, " IndexEditRate = %s\n", IndexEditRate.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " IndexStartPosition = %s\n", i64sz(IndexStartPosition, identbuf)); + fprintf(stream, " IndexDuration = %s\n", i64sz(IndexDuration, identbuf)); + fprintf(stream, " EditUnitByteCount = %u\n", EditUnitByteCount); + fprintf(stream, " IndexSID = %u\n", IndexSID); + fprintf(stream, " BodySID = %u\n", BodySID); + fprintf(stream, " SliceCount = %hu\n", SliceCount); + fprintf(stream, " PosTableCount = %hu\n", PosTableCount); + + fprintf(stream, " DeltaEntryArray:\n"); DeltaEntryArray.Dump(stream); + + if ( IndexEntryArray.size() < 100 ) + { + fprintf(stream, " IndexEntryArray:\n"); + IndexEntryArray.Dump(stream); + } + else + { + fprintf(stream, " IndexEntryArray: %zu entries\n", IndexEntryArray.size()); + } +} + +//------------------------------------------------------------------------------------------ +// + +// +const char* +ASDCP::MXF::IndexTableSegment::DeltaEntry::EncodeString(char* str_buf, ui32_t buf_len) const +{ + snprintf(str_buf, buf_len, "%3d %-3hu %-3u", PosTableIndex, Slice, ElementData); + return str_buf; +} + +// +bool +ASDCP::MXF::IndexTableSegment::DeltaEntry::Unarchive(Kumu::MemIOReader* Reader) +{ + if ( ! Reader->ReadUi8((ui8_t*)&PosTableIndex) ) return false; + if ( ! Reader->ReadUi8(&Slice) ) return false; + if ( ! Reader->ReadUi32BE(&ElementData) ) return false; + return true; +} + +// +bool +ASDCP::MXF::IndexTableSegment::DeltaEntry::Archive(Kumu::MemIOWriter* Writer) const +{ + if ( ! Writer->WriteUi8((ui8_t)PosTableIndex) ) return false; + if ( ! Writer->WriteUi8(Slice) ) return false; + if ( ! Writer->WriteUi32BE(ElementData) ) return false; + return true; +} + +//------------------------------------------------------------------------------------------ +// + +// Flags: +// Bit 7: Random Access +// Bit 6: Sequence Header +// Bit 5: forward prediction flag +// Bit 4: backward prediction flag +// e.g. +// 00== I frame (no prediction) +// 10== P frame(forward prediction from previous frame) +// 01== B frame (backward prediction from future frame) +// 11== B frame (forward & backward prediction) +// Bits 0-3: reserved [RP210 Flags to indicate coding of elements in this edit unit] + +// +const char* +ASDCP::MXF::IndexTableSegment::IndexEntry::EncodeString(char* str_buf, ui32_t buf_len) const +{ + char intbuf[IntBufferLen]; + char txt_flags[6]; + + txt_flags[0] = ( (Flags & 0x80) != 0 ) ? 'r' : ' '; + txt_flags[1] = ( (Flags & 0x40) != 0 ) ? 's' : ' '; + txt_flags[2] = ( (Flags & 0x20) != 0 ) ? 'f' : ' '; + txt_flags[3] = ( (Flags & 0x10) != 0 ) ? 'b' : ' '; + txt_flags[4] = ( (Flags & 0x0f) == 3 ) ? 'B' : ( (Flags & 0x0f) == 2 ) ? 'P' : 'I'; + txt_flags[5] = 0; + + snprintf(str_buf, buf_len, "%3i %-3hu %s %s", + TemporalOffset, KeyFrameOffset, txt_flags, + i64sz(StreamOffset, intbuf)); + + return str_buf; +} + +// +bool +ASDCP::MXF::IndexTableSegment::IndexEntry::Unarchive(Kumu::MemIOReader* Reader) +{ + if ( ! Reader->ReadUi8((ui8_t*)&TemporalOffset) ) return false; + if ( ! Reader->ReadUi8((ui8_t*)&KeyFrameOffset) ) return false; + if ( ! Reader->ReadUi8(&Flags) ) return false; + if ( ! Reader->ReadUi64BE(&StreamOffset) ) return false; + return true; +} + +// +bool +ASDCP::MXF::IndexTableSegment::IndexEntry::Archive(Kumu::MemIOWriter* Writer) const +{ + if ( ! Writer->WriteUi8((ui8_t)TemporalOffset) ) return false; + if ( ! Writer->WriteUi8((ui8_t)KeyFrameOffset) ) return false; + if ( ! Writer->WriteUi8(Flags) ) return false; + if ( ! Writer->WriteUi64BE(StreamOffset) ) return false; + return true; +} + + +// +// end Index.cpp +// + diff --git a/asdcplib/src/JP2K.cpp b/asdcplib/src/JP2K.cpp new file mode 100755 index 0000000..4cc0e50 --- /dev/null +++ b/asdcplib/src/JP2K.cpp @@ -0,0 +1,224 @@ +/* +Copyright (c) 2005-2009, 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 JP2K.cpp + \version $Id: JP2K.cpp,v 1.8 2010/06/17 03:33:17 jhurst Exp $ + \brief JPEG 2000 parser implementation + + This is not a complete implementation of all things JP2K. There is just enough here to + support parsing picture metadata from a codestream header. +*/ + +#include <JP2K.h> +#include <KM_log.h> +using Kumu::DefaultLogSink; + + +// when indexed with the second byte of a marker code, this table will procuce one of +// two values: +// 0 - the marker is a standalone marker +// 1 - the marker designates a marker segment +// +const byte_t MarkerSegmentMap[] = + { + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 + /* 1 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1 + /* 2 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2 + /* 3 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3 + /* 4 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4 + /* 5 */ 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, // 5 + /* 6 */ 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6 + /* 7 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 7 + /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 + /* 9 */ 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9 + /* a */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // a + /* b */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // b + /* c */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // c + /* d */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // d + /* e */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // e + /* f */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // f + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + }; + + +// +ASDCP::Result_t +ASDCP::JP2K::GetNextMarker(const byte_t** buf, JP2K::Marker& Marker) +{ + assert((buf != 0) && (*buf != 0 )); + + if ( **buf != 0xff ) + return ASDCP::RESULT_FAIL; + + Marker.m_IsSegment = (MarkerSegmentMap[*(++(*buf))] == 1); + Marker.m_Type = (Marker_t)(0xff00 | *(*buf)++); + + if ( Marker.m_IsSegment ) + { + Marker.m_DataSize = *(*buf)++ << 8; + Marker.m_DataSize |= *(*buf)++; + Marker.m_DataSize -= 2; + Marker.m_Data = *buf; + *buf += Marker.m_DataSize; + } + + + if ( Marker.m_DataSize != 0 && Marker.m_DataSize < 3 ) + { + DefaultLogSink().Error("Illegal data size: %u\n", Marker.m_DataSize); + return ASDCP::RESULT_FAIL; + } + + return ASDCP::RESULT_OK; +} + + +//------------------------------------------------------------------------------------------------------- +// + +// +void +ASDCP::JP2K::Accessor::SIZ::ReadComponent(ui32_t index, ASDCP::JP2K::ImageComponent_t& IC) +{ + assert ( index < Csize() ); + const byte_t* p = m_MarkerData + 36 + (index * 3); + IC.Ssize = *p++; + IC.XRsize = *p++; + IC.YRsize = *p; +} + +// +void +ASDCP::JP2K::Accessor::SIZ::Dump(FILE* stream) +{ + if ( stream == 0 ) + stream = stderr; + + fprintf(stream, "SIZ: \n"); + fprintf(stream, " Rsize: %hu\n", Rsize()); + fprintf(stream, " Xsize: %u\n", Xsize()); + fprintf(stream, " Ysize: %u\n", Ysize()); + fprintf(stream, " XOsize: %u\n", XOsize()); + fprintf(stream, " YOsize: %u\n", YOsize()); + fprintf(stream, " XTsize: %u\n", XTsize()); + fprintf(stream, " YTsize: %u\n", YTsize()); + fprintf(stream, "XTOsize: %u\n", XTOsize()); + fprintf(stream, "YTOsize: %u\n", YTOsize()); + fprintf(stream, " Csize: %u\n", Csize()); + + if ( Csize() > 0 ) + { + fprintf(stream, "Components\n"); + + for ( ui32_t i = 0; i < Csize(); i++ ) + { + ImageComponent_t TmpComp; + ReadComponent(i, TmpComp); + fprintf(stream, "%u: ", i); + fprintf(stream, "%u, %u, %u\n", TmpComp.Ssize, TmpComp.XRsize, TmpComp.YRsize); + } + } +} + +// +void +ASDCP::JP2K::Accessor::COM::Dump(FILE* stream) +{ + if ( stream == 0 ) + stream = stderr; + + if ( IsText() ) + { + char* t_str = (char*)malloc(CommentSize() + 1); + assert( t_str != 0 ); + ui32_t cs = CommentSize(); + memcpy(t_str, CommentData(), cs); + t_str[cs] = 0; + fprintf(stream, "COM:%s\n", t_str); + } + else + { + fprintf(stream, "COM:\n"); + Kumu::hexdump(CommentData(), CommentSize(), stream); + } +} + + +//------------------------------------------------------------------------------------------------------- +// + + +// +void +ASDCP::JP2K::Marker::Dump(FILE* stream) const +{ + if ( stream == 0 ) + stream = stderr; + + fprintf(stream, "Marker%s 0x%04x: %s", (m_IsSegment ? " segment" : ""), m_Type, GetMarkerString(m_Type)); + + if ( m_IsSegment ) + fprintf(stream, ", 0x%0x bytes", m_DataSize); + + fputc('\n', stream); +} + +// +const char* +ASDCP::JP2K::GetMarkerString(Marker_t m) +{ + switch ( m ) + { + case MRK_NIL: return "NIL"; break; + case MRK_SOC: return "SOC: Start of codestream"; break; + case MRK_SOT: return "SOT: Start of tile-part"; break; + case MRK_SOD: return "SOD: Start of data"; break; + case MRK_EOC: return "EOC: End of codestream"; break; + case MRK_SIZ: return "SIZ: Image and tile size"; break; + case MRK_COD: return "COD: Coding style default"; break; + case MRK_COC: return "COC: Coding style component"; break; + case MRK_RGN: return "RGN: Region of interest"; break; + case MRK_QCD: return "QCD: Quantization default"; break; + case MRK_QCC: return "QCC: Quantization component"; break; + case MRK_POC: return "POC: Progression order change"; break; + case MRK_TLM: return "TLM: Tile-part lengths"; break; + case MRK_PLM: return "PLM: Packet length, main header"; break; + case MRK_PLT: return "PLT: Packet length, tile-part header"; break; + case MRK_PPM: return "PPM: Packed packet headers, main header"; break; + case MRK_PPT: return "PPT: Packed packet headers, tile-part header"; break; + case MRK_SOP: return "SOP: Start of packet"; break; + case MRK_EPH: return "EPH: End of packet header"; break; + case MRK_CRG: return "CRG: Component registration"; break; + case MRK_COM: return "COM: Comment"; break; + } + + return "Unknown marker code"; +} + +// +// end JP2K.cpp +// diff --git a/asdcplib/src/JP2K.h b/asdcplib/src/JP2K.h new file mode 100755 index 0000000..d30dbad --- /dev/null +++ b/asdcplib/src/JP2K.h @@ -0,0 +1,164 @@ +/* +Copyright (c) 2005-2009, 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 JP2K.h + \version $Id: JP2K.h,v 1.4 2009/04/09 19:24:14 msheby Exp $ + \brief JPEG 2000 constants and data structures + + This is not a complete enumeration of all things JP2K. There is just enough here to + support parsing picture metadata from a codestream header. +*/ + +#ifndef _JP2K_H_ +#define _JP2K_H_ + +// AS_DCP.h is included only for it's base type definitions. +#include <KM_platform.h> +#include <KM_util.h> +#include <AS_DCP.h> +#include <assert.h> + +namespace ASDCP +{ +namespace JP2K +{ + const byte_t Magic[] = {0xff, 0x4f, 0xff}; + + enum Marker_t + { + MRK_NIL = 0, + MRK_SOC = 0xff4f, // Start of codestream + MRK_SOT = 0xff90, // Start of tile-part + MRK_SOD = 0xff93, // Start of data + MRK_EOC = 0xffd9, // End of codestream + MRK_SIZ = 0xff51, // Image and tile size + MRK_COD = 0xff52, // Coding style default + MRK_COC = 0xff53, // Coding style component + MRK_RGN = 0xff5e, // Region of interest + MRK_QCD = 0xff5c, // Quantization default + MRK_QCC = 0xff5d, // Quantization component + MRK_POC = 0xff5f, // Progression order change + MRK_TLM = 0xff55, // Tile-part lengths + MRK_PLM = 0xff57, // Packet length, main header + MRK_PLT = 0xff58, // Packet length, tile-part header + MRK_PPM = 0xff60, // Packed packet headers, main header + MRK_PPT = 0xff61, // Packed packet headers, tile-part header + MRK_SOP = 0xff91, // Start of packet + MRK_EPH = 0xff92, // End of packet header + MRK_CRG = 0xff63, // Component registration + MRK_COM = 0xff64, // Comment + }; + + const char* GetMarkerString(Marker_t m); + + // + class Marker + { + KM_NO_COPY_CONSTRUCT(Marker); + + public: + Marker_t m_Type; + bool m_IsSegment; + ui32_t m_DataSize; + const byte_t* m_Data; + + Marker() : m_Type(MRK_NIL), m_IsSegment(false), m_DataSize(0), m_Data(0) {} + ~Marker() {} + + void Dump(FILE* stream = 0) const; + }; + + // + ASDCP::Result_t GetNextMarker(const byte_t**, Marker&); + + // accessor objects for marker segments + namespace Accessor + { + // image size + class SIZ + { + const byte_t* m_MarkerData; + KM_NO_COPY_CONSTRUCT(SIZ); + SIZ(); + + public: + SIZ(const Marker& M) + { + assert(M.m_Type == MRK_SIZ); + m_MarkerData = M.m_Data; + } + + ~SIZ() {} + + inline ui16_t Rsize() { return KM_i16_BE(*(ui16_t*)m_MarkerData); } + inline ui32_t Xsize() { return KM_i32_BE(*(ui32_t*)(m_MarkerData + 2)); } + inline ui32_t Ysize() { return KM_i32_BE(*(ui32_t*)(m_MarkerData + 6)); } + inline ui32_t XOsize() { return KM_i32_BE(*(ui32_t*)(m_MarkerData + 10)); } + inline ui32_t YOsize() { return KM_i32_BE(*(ui32_t*)(m_MarkerData + 14)); } + inline ui32_t XTsize() { return KM_i32_BE(*(ui32_t*)(m_MarkerData + 18)); } + inline ui32_t YTsize() { return KM_i32_BE(*(ui32_t*)(m_MarkerData + 22)); } + inline ui32_t XTOsize() { return KM_i32_BE(*(ui32_t*)(m_MarkerData + 26)); } + inline ui32_t YTOsize() { return KM_i32_BE(*(ui32_t*)(m_MarkerData + 30)); } + inline ui16_t Csize() { return KM_i16_BE(*(ui16_t*)(m_MarkerData + 34)); } + void ReadComponent(ui32_t index, ImageComponent_t& IC); + void Dump(FILE* stream = 0); + }; + + // a comment + class COM + { + bool m_IsText; + const byte_t* m_MarkerData; + ui32_t m_DataSize; + + KM_NO_COPY_CONSTRUCT(COM); + COM(); + + public: + COM(const Marker& M) + { + assert(M.m_Type == MRK_COM); + m_IsText = M.m_Data[1] == 1; + m_MarkerData = M.m_Data + 2; + m_DataSize = M.m_DataSize - 2; + } + + ~COM() {} + + inline bool IsText() { return m_IsText; } + inline const byte_t* CommentData() { return m_MarkerData; } + inline ui32_t CommentSize() { return m_DataSize; } + void Dump(FILE* stream = 0); + }; + } // namespace Accessor +} // namespace JP2K +} // namespace ASDCP + +#endif // _JP2K_H_ + +// +// end JP2K.h +// diff --git a/asdcplib/src/JP2K_Codestream_Parser.cpp b/asdcplib/src/JP2K_Codestream_Parser.cpp new file mode 100755 index 0000000..5ab7a32 --- /dev/null +++ b/asdcplib/src/JP2K_Codestream_Parser.cpp @@ -0,0 +1,270 @@ +/* +Copyright (c) 2004-2009, 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 Codestream_Parser.cpp + \version $Id: JP2K_Codestream_Parser.cpp,v 1.7 2009/04/09 19:16:49 msheby Exp $ + \brief AS-DCP library, JPEG 2000 codestream essence reader implementation +*/ + +#include <KM_fileio.h> +#include <AS_DCP.h> +#include <JP2K.h> +#include <assert.h> +#include <KM_log.h> +using Kumu::DefaultLogSink; + +//------------------------------------------------------------------------------------------ + +class ASDCP::JP2K::CodestreamParser::h__CodestreamParser +{ + ASDCP_NO_COPY_CONSTRUCT(h__CodestreamParser); + +public: + PictureDescriptor m_PDesc; + Kumu::FileReader m_File; + + h__CodestreamParser() + { + memset(&m_PDesc, 0, sizeof(m_PDesc)); + m_PDesc.EditRate = Rational(24,1); + m_PDesc.SampleRate = m_PDesc.EditRate; + } + + ~h__CodestreamParser() {} + + Result_t OpenReadFrame(const char* filename, FrameBuffer& FB) + { + ASDCP_TEST_NULL_STR(filename); + m_File.Close(); + Result_t result = m_File.OpenRead(filename); + + if ( ASDCP_SUCCESS(result) ) + { + Kumu::fsize_t file_size = m_File.Size(); + + if ( FB.Capacity() < file_size ) + { + DefaultLogSink().Error("FrameBuf.Capacity: %u frame length: %u\n", FB.Capacity(), (ui32_t)file_size); + return RESULT_SMALLBUF; + } + } + + ui32_t read_count; + + if ( ASDCP_SUCCESS(result) ) + result = m_File.Read(FB.Data(), FB.Capacity(), &read_count); + + if ( ASDCP_SUCCESS(result) ) + FB.Size(read_count); + + if ( ASDCP_SUCCESS(result) ) + { + byte_t start_of_data = 0; // out param + result = ParseMetadataIntoDesc(FB, m_PDesc, &start_of_data); + + if ( ASDCP_SUCCESS(result) ) + FB.PlaintextOffset(start_of_data); + } + + return result; + } + + Result_t OpenReadFrame(const unsigned char * data, unsigned int size, FrameBuffer& FB) + { + if ( FB.Capacity() < size ) + { + DefaultLogSink().Error("FrameBuf.Capacity: %u frame length: %u\n", FB.Capacity(), (ui32_t) size); + return RESULT_SMALLBUF; + } + + memcpy (FB.Data(), data, size); + FB.Size(size); + + byte_t start_of_data = 0; // out param + const Result_t result = ParseMetadataIntoDesc(FB, m_PDesc, &start_of_data); + + if ( ASDCP_SUCCESS(result) ) + FB.PlaintextOffset(start_of_data); + + return result; + } +}; + +ASDCP::Result_t +ASDCP::JP2K::ParseMetadataIntoDesc(const FrameBuffer& FB, PictureDescriptor& PDesc, byte_t* start_of_data) +{ + Result_t result = RESULT_OK; + Marker NextMarker; + ui32_t i; + const byte_t* p = FB.RoData(); + const byte_t* end_p = p + FB.Size(); + + while ( p < end_p && ASDCP_SUCCESS(result) ) + { + result = GetNextMarker(&p, NextMarker); + + if ( ASDCP_FAILURE(result) ) + { + result = RESULT_RAW_ESS; + break; + } + + switch ( NextMarker.m_Type ) + { + case MRK_SOD: + if ( start_of_data != 0 ) + *start_of_data = p - FB.RoData(); + + p = end_p; + break; + + case MRK_SIZ: + { + Accessor::SIZ SIZ_(NextMarker); + PDesc.StoredWidth = SIZ_.Xsize(); + PDesc.StoredHeight = SIZ_.Ysize(); + PDesc.AspectRatio = Rational(SIZ_.Xsize(), SIZ_.Ysize()); + PDesc.Rsize = SIZ_.Rsize(); + PDesc.Xsize = SIZ_.Xsize(); + PDesc.Ysize = SIZ_.Ysize(); + PDesc.XOsize = SIZ_.XOsize(); + PDesc.YOsize = SIZ_.YOsize(); + PDesc.XTsize = SIZ_.XTsize(); + PDesc.YTsize = SIZ_.YTsize(); + PDesc.XTOsize = SIZ_.XTOsize(); + PDesc.YTOsize = SIZ_.YTOsize(); + PDesc.Csize = SIZ_.Csize(); + + if ( PDesc.Csize != 3 ) + { + DefaultLogSink().Error("Unexpected number of components: %u\n", PDesc.Csize); + return RESULT_RAW_FORMAT; + } + + for ( i = 0; i < PDesc.Csize; i++ ) + SIZ_.ReadComponent(i, PDesc.ImageComponents[i]); + } + break; + + case MRK_COD: + memset(&PDesc.CodingStyleDefault, 0, sizeof(CodingStyleDefault_t)); + + if ( NextMarker.m_DataSize > sizeof(CodingStyleDefault_t) ) + { + DefaultLogSink().Error("Unexpectedly large CodingStyle data: %u\n", NextMarker.m_DataSize); + return RESULT_RAW_FORMAT; + } + + memcpy(&PDesc.CodingStyleDefault, NextMarker.m_Data, NextMarker.m_DataSize); + break; + + case MRK_QCD: + memset(&PDesc.QuantizationDefault, 0, sizeof(QuantizationDefault_t)); + + if ( NextMarker.m_DataSize < 16 ) + { + DefaultLogSink().Error("No quantization signaled\n"); + return RESULT_RAW_FORMAT; + } + + if ( NextMarker.m_DataSize > MaxDefaults ) + { + DefaultLogSink().Error("Quantization Default length exceeds maximum %d\n", NextMarker.m_DataSize); + return RESULT_RAW_FORMAT; + } + + memcpy(&PDesc.QuantizationDefault, NextMarker.m_Data, NextMarker.m_DataSize); + PDesc.QuantizationDefault.SPqcdLength = NextMarker.m_DataSize - 1; + break; + + case MRK_NIL: + case MRK_SOC: + case MRK_SOT: + case MRK_EOC: + case MRK_COC: + case MRK_RGN: + case MRK_QCC: + case MRK_POC: + case MRK_TLM: + case MRK_PLM: + case MRK_PLT: + case MRK_PPM: + case MRK_PPT: + case MRK_SOP: + case MRK_EPH: + case MRK_CRG: + case MRK_COM: + /* Keep gcc quiet */ + break; + } + } + + return result; +} + +//------------------------------------------------------------------------------------------ + +ASDCP::JP2K::CodestreamParser::CodestreamParser() +{ +} + +ASDCP::JP2K::CodestreamParser::~CodestreamParser() +{ +} + +// Opens the stream for reading, parses enough data to provide a complete +// set of stream metadata for the MXFWriter below. +ASDCP::Result_t +ASDCP::JP2K::CodestreamParser::OpenReadFrame(const char* filename, FrameBuffer& FB) const +{ + const_cast<ASDCP::JP2K::CodestreamParser*>(this)->m_Parser = new h__CodestreamParser; + return m_Parser->OpenReadFrame(filename, FB); +} + +// Opens the stream for reading, parses enough data to provide a complete +// set of stream metadata for the MXFWriter below. +ASDCP::Result_t +ASDCP::JP2K::CodestreamParser::OpenReadFrame(const unsigned char* data, unsigned int size, FrameBuffer& FB) const +{ + const_cast<ASDCP::JP2K::CodestreamParser*>(this)->m_Parser = new h__CodestreamParser; + return m_Parser->OpenReadFrame(data, size, FB); +} + +// +ASDCP::Result_t +ASDCP::JP2K::CodestreamParser::FillPictureDescriptor(PictureDescriptor& PDesc) const +{ + if ( m_Parser.empty() ) + return RESULT_INIT; + + PDesc = m_Parser->m_PDesc; + return RESULT_OK; +} + + +// +// end Codestream_Parser.cpp +// diff --git a/asdcplib/src/JP2K_Sequence_Parser.cpp b/asdcplib/src/JP2K_Sequence_Parser.cpp new file mode 100755 index 0000000..3b422d4 --- /dev/null +++ b/asdcplib/src/JP2K_Sequence_Parser.cpp @@ -0,0 +1,392 @@ +/* +Copyright (c) 2004-2011, 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 JP2K_Sequence_Parser.cpp + \version $Id: JP2K_Sequence_Parser.cpp,v 1.8 2011/05/13 01:50:19 jhurst Exp $ + \brief AS-DCP library, JPEG 2000 codestream essence reader implementation +*/ + +#include <AS_DCP.h> +#include <KM_fileio.h> +#include <KM_log.h> +#include <list> +#include <string> +#include <algorithm> +#include <string.h> +#include <assert.h> + +using namespace ASDCP; + + +//------------------------------------------------------------------------------------------ + +class FileList : public std::list<std::string> +{ + std::string m_DirName; + +public: + FileList() {} + ~FileList() {} + + const FileList& operator=(const std::list<std::string>& pathlist) { + std::list<std::string>::const_iterator i; + for ( i = pathlist.begin(); i != pathlist.end(); i++ ) + push_back(*i); + return *this; + } + + // + Result_t InitFromDirectory(const char* path) + { + char next_file[Kumu::MaxFilePath]; + Kumu::DirScanner Scanner; + + Result_t result = Scanner.Open(path); + + if ( ASDCP_SUCCESS(result) ) + { + m_DirName = path; + + while ( ASDCP_SUCCESS(Scanner.GetNext(next_file)) ) + { + if ( next_file[0] == '.' ) // no hidden files or internal links + continue; + + std::string Str(m_DirName); + Str += "/"; + Str += next_file; + + if ( ! Kumu::PathIsDirectory(Str) ) + push_back(Str); + } + + sort(); + } + + return result; + } +}; + +//------------------------------------------------------------------------------------------ + +class ASDCP::JP2K::SequenceParser::h__SequenceParser +{ + ui32_t m_FramesRead; + Rational m_PictureRate; + FileList m_FileList; + FileList::iterator m_CurrentFile; + CodestreamParser m_Parser; + bool m_Pedantic; + + Result_t OpenRead(); + + ASDCP_NO_COPY_CONSTRUCT(h__SequenceParser); + +public: + PictureDescriptor m_PDesc; + + h__SequenceParser() : m_FramesRead(0), m_Pedantic(false) + { + memset(&m_PDesc, 0, sizeof(m_PDesc)); + m_PDesc.EditRate = Rational(24,1); + } + + ~h__SequenceParser() + { + Close(); + } + + Result_t OpenRead(const char* filename, bool pedantic); + Result_t OpenRead(const std::list<std::string>& file_list, bool pedantic); + void Close() {} + + Result_t Reset() + { + m_FramesRead = 0; + m_CurrentFile = m_FileList.begin(); + return RESULT_OK; + } + + Result_t ReadFrame(FrameBuffer&); +}; + + +// +ASDCP::Result_t +ASDCP::JP2K::SequenceParser::h__SequenceParser::OpenRead() +{ + if ( m_FileList.empty() ) + return RESULT_ENDOFFILE; + + m_CurrentFile = m_FileList.begin(); + CodestreamParser Parser; + FrameBuffer TmpBuffer; + + Kumu::fsize_t file_size = Kumu::FileSize((*m_CurrentFile).c_str()); + + if ( file_size == 0 ) + return RESULT_NOT_FOUND; + + assert(file_size <= 0xFFFFFFFFL); + Result_t result = TmpBuffer.Capacity((ui32_t) file_size); + + if ( ASDCP_SUCCESS(result) ) + result = Parser.OpenReadFrame((*m_CurrentFile).c_str(), TmpBuffer); + + if ( ASDCP_SUCCESS(result) ) + result = Parser.FillPictureDescriptor(m_PDesc); + + // how big is it? + if ( ASDCP_SUCCESS(result) ) + m_PDesc.ContainerDuration = m_FileList.size(); + + return result; +} + +// +ASDCP::Result_t +ASDCP::JP2K::SequenceParser::h__SequenceParser::OpenRead(const char* filename, bool pedantic) +{ + ASDCP_TEST_NULL_STR(filename); + m_Pedantic = pedantic; + + Result_t result = m_FileList.InitFromDirectory(filename); + + if ( ASDCP_SUCCESS(result) ) + result = OpenRead(); + + return result; +} + + +// +ASDCP::Result_t +ASDCP::JP2K::SequenceParser::h__SequenceParser::OpenRead(const std::list<std::string>& file_list, bool pedantic) +{ + m_Pedantic = pedantic; + m_FileList = file_list; + return OpenRead(); +} + + +// +bool +operator==(const ASDCP::JP2K::ImageComponent_t& lhs, const ASDCP::JP2K::ImageComponent_t& rhs) +{ + if ( lhs.Ssize != rhs.Ssize ) return false; + if ( lhs.XRsize != rhs.XRsize ) return false; + if ( lhs.YRsize != rhs.YRsize ) return false; + return true; +} + +// +bool +operator==(const ASDCP::JP2K::QuantizationDefault_t& lhs, const ASDCP::JP2K::QuantizationDefault_t& rhs) +{ + if ( lhs.Sqcd != rhs.Sqcd ) return false; + if ( lhs.SPqcdLength != rhs.SPqcdLength ) return false; + + for ( ui32_t i = 0; i < JP2K::MaxDefaults; i++ ) + { + if ( lhs.SPqcd[i] != rhs.SPqcd[i] ) + return false; + } + + return true; +} + +// +bool +operator==(const ASDCP::JP2K::CodingStyleDefault_t& lhs, const ASDCP::JP2K::CodingStyleDefault_t& rhs) +{ + if ( lhs.Scod != rhs.Scod ) return false; + + // SGcod + if ( lhs.SGcod.ProgressionOrder != rhs.SGcod.ProgressionOrder ) return false; + if ( lhs.SGcod.MultiCompTransform != rhs.SGcod.MultiCompTransform ) return false; + + for ( ui32_t i = 0; i < sizeof(ui16_t); i++ ) + { + if ( lhs.SGcod.NumberOfLayers[i] != lhs.SGcod.NumberOfLayers[i] ) + return false; + } + + // SPcod + if ( lhs.SPcod.DecompositionLevels != rhs.SPcod.DecompositionLevels ) return false; + if ( lhs.SPcod.CodeblockWidth != rhs.SPcod.CodeblockWidth ) return false; + if ( lhs.SPcod.CodeblockHeight != rhs.SPcod.CodeblockHeight ) return false; + if ( lhs.SPcod.CodeblockStyle != rhs.SPcod.CodeblockStyle ) return false; + if ( lhs.SPcod.Transformation != rhs.SPcod.Transformation ) return false; + + for ( ui32_t i = 0; i < JP2K::MaxPrecincts; i++ ) + { + if ( lhs.SPcod.PrecinctSize[i] != rhs.SPcod.PrecinctSize[i] ) + return false; + } + + return true; +} + +// +bool +operator==(const ASDCP::JP2K::PictureDescriptor& lhs, const ASDCP::JP2K::PictureDescriptor& rhs) +{ + if ( lhs.EditRate != rhs.EditRate ) return false; + // if ( lhs.ContainerDuration != rhs.ContainerDuration ) return false; + if ( lhs.SampleRate != rhs.SampleRate ) return false; + if ( lhs.StoredWidth != rhs.StoredWidth ) return false; + if ( lhs.StoredHeight != rhs.StoredHeight ) return false; + if ( lhs.AspectRatio != rhs.AspectRatio ) return false; + if ( lhs.Rsize != rhs.Rsize ) return false; + if ( lhs.Xsize != rhs.Xsize ) return false; + if ( lhs.Ysize != rhs.Ysize ) return false; + if ( lhs.XOsize != rhs.XOsize ) return false; + if ( lhs.YOsize != rhs.YOsize ) return false; + if ( lhs.XTsize != rhs.XTsize ) return false; + if ( lhs.YTsize != rhs.YTsize ) return false; + if ( lhs.XTOsize != rhs.XTOsize ) return false; + if ( lhs.YTOsize != rhs.YTOsize ) return false; + if ( lhs.Csize != rhs.Csize ) return false; + if ( ! ( lhs.CodingStyleDefault == rhs.CodingStyleDefault ) ) return false; + if ( ! ( lhs.QuantizationDefault == rhs.QuantizationDefault ) ) return false; + + for ( ui32_t i = 0; i < JP2K::MaxComponents; i++ ) + { + if ( ! ( lhs.ImageComponents[i] == rhs.ImageComponents[i] ) ) + return false; + } + + return true; +} + +// +ASDCP::Result_t +ASDCP::JP2K::SequenceParser::h__SequenceParser::ReadFrame(FrameBuffer& FB) +{ + if ( m_CurrentFile == m_FileList.end() ) + return RESULT_ENDOFFILE; + + // open the file + Result_t result = m_Parser.OpenReadFrame((*m_CurrentFile).c_str(), FB); + + if ( ASDCP_SUCCESS(result) && m_Pedantic ) + { + PictureDescriptor PDesc; + result = m_Parser.FillPictureDescriptor(PDesc); + + if ( ASDCP_SUCCESS(result) && ! ( m_PDesc == PDesc ) ) + { + Kumu::DefaultLogSink().Error("JPEG-2000 codestream parameters do not match at frame %d\n", m_FramesRead + 1); + result = RESULT_RAW_FORMAT; + } + } + + if ( ASDCP_SUCCESS(result) ) + { + FB.FrameNumber(m_FramesRead++); + m_CurrentFile++; + } + + return result; +} + + +//------------------------------------------------------------------------------------------ + +ASDCP::JP2K::SequenceParser::SequenceParser() +{ +} + +ASDCP::JP2K::SequenceParser::~SequenceParser() +{ +} + +// Opens the stream for reading, parses enough data to provide a complete +// set of stream metadata for the MXFWriter below. +ASDCP::Result_t +ASDCP::JP2K::SequenceParser::OpenRead(const char* filename, bool pedantic) const +{ + const_cast<ASDCP::JP2K::SequenceParser*>(this)->m_Parser = new h__SequenceParser; + + Result_t result = m_Parser->OpenRead(filename, pedantic); + + if ( ASDCP_FAILURE(result) ) + const_cast<ASDCP::JP2K::SequenceParser*>(this)->m_Parser.release(); + + return result; +} + +// +Result_t +ASDCP::JP2K::SequenceParser::OpenRead(const std::list<std::string>& file_list, bool pedantic) const +{ + const_cast<ASDCP::JP2K::SequenceParser*>(this)->m_Parser = new h__SequenceParser; + + Result_t result = m_Parser->OpenRead(file_list, pedantic); + + if ( ASDCP_FAILURE(result) ) + const_cast<ASDCP::JP2K::SequenceParser*>(this)->m_Parser.release(); + + return result; +} + + +// Rewinds the stream to the beginning. +ASDCP::Result_t +ASDCP::JP2K::SequenceParser::Reset() const +{ + if ( m_Parser.empty() ) + return RESULT_INIT; + + return m_Parser->Reset(); +} + +// Places a frame of data in the frame buffer. Fails if the buffer is too small +// or the stream is empty. +ASDCP::Result_t +ASDCP::JP2K::SequenceParser::ReadFrame(FrameBuffer& FB) const +{ + if ( m_Parser.empty() ) + return RESULT_INIT; + + return m_Parser->ReadFrame(FB); +} + +// +ASDCP::Result_t +ASDCP::JP2K::SequenceParser::FillPictureDescriptor(PictureDescriptor& PDesc) const +{ + if ( m_Parser.empty() ) + return RESULT_INIT; + + PDesc = m_Parser->m_PDesc; + return RESULT_OK; +} + + +// +// end JP2K_Sequence_Parser.cpp +// diff --git a/asdcplib/src/KLV.cpp b/asdcplib/src/KLV.cpp new file mode 100755 index 0000000..46a8a7a --- /dev/null +++ b/asdcplib/src/KLV.cpp @@ -0,0 +1,319 @@ +/* +Copyright (c) 2005-2009, 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 KLV.cpp + \version $Id: KLV.cpp,v 1.13 2012/02/03 19:49:56 jhurst Exp $ + \brief KLV objects +*/ + +#include "KLV.h" +#include <KM_log.h> +using Kumu::DefaultLogSink; + + +// This is how much we read when we're reading from a file and we don't know +// how long the packet is. This gives us the K (16 bytes) and L (4-9 bytes) +// and the remaining bytes for an even read (tmp_read_size % 16 == 0) +const ui32_t kl_length = ASDCP::SMPTE_UL_LENGTH + ASDCP::MXF_BER_LENGTH; +const ui32_t tmp_read_size = 32; + +//------------------------------------------------------------------------------------------ +// + +// +ASDCP::Result_t +ASDCP::KLVPacket::InitFromBuffer(const byte_t* buf, ui32_t buf_len, const UL& label) +{ + Result_t result = KLVPacket::InitFromBuffer(buf, buf_len); + + if ( ASDCP_SUCCESS(result) ) + result = ( UL(m_KeyStart) == label ) ? RESULT_OK : RESULT_FAIL; + + return result; +} + +// +ASDCP::UL +ASDCP::KLVPacket::GetUL() +{ + if ( m_KeyStart != 0 ) + return UL(m_KeyStart); + + return m_UL; +} + +// +bool +ASDCP::KLVPacket::SetUL(const UL& new_ul) +{ + if ( m_KeyStart != 0 ) + return false; + + m_UL = new_ul; + return true; +} + +// +ASDCP::Result_t +ASDCP::KLVPacket::InitFromBuffer(const byte_t* buf, ui32_t buf_len) +{ + m_KeyStart = m_ValueStart = 0; + m_KLLength = m_ValueLength = 0; + + if ( memcmp(buf, SMPTE_UL_START, 4) != 0 ) + { + DefaultLogSink().Error("Unexpected UL preamble: %02x.%02x.%02x.%02x\n", + buf[0], buf[1], buf[2], buf[3]); + return RESULT_FAIL; + } + + ui32_t ber_len = Kumu::BER_length(buf + SMPTE_UL_LENGTH); + + if ( ber_len > ( buf_len - SMPTE_UL_LENGTH ) ) + { + DefaultLogSink().Error("BER encoding length exceeds buffer size\n"); + return RESULT_FAIL; + } + + if ( ber_len == 0 ) + { + DefaultLogSink().Error("KLV format error, zero BER length not allowed\n"); + return RESULT_FAIL; + } + + ui64_t tmp_size; + if ( ! Kumu::read_BER(buf + SMPTE_UL_LENGTH, &tmp_size) ) + return RESULT_FAIL; + + assert (tmp_size <= 0xFFFFFFFFL); + m_ValueLength = (ui32_t) tmp_size; + m_KLLength = SMPTE_UL_LENGTH + Kumu::BER_length(buf + SMPTE_UL_LENGTH); + m_KeyStart = buf; + m_ValueStart = buf + m_KLLength; + return RESULT_OK; +} + +// +bool +ASDCP::KLVPacket::HasUL(const byte_t* ul) +{ + if ( m_KeyStart != 0 ) + { + return ( memcmp(ul, m_KeyStart, SMPTE_UL_LENGTH) == 0 ) ? true : false; + } + + if ( m_UL.HasValue() ) + { + return UL(ul) == m_UL; + } + + return false; +} + +// +ASDCP::Result_t +ASDCP::KLVPacket::WriteKLToBuffer(ASDCP::FrameBuffer& Buffer, const UL& label, ui32_t length) +{ + assert(label.HasValue()); + + if ( Buffer.Size() + kl_length > Buffer.Capacity() ) + { + DefaultLogSink().Error("Small write buffer\n"); + return RESULT_FAIL; + } + + memcpy(Buffer.Data() + Buffer.Size(), label.Value(), label.Size()); + + if ( ! Kumu::write_BER(Buffer.Data() + Buffer.Size() + SMPTE_UL_LENGTH, length, MXF_BER_LENGTH) ) + return RESULT_FAIL; + + Buffer.Size(Buffer.Size() + kl_length); + return RESULT_OK; +} + +// +void +ASDCP::KLVPacket::Dump(FILE* stream, const Dictionary& Dict, bool show_value) +{ + char buf[64]; + + if ( stream == 0 ) + stream = stderr; + + if ( m_KeyStart != 0 ) + { + assert(m_ValueStart); + UL TmpUL(m_KeyStart); + fprintf(stream, "%s", TmpUL.EncodeString(buf, 64)); + + const MDDEntry* Entry = Dict.FindUL(m_KeyStart); + fprintf(stream, " len: %7u (%s)\n", m_ValueLength, (Entry ? Entry->name : "Unknown")); + + if ( show_value && m_ValueLength < 1000 ) + Kumu::hexdump(m_ValueStart, Kumu::xmin(m_ValueLength, (ui32_t)128), stream); + } + else if ( m_UL.HasValue() ) + { + fprintf(stream, "%s\n", m_UL.EncodeString(buf, 64)); + } + else + { + fprintf(stream, "*** Malformed KLV packet ***\n"); + } +} + +// +ASDCP::Result_t +ASDCP::KLVFilePacket::InitFromFile(const Kumu::FileReader& Reader, const UL& label) +{ + Result_t result = KLVFilePacket::InitFromFile(Reader); + + if ( ASDCP_SUCCESS(result) ) + result = ( UL(m_KeyStart) == label ) ? RESULT_OK : RESULT_FAIL; + + return result; +} + +// TODO: refactor to use InitFromBuffer +ASDCP::Result_t +ASDCP::KLVFilePacket::InitFromFile(const Kumu::FileReader& Reader) +{ + ui32_t read_count; + byte_t tmp_data[tmp_read_size]; + ui64_t tmp_size; + m_KeyStart = m_ValueStart = 0; + m_KLLength = m_ValueLength = 0; + m_Buffer.Size(0); + + Result_t result = Reader.Read(tmp_data, tmp_read_size, &read_count); + + if ( ASDCP_FAILURE(result) ) + return result; + + if ( read_count < (SMPTE_UL_LENGTH + 1) ) + { + DefaultLogSink().Error("Short read of Key and Length got %u\n", read_count); + return RESULT_READFAIL; + } + + if ( memcmp(tmp_data, SMPTE_UL_START, 4) != 0 ) + { + DefaultLogSink().Error("Unexpected UL preamble: %02x.%02x.%02x.%02x\n", + tmp_data[0], tmp_data[1], tmp_data[2], tmp_data[3]); + return RESULT_FAIL; + } + + if ( ! Kumu::read_BER(tmp_data + SMPTE_UL_LENGTH, &tmp_size) ) + { + DefaultLogSink().Error("BER Length decoding error\n"); + return RESULT_FAIL; + } + + if ( tmp_size > MAX_KLV_PACKET_LENGTH ) + { + Kumu::ui64Printer tmp_size_str(tmp_size); + DefaultLogSink().Error("Packet length %s exceeds internal limit\n", tmp_size_str.c_str()); + return RESULT_FAIL; + } + + ui32_t remainder = 0; + ui32_t ber_len = Kumu::BER_length(tmp_data + SMPTE_UL_LENGTH); + m_KLLength = SMPTE_UL_LENGTH + ber_len; + assert(tmp_size <= 0xFFFFFFFFL); + m_ValueLength = (ui32_t) tmp_size; + ui32_t packet_length = m_ValueLength + m_KLLength; + + result = m_Buffer.Capacity(packet_length); + + if ( ASDCP_FAILURE(result) ) + return result; + + m_KeyStart = m_Buffer.Data(); + m_ValueStart = m_Buffer.Data() + m_KLLength; + m_Buffer.Size(packet_length); + + // is the whole packet in the tmp buf? + if ( packet_length <= tmp_read_size ) + { + assert(packet_length <= read_count); + memcpy(m_Buffer.Data(), tmp_data, packet_length); + + if ( (remainder = read_count - packet_length) != 0 ) + { + DefaultLogSink().Warn("Repositioning pointer for short packet\n"); + Kumu::fpos_t pos = Reader.Tell(); + assert(pos > remainder); + result = Reader.Seek(pos - remainder); + } + } + else + { + if ( read_count < tmp_read_size ) + { + DefaultLogSink().Error("Short read of packet body, expecting %u, got %u\n", + m_Buffer.Size(), read_count); + return RESULT_READFAIL; + } + + memcpy(m_Buffer.Data(), tmp_data, tmp_read_size); + remainder = m_Buffer.Size() - tmp_read_size; + + if ( remainder > 0 ) + { + result = Reader.Read(m_Buffer.Data() + tmp_read_size, remainder, &read_count); + + if ( read_count != remainder ) + { + DefaultLogSink().Error("Short read of packet body, expecting %u, got %u\n", + remainder+tmp_read_size, read_count+tmp_read_size); + result = RESULT_READFAIL; + } + } + } + + return result; +} + +// +ASDCP::Result_t +ASDCP::KLVFilePacket::WriteKLToFile(Kumu::FileWriter& Writer, const UL& label, ui32_t length) +{ + byte_t buffer[kl_length]; + memcpy(buffer, label.Value(), label.Size()); + + if ( ! Kumu::write_BER(buffer+SMPTE_UL_LENGTH, length, MXF_BER_LENGTH) ) + return RESULT_FAIL; + + ui32_t write_count; + Writer.Write(buffer, kl_length, &write_count); + assert(write_count == kl_length); + return RESULT_OK; +} + + +// +// end KLV.cpp +// diff --git a/asdcplib/src/KLV.h b/asdcplib/src/KLV.h new file mode 100755 index 0000000..ec34321 --- /dev/null +++ b/asdcplib/src/KLV.h @@ -0,0 +1,256 @@ +/* +Copyright (c) 2005-2011, 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 KLV.h + \version $Id: KLV.h,v 1.25 2012/02/08 02:59:21 jhurst Exp $ + \brief KLV objects +*/ + +#ifndef _KLV_H_ +#define _KLV_H_ + +#include <KM_fileio.h> +#include <KM_memio.h> +#include "AS_DCP.h" +#include "MDD.h" +#include <map> + + +namespace ASDCP +{ + const ui32_t MXF_BER_LENGTH = 4; + const ui32_t MXF_TAG_LENGTH = 2; + const ui32_t SMPTE_UL_LENGTH = 16; + const ui32_t SMPTE_UMID_LENGTH = 32; + const byte_t SMPTE_UL_START[4] = { 0x06, 0x0e, 0x2b, 0x34 }; + +#ifndef MAX_KLV_PACKET_LENGTH + const ui32_t MAX_KLV_PACKET_LENGTH = 1024*1024*64; +#endif + + const ui32_t IdentBufferLen = 128; + const ui32_t IntBufferLen = 64; + +inline const char* i64sz(i64_t i, char* buf) +{ + assert(buf); +#ifdef WIN32 + snprintf(buf, IntBufferLen, "%I64d", i); +#else + snprintf(buf, IntBufferLen, "%lld", i); +#endif + return buf; +} + +inline const char* ui64sz(ui64_t i, char* buf) +{ + assert(buf); +#ifdef WIN32 + snprintf(buf, IntBufferLen, "%I64u", i); +#else + snprintf(buf, IntBufferLen, "%llu", i); +#endif + return buf; +} + + struct TagValue + { + byte_t a; + byte_t b; + + inline bool operator<(const TagValue& rhs) const { + if ( a < rhs.a ) return true; + if ( a == rhs.a && b < rhs.b ) return true; + return false; + } + + inline bool operator==(const TagValue& rhs) const { + if ( a != rhs.a ) return false; + if ( b != rhs.b ) return false; + return true; + } + }; + + using Kumu::UUID; + + // Universal Label + class UL : public Kumu::Identifier<SMPTE_UL_LENGTH> + { + public: + UL() {} + UL(const UL& rhs) : Kumu::Identifier<SMPTE_UL_LENGTH>(rhs) {} + UL(const byte_t* value) : Kumu::Identifier<SMPTE_UL_LENGTH>(value) {} + virtual ~UL() {} + + const char* EncodeString(char* str_buf, ui32_t buf_len) const; + bool operator==(const UL& rhs) const; + bool MatchIgnoreStream(const UL& rhs) const; + bool ExactMatch(const UL& rhs) const; + }; + + // UMID + class UMID : public Kumu::Identifier<SMPTE_UMID_LENGTH> + { + public: + UMID() {} + UMID(const UMID& rhs) : Kumu::Identifier<SMPTE_UMID_LENGTH>(rhs) {} + UMID(const byte_t* value) : Kumu::Identifier<SMPTE_UMID_LENGTH>(value) {} + virtual ~UMID() {} + + void MakeUMID(int Type); + void MakeUMID(int Type, const UUID& ID); + const char* EncodeString(char* str_buf, ui32_t buf_len) const; + }; + + const byte_t nil_UMID[SMPTE_UMID_LENGTH] = {0}; + const UMID NilUMID(nil_UMID); + + // + struct MDDEntry + { + byte_t ul[SMPTE_UL_LENGTH]; + TagValue tag; + bool optional; + const char* name; + }; + + const MDDEntry& MXFInterop_OPAtom_Entry(); + const MDDEntry& SMPTE_390_OPAtom_Entry(); + + // + class Dictionary + { + std::map<ASDCP::UL, ui32_t> m_md_lookup; + std::map<std::string, ui32_t> m_md_sym_lookup; + std::map<ui32_t, ASDCP::UL> m_md_rev_lookup; + MDDEntry m_MDD_Table[(ui32_t)ASDCP::MDD_Max]; + + ASDCP_NO_COPY_CONSTRUCT(Dictionary); + + public: + Dictionary(); + ~Dictionary(); + + // bool operator==(const Dictionary& rhs) const { return this == &rhs; } + + void Init(); + bool AddEntry(const MDDEntry& Entry, ui32_t index); + bool DeleteEntry(ui32_t index); + + const MDDEntry* FindUL(const byte_t*) const; + const MDDEntry* FindSymbol(const std::string&) const; + const MDDEntry& Type(MDD_t type_id) const; + + inline const byte_t* ul(MDD_t type_id) const { + return Type(type_id).ul; + } + + void Dump(FILE* = 0) const; + }; + + + const Dictionary& DefaultSMPTEDict(); + const Dictionary& DefaultInteropDict(); + const Dictionary& DefaultCompositeDict(); + + + // + class IPrimerLookup + { + public: + virtual ~IPrimerLookup() {} + virtual void ClearTagList() = 0; + virtual Result_t InsertTag(const MDDEntry& Entry, ASDCP::TagValue& Tag) = 0; + virtual Result_t TagForKey(const ASDCP::UL& Key, ASDCP::TagValue& Tag) = 0; + }; + + // + class KLVPacket + { + ASDCP_NO_COPY_CONSTRUCT(KLVPacket); + + protected: + const byte_t* m_KeyStart; + ui32_t m_KLLength; + const byte_t* m_ValueStart; + ui32_t m_ValueLength; + UL m_UL; + + public: + KLVPacket() : m_KeyStart(0), m_KLLength(0), m_ValueStart(0), m_ValueLength(0) {} + virtual ~KLVPacket() {} + + ui32_t PacketLength() { + return m_KLLength + m_ValueLength; + } + + ui32_t ValueLength() { + return m_ValueLength; + } + + ui32_t KLLength() { + return m_KLLength; + } + + virtual UL GetUL(); + virtual bool SetUL(const UL&); + virtual bool HasUL(const byte_t*); + virtual Result_t InitFromBuffer(const byte_t*, ui32_t); + virtual Result_t InitFromBuffer(const byte_t*, ui32_t, const UL& label); + virtual Result_t WriteKLToBuffer(ASDCP::FrameBuffer&, const UL& label, ui32_t length); + virtual Result_t WriteKLToBuffer(ASDCP::FrameBuffer& fb, ui32_t length) { + if ( ! m_UL.HasValue() ) + return RESULT_STATE; + return WriteKLToBuffer(fb, m_UL, length); } + + virtual void Dump(FILE*, const Dictionary& Dict, bool show_value); + }; + + // + class KLVFilePacket : public KLVPacket + { + ASDCP_NO_COPY_CONSTRUCT(KLVFilePacket); + + protected: + ASDCP::FrameBuffer m_Buffer; + + public: + KLVFilePacket() {} + virtual ~KLVFilePacket() {} + + virtual Result_t InitFromFile(const Kumu::FileReader&); + virtual Result_t InitFromFile(const Kumu::FileReader&, const UL& label); + virtual Result_t WriteKLToFile(Kumu::FileWriter& Writer, const UL& label, ui32_t length); + }; + +} // namespace ASDCP + +#endif // _KLV_H_ + + +// +// end KLV.h +// diff --git a/asdcplib/src/KM_error.h b/asdcplib/src/KM_error.h new file mode 100755 index 0000000..7639797 --- /dev/null +++ b/asdcplib/src/KM_error.h @@ -0,0 +1,171 @@ +/* +Copyright (c) 2004-2011, 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 KM_error.h + \version $Id: KM_error.h,v 1.12 2011/05/16 04:33:31 jhurst Exp $ + \brief error reporting support + */ + + + +#ifndef _KM_ERROR_H_ +#define _KM_ERROR_H_ + +#define KM_DECLARE_RESULT(sym, i, l) const Result_t RESULT_##sym = Result_t(i, #sym, l); + +namespace Kumu +{ + // Result code container. Both a signed integer and a text string are stored in the object. + // When defining your own codes your choice of integer values is mostly unconstrained, but pay + // attention to the numbering in the other libraries that use Kumu. Values between -99 and 99 + // are reserved for Kumu. + + class Result_t + { + int value; + const char* label; + const char* symbol; + Result_t(); + + public: + // Return registered Result_t for the given "value" code. + static const Result_t& Find(int value); + + // Unregister the Result_t matching the given "value" code. Returns + // RESULT_FALSE if "value" does not match a registered Result_t. + // Returns RESULT_FAIL if ( value < -99 || value > 99 ) (Kumu core + // codes may not be deleted). + static Result_t Delete(int value); + + // Iteration through registered result codes, not thread safe. + // Get accepts contiguous values from 0 to End() - 1. + static unsigned int End(); + static const Result_t& Get(unsigned int); + + Result_t(int v, const char* s, const char* l); + ~Result_t(); + + inline bool operator==(const Result_t& rhs) const { return value == rhs.value; } + inline bool operator!=(const Result_t& rhs) const { return value != rhs.value; } + inline bool Success() const { return ( value >= 0 ); } + inline bool Failure() const { return ( value < 0 ); } + + inline int Value() const { return value; } + inline operator int() const { return value; } + + inline const char* Label() const { return label; } + inline operator const char*() const { return label; } + + inline const char* Symbol() const { return symbol; } + }; + + KM_DECLARE_RESULT(FALSE, 1, "Successful but not true."); + KM_DECLARE_RESULT(OK, 0, "Success."); + KM_DECLARE_RESULT(FAIL, -1, "An undefined error was detected."); + KM_DECLARE_RESULT(PTR, -2, "An unexpected NULL pointer was given."); + KM_DECLARE_RESULT(NULL_STR, -3, "An unexpected empty string was given."); + KM_DECLARE_RESULT(ALLOC, -4, "Error allocating memory."); + KM_DECLARE_RESULT(PARAM, -5, "Invalid parameter."); + KM_DECLARE_RESULT(NOTIMPL, -6, "Unimplemented Feature."); + KM_DECLARE_RESULT(SMALLBUF, -7, "The given buffer is too small."); + KM_DECLARE_RESULT(INIT, -8, "The object is not yet initialized."); + KM_DECLARE_RESULT(NOT_FOUND, -9, "The requested file does not exist on the system."); + KM_DECLARE_RESULT(NO_PERM, -10, "Insufficient privilege exists to perform the operation."); + KM_DECLARE_RESULT(STATE, -11, "Object state error."); + KM_DECLARE_RESULT(CONFIG, -12, "Invalid configuration option detected."); + KM_DECLARE_RESULT(FILEOPEN, -13, "File open failure."); + KM_DECLARE_RESULT(BADSEEK, -14, "An invalid file location was requested."); + KM_DECLARE_RESULT(READFAIL, -15, "File read error."); + KM_DECLARE_RESULT(WRITEFAIL, -16, "File write error."); + KM_DECLARE_RESULT(ENDOFFILE, -17, "Attempt to read past end of file."); + KM_DECLARE_RESULT(FILEEXISTS, -18, "Filename already exists."); + KM_DECLARE_RESULT(NOTAFILE, -19, "Filename not found."); + KM_DECLARE_RESULT(UNKNOWN, -20, "Unknown result code."); + KM_DECLARE_RESULT(DIR_CREATE, -21, "Unable to create directory."); + // -22 is reserved + +} // namespace Kumu + +//-------------------------------------------------------------------------------- +// convenience macros + +// Convenience macros for managing return values in predicates +# define KM_SUCCESS(v) (((v) < 0) ? 0 : 1) +# define KM_FAILURE(v) (((v) < 0) ? 1 : 0) + + +// Returns RESULT_PTR if the given argument is NULL. +// See Result_t above for an explanation of RESULT_* symbols. +# define KM_TEST_NULL(p) \ + if ( (p) == 0 ) { \ + return Kumu::RESULT_PTR; \ + } + +// Returns RESULT_PTR if the given argument is NULL. See Result_t +// in WaimeaCore 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 KM_TEST_NULL_STR(p) \ + KM_TEST_NULL(p); \ + if ( (p)[0] == '\0' ) { \ + return Kumu::RESULT_NULL_STR; \ + } + +namespace Kumu +{ + // simple tracing mechanism + class DTrace_t + { + DTrace_t(); + + protected: + const char* m_Label; + Result_t* m_Watch; + int m_Line; + const char* m_File; + int m_Sequence; + + public: + DTrace_t(const char* Label, Result_t* Watch, int Line, const char* File); + ~DTrace_t(); + }; +} + +#ifdef KM_TRACE +#define WDTRACE(l) DTrace_t __wl__Trace__((l), 0, __LINE__, __FILE__) +#define WDTRACER(l,r) DTrace_t __wl__Trace__((l), &(r), __LINE__, __FILE__) +#else +#define WDTRACE(l) +#define WDTRACER(l,r) +#endif + + +#endif // _KM_ERROR_H_ + +// +// end KM_error.h +// diff --git a/asdcplib/src/KM_fileio.cpp b/asdcplib/src/KM_fileio.cpp new file mode 100644 index 0000000..b20ff7f --- /dev/null +++ b/asdcplib/src/KM_fileio.cpp @@ -0,0 +1,1546 @@ +/* +Copyright (c) 2004-2011, 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 KM_fileio.cpp + \version $Id: KM_fileio.cpp,v 1.31 2011/03/08 19:03:47 jhurst Exp $ + \brief portable file i/o + */ + +#include <KM_fileio.h> +#include <KM_log.h> +#include <fcntl.h> +#include <sstream> +#include <iomanip> + +#include <assert.h> + +#ifdef KM_WIN32 +#include <direct.h> +#else +#define _getcwd getcwd +#define _unlink unlink +#define _rmdir rmdir +#endif + +using namespace Kumu; + +#ifdef KM_WIN32 +typedef struct _stati64 fstat_t; +#define S_IFLNK 0 + +// win32 has WriteFileGather() and ReadFileScatter() but they +// demand page alignment and page sizing, making them unsuitable +// for use with arbitrary buffer sizes. +struct iovec { + char* iov_base; // stupid iovec uses char* + int iov_len; +}; +#else +# if defined(__linux__) +# include <sys/statfs.h> +# else +# include <sys/param.h> +# include <sys/mount.h> +# endif + +#include <sys/stat.h> +#include <sys/uio.h> +typedef struct stat fstat_t; +#endif + +// +static void +split(const std::string& str, char separator, std::list<std::string>& components) +{ + const char* pstr = str.c_str(); + const char* r = strchr(pstr, separator); + + while ( r != 0 ) + { + assert(r >= pstr); + if ( r > pstr ) + { + std::string tmp_str; + tmp_str.assign(pstr, (r - pstr)); + components.push_back(tmp_str); + } + + pstr = r + 1; + r = strchr(pstr, separator); + } + + if( strlen(pstr) > 0 ) + components.push_back(std::string(pstr)); +} + + +// +static Kumu::Result_t +do_stat(const char* path, fstat_t* stat_info) +{ + KM_TEST_NULL_STR_L(path); + KM_TEST_NULL_L(stat_info); + + Kumu::Result_t result = Kumu::RESULT_OK; + +#ifdef KM_WIN32 + UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX); + + int const wn = MultiByteToWideChar (CP_UTF8, 0, path, -1, 0, 0); + wchar_t* buffer = new wchar_t[wn]; + if (MultiByteToWideChar (CP_UTF8, 0, path, -1, buffer, wn) == 0) { + delete[] buffer; + return Kumu::RESULT_FAIL; + } + + if ( _wstati64(buffer, stat_info) == (__int64)-1 ) + result = Kumu::RESULT_FILEOPEN; + + delete[] buffer; + + ::SetErrorMode( prev ); +#else + if ( stat(path, stat_info) == -1L ) + result = Kumu::RESULT_FILEOPEN; + + if ( (stat_info->st_mode & (S_IFREG|S_IFLNK|S_IFDIR)) == 0 ) + result = Kumu::RESULT_FILEOPEN; +#endif + + return result; +} + +#ifndef KM_WIN32 + +// +static Kumu::Result_t +do_fstat(FileHandle handle, fstat_t* stat_info) +{ + KM_TEST_NULL_L(stat_info); + + Kumu::Result_t result = Kumu::RESULT_OK; + + if ( fstat(handle, stat_info) == -1L ) + result = Kumu::RESULT_FILEOPEN; + + if ( (stat_info->st_mode & (S_IFREG|S_IFLNK|S_IFDIR)) == 0 ) + result = Kumu::RESULT_FILEOPEN; + + return result; +} + +#endif + + +// +bool +Kumu::PathExists(const std::string& pathname) +{ + if ( pathname.empty() ) + return false; + + fstat_t info; + + if ( KM_SUCCESS(do_stat(pathname.c_str(), &info)) ) + return true; + + return false; +} + +// +bool +Kumu::PathIsFile(const std::string& pathname) +{ + if ( pathname.empty() ) + return false; + + fstat_t info; + + if ( KM_SUCCESS(do_stat(pathname.c_str(), &info)) ) + { + if ( info.st_mode & ( S_IFREG|S_IFLNK ) ) + return true; + } + + return false; +} + + +// +bool +Kumu::PathIsDirectory(const std::string& pathname) +{ + if ( pathname.empty() ) + return false; + + fstat_t info; + + if ( KM_SUCCESS(do_stat(pathname.c_str(), &info)) ) + { + if ( info.st_mode & S_IFDIR ) + return true; + } + + return false; +} + +// +Kumu::fsize_t +Kumu::FileSize(const std::string& pathname) +{ + if ( pathname.empty() ) + return 0; + + fstat_t info; + + if ( KM_SUCCESS(do_stat(pathname.c_str(), &info)) ) + { + if ( info.st_mode & ( S_IFREG|S_IFLNK ) ) + return(info.st_size); + } + + return 0; +} + +// +static PathCompList_t& +s_PathMakeCanonical(PathCompList_t& CList, bool is_absolute) +{ + PathCompList_t::iterator ci, ri; // component and removal iterators + + for ( ci = CList.begin(); ci != CList.end(); ci++ ) + { + if ( *ci == "." && ( CList.size() > 1 || is_absolute ) ) + { + ri = ci++; + CList.erase(ri); + } + else if ( *ci == ".." && ci != CList.begin() ) + { + ri = ci; + ri--; + + if ( *ri != ".." ) + { + CList.erase(ri); + ri = ci++; + CList.erase(ri); + } + } + } + + return CList; +} + +// +std::string +Kumu::PathMakeCanonical(const std::string& Path, char separator) +{ + PathCompList_t CList; + bool is_absolute = PathIsAbsolute(Path, separator); + s_PathMakeCanonical(PathToComponents(Path, CList, separator), is_absolute); + + if ( is_absolute ) + return ComponentsToAbsolutePath(CList, separator); + + return ComponentsToPath(CList, separator); +} + +// +bool +Kumu::PathsAreEquivalent(const std::string& lhs, const std::string& rhs) +{ + return PathMakeCanonical(lhs) == PathMakeCanonical(rhs); +} + +// +Kumu::PathCompList_t& +Kumu::PathToComponents(const std::string& Path, PathCompList_t& CList, char separator) +{ + split(Path, separator, CList); + return CList; +} + +// +std::string +Kumu::ComponentsToPath(const PathCompList_t& CList, char separator) +{ + if ( CList.empty() ) + return ""; + + PathCompList_t::const_iterator ci = CList.begin(); + std::string out_path = *ci; + + for ( ci++; ci != CList.end(); ci++ ) + out_path += separator + *ci; + + return out_path; +} + +// +std::string +Kumu::ComponentsToAbsolutePath(const PathCompList_t& CList, char separator) +{ + std::string out_path; + + if ( CList.empty() ) + out_path = separator; + else + { + PathCompList_t::const_iterator ci; + + for ( ci = CList.begin(); ci != CList.end(); ci++ ) + out_path += separator + *ci; + } + + return out_path; +} + +// +bool +Kumu::PathHasComponents(const std::string& Path, char separator) +{ + if ( strchr(Path.c_str(), separator) == 0 ) + return false; + + return true; +} + +// +bool +Kumu::PathIsAbsolute(const std::string& Path, char separator) +{ + if ( Path.empty() ) + return false; + + if ( Path[0] == separator) + return true; + + return false; +} + +// +std::string +Kumu::PathMakeAbsolute(const std::string& Path, char separator) +{ + if ( Path.empty() ) + { + std::string out_path; + out_path = separator; + return out_path; + } + + if ( PathIsAbsolute(Path, separator) ) + return Path; + + char cwd_buf [MaxFilePath]; + if ( _getcwd(cwd_buf, MaxFilePath) == 0 ) + { + DefaultLogSink().Error("Error retrieving current working directory."); + return ""; + } + + PathCompList_t CList; + PathToComponents(cwd_buf, CList); + CList.push_back(Path); + + return ComponentsToAbsolutePath(s_PathMakeCanonical(CList, true), separator); +} + +// +std::string +Kumu::PathMakeLocal(const std::string& Path, const std::string& Parent) +{ + size_t pos = Path.find(Parent); + + if ( pos == 0 ) // Parent found at offset 0 + return Path.substr(Parent.size()+1); + + return Path; +} + +// +std::string +Kumu::PathBasename(const std::string& Path, char separator) +{ + PathCompList_t CList; + PathToComponents(Path, CList, separator); + + if ( CList.empty() ) + return ""; + + return CList.back(); +} + +// +std::string +Kumu::PathDirname(const std::string& Path, char separator) +{ + PathCompList_t CList; + bool is_absolute = PathIsAbsolute(Path, separator); + PathToComponents(Path, CList, separator); + + if ( CList.empty() ) + return is_absolute ? "/" : ""; + + CList.pop_back(); + + if ( is_absolute ) + return ComponentsToAbsolutePath(CList, separator); + + return ComponentsToPath(CList, separator); +} + +// +std::string +Kumu::PathGetExtension(const std::string& Path) +{ + std::string Basename = PathBasename(Path); + const char* p = strrchr(Basename.c_str(), '.'); + + if ( p++ == 0 ) + return ""; + + return p; +} + +// +std::string +Kumu::PathSetExtension(const std::string& Path, const std::string& Extension) // empty extension removes +{ + std::string Basename = PathBasename(Path); + const char* p = strrchr(Basename.c_str(), '.'); + + if ( p != 0 ) + Basename = Basename.substr(0, p - Basename.c_str()); + + if ( Extension.empty() ) + return Basename; + + return Basename + "." + Extension; +} + +// +std::string +Kumu::PathJoin(const std::string& Path1, const std::string& Path2, char separator) +{ + return Path1 + separator + Path2; +} + +// +std::string +Kumu::PathJoin(const std::string& Path1, const std::string& Path2, const std::string& Path3, char separator) +{ + return Path1 + separator + Path2 + separator + Path3; +} + +// +std::string +Kumu::PathJoin(const std::string& Path1, const std::string& Path2, + const std::string& Path3, const std::string& Path4, char separator) +{ + return Path1 + separator + Path2 + separator + Path3 + separator + Path4; +} + +// +Kumu::PathList_t& +Kumu::FindInPaths(const IPathMatch& Pattern, const Kumu::PathList_t& SearchPaths, + Kumu::PathList_t& FoundPaths, bool one_shot, char separator) +{ + PathList_t::const_iterator si; + for ( si = SearchPaths.begin(); si != SearchPaths.end(); si++ ) + { + FindInPath(Pattern, *si, FoundPaths, one_shot, separator); + + if ( one_shot && ! FoundPaths.empty() ) + break; + } + + return FoundPaths; +} + +// +Kumu::PathList_t& +Kumu::FindInPath(const IPathMatch& Pattern, const std::string& SearchDir, + Kumu::PathList_t& FoundPaths, bool one_shot, char separator) +{ + char name_buf[MaxFilePath]; + DirScanner Dir; + + if ( KM_SUCCESS(Dir.Open(SearchDir.c_str())) ) + { + while ( KM_SUCCESS(Dir.GetNext(name_buf)) ) + { + if ( name_buf[0] == '.' ) continue; // no hidden files + std::string tmp_path = SearchDir + separator + name_buf; + + if ( PathIsDirectory(tmp_path.c_str()) ) + FindInPath(Pattern, tmp_path, FoundPaths, one_shot, separator); + + else if ( Pattern.Match(name_buf) ) + { + FoundPaths.push_back(SearchDir + separator + name_buf); + if ( one_shot ) + break; + } + } + } + + return FoundPaths; +} + + +#ifndef KM_WIN32 + +// +Kumu::PathMatchRegex::PathMatchRegex(const std::string& s) +{ + int result = regcomp(&m_regex, s.c_str(), REG_NOSUB); // (REG_EXTENDED|REG_NOSUB|REG_NEWLINE)); + + if ( result ) + { + char buf[128]; + regerror(result, &m_regex, buf, 128); + DefaultLogSink().Error("PathMatchRegex: %s\n", buf); + regfree(&m_regex); + } +} + +Kumu::PathMatchRegex::PathMatchRegex(const PathMatchRegex& rhs) : IPathMatch() { + m_regex = rhs.m_regex; +} + +Kumu::PathMatchRegex::~PathMatchRegex() { + regfree(&m_regex); +} + +bool +Kumu::PathMatchRegex::Match(const std::string& s) const { + return ( regexec(&m_regex, s.c_str(), 0, 0, 0) == 0 ); +} + + + +// +Kumu::PathMatchGlob::PathMatchGlob(const std::string& glob) +{ + std::string regex; // convert glob to regex + + for ( const char* p = glob.c_str(); *p != 0; p++ ) + { + switch (*p) + { + case '.': regex += "\\."; break; + case '*': regex += ".*"; break; + case '?': regex += ".?"; break; + default: regex += *p; + } + } + regex += '$'; + + int result = regcomp(&m_regex, regex.c_str(), REG_NOSUB); + + if ( result ) + { + char buf[128]; + regerror(result, &m_regex, buf, 128); + DefaultLogSink().Error("PathMatchRegex: %s\n", buf); + regfree(&m_regex); + } +} + +Kumu::PathMatchGlob::PathMatchGlob(const PathMatchGlob& rhs) : IPathMatch() { + m_regex = rhs.m_regex; +} + +Kumu::PathMatchGlob::~PathMatchGlob() { + regfree(&m_regex); +} + +bool +Kumu::PathMatchGlob::Match(const std::string& s) const { + return ( regexec(&m_regex, s.c_str(), 0, 0, 0) == 0 ); +} + +#endif + +//------------------------------------------------------------------------------------------ +// portable aspects of the file classes + +const int IOVecMaxEntries = 32; // we never use more that 3, but that number seems somehow small... + +// +class Kumu::FileWriter::h__iovec +{ +public: + int m_Count; + struct iovec m_iovec[IOVecMaxEntries]; + h__iovec() : m_Count(0) {} +}; + + + +// +Kumu::fsize_t +Kumu::FileReader::Size() const +{ +#ifdef KM_WIN32 + return FileSize(m_Filename.c_str()); +#else + fstat_t info; + + if ( KM_SUCCESS(do_fstat(m_Handle, &info)) ) + { + if ( info.st_mode & ( S_IFREG|S_IFLNK ) ) + return(info.st_size); + } +#endif + + return 0; +} + +// these are declared here instead of in the header file +// because we have a mem_ptr that is managing a hidden class +Kumu::FileWriter::FileWriter() + : m_Hashing (false) +{} + +Kumu::FileWriter::~FileWriter() {} + +// +Kumu::Result_t +Kumu::FileWriter::Writev(const byte_t* buf, ui32_t buf_len) +{ + assert( ! m_IOVec.empty() ); + register h__iovec* iov = m_IOVec; + KM_TEST_NULL_L(buf); + + if ( iov->m_Count >= IOVecMaxEntries ) + { + DefaultLogSink().Error("The iovec is full! Only %u entries allowed before a flush.\n", + IOVecMaxEntries); + return RESULT_WRITEFAIL; + } + + iov->m_iovec[iov->m_Count].iov_base = (char*)buf; // stupid iovec uses char* + iov->m_iovec[iov->m_Count].iov_len = buf_len; + iov->m_Count++; + + return RESULT_OK; +} + +void +Kumu::FileWriter::StartHashing() +{ + m_Hashing = true; + MD5_Init (&m_MD5Context); +} + +void +Kumu::FileWriter::MaybeHash(void const * data, int size) +{ + if (m_Hashing) { + MD5_Update (&m_MD5Context, data, size); + } +} + +std::string +Kumu::FileWriter::StopHashing() +{ + m_Hashing = false; + + unsigned char digest[MD5_DIGEST_LENGTH]; + MD5_Final (digest, &m_MD5Context); + + std::stringstream s; + for (int i = 0; i < MD5_DIGEST_LENGTH; ++i) { + s << std::hex << std::setfill('0') << std::setw(2) << ((int) digest[i]); + } + + return s.str (); +} + + +#ifdef KM_WIN32 +//------------------------------------------------------------------------------------------ +// + +/** @param filename File name (UTF-8 encoded) */ +Kumu::Result_t +Kumu::FileReader::OpenRead(const char* filename) const +{ + KM_TEST_NULL_STR_L(filename); + const_cast<FileReader*>(this)->m_Filename = filename; + + // suppress popup window on error + UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX); + + int const wn = MultiByteToWideChar (CP_UTF8, 0, filename, -1, 0, 0); + wchar_t* buffer = new wchar_t[wn]; + if (MultiByteToWideChar (CP_UTF8, 0, filename, -1, buffer, wn) == 0) { + delete[] buffer; + return Kumu::RESULT_FAIL; + } + const_cast<FileReader*>(this)->m_Handle = ::CreateFileW(buffer, + (GENERIC_READ), // open for reading + FILE_SHARE_READ, // share for reading + NULL, // no security + OPEN_EXISTING, // read + FILE_ATTRIBUTE_NORMAL, // normal file + NULL // no template file + ); + + delete[] buffer; + + ::SetErrorMode(prev); + + return ( m_Handle == INVALID_HANDLE_VALUE ) ? + Kumu::RESULT_FILEOPEN : Kumu::RESULT_OK; +} + +// +Kumu::Result_t +Kumu::FileReader::Close() const +{ + if ( m_Handle == INVALID_HANDLE_VALUE ) + return Kumu::RESULT_FILEOPEN; + + // suppress popup window on error + UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX); + BOOL result = ::CloseHandle(m_Handle); + ::SetErrorMode(prev); + const_cast<FileReader*>(this)->m_Handle = INVALID_HANDLE_VALUE; + + return ( result == 0 ) ? Kumu::RESULT_FAIL : Kumu::RESULT_OK; +} + +// +Kumu::Result_t +Kumu::FileReader::Seek(Kumu::fpos_t position, SeekPos_t whence) const +{ + if ( m_Handle == INVALID_HANDLE_VALUE ) + return Kumu::RESULT_STATE; + + LARGE_INTEGER in; + UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX); + in.QuadPart = position; + in.LowPart = ::SetFilePointer(m_Handle, in.LowPart, &in.HighPart, whence); + HRESULT LastError = GetLastError(); + ::SetErrorMode(prev); + + if ( (LastError != NO_ERROR + && (in.LowPart == INVALID_SET_FILE_POINTER + || in.LowPart == ERROR_NEGATIVE_SEEK )) ) + return Kumu::RESULT_READFAIL; + + return Kumu::RESULT_OK; +} + +// +Kumu::Result_t +Kumu::FileReader::Tell(Kumu::fpos_t* pos) const +{ + KM_TEST_NULL_L(pos); + + if ( m_Handle == INVALID_HANDLE_VALUE ) + return Kumu::RESULT_FILEOPEN; + + LARGE_INTEGER in; + UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX); + in.QuadPart = (__int64)0; + in.LowPart = ::SetFilePointer(m_Handle, in.LowPart, &in.HighPart, FILE_CURRENT); + HRESULT LastError = GetLastError(); + ::SetErrorMode(prev); + + if ( (LastError != NO_ERROR + && (in.LowPart == INVALID_SET_FILE_POINTER + || in.LowPart == ERROR_NEGATIVE_SEEK )) ) + return Kumu::RESULT_READFAIL; + + *pos = (Kumu::fpos_t)in.QuadPart; + return Kumu::RESULT_OK; +} + +// +Kumu::Result_t +Kumu::FileReader::Read(byte_t* buf, ui32_t buf_len, ui32_t* read_count) const +{ + KM_TEST_NULL_L(buf); + Result_t result = Kumu::RESULT_OK; + DWORD tmp_count; + ui32_t tmp_int; + + if ( read_count == 0 ) + read_count = &tmp_int; + + *read_count = 0; + + if ( m_Handle == INVALID_HANDLE_VALUE ) + return Kumu::RESULT_FILEOPEN; + + UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX); + if ( ::ReadFile(m_Handle, buf, buf_len, &tmp_count, NULL) == 0 ) + result = Kumu::RESULT_READFAIL; + + ::SetErrorMode(prev); + + if ( tmp_count == 0 ) /* EOF */ + result = Kumu::RESULT_ENDOFFILE; + + if ( KM_SUCCESS(result) ) + *read_count = tmp_count; + + return result; +} + + + +//------------------------------------------------------------------------------------------ +// + +/** @param filename File name (UTF-8 encoded) */ +Kumu::Result_t +Kumu::FileWriter::OpenWrite(const char* filename) +{ + KM_TEST_NULL_STR_L(filename); + m_Filename = filename; + + // suppress popup window on error + UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX); + + int const wn = MultiByteToWideChar (CP_UTF8, 0, filename, -1, 0, 0); + wchar_t* buffer = new wchar_t[wn]; + if (MultiByteToWideChar (CP_UTF8, 0, filename, -1, buffer, wn) == 0) { + delete[] buffer; + return Kumu::RESULT_FAIL; + } + + m_Handle = ::CreateFileW(buffer, + (GENERIC_WRITE|GENERIC_READ), // open for reading + FILE_SHARE_READ, // share for reading + NULL, // no security + CREATE_ALWAYS, // overwrite (beware!) + FILE_ATTRIBUTE_NORMAL, // normal file + NULL // no template file + ); + + delete[] buffer; + + ::SetErrorMode(prev); + + if ( m_Handle == INVALID_HANDLE_VALUE ) + return Kumu::RESULT_FILEOPEN; + + m_IOVec = new h__iovec; + return Kumu::RESULT_OK; +} + +/** @param filename File name (UTF-8 encoded) */ +Kumu::Result_t +Kumu::FileWriter::OpenModify(const char* filename) +{ + KM_TEST_NULL_STR_L(filename); + m_Filename = filename; + + // suppress popup window on error + UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX); + + int const wn = MultiByteToWideChar (CP_UTF8, 0, filename, -1, 0, 0); + wchar_t* buffer = new wchar_t[wn]; + if (MultiByteToWideChar (CP_UTF8, 0, filename, -1, buffer, wn) == 0) { + delete[] buffer; + return Kumu::RESULT_FAIL; + } + + m_Handle = ::CreateFileW(buffer, + (GENERIC_WRITE|GENERIC_READ), // open for reading + FILE_SHARE_READ, // share for reading + NULL, // no security + OPEN_ALWAYS, // don't truncate existing + FILE_ATTRIBUTE_NORMAL, // normal file + NULL // no template file + ); + + delete[] buffer; + + ::SetErrorMode(prev); + + if ( m_Handle == INVALID_HANDLE_VALUE ) + return Kumu::RESULT_FILEOPEN; + + m_IOVec = new h__iovec; + return Kumu::RESULT_OK; +} + +// +Kumu::Result_t +Kumu::FileWriter::Writev(ui32_t* bytes_written) +{ + assert( ! m_IOVec.empty() ); + register h__iovec* iov = m_IOVec; + ui32_t tmp_int; + + if ( bytes_written == 0 ) + bytes_written = &tmp_int; + + if ( m_Handle == INVALID_HANDLE_VALUE ) + return Kumu::RESULT_STATE; + + *bytes_written = 0; + UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX); + Result_t result = Kumu::RESULT_OK; + + // AFAIK, there is no writev() equivalent in the win32 API + for ( register int i = 0; i < iov->m_Count; i++ ) + { + ui32_t tmp_count = 0; + BOOL wr_result = ::WriteFile(m_Handle, + iov->m_iovec[i].iov_base, + iov->m_iovec[i].iov_len, + (DWORD*)&tmp_count, + NULL); + + if ( wr_result == 0 || tmp_count != iov->m_iovec[i].iov_len) + { + result = Kumu::RESULT_WRITEFAIL; + break; + } + + MaybeHash (iov->m_iovec[i].iov_base, iov->m_iovec[i].iov_len); + *bytes_written += tmp_count; + } + + ::SetErrorMode(prev); + iov->m_Count = 0; // error nor not, all is lost + + return result; +} + +// +Kumu::Result_t +Kumu::FileWriter::Write(const byte_t* buf, ui32_t buf_len, ui32_t* bytes_written) +{ + KM_TEST_NULL_L(buf); + ui32_t tmp_int; + + if ( bytes_written == 0 ) + bytes_written = &tmp_int; + + if ( m_Handle == INVALID_HANDLE_VALUE ) + return Kumu::RESULT_STATE; + + // suppress popup window on error + UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX); + BOOL result = ::WriteFile(m_Handle, buf, buf_len, (DWORD*)bytes_written, NULL); + ::SetErrorMode(prev); + + if ( result == 0 || *bytes_written != buf_len ) + return Kumu::RESULT_WRITEFAIL; + + MaybeHash (buf, buf_len); + + return Kumu::RESULT_OK; +} + +#else // KM_WIN32 +//------------------------------------------------------------------------------------------ +// POSIX + +// +Kumu::Result_t +Kumu::FileReader::OpenRead(const char* filename) const +{ + KM_TEST_NULL_STR_L(filename); + const_cast<FileReader*>(this)->m_Filename = filename; + const_cast<FileReader*>(this)->m_Handle = open(filename, O_RDONLY, 0); + return ( m_Handle == -1L ) ? RESULT_FILEOPEN : RESULT_OK; +} + +// +Kumu::Result_t +Kumu::FileReader::Close() const +{ + if ( m_Handle == -1L ) + return RESULT_FILEOPEN; + + close(m_Handle); + const_cast<FileReader*>(this)->m_Handle = -1L; + return RESULT_OK; +} + +// +Kumu::Result_t +Kumu::FileReader::Seek(Kumu::fpos_t position, SeekPos_t whence) const +{ + if ( m_Handle == -1L ) + return RESULT_FILEOPEN; + + if ( lseek(m_Handle, position, whence) == -1L ) + return RESULT_BADSEEK; + + return RESULT_OK; +} + +// +Kumu::Result_t +Kumu::FileReader::Tell(Kumu::fpos_t* pos) const +{ + KM_TEST_NULL_L(pos); + + if ( m_Handle == -1L ) + return RESULT_FILEOPEN; + + Kumu::fpos_t tmp_pos; + + if ( (tmp_pos = lseek(m_Handle, 0, SEEK_CUR)) == -1 ) + return RESULT_READFAIL; + + *pos = tmp_pos; + return RESULT_OK; +} + +// +Kumu::Result_t +Kumu::FileReader::Read(byte_t* buf, ui32_t buf_len, ui32_t* read_count) const +{ + KM_TEST_NULL_L(buf); + i32_t tmp_count = 0; + ui32_t tmp_int = 0; + + if ( read_count == 0 ) + read_count = &tmp_int; + + *read_count = 0; + + if ( m_Handle == -1L ) + return RESULT_FILEOPEN; + + if ( (tmp_count = read(m_Handle, buf, buf_len)) == -1L ) + return RESULT_READFAIL; + + *read_count = tmp_count; + return (tmp_count == 0 ? RESULT_ENDOFFILE : RESULT_OK); +} + + +//------------------------------------------------------------------------------------------ +// + +// +Kumu::Result_t +Kumu::FileWriter::OpenWrite(const char* filename) +{ + KM_TEST_NULL_STR_L(filename); + m_Filename = filename; + m_Handle = open(filename, O_RDWR|O_CREAT|O_TRUNC, 0664); + + if ( m_Handle == -1L ) + { + DefaultLogSink().Error("Error opening file %s: %s\n", filename, strerror(errno)); + return RESULT_FILEOPEN; + } + + m_IOVec = new h__iovec; + return RESULT_OK; +} + +// +Kumu::Result_t +Kumu::FileWriter::OpenModify(const char* filename) +{ + KM_TEST_NULL_STR_L(filename); + m_Filename = filename; + m_Handle = open(filename, O_RDWR|O_CREAT, 0664); + + if ( m_Handle == -1L ) + { + DefaultLogSink().Error("Error opening file %s: %s\n", filename, strerror(errno)); + return RESULT_FILEOPEN; + } + + m_IOVec = new h__iovec; + return RESULT_OK; +} + +// +Kumu::Result_t +Kumu::FileWriter::Writev(ui32_t* bytes_written) +{ + assert( ! m_IOVec.empty() ); + register h__iovec* iov = m_IOVec; + ui32_t tmp_int; + + if ( bytes_written == 0 ) + bytes_written = &tmp_int; + + if ( m_Handle == -1L ) + return RESULT_STATE; + + int total_size = 0; + for ( int i = 0; i < iov->m_Count; i++ ) + total_size += iov->m_iovec[i].iov_len; + + int write_size = writev(m_Handle, iov->m_iovec, iov->m_Count); + + if ( write_size == -1L || write_size != total_size ) + return RESULT_WRITEFAIL; + + for (int i = 0; i < iov->m_Count; ++i) { + MaybeHash (iov->m_iovec[i].iov_base, iov->m_iovec[i].iov_len); + } + + iov->m_Count = 0; + *bytes_written = write_size; + return RESULT_OK; +} + +// +Kumu::Result_t +Kumu::FileWriter::Write(const byte_t* buf, ui32_t buf_len, ui32_t* bytes_written) +{ + KM_TEST_NULL_L(buf); + ui32_t tmp_int; + + if ( bytes_written == 0 ) + bytes_written = &tmp_int; + + if ( m_Handle == -1L ) + return RESULT_STATE; + + int write_size = write(m_Handle, buf, buf_len); + MaybeHash (buf, buf_len); + + if ( write_size == -1L || (ui32_t)write_size != buf_len ) + return RESULT_WRITEFAIL; + + *bytes_written = write_size; + return RESULT_OK; +} + + +#endif + +//------------------------------------------------------------------------------------------ + + +// +Kumu::Result_t +Kumu::ReadFileIntoString(const char* filename, std::string& outString, ui32_t max_size) +{ + fsize_t fsize = 0; + ui32_t read_size = 0; + FileReader File; + ByteString ReadBuf; + + KM_TEST_NULL_STR_L(filename); + + Result_t result = File.OpenRead(filename); + + if ( KM_SUCCESS(result) ) + { + fsize = File.Size(); + + if ( fsize > (Kumu::fpos_t)max_size ) + { + DefaultLogSink().Error("%s: exceeds available buffer size (%u)\n", filename, max_size); + return RESULT_ALLOC; + } + + if ( fsize == 0 ) + { + DefaultLogSink().Error("%s: zero file size\n", filename); + return RESULT_READFAIL; + } + + result = ReadBuf.Capacity((ui32_t)fsize); + } + + if ( KM_SUCCESS(result) ) + result = File.Read(ReadBuf.Data(), ReadBuf.Capacity(), &read_size); + + if ( KM_SUCCESS(result) ) + outString.assign((const char*)ReadBuf.RoData(), read_size); + + return result; +} + + +// +Kumu::Result_t +Kumu::WriteStringIntoFile(const char* filename, const std::string& inString) +{ + FileWriter File; + ui32_t write_count = 0; + KM_TEST_NULL_STR_L(filename); + + Result_t result = File.OpenWrite(filename); + + if ( KM_SUCCESS(result) ) + result = File.Write((byte_t*)inString.c_str(), inString.length(), &write_count); + + return result; +} + +//------------------------------------------------------------------------------------------ + + +// +Kumu::Result_t +Kumu::ReadFileIntoObject(const std::string& Filename, Kumu::IArchive& Object, ui32_t) +{ + ByteString Buffer; + ui32_t file_size = static_cast<ui32_t>(FileSize(Filename)); + Result_t result = Buffer.Capacity(file_size); + + if ( KM_SUCCESS(result) ) + { + ui32_t read_count = 0; + FileWriter Reader; + + result = Reader.OpenRead(Filename.c_str()); + + if ( KM_SUCCESS(result) ) + result = Reader.Read(Buffer.Data(), file_size, &read_count); + + if ( KM_SUCCESS(result) ) + { + assert(file_size == read_count); + Buffer.Length(read_count); + MemIOReader MemReader(&Buffer); + result = Object.Unarchive(&MemReader) ? RESULT_OK : RESULT_READFAIL; + } + } + + return result; +} + +// +Kumu::Result_t +Kumu::WriteObjectIntoFile(const Kumu::IArchive& Object, const std::string& Filename) +{ + ByteString Buffer; + Result_t result = Buffer.Capacity(Object.ArchiveLength()); + + if ( KM_SUCCESS(result) ) + { + ui32_t write_count = 0; + FileWriter Writer; + MemIOWriter MemWriter(&Buffer); + + result = Object.Archive(&MemWriter) ? RESULT_OK : RESULT_WRITEFAIL; + + if ( KM_SUCCESS(result) ) + { + Buffer.Length(MemWriter.Length()); + result = Writer.OpenWrite(Filename.c_str()); + } + + if ( KM_SUCCESS(result) ) + result = Writer.Write(Buffer.RoData(), Buffer.Length(), &write_count); + } + + return result; +} + +//------------------------------------------------------------------------------------------ +// + +// +Result_t +Kumu::ReadFileIntoBuffer(const std::string& Filename, Kumu::ByteString& Buffer, ui32_t) +{ + ui32_t file_size = FileSize(Filename); + Result_t result = Buffer.Capacity(file_size); + + if ( KM_SUCCESS(result) ) + { + ui32_t read_count = 0; + FileWriter Reader; + + result = Reader.OpenRead(Filename.c_str()); + + if ( KM_SUCCESS(result) ) + result = Reader.Read(Buffer.Data(), file_size, &read_count); + + if ( KM_SUCCESS(result) ) + { + if ( file_size != read_count) + return RESULT_READFAIL; + + Buffer.Length(read_count); + } + } + + return result; +} + +// +Result_t +Kumu::WriteBufferIntoFile(const Kumu::ByteString& Buffer, const std::string& Filename) +{ + ui32_t write_count = 0; + FileWriter Writer; + + Result_t result = Writer.OpenWrite(Filename.c_str()); + + if ( KM_SUCCESS(result) ) + result = Writer.Write(Buffer.RoData(), Buffer.Length(), &write_count); + + if ( KM_SUCCESS(result) && Buffer.Length() != write_count) + return RESULT_WRITEFAIL; + + return result; +} + +//------------------------------------------------------------------------------------------ +// + +Kumu::DirScanner::DirScanner() +{ + +} + +Result_t +Kumu::DirScanner::Open (const char* filename) +{ + KM_TEST_NULL_L (filename); + + if (!boost::filesystem::is_directory(filename)) { + return RESULT_NOT_FOUND; + } + + _iterator = boost::filesystem::directory_iterator (filename); + return RESULT_OK; +} + +Result_t +Kumu::DirScanner::GetNext (char* filename) +{ + KM_TEST_NULL_L (filename); + + if (_iterator == boost::filesystem::directory_iterator()) { + return RESULT_ENDOFFILE; + } + +#if BOOST_FILESYSTEM_VERSION == 3 + std::string f = boost::filesystem::path(*_iterator).filename().generic_string(); +#else + std::string f = boost::filesystem::path(*_iterator).filename(); +#endif + strncpy (filename, f.c_str(), MaxFilePath); + ++_iterator; + return RESULT_OK; +} + +//------------------------------------------------------------------------------------------ + +// +// Attention Windows users: make sure to use the proper separator character +// with these functions. +// + +// given a path string, create any missing directories so that PathIsDirectory(Path) is true. +// +Result_t +Kumu::CreateDirectoriesInPath(const std::string& Path) +{ + bool abs = PathIsAbsolute(Path); + PathCompList_t PathComps, TmpPathComps; + + PathToComponents(Path, PathComps); + + while ( ! PathComps.empty() ) + { + TmpPathComps.push_back(PathComps.front()); + PathComps.pop_front(); + std::string tmp_path = abs ? ComponentsToAbsolutePath(TmpPathComps) : ComponentsToPath(TmpPathComps); + + if ( ! PathIsDirectory(tmp_path) ) + { +#ifdef KM_WIN32 + if ( _mkdir(tmp_path.c_str()) != 0 ) +#else // KM_WIN32 + if ( mkdir(tmp_path.c_str(), 0775) != 0 ) +#endif // KM_WIN32 + { + DefaultLogSink().Error("CreateDirectoriesInPath mkdir %s: %s\n", + tmp_path.c_str(), strerror(errno)); + return RESULT_DIR_CREATE; + } + } + } + + return RESULT_OK; +} + + +// +Result_t +Kumu::DeleteFile(const std::string& filename) +{ + if ( _unlink(filename.c_str()) == 0 ) + return RESULT_OK; + + switch ( errno ) + { + case ENOENT: + case ENOTDIR: return RESULT_NOTAFILE; + + case EROFS: + case EBUSY: + case EACCES: + case EPERM: return RESULT_NO_PERM; + } + + DefaultLogSink().Error("DeleteFile %s: %s\n", filename.c_str(), strerror(errno)); + return RESULT_FAIL; +} + +// +Result_t +h__DeletePath(const std::string& pathname) +{ + if ( pathname.empty() ) + return RESULT_NULL_STR; + + Result_t result = RESULT_OK; + + if ( ! PathIsDirectory(pathname) ) + { + result = DeleteFile(pathname); + } + else + { + { + DirScanner TestDir; + char next_file[Kumu::MaxFilePath]; + result = TestDir.Open(pathname.c_str()); + + while ( KM_SUCCESS(result) && KM_SUCCESS(TestDir.GetNext(next_file)) ) + { + if ( next_file[0] == '.' ) + { + if ( next_file[1] == 0 ) + continue; // don't delete 'this' + + if ( next_file[1] == '.' && next_file[2] == 0 ) + continue; // don't delete 'this' parent + } + + result = h__DeletePath(pathname + std::string("/") + next_file); + } + } + + if ( _rmdir(pathname.c_str()) != 0 ) + { + switch ( errno ) + { + case ENOENT: + case ENOTDIR: + result = RESULT_NOTAFILE; + break; + + case EROFS: + case EBUSY: + case EACCES: + case EPERM: + result = RESULT_NO_PERM; + break; + + default: + DefaultLogSink().Error("DeletePath %s: %s\n", pathname.c_str(), strerror(errno)); + result = RESULT_FAIL; + } + } + } + + return result; +} + +// +Result_t +Kumu::DeletePath(const std::string& pathname) +{ + std::string c_pathname = PathMakeAbsolute(PathMakeCanonical(pathname)); + DefaultLogSink().Debug("DeletePath (%s) c(%s)\n", pathname.c_str(), c_pathname.c_str()); + return h__DeletePath(c_pathname); +} + + +//------------------------------------------------------------------------------------------ +// + + +Result_t +Kumu::FreeSpaceForPath(const std::string& path, Kumu::fsize_t& free_space, Kumu::fsize_t& total_space) +{ +#ifdef KM_WIN32 + ULARGE_INTEGER lTotalNumberOfBytes; + ULARGE_INTEGER lTotalNumberOfFreeBytes; + + BOOL fResult = ::GetDiskFreeSpaceExA(path.c_str(), NULL, &lTotalNumberOfBytes, &lTotalNumberOfFreeBytes); + if (fResult) { + free_space = static_cast<Kumu::fsize_t>(lTotalNumberOfFreeBytes.QuadPart); + total_space = static_cast<Kumu::fsize_t>(lTotalNumberOfBytes.QuadPart); + return RESULT_OK; + } + HRESULT LastError = ::GetLastError(); + + DefaultLogSink().Error("FreeSpaceForPath GetDiskFreeSpaceEx %s: %lu\n", path.c_str(), ::GetLastError()); + return RESULT_FAIL; +#else // KM_WIN32 + struct statfs s; + + if ( statfs(path.c_str(), &s) == 0 ) + { + if ( s.f_blocks < 1 ) + { + DefaultLogSink().Error("File system %s has impossible size: %ld\n", + path.c_str(), s.f_blocks); + return RESULT_FAIL; + } + + free_space = (Kumu::fsize_t)s.f_bsize * (Kumu::fsize_t)s.f_bavail; + total_space = (Kumu::fsize_t)s.f_bsize * (Kumu::fsize_t)s.f_blocks; + return RESULT_OK; + } + + switch ( errno ) + { + case ENOENT: + case ENOTDIR: return RESULT_NOTAFILE; + case EACCES: return RESULT_NO_PERM; + } + + DefaultLogSink().Error("FreeSpaceForPath statfs %s: %s\n", path.c_str(), strerror(errno)); + return RESULT_FAIL; +#endif // KM_WIN32 +} + + +// +// end KM_fileio.cpp +// diff --git a/asdcplib/src/KM_fileio.h b/asdcplib/src/KM_fileio.h new file mode 100755 index 0000000..cb00acc --- /dev/null +++ b/asdcplib/src/KM_fileio.h @@ -0,0 +1,342 @@ +/* +Copyright (c) 2004-2009, 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 KM_fileio.h + \version $Id: KM_fileio.h,v 1.17 2009/06/22 05:49:02 jhurst Exp $ + \brief portable file i/o + */ + +#ifndef _KM_FILEIO_H_ +#define _KM_FILEIO_H_ + +#include <KM_util.h> +#include <string> +#include <boost/filesystem.hpp> +#include <openssl/md5.h> + +#ifdef KM_WIN32 +# include <io.h> +#else +# include <dirent.h> +# include <unistd.h> +# include <time.h> +# include <sys/types.h> +#include <regex.h> +#endif + +#include <sys/stat.h> + + + +namespace Kumu +{ + class DirScanner + { + public: + DirScanner(); + Result_t Open(const char *); + Result_t GetNext(char *); + Result_t Close(); + private: + boost::filesystem::directory_iterator _iterator; + }; + +#ifdef KM_WIN32 + typedef __int64 fsize_t; + typedef __int64 fpos_t; + typedef HANDLE FileHandle; + + enum SeekPos_t { + SP_BEGIN = FILE_BEGIN, + SP_POS = FILE_CURRENT, + SP_END = FILE_END + }; +#else + typedef off_t fsize_t; + typedef off_t fpos_t; + typedef int FileHandle; + const FileHandle INVALID_HANDLE_VALUE = -1L; + + enum SeekPos_t { + SP_BEGIN = SEEK_SET, + SP_POS = SEEK_CUR, + SP_END = SEEK_END + }; +#endif + + // +#ifndef KM_SMALL_FILES_OK + template <bool sizecheck> void compile_time_size_checker(); + template <> inline void compile_time_size_checker<false>() {} + // + // READ THIS if your compiler is complaining about a previously declared implementation of + // compile_time_size_checker(). For example, GCC 4.0.1 looks like this: + // + // error: 'void Kumu::compile_time_size_checker() [with bool sizecheck = false]' previously declared here + // + // This is happening because the equality being tested below is false. The reason for this + // will depend on your OS, but on Linux it is probably because you have not used -D_FILE_OFFSET_BITS=64 + // Adding this magic macro to your CFLAGS will get you going again. If you are on a system that + // does not support 64-bit files, you can disable this check by using -DKM_SMALL_FILES_OK. You + // will then of course be limited to file sizes < 4GB. + // + template <> inline void compile_time_size_checker<sizeof(Kumu::fsize_t)==sizeof(ui64_t)>() {} +#endif + // + + const ui32_t Kilobyte = 1024; + const ui32_t Megabyte = Kilobyte * Kilobyte; + const ui32_t Gigabyte = Megabyte * Kilobyte; + + const ui32_t MaxFilePath = Kilobyte; + + + //------------------------------------------------------------------------------------------ + // Path Manglers + //------------------------------------------------------------------------------------------ + + // types + typedef std::list<std::string> PathCompList_t; // a list of path components + typedef std::list<std::string> PathList_t; // a list of paths + + // tests + bool PathExists(const std::string& Path); // true if the path exists in the filesystem + bool PathIsFile(const std::string& Path); // true if the path exists in the filesystem and is a file + bool PathIsDirectory(const std::string& Path); // true if the path exists in the filesystem and is a directory + fsize_t FileSize(const std::string& Path); // returns the size of a regular file, 0 for a directory or device + bool PathsAreEquivalent(const std::string& lhs, const std::string& rhs); // true if paths point to the same filesystem entry + + // Returns free space and total space available for the given path + Result_t FreeSpaceForPath(const std::string& path, Kumu::fsize_t& free_space, Kumu::fsize_t& total_space); + + // split and reassemble paths as lists of path components + PathCompList_t& PathToComponents(const std::string& Path, PathCompList_t& CList, char separator = '/'); // removes '//' + std::string ComponentsToPath(const PathCompList_t& CList, char separator = '/'); + std::string ComponentsToAbsolutePath(const PathCompList_t& CList, char separator = '/'); // add separator to the front + bool PathHasComponents(const std::string& Path, char separator = '/'); // true if paths starts with separator + + bool PathIsAbsolute(const std::string& Path, char separator = '/'); // true if path begins with separator + std::string PathMakeAbsolute(const std::string& Path, char separator = '/'); // compute position of relative path using getcwd() + std::string PathMakeLocal(const std::string& Path, const std::string& Parent); // remove Parent from front of Path, if it exists + std::string PathMakeCanonical(const std::string& Path, char separator = '/'); // remove '.' and '..' + + // common operations + std::string PathBasename(const std::string& Path, char separator = '/'); // returns right-most path element (list back()) + std::string PathDirname(const std::string& Path, char separator = '/'); // returns everything but the right-most element + std::string PathGetExtension(const std::string& Path); // returns everything in the right-most element following the right-most '.' + std::string PathSetExtension(const std::string& Path, const std::string& Extension); // empty extension removes '.' as well + + std::string PathJoin(const std::string& Path1, const std::string& Path2, char separator = '/'); + std::string PathJoin(const std::string& Path1, const std::string& Path2, const std::string& Path3, char separator = '/'); + std::string PathJoin(const std::string& Path1, const std::string& Path2, + const std::string& Path3, const std::string& Path4, char separator = '/'); + + + //------------------------------------------------------------------------------------------ + // Path Search + //------------------------------------------------------------------------------------------ + + // An interface for a path matching function, used by FindInPath() and FindInPaths() below + // + class IPathMatch + { + public: + virtual ~IPathMatch() {} + virtual bool Match(const std::string& s) const = 0; + }; + + // matches any pathname + class PathMatchAny : public IPathMatch + { + public: + virtual ~PathMatchAny() {} + inline bool Match(const std::string&) const { return true; } + }; + +#ifndef KM_WIN32 + // matches pathnames using a regular expression + class PathMatchRegex : public IPathMatch + { + regex_t m_regex; + PathMatchRegex(); + const PathMatchRegex& operator=(const PathMatchRegex&); + + public: + PathMatchRegex(const std::string& Pattern); + PathMatchRegex(const PathMatchRegex&); + virtual ~PathMatchRegex(); + bool Match(const std::string& s) const; + }; + + // matches pathnames using a Bourne shell glob expression + class PathMatchGlob : public IPathMatch + { + regex_t m_regex; + PathMatchGlob(); + const PathMatchGlob& operator=(const PathMatchGlob&); + + public: + PathMatchGlob(const std::string& Pattern); + PathMatchGlob(const PathMatchGlob&); + virtual ~PathMatchGlob(); + bool Match(const std::string& s) const; + }; +#endif /* !KM_WIN32 */ + + // Search all paths in SearchPaths for filenames matching Pattern (no directories are returned). + // Put results in FoundPaths. Returns after first find if one_shot is true. + PathList_t& FindInPath(const IPathMatch& Pattern, const std::string& SearchDir, + PathList_t& FoundPaths, bool one_shot = false, char separator = '/'); + + PathList_t& FindInPaths(const IPathMatch& Pattern, const PathList_t& SearchPaths, + PathList_t& FoundPaths, bool one_shot = false, char separator = '/'); + + //------------------------------------------------------------------------------------------ + // Directory Manipulation + //------------------------------------------------------------------------------------------ + + // Create a directory, creates intermediate directories as necessary + Result_t CreateDirectoriesInPath(const std::string& Path); + + // Delete a file (fails if the path points to a directory) + Result_t DeleteFile(const std::string& filename); + + // Recursively remove a file or directory + Result_t DeletePath(const std::string& pathname); + + //------------------------------------------------------------------------------------------ + // File I/O Wrappers + //------------------------------------------------------------------------------------------ + + // Instant IO for strings + // + // Reads an entire file into a string. + Result_t ReadFileIntoString(const char* filename, std::string& outString, ui32_t max_size = 8 * Megabyte); + + // Writes a string to a file, overwrites the existing file if present. + Result_t WriteStringIntoFile(const char* filename, const std::string& inString); + + // Instant IO for archivable objects + // + // Unarchives a file into an object + Result_t ReadFileIntoObject(const std::string& Filename, IArchive& Object, ui32_t max_size = 8 * Kumu::Megabyte); + + // Archives an object into a file + Result_t WriteObjectIntoFile(const IArchive& Object, const std::string& Filename); + + // Instant IO for memory buffers + // + // Unarchives a file into a buffer + Result_t ReadFileIntoBuffer(const std::string& Filename, Kumu::ByteString& Buffer, + ui32_t max_size = 8 * Kumu::Megabyte); + + // Archives a buffer into a file + Result_t WriteBufferIntoFile(const Kumu::ByteString& Buffer, const std::string& Filename); + + + //------------------------------------------------------------------------------------------ + // File I/O + //------------------------------------------------------------------------------------------ + + // + class FileReader + { + KM_NO_COPY_CONSTRUCT(FileReader); + + protected: + std::string m_Filename; + FileHandle m_Handle; + + public: + FileReader() : m_Handle(INVALID_HANDLE_VALUE) {} + virtual ~FileReader() { Close(); } + + Result_t OpenRead(const char*) const; // open the file for reading + Result_t Close() const; // close the file + fsize_t Size() const; // returns the file's current size + Result_t Seek(Kumu::fpos_t = 0, SeekPos_t = SP_BEGIN) const; // move the file pointer + Result_t Tell(Kumu::fpos_t* pos) const; // report the file pointer's location + Result_t Read(byte_t*, ui32_t, ui32_t* = 0) const; // read a buffer of data + + inline Kumu::fpos_t Tell() const // report the file pointer's location + { + Kumu::fpos_t tmp_pos; + Tell(&tmp_pos); + return tmp_pos; + } + + inline bool IsOpen() { // returns true if the file is open + return (m_Handle != INVALID_HANDLE_VALUE); + } + }; + + // + class FileWriter : public FileReader + { + class h__iovec; + mem_ptr<h__iovec> m_IOVec; + KM_NO_COPY_CONSTRUCT(FileWriter); + bool m_Hashing; + MD5_CTX m_MD5Context; + + public: + FileWriter(); + virtual ~FileWriter(); + + Result_t OpenWrite(const char*); // open a new file, overwrites existing + Result_t OpenModify(const char*); // open a file for read/write + + // this part of the interface takes advantage of the iovec structure on + // platforms that support it. For each call to Writev(const byte_t*, ui32_t, ui32_t*), + // the given buffer is added to an internal iovec struct. All items on the list + // are written to disk by a call to Writev(); + Result_t Writev(const byte_t*, ui32_t); // queue buffer for "gather" write + Result_t Writev(ui32_t* = 0); // write all queued buffers + + // if you call this while there are unwritten items on the iovec list, + // the iovec list will be written to disk before the given buffer,as though + // you had called Writev() first. + Result_t Write(const byte_t*, ui32_t, ui32_t* = 0); // write buffer to disk + + void StartHashing(); + void MaybeHash(void const *, int); + std::string StopHashing(); + }; + + Result_t CreateDirectoriesInPath(const std::string& Path); + Result_t FreeSpaceForPath(const std::string& path, Kumu::fsize_t& free_space, Kumu::fsize_t& total_space); + Result_t DeleteFile(const std::string& filename); + Result_t DeletePath(const std::string& pathname); + +} // namespace Kumu + + +#endif // _KM_FILEIO_H_ + + +// +// end KM_fileio.h +// diff --git a/asdcplib/src/KM_log.cpp b/asdcplib/src/KM_log.cpp new file mode 100755 index 0000000..7bd5926 --- /dev/null +++ b/asdcplib/src/KM_log.cpp @@ -0,0 +1,379 @@ +/* +Copyright (c) 2004-2011, 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 KM_log.cpp + \version $Id: KM_log.cpp,v 1.15 2011/03/08 19:03:47 jhurst Exp $ + \brief message logging API + */ + +#include <KM_util.h> +#include <KM_log.h> +#include <KM_mutex.h> +#include <sys/types.h> +#include <string.h> +#include <stdarg.h> +#include <iostream> +#include <sstream> + +#ifdef KM_WIN32 +#define getpid GetCurrentProcessId +#else +#include <unistd.h> +#endif + +//------------------------------------------------------------------------------------------ +// + +void +Kumu::ILogSink::vLogf(LogType_t type, const char* fmt, va_list* list) +{ + char buf[MaxLogLength]; + vsnprintf(buf, MaxLogLength, fmt, *list); + + WriteEntry(LogEntry(getpid(), type, buf)); +} + +//------------------------------------------------------------------------------------------ +// + +static Kumu::Mutex s_DefaultLogSinkLock; +static Kumu::ILogSink* s_DefaultLogSink = 0; +static Kumu::StdioLogSink s_StderrLogSink; + +// +void +Kumu::SetDefaultLogSink(ILogSink* Sink) +{ + AutoMutex L(s_DefaultLogSinkLock); + s_DefaultLogSink = Sink; +} + +// Returns the internal default sink. +Kumu::ILogSink& +Kumu::DefaultLogSink() +{ + AutoMutex L(s_DefaultLogSinkLock); + + if ( s_DefaultLogSink == 0 ) + s_DefaultLogSink = &s_StderrLogSink; + + return *s_DefaultLogSink; +} + + +//------------------------------------------------------------------------------------------ +// + +void +Kumu::EntryListLogSink::WriteEntry(const LogEntry& Entry) +{ + AutoMutex L(m_Lock); + + if ( Entry.TestFilter(m_filter) ) + m_Target.push_back(Entry); +} + +//------------------------------------------------------------------------------------------ +// + +void +Kumu::StdioLogSink::WriteEntry(const LogEntry& Entry) +{ + AutoMutex L(m_Lock); + std::string buf; + + if ( Entry.TestFilter(m_filter) ) + { + Entry.CreateStringWithOptions(buf, m_options); + fputs(buf.c_str(), m_stream); + } +} + +//--------------------------------------------------------------------------------- + +#ifdef KM_WIN32 +// +// http://www.codeguru.com/forum/showthread.php?t=231165 +// +void +Kumu::WinDbgLogSink::WriteEntry(const LogEntry& Entry) +{ + AutoMutex L(m_Lock); + std::string buf; + + if ( Entry.TestFilter(m_filter) ) + { + Entry.CreateStringWithOptions(buf, m_options); + ::OutputDebugStringA(buf.c_str()); + } +} +#endif + +//------------------------------------------------------------------------------------------ +// + +#ifndef KM_WIN32 +// +void +Kumu::StreamLogSink::WriteEntry(const LogEntry& Entry) +{ + AutoMutex L(m_Lock); + std::string buf; + + if ( Entry.TestFilter(m_filter) ) + { + Entry.CreateStringWithOptions(buf, m_options); + write(m_fd, buf.c_str(), buf.size()); + } +} + +// foolin with symbols +//------------------------------------------------------------------------------------------ +#include <syslog.h> +int const SYSLOG_ALERT = LOG_ALERT; +int const SYSLOG_CRIT = LOG_CRIT; +int const SYSLOG_ERR = LOG_ERR; +int const SYSLOG_WARNING = LOG_WARNING; +int const SYSLOG_NOTICE = LOG_NOTICE; +int const SYSLOG_INFO = LOG_INFO; +int const SYSLOG_DEBUG = LOG_DEBUG; +#undef LOG_ALERT +#undef LOG_CRIT +#undef LOG_ERR +#undef LOG_WARNING +#undef LOG_NOTICE +#undef LOG_INFO +#undef LOG_DEBUG +//------------------------------------------------------------------------------------------ + +Kumu::SyslogLogSink::SyslogLogSink(const std::string& source_name, int facility) +{ + if ( facility == 0 ) + facility = LOG_DAEMON; + + openlog(source_name.c_str(), LOG_CONS|LOG_NDELAY||LOG_PID, facility); +} + +Kumu::SyslogLogSink::~SyslogLogSink() +{ + closelog(); +} + +// +void +Kumu::SyslogLogSink::WriteEntry(const LogEntry& Entry) +{ + int priority = 0; + + switch ( Entry.Type ) + { + case Kumu::LOG_ALERT: priority = SYSLOG_ALERT; break; + case Kumu::LOG_CRIT: priority = SYSLOG_CRIT; break; + case Kumu::LOG_ERROR: priority = SYSLOG_ERR; break; + case Kumu::LOG_WARN: priority = SYSLOG_WARNING; break; + case Kumu::LOG_NOTICE: priority = SYSLOG_NOTICE; break; + case Kumu::LOG_INFO: priority = SYSLOG_INFO; break; + case Kumu::LOG_DEBUG: priority = SYSLOG_DEBUG; break; + } + + AutoMutex L(m_Lock); + + if ( Entry.TestFilter(m_filter) ) + { + syslog(priority, "%s", Entry.Msg.substr(0, Entry.Msg.size() - 1).c_str()); + } +} + +// +int +Kumu::SyslogNameToFacility(const std::string& facility_name) +{ + if ( facility_name == "LOG_DAEMON" ) return LOG_DAEMON; + if ( facility_name == "LOG_LOCAL0" ) return LOG_LOCAL0; + if ( facility_name == "LOG_LOCAL1" ) return LOG_LOCAL1; + if ( facility_name == "LOG_LOCAL2" ) return LOG_LOCAL2; + if ( facility_name == "LOG_LOCAL3" ) return LOG_LOCAL3; + if ( facility_name == "LOG_LOCAL4" ) return LOG_LOCAL4; + if ( facility_name == "LOG_LOCAL5" ) return LOG_LOCAL5; + if ( facility_name == "LOG_LOCAL6" ) return LOG_LOCAL6; + if ( facility_name == "LOG_LOCAL7" ) return LOG_LOCAL7; + + DefaultLogSink().Error("Unsupported facility name: %s, using default value LOG_DAEMON\n", facility_name.c_str()); + return LOG_DAEMON; +} + +#endif + +//------------------------------------------------------------------------------------------ + +// +std::basic_ostream<char, std::char_traits<char> >& +Kumu::operator<<(std::basic_ostream<char, std::char_traits<char> >& strm, LogEntry const& Entry) +{ + std::basic_ostringstream<char, std::char_traits<char> > s; + s.copyfmt(strm); + s.width(0); + std::string buf; + + s << Entry.CreateStringWithOptions(buf, LOG_OPTION_ALL); + + strm << s.str(); + return strm; +} + +//------------------------------------------------------------------------------------------ + + +// +bool +Kumu::LogEntry::TestFilter(i32_t filter) const +{ + switch ( Type ) + { + case LOG_CRIT: + if ( (filter & LOG_ALLOW_CRIT) == 0 ) + return false; + break; + + case LOG_ALERT: + if ( (filter & LOG_ALLOW_ALERT) == 0 ) + return false; + break; + + case LOG_NOTICE: + if ( (filter & LOG_ALLOW_NOTICE) == 0 ) + return false; + break; + + case LOG_ERROR: + if ( (filter & LOG_ALLOW_ERROR) == 0 ) + return false; + break; + + case LOG_WARN: + if ( (filter & LOG_ALLOW_WARN) == 0 ) + return false; + break; + + case LOG_INFO: + if ( (filter & LOG_ALLOW_INFO) == 0 ) + return false; + break; + + case LOG_DEBUG: + if ( (filter & LOG_ALLOW_DEBUG) == 0 ) + return false; + break; + + } + + return true; +} + +// +std::string& +Kumu::LogEntry::CreateStringWithOptions(std::string& out_buf, i32_t opt) const +{ + out_buf.erase(); + + if ( opt != 0 ) + { + char buf[64]; + + if ( (opt & LOG_OPTION_TIMESTAMP) != 0 ) + { + Timestamp Now; + out_buf += Now.EncodeString(buf, 64); + } + + if ( (opt & LOG_OPTION_PID) != 0 ) + { + if ( ! out_buf.empty() ) out_buf += " "; + snprintf(buf, 64, "%d", PID); + out_buf += buf; + } + + if ( (opt & LOG_OPTION_TYPE) != 0 ) + { + if ( ! out_buf.empty() ) out_buf += " "; + + switch ( Type ) + { + case LOG_CRIT: out_buf += "CRT"; break; + case LOG_ALERT: out_buf += "ALR"; break; + case LOG_NOTICE: out_buf += "NTC"; break; + case LOG_ERROR: out_buf += "ERR"; break; + case LOG_WARN: out_buf += "WRN"; break; + case LOG_INFO: out_buf += "INF"; break; + case LOG_DEBUG: out_buf += "DBG"; break; + default: out_buf += "DFL"; break; + } + } + + out_buf.insert(0, "["); + out_buf += "]: "; + } + + out_buf += Msg; + return out_buf; +} + + +// +ui32_t +Kumu::LogEntry::ArchiveLength() const +{ + return sizeof(ui32_t) + + EventTime.ArchiveLength() + + sizeof(ui32_t) + + sizeof(ui32_t) + Msg.size(); +} + +// +bool +Kumu::LogEntry::Archive(Kumu::MemIOWriter* Writer) const +{ + if ( ! Writer->WriteUi32BE(PID) ) return false; + if ( ! EventTime.Archive(Writer) ) return false; + if ( ! Writer->WriteUi32BE(Type) ) return false; + if ( ! ArchiveString(*Writer, Msg) ) return false; + return true; +} + +// +bool +Kumu::LogEntry::Unarchive(Kumu::MemIOReader* Reader) +{ + if ( ! Reader->ReadUi32BE(&PID) ) return false; + if ( ! EventTime.Unarchive(Reader) ) return false; + if ( ! Reader->ReadUi32BE((ui32_t*)&Type) ) return false; + if ( ! UnarchiveString(*Reader, Msg) ) return false; + return true; +} + +// +// end +// diff --git a/asdcplib/src/KM_log.h b/asdcplib/src/KM_log.h new file mode 100755 index 0000000..4981b17 --- /dev/null +++ b/asdcplib/src/KM_log.h @@ -0,0 +1,321 @@ +/* +Copyright (c) 2004-2009, 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 KM_log.h + \version $Id: KM_log.h,v 1.13 2011/03/05 19:15:35 jhurst Exp $ + \brief message logging API + */ + + +#ifndef _KM_LOG_H_ +#define _KM_LOG_H_ + +#include <KM_platform.h> +#include <KM_mutex.h> +#include <KM_util.h> +#include <stdarg.h> +#include <errno.h> +#include <iosfwd> + +#define LOG_MSG_IMPL(t) \ + va_list args; \ + va_start(args, fmt); \ + vLogf((t), fmt, &args); \ + va_end(args) + +// Returns RESULT_PTR if the given argument is NULL. +# define KM_TEST_NULL_L(p) \ + if ( (p) == 0 ) { \ + DefaultLogSink().Error("NULL pointer in file %s, line %d\n", __FILE__, __LINE__); \ + return Kumu::RESULT_PTR; \ + } + +// Returns RESULT_PTR if the given argument is NULL. It then +// assumes that the argument is a pointer to a string and returns +// RESULT_NULL_STR if the first character is '\0'. +// +# define KM_TEST_NULL_STR_L(p) \ + KM_TEST_NULL_L(p); \ + if ( (p)[0] == '\0' ) { \ + DefaultLogSink().Error("Empty string in file %s, line %d\n", __FILE__, __LINE__); \ + return Kumu::RESULT_NULL_STR; \ + } + + +namespace Kumu +{ + // no log message will exceed this length + const ui32_t MaxLogLength = 512; + + //--------------------------------------------------------------------------------- + // message logging + + // Log messages are recorded by objects which implement the interface given + // in the class ILogSink below. The library maintains a pointer to a default + // log sink which is used by the library to report messages. + // + + // types of log messages + enum LogType_t { + LOG_DEBUG, // detailed developer info + LOG_INFO, // developer info + LOG_WARN, // library non-fatal or near-miss error + LOG_ERROR, // library fatal error + LOG_NOTICE, // application user info + LOG_ALERT, // application non-fatal or near-miss error + LOG_CRIT, // application fatal error + }; + + + // OR these values together to come up with sink filter flags. + // The default mask is LOG_ALLOW_ALL (all messages). + const i32_t LOG_ALLOW_DEBUG = 0x00000001; + const i32_t LOG_ALLOW_INFO = 0x00000002; + const i32_t LOG_ALLOW_WARN = 0x00000004; + const i32_t LOG_ALLOW_ERROR = 0x00000008; + const i32_t LOG_ALLOW_NOTICE = 0x00000010; + const i32_t LOG_ALLOW_ALERT = 0x00000020; + const i32_t LOG_ALLOW_CRIT = 0x00000040; + const i32_t LOG_ALLOW_NONE = 0x00000000; + const i32_t LOG_ALLOW_ALL = 0x000fffff; + + // options are used to control display format default is 0. + const i32_t LOG_OPTION_TYPE = 0x01000000; + const i32_t LOG_OPTION_TIMESTAMP = 0x02000000; + const i32_t LOG_OPTION_PID = 0x04000000; + const i32_t LOG_OPTION_NONE = 0x00000000; + const i32_t LOG_OPTION_ALL = 0xfff00000; + + // A log message with environmental metadata + class LogEntry : public IArchive + { + public: + ui32_t PID; + Timestamp EventTime; + LogType_t Type; + std::string Msg; + + LogEntry() {} + LogEntry(ui32_t pid, LogType_t t, const char* m) : PID(pid), Type(t), Msg(m) { assert(m); } + virtual ~LogEntry() {} + + // returns true if the message Type is present in the mask + bool TestFilter(i32_t mask_value) const; + + // renders the message into outstr using the given dispaly options + // returns outstr& + std::string& CreateStringWithOptions(std::string& outstr, i32_t mask_value) const; + + // IArchive + bool HasValue() const { return ! Msg.empty(); } + ui32_t ArchiveLength() const; + bool Archive(MemIOWriter* Writer) const; + bool Unarchive(MemIOReader* Reader); + }; + + // + std::basic_ostream<char, std::char_traits<char> >& + operator<<(std::basic_ostream<char, std::char_traits<char> >& strm, LogEntry const& Entry); + + + typedef ArchivableList<LogEntry> LogEntryList; + + // + class ILogSink + { + protected: + i32_t m_filter; + i32_t m_options; + + public: + ILogSink() : m_filter(LOG_ALLOW_ALL), m_options(LOG_OPTION_NONE) {} + virtual ~ILogSink() {} + + void SetFilterFlag(i32_t f) { m_filter |= f; } + void UnsetFilterFlag(i32_t f) { m_filter &= ~f; } + bool TestFilterFlag(i32_t f) const { return ((m_filter & f) == f); } + + void SetOptionFlag(i32_t o) { m_options |= o; } + void UnsetOptionFlag(i32_t o) { m_options &= ~o; } + bool TestOptionFlag(i32_t o) const { return ((m_options & o) == o); } + + // library messages + void Error(const char* fmt, ...) { LOG_MSG_IMPL(LOG_ERROR); } + void Warn(const char* fmt, ...) { LOG_MSG_IMPL(LOG_WARN); } + void Info(const char* fmt, ...) { LOG_MSG_IMPL(LOG_INFO); } + void Debug(const char* fmt, ...) { LOG_MSG_IMPL(LOG_DEBUG); } + + // application messages + void Critical(const char* fmt, ...) { LOG_MSG_IMPL(LOG_CRIT); } + void Alert(const char* fmt, ...) { LOG_MSG_IMPL(LOG_ALERT); } + void Notice(const char* fmt, ...) { LOG_MSG_IMPL(LOG_NOTICE); } + + // message with type + void Logf(LogType_t type, const char* fmt, ...) { LOG_MSG_IMPL(type); } + + // actual log sink input + virtual void vLogf(LogType_t, const char*, va_list*); + virtual void WriteEntry(const LogEntry&) = 0; + }; + + + // 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(); + + + // Sets a log sink as the default until the object is destroyed. + // The original default sink is saved and then restored on delete. + class LogSinkContext + { + KM_NO_COPY_CONSTRUCT(LogSinkContext); + LogSinkContext(); + ILogSink* m_orig; + + public: + LogSinkContext(ILogSink& sink) { + m_orig = &DefaultLogSink(); + SetDefaultLogSink(&sink); + } + + ~LogSinkContext() { + SetDefaultLogSink(m_orig); + } + }; + + //------------------------------------------------------------------------------------------ + // + + // write messages to two subordinate log sinks + class TeeLogSink : public ILogSink + { + KM_NO_COPY_CONSTRUCT(TeeLogSink); + TeeLogSink(); + + ILogSink& m_a; + ILogSink& m_b; + + public: + TeeLogSink(ILogSink& a, ILogSink& b) : m_a(a), m_b(b) {} + virtual ~TeeLogSink() {} + + void WriteEntry(const LogEntry& Entry) { + m_a.WriteEntry(Entry); + m_b.WriteEntry(Entry); + } + }; + + // collect log messages into the given list, does not test filter + class EntryListLogSink : public ILogSink + { + Mutex m_Lock; + LogEntryList& m_Target; + KM_NO_COPY_CONSTRUCT(EntryListLogSink); + EntryListLogSink(); + + public: + EntryListLogSink(LogEntryList& target) : m_Target(target) {} + virtual ~EntryListLogSink() {} + + void WriteEntry(const LogEntry& Entry); + }; + + + // write messages to a POSIX stdio stream + class StdioLogSink : public ILogSink + { + Mutex m_Lock; + FILE* m_stream; + KM_NO_COPY_CONSTRUCT(StdioLogSink); + + public: + StdioLogSink() : m_stream(stderr) {} + StdioLogSink(FILE* stream) : m_stream(stream) {} + virtual ~StdioLogSink() {} + + void WriteEntry(const LogEntry&); + }; + +#ifdef KM_WIN32 + // write messages to the Win32 debug stream + class WinDbgLogSink : public ILogSink + { + Mutex m_Lock; + KM_NO_COPY_CONSTRUCT(WinDbgLogSink); + + public: + WinDbgLogSink() {} + virtual ~WinDbgLogSink() {} + + void WriteEntry(const LogEntry&); + }; +#endif + +#ifndef KM_WIN32 + // write messages to a POSIX file descriptor + class StreamLogSink : public ILogSink + { + Mutex m_Lock; + int m_fd; + KM_NO_COPY_CONSTRUCT(StreamLogSink); + StreamLogSink(); + + public: + StreamLogSink(int fd) : m_fd(fd) {} + virtual ~StreamLogSink() {} + + void WriteEntry(const LogEntry&); + }; + + // write messages to the syslog facility + class SyslogLogSink : public ILogSink + { + Mutex m_Lock; + KM_NO_COPY_CONSTRUCT(SyslogLogSink); + SyslogLogSink(); + + public: + SyslogLogSink(const std::string& source_name, int facility); + virtual ~SyslogLogSink(); + void WriteEntry(const LogEntry&); + }; + + // convert a string into the appropriate syslog facility id + int SyslogNameToFacility(const std::string& facility_name); + +#endif + + +} // namespace Kumu + +#endif // _KM_LOG_H_ + +// +// end KM_log.h +// diff --git a/asdcplib/src/KM_memio.h b/asdcplib/src/KM_memio.h new file mode 100755 index 0000000..69942c7 --- /dev/null +++ b/asdcplib/src/KM_memio.h @@ -0,0 +1,249 @@ +/* +Copyright (c) 2006-2011, 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 KM_memio.h + \version $Id: KM_memio.h,v 1.9 2011/03/07 06:46:36 jhurst Exp $ + \brief abstraction for byte-oriented conversion of integers and objects + */ + +#ifndef _KM_MEMIO_H_ +#define _KM_MEMIO_H_ + +#include <KM_platform.h> +#include <string> +#include <cstring> + +namespace Kumu +{ + class ByteString; + + // + class MemIOWriter + { + KM_NO_COPY_CONSTRUCT(MemIOWriter); + MemIOWriter(); + + protected: + byte_t* m_p; + ui32_t m_capacity; + ui32_t m_size; + + public: + MemIOWriter(byte_t* p, ui32_t c) : m_p(p), m_capacity(c), m_size(0) { + assert(m_p); assert(m_capacity); + } + + MemIOWriter(ByteString* Buf); + ~MemIOWriter() {} + + inline void Reset() { m_size = 0; } + inline byte_t* Data() { return m_p; } + inline const byte_t* RoData() const { return m_p; } + inline byte_t* CurrentData() { return m_p + m_size; } + inline ui32_t Length() const { return m_size; } + inline ui32_t Remainder() const { return m_capacity - m_size; } + + inline bool AddOffset(ui32_t offset) { + if ( ( m_size + offset ) > m_capacity ) + return false; + + m_size += offset; + return true; + + } + + inline bool WriteRaw(const byte_t* p, ui32_t buf_len) { + if ( ( m_size + buf_len ) > m_capacity ) + return false; + + memcpy(m_p + m_size, p, buf_len); + m_size += buf_len; + return true; + } + + bool WriteBER(ui64_t i, ui32_t ber_len); + + inline bool WriteUi8(ui8_t i) { + if ( ( m_size + 1 ) > m_capacity ) + return false; + + *(m_p + m_size) = i; + m_size++; + return true; + } + + inline bool WriteUi16BE(ui16_t i) { + if ( ( m_size + sizeof(ui16_t) ) > m_capacity ) + return false; + + i2p<ui16_t>(KM_i16_BE(i), m_p + m_size); + m_size += sizeof(ui16_t); + return true; + } + + inline bool WriteUi32BE(ui32_t i) { + if ( ( m_size + sizeof(ui32_t) ) > m_capacity ) + return false; + + i2p<ui32_t>(KM_i32_BE(i), m_p + m_size); + m_size += sizeof(ui32_t); + return true; + } + + inline bool WriteUi64BE(ui64_t i) { + if ( ( m_size + sizeof(ui64_t) ) > m_capacity ) + return false; + + i2p<ui64_t>(KM_i64_BE(i), m_p + m_size); + m_size += sizeof(ui64_t); + return true; + } + + inline bool WriteString(const std::string& str) { + ui32_t len = static_cast<ui32_t>(str.length()); + if ( ! WriteUi32BE(len) ) return false; + if ( ! WriteRaw((const byte_t*)str.c_str(), len) ) return false; + return true; + } + }; + + // + class MemIOReader + { + KM_NO_COPY_CONSTRUCT(MemIOReader); + MemIOReader(); + + protected: + const byte_t* m_p; + ui32_t m_capacity; + ui32_t m_size; // this is sort of a misnomer, when we are reading it measures offset + + public: + MemIOReader(const byte_t* p, ui32_t c) : + m_p(p), m_capacity(c), m_size(0) { + assert(m_p); assert(m_capacity); + } + + MemIOReader(const ByteString* Buf); + ~MemIOReader() {} + + inline void Reset() { m_size = 0; } + inline const byte_t* Data() const { return m_p; } + inline const byte_t* CurrentData() const { return m_p + m_size; } + inline ui32_t Offset() const { return m_size; } + inline ui32_t Remainder() const { return m_capacity - m_size; } + + inline bool SkipOffset(ui32_t offset) { + if ( ( m_size + offset ) > m_capacity ) + return false; + + m_size += offset; + return true; + } + + inline bool ReadRaw(byte_t* p, ui32_t buf_len) { + if ( ( m_size + buf_len ) > m_capacity ) + return false; + + memcpy(p, m_p + m_size, buf_len); + m_size += buf_len; + return true; + } + + bool ReadBER(ui64_t* i, ui32_t* ber_len); + + inline bool ReadUi8(ui8_t* i) { + assert(i); + if ( ( m_size + 1 ) > m_capacity ) + return false; + + *i = *(m_p + m_size); + m_size++; + return true; + } + + inline bool ReadUi16BE(ui16_t* i) { + assert(i); + if ( ( m_size + sizeof(ui16_t) ) > m_capacity ) + return false; + + *i = KM_i16_BE(cp2i<ui16_t>(m_p + m_size)); + m_size += sizeof(ui16_t); + return true; + } + + inline bool ReadUi32BE(ui32_t* i) { + assert(i); + if ( ( m_size + sizeof(ui32_t) ) > m_capacity ) + return false; + + *i = KM_i32_BE(cp2i<ui32_t>(m_p + m_size)); + m_size += sizeof(ui32_t); + return true; + } + + inline bool ReadUi64BE(ui64_t* i) { + assert(i); + if ( ( m_size + sizeof(ui64_t) ) > m_capacity ) + return false; + + *i = KM_i64_BE(cp2i<ui64_t>(m_p + m_size)); + m_size += sizeof(ui64_t); + return true; + } + + inline bool ReadString(std::string& str) + { + ui32_t str_length; + if ( ! ReadUi32BE(&str_length) ) return false; + if ( ( m_size + str_length ) > m_capacity ) return false; + str.assign((const char*)CurrentData(), str_length); + if ( ! SkipOffset(str_length) ) return false; + return true; + } + }; + + // + inline bool + UnarchiveString(MemIOReader& Reader, std::string& str) { + return Reader.ReadString(str); + } + + // + inline bool + ArchiveString(MemIOWriter& Writer, const std::string& str) + { + return Writer.WriteString(str); + } + + +} // namespace Kumu + +#endif // _KM_MEMIO_H_ + +// +// end KM_memio.h +// diff --git a/asdcplib/src/KM_mutex.h b/asdcplib/src/KM_mutex.h new file mode 100755 index 0000000..396531d --- /dev/null +++ b/asdcplib/src/KM_mutex.h @@ -0,0 +1,89 @@ +/* +Copyright (c) 2004-2009, 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 KM_mutex.h + \version $Id: KM_mutex.h,v 1.2 2009/04/09 19:16:49 msheby Exp $ + \brief platform portability + */ + +#ifndef _KM_MUTEX_H_ +#define _KM_MUTEX_H_ + +#include <KM_platform.h> + +#ifndef KM_WIN32 +# include <pthread.h> +#endif + +namespace Kumu +{ +#ifdef KM_WIN32 + class Mutex + { + CRITICAL_SECTION m_Mutex; + KM_NO_COPY_CONSTRUCT(Mutex); + + public: + inline Mutex() { ::InitializeCriticalSection(&m_Mutex); } + inline ~Mutex() { ::DeleteCriticalSection(&m_Mutex); } + inline void Lock() { ::EnterCriticalSection(&m_Mutex); } + inline void Unlock() { ::LeaveCriticalSection(&m_Mutex); } + }; +#else // KM_WIN32 + class Mutex + { + pthread_mutex_t m_Mutex; + KM_NO_COPY_CONSTRUCT(Mutex); + + public: + inline Mutex() { pthread_mutex_init(&m_Mutex, 0); } + inline ~Mutex() { pthread_mutex_destroy(&m_Mutex); } + inline void Lock() { pthread_mutex_lock(&m_Mutex); } + inline void Unlock() { pthread_mutex_unlock(&m_Mutex); } + }; +#endif // KM_WIN32 + + // automatic Mutex management within a block - + // the mutex is created by the constructor and + // released by the destructor + class AutoMutex + { + Mutex& m_Mutex; + AutoMutex(); + KM_NO_COPY_CONSTRUCT(AutoMutex); + + public: + AutoMutex(Mutex& Mtx) : m_Mutex(Mtx) { m_Mutex.Lock(); } + ~AutoMutex() { m_Mutex.Unlock(); } + }; + +} // namespace Kumu + +#endif // _KM_MUTEX_H_ + +// +// end KM_mutex.h +// diff --git a/asdcplib/src/KM_platform.h b/asdcplib/src/KM_platform.h new file mode 100644 index 0000000..266c01a --- /dev/null +++ b/asdcplib/src/KM_platform.h @@ -0,0 +1,270 @@ +/* +Copyright (c) 2004-2009, 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 KM_platform.h + \version $Id: KM_platform.h,v 1.6 2010/09/14 19:21:47 msheby Exp $ + \brief platform portability + */ + +#ifndef _KM_PLATFORM_H_ +# define _KM_PLATFORM_H_ + +# ifdef __APPLE__ +# ifdef __BIG_ENDIAN__ +# define KM_BIG_ENDIAN +# endif +# endif + +# ifdef KM_WIN32 +# define WIN32_LEAN_AND_MEAN +# define VC_EXTRALEAN +# include <windows.h> +/* we like the "SendMessage" name, so get rid of the preprocessor define + * and replace with an inline function */ +# undef SendMessage +#ifdef UNICODE
+inline
+WINUSERAPI
+LRESULT
+WINAPI
+SendMessage(
+ HWND hWnd,
+ UINT Msg,
+ WPARAM wParam,
+ LPARAM lParam)
+{
+ return SendMessageW(hWnd, Msg, wParam, lParam);
+}
+#else
+inline
+WINUSERAPI
+LRESULT
+WINAPI
+SendMessage(
+ HWND hWnd,
+ UINT Msg,
+ WPARAM wParam,
+ LPARAM lParam)
+{
+ return SendMessageA(hWnd, Msg, wParam, lParam);
+}
+#endif // !UNICODE
+ +# include <stdlib.h> +# include <stdio.h> +# include <stdarg.h> +# pragma warning(disable:4786) // Ignore "identifer > 255 characters" warning + +typedef unsigned __int64 ui64_t; +typedef __int64 i64_t; +# define i64_C(c) (i64_t)(c) +# define ui64_C(c) (ui64_t)(c) +# define snprintf _snprintf +# define vsnprintf _vsnprintf + +# else // KM_WIN32 +typedef unsigned long long ui64_t; +typedef long long i64_t; +# define i64_C(c) c##LL +# define ui64_C(c) c##ULL + +# endif // KM_WIN32 + +# include <stdio.h> +# include <assert.h> +# include <stdlib.h> +# include <limits.h> + +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; + + +namespace Kumu +{ + inline ui16_t Swap2(ui16_t i) + { + return ( (i << 8) | (( i & 0xff00) >> 8) ); + } + + inline ui32_t Swap4(ui32_t i) + { + return + ( (i & 0x000000ffUL) << 24 ) | + ( (i & 0xff000000UL) >> 24 ) | + ( (i & 0x0000ff00UL) << 8 ) | + ( (i & 0x00ff0000UL) >> 8 ); + } + + inline ui64_t Swap8(ui64_t i) + { + return + ( (i & ui64_C(0x00000000000000FF)) << 56 ) | + ( (i & ui64_C(0xFF00000000000000)) >> 56 ) | + ( (i & ui64_C(0x000000000000FF00)) << 40 ) | + ( (i & ui64_C(0x00FF000000000000)) >> 40 ) | + ( (i & ui64_C(0x0000000000FF0000)) << 24 ) | + ( (i & ui64_C(0x0000FF0000000000)) >> 24 ) | + ( (i & ui64_C(0x00000000FF000000)) << 8 ) | + ( (i & ui64_C(0x000000FF00000000)) >> 8 ); + } + + // + template<class T> + inline T xmin(T lhs, T rhs) { + return (lhs < rhs) ? lhs : rhs; + } + + // + template<class T> + inline T xmax(T lhs, T rhs) { + return (lhs > rhs) ? lhs : rhs; + } + + // + template<class T> + inline T xclamp(T v, T l, T h) { + if ( v < l ) return l; + if ( v > h ) return h; + return v; + } + + + // read an integer from byte-structured storage + template<class T> + inline T cp2i(const byte_t* p) { return *(T*)p; } + + // write an integer to byte-structured storage + template<class T> + inline void i2p(T i, byte_t* p) { *(T*)p = i; } + +# ifdef KM_BIG_ENDIAN +# define KM_i16_LE(i) Kumu::Swap2(i) +# define KM_i32_LE(i) Kumu::Swap4(i) +# define KM_i64_LE(i) Kumu::Swap8(i) +# define KM_i16_BE(i) (i) +# define KM_i32_BE(i) (i) +# define KM_i64_BE(i) (i) +# else +# define KM_i16_LE(i) (i) +# define KM_i32_LE(i) (i) +# define KM_i64_LE(i) (i) +# define KM_i16_BE(i) Kumu::Swap2(i) +# define KM_i32_BE(i) Kumu::Swap4(i) +# define KM_i64_BE(i) Kumu::Swap8(i) +# endif // KM_BIG_ENDIAN + + // A non-reference counting, auto-delete container for internal + // member object pointers. + template <class T> + class mem_ptr + { + mem_ptr(T&); + + protected: + T* m_p; // the thing we point to + + 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) { this->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; } + }; + +} // namespace Kumu + +// Produces copy constructor boilerplate. Allows convenient private +// declatarion of copy constructors to prevent the compiler from +// silently manufacturing default methods. +# define KM_NO_COPY_CONSTRUCT(T) \ + T(const T&); \ + T& operator=(const T&) + +/* +// Example + class foo + { + KM_NO_COPY_CONSTRUCT(foo); // accessing private mthods will cause compile time error + public: + // ... + }; +*/ + +// Produces copy constructor boilerplate. Implements +// copy and assignment, see example below +# define KM_EXPLICIT_COPY_CONSTRUCT(T) \ + T(const T&); \ + const T& operator=(const T&) + +# define KM_EXPLICIT_COPY_CONSTRUCT_IMPL_START(N, T) \ + void T##_copy_impl(N::T& lhs, const N::T& rhs) \ + { + +#define KM_COPY_ITEM(I) lhs.I = rhs.I; + +# define KM_EXPLICIT_COPY_CONSTRUCT_IMPL_END(N, T) \ + } \ + N::T::T(const N::T& rhs) { T##_copy_impl(*this, rhs); } \ + const N::T& N::T::operator=(const N::T& rhs) { T##_copy_impl(*this, rhs); return *this; } + +/* +// Example +namespace bar { + class foo + { + public: + std::string param_a; + int param_b; + + KM_EXPLICIT_COPY_CONSTRUCT(foo); + // ... + }; +} + +// +KM_EXPLICIT_COPY_CONSTRUCT_IMPL_START(bar, foo) +KM_COPY_ITEM(param_a) +KM_COPY_ITEM(param_b) +KM_EXPLICIT_COPY_CONSTRUCT_IMPL_END(bar, foo) +*/ + +#endif // _KM_PLATFORM_H_ + +// +// KM_platform.h +// diff --git a/asdcplib/src/KM_prng.cpp b/asdcplib/src/KM_prng.cpp new file mode 100755 index 0000000..4e85cc5 --- /dev/null +++ b/asdcplib/src/KM_prng.cpp @@ -0,0 +1,271 @@ +/* -*- c-basic-offset: 2; -*- */ + +/* +Copyright (c) 2006-2009, 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 KM_prng.cpp + \version $Id: KM_prng.cpp,v 1.9 2011/06/14 23:38:33 jhurst Exp $ + \brief Fortuna pseudo-random number generator + */ + +#include <KM_prng.h> +#include <KM_log.h> +#include <KM_mutex.h> +#include <string.h> +#include <assert.h> +#include <openssl/aes.h> +#include <openssl/sha.h> +#include <openssl/bn.h> + +using namespace Kumu; + + +#ifdef KM_WIN32 +# include <wincrypt.h> +#else // KM_WIN32 +# include <KM_fileio.h> +const char* DEV_URANDOM = "/dev/urandom"; +#endif // KM_WIN32 + +const ui32_t RNG_KEY_SIZE = 512UL; +const ui32_t RNG_KEY_SIZE_BITS = 256UL; +const ui32_t RNG_BLOCK_SIZE = 16UL; +const ui32_t MAX_SEQUENCE_LEN = 0x00040000UL; + + +// internal implementation class +class h__RNG +{ + KM_NO_COPY_CONSTRUCT(h__RNG); + +public: + AES_KEY m_Context; + byte_t m_ctr_buf[RNG_BLOCK_SIZE]; + Mutex m_Lock; + unsigned int m_libdcp_test_rng_state; + + h__RNG() + { + memset(m_ctr_buf, 0, RNG_BLOCK_SIZE); + byte_t rng_key[RNG_KEY_SIZE]; + + { // this block scopes the following AutoMutex so that it will be + // released before the call to set_key() below. + AutoMutex Lock(m_Lock); + +#ifdef KM_WIN32 + HCRYPTPROV hProvider = 0; + CryptAcquireContext(&hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT); + CryptGenRandom(hProvider, RNG_KEY_SIZE, rng_key); +#else // KM_WIN32 + // on POSIX systems we simply read some seed from /dev/urandom + FileReader URandom; + + Result_t result = URandom.OpenRead(DEV_URANDOM); + + if ( KM_SUCCESS(result) ) + { + ui32_t read_count; + result = URandom.Read(rng_key, RNG_KEY_SIZE, &read_count); + } + + if ( KM_FAILURE(result) ) + DefaultLogSink().Error("Error opening random device: %s\n", DEV_URANDOM); + +#endif // KM_WIN32 + } // end AutoMutex context + + set_key(rng_key); + } + + // + void + set_key(const byte_t* key_fodder) + { + assert(key_fodder); + byte_t sha_buf[20]; + SHA_CTX SHA; + SHA1_Init(&SHA); + + SHA1_Update(&SHA, (byte_t*)&m_Context, sizeof(m_Context)); + SHA1_Update(&SHA, key_fodder, RNG_KEY_SIZE); + SHA1_Final(sha_buf, &SHA); + + AutoMutex Lock(m_Lock); + AES_set_encrypt_key(sha_buf, RNG_KEY_SIZE_BITS, &m_Context); + *(ui32_t*)(m_ctr_buf + 12) = 1; + } + + // + void + fill_rand(byte_t* buf, ui32_t len) + { + assert(len <= MAX_SEQUENCE_LEN); + ui32_t gen_count = 0; + AutoMutex Lock(m_Lock); + + while ( gen_count + RNG_BLOCK_SIZE <= len ) + { + AES_encrypt(m_ctr_buf, buf + gen_count, &m_Context); + *(ui32_t*)(m_ctr_buf + 12) += 1; + gen_count += RNG_BLOCK_SIZE; + } + + if ( len != gen_count ) // partial count needed? + { + byte_t tmp[RNG_BLOCK_SIZE]; + AES_encrypt(m_ctr_buf, tmp, &m_Context); + memcpy(buf + gen_count, tmp, len - gen_count); + } + + } +}; + + +static h__RNG* s_RNG = 0; + + +//------------------------------------------------------------------------------------------ +// +// Fortuna public interface + +Kumu::FortunaRNG::FortunaRNG() +{ + if ( s_RNG == 0 ) + s_RNG = new h__RNG; +} + +Kumu::FortunaRNG::~FortunaRNG() {} + +// +const byte_t* +Kumu::FortunaRNG::FillRandom(byte_t* buf, ui32_t len) +{ + assert(buf); + assert(s_RNG); + const byte_t* front_of_buffer = buf; + + while ( len ) + { + // 2^20 bytes max per seeding, use 2^19 to save + // room for generating reseed values + ui32_t gen_size = xmin(len, MAX_SEQUENCE_LEN); + s_RNG->fill_rand(buf, gen_size); + buf += gen_size; + len -= gen_size; + + // re-seed the generator + byte_t rng_key[RNG_KEY_SIZE]; + s_RNG->fill_rand(rng_key, RNG_KEY_SIZE); + s_RNG->set_key(rng_key); + } + + return front_of_buffer; +} + +// +const byte_t* +Kumu::FortunaRNG::FillRandom(Kumu::ByteString& Buffer) +{ + FillRandom(Buffer.Data(), Buffer.Capacity()); + Buffer.Length(Buffer.Capacity()); + return Buffer.Data(); +} + +//------------------------------------------------------------------------------------------ + +// +// FIPS 186-2 Sec. 3.1 as modified by Change 1, section entitled "General Purpose Random Number Generation" +void +Kumu::Gen_FIPS_186_Value(const byte_t* key, ui32_t key_size, byte_t* out_buf, ui32_t out_buf_len) +{ + byte_t sha_buf[SHA_DIGEST_LENGTH]; + ui32_t const xkey_len = 64; // 512/8 + byte_t xkey[xkey_len]; + BN_CTX* ctx1 = BN_CTX_new(); // used by BN_* functions + assert(ctx1); + + if ( key_size > xkey_len ) + DefaultLogSink().Warn("Key too large for FIPS 186 seed, truncating to 64 bytes.\n"); + + // init key + memset(xkey, 0, xkey_len); + memcpy(xkey, key, xmin<ui32_t>(key_size, xkey_len)); + + if ( key_size < SHA_DIGEST_LENGTH ) + key_size = SHA_DIGEST_LENGTH; // pad short key ( b < 160 ) + + // create the 2^b constant + BIGNUM c_2powb, c_2, c_b; + BN_init(&c_2powb); BN_init(&c_2); BN_init(&c_b); + BN_set_word(&c_2, 2); + BN_set_word(&c_b, key_size * 8); + BN_exp(&c_2powb, &c_2, &c_b, ctx1); + + for (;;) + { + SHA_CTX SHA; + + // step c -- x = G(t,xkey) + SHA1_Init(&SHA); // set t + SHA1_Update(&SHA, xkey, xkey_len); + + ui32_t* buf_p = (ui32_t*)sha_buf; + *buf_p++ = KM_i32_BE(SHA.h0); + *buf_p++ = KM_i32_BE(SHA.h1); + *buf_p++ = KM_i32_BE(SHA.h2); + *buf_p++ = KM_i32_BE(SHA.h3); + *buf_p++ = KM_i32_BE(SHA.h4); + memcpy(out_buf, sha_buf, xmin<ui32_t>(out_buf_len, SHA_DIGEST_LENGTH)); + + if ( out_buf_len <= SHA_DIGEST_LENGTH ) + break; + + out_buf_len -= SHA_DIGEST_LENGTH; + out_buf += SHA_DIGEST_LENGTH; + + // step d -- XKEY = (1 + XKEY + x) mod 2^b + BIGNUM bn_tmp, bn_xkey, bn_x_n; + BN_init(&bn_tmp); BN_init(&bn_xkey); BN_init(&bn_x_n); + + BN_bin2bn(xkey, key_size, &bn_xkey); + BN_bin2bn(sha_buf, SHA_DIGEST_LENGTH, &bn_x_n); + BN_add_word(&bn_xkey, 1); // xkey += 1 + BN_add(&bn_tmp, &bn_xkey, &bn_x_n); // xkey += x + BN_mod(&bn_xkey, &bn_tmp, &c_2powb, ctx1); // xkey = xkey mod (2^b) + + memset(xkey, 0, xkey_len); + ui32_t bn_buf_len = BN_num_bytes(&bn_xkey); + ui32_t idx = ( bn_buf_len < key_size ) ? key_size - bn_buf_len : 0; + BN_bn2bin(&bn_xkey, &xkey[idx]); + } + + BN_CTX_free(ctx1); +} + +// +// end KM_prng.cpp +// diff --git a/asdcplib/src/KM_prng.h b/asdcplib/src/KM_prng.h new file mode 100755 index 0000000..0b941f3 --- /dev/null +++ b/asdcplib/src/KM_prng.h @@ -0,0 +1,64 @@ +/* +Copyright (c) 2006-2009, 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 KM_prng.h + \version $Id: KM_prng.h,v 1.4 2009/04/09 19:24:14 msheby Exp $ + \brief Fortuna pseudo-random number generator + */ + +#ifndef _KM_PRNG_H_ +#define _KM_PRNG_H_ + +#include <KM_util.h> + +namespace Kumu +{ + class FortunaRNG + { + KM_NO_COPY_CONSTRUCT(FortunaRNG); + + public: + FortunaRNG(); + ~FortunaRNG(); + const byte_t* FillRandom(byte_t* buf, ui32_t len); + const byte_t* FillRandom(ByteString&); +#ifdef LIBDCP_POSIX + void Reset(); +#endif + }; + + + // key_len must be <= 64 (larger values will be truncated) + void Gen_FIPS_186_Value(const byte_t* key_in, ui32_t key_len, byte_t* buf, ui32_t buf_len); +} // namespace Kumu + + + +#endif // _KM_PRNG_H_ + +// +// end KM_prng.h +// diff --git a/asdcplib/src/KM_tai.cpp b/asdcplib/src/KM_tai.cpp new file mode 100644 index 0000000..2cbd125 --- /dev/null +++ b/asdcplib/src/KM_tai.cpp @@ -0,0 +1,221 @@ +/* + +THIS IS A SUBSET OF THE FULL LIBTAI. CHANGES HAVE BEEN MADE TO SUIT +LIBKUMU STYLE AND TYPE CONVENTIONS. ALL BUGS BELONG TO JOHN HURST. +THE FOLLOWING IS FOR ATTRIBUTION, THANK YOU MR. BERNSTEIN FOR WRITING +AND DISTRIBUTING SUCH GREAT SOFTWARE: + +libtai 0.60, alpha. +19981013 +Copyright 1998 +D. J. Bernstein, djb@pobox.com +http://pobox.com/~djb/libtai.html + + +libtai is a library for storing and manipulating dates and times. + +libtai supports two time scales: (1) TAI64, covering a few hundred +billion years with 1-second precision; (2) TAI64NA, covering the same +period with 1-attosecond precision. Both scales are defined in terms of +TAI, the current international real time standard. + +libtai provides an internal format for TAI64, struct tai, designed for +fast time manipulations. The tai_pack() and tai_unpack() routines +convert between struct tai and a portable 8-byte TAI64 storage format. +libtai provides similar internal and external formats for TAI64NA. + +libtai provides struct caldate to store dates in year-month-day form. It +can convert struct caldate, under the Gregorian calendar, to a modified +Julian day number for easy date arithmetic. + +libtai provides struct caltime to store calendar dates and times along +with UTC offsets. It can convert from struct tai to struct caltime in +UTC, accounting for leap seconds, for accurate date and time display. It +can also convert back from struct caltime to struct tai for user input. +Its overall UTC-to-TAI conversion speed is 100x better than the usual +UNIX mktime() implementation. + +This version of libtai requires a UNIX system with gettimeofday(). It +will be easy to port to other operating systems with compilers +supporting 64-bit arithmetic. + +The libtai source code is in the public domain. + +*/ + + /*! \file KM_tai.cpp + \version $Id: KM_tai.cpp,v 1.5 2012/03/07 17:30:52 mikey Exp $ + \brief portable time functions + */ + +#include <KM_tai.h> +#ifdef KM_WIN32 +#include <time.h> +#else +#include <sys/time.h> +#endif + +// +void +caldate_frommjd(Kumu::TAI::caldate* cd, i32_t day) +{ + assert(cd); + i32_t year, month, yday; + + year = day / 146097L; + day %= 146097L; + day += 678881L; + while (day >= 146097L) { day -= 146097L; ++year; } + + /* year * 146097 + day - 678881 is MJD; 0 <= day < 146097 */ + /* 2000-03-01, MJD 51604, is year 5, day 0 */ + + year *= 4; + if (day == 146096L) { year += 3; day = 36524L; } + else { year += day / 36524L; day %= 36524L; } + year *= 25; + year += day / 1461; + day %= 1461; + year *= 4; + + yday = (day < 306); + if (day == 1460) { year += 3; day = 365; } + else { year += day / 365; day %= 365; } + yday += day; + + day *= 10; + month = (day + 5) / 306; + day = (day + 5) % 306; + day /= 10; + if (month >= 10) { yday -= 306; ++year; month -= 10; } + else { yday += 59; month += 2; } + + cd->year = year; + cd->month = month + 1; + cd->day = day + 1; +} + +// +static ui32_t times365[4] = { 0, 365, 730, 1095 } ; +static ui32_t times36524[4] = { 0, 36524UL, 73048UL, 109572UL } ; +static ui32_t montab[12] = +{ 0, 31, 61, 92, 122, 153, 184, 214, 245, 275, 306, 337 } ; +/* month length after february is (306 * m + 5) / 10 */ + +// +i32_t +caldate_mjd(const Kumu::TAI::caldate* cd) +{ + assert(cd); + i32_t y, m, d; + + d = cd->day - 678882L; + m = cd->month - 1; + y = cd->year; + + d += 146097L * (y / 400); + y %= 400; + + if (m >= 2) m -= 2; else { m += 10; --y; } + + y += (m / 12); + m %= 12; + if (m < 0) { m += 12; --y; } + + d += montab[m]; + + d += 146097L * (y / 400); + y %= 400; + if (y < 0) { y += 400; d -= 146097L; } + + d += times365[y & 3]; + y >>= 2; + + d += 1461L * (y % 25); + y /= 25; + + d += times36524[y & 3]; + + return d; +} + + +// +void +caltime_utc(Kumu::TAI::caltime* ct, const Kumu::TAI::tai* t) +{ + assert(ct&&t); + Kumu::TAI::tai t2 = *t; + ui64_t u = t2.x + 58486; + i32_t s = (i32_t)(u % ui64_C(86400)); + + ct->second = (s % 60); s /= 60; + ct->minute = s % 60; s /= 60; + ct->hour = s; + + u /= ui64_C(86400); + caldate_frommjd(&ct->date,/*XXX*/(i32_t) (u - ui64_C(53375995543064))); + + ct->offset = 0; +} + +// +void +caltime_tai(const Kumu::TAI::caltime* ct, Kumu::TAI::tai* t) +{ + assert(ct&&t); + i32_t day, s; + + /* XXX: check for overflow? */ + + day = caldate_mjd(&ct->date); + + s = ct->hour * 60 + ct->minute; + s = (s - ct->offset) * 60 + ct->second; + + t->x = day * ui64_C(86400) + ui64_C(4611686014920671114) + (i64_t)s; +} + +// +void +Kumu::TAI::tai::now() +{ +#ifdef KM_WIN32 + SYSTEMTIME st; + ::GetSystemTime(&st); + TAI::caltime ct; + ct.date.year = st.wYear; + ct.date.month = st.wMonth; + ct.date.day = st.wDay; + ct.hour = st.wHour; + ct.minute = st.wMinute; + ct.second = st.wSecond; + caltime_tai(&ct, this); +#else + struct timeval now; + gettimeofday(&now, 0); + x = ui64_C(4611686018427387914) + (ui64_t)now.tv_sec; +#endif +} + + +// +const Kumu::TAI::tai& +Kumu::TAI::tai::operator=(const Kumu::TAI::caltime& rhs) +{ + caltime_tai(&rhs, this); + return *this; +} + +// +const Kumu::TAI::caltime& +Kumu::TAI::caltime::operator=(const Kumu::TAI::tai& rhs) +{ + caltime_utc(this, &rhs); + return *this; +} + + +// +// end KM_tai.cpp +// diff --git a/asdcplib/src/KM_tai.h b/asdcplib/src/KM_tai.h new file mode 100644 index 0000000..a274e8d --- /dev/null +++ b/asdcplib/src/KM_tai.h @@ -0,0 +1,107 @@ +/* + +THIS IS A SUBSET OF THE FULL LIBTAI. CHANGES HAVE BEEN MADE TO SUIT +LIBKUMU STYLE AND TYPE CONVENTIONS. ALL BUGS BELONG TO JOHN HURST. +THE FOLLOWING IS FOR ATTRIBUTION, THANK YOU MR. BERNSTEIN FOR WRITING +AND DISTRIBUTING SUCH GREAT SOFTWARE: + +libtai 0.60, alpha. +19981013 +Copyright 1998 +D. J. Bernstein, djb@pobox.com +http://pobox.com/~djb/libtai.html + + +libtai is a library for storing and manipulating dates and times. + +libtai supports two time scales: (1) TAI64, covering a few hundred +billion years with 1-second precision; (2) TAI64NA, covering the same +period with 1-attosecond precision. Both scales are defined in terms of +TAI, the current international real time standard. + +libtai provides an internal format for TAI64, struct tai, designed for +fast time manipulations. The tai_pack() and tai_unpack() routines +convert between struct tai and a portable 8-byte TAI64 storage format. +libtai provides similar internal and external formats for TAI64NA. + +libtai provides struct caldate to store dates in year-month-day form. It +can convert struct caldate, under the Gregorian calendar, to a modified +Julian day number for easy date arithmetic. + +libtai provides struct caltime to store calendar dates and times along +with UTC offsets. It can convert from struct tai to struct caltime in +UTC, accounting for leap seconds, for accurate date and time display. It +can also convert back from struct caltime to struct tai for user input. +Its overall UTC-to-TAI conversion speed is 100x better than the usual +UNIX mktime() implementation. + +This version of libtai requires a UNIX system with gettimeofday(). It +will be easy to port to other operating systems with compilers +supporting 64-bit arithmetic. + +The libtai source code is in the public domain. + +*/ + + /*! \file KM_tai.h + \version $Id: KM_tai.h,v 1.5 2012/02/21 02:09:30 jhurst Exp $ + \brief portable time functions + */ + +#ifndef _KUMU_TAI_H_ +#define _KUMU_TAI_H_ + +#include <KM_platform.h> + +// +namespace Kumu +{ + namespace TAI + { + class caltime; + + // + struct tai + { + ui64_t x; + inline void add_seconds(i32_t s) { x += s; } + inline void add_minutes(i32_t m) { x += m * 60; } + inline void add_hours(i32_t h) { x += h * 3600; } + inline void add_days(i32_t d) { x += d * 86400; } + void now(); + + const tai& operator=(const caltime& rhs); + }; + + // + struct caldate + { + i32_t year; + i32_t month; + i32_t day; + }; + + // + class caltime + { + public: + caldate date; + i32_t hour; + i32_t minute; + i32_t second; + i32_t offset; + + const caltime& operator=(const tai& rhs); + }; + + + } // namespace TAI + +} // namespace Kumu + + +#endif // _KUMU_TAI_H_ + +// +// end KM_tai.h +// diff --git a/asdcplib/src/KM_util.cpp b/asdcplib/src/KM_util.cpp new file mode 100755 index 0000000..b181484 --- /dev/null +++ b/asdcplib/src/KM_util.cpp @@ -0,0 +1,1141 @@ +/* +Copyright (c) 2005-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 KM_util.cpp + \version $Id: KM_util.cpp,v 1.40 2012/02/22 19:20:33 jhurst Exp $ + \brief Utility functions + */ + +#include <KM_util.h> +#include <KM_prng.h> +#include <KM_memio.h> +#include <KM_fileio.h> +#include <KM_log.h> +#include <KM_mutex.h> +#include <ctype.h> +#include <list> +#include <map> +#include <string> + +bool Kumu::libdcp_test = false; + +const char* +Kumu::Version() +{ + return PACKAGE_VERSION; +} + + +//------------------------------------------------------------------------------------------ + +// Result_t Internals + +struct map_entry_t +{ + int rcode; + Kumu::Result_t* result; +}; + + +// WIN32 does not init this in time for use with Result_t(...) below, so it is +// now a pointer that Result_t(...) fills in when it needs it. +static Kumu::Mutex* s_MapLock = 0; + +static ui32_t s_MapSize = 0; +static const ui32_t MapMax = 2048; +static struct map_entry_t s_ResultMap[MapMax]; + + +// +const Kumu::Result_t& +Kumu::Result_t::Find(int v) +{ + if ( v == 0 ) + return RESULT_OK; + + assert(s_MapLock); + AutoMutex L(*s_MapLock); + + for ( ui32_t i = 0; i < s_MapSize; ++i ) + { + if ( s_ResultMap[i].rcode == v ) + return *s_ResultMap[i].result; + } + + return RESULT_UNKNOWN; +} + +// +Kumu::Result_t +Kumu::Result_t::Delete(int v) +{ + if ( v < -99 || v > 99 ) + { + DefaultLogSink().Error("Cannot delete core result code: %ld\n", v); + return RESULT_FAIL; + } + + assert(s_MapLock); + AutoMutex L(*s_MapLock); + + for ( ui32_t i = 0; i < s_MapSize; ++i ) + { + if ( s_ResultMap[i].rcode == v ) + { + for ( ++i; i < s_MapSize; ++i ) + s_ResultMap[i-1] = s_ResultMap[i]; + + --s_MapSize; + return RESULT_OK; + } + } + + return RESULT_FALSE; +} + +// +unsigned int +Kumu::Result_t::End() +{ + return s_MapSize; +} + +// +const Kumu::Result_t& +Kumu::Result_t::Get(unsigned int i) +{ + return *s_ResultMap[i].result; +} + +// +Kumu::Result_t::Result_t(int v, const char* s, const char* l) : value(v), label(l), symbol(s) +{ + assert(l); + assert(s); + + if ( v == 0 ) + return; + + // This may seem tricky, but it is certain that the static values declared in KM_error.h will + // be created (and thus this method will be called) before main(...) is called. It is not + // until then that threads could be created, thus the mutex will exist before multi-threaded + // access could occur. + if ( s_MapLock == 0 ) + s_MapLock = new Kumu::Mutex; + + assert(s_MapLock); + AutoMutex L(*s_MapLock); + + for ( ui32_t i = 0; i < s_MapSize; ++i ) + { + if ( s_ResultMap[i].rcode == v ) + return; + } + + assert(s_MapSize+1 < MapMax); + + s_ResultMap[s_MapSize].rcode = v; + s_ResultMap[s_MapSize].result = this; + ++s_MapSize; + + return; +} + +Kumu::Result_t::~Result_t() {} + + +//------------------------------------------------------------------------------------------ +// DTrace internals + +static int s_DTraceSequence = 0; + +Kumu::DTrace_t::DTrace_t(const char* Label, Kumu::Result_t* Watch, int Line, const char* File) + : m_Label(Label), m_Watch(Watch), m_Line(Line), m_File(File) +{ + m_Sequence = s_DTraceSequence++; + DefaultLogSink().Debug("@enter %s[%d] (%s at %d)\n", m_Label, m_Sequence, m_File, m_Line); +} + +Kumu::DTrace_t::~DTrace_t() +{ + if ( m_Watch != 0 ) + DefaultLogSink().Debug("@exit %s[%d]: %s\n", m_Label, m_Sequence, m_Watch->Label()); + else + DefaultLogSink().Debug("@exit %s[%d]\n", m_Label, m_Sequence); +} + +//------------------------------------------------------------------------------------------ + + +const char fill = '='; +const char* base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +const byte_t decode_map[] = +{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 62, 0xff, 0xff, 0xff, 63, + 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, + 0xff, 0, 1, 2, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +}; + + +// Convert a binary string to NULL-terminated UTF-8 hexadecimal, returns the buffer +// if the binary buffer was large enough to hold the result. If the output buffer +// is too small or any of the pointer arguments are NULL, the subroutine will +// return 0. +// +const char* +Kumu::base64encode(const byte_t* buf, ui32_t buf_len, char* strbuf, ui32_t strbuf_len) +{ + ui32_t out_char = 0; + ui32_t i, block_len, diff; + + if ( buf == 0 || strbuf == 0 ) + return 0; + + if ( strbuf_len < base64_encode_length(buf_len) + 1 ) + return 0; + + block_len = buf_len; + + while ( block_len % 3 ) + block_len--; + + for ( i = 0; i < block_len; i += 3 ) + { + strbuf[out_char++] = base64_chars[( buf[0] >> 2 )]; + strbuf[out_char++] = base64_chars[( ( ( buf[0] & 0x03 ) << 4 ) | ( buf[1] >> 4 ) )]; + strbuf[out_char++] = base64_chars[( ( ( buf[1] & 0x0f ) << 2 ) | ( buf[2] >> 6 ) )]; + strbuf[out_char++] = base64_chars[( buf[2] & 0x3f )]; + buf += 3; + } + + if ( i < buf_len ) + { + diff = buf_len - i; + assert(diff > 0); + assert(diff < 3); + + strbuf[out_char++] = base64_chars[( buf[0] >> 2 )]; + + if ( diff == 1 ) + { + strbuf[out_char++] = base64_chars[( ( ( buf[0] & 0x03 ) << 4 ) )]; + strbuf[out_char++] = fill; + } + else if ( diff == 2 ) + { + strbuf[out_char++] = base64_chars[( ( ( buf[0] & 0x03 ) << 4 ) | ( buf[1] >> 4 ) )]; + strbuf[out_char++] = base64_chars[( ( ( buf[1] & 0x0f ) << 2 ) )]; + } + + strbuf[out_char++] = fill; + } + + strbuf[out_char] = 0; + return strbuf;; +} + + + + +// Convert NULL-terminated UTF-8 Base64 string to binary, returns 0 if +// the binary buffer was large enough to hold the result. The output parameter +// 'char_count' will contain the length of the converted string. If the output +// buffer is too small or any of the pointer arguments are NULL, the subroutine +// will return -1 and set 'char_count' to the required buffer size. No data will +// be written to 'buf' if the subroutine fails. +// +i32_t +Kumu::base64decode(const char* str, byte_t* buf, ui32_t buf_len, ui32_t* char_count) +{ + register byte_t c = 0, d = 0; + register ui32_t phase = 0, i = 0; + + if ( str == 0 || buf == 0 || char_count == 0 ) + return -1; + + while ( *str != 0 && i < buf_len ) + { + c = decode_map[(int)*str++]; + if ( c == 0xff ) continue; + if ( c == 0xfe ) break; + + switch ( phase++ ) + { + case 0: + buf[i++] = c << 2; + break; + + case 1: + buf[i - 1] |= c >> 4; + d = c; + break; + + case 2: + buf[i++] = ( d << 4 ) | ( c >> 2 ); + d = c; + break; + + case 3: + buf[i++] = ( d << 6 ) | c; + phase = 0; + break; + } + } + + *char_count = i; + return 0; +} + +//------------------------------------------------------------------------------------------ + +// convert utf-8 hext string to bin +i32_t +Kumu::hex2bin(const char* str, byte_t* buf, ui32_t buf_len, ui32_t* conv_size) +{ + KM_TEST_NULL_L(str); + KM_TEST_NULL_L(buf); + KM_TEST_NULL_L(conv_size); + + *conv_size = 0; + + if ( str[0] == 0 ) // nothing to convert + return 0; + + for ( int j = 0; str[j]; j++ ) + { + if ( isxdigit(str[j]) ) + (*conv_size)++; + } + + if ( *conv_size & 0x01 ) (*conv_size)++; + *conv_size /= 2; + + if ( *conv_size > buf_len )// maximum possible data size + return -1; + + *conv_size = 0; + + int phase = 0; // track high/low nybble + + // for each character, fill in the high nybble then the low + for ( int i = 0; str[i]; i++ ) + { + if ( ! isxdigit(str[i]) ) + continue; + + byte_t val = str[i] - ( isdigit(str[i]) ? 0x30 : ( isupper(str[i]) ? 0x37 : 0x57 ) ); + + if ( phase == 0 ) + { + buf[*conv_size] = val << 4; + phase++; + } + else + { + buf[*conv_size] |= val; + phase = 0; + (*conv_size)++; + } + } + + return 0; +} + +#ifdef CONFIG_RANDOM_UUID + +// convert a memory region to a NULL-terminated hexadecimal string +// +static const char* +bin2hex_rand(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len) +{ + if ( bin_buf == 0 + || str_buf == 0 + || ((bin_len * 2) + 1) > str_len ) + return 0; + + char* p = str_buf; + Kumu::mem_ptr<byte_t> rand_buf = new byte_t[bin_len]; + Kumu::FortunaRNG RNG; + RNG.FillRandom(rand_buf, bin_len); + + for ( ui32_t i = 0; i < bin_len; i++ ) + { + *p = (bin_buf[i] >> 4) & 0x0f; + *p += *p < 10 ? 0x30 : (( ((rand_buf[i] & 0x01) == 0) ? 0x61 : 0x41 ) - 10); + p++; + + *p = bin_buf[i] & 0x0f; + *p += *p < 10 ? 0x30 : (( (((rand_buf[i] >> 1) & 0x01) == 0) ? 0x61 : 0x41 ) - 10); + p++; + } + + *p = '\0'; + return str_buf; +} +#endif + +// convert a memory region to a NULL-terminated hexadecimal string +// +const char* +Kumu::bin2hex(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len) +{ + if ( bin_buf == 0 + || str_buf == 0 + || ((bin_len * 2) + 1) > str_len ) + return 0; + +#ifdef CONFIG_RANDOM_UUID + const char* use_random_uuid = getenv("KM_USE_RANDOM_UUID"); + if ( use_random_uuid != 0 && use_random_uuid[0] != 0 && use_random_uuid[0] != '0' ) + return bin2hex_rand(bin_buf, bin_len, str_buf, str_len); +#endif + + char* p = str_buf; + + for ( ui32_t i = 0; i < bin_len; i++ ) + { + *p = (bin_buf[i] >> 4) & 0x0f; + *p += *p < 10 ? 0x30 : 0x61 - 10; + p++; + + *p = bin_buf[i] & 0x0f; + *p += *p < 10 ? 0x30 : 0x61 - 10; + p++; + } + + *p = '\0'; + return str_buf; +} + + +// spew a range of bin data as hex +void +Kumu::hexdump(const byte_t* buf, ui32_t dump_len, FILE* stream) +{ + if ( buf == 0 ) + return; + + if ( stream == 0 ) + stream = stderr; + + static ui32_t row_len = 16; + const byte_t* p = buf; + const byte_t* end_p = p + dump_len; + + for ( ui32_t line = 0; p < end_p; line++ ) + { + fprintf(stream, " %06x: ", line); + ui32_t i; + const byte_t* pp; + + for ( pp = p, i = 0; i < row_len && pp < end_p; i++, pp++ ) + fprintf(stream, "%02x ", *pp); + + while ( i++ < row_len ) + fputs(" ", stream); + + for ( pp = p, i = 0; i < row_len && pp < end_p; i++, pp++ ) + fputc((isprint(*pp) ? *pp : '.'), stream); + + fputc('\n', stream); + p += row_len; + } +} + +// +const char* +Kumu::bin2UUIDhex(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len) +{ + ui32_t i, j, k; + + if ( str_len < 34 || bin_len != UUID_Length ) + return 0; + + if ( bin2hex(bin_buf, bin_len, str_buf, str_len) == 0 ) + return 0; + + // shift the node id + for ( k = 19, i = 12; i > 0; i-- ) + str_buf[k+i+4] = str_buf[k+i]; + + // shift the time (mid+hi+clk) + for ( k = 15, j = 3; k > 6; k -= 4, j-- ) + { + for ( i = 4; i > 0; i-- ) + str_buf[k+i+j] = str_buf[k+i]; + } + + // add in the hyphens and trainling null + for ( i = 8; i < 24; i += 5 ) + str_buf[i] = '-'; + + str_buf[36] = 0; + return str_buf; +} + +// +void +Kumu::GenRandomValue(UUID& ID) +{ + byte_t tmp_buf[UUID_Length]; + GenRandomUUID(tmp_buf); + ID.Set(tmp_buf); +} + +#ifdef LIBDCP_POSIX +void +Kumu::ResetTestRNG() +{ + FortunaRNG RNG; + RNG.Reset(); +} +#endif + +// +void +Kumu::GenRandomUUID(byte_t* buf) +{ + FortunaRNG RNG; + RNG.FillRandom(buf, UUID_Length); + buf[6] &= 0x0f; // clear bits 4-7 + buf[6] |= 0x40; // set UUID version + buf[8] &= 0x3f; // clear bits 6&7 + buf[8] |= 0x80; // set bit 7 +} + +// +void +Kumu::GenRandomValue(SymmetricKey& Key) +{ + byte_t tmp_buf[SymmetricKey_Length]; + FortunaRNG RNG; + RNG.FillRandom(tmp_buf, SymmetricKey_Length); + Key.Set(tmp_buf); +} + + +//------------------------------------------------------------------------------------------ +// read a ber value from the buffer and compare with test value. +// Advances buffer to first character after BER value. +// +bool +Kumu::read_test_BER(byte_t **buf, ui64_t test_value) +{ + if ( buf == 0 ) + return false; + + if ( ( **buf & 0x80 ) == 0 ) + return false; + + ui64_t val = 0; + ui8_t ber_size = ( **buf & 0x0f ) + 1; + + if ( ber_size > 9 ) + return false; + + for ( ui8_t i = 1; i < ber_size; i++ ) + { + if ( (*buf)[i] > 0 ) + val |= (ui64_t)((*buf)[i]) << ( ( ( ber_size - 1 ) - i ) * 8 ); + } + + *buf += ber_size; + return ( val == test_value ); +} + + +// +bool +Kumu::read_BER(const byte_t* buf, ui64_t* val) +{ + ui8_t ber_size, i; + + if ( buf == 0 || val == 0 ) + return false; + + if ( ( *buf & 0x80 ) == 0 ) + return false; + + *val = 0; + ber_size = ( *buf & 0x0f ) + 1; + + if ( ber_size > 9 ) + return false; + + for ( i = 1; i < ber_size; i++ ) + { + if ( buf[i] > 0 ) + *val |= (ui64_t)buf[i] << ( ( ( ber_size - 1 ) - i ) * 8 ); + } + + return true; +} + + +static const ui64_t ber_masks[9] = + { ui64_C(0xffffffffffffffff), ui64_C(0xffffffffffffff00), + ui64_C(0xffffffffffff0000), ui64_C(0xffffffffff000000), + ui64_C(0xffffffff00000000), ui64_C(0xffffff0000000000), + ui64_C(0xffff000000000000), ui64_C(0xff00000000000000), + 0 + }; + +// +ui32_t +Kumu::get_BER_length_for_value(ui64_t val) +{ + for ( ui32_t i = 0; i < 9; i++ ) + { + if ( ( val & ber_masks[i] ) == 0 ) + return i + 1; + } + + ui64Printer tmp_i(val); + DefaultLogSink().Error("BER integer encoding not supported for large value %s\n", tmp_i.c_str()); + return 0; +} + +// +bool +Kumu::write_BER(byte_t* buf, ui64_t val, ui32_t ber_len) +{ + if ( buf == 0 ) + return false; + + if ( ber_len == 0 ) + { // calculate default length + if ( val < 0x01000000L ) + ber_len = 4; + else if ( val < ui64_C(0x0100000000000000) ) + ber_len = 8; + else + ber_len = 9; + } + else + { // sanity check BER length + if ( ber_len > 9 ) + { + DefaultLogSink().Error("BER integer length %u exceeds maximum size of 9\n", ber_len); + return false; + } + + if ( ( val & ber_masks[ber_len - 1] ) != 0 ) + { + ui64Printer tmp_i(val); + DefaultLogSink().Error("BER integer length %u too small for value %s\n", ber_len, tmp_i.c_str()); + return false; + } + } + + buf[0] = 0x80 + ( ber_len - 1 ); + + for ( ui32_t i = ber_len - 1; i > 0; i-- ) + { + buf[i] = (ui8_t)(val & 0xff); + val >>= 8; + } + + return true; +} + + +//------------------------------------------------------------------------------------------ + +#ifndef KM_WIN32 +#include <time.h> +#endif + +// +Kumu::Timestamp::Timestamp() : m_TZOffsetMinutes(0) { + if (libdcp_test) + { + m_Timestamp.x = 42; + } + else + { + m_Timestamp.now(); + } +} + +Kumu::Timestamp::Timestamp(const Timestamp& rhs) { + m_Timestamp = rhs.m_Timestamp; + m_TZOffsetMinutes = rhs.m_TZOffsetMinutes; +} + +Kumu::Timestamp::Timestamp(const char* datestr) : m_TZOffsetMinutes(0) { + DecodeString(datestr); +} + +Kumu::Timestamp::~Timestamp() { +} + +// +const Kumu::Timestamp& +Kumu::Timestamp::operator=(const Timestamp& rhs) +{ + m_Timestamp = rhs.m_Timestamp; + m_TZOffsetMinutes = rhs.m_TZOffsetMinutes; + return *this; +} + +bool Kumu::Timestamp::operator<(const Timestamp& rhs) const { + return m_Timestamp.x < rhs.m_Timestamp.x; +} + +bool Kumu::Timestamp::operator>(const Timestamp& rhs) const { + return m_Timestamp.x > rhs.m_Timestamp.x; +} + +bool Kumu::Timestamp::operator==(const Timestamp& rhs) const { + return m_Timestamp.x == rhs.m_Timestamp.x; +} + +bool Kumu::Timestamp::operator!=(const Timestamp& rhs) const { + return m_Timestamp.x != rhs.m_Timestamp.x; +} + +// +void +Kumu::Timestamp::GetComponents(ui16_t& Year, ui8_t& Month, ui8_t& Day, + ui8_t& Hour, ui8_t& Minute, ui8_t& Second) const +{ + TAI::caltime ct; + ct = m_Timestamp; + Year = ct.date.year; + Month = ct.date.month; + Day = ct.date.day; + Hour = ct.hour; + Minute = ct.minute; + Second = ct.second; +} + +// +void +Kumu::Timestamp::SetComponents(const ui16_t& Year, const ui8_t& Month, const ui8_t& Day, + const ui8_t& Hour, const ui8_t& Minute, const ui8_t& Second) +{ + TAI::caltime ct; + ct.date.year = Year; + ct.date.month = Month; + ct.date.day = Day; + ct.hour = Hour; + ct.minute = Minute; + ct.second = Second; + ct.offset = 0; + m_Timestamp = ct; + m_TZOffsetMinutes = 0; +} + +// returns false if the requested adjustment is out of range +bool +Kumu::Timestamp::SetTZOffsetMinutes(const i32_t& minutes) +{ + static const i32_t tz_limit = 14 * 60 * 60; + + if ( minutes < ( - tz_limit) || minutes > tz_limit ) + return false; + + m_TZOffsetMinutes = minutes; + return true; +} + +// +const char* +Kumu::Timestamp::EncodeString(char* str_buf, ui32_t buf_len) const +{ + if ( buf_len < ( DateTimeLen + 1 ) ) + return 0; + + ui16_t year; + ui8_t month, day, hour, minute, second; + ui32_t ofst_hours = 0, ofst_minutes = 0; + char direction = '+'; + + if ( m_TZOffsetMinutes == 0 ) + { + GetComponents(year, month, day, hour, minute, second); + } + else + { + // calculate local time + Kumu::Timestamp tmp_t(*this); + tmp_t.AddMinutes(m_TZOffsetMinutes); + tmp_t.GetComponents(year, month, day, hour, minute, second); + + ofst_hours = abs(m_TZOffsetMinutes) / 60; + ofst_minutes = abs(m_TZOffsetMinutes) % 60; + + if ( m_TZOffsetMinutes < 0 ) + direction = '-'; + } + + // 2004-05-01T13:20:00+00:00 + snprintf(str_buf, buf_len, + "%04hu-%02hu-%02huT%02hu:%02hu:%02hu%c%02hu:%02hu", + year, month, day, hour, minute, second, + direction, ofst_hours, ofst_minutes); + + return str_buf; +} + +// +bool +Kumu::Timestamp::DecodeString(const char* datestr) +{ + if ( ! ( isdigit(datestr[0]) && isdigit(datestr[1]) && isdigit(datestr[2]) && isdigit(datestr[3]) ) + || datestr[4] != '-' + || ! ( isdigit(datestr[5]) && isdigit(datestr[6]) ) + || datestr[7] != '-' + || ! ( isdigit(datestr[8]) && isdigit(datestr[9]) ) ) + return false; + + ui32_t char_count = 10; + TAI::caltime YMDhms; + YMDhms.offset = 0; + YMDhms.date.year = atoi(datestr); + YMDhms.date.month = atoi(datestr + 5); + YMDhms.date.day = atoi(datestr + 8); + + if ( datestr[10] == 'T' ) + { + if ( ! ( isdigit(datestr[11]) && isdigit(datestr[12]) ) + || datestr[13] != ':' + || ! ( isdigit(datestr[14]) && isdigit(datestr[15]) ) ) + return false; + + char_count += 6; + YMDhms.hour = atoi(datestr + 11); + YMDhms.minute = atoi(datestr + 14); + + if ( datestr[16] == ':' ) + { + if ( ! ( isdigit(datestr[17]) && isdigit(datestr[18]) ) ) + return false; + + char_count += 3; + YMDhms.second = atoi(datestr + 17); + } + + if ( datestr[19] == '.' ) + { + if ( ! ( isdigit(datestr[20]) && isdigit(datestr[21]) && isdigit(datestr[22]) ) ) + return false; + + // we don't carry the ms value + datestr += 4; + } + + if ( datestr[19] == '-' || datestr[19] == '+' ) + { + if ( ! ( isdigit(datestr[20]) && isdigit(datestr[21]) ) + || datestr[22] != ':' + || ! ( isdigit(datestr[23]) && isdigit(datestr[24]) ) ) + return false; + + char_count += 6; + + ui32_t TZ_hh = atoi(datestr + 20); + ui32_t TZ_mm = atoi(datestr + 23); + if ((TZ_hh > 14) || (TZ_mm > 59) || ((TZ_hh == 14) && (TZ_mm > 0))) + return false; + + i32_t TZ_offset = 60 * TZ_hh + TZ_mm; + if (datestr[19] == '-') + TZ_offset = -TZ_offset; + /* at this point, TZ_offset reflects the contents of the string */ + + /* a negative offset is behind UTC and so needs to increment to + * convert, while a positive offset must do the reverse */ + YMDhms.offset = TZ_offset; + } + else if (datestr[19] == 'Z') + { + /* act as if the offset were +00:00 */ + char_count++; + } + } + + if ( datestr[char_count] != 0 ) + { + Kumu::DefaultLogSink().Error("Unexpected extra characters in string: %s (%ld)\n", + datestr, char_count); + return false; + } + + m_Timestamp = YMDhms; + m_TZOffsetMinutes = YMDhms.offset; + return true; +} + +// +bool +Kumu::Timestamp::HasValue() const +{ + return true; +} + +// +bool +Kumu::Timestamp::Unarchive(MemIOReader* Reader) +{ + ui16_t year; + ui8_t month, day, hour, minute, second, tick; + + assert(Reader); + if ( ! Reader->ReadUi16BE(&year) ) return false; + if ( ! Reader->ReadUi8(&month) ) return false; + if ( ! Reader->ReadUi8(&day) ) return false; + if ( ! Reader->ReadUi8(&hour) ) return false; + if ( ! Reader->ReadUi8(&minute) ) return false; + if ( ! Reader->ReadUi8(&second) ) return false; + if ( ! Reader->ReadUi8(&tick) ) return false; + SetComponents(year, month, day, hour, minute, second); + return true; +} + +// +bool +Kumu::Timestamp::Archive(MemIOWriter* Writer) const +{ + assert(Writer); + + ui16_t year; + ui8_t month, day, hour, minute, second, tick = 0; + GetComponents(year, month, day, hour, minute, second); + + if ( ! Writer->WriteUi16BE(year) ) return false; + if ( ! Writer->WriteUi8(month) ) return false; + if ( ! Writer->WriteUi8(day) ) return false; + if ( ! Writer->WriteUi8(hour) ) return false; + if ( ! Writer->WriteUi8(minute) ) return false; + if ( ! Writer->WriteUi8(second) ) return false; + if ( ! Writer->WriteUi8(tick) ) return false; + return true; +} + +// +ui64_t +Kumu::Timestamp::GetCTime() const +{ + return m_Timestamp.x - ui64_C(4611686018427387914); +} + + +//------------------------------------------------------------------------------------------ + +Kumu::MemIOWriter::MemIOWriter(ByteString* Buf) + : m_p(0), m_capacity(0), m_size(0) +{ + m_p = Buf->Data(); + m_capacity = Buf->Capacity(); + assert(m_p); assert(m_capacity); +} + +bool +Kumu::MemIOWriter:: WriteBER(ui64_t i, ui32_t ber_len) +{ + if ( ( m_size + ber_len ) > m_capacity ) + return false; + + if ( ! write_BER(m_p + m_size, i, ber_len) ) + return false; + + m_size += ber_len; + return true; +} + + +Kumu::MemIOReader::MemIOReader(const ByteString* Buf) + : m_p(0), m_capacity(0), m_size(0) +{ + m_p = Buf->RoData(); + m_capacity = Buf->Length(); + assert(m_p); assert(m_capacity); +} + +bool +Kumu::MemIOReader::ReadBER(ui64_t* i, ui32_t* ber_len) +{ + if ( i == 0 || ber_len == 0 ) return false; + + if ( ( *ber_len = BER_length(m_p + m_size) ) == 0 ) + return false; + + if ( ( m_size + *ber_len ) > m_capacity ) + return false; + + if ( ! read_BER(m_p + m_size, i) ) + return false; + + m_size += *ber_len; + return true; +} + +//------------------------------------------------------------------------------------------ + +Kumu::ByteString::ByteString() : m_Data(0), m_Capacity(0), m_Length(0) {} + +Kumu::ByteString::ByteString(ui32_t cap) : m_Data(0), m_Capacity(0), m_Length(0) +{ + Capacity(cap); +} + +Kumu::ByteString::~ByteString() +{ + if ( m_Data != 0 ) + free(m_Data); +} + + +// copy the given data into the ByteString, set Length value. +// Returns error if the ByteString is too small. +Kumu::Result_t +Kumu::ByteString::Set(const byte_t* buf, ui32_t buf_len) +{ + if ( m_Capacity < buf_len ) + return RESULT_ALLOC; + + memcpy(m_Data, buf, buf_len); + m_Length = buf_len; + return RESULT_OK; +} + + +// copy the given data into the ByteString, set Length value. +// Returns error if the ByteString is too small. +Kumu::Result_t +Kumu::ByteString::Set(const ByteString& Buf) +{ + if ( m_Capacity < Buf.m_Capacity ) + return RESULT_ALLOC; + + memcpy(m_Data, Buf.m_Data, Buf.m_Length); + m_Length = Buf.m_Length; + return RESULT_OK; +} + + +// Sets the size of the internally allocate buffer. +Kumu::Result_t +Kumu::ByteString::Capacity(ui32_t cap_size) +{ + if ( m_Capacity >= cap_size ) + return RESULT_OK; + + byte_t* tmp_data = 0; + if ( m_Data != 0 ) + { + if ( m_Length > 0 ) + tmp_data = m_Data; + else + free(m_Data); + } + + if ( ( m_Data = (byte_t*)malloc(cap_size) ) == 0 ) + return RESULT_ALLOC; + + if ( tmp_data != 0 ) + { + assert(m_Length > 0); + memcpy(m_Data, tmp_data, m_Length); + free(tmp_data); + } + + m_Capacity = cap_size; + return RESULT_OK; +} + +// +Kumu::Result_t +Kumu::ByteString::Append(const ByteString& Buf) +{ + Result_t result = RESULT_OK; + ui32_t diff = m_Capacity - m_Length; + + if ( diff < Buf.Length() ) + result = Capacity(m_Capacity + Buf.Length()); + + if ( KM_SUCCESS(result) ) + { + memcpy(m_Data + m_Length, Buf.RoData(), Buf.Length()); + m_Length += Buf.Length(); + } + + return result; +} + +// +Kumu::Result_t +Kumu::ByteString::Append(const byte_t* buf, ui32_t buf_len) +{ + Result_t result = RESULT_OK; + ui32_t diff = m_Capacity - m_Length; + + if ( diff < buf_len ) + result = Capacity(m_Capacity + buf_len); + + if ( KM_SUCCESS(result) ) + { + memcpy(m_Data + m_Length, buf, buf_len); + m_Length += buf_len; + } + + return result; +} + + +// +// end KM_util.cpp +// diff --git a/asdcplib/src/KM_util.h b/asdcplib/src/KM_util.h new file mode 100755 index 0000000..a9793ba --- /dev/null +++ b/asdcplib/src/KM_util.h @@ -0,0 +1,547 @@ +/* +Copyright (c) 2005-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 KM_util.h + \version $Id: KM_util.h,v 1.32 2012/02/21 02:09:30 jhurst Exp $ + \brief Utility functions + */ + +#ifndef _KM_UTIL_H_ +#define _KM_UTIL_H_ + +#include <KM_memio.h> +#include <KM_error.h> +#include <KM_tai.h> +#include <string.h> +#include <string> +#include <list> + +namespace Kumu +{ + extern bool libdcp_test; + + // The version number declaration and explanation are in ../configure.ac + const char* Version(); + + // a class that represents the string form of a value + template <class T, int SIZE = 16> + class IntPrinter : public std::string + { + KM_NO_COPY_CONSTRUCT(IntPrinter); + IntPrinter(); + + protected: + const char* m_format; + char m_strbuf[SIZE]; + + public: + IntPrinter(const char* format, T value) { + assert(format); + m_format = format; + snprintf(m_strbuf, SIZE, m_format, value); + } + + inline operator const char*() { return m_strbuf; } + inline const char* c_str() { return m_strbuf; } + inline const char* set_value(T value) { + snprintf(m_strbuf, SIZE, m_format, value); + return m_strbuf; + } + }; + + struct i8Printer : public IntPrinter<i8_t> { + i8Printer(i8_t value) : IntPrinter<i8_t>("%hd", value) {} + }; + + struct ui8Printer : public IntPrinter<ui8_t> { + ui8Printer(ui8_t value) : IntPrinter<ui8_t>("%hu", value) {} + }; + + struct i16Printer : public IntPrinter<i16_t> { + i16Printer(i16_t value) : IntPrinter<i16_t>("%hd", value) {} + }; + + struct ui16Printer : public IntPrinter<ui16_t> { + ui16Printer(ui16_t value) : IntPrinter<ui16_t>("%hu", value) {} + }; + + struct i32Printer : public IntPrinter<i32_t> { + i32Printer(i32_t value) : IntPrinter<i32_t>("%d", value) {} + }; + + struct ui32Printer : public IntPrinter<ui32_t> { + ui32Printer(ui32_t value) : IntPrinter<ui32_t>("%u", value) {} + }; + +#ifdef KM_WIN32 + struct i64Printer : public IntPrinter<i64_t, 32> { + i64Printer(i64_t value) : IntPrinter<i64_t, 32>("%I64d", value) {} + }; + + struct ui64Printer : public IntPrinter<ui64_t, 32> { + ui64Printer(ui64_t value) : IntPrinter<ui64_t, 32>("%I64u", value) {} + }; +#else + struct i64Printer : public IntPrinter<i64_t, 32> { + i64Printer(i64_t value) : IntPrinter<i64_t, 32>("%qd", value) {} + }; + + struct ui64Printer : public IntPrinter<ui64_t, 32> { + ui64Printer(ui64_t value) : IntPrinter<ui64_t, 32>("%qu", value) {} + }; +#endif + + // Convert NULL-terminated UTF-8 hexadecimal string to binary, returns 0 if + // the binary buffer was large enough to hold the result. The output parameter + // 'char_count' will contain the length of the converted string. If the output + // buffer is too small or any of the pointer arguments are NULL, the subroutine + // will return -1 and set 'char_count' to the required buffer size. No data will + // be written to 'buf' if the subroutine fails. + i32_t hex2bin(const char* str, byte_t* buf, ui32_t buf_len, ui32_t* char_count); + + // Convert a binary string to NULL-terminated UTF-8 hexadecimal, returns the buffer + // if the output buffer was large enough to hold the result. If the output buffer + // is too small or any of the pointer arguments are NULL, the subroutine will + // return 0. + // + const char* bin2hex(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len); + + const char* bin2UUIDhex(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len); + + // same as above for base64 text + i32_t base64decode(const char* str, byte_t* buf, ui32_t buf_len, ui32_t* char_count); + const char* base64encode(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len); + + // returns the length of a Base64 encoding of a buffer of the given length + inline ui32_t base64_encode_length(ui32_t length) { + while ( ( length % 3 ) != 0 ) + length++; + + return ( length / 3 ) * 4; + } + + // print buffer contents to a stream as hexadecimal values in numbered + // rows of 16-bytes each. + // + void hexdump(const byte_t* buf, ui32_t dump_len, FILE* stream = 0); + + // Return the length in bytes of a BER encoded value + inline ui32_t BER_length(const byte_t* buf) + { + if ( buf == 0 || (*buf & 0xf0) != 0x80 ) + return 0; + + return (*buf & 0x0f) + 1; + } + + // Return the BER length required to encode value. A return value of zero + // indicates a value too large for this library. + ui32_t get_BER_length_for_value(ui64_t valuse); + + // read a BER value + bool read_BER(const byte_t* buf, ui64_t* val); + + // decode a ber value and compare it to a test value + bool read_test_BER(byte_t **buf, ui64_t test_value); + + // create BER encoding of integer value + bool write_BER(byte_t* buf, ui64_t val, ui32_t ber_len = 0); + + //---------------------------------------------------------------- + // + + // an abstract base class that objects implement to serialize state + // to and from a binary stream. + class IArchive + { + public: + virtual ~IArchive(){} + virtual bool HasValue() const = 0; + virtual ui32_t ArchiveLength() const = 0; + virtual bool Archive(MemIOWriter* Writer) const = 0; + virtual bool Unarchive(MemIOReader* Reader) = 0; + }; + + // + template <class T> + class ArchivableList : public std::list<T>, public IArchive + { + public: + ArchivableList() {} + virtual ~ArchivableList() {} + + bool HasValue() const { return ! this->empty(); } + + ui32_t ArchiveLength() const + { + ui32_t arch_size = sizeof(ui32_t); + + typename ArchivableList<T>::const_iterator i = this->begin(); + for ( ; i != this->end(); i++ ) + arch_size += i->ArchiveLength(); + + return arch_size; + } + + bool Unarchive(Kumu::MemIOReader* Reader) + { + if ( Reader == 0 ) return false; + ui32_t read_size = 0; + if ( ! Reader->ReadUi32BE(&read_size) ) return false; + for ( ui32_t i = 0; i < read_size; i++ ) + { + T TmpTP; + if ( ! TmpTP.Unarchive(Reader) ) return false; + this->push_back(TmpTP); + } + + return true; + } + + bool Archive(Kumu::MemIOWriter* Writer) const + { + if ( Writer == 0 ) return false; + if ( ! Writer->WriteUi32BE(static_cast<ui32_t>(this->size())) ) return false; + typename ArchivableList<T>::const_iterator i = this->begin(); + for ( ; i != this->end(); i++ ) + if ( ! i->Archive(Writer) ) return false; + + return true; + } + }; + + // archivable version of std::string + + // + class ArchivableString : public std::string, public Kumu::IArchive + { + + public: + ArchivableString() {} + ArchivableString(const char* sz) : std::string(sz) {} + ArchivableString(const std::string& s) : std::string(s) {} + virtual ~ArchivableString() {} + + bool HasValue() const { return ! this->empty(); } + ui32_t ArchiveLength() const { return static_cast<ui32_t>((sizeof(ui32_t) + this->size())|0xffffffff); } + + bool Archive(MemIOWriter* Writer) const { + if ( Writer == 0 ) return false; + return Writer->WriteString(*this); + } + + bool Unarchive(MemIOReader* Reader) { + if ( Reader == 0 ) return false; + return Reader->ReadString(*this); + } + }; + + // + typedef Kumu::ArchivableList<ArchivableString> StringList; + + // + // the base of all identifier classes, Identifier is not usually used directly + // see UUID and SymmetricKey below for more detail. + // + template <ui32_t SIZE> + class Identifier : public IArchive + { + protected: + bool m_HasValue; + byte_t m_Value[SIZE]; + + public: + Identifier() : m_HasValue(false) { memset(m_Value, 0, SIZE); } + Identifier(const byte_t* value) : m_HasValue(true) { memcpy(m_Value, value, SIZE); } + Identifier(const Identifier& rhs) : IArchive() { + m_HasValue = rhs.m_HasValue; + memcpy(m_Value, rhs.m_Value, SIZE); + } + + virtual ~Identifier() {} + + const Identifier& operator=(const Identifier& rhs) { + m_HasValue = rhs.m_HasValue; + memcpy(m_Value, rhs.m_Value, SIZE); + return *this; + } + + inline void Set(const byte_t* value) { m_HasValue = true; memcpy(m_Value, value, SIZE); } + inline void Reset() { m_HasValue = false; memset(m_Value, 0, SIZE); } + inline const byte_t* Value() const { return m_Value; } + inline ui32_t Size() const { return SIZE; } + + inline bool operator<(const Identifier& rhs) const { + ui32_t test_size = xmin(rhs.Size(), SIZE); + + for ( ui32_t i = 0; i < test_size; i++ ) + { + if ( m_Value[i] != rhs.m_Value[i] ) + return m_Value[i] < rhs.m_Value[i]; + } + + return false; + } + + inline bool operator==(const Identifier& rhs) const { + if ( rhs.Size() != SIZE ) return false; + return ( memcmp(m_Value, rhs.m_Value, SIZE) == 0 ); + } + + inline bool operator!=(const Identifier& rhs) const { + if ( rhs.Size() != SIZE ) return true; + return ( memcmp(m_Value, rhs.m_Value, SIZE) != 0 ); + } + + inline bool DecodeHex(const char* str) { + ui32_t char_count; + m_HasValue = ( hex2bin(str, m_Value, SIZE, &char_count) == 0 ); + if ( m_HasValue && char_count != SIZE ) + m_HasValue = false; + return m_HasValue; + } + + inline const char* EncodeHex(char* buf, ui32_t buf_len) const { + return bin2hex(m_Value, SIZE, buf, buf_len); + } + + inline const char* EncodeString(char* str_buf, ui32_t buf_len) const { + return EncodeHex(str_buf, buf_len); + } + + inline bool DecodeBase64(const char* str) { + ui32_t char_count; + m_HasValue = ( base64decode(str, m_Value, SIZE, &char_count) == 0 ); + if ( m_HasValue && char_count != SIZE ) + m_HasValue = false; + return m_HasValue; + } + + inline const char* EncodeBase64(char* buf, ui32_t buf_len) const { + return base64encode(m_Value, SIZE, buf, buf_len); + } + + inline bool HasValue() const { return m_HasValue; } + + inline ui32_t ArchiveLength() const { return SIZE; } + + inline bool Unarchive(Kumu::MemIOReader* Reader) { + m_HasValue = Reader->ReadRaw(m_Value, SIZE); + return m_HasValue; + } + + inline bool Archive(Kumu::MemIOWriter* Writer) const { + return Writer->WriteRaw(m_Value, SIZE); + } + }; + + + // UUID + // + const ui32_t UUID_Length = 16; + class UUID : public Identifier<UUID_Length> + { + public: + UUID() {} + UUID(const byte_t* value) : Identifier<UUID_Length>(value) {} + UUID(const UUID& rhs) : Identifier<UUID_Length>(rhs) {} + virtual ~UUID() {} + + inline const char* EncodeString(char* buf, ui32_t buf_len) const { + return bin2UUIDhex(m_Value, Size(), buf, buf_len); + } + + inline const char* EncodeHex(char* buf, ui32_t buf_len) const { + return bin2UUIDhex(m_Value, Size(), buf, buf_len); + } + }; + + void GenRandomUUID(byte_t* buf); // buf must be UUID_Length or longer + void GenRandomValue(UUID&); +#ifdef LIBDCP_POSIX + void ResetTestRNG(); +#endif + + typedef ArchivableList<UUID> UUIDList; + + // a self-wiping key container + // + const ui32_t SymmetricKey_Length = 16; + const byte_t NilKey[SymmetricKey_Length] = { + 0xfa, 0xce, 0xfa, 0xce, 0xfa, 0xce, 0xfa, 0xce, + 0xfa, 0xce, 0xfa, 0xce, 0xfa, 0xce, 0xfa, 0xce + }; + + class SymmetricKey : public Identifier<SymmetricKey_Length> + { + public: + SymmetricKey() {} + SymmetricKey(const byte_t* value) : Identifier<SymmetricKey_Length>(value) {} + SymmetricKey(const UUID& rhs) : Identifier<SymmetricKey_Length>(rhs) {} + virtual ~SymmetricKey() { memcpy(m_Value, NilKey, 16); m_HasValue = false; } + }; + + void GenRandomValue(SymmetricKey&); + + // + // 2004-05-01T13:20:00+00:00 + const ui32_t DateTimeLen = 25; // the number of chars in the xs:dateTime format (sans milliseconds) + + // UTC time+date representation + class Timestamp : public IArchive + { + TAI::tai m_Timestamp; // always UTC + i32_t m_TZOffsetMinutes; + + public: + Timestamp(); + Timestamp(const Timestamp& rhs); + Timestamp(const char* datestr); + Timestamp(const ui16_t& Year, const ui8_t& Month, const ui8_t& Day); + Timestamp(const ui16_t& Year, const ui8_t& Month, const ui8_t& Day, + const ui8_t& Hour, const ui8_t& Minute, const ui8_t& Second); + virtual ~Timestamp(); + + const Timestamp& operator=(const Timestamp& rhs); + bool operator<(const Timestamp& rhs) const; + bool operator>(const Timestamp& rhs) const; + bool operator==(const Timestamp& rhs) const; + bool operator!=(const Timestamp& rhs) const; + + // always UTC + void GetComponents(ui16_t& Year, ui8_t& Month, ui8_t& Day, + ui8_t& Hour, ui8_t& Minute, ui8_t& Second) const; + void SetComponents(const ui16_t& Year, const ui8_t& Month, const ui8_t& Day, + const ui8_t& Hour, const ui8_t& Minute, const ui8_t& Second); + + // Write the timestamp value to the given buffer in the form 2004-05-01T13:20:00+00:00 + // returns 0 if the buffer is smaller than DateTimeLen + const char* EncodeString(char* str_buf, ui32_t buf_len) const; + + // decode and set value from string formatted by EncodeString + bool DecodeString(const char* datestr); + + // Add the given number of days, hours, minutes, or seconds to the timestamp value. + // Values less than zero will cause the timestamp to decrease + inline void AddDays(const i32_t& d) { m_Timestamp.add_days(d); } + inline void AddHours(const i32_t& h) { m_Timestamp.add_hours(h); } + inline void AddMinutes(const i32_t& m) { m_Timestamp.add_minutes(m); } + inline void AddSeconds(const i32_t& s) { m_Timestamp.add_seconds(s); } + + // returns false if the requested adjustment is out of range + bool SetTZOffsetMinutes(const i32_t& minutes); + inline i32_t GetTZOffsetMinutes() const { return m_TZOffsetMinutes; } + + // Return the number of seconds since the Unix epoch UTC (1970-01-01T00:00:00+00:00) + ui64_t GetCTime() const; + + // Read and write the timestamp (always UTC) value as a byte string having + // the following format: + // | 16 bits int, big-endian | 8 bits | 8 bits | 8 bits | 8 bits | 8 bits | + // | Year A.D | Month(1-12) | Day(1-31) | Hour(0-23) | Minute(0-59) | Second(0-59) | + // + virtual bool HasValue() const; + virtual ui32_t ArchiveLength() const { return 8L; } + virtual bool Archive(MemIOWriter* Writer) const; + virtual bool Unarchive(MemIOReader* Reader); + }; + + // + class ByteString : public IArchive + { + KM_NO_COPY_CONSTRUCT(ByteString); + + 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 + ui32_t m_Length; // length of byte string in memory area pointed to by m_Data + + public: + ByteString(); + ByteString(ui32_t cap); + virtual ~ByteString(); + + // Sets or resets the size of the internally allocated buffer. + Result_t Capacity(ui32_t cap); + + Result_t Append(const ByteString&); + Result_t Append(const byte_t* buf, ui32_t buf_len); + + // 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 { assert(m_Data); return m_Data; } + + // returns a non-const pointer to the essence data + inline byte_t* Data() { assert(m_Data); return m_Data; } + + // set the length of the buffer's contents + inline ui32_t Length(ui32_t l) { return m_Length = l; } + + // returns the length of the buffer's contents + inline ui32_t Length() const { return m_Length; } + + // copy the given data into the ByteString, set Length value. + // Returns error if the ByteString is too small. + Result_t Set(const byte_t* buf, ui32_t buf_len); + Result_t Set(const ByteString& Buf); + + inline virtual bool HasValue() const { return m_Length > 0; } + + inline virtual ui32_t ArchiveLength() const { return m_Length; } + + inline virtual bool Archive(MemIOWriter* Writer) const { + assert(Writer); + if ( ! Writer->WriteUi32BE(m_Length) ) return false; + if ( ! Writer->WriteRaw(m_Data, m_Length) ) return false; + return true; + } + + inline virtual bool Unarchive(MemIOReader* Reader) { + assert(Reader); + ui32_t tmp_len; + if ( ! Reader->ReadUi32BE(&tmp_len) ) return false; + if ( KM_FAILURE(Capacity(tmp_len)) ) return false; + if ( ! Reader->ReadRaw(m_Data, tmp_len) ) return false; + m_Length = tmp_len; + return true; + } + }; + + inline void hexdump(const ByteString& buf, FILE*) { + hexdump(buf.RoData(), buf.Length()); + } + + +} // namespace Kumu + + +#endif // _KM_UTIL_H_ + +// +// end KM_util.h +// diff --git a/asdcplib/src/KM_xml.cpp b/asdcplib/src/KM_xml.cpp new file mode 100644 index 0000000..98dccc4 --- /dev/null +++ b/asdcplib/src/KM_xml.cpp @@ -0,0 +1,1012 @@ +/* +Copyright (c) 2005-2010, 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 KM_xml.cpp + \version $Id: KM_xml.cpp,v 1.19 2011/12/01 18:42:39 jhurst Exp $ + \brief XML writer +*/ + +#include <KM_xml.h> +#include <KM_log.h> +#include <KM_mutex.h> +#include <stack> +#include <map> + +#ifdef HAVE_EXPAT +# ifdef HAVE_XERCES_C +# error "Both HAVE_EXPAT and HAVE_XERCES_C defined" +# endif +#include <expat.h> +#endif + +#ifdef HAVE_XERCES_C +# ifdef HAVE_EXPAT +# error "Both HAVE_EXPAT and HAVE_XERCES_C defined" +# endif + +#include <xercesc/util/PlatformUtils.hpp> +#include <xercesc/util/XMLString.hpp> +#include <xercesc/util/TransService.hpp> +#include <xercesc/sax/AttributeList.hpp> +#include <xercesc/sax/HandlerBase.hpp> +#include <xercesc/sax/ErrorHandler.hpp> +#include <xercesc/sax/SAXParseException.hpp> +#include <xercesc/parsers/SAXParser.hpp> +#include <xercesc/framework/MemBufInputSource.hpp> +#include <xercesc/framework/XMLPScanToken.hpp> + + +XERCES_CPP_NAMESPACE_USE + +namespace Kumu { + void init_xml_dom(); + typedef std::basic_string<XMLCh> XercesString; + bool UTF_8_to_XercesString(const std::string& in_str, XercesString& out_str); + bool UTF_8_to_XercesString(const char* in_str, XercesString& out_str); + bool XercesString_to_UTF_8(const XercesString& in_str, std::string& out_str); + bool XercesString_to_UTF_8(const XMLCh* in_str, std::string& out_str); +} + +#endif + +using namespace Kumu; + + +class ns_map : public std::map<std::string, XMLNamespace*> +{ +public: + ~ns_map() + { + while ( ! empty() ) + { + ns_map::iterator ni = begin(); + delete ni->second; + erase(ni); + } + } +}; + + +Kumu::XMLElement::XMLElement(const char* name) : m_Namespace(0), m_NamespaceOwner(0) +{ + m_Name = name; +} + +Kumu::XMLElement::~XMLElement() +{ + for ( Elem_i i = m_ChildList.begin(); i != m_ChildList.end(); i++ ) + delete *i; + + delete (ns_map*)m_NamespaceOwner; +} + +// +void +Kumu::XMLElement::SetAttr(const char* name, const char* value) +{ + NVPair TmpVal; + TmpVal.name = name; + TmpVal.value = value; + + m_AttrList.push_back(TmpVal); +} + +// +Kumu::XMLElement* +Kumu::XMLElement::AddChild(Kumu::XMLElement* element) +{ + m_ChildList.push_back(element); // takes posession! + return element; +} + +// +Kumu::XMLElement* +Kumu::XMLElement::AddChild(const char* name) +{ + XMLElement* tmpE = new XMLElement(name); + m_ChildList.push_back(tmpE); + return tmpE; +} + +// +Kumu::XMLElement* +Kumu::XMLElement::AddChildWithContent(const char* name, const std::string& value) +{ + return AddChildWithContent(name, value.c_str()); +} + +// +void +Kumu::XMLElement::AppendBody(const std::string& value) +{ + m_Body += value; +} + +// +void +Kumu::XMLElement::SetBody(const std::string& value) +{ + m_Body = value; +} + +// +Kumu::XMLElement* +Kumu::XMLElement::AddChildWithContent(const char* name, const char* value) +{ + assert(name); + assert(value); + XMLElement* tmpE = new XMLElement(name); + tmpE->m_Body = value; + m_ChildList.push_back(tmpE); + return tmpE; +} + +// +Kumu::XMLElement* +Kumu::XMLElement::AddChildWithPrefixedContent(const char* name, const char* prefix, const char* value) +{ + XMLElement* tmpE = new XMLElement(name); + tmpE->m_Body = prefix; + tmpE->m_Body += value; + m_ChildList.push_back(tmpE); + return tmpE; +} + +// +void +Kumu::XMLElement::AddComment(const char* value) +{ + m_Body += " <!-- "; + m_Body += value; + m_Body += " -->\n"; +} + +// +void +Kumu::XMLElement::Render(std::string& outbuf) const +{ + outbuf = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; + RenderElement(outbuf, 0); +} + +// +inline void +add_spacer(std::string& outbuf, i32_t depth) +{ + while ( depth-- ) + outbuf+= " "; +} + +// +void +Kumu::XMLElement::RenderElement(std::string& outbuf, ui32_t depth) const +{ + add_spacer(outbuf, depth); + + outbuf += "<"; + outbuf += m_Name; + + // render attributes + for ( Attr_i i = m_AttrList.begin(); i != m_AttrList.end(); i++ ) + { + outbuf += " "; + outbuf += (*i).name; + outbuf += "=\""; + outbuf += (*i).value; + outbuf += "\""; + } + + outbuf += ">"; + + // body contents and children + if ( ! m_ChildList.empty() ) + { + outbuf += "\n"; + + // render body + if ( m_Body.length() > 0 ) + outbuf += m_Body; + + for ( Elem_i i = m_ChildList.begin(); i != m_ChildList.end(); i++ ) + (*i)->RenderElement(outbuf, depth + 1); + + add_spacer(outbuf, depth); + } + else if ( m_Body.length() > 0 ) + { + outbuf += m_Body; + } + + outbuf += "</"; + outbuf += m_Name; + outbuf += ">\n"; +} + +// +bool +Kumu::XMLElement::HasName(const char* name) const +{ + if ( name == 0 || *name == 0 ) + return false; + + return (m_Name == name); +} + + +void +Kumu::XMLElement::SetName(const char* name) +{ + if ( name != 0) + m_Name = name; +} + +// +const char* +Kumu::XMLElement::GetAttrWithName(const char* name) const +{ + for ( Attr_i i = m_AttrList.begin(); i != m_AttrList.end(); i++ ) + { + if ( (*i).name == name ) + return (*i).value.c_str(); + } + + return 0; +} + +// +Kumu::XMLElement* +Kumu::XMLElement::GetChildWithName(const char* name) const +{ + for ( Elem_i i = m_ChildList.begin(); i != m_ChildList.end(); i++ ) + { + if ( (*i)->HasName(name) ) + return *i; + } + + return 0; +} + +// +const Kumu::ElementList& +Kumu::XMLElement::GetChildrenWithName(const char* name, ElementList& outList) const +{ + assert(name); + for ( Elem_i i = m_ChildList.begin(); i != m_ChildList.end(); i++ ) + { + if ( (*i)->HasName(name) ) + outList.push_back(*i); + + if ( ! (*i)->m_ChildList.empty() ) + (*i)->GetChildrenWithName(name, outList); + } + + return outList; +} + +// +void +Kumu::XMLElement::DeleteAttributes() +{ + m_AttrList.clear(); +} + +// +void +Kumu::XMLElement::DeleteAttrWithName(const char* name) +{ + assert(name); + AttributeList::iterator i = m_AttrList.begin(); + + while ( i != m_AttrList.end() ) + { + if ( i->name == std::string(name) ) + m_AttrList.erase(i++); + else + ++i; + } +} + +// +void +Kumu::XMLElement::DeleteChildren() +{ + while ( ! m_ChildList.empty() ) + { + delete m_ChildList.back(); + m_ChildList.pop_back(); + } +} + +// +void +Kumu::XMLElement::DeleteChild(const XMLElement* element) +{ + if ( element != 0 ) + { + for ( ElementList::iterator i = m_ChildList.begin(); i != m_ChildList.end(); i++ ) + { + if ( *i == element ) + { + delete *i; + m_ChildList.erase(i); + return; + } + } + } +} + +// +void +Kumu::XMLElement::ForgetChild(const XMLElement* element) +{ + if ( element != 0 ) + { + for ( ElementList::iterator i = m_ChildList.begin(); i != m_ChildList.end(); i++ ) + { + if ( *i == element ) + { + m_ChildList.erase(i); + return; + } + } + } +} + +// +bool +Kumu::XMLElement::ParseString(const ByteString& document) +{ + return ParseString((const char*)document.RoData(), document.Length()); +} + +// +bool +Kumu::XMLElement::ParseString(const std::string& document) +{ + return ParseString(document.c_str(), document.size()); +} + + +//---------------------------------------------------------------------------------------------------- + +#ifdef HAVE_EXPAT + + +class ExpatParseContext +{ + KM_NO_COPY_CONSTRUCT(ExpatParseContext); + ExpatParseContext(); +public: + ns_map* Namespaces; + std::stack<XMLElement*> Scope; + XMLElement* Root; + + ExpatParseContext(XMLElement* root) : Root(root) { + Namespaces = new ns_map; + assert(Root); + } + + ~ExpatParseContext() {} +}; + +// expat wrapper functions +// +static void +xph_start(void* p, const XML_Char* name, const XML_Char** attrs) +{ + assert(p); assert(name); assert(attrs); + ExpatParseContext* Ctx = (ExpatParseContext*)p; + XMLElement* Element; + + const char* ns_root = name; + const char* local_name = strchr(name, '|'); + if ( local_name != 0 ) + name = local_name + 1; + + if ( Ctx->Scope.empty() ) + { + Ctx->Scope.push(Ctx->Root); + } + else + { + Element = Ctx->Scope.top(); + Ctx->Scope.push(Element->AddChild(name)); + } + + Element = Ctx->Scope.top(); + Element->SetName(name); + + // map the namespace + std::string key; + if ( ns_root != name ) + key.assign(ns_root, name - ns_root - 1); + + ns_map::iterator ni = Ctx->Namespaces->find(key); + if ( ni != Ctx->Namespaces->end() ) + Element->SetNamespace(ni->second); + + // set attributes + for ( int i = 0; attrs[i] != 0; i += 2 ) + { + if ( ( local_name = strchr(attrs[i], '|') ) == 0 ) + local_name = attrs[i]; + else + local_name++; + + Element->SetAttr(local_name, attrs[i+1]); + } +} + +// +static void +xph_end(void* p, const XML_Char* name) +{ + assert(p); assert(name); + ExpatParseContext* Ctx = (ExpatParseContext*)p; + Ctx->Scope.pop(); +} + +// +static void +xph_char(void* p, const XML_Char* data, int len) +{ + assert(p); assert(data); + ExpatParseContext* Ctx = (ExpatParseContext*)p; + + if ( len > 0 ) + { + std::string tmp_str; + tmp_str.assign(data, len); + Ctx->Scope.top()->AppendBody(tmp_str); + } +} + +// +void +xph_namespace_start(void* p, const XML_Char* ns_prefix, const XML_Char* ns_name) +{ + assert(p); assert(ns_name); + ExpatParseContext* Ctx = (ExpatParseContext*)p; + + if ( ns_prefix == 0 ) + ns_prefix = ""; + + ns_map::iterator ni = Ctx->Namespaces->find(ns_name); + + if ( ni != Ctx->Namespaces->end() ) + { + if ( ni->second->Name() != std::string(ns_name) ) + { + DefaultLogSink().Error("Duplicate prefix: %s\n", ns_prefix); + return; + } + } + else + { + XMLNamespace* Namespace = new XMLNamespace(ns_prefix, ns_name); + Ctx->Namespaces->insert(ns_map::value_type(ns_name, Namespace)); + } +} + +// +bool +Kumu::XMLElement::ParseString(const char* document, ui32_t doc_len) +{ + XML_Parser Parser = XML_ParserCreateNS("UTF-8", '|'); + + if ( Parser == 0 ) + { + DefaultLogSink().Error("Error allocating memory for XML parser.\n"); + return false; + } + + ExpatParseContext Ctx(this); + XML_SetUserData(Parser, (void*)&Ctx); + XML_SetElementHandler(Parser, xph_start, xph_end); + XML_SetCharacterDataHandler(Parser, xph_char); + XML_SetStartNamespaceDeclHandler(Parser, xph_namespace_start); + + if ( ! XML_Parse(Parser, document, doc_len, 1) ) + { + XML_ParserFree(Parser); + DefaultLogSink().Error("XML Parse error on line %d: %s\n", + XML_GetCurrentLineNumber(Parser), + XML_ErrorString(XML_GetErrorCode(Parser))); + return false; + } + + XML_ParserFree(Parser); + + if ( ! Ctx.Namespaces->empty() ) + m_NamespaceOwner = (void*)Ctx.Namespaces; + + return true; +} + +//------------------------------------------------------------------------------------------ + +struct xph_test_wrapper +{ + XML_Parser Parser; + bool Status; + + xph_test_wrapper(XML_Parser p) : Parser(p), Status(false) {} +}; + +// expat wrapper functions, map callbacks to IASAXHandler +// +static void +xph_test_start(void* p, const XML_Char*, const XML_Char**) +{ + assert(p); + xph_test_wrapper* Wrapper = (xph_test_wrapper*)p; + + Wrapper->Status = true; + XML_StopParser(Wrapper->Parser, false); +} + + +// +bool +Kumu::StringIsXML(const char* document, ui32_t len) +{ + if ( document == 0 ) + return false; + + if ( len == 0 ) + len = strlen(document); + + XML_Parser Parser = XML_ParserCreate("UTF-8"); + + if ( Parser == 0 ) + { + DefaultLogSink().Error("Error allocating memory for XML parser.\n"); + return false; + } + + xph_test_wrapper Wrapper(Parser); + XML_SetUserData(Parser, (void*)&Wrapper); + XML_SetStartElementHandler(Parser, xph_test_start); + + XML_Parse(Parser, document, len, 1); + XML_ParserFree(Parser); + return Wrapper.Status; +} + +#endif + +//---------------------------------------------------------------------------------------------------- + +#ifdef HAVE_XERCES_C + +static Mutex sg_xerces_init_lock; // protect the xerces initialized +static bool sg_xml_init = false; // signal initialization +static Mutex sg_coder_lock; // protect the transcoder context +static XMLTranscoder* sg_coder = 0; +static const int sg_coder_buf_len = 128 * 1024; +static char sg_coder_buf[sg_coder_buf_len + 8]; +static unsigned char sg_coder_counts[sg_coder_buf_len / sizeof(XMLCh)]; // see XMLTranscoder::transcodeFrom + +static const XMLCh sg_LS[] = { chLatin_L, chLatin_S, chNull }; +static const XMLCh sg_label_UTF_8[] = { chLatin_U, chLatin_T, chLatin_F, + chDash, chDigit_8, chNull}; + +// +void +Kumu::init_xml_dom() +{ + if ( ! sg_xml_init ) + { + AutoMutex AL(sg_xerces_init_lock); + + if ( ! sg_xml_init ) + { + try + { + XMLPlatformUtils::Initialize(); + sg_xml_init = true; + + XMLTransService::Codes ret; + sg_coder = XMLPlatformUtils::fgTransService->makeNewTranscoderFor(sg_label_UTF_8, ret, sg_coder_buf_len); + + if ( ret != XMLTransService::Ok ) + { + const char* message = "Undefined Error"; + + switch ( ret ) + { + case XMLTransService::UnsupportedEncoding: message = "Unsupported encoding"; break; + case XMLTransService::InternalFailure: message = "Internal failure"; break; + case XMLTransService::SupportFilesNotFound: message = "Support files not found"; break; + } + + DefaultLogSink().Error("Xerces transform initialization error: %s\n", message); + } + } + catch (const XMLException &e) + { + DefaultLogSink().Error("Xerces initialization error: %s\n", e.getMessage()); + } + } + } +} + +// +bool +Kumu::XercesString_to_UTF_8(const Kumu::XercesString& in_str, std::string& out_str) { + return XercesString_to_UTF_8(in_str.c_str(), out_str); +} + +// +bool +Kumu::XercesString_to_UTF_8(const XMLCh* in_str, std::string& out_str) +{ + assert(in_str); + assert(sg_xml_init); + AutoMutex AL(sg_coder_lock); + ui32_t str_len = XMLString::stringLen(in_str); + ui32_t read_total = 0; + + try + { + while ( str_len > 0 ) + { +#if XERCES_VERSION_MAJOR < 3 + ui32_t read_count = 0; +#else + XMLSize_t read_count = 0; +#endif + ui32_t write_count = sg_coder->transcodeTo(in_str + read_total, str_len, + (XMLByte*)sg_coder_buf, sg_coder_buf_len, + read_count, XMLTranscoder::UnRep_Throw); + + out_str.append(sg_coder_buf, write_count); + str_len -= read_count; + read_total += read_count; + assert(str_len >= 0); + } + } + catch (...) + { + return false; + } + + return true; +} + +// +bool +Kumu::UTF_8_to_XercesString(const std::string& in_str, Kumu::XercesString& out_str) { + return UTF_8_to_XercesString(in_str.c_str(), out_str); +} + +// +bool +Kumu::UTF_8_to_XercesString(const char* in_str, Kumu::XercesString& out_str) +{ + assert(in_str); + assert(sg_xml_init); + AutoMutex AL(sg_coder_lock); + ui32_t str_len = strlen(in_str); + ui32_t read_total = 0; + + try + { + while ( str_len > 0 ) + { +#if XERCES_VERSION_MAJOR < 3 + ui32_t read_count = 0; +#else + XMLSize_t read_count = 0; +#endif + ui32_t write_count = sg_coder->transcodeFrom((const XMLByte*)(in_str + read_total), str_len, + (XMLCh*)sg_coder_buf, sg_coder_buf_len / sizeof(XMLCh), + read_count, sg_coder_counts); + + out_str.append((XMLCh*)sg_coder_buf, write_count * sizeof(XMLCh)); + str_len -= read_count; + read_total += read_count; + assert(str_len >= 0); + } + } + catch (...) + { + return false; + } + + return true; +} + +// +class MyTreeHandler : public HandlerBase +{ + ns_map* m_Namespaces; + std::stack<XMLElement*> m_Scope; + XMLElement* m_Root; + bool m_HasEncodeErrors; + +public: + MyTreeHandler(XMLElement* root) : m_Namespaces(0), m_Root(root), m_HasEncodeErrors(false) + { + assert(m_Root); + m_Namespaces = new ns_map; + } + + ~MyTreeHandler() { + delete m_Namespaces; + } + + bool HasEncodeErrors() const { return m_HasEncodeErrors; } + + ns_map* TakeNamespaceMap() + { + if ( m_Namespaces == 0 || m_Namespaces->empty() ) + return 0; + + ns_map* ret = m_Namespaces; + m_Namespaces = 0; + return ret; + } + + // + void AddNamespace(const char* ns_prefix, const char* ns_name) + { + assert(ns_prefix); + assert(ns_name); + + if ( ns_prefix[0] == ':' ) + { + ns_prefix++; + } + else + { + assert(ns_prefix[0] == 0); + ns_prefix = ""; + } + + ns_map::iterator ni = m_Namespaces->find(ns_name); + + if ( ni != m_Namespaces->end() ) + { + if ( ni->second->Name() != std::string(ns_name) ) + { + DefaultLogSink().Error("Duplicate prefix: %s\n", ns_prefix); + return; + } + } + else + { + XMLNamespace* Namespace = new XMLNamespace(ns_prefix, ns_name); + m_Namespaces->insert(ns_map::value_type(ns_prefix, Namespace)); + } + + assert(!m_Namespaces->empty()); + } + + // + void startElement(const XMLCh* const x_name, + XERCES_CPP_NAMESPACE::AttributeList& attributes) + { + assert(x_name); + std::string tx_name; + + if ( ! XercesString_to_UTF_8(x_name, tx_name) ) + m_HasEncodeErrors = true; + + const char* name = tx_name.c_str(); + XMLElement* Element; + const char* ns_root = name; + const char* local_name = strchr(name, ':'); + + if ( local_name != 0 ) + name = local_name + 1; + + if ( m_Scope.empty() ) + { + m_Scope.push(m_Root); + } + else + { + Element = m_Scope.top(); + m_Scope.push(Element->AddChild(name)); + } + + Element = m_Scope.top(); + Element->SetName(name); + + // set attributes + ui32_t a_len = attributes.getLength(); + + for ( ui32_t i = 0; i < a_len; i++) + { + std::string aname, value; + if ( ! XercesString_to_UTF_8(attributes.getName(i), aname) ) + m_HasEncodeErrors = true; + + if ( ! XercesString_to_UTF_8(attributes.getValue(i), value) ) + m_HasEncodeErrors = true; + + const char* x_aname = aname.c_str(); + const char* x_value = value.c_str(); + + if ( strncmp(x_aname, "xmlns", 5) == 0 ) + AddNamespace(x_aname+5, x_value); + + if ( ( local_name = strchr(x_aname, ':') ) == 0 ) + local_name = x_aname; + else + local_name++; + + Element->SetAttr(local_name, x_value); + } + + // map the namespace + std::string key; + if ( ns_root != name ) + key.assign(ns_root, name - ns_root - 1); + + ns_map::iterator ni = m_Namespaces->find(key); + if ( ni != m_Namespaces->end() ) + Element->SetNamespace(ni->second); + } + + void endElement(const XMLCh *const name) { + m_Scope.pop(); + } + + void characters(const XMLCh *const chars, const unsigned int length) + { + if ( length > 0 ) + { + std::string tmp; + if ( ! XercesString_to_UTF_8(chars, tmp) ) + m_HasEncodeErrors = true; + + m_Scope.top()->AppendBody(tmp); + } + } +}; + +// +bool +Kumu::XMLElement::ParseString(const char* document, ui32_t doc_len) +{ + if ( doc_len == 0 ) + return false; + + init_xml_dom(); + + int errorCount = 0; + SAXParser* parser = new SAXParser(); + + parser->setValidationScheme(SAXParser::Val_Always); + parser->setDoNamespaces(true); // optional + + MyTreeHandler* docHandler = new MyTreeHandler(this); + parser->setDocumentHandler(docHandler); + parser->setErrorHandler(docHandler); + + try + { + MemBufInputSource xmlSource(reinterpret_cast<const XMLByte*>(document), + static_cast<const unsigned int>(doc_len), + "pidc_rules_file"); + + parser->parse(xmlSource); + } + catch (const XMLException& e) + { + char* message = XMLString::transcode(e.getMessage()); + DefaultLogSink().Error("Parser error: %s\n", message); + XMLString::release(&message); + errorCount++; + } + catch (const SAXParseException& e) + { + char* message = XMLString::transcode(e.getMessage()); + DefaultLogSink().Error("Parser error: %s at line %d\n", message, e.getLineNumber()); + XMLString::release(&message); + errorCount++; + } + catch (...) + { + DefaultLogSink().Error("Unexpected XML parser error\n"); + errorCount++; + } + + if ( errorCount == 0 ) + m_NamespaceOwner = (void*)docHandler->TakeNamespaceMap(); + + delete parser; + delete docHandler; + + return errorCount > 0 ? false : true; +} + +// +bool +Kumu::StringIsXML(const char* document, ui32_t len) +{ + if ( document == 0 || *document == 0 ) + return false; + + init_xml_dom(); + + if ( len == 0 ) + len = strlen(document); + + SAXParser parser; + XMLPScanToken token; + bool status = false; + + try + { + MemBufInputSource xmlSource(reinterpret_cast<const XMLByte*>(document), + static_cast<const unsigned int>(len), + "pidc_rules_file"); + + if ( parser.parseFirst(xmlSource, token) ) + { + if ( parser.parseNext(token) ) + status = true; + } + } + catch (...) + { + } + + return status; +} + + +#endif + +//---------------------------------------------------------------------------------------------------- + +#if ! defined(HAVE_EXPAT) && ! defined(HAVE_XERCES_C) + +// +bool +Kumu::XMLElement::ParseString(const char*, ui32_t) +{ + DefaultLogSink().Error("Kumu compiled without XML parser support.\n"); + return false; +} + +// +bool +Kumu::StringIsXML(const char*, ui32_t) +{ + DefaultLogSink().Error("Kumu compiled without XML parser support.\n"); + return false; +} + +#endif + + +// +// end KM_xml.cpp +// diff --git a/asdcplib/src/KM_xml.h b/asdcplib/src/KM_xml.h new file mode 100644 index 0000000..cf77366 --- /dev/null +++ b/asdcplib/src/KM_xml.h @@ -0,0 +1,141 @@ +/* +Copyright (c) 2005-2011, 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 KM_xml.h + \version $Id: KM_xml.h,v 1.8 2011/08/15 23:03:26 jhurst Exp $ + \brief XML writer +*/ + + +#ifndef _KM_XML_H_ +#define _KM_XML_H_ + +#include <KM_util.h> +#include <list> +#include <string> + +namespace Kumu +{ + class XMLElement; + + // Return true if the given string contains an XML document (or the start of one). + bool StringIsXML(const char* document, ui32_t len = 0); + + // + struct NVPair + { + std::string name; + std::string value; + }; + + // + typedef std::list<NVPair> AttributeList; + typedef AttributeList::const_iterator Attr_i; + typedef std::list<XMLElement*> ElementList; + typedef ElementList::const_iterator Elem_i; + + // + class XMLNamespace + { + std::string m_Prefix; + std::string m_Name; + + KM_NO_COPY_CONSTRUCT(XMLNamespace); + XMLNamespace(); + + public: + XMLNamespace(const char* prefix, const char* name) : m_Prefix(prefix), m_Name(name) {} + ~XMLNamespace() {} + + inline const std::string& Prefix() const { return m_Prefix; } + inline const std::string& Name() const { return m_Name; } + }; + + // + class XMLElement + { + KM_NO_COPY_CONSTRUCT(XMLElement); + XMLElement(); + + protected: + AttributeList m_AttrList; + ElementList m_ChildList; + const XMLNamespace* m_Namespace; + void* m_NamespaceOwner; + + std::string m_Name; + std::string m_Body; + + public: + XMLElement(const char* name); + ~XMLElement(); + + inline const XMLNamespace* Namespace() const { return m_Namespace; } + inline void SetNamespace(const XMLNamespace* ns) { assert(ns); m_Namespace = ns; } + + bool ParseString(const char* document, ui32_t doc_len); + bool ParseString(const ByteString& document); + bool ParseString(const std::string& document); + + // building + void SetName(const char* name); + void SetBody(const std::string& value); + void AppendBody(const std::string& value); + void SetAttr(const char* name, const char* value); + void SetAttr(const char* name, const std::string& value) { SetAttr(name, value.c_str()); } + XMLElement* AddChild(XMLElement* element); + XMLElement* AddChild(const char* name); + XMLElement* AddChildWithContent(const char* name, const char* value); + XMLElement* AddChildWithContent(const char* name, const std::string& value); + XMLElement* AddChildWithPrefixedContent(const char* name, const char* prefix, const char* value); + void AddComment(const char* value); + void Render(std::string&) const; + void RenderElement(std::string& outbuf, ui32_t depth) const; + + // querying + inline const std::string& GetBody() const { return m_Body; } + inline const ElementList& GetChildren() const { return m_ChildList; } + inline const std::string& GetName() const { return m_Name; } + inline const AttributeList& GetAttributes() const { return m_AttrList; } + const char* GetAttrWithName(const char* name) const; + XMLElement* GetChildWithName(const char* name) const; + const ElementList& GetChildrenWithName(const char* name, ElementList& outList) const; + bool HasName(const char* name) const; + + // altering + void DeleteAttributes(); + void DeleteAttrWithName(const char* name); + void DeleteChildren(); + void DeleteChild(const XMLElement* element); + void ForgetChild(const XMLElement* element); + }; +} // namespace Kumu + +#endif // _KM_XML_H_ + +// +// end KM_xml.h +// diff --git a/asdcplib/src/MDD.cpp b/asdcplib/src/MDD.cpp new file mode 100644 index 0000000..ac8f0dd --- /dev/null +++ b/asdcplib/src/MDD.cpp @@ -0,0 +1,925 @@ +/* +Copyright (c) 2006-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 MDD.[h|cpp] + \version $Id: MDD.cpp,v 1.34 2012/02/02 01:58:43 jhurst Exp $ + \brief MXF Metadata Dictionary +*/ +// +// MDD.cpp +// + +#include "KLV.h" + +static const ASDCP::MDDEntry s_MDD_Table[] = { + { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + {0, 0}, false, "MICAlgorithm_NONE" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x01, // 1 + 0x0d, 0x01, 0x02, 0x01, 0x10, 0x00, 0x00, 0x00 }, + {0, 0}, false, "MXFInterop_OPAtom" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x02, // 2 + 0x0d, 0x01, 0x02, 0x01, 0x10, 0x00, 0x00, 0x00 }, + {0, 0}, false, "OPAtom" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x01, // 3 + 0x0d, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x00 }, + {0, 0}, false, "OP1a" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x03, // 4 + 0x0d, 0x01, 0x03, 0x01, 0x02, 0x7f, 0x01, 0x00 }, + {0, 0}, false, "GCMulti" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x01, // 5 + 0x01, 0x03, 0x02, 0x02, 0x01, 0x00, 0x00, 0x00 }, + {0, 0}, false, "PictureDataDef" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x01, // 6 + 0x01, 0x03, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00 }, + {0, 0}, false, "SoundDataDef" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x01, // 7 + 0x01, 0x03, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00 }, + {0, 0}, false, "TimecodeDataDef" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x01, // 8 + 0x01, 0x03, 0x02, 0x01, 0x10, 0x00, 0x00, 0x00 }, + {0, 0}, false, "DescriptiveMetaDataDef" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x01, // 9 + 0x0d, 0x01, 0x03, 0x01, 0x02, 0x06, 0x01, 0x00 }, + {0, 0}, false, "WAVWrapping" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x02, // 10 + 0x0d, 0x01, 0x03, 0x01, 0x02, 0x04, 0x60, 0x00 }, + {0, 0}, false, "MPEG2_VESWrapping" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x07, // 11 + 0x0d, 0x01, 0x03, 0x01, 0x02, 0x0c, 0x01, 0x00 }, + {0, 0}, false, "JPEG_2000Wrapping" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x02, 0x01, 0x01, // 12 + 0x0d, 0x01, 0x03, 0x01, 0x15, 0x01, 0x08, 0x00 }, + {0, 0}, false, "JPEG2000Essence" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x02, 0x01, 0x01, // 13 + 0x0d, 0x01, 0x03, 0x01, 0x15, 0x01, 0x05, 0x00 }, + {0, 0}, false, "MPEG2Essence" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x04, 0x01, 0x07, // 14 + 0x0d, 0x01, 0x03, 0x01, 0x02, 0x7e, 0x01, 0x00 }, + {0, 0}, false, "MXFInterop_CryptEssence" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x04, 0x01, 0x01, // 15 + 0x0d, 0x01, 0x03, 0x01, 0x02, 0x7e, 0x01, 0x00 }, + {0, 0}, false, "CryptEssence" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x02, 0x01, 0x01, // 16 + 0x0d, 0x01, 0x03, 0x01, 0x16, 0x01, 0x01, 0x00 }, + {0, 0}, false, "WAVEssence" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x09, // 17 + 0x04, 0x01, 0x02, 0x02, 0x03, 0x01, 0x01, 0x03 }, + {0, 0}, false, "JP2KEssenceCompression_2K" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x09, // 18 + 0x04, 0x01, 0x02, 0x02, 0x03, 0x01, 0x01, 0x04 }, + {0, 0}, false, "JP2KEssenceCompression_4K" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x07, // 19 + 0x02, 0x09, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00 }, + {0, 0}, false, "CipherAlgorithm_AES" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x07, // 20 + 0x02, 0x09, 0x02, 0x02, 0x01, 0x00, 0x00, 0x00 }, + {0, 0}, false, "MICAlgorithm_HMAC_SHA1" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 21 + 0x03, 0x01, 0x02, 0x10, 0x01, 0x00, 0x00, 0x00 }, + {0, 0}, false, "KLVFill" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 22 + 0x03, 0x01, 0x02, 0x01, 0x06, 0x00, 0x00, 0x00 }, + {0, 0}, false, "PartitionMetadata_MajorVersion" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 23 + 0x03, 0x01, 0x02, 0x01, 0x07, 0x00, 0x00, 0x00 }, + {0, 0}, false, "PartitionMetadata_MinorVersion" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 24 + 0x03, 0x01, 0x02, 0x01, 0x09, 0x00, 0x00, 0x00 }, + {0, 0}, false, "PartitionMetadata_KAGSize" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 25 + 0x06, 0x10, 0x10, 0x03, 0x01, 0x00, 0x00, 0x00 }, + {0, 0}, false, "PartitionMetadata_ThisPartition" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 26 + 0x06, 0x10, 0x10, 0x02, 0x01, 0x00, 0x00, 0x00 }, + {0, 0}, false, "PartitionMetadata_PreviousPartition" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 27 + 0x06, 0x10, 0x10, 0x05, 0x01, 0x00, 0x00, 0x00 }, + {0, 0}, false, "PartitionMetadata_FooterPartition" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 28 + 0x04, 0x06, 0x09, 0x01, 0x00, 0x00, 0x00, 0x00 }, + {0, 0}, false, "PartitionMetadata_HeaderByteCount" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 29 + 0x04, 0x06, 0x09, 0x02, 0x00, 0x00, 0x00, 0x00 }, + {0, 0}, false, "PartitionMetadata_IndexByteCount" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 30 + 0x01, 0x03, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00 }, + {0, 0}, false, "PartitionMetadata_IndexSID" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 31 + 0x06, 0x08, 0x01, 0x02, 0x01, 0x03, 0x00, 0x00 }, + {0, 0}, false, "PartitionMetadata_BodyOffset" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 32 + 0x01, 0x03, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00 }, + {0, 0}, false, "PartitionMetadata_BodySID" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 33 + 0x01, 0x02, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00 }, + {0, 0}, false, "PartitionMetadata_OperationalPattern" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 34 + 0x01, 0x02, 0x02, 0x10, 0x02, 0x01, 0x00, 0x00 }, + {0, 0}, false, "PartitionMetadata_EssenceContainers" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01, // 35 + 0x0d, 0x01, 0x02, 0x01, 0x01, 0x02, 0x01, 0x00 }, + {0, 0}, false, "OpenHeader" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01, // 36 + 0x0d, 0x01, 0x02, 0x01, 0x01, 0x02, 0x03, 0x00 }, + {0, 0}, false, "OpenCompleteHeader" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01, // 37 + 0x0d, 0x01, 0x02, 0x01, 0x01, 0x02, 0x02, 0x00 }, + {0, 0}, false, "ClosedHeader" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01, // 38 + 0x0d, 0x01, 0x02, 0x01, 0x01, 0x02, 0x04, 0x00 }, + {0, 0}, false, "ClosedCompleteHeader" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01, // 39 + 0x0d, 0x01, 0x02, 0x01, 0x01, 0x03, 0x01, 0x00 }, + {0, 0}, false, "OpenBodyPartition" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01, // 40 + 0x0d, 0x01, 0x02, 0x01, 0x01, 0x03, 0x03, 0x00 }, + {0, 0}, false, "OpenCompleteBodyPartition" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01, // 41 + 0x0d, 0x01, 0x02, 0x01, 0x01, 0x03, 0x02, 0x00 }, + {0, 0}, false, "ClosedBodyPartition" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01, // 42 + 0x0d, 0x01, 0x02, 0x01, 0x01, 0x03, 0x04, 0x00 }, + {0, 0}, false, "ClosedCompleteBodyPartition" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01, // 43 + 0x0d, 0x01, 0x02, 0x01, 0x01, 0x04, 0x02, 0x00 }, + {0, 0}, false, "Footer" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01, // 44 + 0x0d, 0x01, 0x02, 0x01, 0x01, 0x04, 0x04, 0x00 }, + {0, 0}, false, "CompleteFooter" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01, // 45 + 0x0d, 0x01, 0x02, 0x01, 0x01, 0x05, 0x01, 0x00 }, + {0, 0}, false, "Primer" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 46 + 0x06, 0x01, 0x01, 0x07, 0x15, 0x00, 0x00, 0x00 }, + {0, 0}, false, "Primer_LocalTagEntryBatch" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 47 + 0x01, 0x03, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00 }, + {0, 0}, false, "LocalTagEntryBatch_Primer_LocalTag" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 48 + 0x01, 0x03, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00 }, + {0, 0}, false, "LocalTagEntryBatch_Primer_UID" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, // 49 + 0x01, 0x01, 0x15, 0x02, 0x00, 0x00, 0x00, 0x00 }, + {0x3c, 0x0a}, false, "InterchangeObject_InstanceUID" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 50 + 0x05, 0x20, 0x07, 0x01, 0x08, 0x00, 0x00, 0x00 }, + {0x01, 0x02}, true, "GenerationInterchangeObject_GenerationUID" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 51 + 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + {0, 0}, false, "DefaultObject" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 52 + 0x05, 0x30, 0x04, 0x06, 0x00, 0x00, 0x00, 0x00 }, + {0x3f, 0x0b}, false, "IndexTableSegmentBase_IndexEditRate" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 53 + 0x07, 0x02, 0x01, 0x03, 0x01, 0x0a, 0x00, 0x00 }, + {0x3f, 0x0c}, false, "IndexTableSegmentBase_IndexStartPosition" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 54 + 0x07, 0x02, 0x02, 0x01, 0x01, 0x02, 0x00, 0x00 }, + {0x3f, 0x0d}, false, "IndexTableSegmentBase_IndexDuration" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 55 + 0x04, 0x06, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00 }, + {0x3f, 0x05}, false, "IndexTableSegmentBase_EditUnitByteCount" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 56 + 0x01, 0x03, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00 }, + {0x3f, 0x06}, false, "IndexTableSegmentBase_IndexSID" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 57 + 0x01, 0x03, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00 }, + {0x3f, 0x07}, false, "IndexTableSegmentBase_BodySID" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 58 + 0x04, 0x04, 0x04, 0x01, 0x01, 0x00, 0x00, 0x00 }, + {0x3f, 0x08}, false, "IndexTableSegmentBase_SliceCount" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 59 + 0x04, 0x04, 0x04, 0x01, 0x07, 0x00, 0x00, 0x00 }, + {0x3f, 0x0e}, true, "IndexTableSegmentBase_PosTableCount" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 60 + 0x0d, 0x01, 0x02, 0x01, 0x01, 0x10, 0x01, 0x00 }, + {0, 0}, false, "IndexTableSegment" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 61 + 0x04, 0x04, 0x04, 0x01, 0x06, 0x00, 0x00, 0x00 }, + {0x3f, 0x09}, true, "IndexTableSegment_DeltaEntryArray" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 62 + 0x04, 0x04, 0x04, 0x01, 0x04, 0x00, 0x00, 0x00 }, + {0, 0}, false, "DeltaEntryArray_IndexTableSegment_PosTableIndex" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 63 + 0x04, 0x04, 0x04, 0x01, 0x02, 0x00, 0x00, 0x00 }, + {0, 0}, false, "DeltaEntryArray_IndexTableSegment_Slice" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 64 + 0x04, 0x04, 0x04, 0x01, 0x03, 0x00, 0x00, 0x00 }, + {0, 0}, false, "DeltaEntryArray_IndexTableSegment_ElementDelta" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 65 + 0x04, 0x04, 0x04, 0x02, 0x05, 0x00, 0x00, 0x00 }, + {0x3f, 0x0a}, false, "IndexTableSegment_IndexEntryArray" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 66 + 0x04, 0x04, 0x04, 0x02, 0x03, 0x00, 0x00, 0x00 }, + {0, 0}, false, "IndexEntryArray_IndexTableSegment_TemporalOffset" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 67 + 0x04, 0x04, 0x04, 0x02, 0x04, 0x00, 0x00, 0x00 }, + {0, 0}, false, "IndexEntryArray_IndexTableSegment_AnchorOffset" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 68 + 0x04, 0x04, 0x04, 0x02, 0x02, 0x00, 0x00, 0x00 }, + {0, 0}, false, "IndexEntryArray_IndexTableSegment_Flags" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 69 + 0x04, 0x04, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00 }, + {0, 0}, false, "IndexEntryArray_IndexTableSegment_StreamOffset" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 70 + 0x04, 0x04, 0x04, 0x01, 0x05, 0x00, 0x00, 0x00 }, + {0, 0}, false, "IndexEntryArray_IndexTableSegment_SliceOffsetArray" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 71 + 0x04, 0x04, 0x04, 0x01, 0x08, 0x00, 0x00, 0x00 }, + {0, 0}, false, "IndexEntryArray_IndexTableSegment_PosTableArray" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01, // 72 + 0x0d, 0x01, 0x02, 0x01, 0x01, 0x11, 0x01, 0x00 }, + {0, 0}, false, "RandomIndexMetadata" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 73 + 0x01, 0x03, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00 }, + {0, 0}, false, "PartitionArray_RandomIndexMetadata_BodySID" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 74 + 0x06, 0x09, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00 }, + {0, 0}, false, "PartitionArray_RandomIndexMetadata_ByteOffset" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 75 + 0x04, 0x06, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00 }, + {0, 0}, false, "RandomIndexMetadata_Length" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01, // 76 + 0x0d, 0x01, 0x02, 0x01, 0x01, 0x11, 0x00, 0x00 }, + {0, 0}, false, "RandomIndexMetadataV10" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 77 + 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x2f, 0x00 }, + {0, 0}, false, "Preface" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 78 + 0x07, 0x02, 0x01, 0x10, 0x02, 0x04, 0x00, 0x00 }, + {0x3b, 0x02}, false, "Preface_LastModifiedDate" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 79 + 0x03, 0x01, 0x02, 0x01, 0x05, 0x00, 0x00, 0x00 }, + {0x3b, 0x05}, false, "Preface_Version" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 80 + 0x03, 0x01, 0x02, 0x01, 0x04, 0x00, 0x00, 0x00 }, + {0x3b, 0x07}, true, "Preface_ObjectModelVersion" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 81 + 0x06, 0x01, 0x01, 0x04, 0x01, 0x08, 0x00, 0x00 }, + {0x3b, 0x08}, true, "Preface_PrimaryPackage" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 82 + 0x06, 0x01, 0x01, 0x04, 0x06, 0x04, 0x00, 0x00 }, + {0x3b, 0x06}, false, "Preface_Identifications" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 83 + 0x06, 0x01, 0x01, 0x04, 0x02, 0x01, 0x00, 0x00 }, + {0x3b, 0x03}, false, "Preface_ContentStorage" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 84 + 0x01, 0x02, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00 }, + {0x3b, 0x09}, false, "Preface_OperationalPattern" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 85 + 0x01, 0x02, 0x02, 0x10, 0x02, 0x01, 0x00, 0x00 }, + {0x3b, 0x0a}, false, "Preface_EssenceContainers" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 86 + 0x01, 0x02, 0x02, 0x10, 0x02, 0x02, 0x00, 0x00 }, + {0x3b, 0x0b}, false, "Preface_DMSchemes" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 87 + 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x30, 0x00 }, + {0, 0}, false, "Identification" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 88 + 0x05, 0x20, 0x07, 0x01, 0x01, 0x00, 0x00, 0x00 }, + {0x3c, 0x09}, false, "Identification_ThisGenerationUID" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 89 + 0x05, 0x20, 0x07, 0x01, 0x02, 0x01, 0x00, 0x00 }, + {0x3c, 0x01}, false, "Identification_CompanyName" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 90 + 0x05, 0x20, 0x07, 0x01, 0x03, 0x01, 0x00, 0x00 }, + {0x3c, 0x02}, false, "Identification_ProductName" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 91 + 0x05, 0x20, 0x07, 0x01, 0x04, 0x00, 0x00, 0x00 }, + {0x3c, 0x03}, true, "Identification_ProductVersion" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 92 + 0x05, 0x20, 0x07, 0x01, 0x05, 0x01, 0x00, 0x00 }, + {0x3c, 0x04}, false, "Identification_VersionString" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 93 + 0x05, 0x20, 0x07, 0x01, 0x07, 0x00, 0x00, 0x00 }, + {0x3c, 0x05}, false, "Identification_ProductUID" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 94 + 0x07, 0x02, 0x01, 0x10, 0x02, 0x03, 0x00, 0x00 }, + {0x3c, 0x06}, false, "Identification_ModificationDate" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 95 + 0x05, 0x20, 0x07, 0x01, 0x0a, 0x00, 0x00, 0x00 }, + {0x3c, 0x07}, true, "Identification_ToolkitVersion" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 96 + 0x05, 0x20, 0x07, 0x01, 0x06, 0x01, 0x00, 0x00 }, + {0x3c, 0x08}, true, "Identification_Platform" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 97 + 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x18, 0x00 }, + {0, 0}, false, "ContentStorage" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 98 + 0x06, 0x01, 0x01, 0x04, 0x05, 0x01, 0x00, 0x00 }, + {0x19, 0x01}, false, "ContentStorage_Packages" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 99 + 0x06, 0x01, 0x01, 0x04, 0x05, 0x02, 0x00, 0x00 }, + {0x19, 0x02}, true, "ContentStorage_EssenceContainerData" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 100 + 0x06, 0x01, 0x01, 0x04, 0x05, 0x00, 0x00, 0x00 }, + {0x19, 0x01}, false, "ContentStorageKludge_V10Packages" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 101 + 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x23, 0x00 }, + {0, 0}, false, "EssenceContainerData" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 102 + 0x06, 0x01, 0x01, 0x06, 0x01, 0x00, 0x00, 0x00 }, + {0x27, 0x01}, false, "EssenceContainerData_LinkedPackageUID" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 103 + 0x01, 0x03, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00 }, + {0x3f, 0x06}, true, "EssenceContainerData_IndexSID" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 104 + 0x01, 0x03, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00 }, + {0x3f, 0x07}, false, "EssenceContainerData_BodySID" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, // 105 + 0x01, 0x01, 0x15, 0x10, 0x00, 0x00, 0x00, 0x00 }, + {0x44, 0x01}, false, "GenericPackage_PackageUID" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, // 106 + 0x01, 0x03, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00 }, + {0x44, 0x02}, true, "GenericPackage_Name" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 107 + 0x07, 0x02, 0x01, 0x10, 0x01, 0x03, 0x00, 0x00 }, + {0x44, 0x05}, false, "GenericPackage_PackageCreationDate" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 108 + 0x07, 0x02, 0x01, 0x10, 0x02, 0x05, 0x00, 0x00 }, + {0x44, 0x04}, false, "GenericPackage_PackageModifiedDate" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 109 + 0x06, 0x01, 0x01, 0x04, 0x06, 0x05, 0x00, 0x00 }, + {0x44, 0x03}, false, "GenericPackage_Tracks" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 110 + 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x32, 0x00 }, + {0, 0}, false, "NetworkLocator" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, // 111 + 0x01, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00 }, + {0x40, 0x01}, false, "NetworkLocator_URLString" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 112 + 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x33, 0x00 }, + {0, 0}, false, "TextLocator" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 113 + 0x01, 0x04, 0x01, 0x02, 0x01, 0x00, 0x00, 0x00 }, + {0x41, 0x01}, false, "TextLocator_LocatorName" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 114 + 0x01, 0x07, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00 }, + {0x48, 0x01}, false, "GenericTrack_TrackID" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 115 + 0x01, 0x04, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00 }, + {0x48, 0x04}, false, "GenericTrack_TrackNumber" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 116 + 0x01, 0x07, 0x01, 0x02, 0x01, 0x00, 0x00, 0x00 }, + {0x48, 0x02}, true, "GenericTrack_TrackName" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 117 + 0x06, 0x01, 0x01, 0x04, 0x02, 0x04, 0x00, 0x00 }, + {0x48, 0x03}, false, "GenericTrack_Sequence" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 118 + 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x3a, 0x00 }, + {0, 0}, false, "StaticTrack" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 119 + 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x3b, 0x00 }, + {0, 0}, false, "Track" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 120 + 0x05, 0x30, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00 }, + {0x4b, 0x01}, false, "Track_EditRate" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 121 + 0x07, 0x02, 0x01, 0x03, 0x01, 0x03, 0x00, 0x00 }, + {0x4b, 0x02}, false, "Track_Origin" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 122 + 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x39, 0x00 }, + {0, 0}, false, "EventTrack" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 123 + 0x05, 0x30, 0x04, 0x02, 0x00, 0x00, 0x00, 0x00 }, + {0x49, 0x01}, false, "EventTrack_EventEditRate" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 124 + 0x07, 0x02, 0x01, 0x03, 0x01, 0x0b, 0x00, 0x00 }, + {0x49, 0x02}, true, "EventTrack_EventOrigin" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 125 + 0x04, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 }, + {0x02, 0x01}, false, "StructuralComponent_DataDefinition" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 126 + 0x07, 0x02, 0x02, 0x01, 0x01, 0x03, 0x00, 0x00 }, + {0x02, 0x02}, false, "StructuralComponent_Duration" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 127 + 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x0f, 0x00 }, + {0, 0}, false, "Sequence" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 128 + 0x06, 0x01, 0x01, 0x04, 0x06, 0x09, 0x00, 0x00 }, + {0x10, 0x01}, false, "Sequence_StructuralComponents" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 129 + 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x14, 0x00 }, + {0, 0}, false, "TimecodeComponent" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 130 + 0x04, 0x04, 0x01, 0x01, 0x02, 0x06, 0x00, 0x00 }, + {0x15, 0x02}, false, "TimecodeComponent_RoundedTimecodeBase" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 131 + 0x07, 0x02, 0x01, 0x03, 0x01, 0x05, 0x00, 0x00 }, + {0x15, 0x01}, false, "TimecodeComponent_StartTimecode" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, // 132 + 0x04, 0x04, 0x01, 0x01, 0x05, 0x00, 0x00, 0x00 }, + {0x15, 0x03}, false, "TimecodeComponent_DropFrame" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 133 + 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x11, 0x00 }, + {0, 0}, false, "SourceClip" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 134 + 0x07, 0x02, 0x01, 0x03, 0x01, 0x04, 0x00, 0x00 }, + {0x12, 0x01}, false, "SourceClip_StartPosition" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 135 + 0x06, 0x01, 0x01, 0x03, 0x01, 0x00, 0x00, 0x00 }, + {0x11, 0x01}, false, "SourceClip_SourcePackageID" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 136 + 0x06, 0x01, 0x01, 0x03, 0x02, 0x00, 0x00, 0x00 }, + {0x11, 0x02}, false, "SourceClip_SourceTrackID" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 137 + 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x41, 0x00 }, + {0, 0}, false, "DMSegment" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 138 + 0x07, 0x02, 0x01, 0x03, 0x03, 0x03, 0x00, 0x00 }, + {0x06, 0x01}, false, "DMSegment_EventStartPosition" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 139 + 0x05, 0x30, 0x04, 0x04, 0x01, 0x00, 0x00, 0x00 }, + {0x06, 0x02}, true, "DMSegment_EventComment" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 140 + 0x01, 0x07, 0x01, 0x05, 0x00, 0x00, 0x00, 0x00 }, + {0x61, 0x02}, false, "DMSegment_TrackIDs" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 141 + 0x06, 0x01, 0x01, 0x04, 0x02, 0x0c, 0x00, 0x00 }, + {0x61, 0x01}, false, "DMSegment_DMFramework" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 142 + 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x45, 0x00 }, + {0, 0}, false, "DMSourceClip" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 143 + 0x01, 0x07, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00 }, + {0x61, 0x03}, true, "DMSourceClip_DMSourceClipTrackIDs" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 144 + 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x36, 0x00 }, + {0, 0}, false, "MaterialPackage" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 145 + 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x37, 0x00 }, + {0, 0}, false, "SourcePackage" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 146 + 0x06, 0x01, 0x01, 0x04, 0x02, 0x03, 0x00, 0x00 }, + {0x47, 0x01}, false, "SourcePackage_Descriptor" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 147 + 0x06, 0x01, 0x01, 0x04, 0x06, 0x03, 0x00, 0x00 }, + {0x2f, 0x01}, true, "GenericDescriptor_Locators" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x09, // 148 + 0x06, 0x01, 0x01, 0x04, 0x06, 0x10, 0x00, 0x00 }, + {0, 0}, true, "GenericDescriptor_SubDescriptors" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 149 + 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x25, 0x00 }, + {0, 0}, false, "FileDescriptor" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 150 + 0x06, 0x01, 0x01, 0x03, 0x05, 0x00, 0x00, 0x00 }, + {0x30, 0x06}, true, "FileDescriptor_LinkedTrackID" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, // 151 + 0x04, 0x06, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00 }, + {0x30, 0x01}, false, "FileDescriptor_SampleRate" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, // 152 + 0x04, 0x06, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00 }, + {0x30, 0x02}, true, "FileDescriptor_ContainerDuration" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 153 + 0x06, 0x01, 0x01, 0x04, 0x01, 0x02, 0x00, 0x00 }, + {0x30, 0x04}, false, "FileDescriptor_EssenceContainer" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 154 + 0x06, 0x01, 0x01, 0x04, 0x01, 0x03, 0x00, 0x00 }, + {0x30, 0x05}, true, "FileDescriptor_Codec" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 155 + 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x27, 0x00 }, + {0, 0}, false, "GenericPictureEssenceDescriptor" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 156 + 0x04, 0x05, 0x01, 0x13, 0x00, 0x00, 0x00, 0x00 }, + {0x32, 0x15}, true, "GenericPictureEssenceDescriptor_SignalStandard" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, // 157 + 0x04, 0x01, 0x03, 0x01, 0x04, 0x00, 0x00, 0x00 }, + {0x32, 0x0c}, false, "GenericPictureEssenceDescriptor_FrameLayout" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, // 158 + 0x04, 0x01, 0x05, 0x02, 0x02, 0x00, 0x00, 0x00 }, + {0x32, 0x03}, false, "GenericPictureEssenceDescriptor_StoredWidth" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, // 159 + 0x04, 0x01, 0x05, 0x02, 0x01, 0x00, 0x00, 0x00 }, + {0x32, 0x02}, false, "GenericPictureEssenceDescriptor_StoredHeight" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 160 + 0x04, 0x01, 0x03, 0x02, 0x08, 0x00, 0x00, 0x00 }, + {0x32, 0x16}, true, "GenericPictureEssenceDescriptor_StoredF2Offset" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, // 161 + 0x04, 0x01, 0x05, 0x01, 0x08, 0x00, 0x00, 0x00 }, + {0x32, 0x05}, true, "GenericPictureEssenceDescriptor_SampledWidth" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, // 162 + 0x04, 0x01, 0x05, 0x01, 0x07, 0x00, 0x00, 0x00 }, + {0x32, 0x04}, true, "GenericPictureEssenceDescriptor_SampledHeight" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, // 163 + 0x04, 0x01, 0x05, 0x01, 0x09, 0x00, 0x00, 0x00 }, + {0x32, 0x06}, true, "GenericPictureEssenceDescriptor_SampledXOffset" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, // 164 + 0x04, 0x01, 0x05, 0x01, 0x0a, 0x00, 0x00, 0x00 }, + {0x32, 0x07}, true, "GenericPictureEssenceDescriptor_SampledYOffset" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, // 165 + 0x04, 0x01, 0x05, 0x01, 0x0b, 0x00, 0x00, 0x00 }, + {0x32, 0x08}, true, "GenericPictureEssenceDescriptor_DisplayHeight" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, // 166 + 0x04, 0x01, 0x05, 0x01, 0x0c, 0x00, 0x00, 0x00 }, + {0x32, 0x09}, true, "GenericPictureEssenceDescriptor_DisplayWidth" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, // 167 + 0x04, 0x01, 0x05, 0x01, 0x0d, 0x00, 0x00, 0x00 }, + {0x32, 0x0a}, true, "GenericPictureEssenceDescriptor_DisplayXOffset" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, // 168 + 0x04, 0x01, 0x05, 0x01, 0x0e, 0x00, 0x00, 0x00 }, + {0x32, 0x0b}, true, "GenericPictureEssenceDescriptor_DisplayYOffset" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 169 + 0x04, 0x01, 0x03, 0x02, 0x07, 0x00, 0x00, 0x00 }, + {0x32, 0x17}, true, "GenericPictureEssenceDescriptor_DisplayF2Offset" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, // 170 + 0x04, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00 }, + {0x32, 0x0e}, false, "GenericPictureEssenceDescriptor_AspectRatio" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 171 + 0x04, 0x01, 0x03, 0x02, 0x09, 0x00, 0x00, 0x00 }, + {0x32, 0x18}, true, "GenericPictureEssenceDescriptor_ActiveFormatDescriptor" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 172 + 0x04, 0x01, 0x03, 0x02, 0x05, 0x00, 0x00, 0x00 }, + {0x32, 0x0d}, false, "GenericPictureEssenceDescriptor_VideoLineMap" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 173 + 0x05, 0x20, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00 }, + {0x32, 0x0f}, true, "GenericPictureEssenceDescriptor_AlphaTransparency" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 174 + 0x04, 0x01, 0x02, 0x01, 0x01, 0x01, 0x02, 0x00 }, + {0x32, 0x10}, true, "GenericPictureEssenceDescriptor_Gamma" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 175 + 0x04, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00 }, + {0x32, 0x11}, true, "GenericPictureEssenceDescriptor_ImageAlignmentOffset" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 176 + 0x04, 0x18, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00 }, + {0x32, 0x13}, true, "GenericPictureEssenceDescriptor_ImageStartOffset" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 177 + 0x04, 0x18, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00 }, + {0x32, 0x14}, true, "GenericPictureEssenceDescriptor_ImageEndOffset" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 178 + 0x04, 0x01, 0x03, 0x01, 0x06, 0x00, 0x00, 0x00 }, + {0x32, 0x12}, true, "GenericPictureEssenceDescriptor_FieldDominance" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 179 + 0x04, 0x01, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00 }, + {0x32, 0x01}, false, "GenericPictureEssenceDescriptor_PictureEssenceCoding" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 180 + 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x28, 0x00 }, + {0, 0}, false, "CDCIEssenceDescriptor" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 181 + 0x04, 0x01, 0x05, 0x03, 0x0a, 0x00, 0x00, 0x00 }, + {0x33, 0x01}, false, "CDCIEssenceDescriptor_ComponentDepth" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, // 182 + 0x04, 0x01, 0x05, 0x01, 0x05, 0x00, 0x00, 0x00 }, + {0x33, 0x02}, false, "CDCIEssenceDescriptor_HorizontalSubsampling" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 183 + 0x04, 0x01, 0x05, 0x01, 0x10, 0x00, 0x00, 0x00 }, + {0x33, 0x08}, true, "CDCIEssenceDescriptor_VerticalSubsampling" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, // 184 + 0x04, 0x01, 0x05, 0x01, 0x06, 0x00, 0x00, 0x00 }, + {0x33, 0x03}, true, "CDCIEssenceDescriptor_ColorSiting" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 185 + 0x03, 0x01, 0x02, 0x01, 0x0a, 0x00, 0x00, 0x00 }, + {0x33, 0x0b}, true, "CDCIEssenceDescriptor_ReversedByteOrder" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 186 + 0x04, 0x18, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00 }, + {0x33, 0x07}, true, "CDCIEssenceDescriptor_PaddingBits" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 187 + 0x04, 0x01, 0x05, 0x03, 0x07, 0x00, 0x00, 0x00 }, + {0x33, 0x09}, true, "CDCIEssenceDescriptor_AlphaSampleDepth" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, // 188 + 0x04, 0x01, 0x05, 0x03, 0x03, 0x00, 0x00, 0x00 }, + {0x33, 0x04}, true, "CDCIEssenceDescriptor_BlackRefLevel" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, // 189 + 0x04, 0x01, 0x05, 0x03, 0x04, 0x00, 0x00, 0x00 }, + {0x33, 0x05}, true, "CDCIEssenceDescriptor_WhiteReflevel" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 190 + 0x04, 0x01, 0x05, 0x03, 0x05, 0x00, 0x00, 0x00 }, + {0x33, 0x06}, true, "CDCIEssenceDescriptor_ColorRange" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 191 + 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x29, 0x00 }, + {0, 0}, false, "RGBAEssenceDescriptor" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 192 + 0x04, 0x01, 0x05, 0x03, 0x0b, 0x00, 0x00, 0x00 }, + {0x34, 0x06}, true, "RGBAEssenceDescriptor_ComponentMaxRef" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 193 + 0x04, 0x01, 0x05, 0x03, 0x0c, 0x00, 0x00, 0x00 }, + {0x34, 0x07}, true, "RGBAEssenceDescriptor_ComponentMinRef" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 194 + 0x04, 0x01, 0x05, 0x03, 0x0d, 0x00, 0x00, 0x00 }, + {0x34, 0x08}, true, "RGBAEssenceDescriptor_AlphaMaxRef" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 195 + 0x04, 0x01, 0x05, 0x03, 0x0e, 0x00, 0x00, 0x00 }, + {0x34, 0x09}, true, "RGBAEssenceDescriptor_AlphaMinRef" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 196 + 0x04, 0x01, 0x04, 0x04, 0x01, 0x00, 0x00, 0x00 }, + {0x34, 0x05}, true, "RGBAEssenceDescriptor_ScanningDirection" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 197 + 0x04, 0x01, 0x05, 0x03, 0x06, 0x00, 0x00, 0x00 }, + {0x34, 0x01}, false, "RGBAEssenceDescriptor_PixelLayout" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 198 + 0x04, 0x01, 0x05, 0x03, 0x08, 0x00, 0x00, 0x00 }, + {0x34, 0x03}, true, "RGBAEssenceDescriptor_Palette" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 199 + 0x04, 0x01, 0x05, 0x03, 0x09, 0x00, 0x00, 0x00 }, + {0x34, 0x04}, true, "RGBAEssenceDescriptor_PaletteLayout" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 200 + 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x42, 0x00 }, + {0, 0}, false, "GenericSoundEssenceDescriptor" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 201 + 0x04, 0x02, 0x03, 0x01, 0x01, 0x01, 0x00, 0x00 }, + {0x3d, 0x03}, false, "GenericSoundEssenceDescriptor_AudioSamplingRate" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 202 + 0x04, 0x02, 0x03, 0x01, 0x04, 0x00, 0x00, 0x00 }, + {0x3d, 0x02}, false, "GenericSoundEssenceDescriptor_Locked" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, // 203 + 0x04, 0x02, 0x01, 0x01, 0x03, 0x00, 0x00, 0x00 }, + {0x3d, 0x04}, true, "GenericSoundEssenceDescriptor_AudioRefLevel" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, // 204 + 0x04, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00 }, + {0x3d, 0x05}, true, "GenericSoundEssenceDescriptor_ElectroSpatialFormulation" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 205 + 0x04, 0x02, 0x01, 0x01, 0x04, 0x00, 0x00, 0x00 }, + {0x3d, 0x07}, false, "GenericSoundEssenceDescriptor_ChannelCount" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 206 + 0x04, 0x02, 0x03, 0x03, 0x04, 0x00, 0x00, 0x00 }, + {0x3d, 0x01}, false, "GenericSoundEssenceDescriptor_QuantizationBits" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 207 + 0x04, 0x02, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00 }, + {0x3d, 0x0c}, true, "GenericSoundEssenceDescriptor_DialNorm" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 208 + 0x04, 0x02, 0x04, 0x02, 0x00, 0x00, 0x00, 0x00 }, + {0x3d, 0x06}, false, "GenericSoundEssenceDescriptor_SoundEssenceCompression" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 209 + 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x43, 0x00 }, + {0, 0}, false, "GenericDataEssenceDescriptor" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 210 + 0x04, 0x03, 0x03, 0x02, 0x00, 0x00, 0x00, 0x00 }, + {0x3e, 0x01}, false, "GenericDataEssenceDescriptor_DataEssenceCoding" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 211 + 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x44, 0x00 }, + {0, 0}, false, "MultipleDescriptor" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 212 + 0x06, 0x01, 0x01, 0x04, 0x06, 0x0b, 0x00, 0x00 }, + {0x3f, 0x01}, false, "MultipleDescriptor_SubDescriptorUIDs" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 213 + 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x51, 0x00 }, + {0, 0}, false, "MPEG2VideoDescriptor" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 214 + 0x04, 0x01, 0x06, 0x02, 0x01, 0x02, 0x00, 0x00 }, + {0, 0}, true, "MPEG2VideoDescriptor_SingleSequence" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 215 + 0x04, 0x01, 0x06, 0x02, 0x01, 0x03, 0x00, 0x00 }, + {0, 0}, true, "MPEG2VideoDescriptor_ConstantBFrames" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 216 + 0x04, 0x01, 0x06, 0x02, 0x01, 0x04, 0x00, 0x00 }, + {0, 0}, true, "MPEG2VideoDescriptor_CodedContentType" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 217 + 0x04, 0x01, 0x06, 0x02, 0x01, 0x05, 0x00, 0x00 }, + {0, 0}, true, "MPEG2VideoDescriptor_LowDelay" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 218 + 0x04, 0x01, 0x06, 0x02, 0x01, 0x06, 0x00, 0x00 }, + {0, 0}, true, "MPEG2VideoDescriptor_ClosedGOP" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 219 + 0x04, 0x01, 0x06, 0x02, 0x01, 0x07, 0x00, 0x00 }, + {0, 0}, true, "MPEG2VideoDescriptor_IdenticalGOP" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 220 + 0x04, 0x01, 0x06, 0x02, 0x01, 0x08, 0x00, 0x00 }, + {0, 0}, true, "MPEG2VideoDescriptor_MaxGOP" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 221 + 0x04, 0x01, 0x06, 0x02, 0x01, 0x09, 0x00, 0x00 }, + {0, 0}, true, "MPEG2VideoDescriptor_BPictureCount" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 222 + 0x04, 0x01, 0x06, 0x02, 0x01, 0x0b, 0x00, 0x00 }, + {0, 0}, true, "MPEG2VideoDescriptor_BitRate" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 223 + 0x04, 0x01, 0x06, 0x02, 0x01, 0x0a, 0x00, 0x00 }, + {0, 0}, true, "MPEG2VideoDescriptor_ProfileAndLevel" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 224 + 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x48, 0x00 }, + {0, 0}, false, "WaveAudioDescriptor" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 225 + 0x04, 0x02, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00 }, + {0x3d, 0x0a}, false, "WaveAudioDescriptor_BlockAlign" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 226 + 0x04, 0x02, 0x03, 0x02, 0x02, 0x00, 0x00, 0x00 }, + {0x3d, 0x0b}, true, "WaveAudioDescriptor_SequenceOffset" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 227 + 0x04, 0x02, 0x03, 0x03, 0x05, 0x00, 0x00, 0x00 }, + {0x3d, 0x09}, false, "WaveAudioDescriptor_AvgBps" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 228 + 0x04, 0x02, 0x03, 0x01, 0x0e, 0x00, 0x00, 0x00 }, + {0x3d, 0x0e}, true, "WaveAudioDescriptor_PeakEnvelope" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 229 + 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x5a, 0x00 }, + {0, 0}, false, "JPEG2000PictureSubDescriptor" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0a, // 230 + 0x04, 0x01, 0x06, 0x03, 0x01, 0x00, 0x00, 0x00 }, + {0, 0}, false, "JPEG2000PictureSubDescriptor_Rsize" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0a, // 231 + 0x04, 0x01, 0x06, 0x03, 0x02, 0x00, 0x00, 0x00 }, + {0, 0}, false, "JPEG2000PictureSubDescriptor_Xsize" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0a, // 232 + 0x04, 0x01, 0x06, 0x03, 0x03, 0x00, 0x00, 0x00 }, + {0, 0}, false, "JPEG2000PictureSubDescriptor_Ysize" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0a, // 233 + 0x04, 0x01, 0x06, 0x03, 0x04, 0x00, 0x00, 0x00 }, + {0, 0}, false, "JPEG2000PictureSubDescriptor_XOsize" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0a, // 234 + 0x04, 0x01, 0x06, 0x03, 0x05, 0x00, 0x00, 0x00 }, + {0, 0}, false, "JPEG2000PictureSubDescriptor_YOsize" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0a, // 235 + 0x04, 0x01, 0x06, 0x03, 0x06, 0x00, 0x00, 0x00 }, + {0, 0}, false, "JPEG2000PictureSubDescriptor_XTsize" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0a, // 236 + 0x04, 0x01, 0x06, 0x03, 0x07, 0x00, 0x00, 0x00 }, + {0, 0}, false, "JPEG2000PictureSubDescriptor_YTsize" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0a, // 237 + 0x04, 0x01, 0x06, 0x03, 0x08, 0x00, 0x00, 0x00 }, + {0, 0}, false, "JPEG2000PictureSubDescriptor_XTOsize" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0a, // 238 + 0x04, 0x01, 0x06, 0x03, 0x09, 0x00, 0x00, 0x00 }, + {0, 0}, false, "JPEG2000PictureSubDescriptor_YTOsize" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0a, // 239 + 0x04, 0x01, 0x06, 0x03, 0x0a, 0x00, 0x00, 0x00 }, + {0, 0}, false, "JPEG2000PictureSubDescriptor_Csize" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0a, // 240 + 0x04, 0x01, 0x06, 0x03, 0x0b, 0x00, 0x00, 0x00 }, + {0, 0}, false, "JPEG2000PictureSubDescriptor_PictureComponentSizing" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0a, // 241 + 0x04, 0x01, 0x06, 0x03, 0x0c, 0x00, 0x00, 0x00 }, + {0, 0}, true, "JPEG2000PictureSubDescriptor_CodingStyleDefault" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0a, // 242 + 0x04, 0x01, 0x06, 0x03, 0x0d, 0x00, 0x00, 0x00 }, + {0, 0}, true, "JPEG2000PictureSubDescriptor_QuantizationDefault" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 243 + 0x0d, 0x01, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00 }, + {0, 0}, false, "DM_Framework" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 244 + 0x0d, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 }, + {0, 0}, false, "DM_Set" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x07, // 245 + 0x0d, 0x01, 0x03, 0x01, 0x02, 0x0b, 0x01, 0x00 }, + {0, 0}, false, "EncryptedContainerLabel" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x07, // 246 + 0x0d, 0x01, 0x04, 0x01, 0x02, 0x01, 0x01, 0x00 }, + {0, 0}, false, "CryptographicFrameworkLabel" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 247 + 0x0d, 0x01, 0x04, 0x01, 0x02, 0x01, 0x00, 0x00 }, + {0, 0}, false, "CryptographicFramework" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x09, // 248 + 0x06, 0x01, 0x01, 0x04, 0x02, 0x0d, 0x00, 0x00 }, + {0, 0}, false, "CryptographicFramework_ContextSR" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 249 + 0x0d, 0x01, 0x04, 0x01, 0x02, 0x02, 0x00, 0x00 }, + {0, 0}, false, "CryptographicContext" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x09, // 250 + 0x01, 0x01, 0x15, 0x11, 0x00, 0x00, 0x00, 0x00 }, + {0, 0}, false, "CryptographicContext_ContextID" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x09, // 251 + 0x06, 0x01, 0x01, 0x02, 0x02, 0x00, 0x00, 0x00 }, + {0, 0}, false, "CryptographicContext_SourceEssenceContainer" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x09, // 252 + 0x02, 0x09, 0x03, 0x01, 0x01, 0x00, 0x00, 0x00 }, + {0, 0}, false, "CryptographicContext_CipherAlgorithm" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x09, // 253 + 0x02, 0x09, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00 }, + {0, 0}, false, "CryptographicContext_MICAlgorithm" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x09, // 254 + 0x02, 0x09, 0x03, 0x01, 0x02, 0x00, 0x00, 0x00 }, + {0, 0}, false, "CryptographicContext_CryptographicKeyID" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0a, // 255 + 0x0d, 0x01, 0x03, 0x01, 0x02, 0x13, 0x01, 0x01 }, + {0, 0}, false, "TimedTextWrapping" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x02, 0x01, 0x01, // 256 + 0x0d, 0x01, 0x03, 0x01, 0x17, 0x01, 0x0b, 0x01 }, + {0, 0}, false, "TimedTextEssence" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 257 + 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x64, 0x00 }, + {0, 0}, false, "TimedTextDescriptor" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0c, // 258 + 0x01, 0x01, 0x15, 0x12, 0x00, 0x00, 0x00, 0x00 }, + {0, 0}, false, "TimedTextDescriptor_ResourceID" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0c, // 259 + 0x04, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00 }, + {0, 0}, false, "TimedTextDescriptor_UCSEncoding" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x08, // 260 + 0x01, 0x02, 0x01, 0x05, 0x01, 0x00, 0x00, 0x00 }, + {0, 0}, false, "TimedTextDescriptor_NamespaceURI" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 261 + 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x65, 0x00 }, + {0, 0}, false, "TimedTextResourceSubDescriptor" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0c, // 262 + 0x01, 0x01, 0x15, 0x13, 0x00, 0x00, 0x00, 0x00 }, + {0, 0}, false, "TimedTextResourceSubDescriptor_AncillaryResourceID" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x07, // 263 + 0x04, 0x09, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00 }, + {0, 0}, false, "TimedTextResourceSubDescriptor_MIMEMediaType" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 264 + 0x01, 0x03, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00 }, + {0, 0}, false, "TimedTextResourceSubDescriptor_EssenceStreamID" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01, // 265 + 0x0d, 0x01, 0x02, 0x01, 0x01, 0x03, 0x11, 0x00 }, + {0, 0}, false, "GenericStreamPartition" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 266 + 0x04, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 }, + {0x02, 0x01}, false, "DMSegment_DataDefinition" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 267 + 0x07, 0x02, 0x02, 0x01, 0x01, 0x03, 0x00, 0x00 }, + {0x02, 0x02}, true, "DMSegment_Duration" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 268 + 0x01, 0x07, 0x01, 0x05, 0x00, 0x00, 0x00, 0x00 }, + {0x61, 0x02}, false, "DMSegment_TrackIDList" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x0c, // 269 + 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x63, 0x00 }, + {0, 0}, false, "StereoscopicPictureSubDescriptor" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x07, // 270 + 0x04, 0x02, 0x01, 0x01, 0x05, 0x00, 0x00, 0x00 }, + {0x3d, 0x32}, true, "WaveAudioDescriptor_ChannelAssignment" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0c, // 271 + 0x0d, 0x01, 0x05, 0x09, 0x01, 0x00, 0x00, 0x00 }, + {0x00, 0x00}, false, "GenericStream_DataElement" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 272 + 0x06, 0x01, 0x01, 0x04, 0x06, 0x10, 0x00, 0x00 }, + {0, 0}, true, "MXFInterop_GenericDescriptor_SubDescriptors" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 273 + 0x01, 0x03, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00 }, + {0x3f, 0x07}, false, "BodySID" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, // 274 + 0x01, 0x03, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00 }, + {0x3f, 0x06}, false, "IndexSID" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 275 + 0x01, 0x02, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00 }, + {0x3b, 0x09}, false, "OperationalPattern" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 276 + 0x01, 0x02, 0x02, 0x10, 0x02, 0x01, 0x00, 0x00 }, + {0x3b, 0x0a}, false, "EssenceContainers" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0b, // 277 + 0x04, 0x02, 0x02, 0x10, 0x03, 0x01, 0x01, 0x00 }, + {0, 0}, false, "DCAudioChannelCfg_1_5p1" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0b, // 278 + 0x04, 0x02, 0x02, 0x10, 0x03, 0x01, 0x02, 0x00 }, + {0, 0}, false, "DCAudioChannelCfg_2_6p1" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0b, // 279 + 0x04, 0x02, 0x02, 0x10, 0x03, 0x01, 0x03, 0x00 }, + {0, 0}, false, "DCAudioChannelCfg_3_7p1" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0b, // 280 + 0x04, 0x02, 0x02, 0x10, 0x03, 0x01, 0x04, 0x00 }, + {0, 0}, false, "DCAudioChannelCfg_4_WTF" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0b, // 281 + 0x04, 0x02, 0x02, 0x10, 0x03, 0x01, 0x05, 0x00 }, + {0, 0}, false, "DCAudioChannelCfg_5_7p1_DS" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 282 + 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x6a, 0x00 }, + {0, 0}, false, "MCALabelSubDescriptor" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 283 + 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x6b, 0x00 }, + {0, 0}, false, "AudioChannelLabelSubDescriptor" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 284 + 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x6c, 0x00 }, + {0, 0}, false, "SoundfieldGroupLabelSubDescriptor" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 285 + 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x6d, 0x00 }, + {0, 0}, false, "GroupOfSoundfieldGroupsLabelSubDescriptor" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0e, // 286 + 0x01, 0x03, 0x07, 0x01, 0x01, 0x00, 0x00, 0x00 }, + {0, 0}, false, "MCALabelSubDescriptor_MCALabelDictionaryID" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0e, // 287 + 0x01, 0x03, 0x07, 0x01, 0x05, 0x00, 0x00, 0x00 }, + {0, 0}, false, "MCALabelSubDescriptor_MCALinkID" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0e, // 288 + 0x01, 0x03, 0x07, 0x01, 0x02, 0x00, 0x00, 0x00 }, + {0, 0}, false, "MCALabelSubDescriptor_MCATagSymbol" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0e, // 289 + 0x01, 0x03, 0x07, 0x01, 0x03, 0x00, 0x00, 0x00 }, + {0, 0}, false, "MCALabelSubDescriptor_MCATagName" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0e, // 290 + 0x01, 0x03, 0x04, 0x0a, 0x00, 0x00, 0x00, 0x00 }, + {0, 0}, false, "MCALabelSubDescriptor_MCAChannelID" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0d, // 291 + 0x03, 0x01, 0x01, 0x02, 0x03, 0x15, 0x00, 0x00 }, + {0, 0}, false, "MCALabelSubDescriptor_RFC5646SpokenLanguage" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0d, // 292 + 0x01, 0x03, 0x07, 0x01, 0x03, 0x00, 0x00, 0x00 }, + {0, 0}, false, "AudioChannelLabelSubDescriptor_SoundfieldGroupLinkID" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0d, // 293 + 0x01, 0x03, 0x07, 0x01, 0x04, 0x00, 0x00, 0x00 }, + {0, 0}, false, "SoundfieldGroupLabelSubDescriptor_GroupOfSoundfieldGroupsLinkID" }, + { {0, 0}, {0, 0}, false, 0 } +}; + +// +// end MDD.cpp +// diff --git a/asdcplib/src/MDD.h b/asdcplib/src/MDD.h new file mode 100755 index 0000000..595fd54 --- /dev/null +++ b/asdcplib/src/MDD.h @@ -0,0 +1,353 @@ +/* +Copyright (c) 2006-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 MDD.[h|cpp] + \version $Id: MDD.h,v 1.25 2012/02/02 01:58:43 jhurst Exp $ + \brief MXF Metadata Dictionary +*/ + +#ifndef _MDD_H_ +#define _MDD_H_ + +// +namespace ASDCP { + enum MDD_t { + MDD_MICAlgorithm_NONE, // 0 + MDD_MXFInterop_OPAtom, // 1 + MDD_OPAtom, // 2 + MDD_OP1a, // 3 + MDD_GCMulti, // 4 + MDD_PictureDataDef, // 5 + MDD_SoundDataDef, // 6 + MDD_TimecodeDataDef, // 7 + MDD_DescriptiveMetaDataDef, // 8 + MDD_WAVWrapping, // 9 + MDD_MPEG2_VESWrapping, // 10 + MDD_JPEG_2000Wrapping, // 11 + MDD_JPEG2000Essence, // 12 + MDD_MPEG2Essence, // 13 + MDD_MXFInterop_CryptEssence, // 14 + MDD_CryptEssence, // 15 + MDD_WAVEssence, // 16 + MDD_JP2KEssenceCompression_2K, // 17 + MDD_JP2KEssenceCompression_4K, // 18 + MDD_CipherAlgorithm_AES, // 19 + MDD_MICAlgorithm_HMAC_SHA1, // 20 + MDD_KLVFill, // 21 + MDD_PartitionMetadata_MajorVersion, // 22 + MDD_PartitionMetadata_MinorVersion, // 23 + MDD_PartitionMetadata_KAGSize, // 24 + MDD_PartitionMetadata_ThisPartition, // 25 + MDD_PartitionMetadata_PreviousPartition, // 26 + MDD_PartitionMetadata_FooterPartition, // 27 + MDD_PartitionMetadata_HeaderByteCount, // 28 + MDD_PartitionMetadata_IndexByteCount, // 29 + MDD_PartitionMetadata_IndexSID_DEPRECATED, // 30 + MDD_PartitionMetadata_BodyOffset, // 31 + MDD_PartitionMetadata_BodySID_DEPRECATED, // 32 + MDD_PartitionMetadata_OperationalPattern_DEPRECATED, // 33 + MDD_PartitionMetadata_EssenceContainers_DEPRECATED, // 34 + MDD_OpenHeader, // 35 + MDD_OpenCompleteHeader, // 36 + MDD_ClosedHeader, // 37 + MDD_ClosedCompleteHeader, // 38 + MDD_OpenBodyPartition, // 39 + MDD_OpenCompleteBodyPartition, // 40 + MDD_ClosedBodyPartition, // 41 + MDD_ClosedCompleteBodyPartition, // 42 + MDD_Footer, // 43 + MDD_CompleteFooter, // 44 + MDD_Primer, // 45 + MDD_Primer_LocalTagEntryBatch, // 46 + MDD_LocalTagEntryBatch_Primer_LocalTag, // 47 + MDD_LocalTagEntryBatch_Primer_UID, // 48 + MDD_InterchangeObject_InstanceUID, // 49 + MDD_GenerationInterchangeObject_GenerationUID, // 50 + MDD_DefaultObject, // 51 + MDD_IndexTableSegmentBase_IndexEditRate, // 52 + MDD_IndexTableSegmentBase_IndexStartPosition, // 53 + MDD_IndexTableSegmentBase_IndexDuration, // 54 + MDD_IndexTableSegmentBase_EditUnitByteCount, // 55 + MDD_IndexTableSegmentBase_IndexSID_DEPRECATED, // 56 + MDD_IndexTableSegmentBase_BodySID_DEPRECATED, // 57 + MDD_IndexTableSegmentBase_SliceCount, // 58 + MDD_IndexTableSegmentBase_PosTableCount, // 59 + MDD_IndexTableSegment, // 60 + MDD_IndexTableSegment_DeltaEntryArray, // 61 + MDD_DeltaEntryArray_IndexTableSegment_PosTableIndex, // 62 + MDD_DeltaEntryArray_IndexTableSegment_Slice, // 63 + MDD_DeltaEntryArray_IndexTableSegment_ElementDelta, // 64 + MDD_IndexTableSegment_IndexEntryArray, // 65 + MDD_IndexEntryArray_IndexTableSegment_TemporalOffset, // 66 + MDD_IndexEntryArray_IndexTableSegment_AnchorOffset, // 67 + MDD_IndexEntryArray_IndexTableSegment_Flags, // 68 + MDD_IndexEntryArray_IndexTableSegment_StreamOffset, // 69 + MDD_IndexEntryArray_IndexTableSegment_SliceOffsetArray, // 70 + MDD_IndexEntryArray_IndexTableSegment_PosTableArray, // 71 + MDD_RandomIndexMetadata, // 72 + MDD_PartitionArray_RandomIndexMetadata_BodySID_DEPRECATED, // 73 + MDD_PartitionArray_RandomIndexMetadata_ByteOffset, // 74 + MDD_RandomIndexMetadata_Length, // 75 + MDD_RandomIndexMetadataV10, // 76 + MDD_Preface, // 77 + MDD_Preface_LastModifiedDate, // 78 + MDD_Preface_Version, // 79 + MDD_Preface_ObjectModelVersion, // 80 + MDD_Preface_PrimaryPackage, // 81 + MDD_Preface_Identifications, // 82 + MDD_Preface_ContentStorage, // 83 + MDD_Preface_OperationalPattern_DEPRECATED, // 84 + MDD_Preface_EssenceContainers_DEPRECATED, // 85 + MDD_Preface_DMSchemes, // 86 + MDD_Identification, // 87 + MDD_Identification_ThisGenerationUID, // 88 + MDD_Identification_CompanyName, // 89 + MDD_Identification_ProductName, // 90 + MDD_Identification_ProductVersion, // 91 + MDD_Identification_VersionString, // 92 + MDD_Identification_ProductUID, // 93 + MDD_Identification_ModificationDate, // 94 + MDD_Identification_ToolkitVersion, // 95 + MDD_Identification_Platform, // 96 + MDD_ContentStorage, // 97 + MDD_ContentStorage_Packages, // 98 + MDD_ContentStorage_EssenceContainerData, // 99 + MDD_ContentStorageKludge_V10Packages, // 100 + MDD_EssenceContainerData, // 101 + MDD_EssenceContainerData_LinkedPackageUID, // 102 + MDD_EssenceContainerData_IndexSID_DEPRECATED, // 103 + MDD_EssenceContainerData_BodySID_DEPRECATED, // 104 + MDD_GenericPackage_PackageUID, // 105 + MDD_GenericPackage_Name, // 106 + MDD_GenericPackage_PackageCreationDate, // 107 + MDD_GenericPackage_PackageModifiedDate, // 108 + MDD_GenericPackage_Tracks, // 109 + MDD_NetworkLocator, // 110 + MDD_NetworkLocator_URLString, // 111 + MDD_TextLocator, // 112 + MDD_TextLocator_LocatorName, // 113 + MDD_GenericTrack_TrackID, // 114 + MDD_GenericTrack_TrackNumber, // 115 + MDD_GenericTrack_TrackName, // 116 + MDD_GenericTrack_Sequence, // 117 + MDD_StaticTrack, // 118 + MDD_Track, // 119 + MDD_Track_EditRate, // 120 + MDD_Track_Origin, // 121 + MDD_EventTrack, // 122 + MDD_EventTrack_EventEditRate, // 123 + MDD_EventTrack_EventOrigin, // 124 + MDD_StructuralComponent_DataDefinition, // 125 + MDD_StructuralComponent_Duration, // 126 + MDD_Sequence, // 127 + MDD_Sequence_StructuralComponents, // 128 + MDD_TimecodeComponent, // 129 + MDD_TimecodeComponent_RoundedTimecodeBase, // 130 + MDD_TimecodeComponent_StartTimecode, // 131 + MDD_TimecodeComponent_DropFrame, // 132 + MDD_SourceClip, // 133 + MDD_SourceClip_StartPosition, // 134 + MDD_SourceClip_SourcePackageID, // 135 + MDD_SourceClip_SourceTrackID, // 136 + MDD_DMSegment, // 137 + MDD_DMSegment_EventStartPosition, // 138 + MDD_DMSegment_EventComment, // 139 + MDD_DMSegment_TrackIDs, // 140 + MDD_DMSegment_DMFramework, // 141 + MDD_DMSourceClip, // 142 + MDD_DMSourceClip_DMSourceClipTrackIDs, // 143 + MDD_MaterialPackage, // 144 + MDD_SourcePackage, // 145 + MDD_SourcePackage_Descriptor, // 146 + MDD_GenericDescriptor_Locators, // 147 + MDD_GenericDescriptor_SubDescriptors, // 148 + MDD_FileDescriptor, // 149 + MDD_FileDescriptor_LinkedTrackID, // 150 + MDD_FileDescriptor_SampleRate, // 151 + MDD_FileDescriptor_ContainerDuration, // 152 + MDD_FileDescriptor_EssenceContainer, // 153 + MDD_FileDescriptor_Codec, // 154 + MDD_GenericPictureEssenceDescriptor, // 155 + MDD_GenericPictureEssenceDescriptor_SignalStandard, // 156 + MDD_GenericPictureEssenceDescriptor_FrameLayout, // 157 + MDD_GenericPictureEssenceDescriptor_StoredWidth, // 158 + MDD_GenericPictureEssenceDescriptor_StoredHeight, // 159 + MDD_GenericPictureEssenceDescriptor_StoredF2Offset, // 160 + MDD_GenericPictureEssenceDescriptor_SampledWidth, // 161 + MDD_GenericPictureEssenceDescriptor_SampledHeight, // 162 + MDD_GenericPictureEssenceDescriptor_SampledXOffset, // 163 + MDD_GenericPictureEssenceDescriptor_SampledYOffset, // 164 + MDD_GenericPictureEssenceDescriptor_DisplayHeight, // 165 + MDD_GenericPictureEssenceDescriptor_DisplayWidth, // 166 + MDD_GenericPictureEssenceDescriptor_DisplayXOffset, // 167 + MDD_GenericPictureEssenceDescriptor_DisplayYOffset, // 168 + MDD_GenericPictureEssenceDescriptor_DisplayF2Offset, // 169 + MDD_GenericPictureEssenceDescriptor_AspectRatio, // 170 + MDD_GenericPictureEssenceDescriptor_ActiveFormatDescriptor, // 171 + MDD_GenericPictureEssenceDescriptor_VideoLineMap, // 172 + MDD_GenericPictureEssenceDescriptor_AlphaTransparency, // 173 + MDD_GenericPictureEssenceDescriptor_Gamma, // 174 + MDD_GenericPictureEssenceDescriptor_ImageAlignmentOffset, // 175 + MDD_GenericPictureEssenceDescriptor_ImageStartOffset, // 176 + MDD_GenericPictureEssenceDescriptor_ImageEndOffset, // 177 + MDD_GenericPictureEssenceDescriptor_FieldDominance, // 178 + MDD_GenericPictureEssenceDescriptor_PictureEssenceCoding, // 179 + MDD_CDCIEssenceDescriptor, // 180 + MDD_CDCIEssenceDescriptor_ComponentDepth, // 181 + MDD_CDCIEssenceDescriptor_HorizontalSubsampling, // 182 + MDD_CDCIEssenceDescriptor_VerticalSubsampling, // 183 + MDD_CDCIEssenceDescriptor_ColorSiting, // 184 + MDD_CDCIEssenceDescriptor_ReversedByteOrder, // 185 + MDD_CDCIEssenceDescriptor_PaddingBits, // 186 + MDD_CDCIEssenceDescriptor_AlphaSampleDepth, // 187 + MDD_CDCIEssenceDescriptor_BlackRefLevel, // 188 + MDD_CDCIEssenceDescriptor_WhiteReflevel, // 189 + MDD_CDCIEssenceDescriptor_ColorRange, // 190 + MDD_RGBAEssenceDescriptor, // 191 + MDD_RGBAEssenceDescriptor_ComponentMaxRef, // 192 + MDD_RGBAEssenceDescriptor_ComponentMinRef, // 193 + MDD_RGBAEssenceDescriptor_AlphaMaxRef, // 194 + MDD_RGBAEssenceDescriptor_AlphaMinRef, // 195 + MDD_RGBAEssenceDescriptor_ScanningDirection, // 196 + MDD_RGBAEssenceDescriptor_PixelLayout, // 197 + MDD_RGBAEssenceDescriptor_Palette, // 198 + MDD_RGBAEssenceDescriptor_PaletteLayout, // 199 + MDD_GenericSoundEssenceDescriptor, // 200 + MDD_GenericSoundEssenceDescriptor_AudioSamplingRate, // 201 + MDD_GenericSoundEssenceDescriptor_Locked, // 202 + MDD_GenericSoundEssenceDescriptor_AudioRefLevel, // 203 + MDD_GenericSoundEssenceDescriptor_ElectroSpatialFormulation, // 204 + MDD_GenericSoundEssenceDescriptor_ChannelCount, // 205 + MDD_GenericSoundEssenceDescriptor_QuantizationBits, // 206 + MDD_GenericSoundEssenceDescriptor_DialNorm, // 207 + MDD_GenericSoundEssenceDescriptor_SoundEssenceCompression, // 208 + MDD_GenericDataEssenceDescriptor, // 209 + MDD_GenericDataEssenceDescriptor_DataEssenceCoding, // 210 + MDD_MultipleDescriptor, // 211 + MDD_MultipleDescriptor_SubDescriptorUIDs, // 212 + MDD_MPEG2VideoDescriptor, // 213 + MDD_MPEG2VideoDescriptor_SingleSequence, // 214 + MDD_MPEG2VideoDescriptor_ConstantBFrames, // 215 + MDD_MPEG2VideoDescriptor_CodedContentType, // 216 + MDD_MPEG2VideoDescriptor_LowDelay, // 217 + MDD_MPEG2VideoDescriptor_ClosedGOP, // 218 + MDD_MPEG2VideoDescriptor_IdenticalGOP, // 219 + MDD_MPEG2VideoDescriptor_MaxGOP, // 220 + MDD_MPEG2VideoDescriptor_BPictureCount, // 221 + MDD_MPEG2VideoDescriptor_BitRate, // 222 + MDD_MPEG2VideoDescriptor_ProfileAndLevel, // 223 + MDD_WaveAudioDescriptor, // 224 + MDD_WaveAudioDescriptor_BlockAlign, // 225 + MDD_WaveAudioDescriptor_SequenceOffset, // 226 + MDD_WaveAudioDescriptor_AvgBps, // 227 + MDD_WaveAudioDescriptor_PeakEnvelope, // 228 + MDD_JPEG2000PictureSubDescriptor, // 229 + MDD_JPEG2000PictureSubDescriptor_Rsize, // 230 + MDD_JPEG2000PictureSubDescriptor_Xsize, // 231 + MDD_JPEG2000PictureSubDescriptor_Ysize, // 232 + MDD_JPEG2000PictureSubDescriptor_XOsize, // 233 + MDD_JPEG2000PictureSubDescriptor_YOsize, // 234 + MDD_JPEG2000PictureSubDescriptor_XTsize, // 235 + MDD_JPEG2000PictureSubDescriptor_YTsize, // 236 + MDD_JPEG2000PictureSubDescriptor_XTOsize, // 237 + MDD_JPEG2000PictureSubDescriptor_YTOsize, // 238 + MDD_JPEG2000PictureSubDescriptor_Csize, // 239 + MDD_JPEG2000PictureSubDescriptor_PictureComponentSizing, // 240 + MDD_JPEG2000PictureSubDescriptor_CodingStyleDefault, // 241 + MDD_JPEG2000PictureSubDescriptor_QuantizationDefault, // 242 + MDD_DM_Framework, // 243 + MDD_DM_Set, // 244 + MDD_EncryptedContainerLabel, // 245 + MDD_CryptographicFrameworkLabel, // 246 + MDD_CryptographicFramework, // 247 + MDD_CryptographicFramework_ContextSR, // 248 + MDD_CryptographicContext, // 249 + MDD_CryptographicContext_ContextID, // 250 + MDD_CryptographicContext_SourceEssenceContainer, // 251 + MDD_CryptographicContext_CipherAlgorithm, // 252 + MDD_CryptographicContext_MICAlgorithm, // 253 + MDD_CryptographicContext_CryptographicKeyID, // 254 + MDD_TimedTextWrapping, // 255 + MDD_TimedTextEssence, // 256 + MDD_TimedTextDescriptor, // 257 + MDD_TimedTextDescriptor_ResourceID, // 258 + MDD_TimedTextDescriptor_UCSEncoding, // 259 + MDD_TimedTextDescriptor_NamespaceURI, // 260 + MDD_TimedTextResourceSubDescriptor, // 261 + MDD_TimedTextResourceSubDescriptor_AncillaryResourceID, // 262 + MDD_TimedTextResourceSubDescriptor_MIMEMediaType, // 263 + MDD_TimedTextResourceSubDescriptor_EssenceStreamID_DEPRECATED, // 264 + MDD_GenericStreamPartition, // 265 + MDD_DMSegment_DataDefinition_DEPRECATED, // 266 + MDD_DMSegment_Duration_DEPRECATED, // 267 + MDD_DMSegment_TrackIDList, // 268 + MDD_StereoscopicPictureSubDescriptor, // 269 + MDD_WaveAudioDescriptor_ChannelAssignment, // 270 + MDD_GenericStream_DataElement, // 271 + MDD_MXFInterop_GenericDescriptor_SubDescriptors, // 272 + MDD_Core_BodySID, // 273 + MDD_Core_IndexSID, // 274 + MDD_Core_OperationalPattern, // 275 + MDD_Core_EssenceContainers, // 276 + MDD_DCAudioChannelCfg_1_5p1, // 277 + MDD_DCAudioChannelCfg_2_6p1, // 278 + MDD_DCAudioChannelCfg_3_7p1, // 279 + MDD_DCAudioChannelCfg_4_WTF, // 280 + MDD_DCAudioChannelCfg_5_7p1_DS, // 281 + MDD_MCALabelSubDescriptor, // 282 + MDD_AudioChannelLabelSubDescriptor, // 283 + MDD_SoundfieldGroupLabelSubDescriptor, // 284 + MDD_GroupOfSoundfieldGroupsLabelSubDescriptor, // 285 + MDD_MCALabelSubDescriptor_MCALabelDictionaryID, // 286 + MDD_MCALabelSubDescriptor_MCALinkID, // 287 + MDD_MCALabelSubDescriptor_MCATagSymbol, // 288 + MDD_MCALabelSubDescriptor_MCATagName, // 289 + MDD_MCALabelSubDescriptor_MCAChannelID, // 290 + MDD_MCALabelSubDescriptor_RFC5646SpokenLanguage, // 291 + MDD_AudioChannelLabelSubDescriptor_SoundfieldGroupLinkID, // 292 + MDD_SoundfieldGroupLabelSubDescriptor_GroupOfSoundfieldGroupsLinkID, // 293 + MDD_Max + + }; // enum MDD_t + + // + const MDD_t MDD_EssenceContainerData_BodySID = MDD_Core_BodySID; + const MDD_t MDD_IndexTableSegmentBase_IndexSID = MDD_Core_IndexSID; + const MDD_t MDD_EssenceContainerData_IndexSID = MDD_Core_IndexSID; + const MDD_t MDD_DMSegment_DataDefinition = MDD_StructuralComponent_DataDefinition; + const MDD_t MDD_DMSegment_Duration = MDD_StructuralComponent_Duration; + const MDD_t MDD_Preface_EssenceContainers = MDD_Core_EssenceContainers; + const MDD_t MDD_Preface_OperationalPattern = MDD_Core_OperationalPattern; + const MDD_t MDD_TimedTextResourceSubDescriptor_EssenceStreamID = MDD_Core_BodySID; + +} // namespaceASDCP + + +#endif // _MDD_H_ + +// +// end MDD.h +// diff --git a/asdcplib/src/MPEG.cpp b/asdcplib/src/MPEG.cpp new file mode 100755 index 0000000..918b16d --- /dev/null +++ b/asdcplib/src/MPEG.cpp @@ -0,0 +1,295 @@ +/* +Copyright (c) 2005-2009, 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 MPEG.cpp + \version $Id: MPEG.cpp,v 1.4 2009/04/09 19:16:49 msheby Exp $ + \brief MPEG2 VES parser +*/ + +#include <MPEG.h> +#include <KM_log.h> +using Kumu::DefaultLogSink; + +// walk a buffer stopping at the end of the buffer or the end of a VES +// start code '00 00 01'. If successful, returns address of first byte +// of start code +ASDCP::Result_t +ASDCP::MPEG2::FindVESStartCode(const byte_t* buf, ui32_t buf_len, StartCode_t* sc, const byte_t** new_pos) +{ + ASDCP_TEST_NULL(buf); + ASDCP_TEST_NULL(new_pos); + + ui32_t zero_i = 0; + const byte_t* p = buf; + const byte_t* end_p = buf + buf_len; + + for ( ; p < end_p; p++ ) + { + if ( *p == 0 ) + zero_i++; + + else if ( *p == 1 && zero_i > 1 ) + { + // 2 or more 0 bytes followed by a 1, start code is next + if ( ++p == end_p ) + return RESULT_FAIL; + + *new_pos = p - 3; + *sc = (StartCode_t)*p; + return RESULT_OK; + } + else + zero_i = 0; + } + + *new_pos = buf + buf_len; + return RESULT_FAIL; +} + + +//------------------------------------------------------------------------------------------ + +// +ASDCP::Rational +ASDCP::MPEG2::Accessor::Sequence::AspectRatio() +{ + switch ( m_p[3] & 0xf0 ) + { + case 0x10: return Rational(1,1); + case 0x20: return Rational(4,3); + case 0x30: return Rational(16,9); + case 0x40: return Rational(221,100); + } + + DefaultLogSink().Error("Unknown AspectRatio value: %02x\n", m_p[3]); + return Rational(0,0); +} + +//------------------------------------------------------------------------------------------ + +enum State_t { + ST_IDLE, + ST_START_HEADER, + ST_IN_HEADER, +}; + + +// +class ASDCP::MPEG2::VESParser::h__StreamState +{ +public: + State_t m_State; + h__StreamState() : m_State(ST_IDLE) {} + ~h__StreamState() {} + + void Goto_START_HEADER() { m_State = ST_START_HEADER; } + void Goto_IN_HEADER() { m_State = ST_IN_HEADER; } + void Goto_IDLE() { m_State = ST_IDLE; } + bool Test_IDLE() { return m_State == ST_IDLE; } + bool Test_START_HEADER() { return m_State == ST_START_HEADER; } + bool Test_IN_HEADER() { return m_State == ST_IN_HEADER; } +}; + +//------------------------------------------------------------------------------------------ + + +ASDCP::MPEG2::VESParser::VESParser() : + m_Delegate(0), m_HBufLen(0), m_ZeroCount(0) +{ + m_State = new h__StreamState; +} + +ASDCP::MPEG2::VESParser::~VESParser() +{ +} + + +// +void +ASDCP::MPEG2::VESParser::SetDelegate(VESParserDelegate* Delegate) +{ + m_Delegate = Delegate; +} + +// +void +ASDCP::MPEG2::VESParser::Reset() +{ + m_State->Goto_IDLE(); + m_HBufLen = 0; + m_ZeroCount = 0; +} + +// +ASDCP::Result_t +ASDCP::MPEG2::VESParser::Parse(const byte_t* buf, ui32_t buf_len) +{ + ASDCP_TEST_NULL(buf); + ASDCP_TEST_NULL(m_Delegate); + + Result_t result = RESULT_OK; + register const byte_t* end_p = buf + buf_len; + register const byte_t* run_pos = buf; // track runs of uninteresting data using a position and count + register ui32_t run_len = 0; + + // search for MPEG2 headers + // copy interesting data to a buffer and pass to delegate for processing + for ( register const byte_t* p = buf; p < end_p; p++ ) + { + if ( m_State->Test_IN_HEADER() ) + { + assert(run_len==0); + m_HBuf[m_HBufLen++] = *p; + assert(m_HBufLen < VESHeaderBufSize); + } + else + { + run_len++; + } + + if ( m_State->Test_START_HEADER() ) // *p is a start code + { + if ( m_HBufLen == 0) // not already collecting a header + { + m_HBuf[0] = m_HBuf[1] = 0; m_HBuf[2] = 1; m_HBuf[3] = *p; + + // is this one we want? + if ( *p == PIC_START || *p == SEQ_START || *p == EXT_START || *p == GOP_START ) + { + m_HBufLen = 4; + m_State->Goto_IN_HEADER(); + + switch ( run_len ) + { + case 1: // we suppressed writing 001 when exiting from the last call + case 4: // we have exactly 001x + break; + case 2: // we have 1x + case 3: // we have 01x + m_Delegate->Data(this, run_pos, (run_len == 2 ? -2 : -1)); + break; + + default: + m_Delegate->Data(this, run_pos, run_len - 4); + } + + run_len = 0; + } + else + { + m_State->Goto_IDLE(); + + if ( run_len == 1 ) // did we suppress writing 001 when exiting from the last call? + { + m_Delegate->Data(this, m_HBuf, 4); + run_len = 0; + } + } + } + else // currently collecting a header, requires a flush before handling + { + m_HBufLen -= 3; // remove the current partial start code + + // let the delegate handle the header + switch( m_HBuf[3] ) + { + case PIC_START: result = m_Delegate->Picture(this, m_HBuf, m_HBufLen); break; + case EXT_START: result = m_Delegate->Extension(this, m_HBuf, m_HBufLen); break; + case SEQ_START: result = m_Delegate->Sequence(this, m_HBuf, m_HBufLen); break; + case GOP_START: result = m_Delegate->GOP(this, m_HBuf, m_HBufLen); break; + + default: + DefaultLogSink().Error("Unexpected start code: %02x at byte %u\n", + m_HBuf[3], (ui32_t)(p - buf)); + result = RESULT_RAW_FORMAT; + } + + // Parser handlers return RESULT_FALSE to teriminate without error + if ( result != RESULT_OK ) + { + m_State->Goto_IDLE(); + return result; + } + + m_HBuf[0] = m_HBuf[1] = 0; m_HBuf[2] = 1; m_HBuf[3] = *p; // 001x + run_len = 0; + + // is this a header we want? + if ( *p == PIC_START || *p == SEQ_START || *p == EXT_START || *p == GOP_START ) + { + m_HBufLen = 4; + m_State->Goto_IN_HEADER(); + } + else + { + m_HBufLen = 0; + m_State->Goto_IDLE(); + + if ( *p >= FIRST_SLICE && *p <= LAST_SLICE ) + { + result = m_Delegate->Slice(this, *p); + + if ( result != RESULT_OK ) + return result; + } + + m_Delegate->Data(this, m_HBuf, 4); + run_pos = p+1; + } + } + } + else if ( *p == 0 ) + { + m_ZeroCount++; + } + else + { + if ( *p == 1 && m_ZeroCount > 1 ) + m_State->Goto_START_HEADER(); + + m_ZeroCount = 0; + } + } + + if ( run_len > 0 ) + { + if ( m_State->Test_START_HEADER() && run_len != 0 ) + { + assert(run_len > 2); + run_len -= 3; + } + + // flush the current run + m_Delegate->Data(this, run_pos, run_len); + } + + return RESULT_OK; +} + + +// +// end MPEG.cpp +// diff --git a/asdcplib/src/MPEG.h b/asdcplib/src/MPEG.h new file mode 100755 index 0000000..b629b62 --- /dev/null +++ b/asdcplib/src/MPEG.h @@ -0,0 +1,244 @@ +/* +Copyright (c) 2005-2011, 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 MPEG.h + \version $Id: MPEG.h,v 1.5 2011/08/30 17:04:25 jhurst Exp $ + \brief MPEG2 VES parser interface +*/ + +#ifndef _MPEG_H_ +#define _MPEG_H_ + +#include <KM_platform.h> +#include "AS_DCP.h" +#include <stdio.h> +#include <assert.h> + + +namespace ASDCP +{ + namespace MPEG2 + { + // + enum StartCode_t { + PIC_START = 0x00, + SEQ_START = 0xb3, + EXT_START = 0xb5, + GOP_START = 0xb8, + FIRST_SLICE = 0x01, + LAST_SLICE = 0xaf, + INVALID = 0xff + }; + + // + enum RateCode_t { + RATE_23_976 = 0x01, + RATE_24 = 0x02, + RATE_25 = 0x03, + RATE_29_97 = 0x04, + RATE_30 = 0x05 + }; + + // + enum ExtCode_t { + EXT_SEQ = 0x01 + }; + + //------------------------------------------------------------------------------------------ + // VES Parser + + // find the location in the buffer of the next VES packet, returns RESULT_FAIL + // if no start code is found + Result_t FindVESStartCode(const byte_t* buf, ui32_t buf_len, StartCode_t* sc, const byte_t** new_pos); + + // return the extension code of an extension header + inline ExtCode_t ParseExtensionCode(const byte_t* buf) + { + assert(buf); + return (ExtCode_t)(buf[4] >> 4); + } + + // + class VESParserDelegate; // the delegate is declared later + const ui32_t VESHeaderBufSize = 1024*32; // should be larger than any expected header + + // MPEG VES parser class - call Parse() as many times as you want with buffers + // of any size. State is maintained between calls. When complete headers are + // available for examination, the respective delegate method will be called. + // All other data is given to the delegate's Data() method. + class VESParser + { + class h__StreamState; + Kumu::mem_ptr<h__StreamState> m_State; + VESParserDelegate* m_Delegate; + + ui32_t m_HBufLen; // temp space for partial header contents + byte_t m_HBuf[VESHeaderBufSize]; + ui32_t m_ZeroCount; + bool m_Partial; + + ASDCP_NO_COPY_CONSTRUCT(VESParser); + + public: + VESParser(); + ~VESParser(); + + void SetDelegate(VESParserDelegate*); // you must call this before Parse() + Result_t Parse(const byte_t*, ui32_t); // call repeatedly + void Reset(); // resets the internal state machine and counters, return to the top of the file + }; + + // Parser Event Delegate Interface + // + // Create a concrete subclass and give it to the parser by calling SetDelegate(). + // The respective method will be called when a header of the named type is found. + // Handler methods should return RESULT_OK to continue processing or RESULT_FALSE + // to terminate parsing without signaling an error. + // + class VESParserDelegate + { + public: + virtual ~VESParserDelegate() {} + + // header handlers + virtual Result_t Picture(VESParser* Caller, const byte_t* header_buf, ui32_t header_len) = 0; + virtual Result_t Extension(VESParser*, const byte_t*, ui32_t) = 0; + virtual Result_t Sequence(VESParser*, const byte_t*, ui32_t) = 0; + virtual Result_t GOP(VESParser*, const byte_t*, ui32_t) = 0; + + // this is not a header handler, it is a signal that actual picture data + // has started. All Slice data is reported via the Data() method. + virtual Result_t Slice(VESParser*, byte_t slice_id) = 0; + + // Any data not given to the header handlers above is reported here + // This method may be called with a value of -1 or -2. This will happen + // when processing a start code that has one or two leading zeros + // in the preceding buffer + virtual Result_t Data(VESParser*, const byte_t*, i32_t) = 0; + }; + + + //------------------------------------------------------------------------------------------ + // VES header accessor objects + // + // For use within parser delegate methods. The constructor expects a pointer to a buffer + // containing two zero bytes, a one byte, a start code and some number of header bytes. + // They are not documented further as it is hoped that they are self-explanatory. + + // + namespace Accessor + { + // decoding tables + static i16_t FrameRateLUT[] = { 0, 24, 24, 25, 30, 30, 50, 60, 60}; + static bool PulldownLUT[] = { false, true, false, false, true, false, false, true, false}; + + // + class Sequence + { + const byte_t* m_p; + ASDCP_NO_COPY_CONSTRUCT(Sequence); + + public: + Sequence(const byte_t* p) { assert(p); m_p = p + 4; } + inline ui16_t HorizontalSize() { return (ui16_t)( ( m_p[0] << 4 ) | ( m_p[1] >> 4 ) ); } + inline ui16_t VerticalSize() { return (ui16_t)( ( ( m_p[1] & 0x0f ) << 8 ) | m_p[2] ); } + inline RateCode_t RateCode() { return (RateCode_t)( m_p[3] & 0x0f ); } + inline ui16_t FrameRate() { return FrameRateLUT[RateCode()]; } + inline bool Pulldown() { return PulldownLUT[RateCode()] != 0; } + inline i32_t BitRate() { + return ( ( (i32_t)m_p[4] << 10 ) + ( (i32_t)m_p[5] << 2 ) + ( m_p[6] >> 6 ) ) * 400; + } + + Rational AspectRatio(); + }; + + // + class SequenceEx // tension + { + const byte_t* m_p; + ASDCP_NO_COPY_CONSTRUCT(SequenceEx); + + public: + SequenceEx(const byte_t* p) + { + assert(p); + assert(ParseExtensionCode(p) == EXT_SEQ); + m_p = p + 4; + } + + inline ui16_t ProfileAndLevel() { return ( m_p[0] << 4) | ( m_p[1] >> 4 ); } + inline ui8_t ChromaFormat() { return ( m_p[1] >> 1 ) & 0x03; } + inline bool Progressive() { return ( ( m_p[1] >> 3 ) & 0x01 ) > 0; } + inline ui32_t HorizontalSizeExt() { + return ( ( m_p[1] & 0x01 ) << 13 ) | ( ( m_p[2] & 0x80 ) << 5 ); + } + inline ui32_t VerticalSizeExt() { return ( m_p[2] & 0x60 ) << 7; } + inline ui32_t BitRateExt() { + return ( ( m_p[2] & 0x1f ) << 25 ) | ( ( m_p[3] & 0xfe ) << 17 ); + } + + inline bool LowDelay() { return ( m_p[5] & 0x80 ) > 0; } + }; + + // + class GOP + { + const byte_t* m_p; + ASDCP_NO_COPY_CONSTRUCT(GOP); + + public: + GOP(const byte_t* p) { assert(p); m_p = p + 4; } + inline bool Closed() { return ( ( m_p[3] ) >> 6 ) & 0x01; } + }; + + // + class Picture + { + const byte_t* m_p; + ASDCP_NO_COPY_CONSTRUCT(Picture); + + public: + Picture(const byte_t* p) { assert(p); m_p = p + 4; } + inline i16_t TemporalRef() { + return ( (i16_t)( m_p[0] << 2 ) ) | ( ( (i16_t)m_p[1] & 0x00c0 ) >> 6 ); + } + + inline FrameType_t FrameType() { + return (FrameType_t)( ( m_p[1] & 0x38 ) >> 3 ); + } + }; + + } // namespace Accessor + + } // namespace MPEG2 + +} // namespace ASDCP + +#endif // _MPEG_H_ + +// +// end MPEG.h +// diff --git a/asdcplib/src/MPEG2_Parser.cpp b/asdcplib/src/MPEG2_Parser.cpp new file mode 100755 index 0000000..3b81f5a --- /dev/null +++ b/asdcplib/src/MPEG2_Parser.cpp @@ -0,0 +1,639 @@ +/* +Copyright (c) 2004-2011, 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 MPEG2_Parser.cpp + \version $Id: MPEG2_Parser.cpp,v 1.11 2011/08/30 17:04:25 jhurst Exp $ + \brief AS-DCP library, MPEG2 raw essence reader implementation +*/ + +#include <KM_fileio.h> +#include <MPEG.h> + +#include <KM_log.h> +using Kumu::DefaultLogSink; + +using namespace ASDCP; +using namespace ASDCP::MPEG2; + +// data will be read from a VES file in chunks of this size +const ui32_t VESReadSize = 4 * Kumu::Kilobyte; + + +//------------------------------------------------------------------------------------------ + +// +enum ParserState_t { + ST_INIT, + ST_SEQ, + ST_PIC, + ST_GOP, + ST_EXT, + ST_SLICE, +}; + +const char* +StringParserState(ParserState_t state) +{ + switch ( state ) + { + case ST_INIT: return "INIT"; + case ST_SEQ: return "SEQ"; + case ST_PIC: return "PIC"; + case ST_GOP: return "GOP"; + case ST_EXT: return "EXT"; + case ST_SLICE: return "SLICE"; + } + + return "*UNKNOWN*"; +} + + + +// +class h__ParserState +{ + ParserState_t m_State; + ASDCP_NO_COPY_CONSTRUCT(h__ParserState); + + public: + h__ParserState() : m_State(ST_INIT) {} + ~h__ParserState() {} + + inline bool Test_SLICE() { return m_State == ST_SLICE; } + inline void Reset() { m_State = ST_INIT; } + + // + inline Result_t Goto_SEQ() + { + switch ( m_State ) + { + case ST_INIT: + case ST_EXT: + m_State = ST_SEQ; + return RESULT_OK; + case ST_SEQ: + case ST_PIC: + case ST_GOP: + case ST_SLICE: + /* Keep gcc quiet */ + break; + } + + DefaultLogSink().Error("SEQ follows %s\n", StringParserState(m_State)); + return RESULT_STATE; + } + + + // + inline Result_t Goto_SLICE() + { + switch ( m_State ) + { + case ST_PIC: + case ST_EXT: + m_State = ST_SLICE; + return RESULT_OK; + case ST_INIT: + case ST_SEQ: + case ST_GOP: + case ST_SLICE: + /* Keep gcc quiet */ + break; + } + + DefaultLogSink().Error("Slice follows %s\n", StringParserState(m_State)); + return RESULT_STATE; + } + + + // + inline Result_t Goto_PIC() + { + switch ( m_State ) + { + case ST_INIT: + case ST_SEQ: + case ST_GOP: + case ST_EXT: + m_State = ST_PIC; + return RESULT_OK; + case ST_PIC: + case ST_SLICE: + /* Keep gcc quiet */ + break; + } + + DefaultLogSink().Error("PIC follows %s\n", StringParserState(m_State)); + return RESULT_STATE; + } + + + // + inline Result_t Goto_GOP() + { + switch ( m_State ) + { + case ST_EXT: + case ST_SEQ: + m_State = ST_GOP; + return RESULT_OK; + case ST_INIT: + case ST_PIC: + case ST_GOP: + case ST_SLICE: + /* Keep gcc quiet */ + break; + } + + DefaultLogSink().Error("GOP follows %s\n", StringParserState(m_State)); + return RESULT_STATE; + } + + // + inline Result_t Goto_EXT() + { + switch ( m_State ) + { + case ST_PIC: + case ST_EXT: + case ST_SEQ: + case ST_GOP: + m_State = ST_EXT; + return RESULT_OK; + case ST_INIT: + case ST_SLICE: + /* Keep gcc quiet */ + break; + } + + DefaultLogSink().Error("EXT follows %s\n", StringParserState(m_State)); + return RESULT_STATE; + } +}; + +//------------------------------------------------------------------------------------------ + +// This is a parser delagate that reads the stream params from a +// sequence header and sequence extension header. The parser is +// commanded to return after processing the sequence extension +// header. +class StreamParams : public VESParserDelegate +{ + h__ParserState m_State; + + ASDCP_NO_COPY_CONSTRUCT(StreamParams); + +public: + VideoDescriptor m_VDesc; + + StreamParams() + { + m_VDesc.ContainerDuration = 0; + m_VDesc.ComponentDepth = 8; + } + + ~StreamParams() {} + + // + Result_t Sequence(VESParser*, const byte_t* b, ui32_t) + { + Result_t result = m_State.Goto_SEQ(); + + if ( ASDCP_FAILURE(result) ) + return result; + + Accessor::Sequence SEQ(b); + m_VDesc.AspectRatio = SEQ.AspectRatio(); + m_VDesc.FrameRate = SEQ.FrameRate(); + m_VDesc.StoredWidth = SEQ.HorizontalSize(); + m_VDesc.StoredHeight = SEQ.VerticalSize(); + m_VDesc.BitRate = SEQ.BitRate(); + m_VDesc.EditRate = SEQ.Pulldown() ? Rational(SEQ.FrameRate() * 1000, 1001) : Rational(SEQ.FrameRate(), 1); + m_VDesc.SampleRate = m_VDesc.EditRate; + return RESULT_OK; + } + + // + Result_t Extension(VESParser*, const byte_t* b, ui32_t) + { + Result_t result = m_State.Goto_EXT(); + + if ( ASDCP_FAILURE(result) ) + return result; + + Accessor::SequenceEx SEQX(b); + m_VDesc.ProfileAndLevel = SEQX.ProfileAndLevel(); + m_VDesc.FrameLayout = SEQX.Progressive() ? 0 : 1; + m_VDesc.CodedContentType = SEQX.Progressive() ? 1 : 2; + m_VDesc.LowDelay = SEQX.LowDelay(); + m_VDesc.HorizontalSubsampling = SEQX.ChromaFormat() == 3 ? 1 : 2; + m_VDesc.VerticalSubsampling = SEQX.ChromaFormat() >= 3 ? 1 : 2; + + if ( ( m_VDesc.HorizontalSubsampling == 2 ) && ( m_VDesc.VerticalSubsampling == 2 ) ) + m_VDesc.ColorSiting = 3; // 4:2:0 + + else if ( ( m_VDesc.HorizontalSubsampling == 2 ) && ( m_VDesc.VerticalSubsampling == 1 ) ) + m_VDesc.ColorSiting = 4; // 4:2:2 + + else if ( ( m_VDesc.HorizontalSubsampling == 1 ) && ( m_VDesc.VerticalSubsampling == 1 ) ) + m_VDesc.ColorSiting = 0; // 4:4:4 + + // TODO: get H&V size and bit rate extensions + + return RESULT_FALSE; + } + + Result_t GOP(VESParser*, const byte_t*, ui32_t) { return RESULT_FALSE; } + Result_t Picture(VESParser*, const byte_t*, ui32_t) { return RESULT_FALSE; } + Result_t Slice(VESParser*, byte_t) { return RESULT_FALSE; } + Result_t Data(VESParser*, const byte_t*, i32_t) { return RESULT_OK; } +}; + + +//------------------------------------------------------------------------------------------ + +// This is a parser delagate that reads a VES stream and sets public +// instance variables to indicate state. It is used below to read an +// entire frame into a buffer. The delegate retains metadata about the +// frame for later access. +// +class FrameParser : public VESParserDelegate +{ + h__ParserState m_State; + ASDCP_NO_COPY_CONSTRUCT(FrameParser); + +public: + ui32_t m_FrameSize; + bool m_CompletePicture; + bool m_HasGOP; + bool m_ClosedGOP; + ui8_t m_TemporalRef; + ui32_t m_PlaintextOffset; + FrameType_t m_FrameType; + + FrameParser() + { + Reset(); + } + + ~FrameParser() {} + + void Reset() + { + m_FrameSize = 0; + m_HasGOP = m_ClosedGOP = false; + m_CompletePicture = false; + m_TemporalRef = 0; + m_PlaintextOffset = 0; + m_FrameType = FRAME_U; + m_State.Reset(); + } + + Result_t Sequence(VESParser*, const byte_t*, ui32_t s) + { + if ( m_State.Test_SLICE() ) + { + m_CompletePicture = true; + return RESULT_FALSE; + } + + m_FrameSize += s; + return m_State.Goto_SEQ(); + } + + Result_t Picture(VESParser*, const byte_t* b, ui32_t s) + { + if ( m_State.Test_SLICE() ) + { + m_CompletePicture = true; + return RESULT_FALSE; + } + + Accessor::Picture pic(b); + m_TemporalRef = pic.TemporalRef(); + m_FrameType = pic.FrameType(); + m_FrameSize += s; + return m_State.Goto_PIC(); + } + + Result_t Slice(VESParser*, byte_t slice_id) + { + if ( slice_id == FIRST_SLICE ) + { + m_PlaintextOffset = m_FrameSize; + return m_State.Goto_SLICE(); + } + + return m_State.Test_SLICE() ? RESULT_OK : RESULT_FAIL; + } + + Result_t Extension(VESParser*, const byte_t*, ui32_t s) + { + m_FrameSize += s; + return m_State.Goto_EXT(); + } + + Result_t GOP(VESParser*, const byte_t* b, ui32_t s) + { + Accessor::GOP GOP(b); + m_ClosedGOP = GOP.Closed(); + m_HasGOP = true; + m_FrameSize += s; + return m_State.Goto_GOP(); + } + + Result_t Data(VESParser*, const byte_t*, i32_t s) + { + m_FrameSize += s; + return RESULT_OK; + } +}; + +//------------------------------------------------------------------------------------------ + +// The following code assumes the following things: +// - each frame will begin with a picture header or a sequence header +// - any frame that begins with a sequence header is an I frame and is +// assumed to contain a GOP header, a picture header and complete picture data +// - any frame that begins with a picture header is either an I, B or P frame +// and is assumed to contain a complete picture header and picture data + +class ASDCP::MPEG2::Parser::h__Parser +{ + StreamParams m_ParamsDelegate; + FrameParser m_ParserDelegate; + VESParser m_Parser; + Kumu::FileReader m_FileReader; + ui32_t m_FrameNumber; + bool m_EOF; + ASDCP::MPEG2::FrameBuffer m_TmpBuffer; + + ASDCP_NO_COPY_CONSTRUCT(h__Parser); + +public: + h__Parser() : m_TmpBuffer(VESReadSize*8) {} + ~h__Parser() { Close(); } + + Result_t OpenRead(const char* filename); + void Close(); + Result_t Reset(); + Result_t ReadFrame(FrameBuffer&); + Result_t FillVideoDescriptor(VideoDescriptor&); +}; + + +// +Result_t +ASDCP::MPEG2::Parser::h__Parser::Reset() +{ + m_FrameNumber = 0; + m_EOF = false; + m_FileReader.Seek(0); + m_ParserDelegate.Reset(); + return RESULT_OK; +} + +// +void +ASDCP::MPEG2::Parser::h__Parser::Close() +{ + m_FileReader.Close(); +} + +// +ASDCP::Result_t +ASDCP::MPEG2::Parser::h__Parser::OpenRead(const char* filename) +{ + ASDCP_TEST_NULL_STR(filename) + ui32_t read_count = 0; + + Result_t result = m_FileReader.OpenRead(filename); + + if ( ASDCP_SUCCESS(result) ) + result = m_FileReader.Read(m_TmpBuffer.Data(), m_TmpBuffer.Capacity(), &read_count); + + if ( ASDCP_SUCCESS(result) ) + { + const byte_t* p = m_TmpBuffer.RoData(); + + // the mxflib parser demanded the file start with a sequence header. + // Since no one complained and that's the easiest thing to implement, + // I have left it that way. Let me know if you want to be able to + // locate the first GOP in the stream. + ui32_t i = 0; + while ( p[i] == 0 ) i++; + + if ( i < 2 || p[i] != 1 || ! ( p[i+1] == SEQ_START || p[i+1] == PIC_START ) ) + { + DefaultLogSink().Error("Frame buffer does not begin with a PIC or SEQ start code.\n"); + return RESULT_RAW_FORMAT; + } + + if ( ASDCP_SUCCESS(result) ) + { + m_Parser.SetDelegate(&m_ParamsDelegate); + result = m_Parser.Parse(p, read_count); + } + } + + if ( ASDCP_SUCCESS(result) ) + { + ui64_t tmp = m_FileReader.Size() / 65536; // a gross approximation + m_ParamsDelegate.m_VDesc.ContainerDuration = (ui32_t) tmp; + m_Parser.SetDelegate(&m_ParserDelegate); + m_FileReader.Seek(0); + } + + if ( ASDCP_FAILURE(result) ) + { + DefaultLogSink().Error("Unable to identify a wrapping mode for the essence in file \"%s\"\n", filename); + m_FileReader.Close(); + } + + return result;} + + +// +// +ASDCP::Result_t +ASDCP::MPEG2::Parser::h__Parser::ReadFrame(FrameBuffer& FB) +{ + Result_t result = RESULT_OK; + ui32_t write_offset = 0; + ui32_t read_count = 0; + + FB.Size(0); + + if ( m_EOF ) + return RESULT_ENDOFFILE; + + // Data is read in VESReadSize chunks. Each chunk is parsed, and the + // process is stopped when a Sequence or Picture header is found or when + // the input file is exhausted. The partial next frame is cached for the + // next call. + m_ParserDelegate.Reset(); + m_Parser.Reset(); + + if ( m_TmpBuffer.Size() > 0 ) + { + memcpy(FB.Data(), m_TmpBuffer.RoData(), m_TmpBuffer.Size()); + result = m_Parser.Parse(FB.RoData(), m_TmpBuffer.Size()); + write_offset = m_TmpBuffer.Size(); + m_TmpBuffer.Size(0); + } + + while ( ! m_ParserDelegate.m_CompletePicture && result == RESULT_OK ) + { + if ( FB.Capacity() < ( write_offset + VESReadSize ) ) + { + DefaultLogSink().Error("FrameBuf.Capacity: %u FrameLength: %u\n", + FB.Capacity(), ( write_offset + VESReadSize )); + return RESULT_SMALLBUF; + } + + result = m_FileReader.Read(FB.Data() + write_offset, VESReadSize, &read_count); + + if ( result == RESULT_ENDOFFILE || read_count == 0 ) + { + m_EOF = true; + + if ( write_offset > 0 ) + result = RESULT_OK; + } + + if ( ASDCP_SUCCESS(result) ) + { + result = m_Parser.Parse(FB.RoData() + write_offset, read_count); + write_offset += read_count; + } + + if ( m_EOF ) + break; + } + assert(m_ParserDelegate.m_FrameSize <= write_offset); + + if ( ASDCP_SUCCESS(result) + && m_ParserDelegate.m_FrameSize < write_offset ) + { + assert(m_TmpBuffer.Size() == 0); + ui32_t diff = write_offset - m_ParserDelegate.m_FrameSize; + assert(diff <= m_TmpBuffer.Capacity()); + + memcpy(m_TmpBuffer.Data(), FB.RoData() + m_ParserDelegate.m_FrameSize, diff); + m_TmpBuffer.Size(diff); + } + + if ( ASDCP_SUCCESS(result) ) + { + const byte_t* p = FB.RoData(); + if ( p[0] != 0 || p[1] != 0 || p[2] != 1 || ! ( p[3] == SEQ_START || p[3] == PIC_START ) ) + { + DefaultLogSink().Error("Frame buffer does not begin with a PIC or SEQ start code.\n"); + return RESULT_RAW_FORMAT; + } + } + + if ( ASDCP_SUCCESS(result) ) + { + FB.Size(m_ParserDelegate.m_FrameSize); + FB.TemporalOffset(m_ParserDelegate.m_TemporalRef); + FB.FrameType(m_ParserDelegate.m_FrameType); + FB.PlaintextOffset(m_ParserDelegate.m_PlaintextOffset); + FB.FrameNumber(m_FrameNumber++); + FB.GOPStart(m_ParserDelegate.m_HasGOP); + FB.ClosedGOP(m_ParserDelegate.m_ClosedGOP); + } + + return result; +} + + +// Fill a VideoDescriptor struct with the values from the file's header. +ASDCP::Result_t +ASDCP::MPEG2::Parser::h__Parser::FillVideoDescriptor(VideoDescriptor& VDesc) +{ + VDesc = m_ParamsDelegate.m_VDesc; + return RESULT_OK; +} + +//------------------------------------------------------------------------------------------ + +ASDCP::MPEG2::Parser::Parser() +{ +} + +ASDCP::MPEG2::Parser::~Parser() +{ +} + +// Opens the stream for reading, parses enough data to provide a complete +// set of stream metadata for the MXFWriter below. +ASDCP::Result_t +ASDCP::MPEG2::Parser::OpenRead(const char* filename) const +{ + const_cast<ASDCP::MPEG2::Parser*>(this)->m_Parser = new h__Parser; + + Result_t result = m_Parser->OpenRead(filename); + + if ( ASDCP_FAILURE(result) ) + const_cast<ASDCP::MPEG2::Parser*>(this)->m_Parser.release(); + + return result; +} + +// Rewinds the stream to the beginning. +ASDCP::Result_t +ASDCP::MPEG2::Parser::Reset() const +{ + if ( m_Parser.empty() ) + return RESULT_INIT; + + return m_Parser->Reset(); +} + +// Places a frame of data in the frame buffer. Fails if the buffer is too small +// or the stream is empty. +ASDCP::Result_t +ASDCP::MPEG2::Parser::ReadFrame(FrameBuffer& FB) const +{ + if ( m_Parser.empty() ) + return RESULT_INIT; + + return m_Parser->ReadFrame(FB); +} + +ASDCP::Result_t +ASDCP::MPEG2::Parser::FillVideoDescriptor(VideoDescriptor& VDesc) const +{ + if ( m_Parser.empty() ) + return RESULT_INIT; + + return m_Parser->FillVideoDescriptor(VDesc); +} + +// +// end MPEG2_Parser.cpp +// diff --git a/asdcplib/src/MXF.cpp b/asdcplib/src/MXF.cpp new file mode 100755 index 0000000..c35c1d2 --- /dev/null +++ b/asdcplib/src/MXF.cpp @@ -0,0 +1,1489 @@ +/* +Copyright (c) 2005-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 MXF.cpp + \version $Id: MXF.cpp,v 1.62 2012/03/05 13:11:47 jhurst Exp $ + \brief MXF objects +*/ + +#include "MXF.h" +#include "Metadata.h" +#include <KM_log.h> + +using Kumu::DefaultLogSink; +using Kumu::GenRandomValue; + +// index segments must be < 64K +// NOTE: this value may too high if advanced index entry elements are used. +const ui32_t CBRIndexEntriesPerSegment = 5000; + +//------------------------------------------------------------------------------------------ +// + +const ui32_t kl_length = ASDCP::SMPTE_UL_LENGTH + ASDCP::MXF_BER_LENGTH; + +// +ASDCP::Result_t +ASDCP::MXF::SeekToRIP(const Kumu::FileReader& Reader) +{ + Kumu::fpos_t end_pos; + + // go to the end - 4 bytes + Result_t result = Reader.Seek(0, Kumu::SP_END); + + if ( ASDCP_SUCCESS(result) ) + result = Reader.Tell(&end_pos); + + if ( ASDCP_SUCCESS(result) + && end_pos < (SMPTE_UL_LENGTH+MXF_BER_LENGTH) ) + result = RESULT_FAIL; // File is smaller than an empty packet! + + if ( ASDCP_SUCCESS(result) ) + result = Reader.Seek(end_pos - 4); + + // get the ui32_t RIP length + ui32_t read_count; + byte_t intbuf[MXF_BER_LENGTH]; + ui32_t rip_size = 0; + + if ( ASDCP_SUCCESS(result) ) + { + result = Reader.Read(intbuf, MXF_BER_LENGTH, &read_count); + + if ( ASDCP_SUCCESS(result) && read_count != 4 ) + result = RESULT_FAIL; + } + + if ( ASDCP_SUCCESS(result) ) + { + rip_size = KM_i32_BE(Kumu::cp2i<ui32_t>(intbuf)); + + if ( rip_size > end_pos ) // RIP can't be bigger than the file + return RESULT_FAIL; + } + + // reposition to start of RIP + if ( ASDCP_SUCCESS(result) ) + result = Reader.Seek(end_pos - rip_size); + + return result; +} + +// +ASDCP::Result_t +ASDCP::MXF::RIP::GetPairBySID(ui32_t SID, Pair& outPair) const +{ + Array<Pair>::const_iterator pi = PairArray.begin(); + for ( ; pi != PairArray.end(); pi++ ) + { + if ( (*pi).BodySID == SID ) + { + outPair = *pi; + return RESULT_OK; + } + } + + return RESULT_FAIL; +} + +// +ASDCP::Result_t +ASDCP::MXF::RIP::InitFromFile(const Kumu::FileReader& Reader) +{ + assert(m_Dict); + Result_t result = KLVFilePacket::InitFromFile(Reader, m_Dict->ul(MDD_RandomIndexMetadata)); + + if ( ASDCP_SUCCESS(result) ) + { + Kumu::MemIOReader MemRDR(m_ValueStart, m_ValueLength - 4); + result = PairArray.Unarchive(&MemRDR) ? RESULT_OK : RESULT_KLV_CODING; + } + + if ( ASDCP_FAILURE(result) ) + DefaultLogSink().Error("Failed to initialize RIP\n"); + + return result; +} + +// +ASDCP::Result_t +ASDCP::MXF::RIP::WriteToFile(Kumu::FileWriter& Writer) +{ + assert(m_Dict); + ASDCP::FrameBuffer Buffer; + ui32_t RIPSize = ( PairArray.size() * (sizeof(ui32_t) + sizeof(ui64_t)) ) + 4; + Result_t result = Buffer.Capacity(RIPSize); + + if ( ASDCP_SUCCESS(result) ) + result = WriteKLToFile(Writer, m_Dict->ul(MDD_RandomIndexMetadata), RIPSize); + + if ( ASDCP_SUCCESS(result) ) + { + result = RESULT_KLV_CODING; + + Kumu::MemIOWriter MemWRT(Buffer.Data(), Buffer.Capacity()); + if ( PairArray.Archive(&MemWRT) ) + if ( MemWRT.WriteUi32BE(RIPSize + 20) ) + { + Buffer.Size(MemWRT.Length()); + result = RESULT_OK; + } + } + + if ( ASDCP_SUCCESS(result) ) + result = Writer.Write(Buffer.RoData(), Buffer.Size()); + + return result; +} + +// +void +ASDCP::MXF::RIP::Dump(FILE* stream) +{ + if ( stream == 0 ) + stream = stderr; + + KLVFilePacket::Dump(stream, *m_Dict, false); + PairArray.Dump(stream, false); +} + +//------------------------------------------------------------------------------------------ +// + +// +class ASDCP::MXF::Partition::h__PacketList +{ +public: + std::list<InterchangeObject*> m_List; + std::map<UUID, InterchangeObject*> m_Map; + + ~h__PacketList() { + while ( ! m_List.empty() ) + { + delete m_List.back(); + m_List.pop_back(); + } + } + + // + void AddPacket(InterchangeObject* ThePacket) // takes ownership + { + assert(ThePacket); + m_Map.insert(std::map<UUID, InterchangeObject*>::value_type(ThePacket->InstanceUID, ThePacket)); + m_List.push_back(ThePacket); + } + + // + Result_t GetMDObjectByID(const UUID& ObjectID, InterchangeObject** Object) + { + ASDCP_TEST_NULL(Object); + + std::map<UUID, InterchangeObject*>::iterator mi = m_Map.find(ObjectID); + + if ( mi == m_Map.end() ) + { + *Object = 0; + return RESULT_FAIL; + } + + *Object = (*mi).second; + return RESULT_OK; + } + + // + Result_t GetMDObjectByType(const byte_t* ObjectID, InterchangeObject** Object) + { + ASDCP_TEST_NULL(ObjectID); + ASDCP_TEST_NULL(Object); + std::list<InterchangeObject*>::iterator li; + *Object = 0; + + for ( li = m_List.begin(); li != m_List.end(); li++ ) + { + if ( (*li)->HasUL(ObjectID) ) + { + *Object = *li; + return RESULT_OK; + } + } + + return RESULT_FAIL; + } + + // + Result_t GetMDObjectsByType(const byte_t* ObjectID, std::list<InterchangeObject*>& ObjectList) + { + ASDCP_TEST_NULL(ObjectID); + std::list<InterchangeObject*>::iterator li; + + for ( li = m_List.begin(); li != m_List.end(); li++ ) + { + if ( (*li)->HasUL(ObjectID) ) + ObjectList.push_back(*li); + } + + return ObjectList.empty() ? RESULT_FAIL : RESULT_OK; + } +}; + +//------------------------------------------------------------------------------------------ +// + + +ASDCP::MXF::Partition::Partition(const Dictionary*& d) : + m_Dict(d), + MajorVersion(1), MinorVersion(2), + KAGSize(1), ThisPartition(0), PreviousPartition(0), + FooterPartition(0), HeaderByteCount(0), IndexByteCount(0), IndexSID(0), + BodyOffset(0), BodySID(0) +{ + m_PacketList = new h__PacketList; +} + +ASDCP::MXF::Partition::~Partition() +{ +} + +// takes ownership +void +ASDCP::MXF::Partition::AddChildObject(InterchangeObject* Object) +{ + assert(Object); + + if ( ! Object->InstanceUID.HasValue() ) + GenRandomValue(Object->InstanceUID); + + m_PacketList->AddPacket(Object); +} + +// +ASDCP::Result_t +ASDCP::MXF::Partition::InitFromFile(const Kumu::FileReader& Reader) +{ + Result_t result = KLVFilePacket::InitFromFile(Reader); + // test the UL + // could be one of several values + if ( ASDCP_SUCCESS(result) ) + result = ASDCP::MXF::Partition::InitFromBuffer(m_ValueStart, m_ValueLength); + + return result; +} + +// +ASDCP::Result_t +ASDCP::MXF::Partition::InitFromBuffer(const byte_t* p, ui32_t l) +{ + Kumu::MemIOReader MemRDR(p, l); + Result_t result = RESULT_KLV_CODING; + + if ( MemRDR.ReadUi16BE(&MajorVersion) ) + if ( MemRDR.ReadUi16BE(&MinorVersion) ) + if ( MemRDR.ReadUi32BE(&KAGSize) ) + if ( MemRDR.ReadUi64BE(&ThisPartition) ) + if ( MemRDR.ReadUi64BE(&PreviousPartition) ) + if ( MemRDR.ReadUi64BE(&FooterPartition) ) + if ( MemRDR.ReadUi64BE(&HeaderByteCount) ) + if ( MemRDR.ReadUi64BE(&IndexByteCount) ) + if ( MemRDR.ReadUi32BE(&IndexSID) ) + if ( MemRDR.ReadUi64BE(&BodyOffset) ) + if ( MemRDR.ReadUi32BE(&BodySID) ) + if ( OperationalPattern.Unarchive(&MemRDR) ) + if ( EssenceContainers.Unarchive(&MemRDR) ) + result = RESULT_OK; + + if ( ASDCP_FAILURE(result) ) + DefaultLogSink().Error("Failed to initialize Partition\n"); + + return result; +} + +// +ASDCP::Result_t +ASDCP::MXF::Partition::WriteToFile(Kumu::FileWriter& Writer, UL& PartitionLabel) +{ + ASDCP::FrameBuffer Buffer; + Result_t result = Buffer.Capacity(1024); + + if ( ASDCP_SUCCESS(result) ) + { + Kumu::MemIOWriter MemWRT(Buffer.Data(), Buffer.Capacity()); + result = RESULT_KLV_CODING; + if ( MemWRT.WriteUi16BE(MajorVersion) ) + if ( MemWRT.WriteUi16BE(MinorVersion) ) + if ( MemWRT.WriteUi32BE(KAGSize) ) + if ( MemWRT.WriteUi64BE(ThisPartition) ) + if ( MemWRT.WriteUi64BE(PreviousPartition) ) + if ( MemWRT.WriteUi64BE(FooterPartition) ) + if ( MemWRT.WriteUi64BE(HeaderByteCount) ) + if ( MemWRT.WriteUi64BE(IndexByteCount) ) + if ( MemWRT.WriteUi32BE(IndexSID) ) + if ( MemWRT.WriteUi64BE(BodyOffset) ) + if ( MemWRT.WriteUi32BE(BodySID) ) + if ( OperationalPattern.Archive(&MemWRT) ) + if ( EssenceContainers.Archive(&MemWRT) ) + { + Buffer.Size(MemWRT.Length()); + result = RESULT_OK; + } + } + + if ( ASDCP_SUCCESS(result) ) + { + ui32_t write_count; + result = WriteKLToFile(Writer, PartitionLabel.Value(), Buffer.Size()); + + if ( ASDCP_SUCCESS(result) ) + result = Writer.Write(Buffer.RoData(), Buffer.Size(), &write_count); + } + + return result; +} + +// +ui32_t +ASDCP::MXF::Partition::ArchiveSize() +{ + return ( kl_length + + sizeof(ui16_t) + sizeof(ui16_t) + + sizeof(ui32_t) + + sizeof(ui64_t) + sizeof(ui64_t) + sizeof(ui64_t) + sizeof(ui64_t) + sizeof(ui64_t) + + sizeof(ui32_t) + + sizeof(ui64_t) + + sizeof(ui32_t) + + SMPTE_UL_LENGTH + + sizeof(ui32_t) + sizeof(ui32_t) + ( UUIDlen * EssenceContainers.size() ) ); +} + +// +void +ASDCP::MXF::Partition::Dump(FILE* stream) +{ + char identbuf[IdentBufferLen]; + + if ( stream == 0 ) + stream = stderr; + + KLVFilePacket::Dump(stream, *m_Dict, false); + fprintf(stream, " MajorVersion = %hu\n", MajorVersion); + fprintf(stream, " MinorVersion = %hu\n", MinorVersion); + fprintf(stream, " KAGSize = %u\n", KAGSize); + fprintf(stream, " ThisPartition = %s\n", ui64sz(ThisPartition, identbuf)); + fprintf(stream, " PreviousPartition = %s\n", ui64sz(PreviousPartition, identbuf)); + fprintf(stream, " FooterPartition = %s\n", ui64sz(FooterPartition, identbuf)); + fprintf(stream, " HeaderByteCount = %s\n", ui64sz(HeaderByteCount, identbuf)); + fprintf(stream, " IndexByteCount = %s\n", ui64sz(IndexByteCount, identbuf)); + fprintf(stream, " IndexSID = %u\n", IndexSID); + fprintf(stream, " BodyOffset = %s\n", ui64sz(BodyOffset, identbuf)); + fprintf(stream, " BodySID = %u\n", BodySID); + fprintf(stream, " OperationalPattern = %s\n", OperationalPattern.EncodeString(identbuf, IdentBufferLen)); + fputs("Essence Containers:\n", stream); EssenceContainers.Dump(stream); +} + + +//------------------------------------------------------------------------------------------ +// + +class ASDCP::MXF::Primer::h__PrimerLookup : public std::map<UL, TagValue> +{ +public: + void InitWithBatch(ASDCP::MXF::Batch<ASDCP::MXF::Primer::LocalTagEntry>& Batch) + { + ASDCP::MXF::Batch<ASDCP::MXF::Primer::LocalTagEntry>::iterator i = Batch.begin(); + + for ( ; i != Batch.end(); i++ ) + insert(std::map<UL, TagValue>::value_type((*i).UL, (*i).Tag)); + } +}; + + +// +ASDCP::MXF::Primer::Primer(const Dictionary*& d) : m_LocalTag(0xff), m_Dict(d) { + m_UL = m_Dict->ul(MDD_Primer); +} + +// +ASDCP::MXF::Primer::~Primer() {} + +// +void +ASDCP::MXF::Primer::ClearTagList() +{ + LocalTagEntryBatch.clear(); + m_Lookup = new h__PrimerLookup; +} + +// +ASDCP::Result_t +ASDCP::MXF::Primer::InitFromBuffer(const byte_t* p, ui32_t l) +{ + assert(m_Dict); + Result_t result = KLVPacket::InitFromBuffer(p, l, m_Dict->ul(MDD_Primer)); + + if ( ASDCP_SUCCESS(result) ) + { + Kumu::MemIOReader MemRDR(m_ValueStart, m_ValueLength); + result = LocalTagEntryBatch.Unarchive(&MemRDR) ? RESULT_OK : RESULT_KLV_CODING; + } + + if ( ASDCP_SUCCESS(result) ) + { + m_Lookup = new h__PrimerLookup; + m_Lookup->InitWithBatch(LocalTagEntryBatch); + } + + if ( ASDCP_FAILURE(result) ) + DefaultLogSink().Error("Failed to initialize Primer\n"); + + return result; +} + +// +ASDCP::Result_t +ASDCP::MXF::Primer::WriteToFile(Kumu::FileWriter& Writer) +{ + ASDCP::FrameBuffer Buffer; + Result_t result = Buffer.Capacity(128*1024); + + if ( ASDCP_SUCCESS(result) ) + result = WriteToBuffer(Buffer); + + if ( ASDCP_SUCCESS(result) ) + result = Writer.Write(Buffer.RoData(), Buffer.Size()); + + return result; +} + +// +ASDCP::Result_t +ASDCP::MXF::Primer::WriteToBuffer(ASDCP::FrameBuffer& Buffer) +{ + assert(m_Dict); + ASDCP::FrameBuffer LocalTagBuffer; + Kumu::MemIOWriter MemWRT(Buffer.Data() + kl_length, Buffer.Capacity() - kl_length); + Result_t result = LocalTagEntryBatch.Archive(&MemWRT) ? RESULT_OK : RESULT_KLV_CODING; + + if ( ASDCP_SUCCESS(result) ) + { + ui32_t packet_length = MemWRT.Length(); + result = WriteKLToBuffer(Buffer, packet_length); + + if ( ASDCP_SUCCESS(result) ) + Buffer.Size(Buffer.Size() + packet_length); + } + + return result; +} + +// +ASDCP::Result_t +ASDCP::MXF::Primer::InsertTag(const MDDEntry& Entry, ASDCP::TagValue& Tag) +{ + assert(m_Lookup); + UL TestUL(Entry.ul); + std::map<UL, TagValue>::iterator i = m_Lookup->find(TestUL); + + if ( i == m_Lookup->end() ) + { + if ( Entry.tag.a == 0 && Entry.tag.b == 0 ) + { + Tag.a = 0xff; + Tag.b = m_LocalTag--; + } + else + { + Tag.a = Entry.tag.a; + Tag.b = Entry.tag.b; + } + + LocalTagEntry TmpEntry; + TmpEntry.UL = TestUL; + TmpEntry.Tag = Tag; + + LocalTagEntryBatch.push_back(TmpEntry); + m_Lookup->insert(std::map<UL, TagValue>::value_type(TmpEntry.UL, TmpEntry.Tag)); + } + else + { + Tag = (*i).second; + } + + return RESULT_OK; +} + +// +ASDCP::Result_t +ASDCP::MXF::Primer::TagForKey(const ASDCP::UL& Key, ASDCP::TagValue& Tag) +{ + assert(m_Lookup); + if ( m_Lookup.empty() ) + { + DefaultLogSink().Error("Primer lookup is empty\n"); + return RESULT_FAIL; + } + + std::map<UL, TagValue>::iterator i = m_Lookup->find(Key); + + if ( i == m_Lookup->end() ) + return RESULT_FALSE; + + Tag = (*i).second; + return RESULT_OK; +} + +// +void +ASDCP::MXF::Primer::Dump(FILE* stream) +{ + assert(m_Dict); + char identbuf[IdentBufferLen]; + + if ( stream == 0 ) + stream = stderr; + + KLVPacket::Dump(stream, *m_Dict, false); + fprintf(stream, "Primer: %u %s\n", + (ui32_t)LocalTagEntryBatch.size(), + ( LocalTagEntryBatch.size() == 1 ? "entry" : "entries" )); + + Batch<LocalTagEntry>::iterator i = LocalTagEntryBatch.begin(); + for ( ; i != LocalTagEntryBatch.end(); i++ ) + { + const MDDEntry* Entry = m_Dict->FindUL((*i).UL.Value()); + fprintf(stream, " %s %s\n", (*i).EncodeString(identbuf, IdentBufferLen), (Entry ? Entry->name : "Unknown")); + } +} + + +//------------------------------------------------------------------------------------------ +// + +// +ASDCP::MXF::Preface::Preface(const Dictionary*& d) : + InterchangeObject(d), m_Dict(d), Version(258), ObjectModelVersion(0) +{ + assert(m_Dict); + m_UL = m_Dict->Type(MDD_Preface).ul; +} + +// +void +ASDCP::MXF::Preface::Copy(const Preface& rhs) +{ + InterchangeObject::Copy(rhs); + + LastModifiedDate = rhs.LastModifiedDate; + Version = rhs.Version; + ObjectModelVersion = rhs.ObjectModelVersion; + PrimaryPackage = rhs.PrimaryPackage; + Identifications = rhs.Identifications; + ContentStorage = rhs.ContentStorage; + OperationalPattern = rhs.OperationalPattern; + EssenceContainers = rhs.EssenceContainers; + DMSchemes = rhs.DMSchemes; +} + +// +ASDCP::Result_t +ASDCP::MXF::Preface::InitFromTLVSet(TLVReader& TLVSet) +{ + Result_t result = InterchangeObject::InitFromTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Preface, LastModifiedDate)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi16(OBJ_READ_ARGS(Preface, Version)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(Preface, ObjectModelVersion)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Preface, PrimaryPackage)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Preface, Identifications)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Preface, ContentStorage)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Preface, OperationalPattern)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Preface, EssenceContainers)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Preface, DMSchemes)); + return result; +} + +// +ASDCP::Result_t +ASDCP::MXF::Preface::WriteToTLVSet(TLVWriter& TLVSet) +{ + Result_t result = InterchangeObject::WriteToTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Preface, LastModifiedDate)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi16(OBJ_WRITE_ARGS(Preface, Version)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(Preface, ObjectModelVersion)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Preface, PrimaryPackage)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Preface, Identifications)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Preface, ContentStorage)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Preface, OperationalPattern)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Preface, EssenceContainers)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Preface, DMSchemes)); + return result; +} + +// +ASDCP::Result_t +ASDCP::MXF::Preface::InitFromBuffer(const byte_t* p, ui32_t l) +{ + return InterchangeObject::InitFromBuffer(p, l); +} + +// +ASDCP::Result_t +ASDCP::MXF::Preface::WriteToBuffer(ASDCP::FrameBuffer& Buffer) +{ + return InterchangeObject::WriteToBuffer(Buffer); +} + +// +void +ASDCP::MXF::Preface::Dump(FILE* stream) +{ + char identbuf[IdentBufferLen]; + + if ( stream == 0 ) + stream = stderr; + + InterchangeObject::Dump(stream); + fprintf(stream, " %22s = %s\n", "LastModifiedDate", LastModifiedDate.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " %22s = %hu\n", "Version", Version); + fprintf(stream, " %22s = %u\n", "ObjectModelVersion", ObjectModelVersion); + fprintf(stream, " %22s = %s\n", "PrimaryPackage", PrimaryPackage.EncodeHex(identbuf, IdentBufferLen)); + fprintf(stream, " %22s:\n", "Identifications"); Identifications.Dump(stream); + fprintf(stream, " %22s = %s\n", "ContentStorage", ContentStorage.EncodeHex(identbuf, IdentBufferLen)); + fprintf(stream, " %22s = %s\n", "OperationalPattern", OperationalPattern.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " %22s:\n", "EssenceContainers"); EssenceContainers.Dump(stream); + fprintf(stream, " %22s:\n", "DMSchemes"); DMSchemes.Dump(stream); +} + +//------------------------------------------------------------------------------------------ +// + +ASDCP::MXF::OPAtomHeader::OPAtomHeader(const Dictionary*& d) : Partition(d), m_Dict(d), m_RIP(d), m_Primer(d), m_Preface(0), m_HasRIP(false) {} +ASDCP::MXF::OPAtomHeader::~OPAtomHeader() {} + +// +ASDCP::Result_t +ASDCP::MXF::OPAtomHeader::InitFromFile(const Kumu::FileReader& Reader) +{ + m_HasRIP = false; + Result_t result = SeekToRIP(Reader); + + if ( ASDCP_SUCCESS(result) ) + { + result = m_RIP.InitFromFile(Reader); + ui32_t test_s = m_RIP.PairArray.size(); + + if ( ASDCP_FAILURE(result) ) + { + DefaultLogSink().Error("File contains no RIP\n"); + result = RESULT_OK; + } + else if ( test_s == 0 ) + { + DefaultLogSink().Error("RIP contains no Pairs.\n"); + result = RESULT_FORMAT; + } + else + { + if ( test_s < 2 ) + { + // OP-Atom states that there will be either two or three partitions: + // one closed header and one closed footer with an optional body + // SMPTE 429-5 files may have many partitions, see SMPTE 410M + DefaultLogSink().Warn("RIP count is less than 2: %u\n", test_s); + } + + m_HasRIP = true; + + if ( m_RIP.PairArray.front().ByteOffset != 0 ) + { + DefaultLogSink().Error("First Partition in RIP is not at offset 0.\n"); + result = RESULT_FORMAT; + } + } + } + + if ( ASDCP_SUCCESS(result) ) + result = Reader.Seek(0); + + if ( ASDCP_SUCCESS(result) ) + result = Partition::InitFromFile(Reader); // test UL and OP + + if ( ASDCP_FAILURE(result) ) + return result; + + // is it really OP-Atom? + assert(m_Dict); + UL OPAtomUL(SMPTE_390_OPAtom_Entry().ul); + UL InteropOPAtomUL(MXFInterop_OPAtom_Entry().ul); + + if ( OperationalPattern.ExactMatch(OPAtomUL) ) // SMPTE + { + if ( m_Dict == &DefaultCompositeDict() ) + m_Dict = &DefaultSMPTEDict(); + } + else if ( OperationalPattern.ExactMatch(InteropOPAtomUL) ) // Interop + { + if ( m_Dict == &DefaultCompositeDict() ) + m_Dict = &DefaultInteropDict(); + } + else + { + char strbuf[IdentBufferLen]; + const MDDEntry* Entry = m_Dict->FindUL(OperationalPattern.Value()); + if ( Entry == 0 ) + DefaultLogSink().Warn("Operational pattern is not OP-Atom: %s\n", + OperationalPattern.EncodeString(strbuf, IdentBufferLen)); + else + DefaultLogSink().Warn("Operational pattern is not OP-Atom: %s\n", Entry->name); + } + + // slurp up the remainder of the header + if ( HeaderByteCount < 1024 ) + DefaultLogSink().Warn("Improbably small HeaderByteCount value: %u\n", HeaderByteCount); + + assert (HeaderByteCount <= 0xFFFFFFFFL); + result = m_Buffer.Capacity((ui32_t) HeaderByteCount); + + if ( ASDCP_SUCCESS(result) ) + { + ui32_t read_count; + result = Reader.Read(m_Buffer.Data(), m_Buffer.Capacity(), &read_count); + + if ( ASDCP_FAILURE(result) ) + return result; + + if ( read_count != m_Buffer.Capacity() ) + { + DefaultLogSink().Error("Short read of OP-Atom header metadata; wanted %u, got %u\n", + m_Buffer.Capacity(), read_count); + return RESULT_KLV_CODING; + } + } + + if ( ASDCP_SUCCESS(result) ) + result = InitFromBuffer(m_Buffer.RoData(), m_Buffer.Capacity()); + + return result; +} + +// +ASDCP::Result_t +ASDCP::MXF::OPAtomHeader::InitFromPartitionBuffer(const byte_t* p, ui32_t l) +{ + Result_t result = KLVPacket::InitFromBuffer(p, l); + + if ( ASDCP_SUCCESS(result) ) + result = Partition::InitFromBuffer(m_ValueStart, m_ValueLength); // test UL and OP + + if ( ASDCP_SUCCESS(result) ) + { + ui32_t pp_len = KLVPacket::PacketLength(); + result = InitFromBuffer(p + pp_len, l - pp_len); + } + + return result; +} + +// +ASDCP::Result_t +ASDCP::MXF::OPAtomHeader::InitFromBuffer(const byte_t* p, ui32_t l) +{ + assert(m_Dict); + Result_t result = RESULT_OK; + const byte_t* end_p = p + l; + + while ( ASDCP_SUCCESS(result) && p < end_p ) + { + // parse the packets and index them by uid, discard KLVFill items + InterchangeObject* object = CreateObject(m_Dict, p); + assert(object); + + object->m_Lookup = &m_Primer; + result = object->InitFromBuffer(p, end_p - p); + const byte_t* redo_p = p; + p += object->PacketLength(); + // hexdump(p, object->PacketLength()); + + if ( ASDCP_SUCCESS(result) ) + { + if ( object->IsA(m_Dict->ul(MDD_KLVFill)) ) + { + delete object; + } + else if ( object->IsA(m_Dict->ul(MDD_Primer)) ) // TODO: only one primer should be found + { + delete object; + result = m_Primer.InitFromBuffer(redo_p, end_p - redo_p); + } + else + { + m_PacketList->AddPacket(object); // takes ownership + + if ( object->IsA(m_Dict->ul(MDD_Preface)) && m_Preface == 0 ) + m_Preface = (Preface*)object; + } + } + else + { + DefaultLogSink().Error("Error initializing packet\n"); + delete object; + } + } + + return result; +} + +ASDCP::Result_t +ASDCP::MXF::OPAtomHeader::GetMDObjectByID(const UUID& ObjectID, InterchangeObject** Object) +{ + return m_PacketList->GetMDObjectByID(ObjectID, Object); +} + +// +ASDCP::Result_t +ASDCP::MXF::OPAtomHeader::GetMDObjectByType(const byte_t* ObjectID, InterchangeObject** Object) +{ + InterchangeObject* TmpObject; + + if ( Object == 0 ) + Object = &TmpObject; + + return m_PacketList->GetMDObjectByType(ObjectID, Object); +} + +// +ASDCP::Result_t +ASDCP::MXF::OPAtomHeader::GetMDObjectsByType(const byte_t* ObjectID, std::list<InterchangeObject*>& ObjectList) +{ + return m_PacketList->GetMDObjectsByType(ObjectID, ObjectList); +} + +// +ASDCP::MXF::Identification* +ASDCP::MXF::OPAtomHeader::GetIdentification() +{ + InterchangeObject* Object; + + if ( ASDCP_SUCCESS(GetMDObjectByType(OBJ_TYPE_ARGS(Identification), &Object)) ) + return (Identification*)Object; + + return 0; +} + +// +ASDCP::MXF::SourcePackage* +ASDCP::MXF::OPAtomHeader::GetSourcePackage() +{ + InterchangeObject* Object; + + if ( ASDCP_SUCCESS(GetMDObjectByType(OBJ_TYPE_ARGS(SourcePackage), &Object)) ) + return (SourcePackage*)Object; + + return 0; +} + +// +ASDCP::MXF::RIP& +ASDCP::MXF::OPAtomHeader::GetRIP() { return m_RIP; } + +// +ASDCP::Result_t +ASDCP::MXF::OPAtomHeader::WriteToFile(Kumu::FileWriter& Writer, ui32_t HeaderSize) +{ + assert(m_Dict); + if ( m_Preface == 0 ) + return RESULT_STATE; + + if ( HeaderSize < 4096 ) + { + DefaultLogSink().Error("HeaderSize %u is too small. Must be >= 4096\n", HeaderSize); + return RESULT_FAIL; + } + + ASDCP::FrameBuffer HeaderBuffer; + HeaderByteCount = HeaderSize - ArchiveSize(); + assert (HeaderByteCount <= 0xFFFFFFFFL); + Result_t result = HeaderBuffer.Capacity((ui32_t) HeaderByteCount); + m_Preface->m_Lookup = &m_Primer; + + std::list<InterchangeObject*>::iterator pl_i = m_PacketList->m_List.begin(); + for ( ; pl_i != m_PacketList->m_List.end() && ASDCP_SUCCESS(result); pl_i++ ) + { + InterchangeObject* object = *pl_i; + object->m_Lookup = &m_Primer; + + ASDCP::FrameBuffer WriteWrapper; + WriteWrapper.SetData(HeaderBuffer.Data() + HeaderBuffer.Size(), + HeaderBuffer.Capacity() - HeaderBuffer.Size()); + result = object->WriteToBuffer(WriteWrapper); + HeaderBuffer.Size(HeaderBuffer.Size() + WriteWrapper.Size()); + } + + if ( ASDCP_SUCCESS(result) ) + { + UL TmpUL(m_Dict->ul(MDD_ClosedCompleteHeader)); + result = Partition::WriteToFile(Writer, TmpUL); + } + + if ( ASDCP_SUCCESS(result) ) + result = m_Primer.WriteToFile(Writer); + + if ( ASDCP_SUCCESS(result) ) + { + ui32_t write_count; + Writer.Write(HeaderBuffer.RoData(), HeaderBuffer.Size(), &write_count); + assert(write_count == HeaderBuffer.Size()); + } + + // KLV Fill + if ( ASDCP_SUCCESS(result) ) + { + Kumu::fpos_t pos = Writer.Tell(); + + if ( pos > (Kumu::fpos_t)HeaderByteCount ) + { + char intbuf[IntBufferLen]; + DefaultLogSink().Error("Header size %s exceeds specified value %u\n", + ui64sz(pos, intbuf), + HeaderSize); + return RESULT_FAIL; + } + + ASDCP::FrameBuffer NilBuf; + ui32_t klv_fill_length = HeaderSize - (ui32_t)pos; + + if ( klv_fill_length < kl_length ) + { + DefaultLogSink().Error("Remaining region too small for KLV Fill header\n"); + return RESULT_FAIL; + } + + klv_fill_length -= kl_length; + result = WriteKLToFile(Writer, m_Dict->ul(MDD_KLVFill), klv_fill_length); + + if ( ASDCP_SUCCESS(result) ) + result = NilBuf.Capacity(klv_fill_length); + + if ( ASDCP_SUCCESS(result) ) + { + memset(NilBuf.Data(), 0, klv_fill_length); + ui32_t write_count; + Writer.Write(NilBuf.RoData(), klv_fill_length, &write_count); + assert(write_count == klv_fill_length); + } + } + + return result; +} + +// +void +ASDCP::MXF::OPAtomHeader::Dump(FILE* stream) +{ + if ( stream == 0 ) + stream = stderr; + + Partition::Dump(stream); + m_Primer.Dump(stream); + + if ( m_Preface == 0 ) + fputs("No Preface loaded\n", stream); + + std::list<InterchangeObject*>::iterator i = m_PacketList->m_List.begin(); + for ( ; i != m_PacketList->m_List.end(); i++ ) + (*i)->Dump(stream); +} + +//------------------------------------------------------------------------------------------ +// + +ASDCP::MXF::OPAtomIndexFooter::OPAtomIndexFooter(const Dictionary*& d) : + Partition(d), + m_CurrentSegment(0), m_BytesPerEditUnit(0), m_BodySID(0), m_Dict(d), + m_ECOffset(0), m_Lookup(0) +{ + BodySID = 0; + IndexSID = 129; +} + +ASDCP::MXF::OPAtomIndexFooter::~OPAtomIndexFooter() {} + +// +ASDCP::Result_t +ASDCP::MXF::OPAtomIndexFooter::InitFromFile(const Kumu::FileReader& Reader) +{ + Result_t result = Partition::InitFromFile(Reader); // test UL and OP + + // slurp up the remainder of the footer + ui32_t read_count; + + if ( ASDCP_SUCCESS(result) ) + { + assert (IndexByteCount <= 0xFFFFFFFFL); + result = m_Buffer.Capacity((ui32_t) IndexByteCount); + } + + if ( ASDCP_SUCCESS(result) ) + result = Reader.Read(m_Buffer.Data(), m_Buffer.Capacity(), &read_count); + + if ( ASDCP_SUCCESS(result) && read_count != m_Buffer.Capacity() ) + { + DefaultLogSink().Error("Short read of footer partition: got %u, expecting %u\n", + read_count, m_Buffer.Capacity()); + return RESULT_FAIL; + } + + if ( ASDCP_SUCCESS(result) ) + result = InitFromBuffer(m_Buffer.RoData(), m_Buffer.Capacity()); + + return result; +} + +// +ASDCP::Result_t +ASDCP::MXF::OPAtomIndexFooter::InitFromPartitionBuffer(const byte_t* p, ui32_t l) +{ + Result_t result = KLVPacket::InitFromBuffer(p, l); + + if ( ASDCP_SUCCESS(result) ) + result = Partition::InitFromBuffer(m_ValueStart, m_ValueLength); // test UL and OP + + if ( ASDCP_SUCCESS(result) ) + { + ui32_t pp_len = KLVPacket::PacketLength(); + result = InitFromBuffer(p + pp_len, l - pp_len); + } + + return result; +} + +// +ASDCP::Result_t +ASDCP::MXF::OPAtomIndexFooter::InitFromBuffer(const byte_t* p, ui32_t l) +{ + Result_t result = RESULT_OK; + const byte_t* end_p = p + l; + + while ( ASDCP_SUCCESS(result) && p < end_p ) + { + // parse the packets and index them by uid, discard KLVFill items + InterchangeObject* object = CreateObject(m_Dict, p); + assert(object); + + object->m_Lookup = m_Lookup; + result = object->InitFromBuffer(p, end_p - p); + p += object->PacketLength(); + + if ( ASDCP_SUCCESS(result) ) + { + m_PacketList->AddPacket(object); // takes ownership + } + else + { + DefaultLogSink().Error("Error initializing packet\n"); + delete object; + } + } + + if ( ASDCP_FAILURE(result) ) + DefaultLogSink().Error("Failed to initialize OPAtomIndexFooter\n"); + + return result; +} + +// +ASDCP::Result_t +ASDCP::MXF::OPAtomIndexFooter::WriteToFile(Kumu::FileWriter& Writer, ui64_t duration) +{ + assert(m_Dict); + ASDCP::FrameBuffer FooterBuffer; + ui32_t footer_size = m_PacketList->m_List.size() * MaxIndexSegmentSize; // segment-count * max-segment-size + Result_t result = FooterBuffer.Capacity(footer_size); + ui32_t iseg_count = 0; + + if ( m_CurrentSegment != 0 ) + { + m_CurrentSegment->IndexDuration = m_CurrentSegment->IndexEntryArray.size(); + m_CurrentSegment = 0; + } + + std::list<InterchangeObject*>::iterator pl_i = m_PacketList->m_List.begin(); + for ( ; pl_i != m_PacketList->m_List.end() && ASDCP_SUCCESS(result); pl_i++ ) + { + if ( (*pl_i)->IsA(OBJ_TYPE_ARGS(IndexTableSegment)) ) + { + iseg_count++; + IndexTableSegment* Segment = (IndexTableSegment*)(*pl_i); + + if ( m_BytesPerEditUnit != 0 ) + { + if ( iseg_count != 1 ) + return RESULT_STATE; + + Segment->IndexDuration = duration; + } + } + + InterchangeObject* object = *pl_i; + object->m_Lookup = m_Lookup; + + ASDCP::FrameBuffer WriteWrapper; + WriteWrapper.SetData(FooterBuffer.Data() + FooterBuffer.Size(), + FooterBuffer.Capacity() - FooterBuffer.Size()); + result = object->WriteToBuffer(WriteWrapper); + FooterBuffer.Size(FooterBuffer.Size() + WriteWrapper.Size()); + } + + if ( ASDCP_SUCCESS(result) ) + { + IndexByteCount = FooterBuffer.Size(); + UL FooterUL(m_Dict->ul(MDD_CompleteFooter)); + result = Partition::WriteToFile(Writer, FooterUL); + } + + if ( ASDCP_SUCCESS(result) ) + { + ui32_t write_count = 0; + result = Writer.Write(FooterBuffer.RoData(), FooterBuffer.Size(), &write_count); + assert(write_count == FooterBuffer.Size()); + } + + return result; +} + +// +void +ASDCP::MXF::OPAtomIndexFooter::Dump(FILE* stream) +{ + if ( stream == 0 ) + stream = stderr; + + Partition::Dump(stream); + + std::list<InterchangeObject*>::iterator i = m_PacketList->m_List.begin(); + for ( ; i != m_PacketList->m_List.end(); i++ ) + (*i)->Dump(stream); +} + +ASDCP::Result_t +ASDCP::MXF::OPAtomIndexFooter::GetMDObjectByID(const UUID& ObjectID, InterchangeObject** Object) +{ + return m_PacketList->GetMDObjectByID(ObjectID, Object); +} + +// +ASDCP::Result_t +ASDCP::MXF::OPAtomIndexFooter::GetMDObjectByType(const byte_t* ObjectID, InterchangeObject** Object) +{ + InterchangeObject* TmpObject; + + if ( Object == 0 ) + Object = &TmpObject; + + return m_PacketList->GetMDObjectByType(ObjectID, Object); +} + +// +ASDCP::Result_t +ASDCP::MXF::OPAtomIndexFooter::GetMDObjectsByType(const byte_t* ObjectID, std::list<InterchangeObject*>& ObjectList) +{ + return m_PacketList->GetMDObjectsByType(ObjectID, ObjectList); +} + +// +ASDCP::Result_t +ASDCP::MXF::OPAtomIndexFooter::Lookup(ui32_t frame_num, IndexTableSegment::IndexEntry& Entry) const +{ + std::list<InterchangeObject*>::iterator li; + for ( li = m_PacketList->m_List.begin(); li != m_PacketList->m_List.end(); li++ ) + { + if ( (*li)->IsA(OBJ_TYPE_ARGS(IndexTableSegment)) ) + { + IndexTableSegment* Segment = (IndexTableSegment*)(*li); + ui64_t start_pos = Segment->IndexStartPosition; + + if ( Segment->EditUnitByteCount > 0 ) + { + if ( m_PacketList->m_List.size() > 1 ) + DefaultLogSink().Error("Unexpected multiple IndexTableSegment in CBR file\n"); + + if ( ! Segment->IndexEntryArray.empty() ) + DefaultLogSink().Error("Unexpected IndexEntryArray contents in CBR file\n"); + + Entry.StreamOffset = (ui64_t)frame_num * Segment->EditUnitByteCount; + return RESULT_OK; + } + else if ( (ui64_t)frame_num >= start_pos + && (ui64_t)frame_num < (start_pos + Segment->IndexDuration) ) + { + ui64_t tmp = frame_num - start_pos; + assert(tmp <= 0xFFFFFFFFL); + Entry = Segment->IndexEntryArray[(ui32_t) tmp]; + return RESULT_OK; + } + } + } + + return RESULT_FAIL; +} + +// +void +ASDCP::MXF::OPAtomIndexFooter::SetIndexParamsCBR(IPrimerLookup* lookup, ui32_t size, const Rational& Rate) +{ + assert(lookup); + m_Lookup = lookup; + m_BytesPerEditUnit = size; + m_EditRate = Rate; + + IndexTableSegment* Index = new IndexTableSegment(m_Dict); + AddChildObject(Index); + Index->EditUnitByteCount = m_BytesPerEditUnit; + Index->IndexEditRate = Rate; +} + +// +void +ASDCP::MXF::OPAtomIndexFooter::SetIndexParamsVBR(IPrimerLookup* lookup, const Rational& Rate, Kumu::fpos_t offset) +{ + assert(lookup); + m_Lookup = lookup; + m_BytesPerEditUnit = 0; + m_EditRate = Rate; + m_ECOffset = offset; +} + +// +void +ASDCP::MXF::OPAtomIndexFooter::PushIndexEntry(const IndexTableSegment::IndexEntry& Entry) +{ + if ( m_BytesPerEditUnit != 0 ) // are we CBR? that's bad + { + DefaultLogSink().Error("Call to PushIndexEntry() failed: index is CBR\n"); + return; + } + + // do we have an available segment? + if ( m_CurrentSegment == 0 ) + { // no, set up a new segment + m_CurrentSegment = new IndexTableSegment(m_Dict); + assert(m_CurrentSegment); + AddChildObject(m_CurrentSegment); + m_CurrentSegment->DeltaEntryArray.push_back(IndexTableSegment::DeltaEntry()); + m_CurrentSegment->IndexEditRate = m_EditRate; + m_CurrentSegment->IndexStartPosition = 0; + } + else if ( m_CurrentSegment->IndexEntryArray.size() >= CBRIndexEntriesPerSegment ) + { // no, this one is full, start another + m_CurrentSegment->IndexDuration = m_CurrentSegment->IndexEntryArray.size(); + ui64_t StartPosition = m_CurrentSegment->IndexStartPosition + m_CurrentSegment->IndexDuration; + + m_CurrentSegment = new IndexTableSegment(m_Dict); + assert(m_CurrentSegment); + AddChildObject(m_CurrentSegment); + m_CurrentSegment->DeltaEntryArray.push_back(IndexTableSegment::DeltaEntry()); + m_CurrentSegment->IndexEditRate = m_EditRate; + m_CurrentSegment->IndexStartPosition = StartPosition; + } + + m_CurrentSegment->IndexEntryArray.push_back(Entry); +} + +//------------------------------------------------------------------------------------------ +// + +// +void +ASDCP::MXF::InterchangeObject::Copy(const InterchangeObject& rhs) +{ + m_UL = rhs.m_UL; + InstanceUID = rhs.InstanceUID; + GenerationUID = rhs.GenerationUID; +} + +// +ASDCP::Result_t +ASDCP::MXF::InterchangeObject::InitFromTLVSet(TLVReader& TLVSet) +{ + Result_t result = TLVSet.ReadObject(OBJ_READ_ARGS(InterchangeObject, InstanceUID)); + if ( ASDCP_SUCCESS(result) ) + result = TLVSet.ReadObject(OBJ_READ_ARGS(GenerationInterchangeObject, GenerationUID)); + return result; +} + +// +ASDCP::Result_t +ASDCP::MXF::InterchangeObject::WriteToTLVSet(TLVWriter& TLVSet) +{ + Result_t result = TLVSet.WriteObject(OBJ_WRITE_ARGS(InterchangeObject, InstanceUID)); + if ( ASDCP_SUCCESS(result) ) + result = TLVSet.WriteObject(OBJ_WRITE_ARGS(GenerationInterchangeObject, GenerationUID)); + return result; +} + +// +ASDCP::Result_t +ASDCP::MXF::InterchangeObject::InitFromBuffer(const byte_t* p, ui32_t l) +{ + ASDCP_TEST_NULL(p); + Result_t result = RESULT_FALSE; + + if ( m_UL.HasValue() ) + { + result = KLVPacket::InitFromBuffer(p, l, m_UL); + + if ( ASDCP_SUCCESS(result) ) + { + TLVReader MemRDR(m_ValueStart, m_ValueLength, m_Lookup); + result = InitFromTLVSet(MemRDR); + } + } + else + { + result = KLVPacket::InitFromBuffer(p, l); + } + + return result; +} + +// +ASDCP::Result_t +ASDCP::MXF::InterchangeObject::WriteToBuffer(ASDCP::FrameBuffer& Buffer) +{ + if ( ! m_UL.HasValue() ) + return RESULT_STATE; + + TLVWriter MemWRT(Buffer.Data() + kl_length, Buffer.Capacity() - kl_length, m_Lookup); + Result_t result = WriteToTLVSet(MemWRT); + + if ( ASDCP_SUCCESS(result) ) + { + ui32_t packet_length = MemWRT.Length(); + result = WriteKLToBuffer(Buffer, packet_length); + + if ( ASDCP_SUCCESS(result) ) + Buffer.Size(Buffer.Size() + packet_length); + } + + return result; +} + +// +void +ASDCP::MXF::InterchangeObject::Dump(FILE* stream) +{ + char identbuf[IdentBufferLen]; + + fputc('\n', stream); + KLVPacket::Dump(stream, *m_Dict, false); + fprintf(stream, " InstanceUID = %s\n", InstanceUID.EncodeHex(identbuf, IdentBufferLen)); + fprintf(stream, " GenerationUID = %s\n", GenerationUID.EncodeHex(identbuf, IdentBufferLen)); +} + +// +bool +ASDCP::MXF::InterchangeObject::IsA(const byte_t* label) +{ + if ( m_KLLength == 0 ) + return false; + + return ( memcmp(label, m_KeyStart, SMPTE_UL_LENGTH) == 0 ); +} + + +//------------------------------------------------------------------------------------------ + + +typedef std::map<ASDCP::UL, ASDCP::MXF::MXFObjectFactory_t>FactoryMap_t; +typedef FactoryMap_t::iterator FLi_t; + +// +class FactoryList : public FactoryMap_t +{ + Kumu::Mutex m_Lock; + +public: + FactoryList() {} + ~FactoryList() {} + + bool Empty() { + Kumu::AutoMutex BlockLock(m_Lock); + return empty(); + } + + FLi_t Find(const byte_t* label) { + Kumu::AutoMutex BlockLock(m_Lock); + return find(label); + } + + FLi_t End() { + Kumu::AutoMutex BlockLock(m_Lock); + return end(); + } + + void Insert(ASDCP::UL label, ASDCP::MXF::MXFObjectFactory_t factory) { + Kumu::AutoMutex BlockLock(m_Lock); + insert(FactoryList::value_type(label, factory)); + } +}; + +// +static FactoryList s_FactoryList; +static Kumu::Mutex s_InitLock; +static bool s_TypesInit = false; + + +// +void +ASDCP::MXF::SetObjectFactory(ASDCP::UL label, ASDCP::MXF::MXFObjectFactory_t factory) +{ + s_FactoryList.Insert(label, factory); +} + +// +ASDCP::MXF::InterchangeObject* +ASDCP::MXF::CreateObject(const Dictionary*& Dict, const UL& label) +{ + if ( ! s_TypesInit ) + { + Kumu::AutoMutex BlockLock(s_InitLock); + + if ( ! s_TypesInit ) + { + MXF::Metadata_InitTypes(Dict); + s_TypesInit = true; + } + } + + FLi_t i = s_FactoryList.find(label.Value()); + + if ( i == s_FactoryList.end() ) + return new InterchangeObject(Dict); + + return i->second(Dict); +} + + +// +// end MXF.cpp +// diff --git a/asdcplib/src/MXF.h b/asdcplib/src/MXF.h new file mode 100755 index 0000000..c170a2d --- /dev/null +++ b/asdcplib/src/MXF.h @@ -0,0 +1,410 @@ +/* +Copyright (c) 2005-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 MXF.h + \version $Id: MXF.h,v 1.42 2012/03/05 13:11:47 jhurst Exp $ + \brief MXF objects +*/ + +#ifndef _MXF_H_ +#define _MXF_H_ + +#include "MXFTypes.h" + +namespace ASDCP +{ + namespace MXF + { + class InterchangeObject; + + // + typedef ASDCP::MXF::InterchangeObject* (*MXFObjectFactory_t)(const Dictionary*&); + + // + void SetObjectFactory(UL label, MXFObjectFactory_t factory); + + // + InterchangeObject* CreateObject(const Dictionary*& Dict, const UL& label); + + + // seek an open file handle to the start of the RIP KLV packet + Result_t SeekToRIP(const Kumu::FileReader&); + + // + class RIP : public ASDCP::KLVFilePacket + { + ASDCP_NO_COPY_CONSTRUCT(RIP); + RIP(); + + public: + // + class Pair : public Kumu::IArchive + { + public: + ui32_t BodySID; + ui64_t ByteOffset; + + Pair() : BodySID(0), ByteOffset(0) {} + Pair(ui32_t sid, ui64_t offset) : BodySID(sid), ByteOffset(offset) {} + virtual ~Pair() {} + + ui32_t Size() { return sizeof(ui32_t) + sizeof(ui64_t); } + + inline const char* EncodeString(char* str_buf, ui32_t buf_len) const { + Kumu::ui64Printer offset_str(ByteOffset); + snprintf(str_buf, buf_len, "%-6u: %s", BodySID, offset_str.c_str()); + return str_buf; + } + + inline bool HasValue() const { return true; } + inline ui32_t ArchiveLength() const { return sizeof(ui32_t) + sizeof(ui64_t); } + + inline bool Unarchive(Kumu::MemIOReader* Reader) { + if ( ! Reader->ReadUi32BE(&BodySID) ) return false; + if ( ! Reader->ReadUi64BE(&ByteOffset) ) return false; + return true; + } + + inline bool Archive(Kumu::MemIOWriter* Writer) const { + if ( ! Writer->WriteUi32BE(BodySID) ) return false; + if ( ! Writer->WriteUi64BE(ByteOffset) ) return false; + return true; + } + }; + + const Dictionary*& m_Dict; + Array<Pair> PairArray; + + RIP(const Dictionary*& d) : m_Dict(d) {} + virtual ~RIP() {} + virtual Result_t InitFromFile(const Kumu::FileReader& Reader); + virtual Result_t WriteToFile(Kumu::FileWriter& Writer); + virtual Result_t GetPairBySID(ui32_t, Pair&) const; + virtual void Dump(FILE* = 0); + }; + + + // + class Partition : public ASDCP::KLVFilePacket + { + ASDCP_NO_COPY_CONSTRUCT(Partition); + Partition(); + + protected: + class h__PacketList; + mem_ptr<h__PacketList> m_PacketList; + + public: + const Dictionary*& m_Dict; + + ui16_t MajorVersion; + ui16_t MinorVersion; + ui32_t KAGSize; + ui64_t ThisPartition; + ui64_t PreviousPartition; + ui64_t FooterPartition; + ui64_t HeaderByteCount; + ui64_t IndexByteCount; + ui32_t IndexSID; + ui64_t BodyOffset; + ui32_t BodySID; + UL OperationalPattern; + Batch<UL> EssenceContainers; + + Partition(const Dictionary*&); + virtual ~Partition(); + virtual void AddChildObject(InterchangeObject*); // takes ownership + virtual Result_t InitFromFile(const Kumu::FileReader& Reader); + virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l); + virtual Result_t WriteToFile(Kumu::FileWriter& Writer, UL& PartitionLabel); + virtual ui32_t ArchiveSize(); // returns the size of the archived structure + virtual void Dump(FILE* = 0); + }; + + + // + class Primer : public ASDCP::KLVFilePacket, public ASDCP::IPrimerLookup + { + class h__PrimerLookup; + mem_ptr<h__PrimerLookup> m_Lookup; + ui8_t m_LocalTag; + ASDCP_NO_COPY_CONSTRUCT(Primer); + Primer(); + + public: + // + class LocalTagEntry : Kumu::IArchive + { + public: + TagValue Tag; + ASDCP::UL UL; + + LocalTagEntry() { Tag.a = Tag.b = 0; } + LocalTagEntry(const TagValue& tag, ASDCP::UL& ul) : Tag(tag), UL(ul) {} + + inline const char* EncodeString(char* str_buf, ui32_t buf_len) const { + snprintf(str_buf, buf_len, "%02x %02x: ", Tag.a, Tag.b); + UL.EncodeString(str_buf + strlen(str_buf), buf_len - strlen(str_buf)); + return str_buf; + } + + inline bool HasValue() const { return UL.HasValue(); } + inline ui32_t ArchiveLength() const { return 2 + UL.ArchiveLength(); } + + inline bool Unarchive(Kumu::MemIOReader* Reader) { + if ( ! Reader->ReadUi8(&Tag.a) ) return false; + if ( ! Reader->ReadUi8(&Tag.b) ) return false; + return UL.Unarchive(Reader); + } + + inline bool Archive(Kumu::MemIOWriter* Writer) const { + if ( ! Writer->WriteUi8(Tag.a) ) return false; + if ( ! Writer->WriteUi8(Tag.b) ) return false; + return UL.Archive(Writer); + } + }; + + Batch<LocalTagEntry> LocalTagEntryBatch; + const Dictionary*& m_Dict; + + Primer(const Dictionary*&); + virtual ~Primer(); + + virtual void ClearTagList(); + virtual Result_t InsertTag(const MDDEntry& Entry, ASDCP::TagValue& Tag); + virtual Result_t TagForKey(const ASDCP::UL& Key, ASDCP::TagValue& Tag); + + virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l); + virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&); + virtual Result_t WriteToFile(Kumu::FileWriter& Writer); + virtual void Dump(FILE* = 0); + }; + + + // + class InterchangeObject : public ASDCP::KLVPacket + { + InterchangeObject(); + + public: + const Dictionary*& m_Dict; + IPrimerLookup* m_Lookup; + UUID InstanceUID; + UUID GenerationUID; + + InterchangeObject(const Dictionary*& d) : m_Dict(d), m_Lookup(0) {} + virtual ~InterchangeObject() {} + + virtual void Copy(const InterchangeObject& rhs); + virtual Result_t InitFromTLVSet(TLVReader& TLVSet); + virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l); + virtual Result_t WriteToTLVSet(TLVWriter& TLVSet); + virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&); + virtual bool IsA(const byte_t* label); + virtual const char* ObjectName() { return "InterchangeObject"; } + virtual void Dump(FILE* stream = 0); + }; + + // + class Preface : public InterchangeObject + { + ASDCP_NO_COPY_CONSTRUCT(Preface); + Preface(); + + public: + const Dictionary*& m_Dict; + Kumu::Timestamp LastModifiedDate; + ui16_t Version; + ui32_t ObjectModelVersion; + UUID PrimaryPackage; + Batch<UUID> Identifications; + UUID ContentStorage; + UL OperationalPattern; + Batch<UL> EssenceContainers; + Batch<UL> DMSchemes; + + Preface(const Dictionary*& d); + virtual ~Preface() {} + + virtual void Copy(const Preface& rhs); + virtual Result_t InitFromTLVSet(TLVReader& TLVSet); + virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l); + virtual Result_t WriteToTLVSet(TLVWriter& TLVSet); + virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&); + virtual void Dump(FILE* = 0); + }; + + const ui32_t MaxIndexSegmentSize = 65536; + + // + class IndexTableSegment : public InterchangeObject + { + ASDCP_NO_COPY_CONSTRUCT(IndexTableSegment); + + public: + // + class DeltaEntry : public Kumu::IArchive + { + public: + i8_t PosTableIndex; + ui8_t Slice; + ui32_t ElementData; + + DeltaEntry() : PosTableIndex(-1), Slice(0), ElementData(0) {} + DeltaEntry(i8_t pos, ui8_t slice, ui32_t data) : PosTableIndex(pos), Slice(slice), ElementData(data) {} + inline bool HasValue() const { return true; } + ui32_t ArchiveLength() const { return sizeof(ui32_t) + 2; } + bool Unarchive(Kumu::MemIOReader* Reader); + bool Archive(Kumu::MemIOWriter* Writer) const; + const char* EncodeString(char* str_buf, ui32_t buf_len) const; + }; + + // + class IndexEntry : public Kumu::IArchive + { + public: + i8_t TemporalOffset; + i8_t KeyFrameOffset; + ui8_t Flags; + ui64_t StreamOffset; + + // if you use these, you will need to change CBRIndexEntriesPerSegment in MXF.cpp + // to a more suitable value + // std::list<ui32_t> SliceOffset; + // Array<Rational> PosTable; + + IndexEntry() : TemporalOffset(0), KeyFrameOffset(0), Flags(0), StreamOffset(0) {} + IndexEntry(i8_t t_ofst, i8_t k_ofst, ui8_t flags, ui64_t s_ofst) : + TemporalOffset(t_ofst), KeyFrameOffset(k_ofst), Flags(flags), StreamOffset(s_ofst) {} + inline bool HasValue() const { return true; } + ui32_t ArchiveLength() const { return sizeof(ui64_t) + 3; }; + bool Unarchive(Kumu::MemIOReader* Reader); + bool Archive(Kumu::MemIOWriter* Writer) const; + const char* EncodeString(char* str_buf, ui32_t buf_len) const; + }; + + const Dictionary*& m_Dict; + + Rational IndexEditRate; + ui64_t IndexStartPosition; + ui64_t IndexDuration; + ui32_t EditUnitByteCount; + ui32_t IndexSID; + ui32_t BodySID; + ui8_t SliceCount; + ui8_t PosTableCount; + Batch<DeltaEntry> DeltaEntryArray; + Batch<IndexEntry> IndexEntryArray; + + IndexTableSegment(const Dictionary*&); + virtual ~IndexTableSegment(); + + virtual void Copy(const IndexTableSegment& rhs); + virtual Result_t InitFromTLVSet(TLVReader& TLVSet); + virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l); + virtual Result_t WriteToTLVSet(TLVWriter& TLVSet); + virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&); + virtual void Dump(FILE* = 0); + }; + + //--------------------------------------------------------------------------------- + // + class Identification; + class SourcePackage; + + // + class OPAtomHeader : public Partition + { + ASDCP_NO_COPY_CONSTRUCT(OPAtomHeader); + OPAtomHeader(); + + public: + const Dictionary*& m_Dict; + ASDCP::MXF::RIP m_RIP; + ASDCP::MXF::Primer m_Primer; + Preface* m_Preface; + ASDCP::FrameBuffer m_Buffer; + bool m_HasRIP; + + OPAtomHeader(const Dictionary*&); + virtual ~OPAtomHeader(); + virtual Result_t InitFromFile(const Kumu::FileReader& Reader); + virtual Result_t InitFromPartitionBuffer(const byte_t* p, ui32_t l); + virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l); + virtual Result_t WriteToFile(Kumu::FileWriter& Writer, ui32_t HeaderLength = 16384); + virtual void Dump(FILE* = 0); + virtual Result_t GetMDObjectByID(const UUID&, InterchangeObject** = 0); + virtual Result_t GetMDObjectByType(const byte_t*, InterchangeObject** = 0); + virtual Result_t GetMDObjectsByType(const byte_t* ObjectID, std::list<InterchangeObject*>& ObjectList); + virtual ASDCP::MXF::RIP& GetRIP(); + Identification* GetIdentification(); + SourcePackage* GetSourcePackage(); + }; + + // + class OPAtomIndexFooter : public Partition + { + IndexTableSegment* m_CurrentSegment; + ASDCP::FrameBuffer m_Buffer; + ui32_t m_BytesPerEditUnit; + Rational m_EditRate; + ui32_t m_BodySID; + + ASDCP_NO_COPY_CONSTRUCT(OPAtomIndexFooter); + OPAtomIndexFooter(); + + public: + const Dictionary*& m_Dict; + Kumu::fpos_t m_ECOffset; + IPrimerLookup* m_Lookup; + + OPAtomIndexFooter(const Dictionary*&); + virtual ~OPAtomIndexFooter(); + virtual Result_t InitFromFile(const Kumu::FileReader& Reader); + virtual Result_t InitFromPartitionBuffer(const byte_t* p, ui32_t l); + virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l); + virtual Result_t WriteToFile(Kumu::FileWriter& Writer, ui64_t duration); + virtual void Dump(FILE* = 0); + + virtual Result_t GetMDObjectByID(const UUID&, InterchangeObject** = 0); + virtual Result_t GetMDObjectByType(const byte_t*, InterchangeObject** = 0); + virtual Result_t GetMDObjectsByType(const byte_t* ObjectID, std::list<InterchangeObject*>& ObjectList); + + virtual Result_t Lookup(ui32_t frame_num, IndexTableSegment::IndexEntry&) const; + virtual void PushIndexEntry(const IndexTableSegment::IndexEntry&); + virtual void SetIndexParamsCBR(IPrimerLookup* lookup, ui32_t size, const Rational& Rate); + virtual void SetIndexParamsVBR(IPrimerLookup* lookup, const Rational& Rate, Kumu::fpos_t offset); + }; + + } // namespace MXF +} // namespace ASDCP + + +#endif // _MXF_H_ + +// +// end MXF.h +// diff --git a/asdcplib/src/MXFTypes.cpp b/asdcplib/src/MXFTypes.cpp new file mode 100755 index 0000000..13bdaa0 --- /dev/null +++ b/asdcplib/src/MXFTypes.cpp @@ -0,0 +1,682 @@ +/* +Copyright (c) 2005-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 MXFTypes.cpp + \version $Id: MXFTypes.cpp,v 1.27 2012/02/21 02:09:31 jhurst Exp $ + \brief MXF objects +*/ + +#include <KM_prng.h> +#include <KM_tai.h> +#include "MXFTypes.h" +#include <KM_log.h> + +using Kumu::DefaultLogSink; + +//------------------------------------------------------------------------------------------ +// + +// +bool +ASDCP::UL::operator==(const UL& rhs) const +{ + if ( m_Value[0] == rhs.m_Value[0] && + m_Value[1] == rhs.m_Value[1] && + m_Value[2] == rhs.m_Value[2] && + m_Value[3] == rhs.m_Value[3] && + m_Value[4] == rhs.m_Value[4] && + m_Value[5] == rhs.m_Value[5] && + m_Value[6] == rhs.m_Value[6] && + // m_Value[7] == rhs.m_Value[7] && // version is ignored when performing lookups + m_Value[8] == rhs.m_Value[8] && + m_Value[9] == rhs.m_Value[9] && + m_Value[10] == rhs.m_Value[10] && + m_Value[11] == rhs.m_Value[11] && + m_Value[12] == rhs.m_Value[12] && + m_Value[13] == rhs.m_Value[13] && + m_Value[14] == rhs.m_Value[14] && + m_Value[15] == rhs.m_Value[15] + ) + return true; + + return false; +} + +// +bool +ASDCP::UL::MatchIgnoreStream(const UL& rhs) const +{ + if ( m_Value[0] == rhs.m_Value[0] && + m_Value[1] == rhs.m_Value[1] && + m_Value[2] == rhs.m_Value[2] && + m_Value[3] == rhs.m_Value[3] && + m_Value[4] == rhs.m_Value[4] && + m_Value[5] == rhs.m_Value[5] && + m_Value[6] == rhs.m_Value[6] && + // m_Value[7] == rhs.m_Value[7] && // version is ignored when performing lookups + m_Value[8] == rhs.m_Value[8] && + m_Value[9] == rhs.m_Value[9] && + m_Value[10] == rhs.m_Value[10] && + m_Value[11] == rhs.m_Value[11] && + m_Value[12] == rhs.m_Value[12] && + m_Value[13] == rhs.m_Value[13] && + m_Value[14] == rhs.m_Value[14] + // m_Value[15] == rhs.m_Value[15] // ignore stream number + ) + return true; + + return false; +} + +// +bool +ASDCP::UL::ExactMatch(const UL& rhs) const +{ + if ( m_Value[0] == rhs.m_Value[0] && + m_Value[1] == rhs.m_Value[1] && + m_Value[2] == rhs.m_Value[2] && + m_Value[3] == rhs.m_Value[3] && + m_Value[4] == rhs.m_Value[4] && + m_Value[5] == rhs.m_Value[5] && + m_Value[6] == rhs.m_Value[6] && + m_Value[7] == rhs.m_Value[7] && + m_Value[8] == rhs.m_Value[8] && + m_Value[9] == rhs.m_Value[9] && + m_Value[10] == rhs.m_Value[10] && + m_Value[11] == rhs.m_Value[11] && + m_Value[12] == rhs.m_Value[12] && + m_Value[13] == rhs.m_Value[13] && + m_Value[14] == rhs.m_Value[14] && + m_Value[15] == rhs.m_Value[15] + ) + return true; + + return false; +} + +const char* +ASDCP::UL::EncodeString(char* str_buf, ui32_t buf_len) const +{ + if ( buf_len > 38 ) // room for dotted notation? + { + snprintf(str_buf, buf_len, + "%02x%02x%02x%02x.%02x%02x.%02x%02x.%02x%02x%02x%02x.%02x%02x%02x%02x", + m_Value[0], m_Value[1], m_Value[2], m_Value[3], + m_Value[4], m_Value[5], m_Value[6], m_Value[7], + m_Value[8], m_Value[9], m_Value[10], m_Value[11], + m_Value[12], m_Value[13], m_Value[14], m_Value[15] + ); + + return str_buf; + } + else if ( buf_len > 32 ) // room for compact? + { + snprintf(str_buf, buf_len, + "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + m_Value[0], m_Value[1], m_Value[2], m_Value[3], + m_Value[4], m_Value[5], m_Value[6], m_Value[7], + m_Value[8], m_Value[9], m_Value[10], m_Value[11], + m_Value[12], m_Value[13], m_Value[14], m_Value[15] + ); + + return str_buf; + } + + return 0; +} + +// +void +ASDCP::UMID::MakeUMID(int Type) +{ + UUID AssetID; + Kumu::GenRandomValue(AssetID); + MakeUMID(Type, AssetID); +} + +// +void +ASDCP::UMID::MakeUMID(int Type, const UUID& AssetID) +{ + // Set the non-varying base of the UMID + static const byte_t UMIDBase[10] = { 0x06, 0x0a, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }; + memcpy(m_Value, UMIDBase, 10); + m_Value[10] = Type; // Material Type + m_Value[12] = 0x13; // length + + // preserved for compatibility with mfxlib + if( Type > 4 ) m_Value[7] = 5; + m_Value[11] = 0x20; // UUID/UL method, number gen undefined + + // Instance Number + m_Value[13] = m_Value[14] = m_Value[15] = 0; + + memcpy(&m_Value[16], AssetID.Value(), AssetID.Size()); + m_HasValue = true; +} + + +// Write the UMID value to the given buffer in the form +// [00000000.0000.0000.00000000],00,00,00,00,00000000.0000.0000.00000000.00000000] +// or +// [00000000.0000.0000.00000000],00,00,00,00,00000000-0000-0000-0000-000000000000] +// returns 0 if the buffer is smaller than DateTimeLen +const char* +ASDCP::UMID::EncodeString(char* str_buf, ui32_t buf_len) const +{ + assert(str_buf); + + snprintf(str_buf, buf_len, "[%02x%02x%02x%02x.%02x%02x.%02x%02x.%02x%02x%02x%02x],%02x,%02x,%02x,%02x,", + m_Value[0], m_Value[1], m_Value[2], m_Value[3], + m_Value[4], m_Value[5], m_Value[6], m_Value[7], + m_Value[8], m_Value[9], m_Value[10], m_Value[11], + m_Value[12], m_Value[13], m_Value[14], m_Value[15] + ); + + ui32_t offset = strlen(str_buf); + + if ( ( m_Value[8] & 0x80 ) == 0 ) + { + // half-swapped UL, use [bbaa9988.ddcc.ffee.00010203.04050607] + snprintf(str_buf + offset, buf_len - offset, + "[%02x%02x%02x%02x.%02x%02x.%02x%02x.%02x%02x%02x%02x.%02x%02x%02x%02x]", + m_Value[24], m_Value[25], m_Value[26], m_Value[27], + m_Value[28], m_Value[29], m_Value[30], m_Value[31], + m_Value[16], m_Value[17], m_Value[18], m_Value[19], + m_Value[20], m_Value[21], m_Value[22], m_Value[23] + ); + } + else + { + // UUID, use {00112233-4455-6677-8899-aabbccddeeff} + snprintf(str_buf + offset, buf_len - offset, + "{%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x}", + m_Value[16], m_Value[17], m_Value[18], m_Value[19], + m_Value[20], m_Value[21], m_Value[22], m_Value[23], + m_Value[24], m_Value[25], m_Value[26], m_Value[27], + m_Value[28], m_Value[29], m_Value[30], m_Value[31] + ); + } + + return str_buf; +} + +//------------------------------------------------------------------------------------------ +// + +// +const ASDCP::MXF::UTF16String& +ASDCP::MXF::UTF16String::operator=(const char* sz) +{ + if ( sz == 0 || *sz == 0 ) + erase(); + + else + this->assign(sz); + + return *this; +} + +// +const ASDCP::MXF::UTF16String& +ASDCP::MXF::UTF16String::operator=(const std::string& str) +{ + this->assign(str); + return *this; +} + +// +const char* +ASDCP::MXF::UTF16String::EncodeString(char* str_buf, ui32_t buf_len) const +{ + ui32_t write_len = Kumu::xmin(buf_len - 1, (ui32_t)size()); + strncpy(str_buf, c_str(), write_len); + str_buf[write_len] = 0; + return str_buf; +} + +// +bool +ASDCP::MXF::UTF16String::Unarchive(Kumu::MemIOReader* Reader) +{ + erase(); + const ui16_t* p = (ui16_t*)Reader->CurrentData(); + ui32_t length = Reader->Remainder() / 2; + char mb_buf[MB_LEN_MAX+1]; + + for ( ui32_t i = 0; i < length; i++ ) + { + int count = wctomb(mb_buf, KM_i16_BE(p[i])); + + if ( count == -1 ) + { + DefaultLogSink().Error("Unable to decode wide character 0x%04hx\n", p[i]); + return false; + } + + assert(count <= MB_LEN_MAX); + mb_buf[count] = 0; + this->append(mb_buf); + } + + Reader->SkipOffset(length*2); + return true; +} + +// +bool +ASDCP::MXF::UTF16String::Archive(Kumu::MemIOWriter* Writer) const +{ + if ( size() > IdentBufferLen ) + { + DefaultLogSink().Error("String length exceeds maximum %u bytes\n", IdentBufferLen); + return false; + } + + const char* mbp = c_str(); + wchar_t wcp; + ui32_t remainder = size(); + ui32_t length = size(); + ui32_t i = 0; + + while ( i < length ) + { + int count = mbtowc(&wcp, mbp+i, remainder); + + if ( count == -1 ) + { + DefaultLogSink().Error("Error decoding multi-byte sequence starting at offset %u\n", i); + return false; + } + else if ( count == 0 ) + break; + + bool result = Writer->WriteUi16BE((ui16_t)wcp); + + if ( result == false ) + { + DefaultLogSink().Error("No more space in memory IO writer\n"); + return false; + } + + i += count; + remainder -= count; + } + + return true; +} + +//------------------------------------------------------------------------------------------ +// + +// +const ASDCP::MXF::ISO8String& +ASDCP::MXF::ISO8String::operator=(const char* sz) +{ + if ( sz == 0 || *sz == 0 ) + erase(); + + else + this->assign(sz); + + return *this; +} + +// +const ASDCP::MXF::ISO8String& +ASDCP::MXF::ISO8String::operator=(const std::string& str) +{ + this->assign(str); + return *this; +} + +// +const char* +ASDCP::MXF::ISO8String::EncodeString(char* str_buf, ui32_t buf_len) const +{ + ui32_t write_len = Kumu::xmin(buf_len - 1, (ui32_t)size()); + strncpy(str_buf, c_str(), write_len); + str_buf[write_len] = 0; + return str_buf; +} + +// +bool +ASDCP::MXF::ISO8String::Unarchive(Kumu::MemIOReader* Reader) +{ + assign((char*)Reader->CurrentData(), Reader->Remainder()); + return true; +} + +// +bool +ASDCP::MXF::ISO8String::Archive(Kumu::MemIOWriter* Writer) const +{ + if ( size() > IdentBufferLen ) + { + DefaultLogSink().Error("String length exceeds maximum %u bytes\n", IdentBufferLen); + return false; + } + + return Writer->WriteString(*this); +} + +//------------------------------------------------------------------------------------------ +// + +ASDCP::MXF::TLVReader::TLVReader(const byte_t* p, ui32_t c, IPrimerLookup* PrimerLookup) : + MemIOReader(p, c), m_Lookup(PrimerLookup) +{ + Result_t result = RESULT_OK; + + while ( Remainder() > 0 && ASDCP_SUCCESS(result) ) + { + TagValue Tag; + ui16_t pkt_len = 0; + + if ( MemIOReader::ReadUi8(&Tag.a) ) + if ( MemIOReader::ReadUi8(&Tag.b) ) + if ( MemIOReader::ReadUi16BE(&pkt_len) ) + { + m_ElementMap.insert(TagMap::value_type(Tag, ItemInfo(m_size, pkt_len))); + if ( SkipOffset(pkt_len) ) + continue;; + } + + DefaultLogSink().Error("Malformed Set\n"); + m_ElementMap.clear(); + result = RESULT_KLV_CODING; + } +} + +// +bool +ASDCP::MXF::TLVReader::FindTL(const MDDEntry& Entry) +{ + if ( m_Lookup == 0 ) + { + DefaultLogSink().Error("No Lookup service\n"); + return false; + } + + TagValue TmpTag; + + if ( m_Lookup->TagForKey(Entry.ul, TmpTag) != RESULT_OK ) + { + if ( Entry.tag.a == 0 ) + { + // DefaultLogSink().Debug("No such UL in this TL list: %s (%02x %02x)\n", + // Entry.name, Entry.tag.a, Entry.tag.b); + return false; + } + + TmpTag = Entry.tag; + } + + TagMap::iterator e_i = m_ElementMap.find(TmpTag); + + if ( e_i != m_ElementMap.end() ) + { + m_size = (*e_i).second.first; + m_capacity = m_size + (*e_i).second.second; + return true; + } + + // DefaultLogSink().Debug("Not Found (%02x %02x): %s\n", TmpTag.a, TmpTag.b, Entry.name); + return false; +} + +// +ASDCP::Result_t +ASDCP::MXF::TLVReader::ReadObject(const MDDEntry& Entry, Kumu::IArchive* Object) +{ + ASDCP_TEST_NULL(Object); + + if ( FindTL(Entry) ) + { + if ( m_size < m_capacity ) // don't try to unarchive an empty item + return Object->Unarchive(this) ? RESULT_OK : RESULT_KLV_CODING; + } + + return RESULT_FALSE; +} + +// +ASDCP::Result_t +ASDCP::MXF::TLVReader::ReadUi8(const MDDEntry& Entry, ui8_t* value) +{ + ASDCP_TEST_NULL(value); + + if ( FindTL(Entry) ) + return MemIOReader::ReadUi8(value) ? RESULT_OK : RESULT_KLV_CODING; + + return RESULT_FALSE; +} + +// +ASDCP::Result_t +ASDCP::MXF::TLVReader::ReadUi16(const MDDEntry& Entry, ui16_t* value) +{ + ASDCP_TEST_NULL(value); + + if ( FindTL(Entry) ) + return MemIOReader::ReadUi16BE(value) ? RESULT_OK : RESULT_KLV_CODING; + + return RESULT_FALSE; +} + +// +ASDCP::Result_t +ASDCP::MXF::TLVReader::ReadUi32(const MDDEntry& Entry, ui32_t* value) +{ + ASDCP_TEST_NULL(value); + + if ( FindTL(Entry) ) + return MemIOReader::ReadUi32BE(value) ? RESULT_OK : RESULT_KLV_CODING; + + return RESULT_FALSE; +} + +// +ASDCP::Result_t +ASDCP::MXF::TLVReader::ReadUi64(const MDDEntry& Entry, ui64_t* value) +{ + ASDCP_TEST_NULL(value); + + if ( FindTL(Entry) ) + return MemIOReader::ReadUi64BE(value) ? RESULT_OK : RESULT_KLV_CODING; + + return RESULT_FALSE; +} + +//------------------------------------------------------------------------------------------ +// + +ASDCP::MXF::TLVWriter::TLVWriter(byte_t* p, ui32_t c, IPrimerLookup* PrimerLookup) : + MemIOWriter(p, c), m_Lookup(PrimerLookup) +{ + assert(c > 3); +} + +// +ASDCP::Result_t +ASDCP::MXF::TLVWriter::WriteTag(const MDDEntry& Entry) +{ + if ( m_Lookup == 0 ) + { + DefaultLogSink().Error("No Primer object available\n"); + return RESULT_FAIL; + } + + TagValue TmpTag; + + if ( m_Lookup->InsertTag(Entry, TmpTag) != RESULT_OK ) + { + DefaultLogSink().Error("No tag for entry %s\n", Entry.name); + return RESULT_FAIL; + } + + if ( ! MemIOWriter::WriteUi8(TmpTag.a) ) return RESULT_KLV_CODING; + if ( ! MemIOWriter::WriteUi8(TmpTag.b) ) return RESULT_KLV_CODING; + return RESULT_OK; +} + +// +ASDCP::Result_t +ASDCP::MXF::TLVWriter::WriteObject(const MDDEntry& Entry, Kumu::IArchive* Object) +{ + ASDCP_TEST_NULL(Object); + + if ( Entry.optional && ! Object->HasValue() ) + return RESULT_OK; + + Result_t result = WriteTag(Entry); + + if ( ASDCP_SUCCESS(result) ) + { + // write a temp length + byte_t* l_p = CurrentData(); + + if ( ! MemIOWriter::WriteUi16BE(0) ) return RESULT_KLV_CODING; + + ui32_t before = Length(); + if ( ! Object->Archive(this) ) return RESULT_KLV_CODING; + if ( (Length() - before) > 0xffffL ) return RESULT_KLV_CODING; + Kumu::i2p<ui16_t>(KM_i16_BE(Length() - before), l_p); + } + + return result; +} + +// +ASDCP::Result_t +ASDCP::MXF::TLVWriter::WriteUi8(const MDDEntry& Entry, ui8_t* value) +{ + ASDCP_TEST_NULL(value); + Result_t result = WriteTag(Entry); + + if ( ASDCP_SUCCESS(result) ) + { + if ( ! MemIOWriter::WriteUi16BE(sizeof(ui8_t)) ) return RESULT_KLV_CODING; + if ( ! MemIOWriter::WriteUi8(*value) ) return RESULT_KLV_CODING; + } + + return result; +} + +// +ASDCP::Result_t +ASDCP::MXF::TLVWriter::WriteUi16(const MDDEntry& Entry, ui16_t* value) +{ + ASDCP_TEST_NULL(value); + Result_t result = WriteTag(Entry); + + if ( KM_SUCCESS(result) ) + { + if ( ! MemIOWriter::WriteUi16BE(sizeof(ui16_t)) ) return RESULT_KLV_CODING; + if ( ! MemIOWriter::WriteUi16BE(*value) ) return RESULT_KLV_CODING; + } + + return result; +} + +// +ASDCP::Result_t +ASDCP::MXF::TLVWriter::WriteUi32(const MDDEntry& Entry, ui32_t* value) +{ + ASDCP_TEST_NULL(value); + Result_t result = WriteTag(Entry); + + if ( KM_SUCCESS(result) ) + { + if ( ! MemIOWriter::WriteUi16BE(sizeof(ui32_t)) ) return RESULT_KLV_CODING; + if ( ! MemIOWriter::WriteUi32BE(*value) ) return RESULT_KLV_CODING; + } + + return result; +} + +// +ASDCP::Result_t +ASDCP::MXF::TLVWriter::WriteUi64(const MDDEntry& Entry, ui64_t* value) +{ + ASDCP_TEST_NULL(value); + Result_t result = WriteTag(Entry); + + if ( KM_SUCCESS(result) ) + { + if ( ! MemIOWriter::WriteUi16BE(sizeof(ui64_t)) ) return RESULT_KLV_CODING; + if ( ! MemIOWriter::WriteUi64BE(*value) ) return RESULT_KLV_CODING; + } + + return result; +} + + +//---------------------------------------------------------------------------------------------------- +// + +ASDCP::MXF::Raw::Raw() +{ + Capacity(256); +} + +ASDCP::MXF::Raw::~Raw() +{ +} + +// +bool +ASDCP::MXF::Raw::Unarchive(Kumu::MemIOReader* Reader) +{ + ui32_t payload_size = Reader->Remainder(); + if ( payload_size == 0 ) return false; + if ( KM_FAILURE(Capacity(payload_size)) ) return false; + + memcpy(Data(), Reader->CurrentData(), payload_size); + Length(payload_size); + return true; +} + +// +bool +ASDCP::MXF::Raw::Archive(Kumu::MemIOWriter* Writer) const +{ + return Writer->WriteRaw(RoData(), Length()); +} + +// +const char* +ASDCP::MXF::Raw::EncodeString(char* str_buf, ui32_t buf_len) const +{ + *str_buf = 0; + Kumu::bin2hex(RoData(), Length(), str_buf, buf_len); + return str_buf; +} + +// +// end MXFTypes.cpp +// diff --git a/asdcplib/src/MXFTypes.h b/asdcplib/src/MXFTypes.h new file mode 100755 index 0000000..4ab6772 --- /dev/null +++ b/asdcplib/src/MXFTypes.h @@ -0,0 +1,409 @@ +/* +Copyright (c) 2005-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 MXFTypes.h + \version $Id: MXFTypes.h,v 1.29 2012/02/21 02:09:31 jhurst Exp $ + \brief MXF objects +*/ + +#ifndef _MXFTYPES_H_ +#define _MXFTYPES_H_ + +#include "KLV.h" +#include <list> +#include <vector> +#include <map> +#include <wchar.h> + +// used with TLVReader::Read* +// +// these are used below to manufacture arguments +#define OBJ_READ_ARGS(s,l) m_Dict->Type(MDD_##s##_##l), &l +#define OBJ_WRITE_ARGS(s,l) m_Dict->Type(MDD_##s##_##l), &l +#define OBJ_TYPE_ARGS(t) m_Dict->Type(MDD_##t).ul + + +namespace ASDCP +{ + namespace MXF + { + typedef std::pair<ui32_t, ui32_t> ItemInfo; + typedef std::map<TagValue, ItemInfo> TagMap; + + // + class TLVReader : public Kumu::MemIOReader + { + + TagMap m_ElementMap; + IPrimerLookup* m_Lookup; + + TLVReader(); + ASDCP_NO_COPY_CONSTRUCT(TLVReader); + bool FindTL(const MDDEntry&); + + public: + TLVReader(const byte_t* p, ui32_t c, IPrimerLookup* = 0); + Result_t ReadObject(const MDDEntry&, Kumu::IArchive*); + Result_t ReadUi8(const MDDEntry&, ui8_t*); + Result_t ReadUi16(const MDDEntry&, ui16_t*); + Result_t ReadUi32(const MDDEntry&, ui32_t*); + Result_t ReadUi64(const MDDEntry&, ui64_t*); + }; + + // + class TLVWriter : public Kumu::MemIOWriter + { + + TagMap m_ElementMap; + IPrimerLookup* m_Lookup; + + TLVWriter(); + ASDCP_NO_COPY_CONSTRUCT(TLVWriter); + Result_t WriteTag(const MDDEntry&); + + public: + TLVWriter(byte_t* p, ui32_t c, IPrimerLookup* = 0); + Result_t WriteObject(const MDDEntry&, Kumu::IArchive*); + Result_t WriteUi8(const MDDEntry&, ui8_t*); + Result_t WriteUi16(const MDDEntry&, ui16_t*); + Result_t WriteUi32(const MDDEntry&, ui32_t*); + Result_t WriteUi64(const MDDEntry&, ui64_t*); + }; + + // + template <class T> + class Batch : public std::vector<T>, public Kumu::IArchive + { + public: + Batch() {} + ~Batch() {} + + // + virtual bool Unarchive(Kumu::MemIOReader* Reader) { + ui32_t ItemCount, ItemSize; + if ( ! Reader->ReadUi32BE(&ItemCount) ) return false; + if ( ! Reader->ReadUi32BE(&ItemSize) ) return false; + + if ( ( ItemCount > 65536 ) || ( ItemSize > 1024 ) ) + return false; + + bool result = true; + for ( ui32_t i = 0; i < ItemCount && result; i++ ) + { + T Tmp; + result = Tmp.Unarchive(Reader); + + if ( result ) + this->push_back(Tmp); + } + + return result; + } + + inline virtual bool HasValue() const { return ! this->empty(); } + + virtual ui32_t ArchiveLength() const { + ui32_t arch_size = sizeof(ui32_t)*2; + + typename std::vector<T>::const_iterator l_i = this->begin(); + assert(l_i != this->end()); + + for ( ; l_i != this->end(); l_i++ ) + arch_size += l_i->ArchiveLength(); + + return arch_size; + } + + // + virtual bool Archive(Kumu::MemIOWriter* Writer) const { + if ( ! Writer->WriteUi32BE(this->size()) ) return false; + byte_t* p = Writer->CurrentData(); + + if ( ! Writer->WriteUi32BE(0) ) return false; + if ( this->empty() ) return true; + + typename std::vector<T>::const_iterator l_i = this->begin(); + assert(l_i != this->end()); + + ui32_t ItemSize = Writer->Remainder(); + if ( ! (*l_i).Archive(Writer) ) return false; + ItemSize -= Writer->Remainder(); + Kumu::i2p<ui32_t>(KM_i32_BE(ItemSize), p); + l_i++; + + bool result = true; + for ( ; l_i != this->end() && result; l_i++ ) + result = (*l_i).Archive(Writer); + + return result; + } + + // + void Dump(FILE* stream = 0, ui32_t = 0) + { + char identbuf[IdentBufferLen]; + + if ( stream == 0 ) + stream = stderr; + + typename std::vector<T>::iterator i = this->begin(); + for ( ; i != this->end(); i++ ) + fprintf(stream, " %s\n", (*i).EncodeString(identbuf, IdentBufferLen)); + } + }; + + // + template <class T> + class Array : public std::list<T>, public Kumu::IArchive + { + public: + Array() {} + ~Array() {} + + // + virtual bool Unarchive(Kumu::MemIOReader* Reader) + { + bool result = true; + + while ( Reader->Remainder() > 0 && result ) + { + T Tmp; + result = Tmp.Unarchive(Reader); + this->push_back(Tmp); + } + + return result; + } + + inline virtual bool HasValue() const { return ! this->empty(); } + + virtual ui32_t ArchiveLength() const { + ui32_t arch_size = 0; + + typename std::list<T>::const_iterator l_i = this->begin(); + + for ( ; l_i != this->end(); l_i++ ) + arch_size += l_i->ArchiveLength(); + + return arch_size; + } + + // + virtual bool Archive(Kumu::MemIOWriter* Writer) const { + bool result = true; + typename std::list<T>::const_iterator l_i = this->begin(); + + for ( ; l_i != this->end() && result; l_i++ ) + result = (*l_i).Archive(Writer); + + return result; + } + + // + void Dump(FILE* stream = 0, ui32_t = 0) + { + char identbuf[IdentBufferLen]; + + if ( stream == 0 ) + stream = stderr; + + typename std::list<T>::iterator i = this->begin(); + for ( ; i != this->end(); i++ ) + fprintf(stream, " %s\n", (*i).EncodeString(identbuf, IdentBufferLen)); + } + }; + + // + class ISO8String : public std::string, public Kumu::IArchive + { + public: + ISO8String() {} + ~ISO8String() {} + + const ISO8String& operator=(const char*); + const ISO8String& operator=(const std::string&); + + const char* EncodeString(char* str_buf, ui32_t buf_len) const; + inline virtual bool HasValue() const { return ! empty(); } + inline virtual ui32_t ArchiveLength() const { return sizeof(ui32_t) + size(); } + virtual bool Unarchive(Kumu::MemIOReader* Reader); + virtual bool Archive(Kumu::MemIOWriter* Writer) const; + }; + + // + class UTF16String : public std::string, public Kumu::IArchive + { + public: + UTF16String() {} + ~UTF16String() {} + + const UTF16String& operator=(const char*); + const UTF16String& operator=(const std::string&); + + const char* EncodeString(char* str_buf, ui32_t buf_len) const; + inline virtual bool HasValue() const { return ! empty(); } + inline virtual ui32_t ArchiveLength() const { return sizeof(ui32_t) + size(); } + virtual bool Unarchive(Kumu::MemIOReader* Reader); + virtual bool Archive(Kumu::MemIOWriter* Writer) const; + }; + + // + class Rational : public ASDCP::Rational, public Kumu::IArchive + { + public: + Rational() {} + ~Rational() {} + + Rational(const Rational& rhs) : ASDCP::Rational(), IArchive() { + Numerator = rhs.Numerator; + Denominator = rhs.Denominator; + } + + const Rational& operator=(const Rational& rhs) { + Numerator = rhs.Numerator; + Denominator = rhs.Denominator; + return *this; + } + + Rational(const ASDCP::Rational& rhs) { + Numerator = rhs.Numerator; + Denominator = rhs.Denominator; + } + + const Rational& operator=(const ASDCP::Rational& rhs) { + Numerator = rhs.Numerator; + Denominator = rhs.Denominator; + return *this; + } + + // + inline const char* EncodeString(char* str_buf, ui32_t buf_len) const { + snprintf(str_buf, buf_len, "%d/%d", Numerator, Denominator); + return str_buf; + } + + inline virtual bool Unarchive(Kumu::MemIOReader* Reader) { + if ( ! Reader->ReadUi32BE((ui32_t*)&Numerator) ) return false; + if ( ! Reader->ReadUi32BE((ui32_t*)&Denominator) ) return false; + return true; + } + + inline virtual bool HasValue() const { return true; } + inline virtual ui32_t ArchiveLength() const { return sizeof(ui32_t)*2; } + + inline virtual bool Archive(Kumu::MemIOWriter* Writer) const { + if ( ! Writer->WriteUi32BE((ui32_t)Numerator) ) return false; + if ( ! Writer->WriteUi32BE((ui32_t)Denominator) ) return false; + return true; + } + }; + + // + class VersionType : public Kumu::IArchive + { + public: + enum Release_t { RL_UNKNOWN, RL_RELEASE, RL_DEVELOPMENT, RL_PATCHED, RL_BETA, RL_PRIVATE }; + ui16_t Major; + ui16_t Minor; + ui16_t Patch; + ui16_t Build; + Release_t Release; + + VersionType() : Major(0), Minor(0), Patch(0), Build(0), Release(RL_UNKNOWN) {} + VersionType(const VersionType& rhs) { Copy(rhs); } + virtual ~VersionType() {} + + const VersionType& operator=(const VersionType& rhs) { Copy(rhs); return *this; } + void Copy(const VersionType& rhs) { + Major = rhs.Major; + Minor = rhs.Minor; + Patch = rhs.Patch; + Build = rhs.Build; + Release = rhs.Release; + } + + void Dump(FILE* = 0); + + const char* EncodeString(char* str_buf, ui32_t buf_len) const { + snprintf(str_buf, buf_len, "%hu.%hu.%hu.%hur%hu", Major, Minor, Patch, Build, Release); + return str_buf; + } + + virtual bool Unarchive(Kumu::MemIOReader* Reader) { + if ( ! Reader->ReadUi16BE(&Major) ) return false; + if ( ! Reader->ReadUi16BE(&Minor) ) return false; + if ( ! Reader->ReadUi16BE(&Patch) ) return false; + if ( ! Reader->ReadUi16BE(&Build) ) return false; + ui16_t tmp_release; + if ( ! Reader->ReadUi16BE(&tmp_release) ) return false; + Release = (Release_t)tmp_release; + return true; + } + + inline virtual bool HasValue() const { return true; } + inline virtual ui32_t ArchiveLength() const { return sizeof(ui16_t)*5; } + + virtual bool Archive(Kumu::MemIOWriter* Writer) const { + if ( ! Writer->WriteUi16BE(Major) ) return false; + if ( ! Writer->WriteUi16BE(Minor) ) return false; + if ( ! Writer->WriteUi16BE(Patch) ) return false; + if ( ! Writer->WriteUi16BE(Build) ) return false; + if ( ! Writer->WriteUi16BE((ui16_t)(Release & 0x0000ffffL)) ) return false; + return true; + } + }; + + // + class Raw : public Kumu::ByteString + { + public: + Raw(); + Raw(const Raw& rhs) : Kumu::ByteString () { Copy(rhs); } + virtual ~Raw(); + + const Raw& operator=(const Raw& rhs) { Copy(rhs); return *this; } + void Copy(const Raw& rhs) { + if ( KM_SUCCESS(Capacity(rhs.Length())) ) + { + Set(rhs); + } + } + + // + virtual bool Unarchive(Kumu::MemIOReader* Reader); + virtual bool Archive(Kumu::MemIOWriter* Writer) const; + const char* EncodeString(char* str_buf, ui32_t buf_len) const; + }; + + } // namespace MXF +} // namespace ASDCP + + +#endif //_MXFTYPES_H_ + +// +// end MXFTypes.h +// diff --git a/asdcplib/src/Makefile.am b/asdcplib/src/Makefile.am new file mode 100644 index 0000000..85c1e9f --- /dev/null +++ b/asdcplib/src/Makefile.am @@ -0,0 +1,249 @@ +## Makefile.am -- Process this file with automake to produce Makefile.in +# +# $Id: Makefile.am,v 1.53 2012/02/05 21:30:18 jhurst Exp $ +# Copyright (c) 2007-2011 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. + +# Allow for configure's changes to this makefile +AM_CPPFLAGS = +AM_LDFLAGS = + +if OPENBSD_HOST +AM_CPPFLAGS += -I/var/local/include -I/usr/local/include +AM_LDFLAGS += -L./.libs -L/var/local/lib -L/usr/local/lib +endif + +if ENABLE_RANDOM_UUID +AM_CPPFLAGS += -DCONFIG_RANDOM_UUID +endif + +# list of all the header files that should be installed +include_HEADERS = KM_error.h KM_fileio.h KM_log.h KM_memio.h KM_mutex.h \ + KM_platform.h KM_prng.h KM_util.h KM_tai.h KM_xml.h AS_DCP.h +if DEV_HEADERS +include_HEADERS += S12MTimecode.h MDD.h Metadata.h KLV.h MXFTypes.h MXF.h Wav.h \ + PCMParserList.h +nodist_include_HEADERS = TimedText_Transform.h +endif + +# list of the libraries to build and install +lib_LTLIBRARIES = libkumu.la libasdcp.la +# sources for a library +libkumu_la_SOURCES = KM_error.h KM_fileio.cpp KM_fileio.h KM_log.cpp KM_log.h \ + KM_memio.h KM_mutex.h KM_platform.h KM_prng.cpp KM_prng.h KM_util.cpp \ + KM_util.h KM_xml.cpp KM_xml.h KM_tai.h KM_tai.cpp + +# linker flags (*not* including libraries to link against) for a library +libkumu_la_LDFLAGS = -release @VERSION@ + +# sources for a library that don't get added to a distribution +nodist_libasdcp_la_SOURCES = Metadata_h.tt2 Metadata_cpp.tt2 \ + mxfgen.pl MXF_def.pl ullist.pl ULList.xml dict.xml DMS_Crypto.xml + +libasdcp_la_SOURCES = MPEG2_Parser.cpp MPEG.cpp JP2K_Codestream_Parser.cpp \ + JP2K_Sequence_Parser.cpp JP2K.cpp PCM_Parser.cpp Wav.cpp \ + TimedText_Parser.cpp KLV.cpp Dict.cpp MXFTypes.cpp MXF.cpp \ + Index.cpp Metadata.cpp AS_DCP.cpp AS_DCP_MXF.cpp AS_DCP_AES.cpp \ + h__Reader.cpp h__Writer.cpp AS_DCP_MPEG2.cpp AS_DCP_JP2K.cpp \ + AS_DCP_PCM.cpp AS_DCP_TimedText.cpp PCMParserList.cpp \ + Wav.h WavFileWriter.h MXF.h Metadata.h \ + JP2K.h AS_DCP.h AS_DCP_internal.h KLV.h MPEG.h MXFTypes.h MDD.h \ + PCMParserList.h S12MTimecode.h MDD.cpp + +if DEV_HEADERS +nodist_libasdcp_la_SOURCES += TimedText_Transform.h TimedText_Transform.cpp +endif + +libasdcp_la_LDFLAGS = -release @VERSION@ + +# additional libraries to link against for a library +libasdcp_la_LIBADD = libkumu.la +libasdcp_la_CPPFLAGS = -DASDCP_PLATFORM=\"@host@\" + +# Python extension +if PYTHON_USE +lib_LTLIBRARIES += libpyasdcp.la +#### libnapali.la + +nodist_libpyasdcp_la_SOURCES = \ + kumu_python.cpp \ + kumu_python.h \ + asdcp_python.cpp \ + asdcp_python.h \ + asdcp_python_descriptor.cpp \ + asdcp_python_misc.cpp \ + asdcp_python_writerinfo.h \ + asdcp_wrappers.h \ + asdcp_python_mxf.cpp \ + asdcp_python_mxf_text.cpp \ + asdcp_python_mxf_metadata.cpp + +####nodist_libnapali_la_SOURCES = \ +#### napali_python.cpp napali_python.h + +libpyasdcp_la_CPPFLAGS = @PYTHON_CPPFLAGS@ +libpyasdcp_la_LDFLAGS = @PYTHON_LSPEC@ -release @VERSION@ +libpyasdcp_la_LIBADD = libkumu.la libasdcp.la + +####libnapali_la_CPPFLAGS = @PYTHON_CPPFLAGS@ +####libnapali_la_LDFLAGS = @PYTHON_LSPEC@ -release @VERSION@ +####libnapali_la_LIBADD = libkumu.la libasdcp.la + +pyexecdir = @PYTHON_EXECDIR@ +pyexec_includedir = $(PYTHON_PREFIX)/include/python$(PYTHON_SHORTVERSION) +nodist_pyexec_include_HEADERS = kumu_python.h asdcp_python.h asdcp_wrappers.h +pyexec_LTLIBRARIES = kumu.la asdcp.la +#### napali_python.h napali.la + +nodist_kumu_la_SOURCES = pykumu.cpp kumu_python.h +kumu_la_CPPFLAGS = @PYTHON_CPPFLAGS@ +kumu_la_LDFLAGS = @PYTHON_LSPEC@ -avoid-version -module +kumu_la_LIBADD = libpyasdcp.la + +nodist_asdcp_la_SOURCES = pyasdcp.cpp kumu_python.h asdcp_python.h asdcp_wrappers.h +asdcp_la_CPPFLAGS = @PYTHON_CPPFLAGS@ +asdcp_la_LDFLAGS = @PYTHON_LSPEC@ -avoid-version -module +asdcp_la_LIBADD = libpyasdcp.la + +####nodist_napali_la_SOURCES = pynapali.cpp kumu_python.h napali_python.h +####napali_la_CPPFLAGS = @PYTHON_CPPFLAGS@ +####napali_la_LDFLAGS = @PYTHON_LSPEC@ -avoid-version -module +####napali_la_LIBADD = libnapali.la libpyasdcp.la +endif + +# list of programs to be built and installed +bin_PROGRAMS = \ + asdcp-wrap asdcp-unwrap asdcp-util asdcp-info asdcp-test \ + j2c-test blackwave klvwalk wavesplit \ + kmfilegen kmrandgen kmuuidgen + +# sources and linkage for CLI utilities +asdcp_test_SOURCES = asdcp-test.cpp +asdcp_test_LDADD = libasdcp.la + +asdcp_wrap_SOURCES = asdcp-wrap.cpp +asdcp_wrap_LDADD = libasdcp.la + +asdcp_unwrap_SOURCES = asdcp-unwrap.cpp +asdcp_unwrap_LDADD = libasdcp.la + +asdcp_util_SOURCES = asdcp-util.cpp +asdcp_util_LDADD = libasdcp.la + +asdcp_info_SOURCES = asdcp-info.cpp +asdcp_info_LDADD = libasdcp.la + +kmfilegen_SOURCES = kmfilegen.cpp +kmfilegen_LDADD = libkumu.la + +kmrandgen_SOURCES = kmrandgen.cpp +kmrandgen_LDADD = libkumu.la + +kmuuidgen_SOURCES = kmuuidgen.cpp +kmuuidgen_LDADD = libkumu.la + +blackwave_SOURCES = blackwave.cpp +blackwave_LDADD = libasdcp.la + +klvwalk_SOURCES = klvwalk.cpp +klvwalk_LDADD = libasdcp.la + +wavesplit_SOURCES = wavesplit.cpp +wavesplit_LDADD = libasdcp.la + +j2c_test_SOURCES = j2c-test.cpp +j2c_test_LDADD = libasdcp.la + +# list of programs that need to be compiled for use in test suite +check_PROGRAMS = asdcp-mem-test path-test \ + fips-186-rng-test asdcp-version +if DEV_HEADERS +check_PROGRAMS += tt-xform +endif + +# sources for a test program +# list of libraries to link against for a test program +asdcp_mem_test_SOURCES = asdcp-mem-test.cpp +asdcp_mem_test_LDADD = libasdcp.la + +path_test_SOURCES = path-test.cpp +path_test_LDADD = libkumu.la + +fips_186_rng_test_SOURCES = fips-186-rng-test.cpp +fips_186_rng_test_LDADD = libasdcp.la + +asdcp_version_SOURCES = asdcp-version.cpp +asdcp_version_LDADD = libkumu.la + +if DEV_HEADERS +nodist_tt_xform_SOURCES = tt-xform.cpp +tt_xform_LDADD = libasdcp.la +endif + + +# list of test scripts to execute during "make check" +TESTS = rng-tst.sh gen-tst.sh \ + jp2k-tst.sh jp2k-crypt-tst.sh jp2k-stereo-tst.sh jp2k-stereo-crypt-tst.sh \ + wav-tst.sh wav-crypt-tst.sh mpeg-tst.sh mpeg-crypt-tst.sh + +# environment variables to pass to above tests +TESTS_ENVIRONMENT = BUILD_DIR="." TEST_FILES=../tests TEST_FILE_PREFIX=DCPd1-M1 \ + CRYPT_KEY=70e0de21c98fbd455ad5b8042edb41a6 CRYPT_KEY_B=aa2d05475d568cd52cb3415e65cba76f \ + JP2K_PREFIX=MM_2k_XYZ_ + +# files to include in the distribution that automake doesn't automatically include +EXTRA_DIST = fips-186-test-harness.pl $(TESTS) +if !FREEDIST +if DEV_HEADERS +EXTRA_DIST += $(nodist_libasdcp_la_SOURCES) $(nodist_tt_xform_SOURCES) +#### $(nodist_napali_la_SOURCES) $(nodist_libnapali_la_SOURCES) +endif +if PYTHON_USE +EXTRA_DIST += $(nodist_pyexec_include_HEADERS) $(nodist_libpyasdcp_la_SOURCES) $(nodist_kumu_la_SOURCES) $(nodist_asdcp_la_SOURCES) +#### $(nodist_napali_la_SOURCES) $(nodist_libnapali_la_SOURCES) +endif +endif + +# source files that are themselves built +BUILT_SOURCES = Metadata.h Metadata.cpp MDD.h MDD.cpp +# files to be removed with "make maintainer-clean" +MAINTAINERCLEANFILES = Metadata.h Metadata.cpp MDD.h MDD.cpp + +# build commands for built sources +# dependencies: $(srcdir)/ullist.pl $(srcdir)/ULList.xml $(srcdir)/dict.xml $(srcdir)/DMS_Crypto.xml +MDD.h: + $(srcdir)/ullist.pl $(srcdir)/ULList.xml $(srcdir)/dict.xml $(srcdir)/DMS_Crypto.xml > MDD.h +# dependencies: $(srcdir)/ullist.pl $(srcdir)/ULList.xml $(srcdir)/dict.xml $(srcdir)/DMS_Crypto.xml +MDD.cpp: + $(srcdir)/ullist.pl -s $(srcdir)/ULList.xml $(srcdir)/dict.xml $(srcdir)/DMS_Crypto.xml > MDD.cpp +# dependencies: $(srcdir)/Metadata_h.tt2 $(srcdir)/mxfgen.pl $(srcdir)/MXF_def.pl +Metadata.h: + $(srcdir)/mxfgen.pl $(srcdir)/MXF_def.pl $(srcdir)/Metadata_h.tt2 > Metadata.h +# dependencies: Metadata.h $(srcdir)/Metadata_cpp.tt2 +Metadata.cpp: + $(srcdir)/mxfgen.pl $(srcdir)/MXF_def.pl $(srcdir)/Metadata_cpp.tt2 > Metadata.cpp + +# +# +# diff --git a/asdcplib/src/Makefile.in b/asdcplib/src/Makefile.in new file mode 100644 index 0000000..f086f49 --- /dev/null +++ b/asdcplib/src/Makefile.in @@ -0,0 +1,1516 @@ +# Makefile.in generated by automake 1.11.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software +# Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# +# $Id: Makefile.am,v 1.53 2012/02/05 21:30:18 jhurst Exp $ +# Copyright (c) 2007-2011 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. + + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +@OPENBSD_HOST_TRUE@am__append_1 = -I/var/local/include -I/usr/local/include +@OPENBSD_HOST_TRUE@am__append_2 = -L./.libs -L/var/local/lib -L/usr/local/lib +@ENABLE_RANDOM_UUID_TRUE@am__append_3 = -DCONFIG_RANDOM_UUID +@DEV_HEADERS_TRUE@am__append_4 = S12MTimecode.h MDD.h Metadata.h KLV.h MXFTypes.h MXF.h Wav.h \ +@DEV_HEADERS_TRUE@ PCMParserList.h + +@DEV_HEADERS_TRUE@am__append_5 = TimedText_Transform.h TimedText_Transform.cpp + +# Python extension +@PYTHON_USE_TRUE@am__append_6 = libpyasdcp.la +bin_PROGRAMS = asdcp-wrap$(EXEEXT) asdcp-unwrap$(EXEEXT) \ + asdcp-util$(EXEEXT) asdcp-info$(EXEEXT) asdcp-test$(EXEEXT) \ + j2c-test$(EXEEXT) blackwave$(EXEEXT) klvwalk$(EXEEXT) \ + wavesplit$(EXEEXT) kmfilegen$(EXEEXT) kmrandgen$(EXEEXT) \ + kmuuidgen$(EXEEXT) +check_PROGRAMS = asdcp-mem-test$(EXEEXT) path-test$(EXEEXT) \ + fips-186-rng-test$(EXEEXT) asdcp-version$(EXEEXT) \ + $(am__EXEEXT_1) +@DEV_HEADERS_TRUE@am__append_7 = tt-xform +@DEV_HEADERS_TRUE@@FREEDIST_FALSE@am__append_8 = $(nodist_libasdcp_la_SOURCES) $(nodist_tt_xform_SOURCES) +#### $(nodist_napali_la_SOURCES) $(nodist_libnapali_la_SOURCES) +@FREEDIST_FALSE@@PYTHON_USE_TRUE@am__append_9 = $(nodist_pyexec_include_HEADERS) $(nodist_libpyasdcp_la_SOURCES) $(nodist_kumu_la_SOURCES) $(nodist_asdcp_la_SOURCES) +subdir = src +DIST_COMMON = $(am__include_HEADERS_DIST) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_expat.m4 \ + $(top_srcdir)/m4/ax_lib_openssl.m4 \ + $(top_srcdir)/m4/ax_lib_xerces.m4 \ + $(top_srcdir)/m4/az_python.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(pyexecdir)" \ + "$(DESTDIR)$(bindir)" "$(DESTDIR)$(includedir)" \ + "$(DESTDIR)$(includedir)" "$(DESTDIR)$(pyexec_includedir)" +LTLIBRARIES = $(lib_LTLIBRARIES) $(pyexec_LTLIBRARIES) +@PYTHON_USE_TRUE@asdcp_la_DEPENDENCIES = libpyasdcp.la +@PYTHON_USE_TRUE@nodist_asdcp_la_OBJECTS = asdcp_la-pyasdcp.lo +asdcp_la_OBJECTS = $(nodist_asdcp_la_OBJECTS) +asdcp_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ + $(CXXFLAGS) $(asdcp_la_LDFLAGS) $(LDFLAGS) -o $@ +@PYTHON_USE_TRUE@am_asdcp_la_rpath = -rpath $(pyexecdir) +@PYTHON_USE_TRUE@kumu_la_DEPENDENCIES = libpyasdcp.la +@PYTHON_USE_TRUE@nodist_kumu_la_OBJECTS = kumu_la-pykumu.lo +kumu_la_OBJECTS = $(nodist_kumu_la_OBJECTS) +kumu_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \ + $(kumu_la_LDFLAGS) $(LDFLAGS) -o $@ +@PYTHON_USE_TRUE@am_kumu_la_rpath = -rpath $(pyexecdir) +libasdcp_la_DEPENDENCIES = libkumu.la +am_libasdcp_la_OBJECTS = libasdcp_la-MPEG2_Parser.lo \ + libasdcp_la-MPEG.lo libasdcp_la-JP2K_Codestream_Parser.lo \ + libasdcp_la-JP2K_Sequence_Parser.lo libasdcp_la-JP2K.lo \ + libasdcp_la-PCM_Parser.lo libasdcp_la-Wav.lo \ + libasdcp_la-TimedText_Parser.lo libasdcp_la-KLV.lo \ + libasdcp_la-Dict.lo libasdcp_la-MXFTypes.lo libasdcp_la-MXF.lo \ + libasdcp_la-Index.lo libasdcp_la-Metadata.lo \ + libasdcp_la-AS_DCP.lo libasdcp_la-AS_DCP_MXF.lo \ + libasdcp_la-AS_DCP_AES.lo libasdcp_la-h__Reader.lo \ + libasdcp_la-h__Writer.lo libasdcp_la-AS_DCP_MPEG2.lo \ + libasdcp_la-AS_DCP_JP2K.lo libasdcp_la-AS_DCP_PCM.lo \ + libasdcp_la-AS_DCP_TimedText.lo libasdcp_la-PCMParserList.lo \ + libasdcp_la-MDD.lo +@DEV_HEADERS_TRUE@am__objects_1 = libasdcp_la-TimedText_Transform.lo +nodist_libasdcp_la_OBJECTS = $(am__objects_1) +libasdcp_la_OBJECTS = $(am_libasdcp_la_OBJECTS) \ + $(nodist_libasdcp_la_OBJECTS) +libasdcp_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ + $(CXXFLAGS) $(libasdcp_la_LDFLAGS) $(LDFLAGS) -o $@ +libkumu_la_LIBADD = +am_libkumu_la_OBJECTS = KM_fileio.lo KM_log.lo KM_prng.lo KM_util.lo \ + KM_xml.lo KM_tai.lo +libkumu_la_OBJECTS = $(am_libkumu_la_OBJECTS) +libkumu_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ + $(CXXFLAGS) $(libkumu_la_LDFLAGS) $(LDFLAGS) -o $@ +@PYTHON_USE_TRUE@libpyasdcp_la_DEPENDENCIES = libkumu.la libasdcp.la +@PYTHON_USE_TRUE@nodist_libpyasdcp_la_OBJECTS = \ +@PYTHON_USE_TRUE@ libpyasdcp_la-kumu_python.lo \ +@PYTHON_USE_TRUE@ libpyasdcp_la-asdcp_python.lo \ +@PYTHON_USE_TRUE@ libpyasdcp_la-asdcp_python_descriptor.lo \ +@PYTHON_USE_TRUE@ libpyasdcp_la-asdcp_python_misc.lo \ +@PYTHON_USE_TRUE@ libpyasdcp_la-asdcp_python_mxf.lo \ +@PYTHON_USE_TRUE@ libpyasdcp_la-asdcp_python_mxf_text.lo \ +@PYTHON_USE_TRUE@ libpyasdcp_la-asdcp_python_mxf_metadata.lo +libpyasdcp_la_OBJECTS = $(nodist_libpyasdcp_la_OBJECTS) +libpyasdcp_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ + $(CXXFLAGS) $(libpyasdcp_la_LDFLAGS) $(LDFLAGS) -o $@ +@PYTHON_USE_TRUE@am_libpyasdcp_la_rpath = -rpath $(libdir) +@DEV_HEADERS_TRUE@am__EXEEXT_1 = tt-xform$(EXEEXT) +PROGRAMS = $(bin_PROGRAMS) +am_asdcp_info_OBJECTS = asdcp-info.$(OBJEXT) +asdcp_info_OBJECTS = $(am_asdcp_info_OBJECTS) +asdcp_info_DEPENDENCIES = libasdcp.la +am_asdcp_mem_test_OBJECTS = asdcp-mem-test.$(OBJEXT) +asdcp_mem_test_OBJECTS = $(am_asdcp_mem_test_OBJECTS) +asdcp_mem_test_DEPENDENCIES = libasdcp.la +am_asdcp_test_OBJECTS = asdcp-test.$(OBJEXT) +asdcp_test_OBJECTS = $(am_asdcp_test_OBJECTS) +asdcp_test_DEPENDENCIES = libasdcp.la +am_asdcp_unwrap_OBJECTS = asdcp-unwrap.$(OBJEXT) +asdcp_unwrap_OBJECTS = $(am_asdcp_unwrap_OBJECTS) +asdcp_unwrap_DEPENDENCIES = libasdcp.la +am_asdcp_util_OBJECTS = asdcp-util.$(OBJEXT) +asdcp_util_OBJECTS = $(am_asdcp_util_OBJECTS) +asdcp_util_DEPENDENCIES = libasdcp.la +am_asdcp_version_OBJECTS = asdcp-version.$(OBJEXT) +asdcp_version_OBJECTS = $(am_asdcp_version_OBJECTS) +asdcp_version_DEPENDENCIES = libkumu.la +am_asdcp_wrap_OBJECTS = asdcp-wrap.$(OBJEXT) +asdcp_wrap_OBJECTS = $(am_asdcp_wrap_OBJECTS) +asdcp_wrap_DEPENDENCIES = libasdcp.la +am_blackwave_OBJECTS = blackwave.$(OBJEXT) +blackwave_OBJECTS = $(am_blackwave_OBJECTS) +blackwave_DEPENDENCIES = libasdcp.la +am_fips_186_rng_test_OBJECTS = fips-186-rng-test.$(OBJEXT) +fips_186_rng_test_OBJECTS = $(am_fips_186_rng_test_OBJECTS) +fips_186_rng_test_DEPENDENCIES = libasdcp.la +am_j2c_test_OBJECTS = j2c-test.$(OBJEXT) +j2c_test_OBJECTS = $(am_j2c_test_OBJECTS) +j2c_test_DEPENDENCIES = libasdcp.la +am_klvwalk_OBJECTS = klvwalk.$(OBJEXT) +klvwalk_OBJECTS = $(am_klvwalk_OBJECTS) +klvwalk_DEPENDENCIES = libasdcp.la +am_kmfilegen_OBJECTS = kmfilegen.$(OBJEXT) +kmfilegen_OBJECTS = $(am_kmfilegen_OBJECTS) +kmfilegen_DEPENDENCIES = libkumu.la +am_kmrandgen_OBJECTS = kmrandgen.$(OBJEXT) +kmrandgen_OBJECTS = $(am_kmrandgen_OBJECTS) +kmrandgen_DEPENDENCIES = libkumu.la +am_kmuuidgen_OBJECTS = kmuuidgen.$(OBJEXT) +kmuuidgen_OBJECTS = $(am_kmuuidgen_OBJECTS) +kmuuidgen_DEPENDENCIES = libkumu.la +am_path_test_OBJECTS = path-test.$(OBJEXT) +path_test_OBJECTS = $(am_path_test_OBJECTS) +path_test_DEPENDENCIES = libkumu.la +@DEV_HEADERS_TRUE@nodist_tt_xform_OBJECTS = tt-xform.$(OBJEXT) +tt_xform_OBJECTS = $(nodist_tt_xform_OBJECTS) +@DEV_HEADERS_TRUE@tt_xform_DEPENDENCIES = libasdcp.la +am_wavesplit_OBJECTS = wavesplit.$(OBJEXT) +wavesplit_OBJECTS = $(am_wavesplit_OBJECTS) +wavesplit_DEPENDENCIES = libasdcp.la +DEFAULT_INCLUDES = -I.@am__isrc@ +depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +LTCXXCOMPILE = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +CXXLD = $(CXX) +CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(nodist_asdcp_la_SOURCES) $(nodist_kumu_la_SOURCES) \ + $(libasdcp_la_SOURCES) $(nodist_libasdcp_la_SOURCES) \ + $(libkumu_la_SOURCES) $(nodist_libpyasdcp_la_SOURCES) \ + $(asdcp_info_SOURCES) $(asdcp_mem_test_SOURCES) \ + $(asdcp_test_SOURCES) $(asdcp_unwrap_SOURCES) \ + $(asdcp_util_SOURCES) $(asdcp_version_SOURCES) \ + $(asdcp_wrap_SOURCES) $(blackwave_SOURCES) \ + $(fips_186_rng_test_SOURCES) $(j2c_test_SOURCES) \ + $(klvwalk_SOURCES) $(kmfilegen_SOURCES) $(kmrandgen_SOURCES) \ + $(kmuuidgen_SOURCES) $(path_test_SOURCES) \ + $(nodist_tt_xform_SOURCES) $(wavesplit_SOURCES) +DIST_SOURCES = $(libasdcp_la_SOURCES) $(libkumu_la_SOURCES) \ + $(asdcp_info_SOURCES) $(asdcp_mem_test_SOURCES) \ + $(asdcp_test_SOURCES) $(asdcp_unwrap_SOURCES) \ + $(asdcp_util_SOURCES) $(asdcp_version_SOURCES) \ + $(asdcp_wrap_SOURCES) $(blackwave_SOURCES) \ + $(fips_186_rng_test_SOURCES) $(j2c_test_SOURCES) \ + $(klvwalk_SOURCES) $(kmfilegen_SOURCES) $(kmrandgen_SOURCES) \ + $(kmuuidgen_SOURCES) $(path_test_SOURCES) $(wavesplit_SOURCES) +am__include_HEADERS_DIST = KM_error.h KM_fileio.h KM_log.h KM_memio.h \ + KM_mutex.h KM_platform.h KM_prng.h KM_util.h KM_tai.h KM_xml.h \ + AS_DCP.h S12MTimecode.h MDD.h Metadata.h KLV.h MXFTypes.h \ + MXF.h Wav.h PCMParserList.h +HEADERS = $(include_HEADERS) $(nodist_include_HEADERS) \ + $(nodist_pyexec_include_HEADERS) +ETAGS = etags +CTAGS = ctags +am__tty_colors = \ +red=; grn=; lgn=; blu=; std= +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXPAT_CFLAGS = @EXPAT_CFLAGS@ +EXPAT_LDFLAGS = @EXPAT_LDFLAGS@ +EXPAT_VERSION = @EXPAT_VERSION@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OPENSSL_CPPFLAGS = @OPENSSL_CPPFLAGS@ +OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@ +OPENSSL_LIBS = @OPENSSL_LIBS@ +OPENSSL_VERSION = @OPENSSL_VERSION@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PYTHON = @PYTHON@ +PYTHON_CPPFLAGS = @PYTHON_CPPFLAGS@ +PYTHON_CSPEC = @PYTHON_CSPEC@ +PYTHON_EXECDIR = @PYTHON_EXECDIR@ +PYTHON_EXECPREFIX = @PYTHON_EXECPREFIX@ +PYTHON_LDFLAGS = @PYTHON_LDFLAGS@ +PYTHON_LSPEC = @PYTHON_LSPEC@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_SHORTVERSION = @PYTHON_SHORTVERSION@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +XERCES_CPPFLAGS = @XERCES_CPPFLAGS@ +XERCES_LDFLAGS = @XERCES_LDFLAGS@ +XERCES_LIBS = @XERCES_LIBS@ +XERCES_VERSION = @XERCES_VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ + +# Allow for configure's changes to this makefile +AM_CPPFLAGS = $(am__append_1) $(am__append_3) +AM_LDFLAGS = $(am__append_2) + +# list of all the header files that should be installed +include_HEADERS = KM_error.h KM_fileio.h KM_log.h KM_memio.h \ + KM_mutex.h KM_platform.h KM_prng.h KM_util.h KM_tai.h KM_xml.h \ + AS_DCP.h $(am__append_4) +@DEV_HEADERS_TRUE@nodist_include_HEADERS = TimedText_Transform.h + +# list of the libraries to build and install +lib_LTLIBRARIES = libkumu.la libasdcp.la $(am__append_6) +# sources for a library +libkumu_la_SOURCES = KM_error.h KM_fileio.cpp KM_fileio.h KM_log.cpp KM_log.h \ + KM_memio.h KM_mutex.h KM_platform.h KM_prng.cpp KM_prng.h KM_util.cpp \ + KM_util.h KM_xml.cpp KM_xml.h KM_tai.h KM_tai.cpp + + +# linker flags (*not* including libraries to link against) for a library +libkumu_la_LDFLAGS = -release @VERSION@ + +# sources for a library that don't get added to a distribution +nodist_libasdcp_la_SOURCES = Metadata_h.tt2 Metadata_cpp.tt2 mxfgen.pl \ + MXF_def.pl ullist.pl ULList.xml dict.xml DMS_Crypto.xml \ + $(am__append_5) +libasdcp_la_SOURCES = MPEG2_Parser.cpp MPEG.cpp JP2K_Codestream_Parser.cpp \ + JP2K_Sequence_Parser.cpp JP2K.cpp PCM_Parser.cpp Wav.cpp \ + TimedText_Parser.cpp KLV.cpp Dict.cpp MXFTypes.cpp MXF.cpp \ + Index.cpp Metadata.cpp AS_DCP.cpp AS_DCP_MXF.cpp AS_DCP_AES.cpp \ + h__Reader.cpp h__Writer.cpp AS_DCP_MPEG2.cpp AS_DCP_JP2K.cpp \ + AS_DCP_PCM.cpp AS_DCP_TimedText.cpp PCMParserList.cpp \ + Wav.h WavFileWriter.h MXF.h Metadata.h \ + JP2K.h AS_DCP.h AS_DCP_internal.h KLV.h MPEG.h MXFTypes.h MDD.h \ + PCMParserList.h S12MTimecode.h MDD.cpp + +libasdcp_la_LDFLAGS = -release @VERSION@ + +# additional libraries to link against for a library +libasdcp_la_LIBADD = libkumu.la +libasdcp_la_CPPFLAGS = -DASDCP_PLATFORM=\"@host@\" +#### libnapali.la +@PYTHON_USE_TRUE@nodist_libpyasdcp_la_SOURCES = \ +@PYTHON_USE_TRUE@ kumu_python.cpp \ +@PYTHON_USE_TRUE@ kumu_python.h \ +@PYTHON_USE_TRUE@ asdcp_python.cpp \ +@PYTHON_USE_TRUE@ asdcp_python.h \ +@PYTHON_USE_TRUE@ asdcp_python_descriptor.cpp \ +@PYTHON_USE_TRUE@ asdcp_python_misc.cpp \ +@PYTHON_USE_TRUE@ asdcp_python_writerinfo.h \ +@PYTHON_USE_TRUE@ asdcp_wrappers.h \ +@PYTHON_USE_TRUE@ asdcp_python_mxf.cpp \ +@PYTHON_USE_TRUE@ asdcp_python_mxf_text.cpp \ +@PYTHON_USE_TRUE@ asdcp_python_mxf_metadata.cpp + + +####nodist_libnapali_la_SOURCES = \ +#### napali_python.cpp napali_python.h +@PYTHON_USE_TRUE@libpyasdcp_la_CPPFLAGS = @PYTHON_CPPFLAGS@ +@PYTHON_USE_TRUE@libpyasdcp_la_LDFLAGS = @PYTHON_LSPEC@ -release @VERSION@ +@PYTHON_USE_TRUE@libpyasdcp_la_LIBADD = libkumu.la libasdcp.la + +####libnapali_la_CPPFLAGS = @PYTHON_CPPFLAGS@ +####libnapali_la_LDFLAGS = @PYTHON_LSPEC@ -release @VERSION@ +####libnapali_la_LIBADD = libkumu.la libasdcp.la +@PYTHON_USE_TRUE@pyexecdir = @PYTHON_EXECDIR@ +@PYTHON_USE_TRUE@pyexec_includedir = $(PYTHON_PREFIX)/include/python$(PYTHON_SHORTVERSION) +@PYTHON_USE_TRUE@nodist_pyexec_include_HEADERS = kumu_python.h asdcp_python.h asdcp_wrappers.h +@PYTHON_USE_TRUE@pyexec_LTLIBRARIES = kumu.la asdcp.la +#### napali_python.h napali.la +@PYTHON_USE_TRUE@nodist_kumu_la_SOURCES = pykumu.cpp kumu_python.h +@PYTHON_USE_TRUE@kumu_la_CPPFLAGS = @PYTHON_CPPFLAGS@ +@PYTHON_USE_TRUE@kumu_la_LDFLAGS = @PYTHON_LSPEC@ -avoid-version -module +@PYTHON_USE_TRUE@kumu_la_LIBADD = libpyasdcp.la +@PYTHON_USE_TRUE@nodist_asdcp_la_SOURCES = pyasdcp.cpp kumu_python.h asdcp_python.h asdcp_wrappers.h +@PYTHON_USE_TRUE@asdcp_la_CPPFLAGS = @PYTHON_CPPFLAGS@ +@PYTHON_USE_TRUE@asdcp_la_LDFLAGS = @PYTHON_LSPEC@ -avoid-version -module +@PYTHON_USE_TRUE@asdcp_la_LIBADD = libpyasdcp.la + +# sources and linkage for CLI utilities +asdcp_test_SOURCES = asdcp-test.cpp +asdcp_test_LDADD = libasdcp.la +asdcp_wrap_SOURCES = asdcp-wrap.cpp +asdcp_wrap_LDADD = libasdcp.la +asdcp_unwrap_SOURCES = asdcp-unwrap.cpp +asdcp_unwrap_LDADD = libasdcp.la +asdcp_util_SOURCES = asdcp-util.cpp +asdcp_util_LDADD = libasdcp.la +asdcp_info_SOURCES = asdcp-info.cpp +asdcp_info_LDADD = libasdcp.la +kmfilegen_SOURCES = kmfilegen.cpp +kmfilegen_LDADD = libkumu.la +kmrandgen_SOURCES = kmrandgen.cpp +kmrandgen_LDADD = libkumu.la +kmuuidgen_SOURCES = kmuuidgen.cpp +kmuuidgen_LDADD = libkumu.la +blackwave_SOURCES = blackwave.cpp +blackwave_LDADD = libasdcp.la +klvwalk_SOURCES = klvwalk.cpp +klvwalk_LDADD = libasdcp.la +wavesplit_SOURCES = wavesplit.cpp +wavesplit_LDADD = libasdcp.la +j2c_test_SOURCES = j2c-test.cpp +j2c_test_LDADD = libasdcp.la + +# sources for a test program +# list of libraries to link against for a test program +asdcp_mem_test_SOURCES = asdcp-mem-test.cpp +asdcp_mem_test_LDADD = libasdcp.la +path_test_SOURCES = path-test.cpp +path_test_LDADD = libkumu.la +fips_186_rng_test_SOURCES = fips-186-rng-test.cpp +fips_186_rng_test_LDADD = libasdcp.la +asdcp_version_SOURCES = asdcp-version.cpp +asdcp_version_LDADD = libkumu.la +@DEV_HEADERS_TRUE@nodist_tt_xform_SOURCES = tt-xform.cpp +@DEV_HEADERS_TRUE@tt_xform_LDADD = libasdcp.la + +# list of test scripts to execute during "make check" +TESTS = rng-tst.sh gen-tst.sh \ + jp2k-tst.sh jp2k-crypt-tst.sh jp2k-stereo-tst.sh jp2k-stereo-crypt-tst.sh \ + wav-tst.sh wav-crypt-tst.sh mpeg-tst.sh mpeg-crypt-tst.sh + + +# environment variables to pass to above tests +TESTS_ENVIRONMENT = BUILD_DIR="." TEST_FILES=../tests TEST_FILE_PREFIX=DCPd1-M1 \ + CRYPT_KEY=70e0de21c98fbd455ad5b8042edb41a6 CRYPT_KEY_B=aa2d05475d568cd52cb3415e65cba76f \ + JP2K_PREFIX=MM_2k_XYZ_ + + +# files to include in the distribution that automake doesn't automatically include +EXTRA_DIST = fips-186-test-harness.pl $(TESTS) $(am__append_8) \ + $(am__append_9) +#### $(nodist_napali_la_SOURCES) $(nodist_libnapali_la_SOURCES) + +# source files that are themselves built +BUILT_SOURCES = Metadata.h Metadata.cpp MDD.h MDD.cpp +# files to be removed with "make maintainer-clean" +MAINTAINERCLEANFILES = Metadata.h Metadata.cpp MDD.h MDD.cpp +all: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) all-am + +.SUFFIXES: +.SUFFIXES: .cpp .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +install-pyexecLTLIBRARIES: $(pyexec_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(pyexecdir)" || $(MKDIR_P) "$(DESTDIR)$(pyexecdir)" + @list='$(pyexec_LTLIBRARIES)'; test -n "$(pyexecdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pyexecdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pyexecdir)"; \ + } + +uninstall-pyexecLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(pyexec_LTLIBRARIES)'; test -n "$(pyexecdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pyexecdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pyexecdir)/$$f"; \ + done + +clean-pyexecLTLIBRARIES: + -test -z "$(pyexec_LTLIBRARIES)" || rm -f $(pyexec_LTLIBRARIES) + @list='$(pyexec_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +asdcp.la: $(asdcp_la_OBJECTS) $(asdcp_la_DEPENDENCIES) $(EXTRA_asdcp_la_DEPENDENCIES) + $(asdcp_la_LINK) $(am_asdcp_la_rpath) $(asdcp_la_OBJECTS) $(asdcp_la_LIBADD) $(LIBS) +kumu.la: $(kumu_la_OBJECTS) $(kumu_la_DEPENDENCIES) $(EXTRA_kumu_la_DEPENDENCIES) + $(kumu_la_LINK) $(am_kumu_la_rpath) $(kumu_la_OBJECTS) $(kumu_la_LIBADD) $(LIBS) +libasdcp.la: $(libasdcp_la_OBJECTS) $(libasdcp_la_DEPENDENCIES) $(EXTRA_libasdcp_la_DEPENDENCIES) + $(libasdcp_la_LINK) -rpath $(libdir) $(libasdcp_la_OBJECTS) $(libasdcp_la_LIBADD) $(LIBS) +libkumu.la: $(libkumu_la_OBJECTS) $(libkumu_la_DEPENDENCIES) $(EXTRA_libkumu_la_DEPENDENCIES) + $(libkumu_la_LINK) -rpath $(libdir) $(libkumu_la_OBJECTS) $(libkumu_la_LIBADD) $(LIBS) +libpyasdcp.la: $(libpyasdcp_la_OBJECTS) $(libpyasdcp_la_DEPENDENCIES) $(EXTRA_libpyasdcp_la_DEPENDENCIES) + $(libpyasdcp_la_LINK) $(am_libpyasdcp_la_rpath) $(libpyasdcp_la_OBJECTS) $(libpyasdcp_la_LIBADD) $(LIBS) +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p || test -f $$p1; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +clean-checkPROGRAMS: + @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +asdcp-info$(EXEEXT): $(asdcp_info_OBJECTS) $(asdcp_info_DEPENDENCIES) $(EXTRA_asdcp_info_DEPENDENCIES) + @rm -f asdcp-info$(EXEEXT) + $(CXXLINK) $(asdcp_info_OBJECTS) $(asdcp_info_LDADD) $(LIBS) +asdcp-mem-test$(EXEEXT): $(asdcp_mem_test_OBJECTS) $(asdcp_mem_test_DEPENDENCIES) $(EXTRA_asdcp_mem_test_DEPENDENCIES) + @rm -f asdcp-mem-test$(EXEEXT) + $(CXXLINK) $(asdcp_mem_test_OBJECTS) $(asdcp_mem_test_LDADD) $(LIBS) +asdcp-test$(EXEEXT): $(asdcp_test_OBJECTS) $(asdcp_test_DEPENDENCIES) $(EXTRA_asdcp_test_DEPENDENCIES) + @rm -f asdcp-test$(EXEEXT) + $(CXXLINK) $(asdcp_test_OBJECTS) $(asdcp_test_LDADD) $(LIBS) +asdcp-unwrap$(EXEEXT): $(asdcp_unwrap_OBJECTS) $(asdcp_unwrap_DEPENDENCIES) $(EXTRA_asdcp_unwrap_DEPENDENCIES) + @rm -f asdcp-unwrap$(EXEEXT) + $(CXXLINK) $(asdcp_unwrap_OBJECTS) $(asdcp_unwrap_LDADD) $(LIBS) +asdcp-util$(EXEEXT): $(asdcp_util_OBJECTS) $(asdcp_util_DEPENDENCIES) $(EXTRA_asdcp_util_DEPENDENCIES) + @rm -f asdcp-util$(EXEEXT) + $(CXXLINK) $(asdcp_util_OBJECTS) $(asdcp_util_LDADD) $(LIBS) +asdcp-version$(EXEEXT): $(asdcp_version_OBJECTS) $(asdcp_version_DEPENDENCIES) $(EXTRA_asdcp_version_DEPENDENCIES) + @rm -f asdcp-version$(EXEEXT) + $(CXXLINK) $(asdcp_version_OBJECTS) $(asdcp_version_LDADD) $(LIBS) +asdcp-wrap$(EXEEXT): $(asdcp_wrap_OBJECTS) $(asdcp_wrap_DEPENDENCIES) $(EXTRA_asdcp_wrap_DEPENDENCIES) + @rm -f asdcp-wrap$(EXEEXT) + $(CXXLINK) $(asdcp_wrap_OBJECTS) $(asdcp_wrap_LDADD) $(LIBS) +blackwave$(EXEEXT): $(blackwave_OBJECTS) $(blackwave_DEPENDENCIES) $(EXTRA_blackwave_DEPENDENCIES) + @rm -f blackwave$(EXEEXT) + $(CXXLINK) $(blackwave_OBJECTS) $(blackwave_LDADD) $(LIBS) +fips-186-rng-test$(EXEEXT): $(fips_186_rng_test_OBJECTS) $(fips_186_rng_test_DEPENDENCIES) $(EXTRA_fips_186_rng_test_DEPENDENCIES) + @rm -f fips-186-rng-test$(EXEEXT) + $(CXXLINK) $(fips_186_rng_test_OBJECTS) $(fips_186_rng_test_LDADD) $(LIBS) +j2c-test$(EXEEXT): $(j2c_test_OBJECTS) $(j2c_test_DEPENDENCIES) $(EXTRA_j2c_test_DEPENDENCIES) + @rm -f j2c-test$(EXEEXT) + $(CXXLINK) $(j2c_test_OBJECTS) $(j2c_test_LDADD) $(LIBS) +klvwalk$(EXEEXT): $(klvwalk_OBJECTS) $(klvwalk_DEPENDENCIES) $(EXTRA_klvwalk_DEPENDENCIES) + @rm -f klvwalk$(EXEEXT) + $(CXXLINK) $(klvwalk_OBJECTS) $(klvwalk_LDADD) $(LIBS) +kmfilegen$(EXEEXT): $(kmfilegen_OBJECTS) $(kmfilegen_DEPENDENCIES) $(EXTRA_kmfilegen_DEPENDENCIES) + @rm -f kmfilegen$(EXEEXT) + $(CXXLINK) $(kmfilegen_OBJECTS) $(kmfilegen_LDADD) $(LIBS) +kmrandgen$(EXEEXT): $(kmrandgen_OBJECTS) $(kmrandgen_DEPENDENCIES) $(EXTRA_kmrandgen_DEPENDENCIES) + @rm -f kmrandgen$(EXEEXT) + $(CXXLINK) $(kmrandgen_OBJECTS) $(kmrandgen_LDADD) $(LIBS) +kmuuidgen$(EXEEXT): $(kmuuidgen_OBJECTS) $(kmuuidgen_DEPENDENCIES) $(EXTRA_kmuuidgen_DEPENDENCIES) + @rm -f kmuuidgen$(EXEEXT) + $(CXXLINK) $(kmuuidgen_OBJECTS) $(kmuuidgen_LDADD) $(LIBS) +path-test$(EXEEXT): $(path_test_OBJECTS) $(path_test_DEPENDENCIES) $(EXTRA_path_test_DEPENDENCIES) + @rm -f path-test$(EXEEXT) + $(CXXLINK) $(path_test_OBJECTS) $(path_test_LDADD) $(LIBS) +tt-xform$(EXEEXT): $(tt_xform_OBJECTS) $(tt_xform_DEPENDENCIES) $(EXTRA_tt_xform_DEPENDENCIES) + @rm -f tt-xform$(EXEEXT) + $(CXXLINK) $(tt_xform_OBJECTS) $(tt_xform_LDADD) $(LIBS) +wavesplit$(EXEEXT): $(wavesplit_OBJECTS) $(wavesplit_DEPENDENCIES) $(EXTRA_wavesplit_DEPENDENCIES) + @rm -f wavesplit$(EXEEXT) + $(CXXLINK) $(wavesplit_OBJECTS) $(wavesplit_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/KM_fileio.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/KM_log.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/KM_prng.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/KM_tai.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/KM_util.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/KM_xml.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asdcp-info.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asdcp-mem-test.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asdcp-test.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asdcp-unwrap.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asdcp-util.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asdcp-version.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asdcp-wrap.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asdcp_la-pyasdcp.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blackwave.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fips-186-rng-test.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/j2c-test.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/klvwalk.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kmfilegen.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kmrandgen.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kmuuidgen.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kumu_la-pykumu.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libasdcp_la-AS_DCP.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libasdcp_la-AS_DCP_AES.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libasdcp_la-AS_DCP_JP2K.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libasdcp_la-AS_DCP_MPEG2.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libasdcp_la-AS_DCP_MXF.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libasdcp_la-AS_DCP_PCM.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libasdcp_la-AS_DCP_TimedText.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libasdcp_la-Dict.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libasdcp_la-Index.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libasdcp_la-JP2K.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libasdcp_la-JP2K_Codestream_Parser.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libasdcp_la-JP2K_Sequence_Parser.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libasdcp_la-KLV.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libasdcp_la-MDD.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libasdcp_la-MPEG.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libasdcp_la-MPEG2_Parser.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libasdcp_la-MXF.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libasdcp_la-MXFTypes.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libasdcp_la-Metadata.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libasdcp_la-PCMParserList.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libasdcp_la-PCM_Parser.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libasdcp_la-TimedText_Parser.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libasdcp_la-TimedText_Transform.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libasdcp_la-Wav.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libasdcp_la-h__Reader.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libasdcp_la-h__Writer.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpyasdcp_la-asdcp_python.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpyasdcp_la-asdcp_python_descriptor.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpyasdcp_la-asdcp_python_misc.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpyasdcp_la-asdcp_python_mxf.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpyasdcp_la-asdcp_python_mxf_metadata.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpyasdcp_la-asdcp_python_mxf_text.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpyasdcp_la-kumu_python.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/path-test.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tt-xform.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wavesplit.Po@am__quote@ + +.cpp.o: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< + +.cpp.obj: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.cpp.lo: +@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $< + +asdcp_la-pyasdcp.lo: pyasdcp.cpp +@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(asdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT asdcp_la-pyasdcp.lo -MD -MP -MF $(DEPDIR)/asdcp_la-pyasdcp.Tpo -c -o asdcp_la-pyasdcp.lo `test -f 'pyasdcp.cpp' || echo '$(srcdir)/'`pyasdcp.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/asdcp_la-pyasdcp.Tpo $(DEPDIR)/asdcp_la-pyasdcp.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='pyasdcp.cpp' object='asdcp_la-pyasdcp.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(asdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o asdcp_la-pyasdcp.lo `test -f 'pyasdcp.cpp' || echo '$(srcdir)/'`pyasdcp.cpp + +kumu_la-pykumu.lo: pykumu.cpp +@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(kumu_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT kumu_la-pykumu.lo -MD -MP -MF $(DEPDIR)/kumu_la-pykumu.Tpo -c -o kumu_la-pykumu.lo `test -f 'pykumu.cpp' || echo '$(srcdir)/'`pykumu.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/kumu_la-pykumu.Tpo $(DEPDIR)/kumu_la-pykumu.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='pykumu.cpp' object='kumu_la-pykumu.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(kumu_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o kumu_la-pykumu.lo `test -f 'pykumu.cpp' || echo '$(srcdir)/'`pykumu.cpp + +libasdcp_la-MPEG2_Parser.lo: MPEG2_Parser.cpp +@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libasdcp_la-MPEG2_Parser.lo -MD -MP -MF $(DEPDIR)/libasdcp_la-MPEG2_Parser.Tpo -c -o libasdcp_la-MPEG2_Parser.lo `test -f 'MPEG2_Parser.cpp' || echo '$(srcdir)/'`MPEG2_Parser.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libasdcp_la-MPEG2_Parser.Tpo $(DEPDIR)/libasdcp_la-MPEG2_Parser.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='MPEG2_Parser.cpp' object='libasdcp_la-MPEG2_Parser.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libasdcp_la-MPEG2_Parser.lo `test -f 'MPEG2_Parser.cpp' || echo '$(srcdir)/'`MPEG2_Parser.cpp + +libasdcp_la-MPEG.lo: MPEG.cpp +@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libasdcp_la-MPEG.lo -MD -MP -MF $(DEPDIR)/libasdcp_la-MPEG.Tpo -c -o libasdcp_la-MPEG.lo `test -f 'MPEG.cpp' || echo '$(srcdir)/'`MPEG.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libasdcp_la-MPEG.Tpo $(DEPDIR)/libasdcp_la-MPEG.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='MPEG.cpp' object='libasdcp_la-MPEG.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libasdcp_la-MPEG.lo `test -f 'MPEG.cpp' || echo '$(srcdir)/'`MPEG.cpp + +libasdcp_la-JP2K_Codestream_Parser.lo: JP2K_Codestream_Parser.cpp +@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libasdcp_la-JP2K_Codestream_Parser.lo -MD -MP -MF $(DEPDIR)/libasdcp_la-JP2K_Codestream_Parser.Tpo -c -o libasdcp_la-JP2K_Codestream_Parser.lo `test -f 'JP2K_Codestream_Parser.cpp' || echo '$(srcdir)/'`JP2K_Codestream_Parser.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libasdcp_la-JP2K_Codestream_Parser.Tpo $(DEPDIR)/libasdcp_la-JP2K_Codestream_Parser.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='JP2K_Codestream_Parser.cpp' object='libasdcp_la-JP2K_Codestream_Parser.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libasdcp_la-JP2K_Codestream_Parser.lo `test -f 'JP2K_Codestream_Parser.cpp' || echo '$(srcdir)/'`JP2K_Codestream_Parser.cpp + +libasdcp_la-JP2K_Sequence_Parser.lo: JP2K_Sequence_Parser.cpp +@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libasdcp_la-JP2K_Sequence_Parser.lo -MD -MP -MF $(DEPDIR)/libasdcp_la-JP2K_Sequence_Parser.Tpo -c -o libasdcp_la-JP2K_Sequence_Parser.lo `test -f 'JP2K_Sequence_Parser.cpp' || echo '$(srcdir)/'`JP2K_Sequence_Parser.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libasdcp_la-JP2K_Sequence_Parser.Tpo $(DEPDIR)/libasdcp_la-JP2K_Sequence_Parser.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='JP2K_Sequence_Parser.cpp' object='libasdcp_la-JP2K_Sequence_Parser.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libasdcp_la-JP2K_Sequence_Parser.lo `test -f 'JP2K_Sequence_Parser.cpp' || echo '$(srcdir)/'`JP2K_Sequence_Parser.cpp + +libasdcp_la-JP2K.lo: JP2K.cpp +@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libasdcp_la-JP2K.lo -MD -MP -MF $(DEPDIR)/libasdcp_la-JP2K.Tpo -c -o libasdcp_la-JP2K.lo `test -f 'JP2K.cpp' || echo '$(srcdir)/'`JP2K.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libasdcp_la-JP2K.Tpo $(DEPDIR)/libasdcp_la-JP2K.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='JP2K.cpp' object='libasdcp_la-JP2K.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libasdcp_la-JP2K.lo `test -f 'JP2K.cpp' || echo '$(srcdir)/'`JP2K.cpp + +libasdcp_la-PCM_Parser.lo: PCM_Parser.cpp +@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libasdcp_la-PCM_Parser.lo -MD -MP -MF $(DEPDIR)/libasdcp_la-PCM_Parser.Tpo -c -o libasdcp_la-PCM_Parser.lo `test -f 'PCM_Parser.cpp' || echo '$(srcdir)/'`PCM_Parser.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libasdcp_la-PCM_Parser.Tpo $(DEPDIR)/libasdcp_la-PCM_Parser.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='PCM_Parser.cpp' object='libasdcp_la-PCM_Parser.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libasdcp_la-PCM_Parser.lo `test -f 'PCM_Parser.cpp' || echo '$(srcdir)/'`PCM_Parser.cpp + +libasdcp_la-Wav.lo: Wav.cpp +@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libasdcp_la-Wav.lo -MD -MP -MF $(DEPDIR)/libasdcp_la-Wav.Tpo -c -o libasdcp_la-Wav.lo `test -f 'Wav.cpp' || echo '$(srcdir)/'`Wav.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libasdcp_la-Wav.Tpo $(DEPDIR)/libasdcp_la-Wav.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='Wav.cpp' object='libasdcp_la-Wav.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libasdcp_la-Wav.lo `test -f 'Wav.cpp' || echo '$(srcdir)/'`Wav.cpp + +libasdcp_la-TimedText_Parser.lo: TimedText_Parser.cpp +@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libasdcp_la-TimedText_Parser.lo -MD -MP -MF $(DEPDIR)/libasdcp_la-TimedText_Parser.Tpo -c -o libasdcp_la-TimedText_Parser.lo `test -f 'TimedText_Parser.cpp' || echo '$(srcdir)/'`TimedText_Parser.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libasdcp_la-TimedText_Parser.Tpo $(DEPDIR)/libasdcp_la-TimedText_Parser.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='TimedText_Parser.cpp' object='libasdcp_la-TimedText_Parser.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libasdcp_la-TimedText_Parser.lo `test -f 'TimedText_Parser.cpp' || echo '$(srcdir)/'`TimedText_Parser.cpp + +libasdcp_la-KLV.lo: KLV.cpp +@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libasdcp_la-KLV.lo -MD -MP -MF $(DEPDIR)/libasdcp_la-KLV.Tpo -c -o libasdcp_la-KLV.lo `test -f 'KLV.cpp' || echo '$(srcdir)/'`KLV.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libasdcp_la-KLV.Tpo $(DEPDIR)/libasdcp_la-KLV.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='KLV.cpp' object='libasdcp_la-KLV.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libasdcp_la-KLV.lo `test -f 'KLV.cpp' || echo '$(srcdir)/'`KLV.cpp + +libasdcp_la-Dict.lo: Dict.cpp +@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libasdcp_la-Dict.lo -MD -MP -MF $(DEPDIR)/libasdcp_la-Dict.Tpo -c -o libasdcp_la-Dict.lo `test -f 'Dict.cpp' || echo '$(srcdir)/'`Dict.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libasdcp_la-Dict.Tpo $(DEPDIR)/libasdcp_la-Dict.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='Dict.cpp' object='libasdcp_la-Dict.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libasdcp_la-Dict.lo `test -f 'Dict.cpp' || echo '$(srcdir)/'`Dict.cpp + +libasdcp_la-MXFTypes.lo: MXFTypes.cpp +@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libasdcp_la-MXFTypes.lo -MD -MP -MF $(DEPDIR)/libasdcp_la-MXFTypes.Tpo -c -o libasdcp_la-MXFTypes.lo `test -f 'MXFTypes.cpp' || echo '$(srcdir)/'`MXFTypes.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libasdcp_la-MXFTypes.Tpo $(DEPDIR)/libasdcp_la-MXFTypes.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='MXFTypes.cpp' object='libasdcp_la-MXFTypes.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libasdcp_la-MXFTypes.lo `test -f 'MXFTypes.cpp' || echo '$(srcdir)/'`MXFTypes.cpp + +libasdcp_la-MXF.lo: MXF.cpp +@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libasdcp_la-MXF.lo -MD -MP -MF $(DEPDIR)/libasdcp_la-MXF.Tpo -c -o libasdcp_la-MXF.lo `test -f 'MXF.cpp' || echo '$(srcdir)/'`MXF.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libasdcp_la-MXF.Tpo $(DEPDIR)/libasdcp_la-MXF.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='MXF.cpp' object='libasdcp_la-MXF.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libasdcp_la-MXF.lo `test -f 'MXF.cpp' || echo '$(srcdir)/'`MXF.cpp + +libasdcp_la-Index.lo: Index.cpp +@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libasdcp_la-Index.lo -MD -MP -MF $(DEPDIR)/libasdcp_la-Index.Tpo -c -o libasdcp_la-Index.lo `test -f 'Index.cpp' || echo '$(srcdir)/'`Index.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libasdcp_la-Index.Tpo $(DEPDIR)/libasdcp_la-Index.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='Index.cpp' object='libasdcp_la-Index.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libasdcp_la-Index.lo `test -f 'Index.cpp' || echo '$(srcdir)/'`Index.cpp + +libasdcp_la-Metadata.lo: Metadata.cpp +@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libasdcp_la-Metadata.lo -MD -MP -MF $(DEPDIR)/libasdcp_la-Metadata.Tpo -c -o libasdcp_la-Metadata.lo `test -f 'Metadata.cpp' || echo '$(srcdir)/'`Metadata.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libasdcp_la-Metadata.Tpo $(DEPDIR)/libasdcp_la-Metadata.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='Metadata.cpp' object='libasdcp_la-Metadata.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libasdcp_la-Metadata.lo `test -f 'Metadata.cpp' || echo '$(srcdir)/'`Metadata.cpp + +libasdcp_la-AS_DCP.lo: AS_DCP.cpp +@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libasdcp_la-AS_DCP.lo -MD -MP -MF $(DEPDIR)/libasdcp_la-AS_DCP.Tpo -c -o libasdcp_la-AS_DCP.lo `test -f 'AS_DCP.cpp' || echo '$(srcdir)/'`AS_DCP.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libasdcp_la-AS_DCP.Tpo $(DEPDIR)/libasdcp_la-AS_DCP.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='AS_DCP.cpp' object='libasdcp_la-AS_DCP.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libasdcp_la-AS_DCP.lo `test -f 'AS_DCP.cpp' || echo '$(srcdir)/'`AS_DCP.cpp + +libasdcp_la-AS_DCP_MXF.lo: AS_DCP_MXF.cpp +@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libasdcp_la-AS_DCP_MXF.lo -MD -MP -MF $(DEPDIR)/libasdcp_la-AS_DCP_MXF.Tpo -c -o libasdcp_la-AS_DCP_MXF.lo `test -f 'AS_DCP_MXF.cpp' || echo '$(srcdir)/'`AS_DCP_MXF.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libasdcp_la-AS_DCP_MXF.Tpo $(DEPDIR)/libasdcp_la-AS_DCP_MXF.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='AS_DCP_MXF.cpp' object='libasdcp_la-AS_DCP_MXF.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libasdcp_la-AS_DCP_MXF.lo `test -f 'AS_DCP_MXF.cpp' || echo '$(srcdir)/'`AS_DCP_MXF.cpp + +libasdcp_la-AS_DCP_AES.lo: AS_DCP_AES.cpp +@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libasdcp_la-AS_DCP_AES.lo -MD -MP -MF $(DEPDIR)/libasdcp_la-AS_DCP_AES.Tpo -c -o libasdcp_la-AS_DCP_AES.lo `test -f 'AS_DCP_AES.cpp' || echo '$(srcdir)/'`AS_DCP_AES.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libasdcp_la-AS_DCP_AES.Tpo $(DEPDIR)/libasdcp_la-AS_DCP_AES.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='AS_DCP_AES.cpp' object='libasdcp_la-AS_DCP_AES.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libasdcp_la-AS_DCP_AES.lo `test -f 'AS_DCP_AES.cpp' || echo '$(srcdir)/'`AS_DCP_AES.cpp + +libasdcp_la-h__Reader.lo: h__Reader.cpp +@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libasdcp_la-h__Reader.lo -MD -MP -MF $(DEPDIR)/libasdcp_la-h__Reader.Tpo -c -o libasdcp_la-h__Reader.lo `test -f 'h__Reader.cpp' || echo '$(srcdir)/'`h__Reader.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libasdcp_la-h__Reader.Tpo $(DEPDIR)/libasdcp_la-h__Reader.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='h__Reader.cpp' object='libasdcp_la-h__Reader.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libasdcp_la-h__Reader.lo `test -f 'h__Reader.cpp' || echo '$(srcdir)/'`h__Reader.cpp + +libasdcp_la-h__Writer.lo: h__Writer.cpp +@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libasdcp_la-h__Writer.lo -MD -MP -MF $(DEPDIR)/libasdcp_la-h__Writer.Tpo -c -o libasdcp_la-h__Writer.lo `test -f 'h__Writer.cpp' || echo '$(srcdir)/'`h__Writer.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libasdcp_la-h__Writer.Tpo $(DEPDIR)/libasdcp_la-h__Writer.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='h__Writer.cpp' object='libasdcp_la-h__Writer.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libasdcp_la-h__Writer.lo `test -f 'h__Writer.cpp' || echo '$(srcdir)/'`h__Writer.cpp + +libasdcp_la-AS_DCP_MPEG2.lo: AS_DCP_MPEG2.cpp +@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libasdcp_la-AS_DCP_MPEG2.lo -MD -MP -MF $(DEPDIR)/libasdcp_la-AS_DCP_MPEG2.Tpo -c -o libasdcp_la-AS_DCP_MPEG2.lo `test -f 'AS_DCP_MPEG2.cpp' || echo '$(srcdir)/'`AS_DCP_MPEG2.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libasdcp_la-AS_DCP_MPEG2.Tpo $(DEPDIR)/libasdcp_la-AS_DCP_MPEG2.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='AS_DCP_MPEG2.cpp' object='libasdcp_la-AS_DCP_MPEG2.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libasdcp_la-AS_DCP_MPEG2.lo `test -f 'AS_DCP_MPEG2.cpp' || echo '$(srcdir)/'`AS_DCP_MPEG2.cpp + +libasdcp_la-AS_DCP_JP2K.lo: AS_DCP_JP2K.cpp +@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libasdcp_la-AS_DCP_JP2K.lo -MD -MP -MF $(DEPDIR)/libasdcp_la-AS_DCP_JP2K.Tpo -c -o libasdcp_la-AS_DCP_JP2K.lo `test -f 'AS_DCP_JP2K.cpp' || echo '$(srcdir)/'`AS_DCP_JP2K.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libasdcp_la-AS_DCP_JP2K.Tpo $(DEPDIR)/libasdcp_la-AS_DCP_JP2K.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='AS_DCP_JP2K.cpp' object='libasdcp_la-AS_DCP_JP2K.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libasdcp_la-AS_DCP_JP2K.lo `test -f 'AS_DCP_JP2K.cpp' || echo '$(srcdir)/'`AS_DCP_JP2K.cpp + +libasdcp_la-AS_DCP_PCM.lo: AS_DCP_PCM.cpp +@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libasdcp_la-AS_DCP_PCM.lo -MD -MP -MF $(DEPDIR)/libasdcp_la-AS_DCP_PCM.Tpo -c -o libasdcp_la-AS_DCP_PCM.lo `test -f 'AS_DCP_PCM.cpp' || echo '$(srcdir)/'`AS_DCP_PCM.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libasdcp_la-AS_DCP_PCM.Tpo $(DEPDIR)/libasdcp_la-AS_DCP_PCM.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='AS_DCP_PCM.cpp' object='libasdcp_la-AS_DCP_PCM.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libasdcp_la-AS_DCP_PCM.lo `test -f 'AS_DCP_PCM.cpp' || echo '$(srcdir)/'`AS_DCP_PCM.cpp + +libasdcp_la-AS_DCP_TimedText.lo: AS_DCP_TimedText.cpp +@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libasdcp_la-AS_DCP_TimedText.lo -MD -MP -MF $(DEPDIR)/libasdcp_la-AS_DCP_TimedText.Tpo -c -o libasdcp_la-AS_DCP_TimedText.lo `test -f 'AS_DCP_TimedText.cpp' || echo '$(srcdir)/'`AS_DCP_TimedText.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libasdcp_la-AS_DCP_TimedText.Tpo $(DEPDIR)/libasdcp_la-AS_DCP_TimedText.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='AS_DCP_TimedText.cpp' object='libasdcp_la-AS_DCP_TimedText.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libasdcp_la-AS_DCP_TimedText.lo `test -f 'AS_DCP_TimedText.cpp' || echo '$(srcdir)/'`AS_DCP_TimedText.cpp + +libasdcp_la-PCMParserList.lo: PCMParserList.cpp +@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libasdcp_la-PCMParserList.lo -MD -MP -MF $(DEPDIR)/libasdcp_la-PCMParserList.Tpo -c -o libasdcp_la-PCMParserList.lo `test -f 'PCMParserList.cpp' || echo '$(srcdir)/'`PCMParserList.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libasdcp_la-PCMParserList.Tpo $(DEPDIR)/libasdcp_la-PCMParserList.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='PCMParserList.cpp' object='libasdcp_la-PCMParserList.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libasdcp_la-PCMParserList.lo `test -f 'PCMParserList.cpp' || echo '$(srcdir)/'`PCMParserList.cpp + +libasdcp_la-MDD.lo: MDD.cpp +@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libasdcp_la-MDD.lo -MD -MP -MF $(DEPDIR)/libasdcp_la-MDD.Tpo -c -o libasdcp_la-MDD.lo `test -f 'MDD.cpp' || echo '$(srcdir)/'`MDD.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libasdcp_la-MDD.Tpo $(DEPDIR)/libasdcp_la-MDD.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='MDD.cpp' object='libasdcp_la-MDD.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libasdcp_la-MDD.lo `test -f 'MDD.cpp' || echo '$(srcdir)/'`MDD.cpp + +libasdcp_la-TimedText_Transform.lo: TimedText_Transform.cpp +@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libasdcp_la-TimedText_Transform.lo -MD -MP -MF $(DEPDIR)/libasdcp_la-TimedText_Transform.Tpo -c -o libasdcp_la-TimedText_Transform.lo `test -f 'TimedText_Transform.cpp' || echo '$(srcdir)/'`TimedText_Transform.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libasdcp_la-TimedText_Transform.Tpo $(DEPDIR)/libasdcp_la-TimedText_Transform.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='TimedText_Transform.cpp' object='libasdcp_la-TimedText_Transform.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libasdcp_la-TimedText_Transform.lo `test -f 'TimedText_Transform.cpp' || echo '$(srcdir)/'`TimedText_Transform.cpp + +libpyasdcp_la-kumu_python.lo: kumu_python.cpp +@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpyasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libpyasdcp_la-kumu_python.lo -MD -MP -MF $(DEPDIR)/libpyasdcp_la-kumu_python.Tpo -c -o libpyasdcp_la-kumu_python.lo `test -f 'kumu_python.cpp' || echo '$(srcdir)/'`kumu_python.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libpyasdcp_la-kumu_python.Tpo $(DEPDIR)/libpyasdcp_la-kumu_python.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='kumu_python.cpp' object='libpyasdcp_la-kumu_python.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpyasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libpyasdcp_la-kumu_python.lo `test -f 'kumu_python.cpp' || echo '$(srcdir)/'`kumu_python.cpp + +libpyasdcp_la-asdcp_python.lo: asdcp_python.cpp +@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpyasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libpyasdcp_la-asdcp_python.lo -MD -MP -MF $(DEPDIR)/libpyasdcp_la-asdcp_python.Tpo -c -o libpyasdcp_la-asdcp_python.lo `test -f 'asdcp_python.cpp' || echo '$(srcdir)/'`asdcp_python.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libpyasdcp_la-asdcp_python.Tpo $(DEPDIR)/libpyasdcp_la-asdcp_python.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='asdcp_python.cpp' object='libpyasdcp_la-asdcp_python.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpyasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libpyasdcp_la-asdcp_python.lo `test -f 'asdcp_python.cpp' || echo '$(srcdir)/'`asdcp_python.cpp + +libpyasdcp_la-asdcp_python_descriptor.lo: asdcp_python_descriptor.cpp +@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpyasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libpyasdcp_la-asdcp_python_descriptor.lo -MD -MP -MF $(DEPDIR)/libpyasdcp_la-asdcp_python_descriptor.Tpo -c -o libpyasdcp_la-asdcp_python_descriptor.lo `test -f 'asdcp_python_descriptor.cpp' || echo '$(srcdir)/'`asdcp_python_descriptor.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libpyasdcp_la-asdcp_python_descriptor.Tpo $(DEPDIR)/libpyasdcp_la-asdcp_python_descriptor.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='asdcp_python_descriptor.cpp' object='libpyasdcp_la-asdcp_python_descriptor.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpyasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libpyasdcp_la-asdcp_python_descriptor.lo `test -f 'asdcp_python_descriptor.cpp' || echo '$(srcdir)/'`asdcp_python_descriptor.cpp + +libpyasdcp_la-asdcp_python_misc.lo: asdcp_python_misc.cpp +@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpyasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libpyasdcp_la-asdcp_python_misc.lo -MD -MP -MF $(DEPDIR)/libpyasdcp_la-asdcp_python_misc.Tpo -c -o libpyasdcp_la-asdcp_python_misc.lo `test -f 'asdcp_python_misc.cpp' || echo '$(srcdir)/'`asdcp_python_misc.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libpyasdcp_la-asdcp_python_misc.Tpo $(DEPDIR)/libpyasdcp_la-asdcp_python_misc.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='asdcp_python_misc.cpp' object='libpyasdcp_la-asdcp_python_misc.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpyasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libpyasdcp_la-asdcp_python_misc.lo `test -f 'asdcp_python_misc.cpp' || echo '$(srcdir)/'`asdcp_python_misc.cpp + +libpyasdcp_la-asdcp_python_mxf.lo: asdcp_python_mxf.cpp +@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpyasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libpyasdcp_la-asdcp_python_mxf.lo -MD -MP -MF $(DEPDIR)/libpyasdcp_la-asdcp_python_mxf.Tpo -c -o libpyasdcp_la-asdcp_python_mxf.lo `test -f 'asdcp_python_mxf.cpp' || echo '$(srcdir)/'`asdcp_python_mxf.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libpyasdcp_la-asdcp_python_mxf.Tpo $(DEPDIR)/libpyasdcp_la-asdcp_python_mxf.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='asdcp_python_mxf.cpp' object='libpyasdcp_la-asdcp_python_mxf.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpyasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libpyasdcp_la-asdcp_python_mxf.lo `test -f 'asdcp_python_mxf.cpp' || echo '$(srcdir)/'`asdcp_python_mxf.cpp + +libpyasdcp_la-asdcp_python_mxf_text.lo: asdcp_python_mxf_text.cpp +@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpyasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libpyasdcp_la-asdcp_python_mxf_text.lo -MD -MP -MF $(DEPDIR)/libpyasdcp_la-asdcp_python_mxf_text.Tpo -c -o libpyasdcp_la-asdcp_python_mxf_text.lo `test -f 'asdcp_python_mxf_text.cpp' || echo '$(srcdir)/'`asdcp_python_mxf_text.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libpyasdcp_la-asdcp_python_mxf_text.Tpo $(DEPDIR)/libpyasdcp_la-asdcp_python_mxf_text.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='asdcp_python_mxf_text.cpp' object='libpyasdcp_la-asdcp_python_mxf_text.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpyasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libpyasdcp_la-asdcp_python_mxf_text.lo `test -f 'asdcp_python_mxf_text.cpp' || echo '$(srcdir)/'`asdcp_python_mxf_text.cpp + +libpyasdcp_la-asdcp_python_mxf_metadata.lo: asdcp_python_mxf_metadata.cpp +@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpyasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libpyasdcp_la-asdcp_python_mxf_metadata.lo -MD -MP -MF $(DEPDIR)/libpyasdcp_la-asdcp_python_mxf_metadata.Tpo -c -o libpyasdcp_la-asdcp_python_mxf_metadata.lo `test -f 'asdcp_python_mxf_metadata.cpp' || echo '$(srcdir)/'`asdcp_python_mxf_metadata.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libpyasdcp_la-asdcp_python_mxf_metadata.Tpo $(DEPDIR)/libpyasdcp_la-asdcp_python_mxf_metadata.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='asdcp_python_mxf_metadata.cpp' object='libpyasdcp_la-asdcp_python_mxf_metadata.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpyasdcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libpyasdcp_la-asdcp_python_mxf_metadata.lo `test -f 'asdcp_python_mxf_metadata.cpp' || echo '$(srcdir)/'`asdcp_python_mxf_metadata.cpp + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-includeHEADERS: $(include_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(includedir)" || $(MKDIR_P) "$(DESTDIR)$(includedir)" + @list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(includedir)'"; \ + $(INSTALL_HEADER) $$files "$(DESTDIR)$(includedir)" || exit $$?; \ + done + +uninstall-includeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(includedir)'; $(am__uninstall_files_from_dir) +install-nodist_includeHEADERS: $(nodist_include_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(includedir)" || $(MKDIR_P) "$(DESTDIR)$(includedir)" + @list='$(nodist_include_HEADERS)'; test -n "$(includedir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(includedir)'"; \ + $(INSTALL_HEADER) $$files "$(DESTDIR)$(includedir)" || exit $$?; \ + done + +uninstall-nodist_includeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(nodist_include_HEADERS)'; test -n "$(includedir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(includedir)'; $(am__uninstall_files_from_dir) +install-nodist_pyexec_includeHEADERS: $(nodist_pyexec_include_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(pyexec_includedir)" || $(MKDIR_P) "$(DESTDIR)$(pyexec_includedir)" + @list='$(nodist_pyexec_include_HEADERS)'; test -n "$(pyexec_includedir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(pyexec_includedir)'"; \ + $(INSTALL_HEADER) $$files "$(DESTDIR)$(pyexec_includedir)" || exit $$?; \ + done + +uninstall-nodist_pyexec_includeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(nodist_pyexec_include_HEADERS)'; test -n "$(pyexec_includedir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(pyexec_includedir)'; $(am__uninstall_files_from_dir) + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ + srcdir=$(srcdir); export srcdir; \ + list=' $(TESTS) '; \ + $(am__tty_colors); \ + if test -n "$$list"; then \ + for tst in $$list; do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + col=$$red; res=XPASS; \ + ;; \ + *) \ + col=$$grn; res=PASS; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xfail=`expr $$xfail + 1`; \ + col=$$lgn; res=XFAIL; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + col=$$red; res=FAIL; \ + ;; \ + esac; \ + else \ + skip=`expr $$skip + 1`; \ + col=$$blu; res=SKIP; \ + fi; \ + echo "$${col}$$res$${std}: $$tst"; \ + done; \ + if test "$$all" -eq 1; then \ + tests="test"; \ + All=""; \ + else \ + tests="tests"; \ + All="All "; \ + fi; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="$$All$$all $$tests passed"; \ + else \ + if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ + banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all $$tests failed"; \ + else \ + if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ + banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ + fi; \ + fi; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + if test "$$skip" -eq 1; then \ + skipped="($$skip test was not run)"; \ + else \ + skipped="($$skip tests were not run)"; \ + fi; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ + if test "$$failed" -eq 0; then \ + col="$$grn"; \ + else \ + col="$$red"; \ + fi; \ + echo "$${col}$$dashes$${std}"; \ + echo "$${col}$$banner$${std}"; \ + test -z "$$skipped" || echo "$${col}$$skipped$${std}"; \ + test -z "$$report" || echo "$${col}$$report$${std}"; \ + echo "$${col}$$dashes$${std}"; \ + test "$$failed" -eq 0; \ + else :; fi + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) check-am +all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(HEADERS) +install-binPROGRAMS: install-libLTLIBRARIES + +installdirs: + for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(pyexecdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(includedir)" "$(DESTDIR)$(includedir)" "$(DESTDIR)$(pyexec_includedir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-am + +clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ + clean-libLTLIBRARIES clean-libtool clean-pyexecLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-includeHEADERS install-nodist_includeHEADERS + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-binPROGRAMS install-libLTLIBRARIES \ + install-nodist_pyexec_includeHEADERS install-pyexecLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-includeHEADERS \ + uninstall-libLTLIBRARIES uninstall-nodist_includeHEADERS \ + uninstall-nodist_pyexec_includeHEADERS \ + uninstall-pyexecLTLIBRARIES + +.MAKE: all check check-am install install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ + clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ + clean-libLTLIBRARIES clean-libtool clean-pyexecLTLIBRARIES \ + ctags distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-binPROGRAMS \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-includeHEADERS install-info install-info-am \ + install-libLTLIBRARIES install-man \ + install-nodist_includeHEADERS \ + install-nodist_pyexec_includeHEADERS install-pdf \ + install-pdf-am install-ps install-ps-am \ + install-pyexecLTLIBRARIES install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-binPROGRAMS \ + uninstall-includeHEADERS uninstall-libLTLIBRARIES \ + uninstall-nodist_includeHEADERS \ + uninstall-nodist_pyexec_includeHEADERS \ + uninstall-pyexecLTLIBRARIES + + +# build commands for built sources +# dependencies: $(srcdir)/ullist.pl $(srcdir)/ULList.xml $(srcdir)/dict.xml $(srcdir)/DMS_Crypto.xml +MDD.h: + $(srcdir)/ullist.pl $(srcdir)/ULList.xml $(srcdir)/dict.xml $(srcdir)/DMS_Crypto.xml > MDD.h +# dependencies: $(srcdir)/ullist.pl $(srcdir)/ULList.xml $(srcdir)/dict.xml $(srcdir)/DMS_Crypto.xml +MDD.cpp: + $(srcdir)/ullist.pl -s $(srcdir)/ULList.xml $(srcdir)/dict.xml $(srcdir)/DMS_Crypto.xml > MDD.cpp +# dependencies: $(srcdir)/Metadata_h.tt2 $(srcdir)/mxfgen.pl $(srcdir)/MXF_def.pl +Metadata.h: + $(srcdir)/mxfgen.pl $(srcdir)/MXF_def.pl $(srcdir)/Metadata_h.tt2 > Metadata.h +# dependencies: Metadata.h $(srcdir)/Metadata_cpp.tt2 +Metadata.cpp: + $(srcdir)/mxfgen.pl $(srcdir)/MXF_def.pl $(srcdir)/Metadata_cpp.tt2 > Metadata.cpp + +# +# +# + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/asdcplib/src/Metadata.cpp b/asdcplib/src/Metadata.cpp new file mode 100755 index 0000000..a9a15e5 --- /dev/null +++ b/asdcplib/src/Metadata.cpp @@ -0,0 +1,2893 @@ +/* +Copyright (c) 2005-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 Metadata.cpp + \version $Id: Metadata.cpp,v 1.31 2012/02/21 02:09:31 jhurst Exp $ + \brief AS-DCP library, MXF Metadata Sets implementation +*/ + + +#include <KM_mutex.h> +#include "Metadata.h" + +using namespace ASDCP; +using namespace ASDCP::MXF; + +const ui32_t kl_length = ASDCP::SMPTE_UL_LENGTH + ASDCP::MXF_BER_LENGTH; + +//------------------------------------------------------------------------------------------ + +static InterchangeObject* Preface_Factory(const Dictionary*& Dict) { return new Preface(Dict); } +static InterchangeObject* IndexTableSegment_Factory(const Dictionary*& Dict) { return new IndexTableSegment(Dict); } + +static InterchangeObject* Identification_Factory(const Dictionary*& Dict) { return new Identification(Dict); } +static InterchangeObject* ContentStorage_Factory(const Dictionary*& Dict) { return new ContentStorage(Dict); } +static InterchangeObject* EssenceContainerData_Factory(const Dictionary*& Dict) { return new EssenceContainerData(Dict); } +static InterchangeObject* MaterialPackage_Factory(const Dictionary*& Dict) { return new MaterialPackage(Dict); } +static InterchangeObject* SourcePackage_Factory(const Dictionary*& Dict) { return new SourcePackage(Dict); } +static InterchangeObject* StaticTrack_Factory(const Dictionary*& Dict) { return new StaticTrack(Dict); } +static InterchangeObject* Track_Factory(const Dictionary*& Dict) { return new Track(Dict); } +static InterchangeObject* Sequence_Factory(const Dictionary*& Dict) { return new Sequence(Dict); } +static InterchangeObject* SourceClip_Factory(const Dictionary*& Dict) { return new SourceClip(Dict); } +static InterchangeObject* TimecodeComponent_Factory(const Dictionary*& Dict) { return new TimecodeComponent(Dict); } +static InterchangeObject* FileDescriptor_Factory(const Dictionary*& Dict) { return new FileDescriptor(Dict); } +static InterchangeObject* GenericSoundEssenceDescriptor_Factory(const Dictionary*& Dict) { return new GenericSoundEssenceDescriptor(Dict); } +static InterchangeObject* WaveAudioDescriptor_Factory(const Dictionary*& Dict) { return new WaveAudioDescriptor(Dict); } +static InterchangeObject* GenericPictureEssenceDescriptor_Factory(const Dictionary*& Dict) { return new GenericPictureEssenceDescriptor(Dict); } +static InterchangeObject* RGBAEssenceDescriptor_Factory(const Dictionary*& Dict) { return new RGBAEssenceDescriptor(Dict); } +static InterchangeObject* JPEG2000PictureSubDescriptor_Factory(const Dictionary*& Dict) { return new JPEG2000PictureSubDescriptor(Dict); } +static InterchangeObject* CDCIEssenceDescriptor_Factory(const Dictionary*& Dict) { return new CDCIEssenceDescriptor(Dict); } +static InterchangeObject* MPEG2VideoDescriptor_Factory(const Dictionary*& Dict) { return new MPEG2VideoDescriptor(Dict); } +static InterchangeObject* DMSegment_Factory(const Dictionary*& Dict) { return new DMSegment(Dict); } +static InterchangeObject* CryptographicFramework_Factory(const Dictionary*& Dict) { return new CryptographicFramework(Dict); } +static InterchangeObject* CryptographicContext_Factory(const Dictionary*& Dict) { return new CryptographicContext(Dict); } +static InterchangeObject* GenericDataEssenceDescriptor_Factory(const Dictionary*& Dict) { return new GenericDataEssenceDescriptor(Dict); } +static InterchangeObject* TimedTextDescriptor_Factory(const Dictionary*& Dict) { return new TimedTextDescriptor(Dict); } +static InterchangeObject* TimedTextResourceSubDescriptor_Factory(const Dictionary*& Dict) { return new TimedTextResourceSubDescriptor(Dict); } +static InterchangeObject* StereoscopicPictureSubDescriptor_Factory(const Dictionary*& Dict) { return new StereoscopicPictureSubDescriptor(Dict); } +static InterchangeObject* NetworkLocator_Factory(const Dictionary*& Dict) { return new NetworkLocator(Dict); } +static InterchangeObject* MCALabelSubDescriptor_Factory(const Dictionary*& Dict) { return new MCALabelSubDescriptor(Dict); } +static InterchangeObject* AudioChannelLabelSubDescriptor_Factory(const Dictionary*& Dict) { return new AudioChannelLabelSubDescriptor(Dict); } +static InterchangeObject* SoundfieldGroupLabelSubDescriptor_Factory(const Dictionary*& Dict) { return new SoundfieldGroupLabelSubDescriptor(Dict); } +static InterchangeObject* GroupOfSoundfieldGroupsLabelSubDescriptor_Factory(const Dictionary*& Dict) { return new GroupOfSoundfieldGroupsLabelSubDescriptor(Dict); } + + +void +ASDCP::MXF::Metadata_InitTypes(const Dictionary*& Dict) +{ + assert(Dict); + SetObjectFactory(Dict->ul(MDD_Preface), Preface_Factory); + SetObjectFactory(Dict->ul(MDD_IndexTableSegment), IndexTableSegment_Factory); + + SetObjectFactory(Dict->ul(MDD_Identification), Identification_Factory); + SetObjectFactory(Dict->ul(MDD_ContentStorage), ContentStorage_Factory); + SetObjectFactory(Dict->ul(MDD_EssenceContainerData), EssenceContainerData_Factory); + SetObjectFactory(Dict->ul(MDD_MaterialPackage), MaterialPackage_Factory); + SetObjectFactory(Dict->ul(MDD_SourcePackage), SourcePackage_Factory); + SetObjectFactory(Dict->ul(MDD_StaticTrack), StaticTrack_Factory); + SetObjectFactory(Dict->ul(MDD_Track), Track_Factory); + SetObjectFactory(Dict->ul(MDD_Sequence), Sequence_Factory); + SetObjectFactory(Dict->ul(MDD_SourceClip), SourceClip_Factory); + SetObjectFactory(Dict->ul(MDD_TimecodeComponent), TimecodeComponent_Factory); + SetObjectFactory(Dict->ul(MDD_FileDescriptor), FileDescriptor_Factory); + SetObjectFactory(Dict->ul(MDD_GenericSoundEssenceDescriptor), GenericSoundEssenceDescriptor_Factory); + SetObjectFactory(Dict->ul(MDD_WaveAudioDescriptor), WaveAudioDescriptor_Factory); + SetObjectFactory(Dict->ul(MDD_GenericPictureEssenceDescriptor), GenericPictureEssenceDescriptor_Factory); + SetObjectFactory(Dict->ul(MDD_RGBAEssenceDescriptor), RGBAEssenceDescriptor_Factory); + SetObjectFactory(Dict->ul(MDD_JPEG2000PictureSubDescriptor), JPEG2000PictureSubDescriptor_Factory); + SetObjectFactory(Dict->ul(MDD_CDCIEssenceDescriptor), CDCIEssenceDescriptor_Factory); + SetObjectFactory(Dict->ul(MDD_MPEG2VideoDescriptor), MPEG2VideoDescriptor_Factory); + SetObjectFactory(Dict->ul(MDD_DMSegment), DMSegment_Factory); + SetObjectFactory(Dict->ul(MDD_CryptographicFramework), CryptographicFramework_Factory); + SetObjectFactory(Dict->ul(MDD_CryptographicContext), CryptographicContext_Factory); + SetObjectFactory(Dict->ul(MDD_GenericDataEssenceDescriptor), GenericDataEssenceDescriptor_Factory); + SetObjectFactory(Dict->ul(MDD_TimedTextDescriptor), TimedTextDescriptor_Factory); + SetObjectFactory(Dict->ul(MDD_TimedTextResourceSubDescriptor), TimedTextResourceSubDescriptor_Factory); + SetObjectFactory(Dict->ul(MDD_StereoscopicPictureSubDescriptor), StereoscopicPictureSubDescriptor_Factory); + SetObjectFactory(Dict->ul(MDD_NetworkLocator), NetworkLocator_Factory); + SetObjectFactory(Dict->ul(MDD_MCALabelSubDescriptor), MCALabelSubDescriptor_Factory); + SetObjectFactory(Dict->ul(MDD_AudioChannelLabelSubDescriptor), AudioChannelLabelSubDescriptor_Factory); + SetObjectFactory(Dict->ul(MDD_SoundfieldGroupLabelSubDescriptor), SoundfieldGroupLabelSubDescriptor_Factory); + SetObjectFactory(Dict->ul(MDD_GroupOfSoundfieldGroupsLabelSubDescriptor), GroupOfSoundfieldGroupsLabelSubDescriptor_Factory); +} + +//------------------------------------------------------------------------------------------ +// KLV Sets + + + +//------------------------------------------------------------------------------------------ +// Identification + +// + +Identification::Identification(const Dictionary*& d) : InterchangeObject(d), m_Dict(d) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_Identification); +} + +Identification::Identification(const Identification& rhs) : InterchangeObject(rhs.m_Dict), m_Dict(rhs.m_Dict) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_Identification); + Copy(rhs); +} + + +// +ASDCP::Result_t +Identification::InitFromTLVSet(TLVReader& TLVSet) +{ + assert(m_Dict); + Result_t result = InterchangeObject::InitFromTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Identification, ThisGenerationUID)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Identification, CompanyName)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Identification, ProductName)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Identification, ProductVersion)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Identification, VersionString)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Identification, ProductUID)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Identification, ModificationDate)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Identification, ToolkitVersion)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Identification, Platform)); + return result; +} + +// +ASDCP::Result_t +Identification::WriteToTLVSet(TLVWriter& TLVSet) +{ + assert(m_Dict); + Result_t result = InterchangeObject::WriteToTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Identification, ThisGenerationUID)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Identification, CompanyName)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Identification, ProductName)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Identification, ProductVersion)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Identification, VersionString)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Identification, ProductUID)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Identification, ModificationDate)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Identification, ToolkitVersion)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Identification, Platform)); + return result; +} + +// +void +Identification::Copy(const Identification& rhs) +{ + InterchangeObject::Copy(rhs); + ThisGenerationUID = rhs.ThisGenerationUID; + CompanyName = rhs.CompanyName; + ProductName = rhs.ProductName; + ProductVersion = rhs.ProductVersion; + VersionString = rhs.VersionString; + ProductUID = rhs.ProductUID; + ModificationDate = rhs.ModificationDate; + ToolkitVersion = rhs.ToolkitVersion; + Platform = rhs.Platform; +} + +// +void +Identification::Dump(FILE* stream) +{ + char identbuf[IdentBufferLen]; + *identbuf = 0; + + if ( stream == 0 ) + stream = stderr; + + InterchangeObject::Dump(stream); + fprintf(stream, " %22s = %s\n", "ThisGenerationUID", ThisGenerationUID.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " %22s = %s\n", "CompanyName", CompanyName.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " %22s = %s\n", "ProductName", ProductName.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " %22s = %s\n", "ProductVersion", ProductVersion.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " %22s = %s\n", "VersionString", VersionString.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " %22s = %s\n", "ProductUID", ProductUID.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " %22s = %s\n", "ModificationDate", ModificationDate.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " %22s = %s\n", "ToolkitVersion", ToolkitVersion.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " %22s = %s\n", "Platform", Platform.EncodeString(identbuf, IdentBufferLen)); +} + +// +ASDCP::Result_t +Identification::InitFromBuffer(const byte_t* p, ui32_t l) +{ + return InterchangeObject::InitFromBuffer(p, l); +} + +// +ASDCP::Result_t +Identification::WriteToBuffer(ASDCP::FrameBuffer& Buffer) +{ + return InterchangeObject::WriteToBuffer(Buffer); +} + +//------------------------------------------------------------------------------------------ +// ContentStorage + +// + +ContentStorage::ContentStorage(const Dictionary*& d) : InterchangeObject(d), m_Dict(d) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_ContentStorage); +} + +ContentStorage::ContentStorage(const ContentStorage& rhs) : InterchangeObject(rhs.m_Dict), m_Dict(rhs.m_Dict) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_ContentStorage); + Copy(rhs); +} + + +// +ASDCP::Result_t +ContentStorage::InitFromTLVSet(TLVReader& TLVSet) +{ + assert(m_Dict); + Result_t result = InterchangeObject::InitFromTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(ContentStorage, Packages)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(ContentStorage, EssenceContainerData)); + return result; +} + +// +ASDCP::Result_t +ContentStorage::WriteToTLVSet(TLVWriter& TLVSet) +{ + assert(m_Dict); + Result_t result = InterchangeObject::WriteToTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(ContentStorage, Packages)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(ContentStorage, EssenceContainerData)); + return result; +} + +// +void +ContentStorage::Copy(const ContentStorage& rhs) +{ + InterchangeObject::Copy(rhs); + Packages = rhs.Packages; + EssenceContainerData = rhs.EssenceContainerData; +} + +// +void +ContentStorage::Dump(FILE* stream) +{ + char identbuf[IdentBufferLen]; + *identbuf = 0; + + if ( stream == 0 ) + stream = stderr; + + InterchangeObject::Dump(stream); + fprintf(stream, " %22s:\n", "Packages"); + Packages.Dump(stream); + fprintf(stream, " %22s:\n", "EssenceContainerData"); + EssenceContainerData.Dump(stream); +} + +// +ASDCP::Result_t +ContentStorage::InitFromBuffer(const byte_t* p, ui32_t l) +{ + return InterchangeObject::InitFromBuffer(p, l); +} + +// +ASDCP::Result_t +ContentStorage::WriteToBuffer(ASDCP::FrameBuffer& Buffer) +{ + return InterchangeObject::WriteToBuffer(Buffer); +} + +//------------------------------------------------------------------------------------------ +// EssenceContainerData + +// + +EssenceContainerData::EssenceContainerData(const Dictionary*& d) : InterchangeObject(d), m_Dict(d), IndexSID(0), BodySID(0) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_EssenceContainerData); +} + +EssenceContainerData::EssenceContainerData(const EssenceContainerData& rhs) : InterchangeObject(rhs.m_Dict), m_Dict(rhs.m_Dict) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_EssenceContainerData); + Copy(rhs); +} + + +// +ASDCP::Result_t +EssenceContainerData::InitFromTLVSet(TLVReader& TLVSet) +{ + assert(m_Dict); + Result_t result = InterchangeObject::InitFromTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(EssenceContainerData, LinkedPackageUID)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(EssenceContainerData, IndexSID)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(EssenceContainerData, BodySID)); + return result; +} + +// +ASDCP::Result_t +EssenceContainerData::WriteToTLVSet(TLVWriter& TLVSet) +{ + assert(m_Dict); + Result_t result = InterchangeObject::WriteToTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(EssenceContainerData, LinkedPackageUID)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(EssenceContainerData, IndexSID)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(EssenceContainerData, BodySID)); + return result; +} + +// +void +EssenceContainerData::Copy(const EssenceContainerData& rhs) +{ + InterchangeObject::Copy(rhs); + LinkedPackageUID = rhs.LinkedPackageUID; + IndexSID = rhs.IndexSID; + BodySID = rhs.BodySID; +} + +// +void +EssenceContainerData::Dump(FILE* stream) +{ + char identbuf[IdentBufferLen]; + *identbuf = 0; + + if ( stream == 0 ) + stream = stderr; + + InterchangeObject::Dump(stream); + fprintf(stream, " %22s = %s\n", "LinkedPackageUID", LinkedPackageUID.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " %22s = %d\n", "IndexSID", IndexSID); + fprintf(stream, " %22s = %d\n", "BodySID", BodySID); +} + +// +ASDCP::Result_t +EssenceContainerData::InitFromBuffer(const byte_t* p, ui32_t l) +{ + return InterchangeObject::InitFromBuffer(p, l); +} + +// +ASDCP::Result_t +EssenceContainerData::WriteToBuffer(ASDCP::FrameBuffer& Buffer) +{ + return InterchangeObject::WriteToBuffer(Buffer); +} + +//------------------------------------------------------------------------------------------ +// GenericPackage + +// +GenericPackage::GenericPackage(const Dictionary*& d) : InterchangeObject(d), m_Dict(d) {} + +GenericPackage::GenericPackage(const GenericPackage& rhs) : InterchangeObject(rhs.m_Dict), m_Dict(rhs.m_Dict) +{ + Copy(rhs); +} + + +// +ASDCP::Result_t +GenericPackage::InitFromTLVSet(TLVReader& TLVSet) +{ + assert(m_Dict); + Result_t result = InterchangeObject::InitFromTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(GenericPackage, PackageUID)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(GenericPackage, Name)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(GenericPackage, PackageCreationDate)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(GenericPackage, PackageModifiedDate)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(GenericPackage, Tracks)); + return result; +} + +// +ASDCP::Result_t +GenericPackage::WriteToTLVSet(TLVWriter& TLVSet) +{ + assert(m_Dict); + Result_t result = InterchangeObject::WriteToTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(GenericPackage, PackageUID)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(GenericPackage, Name)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(GenericPackage, PackageCreationDate)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(GenericPackage, PackageModifiedDate)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(GenericPackage, Tracks)); + return result; +} + +// +void +GenericPackage::Copy(const GenericPackage& rhs) +{ + InterchangeObject::Copy(rhs); + PackageUID = rhs.PackageUID; + Name = rhs.Name; + PackageCreationDate = rhs.PackageCreationDate; + PackageModifiedDate = rhs.PackageModifiedDate; + Tracks = rhs.Tracks; +} + +// +void +GenericPackage::Dump(FILE* stream) +{ + char identbuf[IdentBufferLen]; + *identbuf = 0; + + if ( stream == 0 ) + stream = stderr; + + InterchangeObject::Dump(stream); + fprintf(stream, " %22s = %s\n", "PackageUID", PackageUID.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " %22s = %s\n", "Name", Name.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " %22s = %s\n", "PackageCreationDate", PackageCreationDate.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " %22s = %s\n", "PackageModifiedDate", PackageModifiedDate.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " %22s:\n", "Tracks"); + Tracks.Dump(stream); +} + + +//------------------------------------------------------------------------------------------ +// MaterialPackage + +// + +MaterialPackage::MaterialPackage(const Dictionary*& d) : GenericPackage(d), m_Dict(d) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_MaterialPackage); +} + +MaterialPackage::MaterialPackage(const MaterialPackage& rhs) : GenericPackage(rhs.m_Dict), m_Dict(rhs.m_Dict) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_MaterialPackage); + Copy(rhs); +} + + +// +ASDCP::Result_t +MaterialPackage::InitFromTLVSet(TLVReader& TLVSet) +{ + assert(m_Dict); + Result_t result = GenericPackage::InitFromTLVSet(TLVSet); + return result; +} + +// +ASDCP::Result_t +MaterialPackage::WriteToTLVSet(TLVWriter& TLVSet) +{ + assert(m_Dict); + Result_t result = GenericPackage::WriteToTLVSet(TLVSet); + return result; +} + +// +void +MaterialPackage::Copy(const MaterialPackage& rhs) +{ + GenericPackage::Copy(rhs); +} + +// +void +MaterialPackage::Dump(FILE* stream) +{ + char identbuf[IdentBufferLen]; + *identbuf = 0; + + if ( stream == 0 ) + stream = stderr; + + GenericPackage::Dump(stream); +} + +// +ASDCP::Result_t +MaterialPackage::InitFromBuffer(const byte_t* p, ui32_t l) +{ + return InterchangeObject::InitFromBuffer(p, l); +} + +// +ASDCP::Result_t +MaterialPackage::WriteToBuffer(ASDCP::FrameBuffer& Buffer) +{ + return InterchangeObject::WriteToBuffer(Buffer); +} + +//------------------------------------------------------------------------------------------ +// SourcePackage + +// + +SourcePackage::SourcePackage(const Dictionary*& d) : GenericPackage(d), m_Dict(d) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_SourcePackage); +} + +SourcePackage::SourcePackage(const SourcePackage& rhs) : GenericPackage(rhs.m_Dict), m_Dict(rhs.m_Dict) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_SourcePackage); + Copy(rhs); +} + + +// +ASDCP::Result_t +SourcePackage::InitFromTLVSet(TLVReader& TLVSet) +{ + assert(m_Dict); + Result_t result = GenericPackage::InitFromTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(SourcePackage, Descriptor)); + return result; +} + +// +ASDCP::Result_t +SourcePackage::WriteToTLVSet(TLVWriter& TLVSet) +{ + assert(m_Dict); + Result_t result = GenericPackage::WriteToTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(SourcePackage, Descriptor)); + return result; +} + +// +void +SourcePackage::Copy(const SourcePackage& rhs) +{ + GenericPackage::Copy(rhs); + Descriptor = rhs.Descriptor; +} + +// +void +SourcePackage::Dump(FILE* stream) +{ + char identbuf[IdentBufferLen]; + *identbuf = 0; + + if ( stream == 0 ) + stream = stderr; + + GenericPackage::Dump(stream); + fprintf(stream, " %22s = %s\n", "Descriptor", Descriptor.EncodeString(identbuf, IdentBufferLen)); +} + +// +ASDCP::Result_t +SourcePackage::InitFromBuffer(const byte_t* p, ui32_t l) +{ + return InterchangeObject::InitFromBuffer(p, l); +} + +// +ASDCP::Result_t +SourcePackage::WriteToBuffer(ASDCP::FrameBuffer& Buffer) +{ + return InterchangeObject::WriteToBuffer(Buffer); +} + +//------------------------------------------------------------------------------------------ +// GenericTrack + +// +GenericTrack::GenericTrack(const Dictionary*& d) : InterchangeObject(d), m_Dict(d), TrackID(0), TrackNumber(0) {} + +GenericTrack::GenericTrack(const GenericTrack& rhs) : InterchangeObject(rhs.m_Dict), m_Dict(rhs.m_Dict) +{ + Copy(rhs); +} + + +// +ASDCP::Result_t +GenericTrack::InitFromTLVSet(TLVReader& TLVSet) +{ + assert(m_Dict); + Result_t result = InterchangeObject::InitFromTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(GenericTrack, TrackID)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(GenericTrack, TrackNumber)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(GenericTrack, TrackName)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(GenericTrack, Sequence)); + return result; +} + +// +ASDCP::Result_t +GenericTrack::WriteToTLVSet(TLVWriter& TLVSet) +{ + assert(m_Dict); + Result_t result = InterchangeObject::WriteToTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(GenericTrack, TrackID)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(GenericTrack, TrackNumber)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(GenericTrack, TrackName)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(GenericTrack, Sequence)); + return result; +} + +// +void +GenericTrack::Copy(const GenericTrack& rhs) +{ + InterchangeObject::Copy(rhs); + TrackID = rhs.TrackID; + TrackNumber = rhs.TrackNumber; + TrackName = rhs.TrackName; + Sequence = rhs.Sequence; +} + +// +void +GenericTrack::Dump(FILE* stream) +{ + char identbuf[IdentBufferLen]; + *identbuf = 0; + + if ( stream == 0 ) + stream = stderr; + + InterchangeObject::Dump(stream); + fprintf(stream, " %22s = %d\n", "TrackID", TrackID); + fprintf(stream, " %22s = %d\n", "TrackNumber", TrackNumber); + fprintf(stream, " %22s = %s\n", "TrackName", TrackName.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " %22s = %s\n", "Sequence", Sequence.EncodeString(identbuf, IdentBufferLen)); +} + + +//------------------------------------------------------------------------------------------ +// StaticTrack + +// + +StaticTrack::StaticTrack(const Dictionary*& d) : GenericTrack(d), m_Dict(d) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_StaticTrack); +} + +StaticTrack::StaticTrack(const StaticTrack& rhs) : GenericTrack(rhs.m_Dict), m_Dict(rhs.m_Dict) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_StaticTrack); + Copy(rhs); +} + + +// +ASDCP::Result_t +StaticTrack::InitFromTLVSet(TLVReader& TLVSet) +{ + assert(m_Dict); + Result_t result = GenericTrack::InitFromTLVSet(TLVSet); + return result; +} + +// +ASDCP::Result_t +StaticTrack::WriteToTLVSet(TLVWriter& TLVSet) +{ + assert(m_Dict); + Result_t result = GenericTrack::WriteToTLVSet(TLVSet); + return result; +} + +// +void +StaticTrack::Copy(const StaticTrack& rhs) +{ + GenericTrack::Copy(rhs); +} + +// +void +StaticTrack::Dump(FILE* stream) +{ + char identbuf[IdentBufferLen]; + *identbuf = 0; + + if ( stream == 0 ) + stream = stderr; + + GenericTrack::Dump(stream); +} + +// +ASDCP::Result_t +StaticTrack::InitFromBuffer(const byte_t* p, ui32_t l) +{ + return InterchangeObject::InitFromBuffer(p, l); +} + +// +ASDCP::Result_t +StaticTrack::WriteToBuffer(ASDCP::FrameBuffer& Buffer) +{ + return InterchangeObject::WriteToBuffer(Buffer); +} + +//------------------------------------------------------------------------------------------ +// Track + +// + +Track::Track(const Dictionary*& d) : GenericTrack(d), m_Dict(d), Origin(0) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_Track); +} + +Track::Track(const Track& rhs) : GenericTrack(rhs.m_Dict), m_Dict(rhs.m_Dict) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_Track); + Copy(rhs); +} + + +// +ASDCP::Result_t +Track::InitFromTLVSet(TLVReader& TLVSet) +{ + assert(m_Dict); + Result_t result = GenericTrack::InitFromTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Track, EditRate)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi64(OBJ_READ_ARGS(Track, Origin)); + return result; +} + +// +ASDCP::Result_t +Track::WriteToTLVSet(TLVWriter& TLVSet) +{ + assert(m_Dict); + Result_t result = GenericTrack::WriteToTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Track, EditRate)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi64(OBJ_WRITE_ARGS(Track, Origin)); + return result; +} + +// +void +Track::Copy(const Track& rhs) +{ + GenericTrack::Copy(rhs); + EditRate = rhs.EditRate; + Origin = rhs.Origin; +} + +// +void +Track::Dump(FILE* stream) +{ + char identbuf[IdentBufferLen]; + *identbuf = 0; + + if ( stream == 0 ) + stream = stderr; + + GenericTrack::Dump(stream); + fprintf(stream, " %22s = %s\n", "EditRate", EditRate.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " %22s = %s\n", "Origin", i64sz(Origin, identbuf)); +} + +// +ASDCP::Result_t +Track::InitFromBuffer(const byte_t* p, ui32_t l) +{ + return InterchangeObject::InitFromBuffer(p, l); +} + +// +ASDCP::Result_t +Track::WriteToBuffer(ASDCP::FrameBuffer& Buffer) +{ + return InterchangeObject::WriteToBuffer(Buffer); +} + +//------------------------------------------------------------------------------------------ +// StructuralComponent + +// +StructuralComponent::StructuralComponent(const Dictionary*& d) : InterchangeObject(d), m_Dict(d), Duration(0) {} + +StructuralComponent::StructuralComponent(const StructuralComponent& rhs) : InterchangeObject(rhs.m_Dict), m_Dict(rhs.m_Dict) +{ + Copy(rhs); +} + + +// +ASDCP::Result_t +StructuralComponent::InitFromTLVSet(TLVReader& TLVSet) +{ + assert(m_Dict); + Result_t result = InterchangeObject::InitFromTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(StructuralComponent, DataDefinition)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi64(OBJ_READ_ARGS(StructuralComponent, Duration)); + return result; +} + +// +ASDCP::Result_t +StructuralComponent::WriteToTLVSet(TLVWriter& TLVSet) +{ + assert(m_Dict); + Result_t result = InterchangeObject::WriteToTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(StructuralComponent, DataDefinition)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi64(OBJ_WRITE_ARGS(StructuralComponent, Duration)); + return result; +} + +// +void +StructuralComponent::Copy(const StructuralComponent& rhs) +{ + InterchangeObject::Copy(rhs); + DataDefinition = rhs.DataDefinition; + Duration = rhs.Duration; +} + +// +void +StructuralComponent::Dump(FILE* stream) +{ + char identbuf[IdentBufferLen]; + *identbuf = 0; + + if ( stream == 0 ) + stream = stderr; + + InterchangeObject::Dump(stream); + fprintf(stream, " %22s = %s\n", "DataDefinition", DataDefinition.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " %22s = %s\n", "Duration", i64sz(Duration, identbuf)); +} + + +//------------------------------------------------------------------------------------------ +// Sequence + +// + +Sequence::Sequence(const Dictionary*& d) : StructuralComponent(d), m_Dict(d) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_Sequence); +} + +Sequence::Sequence(const Sequence& rhs) : StructuralComponent(rhs.m_Dict), m_Dict(rhs.m_Dict) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_Sequence); + Copy(rhs); +} + + +// +ASDCP::Result_t +Sequence::InitFromTLVSet(TLVReader& TLVSet) +{ + assert(m_Dict); + Result_t result = StructuralComponent::InitFromTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Sequence, StructuralComponents)); + return result; +} + +// +ASDCP::Result_t +Sequence::WriteToTLVSet(TLVWriter& TLVSet) +{ + assert(m_Dict); + Result_t result = StructuralComponent::WriteToTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Sequence, StructuralComponents)); + return result; +} + +// +void +Sequence::Copy(const Sequence& rhs) +{ + StructuralComponent::Copy(rhs); + StructuralComponents = rhs.StructuralComponents; +} + +// +void +Sequence::Dump(FILE* stream) +{ + char identbuf[IdentBufferLen]; + *identbuf = 0; + + if ( stream == 0 ) + stream = stderr; + + StructuralComponent::Dump(stream); + fprintf(stream, " %22s:\n", "StructuralComponents"); + StructuralComponents.Dump(stream); +} + +// +ASDCP::Result_t +Sequence::InitFromBuffer(const byte_t* p, ui32_t l) +{ + return InterchangeObject::InitFromBuffer(p, l); +} + +// +ASDCP::Result_t +Sequence::WriteToBuffer(ASDCP::FrameBuffer& Buffer) +{ + return InterchangeObject::WriteToBuffer(Buffer); +} + +//------------------------------------------------------------------------------------------ +// SourceClip + +// + +SourceClip::SourceClip(const Dictionary*& d) : StructuralComponent(d), m_Dict(d), StartPosition(0), SourceTrackID(0) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_SourceClip); +} + +SourceClip::SourceClip(const SourceClip& rhs) : StructuralComponent(rhs.m_Dict), m_Dict(rhs.m_Dict) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_SourceClip); + Copy(rhs); +} + + +// +ASDCP::Result_t +SourceClip::InitFromTLVSet(TLVReader& TLVSet) +{ + assert(m_Dict); + Result_t result = StructuralComponent::InitFromTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi64(OBJ_READ_ARGS(SourceClip, StartPosition)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(SourceClip, SourcePackageID)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(SourceClip, SourceTrackID)); + return result; +} + +// +ASDCP::Result_t +SourceClip::WriteToTLVSet(TLVWriter& TLVSet) +{ + assert(m_Dict); + Result_t result = StructuralComponent::WriteToTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi64(OBJ_WRITE_ARGS(SourceClip, StartPosition)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(SourceClip, SourcePackageID)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(SourceClip, SourceTrackID)); + return result; +} + +// +void +SourceClip::Copy(const SourceClip& rhs) +{ + StructuralComponent::Copy(rhs); + StartPosition = rhs.StartPosition; + SourcePackageID = rhs.SourcePackageID; + SourceTrackID = rhs.SourceTrackID; +} + +// +void +SourceClip::Dump(FILE* stream) +{ + char identbuf[IdentBufferLen]; + *identbuf = 0; + + if ( stream == 0 ) + stream = stderr; + + StructuralComponent::Dump(stream); + fprintf(stream, " %22s = %s\n", "StartPosition", i64sz(StartPosition, identbuf)); + fprintf(stream, " %22s = %s\n", "SourcePackageID", SourcePackageID.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " %22s = %d\n", "SourceTrackID", SourceTrackID); +} + +// +ASDCP::Result_t +SourceClip::InitFromBuffer(const byte_t* p, ui32_t l) +{ + return InterchangeObject::InitFromBuffer(p, l); +} + +// +ASDCP::Result_t +SourceClip::WriteToBuffer(ASDCP::FrameBuffer& Buffer) +{ + return InterchangeObject::WriteToBuffer(Buffer); +} + +//------------------------------------------------------------------------------------------ +// TimecodeComponent + +// + +TimecodeComponent::TimecodeComponent(const Dictionary*& d) : StructuralComponent(d), m_Dict(d), RoundedTimecodeBase(0), StartTimecode(0), DropFrame(0) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_TimecodeComponent); +} + +TimecodeComponent::TimecodeComponent(const TimecodeComponent& rhs) : StructuralComponent(rhs.m_Dict), m_Dict(rhs.m_Dict) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_TimecodeComponent); + Copy(rhs); +} + + +// +ASDCP::Result_t +TimecodeComponent::InitFromTLVSet(TLVReader& TLVSet) +{ + assert(m_Dict); + Result_t result = StructuralComponent::InitFromTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi16(OBJ_READ_ARGS(TimecodeComponent, RoundedTimecodeBase)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi64(OBJ_READ_ARGS(TimecodeComponent, StartTimecode)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi8(OBJ_READ_ARGS(TimecodeComponent, DropFrame)); + return result; +} + +// +ASDCP::Result_t +TimecodeComponent::WriteToTLVSet(TLVWriter& TLVSet) +{ + assert(m_Dict); + Result_t result = StructuralComponent::WriteToTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi16(OBJ_WRITE_ARGS(TimecodeComponent, RoundedTimecodeBase)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi64(OBJ_WRITE_ARGS(TimecodeComponent, StartTimecode)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi8(OBJ_WRITE_ARGS(TimecodeComponent, DropFrame)); + return result; +} + +// +void +TimecodeComponent::Copy(const TimecodeComponent& rhs) +{ + StructuralComponent::Copy(rhs); + RoundedTimecodeBase = rhs.RoundedTimecodeBase; + StartTimecode = rhs.StartTimecode; + DropFrame = rhs.DropFrame; +} + +// +void +TimecodeComponent::Dump(FILE* stream) +{ + char identbuf[IdentBufferLen]; + *identbuf = 0; + + if ( stream == 0 ) + stream = stderr; + + StructuralComponent::Dump(stream); + fprintf(stream, " %22s = %d\n", "RoundedTimecodeBase", RoundedTimecodeBase); + fprintf(stream, " %22s = %s\n", "StartTimecode", i64sz(StartTimecode, identbuf)); + fprintf(stream, " %22s = %d\n", "DropFrame", DropFrame); +} + +// +ASDCP::Result_t +TimecodeComponent::InitFromBuffer(const byte_t* p, ui32_t l) +{ + return InterchangeObject::InitFromBuffer(p, l); +} + +// +ASDCP::Result_t +TimecodeComponent::WriteToBuffer(ASDCP::FrameBuffer& Buffer) +{ + return InterchangeObject::WriteToBuffer(Buffer); +} + +//------------------------------------------------------------------------------------------ +// GenericDescriptor + +// +GenericDescriptor::GenericDescriptor(const Dictionary*& d) : InterchangeObject(d), m_Dict(d) {} + +GenericDescriptor::GenericDescriptor(const GenericDescriptor& rhs) : InterchangeObject(rhs.m_Dict), m_Dict(rhs.m_Dict) +{ + Copy(rhs); +} + + +// +ASDCP::Result_t +GenericDescriptor::InitFromTLVSet(TLVReader& TLVSet) +{ + assert(m_Dict); + Result_t result = InterchangeObject::InitFromTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(GenericDescriptor, Locators)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(GenericDescriptor, SubDescriptors)); + return result; +} + +// +ASDCP::Result_t +GenericDescriptor::WriteToTLVSet(TLVWriter& TLVSet) +{ + assert(m_Dict); + Result_t result = InterchangeObject::WriteToTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(GenericDescriptor, Locators)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(GenericDescriptor, SubDescriptors)); + return result; +} + +// +void +GenericDescriptor::Copy(const GenericDescriptor& rhs) +{ + InterchangeObject::Copy(rhs); + Locators = rhs.Locators; + SubDescriptors = rhs.SubDescriptors; +} + +// +void +GenericDescriptor::Dump(FILE* stream) +{ + char identbuf[IdentBufferLen]; + *identbuf = 0; + + if ( stream == 0 ) + stream = stderr; + + InterchangeObject::Dump(stream); + fprintf(stream, " %22s:\n", "Locators"); + Locators.Dump(stream); + fprintf(stream, " %22s:\n", "SubDescriptors"); + SubDescriptors.Dump(stream); +} + + +//------------------------------------------------------------------------------------------ +// FileDescriptor + +// + +FileDescriptor::FileDescriptor(const Dictionary*& d) : GenericDescriptor(d), m_Dict(d), LinkedTrackID(0), ContainerDuration(0) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_FileDescriptor); +} + +FileDescriptor::FileDescriptor(const FileDescriptor& rhs) : GenericDescriptor(rhs.m_Dict), m_Dict(rhs.m_Dict) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_FileDescriptor); + Copy(rhs); +} + + +// +ASDCP::Result_t +FileDescriptor::InitFromTLVSet(TLVReader& TLVSet) +{ + assert(m_Dict); + Result_t result = GenericDescriptor::InitFromTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(FileDescriptor, LinkedTrackID)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(FileDescriptor, SampleRate)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi64(OBJ_READ_ARGS(FileDescriptor, ContainerDuration)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(FileDescriptor, EssenceContainer)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(FileDescriptor, Codec)); + return result; +} + +// +ASDCP::Result_t +FileDescriptor::WriteToTLVSet(TLVWriter& TLVSet) +{ + assert(m_Dict); + Result_t result = GenericDescriptor::WriteToTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(FileDescriptor, LinkedTrackID)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(FileDescriptor, SampleRate)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi64(OBJ_WRITE_ARGS(FileDescriptor, ContainerDuration)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(FileDescriptor, EssenceContainer)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(FileDescriptor, Codec)); + return result; +} + +// +void +FileDescriptor::Copy(const FileDescriptor& rhs) +{ + GenericDescriptor::Copy(rhs); + LinkedTrackID = rhs.LinkedTrackID; + SampleRate = rhs.SampleRate; + ContainerDuration = rhs.ContainerDuration; + EssenceContainer = rhs.EssenceContainer; + Codec = rhs.Codec; +} + +// +void +FileDescriptor::Dump(FILE* stream) +{ + char identbuf[IdentBufferLen]; + *identbuf = 0; + + if ( stream == 0 ) + stream = stderr; + + GenericDescriptor::Dump(stream); + fprintf(stream, " %22s = %d\n", "LinkedTrackID", LinkedTrackID); + fprintf(stream, " %22s = %s\n", "SampleRate", SampleRate.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " %22s = %s\n", "ContainerDuration", i64sz(ContainerDuration, identbuf)); + fprintf(stream, " %22s = %s\n", "EssenceContainer", EssenceContainer.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " %22s = %s\n", "Codec", Codec.EncodeString(identbuf, IdentBufferLen)); +} + +// +ASDCP::Result_t +FileDescriptor::InitFromBuffer(const byte_t* p, ui32_t l) +{ + return InterchangeObject::InitFromBuffer(p, l); +} + +// +ASDCP::Result_t +FileDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer) +{ + return InterchangeObject::WriteToBuffer(Buffer); +} + +//------------------------------------------------------------------------------------------ +// GenericSoundEssenceDescriptor + +// + +GenericSoundEssenceDescriptor::GenericSoundEssenceDescriptor(const Dictionary*& d) : FileDescriptor(d), m_Dict(d), Locked(0), AudioRefLevel(0), ChannelCount(0), QuantizationBits(0), DialNorm(0) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_GenericSoundEssenceDescriptor); +} + +GenericSoundEssenceDescriptor::GenericSoundEssenceDescriptor(const GenericSoundEssenceDescriptor& rhs) : FileDescriptor(rhs.m_Dict), m_Dict(rhs.m_Dict) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_GenericSoundEssenceDescriptor); + Copy(rhs); +} + + +// +ASDCP::Result_t +GenericSoundEssenceDescriptor::InitFromTLVSet(TLVReader& TLVSet) +{ + assert(m_Dict); + Result_t result = FileDescriptor::InitFromTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(GenericSoundEssenceDescriptor, AudioSamplingRate)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi8(OBJ_READ_ARGS(GenericSoundEssenceDescriptor, Locked)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi8(OBJ_READ_ARGS(GenericSoundEssenceDescriptor, AudioRefLevel)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(GenericSoundEssenceDescriptor, ChannelCount)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(GenericSoundEssenceDescriptor, QuantizationBits)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi8(OBJ_READ_ARGS(GenericSoundEssenceDescriptor, DialNorm)); + return result; +} + +// +ASDCP::Result_t +GenericSoundEssenceDescriptor::WriteToTLVSet(TLVWriter& TLVSet) +{ + assert(m_Dict); + Result_t result = FileDescriptor::WriteToTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(GenericSoundEssenceDescriptor, AudioSamplingRate)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi8(OBJ_WRITE_ARGS(GenericSoundEssenceDescriptor, Locked)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi8(OBJ_WRITE_ARGS(GenericSoundEssenceDescriptor, AudioRefLevel)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(GenericSoundEssenceDescriptor, ChannelCount)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(GenericSoundEssenceDescriptor, QuantizationBits)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi8(OBJ_WRITE_ARGS(GenericSoundEssenceDescriptor, DialNorm)); + return result; +} + +// +void +GenericSoundEssenceDescriptor::Copy(const GenericSoundEssenceDescriptor& rhs) +{ + FileDescriptor::Copy(rhs); + AudioSamplingRate = rhs.AudioSamplingRate; + Locked = rhs.Locked; + AudioRefLevel = rhs.AudioRefLevel; + ChannelCount = rhs.ChannelCount; + QuantizationBits = rhs.QuantizationBits; + DialNorm = rhs.DialNorm; +} + +// +void +GenericSoundEssenceDescriptor::Dump(FILE* stream) +{ + char identbuf[IdentBufferLen]; + *identbuf = 0; + + if ( stream == 0 ) + stream = stderr; + + FileDescriptor::Dump(stream); + fprintf(stream, " %22s = %s\n", "AudioSamplingRate", AudioSamplingRate.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " %22s = %d\n", "Locked", Locked); + fprintf(stream, " %22s = %d\n", "AudioRefLevel", AudioRefLevel); + fprintf(stream, " %22s = %d\n", "ChannelCount", ChannelCount); + fprintf(stream, " %22s = %d\n", "QuantizationBits", QuantizationBits); + fprintf(stream, " %22s = %d\n", "DialNorm", DialNorm); +} + +// +ASDCP::Result_t +GenericSoundEssenceDescriptor::InitFromBuffer(const byte_t* p, ui32_t l) +{ + return InterchangeObject::InitFromBuffer(p, l); +} + +// +ASDCP::Result_t +GenericSoundEssenceDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer) +{ + return InterchangeObject::WriteToBuffer(Buffer); +} + +//------------------------------------------------------------------------------------------ +// WaveAudioDescriptor + +// + +WaveAudioDescriptor::WaveAudioDescriptor(const Dictionary*& d) : GenericSoundEssenceDescriptor(d), m_Dict(d), BlockAlign(0), SequenceOffset(0), AvgBps(0) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_WaveAudioDescriptor); +} + +WaveAudioDescriptor::WaveAudioDescriptor(const WaveAudioDescriptor& rhs) : GenericSoundEssenceDescriptor(rhs.m_Dict), m_Dict(rhs.m_Dict) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_WaveAudioDescriptor); + Copy(rhs); +} + + +// +ASDCP::Result_t +WaveAudioDescriptor::InitFromTLVSet(TLVReader& TLVSet) +{ + assert(m_Dict); + Result_t result = GenericSoundEssenceDescriptor::InitFromTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi16(OBJ_READ_ARGS(WaveAudioDescriptor, BlockAlign)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi8(OBJ_READ_ARGS(WaveAudioDescriptor, SequenceOffset)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(WaveAudioDescriptor, AvgBps)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(WaveAudioDescriptor, ChannelAssignment)); + return result; +} + +// +ASDCP::Result_t +WaveAudioDescriptor::WriteToTLVSet(TLVWriter& TLVSet) +{ + assert(m_Dict); + Result_t result = GenericSoundEssenceDescriptor::WriteToTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi16(OBJ_WRITE_ARGS(WaveAudioDescriptor, BlockAlign)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi8(OBJ_WRITE_ARGS(WaveAudioDescriptor, SequenceOffset)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(WaveAudioDescriptor, AvgBps)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(WaveAudioDescriptor, ChannelAssignment)); + return result; +} + +// +void +WaveAudioDescriptor::Copy(const WaveAudioDescriptor& rhs) +{ + GenericSoundEssenceDescriptor::Copy(rhs); + BlockAlign = rhs.BlockAlign; + SequenceOffset = rhs.SequenceOffset; + AvgBps = rhs.AvgBps; + ChannelAssignment = rhs.ChannelAssignment; +} + +// +void +WaveAudioDescriptor::Dump(FILE* stream) +{ + char identbuf[IdentBufferLen]; + *identbuf = 0; + + if ( stream == 0 ) + stream = stderr; + + GenericSoundEssenceDescriptor::Dump(stream); + fprintf(stream, " %22s = %d\n", "BlockAlign", BlockAlign); + fprintf(stream, " %22s = %d\n", "SequenceOffset", SequenceOffset); + fprintf(stream, " %22s = %d\n", "AvgBps", AvgBps); + fprintf(stream, " %22s = %s\n", "ChannelAssignment", ChannelAssignment.EncodeString(identbuf, IdentBufferLen)); +} + +// +ASDCP::Result_t +WaveAudioDescriptor::InitFromBuffer(const byte_t* p, ui32_t l) +{ + return InterchangeObject::InitFromBuffer(p, l); +} + +// +ASDCP::Result_t +WaveAudioDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer) +{ + return InterchangeObject::WriteToBuffer(Buffer); +} + +//------------------------------------------------------------------------------------------ +// GenericPictureEssenceDescriptor + +// + +GenericPictureEssenceDescriptor::GenericPictureEssenceDescriptor(const Dictionary*& d) : FileDescriptor(d), m_Dict(d), FrameLayout(0), StoredWidth(0), StoredHeight(0) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_GenericPictureEssenceDescriptor); +} + +GenericPictureEssenceDescriptor::GenericPictureEssenceDescriptor(const GenericPictureEssenceDescriptor& rhs) : FileDescriptor(rhs.m_Dict), m_Dict(rhs.m_Dict) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_GenericPictureEssenceDescriptor); + Copy(rhs); +} + + +// +ASDCP::Result_t +GenericPictureEssenceDescriptor::InitFromTLVSet(TLVReader& TLVSet) +{ + assert(m_Dict); + Result_t result = FileDescriptor::InitFromTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi8(OBJ_READ_ARGS(GenericPictureEssenceDescriptor, FrameLayout)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(GenericPictureEssenceDescriptor, StoredWidth)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(GenericPictureEssenceDescriptor, StoredHeight)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(GenericPictureEssenceDescriptor, AspectRatio)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(GenericPictureEssenceDescriptor, PictureEssenceCoding)); + return result; +} + +// +ASDCP::Result_t +GenericPictureEssenceDescriptor::WriteToTLVSet(TLVWriter& TLVSet) +{ + assert(m_Dict); + Result_t result = FileDescriptor::WriteToTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi8(OBJ_WRITE_ARGS(GenericPictureEssenceDescriptor, FrameLayout)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(GenericPictureEssenceDescriptor, StoredWidth)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(GenericPictureEssenceDescriptor, StoredHeight)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(GenericPictureEssenceDescriptor, AspectRatio)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(GenericPictureEssenceDescriptor, PictureEssenceCoding)); + return result; +} + +// +void +GenericPictureEssenceDescriptor::Copy(const GenericPictureEssenceDescriptor& rhs) +{ + FileDescriptor::Copy(rhs); + FrameLayout = rhs.FrameLayout; + StoredWidth = rhs.StoredWidth; + StoredHeight = rhs.StoredHeight; + AspectRatio = rhs.AspectRatio; + PictureEssenceCoding = rhs.PictureEssenceCoding; +} + +// +void +GenericPictureEssenceDescriptor::Dump(FILE* stream) +{ + char identbuf[IdentBufferLen]; + *identbuf = 0; + + if ( stream == 0 ) + stream = stderr; + + FileDescriptor::Dump(stream); + fprintf(stream, " %22s = %d\n", "FrameLayout", FrameLayout); + fprintf(stream, " %22s = %d\n", "StoredWidth", StoredWidth); + fprintf(stream, " %22s = %d\n", "StoredHeight", StoredHeight); + fprintf(stream, " %22s = %s\n", "AspectRatio", AspectRatio.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " %22s = %s\n", "PictureEssenceCoding", PictureEssenceCoding.EncodeString(identbuf, IdentBufferLen)); +} + +// +ASDCP::Result_t +GenericPictureEssenceDescriptor::InitFromBuffer(const byte_t* p, ui32_t l) +{ + return InterchangeObject::InitFromBuffer(p, l); +} + +// +ASDCP::Result_t +GenericPictureEssenceDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer) +{ + return InterchangeObject::WriteToBuffer(Buffer); +} + +//------------------------------------------------------------------------------------------ +// RGBAEssenceDescriptor + +// + +RGBAEssenceDescriptor::RGBAEssenceDescriptor(const Dictionary*& d) : GenericPictureEssenceDescriptor(d), m_Dict(d), ComponentMaxRef(0), ComponentMinRef(0) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_RGBAEssenceDescriptor); +} + +RGBAEssenceDescriptor::RGBAEssenceDescriptor(const RGBAEssenceDescriptor& rhs) : GenericPictureEssenceDescriptor(rhs.m_Dict), m_Dict(rhs.m_Dict) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_RGBAEssenceDescriptor); + Copy(rhs); +} + + +// +ASDCP::Result_t +RGBAEssenceDescriptor::InitFromTLVSet(TLVReader& TLVSet) +{ + assert(m_Dict); + Result_t result = GenericPictureEssenceDescriptor::InitFromTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(RGBAEssenceDescriptor, ComponentMaxRef)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(RGBAEssenceDescriptor, ComponentMinRef)); + return result; +} + +// +ASDCP::Result_t +RGBAEssenceDescriptor::WriteToTLVSet(TLVWriter& TLVSet) +{ + assert(m_Dict); + Result_t result = GenericPictureEssenceDescriptor::WriteToTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(RGBAEssenceDescriptor, ComponentMaxRef)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(RGBAEssenceDescriptor, ComponentMinRef)); + return result; +} + +// +void +RGBAEssenceDescriptor::Copy(const RGBAEssenceDescriptor& rhs) +{ + GenericPictureEssenceDescriptor::Copy(rhs); + ComponentMaxRef = rhs.ComponentMaxRef; + ComponentMinRef = rhs.ComponentMinRef; +} + +// +void +RGBAEssenceDescriptor::Dump(FILE* stream) +{ + char identbuf[IdentBufferLen]; + *identbuf = 0; + + if ( stream == 0 ) + stream = stderr; + + GenericPictureEssenceDescriptor::Dump(stream); + fprintf(stream, " %22s = %d\n", "ComponentMaxRef", ComponentMaxRef); + fprintf(stream, " %22s = %d\n", "ComponentMinRef", ComponentMinRef); +} + +// +ASDCP::Result_t +RGBAEssenceDescriptor::InitFromBuffer(const byte_t* p, ui32_t l) +{ + return InterchangeObject::InitFromBuffer(p, l); +} + +// +ASDCP::Result_t +RGBAEssenceDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer) +{ + return InterchangeObject::WriteToBuffer(Buffer); +} + +//------------------------------------------------------------------------------------------ +// JPEG2000PictureSubDescriptor + +// + +JPEG2000PictureSubDescriptor::JPEG2000PictureSubDescriptor(const Dictionary*& d) : InterchangeObject(d), m_Dict(d), Rsize(0), Xsize(0), Ysize(0), XOsize(0), YOsize(0), XTsize(0), YTsize(0), XTOsize(0), YTOsize(0), Csize(0) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_JPEG2000PictureSubDescriptor); +} + +JPEG2000PictureSubDescriptor::JPEG2000PictureSubDescriptor(const JPEG2000PictureSubDescriptor& rhs) : InterchangeObject(rhs.m_Dict), m_Dict(rhs.m_Dict) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_JPEG2000PictureSubDescriptor); + Copy(rhs); +} + + +// +ASDCP::Result_t +JPEG2000PictureSubDescriptor::InitFromTLVSet(TLVReader& TLVSet) +{ + assert(m_Dict); + Result_t result = InterchangeObject::InitFromTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi16(OBJ_READ_ARGS(JPEG2000PictureSubDescriptor, Rsize)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(JPEG2000PictureSubDescriptor, Xsize)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(JPEG2000PictureSubDescriptor, Ysize)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(JPEG2000PictureSubDescriptor, XOsize)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(JPEG2000PictureSubDescriptor, YOsize)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(JPEG2000PictureSubDescriptor, XTsize)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(JPEG2000PictureSubDescriptor, YTsize)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(JPEG2000PictureSubDescriptor, XTOsize)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(JPEG2000PictureSubDescriptor, YTOsize)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi16(OBJ_READ_ARGS(JPEG2000PictureSubDescriptor, Csize)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(JPEG2000PictureSubDescriptor, PictureComponentSizing)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(JPEG2000PictureSubDescriptor, CodingStyleDefault)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(JPEG2000PictureSubDescriptor, QuantizationDefault)); + return result; +} + +// +ASDCP::Result_t +JPEG2000PictureSubDescriptor::WriteToTLVSet(TLVWriter& TLVSet) +{ + assert(m_Dict); + Result_t result = InterchangeObject::WriteToTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi16(OBJ_WRITE_ARGS(JPEG2000PictureSubDescriptor, Rsize)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(JPEG2000PictureSubDescriptor, Xsize)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(JPEG2000PictureSubDescriptor, Ysize)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(JPEG2000PictureSubDescriptor, XOsize)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(JPEG2000PictureSubDescriptor, YOsize)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(JPEG2000PictureSubDescriptor, XTsize)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(JPEG2000PictureSubDescriptor, YTsize)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(JPEG2000PictureSubDescriptor, XTOsize)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(JPEG2000PictureSubDescriptor, YTOsize)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi16(OBJ_WRITE_ARGS(JPEG2000PictureSubDescriptor, Csize)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(JPEG2000PictureSubDescriptor, PictureComponentSizing)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(JPEG2000PictureSubDescriptor, CodingStyleDefault)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(JPEG2000PictureSubDescriptor, QuantizationDefault)); + return result; +} + +// +void +JPEG2000PictureSubDescriptor::Copy(const JPEG2000PictureSubDescriptor& rhs) +{ + InterchangeObject::Copy(rhs); + Rsize = rhs.Rsize; + Xsize = rhs.Xsize; + Ysize = rhs.Ysize; + XOsize = rhs.XOsize; + YOsize = rhs.YOsize; + XTsize = rhs.XTsize; + YTsize = rhs.YTsize; + XTOsize = rhs.XTOsize; + YTOsize = rhs.YTOsize; + Csize = rhs.Csize; + PictureComponentSizing = rhs.PictureComponentSizing; + CodingStyleDefault = rhs.CodingStyleDefault; + QuantizationDefault = rhs.QuantizationDefault; +} + +// +void +JPEG2000PictureSubDescriptor::Dump(FILE* stream) +{ + char identbuf[IdentBufferLen]; + *identbuf = 0; + + if ( stream == 0 ) + stream = stderr; + + InterchangeObject::Dump(stream); + fprintf(stream, " %22s = %d\n", "Rsize", Rsize); + fprintf(stream, " %22s = %d\n", "Xsize", Xsize); + fprintf(stream, " %22s = %d\n", "Ysize", Ysize); + fprintf(stream, " %22s = %d\n", "XOsize", XOsize); + fprintf(stream, " %22s = %d\n", "YOsize", YOsize); + fprintf(stream, " %22s = %d\n", "XTsize", XTsize); + fprintf(stream, " %22s = %d\n", "YTsize", YTsize); + fprintf(stream, " %22s = %d\n", "XTOsize", XTOsize); + fprintf(stream, " %22s = %d\n", "YTOsize", YTOsize); + fprintf(stream, " %22s = %d\n", "Csize", Csize); + fprintf(stream, " %22s = %s\n", "PictureComponentSizing", PictureComponentSizing.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " %22s = %s\n", "CodingStyleDefault", CodingStyleDefault.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " %22s = %s\n", "QuantizationDefault", QuantizationDefault.EncodeString(identbuf, IdentBufferLen)); +} + +// +ASDCP::Result_t +JPEG2000PictureSubDescriptor::InitFromBuffer(const byte_t* p, ui32_t l) +{ + return InterchangeObject::InitFromBuffer(p, l); +} + +// +ASDCP::Result_t +JPEG2000PictureSubDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer) +{ + return InterchangeObject::WriteToBuffer(Buffer); +} + +//------------------------------------------------------------------------------------------ +// CDCIEssenceDescriptor + +// + +CDCIEssenceDescriptor::CDCIEssenceDescriptor(const Dictionary*& d) : GenericPictureEssenceDescriptor(d), m_Dict(d), ComponentDepth(0), HorizontalSubsampling(0), VerticalSubsampling(0), ColorSiting(0) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_CDCIEssenceDescriptor); +} + +CDCIEssenceDescriptor::CDCIEssenceDescriptor(const CDCIEssenceDescriptor& rhs) : GenericPictureEssenceDescriptor(rhs.m_Dict), m_Dict(rhs.m_Dict) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_CDCIEssenceDescriptor); + Copy(rhs); +} + + +// +ASDCP::Result_t +CDCIEssenceDescriptor::InitFromTLVSet(TLVReader& TLVSet) +{ + assert(m_Dict); + Result_t result = GenericPictureEssenceDescriptor::InitFromTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(CDCIEssenceDescriptor, ComponentDepth)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(CDCIEssenceDescriptor, HorizontalSubsampling)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(CDCIEssenceDescriptor, VerticalSubsampling)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi8(OBJ_READ_ARGS(CDCIEssenceDescriptor, ColorSiting)); + return result; +} + +// +ASDCP::Result_t +CDCIEssenceDescriptor::WriteToTLVSet(TLVWriter& TLVSet) +{ + assert(m_Dict); + Result_t result = GenericPictureEssenceDescriptor::WriteToTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(CDCIEssenceDescriptor, ComponentDepth)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(CDCIEssenceDescriptor, HorizontalSubsampling)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(CDCIEssenceDescriptor, VerticalSubsampling)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi8(OBJ_WRITE_ARGS(CDCIEssenceDescriptor, ColorSiting)); + return result; +} + +// +void +CDCIEssenceDescriptor::Copy(const CDCIEssenceDescriptor& rhs) +{ + GenericPictureEssenceDescriptor::Copy(rhs); + ComponentDepth = rhs.ComponentDepth; + HorizontalSubsampling = rhs.HorizontalSubsampling; + VerticalSubsampling = rhs.VerticalSubsampling; + ColorSiting = rhs.ColorSiting; +} + +// +void +CDCIEssenceDescriptor::Dump(FILE* stream) +{ + char identbuf[IdentBufferLen]; + *identbuf = 0; + + if ( stream == 0 ) + stream = stderr; + + GenericPictureEssenceDescriptor::Dump(stream); + fprintf(stream, " %22s = %d\n", "ComponentDepth", ComponentDepth); + fprintf(stream, " %22s = %d\n", "HorizontalSubsampling", HorizontalSubsampling); + fprintf(stream, " %22s = %d\n", "VerticalSubsampling", VerticalSubsampling); + fprintf(stream, " %22s = %d\n", "ColorSiting", ColorSiting); +} + +// +ASDCP::Result_t +CDCIEssenceDescriptor::InitFromBuffer(const byte_t* p, ui32_t l) +{ + return InterchangeObject::InitFromBuffer(p, l); +} + +// +ASDCP::Result_t +CDCIEssenceDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer) +{ + return InterchangeObject::WriteToBuffer(Buffer); +} + +//------------------------------------------------------------------------------------------ +// MPEG2VideoDescriptor + +// + +MPEG2VideoDescriptor::MPEG2VideoDescriptor(const Dictionary*& d) : CDCIEssenceDescriptor(d), m_Dict(d), CodedContentType(0), LowDelay(0), BitRate(0), ProfileAndLevel(0) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_MPEG2VideoDescriptor); +} + +MPEG2VideoDescriptor::MPEG2VideoDescriptor(const MPEG2VideoDescriptor& rhs) : CDCIEssenceDescriptor(rhs.m_Dict), m_Dict(rhs.m_Dict) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_MPEG2VideoDescriptor); + Copy(rhs); +} + + +// +ASDCP::Result_t +MPEG2VideoDescriptor::InitFromTLVSet(TLVReader& TLVSet) +{ + assert(m_Dict); + Result_t result = CDCIEssenceDescriptor::InitFromTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi8(OBJ_READ_ARGS(MPEG2VideoDescriptor, CodedContentType)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi8(OBJ_READ_ARGS(MPEG2VideoDescriptor, LowDelay)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(MPEG2VideoDescriptor, BitRate)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi8(OBJ_READ_ARGS(MPEG2VideoDescriptor, ProfileAndLevel)); + return result; +} + +// +ASDCP::Result_t +MPEG2VideoDescriptor::WriteToTLVSet(TLVWriter& TLVSet) +{ + assert(m_Dict); + Result_t result = CDCIEssenceDescriptor::WriteToTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi8(OBJ_WRITE_ARGS(MPEG2VideoDescriptor, CodedContentType)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi8(OBJ_WRITE_ARGS(MPEG2VideoDescriptor, LowDelay)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(MPEG2VideoDescriptor, BitRate)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi8(OBJ_WRITE_ARGS(MPEG2VideoDescriptor, ProfileAndLevel)); + return result; +} + +// +void +MPEG2VideoDescriptor::Copy(const MPEG2VideoDescriptor& rhs) +{ + CDCIEssenceDescriptor::Copy(rhs); + CodedContentType = rhs.CodedContentType; + LowDelay = rhs.LowDelay; + BitRate = rhs.BitRate; + ProfileAndLevel = rhs.ProfileAndLevel; +} + +// +void +MPEG2VideoDescriptor::Dump(FILE* stream) +{ + char identbuf[IdentBufferLen]; + *identbuf = 0; + + if ( stream == 0 ) + stream = stderr; + + CDCIEssenceDescriptor::Dump(stream); + fprintf(stream, " %22s = %d\n", "CodedContentType", CodedContentType); + fprintf(stream, " %22s = %d\n", "LowDelay", LowDelay); + fprintf(stream, " %22s = %d\n", "BitRate", BitRate); + fprintf(stream, " %22s = %d\n", "ProfileAndLevel", ProfileAndLevel); +} + +// +ASDCP::Result_t +MPEG2VideoDescriptor::InitFromBuffer(const byte_t* p, ui32_t l) +{ + return InterchangeObject::InitFromBuffer(p, l); +} + +// +ASDCP::Result_t +MPEG2VideoDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer) +{ + return InterchangeObject::WriteToBuffer(Buffer); +} + +//------------------------------------------------------------------------------------------ +// DMSegment + +// + +DMSegment::DMSegment(const Dictionary*& d) : InterchangeObject(d), m_Dict(d), EventStartPosition(0), Duration(0) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_DMSegment); +} + +DMSegment::DMSegment(const DMSegment& rhs) : InterchangeObject(rhs.m_Dict), m_Dict(rhs.m_Dict) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_DMSegment); + Copy(rhs); +} + + +// +ASDCP::Result_t +DMSegment::InitFromTLVSet(TLVReader& TLVSet) +{ + assert(m_Dict); + Result_t result = InterchangeObject::InitFromTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(DMSegment, DataDefinition)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi64(OBJ_READ_ARGS(DMSegment, EventStartPosition)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi64(OBJ_READ_ARGS(DMSegment, Duration)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(DMSegment, EventComment)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(DMSegment, DMFramework)); + return result; +} + +// +ASDCP::Result_t +DMSegment::WriteToTLVSet(TLVWriter& TLVSet) +{ + assert(m_Dict); + Result_t result = InterchangeObject::WriteToTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(DMSegment, DataDefinition)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi64(OBJ_WRITE_ARGS(DMSegment, EventStartPosition)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi64(OBJ_WRITE_ARGS(DMSegment, Duration)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(DMSegment, EventComment)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(DMSegment, DMFramework)); + return result; +} + +// +void +DMSegment::Copy(const DMSegment& rhs) +{ + InterchangeObject::Copy(rhs); + DataDefinition = rhs.DataDefinition; + EventStartPosition = rhs.EventStartPosition; + Duration = rhs.Duration; + EventComment = rhs.EventComment; + DMFramework = rhs.DMFramework; +} + +// +void +DMSegment::Dump(FILE* stream) +{ + char identbuf[IdentBufferLen]; + *identbuf = 0; + + if ( stream == 0 ) + stream = stderr; + + InterchangeObject::Dump(stream); + fprintf(stream, " %22s = %s\n", "DataDefinition", DataDefinition.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " %22s = %s\n", "EventStartPosition", i64sz(EventStartPosition, identbuf)); + fprintf(stream, " %22s = %s\n", "Duration", i64sz(Duration, identbuf)); + fprintf(stream, " %22s = %s\n", "EventComment", EventComment.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " %22s = %s\n", "DMFramework", DMFramework.EncodeString(identbuf, IdentBufferLen)); +} + +// +ASDCP::Result_t +DMSegment::InitFromBuffer(const byte_t* p, ui32_t l) +{ + return InterchangeObject::InitFromBuffer(p, l); +} + +// +ASDCP::Result_t +DMSegment::WriteToBuffer(ASDCP::FrameBuffer& Buffer) +{ + return InterchangeObject::WriteToBuffer(Buffer); +} + +//------------------------------------------------------------------------------------------ +// CryptographicFramework + +// + +CryptographicFramework::CryptographicFramework(const Dictionary*& d) : InterchangeObject(d), m_Dict(d) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_CryptographicFramework); +} + +CryptographicFramework::CryptographicFramework(const CryptographicFramework& rhs) : InterchangeObject(rhs.m_Dict), m_Dict(rhs.m_Dict) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_CryptographicFramework); + Copy(rhs); +} + + +// +ASDCP::Result_t +CryptographicFramework::InitFromTLVSet(TLVReader& TLVSet) +{ + assert(m_Dict); + Result_t result = InterchangeObject::InitFromTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(CryptographicFramework, ContextSR)); + return result; +} + +// +ASDCP::Result_t +CryptographicFramework::WriteToTLVSet(TLVWriter& TLVSet) +{ + assert(m_Dict); + Result_t result = InterchangeObject::WriteToTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(CryptographicFramework, ContextSR)); + return result; +} + +// +void +CryptographicFramework::Copy(const CryptographicFramework& rhs) +{ + InterchangeObject::Copy(rhs); + ContextSR = rhs.ContextSR; +} + +// +void +CryptographicFramework::Dump(FILE* stream) +{ + char identbuf[IdentBufferLen]; + *identbuf = 0; + + if ( stream == 0 ) + stream = stderr; + + InterchangeObject::Dump(stream); + fprintf(stream, " %22s = %s\n", "ContextSR", ContextSR.EncodeString(identbuf, IdentBufferLen)); +} + +// +ASDCP::Result_t +CryptographicFramework::InitFromBuffer(const byte_t* p, ui32_t l) +{ + return InterchangeObject::InitFromBuffer(p, l); +} + +// +ASDCP::Result_t +CryptographicFramework::WriteToBuffer(ASDCP::FrameBuffer& Buffer) +{ + return InterchangeObject::WriteToBuffer(Buffer); +} + +//------------------------------------------------------------------------------------------ +// CryptographicContext + +// + +CryptographicContext::CryptographicContext(const Dictionary*& d) : InterchangeObject(d), m_Dict(d) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_CryptographicContext); +} + +CryptographicContext::CryptographicContext(const CryptographicContext& rhs) : InterchangeObject(rhs.m_Dict), m_Dict(rhs.m_Dict) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_CryptographicContext); + Copy(rhs); +} + + +// +ASDCP::Result_t +CryptographicContext::InitFromTLVSet(TLVReader& TLVSet) +{ + assert(m_Dict); + Result_t result = InterchangeObject::InitFromTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(CryptographicContext, ContextID)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(CryptographicContext, SourceEssenceContainer)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(CryptographicContext, CipherAlgorithm)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(CryptographicContext, MICAlgorithm)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(CryptographicContext, CryptographicKeyID)); + return result; +} + +// +ASDCP::Result_t +CryptographicContext::WriteToTLVSet(TLVWriter& TLVSet) +{ + assert(m_Dict); + Result_t result = InterchangeObject::WriteToTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(CryptographicContext, ContextID)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(CryptographicContext, SourceEssenceContainer)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(CryptographicContext, CipherAlgorithm)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(CryptographicContext, MICAlgorithm)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(CryptographicContext, CryptographicKeyID)); + return result; +} + +// +void +CryptographicContext::Copy(const CryptographicContext& rhs) +{ + InterchangeObject::Copy(rhs); + ContextID = rhs.ContextID; + SourceEssenceContainer = rhs.SourceEssenceContainer; + CipherAlgorithm = rhs.CipherAlgorithm; + MICAlgorithm = rhs.MICAlgorithm; + CryptographicKeyID = rhs.CryptographicKeyID; +} + +// +void +CryptographicContext::Dump(FILE* stream) +{ + char identbuf[IdentBufferLen]; + *identbuf = 0; + + if ( stream == 0 ) + stream = stderr; + + InterchangeObject::Dump(stream); + fprintf(stream, " %22s = %s\n", "ContextID", ContextID.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " %22s = %s\n", "SourceEssenceContainer", SourceEssenceContainer.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " %22s = %s\n", "CipherAlgorithm", CipherAlgorithm.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " %22s = %s\n", "MICAlgorithm", MICAlgorithm.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " %22s = %s\n", "CryptographicKeyID", CryptographicKeyID.EncodeString(identbuf, IdentBufferLen)); +} + +// +ASDCP::Result_t +CryptographicContext::InitFromBuffer(const byte_t* p, ui32_t l) +{ + return InterchangeObject::InitFromBuffer(p, l); +} + +// +ASDCP::Result_t +CryptographicContext::WriteToBuffer(ASDCP::FrameBuffer& Buffer) +{ + return InterchangeObject::WriteToBuffer(Buffer); +} + +//------------------------------------------------------------------------------------------ +// GenericDataEssenceDescriptor + +// + +GenericDataEssenceDescriptor::GenericDataEssenceDescriptor(const Dictionary*& d) : FileDescriptor(d), m_Dict(d) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_GenericDataEssenceDescriptor); +} + +GenericDataEssenceDescriptor::GenericDataEssenceDescriptor(const GenericDataEssenceDescriptor& rhs) : FileDescriptor(rhs.m_Dict), m_Dict(rhs.m_Dict) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_GenericDataEssenceDescriptor); + Copy(rhs); +} + + +// +ASDCP::Result_t +GenericDataEssenceDescriptor::InitFromTLVSet(TLVReader& TLVSet) +{ + assert(m_Dict); + Result_t result = FileDescriptor::InitFromTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(GenericDataEssenceDescriptor, DataEssenceCoding)); + return result; +} + +// +ASDCP::Result_t +GenericDataEssenceDescriptor::WriteToTLVSet(TLVWriter& TLVSet) +{ + assert(m_Dict); + Result_t result = FileDescriptor::WriteToTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(GenericDataEssenceDescriptor, DataEssenceCoding)); + return result; +} + +// +void +GenericDataEssenceDescriptor::Copy(const GenericDataEssenceDescriptor& rhs) +{ + FileDescriptor::Copy(rhs); + DataEssenceCoding = rhs.DataEssenceCoding; +} + +// +void +GenericDataEssenceDescriptor::Dump(FILE* stream) +{ + char identbuf[IdentBufferLen]; + *identbuf = 0; + + if ( stream == 0 ) + stream = stderr; + + FileDescriptor::Dump(stream); + fprintf(stream, " %22s = %s\n", "DataEssenceCoding", DataEssenceCoding.EncodeString(identbuf, IdentBufferLen)); +} + +// +ASDCP::Result_t +GenericDataEssenceDescriptor::InitFromBuffer(const byte_t* p, ui32_t l) +{ + return InterchangeObject::InitFromBuffer(p, l); +} + +// +ASDCP::Result_t +GenericDataEssenceDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer) +{ + return InterchangeObject::WriteToBuffer(Buffer); +} + +//------------------------------------------------------------------------------------------ +// TimedTextDescriptor + +// + +TimedTextDescriptor::TimedTextDescriptor(const Dictionary*& d) : GenericDataEssenceDescriptor(d), m_Dict(d) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_TimedTextDescriptor); +} + +TimedTextDescriptor::TimedTextDescriptor(const TimedTextDescriptor& rhs) : GenericDataEssenceDescriptor(rhs.m_Dict), m_Dict(rhs.m_Dict) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_TimedTextDescriptor); + Copy(rhs); +} + + +// +ASDCP::Result_t +TimedTextDescriptor::InitFromTLVSet(TLVReader& TLVSet) +{ + assert(m_Dict); + Result_t result = GenericDataEssenceDescriptor::InitFromTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(TimedTextDescriptor, ResourceID)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(TimedTextDescriptor, UCSEncoding)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(TimedTextDescriptor, NamespaceURI)); + return result; +} + +// +ASDCP::Result_t +TimedTextDescriptor::WriteToTLVSet(TLVWriter& TLVSet) +{ + assert(m_Dict); + Result_t result = GenericDataEssenceDescriptor::WriteToTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(TimedTextDescriptor, ResourceID)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(TimedTextDescriptor, UCSEncoding)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(TimedTextDescriptor, NamespaceURI)); + return result; +} + +// +void +TimedTextDescriptor::Copy(const TimedTextDescriptor& rhs) +{ + GenericDataEssenceDescriptor::Copy(rhs); + ResourceID = rhs.ResourceID; + UCSEncoding = rhs.UCSEncoding; + NamespaceURI = rhs.NamespaceURI; +} + +// +void +TimedTextDescriptor::Dump(FILE* stream) +{ + char identbuf[IdentBufferLen]; + *identbuf = 0; + + if ( stream == 0 ) + stream = stderr; + + GenericDataEssenceDescriptor::Dump(stream); + fprintf(stream, " %22s = %s\n", "ResourceID", ResourceID.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " %22s = %s\n", "UCSEncoding", UCSEncoding.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " %22s = %s\n", "NamespaceURI", NamespaceURI.EncodeString(identbuf, IdentBufferLen)); +} + +// +ASDCP::Result_t +TimedTextDescriptor::InitFromBuffer(const byte_t* p, ui32_t l) +{ + return InterchangeObject::InitFromBuffer(p, l); +} + +// +ASDCP::Result_t +TimedTextDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer) +{ + return InterchangeObject::WriteToBuffer(Buffer); +} + +//------------------------------------------------------------------------------------------ +// TimedTextResourceSubDescriptor + +// + +TimedTextResourceSubDescriptor::TimedTextResourceSubDescriptor(const Dictionary*& d) : InterchangeObject(d), m_Dict(d), EssenceStreamID(0) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_TimedTextResourceSubDescriptor); +} + +TimedTextResourceSubDescriptor::TimedTextResourceSubDescriptor(const TimedTextResourceSubDescriptor& rhs) : InterchangeObject(rhs.m_Dict), m_Dict(rhs.m_Dict) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_TimedTextResourceSubDescriptor); + Copy(rhs); +} + + +// +ASDCP::Result_t +TimedTextResourceSubDescriptor::InitFromTLVSet(TLVReader& TLVSet) +{ + assert(m_Dict); + Result_t result = InterchangeObject::InitFromTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(TimedTextResourceSubDescriptor, AncillaryResourceID)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(TimedTextResourceSubDescriptor, MIMEMediaType)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(TimedTextResourceSubDescriptor, EssenceStreamID)); + return result; +} + +// +ASDCP::Result_t +TimedTextResourceSubDescriptor::WriteToTLVSet(TLVWriter& TLVSet) +{ + assert(m_Dict); + Result_t result = InterchangeObject::WriteToTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(TimedTextResourceSubDescriptor, AncillaryResourceID)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(TimedTextResourceSubDescriptor, MIMEMediaType)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(TimedTextResourceSubDescriptor, EssenceStreamID)); + return result; +} + +// +void +TimedTextResourceSubDescriptor::Copy(const TimedTextResourceSubDescriptor& rhs) +{ + InterchangeObject::Copy(rhs); + AncillaryResourceID = rhs.AncillaryResourceID; + MIMEMediaType = rhs.MIMEMediaType; + EssenceStreamID = rhs.EssenceStreamID; +} + +// +void +TimedTextResourceSubDescriptor::Dump(FILE* stream) +{ + char identbuf[IdentBufferLen]; + *identbuf = 0; + + if ( stream == 0 ) + stream = stderr; + + InterchangeObject::Dump(stream); + fprintf(stream, " %22s = %s\n", "AncillaryResourceID", AncillaryResourceID.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " %22s = %s\n", "MIMEMediaType", MIMEMediaType.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " %22s = %d\n", "EssenceStreamID", EssenceStreamID); +} + +// +ASDCP::Result_t +TimedTextResourceSubDescriptor::InitFromBuffer(const byte_t* p, ui32_t l) +{ + return InterchangeObject::InitFromBuffer(p, l); +} + +// +ASDCP::Result_t +TimedTextResourceSubDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer) +{ + return InterchangeObject::WriteToBuffer(Buffer); +} + +//------------------------------------------------------------------------------------------ +// StereoscopicPictureSubDescriptor + +// + +StereoscopicPictureSubDescriptor::StereoscopicPictureSubDescriptor(const Dictionary*& d) : InterchangeObject(d), m_Dict(d) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_StereoscopicPictureSubDescriptor); +} + +StereoscopicPictureSubDescriptor::StereoscopicPictureSubDescriptor(const StereoscopicPictureSubDescriptor& rhs) : InterchangeObject(rhs.m_Dict), m_Dict(rhs.m_Dict) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_StereoscopicPictureSubDescriptor); + Copy(rhs); +} + + +// +ASDCP::Result_t +StereoscopicPictureSubDescriptor::InitFromTLVSet(TLVReader& TLVSet) +{ + assert(m_Dict); + Result_t result = InterchangeObject::InitFromTLVSet(TLVSet); + return result; +} + +// +ASDCP::Result_t +StereoscopicPictureSubDescriptor::WriteToTLVSet(TLVWriter& TLVSet) +{ + assert(m_Dict); + Result_t result = InterchangeObject::WriteToTLVSet(TLVSet); + return result; +} + +// +void +StereoscopicPictureSubDescriptor::Copy(const StereoscopicPictureSubDescriptor& rhs) +{ + InterchangeObject::Copy(rhs); +} + +// +void +StereoscopicPictureSubDescriptor::Dump(FILE* stream) +{ + char identbuf[IdentBufferLen]; + *identbuf = 0; + + if ( stream == 0 ) + stream = stderr; + + InterchangeObject::Dump(stream); +} + +// +ASDCP::Result_t +StereoscopicPictureSubDescriptor::InitFromBuffer(const byte_t* p, ui32_t l) +{ + return InterchangeObject::InitFromBuffer(p, l); +} + +// +ASDCP::Result_t +StereoscopicPictureSubDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer) +{ + return InterchangeObject::WriteToBuffer(Buffer); +} + +//------------------------------------------------------------------------------------------ +// NetworkLocator + +// + +NetworkLocator::NetworkLocator(const Dictionary*& d) : InterchangeObject(d), m_Dict(d) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_NetworkLocator); +} + +NetworkLocator::NetworkLocator(const NetworkLocator& rhs) : InterchangeObject(rhs.m_Dict), m_Dict(rhs.m_Dict) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_NetworkLocator); + Copy(rhs); +} + + +// +ASDCP::Result_t +NetworkLocator::InitFromTLVSet(TLVReader& TLVSet) +{ + assert(m_Dict); + Result_t result = InterchangeObject::InitFromTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(NetworkLocator, URLString)); + return result; +} + +// +ASDCP::Result_t +NetworkLocator::WriteToTLVSet(TLVWriter& TLVSet) +{ + assert(m_Dict); + Result_t result = InterchangeObject::WriteToTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(NetworkLocator, URLString)); + return result; +} + +// +void +NetworkLocator::Copy(const NetworkLocator& rhs) +{ + InterchangeObject::Copy(rhs); + URLString = rhs.URLString; +} + +// +void +NetworkLocator::Dump(FILE* stream) +{ + char identbuf[IdentBufferLen]; + *identbuf = 0; + + if ( stream == 0 ) + stream = stderr; + + InterchangeObject::Dump(stream); + fprintf(stream, " %22s = %s\n", "URLString", URLString.EncodeString(identbuf, IdentBufferLen)); +} + +// +ASDCP::Result_t +NetworkLocator::InitFromBuffer(const byte_t* p, ui32_t l) +{ + return InterchangeObject::InitFromBuffer(p, l); +} + +// +ASDCP::Result_t +NetworkLocator::WriteToBuffer(ASDCP::FrameBuffer& Buffer) +{ + return InterchangeObject::WriteToBuffer(Buffer); +} + +//------------------------------------------------------------------------------------------ +// MCALabelSubDescriptor + +// + +MCALabelSubDescriptor::MCALabelSubDescriptor(const Dictionary*& d) : InterchangeObject(d), m_Dict(d), MCAChannelID(0) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_MCALabelSubDescriptor); +} + +MCALabelSubDescriptor::MCALabelSubDescriptor(const MCALabelSubDescriptor& rhs) : InterchangeObject(rhs.m_Dict), m_Dict(rhs.m_Dict) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_MCALabelSubDescriptor); + Copy(rhs); +} + + +// +ASDCP::Result_t +MCALabelSubDescriptor::InitFromTLVSet(TLVReader& TLVSet) +{ + assert(m_Dict); + Result_t result = InterchangeObject::InitFromTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(MCALabelSubDescriptor, MCALabelDictionaryID)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(MCALabelSubDescriptor, MCALinkID)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(MCALabelSubDescriptor, MCATagSymbol)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(MCALabelSubDescriptor, MCATagName)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(MCALabelSubDescriptor, MCAChannelID)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(MCALabelSubDescriptor, RFC5646SpokenLanguage)); + return result; +} + +// +ASDCP::Result_t +MCALabelSubDescriptor::WriteToTLVSet(TLVWriter& TLVSet) +{ + assert(m_Dict); + Result_t result = InterchangeObject::WriteToTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(MCALabelSubDescriptor, MCALabelDictionaryID)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(MCALabelSubDescriptor, MCALinkID)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(MCALabelSubDescriptor, MCATagSymbol)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(MCALabelSubDescriptor, MCATagName)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(MCALabelSubDescriptor, MCAChannelID)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(MCALabelSubDescriptor, RFC5646SpokenLanguage)); + return result; +} + +// +void +MCALabelSubDescriptor::Copy(const MCALabelSubDescriptor& rhs) +{ + InterchangeObject::Copy(rhs); + MCALabelDictionaryID = rhs.MCALabelDictionaryID; + MCALinkID = rhs.MCALinkID; + MCATagSymbol = rhs.MCATagSymbol; + MCATagName = rhs.MCATagName; + MCAChannelID = rhs.MCAChannelID; + RFC5646SpokenLanguage = rhs.RFC5646SpokenLanguage; +} + +// +void +MCALabelSubDescriptor::Dump(FILE* stream) +{ + char identbuf[IdentBufferLen]; + *identbuf = 0; + + if ( stream == 0 ) + stream = stderr; + + InterchangeObject::Dump(stream); + fprintf(stream, " %22s = %s\n", "MCALabelDictionaryID", MCALabelDictionaryID.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " %22s = %s\n", "MCALinkID", MCALinkID.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " %22s = %s\n", "MCATagSymbol", MCATagSymbol.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " %22s = %s\n", "MCATagName", MCATagName.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " %22s = %d\n", "MCAChannelID", MCAChannelID); + fprintf(stream, " %22s = %s\n", "RFC5646SpokenLanguage", RFC5646SpokenLanguage.EncodeString(identbuf, IdentBufferLen)); +} + +// +ASDCP::Result_t +MCALabelSubDescriptor::InitFromBuffer(const byte_t* p, ui32_t l) +{ + return InterchangeObject::InitFromBuffer(p, l); +} + +// +ASDCP::Result_t +MCALabelSubDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer) +{ + return InterchangeObject::WriteToBuffer(Buffer); +} + +//------------------------------------------------------------------------------------------ +// AudioChannelLabelSubDescriptor + +// + +AudioChannelLabelSubDescriptor::AudioChannelLabelSubDescriptor(const Dictionary*& d) : MCALabelSubDescriptor(d), m_Dict(d) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_AudioChannelLabelSubDescriptor); +} + +AudioChannelLabelSubDescriptor::AudioChannelLabelSubDescriptor(const AudioChannelLabelSubDescriptor& rhs) : MCALabelSubDescriptor(rhs.m_Dict), m_Dict(rhs.m_Dict) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_AudioChannelLabelSubDescriptor); + Copy(rhs); +} + + +// +ASDCP::Result_t +AudioChannelLabelSubDescriptor::InitFromTLVSet(TLVReader& TLVSet) +{ + assert(m_Dict); + Result_t result = MCALabelSubDescriptor::InitFromTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(AudioChannelLabelSubDescriptor, SoundfieldGroupLinkID)); + return result; +} + +// +ASDCP::Result_t +AudioChannelLabelSubDescriptor::WriteToTLVSet(TLVWriter& TLVSet) +{ + assert(m_Dict); + Result_t result = MCALabelSubDescriptor::WriteToTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(AudioChannelLabelSubDescriptor, SoundfieldGroupLinkID)); + return result; +} + +// +void +AudioChannelLabelSubDescriptor::Copy(const AudioChannelLabelSubDescriptor& rhs) +{ + MCALabelSubDescriptor::Copy(rhs); + SoundfieldGroupLinkID = rhs.SoundfieldGroupLinkID; +} + +// +void +AudioChannelLabelSubDescriptor::Dump(FILE* stream) +{ + char identbuf[IdentBufferLen]; + *identbuf = 0; + + if ( stream == 0 ) + stream = stderr; + + MCALabelSubDescriptor::Dump(stream); + fprintf(stream, " %22s = %s\n", "SoundfieldGroupLinkID", SoundfieldGroupLinkID.EncodeString(identbuf, IdentBufferLen)); +} + +// +ASDCP::Result_t +AudioChannelLabelSubDescriptor::InitFromBuffer(const byte_t* p, ui32_t l) +{ + return InterchangeObject::InitFromBuffer(p, l); +} + +// +ASDCP::Result_t +AudioChannelLabelSubDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer) +{ + return InterchangeObject::WriteToBuffer(Buffer); +} + +//------------------------------------------------------------------------------------------ +// SoundfieldGroupLabelSubDescriptor + +// + +SoundfieldGroupLabelSubDescriptor::SoundfieldGroupLabelSubDescriptor(const Dictionary*& d) : MCALabelSubDescriptor(d), m_Dict(d) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_SoundfieldGroupLabelSubDescriptor); +} + +SoundfieldGroupLabelSubDescriptor::SoundfieldGroupLabelSubDescriptor(const SoundfieldGroupLabelSubDescriptor& rhs) : MCALabelSubDescriptor(rhs.m_Dict), m_Dict(rhs.m_Dict) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_SoundfieldGroupLabelSubDescriptor); + Copy(rhs); +} + + +// +ASDCP::Result_t +SoundfieldGroupLabelSubDescriptor::InitFromTLVSet(TLVReader& TLVSet) +{ + assert(m_Dict); + Result_t result = MCALabelSubDescriptor::InitFromTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(SoundfieldGroupLabelSubDescriptor, GroupOfSoundfieldGroupsLinkID)); + return result; +} + +// +ASDCP::Result_t +SoundfieldGroupLabelSubDescriptor::WriteToTLVSet(TLVWriter& TLVSet) +{ + assert(m_Dict); + Result_t result = MCALabelSubDescriptor::WriteToTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(SoundfieldGroupLabelSubDescriptor, GroupOfSoundfieldGroupsLinkID)); + return result; +} + +// +void +SoundfieldGroupLabelSubDescriptor::Copy(const SoundfieldGroupLabelSubDescriptor& rhs) +{ + MCALabelSubDescriptor::Copy(rhs); + GroupOfSoundfieldGroupsLinkID = rhs.GroupOfSoundfieldGroupsLinkID; +} + +// +void +SoundfieldGroupLabelSubDescriptor::Dump(FILE* stream) +{ + char identbuf[IdentBufferLen]; + *identbuf = 0; + + if ( stream == 0 ) + stream = stderr; + + MCALabelSubDescriptor::Dump(stream); + fprintf(stream, " %22s:\n", "GroupOfSoundfieldGroupsLinkID"); + GroupOfSoundfieldGroupsLinkID.Dump(stream); +} + +// +ASDCP::Result_t +SoundfieldGroupLabelSubDescriptor::InitFromBuffer(const byte_t* p, ui32_t l) +{ + return InterchangeObject::InitFromBuffer(p, l); +} + +// +ASDCP::Result_t +SoundfieldGroupLabelSubDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer) +{ + return InterchangeObject::WriteToBuffer(Buffer); +} + +//------------------------------------------------------------------------------------------ +// GroupOfSoundfieldGroupsLabelSubDescriptor + +// + +GroupOfSoundfieldGroupsLabelSubDescriptor::GroupOfSoundfieldGroupsLabelSubDescriptor(const Dictionary*& d) : MCALabelSubDescriptor(d), m_Dict(d) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_GroupOfSoundfieldGroupsLabelSubDescriptor); +} + +GroupOfSoundfieldGroupsLabelSubDescriptor::GroupOfSoundfieldGroupsLabelSubDescriptor(const GroupOfSoundfieldGroupsLabelSubDescriptor& rhs) : MCALabelSubDescriptor(rhs.m_Dict), m_Dict(rhs.m_Dict) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_GroupOfSoundfieldGroupsLabelSubDescriptor); + Copy(rhs); +} + + +// +ASDCP::Result_t +GroupOfSoundfieldGroupsLabelSubDescriptor::InitFromTLVSet(TLVReader& TLVSet) +{ + assert(m_Dict); + Result_t result = MCALabelSubDescriptor::InitFromTLVSet(TLVSet); + return result; +} + +// +ASDCP::Result_t +GroupOfSoundfieldGroupsLabelSubDescriptor::WriteToTLVSet(TLVWriter& TLVSet) +{ + assert(m_Dict); + Result_t result = MCALabelSubDescriptor::WriteToTLVSet(TLVSet); + return result; +} + +// +void +GroupOfSoundfieldGroupsLabelSubDescriptor::Copy(const GroupOfSoundfieldGroupsLabelSubDescriptor& rhs) +{ + MCALabelSubDescriptor::Copy(rhs); +} + +// +void +GroupOfSoundfieldGroupsLabelSubDescriptor::Dump(FILE* stream) +{ + char identbuf[IdentBufferLen]; + *identbuf = 0; + + if ( stream == 0 ) + stream = stderr; + + MCALabelSubDescriptor::Dump(stream); +} + +// +ASDCP::Result_t +GroupOfSoundfieldGroupsLabelSubDescriptor::InitFromBuffer(const byte_t* p, ui32_t l) +{ + return InterchangeObject::InitFromBuffer(p, l); +} + +// +ASDCP::Result_t +GroupOfSoundfieldGroupsLabelSubDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer) +{ + return InterchangeObject::WriteToBuffer(Buffer); +} + +// +// end Metadata.cpp +// diff --git a/asdcplib/src/Metadata.h b/asdcplib/src/Metadata.h new file mode 100755 index 0000000..3360cdf --- /dev/null +++ b/asdcplib/src/Metadata.h @@ -0,0 +1,900 @@ +/* +Copyright (c) 2005-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 Metadata.h + \version $Id: Metadata.h,v 1.29 2012/02/21 02:09:31 jhurst Exp $ + \brief MXF metadata objects +*/ + +#ifndef _Metadata_H_ +#define _Metadata_H_ + +#include "MXF.h" + +namespace ASDCP +{ + namespace MXF + { + void Metadata_InitTypes(const Dictionary*& Dict); + + // + + // + class Identification : public InterchangeObject + { + Identification(); + + public: + const Dictionary*& m_Dict; + UUID ThisGenerationUID; + UTF16String CompanyName; + UTF16String ProductName; + VersionType ProductVersion; + UTF16String VersionString; + UUID ProductUID; + Kumu::Timestamp ModificationDate; + VersionType ToolkitVersion; + UTF16String Platform; + + Identification(const Dictionary*& d); + Identification(const Identification& rhs); + virtual ~Identification() {} + + const Identification& operator=(const Identification& rhs) { Copy(rhs); return *this; } + virtual void Copy(const Identification& rhs); + virtual const char* HasName() { return "Identification"; } + virtual Result_t InitFromTLVSet(TLVReader& TLVSet); + virtual Result_t WriteToTLVSet(TLVWriter& TLVSet); + virtual void Dump(FILE* = 0); + virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l); + virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&); + }; + + // + class ContentStorage : public InterchangeObject + { + ContentStorage(); + + public: + const Dictionary*& m_Dict; + Batch<UUID> Packages; + Batch<UUID> EssenceContainerData; + + ContentStorage(const Dictionary*& d); + ContentStorage(const ContentStorage& rhs); + virtual ~ContentStorage() {} + + const ContentStorage& operator=(const ContentStorage& rhs) { Copy(rhs); return *this; } + virtual void Copy(const ContentStorage& rhs); + virtual const char* HasName() { return "ContentStorage"; } + virtual Result_t InitFromTLVSet(TLVReader& TLVSet); + virtual Result_t WriteToTLVSet(TLVWriter& TLVSet); + virtual void Dump(FILE* = 0); + virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l); + virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&); + }; + + // + class EssenceContainerData : public InterchangeObject + { + EssenceContainerData(); + + public: + const Dictionary*& m_Dict; + UMID LinkedPackageUID; + ui32_t IndexSID; + ui32_t BodySID; + + EssenceContainerData(const Dictionary*& d); + EssenceContainerData(const EssenceContainerData& rhs); + virtual ~EssenceContainerData() {} + + const EssenceContainerData& operator=(const EssenceContainerData& rhs) { Copy(rhs); return *this; } + virtual void Copy(const EssenceContainerData& rhs); + virtual const char* HasName() { return "EssenceContainerData"; } + virtual Result_t InitFromTLVSet(TLVReader& TLVSet); + virtual Result_t WriteToTLVSet(TLVWriter& TLVSet); + virtual void Dump(FILE* = 0); + virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l); + virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&); + }; + + // + class GenericPackage : public InterchangeObject + { + GenericPackage(); + + public: + const Dictionary*& m_Dict; + UMID PackageUID; + UTF16String Name; + Kumu::Timestamp PackageCreationDate; + Kumu::Timestamp PackageModifiedDate; + Batch<UUID> Tracks; + + GenericPackage(const Dictionary*& d); + GenericPackage(const GenericPackage& rhs); + virtual ~GenericPackage() {} + + const GenericPackage& operator=(const GenericPackage& rhs) { Copy(rhs); return *this; } + virtual void Copy(const GenericPackage& rhs); + virtual const char* HasName() { return "GenericPackage"; } + virtual Result_t InitFromTLVSet(TLVReader& TLVSet); + virtual Result_t WriteToTLVSet(TLVWriter& TLVSet); + virtual void Dump(FILE* = 0); + }; + + // + class MaterialPackage : public GenericPackage + { + MaterialPackage(); + + public: + const Dictionary*& m_Dict; + + MaterialPackage(const Dictionary*& d); + MaterialPackage(const MaterialPackage& rhs); + virtual ~MaterialPackage() {} + + const MaterialPackage& operator=(const MaterialPackage& rhs) { Copy(rhs); return *this; } + virtual void Copy(const MaterialPackage& rhs); + virtual const char* HasName() { return "MaterialPackage"; } + virtual Result_t InitFromTLVSet(TLVReader& TLVSet); + virtual Result_t WriteToTLVSet(TLVWriter& TLVSet); + virtual void Dump(FILE* = 0); + virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l); + virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&); + }; + + // + class SourcePackage : public GenericPackage + { + SourcePackage(); + + public: + const Dictionary*& m_Dict; + UUID Descriptor; + + SourcePackage(const Dictionary*& d); + SourcePackage(const SourcePackage& rhs); + virtual ~SourcePackage() {} + + const SourcePackage& operator=(const SourcePackage& rhs) { Copy(rhs); return *this; } + virtual void Copy(const SourcePackage& rhs); + virtual const char* HasName() { return "SourcePackage"; } + virtual Result_t InitFromTLVSet(TLVReader& TLVSet); + virtual Result_t WriteToTLVSet(TLVWriter& TLVSet); + virtual void Dump(FILE* = 0); + virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l); + virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&); + }; + + // + class GenericTrack : public InterchangeObject + { + GenericTrack(); + + public: + const Dictionary*& m_Dict; + ui32_t TrackID; + ui32_t TrackNumber; + UTF16String TrackName; + UUID Sequence; + + GenericTrack(const Dictionary*& d); + GenericTrack(const GenericTrack& rhs); + virtual ~GenericTrack() {} + + const GenericTrack& operator=(const GenericTrack& rhs) { Copy(rhs); return *this; } + virtual void Copy(const GenericTrack& rhs); + virtual const char* HasName() { return "GenericTrack"; } + virtual Result_t InitFromTLVSet(TLVReader& TLVSet); + virtual Result_t WriteToTLVSet(TLVWriter& TLVSet); + virtual void Dump(FILE* = 0); + }; + + // + class StaticTrack : public GenericTrack + { + StaticTrack(); + + public: + const Dictionary*& m_Dict; + + StaticTrack(const Dictionary*& d); + StaticTrack(const StaticTrack& rhs); + virtual ~StaticTrack() {} + + const StaticTrack& operator=(const StaticTrack& rhs) { Copy(rhs); return *this; } + virtual void Copy(const StaticTrack& rhs); + virtual const char* HasName() { return "StaticTrack"; } + virtual Result_t InitFromTLVSet(TLVReader& TLVSet); + virtual Result_t WriteToTLVSet(TLVWriter& TLVSet); + virtual void Dump(FILE* = 0); + virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l); + virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&); + }; + + // + class Track : public GenericTrack + { + Track(); + + public: + const Dictionary*& m_Dict; + Rational EditRate; + ui64_t Origin; + + Track(const Dictionary*& d); + Track(const Track& rhs); + virtual ~Track() {} + + const Track& operator=(const Track& rhs) { Copy(rhs); return *this; } + virtual void Copy(const Track& rhs); + virtual const char* HasName() { return "Track"; } + virtual Result_t InitFromTLVSet(TLVReader& TLVSet); + virtual Result_t WriteToTLVSet(TLVWriter& TLVSet); + virtual void Dump(FILE* = 0); + virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l); + virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&); + }; + + // + class StructuralComponent : public InterchangeObject + { + StructuralComponent(); + + public: + const Dictionary*& m_Dict; + UL DataDefinition; + ui64_t Duration; + + StructuralComponent(const Dictionary*& d); + StructuralComponent(const StructuralComponent& rhs); + virtual ~StructuralComponent() {} + + const StructuralComponent& operator=(const StructuralComponent& rhs) { Copy(rhs); return *this; } + virtual void Copy(const StructuralComponent& rhs); + virtual const char* HasName() { return "StructuralComponent"; } + virtual Result_t InitFromTLVSet(TLVReader& TLVSet); + virtual Result_t WriteToTLVSet(TLVWriter& TLVSet); + virtual void Dump(FILE* = 0); + }; + + // + class Sequence : public StructuralComponent + { + Sequence(); + + public: + const Dictionary*& m_Dict; + Batch<UUID> StructuralComponents; + + Sequence(const Dictionary*& d); + Sequence(const Sequence& rhs); + virtual ~Sequence() {} + + const Sequence& operator=(const Sequence& rhs) { Copy(rhs); return *this; } + virtual void Copy(const Sequence& rhs); + virtual const char* HasName() { return "Sequence"; } + virtual Result_t InitFromTLVSet(TLVReader& TLVSet); + virtual Result_t WriteToTLVSet(TLVWriter& TLVSet); + virtual void Dump(FILE* = 0); + virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l); + virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&); + }; + + // + class SourceClip : public StructuralComponent + { + SourceClip(); + + public: + const Dictionary*& m_Dict; + ui64_t StartPosition; + UMID SourcePackageID; + ui32_t SourceTrackID; + + SourceClip(const Dictionary*& d); + SourceClip(const SourceClip& rhs); + virtual ~SourceClip() {} + + const SourceClip& operator=(const SourceClip& rhs) { Copy(rhs); return *this; } + virtual void Copy(const SourceClip& rhs); + virtual const char* HasName() { return "SourceClip"; } + virtual Result_t InitFromTLVSet(TLVReader& TLVSet); + virtual Result_t WriteToTLVSet(TLVWriter& TLVSet); + virtual void Dump(FILE* = 0); + virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l); + virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&); + }; + + // + class TimecodeComponent : public StructuralComponent + { + TimecodeComponent(); + + public: + const Dictionary*& m_Dict; + ui16_t RoundedTimecodeBase; + ui64_t StartTimecode; + ui8_t DropFrame; + + TimecodeComponent(const Dictionary*& d); + TimecodeComponent(const TimecodeComponent& rhs); + virtual ~TimecodeComponent() {} + + const TimecodeComponent& operator=(const TimecodeComponent& rhs) { Copy(rhs); return *this; } + virtual void Copy(const TimecodeComponent& rhs); + virtual const char* HasName() { return "TimecodeComponent"; } + virtual Result_t InitFromTLVSet(TLVReader& TLVSet); + virtual Result_t WriteToTLVSet(TLVWriter& TLVSet); + virtual void Dump(FILE* = 0); + virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l); + virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&); + }; + + // + class GenericDescriptor : public InterchangeObject + { + GenericDescriptor(); + + public: + const Dictionary*& m_Dict; + Batch<UUID> Locators; + Batch<UUID> SubDescriptors; + + GenericDescriptor(const Dictionary*& d); + GenericDescriptor(const GenericDescriptor& rhs); + virtual ~GenericDescriptor() {} + + const GenericDescriptor& operator=(const GenericDescriptor& rhs) { Copy(rhs); return *this; } + virtual void Copy(const GenericDescriptor& rhs); + virtual const char* HasName() { return "GenericDescriptor"; } + virtual Result_t InitFromTLVSet(TLVReader& TLVSet); + virtual Result_t WriteToTLVSet(TLVWriter& TLVSet); + virtual void Dump(FILE* = 0); + }; + + // + class FileDescriptor : public GenericDescriptor + { + FileDescriptor(); + + public: + const Dictionary*& m_Dict; + ui32_t LinkedTrackID; + Rational SampleRate; + ui64_t ContainerDuration; + UL EssenceContainer; + UL Codec; + + FileDescriptor(const Dictionary*& d); + FileDescriptor(const FileDescriptor& rhs); + virtual ~FileDescriptor() {} + + const FileDescriptor& operator=(const FileDescriptor& rhs) { Copy(rhs); return *this; } + virtual void Copy(const FileDescriptor& rhs); + virtual const char* HasName() { return "FileDescriptor"; } + virtual Result_t InitFromTLVSet(TLVReader& TLVSet); + virtual Result_t WriteToTLVSet(TLVWriter& TLVSet); + virtual void Dump(FILE* = 0); + virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l); + virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&); + }; + + // + class GenericSoundEssenceDescriptor : public FileDescriptor + { + GenericSoundEssenceDescriptor(); + + public: + const Dictionary*& m_Dict; + Rational AudioSamplingRate; + ui8_t Locked; + ui8_t AudioRefLevel; + ui32_t ChannelCount; + ui32_t QuantizationBits; + ui8_t DialNorm; + + GenericSoundEssenceDescriptor(const Dictionary*& d); + GenericSoundEssenceDescriptor(const GenericSoundEssenceDescriptor& rhs); + virtual ~GenericSoundEssenceDescriptor() {} + + const GenericSoundEssenceDescriptor& operator=(const GenericSoundEssenceDescriptor& rhs) { Copy(rhs); return *this; } + virtual void Copy(const GenericSoundEssenceDescriptor& rhs); + virtual const char* HasName() { return "GenericSoundEssenceDescriptor"; } + virtual Result_t InitFromTLVSet(TLVReader& TLVSet); + virtual Result_t WriteToTLVSet(TLVWriter& TLVSet); + virtual void Dump(FILE* = 0); + virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l); + virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&); + }; + + // + class WaveAudioDescriptor : public GenericSoundEssenceDescriptor + { + WaveAudioDescriptor(); + + public: + const Dictionary*& m_Dict; + ui16_t BlockAlign; + ui8_t SequenceOffset; + ui32_t AvgBps; + UL ChannelAssignment; + + WaveAudioDescriptor(const Dictionary*& d); + WaveAudioDescriptor(const WaveAudioDescriptor& rhs); + virtual ~WaveAudioDescriptor() {} + + const WaveAudioDescriptor& operator=(const WaveAudioDescriptor& rhs) { Copy(rhs); return *this; } + virtual void Copy(const WaveAudioDescriptor& rhs); + virtual const char* HasName() { return "WaveAudioDescriptor"; } + virtual Result_t InitFromTLVSet(TLVReader& TLVSet); + virtual Result_t WriteToTLVSet(TLVWriter& TLVSet); + virtual void Dump(FILE* = 0); + virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l); + virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&); + }; + + // + class GenericPictureEssenceDescriptor : public FileDescriptor + { + GenericPictureEssenceDescriptor(); + + public: + const Dictionary*& m_Dict; + ui8_t FrameLayout; + ui32_t StoredWidth; + ui32_t StoredHeight; + Rational AspectRatio; + UL PictureEssenceCoding; + + GenericPictureEssenceDescriptor(const Dictionary*& d); + GenericPictureEssenceDescriptor(const GenericPictureEssenceDescriptor& rhs); + virtual ~GenericPictureEssenceDescriptor() {} + + const GenericPictureEssenceDescriptor& operator=(const GenericPictureEssenceDescriptor& rhs) { Copy(rhs); return *this; } + virtual void Copy(const GenericPictureEssenceDescriptor& rhs); + virtual const char* HasName() { return "GenericPictureEssenceDescriptor"; } + virtual Result_t InitFromTLVSet(TLVReader& TLVSet); + virtual Result_t WriteToTLVSet(TLVWriter& TLVSet); + virtual void Dump(FILE* = 0); + virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l); + virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&); + }; + + // + class RGBAEssenceDescriptor : public GenericPictureEssenceDescriptor + { + RGBAEssenceDescriptor(); + + public: + const Dictionary*& m_Dict; + ui32_t ComponentMaxRef; + ui32_t ComponentMinRef; + + RGBAEssenceDescriptor(const Dictionary*& d); + RGBAEssenceDescriptor(const RGBAEssenceDescriptor& rhs); + virtual ~RGBAEssenceDescriptor() {} + + const RGBAEssenceDescriptor& operator=(const RGBAEssenceDescriptor& rhs) { Copy(rhs); return *this; } + virtual void Copy(const RGBAEssenceDescriptor& rhs); + virtual const char* HasName() { return "RGBAEssenceDescriptor"; } + virtual Result_t InitFromTLVSet(TLVReader& TLVSet); + virtual Result_t WriteToTLVSet(TLVWriter& TLVSet); + virtual void Dump(FILE* = 0); + virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l); + virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&); + }; + + // + class JPEG2000PictureSubDescriptor : public InterchangeObject + { + JPEG2000PictureSubDescriptor(); + + public: + const Dictionary*& m_Dict; + 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; + Raw PictureComponentSizing; + Raw CodingStyleDefault; + Raw QuantizationDefault; + + JPEG2000PictureSubDescriptor(const Dictionary*& d); + JPEG2000PictureSubDescriptor(const JPEG2000PictureSubDescriptor& rhs); + virtual ~JPEG2000PictureSubDescriptor() {} + + const JPEG2000PictureSubDescriptor& operator=(const JPEG2000PictureSubDescriptor& rhs) { Copy(rhs); return *this; } + virtual void Copy(const JPEG2000PictureSubDescriptor& rhs); + virtual const char* HasName() { return "JPEG2000PictureSubDescriptor"; } + virtual Result_t InitFromTLVSet(TLVReader& TLVSet); + virtual Result_t WriteToTLVSet(TLVWriter& TLVSet); + virtual void Dump(FILE* = 0); + virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l); + virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&); + }; + + // + class CDCIEssenceDescriptor : public GenericPictureEssenceDescriptor + { + CDCIEssenceDescriptor(); + + public: + const Dictionary*& m_Dict; + ui32_t ComponentDepth; + ui32_t HorizontalSubsampling; + ui32_t VerticalSubsampling; + ui8_t ColorSiting; + + CDCIEssenceDescriptor(const Dictionary*& d); + CDCIEssenceDescriptor(const CDCIEssenceDescriptor& rhs); + virtual ~CDCIEssenceDescriptor() {} + + const CDCIEssenceDescriptor& operator=(const CDCIEssenceDescriptor& rhs) { Copy(rhs); return *this; } + virtual void Copy(const CDCIEssenceDescriptor& rhs); + virtual const char* HasName() { return "CDCIEssenceDescriptor"; } + virtual Result_t InitFromTLVSet(TLVReader& TLVSet); + virtual Result_t WriteToTLVSet(TLVWriter& TLVSet); + virtual void Dump(FILE* = 0); + virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l); + virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&); + }; + + // + class MPEG2VideoDescriptor : public CDCIEssenceDescriptor + { + MPEG2VideoDescriptor(); + + public: + const Dictionary*& m_Dict; + ui8_t CodedContentType; + ui8_t LowDelay; + ui32_t BitRate; + ui8_t ProfileAndLevel; + + MPEG2VideoDescriptor(const Dictionary*& d); + MPEG2VideoDescriptor(const MPEG2VideoDescriptor& rhs); + virtual ~MPEG2VideoDescriptor() {} + + const MPEG2VideoDescriptor& operator=(const MPEG2VideoDescriptor& rhs) { Copy(rhs); return *this; } + virtual void Copy(const MPEG2VideoDescriptor& rhs); + virtual const char* HasName() { return "MPEG2VideoDescriptor"; } + virtual Result_t InitFromTLVSet(TLVReader& TLVSet); + virtual Result_t WriteToTLVSet(TLVWriter& TLVSet); + virtual void Dump(FILE* = 0); + virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l); + virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&); + }; + + // + class DMSegment : public InterchangeObject + { + DMSegment(); + + public: + const Dictionary*& m_Dict; + UL DataDefinition; + ui64_t EventStartPosition; + ui64_t Duration; + UTF16String EventComment; + UUID DMFramework; + + DMSegment(const Dictionary*& d); + DMSegment(const DMSegment& rhs); + virtual ~DMSegment() {} + + const DMSegment& operator=(const DMSegment& rhs) { Copy(rhs); return *this; } + virtual void Copy(const DMSegment& rhs); + virtual const char* HasName() { return "DMSegment"; } + virtual Result_t InitFromTLVSet(TLVReader& TLVSet); + virtual Result_t WriteToTLVSet(TLVWriter& TLVSet); + virtual void Dump(FILE* = 0); + virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l); + virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&); + }; + + // + class CryptographicFramework : public InterchangeObject + { + CryptographicFramework(); + + public: + const Dictionary*& m_Dict; + UUID ContextSR; + + CryptographicFramework(const Dictionary*& d); + CryptographicFramework(const CryptographicFramework& rhs); + virtual ~CryptographicFramework() {} + + const CryptographicFramework& operator=(const CryptographicFramework& rhs) { Copy(rhs); return *this; } + virtual void Copy(const CryptographicFramework& rhs); + virtual const char* HasName() { return "CryptographicFramework"; } + virtual Result_t InitFromTLVSet(TLVReader& TLVSet); + virtual Result_t WriteToTLVSet(TLVWriter& TLVSet); + virtual void Dump(FILE* = 0); + virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l); + virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&); + }; + + // + class CryptographicContext : public InterchangeObject + { + CryptographicContext(); + + public: + const Dictionary*& m_Dict; + UUID ContextID; + UL SourceEssenceContainer; + UL CipherAlgorithm; + UL MICAlgorithm; + UUID CryptographicKeyID; + + CryptographicContext(const Dictionary*& d); + CryptographicContext(const CryptographicContext& rhs); + virtual ~CryptographicContext() {} + + const CryptographicContext& operator=(const CryptographicContext& rhs) { Copy(rhs); return *this; } + virtual void Copy(const CryptographicContext& rhs); + virtual const char* HasName() { return "CryptographicContext"; } + virtual Result_t InitFromTLVSet(TLVReader& TLVSet); + virtual Result_t WriteToTLVSet(TLVWriter& TLVSet); + virtual void Dump(FILE* = 0); + virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l); + virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&); + }; + + // + class GenericDataEssenceDescriptor : public FileDescriptor + { + GenericDataEssenceDescriptor(); + + public: + const Dictionary*& m_Dict; + UL DataEssenceCoding; + + GenericDataEssenceDescriptor(const Dictionary*& d); + GenericDataEssenceDescriptor(const GenericDataEssenceDescriptor& rhs); + virtual ~GenericDataEssenceDescriptor() {} + + const GenericDataEssenceDescriptor& operator=(const GenericDataEssenceDescriptor& rhs) { Copy(rhs); return *this; } + virtual void Copy(const GenericDataEssenceDescriptor& rhs); + virtual const char* HasName() { return "GenericDataEssenceDescriptor"; } + virtual Result_t InitFromTLVSet(TLVReader& TLVSet); + virtual Result_t WriteToTLVSet(TLVWriter& TLVSet); + virtual void Dump(FILE* = 0); + virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l); + virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&); + }; + + // + class TimedTextDescriptor : public GenericDataEssenceDescriptor + { + TimedTextDescriptor(); + + public: + const Dictionary*& m_Dict; + UUID ResourceID; + UTF16String UCSEncoding; + UTF16String NamespaceURI; + + TimedTextDescriptor(const Dictionary*& d); + TimedTextDescriptor(const TimedTextDescriptor& rhs); + virtual ~TimedTextDescriptor() {} + + const TimedTextDescriptor& operator=(const TimedTextDescriptor& rhs) { Copy(rhs); return *this; } + virtual void Copy(const TimedTextDescriptor& rhs); + virtual const char* HasName() { return "TimedTextDescriptor"; } + virtual Result_t InitFromTLVSet(TLVReader& TLVSet); + virtual Result_t WriteToTLVSet(TLVWriter& TLVSet); + virtual void Dump(FILE* = 0); + virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l); + virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&); + }; + + // + class TimedTextResourceSubDescriptor : public InterchangeObject + { + TimedTextResourceSubDescriptor(); + + public: + const Dictionary*& m_Dict; + UUID AncillaryResourceID; + UTF16String MIMEMediaType; + ui32_t EssenceStreamID; + + TimedTextResourceSubDescriptor(const Dictionary*& d); + TimedTextResourceSubDescriptor(const TimedTextResourceSubDescriptor& rhs); + virtual ~TimedTextResourceSubDescriptor() {} + + const TimedTextResourceSubDescriptor& operator=(const TimedTextResourceSubDescriptor& rhs) { Copy(rhs); return *this; } + virtual void Copy(const TimedTextResourceSubDescriptor& rhs); + virtual const char* HasName() { return "TimedTextResourceSubDescriptor"; } + virtual Result_t InitFromTLVSet(TLVReader& TLVSet); + virtual Result_t WriteToTLVSet(TLVWriter& TLVSet); + virtual void Dump(FILE* = 0); + virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l); + virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&); + }; + + // + class StereoscopicPictureSubDescriptor : public InterchangeObject + { + StereoscopicPictureSubDescriptor(); + + public: + const Dictionary*& m_Dict; + + StereoscopicPictureSubDescriptor(const Dictionary*& d); + StereoscopicPictureSubDescriptor(const StereoscopicPictureSubDescriptor& rhs); + virtual ~StereoscopicPictureSubDescriptor() {} + + const StereoscopicPictureSubDescriptor& operator=(const StereoscopicPictureSubDescriptor& rhs) { Copy(rhs); return *this; } + virtual void Copy(const StereoscopicPictureSubDescriptor& rhs); + virtual const char* HasName() { return "StereoscopicPictureSubDescriptor"; } + virtual Result_t InitFromTLVSet(TLVReader& TLVSet); + virtual Result_t WriteToTLVSet(TLVWriter& TLVSet); + virtual void Dump(FILE* = 0); + virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l); + virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&); + }; + + // + class NetworkLocator : public InterchangeObject + { + NetworkLocator(); + + public: + const Dictionary*& m_Dict; + UTF16String URLString; + + NetworkLocator(const Dictionary*& d); + NetworkLocator(const NetworkLocator& rhs); + virtual ~NetworkLocator() {} + + const NetworkLocator& operator=(const NetworkLocator& rhs) { Copy(rhs); return *this; } + virtual void Copy(const NetworkLocator& rhs); + virtual const char* HasName() { return "NetworkLocator"; } + virtual Result_t InitFromTLVSet(TLVReader& TLVSet); + virtual Result_t WriteToTLVSet(TLVWriter& TLVSet); + virtual void Dump(FILE* = 0); + virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l); + virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&); + }; + + // + class MCALabelSubDescriptor : public InterchangeObject + { + MCALabelSubDescriptor(); + + public: + const Dictionary*& m_Dict; + UL MCALabelDictionaryID; + UUID MCALinkID; + UTF16String MCATagSymbol; + UTF16String MCATagName; + ui32_t MCAChannelID; + ISO8String RFC5646SpokenLanguage; + + MCALabelSubDescriptor(const Dictionary*& d); + MCALabelSubDescriptor(const MCALabelSubDescriptor& rhs); + virtual ~MCALabelSubDescriptor() {} + + const MCALabelSubDescriptor& operator=(const MCALabelSubDescriptor& rhs) { Copy(rhs); return *this; } + virtual void Copy(const MCALabelSubDescriptor& rhs); + virtual const char* HasName() { return "MCALabelSubDescriptor"; } + virtual Result_t InitFromTLVSet(TLVReader& TLVSet); + virtual Result_t WriteToTLVSet(TLVWriter& TLVSet); + virtual void Dump(FILE* = 0); + virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l); + virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&); + }; + + // + class AudioChannelLabelSubDescriptor : public MCALabelSubDescriptor + { + AudioChannelLabelSubDescriptor(); + + public: + const Dictionary*& m_Dict; + UUID SoundfieldGroupLinkID; + + AudioChannelLabelSubDescriptor(const Dictionary*& d); + AudioChannelLabelSubDescriptor(const AudioChannelLabelSubDescriptor& rhs); + virtual ~AudioChannelLabelSubDescriptor() {} + + const AudioChannelLabelSubDescriptor& operator=(const AudioChannelLabelSubDescriptor& rhs) { Copy(rhs); return *this; } + virtual void Copy(const AudioChannelLabelSubDescriptor& rhs); + virtual const char* HasName() { return "AudioChannelLabelSubDescriptor"; } + virtual Result_t InitFromTLVSet(TLVReader& TLVSet); + virtual Result_t WriteToTLVSet(TLVWriter& TLVSet); + virtual void Dump(FILE* = 0); + virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l); + virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&); + }; + + // + class SoundfieldGroupLabelSubDescriptor : public MCALabelSubDescriptor + { + SoundfieldGroupLabelSubDescriptor(); + + public: + const Dictionary*& m_Dict; + Array<UUID> GroupOfSoundfieldGroupsLinkID; + + SoundfieldGroupLabelSubDescriptor(const Dictionary*& d); + SoundfieldGroupLabelSubDescriptor(const SoundfieldGroupLabelSubDescriptor& rhs); + virtual ~SoundfieldGroupLabelSubDescriptor() {} + + const SoundfieldGroupLabelSubDescriptor& operator=(const SoundfieldGroupLabelSubDescriptor& rhs) { Copy(rhs); return *this; } + virtual void Copy(const SoundfieldGroupLabelSubDescriptor& rhs); + virtual const char* HasName() { return "SoundfieldGroupLabelSubDescriptor"; } + virtual Result_t InitFromTLVSet(TLVReader& TLVSet); + virtual Result_t WriteToTLVSet(TLVWriter& TLVSet); + virtual void Dump(FILE* = 0); + virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l); + virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&); + }; + + // + class GroupOfSoundfieldGroupsLabelSubDescriptor : public MCALabelSubDescriptor + { + GroupOfSoundfieldGroupsLabelSubDescriptor(); + + public: + const Dictionary*& m_Dict; + + GroupOfSoundfieldGroupsLabelSubDescriptor(const Dictionary*& d); + GroupOfSoundfieldGroupsLabelSubDescriptor(const GroupOfSoundfieldGroupsLabelSubDescriptor& rhs); + virtual ~GroupOfSoundfieldGroupsLabelSubDescriptor() {} + + const GroupOfSoundfieldGroupsLabelSubDescriptor& operator=(const GroupOfSoundfieldGroupsLabelSubDescriptor& rhs) { Copy(rhs); return *this; } + virtual void Copy(const GroupOfSoundfieldGroupsLabelSubDescriptor& rhs); + virtual const char* HasName() { return "GroupOfSoundfieldGroupsLabelSubDescriptor"; } + virtual Result_t InitFromTLVSet(TLVReader& TLVSet); + virtual Result_t WriteToTLVSet(TLVWriter& TLVSet); + virtual void Dump(FILE* = 0); + virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l); + virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&); + }; + + } // namespace MXF +} // namespace ASDCP + + +#endif // _Metadata_H_ + +// +// end Metadata.h +// diff --git a/asdcplib/src/PCMParserList.cpp b/asdcplib/src/PCMParserList.cpp new file mode 100755 index 0000000..444b883 --- /dev/null +++ b/asdcplib/src/PCMParserList.cpp @@ -0,0 +1,285 @@ +/* +Copyright (c) 2004-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 PCMParserList.cpp + \version $Id: PCMParserList.cpp,v 1.9 2012/02/21 02:09:31 jhurst Exp $ + \brief Read WAV file(s), multiplex multiple PCM frame buffers into one +*/ + +#include <PCMParserList.h> +#include <KM_fileio.h> +#include <KM_log.h> +#include <assert.h> + +using namespace ASDCP; +using namespace Kumu; + + +ASDCP::ParserInstance::ParserInstance() : m_p(0), m_SampleSize(0) +{ +} + +ASDCP::ParserInstance::~ParserInstance() +{ +} + +// PCM::CalcSampleSize(ADesc); +Result_t +ASDCP::ParserInstance::OpenRead(const char* filename, const Rational& PictureRate) +{ + ASDCP_TEST_NULL_STR(filename); + + Result_t result = Parser.OpenRead(filename, PictureRate); + + if ( ASDCP_SUCCESS(result) ) + result = Parser.FillAudioDescriptor(ADesc); + + if ( ASDCP_SUCCESS(result) ) + { + ADesc.EditRate = PictureRate; + m_SampleSize = PCM::CalcSampleSize(ADesc); + result = FB.Capacity(PCM::CalcFrameBufferSize(ADesc)); + } + + return result; +} + + +// deposit the next available sample into the given framebuffer +Result_t +ASDCP::ParserInstance::PutSample(byte_t* p) +{ + ASDCP_TEST_NULL(p); + + memcpy(p, m_p, m_SampleSize); + m_p += m_SampleSize; + return RESULT_OK; +} + + +// +Result_t +ASDCP::ParserInstance::ReadFrame() +{ + Result_t result = Parser.ReadFrame(FB); + m_p = ASDCP_SUCCESS(result) ? FB.RoData() : 0; + return result; +} + + +//------------------------------------------------------------------------------------------ +// + + +// +ASDCP::PCMParserList::PCMParserList() : m_ChannelCount(0) +{ +} + +ASDCP::PCMParserList::~PCMParserList() +{ + while ( ! empty() ) + { + delete back(); + pop_back(); + } +} + +// +Result_t +ASDCP::PCMParserList::OpenRead(ui32_t argc, const char** argv, const Rational& PictureRate) +{ + ASDCP_TEST_NULL_STR(argv); + PathList_t TmpFileList; + + for ( ui32_t i = 0; i < argc; ++i ) + TmpFileList.push_back(argv[i]); + + return OpenRead(TmpFileList, PictureRate); +} + +// +Result_t +ASDCP::PCMParserList::OpenRead(const Kumu::PathList_t& argv, const Rational& PictureRate) +{ + Result_t result = RESULT_OK; + PathList_t::iterator fi; + Kumu::PathList_t file_list; + + if ( argv.size() == 1 && PathIsDirectory(argv.front()) ) + { + DirScanner Dir; + char name_buf[MaxFilePath]; + result = Dir.Open(argv.front().c_str()); + + if ( KM_SUCCESS(result) ) + result = Dir.GetNext(name_buf); + + while ( KM_SUCCESS(result) ) + { + if ( name_buf[0] != '.' ) // no hidden files + { + std::string tmp_path = argv.front() + "/" + name_buf; + file_list.push_back(tmp_path); + } + + result = Dir.GetNext(name_buf); + } + + if ( result == RESULT_ENDOFFILE ) + { + result = RESULT_OK; + file_list.sort(); + } + } + else + { + file_list = argv; + } + + for ( fi = file_list.begin(); KM_SUCCESS(result) && fi != file_list.end(); ++fi ) + { + mem_ptr<ParserInstance> I = new ParserInstance; + result = I->OpenRead(fi->c_str(), PictureRate); + + if ( ASDCP_SUCCESS(result) ) + { + if ( fi == file_list.begin() ) + { + m_ADesc = I->ADesc; + } + else + { + if ( I->ADesc.AudioSamplingRate != m_ADesc.AudioSamplingRate ) + { + DefaultLogSink().Error("AudioSamplingRate mismatch in PCM parser list."); + return RESULT_FORMAT; + } + + if ( I->ADesc.QuantizationBits != m_ADesc.QuantizationBits ) + { + DefaultLogSink().Error("QuantizationBits mismatch in PCM parser list."); + return RESULT_FORMAT; + } + + if ( I->ADesc.ContainerDuration < m_ADesc.ContainerDuration ) + m_ADesc.ContainerDuration = I->ADesc.ContainerDuration; + + m_ADesc.BlockAlign += I->ADesc.BlockAlign; + } + + m_ChannelCount += I->ADesc.ChannelCount; + } + + if ( ASDCP_SUCCESS(result) ) + result = I->FB.Capacity(PCM::CalcFrameBufferSize(m_ADesc)); + + if ( ASDCP_SUCCESS(result) ) + { + push_back(I); + I.release(); + } + } + + if ( ASDCP_SUCCESS(result) ) + { + m_ADesc.ChannelCount = m_ChannelCount; + m_ADesc.AvgBps = (ui32_t)(ceil(m_ADesc.AudioSamplingRate.Quotient()) * m_ADesc.BlockAlign); + } + else + { + clear(); + } + + return result; +} + +// +Result_t +ASDCP::PCMParserList::FillAudioDescriptor(PCM::AudioDescriptor& ADesc) const +{ + ADesc = m_ADesc; + return RESULT_OK; +} + +// +Result_t +ASDCP::PCMParserList::Reset() +{ + Result_t result = RESULT_OK; + PCMParserList::iterator self_i; + + for ( self_i = begin(); self_i != end() && ASDCP_SUCCESS(result) ; self_i++ ) + result = (*self_i)->Parser.Reset(); + + return result; +} + + +// +Result_t +ASDCP::PCMParserList::ReadFrame(PCM::FrameBuffer& OutFB) +{ + Result_t result = RESULT_OK; + + if ( size() == 1 ) + return front()->Parser.ReadFrame(OutFB); + + PCMParserList::iterator self_i; + assert(PCM::CalcFrameBufferSize(m_ADesc) <= OutFB.Capacity()); + + for ( self_i = begin(); self_i != end() && ASDCP_SUCCESS(result) ; self_i++ ) + result = (*self_i)->ReadFrame(); + + if ( ASDCP_SUCCESS(result) ) + { + OutFB.Size(PCM::CalcFrameBufferSize(m_ADesc)); + + // ui32_t sample_size = (PCM::CalcSampleSize(m_ADesc)); + byte_t* Out_p = OutFB.Data(); + byte_t* End_p = Out_p + OutFB.Size(); + + while ( Out_p < End_p && ASDCP_SUCCESS(result) ) + { + self_i = begin(); + + while ( self_i != end() && ASDCP_SUCCESS(result) ) + { + result = (*self_i)->PutSample(Out_p); + Out_p += (*self_i)->SampleSize(); + self_i++; + } + } + + assert(Out_p == End_p); + } + + return result; +} + +// +// end PCMParserList.cpp +// diff --git a/asdcplib/src/PCMParserList.h b/asdcplib/src/PCMParserList.h new file mode 100755 index 0000000..b744531 --- /dev/null +++ b/asdcplib/src/PCMParserList.h @@ -0,0 +1,89 @@ +/* +Copyright (c) 2004-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 PCMParserList.h + \version $Id: PCMParserList.h,v 1.4 2012/02/03 19:49:56 jhurst Exp $ + \brief Read WAV file(s), multiplex multiple PCM frame buffers into one +*/ + +#ifndef _PCMPARSERLIST_H_ +#define _PCMPARSERLIST_H_ + +#include <KM_fileio.h> +#include <AS_DCP.h> +#include <vector> + +namespace ASDCP +{ + // + class ParserInstance + { + const byte_t* m_p; + ui32_t m_SampleSize; + + ASDCP_NO_COPY_CONSTRUCT(ParserInstance); + + public: + PCM::WAVParser Parser; + PCM::FrameBuffer FB; + PCM::AudioDescriptor ADesc; + + ParserInstance(); + virtual ~ParserInstance(); + + Result_t OpenRead(const char* filename, const Rational& PictureRate); + Result_t PutSample(byte_t* p); + Result_t ReadFrame(); + inline ui32_t SampleSize() { return m_SampleSize; } + }; + + // + class PCMParserList : public std::vector<ParserInstance*> + { + ASDCP_NO_COPY_CONSTRUCT(PCMParserList); + + protected: + PCM::AudioDescriptor m_ADesc; + ui32_t m_ChannelCount; + + public: + PCMParserList(); + virtual ~PCMParserList(); + + Result_t OpenRead(ui32_t argc, const char** argv, const Rational& PictureRate); + Result_t OpenRead(const Kumu::PathList_t& argv, const Rational& PictureRate); + Result_t FillAudioDescriptor(PCM::AudioDescriptor& ADesc) const; + Result_t Reset(); + Result_t ReadFrame(PCM::FrameBuffer& OutFB); + }; +} + + +#endif // _PCMPARSERLIST_H_ + +// +// end PCMParserList.h +// diff --git a/asdcplib/src/PCM_Parser.cpp b/asdcplib/src/PCM_Parser.cpp new file mode 100755 index 0000000..e556341 --- /dev/null +++ b/asdcplib/src/PCM_Parser.cpp @@ -0,0 +1,236 @@ +/* +Copyright (c) 2004-2011, 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 PCM_Parser.cpp + \version $Id: PCM_Parser.cpp,v 1.7 2011/05/13 01:50:19 jhurst Exp $ + \brief AS-DCP library, PCM raw essence reader implementation +*/ + +#include <Wav.h> +#include <assert.h> +#include <KM_log.h> +using Kumu::DefaultLogSink; + +using namespace ASDCP; +using namespace ASDCP::PCM; +using namespace ASDCP::Wav; + + +//------------------------------------------------------------------------------------------ + +// +class ASDCP::PCM::WAVParser::h__WAVParser +{ + Kumu::FileReader m_FileReader; + bool m_EOF; + ui32_t m_DataStart; + ui32_t m_DataLength; + ui32_t m_ReadCount; + ui32_t m_FrameBufferSize; + ui32_t m_FramesRead; + Rational m_PictureRate; + + ASDCP_NO_COPY_CONSTRUCT(h__WAVParser); + +public: + AudioDescriptor m_ADesc; + + + h__WAVParser() : + m_EOF(false), m_DataStart(0), m_DataLength(0), m_ReadCount(0), + m_FrameBufferSize(0), m_FramesRead(0) {} + + ~h__WAVParser() + { + Close(); + } + + Result_t OpenRead(const char* filename, const Rational& PictureRate); + void Close(); + void Reset(); + Result_t ReadFrame(FrameBuffer&); +}; + + +// +void +ASDCP::PCM::WAVParser::h__WAVParser::Close() +{ + m_FileReader.Close(); +} + +// +void +ASDCP::PCM::WAVParser::h__WAVParser::Reset() +{ + m_FileReader.Seek(m_DataStart); + m_FramesRead = 0; + m_ReadCount = 0; +} + +// +ASDCP::Result_t +ASDCP::PCM::WAVParser::h__WAVParser::OpenRead(const char* filename, const Rational& PictureRate) +{ + ASDCP_TEST_NULL_STR(filename); + + Result_t result = m_FileReader.OpenRead(filename); + + if ( ASDCP_SUCCESS(result) ) + { + SimpleWaveHeader WavHeader; + result = WavHeader.ReadFromFile(m_FileReader, &m_DataStart); + + if ( ASDCP_SUCCESS(result) ) + { + WavHeader.FillADesc(m_ADesc, PictureRate); + m_FrameBufferSize = ASDCP::PCM::CalcFrameBufferSize(m_ADesc); + m_DataLength = WavHeader.data_len; + m_ADesc.ContainerDuration = m_DataLength / m_FrameBufferSize; + m_ADesc.ChannelFormat = PCM::CF_NONE; + Reset(); + } + else + { + ASDCP::AIFF::SimpleAIFFHeader AIFFHeader; + m_FileReader.Seek(0); + + result = AIFFHeader.ReadFromFile(m_FileReader, &m_DataStart); + + if ( ASDCP_SUCCESS(result) ) + { + AIFFHeader.FillADesc(m_ADesc, PictureRate); + m_FrameBufferSize = ASDCP::PCM::CalcFrameBufferSize(m_ADesc); + m_DataLength = AIFFHeader.data_len; + m_ADesc.ContainerDuration = m_DataLength / m_FrameBufferSize; + m_ADesc.ChannelFormat = PCM::CF_NONE; + Reset(); + } + } + } + + return result; +} + +// +ASDCP::Result_t +ASDCP::PCM::WAVParser::h__WAVParser::ReadFrame(FrameBuffer& FB) +{ + FB.Size(0); + + if ( m_EOF || m_ReadCount >= m_DataLength ) + return RESULT_ENDOFFILE; + + if ( FB.Capacity() < m_FrameBufferSize ) + { + DefaultLogSink().Error("FrameBuf.Capacity: %u FrameLength: %u\n", + FB.Capacity(), m_FrameBufferSize); + return RESULT_SMALLBUF; + } + + ui32_t read_count = 0; + Result_t result = m_FileReader.Read(FB.Data(), m_FrameBufferSize, &read_count); + + if ( result == RESULT_ENDOFFILE ) + { + m_EOF = true; + + if ( read_count > 0 ) + result = RESULT_OK; + } + + if ( ASDCP_SUCCESS(result) ) + { + m_ReadCount += read_count; + FB.Size(read_count); + FB.FrameNumber(m_FramesRead++); + } + + return result; +} + + +//------------------------------------------------------------------------------------------ + +ASDCP::PCM::WAVParser::WAVParser() +{ +} + +ASDCP::PCM::WAVParser::~WAVParser() +{ +} + +// Opens the stream for reading, parses enough data to provide a complete +// set of stream metadata for the MXFWriter below. +ASDCP::Result_t +ASDCP::PCM::WAVParser::OpenRead(const char* filename, const Rational& PictureRate) const +{ + const_cast<ASDCP::PCM::WAVParser*>(this)->m_Parser = new h__WAVParser; + + Result_t result = m_Parser->OpenRead(filename, PictureRate); + + if ( ASDCP_FAILURE(result) ) + const_cast<ASDCP::PCM::WAVParser*>(this)->m_Parser.release(); + + return result; +} + +// Rewinds the stream to the beginning. +ASDCP::Result_t +ASDCP::PCM::WAVParser::Reset() const +{ + if ( m_Parser.empty() ) + return RESULT_INIT; + + m_Parser->Reset(); + return RESULT_OK; +} + +// Places a frame of data in the frame buffer. Fails if the buffer is too small +// or the stream is empty. +ASDCP::Result_t +ASDCP::PCM::WAVParser::ReadFrame(FrameBuffer& FB) const +{ + if ( m_Parser.empty() ) + return RESULT_INIT; + + return m_Parser->ReadFrame(FB); +} + +ASDCP::Result_t +ASDCP::PCM::WAVParser::FillAudioDescriptor(AudioDescriptor& ADesc) const +{ + if ( m_Parser.empty() ) + return RESULT_INIT; + + ADesc = m_Parser->m_ADesc; + return RESULT_OK; +} + + +// +// end PCM_Parser.cpp +// diff --git a/asdcplib/src/S12MTimecode.h b/asdcplib/src/S12MTimecode.h new file mode 100644 index 0000000..7e355a6 --- /dev/null +++ b/asdcplib/src/S12MTimecode.h @@ -0,0 +1,158 @@ +/* +Copyright (c) 2007-2009, 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 S12MTimecode.cpp + \version $Id: S12MTimecode.h,v 1.5 2009/04/09 19:24:14 msheby Exp $ + \brief AS-DCP library, Timecode PCM essence reader and writer implementation +*/ + +/* + + DROP-FRAME NOT SUPPORTED! + +*/ + +#ifndef _S12MTIMECODE_H_ +#define _S12MTIMECODE_H_ + +#include "KM_util.h" +#include "KM_memio.h" + +namespace ASDCP { + + class S12MTimecode : public Kumu::IArchive +{ + protected: + ui32_t m_FrameCount; + ui32_t m_FPS; + +public: + S12MTimecode() : m_FrameCount(0), m_FPS(0) {} + + S12MTimecode(ui32_t frame_count, ui32_t fps) : m_FrameCount(frame_count), m_FPS(fps) {} + + S12MTimecode(const std::string& tc, ui32_t fps) : m_FrameCount(0), m_FPS(fps) + { + DecodeString(tc); + } + + S12MTimecode(const S12MTimecode& rhs) : IArchive(), m_FrameCount(0), m_FPS(0) + { + m_FPS = rhs.m_FPS; + m_FrameCount = rhs.m_FrameCount; + } + + ~S12MTimecode() {} + + const S12MTimecode& operator=(const S12MTimecode& rhs) + { + assert(m_FPS != 0); + m_FrameCount = rhs.m_FrameCount; + return *this; + } + + inline void SetFPS(ui32_t fps) { m_FPS = fps; } + inline ui32_t GetFPS() const { return m_FPS; } + + inline void SetFrames(ui32_t frame_count) { m_FrameCount = frame_count; } + inline ui32_t GetFrames() const { return m_FrameCount; } + + inline bool operator==(const S12MTimecode& rhs) const { return m_FrameCount == rhs.m_FrameCount; } + inline bool operator<(const S12MTimecode& rhs) const { return m_FrameCount < rhs.m_FrameCount; } + + inline const S12MTimecode operator+(const S12MTimecode& rhs){ + assert(m_FPS > 0); + assert(m_FPS == rhs.m_FPS); + return S12MTimecode(m_FrameCount + rhs.m_FrameCount, m_FPS); + } + + inline const S12MTimecode operator-(const S12MTimecode& rhs){ + assert(m_FPS > 0); + assert(m_FPS == rhs.m_FPS); + return S12MTimecode(m_FrameCount + rhs.m_FrameCount, m_FPS); + } + + + void DecodeString(const std::string& tc) + { + assert(m_FPS > 0); + const char* p = tc.c_str(); + + while ( *p != 0 && ! isdigit(*p) ) + p++; + + if ( *p != 0 ) + { + ui32_t hours = atoi(p); + ui32_t minutes = atoi(p+3); + ui32_t seconds = atoi(p+6); + ui32_t frames = atoi(p+9); + + m_FrameCount = (((((hours * 60) + minutes) * 60) + seconds) * m_FPS)+ frames; + } + } + + const char* EncodeString(char* buf, ui32_t buf_len) + { + assert(m_FPS > 0); + ui32_t frames = m_FrameCount % m_FPS; + m_FrameCount /= m_FPS; + ui32_t seconds = m_FrameCount % 60; + m_FrameCount /= 60; + ui32_t minutes = m_FrameCount % 60; + ui32_t hours = m_FrameCount / 60; + + snprintf(buf, buf_len, "%02d:%02d:%02d:%02d", hours, minutes, seconds, frames); + return buf; + } + + // IArchive + bool HasValue() const { return (m_FPS > 0); } + ui32_t ArchiveLength() const { return sizeof(ui32_t)*2; } + + bool Archive(Kumu::MemIOWriter* Writer) const + { + if ( ! Writer->WriteUi32BE(m_FPS) ) return false; + if ( ! Writer->WriteUi32BE(m_FrameCount) ) return false; + return true; + } + + bool Unarchive(Kumu::MemIOReader* Reader) + { + if ( ! Reader->ReadUi32BE(&m_FPS) ) return false; + if ( ! Reader->ReadUi32BE(&m_FrameCount) ) return false; + return true; + } +}; + + +} // namespace ASDCP + +#endif // _S12MTIMECODE_H_ + +// +// end S12MTimecode.h +// diff --git a/asdcplib/src/TimedText_Parser.cpp b/asdcplib/src/TimedText_Parser.cpp new file mode 100644 index 0000000..ce16aee --- /dev/null +++ b/asdcplib/src/TimedText_Parser.cpp @@ -0,0 +1,447 @@ +/* +Copyright (c) 2007-2009, 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_TimedText.cpp + \version $Id: TimedText_Parser.cpp,v 1.15 2010/11/15 17:04:13 jhurst Exp $ + \brief AS-DCP library, PCM essence reader and writer implementation +*/ + + +#include "AS_DCP_internal.h" +#include "S12MTimecode.h" +#include "KM_xml.h" + +using namespace Kumu; +using namespace ASDCP; + +using Kumu::DefaultLogSink; + +const char* c_dcst_namespace_name = "http://www.smpte-ra.org/schemas/428-7/2007/DCST"; + +//------------------------------------------------------------------------------------------ + + + +class FilenameResolver : public ASDCP::TimedText::IResourceResolver +{ + std::string m_Dirname; + + FilenameResolver(); + bool operator==(const FilenameResolver&); + +public: + FilenameResolver(const std::string& dirname) + { + if ( PathIsDirectory(dirname) ) + { + m_Dirname = dirname; + return; + } + + DefaultLogSink().Error("Path '%s' is not a directory, defaulting to '.'\n", dirname.c_str()); + m_Dirname = "."; + } + + // + Result_t ResolveRID(const byte_t* uuid, TimedText::FrameBuffer& FrameBuf) const + { + FileReader Reader; + char buf[64]; + UUID RID(uuid); + std::string filename = m_Dirname + "/" + RID.EncodeHex(buf, 64); + DefaultLogSink().Debug("retrieving resource %s from file %s\n", buf, filename.c_str()); + + Result_t result = Reader.OpenRead(filename.c_str()); + + if ( KM_SUCCESS(result) ) + { + ui32_t read_count, read_size = Reader.Size(); + + result = FrameBuf.Capacity(read_size); + + if ( KM_SUCCESS(result) ) + result = Reader.Read(FrameBuf.Data(), read_size, &read_count); + + if ( KM_SUCCESS(result) ) + FrameBuf.Size(read_count); + } + + return result; + } +}; + +//------------------------------------------------------------------------------------------ + +typedef std::map<Kumu::UUID, TimedText::MIMEType_t> ResourceTypeMap_t; + +class ASDCP::TimedText::DCSubtitleParser::h__SubtitleParser +{ + XMLElement m_Root; + ResourceTypeMap_t m_ResourceTypes; + Result_t OpenRead(); + + ASDCP_NO_COPY_CONSTRUCT(h__SubtitleParser); + +public: + std::string m_Filename; + std::string m_XMLDoc; + TimedTextDescriptor m_TDesc; + mem_ptr<FilenameResolver> m_DefaultResolver; + + h__SubtitleParser() : m_Root("**ParserRoot**") + { + memset(&m_TDesc.AssetID, 0, UUIDlen); + } + + ~h__SubtitleParser() {} + + TimedText::IResourceResolver* GetDefaultResolver() + { + if ( m_DefaultResolver.empty() ) + m_DefaultResolver = new FilenameResolver(PathDirname(m_Filename)); + + return m_DefaultResolver; + } + + Result_t OpenRead(const char* filename); + Result_t OpenRead(const std::string& xml_doc, const char* filename); + Result_t ReadAncillaryResource(const byte_t* uuid, FrameBuffer& FrameBuf, const IResourceResolver& Resolver) const; +}; + +// +bool +get_UUID_from_element(XMLElement* Element, UUID& ID) +{ + assert(Element); + const char* p = Element->GetBody().c_str(); + if ( strncmp(p, "urn:uuid:", 9) == 0 ) p += 9; + return ID.DecodeHex(p); +} + +// +bool +get_UUID_from_child_element(const char* name, XMLElement* Parent, UUID& outID) +{ + assert(name); assert(Parent); + XMLElement* Child = Parent->GetChildWithName(name); + if ( Child == 0 ) return false; + return get_UUID_from_element(Child, outID); +} + +// +static ASDCP::Rational +decode_rational(const char* str_rat) +{ + assert(str_rat); + ui32_t Num = atoi(str_rat); + ui32_t Den = 0; + + const char* den_str = strrchr(str_rat, ' '); + if ( den_str != 0 ) + Den = atoi(den_str+1); + + return ASDCP::Rational(Num, Den); +} + +// +Result_t +ASDCP::TimedText::DCSubtitleParser::h__SubtitleParser::OpenRead(const char* filename) +{ + Result_t result = ReadFileIntoString(filename, m_XMLDoc); + + if ( KM_SUCCESS(result) ) + result = OpenRead(); + + m_Filename = filename; + return result; +} + +// +Result_t +ASDCP::TimedText::DCSubtitleParser::h__SubtitleParser::OpenRead(const std::string& xml_doc, const char* filename) +{ + m_XMLDoc = xml_doc; + + if ( filename != 0 ) + m_Filename = filename; + else + m_Filename = "<string>"; + + return OpenRead(); +} + +// +Result_t +ASDCP::TimedText::DCSubtitleParser::h__SubtitleParser::OpenRead() +{ + if ( ! m_Root.ParseString(m_XMLDoc.c_str()) ) + return RESULT_FORMAT; + + m_TDesc.EncodingName = "UTF-8"; // the XML parser demands UTF-8 + m_TDesc.ResourceList.clear(); + m_TDesc.ContainerDuration = 0; + const XMLNamespace* ns = m_Root.Namespace(); + + if ( ns == 0 ) + { + DefaultLogSink(). Warn("Document has no namespace name, assuming %s\n", c_dcst_namespace_name); + m_TDesc.NamespaceName = c_dcst_namespace_name; + } + else + { + m_TDesc.NamespaceName = ns->Name(); + } + + UUID DocID; + if ( ! get_UUID_from_child_element("Id", &m_Root, DocID) ) + { + DefaultLogSink(). Error("Id element missing from input document\n"); + return RESULT_FORMAT; + } + + memcpy(m_TDesc.AssetID, DocID.Value(), DocID.Size()); + XMLElement* EditRate = m_Root.GetChildWithName("EditRate"); + + if ( EditRate == 0 ) + { + DefaultLogSink(). Error("EditRate element missing from input document\n"); + return RESULT_FORMAT; + } + + m_TDesc.EditRate = decode_rational(EditRate->GetBody().c_str()); + + if ( m_TDesc.EditRate != EditRate_23_98 + && m_TDesc.EditRate != EditRate_24 + && m_TDesc.EditRate != EditRate_25 + && m_TDesc.EditRate != EditRate_30 + && m_TDesc.EditRate != EditRate_48 + && m_TDesc.EditRate != EditRate_50 + && m_TDesc.EditRate != EditRate_60 ) + { + DefaultLogSink(). Error("Unexpected EditRate: %d/%d\n", + m_TDesc.EditRate.Numerator, m_TDesc.EditRate.Denominator); + return RESULT_FORMAT; + } + + // list of fonts + ElementList FontList; + m_Root.GetChildrenWithName("LoadFont", FontList); + + for ( Elem_i i = FontList.begin(); i != FontList.end(); i++ ) + { + UUID AssetID; + if ( ! get_UUID_from_element(*i, AssetID) ) + { + DefaultLogSink(). Error("LoadFont element does not contain a urn:uuid value as expected.\n"); + return RESULT_FORMAT; + } + + TimedTextResourceDescriptor TmpResource; + memcpy(TmpResource.ResourceID, AssetID.Value(), UUIDlen); + TmpResource.Type = MT_OPENTYPE; + m_TDesc.ResourceList.push_back(TmpResource); + m_ResourceTypes.insert(ResourceTypeMap_t::value_type(UUID(TmpResource.ResourceID), MT_OPENTYPE)); + } + + // list of images + ElementList ImageList; + m_Root.GetChildrenWithName("Image", ImageList); + + for ( Elem_i i = ImageList.begin(); i != ImageList.end(); i++ ) + { + UUID AssetID; + if ( ! get_UUID_from_element(*i, AssetID) ) + { + DefaultLogSink(). Error("Image element does not contain a urn:uuid value as expected.\n"); + return RESULT_FORMAT; + } + + TimedTextResourceDescriptor TmpResource; + memcpy(TmpResource.ResourceID, AssetID.Value(), UUIDlen); + TmpResource.Type = MT_PNG; + m_TDesc.ResourceList.push_back(TmpResource); + m_ResourceTypes.insert(ResourceTypeMap_t::value_type(UUID(TmpResource.ResourceID), MT_PNG)); + } + + // Calculate the timeline duration. + // This is a little ugly because the last element in the file is not necessarily + // the last instance to be displayed, e.g., element n and element n-1 may have the + // same start time but n-1 may have a greater duration making it the last to be seen. + // We must scan the list to accumulate the latest TimeOut value. + ElementList InstanceList; + ElementList::const_iterator ei; + ui32_t end_count = 0; + + m_Root.GetChildrenWithName("Subtitle", InstanceList); + + if ( InstanceList.empty() ) + { + DefaultLogSink(). Error("XML document contains no Subtitle elements.\n"); + return RESULT_FORMAT; + } + + // assumes edit rate is constrained above + ui32_t TCFrameRate = ( m_TDesc.EditRate == EditRate_23_98 ) ? 24 : m_TDesc.EditRate.Numerator; + + S12MTimecode beginTC; + beginTC.SetFPS(TCFrameRate); + XMLElement* StartTime = m_Root.GetChildWithName("StartTime"); + + if ( StartTime != 0 ) + beginTC.DecodeString(StartTime->GetBody()); + + for ( ei = InstanceList.begin(); ei != InstanceList.end(); ei++ ) + { + S12MTimecode tmpTC((*ei)->GetAttrWithName("TimeOut"), TCFrameRate); + if ( end_count < tmpTC.GetFrames() ) + end_count = tmpTC.GetFrames(); + } + + if ( end_count <= beginTC.GetFrames() ) + { + DefaultLogSink(). Error("Timed Text file has zero-length timeline.\n"); + return RESULT_FORMAT; + } + + m_TDesc.ContainerDuration = end_count - beginTC.GetFrames(); + + return RESULT_OK; +} + + +// +Result_t +ASDCP::TimedText::DCSubtitleParser::h__SubtitleParser::ReadAncillaryResource(const byte_t* uuid, FrameBuffer& FrameBuf, + const IResourceResolver& Resolver) const +{ + FrameBuf.AssetID(uuid); + UUID TmpID(uuid); + char buf[64]; + + ResourceTypeMap_t::const_iterator rmi = m_ResourceTypes.find(TmpID); + + if ( rmi == m_ResourceTypes.end() ) + { + DefaultLogSink().Error("Unknown ancillary resource id: %s\n", TmpID.EncodeHex(buf, 64)); + return RESULT_RANGE; + } + + Result_t result = Resolver.ResolveRID(uuid, FrameBuf); + + if ( KM_SUCCESS(result) ) + { + if ( (*rmi).second == MT_PNG ) + FrameBuf.MIMEType("image/png"); + + else if ( (*rmi).second == MT_OPENTYPE ) + FrameBuf.MIMEType("application/x-font-opentype"); + + else + FrameBuf.MIMEType("application/octet-stream"); + } + + return result; +} + +//------------------------------------------------------------------------------------------ + +ASDCP::TimedText::DCSubtitleParser::DCSubtitleParser() +{ +} + +ASDCP::TimedText::DCSubtitleParser::~DCSubtitleParser() +{ +} + +// Opens the stream for reading, parses enough data to provide a complete +// set of stream metadata for the MXFWriter below. +ASDCP::Result_t +ASDCP::TimedText::DCSubtitleParser::OpenRead(const char* filename) const +{ + const_cast<ASDCP::TimedText::DCSubtitleParser*>(this)->m_Parser = new h__SubtitleParser; + + Result_t result = m_Parser->OpenRead(filename); + + if ( ASDCP_FAILURE(result) ) + const_cast<ASDCP::TimedText::DCSubtitleParser*>(this)->m_Parser = 0; + + return result; +} + +// Parses an XML document to provide a complete set of stream metadata for the MXFWriter below. +Result_t +ASDCP::TimedText::DCSubtitleParser::OpenRead(const std::string& xml_doc, const char* filename) const +{ + const_cast<ASDCP::TimedText::DCSubtitleParser*>(this)->m_Parser = new h__SubtitleParser; + + Result_t result = m_Parser->OpenRead(xml_doc, filename); + + if ( ASDCP_FAILURE(result) ) + const_cast<ASDCP::TimedText::DCSubtitleParser*>(this)->m_Parser = 0; + + return result; +} + +// +ASDCP::Result_t +ASDCP::TimedText::DCSubtitleParser::FillTimedTextDescriptor(TimedTextDescriptor& TDesc) const +{ + if ( m_Parser.empty() ) + return RESULT_INIT; + + TDesc = m_Parser->m_TDesc; + return RESULT_OK; +} + +// Reads the complete Timed Text Resource into the given string. +ASDCP::Result_t +ASDCP::TimedText::DCSubtitleParser::ReadTimedTextResource(std::string& s) const +{ + if ( m_Parser.empty() ) + return RESULT_INIT; + + s = m_Parser->m_XMLDoc; + return RESULT_OK; +} + +// +ASDCP::Result_t +ASDCP::TimedText::DCSubtitleParser::ReadAncillaryResource(const byte_t* uuid, FrameBuffer& FrameBuf, + const IResourceResolver* Resolver) const +{ + if ( m_Parser.empty() ) + return RESULT_INIT; + + if ( Resolver == 0 ) + Resolver = m_Parser->GetDefaultResolver(); + + return m_Parser->ReadAncillaryResource(uuid, FrameBuf, *Resolver); +} + + +// +// end AS_DCP_timedText.cpp +// diff --git a/asdcplib/src/Wav.cpp b/asdcplib/src/Wav.cpp new file mode 100755 index 0000000..ee1e93d --- /dev/null +++ b/asdcplib/src/Wav.cpp @@ -0,0 +1,370 @@ +/* +Copyright (c) 2005-2009, 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 Wav.cpp + \version $Id: Wav.cpp,v 1.11 2010/02/16 18:40:57 jhurst Exp $ + \brief Wave file common elements +*/ + +#include "Wav.h" +#include <assert.h> +#include <KM_log.h> +using Kumu::DefaultLogSink; + + +const ui32_t SimpleWavHeaderLength = 46; + +// +ASDCP::Wav::SimpleWaveHeader::SimpleWaveHeader(ASDCP::PCM::AudioDescriptor& ADesc) +{ + format = 1; + nchannels = ADesc.ChannelCount; + bitspersample = ADesc.QuantizationBits; + samplespersec = (ui32_t)ceil(ADesc.AudioSamplingRate.Quotient()); + blockalign = nchannels * (bitspersample / 8); + avgbps = samplespersec * blockalign; + cbsize = 0; + data_len = ASDCP::PCM::CalcFrameBufferSize(ADesc) * ADesc.ContainerDuration; +} + +// +void +ASDCP::Wav::SimpleWaveHeader::FillADesc(ASDCP::PCM::AudioDescriptor& ADesc, ASDCP::Rational PictureRate) const +{ + ADesc.EditRate = PictureRate; + + ADesc.LinkedTrackID = 0; + ADesc.Locked = 0; + ADesc.ChannelCount = nchannels; + ADesc.AudioSamplingRate = Rational(samplespersec, 1); + ADesc.AvgBps = avgbps; + ADesc.BlockAlign = blockalign; + ADesc.QuantizationBits = bitspersample; + ui32_t FrameBufferSize = ASDCP::PCM::CalcFrameBufferSize(ADesc); + ADesc.ContainerDuration = data_len / FrameBufferSize; + ADesc.ChannelFormat = PCM::CF_NONE; +} + + +// +ASDCP::Result_t +ASDCP::Wav::SimpleWaveHeader::WriteToFile(Kumu::FileWriter& OutFile) const +{ + ui32_t write_count; + byte_t tmp_header[SimpleWavHeaderLength]; + byte_t* p = tmp_header; + + static ui32_t fmt_len = + sizeof(format) + + sizeof(nchannels) + + sizeof(samplespersec) + + sizeof(avgbps) + + sizeof(blockalign) + + sizeof(bitspersample) + + sizeof(cbsize); + + ui32_t RIFF_len = data_len + SimpleWavHeaderLength - 8; + + memcpy(p, &FCC_RIFF, sizeof(fourcc)); p += 4; + *((ui32_t*)p) = KM_i32_LE(RIFF_len); p += 4; + memcpy(p, &FCC_WAVE, sizeof(fourcc)); p += 4; + memcpy(p, &FCC_fmt_, sizeof(fourcc)); p += 4; + *((ui32_t*)p) = KM_i32_LE(fmt_len); p += 4; + *((ui16_t*)p) = KM_i16_LE(format); p += 2; + *((ui16_t*)p) = KM_i16_LE(nchannels); p += 2; + *((ui32_t*)p) = KM_i32_LE(samplespersec); p += 4; + *((ui32_t*)p) = KM_i32_LE(avgbps); p += 4; + *((ui16_t*)p) = KM_i16_LE(blockalign); p += 2; + *((ui16_t*)p) = KM_i16_LE(bitspersample); p += 2; + *((ui16_t*)p) = KM_i16_LE(cbsize); p += 2; + memcpy(p, &FCC_data, sizeof(fourcc)); p += 4; + *((ui32_t*)p) = KM_i32_LE(data_len); p += 4; + + return OutFile.Write(tmp_header, SimpleWavHeaderLength, &write_count); +} + +// +ASDCP::Result_t +ASDCP::Wav::SimpleWaveHeader::ReadFromFile(const Kumu::FileReader& InFile, ui32_t* data_start) +{ + ui32_t read_count = 0; + ui32_t local_data_start = 0; + ASDCP::PCM::FrameBuffer TmpBuffer(MaxWavHeader); + + if ( data_start == 0 ) + data_start = &local_data_start; + + Result_t result = InFile.Read(TmpBuffer.Data(), TmpBuffer.Capacity(), &read_count); + + if ( ASDCP_SUCCESS(result) ) + result = ReadFromBuffer(TmpBuffer.RoData(), read_count, data_start); + + return result; +} + +ASDCP::Result_t +ASDCP::Wav::SimpleWaveHeader::ReadFromBuffer(const byte_t* buf, ui32_t buf_len, ui32_t* data_start) +{ + if ( buf_len < SimpleWavHeaderLength ) + return RESULT_SMALLBUF; + + *data_start = 0; + const byte_t* p = buf; + const byte_t* end_p = p + buf_len; + + fourcc test_RIFF(p); p += 4; + if ( test_RIFF != FCC_RIFF ) + { + // DefaultLogSink().Debug("File does not begin with RIFF header\n"); + return RESULT_RAW_FORMAT; + } + + ui32_t RIFF_len = KM_i32_LE(*(ui32_t*)p); p += 4; + + fourcc test_WAVE(p); p += 4; + if ( test_WAVE != FCC_WAVE ) + { + DefaultLogSink().Debug("File does not contain a WAVE header\n"); + return RESULT_RAW_FORMAT; + } + + fourcc test_fcc; + + while ( p < end_p ) + { + test_fcc = fourcc(p); p += 4; + ui32_t chunk_size = KM_i32_LE(*(ui32_t*)p); p += 4; + + if ( test_fcc == FCC_data ) + { + if ( chunk_size > RIFF_len ) + { + DefaultLogSink().Error("Chunk size %u larger than file: %u\n", chunk_size, RIFF_len); + return RESULT_RAW_FORMAT; + } + + data_len = chunk_size; + *data_start = p - buf; + break; + } + + if ( test_fcc == FCC_fmt_ ) + { + ui16_t format = KM_i16_LE(*(ui16_t*)p); p += 2; + + if ( format != WAVE_FORMAT_PCM && format != WAVE_FORMAT_EXTENSIBLE ) + { + DefaultLogSink().Error("Expecting uncompressed PCM data, got format type %hd\n", format); + return RESULT_RAW_FORMAT; + } + + nchannels = KM_i16_LE(*(ui16_t*)p); p += 2; + samplespersec = KM_i32_LE(*(ui32_t*)p); p += 4; + avgbps = KM_i32_LE(*(ui32_t*)p); p += 4; + blockalign = KM_i16_LE(*(ui16_t*)p); p += 2; + bitspersample = KM_i16_LE(*(ui16_t*)p); p += 2; + p += chunk_size - 16; // 16 is the number of bytes read in this block + } + else + { + p += chunk_size; + } + } + + if ( *data_start == 0 ) // can't have no data! + { + DefaultLogSink().Error("No data chunk found, file contains no essence\n"); + return RESULT_RAW_FORMAT; + } + + return RESULT_OK; +} + +//------------------------------------------------------------------------------------------ +// conversion algorithms from http://www.borg.com/~jglatt/tech/aiff.htm + +// +void +Rat_to_extended(ASDCP::Rational rate, byte_t* buf) +{ + memset(buf, 0, 10); + ui32_t value = (ui32_t)ceil(rate.Quotient()); + ui32_t exp = value; + exp >>= 1; + ui8_t i = 0; + + for ( ; i < 32; i++ ) + { + exp >>= 1; + if ( ! exp ) + break; + } + + *(buf+1) = i; + + for ( i = 32; i != 0 ; i-- ) + { + if ( value & 0x80000000 ) + break; + value <<= 1; + } + + *(ui32_t*)(buf+2) = KM_i32_BE(value); +} + +// +ASDCP::Rational +extended_to_Rat(const byte_t* buf) +{ + ui32_t last = 0; + ui32_t mantissa = KM_i32_BE(*(ui32_t*)(buf+2)); + + byte_t exp = 30 - *(buf+1); + + while ( exp-- ) + { + last = mantissa; + mantissa >>= 1; + } + + if ( last & 0x00000001 ) + mantissa++; + + return ASDCP::Rational(mantissa, 1); +} + +// +void +ASDCP::AIFF::SimpleAIFFHeader::FillADesc(ASDCP::PCM::AudioDescriptor& ADesc, ASDCP::Rational PictureRate) const +{ + ADesc.EditRate = PictureRate; + + ADesc.ChannelCount = numChannels; + ADesc.AudioSamplingRate = extended_to_Rat(sampleRate); + ADesc.QuantizationBits = sampleSize; + ADesc.BlockAlign = sampleSize / 8; + ADesc.AvgBps = (ui32_t) (ADesc.BlockAlign * ADesc.AudioSamplingRate.Quotient()); + ui32_t FrameBufferSize = ASDCP::PCM::CalcFrameBufferSize(ADesc); + ADesc.ContainerDuration = data_len / FrameBufferSize; + ADesc.ChannelFormat = PCM::CF_NONE; +} + +// +ASDCP::Result_t +ASDCP::AIFF::SimpleAIFFHeader::ReadFromFile(const Kumu::FileReader& InFile, ui32_t* data_start) +{ + ui32_t read_count = 0; + ui32_t local_data_start = 0; + ASDCP::PCM::FrameBuffer TmpBuffer(Wav::MaxWavHeader); + + if ( data_start == 0 ) + data_start = &local_data_start; + + Result_t result = InFile.Read(TmpBuffer.Data(), TmpBuffer.Capacity(), &read_count); + + if ( ASDCP_SUCCESS(result) ) + result = ReadFromBuffer(TmpBuffer.RoData(), read_count, data_start); + + return result; +} + +// +ASDCP::Result_t +ASDCP::AIFF::SimpleAIFFHeader::ReadFromBuffer(const byte_t* buf, ui32_t buf_len, ui32_t* data_start) +{ + if ( buf_len < 32 ) + return RESULT_SMALLBUF; + + *data_start = 0; + const byte_t* p = buf; + const byte_t* end_p = p + buf_len; + + fourcc test_FORM(p); p += 4; + if ( test_FORM != FCC_FORM ) + { + // DefaultLogSink().Debug("File does not begin with FORM header\n"); + return RESULT_RAW_FORMAT; + } + + ui32_t RIFF_len = KM_i32_BE(*(ui32_t*)p); p += 4; + + fourcc test_AIFF(p); p += 4; + if ( test_AIFF != FCC_AIFF ) + { + DefaultLogSink().Debug("File does not contain an AIFF header\n"); + return RESULT_RAW_FORMAT; + } + + fourcc test_fcc; + + while ( p < end_p ) + { + test_fcc = fourcc(p); p += 4; + ui32_t chunk_size = KM_i32_BE(*(ui32_t*)p); p += 4; + + if ( test_fcc == FCC_COMM ) + { + numChannels = KM_i16_BE(*(ui16_t*)p); p += 2; + numSampleFrames = KM_i32_BE(*(ui32_t*)p); p += 4; + sampleSize = KM_i16_BE(*(ui16_t*)p); p += 2; + memcpy(sampleRate, p, 10); + p += 10; + } + else if ( test_fcc == FCC_SSND ) + { + if ( chunk_size > RIFF_len ) + { + DefaultLogSink().Error("Chunk size %u larger than file: %u\n", chunk_size, RIFF_len); + return RESULT_RAW_FORMAT; + } + + ui32_t offset = KM_i32_BE(*(ui32_t*)p); p += 4; + p += 4; // blockSize; + + data_len = chunk_size - 8; + *data_start = (p - buf) + offset; + break; + } + else + { + p += chunk_size; + } + } + + if ( *data_start == 0 ) // can't have no data! + { + DefaultLogSink().Error("No data chunk found, file contains no essence\n"); + return RESULT_RAW_FORMAT; + } + + return RESULT_OK; +} + + + +// +// end Wav.cpp +// diff --git a/asdcplib/src/Wav.h b/asdcplib/src/Wav.h new file mode 100755 index 0000000..09ee48a --- /dev/null +++ b/asdcplib/src/Wav.h @@ -0,0 +1,127 @@ +/* +Copyright (c) 2005-2009, 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 Wav.h + \version $Id: Wav.h,v 1.5 2009/04/09 19:24:14 msheby Exp $ + \brief Wave file common elements +*/ + +#ifndef _WAV_H_ +#define _WAV_H_ + +#include <KM_fileio.h> +#include <AS_DCP.h> + +namespace ASDCP +{ + // + class fourcc + { + private: + byte_t data[4]; + + public: + inline fourcc() { memset( data, 0, 4 ); } + inline fourcc( const char* v ) { memcpy( this->data, v, 4 ); } + inline fourcc( const byte_t* v ) { memcpy( this->data, v, 4 ); } + inline fourcc& operator=(const fourcc & s) { memcpy( this->data, s.data, 4); return *this; } + inline bool operator==(const fourcc &rhs) { return memcmp(data, rhs.data, 4) == 0 ? true : false; } + inline bool operator!=(const fourcc &rhs) { return memcmp(data, rhs.data, 4) != 0 ? true : false; } + }; + + namespace AIFF + { + const fourcc FCC_FORM("FORM"); + const fourcc FCC_AIFF("AIFF"); + const fourcc FCC_COMM("COMM"); + const fourcc FCC_SSND("SSND"); + + class SimpleAIFFHeader + { + public: + ui16_t numChannels; + ui32_t numSampleFrames; + ui16_t sampleSize; + byte_t sampleRate[10]; // 80-bit IEEE 754 float + ui32_t data_len; + + SimpleAIFFHeader() : + numChannels(0), numSampleFrames(0), sampleSize(0), data_len(0) { + memset(sampleRate, 0, 10); + } + + Result_t ReadFromBuffer(const byte_t* buf, ui32_t buf_len, ui32_t* data_start); + Result_t ReadFromFile(const Kumu::FileReader& InFile, ui32_t* data_start); + void FillADesc(ASDCP::PCM::AudioDescriptor& ADesc, Rational PictureRate) const; + }; + + } // namespace AIFF + + namespace Wav + { + const ui32_t MaxWavHeader = 1024*32; // must find "data" within this space or no happy + + const fourcc FCC_RIFF("RIFF"); + const fourcc FCC_WAVE("WAVE"); + const fourcc FCC_fmt_("fmt "); + const fourcc FCC_data("data"); + + const ui16_t WAVE_FORMAT_PCM = 1; + const ui16_t WAVE_FORMAT_EXTENSIBLE = 65534; + + // + class SimpleWaveHeader + { + public: + ui16_t format; + ui16_t nchannels; + ui32_t samplespersec; + ui32_t avgbps; + ui16_t blockalign; + ui16_t bitspersample; + ui16_t cbsize; + ui32_t data_len; + + SimpleWaveHeader() : + format(0), nchannels(0), samplespersec(0), avgbps(0), + blockalign(0), bitspersample(0), cbsize(0), data_len(0) {} + + SimpleWaveHeader(ASDCP::PCM::AudioDescriptor& ADesc); + + Result_t ReadFromBuffer(const byte_t* buf, ui32_t buf_len, ui32_t* data_start); + Result_t ReadFromFile(const Kumu::FileReader& InFile, ui32_t* data_start); + Result_t WriteToFile(Kumu::FileWriter& OutFile) const; + void FillADesc(ASDCP::PCM::AudioDescriptor& ADesc, Rational PictureRate) const; + }; + + } // namespace Wav +} // namespace ASDCP + +#endif // _WAV_H_ + +// +// end Wav.h +// diff --git a/asdcplib/src/WavFileWriter.h b/asdcplib/src/WavFileWriter.h new file mode 100755 index 0000000..daf26ea --- /dev/null +++ b/asdcplib/src/WavFileWriter.h @@ -0,0 +1,198 @@ +/* +Copyright (c) 2005-2009, 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 WavFileWriter.h + \version $Id: WavFileWriter.h,v 1.6 2009/04/09 19:16:49 msheby Exp $ + \brief demux and write PCM data to WAV file(s) +*/ + +#include <KM_fileio.h> +#include <KM_log.h> +#include <Wav.h> +#include <list> + +#ifndef _WAVFILEWRITER_H_ +#define _WAVFILEWRITER_H_ + + +// +class WavFileElement : public Kumu::FileWriter +{ + ASDCP::PCM::FrameBuffer m_Buf; + byte_t* m_p; + + WavFileElement(); + KM_NO_COPY_CONSTRUCT(WavFileElement); + +public: + WavFileElement(ui32_t s) : m_Buf(s), m_p(0) + { + m_p = m_Buf.Data(); + } + + ~WavFileElement() {} + + void WriteSample(const byte_t* sample, ui32_t sample_size) + { + memcpy(m_p, sample, sample_size); + m_p += sample_size; + } + + ASDCP::Result_t Flush() + { + ui32_t write_count = 0; + + if ( m_p == m_Buf.Data() ) + return ASDCP::RESULT_EMPTY_FB; + + ui32_t write_size = m_p - m_Buf.Data(); + m_p = m_Buf.Data(); + return Write(m_Buf.RoData(), write_size, &write_count); + } +}; + + +// +class WavFileWriter +{ + ASDCP::PCM::AudioDescriptor m_ADesc; + std::list<WavFileElement*> m_OutFile; + ui32_t m_ChannelCount; + ASDCP_NO_COPY_CONSTRUCT(WavFileWriter); + + public: + WavFileWriter() : m_ChannelCount(0) {} + ~WavFileWriter() + { + while ( ! m_OutFile.empty() ) + { + delete m_OutFile.back(); + m_OutFile.pop_back(); + } + } + + // + enum SplitType_t { + ST_NONE, // write all channels to a single WAV file + ST_MONO, // write each channel a separate WAV file + ST_STEREO // write channel pairs to separate WAV files + }; + + ASDCP::Result_t + OpenWrite(ASDCP::PCM::AudioDescriptor &ADesc, const char* file_root, SplitType_t split = ST_NONE) + { + ASDCP_TEST_NULL_STR(file_root); + char filename[Kumu::MaxFilePath]; + ui32_t file_count = 0; + ASDCP::Result_t result = ASDCP::RESULT_OK; + m_ADesc = ADesc; + + switch ( split ) + { + case ST_NONE: + file_count = 1; + m_ChannelCount = m_ADesc.ChannelCount; + break; + + case ST_MONO: + file_count = m_ADesc.ChannelCount; + m_ChannelCount = 1; + break; + + case ST_STEREO: + if ( m_ADesc.ChannelCount % 2 != 0 ) + { + Kumu::DefaultLogSink().Error("Unable to create 2-channel splits with odd number of input channels.\n"); + return ASDCP::RESULT_PARAM; + } + + file_count = m_ADesc.ChannelCount / 2; + m_ChannelCount = 2; + break; + } + assert(file_count && m_ChannelCount); + + ui32_t element_size = ASDCP::PCM::CalcFrameBufferSize(m_ADesc) / file_count; + + for ( ui32_t i = 0; i < file_count && ASDCP_SUCCESS(result); i++ ) + { + snprintf(filename, Kumu::MaxFilePath, "%s_%u.wav", file_root, (i + 1)); + m_OutFile.push_back(new WavFileElement(element_size)); + result = m_OutFile.back()->OpenWrite(filename); + + if ( ASDCP_SUCCESS(result) ) + { + ASDCP::PCM::AudioDescriptor tmpDesc = m_ADesc; + tmpDesc.ChannelCount = m_ChannelCount; + ASDCP::Wav::SimpleWaveHeader Wav(tmpDesc); + result = Wav.WriteToFile(*(m_OutFile.back())); + } + } + + return result; + } + + ASDCP::Result_t + WriteFrame(ASDCP::PCM::FrameBuffer& FB) + { + if ( m_OutFile.empty() ) + return ASDCP::RESULT_STATE; + + if ( m_OutFile.size() == 1 ) // no de-interleave needed, just write out the frame + return m_OutFile.back()->Write(FB.RoData(), FB.Size(), 0); + + std::list<WavFileElement*>::iterator fi; + ui32_t sample_size = m_ADesc.QuantizationBits / 8; + const byte_t* p = FB.RoData(); + const byte_t* end_p = p + FB.Size(); + + while ( p < end_p ) + { + for ( fi = m_OutFile.begin(); fi != m_OutFile.end(); fi++ ) + { + for ( ui32_t c = 0; c < m_ChannelCount; c++ ) + { + (*fi)->WriteSample(p, sample_size); + p += sample_size; + } + } + } + + ASDCP::Result_t result = ASDCP::RESULT_OK; + + for ( fi = m_OutFile.begin(); fi != m_OutFile.end() && ASDCP_SUCCESS(result); fi++ ) + result = (*fi)->Flush(); + + return result; + } +}; + + +#endif // _WAVFILEWRITER_H_ + +// +// end WavFileWriter.h +// diff --git a/asdcplib/src/asdcp-info.cpp b/asdcplib/src/asdcp-info.cpp new file mode 100755 index 0000000..0622763 --- /dev/null +++ b/asdcplib/src/asdcp-info.cpp @@ -0,0 +1,428 @@ +/* +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 asdcp-info.cpp + \version $Id: asdcp-info.cpp,v 1.1 2012/02/03 19:49:56 jhurst Exp $ + \brief AS-DCP file metadata utility + + This program provides metadata information about an AS-DCP file. + + For more information about asdcplib, please refer to the header file AS_DCP.h +*/ + +#include <KM_fileio.h> +#include <AS_DCP.h> +#include <MXF.h> +#include <Metadata.h> +#include <openssl/sha.h> + +using namespace Kumu; +using namespace ASDCP; + +const ui32_t FRAME_BUFFER_SIZE = 4 * Kumu::Megabyte; + +//------------------------------------------------------------------------------------------ +// +// command line option parser class + +static const char* PROGRAM_NAME = "asdcp-info"; // program name for messages + + +// Increment the iterator, test for an additional non-option command line argument. +// Causes the caller to return if there are no remaining arguments or if the next +// argument begins with '-'. +#define TEST_EXTRA_ARG(i,c) \ + if ( ++i >= argc || argv[(i)][0] == '-' ) { \ + fprintf(stderr, "Argument not found for option -%c.\n", (c)); \ + return; \ + } + +// +void +banner(FILE* stream = stdout) +{ + fprintf(stream, "\n\ +%s (asdcplib %s)\n\n\ +Copyright (c) 2003-2012 John Hurst\n\n\ +asdcplib may be copied only under the terms of the license found at\n\ +the top of every file in the asdcplib distribution kit.\n\n\ +Specify the -h (help) option for further information about %s\n\n", + PROGRAM_NAME, ASDCP::Version(), PROGRAM_NAME); +} + +// +void +usage(FILE* stream = stdout) +{ + fprintf(stream, "\ +USAGE:%s [-h|-help] [-V]\n\ +\n\ + %s [-3] [-H] [-n] <input-file>+\n\ +\n\ +Options:\n\ + -3 - Force stereoscopic interpretation of a JP2K file\n\ + -h | -help - Show help\n\ + -H - Show MXF header metadata\n\ + -n - Show index\n\ + -V - Show version information\n\ +\n\ + NOTES: o There is no option grouping, all options must be distinct arguments.\n\ + o All option arguments must be separated from the option by whitespace.\n\n", + PROGRAM_NAME, PROGRAM_NAME); + +} + +// +class CommandOptions +{ + CommandOptions(); + +public: + bool error_flag; // true if the given options are in error or not complete + bool version_flag; // true if the version display option was selected + bool help_flag; // true if the help display option was selected + PathList_t filenames; // list of filenames to be processed + bool showindex_flag; // true if index is to be displayed + bool showheader_flag; // true if MXF file header is to be displayed + bool stereo_image_flag; // if true, expect stereoscopic JP2K input (left eye first) + + // + CommandOptions(int argc, const char** argv) : + error_flag(true), version_flag(false), help_flag(false), + showindex_flag(), showheader_flag(), stereo_image_flag(false) + { + for ( int i = 1; i < argc; ++i ) + { + + if ( (strcmp( argv[i], "-help") == 0) ) + { + help_flag = true; + continue; + } + + if ( argv[i][0] == '-' + && ( isalpha(argv[i][1]) || isdigit(argv[i][1]) ) + && argv[i][2] == 0 ) + { + switch ( argv[i][1] ) + { + case '3': stereo_image_flag = true; break; + case 'H': showheader_flag = true; break; + case 'h': help_flag = true; break; + case 'n': showindex_flag = true; break; + case 'V': version_flag = true; break; + + default: + fprintf(stderr, "Unrecognized option: %s\n", argv[i]); + return; + } + } + else + { + if ( argv[i][0] != '-' ) + { + filenames.push_back(argv[i]); + } + else + { + fprintf(stderr, "Unrecognized argument: %s\n", argv[i]); + return; + } + } + } + + if ( help_flag || version_flag ) + return; + + if ( filenames.empty() ) + { + fputs("Option requires at least one filename argument.\n", stderr); + return; + } + + error_flag = false; + } +}; + +//------------------------------------------------------------------------------------------ +// + +// +// These classes wrap the irregular names in the asdcplib API +// so that I can use a template to simplify the implementation +// of show_file_info() + +class MyVideoDescriptor : public MPEG2::VideoDescriptor +{ + public: + void FillDescriptor(MPEG2::MXFReader& Reader) { + Reader.FillVideoDescriptor(*this); + } + + void Dump(FILE* stream) { + MPEG2::VideoDescriptorDump(*this, stream); + } +}; + +class MyPictureDescriptor : public JP2K::PictureDescriptor +{ + public: + void FillDescriptor(JP2K::MXFReader& Reader) { + Reader.FillPictureDescriptor(*this); + } + + void Dump(FILE* stream) { + JP2K::PictureDescriptorDump(*this, stream); + } +}; + +class MyStereoPictureDescriptor : public JP2K::PictureDescriptor +{ + public: + void FillDescriptor(JP2K::MXFSReader& Reader) { + Reader.FillPictureDescriptor(*this); + } + + void Dump(FILE* stream) { + JP2K::PictureDescriptorDump(*this, stream); + } +}; + +class MyAudioDescriptor : public PCM::AudioDescriptor +{ + public: + void FillDescriptor(PCM::MXFReader& Reader) { + Reader.FillAudioDescriptor(*this); + } + + void Dump(FILE* stream) { + PCM::AudioDescriptorDump(*this, stream); + } +}; + +class MyTextDescriptor : public TimedText::TimedTextDescriptor +{ + public: + void FillDescriptor(TimedText::MXFReader& Reader) { + Reader.FillTimedTextDescriptor(*this); + } + + void Dump(FILE* stream) { + TimedText::DescriptorDump(*this, stream); + } +}; + +// MSVC didn't like the function template, so now it's a static class method +template<class ReaderT, class DescriptorT> +class FileInfoWrapper +{ +public: + static Result_t + file_info(CommandOptions& Options, const char* type_string, FILE* stream = 0) + { + assert(type_string); + if ( stream == 0 ) + stream = stdout; + + Result_t result = RESULT_OK; + ReaderT Reader; + result = Reader.OpenRead(Options.filenames.front().c_str()); + + if ( ASDCP_SUCCESS(result) ) + { + fprintf(stdout, "File essence type is %s.\n", type_string); + + if ( Options.showheader_flag ) + Reader.DumpHeaderMetadata(stream); + + WriterInfo WI; + Reader.FillWriterInfo(WI); + WriterInfoDump(WI, stream); + + DescriptorT Desc; + Desc.FillDescriptor(Reader); + Desc.Dump(stream); + + if ( Options.showindex_flag ) + Reader.DumpIndex(stream); + } + else if ( result == RESULT_FORMAT && Options.showheader_flag ) + { + Reader.DumpHeaderMetadata(stream); + } + + return result; + } +}; + +// Read header metadata from an ASDCP file +// +Result_t +show_file_info(CommandOptions& Options) +{ + EssenceType_t EssenceType; + Result_t result = ASDCP::EssenceType(Options.filenames.front().c_str(), EssenceType); + + if ( ASDCP_FAILURE(result) ) + return result; + + if ( EssenceType == ESS_MPEG2_VES ) + { + result = FileInfoWrapper<ASDCP::MPEG2::MXFReader, MyVideoDescriptor>::file_info(Options, "MPEG2 video"); + } + else if ( EssenceType == ESS_PCM_24b_48k || EssenceType == ESS_PCM_24b_96k ) + { + result = FileInfoWrapper<ASDCP::PCM::MXFReader, MyAudioDescriptor>::file_info(Options, "PCM audio"); + + if ( ASDCP_SUCCESS(result) ) + { + const Dictionary* Dict = &DefaultCompositeDict(); + PCM::MXFReader Reader; + MXF::OPAtomHeader OPAtomHeader(Dict); + MXF::WaveAudioDescriptor *descriptor = 0; + + result = Reader.OpenRead(Options.filenames.front().c_str()); + + if ( ASDCP_SUCCESS(result) ) + result = Reader.OPAtomHeader().GetMDObjectByType(Dict->ul(MDD_WaveAudioDescriptor), reinterpret_cast<MXF::InterchangeObject**>(&descriptor)); + + if ( ASDCP_SUCCESS(result) ) + { + char buf[64]; + fprintf(stdout, " ChannelAssignment: %s\n", descriptor->ChannelAssignment.EncodeString(buf, 64)); + } + } + } + else if ( EssenceType == ESS_JPEG_2000 ) + { + if ( Options.stereo_image_flag ) + { + result = FileInfoWrapper<ASDCP::JP2K::MXFSReader, + MyStereoPictureDescriptor>::file_info(Options, "JPEG 2000 stereoscopic pictures"); + } + else + { + result = FileInfoWrapper<ASDCP::JP2K::MXFReader, + MyPictureDescriptor>::file_info(Options, "JPEG 2000 pictures"); + } + } + else if ( EssenceType == ESS_JPEG_2000_S ) + { + result = FileInfoWrapper<ASDCP::JP2K::MXFSReader, + MyStereoPictureDescriptor>::file_info(Options, "JPEG 2000 stereoscopic pictures"); + } + else if ( EssenceType == ESS_TIMED_TEXT ) + { + result = FileInfoWrapper<ASDCP::TimedText::MXFReader, MyTextDescriptor>::file_info(Options, "Timed Text"); + } + else + { + fprintf(stderr, "File is not AS-DCP: %s\n", Options.filenames.front().c_str()); + Kumu::FileReader Reader; + const Dictionary* Dict = &DefaultCompositeDict(); + MXF::OPAtomHeader TestHeader(Dict); + + result = Reader.OpenRead(Options.filenames.front().c_str()); + + if ( ASDCP_SUCCESS(result) ) + result = TestHeader.InitFromFile(Reader); // test UL and OP + + if ( ASDCP_SUCCESS(result) ) + { + TestHeader.Partition::Dump(stdout); + + if ( MXF::Identification* ID = TestHeader.GetIdentification() ) + ID->Dump(stdout); + else + fputs("File contains no Identification object.\n", stdout); + + if ( MXF::SourcePackage* SP = TestHeader.GetSourcePackage() ) + SP->Dump(stdout); + else + fputs("File contains no SourcePackage object.\n", stdout); + } + else + { + fputs("File is not MXF.\n", stdout); + } + } + + return result; +} + +// +int +main(int argc, const char** argv) +{ + Result_t result = RESULT_OK; + char str_buf[64]; + CommandOptions Options(argc, argv); + + if ( Options.version_flag ) + banner(); + + if ( Options.help_flag ) + usage(); + + if ( Options.version_flag || Options.help_flag ) + return 0; + + if ( Options.error_flag ) + { + fprintf(stderr, "There was a problem. Type %s -h for help.\n", PROGRAM_NAME); + return 3; + } + + while ( ! Options.filenames.empty() && ASDCP_SUCCESS(result) ) + { + result = show_file_info(Options); + Options.filenames.pop_front(); + } + + if ( ASDCP_FAILURE(result) ) + { + fputs("Program stopped on error.\n", stderr); + + if ( result == RESULT_SFORMAT ) + { + fputs("Use option '-3' to force stereoscopic mode.\n", stderr); + } + else if ( result != RESULT_FAIL ) + { + fputs(result, stderr); + fputc('\n', stderr); + } + + return 1; + } + + return 0; +} + + +// +// end asdcp-info.cpp +// diff --git a/asdcplib/src/asdcp-mem-test.cpp b/asdcplib/src/asdcp-mem-test.cpp new file mode 100755 index 0000000..0ce6d90 --- /dev/null +++ b/asdcplib/src/asdcp-mem-test.cpp @@ -0,0 +1,148 @@ +/* +Copyright (c) 2004-2009, 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 asdcp-mem-test.cpp + \version $Id: asdcp-mem-test.cpp,v 1.4 2009/04/09 19:24:14 msheby Exp $ + \brief AS-DCP frame buffer allocation test +*/ + + +#include <AS_DCP_internal.h> +//#include <KM_platform.h> +#include <KM_prng.h> + +#include <iostream> +#include <assert.h> + +using namespace ASDCP; +using namespace Kumu; + +const ui32_t buf_size = 1024; +FortunaRNG RNG; + +// +int a() +{ + FrameBuffer FB; + FB.Capacity(buf_size); + assert(FB.Capacity() == buf_size); + RNG.FillRandom(FB.Data(), FB.Capacity()); + + return 0; +} + +// +int b() +{ + byte_t* buf = (byte_t*)malloc(buf_size); + assert(buf); + RNG.FillRandom(buf, buf_size); + + { + FrameBuffer FB; + FB.SetData(buf, buf_size); + assert(FB.Data() == buf); + assert(FB.Capacity() == buf_size); + // ~FB() is called... + } + + free(buf); + return 0; +} + +// +int c() +{ + byte_t* buf = (byte_t*)malloc(buf_size); + assert(buf); + RNG.FillRandom(buf, buf_size); + + { + FrameBuffer FB; + FB.SetData(buf, buf_size); + assert(FB.Data() == buf); + assert(FB.Capacity() == buf_size); + + FB.SetData(0,0); + assert(FB.Data() == 0); + assert(FB.Capacity() == 0); + + FB.Capacity(buf_size); + assert(FB.Capacity() == buf_size); + RNG.FillRandom(FB.Data(), FB.Capacity()); + // ~FB() is called... + } + + free(buf); + return 0; +} + +// +int d() +{ + // MPEG2::Parser mPFile; + MPEG2::MXFReader mRFile; + Result_t result = mRFile.OpenRead("../tests/write_test_mpeg.mxf"); + assert(ASDCP_SUCCESS(result)); + + // MPEG2::MXFWriter mWFile; + JP2K::CodestreamParser jPCFile; + JP2K::SequenceParser jPSFile; + JP2K::MXFReader jRFile; + JP2K::MXFWriter jWFile; + + PCM::WAVParser pPFile; + PCM::MXFReader pRFile; + PCM::MXFWriter pWFile; + return 0; +} + +// +int +main( int argc, char **argv ) +{ + ui32_t i = 0x00010000; + fputs("Watch your process monitor, memory usage should not change after startup.\n", stderr); + + while ( i-- ) + { + a(); + b(); + c(); + d(); + + if ( i && ( i % 1000 ) == 0 ) + fputc('.', stderr); + } + + fputc('\n', stderr); + return 0; +} + + +// +// end asdcp-mem-test.cpp +// diff --git a/asdcplib/src/asdcp-test.cpp b/asdcplib/src/asdcp-test.cpp new file mode 100755 index 0000000..05f486f --- /dev/null +++ b/asdcplib/src/asdcp-test.cpp @@ -0,0 +1,2087 @@ +/* +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 asdcp-test.cpp + \version $Id: asdcp-test.cpp,v 1.46 2012/02/03 19:49:56 jhurst Exp $ + \brief AS-DCP file manipulation utility + + This program provides command line access to the major features of the asdcplib + library, and serves as a library unit test which provides the functionality of + the supported use cases. + + For more information about asdcplib, please refer to the header file AS_DCP.h + + WARNING: While the asdcplib library attempts to provide a complete and secure + implementation of the cryptographic features of the AS-DCP file formats, this + unit test program is NOT secure and is therefore NOT SUITABLE FOR USE in a + production environment without some modification. + + In particular, this program uses weak IV generation and externally generated + plaintext keys. These shortcomings exist because cryptographic-quality + random number generation and key management are outside the scope of the + asdcplib library. Developers using asdcplib for commercial implementations + claiming SMPTE conformance are expected to provide proper implementations of + these features. +*/ + +#include <KM_fileio.h> +#include <KM_prng.h> +#include <PCMParserList.h> +#include <WavFileWriter.h> +#include <MXF.h> +#include <Metadata.h> +#include <openssl/sha.h> + +#include <iostream> +#include <assert.h> + +using namespace ASDCP; + +const ui32_t FRAME_BUFFER_SIZE = 4 * Kumu::Megabyte; + +//------------------------------------------------------------------------------------------ +// +// command line option parser class + +static const char* PROGRAM_NAME = "asdcp-test"; // program name for messages +const ui32_t MAX_IN_FILES = 16; // maximum number of input files handled by + // the command option parser + +// local program identification info written to file headers +class MyInfo : public WriterInfo +{ +public: + MyInfo() + { + static byte_t default_ProductUUID_Data[UUIDlen] = + { 0x7d, 0x83, 0x6e, 0x16, 0x37, 0xc7, 0x4c, 0x22, + 0xb2, 0xe0, 0x46, 0xa7, 0x17, 0xe8, 0x4f, 0x42 }; + + memcpy(ProductUUID, default_ProductUUID_Data, UUIDlen); + CompanyName = "WidgetCo"; + ProductName = "asdcp-test"; + ProductVersion = ASDCP::Version(); + } +} s_MyInfo; + + + +// Increment the iterator, test for an additional non-option command line argument. +// Causes the caller to return if there are no remaining arguments or if the next +// argument begins with '-'. +#define TEST_EXTRA_ARG(i,c) if ( ++i >= argc || argv[(i)][0] == '-' ) \ + { \ + fprintf(stderr, "Argument not found for option -%c.\n", (c)); \ + return; \ + } +// +void +banner(FILE* stream = stdout) +{ + fprintf(stream, "\n\ +%s (asdcplib %s)\n\n\ +Copyright (c) 2003-2012 John Hurst\n\n\ +asdcplib may be copied only under the terms of the license found at\n\ +the top of every file in the asdcplib distribution kit.\n\n\ +Specify the -h (help) option for further information about %s\n\n", + PROGRAM_NAME, ASDCP::Version(), PROGRAM_NAME); +} + +// +void +usage(FILE* stream = stdout) +{ + fprintf(stream, "\ +USAGE: %s -c <output-file> [-3] [-a <uuid>] [-b <buffer-size>]\n\ + [-d <duration>] [-e|-E] [-f <start-frame>] [-j <key-id-string>]\n\ + [-k <key-string>] [-l <label>] [-L] [-M] [-p <frame-rate>] [-R]\n\ + [-s <num>] [-v] [-W] [-z|-Z] <input-file> [<input-file-2> ...]\n\ +\n\ + %s [-h|-help] [-V]\n\ +\n\ + %s -i [-H] [-n] [-v] <input-file>\n\ +\n\ + %s -g | -u\n\ +\n\ + %s -G [-v] <input-file>\n\ +\n\ + %s -t <input-file>\n\ +\n\ + %s -x <file-prefix> [-3] [-b <buffer-size>] [-d <duration>]\n\ + [-f <starting-frame>] [-m] [-p <frame-rate>] [-R] [-s <num>] [-S|-1]\n\ + [-v] [-W] [-w] <input-file>\n\n", + PROGRAM_NAME, PROGRAM_NAME, PROGRAM_NAME, PROGRAM_NAME, + PROGRAM_NAME, PROGRAM_NAME, PROGRAM_NAME); + + fprintf(stream, "\ +Major modes:\n\ + -3 - With -c, create a stereoscopic image file. Expects two\n\ + directories of JP2K codestreams (directories must have\n\ + an equal number of frames; left eye is first).\n\ + - With -x, force stereoscopic interpretation of a JP2K\n\ + track file.\n\ + -c <output-file> - Create an AS-DCP track file from input(s)\n\ + -g - Generate a random 16 byte value to stdout\n\ + -G - Perform GOP start lookup test on MXF+Interop MPEG file\n\ + -h | -help - Show help\n\ + -i - Show file info\n\ + -t - Calculate message digest of input file\n\ + -U - Dump UL catalog to stdout\n\ + -u - Generate a random UUID value to stdout\n\ + -V - Show version information\n\ + -x <root-name> - Extract essence from AS-DCP file to named file(s)\n\ +\n"); + + fprintf(stream, "\ +Security Options:\n\ + -e - Encrypt MPEG or JP2K headers (default)\n\ + -E - Do not encrypt MPEG or JP2K headers\n\ + -j <key-id-str> - Write key ID instead of creating a random value\n\ + -k <key-string> - Use key for ciphertext operations\n\ + -m - verify HMAC values when reading\n\ + -M - Do not create HMAC values when writing\n\ +\n"); + + fprintf(stream, "\ +Read/Write Options:\n\ + -a <UUID> - Specify the Asset ID of a file (with -c)\n\ + -b <buffer-size> - Specify size in bytes of picture frame buffer.\n\ + Defaults to 4,194,304 (4MB)\n\ + -d <duration> - Number of frames to process, default all\n\ + -f <start-frame> - Starting frame number, default 0\n\ + -l <label> - Use given channel format label when writing MXF sound\n\ + files. SMPTE 429-2 labels: '5.1', '6.1', '7.1', '7.1DS', 'WTF'.\n\ + Default is no label (valid for Interop only).\n\ + -L - Write SMPTE UL values instead of MXF Interop\n\ + -p <rate> - fps of picture when wrapping PCM or JP2K:\n\ + Use one of [23|24|25|30|48|50|60], 24 is default\n\ + -R - Repeat the first frame over the entire file (picture\n\ + essence only, requires -c, -d)\n\ + -S - Split Wave essence to stereo WAV files during extract.\n\ + Default is multichannel WAV\n\ + -1 - Split Wave essence to mono WAV files during extract.\n\ + Default is multichannel WAV\n\ + -W - Read input file only, do not write source file\n\ + -w <width> - Width of numeric element in a series of frame file names\n\ + (use with -x, default 6).\n\ + -z - Fail if j2c inputs have unequal parameters (default)\n\ + -Z - Ignore unequal parameters in j2c inputs\n\ +\n"); + + fprintf(stream, "\ +Info Options:\n\ + -H - Show MXF header metadata, used with option -i\n\ + -n - Show index, used with option -i\n\ +\n\ +Other Options:\n\ + -s <num> - Number of bytes of frame buffer to be dumped as hex to\n\ + stderr, used with option -v\n\ + -v - Verbose, prints informative messages to stderr\n\ +\n\ + NOTES: o There is no option grouping, all options must be distinct arguments.\n\ + o All option arguments must be separated from the option by whitespace.\n\ + o An argument of \"23\" to the -p option will be interpreted\n\ + as 24000/1001 fps.\n\ +\n"); +} + +// +enum MajorMode_t +{ + MMT_NONE, + MMT_INFO, + MMT_CREATE, + MMT_EXTRACT, + MMT_GEN_ID, + MMT_GEN_KEY, + MMT_GOP_START, + MMT_DIGEST, + MMT_UL_LIST, +}; + +// +PCM::ChannelFormat_t +decode_channel_fmt(const std::string& label_name) +{ + if ( label_name == "5.1" ) + return PCM::CF_CFG_1; + + else if ( label_name == "6.1" ) + return PCM::CF_CFG_2; + + else if ( label_name == "7.1" ) + return PCM::CF_CFG_3; + + else if ( label_name == "WTF" ) + return PCM::CF_CFG_4; + + else if ( label_name == "7.1DS" ) + return PCM::CF_CFG_5; + + fprintf(stderr, "Error decoding channel format string: %s\n", label_name.c_str()); + fprintf(stderr, "Expecting '5.1', '6.1', '7.1', '7.1DS' or 'WTF'\n"); + return PCM::CF_NONE; +} + +// +// +class CommandOptions +{ + CommandOptions(); + +public: + MajorMode_t mode; + bool error_flag; // true if the given options are in error or not complete + bool key_flag; // true if an encryption key was given + bool key_id_flag; // true if a key ID was given + bool asset_id_flag; // true if an asset ID was given + bool encrypt_header_flag; // true if mpeg headers are to be encrypted + bool write_hmac; // true if HMAC values are to be generated and written + bool read_hmac; // true if HMAC values are to be validated + bool split_wav; // true if PCM is to be extracted to stereo WAV files + bool mono_wav; // true if PCM is to be extracted to mono WAV files + bool verbose_flag; // true if the verbose option was selected + ui32_t fb_dump_size; // number of bytes of frame buffer to dump + bool showindex_flag; // true if index is to be displayed + bool showheader_flag; // true if MXF file header is to be displayed + bool no_write_flag; // true if no output files are to be written + bool version_flag; // true if the version display option was selected + bool help_flag; // true if the help display option was selected + bool stereo_image_flag; // if true, expect stereoscopic JP2K input (left eye first) + ui32_t number_width; // number of digits in a serialized filename (for JPEG extract) + ui32_t start_frame; // frame number to begin processing + ui32_t duration; // number of frames to be processed + bool duration_flag; // true if duration argument given + bool do_repeat; // if true and -c -d, repeat first input frame + bool use_smpte_labels; // if true, SMPTE UL values will be written instead of MXF Interop values + bool j2c_pedantic; // passed to JP2K::SequenceParser::OpenRead + ui32_t picture_rate; // fps of picture when wrapping PCM + ui32_t fb_size; // size of picture frame buffer + ui32_t file_count; // number of elements in filenames[] + const char* file_root; // filename pre for files written by the extract mode + const char* out_file; // name of mxf file created by create mode + byte_t key_value[KeyLen]; // value of given encryption key (when key_flag is true) + byte_t key_id_value[UUIDlen];// value of given key ID (when key_id_flag is true) + byte_t asset_id_value[UUIDlen];// value of asset ID (when asset_id_flag is true) + const char* filenames[MAX_IN_FILES]; // list of filenames to be processed + PCM::ChannelFormat_t channel_fmt; // audio channel arrangement + + // + Rational PictureRate() + { + if ( picture_rate == 23 ) return EditRate_23_98; + if ( picture_rate == 24 ) return EditRate_24; + if ( picture_rate == 25 ) return EditRate_25; + if ( picture_rate == 30 ) return EditRate_30; + if ( picture_rate == 48 ) return EditRate_48; + if ( picture_rate == 50 ) return EditRate_50; + if ( picture_rate == 60 ) return EditRate_60; + if ( picture_rate == 96 ) return EditRate_96; + if ( picture_rate == 100 ) return EditRate_100; + if ( picture_rate == 120 ) return EditRate_120; + return EditRate_24; + } + + // + const char* szPictureRate() + { + if ( picture_rate == 23 ) return "23.976"; + if ( picture_rate == 24 ) return "24"; + if ( picture_rate == 25 ) return "25"; + if ( picture_rate == 30 ) return "30"; + if ( picture_rate == 48 ) return "48"; + if ( picture_rate == 50 ) return "50"; + if ( picture_rate == 60 ) return "60"; + if ( picture_rate == 96 ) return "96"; + if ( picture_rate == 100 ) return "100"; + if ( picture_rate == 120 ) return "120"; + return "24"; + } + + // + CommandOptions(int argc, const char** argv) : + mode(MMT_NONE), error_flag(true), key_flag(false), key_id_flag(false), asset_id_flag(false), + encrypt_header_flag(true), write_hmac(true), read_hmac(false), split_wav(false), mono_wav(false), + verbose_flag(false), fb_dump_size(0), showindex_flag(false), showheader_flag(false), + no_write_flag(false), version_flag(false), help_flag(false), stereo_image_flag(false), + number_width(6), start_frame(0), + duration(0xffffffff), duration_flag(false), do_repeat(false), use_smpte_labels(false), j2c_pedantic(true), + picture_rate(24), fb_size(FRAME_BUFFER_SIZE), file_count(0), file_root(0), out_file(0), + channel_fmt(PCM::CF_NONE) + { + memset(key_value, 0, KeyLen); + memset(key_id_value, 0, UUIDlen); + + for ( int i = 1; i < argc; i++ ) + { + + if ( (strcmp( argv[i], "-help") == 0) ) + { + help_flag = true; + continue; + } + + if ( argv[i][0] == '-' + && ( isalpha(argv[i][1]) || isdigit(argv[i][1]) ) + && argv[i][2] == 0 ) + { + switch ( argv[i][1] ) + { + case '1': mono_wav = true; break; + case '2': split_wav = true; break; + case '3': stereo_image_flag = true; break; + + case 'a': + asset_id_flag = true; + TEST_EXTRA_ARG(i, 'a'); + { + ui32_t length; + Kumu::hex2bin(argv[i], asset_id_value, UUIDlen, &length); + + if ( length != UUIDlen ) + { + fprintf(stderr, "Unexpected asset ID length: %u, expecting %u characters.\n", length, UUIDlen); + return; + } + } + break; + + case 'b': + TEST_EXTRA_ARG(i, 'b'); + fb_size = abs(atoi(argv[i])); + + if ( verbose_flag ) + fprintf(stderr, "Frame Buffer size: %u bytes.\n", fb_size); + + break; + + case 'c': + TEST_EXTRA_ARG(i, 'c'); + mode = MMT_CREATE; + out_file = argv[i]; + break; + + case 'd': + TEST_EXTRA_ARG(i, 'd'); + duration_flag = true; + duration = abs(atoi(argv[i])); + break; + + case 'E': encrypt_header_flag = false; break; + case 'e': encrypt_header_flag = true; break; + + case 'f': + TEST_EXTRA_ARG(i, 'f'); + start_frame = abs(atoi(argv[i])); + break; + + case 'G': mode = MMT_GOP_START; break; + case 'g': mode = MMT_GEN_KEY; break; + case 'H': showheader_flag = true; break; + case 'h': help_flag = true; break; + case 'i': mode = MMT_INFO; break; + + case 'j': key_id_flag = true; + TEST_EXTRA_ARG(i, 'j'); + { + ui32_t length; + Kumu::hex2bin(argv[i], key_id_value, UUIDlen, &length); + + if ( length != UUIDlen ) + { + fprintf(stderr, "Unexpected key ID length: %u, expecting %u characters.\n", length, UUIDlen); + return; + } + } + break; + + case 'k': key_flag = true; + TEST_EXTRA_ARG(i, 'k'); + { + ui32_t length; + Kumu::hex2bin(argv[i], key_value, KeyLen, &length); + + if ( length != KeyLen ) + { + fprintf(stderr, "Unexpected key length: %u, expecting %u characters.\n", length, KeyLen); + return; + } + } + break; + + case 'l': + TEST_EXTRA_ARG(i, 'l'); + channel_fmt = decode_channel_fmt(argv[i]); + break; + + case 'L': use_smpte_labels = true; break; + case 'M': write_hmac = false; break; + case 'm': read_hmac = true; break; + case 'n': showindex_flag = true; break; + + case 'p': + TEST_EXTRA_ARG(i, 'p'); + picture_rate = abs(atoi(argv[i])); + break; + + case 'R': do_repeat = true; break; + case 'S': split_wav = true; break; + + case 's': + TEST_EXTRA_ARG(i, 's'); + fb_dump_size = abs(atoi(argv[i])); + break; + + case 't': mode = MMT_DIGEST; break; + case 'U': mode = MMT_UL_LIST; break; + case 'u': mode = MMT_GEN_ID; break; + case 'V': version_flag = true; break; + case 'v': verbose_flag = true; break; + case 'W': no_write_flag = true; break; + + case 'w': + TEST_EXTRA_ARG(i, 'w'); + number_width = abs(atoi(argv[i])); + break; + + case 'x': + TEST_EXTRA_ARG(i, 'x'); + mode = MMT_EXTRACT; + file_root = argv[i]; + break; + + case 'Z': j2c_pedantic = false; break; + case 'z': j2c_pedantic = true; break; + + default: + fprintf(stderr, "Unrecognized option: %s\n", argv[i]); + return; + } + } + else + { + + if ( argv[i][0] != '-' ) + { + filenames[file_count++] = argv[i]; + } + else + { + fprintf(stderr, "Unrecognized argument: %s\n", argv[i]); + return; + } + + if ( file_count >= MAX_IN_FILES ) + { + fprintf(stderr, "Filename lists exceeds maximum list size: %u\n", MAX_IN_FILES); + return; + } + } + } + + if ( help_flag || version_flag ) + return; + + if ( ( mode == MMT_INFO + || mode == MMT_CREATE + || mode == MMT_EXTRACT + || mode == MMT_GOP_START + || mode == MMT_DIGEST ) && file_count == 0 ) + { + fputs("Option requires at least one filename argument.\n", stderr); + return; + } + + if ( mode == MMT_NONE && ! help_flag && ! version_flag ) + { + fputs("No operation selected (use one of -[gGcitux] or -h for help).\n", stderr); + return; + } + + error_flag = false; + } +}; + +//------------------------------------------------------------------------------------------ +// MPEG2 essence + +// Write a plaintext MPEG2 Video Elementary Stream to a plaintext ASDCP file +// Write a plaintext MPEG2 Video Elementary Stream to a ciphertext ASDCP file +// +Result_t +write_MPEG2_file(CommandOptions& Options) +{ + AESEncContext* Context = 0; + HMACContext* HMAC = 0; + MPEG2::FrameBuffer FrameBuffer(Options.fb_size); + MPEG2::Parser Parser; + MPEG2::MXFWriter Writer; + MPEG2::VideoDescriptor VDesc; + byte_t IV_buf[CBC_BLOCK_SIZE]; + Kumu::FortunaRNG RNG; + + // set up essence parser + Result_t result = Parser.OpenRead(Options.filenames[0]); + + // set up MXF writer + if ( ASDCP_SUCCESS(result) ) + { + Parser.FillVideoDescriptor(VDesc); + + if ( Options.verbose_flag ) + { + fputs("MPEG-2 Pictures\n", stderr); + fputs("VideoDescriptor:\n", stderr); + fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size); + MPEG2::VideoDescriptorDump(VDesc); + } + } + + if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag ) + { + WriterInfo Info = s_MyInfo; // fill in your favorite identifiers here + if ( Options.asset_id_flag ) + memcpy(Info.AssetUUID, Options.asset_id_value, UUIDlen); + else + Kumu::GenRandomUUID(Info.AssetUUID); + + if ( Options.use_smpte_labels ) + { + Info.LabelSetType = LS_MXF_SMPTE; + fprintf(stderr, "ATTENTION! Writing SMPTE Universal Labels\n"); + } + + // configure encryption + if( Options.key_flag ) + { + Kumu::GenRandomUUID(Info.ContextID); + Info.EncryptedEssence = true; + + if ( Options.key_id_flag ) + memcpy(Info.CryptographicKeyID, Options.key_id_value, UUIDlen); + else + RNG.FillRandom(Info.CryptographicKeyID, UUIDlen); + + Context = new AESEncContext; + result = Context->InitKey(Options.key_value); + + if ( ASDCP_SUCCESS(result) ) + result = Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE)); + + if ( ASDCP_SUCCESS(result) && Options.write_hmac ) + { + Info.UsesHMAC = true; + HMAC = new HMACContext; + result = HMAC->InitKey(Options.key_value, Info.LabelSetType); + } + } + + if ( ASDCP_SUCCESS(result) ) + result = Writer.OpenWrite(Options.out_file, Info, VDesc); + } + + if ( ASDCP_SUCCESS(result) ) + // loop through the frames + { + result = Parser.Reset(); + ui32_t duration = 0; + + while ( ASDCP_SUCCESS(result) && duration++ < Options.duration ) + { + if ( ! Options.do_repeat || duration == 1 ) + { + result = Parser.ReadFrame(FrameBuffer); + + if ( ASDCP_SUCCESS(result) ) + { + if ( Options.verbose_flag ) + FrameBuffer.Dump(stderr, Options.fb_dump_size); + + if ( Options.encrypt_header_flag ) + FrameBuffer.PlaintextOffset(0); + } + } + + if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag ) + { + result = Writer.WriteFrame(FrameBuffer, Context, HMAC); + + // The Writer class will forward the last block of ciphertext + // to the encryption context for use as the IV for the next + // frame. If you want to use non-sequitur IV values, un-comment + // the following line of code. + // if ( ASDCP_SUCCESS(result) && Options.key_flag ) + // Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE)); + } + } + + if ( result == RESULT_ENDOFFILE ) + result = RESULT_OK; + } + + if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag ) + result = Writer.Finalize(); + + return result; +} + +// Read a plaintext MPEG2 Video Elementary Stream from a plaintext ASDCP file +// Read a plaintext MPEG2 Video Elementary Stream from a ciphertext ASDCP file +// Read a ciphertext MPEG2 Video Elementary Stream from a ciphertext ASDCP file +// +Result_t +read_MPEG2_file(CommandOptions& Options) +{ + AESDecContext* Context = 0; + HMACContext* HMAC = 0; + MPEG2::MXFReader Reader; + MPEG2::FrameBuffer FrameBuffer(Options.fb_size); + Kumu::FileWriter OutFile; + ui32_t frame_count = 0; + + Result_t result = Reader.OpenRead(Options.filenames[0]); + + if ( ASDCP_SUCCESS(result) ) + { + MPEG2::VideoDescriptor VDesc; + Reader.FillVideoDescriptor(VDesc); + frame_count = VDesc.ContainerDuration; + + if ( Options.verbose_flag ) + { + fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size); + MPEG2::VideoDescriptorDump(VDesc); + } + } + + if ( ASDCP_SUCCESS(result) ) + { + char filename[256]; + snprintf(filename, 256, "%s.ves", Options.file_root); + result = OutFile.OpenWrite(filename); + } + + if ( ASDCP_SUCCESS(result) && Options.key_flag ) + { + Context = new AESDecContext; + result = Context->InitKey(Options.key_value); + + if ( ASDCP_SUCCESS(result) && Options.read_hmac ) + { + WriterInfo Info; + Reader.FillWriterInfo(Info); + + if ( Info.UsesHMAC ) + { + HMAC = new HMACContext; + result = HMAC->InitKey(Options.key_value, Info.LabelSetType); + } + else + { + fputs("File does not contain HMAC values, ignoring -m option.\n", stderr); + } + } + } + + ui32_t last_frame = Options.start_frame + ( Options.duration ? Options.duration : frame_count); + if ( last_frame > frame_count ) + last_frame = frame_count; + + for ( ui32_t i = Options.start_frame; ASDCP_SUCCESS(result) && i < last_frame; i++ ) + { + result = Reader.ReadFrame(i, FrameBuffer, Context, HMAC); + + if ( ASDCP_SUCCESS(result) ) + { + if ( Options.verbose_flag ) + FrameBuffer.Dump(stderr, Options.fb_dump_size); + + ui32_t write_count = 0; + result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count); + } + } + + return result; +} + + +// +Result_t +gop_start_test(CommandOptions& Options) +{ + using namespace ASDCP::MPEG2; + + MXFReader Reader; + MPEG2::FrameBuffer FrameBuffer(Options.fb_size); + ui32_t frame_count = 0; + + Result_t result = Reader.OpenRead(Options.filenames[0]); + + if ( ASDCP_SUCCESS(result) ) + { + MPEG2::VideoDescriptor VDesc; + Reader.FillVideoDescriptor(VDesc); + frame_count = VDesc.ContainerDuration; + + if ( Options.verbose_flag ) + { + fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size); + MPEG2::VideoDescriptorDump(VDesc); + } + } + + ui32_t last_frame = Options.start_frame + ( Options.duration ? Options.duration : frame_count); + if ( last_frame > frame_count ) + last_frame = frame_count; + + for ( ui32_t i = Options.start_frame; ASDCP_SUCCESS(result) && i < last_frame; i++ ) + { + result = Reader.ReadFrameGOPStart(i, FrameBuffer); + + if ( ASDCP_SUCCESS(result) ) + { + if ( Options.verbose_flag ) + FrameBuffer.Dump(stderr, Options.fb_dump_size); + + if ( FrameBuffer.FrameType() != FRAME_I ) + fprintf(stderr, "Expecting an I frame, got %c\n", FrameTypeChar(FrameBuffer.FrameType())); + + fprintf(stderr, "Requested frame %u, got %u\n", i, FrameBuffer.FrameNumber()); + } + } + + return result; +} + +//------------------------------------------------------------------------------------------ +// JPEG 2000 essence + +// Write one or more plaintext JPEG 2000 stereoscopic codestream pairs to a plaintext ASDCP file +// Write one or more plaintext JPEG 2000 stereoscopic codestream pairs to a ciphertext ASDCP file +// +Result_t +write_JP2K_S_file(CommandOptions& Options) +{ + AESEncContext* Context = 0; + HMACContext* HMAC = 0; + JP2K::MXFSWriter Writer; + JP2K::FrameBuffer FrameBuffer(Options.fb_size); + JP2K::PictureDescriptor PDesc; + JP2K::SequenceParser ParserLeft, ParserRight; + byte_t IV_buf[CBC_BLOCK_SIZE]; + Kumu::FortunaRNG RNG; + + if ( Options.file_count != 2 ) + { + fprintf(stderr, "Two inputs are required for stereoscopic option.\n"); + return RESULT_FAIL; + } + + // set up essence parser + Result_t result = ParserLeft.OpenRead(Options.filenames[0], Options.j2c_pedantic); + + if ( ASDCP_SUCCESS(result) ) + result = ParserRight.OpenRead(Options.filenames[1], Options.j2c_pedantic); + + // set up MXF writer + if ( ASDCP_SUCCESS(result) ) + { + ParserLeft.FillPictureDescriptor(PDesc); + PDesc.EditRate = Options.PictureRate(); + + if ( Options.verbose_flag ) + { + fputs("JPEG 2000 stereoscopic pictures\nPictureDescriptor:\n", stderr); + fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size); + JP2K::PictureDescriptorDump(PDesc); + } + } + + if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag ) + { + WriterInfo Info = s_MyInfo; // fill in your favorite identifiers here + if ( Options.asset_id_flag ) + memcpy(Info.AssetUUID, Options.asset_id_value, UUIDlen); + else + Kumu::GenRandomUUID(Info.AssetUUID); + + if ( Options.use_smpte_labels ) + { + Info.LabelSetType = LS_MXF_SMPTE; + fprintf(stderr, "ATTENTION! Writing SMPTE Universal Labels\n"); + } + + // configure encryption + if( Options.key_flag ) + { + Kumu::GenRandomUUID(Info.ContextID); + Info.EncryptedEssence = true; + + if ( Options.key_id_flag ) + memcpy(Info.CryptographicKeyID, Options.key_id_value, UUIDlen); + else + RNG.FillRandom(Info.CryptographicKeyID, UUIDlen); + + Context = new AESEncContext; + result = Context->InitKey(Options.key_value); + + if ( ASDCP_SUCCESS(result) ) + result = Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE)); + + if ( ASDCP_SUCCESS(result) && Options.write_hmac ) + { + Info.UsesHMAC = true; + HMAC = new HMACContext; + result = HMAC->InitKey(Options.key_value, Info.LabelSetType); + } + } + + if ( ASDCP_SUCCESS(result) ) + result = Writer.OpenWrite(Options.out_file, Info, PDesc); + } + + if ( ASDCP_SUCCESS(result) ) + { + ui32_t duration = 0; + result = ParserLeft.Reset(); + if ( ASDCP_SUCCESS(result) ) result = ParserRight.Reset(); + + while ( ASDCP_SUCCESS(result) && duration++ < Options.duration ) + { + result = ParserLeft.ReadFrame(FrameBuffer); + + if ( ASDCP_SUCCESS(result) ) + { + if ( Options.verbose_flag ) + FrameBuffer.Dump(stderr, Options.fb_dump_size); + + if ( Options.encrypt_header_flag ) + FrameBuffer.PlaintextOffset(0); + } + + if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag ) + result = Writer.WriteFrame(FrameBuffer, JP2K::SP_LEFT, Context, HMAC); + + if ( ASDCP_SUCCESS(result) ) + result = ParserRight.ReadFrame(FrameBuffer); + + if ( ASDCP_SUCCESS(result) ) + { + if ( Options.verbose_flag ) + FrameBuffer.Dump(stderr, Options.fb_dump_size); + + if ( Options.encrypt_header_flag ) + FrameBuffer.PlaintextOffset(0); + } + + if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag ) + result = Writer.WriteFrame(FrameBuffer, JP2K::SP_RIGHT, Context, HMAC); + } + + if ( result == RESULT_ENDOFFILE ) + result = RESULT_OK; + } + + if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag ) + result = Writer.Finalize(); + + return result; +} + +// Read one or more plaintext JPEG 2000 stereoscopic codestream pairs from a plaintext ASDCP file +// Read one or more plaintext JPEG 2000 stereoscopic codestream pairs from a ciphertext ASDCP file +// Read one or more ciphertext JPEG 2000 stereoscopic codestream pairs from a ciphertext ASDCP file +Result_t +read_JP2K_S_file(CommandOptions& Options) +{ + AESDecContext* Context = 0; + HMACContext* HMAC = 0; + JP2K::MXFSReader Reader; + JP2K::FrameBuffer FrameBuffer(Options.fb_size); + ui32_t frame_count = 0; + + Result_t result = Reader.OpenRead(Options.filenames[0]); + + if ( ASDCP_SUCCESS(result) ) + { + JP2K::PictureDescriptor PDesc; + Reader.FillPictureDescriptor(PDesc); + + frame_count = PDesc.ContainerDuration; + + if ( Options.verbose_flag ) + { + fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size); + JP2K::PictureDescriptorDump(PDesc); + } + } + + if ( ASDCP_SUCCESS(result) && Options.key_flag ) + { + Context = new AESDecContext; + result = Context->InitKey(Options.key_value); + + if ( ASDCP_SUCCESS(result) && Options.read_hmac ) + { + WriterInfo Info; + Reader.FillWriterInfo(Info); + + if ( Info.UsesHMAC ) + { + HMAC = new HMACContext; + result = HMAC->InitKey(Options.key_value, Info.LabelSetType); + } + else + { + fputs("File does not contain HMAC values, ignoring -m option.\n", stderr); + } + } + } + + const int filename_max = 1024; + char filename[filename_max]; + ui32_t last_frame = Options.start_frame + ( Options.duration ? Options.duration : frame_count); + if ( last_frame > frame_count ) + last_frame = frame_count; + + char left_format[64]; char right_format[64]; + snprintf(left_format, 64, "%%s%%0%duL.j2c", Options.number_width); + snprintf(right_format, 64, "%%s%%0%duR.j2c", Options.number_width); + + for ( ui32_t i = Options.start_frame; ASDCP_SUCCESS(result) && i < last_frame; i++ ) + { + result = Reader.ReadFrame(i, JP2K::SP_LEFT, FrameBuffer, Context, HMAC); + + if ( ASDCP_SUCCESS(result) ) + { + Kumu::FileWriter OutFile; + ui32_t write_count; + snprintf(filename, filename_max, left_format, Options.file_root, i); + result = OutFile.OpenWrite(filename); + + if ( ASDCP_SUCCESS(result) ) + result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count); + + if ( Options.verbose_flag ) + FrameBuffer.Dump(stderr, Options.fb_dump_size); + } + + if ( ASDCP_SUCCESS(result) ) + result = Reader.ReadFrame(i, JP2K::SP_RIGHT, FrameBuffer, Context, HMAC); + + if ( ASDCP_SUCCESS(result) ) + { + Kumu::FileWriter OutFile; + ui32_t write_count; + snprintf(filename, filename_max, right_format, Options.file_root, i); + result = OutFile.OpenWrite(filename); + + if ( ASDCP_SUCCESS(result) ) + result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count); + } + } + + return result; +} + + + +// Write one or more plaintext JPEG 2000 codestreams to a plaintext ASDCP file +// Write one or more plaintext JPEG 2000 codestreams to a ciphertext ASDCP file +// +Result_t +write_JP2K_file(CommandOptions& Options) +{ + AESEncContext* Context = 0; + HMACContext* HMAC = 0; + JP2K::MXFWriter Writer; + JP2K::FrameBuffer FrameBuffer(Options.fb_size); + JP2K::PictureDescriptor PDesc; + JP2K::SequenceParser Parser; + byte_t IV_buf[CBC_BLOCK_SIZE]; + Kumu::FortunaRNG RNG; + + // set up essence parser + Result_t result = Parser.OpenRead(Options.filenames[0], Options.j2c_pedantic); + + // set up MXF writer + if ( ASDCP_SUCCESS(result) ) + { + Parser.FillPictureDescriptor(PDesc); + PDesc.EditRate = Options.PictureRate(); + + if ( Options.verbose_flag ) + { + fprintf(stderr, "JPEG 2000 pictures\n"); + fputs("PictureDescriptor:\n", stderr); + fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size); + JP2K::PictureDescriptorDump(PDesc); + } + } + + if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag ) + { + WriterInfo Info = s_MyInfo; // fill in your favorite identifiers here + if ( Options.asset_id_flag ) + memcpy(Info.AssetUUID, Options.asset_id_value, UUIDlen); + else + Kumu::GenRandomUUID(Info.AssetUUID); + + if ( Options.use_smpte_labels ) + { + Info.LabelSetType = LS_MXF_SMPTE; + fprintf(stderr, "ATTENTION! Writing SMPTE Universal Labels\n"); + } + + // configure encryption + if( Options.key_flag ) + { + Kumu::GenRandomUUID(Info.ContextID); + Info.EncryptedEssence = true; + + if ( Options.key_id_flag ) + memcpy(Info.CryptographicKeyID, Options.key_id_value, UUIDlen); + else + RNG.FillRandom(Info.CryptographicKeyID, UUIDlen); + + Context = new AESEncContext; + result = Context->InitKey(Options.key_value); + + if ( ASDCP_SUCCESS(result) ) + result = Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE)); + + if ( ASDCP_SUCCESS(result) && Options.write_hmac ) + { + Info.UsesHMAC = true; + HMAC = new HMACContext; + result = HMAC->InitKey(Options.key_value, Info.LabelSetType); + } + } + + if ( ASDCP_SUCCESS(result) ) + result = Writer.OpenWrite(Options.out_file, Info, PDesc); + } + + if ( ASDCP_SUCCESS(result) ) + { + ui32_t duration = 0; + result = Parser.Reset(); + + while ( ASDCP_SUCCESS(result) && duration++ < Options.duration ) + { + if ( ! Options.do_repeat || duration == 1 ) + { + result = Parser.ReadFrame(FrameBuffer); + + if ( ASDCP_SUCCESS(result) ) + { + if ( Options.verbose_flag ) + FrameBuffer.Dump(stderr, Options.fb_dump_size); + + if ( Options.encrypt_header_flag ) + FrameBuffer.PlaintextOffset(0); + } + } + + if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag ) + { + result = Writer.WriteFrame(FrameBuffer, Context, HMAC); + + // The Writer class will forward the last block of ciphertext + // to the encryption context for use as the IV for the next + // frame. If you want to use non-sequitur IV values, un-comment + // the following line of code. + // if ( ASDCP_SUCCESS(result) && Options.key_flag ) + // Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE)); + } + } + + if ( result == RESULT_ENDOFFILE ) + result = RESULT_OK; + } + + if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag ) + result = Writer.Finalize(); + + return result; +} + +// Read one or more plaintext JPEG 2000 codestreams from a plaintext ASDCP file +// Read one or more plaintext JPEG 2000 codestreams from a ciphertext ASDCP file +// Read one or more ciphertext JPEG 2000 codestreams from a ciphertext ASDCP file +// +Result_t +read_JP2K_file(CommandOptions& Options) +{ + AESDecContext* Context = 0; + HMACContext* HMAC = 0; + JP2K::MXFReader Reader; + JP2K::FrameBuffer FrameBuffer(Options.fb_size); + ui32_t frame_count = 0; + + Result_t result = Reader.OpenRead(Options.filenames[0]); + + if ( ASDCP_SUCCESS(result) ) + { + JP2K::PictureDescriptor PDesc; + Reader.FillPictureDescriptor(PDesc); + + frame_count = PDesc.ContainerDuration; + + if ( Options.verbose_flag ) + { + fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size); + JP2K::PictureDescriptorDump(PDesc); + } + } + + if ( ASDCP_SUCCESS(result) && Options.key_flag ) + { + Context = new AESDecContext; + result = Context->InitKey(Options.key_value); + + if ( ASDCP_SUCCESS(result) && Options.read_hmac ) + { + WriterInfo Info; + Reader.FillWriterInfo(Info); + + if ( Info.UsesHMAC ) + { + HMAC = new HMACContext; + result = HMAC->InitKey(Options.key_value, Info.LabelSetType); + } + else + { + fputs("File does not contain HMAC values, ignoring -m option.\n", stderr); + } + } + } + + ui32_t last_frame = Options.start_frame + ( Options.duration ? Options.duration : frame_count); + if ( last_frame > frame_count ) + last_frame = frame_count; + + char name_format[64]; + snprintf(name_format, 64, "%%s%%0%du.j2c", Options.number_width); + + for ( ui32_t i = Options.start_frame; ASDCP_SUCCESS(result) && i < last_frame; i++ ) + { + result = Reader.ReadFrame(i, FrameBuffer, Context, HMAC); + + if ( ASDCP_SUCCESS(result) ) + { + Kumu::FileWriter OutFile; + char filename[256]; + ui32_t write_count; + snprintf(filename, 256, name_format, Options.file_root, i); + result = OutFile.OpenWrite(filename); + + if ( ASDCP_SUCCESS(result) ) + result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count); + + if ( Options.verbose_flag ) + FrameBuffer.Dump(stderr, Options.fb_dump_size); + } + } + + return result; +} + +//------------------------------------------------------------------------------------------ +// PCM essence + + +// Write one or more plaintext PCM audio streams to a plaintext ASDCP file +// Write one or more plaintext PCM audio streams to a ciphertext ASDCP file +// +Result_t +write_PCM_file(CommandOptions& Options) +{ + AESEncContext* Context = 0; + HMACContext* HMAC = 0; + PCMParserList Parser; + PCM::MXFWriter Writer; + PCM::FrameBuffer FrameBuffer; + PCM::AudioDescriptor ADesc; + Rational PictureRate = Options.PictureRate(); + byte_t IV_buf[CBC_BLOCK_SIZE]; + Kumu::FortunaRNG RNG; + + // set up essence parser + Result_t result = Parser.OpenRead(Options.file_count, Options.filenames, PictureRate); + + // set up MXF writer + if ( ASDCP_SUCCESS(result) ) + { + Parser.FillAudioDescriptor(ADesc); + + ADesc.EditRate = PictureRate; + FrameBuffer.Capacity(PCM::CalcFrameBufferSize(ADesc)); + ADesc.ChannelFormat = Options.channel_fmt; + + if ( Options.use_smpte_labels && ADesc.ChannelFormat == PCM::CF_NONE) + { + fprintf(stderr, "ATTENTION! Writing SMPTE audio without ChannelAssignment property (see option -l)\n"); + } + + if ( Options.verbose_flag ) + { + fprintf(stderr, "%.1fkHz PCM Audio, %s fps (%u spf)\n", + ADesc.AudioSamplingRate.Quotient() / 1000.0, + Options.szPictureRate(), + PCM::CalcSamplesPerFrame(ADesc)); + fputs("AudioDescriptor:\n", stderr); + PCM::AudioDescriptorDump(ADesc); + } + } + + if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag ) + { + WriterInfo Info = s_MyInfo; // fill in your favorite identifiers here + if ( Options.asset_id_flag ) + memcpy(Info.AssetUUID, Options.asset_id_value, UUIDlen); + else + Kumu::GenRandomUUID(Info.AssetUUID); + + if ( Options.use_smpte_labels ) + { + Info.LabelSetType = LS_MXF_SMPTE; + fprintf(stderr, "ATTENTION! Writing SMPTE Universal Labels\n"); + } + + // configure encryption + if( Options.key_flag ) + { + Kumu::GenRandomUUID(Info.ContextID); + Info.EncryptedEssence = true; + + if ( Options.key_id_flag ) + memcpy(Info.CryptographicKeyID, Options.key_id_value, UUIDlen); + else + RNG.FillRandom(Info.CryptographicKeyID, UUIDlen); + + Context = new AESEncContext; + result = Context->InitKey(Options.key_value); + + if ( ASDCP_SUCCESS(result) ) + result = Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE)); + + if ( ASDCP_SUCCESS(result) && Options.write_hmac ) + { + Info.UsesHMAC = true; + HMAC = new HMACContext; + result = HMAC->InitKey(Options.key_value, Info.LabelSetType); + } + } + + if ( ASDCP_SUCCESS(result) ) + result = Writer.OpenWrite(Options.out_file, Info, ADesc); + } + + if ( ASDCP_SUCCESS(result) ) + { + result = Parser.Reset(); + ui32_t duration = 0; + + while ( ASDCP_SUCCESS(result) && duration++ < Options.duration ) + { + result = Parser.ReadFrame(FrameBuffer); + + if ( ASDCP_SUCCESS(result) ) + { + if ( FrameBuffer.Size() != FrameBuffer.Capacity() ) + { + fprintf(stderr, "WARNING: Last frame read was short, PCM input is possibly not frame aligned.\n"); + fprintf(stderr, "Expecting %u bytes, got %u.\n", FrameBuffer.Capacity(), FrameBuffer.Size()); + result = RESULT_ENDOFFILE; + continue; + } + + if ( Options.verbose_flag ) + FrameBuffer.Dump(stderr, Options.fb_dump_size); + + if ( ! Options.no_write_flag ) + { + result = Writer.WriteFrame(FrameBuffer, Context, HMAC); + + // The Writer class will forward the last block of ciphertext + // to the encryption context for use as the IV for the next + // frame. If you want to use non-sequitur IV values, un-comment + // the following line of code. + // if ( ASDCP_SUCCESS(result) && Options.key_flag ) + // Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE)); + } + } + } + + if ( result == RESULT_ENDOFFILE ) + result = RESULT_OK; + } + + if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag ) + result = Writer.Finalize(); + + return result; +} + +// Read one or more plaintext PCM audio streams from a plaintext ASDCP file +// Read one or more plaintext PCM audio streams from a ciphertext ASDCP file +// Read one or more ciphertext PCM audio streams from a ciphertext ASDCP file +// +Result_t +read_PCM_file(CommandOptions& Options) +{ + AESDecContext* Context = 0; + HMACContext* HMAC = 0; + PCM::MXFReader Reader; + PCM::FrameBuffer FrameBuffer; + WavFileWriter OutWave; + PCM::AudioDescriptor ADesc; + ui32_t last_frame = 0; + + Result_t result = Reader.OpenRead(Options.filenames[0]); + + if ( ASDCP_SUCCESS(result) ) + { + Reader.FillAudioDescriptor(ADesc); + + if ( ADesc.EditRate != EditRate_23_98 + && ADesc.EditRate != EditRate_24 + && ADesc.EditRate != EditRate_25 + && ADesc.EditRate != EditRate_30 + && ADesc.EditRate != EditRate_48 + && ADesc.EditRate != EditRate_50 + && ADesc.EditRate != EditRate_60 ) + ADesc.EditRate = Options.PictureRate(); + + FrameBuffer.Capacity(PCM::CalcFrameBufferSize(ADesc)); + + if ( Options.verbose_flag ) + PCM::AudioDescriptorDump(ADesc); + } + + if ( ASDCP_SUCCESS(result) ) + { + last_frame = ADesc.ContainerDuration; + + if ( Options.duration > 0 && Options.duration < last_frame ) + last_frame = Options.duration; + + if ( Options.start_frame > 0 ) + { + if ( Options.start_frame > ADesc.ContainerDuration ) + { + fprintf(stderr, "Start value greater than file duration.\n"); + return RESULT_FAIL; + } + + last_frame = Kumu::xmin(Options.start_frame + last_frame, ADesc.ContainerDuration); + } + + ADesc.ContainerDuration = last_frame - Options.start_frame; + OutWave.OpenWrite(ADesc, Options.file_root, + ( Options.split_wav ? WavFileWriter::ST_STEREO : + ( Options.mono_wav ? WavFileWriter::ST_MONO : WavFileWriter::ST_NONE ) )); + } + + if ( ASDCP_SUCCESS(result) && Options.key_flag ) + { + Context = new AESDecContext; + result = Context->InitKey(Options.key_value); + + if ( ASDCP_SUCCESS(result) && Options.read_hmac ) + { + WriterInfo Info; + Reader.FillWriterInfo(Info); + + if ( Info.UsesHMAC ) + { + HMAC = new HMACContext; + result = HMAC->InitKey(Options.key_value, Info.LabelSetType); + } + else + { + fputs("File does not contain HMAC values, ignoring -m option.\n", stderr); + } + } + } + + for ( ui32_t i = Options.start_frame; ASDCP_SUCCESS(result) && i < last_frame; i++ ) + { + result = Reader.ReadFrame(i, FrameBuffer, Context, HMAC); + + if ( ASDCP_SUCCESS(result) ) + { + if ( Options.verbose_flag ) + FrameBuffer.Dump(stderr, Options.fb_dump_size); + + result = OutWave.WriteFrame(FrameBuffer); + } + } + + return result; +} + + +//------------------------------------------------------------------------------------------ +// TimedText essence + + +// Write one or more plaintext timed text streams to a plaintext ASDCP file +// Write one or more plaintext timed text streams to a ciphertext ASDCP file +// +Result_t +write_timed_text_file(CommandOptions& Options) +{ + AESEncContext* Context = 0; + HMACContext* HMAC = 0; + TimedText::DCSubtitleParser Parser; + TimedText::MXFWriter Writer; + TimedText::FrameBuffer FrameBuffer; + TimedText::TimedTextDescriptor TDesc; + byte_t IV_buf[CBC_BLOCK_SIZE]; + Kumu::FortunaRNG RNG; + + // set up essence parser + Result_t result = Parser.OpenRead(Options.filenames[0]); + + // set up MXF writer + if ( ASDCP_SUCCESS(result) ) + { + Parser.FillTimedTextDescriptor(TDesc); + FrameBuffer.Capacity(Options.fb_size); + + if ( Options.verbose_flag ) + { + fputs("D-Cinema Timed-Text Descriptor:\n", stderr); + TimedText::DescriptorDump(TDesc); + } + } + + if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag ) + { + WriterInfo Info = s_MyInfo; // fill in your favorite identifiers here + if ( Options.asset_id_flag ) + memcpy(Info.AssetUUID, Options.asset_id_value, UUIDlen); + else + Kumu::GenRandomUUID(Info.AssetUUID); + + if ( Options.use_smpte_labels ) + { + Info.LabelSetType = LS_MXF_SMPTE; + fprintf(stderr, "ATTENTION! Writing SMPTE Universal Labels\n"); + } + + // configure encryption + if( Options.key_flag ) + { + Kumu::GenRandomUUID(Info.ContextID); + Info.EncryptedEssence = true; + + if ( Options.key_id_flag ) + memcpy(Info.CryptographicKeyID, Options.key_id_value, UUIDlen); + else + RNG.FillRandom(Info.CryptographicKeyID, UUIDlen); + + Context = new AESEncContext; + result = Context->InitKey(Options.key_value); + + if ( ASDCP_SUCCESS(result) ) + result = Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE)); + + if ( ASDCP_SUCCESS(result) && Options.write_hmac ) + { + Info.UsesHMAC = true; + HMAC = new HMACContext; + result = HMAC->InitKey(Options.key_value, Info.LabelSetType); + } + } + + if ( ASDCP_SUCCESS(result) ) + result = Writer.OpenWrite(Options.out_file, Info, TDesc); + } + + if ( ASDCP_FAILURE(result) ) + return result; + + std::string XMLDoc; + TimedText::ResourceList_t::const_iterator ri; + + result = Parser.ReadTimedTextResource(XMLDoc); + + if ( ASDCP_SUCCESS(result) ) + result = Writer.WriteTimedTextResource(XMLDoc, Context, HMAC); + + for ( ri = TDesc.ResourceList.begin() ; ri != TDesc.ResourceList.end() && ASDCP_SUCCESS(result); ri++ ) + { + result = Parser.ReadAncillaryResource((*ri).ResourceID, FrameBuffer); + + if ( ASDCP_SUCCESS(result) ) + { + if ( Options.verbose_flag ) + FrameBuffer.Dump(stderr, Options.fb_dump_size); + + if ( ! Options.no_write_flag ) + { + result = Writer.WriteAncillaryResource(FrameBuffer, Context, HMAC); + + // The Writer class will forward the last block of ciphertext + // to the encryption context for use as the IV for the next + // frame. If you want to use non-sequitur IV values, un-comment + // the following line of code. + // if ( ASDCP_SUCCESS(result) && Options.key_flag ) + // Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE)); + } + } + + if ( result == RESULT_ENDOFFILE ) + result = RESULT_OK; + } + + if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag ) + result = Writer.Finalize(); + + return result; +} + + +// Read one or more timed text streams from a plaintext ASDCP file +// Read one or more timed text streams from a ciphertext ASDCP file +// Read one or more timed text streams from a ciphertext ASDCP file +// +Result_t +read_timed_text_file(CommandOptions& Options) +{ + AESDecContext* Context = 0; + HMACContext* HMAC = 0; + TimedText::MXFReader Reader; + TimedText::FrameBuffer FrameBuffer; + TimedText::TimedTextDescriptor TDesc; + + Result_t result = Reader.OpenRead(Options.filenames[0]); + + if ( ASDCP_SUCCESS(result) ) + { + Reader.FillTimedTextDescriptor(TDesc); + FrameBuffer.Capacity(Options.fb_size); + + if ( Options.verbose_flag ) + TimedText::DescriptorDump(TDesc); + } + + if ( ASDCP_SUCCESS(result) && Options.key_flag ) + { + Context = new AESDecContext; + result = Context->InitKey(Options.key_value); + + if ( ASDCP_SUCCESS(result) && Options.read_hmac ) + { + WriterInfo Info; + Reader.FillWriterInfo(Info); + + if ( Info.UsesHMAC ) + { + HMAC = new HMACContext; + result = HMAC->InitKey(Options.key_value, Info.LabelSetType); + } + else + { + fputs("File does not contain HMAC values, ignoring -m option.\n", stderr); + } + } + } + + if ( ASDCP_FAILURE(result) ) + return result; + + std::string XMLDoc; + std::string out_path = Kumu::PathDirname(Options.file_root); + ui32_t write_count; + char buf[64]; + TimedText::ResourceList_t::const_iterator ri; + + result = Reader.ReadTimedTextResource(XMLDoc, Context, HMAC); + + if ( ASDCP_SUCCESS(result) ) + { + Kumu::FileWriter Writer; + result = Writer.OpenWrite(Options.file_root); + + if ( ASDCP_SUCCESS(result) ) + result = Writer.Write(reinterpret_cast<const byte_t*>(XMLDoc.c_str()), XMLDoc.size(), &write_count); + } + + for ( ri = TDesc.ResourceList.begin() ; ri != TDesc.ResourceList.end() && ASDCP_SUCCESS(result); ri++ ) + { + result = Reader.ReadAncillaryResource(ri->ResourceID, FrameBuffer, Context, HMAC); + + if ( ASDCP_SUCCESS(result) ) + { + Kumu::FileWriter Writer; + result = Writer.OpenWrite(Kumu::PathJoin(out_path, Kumu::UUID(ri->ResourceID).EncodeHex(buf, 64)).c_str()); + + if ( ASDCP_SUCCESS(result) ) + { + if ( Options.verbose_flag ) + FrameBuffer.Dump(stderr, Options.fb_dump_size); + + result = Writer.Write(FrameBuffer.RoData(), FrameBuffer.Size(), &write_count); + } + } + } + + return result; +} + +//------------------------------------------------------------------------------------------ +// + +// +// These classes wrap the irregular names in the asdcplib API +// so that I can use a template to simplify the implementation +// of show_file_info() + +class MyVideoDescriptor : public MPEG2::VideoDescriptor +{ + public: + void FillDescriptor(MPEG2::MXFReader& Reader) { + Reader.FillVideoDescriptor(*this); + } + + void Dump(FILE* stream) { + MPEG2::VideoDescriptorDump(*this, stream); + } +}; + +class MyPictureDescriptor : public JP2K::PictureDescriptor +{ + public: + void FillDescriptor(JP2K::MXFReader& Reader) { + Reader.FillPictureDescriptor(*this); + } + + void Dump(FILE* stream) { + JP2K::PictureDescriptorDump(*this, stream); + } +}; + +class MyStereoPictureDescriptor : public JP2K::PictureDescriptor +{ + public: + void FillDescriptor(JP2K::MXFSReader& Reader) { + Reader.FillPictureDescriptor(*this); + } + + void Dump(FILE* stream) { + JP2K::PictureDescriptorDump(*this, stream); + } +}; + +class MyAudioDescriptor : public PCM::AudioDescriptor +{ + public: + void FillDescriptor(PCM::MXFReader& Reader) { + Reader.FillAudioDescriptor(*this); + } + + void Dump(FILE* stream) { + PCM::AudioDescriptorDump(*this, stream); + } +}; + +class MyTextDescriptor : public TimedText::TimedTextDescriptor +{ + public: + void FillDescriptor(TimedText::MXFReader& Reader) { + Reader.FillTimedTextDescriptor(*this); + } + + void Dump(FILE* stream) { + TimedText::DescriptorDump(*this, stream); + } +}; + +// MSVC didn't like the function template, so now it's a static class method +template<class ReaderT, class DescriptorT> +class FileInfoWrapper +{ +public: + static Result_t + file_info(CommandOptions& Options, const char* type_string, FILE* stream = 0) + { + assert(type_string); + if ( stream == 0 ) + stream = stdout; + + Result_t result = RESULT_OK; + + if ( Options.verbose_flag || Options.showheader_flag ) + { + ReaderT Reader; + result = Reader.OpenRead(Options.filenames[0]); + + if ( ASDCP_SUCCESS(result) ) + { + fprintf(stdout, "File essence type is %s.\n", type_string); + + if ( Options.showheader_flag ) + Reader.DumpHeaderMetadata(stream); + + WriterInfo WI; + Reader.FillWriterInfo(WI); + WriterInfoDump(WI, stream); + + DescriptorT Desc; + Desc.FillDescriptor(Reader); + Desc.Dump(stream); + + if ( Options.showindex_flag ) + Reader.DumpIndex(stream); + } + else if ( result == RESULT_FORMAT && Options.showheader_flag ) + { + Reader.DumpHeaderMetadata(stream); + } + } + + return result; + } +}; + +// Read header metadata from an ASDCP file +// +Result_t +show_file_info(CommandOptions& Options) +{ + EssenceType_t EssenceType; + Result_t result = ASDCP::EssenceType(Options.filenames[0], EssenceType); + + if ( ASDCP_FAILURE(result) ) + return result; + + if ( EssenceType == ESS_MPEG2_VES ) + { + result = FileInfoWrapper<ASDCP::MPEG2::MXFReader, MyVideoDescriptor>::file_info(Options, "MPEG2 video"); + } + else if ( EssenceType == ESS_PCM_24b_48k || EssenceType == ESS_PCM_24b_96k ) + { + result = FileInfoWrapper<ASDCP::PCM::MXFReader, MyAudioDescriptor>::file_info(Options, "PCM audio"); + + if ( ASDCP_SUCCESS(result) ) + { + const Dictionary* Dict = &DefaultCompositeDict(); + PCM::MXFReader Reader; + MXF::OPAtomHeader OPAtomHeader(Dict); + MXF::WaveAudioDescriptor *descriptor = 0; + + result = Reader.OpenRead(Options.filenames[0]); + + if ( ASDCP_SUCCESS(result) ) + result = Reader.OPAtomHeader().GetMDObjectByType(Dict->ul(MDD_WaveAudioDescriptor), reinterpret_cast<MXF::InterchangeObject**>(&descriptor)); + + if ( ASDCP_SUCCESS(result) ) + { + char buf[64]; + fprintf(stdout, " ChannelAssignment: %s\n", descriptor->ChannelAssignment.EncodeString(buf, 64)); + } + } + } + else if ( EssenceType == ESS_JPEG_2000 ) + { + if ( Options.stereo_image_flag ) + { + result = FileInfoWrapper<ASDCP::JP2K::MXFSReader, + MyStereoPictureDescriptor>::file_info(Options, "JPEG 2000 stereoscopic pictures"); + } + else + { + result = FileInfoWrapper<ASDCP::JP2K::MXFReader, + MyPictureDescriptor>::file_info(Options, "JPEG 2000 pictures"); + } + } + else if ( EssenceType == ESS_JPEG_2000_S ) + { + result = FileInfoWrapper<ASDCP::JP2K::MXFSReader, + MyStereoPictureDescriptor>::file_info(Options, "JPEG 2000 stereoscopic pictures"); + } + else if ( EssenceType == ESS_TIMED_TEXT ) + { + result = FileInfoWrapper<ASDCP::TimedText::MXFReader, MyTextDescriptor>::file_info(Options, "Timed Text"); + } + else + { + fprintf(stderr, "File is not AS-DCP: %s\n", Options.filenames[0]); + Kumu::FileReader Reader; + const Dictionary* Dict = &DefaultCompositeDict(); + MXF::OPAtomHeader TestHeader(Dict); + + result = Reader.OpenRead(Options.filenames[0]); + + if ( ASDCP_SUCCESS(result) ) + result = TestHeader.InitFromFile(Reader); // test UL and OP + + if ( ASDCP_SUCCESS(result) ) + { + TestHeader.Partition::Dump(stdout); + + if ( MXF::Identification* ID = TestHeader.GetIdentification() ) + ID->Dump(stdout); + else + fputs("File contains no Identification object.\n", stdout); + + if ( MXF::SourcePackage* SP = TestHeader.GetSourcePackage() ) + SP->Dump(stdout); + else + fputs("File contains no SourcePackage object.\n", stdout); + } + else + { + fputs("File is not MXF.\n", stdout); + } + } + + return result; +} + + +// +Result_t +digest_file(const char* filename) +{ + using namespace Kumu; + + ASDCP_TEST_NULL_STR(filename); + FileReader Reader; + SHA_CTX Ctx; + SHA1_Init(&Ctx); + ByteString Buf(8192); + + Result_t result = Reader.OpenRead(filename); + + while ( ASDCP_SUCCESS(result) ) + { + ui32_t read_count = 0; + result = Reader.Read(Buf.Data(), Buf.Capacity(), &read_count); + + if ( result == RESULT_ENDOFFILE ) + { + result = RESULT_OK; + break; + } + + if ( ASDCP_SUCCESS(result) ) + SHA1_Update(&Ctx, Buf.Data(), read_count); + } + + if ( ASDCP_SUCCESS(result) ) + { + const ui32_t sha_len = 20; + byte_t bin_buf[sha_len]; + char sha_buf[64]; + SHA1_Final(bin_buf, &Ctx); + + fprintf(stdout, "%s %s\n", base64encode(bin_buf, sha_len, sha_buf, 64), filename); + } + + return result; +} + +// +int +main(int argc, const char** argv) +{ + Result_t result = RESULT_OK; + char str_buf[64]; + CommandOptions Options(argc, argv); + + if ( Options.version_flag ) + banner(); + + if ( Options.help_flag ) + usage(); + + if ( Options.version_flag || Options.help_flag ) + return 0; + + if ( Options.error_flag ) + { + fprintf(stderr, "There was a problem. Type %s -h for help.\n", PROGRAM_NAME); + return 3; + } + + if ( Options.mode == MMT_INFO ) + { + result = show_file_info(Options); + + for ( int i = 1; ASDCP_SUCCESS(result) && i < Options.file_count; ++i ) + { + Options.filenames[0] = Options.filenames[i]; // oh-so hackish + result = show_file_info(Options); + } + } + else if ( Options.mode == MMT_GOP_START ) + { + result = gop_start_test(Options); + } + else if ( Options.mode == MMT_GEN_KEY ) + { + Kumu::FortunaRNG RNG; + byte_t bin_buf[KeyLen]; + + RNG.FillRandom(bin_buf, KeyLen); + printf("%s\n", Kumu::bin2hex(bin_buf, KeyLen, str_buf, 64)); + } + else if ( Options.mode == MMT_GEN_ID ) + { + UUID TmpID; + Kumu::GenRandomValue(TmpID); + printf("%s\n", TmpID.EncodeHex(str_buf, 64)); + } + else if ( Options.mode == MMT_DIGEST ) + { + for ( ui32_t i = 0; i < Options.file_count && ASDCP_SUCCESS(result); i++ ) + result = digest_file(Options.filenames[i]); + } + else if ( Options.mode == MMT_UL_LIST ) + { + if ( Options.use_smpte_labels ) + DefaultSMPTEDict().Dump(stdout); + else + DefaultInteropDict().Dump(stdout); + } + else if ( Options.mode == MMT_EXTRACT ) + { + EssenceType_t EssenceType; + result = ASDCP::EssenceType(Options.filenames[0], EssenceType); + + if ( ASDCP_SUCCESS(result) ) + { + switch ( EssenceType ) + { + case ESS_MPEG2_VES: + result = read_MPEG2_file(Options); + break; + + case ESS_JPEG_2000: + if ( Options.stereo_image_flag ) + result = read_JP2K_S_file(Options); + else + result = read_JP2K_file(Options); + break; + + case ESS_JPEG_2000_S: + result = read_JP2K_S_file(Options); + break; + + case ESS_PCM_24b_48k: + case ESS_PCM_24b_96k: + result = read_PCM_file(Options); + break; + + case ESS_TIMED_TEXT: + result = read_timed_text_file(Options); + break; + + default: + fprintf(stderr, "%s: Unknown file type, not ASDCP essence.\n", Options.filenames[0]); + return 5; + } + } + } + else if ( Options.mode == MMT_CREATE ) + { + if ( Options.do_repeat && ! Options.duration_flag ) + { + fputs("Option -R requires -d <duration>\n", stderr); + return RESULT_FAIL; + } + + EssenceType_t EssenceType; + result = ASDCP::RawEssenceType(Options.filenames[0], EssenceType); + + if ( ASDCP_SUCCESS(result) ) + { + switch ( EssenceType ) + { + case ESS_MPEG2_VES: + result = write_MPEG2_file(Options); + break; + + case ESS_JPEG_2000: + if ( Options.stereo_image_flag ) + result = write_JP2K_S_file(Options); + + else + result = write_JP2K_file(Options); + + break; + + case ESS_PCM_24b_48k: + case ESS_PCM_24b_96k: + result = write_PCM_file(Options); + break; + + case ESS_TIMED_TEXT: + result = write_timed_text_file(Options); + break; + + default: + fprintf(stderr, "%s: Unknown file type, not ASDCP-compatible essence.\n", + Options.filenames[0]); + return 5; + } + } + } + else + { + fprintf(stderr, "Unhandled mode: %d.\n", Options.mode); + return 6; + } + + if ( ASDCP_FAILURE(result) ) + { + fputs("Program stopped on error.\n", stderr); + + if ( result == RESULT_SFORMAT ) + { + fputs("Use option '-3' to force stereoscopic mode.\n", stderr); + } + else if ( result != RESULT_FAIL ) + { + fputs(result, stderr); + fputc('\n', stderr); + } + + return 1; + } + + return 0; +} + + +// +// end asdcp-test.cpp +// diff --git a/asdcplib/src/asdcp-unwrap.cpp b/asdcplib/src/asdcp-unwrap.cpp new file mode 100755 index 0000000..b7b7fef --- /dev/null +++ b/asdcplib/src/asdcp-unwrap.cpp @@ -0,0 +1,896 @@ +/* +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 asdcp-unwrap.cpp + \version $Id: asdcp-unwrap.cpp,v 1.1 2012/02/03 19:49:57 jhurst Exp $ + \brief AS-DCP file manipulation utility + + This program extracts picture, sound and text essence from AS-DCP files. + + For more information about asdcplib, please refer to the header file AS_DCP.h +*/ + +#include <KM_fileio.h> +#include <WavFileWriter.h> + +using namespace ASDCP; + +const ui32_t FRAME_BUFFER_SIZE = 4 * Kumu::Megabyte; + +//------------------------------------------------------------------------------------------ +// +// command line option parser class + +static const char* PROGRAM_NAME = "asdcp-unwrap"; // program name for messages + +// Increment the iterator, test for an additional non-option command line argument. +// Causes the caller to return if there are no remaining arguments or if the next +// argument begins with '-'. +#define TEST_EXTRA_ARG(i,c) \ + if ( ++i >= argc || argv[(i)][0] == '-' ) { \ + fprintf(stderr, "Argument not found for option -%c.\n", (c)); \ + return; \ + } + +// +void +banner(FILE* stream = stdout) +{ + fprintf(stream, "\n\ +%s (asdcplib %s)\n\n\ +Copyright (c) 2003-2012 John Hurst\n\n\ +asdcplib may be copied only under the terms of the license found at\n\ +the top of every file in the asdcplib distribution kit.\n\n\ +Specify the -h (help) option for further information about %s\n\n", + PROGRAM_NAME, ASDCP::Version(), PROGRAM_NAME); +} + +// +void +usage(FILE* stream = stdout) +{ + fprintf(stream, "\ +USAGE: %s [-h|-help] [-V]\n\ +\n\ + %s -G [-v] <input-file>\n\ +\n\ + %s [-1|-2] [-3] [-b <buffer-size>] [-d <duration>]\n\ + [-f <starting-frame>] [-m] [-p <frame-rate>] [-R] [-s <size>] [-v] [-W]\n\ + [-w] <input-file> [<file-prefix>]\n\n", + PROGRAM_NAME, PROGRAM_NAME, PROGRAM_NAME); + + fprintf(stream, "\ +Options:\n\ + -1 - Split Wave essence to mono WAV files during extract.\n\ + Default is multichannel WAV\n\ + -2 - Split Wave essence to stereo WAV files during extract.\n\ + Default is multichannel WAV\n\ + -3 - Force stereoscopic interpretation of a JP2K file.\n\ + -b <buffer-size> - Specify size in bytes of picture frame buffer.\n\ + Defaults to 4,194,304 (4MB)\n\ + -d <duration> - Number of frames to process, default all\n\ + -f <start-frame> - Starting frame number, default 0\n\ + -G - Perform GOP start lookup test on MXF+Interop MPEG file\n\ + -h | -help - Show help\n\ + -k <key-string> - Use key for ciphertext operations\n\ + -m - verify HMAC values when reading\n\ + -p <rate> - fps of picture when wrapping PCM or JP2K:\n\ + Use one of [23|24|25|30|48|50|60], 24 is default\n\ + -s <size> - Number of bytes to dump to output when -v is given\n\ + -V - Show version information\n\ + -v - Verbose, prints informative messages to stderr\n\ + -W - Read input file only, do not write destination file\n\ + -w <width> - Width of numeric element in a series of frame file names\n\ + (default 6).\n\ + -z - Fail if j2c inputs have unequal parameters (default)\n\ + -Z - Ignore unequal parameters in j2c inputs\n\ +\n\ + NOTES: o There is no option grouping, all options must be distinct arguments.\n\ + o All option arguments must be separated from the option by whitespace.\n\ + o An argument of \"23\" to the -p option will be interpreted\n\ + as 24000/1001 fps.\n\n"); +} + +// +enum MajorMode_t +{ + MMT_NONE, + MMT_EXTRACT, + MMT_GOP_START, +}; + +// +class CommandOptions +{ + CommandOptions(); + +public: + MajorMode_t mode; + bool error_flag; // true if the given options are in error or not complete + bool key_flag; // true if an encryption key was given + bool read_hmac; // true if HMAC values are to be validated + bool split_wav; // true if PCM is to be extracted to stereo WAV files + bool mono_wav; // true if PCM is to be extracted to mono WAV files + bool verbose_flag; // true if the verbose option was selected + ui32_t fb_dump_size; // number of bytes of frame buffer to dump + bool no_write_flag; // true if no output files are to be written + bool version_flag; // true if the version display option was selected + bool help_flag; // true if the help display option was selected + bool stereo_image_flag; // if true, expect stereoscopic JP2K input (left eye first) + ui32_t number_width; // number of digits in a serialized filename (for JPEG extract) + ui32_t start_frame; // frame number to begin processing + ui32_t duration; // number of frames to be processed + bool duration_flag; // true if duration argument given + bool j2c_pedantic; // passed to JP2K::SequenceParser::OpenRead + ui32_t picture_rate; // fps of picture when wrapping PCM + ui32_t fb_size; // size of picture frame buffer + const char* file_prefix; // filename pre for files written by the extract mode + byte_t key_value[KeyLen]; // value of given encryption key (when key_flag is true) + byte_t key_id_value[UUIDlen];// value of given key ID (when key_id_flag is true) + PCM::ChannelFormat_t channel_fmt; // audio channel arrangement + const char* input_filename; + std::string prefix_buffer; + + // + Rational PictureRate() + { + if ( picture_rate == 23 ) return EditRate_23_98; + if ( picture_rate == 24 ) return EditRate_24; + if ( picture_rate == 25 ) return EditRate_25; + if ( picture_rate == 30 ) return EditRate_30; + if ( picture_rate == 48 ) return EditRate_48; + if ( picture_rate == 50 ) return EditRate_50; + if ( picture_rate == 60 ) return EditRate_60; + if ( picture_rate == 96 ) return EditRate_96; + if ( picture_rate == 100 ) return EditRate_100; + if ( picture_rate == 120 ) return EditRate_120; + return EditRate_24; + } + + // + CommandOptions(int argc, const char** argv) : + mode(MMT_EXTRACT), error_flag(true), key_flag(false), read_hmac(false), split_wav(false), + mono_wav(false), verbose_flag(false), fb_dump_size(0), no_write_flag(false), + version_flag(false), help_flag(false), stereo_image_flag(false), number_width(6), + start_frame(0), duration(0xffffffff), duration_flag(false), j2c_pedantic(true), + picture_rate(24), fb_size(FRAME_BUFFER_SIZE), file_prefix(0), + channel_fmt(PCM::CF_NONE), input_filename(0) + { + memset(key_value, 0, KeyLen); + memset(key_id_value, 0, UUIDlen); + + for ( int i = 1; i < argc; ++i ) + { + + if ( (strcmp( argv[i], "-help") == 0) ) + { + help_flag = true; + continue; + } + + if ( argv[i][0] == '-' + && ( isalpha(argv[i][1]) || isdigit(argv[i][1]) ) + && argv[i][2] == 0 ) + { + switch ( argv[i][1] ) + { + case '1': mono_wav = true; break; + case '2': split_wav = true; break; + case '3': stereo_image_flag = true; break; + + case 'b': + TEST_EXTRA_ARG(i, 'b'); + fb_size = abs(atoi(argv[i])); + + if ( verbose_flag ) + fprintf(stderr, "Frame Buffer size: %u bytes.\n", fb_size); + + break; + + case 'd': + TEST_EXTRA_ARG(i, 'd'); + duration_flag = true; + duration = abs(atoi(argv[i])); + break; + + case 'f': + TEST_EXTRA_ARG(i, 'f'); + start_frame = abs(atoi(argv[i])); + break; + + case 'G': mode = MMT_GOP_START; break; + case 'h': help_flag = true; break; + + case 'm': read_hmac = true; break; + + case 'p': + TEST_EXTRA_ARG(i, 'p'); + picture_rate = abs(atoi(argv[i])); + break; + + case 's': + TEST_EXTRA_ARG(i, 's'); + fb_dump_size = abs(atoi(argv[i])); + break; + + case 'V': version_flag = true; break; + case 'v': verbose_flag = true; break; + case 'W': no_write_flag = true; break; + + case 'w': + TEST_EXTRA_ARG(i, 'w'); + number_width = abs(atoi(argv[i])); + break; + + case 'Z': j2c_pedantic = false; break; + case 'z': j2c_pedantic = true; break; + + default: + fprintf(stderr, "Unrecognized option: %s\n", argv[i]); + return; + } + } + else + { + if ( argv[i][0] != '-' ) + { + if ( input_filename == 0 ) + { + input_filename = argv[i]; + } + else if ( file_prefix == 0 ) + { + file_prefix = argv[i]; + } + } + else + { + fprintf(stderr, "Unrecognized argument: %s\n", argv[i]); + return; + } + } + } + + if ( help_flag || version_flag ) + return; + + if ( ( mode == MMT_EXTRACT || mode == MMT_GOP_START ) && input_filename == 0 ) + { + fputs("Option requires at least one filename argument.\n", stderr); + return; + } + + if ( mode == MMT_EXTRACT && file_prefix == 0 ) + { + prefix_buffer = Kumu::PathSetExtension(input_filename, "") + "_"; + file_prefix = prefix_buffer.c_str(); + } + + error_flag = false; + } +}; + +//------------------------------------------------------------------------------------------ +// MPEG2 essence + +// Read a plaintext MPEG2 Video Elementary Stream from a plaintext ASDCP file +// Read a plaintext MPEG2 Video Elementary Stream from a ciphertext ASDCP file +// Read a ciphertext MPEG2 Video Elementary Stream from a ciphertext ASDCP file +// +Result_t +read_MPEG2_file(CommandOptions& Options) +{ + AESDecContext* Context = 0; + HMACContext* HMAC = 0; + MPEG2::MXFReader Reader; + MPEG2::FrameBuffer FrameBuffer(Options.fb_size); + Kumu::FileWriter OutFile; + ui32_t frame_count = 0; + + Result_t result = Reader.OpenRead(Options.input_filename); + + if ( ASDCP_SUCCESS(result) ) + { + MPEG2::VideoDescriptor VDesc; + Reader.FillVideoDescriptor(VDesc); + frame_count = VDesc.ContainerDuration; + + if ( Options.verbose_flag ) + { + fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size); + MPEG2::VideoDescriptorDump(VDesc); + } + } + + if ( ASDCP_SUCCESS(result) ) + { + char filename[256]; + snprintf(filename, 256, "%s.ves", Options.file_prefix); + result = OutFile.OpenWrite(filename); + } + + if ( ASDCP_SUCCESS(result) && Options.key_flag ) + { + Context = new AESDecContext; + result = Context->InitKey(Options.key_value); + + if ( ASDCP_SUCCESS(result) && Options.read_hmac ) + { + WriterInfo Info; + Reader.FillWriterInfo(Info); + + if ( Info.UsesHMAC ) + { + HMAC = new HMACContext; + result = HMAC->InitKey(Options.key_value, Info.LabelSetType); + } + else + { + fputs("File does not contain HMAC values, ignoring -m option.\n", stderr); + } + } + } + + ui32_t last_frame = Options.start_frame + ( Options.duration ? Options.duration : frame_count); + if ( last_frame > frame_count ) + last_frame = frame_count; + + for ( ui32_t i = Options.start_frame; ASDCP_SUCCESS(result) && i < last_frame; i++ ) + { + result = Reader.ReadFrame(i, FrameBuffer, Context, HMAC); + + if ( ASDCP_SUCCESS(result) ) + { + if ( Options.verbose_flag ) + FrameBuffer.Dump(stderr, Options.fb_dump_size); + + ui32_t write_count = 0; + result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count); + } + } + + return result; +} + + +// +Result_t +gop_start_test(CommandOptions& Options) +{ + using namespace ASDCP::MPEG2; + + MXFReader Reader; + MPEG2::FrameBuffer FrameBuffer(Options.fb_size); + ui32_t frame_count = 0; + + Result_t result = Reader.OpenRead(Options.input_filename); + + if ( ASDCP_SUCCESS(result) ) + { + MPEG2::VideoDescriptor VDesc; + Reader.FillVideoDescriptor(VDesc); + frame_count = VDesc.ContainerDuration; + + if ( Options.verbose_flag ) + { + fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size); + MPEG2::VideoDescriptorDump(VDesc); + } + } + + ui32_t last_frame = Options.start_frame + ( Options.duration ? Options.duration : frame_count); + if ( last_frame > frame_count ) + last_frame = frame_count; + + for ( ui32_t i = Options.start_frame; ASDCP_SUCCESS(result) && i < last_frame; i++ ) + { + result = Reader.ReadFrameGOPStart(i, FrameBuffer); + + if ( ASDCP_SUCCESS(result) ) + { + if ( Options.verbose_flag ) + FrameBuffer.Dump(stderr, Options.fb_dump_size); + + if ( FrameBuffer.FrameType() != FRAME_I ) + fprintf(stderr, "Expecting an I frame, got %c\n", FrameTypeChar(FrameBuffer.FrameType())); + + fprintf(stderr, "Requested frame %u, got %u\n", i, FrameBuffer.FrameNumber()); + } + } + + return result; +} + +//------------------------------------------------------------------------------------------ +// JPEG 2000 essence + + +// Read one or more plaintext JPEG 2000 stereoscopic codestream pairs from a plaintext ASDCP file +// Read one or more plaintext JPEG 2000 stereoscopic codestream pairs from a ciphertext ASDCP file +// Read one or more ciphertext JPEG 2000 stereoscopic codestream pairs from a ciphertext ASDCP file +Result_t +read_JP2K_S_file(CommandOptions& Options) +{ + AESDecContext* Context = 0; + HMACContext* HMAC = 0; + JP2K::MXFSReader Reader; + JP2K::FrameBuffer FrameBuffer(Options.fb_size); + ui32_t frame_count = 0; + + Result_t result = Reader.OpenRead(Options.input_filename); + + if ( ASDCP_SUCCESS(result) ) + { + JP2K::PictureDescriptor PDesc; + Reader.FillPictureDescriptor(PDesc); + + frame_count = PDesc.ContainerDuration; + + if ( Options.verbose_flag ) + { + fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size); + JP2K::PictureDescriptorDump(PDesc); + } + } + + if ( ASDCP_SUCCESS(result) && Options.key_flag ) + { + Context = new AESDecContext; + result = Context->InitKey(Options.key_value); + + if ( ASDCP_SUCCESS(result) && Options.read_hmac ) + { + WriterInfo Info; + Reader.FillWriterInfo(Info); + + if ( Info.UsesHMAC ) + { + HMAC = new HMACContext; + result = HMAC->InitKey(Options.key_value, Info.LabelSetType); + } + else + { + fputs("File does not contain HMAC values, ignoring -m option.\n", stderr); + } + } + } + + const int filename_max = 1024; + char filename[filename_max]; + ui32_t last_frame = Options.start_frame + ( Options.duration ? Options.duration : frame_count); + if ( last_frame > frame_count ) + last_frame = frame_count; + + char left_format[64]; char right_format[64]; + snprintf(left_format, 64, "%%s%%0%duL.j2c", Options.number_width); + snprintf(right_format, 64, "%%s%%0%duR.j2c", Options.number_width); + + for ( ui32_t i = Options.start_frame; ASDCP_SUCCESS(result) && i < last_frame; i++ ) + { + result = Reader.ReadFrame(i, JP2K::SP_LEFT, FrameBuffer, Context, HMAC); + + if ( ASDCP_SUCCESS(result) ) + { + Kumu::FileWriter OutFile; + ui32_t write_count; + snprintf(filename, filename_max, left_format, Options.file_prefix, i); + result = OutFile.OpenWrite(filename); + + if ( ASDCP_SUCCESS(result) ) + result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count); + + if ( Options.verbose_flag ) + FrameBuffer.Dump(stderr, Options.fb_dump_size); + } + + if ( ASDCP_SUCCESS(result) ) + result = Reader.ReadFrame(i, JP2K::SP_RIGHT, FrameBuffer, Context, HMAC); + + if ( ASDCP_SUCCESS(result) ) + { + Kumu::FileWriter OutFile; + ui32_t write_count; + snprintf(filename, filename_max, right_format, Options.file_prefix, i); + result = OutFile.OpenWrite(filename); + + if ( ASDCP_SUCCESS(result) ) + result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count); + } + } + + return result; +} + +// Read one or more plaintext JPEG 2000 codestreams from a plaintext ASDCP file +// Read one or more plaintext JPEG 2000 codestreams from a ciphertext ASDCP file +// Read one or more ciphertext JPEG 2000 codestreams from a ciphertext ASDCP file +// +Result_t +read_JP2K_file(CommandOptions& Options) +{ + AESDecContext* Context = 0; + HMACContext* HMAC = 0; + JP2K::MXFReader Reader; + JP2K::FrameBuffer FrameBuffer(Options.fb_size); + ui32_t frame_count = 0; + + Result_t result = Reader.OpenRead(Options.input_filename); + + if ( ASDCP_SUCCESS(result) ) + { + JP2K::PictureDescriptor PDesc; + Reader.FillPictureDescriptor(PDesc); + + frame_count = PDesc.ContainerDuration; + + if ( Options.verbose_flag ) + { + fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size); + JP2K::PictureDescriptorDump(PDesc); + } + } + + if ( ASDCP_SUCCESS(result) && Options.key_flag ) + { + Context = new AESDecContext; + result = Context->InitKey(Options.key_value); + + if ( ASDCP_SUCCESS(result) && Options.read_hmac ) + { + WriterInfo Info; + Reader.FillWriterInfo(Info); + + if ( Info.UsesHMAC ) + { + HMAC = new HMACContext; + result = HMAC->InitKey(Options.key_value, Info.LabelSetType); + } + else + { + fputs("File does not contain HMAC values, ignoring -m option.\n", stderr); + } + } + } + + ui32_t last_frame = Options.start_frame + ( Options.duration ? Options.duration : frame_count); + if ( last_frame > frame_count ) + last_frame = frame_count; + + char name_format[64]; + snprintf(name_format, 64, "%%s%%0%du.j2c", Options.number_width); + + for ( ui32_t i = Options.start_frame; ASDCP_SUCCESS(result) && i < last_frame; i++ ) + { + result = Reader.ReadFrame(i, FrameBuffer, Context, HMAC); + + if ( ASDCP_SUCCESS(result) ) + { + Kumu::FileWriter OutFile; + char filename[256]; + ui32_t write_count; + snprintf(filename, 256, name_format, Options.file_prefix, i); + result = OutFile.OpenWrite(filename); + + if ( ASDCP_SUCCESS(result) ) + result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count); + + if ( Options.verbose_flag ) + FrameBuffer.Dump(stderr, Options.fb_dump_size); + } + } + + return result; +} + +//------------------------------------------------------------------------------------------ +// PCM essence + +// Read one or more plaintext PCM audio streams from a plaintext ASDCP file +// Read one or more plaintext PCM audio streams from a ciphertext ASDCP file +// Read one or more ciphertext PCM audio streams from a ciphertext ASDCP file +// +Result_t +read_PCM_file(CommandOptions& Options) +{ + AESDecContext* Context = 0; + HMACContext* HMAC = 0; + PCM::MXFReader Reader; + PCM::FrameBuffer FrameBuffer; + WavFileWriter OutWave; + PCM::AudioDescriptor ADesc; + ui32_t last_frame = 0; + + Result_t result = Reader.OpenRead(Options.input_filename); + + if ( ASDCP_SUCCESS(result) ) + { + Reader.FillAudioDescriptor(ADesc); + + if ( ADesc.EditRate != EditRate_23_98 + && ADesc.EditRate != EditRate_24 + && ADesc.EditRate != EditRate_25 + && ADesc.EditRate != EditRate_30 + && ADesc.EditRate != EditRate_48 + && ADesc.EditRate != EditRate_50 + && ADesc.EditRate != EditRate_60 ) + ADesc.EditRate = Options.PictureRate(); + + FrameBuffer.Capacity(PCM::CalcFrameBufferSize(ADesc)); + + if ( Options.verbose_flag ) + PCM::AudioDescriptorDump(ADesc); + } + + if ( ASDCP_SUCCESS(result) ) + { + last_frame = ADesc.ContainerDuration; + + if ( Options.duration > 0 && Options.duration < last_frame ) + last_frame = Options.duration; + + if ( Options.start_frame > 0 ) + { + if ( Options.start_frame > ADesc.ContainerDuration ) + { + fprintf(stderr, "Start value greater than file duration.\n"); + return RESULT_FAIL; + } + + last_frame = Kumu::xmin(Options.start_frame + last_frame, ADesc.ContainerDuration); + } + + ADesc.ContainerDuration = last_frame - Options.start_frame; + OutWave.OpenWrite(ADesc, Options.file_prefix, + ( Options.split_wav ? WavFileWriter::ST_STEREO : + ( Options.mono_wav ? WavFileWriter::ST_MONO : WavFileWriter::ST_NONE ) )); + } + + if ( ASDCP_SUCCESS(result) && Options.key_flag ) + { + Context = new AESDecContext; + result = Context->InitKey(Options.key_value); + + if ( ASDCP_SUCCESS(result) && Options.read_hmac ) + { + WriterInfo Info; + Reader.FillWriterInfo(Info); + + if ( Info.UsesHMAC ) + { + HMAC = new HMACContext; + result = HMAC->InitKey(Options.key_value, Info.LabelSetType); + } + else + { + fputs("File does not contain HMAC values, ignoring -m option.\n", stderr); + } + } + } + + for ( ui32_t i = Options.start_frame; ASDCP_SUCCESS(result) && i < last_frame; i++ ) + { + result = Reader.ReadFrame(i, FrameBuffer, Context, HMAC); + + if ( ASDCP_SUCCESS(result) ) + { + if ( Options.verbose_flag ) + FrameBuffer.Dump(stderr, Options.fb_dump_size); + + result = OutWave.WriteFrame(FrameBuffer); + } + } + + return result; +} + + +//------------------------------------------------------------------------------------------ +// TimedText essence + +// Read one or more timed text streams from a plaintext ASDCP file +// Read one or more timed text streams from a ciphertext ASDCP file +// Read one or more timed text streams from a ciphertext ASDCP file +// +Result_t +read_timed_text_file(CommandOptions& Options) +{ + AESDecContext* Context = 0; + HMACContext* HMAC = 0; + TimedText::MXFReader Reader; + TimedText::FrameBuffer FrameBuffer; + TimedText::TimedTextDescriptor TDesc; + + Result_t result = Reader.OpenRead(Options.input_filename); + + if ( ASDCP_SUCCESS(result) ) + { + Reader.FillTimedTextDescriptor(TDesc); + FrameBuffer.Capacity(Options.fb_size); + + if ( Options.verbose_flag ) + TimedText::DescriptorDump(TDesc); + } + + if ( ASDCP_SUCCESS(result) && Options.key_flag ) + { + Context = new AESDecContext; + result = Context->InitKey(Options.key_value); + + if ( ASDCP_SUCCESS(result) && Options.read_hmac ) + { + WriterInfo Info; + Reader.FillWriterInfo(Info); + + if ( Info.UsesHMAC ) + { + HMAC = new HMACContext; + result = HMAC->InitKey(Options.key_value, Info.LabelSetType); + } + else + { + fputs("File does not contain HMAC values, ignoring -m option.\n", stderr); + } + } + } + + if ( ASDCP_FAILURE(result) ) + return result; + + std::string XMLDoc; + std::string out_path = Kumu::PathDirname(Options.file_prefix); + ui32_t write_count; + char buf[64]; + TimedText::ResourceList_t::const_iterator ri; + + result = Reader.ReadTimedTextResource(XMLDoc, Context, HMAC); + + if ( ASDCP_SUCCESS(result) ) + { + Kumu::FileWriter Writer; + result = Writer.OpenWrite(Options.file_prefix); + + if ( ASDCP_SUCCESS(result) ) + result = Writer.Write(reinterpret_cast<const byte_t*>(XMLDoc.c_str()), XMLDoc.size(), &write_count); + } + + for ( ri = TDesc.ResourceList.begin() ; ri != TDesc.ResourceList.end() && ASDCP_SUCCESS(result); ri++ ) + { + result = Reader.ReadAncillaryResource(ri->ResourceID, FrameBuffer, Context, HMAC); + + if ( ASDCP_SUCCESS(result) ) + { + Kumu::FileWriter Writer; + result = Writer.OpenWrite(Kumu::PathJoin(out_path, Kumu::UUID(ri->ResourceID).EncodeHex(buf, 64)).c_str()); + + if ( ASDCP_SUCCESS(result) ) + { + if ( Options.verbose_flag ) + FrameBuffer.Dump(stderr, Options.fb_dump_size); + + result = Writer.Write(FrameBuffer.RoData(), FrameBuffer.Size(), &write_count); + } + } + } + + return result; +} + +// +int +main(int argc, const char** argv) +{ + Result_t result = RESULT_OK; + char str_buf[64]; + CommandOptions Options(argc, argv); + + if ( Options.version_flag ) + banner(); + + if ( Options.help_flag ) + usage(); + + if ( Options.version_flag || Options.help_flag ) + return 0; + + if ( Options.error_flag ) + { + fprintf(stderr, "There was a problem. Type %s -h for help.\n", PROGRAM_NAME); + return 3; + } + + if ( Options.mode == MMT_GOP_START ) + { + result = gop_start_test(Options); + } + else if ( Options.mode == MMT_EXTRACT ) + { + EssenceType_t EssenceType; + result = ASDCP::EssenceType(Options.input_filename, EssenceType); + + if ( ASDCP_SUCCESS(result) ) + { + switch ( EssenceType ) + { + case ESS_MPEG2_VES: + result = read_MPEG2_file(Options); + break; + + case ESS_JPEG_2000: + if ( Options.stereo_image_flag ) + result = read_JP2K_S_file(Options); + else + result = read_JP2K_file(Options); + break; + + case ESS_JPEG_2000_S: + result = read_JP2K_S_file(Options); + break; + + case ESS_PCM_24b_48k: + case ESS_PCM_24b_96k: + result = read_PCM_file(Options); + break; + + case ESS_TIMED_TEXT: + result = read_timed_text_file(Options); + break; + + default: + fprintf(stderr, "%s: Unknown file type, not ASDCP essence.\n", Options.input_filename); + return 5; + } + } + } + else + { + fprintf(stderr, "Unhandled mode: %d.\n", Options.mode); + return 6; + } + + if ( ASDCP_FAILURE(result) ) + { + fputs("Program stopped on error.\n", stderr); + + if ( result == RESULT_SFORMAT ) + { + fputs("Use option '-3' to force stereoscopic mode.\n", stderr); + } + else if ( result != RESULT_FAIL ) + { + fputs(result, stderr); + fputc('\n', stderr); + } + + return 1; + } + + return 0; +} + + +// +// end asdcp-unwrap.cpp +// diff --git a/asdcplib/src/asdcp-util.cpp b/asdcplib/src/asdcp-util.cpp new file mode 100755 index 0000000..0d9ed4c --- /dev/null +++ b/asdcplib/src/asdcp-util.cpp @@ -0,0 +1,294 @@ +/* +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 asdcp-util.cpp + \version $Id: asdcp-util.cpp,v 1.1 2012/02/03 19:49:57 jhurst Exp $ + \brief Utility functions for working with AS-DCP files + + This program provides utility features commonly useful in DCP workflows. + + For more information about asdcplib, please refer to the header file AS_DCP.h +*/ + +#include <KM_fileio.h> +#include <KM_prng.h> +#include <AS_DCP.h> +#include <openssl/sha.h> + +using namespace Kumu; + + +//------------------------------------------------------------------------------------------ +// +// command line option parser class + +static const char* PROGRAM_NAME = "asdcp-util"; // program name for messages + +// Increment the iterator, test for an additional non-option command line argument. +// Causes the caller to return if there are no remaining arguments or if the next +// argument begins with '-'. +#define TEST_EXTRA_ARG(i,c) \ + if ( ++i >= argc || argv[(i)][0] == '-' ) { \ + fprintf(stderr, "Argument not found for option -%c.\n", (c)); \ + return; \ + } + +// +void +banner(FILE* stream = stdout) +{ + fprintf(stream, "\n\ +%s (asdcplib %s)\n\n\ +Copyright (c) 2003-2012 John Hurst\n\n\ +asdcplib may be copied only under the terms of the license found at\n\ +the top of every file in the asdcplib distribution kit.\n\n\ +Specify the -h (help) option for further information about %s\n\n", + PROGRAM_NAME, ASDCP::Version(), PROGRAM_NAME); +} + +// +void +usage(FILE* stream = stdout) +{ + fprintf(stream, "\ +USAGE: %s [-h|-help] [-V]\n\ +\n\ + %s -d <input-file>\n\ +\n\ + %s -g | -u\n\ +\n\ + %s -u\n\n", + PROGRAM_NAME, PROGRAM_NAME, PROGRAM_NAME, PROGRAM_NAME); + + fprintf(stream, "\ +Major modes:\n\ + -d - Calculate message digest of input file\n\ + -g - Generate a random 16 byte value to stdout\n\ + -h | -help - Show help\n\ + -u - Generate a random UUID value to stdout\n\ + -V - Show version information\n\ +\n\ + NOTES: o There is no option grouping, all options must be distinct arguments.\n\ + o All option arguments must be separated from the option by whitespace.\n\n"); +} + +// +enum MajorMode_t +{ + MMT_NONE, + MMT_GEN_ID, + MMT_GEN_KEY, + MMT_DIGEST, +}; + +// +class CommandOptions +{ + CommandOptions(); + +public: + MajorMode_t mode; + bool error_flag; // true if the given options are in error or not complete + bool version_flag; // true if the version display option was selected + bool help_flag; // true if the help display option was selected + PathList_t filenames; // list of filenames to be processed + + // + CommandOptions(int argc, const char** argv) : + mode(MMT_NONE), error_flag(true), version_flag(false), help_flag(false) + { + for ( int i = 1; i < argc; ++i ) + { + + if ( (strcmp( argv[i], "-help") == 0) ) + { + help_flag = true; + continue; + } + + if ( argv[i][0] == '-' + && ( isalpha(argv[i][1]) || isdigit(argv[i][1]) ) + && argv[i][2] == 0 ) + { + switch ( argv[i][1] ) + { + case 'd': mode = MMT_DIGEST; break; + case 'g': mode = MMT_GEN_KEY; break; + case 'h': help_flag = true; break; + case 'u': mode = MMT_GEN_ID; break; + case 'V': version_flag = true; break; + + default: + fprintf(stderr, "Unrecognized option: %s\n", argv[i]); + return; + } + } + else + { + if ( argv[i][0] != '-' ) + { + filenames.push_back(argv[i]); + } + else + { + fprintf(stderr, "Unrecognized argument: %s\n", argv[i]); + return; + } + } + } + + if ( help_flag || version_flag ) + return; + + if ( ( mode == MMT_DIGEST ) && filenames.empty() ) + { + fputs("Option requires at least one filename argument.\n", stderr); + return; + } + + if ( mode == MMT_NONE && ! help_flag && ! version_flag ) + { + fputs("No operation selected (use one of -[dgu] or -h for help).\n", stderr); + return; + } + + error_flag = false; + } +}; + +// +Result_t +digest_file(const std::string& filename) +{ + FileReader Reader; + SHA_CTX Ctx; + SHA1_Init(&Ctx); + ByteString Buf(8192); + + Result_t result = Reader.OpenRead(filename.c_str()); + + while ( ASDCP_SUCCESS(result) ) + { + ui32_t read_count = 0; + result = Reader.Read(Buf.Data(), Buf.Capacity(), &read_count); + + if ( result == RESULT_ENDOFFILE ) + { + result = RESULT_OK; + break; + } + + if ( ASDCP_SUCCESS(result) ) + SHA1_Update(&Ctx, Buf.Data(), read_count); + } + + if ( ASDCP_SUCCESS(result) ) + { + const ui32_t sha_len = 20; + byte_t bin_buf[sha_len]; + char sha_buf[64]; + SHA1_Final(bin_buf, &Ctx); + + fprintf(stdout, "%s %s\n", + base64encode(bin_buf, sha_len, sha_buf, 64), + filename.c_str()); + } + + return result; +} + +// +int +main(int argc, const char** argv) +{ + Result_t result = RESULT_OK; + char str_buf[64]; + CommandOptions Options(argc, argv); + + if ( Options.version_flag ) + banner(); + + if ( Options.help_flag ) + usage(); + + if ( Options.version_flag || Options.help_flag ) + return 0; + + if ( Options.error_flag ) + { + fprintf(stderr, "There was a problem. Type %s -h for help.\n", + PROGRAM_NAME); + return 3; + } + + if ( Options.mode == MMT_GEN_KEY ) + { + Kumu::FortunaRNG RNG; + byte_t bin_buf[ASDCP::KeyLen]; + + RNG.FillRandom(bin_buf, ASDCP::KeyLen); + printf("%s\n", Kumu::bin2hex(bin_buf, ASDCP::KeyLen, str_buf, 64)); + } + else if ( Options.mode == MMT_GEN_ID ) + { + UUID TmpID; + Kumu::GenRandomValue(TmpID); + printf("%s\n", TmpID.EncodeHex(str_buf, 64)); + } + else if ( Options.mode == MMT_DIGEST ) + { + PathList_t::iterator i; + + for ( i = Options.filenames.begin(); + i != Options.filenames.end() && ASDCP_SUCCESS(result); ++i ) + result = digest_file(*i); + } + else + { + fprintf(stderr, "Unhandled mode: %d.\n", Options.mode); + return 6; + } + + if ( ASDCP_FAILURE(result) ) + { + fputs("Program stopped on error.\n", stderr); + + if ( result != RESULT_FAIL ) + { + fputs(result, stderr); + fputc('\n', stderr); + } + + return 1; + } + + return 0; +} + + +// +// end asdcp-util.cpp +// diff --git a/asdcplib/src/asdcp-version.cpp b/asdcplib/src/asdcp-version.cpp new file mode 100755 index 0000000..621eec3 --- /dev/null +++ b/asdcplib/src/asdcp-version.cpp @@ -0,0 +1,46 @@ +/* +Copyright (c) 2004-2009, 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 asdcp-version.cpp + \version $Id: asdcp-version.cpp,v 1.4 2009/04/09 19:24:14 msheby Exp $ + \brief AS-DCP library version annunciator +*/ + +#include <AS_DCP.h> +using namespace ASDCP; + +// +int +main() +{ + printf("%s", VERSION); + return 0; +} + + +// +// end asdcp-version.cpp +// diff --git a/asdcplib/src/asdcp-wrap.cpp b/asdcplib/src/asdcp-wrap.cpp new file mode 100755 index 0000000..e1182ae --- /dev/null +++ b/asdcplib/src/asdcp-wrap.cpp @@ -0,0 +1,1151 @@ +/* +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 asdcp-wrap.cpp + \version $Id: asdcp-wrap.cpp,v 1.5 2012/03/07 18:47:02 mikey Exp $ + \brief AS-DCP file manipulation utility + + This program wraps d-cinema essence (picture, sound or text) in t an AS-DCP + MXF file. + + For more information about asdcplib, please refer to the header file AS_DCP.h + + WARNING: While the asdcplib library attempts to provide a complete and secure + implementation of the cryptographic features of the AS-DCP file formats, this + unit test program is NOT secure and is therefore NOT SUITABLE FOR USE in a + production environment without some modification. + + In particular, this program uses weak IV generation and externally generated + plaintext keys. These shortcomings exist because cryptographic-quality + random number generation and key management are outside the scope of the + asdcplib library. Developers using asdcplib for commercial implementations + claiming SMPTE conformance are expected to provide proper implementations of + these features. +*/ + +#include <KM_fileio.h> +#include <KM_prng.h> +#include <AS_DCP.h> +#include <PCMParserList.h> +#include <Metadata.h> + +using namespace ASDCP; + +const ui32_t FRAME_BUFFER_SIZE = 4 * Kumu::Megabyte; + +//------------------------------------------------------------------------------------------ +// +// command line option parser class + +static const char* PROGRAM_NAME = "asdcp-wrap"; // program name for messages + +// local program identification info written to file headers +class MyInfo : public WriterInfo +{ +public: + MyInfo() + { + static byte_t default_ProductUUID_Data[UUIDlen] = + { 0x7d, 0x83, 0x6e, 0x16, 0x37, 0xc7, 0x4c, 0x22, + 0xb2, 0xe0, 0x46, 0xa7, 0x17, 0xe8, 0x4f, 0x42 }; + + memcpy(ProductUUID, default_ProductUUID_Data, UUIDlen); + CompanyName = "WidgetCo"; + ProductName = "asdcp-wrap"; + ProductVersion = ASDCP::Version(); + } +} s_MyInfo; + + + +// Increment the iterator, test for an additional non-option command line argument. +// Causes the caller to return if there are no remaining arguments or if the next +// argument begins with '-'. +#define TEST_EXTRA_ARG(i,c) \ + if ( ++i >= argc || argv[(i)][0] == '-' ) { \ + fprintf(stderr, "Argument not found for option -%c.\n", (c)); \ + return; \ + } + +// +void +banner(FILE* stream = stdout) +{ + fprintf(stream, "\n\ +%s (asdcplib %s)\n\n\ +Copyright (c) 2003-2012 John Hurst\n\n\ +asdcplib may be copied only under the terms of the license found at\n\ +the top of every file in the asdcplib distribution kit.\n\n\ +Specify the -h (help) option for further information about %s\n\n", + PROGRAM_NAME, ASDCP::Version(), PROGRAM_NAME); +} + +// +void +usage(FILE* stream = stdout) +{ + fprintf(stream, "\ +USAGE: %s [-h|-help] [-V]\n\ +\n\ + %s [-3] [-a <uuid>] [-b <buffer-size>] [-C <UL>] [-d <duration>]\n\ + [-e|-E] [-f <start-frame>] [-j <key-id-string>] [-k <key-string>]\n\ + [-l <label>] [-L] [-M] [-p <frame-rate>] [-s <num>] [-v] [-W]\n\ + [-z|-Z] <input-file>+ <output-file>\n\n", + PROGRAM_NAME, PROGRAM_NAME); + + fprintf(stream, "\ +Options:\n\ + -3 - Create a stereoscopic image file. Expects two\n\ + directories of JP2K codestreams (directories must have\n\ + an equal number of frames; left eye is first).\n\ + -C <UL> - Set ChannelAssignment UL value\n\ + -h | -help - Show help\n\ + -V - Show version information\n\ + -e - Encrypt MPEG or JP2K headers (default)\n\ + -E - Do not encrypt MPEG or JP2K headers\n\ + -j <key-id-str> - Write key ID instead of creating a random value\n\ + -k <key-string> - Use key for ciphertext operations\n\ + -M - Do not create HMAC values when writing\n\ + -a <UUID> - Specify the Asset ID of a file (with -c)\n\ + -b <buffer-size> - Specify size in bytes of picture frame buffer.\n\ + Defaults to 4,194,304 (4MB)\n\ + -d <duration> - Number of frames to process, default all\n\ + -f <start-frame> - Starting frame number, default 0\n\ + -l <label> - Use given channel format label when writing MXF sound\n\ + files. SMPTE 429-2 labels: '5.1', '6.1', '7.1',\n\ + '7.1DS', 'WTF'\n\ + Default is no label (valid for Interop only).\n\ + -L - Write SMPTE UL values instead of MXF Interop\n\ + -p <rate> - fps of picture when wrapping PCM or JP2K:\n\ + Use one of [23|24|25|30|48|50|60], 24 is default\n\ + -v - Verbose, prints informative messages to stderr\n\ + -W - Read input file only, do not write source file\n\ + -z - Fail if j2c inputs have unequal parameters (default)\n\ + -Z - Ignore unequal parameters in j2c inputs\n\ +\n\ + NOTES: o There is no option grouping, all options must be distinct arguments.\n\ + o All option arguments must be separated from the option by whitespace.\n\ + o An argument of \"23\" to the -p option will be interpreted\n\ + as 24000/1001 fps.\n\ +\n"); +} + +// +PCM::ChannelFormat_t +decode_channel_fmt(const std::string& label_name) +{ + if ( label_name == "5.1" ) + return PCM::CF_CFG_1; + + else if ( label_name == "6.1" ) + return PCM::CF_CFG_2; + + else if ( label_name == "7.1" ) + return PCM::CF_CFG_3; + + else if ( label_name == "WTF" ) + return PCM::CF_CFG_4; + + else if ( label_name == "7.1DS" ) + return PCM::CF_CFG_5; + + fprintf(stderr, "Error decoding channel format string: %s\n", label_name.c_str()); + fprintf(stderr, "Expecting '5.1', '6.1', '7.1', '7.1DS' or 'WTF'\n"); + return PCM::CF_NONE; +} + +// +// +class CommandOptions +{ + CommandOptions(); + +public: + bool error_flag; // true if the given options are in error or not complete + bool key_flag; // true if an encryption key was given + bool asset_id_flag; // true if an asset ID was given + bool encrypt_header_flag; // true if mpeg headers are to be encrypted + bool write_hmac; // true if HMAC values are to be generated and written + /// bool read_hmac; // true if HMAC values are to be validated + /// bool split_wav; // true if PCM is to be extracted to stereo WAV files + /// bool mono_wav; // true if PCM is to be extracted to mono WAV files + bool verbose_flag; // true if the verbose option was selected + ui32_t fb_dump_size; // number of bytes of frame buffer to dump + /// bool showindex_flag; // true if index is to be displayed + /// bool showheader_flag; // true if MXF file header is to be displayed + bool no_write_flag; // true if no output files are to be written + bool version_flag; // true if the version display option was selected + bool help_flag; // true if the help display option was selected + bool stereo_image_flag; // if true, expect stereoscopic JP2K input (left eye first) + /// ui32_t number_width; // number of digits in a serialized filename (for JPEG extract) + ui32_t start_frame; // frame number to begin processing + ui32_t duration; // number of frames to be processed + bool use_smpte_labels; // if true, SMPTE UL values will be written instead of MXF Interop values + bool j2c_pedantic; // passed to JP2K::SequenceParser::OpenRead + ui32_t picture_rate; // fps of picture when wrapping PCM + ui32_t fb_size; // size of picture frame buffer + byte_t key_value[KeyLen]; // value of given encryption key (when key_flag is true) + bool key_id_flag; // true if a key ID was given + byte_t key_id_value[UUIDlen];// value of given key ID (when key_id_flag is true) + byte_t asset_id_value[UUIDlen];// value of asset ID (when asset_id_flag is true) + PCM::ChannelFormat_t channel_fmt; // audio channel arrangement + std::string out_file; // + bool show_ul_values; /// if true, dump the UL table before going tp work. + Kumu::PathList_t filenames; // list of filenames to be processed + UL channel_assignment; + + // + Rational PictureRate() + { + if ( picture_rate == 23 ) return EditRate_23_98; + if ( picture_rate == 24 ) return EditRate_24; + if ( picture_rate == 25 ) return EditRate_25; + if ( picture_rate == 30 ) return EditRate_30; + if ( picture_rate == 48 ) return EditRate_48; + if ( picture_rate == 50 ) return EditRate_50; + if ( picture_rate == 60 ) return EditRate_60; + if ( picture_rate == 96 ) return EditRate_96; + if ( picture_rate == 100 ) return EditRate_100; + if ( picture_rate == 120 ) return EditRate_120; + return EditRate_24; + } + + // + const char* szPictureRate() + { + if ( picture_rate == 23 ) return "23.976"; + if ( picture_rate == 24 ) return "24"; + if ( picture_rate == 25 ) return "25"; + if ( picture_rate == 30 ) return "30"; + if ( picture_rate == 48 ) return "48"; + if ( picture_rate == 50 ) return "50"; + if ( picture_rate == 60 ) return "60"; + if ( picture_rate == 96 ) return "96"; + if ( picture_rate == 100 ) return "100"; + if ( picture_rate == 120 ) return "120"; + return "24"; + } + + // + CommandOptions(int argc, const char** argv) : + error_flag(true), key_flag(false), key_id_flag(false), asset_id_flag(false), + encrypt_header_flag(true), write_hmac(true), + verbose_flag(false), fb_dump_size(0), + no_write_flag(false), version_flag(false), help_flag(false), stereo_image_flag(false), + start_frame(0), + duration(0xffffffff), use_smpte_labels(false), j2c_pedantic(true), + fb_size(FRAME_BUFFER_SIZE), + channel_fmt(PCM::CF_NONE), + show_ul_values(false) + { + memset(key_value, 0, KeyLen); + memset(key_id_value, 0, UUIDlen); + + for ( int i = 1; i < argc; i++ ) + { + + if ( (strcmp( argv[i], "-help") == 0) ) + { + help_flag = true; + continue; + } + + if ( argv[i][0] == '-' + && ( isalpha(argv[i][1]) || isdigit(argv[i][1]) ) + && argv[i][2] == 0 ) + { + switch ( argv[i][1] ) + { + case '3': stereo_image_flag = true; break; + + case 'a': + asset_id_flag = true; + TEST_EXTRA_ARG(i, 'a'); + { + ui32_t length; + Kumu::hex2bin(argv[i], asset_id_value, UUIDlen, &length); + + if ( length != UUIDlen ) + { + fprintf(stderr, "Unexpected asset ID length: %u, expecting %u characters.\n", length, UUIDlen); + return; + } + } + break; + + case 'b': + TEST_EXTRA_ARG(i, 'b'); + fb_size = abs(atoi(argv[i])); + + if ( verbose_flag ) + fprintf(stderr, "Frame Buffer size: %u bytes.\n", fb_size); + + break; + + case 'C': + TEST_EXTRA_ARG(i, 'U'); + if ( ! channel_assignment.DecodeHex(argv[i]) ) + { + fprintf(stderr, "Error decoding UL value: %s\n", argv[i]); + return; + } + break; + + case 'd': + TEST_EXTRA_ARG(i, 'd'); + duration = abs(atoi(argv[i])); + break; + + case 'E': encrypt_header_flag = false; break; + case 'e': encrypt_header_flag = true; break; + + case 'f': + TEST_EXTRA_ARG(i, 'f'); + start_frame = abs(atoi(argv[i])); + break; + + case 'h': help_flag = true; break; + + case 'j': key_id_flag = true; + TEST_EXTRA_ARG(i, 'j'); + { + ui32_t length; + Kumu::hex2bin(argv[i], key_id_value, UUIDlen, &length); + + if ( length != UUIDlen ) + { + fprintf(stderr, "Unexpected key ID length: %u, expecting %u characters.\n", length, UUIDlen); + return; + } + } + break; + + case 'k': key_flag = true; + TEST_EXTRA_ARG(i, 'k'); + { + ui32_t length; + Kumu::hex2bin(argv[i], key_value, KeyLen, &length); + + if ( length != KeyLen ) + { + fprintf(stderr, "Unexpected key length: %u, expecting %u characters.\n", length, KeyLen); + return; + } + } + break; + + case 'l': + TEST_EXTRA_ARG(i, 'l'); + channel_fmt = decode_channel_fmt(argv[i]); + break; + + case 'L': use_smpte_labels = true; break; + case 'M': write_hmac = false; break; + + case 'p': + TEST_EXTRA_ARG(i, 'p'); + picture_rate = abs(atoi(argv[i])); + break; + + case 'V': version_flag = true; break; + case 'v': verbose_flag = true; break; + case 'W': no_write_flag = true; break; + case 'Z': j2c_pedantic = false; break; + case 'z': j2c_pedantic = true; break; + + default: + fprintf(stderr, "Unrecognized option: %s\n", argv[i]); + return; + } + } + else + { + + if ( argv[i][0] != '-' ) + { + filenames.push_back(argv[i]); + } + else + { + fprintf(stderr, "Unrecognized argument: %s\n", argv[i]); + return; + } + } + } + + if ( help_flag || version_flag ) + return; + + if ( filenames.size() < 2 ) + { + fputs("Option requires at least two filename arguments: <input-file> <output-file>\n", stderr); + return; + } + + out_file = filenames.back(); + filenames.pop_back(); + error_flag = false; + } +}; + +//------------------------------------------------------------------------------------------ +// MPEG2 essence + +// Write a plaintext MPEG2 Video Elementary Stream to a plaintext ASDCP file +// Write a plaintext MPEG2 Video Elementary Stream to a ciphertext ASDCP file +// +Result_t +write_MPEG2_file(CommandOptions& Options) +{ + AESEncContext* Context = 0; + HMACContext* HMAC = 0; + MPEG2::FrameBuffer FrameBuffer(Options.fb_size); + MPEG2::Parser Parser; + MPEG2::MXFWriter Writer; + MPEG2::VideoDescriptor VDesc; + byte_t IV_buf[CBC_BLOCK_SIZE]; + Kumu::FortunaRNG RNG; + + // set up essence parser + Result_t result = Parser.OpenRead(Options.filenames.front().c_str()); + + // set up MXF writer + if ( ASDCP_SUCCESS(result) ) + { + Parser.FillVideoDescriptor(VDesc); + + if ( Options.verbose_flag ) + { + fputs("MPEG-2 Pictures\n", stderr); + fputs("VideoDescriptor:\n", stderr); + fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size); + MPEG2::VideoDescriptorDump(VDesc); + } + } + + if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag ) + { + WriterInfo Info = s_MyInfo; // fill in your favorite identifiers here + if ( Options.asset_id_flag ) + memcpy(Info.AssetUUID, Options.asset_id_value, UUIDlen); + else + Kumu::GenRandomUUID(Info.AssetUUID); + + if ( Options.use_smpte_labels ) + { + Info.LabelSetType = LS_MXF_SMPTE; + fprintf(stderr, "ATTENTION! Writing SMPTE Universal Labels\n"); + } + + // configure encryption + if( Options.key_flag ) + { + Kumu::GenRandomUUID(Info.ContextID); + Info.EncryptedEssence = true; + + if ( Options.key_id_flag ) + memcpy(Info.CryptographicKeyID, Options.key_id_value, UUIDlen); + else + RNG.FillRandom(Info.CryptographicKeyID, UUIDlen); + + Context = new AESEncContext; + result = Context->InitKey(Options.key_value); + + if ( ASDCP_SUCCESS(result) ) + result = Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE)); + + if ( ASDCP_SUCCESS(result) && Options.write_hmac ) + { + Info.UsesHMAC = true; + HMAC = new HMACContext; + result = HMAC->InitKey(Options.key_value, Info.LabelSetType); + } + } + + if ( ASDCP_SUCCESS(result) ) + result = Writer.OpenWrite(Options.out_file.c_str(), Info, VDesc); + } + + if ( ASDCP_SUCCESS(result) ) + // loop through the frames + { + result = Parser.Reset(); + ui32_t duration = 0; + + while ( ASDCP_SUCCESS(result) && duration++ < Options.duration ) + { + if ( duration == 1 ) + { + result = Parser.ReadFrame(FrameBuffer); + + if ( ASDCP_SUCCESS(result) ) + { + if ( Options.verbose_flag ) + FrameBuffer.Dump(stderr, Options.fb_dump_size); + + if ( Options.encrypt_header_flag ) + FrameBuffer.PlaintextOffset(0); + } + } + + if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag ) + { + result = Writer.WriteFrame(FrameBuffer, Context, HMAC); + + // The Writer class will forward the last block of ciphertext + // to the encryption context for use as the IV for the next + // frame. If you want to use non-sequitur IV values, un-comment + // the following line of code. + // if ( ASDCP_SUCCESS(result) && Options.key_flag ) + // Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE)); + } + } + + if ( result == RESULT_ENDOFFILE ) + result = RESULT_OK; + } + + if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag ) + result = Writer.Finalize(); + + return result; +} + + +//------------------------------------------------------------------------------------------ +// JPEG 2000 essence + +// Write one or more plaintext JPEG 2000 stereoscopic codestream pairs to a plaintext ASDCP file +// Write one or more plaintext JPEG 2000 stereoscopic codestream pairs to a ciphertext ASDCP file +// +Result_t +write_JP2K_S_file(CommandOptions& Options) +{ + AESEncContext* Context = 0; + HMACContext* HMAC = 0; + JP2K::MXFSWriter Writer; + JP2K::FrameBuffer FrameBuffer(Options.fb_size); + JP2K::PictureDescriptor PDesc; + JP2K::SequenceParser ParserLeft, ParserRight; + byte_t IV_buf[CBC_BLOCK_SIZE]; + Kumu::FortunaRNG RNG; + + if ( Options.filenames.size() != 2 ) + { + fprintf(stderr, "Two inputs are required for stereoscopic option.\n"); + return RESULT_FAIL; + } + + // set up essence parser + Result_t result = ParserLeft.OpenRead(Options.filenames.front().c_str(), Options.j2c_pedantic); + + if ( ASDCP_SUCCESS(result) ) + { + Options.filenames.pop_front(); + result = ParserRight.OpenRead(Options.filenames.front().c_str(), Options.j2c_pedantic); + } + + // set up MXF writer + if ( ASDCP_SUCCESS(result) ) + { + ParserLeft.FillPictureDescriptor(PDesc); + PDesc.EditRate = Options.PictureRate(); + + if ( Options.verbose_flag ) + { + fputs("JPEG 2000 stereoscopic pictures\nPictureDescriptor:\n", stderr); + fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size); + JP2K::PictureDescriptorDump(PDesc); + } + } + + if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag ) + { + WriterInfo Info = s_MyInfo; // fill in your favorite identifiers here + if ( Options.asset_id_flag ) + memcpy(Info.AssetUUID, Options.asset_id_value, UUIDlen); + else + Kumu::GenRandomUUID(Info.AssetUUID); + + if ( Options.use_smpte_labels ) + { + Info.LabelSetType = LS_MXF_SMPTE; + fprintf(stderr, "ATTENTION! Writing SMPTE Universal Labels\n"); + } + + // configure encryption + if( Options.key_flag ) + { + Kumu::GenRandomUUID(Info.ContextID); + Info.EncryptedEssence = true; + + if ( Options.key_id_flag ) + memcpy(Info.CryptographicKeyID, Options.key_id_value, UUIDlen); + else + RNG.FillRandom(Info.CryptographicKeyID, UUIDlen); + + Context = new AESEncContext; + result = Context->InitKey(Options.key_value); + + if ( ASDCP_SUCCESS(result) ) + result = Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE)); + + if ( ASDCP_SUCCESS(result) && Options.write_hmac ) + { + Info.UsesHMAC = true; + HMAC = new HMACContext; + result = HMAC->InitKey(Options.key_value, Info.LabelSetType); + } + } + + if ( ASDCP_SUCCESS(result) ) + result = Writer.OpenWrite(Options.out_file.c_str(), Info, PDesc); + } + + if ( ASDCP_SUCCESS(result) ) + { + ui32_t duration = 0; + result = ParserLeft.Reset(); + if ( ASDCP_SUCCESS(result) ) result = ParserRight.Reset(); + + while ( ASDCP_SUCCESS(result) && duration++ < Options.duration ) + { + result = ParserLeft.ReadFrame(FrameBuffer); + + if ( ASDCP_SUCCESS(result) ) + { + if ( Options.verbose_flag ) + FrameBuffer.Dump(stderr, Options.fb_dump_size); + + if ( Options.encrypt_header_flag ) + FrameBuffer.PlaintextOffset(0); + } + + if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag ) + result = Writer.WriteFrame(FrameBuffer, JP2K::SP_LEFT, Context, HMAC); + + if ( ASDCP_SUCCESS(result) ) + result = ParserRight.ReadFrame(FrameBuffer); + + if ( ASDCP_SUCCESS(result) ) + { + if ( Options.verbose_flag ) + FrameBuffer.Dump(stderr, Options.fb_dump_size); + + if ( Options.encrypt_header_flag ) + FrameBuffer.PlaintextOffset(0); + } + + if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag ) + result = Writer.WriteFrame(FrameBuffer, JP2K::SP_RIGHT, Context, HMAC); + } + + if ( result == RESULT_ENDOFFILE ) + result = RESULT_OK; + } + + if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag ) + result = Writer.Finalize(); + + return result; +} + +// Write one or more plaintext JPEG 2000 codestreams to a plaintext ASDCP file +// Write one or more plaintext JPEG 2000 codestreams to a ciphertext ASDCP file +// +Result_t +write_JP2K_file(CommandOptions& Options) +{ + AESEncContext* Context = 0; + HMACContext* HMAC = 0; + JP2K::MXFWriter Writer; + JP2K::FrameBuffer FrameBuffer(Options.fb_size); + JP2K::PictureDescriptor PDesc; + JP2K::SequenceParser Parser; + byte_t IV_buf[CBC_BLOCK_SIZE]; + Kumu::FortunaRNG RNG; + + // set up essence parser + Result_t result = Parser.OpenRead(Options.filenames.front().c_str(), Options.j2c_pedantic); + + // set up MXF writer + if ( ASDCP_SUCCESS(result) ) + { + Parser.FillPictureDescriptor(PDesc); + PDesc.EditRate = Options.PictureRate(); + + if ( Options.verbose_flag ) + { + fprintf(stderr, "JPEG 2000 pictures\n"); + fputs("PictureDescriptor:\n", stderr); + fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size); + JP2K::PictureDescriptorDump(PDesc); + } + } + + if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag ) + { + WriterInfo Info = s_MyInfo; // fill in your favorite identifiers here + if ( Options.asset_id_flag ) + memcpy(Info.AssetUUID, Options.asset_id_value, UUIDlen); + else + Kumu::GenRandomUUID(Info.AssetUUID); + + if ( Options.use_smpte_labels ) + { + Info.LabelSetType = LS_MXF_SMPTE; + fprintf(stderr, "ATTENTION! Writing SMPTE Universal Labels\n"); + } + + // configure encryption + if( Options.key_flag ) + { + Kumu::GenRandomUUID(Info.ContextID); + Info.EncryptedEssence = true; + + if ( Options.key_id_flag ) + memcpy(Info.CryptographicKeyID, Options.key_id_value, UUIDlen); + else + RNG.FillRandom(Info.CryptographicKeyID, UUIDlen); + + Context = new AESEncContext; + result = Context->InitKey(Options.key_value); + + if ( ASDCP_SUCCESS(result) ) + result = Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE)); + + if ( ASDCP_SUCCESS(result) && Options.write_hmac ) + { + Info.UsesHMAC = true; + HMAC = new HMACContext; + result = HMAC->InitKey(Options.key_value, Info.LabelSetType); + } + } + + if ( ASDCP_SUCCESS(result) ) + result = Writer.OpenWrite(Options.out_file.c_str(), Info, PDesc); + } + + if ( ASDCP_SUCCESS(result) ) + { + ui32_t duration = 0; + result = Parser.Reset(); + + while ( ASDCP_SUCCESS(result) && duration++ < Options.duration ) + { + if ( duration == 1 ) + { + result = Parser.ReadFrame(FrameBuffer); + + if ( ASDCP_SUCCESS(result) ) + { + if ( Options.verbose_flag ) + FrameBuffer.Dump(stderr, Options.fb_dump_size); + + if ( Options.encrypt_header_flag ) + FrameBuffer.PlaintextOffset(0); + } + } + + if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag ) + { + result = Writer.WriteFrame(FrameBuffer, Context, HMAC); + + // The Writer class will forward the last block of ciphertext + // to the encryption context for use as the IV for the next + // frame. If you want to use non-sequitur IV values, un-comment + // the following line of code. + // if ( ASDCP_SUCCESS(result) && Options.key_flag ) + // Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE)); + } + } + + if ( result == RESULT_ENDOFFILE ) + result = RESULT_OK; + } + + if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag ) + result = Writer.Finalize(); + + return result; +} + +//------------------------------------------------------------------------------------------ +// PCM essence + + +// Write one or more plaintext PCM audio streams to a plaintext ASDCP file +// Write one or more plaintext PCM audio streams to a ciphertext ASDCP file +// +Result_t +write_PCM_file(CommandOptions& Options) +{ + AESEncContext* Context = 0; + HMACContext* HMAC = 0; + PCMParserList Parser; + PCM::MXFWriter Writer; + PCM::FrameBuffer FrameBuffer; + PCM::AudioDescriptor ADesc; + Rational PictureRate = Options.PictureRate(); + byte_t IV_buf[CBC_BLOCK_SIZE]; + Kumu::FortunaRNG RNG; + + // set up essence parser + Result_t result = Parser.OpenRead(Options.filenames, PictureRate); + + // set up MXF writer + if ( ASDCP_SUCCESS(result) ) + { + Parser.FillAudioDescriptor(ADesc); + + ADesc.EditRate = PictureRate; + FrameBuffer.Capacity(PCM::CalcFrameBufferSize(ADesc)); + ADesc.ChannelFormat = Options.channel_fmt; + + if ( Options.use_smpte_labels && ADesc.ChannelFormat == PCM::CF_NONE) + { + fprintf(stderr, "ATTENTION! Writing SMPTE audio without ChannelAssignment property (see option -l)\n"); + } + + if ( Options.verbose_flag ) + { + fprintf(stderr, "%.1fkHz PCM Audio, %s fps (%u spf)\n", + ADesc.AudioSamplingRate.Quotient() / 1000.0, + Options.szPictureRate(), + PCM::CalcSamplesPerFrame(ADesc)); + fputs("AudioDescriptor:\n", stderr); + PCM::AudioDescriptorDump(ADesc); + } + } + + if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag ) + { + WriterInfo Info = s_MyInfo; // fill in your favorite identifiers here + if ( Options.asset_id_flag ) + memcpy(Info.AssetUUID, Options.asset_id_value, UUIDlen); + else + Kumu::GenRandomUUID(Info.AssetUUID); + + if ( Options.use_smpte_labels ) + { + Info.LabelSetType = LS_MXF_SMPTE; + fprintf(stderr, "ATTENTION! Writing SMPTE Universal Labels\n"); + } + + // configure encryption + if( Options.key_flag ) + { + Kumu::GenRandomUUID(Info.ContextID); + Info.EncryptedEssence = true; + + if ( Options.key_id_flag ) + memcpy(Info.CryptographicKeyID, Options.key_id_value, UUIDlen); + else + RNG.FillRandom(Info.CryptographicKeyID, UUIDlen); + + Context = new AESEncContext; + result = Context->InitKey(Options.key_value); + + if ( ASDCP_SUCCESS(result) ) + result = Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE)); + + if ( ASDCP_SUCCESS(result) && Options.write_hmac ) + { + Info.UsesHMAC = true; + HMAC = new HMACContext; + result = HMAC->InitKey(Options.key_value, Info.LabelSetType); + } + } + + if ( ASDCP_SUCCESS(result) ) + result = Writer.OpenWrite(Options.out_file.c_str(), Info, ADesc); + + if ( ASDCP_SUCCESS(result) && Options.channel_assignment.HasValue() ) + { + MXF::WaveAudioDescriptor *descriptor = 0; + Writer.OPAtomHeader().GetMDObjectByType(DefaultSMPTEDict().ul(MDD_WaveAudioDescriptor), + reinterpret_cast<MXF::InterchangeObject**>(&descriptor)); + descriptor->ChannelAssignment = Options.channel_assignment; + } + } + + if ( ASDCP_SUCCESS(result) ) + { + result = Parser.Reset(); + ui32_t duration = 0; + + while ( ASDCP_SUCCESS(result) && duration++ < Options.duration ) + { + result = Parser.ReadFrame(FrameBuffer); + + if ( ASDCP_SUCCESS(result) ) + { + if ( FrameBuffer.Size() != FrameBuffer.Capacity() ) + { + fprintf(stderr, "WARNING: Last frame read was short, PCM input is possibly not frame aligned.\n"); + fprintf(stderr, "Expecting %u bytes, got %u.\n", FrameBuffer.Capacity(), FrameBuffer.Size()); + result = RESULT_ENDOFFILE; + continue; + } + + if ( Options.verbose_flag ) + FrameBuffer.Dump(stderr, Options.fb_dump_size); + + if ( ! Options.no_write_flag ) + { + result = Writer.WriteFrame(FrameBuffer, Context, HMAC); + + // The Writer class will forward the last block of ciphertext + // to the encryption context for use as the IV for the next + // frame. If you want to use non-sequitur IV values, un-comment + // the following line of code. + // if ( ASDCP_SUCCESS(result) && Options.key_flag ) + // Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE)); + } + } + } + + if ( result == RESULT_ENDOFFILE ) + result = RESULT_OK; + } + + if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag ) + result = Writer.Finalize(); + + return result; +} + + +//------------------------------------------------------------------------------------------ +// TimedText essence + + +// Write one or more plaintext timed text streams to a plaintext ASDCP file +// Write one or more plaintext timed text streams to a ciphertext ASDCP file +// +Result_t +write_timed_text_file(CommandOptions& Options) +{ + AESEncContext* Context = 0; + HMACContext* HMAC = 0; + TimedText::DCSubtitleParser Parser; + TimedText::MXFWriter Writer; + TimedText::FrameBuffer FrameBuffer; + TimedText::TimedTextDescriptor TDesc; + byte_t IV_buf[CBC_BLOCK_SIZE]; + Kumu::FortunaRNG RNG; + + // set up essence parser + Result_t result = Parser.OpenRead(Options.filenames.front().c_str()); + + // set up MXF writer + if ( ASDCP_SUCCESS(result) ) + { + Parser.FillTimedTextDescriptor(TDesc); + FrameBuffer.Capacity(Options.fb_size); + + if ( Options.verbose_flag ) + { + fputs("D-Cinema Timed-Text Descriptor:\n", stderr); + TimedText::DescriptorDump(TDesc); + } + } + + if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag ) + { + WriterInfo Info = s_MyInfo; // fill in your favorite identifiers here + if ( Options.asset_id_flag ) + memcpy(Info.AssetUUID, Options.asset_id_value, UUIDlen); + else + Kumu::GenRandomUUID(Info.AssetUUID); + + if ( Options.use_smpte_labels ) + { + Info.LabelSetType = LS_MXF_SMPTE; + fprintf(stderr, "ATTENTION! Writing SMPTE Universal Labels\n"); + } + + // configure encryption + if( Options.key_flag ) + { + Kumu::GenRandomUUID(Info.ContextID); + Info.EncryptedEssence = true; + + if ( Options.key_id_flag ) + memcpy(Info.CryptographicKeyID, Options.key_id_value, UUIDlen); + else + RNG.FillRandom(Info.CryptographicKeyID, UUIDlen); + + Context = new AESEncContext; + result = Context->InitKey(Options.key_value); + + if ( ASDCP_SUCCESS(result) ) + result = Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE)); + + if ( ASDCP_SUCCESS(result) && Options.write_hmac ) + { + Info.UsesHMAC = true; + HMAC = new HMACContext; + result = HMAC->InitKey(Options.key_value, Info.LabelSetType); + } + } + + if ( ASDCP_SUCCESS(result) ) + result = Writer.OpenWrite(Options.out_file.c_str(), Info, TDesc); + } + + if ( ASDCP_FAILURE(result) ) + return result; + + std::string XMLDoc; + TimedText::ResourceList_t::const_iterator ri; + + result = Parser.ReadTimedTextResource(XMLDoc); + + if ( ASDCP_SUCCESS(result) ) + result = Writer.WriteTimedTextResource(XMLDoc, Context, HMAC); + + for ( ri = TDesc.ResourceList.begin() ; ri != TDesc.ResourceList.end() && ASDCP_SUCCESS(result); ri++ ) + { + result = Parser.ReadAncillaryResource((*ri).ResourceID, FrameBuffer); + + if ( ASDCP_SUCCESS(result) ) + { + if ( Options.verbose_flag ) + FrameBuffer.Dump(stderr, Options.fb_dump_size); + + if ( ! Options.no_write_flag ) + { + result = Writer.WriteAncillaryResource(FrameBuffer, Context, HMAC); + + // The Writer class will forward the last block of ciphertext + // to the encryption context for use as the IV for the next + // frame. If you want to use non-sequitur IV values, un-comment + // the following line of code. + // if ( ASDCP_SUCCESS(result) && Options.key_flag ) + // Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE)); + } + } + + if ( result == RESULT_ENDOFFILE ) + result = RESULT_OK; + } + + if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag ) + result = Writer.Finalize(); + + return result; +} + +// +int +main(int argc, const char** argv) +{ + Result_t result = RESULT_OK; + char str_buf[64]; + CommandOptions Options(argc, argv); + + if ( Options.version_flag ) + banner(); + + if ( Options.help_flag ) + usage(); + + if ( Options.version_flag || Options.help_flag ) + return 0; + + if ( Options.error_flag ) + { + fprintf(stderr, "There was a problem. Type %s -h for help.\n", PROGRAM_NAME); + return 3; + } + + if ( Options.show_ul_values ) + { + if ( Options.use_smpte_labels ) + DefaultSMPTEDict().Dump(stdout); + else + DefaultInteropDict().Dump(stdout); + } + + EssenceType_t EssenceType; + result = ASDCP::RawEssenceType(Options.filenames.front().c_str(), EssenceType); + + if ( ASDCP_SUCCESS(result) ) + { + switch ( EssenceType ) + { + case ESS_MPEG2_VES: + result = write_MPEG2_file(Options); + break; + + case ESS_JPEG_2000: + if ( Options.stereo_image_flag ) + { + result = write_JP2K_S_file(Options); + } + else + { + result = write_JP2K_file(Options); + } + break; + + case ESS_PCM_24b_48k: + case ESS_PCM_24b_96k: + result = write_PCM_file(Options); + break; + + case ESS_TIMED_TEXT: + result = write_timed_text_file(Options); + break; + + default: + fprintf(stderr, "%s: Unknown file type, not ASDCP-compatible essence.\n", + Options.filenames.front().c_str()); + return 5; + } + } + + if ( ASDCP_FAILURE(result) ) + { + fputs("Program stopped on error.\n", stderr); + + if ( result != RESULT_FAIL ) + { + fputs(result, stderr); + fputc('\n', stderr); + } + + return 1; + } + + return 0; +} + + +// +// end asdcp-wrap.cpp +// diff --git a/asdcplib/src/blackwave.cpp b/asdcplib/src/blackwave.cpp new file mode 100644 index 0000000..8498655 --- /dev/null +++ b/asdcplib/src/blackwave.cpp @@ -0,0 +1,245 @@ +/* +Copyright (c) 2005-2009, 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 wavsplit.cpp + \version $Id: blackwave.cpp,v 1.10 2010/02/16 18:40:57 jhurst Exp $ + \brief Black WAV file generator +*/ + +#include "Wav.h" +#include <assert.h> + +using namespace ASDCP; + +//------------------------------------------------------------------------------------------ +// +// command line option parser class + +static const char* PROGRAM_NAME = "blackwave"; // program name for messages + +// Macros used to test command option data state. + +// Increment the iterator, test for an additional non-option command line argument. +// Causes the caller to return if there are no remaining arguments or if the next +// argument begins with '-'. +#define TEST_EXTRA_ARG(i,c) if ( ++i >= argc || argv[(i)][0] == '-' ) \ + { \ + fprintf(stderr, "Argument not found for option %c.\n", (c)); \ + return; \ + } +// +void +banner(FILE* stream = stderr) +{ + fprintf(stream, "\n\ +%s (asdcplib %s)\n\n\ +Copyright (c) 2005-2009 John Hurst\n\n\ +%s is part of asdcplib.\n\ +asdcplib may be copied only under the terms of the license found at\n\ +the top of every file in the asdcplib distribution kit.\n\n\ +Specify the -h (help) option for further information about %s\n\n", + PROGRAM_NAME, ASDCP::Version(), PROGRAM_NAME, PROGRAM_NAME); +} + +// +void +usage(FILE* stream = stderr) +{ + fprintf(stream, "\ +USAGE: %s [-v|-h[-d]] <filename>\n\ +\n\ + -V - Show version\n\ + -h - Show help\n\ + -d <duration> - Number of 2k-sample frames to process, default 1440\n\ +\n\ +Other Options:\n\ + -v - Verbose, show extra detail during run\n\ +\n\ + NOTES: o There is no option grouping, all options must be distinct arguments.\n\ + o All option arguments must be separated from the option by whitespace.\n\ +\n", PROGRAM_NAME); +} + +// +// +class CommandOptions +{ + CommandOptions(); + +public: + bool error_flag; // true if the given options are in error or not complete + bool verbose_flag; // true if the verbose option was selected + bool version_flag; // true if the version display option was selected + bool help_flag; // true if the help display option was selected + ui32_t duration; // number of frames to be processed + const char* filename; // filename prefix for files written by the extract mode + + CommandOptions(int argc, const char** argv) : + error_flag(true), verbose_flag(false), version_flag(false), help_flag(false), + duration(1440), filename(0) + { + for ( int i = 1; i < argc; i++ ) + { + if ( argv[i][0] == '-' && isalpha(argv[i][1]) && argv[i][2] == 0 ) + { + switch ( argv[i][1] ) + { + case 'V': version_flag = true; break; + case 'h': help_flag = true; break; + case 'v': verbose_flag = true; break; + + case 'd': + TEST_EXTRA_ARG(i, 'd'); + duration = atoi(argv[i]); // TODO: test for negative value, should use strtol() + break; + + default: + fprintf(stderr, "Unrecognized option: %c\n", argv[i][1]); + return; + } + } + else + { + if ( filename ) + { + fprintf(stderr, "Unexpected extra filename.\n"); + return; + } + + filename = argv[i]; + } + } + + if ( filename == 0 ) + { + fputs("Output filename required.\n", stderr); + return; + } + + error_flag = false; + } +}; + + +// +// +Result_t +make_black_wav_file(CommandOptions& Options) +{ + PCM::FrameBuffer FrameBuffer; + PCM::AudioDescriptor ADesc; + + ADesc.EditRate = Rational(24,1); + ADesc.AudioSamplingRate = ASDCP::SampleRate_48k; + ADesc.Locked = 0; + ADesc.ChannelCount = 1; + ADesc.QuantizationBits = 24; + ADesc.BlockAlign = 3; + ADesc.AvgBps = 14400; + ADesc.LinkedTrackID = 1; + ADesc.ContainerDuration = Options.duration; + + // fill the frame buffer with a frame (2000 samples) of black + FrameBuffer.Capacity(PCM::CalcFrameBufferSize(ADesc)); + memset(FrameBuffer.Data(), 0, FrameBuffer.Capacity()); + FrameBuffer.Size(FrameBuffer.Capacity()); + + if ( Options.verbose_flag ) + { + fprintf(stderr, "48Khz PCM Audio, %s fps (%u spf)\n", "24", + PCM::CalcSamplesPerFrame(ADesc)); + fputs("AudioDescriptor:\n", stderr); + PCM::AudioDescriptorDump(ADesc); + } + + // set up output file + Kumu::FileWriter OutFile; + Result_t result = OutFile.OpenWrite(Options.filename); + + if ( ASDCP_SUCCESS(result) ) + { + Wav::SimpleWaveHeader WavHeader(ADesc); + result = WavHeader.WriteToFile(OutFile); + } + + if ( ASDCP_SUCCESS(result) ) + { + ui32_t write_count = 0; + ui32_t duration = 0; + + while ( ASDCP_SUCCESS(result) && (duration++ < Options.duration) ) + { + result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count); + } + + if ( result == RESULT_ENDOFFILE ) + result = RESULT_OK; + } + + return RESULT_OK; +} + + +// +int +main(int argc, const char** argv) +{ + Result_t result = RESULT_OK; + CommandOptions Options(argc, argv); + + if ( Options.help_flag ) + { + usage(); + return 0; + } + + if ( Options.error_flag ) + return 3; + + if ( Options.version_flag ) + banner(); + + else + result = make_black_wav_file(Options); + + if ( result != RESULT_OK ) + { + fputs("Program stopped on error.\n", stderr); + + if ( result != RESULT_FAIL ) + { + fputs(result, stderr); + fputc('\n', stderr); + } + + return 1; + } + + return 0; +} + + +// diff --git a/asdcplib/src/fips-186-rng-test.cpp b/asdcplib/src/fips-186-rng-test.cpp new file mode 100755 index 0000000..aef3b87 --- /dev/null +++ b/asdcplib/src/fips-186-rng-test.cpp @@ -0,0 +1,96 @@ +/* +Copyright (c) 2007-2009, 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 fips-186-rng-test.cpp + \version $Id: fips-186-rng-test.cpp,v 1.4 2009/10/08 15:58:16 jhurst Exp $ + \brief FIPS 186-2 RNG test wrapper +*/ + +#include <KM_util.h> +#include <KM_prng.h> +#include <openssl/sha.h> + +using namespace Kumu; + +// +int +main(int argc, const char** argv) +{ + if ( argc != 5 ) + { + fprintf(stderr, "USAGE: fips-186-test <rounds> <b> <XKey-hex> <X-hex>\n"); + return 2; + } + + ui32_t const X_buf_len = 1024; + byte_t XKey_buf[X_buf_len]; + byte_t X_test_buf[X_buf_len]; + ui32_t char_count; + + char* end = 0; + ui32_t rounds = strtol(argv[1], &end, 10); + ui32_t B = strtol(argv[2], &end, 10) / 8; + + if ( hex2bin(argv[3], XKey_buf, X_buf_len, &char_count) != 0 ) + { + fprintf(stderr, "Error parsing <XKey-hex> value\n"); + return 3; + } + + if ( char_count != B ) + { + fprintf(stderr, "Incorrect length for <XKey-hex> value (expecting %d decoded bytes)\n", B); + return 3; + } + + if ( hex2bin(argv[4], X_test_buf, X_buf_len, &char_count) != 0 ) + { + fprintf(stderr, "Error parsing <X-hex> value\n"); + return 3; + } + + ui32_t const meg = 1024*1024; + ui32_t out_size = char_count; + byte_t X_buf[meg]; + ui32_t fill_size = rounds * 20; + assert(fill_size < meg); + Gen_FIPS_186_Value(XKey_buf, B, X_buf, fill_size); + + byte_t* test_key = &X_buf[fill_size - out_size]; + + if ( memcmp(test_key, X_test_buf, char_count) != 0 ) + { + fprintf(stderr, "Test vector value does not match:\n"); + hexdump(test_key, char_count); + return 4; + } + + return 0; +} + +// +// end rng.cpp +// diff --git a/asdcplib/src/fips-186-test-harness.pl b/asdcplib/src/fips-186-test-harness.pl new file mode 100755 index 0000000..1fb458a --- /dev/null +++ b/asdcplib/src/fips-186-test-harness.pl @@ -0,0 +1,1318 @@ +#!/usr/bin/env perl +# +# Copyright (c) 2003-2009, 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. +# +# +# +# $Id: fips-186-test-harness.pl,v 1.4 2009/10/08 15:58:16 jhurst Exp $ +# + + + +use strict; +my $rng_prog = $ARGV[0]; + +die "Expecting RNG program name as argument" unless ( -x $rng_prog ); + +my $test_count = 0; +my $rounds = 2; +my $i = 0; + +while ( my $line = <DATA> ) { + if ( $line =~ /^<MCT>/ ) { + $rounds = 10000; + next; + } + +# next if ($rounds == 2); + + if ( $line =~ /^b = (\d+)/ ) { + my $vlen = $1; + + my $XKey = <DATA>; + die if ( $XKey !~ /^XKey = (\w+)/ ); + $XKey = $1; + + my $XSeed = <DATA>; + + my $Xval = <DATA>; + die if ( $Xval !~ /^X = (\w+)/ ); + $Xval = $1; + + system("$rng_prog $rounds $vlen $XKey $Xval"); + my $ret = $?; + die "\nTest vector failure at test $test_count: r=$rounds b=$vlen k=$XKey v=$Xval ($ret)\n" if ( $ret != 0 ); + print STDERR '.'; + $test_count++; + } +} + +print STDERR "\nfound $test_count test cases\n" + + +# FIPS186_VSTGEN_XChange_Sha1.txt +__DATA__ +[Xchange - SHA1] + +COUNT = 0 +b = 160 +XKey = 8000000000000000000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = da39a3ee5e6b4b0d3255bfef95601890afd8070992d5f201dc6e0e4efff2fabad419d4bf7e41fa58 + +COUNT = 1 +b = 160 +XKey = c000000000000000000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = fccbeb651889c0c4836c2f94ebf67bbe59af0ef8f21ae5a3ff0c67ed1c578a6f1223fd2130f5638a + +COUNT = 2 +b = 160 +XKey = e000000000000000000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = b0f74533c0072c2c99d241a4c5f4c73bc396fdf247dcb245b337d3cf9531142a8f2a1d132a3b72c1 + +COUNT = 3 +b = 160 +XKey = f000000000000000000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 3f87039d81ff007b02d2a4cbf1eb28be42ad9fc3e793c4c4403c8183b7b063b1ff2a476c86a29150 + +COUNT = 4 +b = 160 +XKey = f800000000000000000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 76aae1571999ccf26fc1d8050da716fcd1d4601ed4032c82f7e5331aecca066455117e6c8eec204e + +COUNT = 5 +b = 160 +XKey = fc00000000000000000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 28de1e50400afdd50328f7d165a6664989fb8a27d952a36ea896bfcd1e3135c544194985fd436b69 + +COUNT = 6 +b = 160 +XKey = fe00000000000000000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = faf212c7824683ba4c58ea4de177714250bbbaa1b9bf77a7ccf493955f00dff8902fd8fd0af446d9 + +COUNT = 7 +b = 160 +XKey = ff00000000000000000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 3c48a3452a597b40b448ee99eef36221b91a9fc98cfc3f73c492cd2dcb4c8512d7ce16198f41d9e0 + +COUNT = 8 +b = 160 +XKey = ff80000000000000000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 02db90873dafeddd6b909280cb08ad51b7ac97782aafa0e44b2ecfbe98648fbdc70388e6c4bc138e + +COUNT = 9 +b = 160 +XKey = ffc0000000000000000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 7dcfc01746dede2322bad50d179a069a7808ab2272cd1b8a0fb3b8504ed443ce30a109a2af82abf5 + +COUNT = 10 +b = 160 +XKey = ffe0000000000000000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 290b3a3b277cccc4bc9893835b017bad8c0cf5be20ec5fbe6ca4174fbcacf1f2ce325270974e2782 + +COUNT = 11 +b = 160 +XKey = fff0000000000000000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = dc8397bfd2baad0409746d9e4c3bb0ce32b981b09b7ed6dafaa1d11f4a063d55c315572796f92a3a + +COUNT = 12 +b = 160 +XKey = fff8000000000000000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = a422b968f8864f33e73a7d248ba5e664d312796cb229e54cc63a7429da530f4df0732d2cb1f17e66 + +COUNT = 13 +b = 160 +XKey = fffc000000000000000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = dafa5baadb51bc19fa716e066ec6cfb476cf4d66ea2e3a41c0d192080efc71bbaa74e15f3671333c + +COUNT = 14 +b = 160 +XKey = fffe000000000000000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = f4107d1d55ce2f2eea18e62f36e67c6cb834072989882745f96d2b055d73aa511a72930862816a3c + +COUNT = 15 +b = 160 +XKey = ffff000000000000000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = bec44e48afa08c1ddd4d003d731eb3fa92ccfba7a22e2b34133693c520647cbdb5c67662400a78ab + +COUNT = 16 +b = 160 +XKey = ffff800000000000000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 4d74c089c13a33eb2870dd2c57baa69c8d13d9bdd086c5ed1eee776e1b405fed8187ec338ff2e404 + +COUNT = 17 +b = 160 +XKey = ffffc00000000000000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 35fd5500ed91ea2750740be274fa9819997c246d6e4568f78f0de506c7eb89a82cfd7b7a38d89752 + +COUNT = 18 +b = 160 +XKey = ffffe00000000000000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = d7f5a4bf869c4dda9967e10e15e45d713ad616e7135e579e8feec4c3295118d0f2b102ce44746d2f + +COUNT = 19 +b = 160 +XKey = fffff00000000000000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = d875ec45e85c07e11996b56fee6e7efab3f152c36092d82e4f560c907b286da58325a61900cbe98b + +COUNT = 20 +b = 160 +XKey = fffff80000000000000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 6485831589eee689e84dcb9af46aa3a124d85657ba82f2ad8cf01bcbbc75ba775366b535d7a47896 + +COUNT = 21 +b = 160 +XKey = fffffc0000000000000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 17e0dd120fa8cb7a16eb17228270e338f37b158ea22c0c486d4b1992d6d5f20636ca838271805440 + +COUNT = 22 +b = 160 +XKey = fffffe0000000000000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 919d8d62befb49c68520c5a458b00d0577033f47b6ac4fe8b8abf3d9991696bc6fe213960c645a42 + +COUNT = 23 +b = 160 +XKey = ffffff0000000000000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 56e2e117e2c73527e3971c9d3bffb5379cef75d157f93aff7b051dd7fdd8611666689a3e3526c0ce + +COUNT = 24 +b = 160 +XKey = ffffff8000000000000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = fcf9e6f9bfc8cf6d46c760ed213331594d95a895c47beeeaa4b7129ca8c4b249e477a46af5e16ac9 + +COUNT = 25 +b = 160 +XKey = ffffffc000000000000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = e01170df33061c4cb1d123fb0a9e186af468a87696ea8e48f5f1697e51595f58d1e6e7e3440f1407 + +COUNT = 26 +b = 160 +XKey = ffffffe000000000000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 936940fd12fc688855f8a6d0be2722e4294bb0d0af94aa51b0a2f0d93f080daeaf9bfcd8f4c01e82 + +COUNT = 27 +b = 160 +XKey = fffffff000000000000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 6e0abd8f57f876296a237fc17b2181a5bbe0d6e82a7a36d59c9a68e13e40e9e8136d4c0ccf0acd6b + +COUNT = 28 +b = 160 +XKey = fffffff800000000000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = dd7de50650bbd6b86e88eba9ea428f0a2b340cc0a361f0053cd1447a4c9d4d5e2d42f114d033eafe + +COUNT = 29 +b = 160 +XKey = fffffffc00000000000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 52bb6338b2b72fd29167b40caa34123232f770ab7808cfe6f3cb148502d89ff5a80b4ac0778faaeb + +COUNT = 30 +b = 160 +XKey = fffffffe00000000000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = ae017f7b0e253701216941e1c9d7821f077bfdc3bcd4a02603a2d63d1849072801d78482fa84dc50 + +COUNT = 31 +b = 160 +XKey = ffffffff00000000000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 6bca6679907d54bd1254ee87ded30591305d436c2f552f28f4ec1f7fbac29a25c3dcb7e630cc41e1 + +COUNT = 32 +b = 160 +XKey = ffffffff80000000000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 72253fe10d13536bc715464d28ae70cd8dcea9451e6140ee837caddb81de309497e7f95d0fcf09d6 + +COUNT = 33 +b = 160 +XKey = ffffffffc0000000000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 5784b0627abe62043f7b9fb08e54eaf067c7c6a8f8dbcae34dcd15a7f9bf9b52fef7ff90b792a8f8 + +COUNT = 34 +b = 160 +XKey = ffffffffe0000000000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 815abfe389de4cb500ea789dd04042f81817fcae3d7a9fbb50b251676653ef671eb29f47cce6ff65 + +COUNT = 35 +b = 160 +XKey = fffffffff0000000000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 3152b9db05fb216edc61782d254a38533988200d02b72cf15cd4404f7e9f4f823544e693889ea3ca + +COUNT = 36 +b = 160 +XKey = fffffffff8000000000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 1158d881597e94db9cdfb79997a571740ae24386dcb0cbafe2e20d2b6cca811a98dc0ebb65028296 + +COUNT = 37 +b = 160 +XKey = fffffffffc000000000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 7a252c33152e04374a51c36a8ff386a9125983993d0bfaa073738384128969404434b3ad3badf8dc + +COUNT = 38 +b = 160 +XKey = fffffffffe000000000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = f22ee43a5dafca77e87b0d2eb6fe202ce0fcc83da391d6a9ca5cd6865744256866d09531ccd9c1a9 + +COUNT = 39 +b = 160 +XKey = ffffffffff000000000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = ac6fffbb332e9e733de0f3a85404e22d0c9c53cfc2226a3cb08df3747e541904d9909f05d5932cee + +COUNT = 40 +b = 160 +XKey = ffffffffff800000000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 909649b02d9bbf2da624a40a4c5dcec233e58f41ffc0d1b8c0810a1cce89f25cebf40d576f27b808 + +COUNT = 41 +b = 160 +XKey = ffffffffffc00000000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 7328500ca54c4fb9eddf8e3ecf2e851b0f8821ac5f1823e77dd73e8cb2e4727ba9e7f2de71737c0c + +COUNT = 42 +b = 160 +XKey = ffffffffffe00000000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 2bf06c06d4c1c11276718320c886c74dabb7fd92ccf743e2023909a6d33ff8a42a56f8879804219e + +COUNT = 43 +b = 160 +XKey = fffffffffff00000000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = a812af3c2f0ee5615688b966b8885e75a7c76be5e5c9518347f6f23475ed601f556f50a253f64463 + +COUNT = 44 +b = 160 +XKey = fffffffffff80000000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = d9e4f7719a31e05bc6f07779b4eed313c94346d6a1485c5847f0e7ed5dbd8bf5c4e5ea847207739b + +COUNT = 45 +b = 160 +XKey = fffffffffffc0000000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 4b3f3951c0eac34ee8562fb4b7f2d5e7787b0ba705ba474fc13ec9d99f7877ad4b934d7111ee1ccc + +COUNT = 46 +b = 160 +XKey = fffffffffffe0000000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 41212672a59e2f50dc0e55107df6fe6e1a6f0806012517058efa8678e1b5709579aeff58d4523a1f + +COUNT = 47 +b = 160 +XKey = ffffffffffff0000000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = d279d878c380f846f5790f32881f689d3463ef4f577c7bedb83dcdae06aeefe0acf28bc6abc398d6 + +COUNT = 48 +b = 160 +XKey = ffffffffffff8000000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = cc2adbd3e9389f19a44bc74585c926de5383f0aaf7591019deffb70cf2106934a09b7c3bb7d36a57 + +COUNT = 49 +b = 160 +XKey = ffffffffffffc000000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = aab87ca3ecfd8b84cf2a804d7dfd79f181657c6660e1cffaf9bce87899064b9ef85f4d4edd5b9c97 + +COUNT = 50 +b = 160 +XKey = ffffffffffffe000000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = d05170a4077035b188e903decf7cd0c8d738c65ebf3d345962da2e10cc480a0e6dac962e784437ea + +COUNT = 51 +b = 160 +XKey = fffffffffffff000000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = df094f91e6e721f7f5c8920cc8699d50d6d2e26677e0595f7ed1fbec275013d9eaec9f8ff0192eba + +COUNT = 52 +b = 160 +XKey = fffffffffffff800000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 840b7bf475412aec0ed426bfc95dbff1dfb3c01993744a1cd5cd57ee1c72157c4576f6fc868e4d67 + +COUNT = 53 +b = 160 +XKey = fffffffffffffc00000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 081c963bfa542131e47a6f824702c81d036170c059d320a7347371e92e8019b0a5a6b674626d1e91 + +COUNT = 54 +b = 160 +XKey = fffffffffffffe00000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 68f04715ea256ee6e48c02d2916a1488d40ec866e1d6a5add4abaef3b8323e62b6693514f14c3db7 + +COUNT = 55 +b = 160 +XKey = ffffffffffffff00000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = d3d213d73d9738b9179949641a17cd7a2e4866623e01941575430a978c5edf326cd5215b3bd74e30 + +COUNT = 56 +b = 160 +XKey = ffffffffffffff80000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 68c5582035c3644249e3412eb70336617bc4a593850312fed7a20d25115d1f001f9abbfd118c7753 + +COUNT = 57 +b = 160 +XKey = ffffffffffffffc0000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 12d6de348e76dd0f6380b13bd88d43ea2d5b7c443d794a3fb7758590a1dfa5f34cd9dfff104cbbf5 + +COUNT = 58 +b = 160 +XKey = ffffffffffffffe0000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = a9f1c1cad88416a12c6108de1971198fbd6057f3efe49495894a4e2a69a5ea8714cb3a57b37b93ac + +COUNT = 59 +b = 160 +XKey = fffffffffffffff0000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 789e072cc3185a627d92945339bb1950e915e989dc1490d2b59a054ca1c20017c1bee4aaf9757b5f + +COUNT = 60 +b = 160 +XKey = fffffffffffffff8000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 5509de87994a508680b545fa58aab69cb142f2badf1021645e7430d02cdf6111b0afe66cb7678af0 + +COUNT = 61 +b = 160 +XKey = fffffffffffffffc000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 802cae54caf47f45d5ab352f10cd47774a5895bf29b60f2bb7d20da67d2ee5943de44ddda445367c + +COUNT = 62 +b = 160 +XKey = fffffffffffffffe000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 18001b828028eb44228fa7421cceaba5e12b4feb1ad7c57483d64c39d5d99f737002be9f13162c89 + +COUNT = 63 +b = 160 +XKey = ffffffffffffffff000000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = cb8128e1cbc093306b23da2814d1265dd0d2f9774dd164f011e4fedc044c308b8800057c18ab5a4e + +COUNT = 64 +b = 160 +XKey = ffffffffffffffff800000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = d7aec22fb3704dd2ddc721c4d715630a400a15fd192cd7e3627387b47b58fc39d5be4064822b3aad + +COUNT = 65 +b = 160 +XKey = ffffffffffffffffc00000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 45e7933ada2666ca8cd76e4778f290bf41378c217e0286bb1e95ee2f2f7c1eb698248e821b4a0656 + +COUNT = 66 +b = 160 +XKey = ffffffffffffffffe00000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 9eba05157ea9936e6521eb5807b0026c8542d607ea8bce39861123448752f40b4d2fc456d53c34f4 + +COUNT = 67 +b = 160 +XKey = fffffffffffffffff00000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 07b692581741a1e7ee37425c524b1d82662e46b155889af1b444290e586edba269f0f38042ebe9b5 + +COUNT = 68 +b = 160 +XKey = fffffffffffffffff80000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = c71b439ca40ac57e1ec5d9ad4383ee8b61d370b5807590d7fdbfdca963f1b1d4b29092cbb598d1f6 + +COUNT = 69 +b = 160 +XKey = fffffffffffffffffc0000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 3b49c50cd7d319774f91275892f751d1c3bc50a38fb3ee13955c718d67c917307a8888dbd1f55339 + +COUNT = 70 +b = 160 +XKey = fffffffffffffffffe0000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = aece9cdcd70b4f65d63c9c2d10a612ac4f24725d0111932147bddee3436d37d15b7354240685bdee + +COUNT = 71 +b = 160 +XKey = ffffffffffffffffff0000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = ac4b24ba0c7976303566e2a0a51959849958db04a001d82153acd09e33ee71efebe458c4f9543119 + +COUNT = 72 +b = 160 +XKey = ffffffffffffffffff8000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 495660a402a40de3f1375ae40e076c7c2aa044287d9930572bb6b13ce419f22a6bf9ae63fd603b3a + +COUNT = 73 +b = 160 +XKey = ffffffffffffffffffc000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = d985a58306469ecc0651d039ac8610fc9e71ccd4cdf9c6d1715c4197850e11e39bd27e2ec49801d4 + +COUNT = 74 +b = 160 +XKey = ffffffffffffffffffe000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 42aa31de6a5ce807b14c2e3ad91d91589119da04103cfc7c94860eebe6b4bcae6ba069033c0366ad + +COUNT = 75 +b = 160 +XKey = fffffffffffffffffff000000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 6e8cb43e720c5533ba5fc017c4df8c6f278f2dad63ae8154a2720e077cf423b995c835b068e27fa5 + +COUNT = 76 +b = 160 +XKey = fffffffffffffffffff800000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = d038ba69be6edad3cb10e5ef9638214e4da3aa23571c1fd2ce9d56b294ab48738339876367af37c1 + +COUNT = 77 +b = 160 +XKey = fffffffffffffffffffc00000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = d0404a3aa63f64da9dd9ac380b6610a7a49c0e342f98bdc235fb6055ff3d786602bf62cdd8add78e + +COUNT = 78 +b = 160 +XKey = fffffffffffffffffffe00000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = be00ae42cbaf9b94b803549533607a0f69154c0008d2de3b583b2616c74b36566ae767ff34b86654 + +COUNT = 79 +b = 160 +XKey = ffffffffffffffffffff00000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 2f02675d18bc26297f4368b634e1ebdf2c5ab677e84f33d437481adebdc5e7bfc556fe6f45072c6a + +COUNT = 80 +b = 160 +XKey = ffffffffffffffffffff80000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = f633f34bb5166cebfecde2295ce7648dec442ff159765c7a86332beb46f7842133f5a3ed6960a3f0 + +COUNT = 81 +b = 160 +XKey = ffffffffffffffffffffc0000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = fdd3881997edbedfe956fc8a013afd072a73c70bbb31390a0fd756b7337863b43fd820ae4e257180 + +COUNT = 82 +b = 160 +XKey = ffffffffffffffffffffe0000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 7d5b95d8bd5db5df0b91df0edb1f287118a57d459b94a90a6e1a0524fd141be752e802c5c6f5fa61 + +COUNT = 83 +b = 160 +XKey = fffffffffffffffffffff0000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = bf8d570e5f9299df9dd93db0c809ff6bfbb35481e2283705a9676727a84d02e2b8883828a05f1bdc + +COUNT = 84 +b = 160 +XKey = fffffffffffffffffffff8000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = bdcabf104dfec16b2a484df9596abda1d4b72afcf8cee6bf749c4bc0c124df9b29b11785d487d54f + +COUNT = 85 +b = 160 +XKey = fffffffffffffffffffffc000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 79d4b08aa8efc652f2f81a5f58d1af456806686fe495d25db5ed36dd034d3e71eb0fcb35d7b0b903 + +COUNT = 86 +b = 160 +XKey = fffffffffffffffffffffe000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = a8d1aef1f8cf16a0c6dbe31542ca390e77bc5be962c1e7cbfb0ef37196b95236b8e105b96da055de + +COUNT = 87 +b = 160 +XKey = ffffffffffffffffffffff000000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 13df68dd0de319394623acd11181384072c2b120a6dc9f090faeaa03484d0862e50cbd2502d963c6 + +COUNT = 88 +b = 160 +XKey = ffffffffffffffffffffff800000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 07cc9dbedb074f9ecce0e3ea54f59d943f57c4fa4909c59e7b2c513f77d4b7c0c30d10bb77e0617f + +COUNT = 89 +b = 160 +XKey = ffffffffffffffffffffffc00000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 6b5da347070676406474673f0ca9ca10624f01d965cbdf2975442fc134c0c50ef1bf2ae000ec67a5 + +COUNT = 90 +b = 160 +XKey = ffffffffffffffffffffffe00000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 3dec2b91ba61d60714bba70628413436e238fb0ca9178e7b50ffcadeeb1c3c72536b90ea2d2ce965 + +COUNT = 91 +b = 160 +XKey = fffffffffffffffffffffff00000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = f69d9a2891892b60cfeb504f17fb6ee0a30cbee1cb27802af04191e8386e7a0f612f2bd4d6665f3b + +COUNT = 92 +b = 160 +XKey = fffffffffffffffffffffff80000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 4f78f5e39217be13e1d57aa3f4d55e5955a8ef5c5a98e8e02fb7807b4a885c2de8f64bbb42390302 + +COUNT = 93 +b = 160 +XKey = fffffffffffffffffffffffc0000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = df5c9790c61dde09a272c5c5f5c78e867b10a2e0e18ed67114e130c3af1442d3fe13c53e3072ac60 + +COUNT = 94 +b = 160 +XKey = fffffffffffffffffffffffe0000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = ce06588dccb3d9b8fd40076e57c29bc22d90bd4d56676d8dad83d750be12da19b3a7fea0dde986f4 + +COUNT = 95 +b = 160 +XKey = ffffffffffffffffffffffff0000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = afca72d4d8eeac89452c2d8240611385de4dd1d05d9db6a1b1d0e7df7fa49075c44fd3df0a8f4797 + +COUNT = 96 +b = 160 +XKey = ffffffffffffffffffffffff8000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 65d921596731fb52bc87a79d8996475530015bbd3fb24e206cffb17f8cb92a20cbb434cc13aafbd4 + +COUNT = 97 +b = 160 +XKey = ffffffffffffffffffffffffc000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 3ff9c54cc76869bd329ea6fe65935e036900e82df945466a0875379c065121fc5e5620a51adb48bb + +COUNT = 98 +b = 160 +XKey = ffffffffffffffffffffffffe000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = c30a129ddf99ca2ddf8aa065607facbcf86b3b9382cf694fdcb2f55321a52c87c7ab0d701fcf0ab9 + +COUNT = 99 +b = 160 +XKey = fffffffffffffffffffffffff000000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = c81cb8b066027949826b69b919960c0096e0e9f2eeb9e53d2acbd3b40a92470a5665d31582a38b93 + +COUNT = 100 +b = 160 +XKey = fffffffffffffffffffffffff800000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = eba40737de37c4fb7f9931fd455bc6c32a184dd44f524c7dd9681ba0b995df8d7fe461c5df6c3c2b + +COUNT = 101 +b = 160 +XKey = fffffffffffffffffffffffffc00000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 4d4d5aa335b046fcdf9ea069e938f9b662f22286a6a9146296843a0579c5ce81f338517cd7baef4e + +COUNT = 102 +b = 160 +XKey = fffffffffffffffffffffffffe00000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 885b0b6662bc6a1315020e801f4b0400e202fae240441a93e3aa4117745ecb7cd870a77b5fec12f6 + +COUNT = 103 +b = 160 +XKey = ffffffffffffffffffffffffff00000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = d27612b331bf2ebd86c6b018020a284d58dbbd8a90216cdc7d5292c8d69361d19bdfe54da83ff0a8 + +COUNT = 104 +b = 160 +XKey = ffffffffffffffffffffffffff80000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 77fc40d4b1690236b746fdca741541467344caa0715ce6d2abeb8288a3913499e82425717a013d5c + +COUNT = 105 +b = 160 +XKey = ffffffffffffffffffffffffffc0000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = ff32e03b70d7bd9786dc0515cfca1e0f94bee4f22cceead4066accae3d9ee320aeca667367a84acb + +COUNT = 106 +b = 160 +XKey = ffffffffffffffffffffffffffe0000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = e66d2df35bfd3e697069825d96d9d60d113c032f2f772136624475e024f18c5e14b3172155307af3 + +COUNT = 107 +b = 160 +XKey = fffffffffffffffffffffffffff0000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 1c903f71d11d598fe1bf4a79e98b7e7d5d1cb3f700dd7a1dd476ae9bb3d49ec940f56ea03a22659c + +COUNT = 108 +b = 160 +XKey = fffffffffffffffffffffffffff8000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 074c8a6168c9c7df3a87bc57f6eb23251ba7052049ac327af36b12fdbaa4b4b055bc8d680cb8d3f9 + +COUNT = 109 +b = 160 +XKey = fffffffffffffffffffffffffffc000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 8534b835c335c2866bf8e5ddf686c6d4a2a1d4802454314f1e1eedad06355a3c6b39b44c3aa7ecc9 + +COUNT = 110 +b = 160 +XKey = fffffffffffffffffffffffffffe000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 6adcebdf6badfdbaf3675ae97d7da3da4d4a93122c7da68c74f19d3404f143e8c8f7cfb74bbd6415 + +COUNT = 111 +b = 160 +XKey = ffffffffffffffffffffffffffff000000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 8fc7605166aeed6c1d9795bb5aff9a44c6aba7dfca1b0d8b101c78fdc7e3bfd65f4076ca600c1288 + +COUNT = 112 +b = 160 +XKey = ffffffffffffffffffffffffffff800000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 52798b5b8df1b2bfa466713b346961906c210b0bbc40e5b7a62bb4c70ae41a9447b224537ddd14de + +COUNT = 113 +b = 160 +XKey = ffffffffffffffffffffffffffffc00000000000 +XSeed = 0000000000000000000000000000000000000000 +X = a0f58dafbc95601dd59de0dd47cadfe1ea34e9925ba468099308a9450fb52c97db57b4214e58bdce + +COUNT = 114 +b = 160 +XKey = ffffffffffffffffffffffffffffe00000000000 +XSeed = 0000000000000000000000000000000000000000 +X = e19df3f756485974d6381865503eaba161c90d0cecfa163e27fffd5248d31f5bb7a1b92a862b3ad3 + +COUNT = 115 +b = 160 +XKey = fffffffffffffffffffffffffffff00000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 35c284d7dcb6d6623ea34be1371db0b325b3920564e55828a288be312d610666af76f44254964077 + +COUNT = 116 +b = 160 +XKey = fffffffffffffffffffffffffffff80000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 989ce65ed122d1405de7a57664f7ac705cb9b5aaed3b6f05e227229c23c575c4b18e88335eb2c81a + +COUNT = 117 +b = 160 +XKey = fffffffffffffffffffffffffffffc0000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 05d73bc99c91150aa39840544b5bd3b46251bbced56f79000c63f0166d0ca62ed4b9cd3b17afc68b + +COUNT = 118 +b = 160 +XKey = fffffffffffffffffffffffffffffe0000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 758355389548decb4d674f76b286cdfc71f85b7169be18b6b7ac546847056f2a9c9f096dffb27afc + +COUNT = 119 +b = 160 +XKey = ffffffffffffffffffffffffffffff0000000000 +XSeed = 0000000000000000000000000000000000000000 +X = da754c2f1101e44c12a64ce93d7e038531c114df55ce1b0ef8d213ad6f2f43d210e91e1a93f655bf + +COUNT = 120 +b = 160 +XKey = ffffffffffffffffffffffffffffff8000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 2ff3dc5be596d44376eba1b07c8a0048f66d2782b0a1340d919ce12b5dbf2f36c7ce543c55a24dea + +COUNT = 121 +b = 160 +XKey = ffffffffffffffffffffffffffffffc000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 75e6528a68783de77204a15162f84d71f180abba9d9a8e6d239531595f028a116ec0e2c835675762 + +COUNT = 122 +b = 160 +XKey = ffffffffffffffffffffffffffffffe000000000 +XSeed = 0000000000000000000000000000000000000000 +X = 0a1a7503b77852574e366b0117eb3861e8515dfbb3d2dd9fb374146930c4d25590214777c782e203 + +COUNT = 123 +b = 160 +XKey = fffffffffffffffffffffffffffffff000000000 +XSeed = 0000000000000000000000000000000000000000 +X = bc36f8b79d84ab9263f87eaed6252f6bca8fe8df30c91e9427fe4d3d41842460c7a3450c2f300045 + +COUNT = 124 +b = 160 +XKey = fffffffffffffffffffffffffffffff800000000 +XSeed = 0000000000000000000000000000000000000000 +X = 0d824e023491df1aabaeb6737dd61d5aed1b2c874dfda9d4a5b84acd3176e132dd6c29bc47c125f8 + +COUNT = 125 +b = 160 +XKey = fffffffffffffffffffffffffffffffc00000000 +XSeed = 0000000000000000000000000000000000000000 +X = 512664fb393f2b5621292dd26815a78d220847fa1ea1ce8935a07da2e1b12e7299c24b806f24d431 + +COUNT = 126 +b = 160 +XKey = fffffffffffffffffffffffffffffffe00000000 +XSeed = 0000000000000000000000000000000000000000 +X = 950f07a99423ef6afef65ee6da5afc9689f4ad74ce4c86a684398596230f42aee9ad7a185c335347 + +COUNT = 127 +b = 160 +XKey = ffffffffffffffffffffffffffffffff00000000 +XSeed = 0000000000000000000000000000000000000000 +X = 411e11e04b566e3b991613ac2fc1937ca252a7430d18d62106b6088e384a9df4740aca77e822d484 + +COUNT = 128 +b = 160 +XKey = ffffffffffffffffffffffffffffffff80000000 +XSeed = 0000000000000000000000000000000000000000 +X = 7f7aaa087a285980a31c1db915b6bb499e1d9d0a8bdc7f7cbec229a634d9d1a90ca57dcc2fa70f21 + +COUNT = 129 +b = 160 +XKey = ffffffffffffffffffffffffffffffffc0000000 +XSeed = 0000000000000000000000000000000000000000 +X = d3d39e0f1128aca1a6d509730d6eb42cadaf249fc287351728912d33ab57a6665db1b96ebceddd19 + +COUNT = 130 +b = 160 +XKey = ffffffffffffffffffffffffffffffffe0000000 +XSeed = 0000000000000000000000000000000000000000 +X = 3ac0800d44e2f327fdcbd61cdcd7075afce0676f04526a0d0fa9617d8e243ea592af8092db30f5d6 + +COUNT = 131 +b = 160 +XKey = fffffffffffffffffffffffffffffffff0000000 +XSeed = 0000000000000000000000000000000000000000 +X = e742ad48abc285207e067251344b1c68155dab1d59d2c0b1210e1cfae4a5f27ae29d3d9515ec5d11 + +COUNT = 132 +b = 160 +XKey = fffffffffffffffffffffffffffffffff8000000 +XSeed = 0000000000000000000000000000000000000000 +X = b32b0cc4e26f0bcc19ba1aa95533a816d362389af8f81600805c0647d5d8cd64f43d85090e0d200a + +COUNT = 133 +b = 160 +XKey = fffffffffffffffffffffffffffffffffc000000 +XSeed = 0000000000000000000000000000000000000000 +X = 30e347b89c94e6ab2baaadc98f299b24b00ddc8a615def35bfd9194cedbd64d6e924a9ff7a06f33a + +COUNT = 134 +b = 160 +XKey = fffffffffffffffffffffffffffffffffe000000 +XSeed = 0000000000000000000000000000000000000000 +X = c32afe8f42a86036e221607635baa6cbcaf3aeda185a17ba1af4707a84977edfb73e42c3d731f3a5 + +COUNT = 135 +b = 160 +XKey = ffffffffffffffffffffffffffffffffff000000 +XSeed = 0000000000000000000000000000000000000000 +X = f6f062e0f58342e472de9f624373541656b77cacebf5a2db800646f03ede6316a08985f95d554d17 + +COUNT = 136 +b = 160 +XKey = ffffffffffffffffffffffffffffffffff800000 +XSeed = 0000000000000000000000000000000000000000 +X = d5a9fec94ed0a7840d9d93d1978c89bbdefff4524a091f4dc4ef6834f787ba5dcccd20b6a22c945f + +COUNT = 137 +b = 160 +XKey = ffffffffffffffffffffffffffffffffffc00000 +XSeed = 0000000000000000000000000000000000000000 +X = 8a0bc648ba06d5d56f77e31610f41808fce53b436b8b2016c7d788aed7c832c7672d7edad73c75b4 + +COUNT = 138 +b = 160 +XKey = ffffffffffffffffffffffffffffffffffe00000 +XSeed = 0000000000000000000000000000000000000000 +X = 90f3cfc64efc79e0acc670373a89960800775edac7d130c5f80c0bdc7f393fbc898deae1032d5de1 + +COUNT = 139 +b = 160 +XKey = fffffffffffffffffffffffffffffffffff00000 +XSeed = 0000000000000000000000000000000000000000 +X = 182b43626fb350fb68ecdb2e7e468d2297e0faf86b79954c04c253f9aebc8e24837b0a3098bcd501 + +COUNT = 140 +b = 160 +XKey = fffffffffffffffffffffffffffffffffff80000 +XSeed = 0000000000000000000000000000000000000000 +X = f2142110ad487a61e4284154ad9326f7bb21496f6759340d991c96df76648d82e7f9939304d10f3f + +COUNT = 141 +b = 160 +XKey = fffffffffffffffffffffffffffffffffffc0000 +XSeed = 0000000000000000000000000000000000000000 +X = 1175fd3fc41d7339a3003087664c97569a8c230b148a898071b3cbe97e5a285249bfae8a1b4d5535 + +COUNT = 142 +b = 160 +XKey = fffffffffffffffffffffffffffffffffffe0000 +XSeed = 0000000000000000000000000000000000000000 +X = 95942d02ee8f3dd6a341e393d977a90d9d0ef6c3e365ecde89fedecd0219698f4de70d37d939d07e + +COUNT = 143 +b = 160 +XKey = ffffffffffffffffffffffffffffffffffff0000 +XSeed = 0000000000000000000000000000000000000000 +X = dc3d4ab9764f3e7b25784c64c22452c03dabd02ca03c1f871dd8c5ebcf525e9946a2c1d5d259de01 + +COUNT = 144 +b = 160 +XKey = ffffffffffffffffffffffffffffffffffff8000 +XSeed = 0000000000000000000000000000000000000000 +X = cf11ac36a96972cdbb7f35150dd344e4d1341325ee4a44ff09bd9c53108998b5d04b5f07f2bd5300 + +COUNT = 145 +b = 160 +XKey = ffffffffffffffffffffffffffffffffffffc000 +XSeed = 0000000000000000000000000000000000000000 +X = 5fe0bd81f1801a3ffa3d3e493075d4120c952f53cca22cbd803abe278f9fdb124502de6066021ad0 + +COUNT = 146 +b = 160 +XKey = ffffffffffffffffffffffffffffffffffffe000 +XSeed = 0000000000000000000000000000000000000000 +X = 7859276d44f3a10f844010a375d3eb078e443d28da1de77d77dc3cfe79739027c8f448952df50b76 + +COUNT = 147 +b = 160 +XKey = fffffffffffffffffffffffffffffffffffff000 +XSeed = 0000000000000000000000000000000000000000 +X = b6f311fce947d8de23b678566ca64cddc3404c1da4a888c3b19781d904b437534d397307e6f6d41b + +COUNT = 148 +b = 160 +XKey = fffffffffffffffffffffffffffffffffffff800 +XSeed = 0000000000000000000000000000000000000000 +X = 7af5b5e370d5be661bdd57cdfb81b2aa165ec0e47cec20bddfcaf0fc48711c1d12530e3b5b439cb1 + +COUNT = 149 +b = 160 +XKey = fffffffffffffffffffffffffffffffffffffc00 +XSeed = 0000000000000000000000000000000000000000 +X = 2a738e1979d44cb91c43734026208d39bc20e48cabfa98d32debed67ac44349ef7def37d69a59ab2 + +COUNT = 150 +b = 160 +XKey = fffffffffffffffffffffffffffffffffffffe00 +XSeed = 0000000000000000000000000000000000000000 +X = a660765d616ba5b347c6ed86a7009c42ffd9f746f0ab945b21ec5e4a65de2866f89534aed10fb5f8 + +COUNT = 151 +b = 160 +XKey = ffffffffffffffffffffffffffffffffffffff00 +XSeed = 0000000000000000000000000000000000000000 +X = 71cd5ad24edfaeacc9daa6b7670e449b52e0766e2a86db40ecf512883ed1d3d28e1bb6b8dc763c9e + +COUNT = 152 +b = 160 +XKey = ffffffffffffffffffffffffffffffffffffff80 +XSeed = 0000000000000000000000000000000000000000 +X = 42f628ec7de1c6f7a2a08232512d8369fbc79d1d9211928ad40bd0fee4fcd0b27099ea868024f97c + +COUNT = 153 +b = 160 +XKey = ffffffffffffffffffffffffffffffffffffffc0 +XSeed = 0000000000000000000000000000000000000000 +X = e02365404191d8469d5e3022921027f0d27aa372f3d76956b261390f3f880f2fa32a8440a5301c82 + +COUNT = 154 +b = 160 +XKey = ffffffffffffffffffffffffffffffffffffffe0 +XSeed = 0000000000000000000000000000000000000000 +X = 439347cebc1782cc675e2bc25c0cacafe2d3a1b40305f10889ee9cdb4c58ef68d970e94b08556636 + +COUNT = 155 +b = 160 +XKey = fffffffffffffffffffffffffffffffffffffff0 +XSeed = 0000000000000000000000000000000000000000 +X = 59626e8b9318c3c9f46e1a8fac4693faca8ee1ea548a98ab441c6c088ddb58b03d2b5a69708bc26d + +COUNT = 156 +b = 160 +XKey = fffffffffffffffffffffffffffffffffffffff8 +XSeed = 0000000000000000000000000000000000000000 +X = ffd98581d37523fbc53de4a87d5abe516420343f62277bfc3956607d759e63dd89728ef434dc902d + +COUNT = 157 +b = 160 +XKey = fffffffffffffffffffffffffffffffffffffffc +XSeed = 0000000000000000000000000000000000000000 +X = 624048e1eeb7325f7e3251da67f79341bdbd00b0005951d0fec9b327eeb5ff178a7f502d8f57c42b + +COUNT = 158 +b = 160 +XKey = fffffffffffffffffffffffffffffffffffffffe +XSeed = 0000000000000000000000000000000000000000 +X = 089fc77cf8929c246fcee00b92c27676cca08e7598a1213777c0cda53c7016b09667e974f4b1173b + +COUNT = 159 +b = 160 +XKey = ffffffffffffffffffffffffffffffffffffffff +XSeed = 0000000000000000000000000000000000000000 +X = ce8dd97eb53de8b8997d71af15eed31ffc822deb269cb566a0a9645811a3d9c977c5d8fbe8ddf6bb + +# CAVS 5.0 +# "FIPS 186 - General Purpose" information for "rngtestvalues" +# Generators selected: Xorg Xchange +# G-Functions selected: SHA-1 DES +# Generated on Wed Feb 08 15:20:53 2006 + +<MCT> +[Xorg - SHA1] + +COUNT = 0 +b = 160 +XKey = 1c670cfd3b421f21fdb0f3885a204eb659ca9740 +XSeed = 0000000000000000000000000000000000000000 +X = e5121116d1a99e62902ffd279261500e0e16b0f3 + +COUNT = 1 +b = 168 +XKey = d87f639afea75ba44bbc6bd0fb5ac84a12c2c6ed95 +XSeed = 000000000000000000000000000000000000000000 +X = 09328f082e48135784d39f9f0ec67911ef708788 + +COUNT = 2 +b = 176 +XKey = f0ecfa38f93823dcf6c918432d1d72731f02d74cbafa +XSeed = 00000000000000000000000000000000000000000000 +X = 1675536299b8a05236cc460944e691e952adbb80 + +COUNT = 3 +b = 184 +XKey = 574508895ccfdcf4a1ad8284ad94eb3321f5d1a4a6244b +XSeed = 0000000000000000000000000000000000000000000000 +X = f90c11ae695df29ae707a187a2eeeea92dcbd84b + +COUNT = 4 +b = 192 +XKey = 6e9d90254b9534d3ae680c9ab38d434114a58715fd00758b +XSeed = 000000000000000000000000000000000000000000000000 +X = d562e8d50a86de701d6fb076a378282bae721849 + +COUNT = 5 +b = 200 +XKey = 3477f6949b5278183169e9decf0010e683be87afe3b1b357a1 +XSeed = 00000000000000000000000000000000000000000000000000 +X = d954bc9c0537484f8ec13f4dde1905e3441dbac0 + +COUNT = 6 +b = 208 +XKey = 533acb38c61100b152c326c7b4ea027df73b07c94309ca3cf60a +XSeed = 0000000000000000000000000000000000000000000000000000 +X = 14b266d8c1fd4871104dd4f91c6d6d15c8e76c37 + +COUNT = 7 +b = 216 +XKey = 21392b55c4e3af82523cdf81eaf1868055bd3e3ea18236c30b9833 +XSeed = 000000000000000000000000000000000000000000000000000000 +X = 7318576beb22084349f749d7ca615f1333f6bff4 + +COUNT = 8 +b = 224 +XKey = b33ba749e3057b7a8aa61f3c78771655710157323bc1fecef62842d5 +XSeed = 00000000000000000000000000000000000000000000000000000000 +X = a24fa133c2e5ae5a2378af37e6097e1b5f503dd0 + +COUNT = 9 +b = 232 +XKey = 2c685c7482c85777d9de02ee550fc2f5aa0e0f76319f27043ba10407a5 +XSeed = 0000000000000000000000000000000000000000000000000000000000 +X = fceae60fcdda5782a43916d23c133d4aa59588f9 + +COUNT = 10 +b = 240 +XKey = aaa6e9a6525a0dbebf306a487f168bb31411ac5b3d761e5b775deda2c253 +XSeed = 000000000000000000000000000000000000000000000000000000000000 +X = c87d4f6f1dfff1c7c0517a3ba478ea3db40c915d + +COUNT = 11 +b = 248 +XKey = 5061d23eb06b7844fcad7e0b55d6abd6455775cca2bc0cf1b53d9a559c90c9 +XSeed = 00000000000000000000000000000000000000000000000000000000000000 +X = 96116ca45240c44249b8265d736572a3555d4bd8 + +COUNT = 12 +b = 256 +XKey = b436c1e06d76015c85d145cfb2f513f2dbffa7682b3ea09f6539f8f777f33926 +XSeed = 0000000000000000000000000000000000000000000000000000000000000000 +X = 8123d23bdb6379a8383a25fda023af25ec0dd8d0 + +COUNT = 13 +b = 264 +XKey = b6fb9e128dc5985f3a49ab84ee0336f8954318a9b681bbef9bf052beb3555e2134 +XSeed = 000000000000000000000000000000000000000000000000000000000000000000 +X = dcbd4dc592d2eadff08c532614ae28c030e9b60c + +COUNT = 14 +b = 272 +XKey = fe9e57d121e2bd431c41f1f757d2bd5b141c98daa47e795fdbcfed15c14168728a8b +XSeed = 00000000000000000000000000000000000000000000000000000000000000000000 +X = 1945ac66fd792852da50b72e33bac69ed3ce9bbd + +COUNT = 15 +b = 280 +XKey = 635debc0f6a35bea4b6de3db176b06600370d9840375feb1e3e1d6172308f35104f1cc +XSeed = 0000000000000000000000000000000000000000000000000000000000000000000000 +X = 72b363e7676288180c41d42a0934714c745bdbb0 + +COUNT = 16 +b = 288 +XKey = 66682eeb3ba396a7654d5e3e1230376d9c8d710f00bb13e493112a92f00661e93597d26b +XSeed = 000000000000000000000000000000000000000000000000000000000000000000000000 +X = 1d7d5a287a2198fc2ed407838521c6be1d7cd11d + +COUNT = 17 +b = 296 +XKey = 575289a193c212b874e690bf22d807b568c63a66b9eaccf871bca5c05e66975a7f7841f80b +XSeed = 00000000000000000000000000000000000000000000000000000000000000000000000000 +X = 5c9f11ba4939c6ce67bdc0c35aaa418151b0b9d0 + +COUNT = 18 +b = 304 +XKey = 6df2a963884ec9a615e398d010cc91026060845b01c0de2362ac2b490c9bd910850a3f057414 +XSeed = 0000000000000000000000000000000000000000000000000000000000000000000000000000 +X = 6a244d9944384feb512d4e080d308096ddfe8066 + +COUNT = 19 +b = 312 +XKey = 2c4b6df63cb790996f0c032657e608a76b2af9d9ff30df77732841bbaab63a23bde0ce71f12a7e +XSeed = 000000000000000000000000000000000000000000000000000000000000000000000000000000 +X = f2c6c8fe88d73a1940d0de419ffebc5b2070c5c7 + +COUNT = 20 +b = 320 +XKey = dfb6bfe8d24fd6395c811928a7953aee1a2de5d6e484f69fd9f7e9227ec591355f130dcea933f96c +XSeed = 00000000000000000000000000000000000000000000000000000000000000000000000000000000 +X = 54c4809627894c7be99d752be77a41a71e1177bc + +COUNT = 21 +b = 328 +XKey = 5ae22f47f7301856ada0553c6191977adfb39b64791df5d4f19a0d1f9a446748b95527743139d49e60 +XSeed = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000 +X = 44ed62cc4a46740532b1178c75919e55598a3094 + +COUNT = 22 +b = 336 +XKey = ee2ef8ae409bc544bda6637166568b93721db4d7a9b194ac0e17e378c000628922591c4e3a1eebc7576f +XSeed = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +X = 98e18826178499f6b5e9f7dbbc7fbb5ea8ece400 + +COUNT = 23 +b = 344 +XKey = d071c39a5d2e9a2aaf716f1ad84c16ba74411d3597615dcd04b6cf68a0dfa14c26fa89271bc75a520509d5 +XSeed = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +X = 5f8264026559da35e0bea1fdab8bc967079b1fd9 + +COUNT = 24 +b = 352 +XKey = 369b80c1a1c6fb9d69a01c727cece3547371544418631d4a252079c44f1d54fd831fb00170ae47b045c67212 +XSeed = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +X = 148e0ecee150cb59b1ee70586e0f493b74dda65d + +COUNT = 25 +b = 360 +XKey = d0a014bda380b171255b36e40f20a69821957dae52eff01229a077f36b708976f6cfa6abed699bc015fc02747f +XSeed = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +X = 1a67a8bcdffd0e07606288fb0bb0726b36b259bf + +COUNT = 26 +b = 368 +XKey = aae6ae0f2eb856f812733764e7ec1cfc7d49e92e61703738a5c03f83dffef933749285fc17f3c9378c605c35b2d1 +XSeed = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +X = 10b3ebf6cd54131ce1e902829a0ab251f193eb24 + +COUNT = 27 +b = 376 +XKey = f36b395eb02579985875f6183210e452b91c20bd58e4172772d1e44ba596b8a550aa7f8552fbc06315e1c572cc50fd +XSeed = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +X = 110bb9281f2e1ffac8252473be9f1ef2629513f0 + +COUNT = 28 +b = 384 +XKey = 7af1449287ffbf7428814dd6217aee8695d7f463760a121e40f6b642e70b98720db293f279ebb56ac53492e656aedd20 +XSeed = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +X = 08ea8feab6b529788d904bdbd43b9db583c95b3c + +COUNT = 29 +b = 392 +XKey = 94a62f890e754bda69b6d2a71a9c7cda337b99902d80f76ee4a00638e3ce3a9fe271b15b8d15167a8760c5f8af482f8fa2 +XSeed = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +X = c65ba4525e3bb1f083ac1bd971d952d8fb4ea820 + +COUNT = 30 +b = 400 +XKey = 417891bdbf562d87c93ca9c53aac522161c793e8a762bcbe725b0391492dc9cb38c31ecc768a869745cafdcb1a363ad6fec2 +XSeed = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +X = 09ffcbaca867d86fb5a90e44ad5d60b96b52e090 + +COUNT = 31 +b = 408 +XKey = 999a1eeca775bdbe61f3772f6cfc28ff95f13745ac35100e95ecd4479c024edd096f2a22f4ba61735bbcf81872a7ea6b3a4763 +XSeed = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +X = f2fef1651d92847c0facc14799153aac54289afc + +COUNT = 32 +b = 416 +XKey = 41f80eca8e883ceb6a772453131c922d542749c2a93248a4a4994c2c8f8c96275362eecd9930e8f32e9b6681acea5e255760de49 +XSeed = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +X = e750fd8a3815189e7b1ffba65760c6896773195f + +COUNT = 33 +b = 424 +XKey = 7eae482dcfa5e02acf05e105db48283f440640439a24ca3b2a482228c58f3f32c383db3c4847d4bcc615d3cac3eb2b77dd80045f0b +XSeed = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +X = 26e00f1ea68d5bde0c820837c18f564347507dc9 + +COUNT = 34 +b = 432 +XKey = d8143b6190d098d8c0b9af5c175344b602e6d086732e6b96e054ef688e1d5b110f62754a0ac0b4c53a905cbdb919ebd17f05b4122512 +XSeed = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +X = 60ac25c92a8c7da14edfebde25a97646474c9009 + +COUNT = 35 +b = 440 +XKey = 6f54f8051f7c172493f282be71942d4a65285560bca1b61b2f9effc1fc3483a63ced314d7010c6d15d2341831aaf97d56743a97740bb73 +XSeed = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +X = 1130c281c88ecad60736ac5bf6c9db4fc2e8334a + +COUNT = 36 +b = 448 +XKey = ca82c17fc3ac423e00c8b7c6f48bd0976d9e60c973f460fe735c37959d5239208a1b6d18221193d0bd3b65a888201e832bdd397ba8767bd3 +XSeed = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +X = 8da6754cadeb3f9121239381de1ff40061abe07e + +COUNT = 37 +b = 456 +XKey = 058f0d2e2a8b17581ab00d8b7ed2fef2e21dfaa60b120fd28acc771591880f2706640bc0d667e8b58cc2a3642255295316750e14c1ed816ce5 +XSeed = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +X = 5fd13163fb1fe4417fe96d7fb13ef2577f5868b2 + +COUNT = 38 +b = 464 +XKey = a8806c3e36700c4b8b45555dc9679bcb036fa3924fe85a3d1d57c708c77a3f4469ced8fdf25320db7b930e46d8e138cd6ddf47c94343a83d5cda +XSeed = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +X = 5704c42642beaa28896816eb196d2cf6b3de61f6 + +COUNT = 39 +b = 472 +XKey = 1a02d007f03b34ed427631283eb614db4d521f555136e7e42b4cfbee8134c63dbe3bb79b5a8b9f9f5b9f5ac61cfab1c54d197f1e3ba613f251eed6 +XSeed = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +X = f6f672ba423d82f4e86d1c7a41b4547972e859de + +COUNT = 40 +b = 480 +XKey = 28c1adb2742ac3b9c15d22f737ac5ffd34d0e5d79ee6ea3677b7a2cfb13cb2fe4462e7af7f0a287e9b54a91d961d62f63fc6c0128d379a3a3424665c +XSeed = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +X = 4596045105a7e36296b9ad7353723ba306353004 + +COUNT = 41 +b = 488 +XKey = 195adc728e0ec4f0b210b57658b448860e219231ad9d56812e0b7815bfb1b50b163f9223060d922050a5ac72bb81fc136716b9af5e1167076ce04e9731 +XSeed = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +X = 3e573f2a097c3568c9cf52f20eb141e63f9f776e + +COUNT = 42 +b = 496 +XKey = 866db552cf4745908fdf35d4c0967428d56039b1f223df315c61f2d12f178a1e4fe5d751a06efed37a022300577bc72ccf6455e3c761f775e5caaeb2479a +XSeed = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +X = 0077207b39f67aa80cb2ea90818440d4e5ccc414 + +COUNT = 43 +b = 504 +XKey = 641846ce2ba4396a391651179231d553c9061c6619bd4545b29228b6511e8bb513d89a168bdb916d12eabc2b5eb1a109574d7caa250feb7b8e7debdf7f9a03 +XSeed = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +X = 2166c4e99be5dc0cdc747c7c6d27105a8e115ba5 + +COUNT = 44 +b = 512 +XKey = 5cbb6d193c13bd62f5658ed4304774c6b1faf5b3dce432487840cabab415fb5d67640a739ca6e5414e760869708a9d7331e7e7ad7d55e035c711215406c3030d +XSeed = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +X = a2322c754fe789af3afae00b9fbbbd613076ea9f + diff --git a/asdcplib/src/gen-tst.sh b/asdcplib/src/gen-tst.sh new file mode 100755 index 0000000..31ed12d --- /dev/null +++ b/asdcplib/src/gen-tst.sh @@ -0,0 +1,28 @@ +#!/bin/sh +# +# $Id: gen-tst.sh,v 1.3 2009/04/09 19:16:49 msheby Exp $ +# Copyright (c) 2007-2009 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. + +${BUILD_DIR}/asdcp-test${EXEEXT} -g diff --git a/asdcplib/src/h__Reader.cpp b/asdcplib/src/h__Reader.cpp new file mode 100755 index 0000000..ebf3443 --- /dev/null +++ b/asdcplib/src/h__Reader.cpp @@ -0,0 +1,460 @@ +/* +Copyright (c) 2004-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 h__Reader.cpp + \version $Id: h__Reader.cpp,v 1.31 2012/02/07 18:54:25 jhurst Exp $ + \brief MXF file reader base class +*/ + +#define DEFAULT_MD_DECL +#include "AS_DCP_internal.h" +#include "KLV.h" + +using namespace ASDCP; +using namespace ASDCP::MXF; + +static Kumu::Mutex sg_DefaultMDInitLock; +static bool sg_DefaultMDTypesInit = false; +static const ASDCP::Dictionary *sg_dict; + +// +void +ASDCP::default_md_object_init() +{ + if ( ! sg_DefaultMDTypesInit ) + { + Kumu::AutoMutex BlockLock(sg_DefaultMDInitLock); + + if ( ! sg_DefaultMDTypesInit ) + { + sg_dict = &DefaultSMPTEDict(); + g_OPAtomHeader = new ASDCP::MXF::OPAtomHeader(sg_dict); + g_OPAtomIndexFooter = new ASDCP::MXF::OPAtomIndexFooter(sg_dict); + sg_DefaultMDTypesInit = true; + } + } +} + + +// +ASDCP::h__Reader::h__Reader(const Dictionary& d) : + m_Dict(&d), m_HeaderPart(m_Dict), m_BodyPart(m_Dict), m_FooterPart(m_Dict), m_EssenceStart(0) +{ + default_md_object_init(); +} + +ASDCP::h__Reader::~h__Reader() +{ + Close(); +} + +void +ASDCP::h__Reader::Close() +{ + m_File.Close(); +} + +//------------------------------------------------------------------------------------------ +// + +// +Result_t +ASDCP::h__Reader::InitInfo() +{ + assert(m_Dict); + InterchangeObject* Object; + + m_Info.LabelSetType = LS_MXF_UNKNOWN; + + if ( m_HeaderPart.OperationalPattern.ExactMatch(MXFInterop_OPAtom_Entry().ul) ) + m_Info.LabelSetType = LS_MXF_INTEROP; + else if ( m_HeaderPart.OperationalPattern.ExactMatch(SMPTE_390_OPAtom_Entry().ul) ) + m_Info.LabelSetType = LS_MXF_SMPTE; + + // Identification + Result_t result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(Identification), &Object); + + if( ASDCP_SUCCESS(result) ) + MD_to_WriterInfo((Identification*)Object, m_Info); + + // SourcePackage + if( ASDCP_SUCCESS(result) ) + result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(SourcePackage), &Object); + + if( ASDCP_SUCCESS(result) ) + { + SourcePackage* SP = (SourcePackage*)Object; + memcpy(m_Info.AssetUUID, SP->PackageUID.Value() + 16, UUIDlen); + } + + // optional CryptographicContext + if( ASDCP_SUCCESS(result) ) + { + Result_t cr_result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(CryptographicContext), &Object); + + if( ASDCP_SUCCESS(cr_result) ) + MD_to_CryptoInfo((CryptographicContext*)Object, m_Info, *m_Dict); + } + + return result; +} + + +// standard method of opening an MXF file for read +Result_t +ASDCP::h__Reader::OpenMXFRead(const char* filename) +{ + m_LastPosition = 0; + Result_t result = m_File.OpenRead(filename); + + if ( ASDCP_SUCCESS(result) ) + result = m_HeaderPart.InitFromFile(m_File); + + if ( ASDCP_SUCCESS(result) ) + { + // if this is a three partition file, go to the body + // partition and read the partition pack + if ( m_HeaderPart.m_RIP.PairArray.size() > 2 ) + { + Array<RIP::Pair>::iterator r_i = m_HeaderPart.m_RIP.PairArray.begin(); + r_i++; + m_File.Seek((*r_i).ByteOffset); + + result = m_BodyPart.InitFromFile(m_File); + } + + m_EssenceStart = m_File.Tell(); + } + + return result; +} + + +// standard method of populating the in-memory index +Result_t +ASDCP::h__Reader::InitMXFIndex() +{ + if ( ! m_File.IsOpen() ) + return RESULT_INIT; + + Result_t result = m_File.Seek(m_HeaderPart.FooterPartition); + + if ( ASDCP_SUCCESS(result) ) + { + m_FooterPart.m_Lookup = &m_HeaderPart.m_Primer; + result = m_FooterPart.InitFromFile(m_File); + } + + if ( ASDCP_SUCCESS(result) ) + m_File.Seek(m_EssenceStart); + + return result; +} + +// +Result_t +ASDCP::KLReader::ReadKLFromFile(Kumu::FileReader& Reader) +{ + ui32_t read_count; + ui32_t header_length = SMPTE_UL_LENGTH + MXF_BER_LENGTH; + Result_t result = Reader.Read(m_KeyBuf, header_length, &read_count); + + if ( ASDCP_FAILURE(result) ) + return result; + + if ( read_count != header_length ) + return RESULT_READFAIL; + + const byte_t* ber_start = m_KeyBuf + SMPTE_UL_LENGTH; + + if ( ( *ber_start & 0x80 ) == 0 ) + { + DefaultLogSink().Error("BER encoding error.\n"); + return RESULT_FORMAT; + } + + ui8_t ber_size = ( *ber_start & 0x0f ) + 1; + + if ( ber_size > 9 ) + { + DefaultLogSink().Error("BER size encoding error.\n"); + return RESULT_FORMAT; + } + + if ( ber_size < MXF_BER_LENGTH ) + { + DefaultLogSink().Error("BER size %d shorter than AS-DCP minimum %d.\n", + ber_size, MXF_BER_LENGTH); + return RESULT_FORMAT; + } + + if ( ber_size > MXF_BER_LENGTH ) + { + ui32_t diff = ber_size - MXF_BER_LENGTH; + assert((SMPTE_UL_LENGTH + MXF_BER_LENGTH + diff) <= (SMPTE_UL_LENGTH * 2)); + result = Reader.Read(m_KeyBuf + SMPTE_UL_LENGTH + MXF_BER_LENGTH, diff, &read_count); + + if ( ASDCP_FAILURE(result) ) + return result; + + if ( read_count != diff ) + return RESULT_READFAIL; + + header_length += diff; + } + + return InitFromBuffer(m_KeyBuf, header_length); +} + +// standard method of reading a plaintext or encrypted frame +Result_t +ASDCP::h__Reader::ReadEKLVFrame(ui32_t FrameNum, ASDCP::FrameBuffer& FrameBuf, + const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC) +{ + // look up frame index node + IndexTableSegment::IndexEntry TmpEntry; + + if ( ASDCP_FAILURE(m_FooterPart.Lookup(FrameNum, TmpEntry)) ) + { + DefaultLogSink().Error("Frame value out of range: %u\n", FrameNum); + return RESULT_RANGE; + } + + // get frame position and go read the frame's key and length + Kumu::fpos_t FilePosition = m_EssenceStart + TmpEntry.StreamOffset; + Result_t result = RESULT_OK; + + if ( FilePosition != m_LastPosition ) + { + m_LastPosition = FilePosition; + result = m_File.Seek(FilePosition); + } + + if( ASDCP_SUCCESS(result) ) + result = ReadEKLVPacket(FrameNum, FrameNum + 1, FrameBuf, EssenceUL, Ctx, HMAC); + + return result; +} + + +Result_t +ASDCP::h__Reader::ReadEKLVPacket(ui32_t FrameNum, ui32_t SequenceNum, ASDCP::FrameBuffer& FrameBuf, + const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC) +{ + KLReader Reader; + Result_t result = Reader.ReadKLFromFile(m_File); + + if ( ASDCP_FAILURE(result) ) + return result; + + UL Key(Reader.Key()); + ui64_t PacketLength = Reader.Length(); + m_LastPosition = m_LastPosition + Reader.KLLength() + PacketLength; + assert(m_Dict); + + if ( Key.MatchIgnoreStream(m_Dict->ul(MDD_CryptEssence)) ) // ignore the stream numbers + { + if ( ! m_Info.EncryptedEssence ) + { + DefaultLogSink().Error("EKLV packet found, no Cryptographic Context in header.\n"); + return RESULT_FORMAT; + } + + // read encrypted triplet value into internal buffer + assert(PacketLength <= 0xFFFFFFFFL); + m_CtFrameBuf.Capacity((ui32_t) PacketLength); + ui32_t read_count; + result = m_File.Read(m_CtFrameBuf.Data(), (ui32_t) PacketLength, + &read_count); + + if ( ASDCP_FAILURE(result) ) + return result; + + if ( read_count != PacketLength ) + { + DefaultLogSink().Error("read length is smaller than EKLV packet length.\n"); + return RESULT_FORMAT; + } + + m_CtFrameBuf.Size((ui32_t) PacketLength); + + // should be const but mxflib::ReadBER is not + byte_t* ess_p = m_CtFrameBuf.Data(); + + // read context ID length + if ( ! Kumu::read_test_BER(&ess_p, UUIDlen) ) + return RESULT_FORMAT; + + // test the context ID + if ( memcmp(ess_p, m_Info.ContextID, UUIDlen) != 0 ) + { + DefaultLogSink().Error("Packet's Cryptographic Context ID does not match the header.\n"); + return RESULT_FORMAT; + } + ess_p += UUIDlen; + + // read PlaintextOffset length + if ( ! Kumu::read_test_BER(&ess_p, sizeof(ui64_t)) ) + return RESULT_FORMAT; + + ui32_t PlaintextOffset = (ui32_t)KM_i64_BE(Kumu::cp2i<ui64_t>(ess_p)); + ess_p += sizeof(ui64_t); + + // read essence UL length + if ( ! Kumu::read_test_BER(&ess_p, SMPTE_UL_LENGTH) ) + return RESULT_FORMAT; + + // test essence UL + if ( ! UL(ess_p).MatchIgnoreStream(EssenceUL) ) // ignore the stream number + { + char strbuf[IntBufferLen]; + const MDDEntry* Entry = m_Dict->FindUL(Key.Value()); + if ( Entry == 0 ) + DefaultLogSink().Warn("Unexpected Encrypted Essence UL found: %s.\n", Key.EncodeString(strbuf, IntBufferLen)); + else + DefaultLogSink().Warn("Unexpected Encrypted Essence UL found: %s.\n", Entry->name); + return RESULT_FORMAT; + } + ess_p += SMPTE_UL_LENGTH; + + // read SourceLength length + if ( ! Kumu::read_test_BER(&ess_p, sizeof(ui64_t)) ) + return RESULT_FORMAT; + + ui32_t SourceLength = (ui32_t)KM_i64_BE(Kumu::cp2i<ui64_t>(ess_p)); + ess_p += sizeof(ui64_t); + assert(SourceLength); + + if ( FrameBuf.Capacity() < SourceLength ) + { + DefaultLogSink().Error("FrameBuf.Capacity: %u SourceLength: %u\n", FrameBuf.Capacity(), SourceLength); + return RESULT_SMALLBUF; + } + + ui32_t esv_length = calc_esv_length(SourceLength, PlaintextOffset); + + // read ESV length + if ( ! Kumu::read_test_BER(&ess_p, esv_length) ) + { + DefaultLogSink().Error("read_test_BER did not return %u\n", esv_length); + return RESULT_FORMAT; + } + + ui32_t tmp_len = esv_length + (m_Info.UsesHMAC ? klv_intpack_size : 0); + + if ( PacketLength < tmp_len ) + { + DefaultLogSink().Error("Frame length is larger than EKLV packet length.\n"); + return RESULT_FORMAT; + } + + if ( Ctx ) + { + // wrap the pointer and length as a FrameBuffer for use by + // DecryptFrameBuffer() and TestValues() + FrameBuffer TmpWrapper; + TmpWrapper.SetData(ess_p, tmp_len); + TmpWrapper.Size(tmp_len); + TmpWrapper.SourceLength(SourceLength); + TmpWrapper.PlaintextOffset(PlaintextOffset); + + result = DecryptFrameBuffer(TmpWrapper, FrameBuf, Ctx); + FrameBuf.FrameNumber(FrameNum); + + // detect and test integrity pack + if ( ASDCP_SUCCESS(result) && m_Info.UsesHMAC && HMAC ) + { + IntegrityPack IntPack; + result = IntPack.TestValues(TmpWrapper, m_Info.AssetUUID, SequenceNum, HMAC); + } + } + else // return ciphertext to caller + { + if ( FrameBuf.Capacity() < tmp_len ) + { + char intbuf[IntBufferLen]; + DefaultLogSink().Error("FrameBuf.Capacity: %u FrameLength: %s\n", + FrameBuf.Capacity(), ui64sz(PacketLength, intbuf)); + return RESULT_SMALLBUF; + } + + memcpy(FrameBuf.Data(), ess_p, tmp_len); + FrameBuf.Size(tmp_len); + FrameBuf.FrameNumber(FrameNum); + FrameBuf.SourceLength(SourceLength); + FrameBuf.PlaintextOffset(PlaintextOffset); + } + } + else if ( Key.MatchIgnoreStream(EssenceUL) ) // ignore the stream number + { // read plaintext frame + if ( FrameBuf.Capacity() < PacketLength ) + { + char intbuf[IntBufferLen]; + DefaultLogSink().Error("FrameBuf.Capacity: %u FrameLength: %s\n", + FrameBuf.Capacity(), ui64sz(PacketLength, intbuf)); + return RESULT_SMALLBUF; + } + + // read the data into the supplied buffer + ui32_t read_count; + assert(PacketLength <= 0xFFFFFFFFL); + result = m_File.Read(FrameBuf.Data(), (ui32_t) PacketLength, &read_count); + + if ( ASDCP_FAILURE(result) ) + return result; + + if ( read_count != PacketLength ) + { + char intbuf1[IntBufferLen]; + char intbuf2[IntBufferLen]; + DefaultLogSink().Error("read_count: %s != FrameLength: %s\n", + ui64sz(read_count, intbuf1), + ui64sz(PacketLength, intbuf2) ); + + return RESULT_READFAIL; + } + + FrameBuf.FrameNumber(FrameNum); + FrameBuf.Size(read_count); + } + else + { + char strbuf[IntBufferLen]; + const MDDEntry* Entry = m_Dict->FindUL(Key.Value()); + if ( Entry == 0 ) + DefaultLogSink().Warn("Unexpected Essence UL found: %s.\n", Key.EncodeString(strbuf, IntBufferLen)); + else + DefaultLogSink().Warn("Unexpected Essence UL found: %s.\n", Entry->name); + return RESULT_FORMAT; + } + + return result; +} + + +// +// end h__Reader.cpp +// diff --git a/asdcplib/src/h__Writer.cpp b/asdcplib/src/h__Writer.cpp new file mode 100755 index 0000000..d743e30 --- /dev/null +++ b/asdcplib/src/h__Writer.cpp @@ -0,0 +1,710 @@ +/* +Copyright (c) 2004-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 h__Writer.cpp + \version $Id: h__Writer.cpp,v 1.51 2012/02/07 18:54:25 jhurst Exp $ + \brief MXF file writer base class +*/ + +#include "AS_DCP_internal.h" +#include "KLV.h" + +using std::cout; +using namespace ASDCP; +using namespace ASDCP::MXF; + +// a magic number identifying asdcplib +#ifndef ASDCP_BUILD_NUMBER +#define ASDCP_BUILD_NUMBER 0x6A68 +#endif + + +static std::vector<int> +version_split(const char* str) +{ + std::vector<int> result; + + const char* pstr = str; + const char* r = strchr(pstr, '.'); + + while ( r != 0 ) + { + assert(r >= pstr); + if ( r > pstr ) + result.push_back(atoi(pstr)); + + pstr = r + 1; + r = strchr(pstr, '.'); + } + + if( strlen(pstr) > 0 ) + result.push_back(atoi(pstr)); + + assert(result.size() == 3); + return result; +} + + +// +ASDCP::h__Writer::h__Writer(const Dictionary& d) : + m_Dict(&d), m_HeaderSize(0), m_HeaderPart(m_Dict), + m_BodyPart(m_Dict), m_FooterPart(m_Dict), m_EssenceStart(0), + m_EssenceDescriptor(0), m_FramesWritten(0), m_StreamOffset(0) +{ + default_md_object_init(); +} + +ASDCP::h__Writer::~h__Writer() +{ +} + +// +// add DMS CryptographicFramework entry to source package +void +AddDMScrypt(Partition& HeaderPart, SourcePackage& Package, + WriterInfo& Descr, const UL& WrappingUL, const Dictionary*& Dict) +{ + assert(Dict); + // Essence Track + StaticTrack* NewTrack = new StaticTrack(Dict); + HeaderPart.AddChildObject(NewTrack); + Package.Tracks.push_back(NewTrack->InstanceUID); + NewTrack->TrackName = "Descriptive Track"; + NewTrack->TrackID = 3; + + Sequence* Seq = new Sequence(Dict); + HeaderPart.AddChildObject(Seq); + NewTrack->Sequence = Seq->InstanceUID; + Seq->DataDefinition = UL(Dict->ul(MDD_DescriptiveMetaDataDef)); + + DMSegment* Segment = new DMSegment(Dict); + HeaderPart.AddChildObject(Segment); + Seq->StructuralComponents.push_back(Segment->InstanceUID); + Segment->EventComment = "AS-DCP KLV Encryption"; + + CryptographicFramework* CFW = new CryptographicFramework(Dict); + HeaderPart.AddChildObject(CFW); + Segment->DMFramework = CFW->InstanceUID; + + CryptographicContext* Context = new CryptographicContext(Dict); + HeaderPart.AddChildObject(Context); + CFW->ContextSR = Context->InstanceUID; + + Context->ContextID.Set(Descr.ContextID); + Context->SourceEssenceContainer = WrappingUL; // ?????? + Context->CipherAlgorithm.Set(Dict->ul(MDD_CipherAlgorithm_AES)); + Context->MICAlgorithm.Set( Descr.UsesHMAC ? Dict->ul(MDD_MICAlgorithm_HMAC_SHA1) : Dict->ul(MDD_MICAlgorithm_NONE) ); + Context->CryptographicKeyID.Set(Descr.CryptographicKeyID); +} + +// +void +ASDCP::h__Writer::InitHeader() +{ + assert(m_Dict); + assert(m_EssenceDescriptor); + + m_HeaderPart.m_Primer.ClearTagList(); + m_HeaderPart.m_Preface = new Preface(m_Dict); + m_HeaderPart.AddChildObject(m_HeaderPart.m_Preface); + + // Set the Operational Pattern label -- we're just starting and have no RIP or index, + // so we tell the world by using OP1a + m_HeaderPart.m_Preface->OperationalPattern = UL(m_Dict->ul(MDD_OP1a)); + m_HeaderPart.OperationalPattern = m_HeaderPart.m_Preface->OperationalPattern; + + // First RIP Entry + if ( m_Info.LabelSetType == LS_MXF_SMPTE ) + m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(0, 0)); // 3-part, no essence in header + else + m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(1, 0)); // 2-part, essence in header + + // + // Identification + // + Identification* Ident = new Identification(m_Dict); + m_HeaderPart.AddChildObject(Ident); + m_HeaderPart.m_Preface->Identifications.push_back(Ident->InstanceUID); + + Kumu::GenRandomValue(Ident->ThisGenerationUID); + Ident->CompanyName = m_Info.CompanyName.c_str(); + Ident->ProductName = m_Info.ProductName.c_str(); + Ident->VersionString = m_Info.ProductVersion.c_str(); + Ident->ProductUID.Set(m_Info.ProductUUID); + Ident->Platform = ASDCP_PLATFORM; + + std::vector<int> version = version_split(Version()); + + Ident->ToolkitVersion.Major = version[0]; + Ident->ToolkitVersion.Minor = version[1]; + Ident->ToolkitVersion.Patch = version[2]; + Ident->ToolkitVersion.Build = ASDCP_BUILD_NUMBER; + Ident->ToolkitVersion.Release = VersionType::RL_RELEASE; +} + +// +template <class ClipT> +struct TrackSet +{ + MXF::Track* Track; + MXF::Sequence* Sequence; + ClipT* Clip; + + TrackSet() : Track(0), Sequence(0), Clip(0) {} +}; + +// +template <class PackageT, class ClipT> +TrackSet<ClipT> +CreateTrackAndSequence(OPAtomHeader& Header, PackageT& Package, const std::string TrackName, + const MXF::Rational& EditRate, const UL& Definition, ui32_t TrackID, const Dictionary*& Dict) +{ + TrackSet<ClipT> NewTrack; + + NewTrack.Track = new Track(Dict); + Header.AddChildObject(NewTrack.Track); + NewTrack.Track->EditRate = EditRate; + Package.Tracks.push_back(NewTrack.Track->InstanceUID); + NewTrack.Track->TrackID = TrackID; + NewTrack.Track->TrackName = TrackName.c_str(); + + NewTrack.Sequence = new Sequence(Dict); + Header.AddChildObject(NewTrack.Sequence); + NewTrack.Track->Sequence = NewTrack.Sequence->InstanceUID; + NewTrack.Sequence->DataDefinition = Definition; + + return NewTrack; +} + +// +template <class PackageT> +TrackSet<TimecodeComponent> +CreateTimecodeTrack(OPAtomHeader& Header, PackageT& Package, + const MXF::Rational& EditRate, ui32_t TCFrameRate, ui64_t TCStart, const Dictionary*& Dict) +{ + assert(Dict); + UL TCUL(Dict->ul(MDD_TimecodeDataDef)); + + TrackSet<TimecodeComponent> NewTrack = CreateTrackAndSequence<PackageT, TimecodeComponent>(Header, Package, "Timecode Track", EditRate, TCUL, 1, Dict); + + NewTrack.Clip = new TimecodeComponent(Dict); + Header.AddChildObject(NewTrack.Clip); + NewTrack.Sequence->StructuralComponents.push_back(NewTrack.Clip->InstanceUID); + NewTrack.Clip->RoundedTimecodeBase = TCFrameRate; + NewTrack.Clip->StartTimecode = TCStart; + NewTrack.Clip->DataDefinition = TCUL; + + return NewTrack; +} + + +// +void +ASDCP::h__Writer::AddSourceClip(const MXF::Rational& EditRate, ui32_t TCFrameRate, + const std::string& TrackName, const UL& EssenceUL, + const UL& DataDefinition, const std::string& PackageLabel) +{ + // + ContentStorage* Storage = new ContentStorage(m_Dict); + m_HeaderPart.AddChildObject(Storage); + m_HeaderPart.m_Preface->ContentStorage = Storage->InstanceUID; + + EssenceContainerData* ECD = new EssenceContainerData(m_Dict); + m_HeaderPart.AddChildObject(ECD); + Storage->EssenceContainerData.push_back(ECD->InstanceUID); + ECD->IndexSID = 129; + ECD->BodySID = 1; + + UUID assetUUID(m_Info.AssetUUID); + UMID SourcePackageUMID, MaterialPackageUMID; + SourcePackageUMID.MakeUMID(0x0f, assetUUID); + MaterialPackageUMID.MakeUMID(0x0f); // unidentified essence + + // + // Material Package + // + m_MaterialPackage = new MaterialPackage(m_Dict); + m_MaterialPackage->Name = "AS-DCP Material Package"; + m_MaterialPackage->PackageUID = MaterialPackageUMID; + m_HeaderPart.AddChildObject(m_MaterialPackage); + Storage->Packages.push_back(m_MaterialPackage->InstanceUID); + + TrackSet<TimecodeComponent> MPTCTrack = + CreateTimecodeTrack<MaterialPackage>(m_HeaderPart, *m_MaterialPackage, + EditRate, TCFrameRate, 0, m_Dict); + m_DurationUpdateList.push_back(&(MPTCTrack.Sequence->Duration)); + m_DurationUpdateList.push_back(&(MPTCTrack.Clip->Duration)); + + TrackSet<SourceClip> MPTrack = + CreateTrackAndSequence<MaterialPackage, SourceClip>(m_HeaderPart, *m_MaterialPackage, + TrackName, EditRate, DataDefinition, + 2, m_Dict); + m_DurationUpdateList.push_back(&(MPTrack.Sequence->Duration)); + + MPTrack.Clip = new SourceClip(m_Dict); + m_HeaderPart.AddChildObject(MPTrack.Clip); + MPTrack.Sequence->StructuralComponents.push_back(MPTrack.Clip->InstanceUID); + MPTrack.Clip->DataDefinition = DataDefinition; + MPTrack.Clip->SourcePackageID = SourcePackageUMID; + MPTrack.Clip->SourceTrackID = 2; + m_DurationUpdateList.push_back(&(MPTrack.Clip->Duration)); + + + // + // File (Source) Package + // + m_FilePackage = new SourcePackage(m_Dict); + m_FilePackage->Name = PackageLabel.c_str(); + m_FilePackage->PackageUID = SourcePackageUMID; + ECD->LinkedPackageUID = SourcePackageUMID; + + m_HeaderPart.AddChildObject(m_FilePackage); + Storage->Packages.push_back(m_FilePackage->InstanceUID); + + TrackSet<TimecodeComponent> FPTCTrack = + CreateTimecodeTrack<SourcePackage>(m_HeaderPart, *m_FilePackage, + EditRate, TCFrameRate, + ui64_C(3600) * TCFrameRate, m_Dict); + m_DurationUpdateList.push_back(&(FPTCTrack.Sequence->Duration)); + m_DurationUpdateList.push_back(&(FPTCTrack.Clip->Duration)); + TrackSet<SourceClip> FPTrack = + CreateTrackAndSequence<SourcePackage, SourceClip>(m_HeaderPart, *m_FilePackage, + TrackName, EditRate, DataDefinition, + 2, m_Dict); + m_DurationUpdateList.push_back(&(FPTrack.Sequence->Duration)); + + // Consult ST 379:2004 Sec. 6.3, "Element to track relationship" to see where "12" comes from. + FPTrack.Track->TrackNumber = KM_i32_BE(Kumu::cp2i<ui32_t>((EssenceUL.Value() + 12))); + + FPTrack.Clip = new SourceClip(m_Dict); + m_HeaderPart.AddChildObject(FPTrack.Clip); + FPTrack.Sequence->StructuralComponents.push_back(FPTrack.Clip->InstanceUID); + FPTrack.Clip->DataDefinition = DataDefinition; + + // for now we do not allow setting this value, so all files will be 'original' + FPTrack.Clip->SourceTrackID = 0; + FPTrack.Clip->SourcePackageID = NilUMID; + m_DurationUpdateList.push_back(&(FPTrack.Clip->Duration)); + + m_EssenceDescriptor->LinkedTrackID = FPTrack.Track->TrackID; +} + +// +void +ASDCP::h__Writer::AddDMSegment(const MXF::Rational& EditRate, ui32_t TCFrameRate, + const std::string& TrackName, const UL& DataDefinition, + const std::string& PackageLabel) +{ + // + ContentStorage* Storage = new ContentStorage(m_Dict); + m_HeaderPart.AddChildObject(Storage); + m_HeaderPart.m_Preface->ContentStorage = Storage->InstanceUID; + + EssenceContainerData* ECD = new EssenceContainerData(m_Dict); + m_HeaderPart.AddChildObject(ECD); + Storage->EssenceContainerData.push_back(ECD->InstanceUID); + ECD->IndexSID = 129; + ECD->BodySID = 1; + + UUID assetUUID(m_Info.AssetUUID); + UMID SourcePackageUMID, MaterialPackageUMID; + SourcePackageUMID.MakeUMID(0x0f, assetUUID); + MaterialPackageUMID.MakeUMID(0x0f); // unidentified essence + + // + // Material Package + // + m_MaterialPackage = new MaterialPackage(m_Dict); + m_MaterialPackage->Name = "AS-DCP Material Package"; + m_MaterialPackage->PackageUID = MaterialPackageUMID; + m_HeaderPart.AddChildObject(m_MaterialPackage); + Storage->Packages.push_back(m_MaterialPackage->InstanceUID); + + TrackSet<TimecodeComponent> MPTCTrack = + CreateTimecodeTrack<MaterialPackage>(m_HeaderPart, *m_MaterialPackage, + EditRate, TCFrameRate, 0, m_Dict); + m_DurationUpdateList.push_back(&(MPTCTrack.Sequence->Duration)); + m_DurationUpdateList.push_back(&(MPTCTrack.Clip->Duration)); + + TrackSet<DMSegment> MPTrack = + CreateTrackAndSequence<MaterialPackage, DMSegment>(m_HeaderPart, *m_MaterialPackage, + TrackName, EditRate, DataDefinition, + 2, m_Dict); + m_DurationUpdateList.push_back(&(MPTrack.Sequence->Duration)); + + MPTrack.Clip = new DMSegment(m_Dict); + m_HeaderPart.AddChildObject(MPTrack.Clip); + MPTrack.Sequence->StructuralComponents.push_back(MPTrack.Clip->InstanceUID); + MPTrack.Clip->DataDefinition = DataDefinition; + // MPTrack.Clip->SourcePackageID = SourcePackageUMID; + // MPTrack.Clip->SourceTrackID = 2; + m_DurationUpdateList.push_back(&(MPTrack.Clip->Duration)); + + + // + // File (Source) Package + // + m_FilePackage = new SourcePackage(m_Dict); + m_FilePackage->Name = PackageLabel.c_str(); + m_FilePackage->PackageUID = SourcePackageUMID; + ECD->LinkedPackageUID = SourcePackageUMID; + + m_HeaderPart.AddChildObject(m_FilePackage); + Storage->Packages.push_back(m_FilePackage->InstanceUID); + + TrackSet<TimecodeComponent> FPTCTrack = + CreateTimecodeTrack<SourcePackage>(m_HeaderPart, *m_FilePackage, + EditRate, TCFrameRate, + ui64_C(3600) * TCFrameRate, m_Dict); + m_DurationUpdateList.push_back(&(FPTCTrack.Sequence->Duration)); + m_DurationUpdateList.push_back(&(FPTCTrack.Clip->Duration)); + + TrackSet<DMSegment> FPTrack = + CreateTrackAndSequence<SourcePackage, DMSegment>(m_HeaderPart, *m_FilePackage, + TrackName, EditRate, DataDefinition, + 2, m_Dict); + m_DurationUpdateList.push_back(&(FPTrack.Sequence->Duration)); + + FPTrack.Clip = new DMSegment(m_Dict); + m_HeaderPart.AddChildObject(FPTrack.Clip); + FPTrack.Sequence->StructuralComponents.push_back(FPTrack.Clip->InstanceUID); + FPTrack.Clip->DataDefinition = DataDefinition; + FPTrack.Clip->EventComment = "D-Cinema Timed Text"; + + m_DurationUpdateList.push_back(&(FPTrack.Clip->Duration)); + m_EssenceDescriptor->LinkedTrackID = FPTrack.Track->TrackID; +} + +// +void +ASDCP::h__Writer::AddEssenceDescriptor(const UL& WrappingUL) +{ + // + // Essence Descriptor + // + m_EssenceDescriptor->EssenceContainer = WrappingUL; + m_HeaderPart.m_Preface->PrimaryPackage = m_FilePackage->InstanceUID; + + // + // Essence Descriptors + // + assert(m_Dict); + UL GenericContainerUL(m_Dict->ul(MDD_GCMulti)); + m_HeaderPart.EssenceContainers.push_back(GenericContainerUL); + + if ( m_Info.EncryptedEssence ) + { + UL CryptEssenceUL(m_Dict->ul(MDD_EncryptedContainerLabel)); + m_HeaderPart.EssenceContainers.push_back(CryptEssenceUL); + m_HeaderPart.m_Preface->DMSchemes.push_back(UL(m_Dict->ul(MDD_CryptographicFrameworkLabel))); + AddDMScrypt(m_HeaderPart, *m_FilePackage, m_Info, WrappingUL, m_Dict); + } + else + { + m_HeaderPart.EssenceContainers.push_back(WrappingUL); + } + + m_HeaderPart.m_Preface->EssenceContainers = m_HeaderPart.EssenceContainers; + m_HeaderPart.AddChildObject(m_EssenceDescriptor); + + std::list<InterchangeObject*>::iterator sdli = m_EssenceSubDescriptorList.begin(); + for ( ; sdli != m_EssenceSubDescriptorList.end(); sdli++ ) + m_HeaderPart.AddChildObject(*sdli); + + m_FilePackage->Descriptor = m_EssenceDescriptor->InstanceUID; +} + +// +Result_t +ASDCP::h__Writer::CreateBodyPart(const MXF::Rational& EditRate, ui32_t BytesPerEditUnit) +{ + assert(m_Dict); + Result_t result = RESULT_OK; + + // create a body partition if we're writing proper 429-3/OP-Atom + if ( m_Info.LabelSetType == LS_MXF_SMPTE ) + { + // Body Partition + m_BodyPart.EssenceContainers = m_HeaderPart.EssenceContainers; + m_BodyPart.ThisPartition = m_File.Tell(); + m_BodyPart.BodySID = 1; + UL OPAtomUL(m_Dict->ul(MDD_OPAtom)); + m_BodyPart.OperationalPattern = OPAtomUL; + m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(1, m_BodyPart.ThisPartition)); // Second RIP Entry + + UL BodyUL(m_Dict->ul(MDD_ClosedCompleteBodyPartition)); + result = m_BodyPart.WriteToFile(m_File, BodyUL); + } + else + { + m_HeaderPart.BodySID = 1; + } + + if ( ASDCP_SUCCESS(result) ) + { + // Index setup + Kumu::fpos_t ECoffset = m_File.Tell(); + m_FooterPart.IndexSID = 129; + + if ( BytesPerEditUnit == 0 ) + m_FooterPart.SetIndexParamsVBR(&m_HeaderPart.m_Primer, EditRate, ECoffset); + else + m_FooterPart.SetIndexParamsCBR(&m_HeaderPart.m_Primer, BytesPerEditUnit, EditRate); + } + + return result; +} + +// +Result_t +ASDCP::h__Writer::WriteMXFHeader(const std::string& PackageLabel, const UL& WrappingUL, + const std::string& TrackName, const UL& EssenceUL, const UL& DataDefinition, + const MXF::Rational& EditRate, ui32_t TCFrameRate, ui32_t BytesPerEditUnit) +{ + InitHeader(); + AddSourceClip(EditRate, TCFrameRate, TrackName, EssenceUL, DataDefinition, PackageLabel); + AddEssenceDescriptor(WrappingUL); + + Result_t result = m_HeaderPart.WriteToFile(m_File, m_HeaderSize); + + if ( KM_SUCCESS(result) ) + result = CreateBodyPart(EditRate, BytesPerEditUnit); + + return result; +} + + +// standard method of writing a plaintext or encrypted frame +Result_t +ASDCP::h__Writer::WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf, const byte_t* EssenceUL, + AESEncContext* Ctx, HMACContext* HMAC, std::string* hash) +{ + Result_t result = RESULT_OK; + IntegrityPack IntPack; + + m_File.StartHashing(); + + byte_t overhead[128]; + Kumu::MemIOWriter Overhead(overhead, 128); + assert(m_Dict); + + if ( FrameBuf.Size() == 0 ) + { + DefaultLogSink().Error("Cannot write empty frame buffer\n"); + return RESULT_EMPTY_FB; + } + + if ( m_Info.EncryptedEssence ) + { + if ( ! Ctx ) + return RESULT_CRYPT_CTX; + + if ( m_Info.UsesHMAC && ! HMAC ) + return RESULT_HMAC_CTX; + + if ( FrameBuf.PlaintextOffset() > FrameBuf.Size() ) + return RESULT_LARGE_PTO; + + // encrypt the essence data (create encrypted source value) + result = EncryptFrameBuffer(FrameBuf, m_CtFrameBuf, Ctx); + + // create HMAC + if ( ASDCP_SUCCESS(result) && m_Info.UsesHMAC ) + result = IntPack.CalcValues(m_CtFrameBuf, m_Info.AssetUUID, m_FramesWritten + 1, HMAC); + + if ( ASDCP_SUCCESS(result) ) + { // write UL + Overhead.WriteRaw(m_Dict->ul(MDD_CryptEssence), SMPTE_UL_LENGTH); + + // construct encrypted triplet header + ui32_t ETLength = klv_cryptinfo_size + m_CtFrameBuf.Size(); + ui32_t BER_length = MXF_BER_LENGTH; + + if ( m_Info.UsesHMAC ) + ETLength += klv_intpack_size; + else + ETLength += (MXF_BER_LENGTH * 3); // for empty intpack + + if ( ETLength > 0x00ffffff ) // Need BER integer longer than MXF_BER_LENGTH bytes + { + BER_length = Kumu::get_BER_length_for_value(ETLength); + + // the packet is longer by the difference in expected vs. actual BER length + ETLength += BER_length - MXF_BER_LENGTH; + + if ( BER_length == 0 ) + result = RESULT_KLV_CODING; + } + + if ( ASDCP_SUCCESS(result) ) + { + if ( ! ( Overhead.WriteBER(ETLength, BER_length) // write encrypted triplet length + && Overhead.WriteBER(UUIDlen, MXF_BER_LENGTH) // write ContextID length + && Overhead.WriteRaw(m_Info.ContextID, UUIDlen) // write ContextID + && Overhead.WriteBER(sizeof(ui64_t), MXF_BER_LENGTH) // write PlaintextOffset length + && Overhead.WriteUi64BE(FrameBuf.PlaintextOffset()) // write PlaintextOffset + && Overhead.WriteBER(SMPTE_UL_LENGTH, MXF_BER_LENGTH) // write essence UL length + && Overhead.WriteRaw((byte_t*)EssenceUL, SMPTE_UL_LENGTH) // write the essence UL + && Overhead.WriteBER(sizeof(ui64_t), MXF_BER_LENGTH) // write SourceLength length + && Overhead.WriteUi64BE(FrameBuf.Size()) // write SourceLength + && Overhead.WriteBER(m_CtFrameBuf.Size(), BER_length) ) ) // write ESV length + { + result = RESULT_KLV_CODING; + } + } + + if ( ASDCP_SUCCESS(result) ) + result = m_File.Writev(Overhead.Data(), Overhead.Length()); + } + + if ( ASDCP_SUCCESS(result) ) + { + m_StreamOffset += Overhead.Length(); + // write encrypted source value + result = m_File.Writev((byte_t*)m_CtFrameBuf.RoData(), m_CtFrameBuf.Size()); + } + + if ( ASDCP_SUCCESS(result) ) + { + m_StreamOffset += m_CtFrameBuf.Size(); + + byte_t hmoverhead[512]; + Kumu::MemIOWriter HMACOverhead(hmoverhead, 512); + + // write the HMAC + if ( m_Info.UsesHMAC ) + { + HMACOverhead.WriteRaw(IntPack.Data, klv_intpack_size); + } + else + { // we still need the var-pack length values if the intpack is empty + for ( ui32_t i = 0; i < 3 ; i++ ) + HMACOverhead.WriteBER(0, MXF_BER_LENGTH); + } + + // write HMAC + result = m_File.Writev(HMACOverhead.Data(), HMACOverhead.Length()); + m_StreamOffset += HMACOverhead.Length(); + } + } + else + { + ui32_t BER_length = MXF_BER_LENGTH; + + if ( FrameBuf.Size() > 0x00ffffff ) // Need BER integer longer than MXF_BER_LENGTH bytes + { + BER_length = Kumu::get_BER_length_for_value(FrameBuf.Size()); + + if ( BER_length == 0 ) + result = RESULT_KLV_CODING; + } + + Overhead.WriteRaw((byte_t*)EssenceUL, SMPTE_UL_LENGTH); + Overhead.WriteBER(FrameBuf.Size(), BER_length); + + if ( ASDCP_SUCCESS(result) ) + result = m_File.Writev(Overhead.Data(), Overhead.Length()); + + if ( ASDCP_SUCCESS(result) ) + result = m_File.Writev((byte_t*)FrameBuf.RoData(), FrameBuf.Size()); + + if ( ASDCP_SUCCESS(result) ) + m_StreamOffset += Overhead.Length() + FrameBuf.Size(); + } + + if ( ASDCP_SUCCESS(result) ) + result = m_File.Writev(); + + if (hash) { + *hash = m_File.StopHashing(); + } + + return result; +} + +Result_t +ASDCP::h__Writer::FakeWriteEKLVPacket(int size) +{ + Result_t result = RESULT_OK; + + m_StreamOffset += size; + m_File.Seek(size, Kumu::SP_POS); + + return result; +} + + +// standard method of writing the header and footer of a completed MXF file +// +Result_t +ASDCP::h__Writer::WriteMXFFooter() +{ + // Set top-level file package correctly for OP-Atom + + // m_MPTCSequence->Duration = m_MPTimecode->Duration = m_MPClSequence->Duration = m_MPClip->Duration = + // m_FPTCSequence->Duration = m_FPTimecode->Duration = m_FPClSequence->Duration = m_FPClip->Duration = + + DurationElementList_t::iterator dli = m_DurationUpdateList.begin(); + + for (; dli != m_DurationUpdateList.end(); dli++ ) + **dli = m_FramesWritten; + + m_EssenceDescriptor->ContainerDuration = m_FramesWritten; + m_FooterPart.PreviousPartition = m_HeaderPart.m_RIP.PairArray.back().ByteOffset; + + Kumu::fpos_t here = m_File.Tell(); + m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(0, here)); // Last RIP Entry + m_HeaderPart.FooterPartition = here; + + assert(m_Dict); + // re-label the partition + UL OPAtomUL(m_Dict->ul(MDD_OPAtom)); + m_HeaderPart.OperationalPattern = OPAtomUL; + m_HeaderPart.m_Preface->OperationalPattern = m_HeaderPart.OperationalPattern; + + m_FooterPart.OperationalPattern = m_HeaderPart.OperationalPattern; + m_FooterPart.EssenceContainers = m_HeaderPart.EssenceContainers; + m_FooterPart.FooterPartition = here; + m_FooterPart.ThisPartition = here; + + Result_t result = m_FooterPart.WriteToFile(m_File, m_FramesWritten); + + if ( ASDCP_SUCCESS(result) ) + result = m_HeaderPart.m_RIP.WriteToFile(m_File); + + if ( ASDCP_SUCCESS(result) ) + result = m_File.Seek(0); + + if ( ASDCP_SUCCESS(result) ) + result = m_HeaderPart.WriteToFile(m_File, m_HeaderSize); + + m_File.Close(); + return result; +} + +// +// end h__Writer.cpp +// diff --git a/asdcplib/src/j2c-test.cpp b/asdcplib/src/j2c-test.cpp new file mode 100755 index 0000000..8f02826 --- /dev/null +++ b/asdcplib/src/j2c-test.cpp @@ -0,0 +1,234 @@ +/* +Copyright (c) 2005-2010, 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 j2c-test.cpp + \version $Id: j2c-test.cpp,v 1.6 2010/06/17 20:11:42 jhurst Exp $ + \brief JP2K parser test +*/ + +#include <AS_DCP.h> +#include <KM_fileio.h> +#include <KM_util.h> +#include <JP2K.h> + +using namespace Kumu; +using namespace ASDCP; +using namespace ASDCP::JP2K; + + + +//------------------------------------------------------------------------------------------ +// +// command line option parser class + +static const char* PROGRAM_NAME = "j2c-test"; // program name for messages + +// Macros used to test command option data state. + +// Increment the iterator, test for an additional non-option command line argument. +// Causes the caller to return if there are no remaining arguments or if the next +// argument begins with '-'. +#define TEST_EXTRA_ARG(i,c) if ( ++i >= argc || argv[(i)][0] == '-' ) \ + { \ + fprintf(stderr, "Argument not found for option %c.\n", (c)); \ + return; \ + } +// +void +banner(FILE* stream = stderr) +{ + fprintf(stream, "\n\ +%s (asdcplib %s)\n\n\ +Copyright (c) 2005-2010 John Hurst\n\n\ +%s is part of asdcplib.\n\ +asdcplib may be copied only under the terms of the license found at\n\ +the top of every file in the asdcplib distribution kit.\n\n\ +Specify the -h (help) option for further information about %s\n\n", + PROGRAM_NAME, ASDCP::Version(), PROGRAM_NAME, PROGRAM_NAME); +} + +// +void +usage(FILE* stream = stderr) +{ + fprintf(stream, "\ +USAGE: %s [-h|-help] [-V]\n\ +\n\ + %s [-r] [-v] <filename> [...]\n\ +\n\ + -V - Show version\n\ + -h - Show help\n\ + -r - Show raw data\n\ + -v - Print extra detail\n\ +\n\ + NOTES: o There is no option grouping, all options must be distinct arguments.\n\ + o All option arguments must be separated from the option by whitespace.\n\ +\n", PROGRAM_NAME, PROGRAM_NAME); +} + +// +// +class CommandOptions +{ + CommandOptions(); + +public: + bool error_flag; // true if the given options are in error or not complete + bool version_flag; // true if the version display option was selected + bool verbose_flag; // true if the verbose option was selected + bool detail_flag; // true if the version display option was selected + bool help_flag; // true if the help display option was selected + std::list<std::string> filename_list; + + CommandOptions(int argc, const char** argv) : + error_flag(true), version_flag(false), verbose_flag(false), + detail_flag(false), help_flag(false) + { + for ( int i = 1; i < argc; i++ ) + { + if ( argv[i][0] == '-' && isalpha(argv[i][1]) && argv[i][2] == 0 ) + { + switch ( argv[i][1] ) + { + case 'V': version_flag = true; break; + case 'h': help_flag = true; break; + case 'r': detail_flag = true; break; + case 'v': verbose_flag = true; break; + + default: + fprintf(stderr, "Unrecognized option: %c\n", argv[i][1]); + return; + } + } + else + { + filename_list.push_back(argv[i]); + } + } + + if ( filename_list.empty() ) + { + fputs("Input j2c filename(s) required.\n", stderr); + return; + } + + error_flag = false; + } +}; + + + + +// +int +main(int argc, const char** argv) +{ + CommandOptions Options(argc, argv); + + if ( Options.version_flag ) + banner(); + + if ( Options.help_flag ) + usage(); + + if ( Options.version_flag || Options.help_flag ) + return 0; + + if ( Options.error_flag ) + { + fprintf(stderr, "There was a problem. Type %s -h for help.\n", PROGRAM_NAME); + return 3; + } + + ASDCP::JP2K::FrameBuffer FB; + Marker MyMarker; + CodestreamParser Parser; + std::list<std::string>::iterator i; + + Result_t result = FB.Capacity(1024*1024*4); + + for ( i = Options.filename_list.begin(); ASDCP_SUCCESS(result) && i != Options.filename_list.end(); i++ ) + { + result = Parser.OpenReadFrame(i->c_str(), FB); + + if ( ASDCP_SUCCESS(result) ) + { + const byte_t* p = FB.RoData(); + const byte_t* end_p = p + FB.Size(); + + while ( p < end_p && ASDCP_SUCCESS(GetNextMarker(&p, MyMarker)) ) + { + if ( Options.verbose_flag ) + { + MyMarker.Dump(stdout); + + if ( Options.detail_flag ) + hexdump(MyMarker.m_Data - 2, MyMarker.m_DataSize + 2, stdout); + } + + switch ( MyMarker.m_Type ) + { + case MRK_SOD: + p = end_p; + break; + + case MRK_SIZ: + { + Accessor::SIZ SIZ_(MyMarker); + SIZ_.Dump(stdout); + } + break; + + case MRK_COM: + { + Accessor::COM COM_(MyMarker); + COM_.Dump(stdout); + } + break; + } + } + } + } + + if ( ASDCP_FAILURE(result) ) + { + fputs("Program stopped on error.\n", stderr); + + if ( result != RESULT_FAIL ) + { + fputs(result, stderr); + fputc('\n', stderr); + } + + return 1; + } + + return 0; +} + +// +// end j2c-test.cpp +// diff --git a/asdcplib/src/jp2k-crypt-tst.sh b/asdcplib/src/jp2k-crypt-tst.sh new file mode 100755 index 0000000..1836fef --- /dev/null +++ b/asdcplib/src/jp2k-crypt-tst.sh @@ -0,0 +1,58 @@ +#!/bin/sh +# +# $Id: jp2k-crypt-tst.sh,v 1.4 2009/04/09 19:16:49 msheby Exp $ +# Copyright (c) 2007-2009 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. + +# crypto JPEG 2000 tests + +${BUILD_DIR}/asdcp-test${EXEEXT} -k ${CRYPT_KEY} \ + -c ${TEST_FILES}/write_crypt_test_jp2k.mxf ${TEST_FILES}/${TEST_FILE_PREFIX} +if [ $? -ne 0 ]; then + exit 1 +fi +${BUILD_DIR}/asdcp-test${EXEEXT} -i ${TEST_FILES}/write_crypt_test_jp2k.mxf +if [ $? -ne 0 ]; then + exit 1 +fi + + +(${BUILD_DIR}/asdcp-test${EXEEXT} -k ${CRYPT_KEY_B} \ + -x ${TEST_FILES}/plaintext ${TEST_FILES}/write_crypt_test_jp2k.mxf; \ + if [ $? -eq 1 ]; then exit 0; fi; exit 1 ) +if [ $? -ne 0 ]; then + exit 1 +fi +${BUILD_DIR}/asdcp-test${EXEEXT} -m -k ${CRYPT_KEY} \ + -x ${TEST_FILES}/plaintext/${JP2K_PREFIX} ${TEST_FILES}/write_crypt_test_jp2k.mxf +if [ $? -ne 0 ]; then + exit 1 +fi +for file in `ls ${TEST_FILES}/${TEST_FILE_PREFIX}`; do \ + echo "$file"; \ + cmp ${TEST_FILES}/${TEST_FILE_PREFIX}/$file ${TEST_FILES}/plaintext/$file; \ + if [ $? -ne 0 ]; then \ + exit 1; \ + fi; \ +done diff --git a/asdcplib/src/jp2k-stereo-crypt-tst.sh b/asdcplib/src/jp2k-stereo-crypt-tst.sh new file mode 100755 index 0000000..e8324a0 --- /dev/null +++ b/asdcplib/src/jp2k-stereo-crypt-tst.sh @@ -0,0 +1,56 @@ +#!/bin/sh +# +# $Id: jp2k-stereo-crypt-tst.sh,v 1.4 2009/04/09 19:16:49 msheby Exp $ +# Copyright (c) 2007-2009 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. + +# crypto JPEG 2000 stereoscopic tests + +${BUILD_DIR}/asdcp-test${EXEEXT} -k ${CRYPT_KEY} \ + -3 -c ${TEST_FILES}/write_crypt_test_jp2k.mxf \ + ${TEST_FILES}/${TEST_FILE_PREFIX} ${TEST_FILES}/${TEST_FILE_PREFIX} +if [ $? -ne 0 ]; then + exit 1 +fi +${BUILD_DIR}/asdcp-test${EXEEXT} -i ${TEST_FILES}/write_crypt_test_jp2k.mxf +if [ $? -ne 0 ]; then + exit 1 +fi + + +(${BUILD_DIR}/asdcp-test${EXEEXT} -k ${CRYPT_KEY_B} \ + -3 -x ${TEST_FILES}/plaintext ${TEST_FILES}/write_crypt_test_jp2k.mxf; \ + if [ $? -eq 1 ]; then exit 0; fi; exit 1 ) +${BUILD_DIR}/asdcp-test${EXEEXT} -m -k ${CRYPT_KEY} \ + -3 -x ${TEST_FILES}/plaintext/${JP2K_PREFIX} ${TEST_FILES}/write_crypt_test_jp2k.mxf +if [ $? -ne 0 ]; then + exit 1 +fi +for file in `ls ${TEST_FILES}/${TEST_FILE_PREFIX}`; do \ + echo "$file"; \ + cmp ${TEST_FILES}/${TEST_FILE_PREFIX}/$file ${TEST_FILES}/plaintext/$file; \ + if [ $? -ne 0 ]; then \ + exit 1; \ + fi; \ +done diff --git a/asdcplib/src/jp2k-stereo-tst.sh b/asdcplib/src/jp2k-stereo-tst.sh new file mode 100755 index 0000000..eacd090 --- /dev/null +++ b/asdcplib/src/jp2k-stereo-tst.sh @@ -0,0 +1,47 @@ +#!/bin/sh +# +# $Id: jp2k-stereo-tst.sh,v 1.3 2009/04/09 19:16:49 msheby Exp $ +# Copyright (c) 2007-2009 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. + +# JPEG 2000 stereoscopic tests + +${BUILD_DIR}/asdcp-test${EXEEXT} -3 -c ${TEST_FILES}/write_test_jp2k.mxf \ + ${TEST_FILES}/${TEST_FILE_PREFIX} ${TEST_FILES}/${TEST_FILE_PREFIX} +if [ $? -ne 0 ]; then + exit 1 +fi + + +${BUILD_DIR}/asdcp-test${EXEEXT} -3 -x ${TEST_FILES}/extract/${JP2K_PREFIX} ${TEST_FILES}/write_test_jp2k.mxf +if [ $? -ne 0 ]; then + exit 1 +fi +for file in `ls ${TEST_FILES}/${TEST_FILE_PREFIX}`; do \ + echo "$file"; \ + cmp ${TEST_FILES}/${TEST_FILE_PREFIX}/$file ${TEST_FILES}/extract/$file; \ + if [ $? -ne 0 ]; then \ + exit 1; \ + fi; \ +done diff --git a/asdcplib/src/jp2k-tst.sh b/asdcplib/src/jp2k-tst.sh new file mode 100755 index 0000000..ee8a18d --- /dev/null +++ b/asdcplib/src/jp2k-tst.sh @@ -0,0 +1,54 @@ +#!/bin/sh +# +# $Id: jp2k-tst.sh,v 1.5 2010/01/05 04:12:15 jhurst Exp $ +# Copyright (c) 2007-2009 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. + +# JPEG 2000 tests + +mkdir -p ${TEST_FILES}/extract ${TEST_FILES}/plaintext + +${BUILD_DIR}/asdcp-test${EXEEXT} -c ${TEST_FILES}/write_test_jp2k.mxf ${TEST_FILES}/${TEST_FILE_PREFIX} +if [ $? -ne 0 ]; then + exit 1 +fi + + +${BUILD_DIR}/asdcp-test${EXEEXT} -x ${TEST_FILES}/extract/${JP2K_PREFIX} ${TEST_FILES}/write_test_jp2k.mxf +if [ $? -ne 0 ]; then + exit 1 +fi +for file in `ls ${TEST_FILES}/${TEST_FILE_PREFIX}`; do \ + echo "$file"; \ + cmp ${TEST_FILES}/${TEST_FILE_PREFIX}/$file ${TEST_FILES}/extract/$file; \ + if [ $? -ne 0 ]; then \ + exit 1; \ + fi; \ +done + + +#${BUILD_DIR}/j2c-test${EXEEXT} ${TEST_FILES}/${TEST_FILE_PREFIX}/MM_2k_XYZ_000000.j2c +#if [ $? -ne 0 ]; then +# exit 1 +#fi diff --git a/asdcplib/src/klvwalk.cpp b/asdcplib/src/klvwalk.cpp new file mode 100755 index 0000000..299cb02 --- /dev/null +++ b/asdcplib/src/klvwalk.cpp @@ -0,0 +1,287 @@ +/* +Copyright (c) 2005-2009, 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 klvwalk.cpp + \version $Id: klvwalk.cpp,v 1.18 2010/11/15 17:04:13 jhurst Exp $ + \brief KLV+MXF test +*/ + +#include "AS_DCP.h" +#include "MXF.h" +#include <KM_log.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <assert.h> +#include <sys/types.h> +#include <sys/stat.h> + +using namespace ASDCP; +using Kumu::DefaultLogSink; + + +//------------------------------------------------------------------------------------------ +// +// command line option parser class + +static const char* PROGRAM_NAME = "klvwalk"; // program name for messages +typedef std::list<std::string> FileList_t; + +// Increment the iterator, test for an additional non-option command line argument. +// Causes the caller to return if there are no remaining arguments or if the next +// argument begins with '-'. +#define TEST_EXTRA_ARG(i,c) if ( ++i >= argc || argv[(i)][0] == '-' ) \ + { \ + fprintf(stderr, "Argument not found for option -%c.\n", (c)); \ + return; \ + } + +// +void +banner(FILE* stream = stdout) +{ + fprintf(stream, "\n\ +%s (asdcplib %s)\n\n\ +Copyright (c) 2005-2009 John Hurst\n\ +%s is part of the asdcplib DCP tools package.\n\ +asdcplib may be copied only under the terms of the license found at\n\ +the top of every file in the asdcplib distribution kit.\n\n\ +Specify the -h (help) option for further information about %s\n\n", + PROGRAM_NAME, ASDCP::Version(), PROGRAM_NAME, PROGRAM_NAME); +} + +// +void +usage(FILE* stream = stdout) +{ + fprintf(stream, "\ +USAGE: %s [-r] [-v] <input-file> [<input-file2> ...]\n\ +\n\ + %s [-h|-help] [-V]\n\ +\n\ + -h | -help - Show help\n\ + -r - When KLV data is an MXF OPAtom file, display OPAtom headers\n\ + -v - Verbose. Prints informative messages to stderr\n\ + -V - Show version information\n\ +\n\ + NOTES: o There is no option grouping, all options must be distinct arguments.\n\ + o All option arguments must be separated from the option by whitespace.\n\ +\n", PROGRAM_NAME, PROGRAM_NAME); +} + +// +// + class CommandOptions + { + CommandOptions(); + + public: + bool error_flag; // true if the given options are in error or not complete + bool version_flag; // true if the version display option was selected + bool help_flag; // true if the help display option was selected + bool verbose_flag; // true if the informative messages option was selected + bool read_mxf_flag; // true if the -r option was selected + FileList_t inFileList; // File to operate on + + CommandOptions(int argc, const char** argv) : + error_flag(true), version_flag(false), help_flag(false), verbose_flag(false), read_mxf_flag(false) + { + for ( int i = 1; i < argc; i++ ) + { + + if ( (strcmp( argv[i], "-help") == 0) ) + { + help_flag = true; + continue; + } + + if ( argv[i][0] == '-' && isalpha(argv[i][1]) && argv[i][2] == 0 ) + { + switch ( argv[i][1] ) + { + case 'h': help_flag = true; break; + case 'r': read_mxf_flag = true; break; + case 'V': version_flag = true; break; + case 'v': verbose_flag = true; break; + + default: + fprintf(stderr, "Unrecognized option: %s\n", argv[i]); + return; + } + } + else + { + if ( argv[i][0] != '-' ) + inFileList.push_back(argv[i]); + + else + { + fprintf(stderr, "Unrecognized option: %s\n", argv[i]); + return; + } + } + } + + if ( help_flag || version_flag ) + return; + + if ( inFileList.empty() ) + { + fputs("Input filename(s) required.\n", stderr); + return; + } + + error_flag = false; + } + }; + + +//--------------------------------------------------------------------------------------------------- +// + +int +main(int argc, const char** argv) +{ + CommandOptions Options(argc, argv); + + if ( Options.version_flag ) + banner(); + + if ( Options.help_flag ) + usage(); + + if ( Options.version_flag || Options.help_flag ) + return 0; + + if ( Options.error_flag ) + { + fprintf(stderr, "There was a problem. Type %s -h for help.\n", PROGRAM_NAME); + return 3; + } + + FileList_t::iterator fi; + Result_t result = RESULT_OK; + + for ( fi = Options.inFileList.begin(); ASDCP_SUCCESS(result) && fi != Options.inFileList.end(); fi++ ) + { + if (Options.verbose_flag) + fprintf(stderr, "Opening file %s\n", ((*fi).c_str())); + + if ( Options.read_mxf_flag ) // dump MXF + { + Kumu::FileReader Reader; + const Dictionary* Dict = &DefaultCompositeDict(); + ASDCP::MXF::OPAtomHeader Header(Dict); + + result = Reader.OpenRead((*fi).c_str()); + + if ( ASDCP_SUCCESS(result) ) + result = Header.InitFromFile(Reader); + + if ( ASDCP_SUCCESS(result) ) + Header.Dump(stdout); + + if ( ASDCP_SUCCESS(result) && Header.m_RIP.PairArray.size() > 2 ) + { + MXF::Array<MXF::RIP::Pair>::const_iterator pi = Header.m_RIP.PairArray.begin(); + + for ( pi++; pi != Header.m_RIP.PairArray.end() && ASDCP_SUCCESS(result); pi++ ) + { + result = Reader.Seek((*pi).ByteOffset); + + if ( ASDCP_SUCCESS(result) ) + { + MXF::Partition TmpPart(Dict); + result = TmpPart.InitFromFile(Reader); + + if ( ASDCP_SUCCESS(result) && TmpPart.BodySID > 0 ) + TmpPart.Dump(stdout); + } + } + } + + if ( ASDCP_SUCCESS(result) ) + { + ASDCP::MXF::OPAtomIndexFooter Index(Dict); + result = Reader.Seek(Header.FooterPartition); + + if ( ASDCP_SUCCESS(result) ) + { + Index.m_Lookup = &Header.m_Primer; + result = Index.InitFromFile(Reader); + } + + if ( ASDCP_SUCCESS(result) ) + Index.Dump(stdout); + } + + if ( ASDCP_SUCCESS(result) ) + Header.m_RIP.Dump(stdout); + } + else // dump klv + { + Kumu::FileReader Reader; + KLVFilePacket KP; + ui64_t pos = 0; + + result = Reader.OpenRead((*fi).c_str()); + + if ( ASDCP_SUCCESS(result) ) + result = KP.InitFromFile(Reader); + + while ( ASDCP_SUCCESS(result) ) + { + fprintf(stdout, "@0x%08qx: ", pos); + KP.Dump(stdout, DefaultCompositeDict(), true); + pos = Reader.Tell(); + result = KP.InitFromFile(Reader); + } + + if( result == RESULT_ENDOFFILE ) + result = RESULT_OK; + } + } + + if ( ASDCP_FAILURE(result) ) + { + fputs("Program stopped on error.\n", stderr); + + if ( result != RESULT_FAIL ) + { + fputs(result, stderr); + fputc('\n', stderr); + } + + return 1; + } + + return 0; +} + + +// +// end klvwalk.cpp +// diff --git a/asdcplib/src/kmfilegen.cpp b/asdcplib/src/kmfilegen.cpp new file mode 100755 index 0000000..fb4360e --- /dev/null +++ b/asdcplib/src/kmfilegen.cpp @@ -0,0 +1,616 @@ +/* +Copyright (c) 2005-2009, 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 kmfilegen.cpp + \version $Id: kmfilegen.cpp,v 1.8 2009/03/04 17:52:45 jhurst Exp $ + \brief large file test program +*/ + + +#include "AS_DCP.h" +#include <iostream> +#include <KM_fileio.h> +#include <KM_prng.h> +#include <openssl/aes.h> +#include <assert.h> + +using namespace Kumu; + +// constants +static const char* PROGRAM_NAME = "kmfilegen"; // program name for messages +const ui32_t RNG_KEY_SIZE = 16; +const ui32_t RNG_KEY_SIZE_BITS = 128; +const ui32_t RNG_BLOCK_SIZE = 16; + +// globals +ui32_t s_Nonce = 0; +FortunaRNG s_RNG; + + +//------------------------------------------------------------------------------------------ +// +// command line option parser class + +// Increment the iterator, test for an additional non-option command line argument. +// Causes the caller to return if there are no remaining arguments or if the next +// argument begins with '-'. +#define TEST_EXTRA_ARG(i,c) if ( ++i >= argc || argv[(i)][0] == '-' ) \ + { \ + fprintf(stderr, "Argument not found for option -%c.\n", (c)); \ + return; \ + } + +// +void +banner(FILE* stream = stdout) +{ + fprintf(stream, "\n\ +%s (asdcplib %s)\n\n\ +Copyright (c) 2005-2009 John Hurst\n\ +%s is part of the asdcplib DCP tools package.\n\ +asdcplib may be copied only under the terms of the license found at\n\ +the top of every file in the asdcplib distribution kit.\n\n\ +Specify the -h (help) option for further information about %s\n\n", + PROGRAM_NAME, Kumu::Version(), PROGRAM_NAME, PROGRAM_NAME); +} + + +// +void +usage(FILE* stream = stdout) +{ + fprintf(stream, "\ +USAGE: %s [-c <file-size>] [-v] <output-file>\n\ +\n\ + %s [-o <fwd|rev|rand>] [-v] <input-file>\n\ +\n\ + %s [-w <output-file>] [-v] <input-file>\n\ +\n\ + %s [-h|-help] [-V]\n\ +\n\ + -c <file-size> - Create test file containing <file-size> megabytes of data\n\ + -h | -help - Show help\n\ + -o <fwd|rev|rand> - Specify order used when validating a file.\n\ + One of fwd|rev|rand, default is rand\n\ + -v - Verbose. Prints informative messages to stderr\n\ + -V - Show version information\n\ + -w <output-file> - Read-Validate-Write - file is written to <output-file>\n\ + (sequential read only)\n\ +\n\ + NOTES: o There is no option grouping, all options must be distinct arguments.\n\ + o All option arguments must be separated from the option by whitespace.\n\ +\n", PROGRAM_NAME, PROGRAM_NAME, PROGRAM_NAME, PROGRAM_NAME); +} + +enum MajorMode_t { + MMT_NONE, + MMT_CREATE, + MMT_VALIDATE, + MMT_VAL_WRITE +}; + +// +class CommandOptions +{ + CommandOptions(); + +public: + bool error_flag; // true if the given options are in error or not complete + const char* order; // one of fwd|rev|rand + bool verbose_flag; // true if the verbose option was selected + bool version_flag; // true if the version display option was selected + bool help_flag; // true if the help display option was selected + const char* filename; // filename to be processed + const char* write_filename; // filename to write with val_write_flag + ui32_t chunk_count; + MajorMode_t mode; // MajorMode selector + + // + CommandOptions(int argc, const char** argv) : + error_flag(true), order(""), verbose_flag(false), version_flag(false), help_flag(false), + filename(""), write_filename(""), chunk_count(0), mode(MMT_VALIDATE) + { + // order = "rand"; + + for ( int i = 1; i < argc; i++ ) + { + + if ( (strcmp( argv[i], "-help") == 0) ) + { + help_flag = true; + continue; + } + + if ( argv[i][0] == '-' && isalpha(argv[i][1]) && argv[i][2] == 0 ) + { + switch ( argv[i][1] ) + { + case 'c': + mode = MMT_CREATE; + TEST_EXTRA_ARG(i, 'c'); + chunk_count = atoi(argv[i]); + break; + + case 'V': version_flag = true; break; + case 'h': help_flag = true; break; + case 'v': verbose_flag = true; break; + + case 'o': + TEST_EXTRA_ARG(i, 'o'); + order = argv[i]; + + if ( strcmp(order, "fwd" ) != 0 + && strcmp(order, "rev" ) != 0 + && strcmp(order, "rand" ) != 0 ) + { + fprintf(stderr, "Unexpected order token: %s, expecting fwd|rev|rand\n", order); + return; + } + + break; + + case 'w': + mode = MMT_VAL_WRITE; + TEST_EXTRA_ARG(i, 'w'); + write_filename = argv[i]; + break; + + default: + fprintf(stderr, "Unrecognized option: %s\n", argv[i]); + return; + } + } + else + { + if (argv[i][0] != '-' ) + { + if ( filename != "" ) + { + fprintf(stderr, "Extra filename found: %s\n", argv[i]); + return; + } + else + filename = argv[i]; + } + else + { + fprintf(stderr, "Unrecognized option: %s\n", argv[i]); + return; + } + } + } + + if ( help_flag || version_flag ) + return; + + if ( strlen ( filename ) == 0 ) + { + fprintf(stderr, "Filename required.\n"); + return; + } + + if ( mode != MMT_VALIDATE && strcmp(order, "") != 0 ) + { + fprintf(stderr, "-o option not valid with -c or -w options.\n"); + return; + } + else + if ( strcmp(order, "") == 0 ) + order = "rand"; + + if ( strcmp ( filename, write_filename ) == 0 ) + { + fprintf(stderr, "Output and input files must be different.\n"); + return; + } + + error_flag = false; + } +}; + +//------------------------------------------------------------------------------------------ + + +// +#pragma pack(4) +class CTR_Setup +{ + AES_KEY m_Context; + byte_t m_key[RNG_KEY_SIZE]; + byte_t m_preamble[8]; + ui32_t m_nonce; + ui32_t m_ctr; + + KM_NO_COPY_CONSTRUCT(CTR_Setup); + +public: + CTR_Setup() {} + ~CTR_Setup() {} + + inline ui32_t Nonce() { return KM_i32_LE(m_nonce); } + inline ui32_t WriteSize() { return ( sizeof(m_key) + sizeof(m_preamble) + + sizeof(m_nonce) + sizeof(m_ctr) ); } + + // + void SetupWrite(byte_t* buf) + { + assert(buf); + s_RNG.FillRandom(m_key, WriteSize()); + assert(s_Nonce > 0); + m_nonce = KM_i32_LE(s_Nonce--); + m_ctr &= KM_i32_LE(0x7fffffff); // make sure we have 2GB headroom + memcpy(buf, m_key, WriteSize()); + AES_set_encrypt_key(m_key, RNG_KEY_SIZE_BITS, &m_Context); + } + + // + void SetupRead(const byte_t* buf) + { + assert(buf); + memcpy(m_key, buf, WriteSize()); + AES_set_encrypt_key(m_key, RNG_KEY_SIZE_BITS, &m_Context); + } + + // + void FillRandom(byte_t* buf, ui32_t buf_len) + { + ui32_t gen_count = 0; + while ( gen_count + RNG_BLOCK_SIZE <= buf_len ) + { + AES_encrypt(m_preamble, buf + gen_count, &m_Context); + m_ctr = KM_i32_LE(KM_i32_LE(m_ctr) + 1); + gen_count += RNG_BLOCK_SIZE; + } + } +}; + +// +Result_t +CreateLargeFile(CommandOptions& Options) +{ + ui32_t write_total = 0; + ui32_t write_count = 0; + FileWriter Writer; + ByteString FB; + + FB.Capacity(Megabyte); + assert(FB.Capacity() == Megabyte); + + fprintf(stderr, "Writing %u chunks:\n", Options.chunk_count); + s_Nonce = Options.chunk_count; + Result_t result = Writer.OpenWrite(Options.filename); + + while ( KM_SUCCESS(result) && write_total < Options.chunk_count ) + { + if ( KM_SUCCESS(result)) + { + CTR_Setup CTR; + CTR.SetupWrite(FB.Data()); + CTR.FillRandom(FB.Data() + CTR.WriteSize(), Megabyte - CTR.WriteSize()); + result = Writer.Write(FB.RoData(), Megabyte, &write_count); + assert(write_count == Megabyte); + fprintf(stderr, "\r%8u ", ++write_total); + } + } + + fputs("\n", stderr); + + return result; +} + +// +Result_t +validate_chunk(ByteString& FB, ByteString& CB, ui32_t* nonce_value) +{ + assert(nonce_value); + CTR_Setup CTR; + CTR.SetupRead(FB.RoData()); + + CTR.FillRandom(CB.Data() + CTR.WriteSize(), + Megabyte - CTR.WriteSize()); + + if ( memcmp(FB.RoData() + CTR.WriteSize(), + CB.RoData() + CTR.WriteSize(), + Megabyte - CTR.WriteSize()) != 0 ) + { + fprintf(stderr, "Check data mismatched in chunk\n"); + return RESULT_FAIL; + } + + *nonce_value = CTR.Nonce(); + + return RESULT_OK; +} + +// +struct read_list_t +{ + ui32_t nonce; + Kumu::fpos_t position; +}; + +// +void +randomize_list(read_list_t* read_list, ui32_t check_total) +{ + static ui32_t tmp_ints[4]; + static ui32_t seq = 0; + + for ( ui32_t j = 0; j < check_total; j++ ) + { + if ( seq > 3 ) + seq = 0; + + if ( seq == 0 ) + s_RNG.FillRandom((byte_t*)tmp_ints, 16); + + ui32_t i = tmp_ints[seq++] % (check_total - 1); + + if ( i == j ) + continue; + + read_list_t t = read_list[i]; + read_list[i] = read_list[j]; + read_list[j] = t; + } +} + +// +Result_t +ReadValidateWriteLargeFile(CommandOptions& Options) +{ + assert(Options.write_filename); + ui32_t check_total = 0; + ui32_t write_total = 0; + ui32_t read_count = 0; + ui32_t write_count = 0; + FileReader Reader; + FileWriter Writer; + ByteString FB, CB; // Frame Buffer and Check Buffer + + + FB.Capacity(Megabyte); + assert(FB.Capacity() == Megabyte); + CB.Capacity(Megabyte); + assert(CB.Capacity() == Megabyte); + + Result_t result = Reader.OpenRead(Options.filename); + + if ( KM_SUCCESS(result) ) + result = Writer.OpenWrite(Options.write_filename); + + // read the first chunk and get set up + while ( KM_SUCCESS(result) ) + { + result = Reader.Read(FB.Data(), Megabyte, &read_count); + + if ( KM_SUCCESS(result) ) + { + if ( read_count < Megabyte ) + { + fprintf(stderr, "Read() returned short buffer: %u\n", read_count); + result = RESULT_FAIL; + } + + result = validate_chunk(FB, CB, &check_total); + + if ( KM_SUCCESS(result) ) + { + result = Writer.Write(FB.RoData(), Megabyte, &write_count); + assert(write_count == Megabyte); + fprintf(stderr, "\r%8u ", ++write_total); + } + } + else if ( result == RESULT_ENDOFFILE ) + { + result = RESULT_OK; + break; + } + } + + fputs("\n", stderr); + return result; +} + + +// +Result_t +ValidateLargeFile(CommandOptions& Options) +{ + ui32_t check_total = 0; + ui32_t read_count = 0; + ui32_t read_list_i = 0; + read_list_t* read_list = 0; + FileReader Reader; + ByteString FB, CB; // Frame Buffer and Check Buffer + + FB.Capacity(Megabyte); + assert(FB.Capacity() == Megabyte); + CB.Capacity(Megabyte); + assert(CB.Capacity() == Megabyte); + + Result_t result = Reader.OpenRead(Options.filename); + + // read the first chunk and get set up + if ( KM_SUCCESS(result) ) + { + result = Reader.Read(FB.Data(), Megabyte, &read_count); + + if ( read_count < Megabyte ) + { + fprintf(stderr, "Read() returned short buffer: %u\n", read_count); + result = RESULT_FAIL; + } + else if ( KM_SUCCESS(result) ) + result = validate_chunk(FB, CB, &check_total); + + if ( KM_SUCCESS(result) ) + { + fprintf(stderr, "Validating %u chunk%s in %s order:\n", + check_total, (check_total == 1 ? "" : "s"), Options.order); + assert(read_list == 0); + read_list = (read_list_t*)malloc(check_total * sizeof(read_list_t)); + assert(read_list); + + // Set up an index to the chunks. The chunks are written + // to the file in order of descending nonce value. + if ( strcmp(Options.order, "fwd") == 0 ) + { + for ( ui32_t i = 0; i < check_total; i++ ) + { + read_list[i].nonce = check_total - i; + Kumu::fpos_t ofst = check_total - read_list[i].nonce; + read_list[i].position = ofst * (Kumu::fpos_t)Megabyte; + } + } + else + { + for ( ui32_t i = 0; i < check_total; i++ ) + { + read_list[i].nonce = i + 1; + Kumu::fpos_t ofst = check_total - read_list[i].nonce; + read_list[i].position = ofst * (Kumu::fpos_t)Megabyte; + } + + if ( strcmp(Options.order, "rand") == 0 ) + randomize_list(read_list, check_total); // this makes it random + } + } + } + + if ( KM_SUCCESS(result) ) + { + assert(read_list); + ui32_t nonce = 0; + + for ( read_list_i = 0; + read_list_i < check_total && KM_SUCCESS(result); + read_list_i++ ) + { + fprintf(stderr, "\r%8u [%8u] ", read_list_i+1, read_list[read_list_i].nonce); + result = Reader.Seek(read_list[read_list_i].position); + + if ( KM_SUCCESS(result) ) + result = Reader.Read(FB.Data(), Megabyte, &read_count); + + if ( result == RESULT_ENDOFFILE ) + break; + + else if ( read_count < Megabyte ) + { + fprintf(stderr, "Read() returned short buffer: %u\n", read_count); + result = RESULT_FAIL; + } + else if ( KM_SUCCESS(result) ) + { + result = validate_chunk(FB, CB, &nonce); + + if ( nonce != read_list[read_list_i].nonce ) + { + fprintf(stderr, "Nonce mismatch: expecting %u, got %u\n", + nonce, read_list[read_list_i].nonce); + + return RESULT_FAIL; + } + } + } + } + + fputs("\n", stderr); + + if ( result == RESULT_ENDOFFILE ) + { + if ( check_total == read_list_i ) + result = RESULT_OK; + else + { + fprintf(stderr, "Unexpected chunk count, got %u, wanted %u\n", + read_list_i, check_total); + result = RESULT_FAIL; + } + } + + return result; +} + +// +int +main(int argc, const char **argv) +{ + Result_t result = RESULT_FAIL; + CommandOptions Options(argc, argv); + + if ( Options.version_flag ) + banner(); + + if ( Options.help_flag ) + usage(); + + if ( Options.version_flag || Options.help_flag ) + return 0; + + if ( Options.error_flag ) + { + fprintf(stderr, "There was a problem. Type %s -h for help.\n", PROGRAM_NAME); + return 3; + } + + switch ( Options.mode ) + { + + case MMT_CREATE: + result = CreateLargeFile(Options); + break; + + case MMT_VALIDATE: + result = ValidateLargeFile(Options); + break; + + case MMT_VAL_WRITE: + result = ReadValidateWriteLargeFile(Options); + break; + } + + if ( result != RESULT_OK ) + { + fputs("Program stopped on error.\n", stderr); + + if ( result != RESULT_FAIL ) + { + fputs(result.Label(), stderr); + fputc('\n', stderr); + } + + return 1; + } + + return 0; +} + + +// +// end kmfilegen.cpp +// diff --git a/asdcplib/src/kmrandgen.cpp b/asdcplib/src/kmrandgen.cpp new file mode 100644 index 0000000..560fa6e --- /dev/null +++ b/asdcplib/src/kmrandgen.cpp @@ -0,0 +1,292 @@ +/* +Copyright (c) 2005-2009, 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 kmrandgen.cpp + \version $Id: kmrandgen.cpp,v 1.8 2009/03/04 17:52:45 jhurst Exp $ + \brief psuedo-random number generation utility + */ + +#include "AS_DCP.h" +#include <KM_fileio.h> +#include <KM_prng.h> +#include <ctype.h> + +using namespace Kumu; + +const ui32_t RandBlockSize = 16; +const char* PROGRAM_NAME = "kmrandgen"; + +// Increment the iterator, test for an additional non-option command line argument. +// Causes the caller to return if there are no remaining arguments or if the next +// argument begins with '-'. +#define TEST_EXTRA_ARG(i,c) if ( ++i >= argc || argv[(i)][0] == '-' ) \ + { \ + fprintf(stderr, "Argument not found for option -%c.\n", (c)); \ + return; \ + } + +// +void +banner(FILE* stream = stdout) +{ + fprintf(stream, "\n\ +%s (asdcplib %s)\n\n\ +Copyright (c) 2003-2009 John Hurst\n\n\ +%s is part of the asdcp DCP tools package.\n\ +asdcplib may be copied only under the terms of the license found at\n\ +the top of every file in the asdcplib distribution kit.\n\n\ +Specify the -h (help) option for further information about %s\n\n", + PROGRAM_NAME, Kumu::Version(), PROGRAM_NAME, PROGRAM_NAME); +} + +// +void +usage(FILE* stream = stdout) +{ + fprintf(stream, "\ +USAGE: %s [-b|-B|-c|-x] [-n] [-s <size>] [-v]\n\ +\n\ + %s [-h|-help] [-V]\n\ +\n\ + -b - Output a stream of binary data\n\ + -B - Output a Base64 string\n\ + -c - Output a C-language struct containing the values\n\ + -h | -help - Show help\n\ + -n - Suppress newlines\n\ + -s <size> - Number of random bytes to generate (default 32)\n\ + -v - Verbose. Prints informative messages to stderr\n\ + -V - Show version information\n\ + -x - Output hexadecimal (default)\n\ +\n\ + NOTES: o There is no option grouping, all options must be distinct arguments.\n\ + o All option arguments must be separated from the option by whitespace.\n\ +\n", PROGRAM_NAME, PROGRAM_NAME); +} + +enum OutputFormat_t { + OF_HEX, + OF_BINARY, + OF_BASE64, + OF_CSTRUCT +}; + +// +class CommandOptions +{ + CommandOptions(); + +public: + bool error_flag; // true if the given options are in error or not complete + bool no_newline_flag; // + bool verbose_flag; // true if the verbose option was selected + bool version_flag; // true if the version display option was selected + bool help_flag; // true if the help display option was selected + OutputFormat_t format; // + ui32_t request_size; + + // + CommandOptions(int argc, const char** argv) : + error_flag(true), no_newline_flag(false), verbose_flag(false), + version_flag(false), help_flag(false), format(OF_HEX), request_size(RandBlockSize*2) + { + for ( int i = 1; i < argc; i++ ) + { + + if ( (strcmp( argv[i], "-help") == 0) ) + { + help_flag = true; + continue; + } + + if ( argv[i][0] == '-' && isalpha(argv[i][1]) && argv[i][2] == 0 ) + { + switch ( argv[i][1] ) + { + case 'b': format = OF_BINARY; break; + case 'B': format = OF_BASE64; break; + case 'c': format = OF_CSTRUCT; break; + case 'n': no_newline_flag = true; break; + case 'h': help_flag = true; break; + + case 's': + TEST_EXTRA_ARG(i, 's'); + request_size = abs(atoi(argv[i])); + break; + + case 'v': verbose_flag = true; break; + case 'V': version_flag = true; break; + case 'x': format = OF_HEX; break; + + default: + fprintf(stderr, "Unrecognized option: %s\n", argv[i]); + return; + } + } + else + { + fprintf(stderr, "Unrecognized option: %s\n", argv[i]); + return; + } + } + + if ( help_flag || version_flag ) + return; + + if ( request_size == 0 ) + { + fprintf(stderr, "Please use a non-zero request size\n"); + return; + } + + error_flag = false; + } +}; + + +// +int +main(int argc, const char** argv) +{ + CommandOptions Options(argc, argv); + + if ( Options.version_flag ) + banner(); + + if ( Options.help_flag ) + usage(); + + if ( Options.version_flag || Options.help_flag ) + return 0; + + if ( Options.error_flag ) + { + fprintf(stderr, "There was a problem. Type %s -h for help.\n", PROGRAM_NAME); + return 3; + } + + FortunaRNG RandGen; + ByteString Buf(Kumu::Kilobyte); + + if ( Options.verbose_flag ) + fprintf(stderr, "Generating %d random byte%s.\n", Options.request_size, (Options.request_size == 1 ? "" : "s")); + + if ( Options.format == OF_BINARY ) + { + if ( KM_FAILURE(Buf.Capacity(Options.request_size)) ) + { + fprintf(stderr, "randbuf: %s\n", RESULT_ALLOC.Label()); + return 1; + } + + RandGen.FillRandom(Buf.Data(), Options.request_size); + fwrite((byte_t*)Buf.Data(), 1, Options.request_size, stdout); + } + else if ( Options.format == OF_CSTRUCT ) + { + ui32_t line_count = 0; + byte_t* p = Buf.Data(); + printf("byte_t rand_buf[%u] = {\n", Options.request_size); + + if ( Options.request_size > 128 ) + fputs(" // 0x00000000\n", stdout); + + while ( Options.request_size > 0 ) + { + if ( line_count > 0 && (line_count % (RandBlockSize*8)) == 0 ) + fprintf(stdout, " // 0x%08x\n", line_count); + + RandGen.FillRandom(p, RandBlockSize); + fputc(' ', stdout); + + for ( ui32_t i = 0; i < RandBlockSize && Options.request_size > 0; i++, Options.request_size-- ) + printf(" 0x%02x,", p[i]); + + fputc('\n', stdout); + line_count += RandBlockSize; + } + + fputs("};", stdout); + + if ( ! Options.no_newline_flag ) + fputc('\n', stdout); + } + else if ( Options.format == OF_BASE64 ) + { + if ( KM_FAILURE(Buf.Capacity(Options.request_size)) ) + { + fprintf(stderr, "randbuf: %s\n", RESULT_ALLOC.Label()); + return 1; + } + + ByteString Strbuf; + ui32_t e_len = base64_encode_length(Options.request_size) + 1; + + if ( KM_FAILURE(Strbuf.Capacity(e_len)) ) + { + fprintf(stderr, "strbuf: %s\n", RESULT_ALLOC.Label()); + return 1; + } + + RandGen.FillRandom(Buf.Data(), Options.request_size); + + if ( base64encode(Buf.RoData(), Options.request_size, (char*)Strbuf.Data(), Strbuf.Capacity()) == 0 ) + { + fprintf(stderr, "encode error\n"); + return 2; + } + + fputs((const char*)Strbuf.RoData(), stdout); + + if ( ! Options.no_newline_flag ) + fputs("\n", stdout); + } + else // OF_HEX + { + byte_t* p = Buf.Data(); + char hex_buf[64]; + + while ( Options.request_size > 0 ) + { + ui32_t x_len = xmin(Options.request_size, RandBlockSize); + RandGen.FillRandom(p, RandBlockSize); + bin2hex(p, x_len, hex_buf, 64); + fputs(hex_buf, stdout); + + if ( ! Options.no_newline_flag ) + fputc('\n', stdout); + + Options.request_size -= x_len; + } + + } + + return 0; +} + + +// +// end kmrandgen.cpp +// diff --git a/asdcplib/src/kmuuidgen.cpp b/asdcplib/src/kmuuidgen.cpp new file mode 100644 index 0000000..d57154b --- /dev/null +++ b/asdcplib/src/kmuuidgen.cpp @@ -0,0 +1,195 @@ +/* +Copyright (c) 2005-2009, 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 kmuuidgen.cpp + \version $Id: kmuuidgen.cpp,v 1.7 2009/03/04 17:52:45 jhurst Exp $ + \brief UUID generation utility + */ + +#include "AS_DCP.h" +#include <KM_util.h> +#include <ctype.h> + + +const char* PROGRAM_NAME = "kmuuidgen"; + +// Increment the iterator, test for an additional non-option command line argument. +// Causes the caller to return if there are no remaining arguments or if the next +// argument begins with '-'. +#define TEST_EXTRA_ARG(i,c) if ( ++i >= argc || argv[(i)][0] == '-' ) \ + { \ + fprintf(stderr, "Argument not found for option -%c.\n", (c)); \ + return; \ + } + +// +void +banner(FILE* stream = stdout) +{ + fprintf(stream, "\n\ +%s (asdcplib %s)\n\n\ +Copyright (c) 2003-2009 John Hurst\n\n\ +%s is part of the asdcp DCP tools package.\n\ +asdcplib may be copied only under the terms of the license found at\n\ +the top of every file in the asdcplib distribution kit.\n\n\ +Specify the -h (help) option for further information about %s\n\n", + PROGRAM_NAME, Kumu::Version(), PROGRAM_NAME, PROGRAM_NAME); +} + +// +void +usage(FILE* stream = stdout) +{ + fprintf(stream, "\ +USAGE: %s [-c] [-n] [-v]\n\ +\n\ + %s [-h|-help] [-V]\n\ +\n\ + -c - Output a C-language struct containing the value\n\ + -h | -help - Show help\n\ + -n - Suppress the newline\n\ + -v - Verbose. Prints informative messages to stderr\n\ + -V - Show version information\n\ +\n\ + NOTES: o There is no option grouping, all options must be distinct arguments.\n\ + o All option arguments must be separated from the option by whitespace.\n\ +\n", PROGRAM_NAME, PROGRAM_NAME); +} + +// +class CommandOptions +{ + CommandOptions(); + +public: + bool error_flag; // true if the given options are in error or not complete + bool no_newline_flag; // + bool c_array_flag; // + bool version_flag; // true if the version display option was selected + bool help_flag; // true if the help display option was selected + bool verbose_flag; // true if the verbose flag was selected + + // + CommandOptions(int argc, const char** argv) : + error_flag(true), no_newline_flag(false), c_array_flag(false), version_flag(false), + help_flag(false), verbose_flag(false) + { + for ( int i = 1; i < argc; i++ ) + { + + if ( (strcmp( argv[i], "-help") == 0) ) + { + help_flag = true; + continue; + } + + if ( argv[i][0] == '-' && isalpha(argv[i][1]) && argv[i][2] == 0 ) + { + switch ( argv[i][1] ) + { + case 'c': c_array_flag = true; break; + case 'n': no_newline_flag = true; break; + case 'h': help_flag = true; break; + case 'v': verbose_flag = true; break; + case 'V': version_flag = true; break; + + default: + fprintf(stderr, "Unrecognized option: %s\n", argv[i]); + return; + } + } + else + { + fprintf(stderr, "Unrecognized option: %s\n", argv[i]); + return; + } + } + + if ( help_flag || version_flag ) + return; + + error_flag = false; + } +}; + + + +// +int +main(int argc, const char** argv) +{ + CommandOptions Options(argc, argv); + + if ( Options.version_flag ) + banner(); + + if ( Options.help_flag ) + usage(); + + if ( Options.version_flag || Options.help_flag ) + return 0; + + if ( Options.error_flag ) + { + fprintf(stderr, "There was a problem. Type %s -h for help.\n", PROGRAM_NAME); + return 3; + } + + Kumu::UUID UUID; + Kumu::GenRandomValue(UUID); + char uuid_buf[40]; + + if ( Options.c_array_flag ) + { + const byte_t* p = UUID.Value(); + + printf("\ +byte_t uuid_buf[] = {\n\ + // %s\n ", + UUID.EncodeHex(uuid_buf, 40)); + + for ( ui32_t i = 0; i < 16; i++ ) + printf(" 0x%02x,", p[i]); + + printf("\n"); + printf("};\n"); + return 0; + } + else + { + fputs(UUID.EncodeHex(uuid_buf, 40), stdout); + } + + if ( Options.no_newline_flag == 0 ) + printf("\n"); + + return 0; +} + + +// +// end kmuuidgen.cpp +// diff --git a/asdcplib/src/mpeg-crypt-tst.sh b/asdcplib/src/mpeg-crypt-tst.sh new file mode 100755 index 0000000..3a952f7 --- /dev/null +++ b/asdcplib/src/mpeg-crypt-tst.sh @@ -0,0 +1,52 @@ +#!/bin/sh +# +# $Id: mpeg-crypt-tst.sh,v 1.3 2009/04/09 19:16:49 msheby Exp $ +# Copyright (c) 2007-2009 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. + +# crypto MPEG tests + +${BUILD_DIR}/asdcp-test${EXEEXT} -k ${CRYPT_KEY} \ + -c ${TEST_FILES}/write_crypt_test_mpeg.mxf ${TEST_FILES}/${TEST_FILE_PREFIX}.mpg +if [ $? -ne 0 ]; then + exit 1 +fi +${BUILD_DIR}/asdcp-test${EXEEXT} -i ${TEST_FILES}/write_crypt_test_mpeg.mxf +if [ $? -ne 0 ]; then + exit 1 +fi + + +(${BUILD_DIR}/asdcp-test${EXEEXT} -k ${CRYPT_KEY_B} \ + -x ${TEST_FILES}/plaintext ${TEST_FILES}/write_crypt_test_mpeg.mxf; \ + if [ $? -eq 1 ]; then exit 0; fi; exit 1 ) +${BUILD_DIR}/asdcp-test${EXEEXT} -m -k ${CRYPT_KEY} \ + -x ${TEST_FILES}/plaintext ${TEST_FILES}/write_crypt_test_mpeg.mxf +if [ $? -ne 0 ]; then + exit 1 +fi +cmp ${TEST_FILES}/${TEST_FILE_PREFIX}.mpg ${TEST_FILES}/plaintext.ves +if [ $? -ne 0 ]; then + exit 1 +fi diff --git a/asdcplib/src/mpeg-tst.sh b/asdcplib/src/mpeg-tst.sh new file mode 100755 index 0000000..94d7ba6 --- /dev/null +++ b/asdcplib/src/mpeg-tst.sh @@ -0,0 +1,49 @@ +#!/bin/sh +# +# $Id: mpeg-tst.sh,v 1.3 2009/04/09 19:16:49 msheby Exp $ +# Copyright (c) 2007-2009 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. + +# MPEG tests + +${BUILD_DIR}/asdcp-test${EXEEXT} -c ${TEST_FILES}/write_test_mpeg.mxf ${TEST_FILES}/${TEST_FILE_PREFIX}.mpg +if [ $? -ne 0 ]; then + exit 1 +fi + + +${BUILD_DIR}/asdcp-test${EXEEXT} -x ${TEST_FILES}/extract ${TEST_FILES}/write_test_mpeg.mxf +if [ $? -ne 0 ]; then + exit 1 +fi +cmp ${TEST_FILES}/${TEST_FILE_PREFIX}.mpg ${TEST_FILES}/extract.ves +if [ $? -ne 0 ]; then + exit 1 +fi + + +#${BUILD_DIR}/asdcp-test${EXEEXT} -G ${TEST_FILES}/write_test_mpeg.mxf +#if [ $? -ne 0 ]; then +# exit 1 +#fi diff --git a/asdcplib/src/path-test.cpp b/asdcplib/src/path-test.cpp new file mode 100644 index 0000000..b556bdd --- /dev/null +++ b/asdcplib/src/path-test.cpp @@ -0,0 +1,145 @@ +/* +Copyright (c) 2004-2009, 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 path-test.cpp + \version $Id: path-test.cpp,v 1.8 2009/07/10 18:14:01 jhurst Exp $ + \brief test harness for path manglers defined in KM_fileio.h +*/ + + +#include <KM_fileio.h> +#include <iostream> + +using namespace std; +using namespace Kumu; + + +// +int +main(int argc, const char** argv) +{ + + string Path_1 = "path-test.cpp"; + assert(PathExists(Path_1)); + assert(PathIsFile(Path_1)); + assert(!PathIsDirectory(Path_1)); + + string Path_2 = "."; + assert(PathExists(Path_2)); + assert(!PathIsFile(Path_2)); + assert(PathIsDirectory(Path_2)); + + string Path_3 = "/foo/bar/baz.buz"; // must have 3 elements + PathCompList_t PathList_3; + PathToComponents(Path_3, PathList_3); + + assert(PathList_3.size() == 3); + + string Path_4 = ComponentsToPath(PathList_3); + string Path_5 = PathMakeAbsolute(Path_4); + + fprintf(stderr, "PathMakeAbsolute in: %s\n", Path_4.c_str()); + fprintf(stderr, "PathMakeAbsolute out: %s\n", Path_5.c_str()); + + string Path_6 = ComponentsToAbsolutePath(PathList_3); + assert(Path_3 == Path_6); + assert(PathsAreEquivalent(Path_3, Path_6)); + assert(!PathsAreEquivalent(Path_3, Path_4)); + + assert(!PathHasComponents(PathList_3.back())); + assert(PathHasComponents(Path_3)); + + assert(!PathIsAbsolute(Path_4)); + assert(PathIsAbsolute(Path_5)); + assert(PathMakeLocal(Path_3, "/foo") == "bar/baz.buz"); + + assert(PathsAreEquivalent("/foo/bar/baz", "/foo/bar/./baz")); + assert(PathsAreEquivalent("/foo/baz", "/foo/bar/../baz")); + + assert(PathBasename(Path_3) == "baz.buz"); + assert(PathDirname(Path_3) == "/foo/bar"); + assert(PathDirname("/foo") == "/"); + + assert(PathGetExtension(Path_3) == "buz"); + assert(PathGetExtension("foo") == ""); + assert(PathSetExtension("foo.bar", "") == "foo"); + assert(PathSetExtension(Path_3, "xml") == "baz.xml"); + + string Path_7 = "//tmp///////fooo"; + + PathCompList_t PathList_7; + PathToComponents(Path_7, PathList_7); + for ( PathCompList_t::const_iterator i = PathList_7.begin(); i != PathList_7.end(); i++ ) + fprintf(stderr, "xx: \"%s\"\n", i->c_str()); + assert(PathsAreEquivalent(PathMakeLocal(PathMakeCanonical(Path_7), "/tmp"), "fooo")); + + string Path_8 = "tmp/foo/bar/ack"; + CreateDirectoriesInPath(Path_8); + assert(PathExists(Path_8)); + DeletePath(Path_8); + assert(!PathExists(Path_8)); + + PathList_t InList, OutList; + InList.push_back("tmp"); + InList.push_back("Darwin"); + InList.push_back("."); + + cerr << "----------------------------------" << endl; + FindInPaths(PathMatchAny(), InList, OutList); + PathList_t::iterator pi; + + for ( pi = OutList.begin(); pi != OutList.end(); pi++ ) + cerr << *pi << endl; + + cerr << "----------------------------------" << endl; + OutList.clear(); + FindInPaths(PathMatchRegex("^[A-J].*\\.h$"), InList, OutList); + + for ( pi = OutList.begin(); pi != OutList.end(); pi++ ) + cerr << *pi << endl; + + cerr << "----------------------------------" << endl; + OutList.clear(); + FindInPaths(PathMatchGlob("*.h"), InList, OutList); + + for ( pi = OutList.begin(); pi != OutList.end(); pi++ ) + cerr << *pi << endl; + + cerr << "----------------------------------" << endl; + + fsize_t free_space, total_space; + FreeSpaceForPath("/", free_space, total_space); + cerr << "Free space: " << free_space << endl; + cerr << "Total space: " << total_space << endl; + + cerr << "OK" << endl; + + return 0; +} + +// +// end path-test.cpp +// diff --git a/asdcplib/src/rng-tst.sh b/asdcplib/src/rng-tst.sh new file mode 100755 index 0000000..b0b35c8 --- /dev/null +++ b/asdcplib/src/rng-tst.sh @@ -0,0 +1,28 @@ +#!/bin/sh +# +# $Id: rng-tst.sh,v 1.3 2009/04/09 19:16:49 msheby Exp $ +# Copyright (c) 2007-2009 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. + +${srcdir}/fips-186-test-harness.pl ${BUILD_DIR}/fips-186-rng-test${EXEEXT} diff --git a/asdcplib/src/wav-crypt-tst.sh b/asdcplib/src/wav-crypt-tst.sh new file mode 100755 index 0000000..fce54c0 --- /dev/null +++ b/asdcplib/src/wav-crypt-tst.sh @@ -0,0 +1,69 @@ +#!/bin/sh +# +# $Id: wav-crypt-tst.sh,v 1.3 2009/04/09 19:16:49 msheby Exp $ +# Copyright (c) 2007-2009 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. + +# crypto WAV tests + +${BUILD_DIR}/asdcp-test${EXEEXT} -k ${CRYPT_KEY} \ + -c ${TEST_FILES}/write_crypt_test_wav.mxf ${TEST_FILES}/${TEST_FILE_PREFIX}.wav +if [ $? -ne 0 ]; then + exit 1 +fi +${BUILD_DIR}/asdcp-test${EXEEXT} -i ${TEST_FILES}/write_crypt_test_wav.mxf +if [ $? -ne 0 ]; then + exit 1 +fi +${BUILD_DIR}/asdcp-test${EXEEXT} -p 23 -k ${CRYPT_KEY} \ + -c ${TEST_FILES}/write_crypt_test_2398_wav.mxf ${TEST_FILES}/${TEST_FILE_PREFIX}.wav +if [ $? -ne 0 ]; then + exit 1 +fi +${BUILD_DIR}/asdcp-test${EXEEXT} -i ${TEST_FILES}/write_crypt_test_2398_wav.mxf +if [ $? -ne 0 ]; then + exit 1 +fi + + +( ${BUILD_DIR}/asdcp-test${EXEEXT} -k ${CRYPT_KEY_B} \ + -x ${TEST_FILES}/plaintext ${TEST_FILES}/write_crypt_test_wav.mxf; \ + if [ $? -eq 1 ]; then exit 0; fi; exit 1 ) +${BUILD_DIR}/asdcp-test${EXEEXT} -m -k ${CRYPT_KEY} \ + -x ${TEST_FILES}/plaintext ${TEST_FILES}/write_crypt_test_wav.mxf +if [ $? -ne 0 ]; then + exit 1 +fi +cmp ${TEST_FILES}/${TEST_FILE_PREFIX}.wav ${TEST_FILES}/plaintext_1.wav +if [ $? -ne 0 ]; then + exit 1 +fi +( ${BUILD_DIR}/asdcp-test${EXEEXT} -k ${CRYPT_KEY_B} \ + -x ${TEST_FILES}/plaintext_2398 ${TEST_FILES}/write_crypt_test_2398_wav.mxf; \ + if [ $? -eq 1 ]; then exit 0; fi; exit 1 ) +${BUILD_DIR}/asdcp-test${EXEEXT} -m -k ${CRYPT_KEY} \ + -x ${TEST_FILES}/plaintext_2398 ${TEST_FILES}/write_crypt_test_2398_wav.mxf +if [ $? -ne 0 ]; then + exit 1 +fi diff --git a/asdcplib/src/wav-tst.sh b/asdcplib/src/wav-tst.sh new file mode 100755 index 0000000..e124e8e --- /dev/null +++ b/asdcplib/src/wav-tst.sh @@ -0,0 +1,42 @@ +#!/bin/sh +# +# $Id: wav-tst.sh,v 1.3 2009/04/09 19:16:49 msheby Exp $ +# Copyright (c) 2007-2009 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. + +# WAV tests + +${BUILD_DIR}/asdcp-test${EXEEXT} -c ${TEST_FILES}/write_test_wav.mxf ${TEST_FILES}/${TEST_FILE_PREFIX}.wav +if [ $? -ne 0 ]; then + exit 1 +fi + +${BUILD_DIR}/asdcp-test${EXEEXT} -x ${TEST_FILES}/extract ${TEST_FILES}/write_test_wav.mxf +if [ $? -ne 0 ]; then + exit 1 +fi +cmp ${TEST_FILES}/${TEST_FILE_PREFIX}.wav ${TEST_FILES}/extract_1.wav +if [ $? -ne 0 ]; then + exit 1 +fi diff --git a/asdcplib/src/wavesplit.cpp b/asdcplib/src/wavesplit.cpp new file mode 100755 index 0000000..8785198 --- /dev/null +++ b/asdcplib/src/wavesplit.cpp @@ -0,0 +1,397 @@ +/* +Copyright (c) 2005-2009, 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 wavesplit.cpp + \version $Id: wavesplit.cpp,v 1.11 2010/02/16 18:40:57 jhurst Exp $ + \brief WAV file splitter +*/ + +#include <AS_DCP.h> +#include <WavFileWriter.h> +#include <assert.h> + +using namespace ASDCP; + +//------------------------------------------------------------------------------------------ +// +// command line option parser class + +static const char* PROGRAM_NAME = "wavesplit"; // program name for messages + +// Macros used to test command option data state. + +// True if a major mode has already been selected. +#define TEST_MAJOR_MODE() ( create_flag || info_flag ) + +// Causes the caller to return if a major mode has already been selected, +// otherwise sets the given flag. +#define TEST_SET_MAJOR_MODE(f) if ( TEST_MAJOR_MODE() ) \ + { \ + fputs("Conflicting major mode, choose one of -(ic).\n", stderr); \ + return; \ + } \ + (f) = true; + +// Increment the iterator, test for an additional non-option command line argument. +// Causes the caller to return if there are no remaining arguments or if the next +// argument begins with '-'. +#define TEST_EXTRA_ARG(i,c) if ( ++i >= argc || argv[(i)][0] == '-' ) \ + { \ + fprintf(stderr, "Argument not found for option %c.\n", (c)); \ + return; \ + } +// +void +banner(FILE* stream = stderr) +{ + fprintf(stream, "\n\ +%s (asdcplib %s)\n\n\ +Copyright (c) 2005-2009 John Hurst\n\n\ +%s is part of asdcplib.\n\ +asdcplib may be copied only under the terms of the license found at\n\ +the top of every file in the asdcplib distribution kit.\n\n\ +Specify the -h (help) option for further information about %s\n\n", + PROGRAM_NAME, ASDCP::Version(), PROGRAM_NAME, PROGRAM_NAME); +} + +// +void +usage(FILE* stream = stderr) +{ + fprintf(stream, "\ +USAGE: %s [-v] -V\n\ + %s [-v] -c <root-name> [-d <duration>] [-f <start-frame>] <filename>\n\ + %s [-v] -i <filename>\n\ +\n\ +Major modes:\n\ + -c <root-name> - Create a WAV file for each channel in the input file\n\ + (default is two-channel files)\n\ + -d <duration> - Number of frames to process, default all\n\ + -f <frame-num> - Starting frame number, default 0\n\ + -h - Show help\n\ + -i - Show input file metadata (no output created)\n\ + -V - Show version\n\ + -v - Print extra info while processing\n\ +\n\ + NOTES: o There is no option grouping, all options must be distinct arguments.\n\ + o All option arguments must be separated from the option by whitespace.\n\ +\n", PROGRAM_NAME, PROGRAM_NAME, PROGRAM_NAME); +} + +// +// +class CommandOptions +{ + CommandOptions(); + +public: + bool error_flag; // true if the given options are in error or not complete + bool create_flag; // true if the file create mode was selected + bool info_flag; // true if the file info mode was selected + bool version_flag; // true if the version display option was selected + bool help_flag; // true if the help display option was selected + bool verbose_flag; // true for extra info during procesing + ui32_t start_frame; // frame number to begin processing + ui32_t duration; // number of frames to be processed + const char* file_root; // filename prefix for files written by the extract mode + const char* filename; // filename to be processed + + CommandOptions(int argc, const char** argv) : + error_flag(true), create_flag(false), info_flag(false), + version_flag(false), help_flag(false), start_frame(0), + duration(0xffffffff), file_root(0), filename(0) + { + for ( int i = 1; i < argc; i++ ) + { + if ( argv[i][0] == '-' && isalpha(argv[i][1]) && argv[i][2] == 0 ) + { + switch ( argv[i][1] ) + { + case 'c': + TEST_SET_MAJOR_MODE(create_flag); + TEST_EXTRA_ARG(i, 'c'); + file_root = argv[i]; + break; + + case 'd': + TEST_EXTRA_ARG(i, 'd'); + duration = atoi(argv[i]); // TODO: test for negative value, should use strtol() + break; + + case 'f': + TEST_EXTRA_ARG(i, 'f'); + start_frame = atoi(argv[i]); // TODO: test for negative value, should use strtol() + break; + + case 'h': help_flag = true; break; + case 'i': TEST_SET_MAJOR_MODE(info_flag); break; + case 'V': version_flag = true; break; + + default: + fprintf(stderr, "Unrecognized option: %c\n", argv[i][1]); + return; + } + } + else + { + if ( filename ) + { + fprintf(stderr, "Unexpected extra filename.\n"); + return; + } + + filename = argv[i]; + } + } + + if ( TEST_MAJOR_MODE() ) + { + if ( filename == 0 ) + { + fputs("Input filename required.\n", stderr); + return; + } + } + + if ( ! TEST_MAJOR_MODE() && ! help_flag && ! version_flag ) + { + fputs("No operation selected (use one of -(ic) or -h for help).\n", stderr); + return; + } + + error_flag = false; + } +}; + +// +Result_t +wav_file_info(CommandOptions& Options) +{ + PCM::AudioDescriptor ADesc; + Rational PictureRate = EditRate_24; + PCM::WAVParser Parser; + + // set up essence parser + Result_t result = Parser.OpenRead(Options.filename, PictureRate); + + if ( ASDCP_SUCCESS(result) ) + { + Parser.FillAudioDescriptor(ADesc); + ADesc.EditRate = PictureRate; + fprintf(stderr, "48Khz PCM Audio, %s fps (%u spf)\n", "24", + PCM::CalcSamplesPerFrame(ADesc)); + fputs("AudioDescriptor:\n", stderr); + PCM::AudioDescriptorDump(ADesc); + } + + return result; +} + +// +void +split_buffer(ui32_t sample_size, PCM::FrameBuffer& FrameBuffer, + PCM::FrameBuffer& L_FrameBuffer, PCM::FrameBuffer& R_FrameBuffer) +{ + assert((FrameBuffer.Size() % 2) == 0); + byte_t* p = FrameBuffer.Data(); + byte_t* end_p = p + FrameBuffer.Size(); + byte_t* lp = L_FrameBuffer.Data(); + byte_t* rp = R_FrameBuffer.Data(); + + for ( ; p < end_p; ) + { + memcpy(lp, p, sample_size); + lp += sample_size; + p += sample_size; + memcpy(rp, p, sample_size); + rp += sample_size; + p += sample_size; + } + + L_FrameBuffer.Size(L_FrameBuffer.Capacity()); + R_FrameBuffer.Size(R_FrameBuffer.Capacity()); +} + +// +Result_t +split_wav_file(CommandOptions& Options) +{ + PCM::FrameBuffer FrameBuffer; + PCM::FrameBuffer L_FrameBuffer; + PCM::FrameBuffer R_FrameBuffer; + PCM::AudioDescriptor ADesc; + Rational PictureRate = EditRate_24; + PCM::WAVParser Parser; + + // set up essence parser + Result_t result = Parser.OpenRead(Options.filename, PictureRate); + + if ( ASDCP_SUCCESS(result) ) + { + Parser.FillAudioDescriptor(ADesc); + + ADesc.EditRate = PictureRate; + ui32_t fb_size = PCM::CalcFrameBufferSize(ADesc); + assert((fb_size % 2) == 0); + FrameBuffer.Capacity(fb_size); + L_FrameBuffer.Capacity(fb_size/2); + R_FrameBuffer.Capacity(fb_size/2); + + if ( Options.verbose_flag ) + { + fprintf(stderr, "48Khz PCM Audio, %s fps (%u spf)\n", "24", + PCM::CalcSamplesPerFrame(ADesc)); + fputs("AudioDescriptor:\n", stderr); + PCM::AudioDescriptorDump(ADesc); + } + + ADesc.ChannelCount = 1; + } + + // set up output files + Kumu::FileWriter L_OutFile; + Kumu::FileWriter R_OutFile; + + if ( ASDCP_SUCCESS(result) ) + { + char filename[256]; + snprintf(filename, 256, "%s_l.wav", Options.file_root); + result = L_OutFile.OpenWrite(filename); + + if ( ASDCP_SUCCESS(result) ) + { + snprintf(filename, 256, "%s_r.wav", Options.file_root); + result = R_OutFile.OpenWrite(filename); + } + } + + + if ( ASDCP_SUCCESS(result) ) + { + Wav::SimpleWaveHeader WavHeader(ADesc); + result = WavHeader.WriteToFile(L_OutFile); + + if ( ASDCP_SUCCESS(result) ) + result = WavHeader.WriteToFile(R_OutFile); + } + + if ( ASDCP_SUCCESS(result) ) + { + ui32_t write_count = 0; + ui32_t duration = 0; + + while ( ASDCP_SUCCESS(result) && (duration++ < Options.duration) ) + { + result = Parser.ReadFrame(FrameBuffer); + + if ( FrameBuffer.Size() != FrameBuffer.Capacity() ) + { + fprintf(stderr, "WARNING: Last frame read was short, PCM input is possibly not frame aligned.\n"); + fprintf(stderr, "Expecting %u bytes, got %u.\n", FrameBuffer.Capacity(), FrameBuffer.Size()); + result = RESULT_ENDOFFILE; + continue; + } + + if ( Options.verbose_flag ) + FrameBuffer.Dump(stderr); + + if ( ASDCP_SUCCESS(result) ) + { + split_buffer(PCM::CalcSampleSize(ADesc), FrameBuffer, L_FrameBuffer, R_FrameBuffer); + result = L_OutFile.Write(L_FrameBuffer.Data(), L_FrameBuffer.Size(), &write_count); + + if ( ASDCP_SUCCESS(result) ) + result = R_OutFile.Write(R_FrameBuffer.Data(), R_FrameBuffer.Size(), &write_count); + } + } + + if ( result == RESULT_ENDOFFILE ) + result = RESULT_OK; + + if ( ASDCP_SUCCESS(result) ) + { + ADesc.ContainerDuration = duration; + Wav::SimpleWaveHeader WavHeader(ADesc); + L_OutFile.Seek(); + + if ( ASDCP_SUCCESS(result) ) + result = R_OutFile.Seek(); + + if ( ASDCP_SUCCESS(result) ) + result = WavHeader.WriteToFile(L_OutFile); + + if ( ASDCP_SUCCESS(result) ) + result = WavHeader.WriteToFile(R_OutFile); + } + } + + return RESULT_OK; +} + + +// +int +main(int argc, const char** argv) +{ + Result_t result = RESULT_OK; + CommandOptions Options(argc, argv); + + if ( Options.help_flag ) + { + usage(); + return 0; + } + + if ( Options.error_flag ) + return 3; + + if ( Options.version_flag ) + banner(); + + if ( Options.info_flag ) + result = wav_file_info(Options); + + else if ( Options.create_flag ) + result = split_wav_file(Options); + + if ( result != RESULT_OK ) + { + fputs("Program stopped on error.\n", stderr); + + if ( result != RESULT_FAIL ) + { + fputs(result, stderr); + fputc('\n', stderr); + } + + return 1; + } + + return 0; +} + + +// diff --git a/asdcplib/src/wscript b/asdcplib/src/wscript new file mode 100644 index 0000000..7c78616 --- /dev/null +++ b/asdcplib/src/wscript @@ -0,0 +1,71 @@ +def configure(conf): + conf.env.append_value('CXXFLAGS', '-D_FILE_OFFSET_BITS=64') + conf.env.append_value('CXXFLAGS', '-DPACKAGE_VERSION="1.9.45-carlh"') + if conf.options.target_windows: + conf.env.append_value('CXXFLAGS', '-DASDCP_PLATFORM="win32"') + conf.env.append_value('CXXFLAGS', '-DKM_WIN32') + else: + conf.env.append_value('CXXFLAGS', '-DASDCP_PLATFORM="linux"') + +def build(bld): + if bld.env.STATIC: + obj = bld(features = 'cxx cxxstlib') + else: + obj = bld(features = 'cxx cxxshlib') + + obj.name = 'libkumu-libsub' + obj.target = 'kumu-libsub' + obj.uselib = 'OPENSSL BOOST_FILESYSTEM' + obj.includes = ['.'] + obj.export_includes = ['.'] + obj.source = """ + KM_fileio.cpp + KM_log.cpp + KM_util.cpp + KM_xml.cpp + KM_tai.cpp + KM_prng.cpp + """ + + if bld.env.STATIC: + obj = bld(features = 'cxx cxxstlib') + else: + obj = bld(features = 'cxx cxxshlib') + + obj.name = 'libasdcp-libsub' + obj.target = 'asdcp-libsub' + obj.uselib = 'OPENSSL' + obj.use = 'libkumu-libsub' + obj.includes = ['.'] + obj.export_includes = ['.'] + obj.source = """ + MPEG2_Parser.cpp + MPEG.cpp + JP2K_Codestream_Parser.cpp + JP2K_Sequence_Parser.cpp + JP2K.cpp + PCM_Parser.cpp + Wav.cpp + TimedText_Parser.cpp + KLV.cpp + Dict.cpp + MXFTypes.cpp + MXF.cpp + Index.cpp + Metadata.cpp + AS_DCP.cpp + AS_DCP_MXF.cpp + AS_DCP_AES.cpp + h__Reader.cpp + h__Writer.cpp + AS_DCP_MPEG2.cpp + AS_DCP_JP2K.cpp + AS_DCP_PCM.cpp + AS_DCP_TimedText.cpp + PCMParserList.cpp + MDD.cpp + """ + + if bld.env.STATIC: + bld.install_files('${PREFIX}/lib', 'libkumu-libsub.a') + bld.install_files('${PREFIX}/lib', 'libasdcp-libsub.a') |
