X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=src%2FAS_DCP.h;h=6b598cc301c14713763cbe10779b12e29d1bf876;hb=620722efa3a2df7857074e36abd751826a61d0e0;hp=93288dd84712eac8a64b91eaf6c7d0406d0bcb07;hpb=ed48db5fd3e22af1578b37b8a8f7e8ae24036897;p=asdcplib.git diff --git a/src/AS_DCP.h b/src/AS_DCP.h index 93288dd..6b598cc 100755 --- a/src/AS_DCP.h +++ b/src/AS_DCP.h @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2009, John Hurst +Copyright (c) 2003-2013, John Hurst All rights reserved. Redistribution and use in source and binary forms, with or without @@ -25,7 +25,7 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /*! \file AS_DCP.h - \version $Id$ + \version $Id$ \brief AS-DCP library, public interface The asdcplib library is a set of file access objects that offer simplified @@ -34,22 +34,23 @@ 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 429-2-2009 DCP Operational Constraints - o SMPTE 429-3-2006 Track File Specification - o SMPTE 429-4-2006 JPEG 2000 for D-Cinema - o SMPTE 429-5-2009 Timed Text Track File - o SMPTE 429-6-2006 Essence Encryption Specification - o SMPTE 429-10-2008 Stereoscopic Image Track File - o SMPTE 330M - UMID - o SMPTE 336M - KLV - o SMPTE 377M - MXF - o SMPTE 390M - OP-Atom - o SMPTE 379M - Generic Container - o SMPTE 381M - MPEG2 picture - o SMPTE 422M - JPEG 2000 picture - o SMPTE 382M - WAV/PCM sound + 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) + o NIST FIPS 197 - AES (Rijndael) (via OpenSSL) o MXF Interop Track File Specification o MXF Interop Track File Essence Encryption Specification @@ -65,6 +66,8 @@ The following use cases are supported by the library: JPEG 2000 stereoscopic codestream pairs PCM audio streams SMPTE 429-7 Timed Text XML with font and image resources + Proposed SMPTE Aux Data track file + Proposed Dolby (TM) Atmos track file o Read essence from a plaintext or ciphertext AS-DCP file: MPEG2 Video Elementary Stream @@ -72,6 +75,8 @@ The following use cases are supported by the library: JPEG 2000 stereoscopic codestream pairs PCM audio streams SMPTE 429-7 Timed Text XML with font and image resources + Proposed SMPTE Aux Data track file + Proposed Dolby (TM) Atmos track file o Read header metadata from an AS-DCP file @@ -79,13 +84,14 @@ 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 429-5-2009. + 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 +#include #include #include #include @@ -180,21 +186,21 @@ namespace ASDCP { using Kumu::RESULT_ENDOFFILE; using Kumu::RESULT_CONFIG; - const Kumu::Result_t RESULT_FORMAT (-101, "The file format is not proper OP-Atom/AS-DCP."); - const Kumu::Result_t RESULT_RAW_ESS (-102, "Unknown raw essence file type."); - const Kumu::Result_t RESULT_RAW_FORMAT (-103, "Raw essence format invalid."); - const Kumu::Result_t RESULT_RANGE (-104, "Frame number out of range."); - const Kumu::Result_t RESULT_CRYPT_CTX (-105, "AESEncContext required when writing to encrypted file."); - const Kumu::Result_t RESULT_LARGE_PTO (-106, "Plaintext offset exceeds frame buffer size."); - const Kumu::Result_t RESULT_CAPEXTMEM (-107, "Cannot resize externally allocated memory."); - const Kumu::Result_t RESULT_CHECKFAIL (-108, "The check value did not decrypt correctly."); - const Kumu::Result_t RESULT_HMACFAIL (-109, "HMAC authentication failure."); - const Kumu::Result_t RESULT_HMAC_CTX (-110, "HMAC context required."); - const Kumu::Result_t RESULT_CRYPT_INIT (-111, "Error initializing block cipher context."); - const Kumu::Result_t RESULT_EMPTY_FB (-112, "Empty frame buffer."); - const Kumu::Result_t RESULT_KLV_CODING (-113, "KLV coding error."); - const Kumu::Result_t RESULT_SPHASE (-114, "Stereoscopic phase mismatch."); - const Kumu::Result_t RESULT_SFORMAT (-115, "Rate mismatch, file may contain stereoscopic essence."); + 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 @@ -202,24 +208,38 @@ namespace ASDCP { // The file accessors in this library implement a bounded set of essence types. // This list will be expanded when support for new types is added to the library. enum EssenceType_t { - ESS_UNKNOWN, // the file is not a supported AS-DCP essence container - ESS_MPEG2_VES, // the file contains an MPEG video elementary stream - ESS_JPEG_2000, // the file contains one or more JPEG 2000 codestreams - ESS_PCM_24b_48k, // the file contains one or more PCM audio pairs - ESS_PCM_24b_96k, // the file contains one or more PCM audio pairs - ESS_TIMED_TEXT, // the file contains an XML timed text document and one or more resources - ESS_JPEG_2000_S, // the file contains one or more JPEG 2000 codestream pairs (stereoscopic) + ESS_UNKNOWN, // the file is not a supported AS-DCP of AS-02 essence container + + // + ESS_MPEG2_VES, // the file contains an MPEG-2 video elementary stream + + // d-cinema essence types + ESS_JPEG_2000, // the file contains one or more JPEG 2000 codestreams + ESS_PCM_24b_48k, // the file contains one or more PCM audio pairs + ESS_PCM_24b_96k, // the file contains one or more PCM audio pairs + ESS_TIMED_TEXT, // the file contains an XML timed text document and one or more resources + ESS_JPEG_2000_S, // the file contains one or more JPEG 2000 codestream pairs (stereoscopic) + ESS_DCDATA_UNKNOWN, // the file contains one or more D-Cinema Data bytestreams + ESS_DCDATA_DOLBY_ATMOS, // the file contains one or more DolbyATMOS bytestreams + + // IMF essence types + ESS_AS02_JPEG_2000, // the file contains one or more JPEG 2000 codestreams + ESS_AS02_PCM_24b_48k, // the file contains one or more PCM audio pairs, clip wrapped + ESS_AS02_PCM_24b_96k, // the file contains one or more PCM audio pairs, clip wrapped + ESS_AS02_TIMED_TEXT, // the file contains a TTML document and zero or more resources + + ESS_MAX }; // Determine the type of essence contained in the given MXF file. RESULT_OK // is returned if the file is successfully opened and contains a valid MXF // stream. If there is an error, the result code will indicate the reason. - Result_t EssenceType(const char* filename, EssenceType_t& type); + Result_t EssenceType(const std::string& filename, EssenceType_t& type); // Determine the type of essence contained in the given raw file. RESULT_OK // is returned if the file is successfully opened and contains a known // stream type. If there is an error, the result code will indicate the reason. - Result_t RawEssenceType(const char* filename, EssenceType_t& type); + Result_t RawEssenceType(const std::string& filename, EssenceType_t& type); //--------------------------------------------------------------------------------- @@ -246,22 +266,46 @@ namespace ASDCP { inline bool operator!=(const Rational& rhs) const { return ( rhs.Numerator != Numerator || rhs.Denominator != Denominator ); } + + inline bool operator<(const Rational& rhs) { + if ( Numerator < rhs.Numerator ) return true; + if ( Numerator == rhs.Numerator && Denominator < rhs.Denominator ) return true; + return false; + } + + inline bool operator>(const Rational& rhs) { + if ( Numerator > rhs.Numerator ) return true; + if ( Numerator == rhs.Numerator && Denominator > rhs.Denominator ) return true; + return false; + } }; // common edit rates, use these instead of hard coded constants - const Rational EditRate_24(24,1); - const Rational EditRate_23_98(24000,1001); // Not a DCI-compliant value! - const Rational EditRate_48(48,1); - const Rational SampleRate_48k(48000,1); - const Rational SampleRate_96k(96000,1); - - // Additional frame rates, see SMPTE 428-11 - // These rates are new and not supported by all systems. Do not assume that a package - // made using on of these rates will work just anywhere! - const Rational EditRate_25(25,1); - const Rational EditRate_30(30,1); - const Rational EditRate_50(50,1); - const Rational EditRate_60(60,1); + const Rational EditRate_24 = Rational(24,1); + const Rational EditRate_23_98 = Rational(24000,1001); // Not a DCI-compliant value! + const Rational EditRate_48 = Rational(48,1); + const Rational SampleRate_48k = Rational(48000,1); + const Rational SampleRate_96k = Rational(96000,1); + + // Additional frame rates, see ST 428-11, ST 429-13 + // These rates are new and not supported by all systems. Do not assume that + // a package made using one of these rates will work just anywhere! + const Rational EditRate_25 = Rational(25,1); + const Rational EditRate_30 = Rational(30,1); + const Rational EditRate_50 = Rational(50,1); + const Rational EditRate_60 = Rational(60,1); + const Rational EditRate_96 = Rational(96,1); + const Rational EditRate_100 = Rational(100,1); + const Rational EditRate_120 = Rational(120,1); + + // Archival frame rates, see ST 428-21 + // These rates are new and not supported by all systems. Do not assume that + // a package made using one of these rates will work just anywhere! + const Rational EditRate_16 = Rational(16,1); + const Rational EditRate_18 = Rational(200,11); // 18.182 + const Rational EditRate_20 = Rational(20,1); + const Rational EditRate_22 = Rational(240,11); // 21.818 + // Non-reference counting container for internal member objects. // Please do not use this class for any other purpose. @@ -294,24 +338,32 @@ namespace ASDCP { // 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 - // and SMPTE. The two differ only in the values of two labels: + // (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 // - // OP Atom / Interop : 06 0e 2b 34 04 01 01 01 0d 01 02 01 10 00 00 00 - // OP Atom / SMPTE : 06 0e 2b 34 04 01 01 02 0d 01 02 01 10 00 00 00 - // and - // EKLV Packet / Interop : 06 0e 2b 34 02 04 01 07 0d 01 03 01 02 7e 01 00 - // EKLV Packet / SMPTE : 06 0e 2b 34 02 04 01 01 0d 01 03 01 02 7e 01 00 + // EKLV Packet: + // Interop : 06 0e 2b 34 02 04 01 07 0d 01 03 01 02 7e 01 00 + // SMPTE : 06 0e 2b 34 02 04 01 01 0d 01 03 01 02 7e 01 00 + // + // GenericDescriptor/SubDescriptors: + // Interop : 06 0e 2b 34 01 01 01 02 06 01 01 04 06 10 00 00 + // SMPTE : 06 0e 2b 34 01 01 01 09 06 01 01 04 06 10 00 00 // // asdcplib will read any (otherwise valid) file which has any combination of the // above values. When writing files, MXF Interop labels are used by default. To // write a file containing SMPTE labels, replace the default label set value in // the WriterInfo before calling OpenWrite() // + // enum LabelSet_t { LS_MXF_UNKNOWN, LS_MXF_INTEROP, - LS_MXF_SMPTE + LS_MXF_SMPTE, + LS_MAX }; // @@ -333,7 +385,7 @@ namespace ASDCP { 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); @@ -375,7 +427,7 @@ namespace ASDCP { // Initializes Rijndael CBC encryption context. // Returns error if the key argument is NULL. Result_t InitKey(const byte_t* key); - + // Initializes 16 byte CBC Initialization Vector. This operation may be performed // any number of times for a given key. // Returns error if the i_vec argument is NULL. @@ -529,6 +581,16 @@ namespace ASDCP { inline ui32_t PlaintextOffset() const { return m_PlaintextOffset; } }; + //--------------------------------------------------------------------------------- + // Accessors in the MXFReader and MXFWriter classes below return these types to + // provide direct access to MXF metadata structures declared in MXF.h and Metadata.h + + namespace MXF { + // #include to use these + class OP1aHeader; + class OPAtomIndexFooter; + class RIP; + }; //--------------------------------------------------------------------------------- // MPEG2 video elementary stream support @@ -560,22 +622,22 @@ namespace ASDCP { // MPEG2VideoDescriptor object. struct VideoDescriptor { - Rational EditRate; // - ui32_t FrameRate; // - Rational SampleRate; // - ui8_t FrameLayout; // - ui32_t StoredWidth; // - ui32_t StoredHeight; // - Rational AspectRatio; // - ui32_t ComponentDepth; // - ui32_t HorizontalSubsampling; // - ui32_t VerticalSubsampling; // - ui8_t ColorSiting; // - ui8_t CodedContentType; // - bool LowDelay; // - ui32_t BitRate; // - ui8_t ProfileAndLevel; // - ui32_t ContainerDuration; // + Rational EditRate; // + ui32_t FrameRate; // + Rational SampleRate; // + ui8_t FrameLayout; // + ui32_t StoredWidth; // + ui32_t StoredHeight; // + Rational AspectRatio; // + ui32_t ComponentDepth; // + ui32_t HorizontalSubsampling; // + ui32_t VerticalSubsampling; // + ui8_t ColorSiting; // + ui8_t CodedContentType; // + bool LowDelay; // + ui32_t BitRate; // + ui8_t ProfileAndLevel; // + ui32_t ContainerDuration; // }; // Print VideoDescriptor to std::ostream @@ -605,7 +667,7 @@ namespace ASDCP { { Capacity(size); } - + virtual ~FrameBuffer() {} // Sets the MPEG frame type of the picture data in the frame buffer. @@ -656,7 +718,7 @@ namespace ASDCP { // Opens the stream for reading, parses enough data to provide a complete // set of stream metadata for the MXFWriter below. - Result_t OpenRead(const char* filename) const; + Result_t OpenRead(const std::string& filename) const; // Fill a VideoDescriptor struct with the values from the file's header. // Returns RESULT_INIT if the file is not open. @@ -685,10 +747,16 @@ namespace ASDCP { MXFWriter(); virtual ~MXFWriter(); + // Warning: direct manipulation of MXF structures can interfere + // with the normal operation of the wrapper. Caveat emptor! + virtual MXF::OP1aHeader& OP1aHeader(); + virtual MXF::OPAtomIndexFooter& OPAtomIndexFooter(); + virtual MXF::RIP& RIP(); + // Open the file for writing. The file must not exist. Returns error if // the operation cannot be completed or if nonsensical data is discovered // in the essence descriptor. - Result_t OpenWrite(const char* filename, const WriterInfo&, + Result_t OpenWrite(const std::string& filename, const WriterInfo&, const VideoDescriptor&, ui32_t HeaderSize = 16384); // Writes a frame of essence to the MXF file. If the optional AESEncContext @@ -712,9 +780,15 @@ namespace ASDCP { MXFReader(); virtual ~MXFReader(); + // Warning: direct manipulation of MXF structures can interfere + // with the normal operation of the wrapper. Caveat emptor! + virtual MXF::OP1aHeader& OP1aHeader(); + virtual MXF::OPAtomIndexFooter& OPAtomIndexFooter(); + virtual MXF::RIP& RIP(); + // Open the file for reading. The file must exist. Returns error if the // operation cannot be completed. - Result_t OpenRead(const char* filename) const; + Result_t OpenRead(const std::string& filename) const; // Returns RESULT_INIT if the file is not open. Result_t Close() const; @@ -736,6 +810,12 @@ namespace ASDCP { // out of range, or if optional decrypt or HAMC operations fail. Result_t ReadFrame(ui32_t frame_number, FrameBuffer&, AESDecContext* = 0, HMACContext* = 0) const; + // Using the index table read from the footer partition, lookup the frame number + // and return the offset into the file at which to read that frame of essence. + // Returns RESULT_INIT if the file is not open, and RESULT_RANGE if the frame number is + // out of range. + Result_t LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset, i8_t& temporalOffset, i8_t& keyFrameOffset) const; + // Calculates the first frame in transport order of the GOP in which the requested // frame is located. Calls ReadFrame() to fetch the frame at the calculated position. // Returns RESULT_INIT if the file is not open. @@ -758,6 +838,9 @@ namespace ASDCP { //--------------------------------------------------------------------------------- // + + + namespace PCM { // The default value of the ChannelFormat element of the AudioDescriptor struct @@ -773,19 +856,23 @@ namespace ASDCP { 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 with optional HI/VI + CF_CFG_3, // 7.1 (SDDS) with optional HI/VI + CF_CFG_4, // Wild Track Format + CF_CFG_5, // 7.1 DS with optional HI/VI + CF_CFG_6, // ST 377-4 (MCA) labels (see also ASDCP::MXF::decode_mca_string) + CF_MAXIMUM }; struct AudioDescriptor { - Rational SampleRate; // rate of frame wrapping + Rational EditRate; // rate of frame wrapping Rational AudioSamplingRate; // rate of audio sample - ui32_t Locked; // + ui32_t Locked; // ui32_t ChannelCount; // number of channels ui32_t QuantizationBits; // number of bits per single-channel sample ui32_t BlockAlign; // number of bytes ber sample, all channels - ui32_t AvgBps; // - ui32_t LinkedTrackID; // + ui32_t AvgBps; // + ui32_t LinkedTrackID; // ui32_t ContainerDuration; // number of frames ChannelFormat_t ChannelFormat; // audio channel arrangement }; @@ -804,7 +891,7 @@ namespace ASDCP { // Returns number of samples per frame of data described by ADesc inline ui32_t CalcSamplesPerFrame(const AudioDescriptor& ADesc) { - double tmpd = ADesc.AudioSamplingRate.Quotient() / ADesc.SampleRate.Quotient(); + double tmpd = ADesc.AudioSamplingRate.Quotient() / ADesc.EditRate.Quotient(); return (ui32_t)ceil(tmpd); } @@ -821,7 +908,7 @@ namespace ASDCP { FrameBuffer() {} FrameBuffer(ui32_t size) { Capacity(size); } virtual ~FrameBuffer() {} - + // Print debugging information to stream (stderr default) void Dump(FILE* = 0, ui32_t dump_bytes = 0) const; }; @@ -843,7 +930,7 @@ namespace ASDCP { // Opens the stream for reading, parses enough data to provide a complete // set of stream metadata for the MXFWriter below. PictureRate controls // ther frame rate for the MXF frame wrapping option. - Result_t OpenRead(const char* filename, const Rational& PictureRate) const; + Result_t OpenRead(const std::string& filename, const Rational& PictureRate) const; // Fill an AudioDescriptor struct with the values from the file's header. // Returns RESULT_INIT if the file is not open. @@ -869,10 +956,16 @@ namespace ASDCP { MXFWriter(); virtual ~MXFWriter(); + // Warning: direct manipulation of MXF structures can interfere + // with the normal operation of the wrapper. Caveat emptor! + virtual MXF::OP1aHeader& OP1aHeader(); + virtual MXF::OPAtomIndexFooter& OPAtomIndexFooter(); + virtual MXF::RIP& RIP(); + // Open the file for writing. The file must not exist. Returns error if // the operation cannot be completed or if nonsensical data is discovered // in the essence descriptor. - Result_t OpenWrite(const char* filename, const WriterInfo&, + Result_t OpenWrite(const std::string& filename, const WriterInfo&, const AudioDescriptor&, ui32_t HeaderSize = 16384); // Writes a frame of essence to the MXF file. If the optional AESEncContext @@ -896,9 +989,15 @@ namespace ASDCP { MXFReader(); virtual ~MXFReader(); + // Warning: direct manipulation of MXF structures can interfere + // with the normal operation of the wrapper. Caveat emptor! + virtual MXF::OP1aHeader& OP1aHeader(); + virtual MXF::OPAtomIndexFooter& OPAtomIndexFooter(); + virtual MXF::RIP& RIP(); + // Open the file for reading. The file must exist. Returns error if the // operation cannot be completed. - Result_t OpenRead(const char* filename) const; + Result_t OpenRead(const std::string& filename) const; // Returns RESULT_INIT if the file is not open. Result_t Close() const; @@ -920,6 +1019,12 @@ namespace ASDCP { // out of range, or if optional decrypt or HAMC operations fail. Result_t ReadFrame(ui32_t frame_number, FrameBuffer&, AESDecContext* = 0, HMACContext* = 0) const; + // Using the index table read from the footer partition, lookup the frame number + // and return the offset into the file at which to read that frame of essence. + // Returns RESULT_INIT if the file is not open, and RESULT_RANGE if the frame number is + // out of range. + Result_t LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset, i8_t& temporalOffset, i8_t& keyFrameOffset) const; + // Print debugging information to stream void DumpHeaderMetadata(FILE* = 0) const; void DumpIndex(FILE* = 0) const; @@ -952,7 +1057,7 @@ namespace ASDCP { ui8_t NumberOfLayers[sizeof(ui16_t)]; ui8_t MultiCompTransform; } SGcod; - + struct { ui8_t DecompositionLevels; @@ -1007,7 +1112,7 @@ namespace ASDCP { FrameBuffer() {} FrameBuffer(ui32_t size) { Capacity(size); } virtual ~FrameBuffer() {} - + // Print debugging information to stream (stderr default) void Dump(FILE* = 0, ui32_t dump_bytes = 0) const; }; @@ -1031,7 +1136,7 @@ namespace ASDCP { // The frame buffer's PlaintextOffset parameter will be set to the first // byte of the data segment. Set this value to zero if you want // encrypted headers. - Result_t OpenReadFrame(const char* filename, FrameBuffer&) const; + Result_t OpenReadFrame(const std::string& filename, FrameBuffer&) const; // Fill a PictureDescriptor struct with the values from the file's codestream. // Returns RESULT_INIT if the file is not open. @@ -1059,9 +1164,18 @@ namespace ASDCP { // alphabetically by filename. The parser will automatically parse enough data // from the first file to provide a complete set of stream metadata for the // MXFWriter below. If the "pedantic" parameter is given and is true, the - // parser will check the metadata for each codestream and fail if a + // parser will check the metadata for each codestream and fail if a + // mismatch is detected. + Result_t OpenRead(const std::string& filename, bool pedantic = false) const; + + // Opens a file sequence for reading. The sequence is expected to contain one or + // more filenames, each naming a file containing the codestream for exactly one + // picture. The parser will automatically parse enough data + // from the first file to provide a complete set of stream metadata for the + // MXFWriter below. If the "pedantic" parameter is given and is true, the + // parser will check the metadata for each codestream and fail if a // mismatch is detected. - Result_t OpenRead(const char* filename, bool pedantic = false) const; + Result_t OpenRead(const std::list& file_list, bool pedantic = false) const; // Fill a PictureDescriptor struct with the values from the first file's codestream. // Returns RESULT_INIT if the directory is not open. @@ -1091,10 +1205,16 @@ namespace ASDCP { MXFWriter(); virtual ~MXFWriter(); + // Warning: direct manipulation of MXF structures can interfere + // with the normal operation of the wrapper. Caveat emptor! + virtual MXF::OP1aHeader& OP1aHeader(); + virtual MXF::OPAtomIndexFooter& OPAtomIndexFooter(); + virtual MXF::RIP& RIP(); + // Open the file for writing. The file must not exist. Returns error if // the operation cannot be completed or if nonsensical data is discovered // in the essence descriptor. - Result_t OpenWrite(const char* filename, const WriterInfo&, + Result_t OpenWrite(const std::string& filename, const WriterInfo&, const PictureDescriptor&, ui32_t HeaderSize = 16384); // Writes a frame of essence to the MXF file. If the optional AESEncContext @@ -1118,9 +1238,15 @@ namespace ASDCP { MXFReader(); virtual ~MXFReader(); + // Warning: direct manipulation of MXF structures can interfere + // with the normal operation of the wrapper. Caveat emptor! + virtual MXF::OP1aHeader& OP1aHeader(); + virtual MXF::OPAtomIndexFooter& OPAtomIndexFooter(); + virtual MXF::RIP& RIP(); + // Open the file for reading. The file must exist. Returns error if the // operation cannot be completed. - Result_t OpenRead(const char* filename) const; + Result_t OpenRead(const std::string& filename) const; // Returns RESULT_INIT if the file is not open. Result_t Close() const; @@ -1142,6 +1268,12 @@ namespace ASDCP { // out of range, or if optional decrypt or HAMC operations fail. Result_t ReadFrame(ui32_t frame_number, FrameBuffer&, AESDecContext* = 0, HMACContext* = 0) const; + // Using the index table read from the footer partition, lookup the frame number + // and return the offset into the file at which to read that frame of essence. + // Returns RESULT_INIT if the file is not open, and RESULT_FRAME if the frame number is + // out of range. + Result_t LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset, i8_t& temporalOffset, i8_t& keyFrameOffset) const; + // Print debugging information to stream void DumpHeaderMetadata(FILE* = 0) const; void DumpIndex(FILE* = 0) const; @@ -1156,7 +1288,7 @@ namespace ASDCP { SP_LEFT, SP_RIGHT }; - + struct SFrameBuffer { JP2K::FrameBuffer Left; @@ -1178,10 +1310,16 @@ namespace ASDCP { MXFSWriter(); virtual ~MXFSWriter(); + // Warning: direct manipulation of MXF structures can interfere + // with the normal operation of the wrapper. Caveat emptor! + virtual MXF::OP1aHeader& OP1aHeader(); + virtual MXF::OPAtomIndexFooter& OPAtomIndexFooter(); + virtual MXF::RIP& RIP(); + // Open the file for writing. The file must not exist. Returns error if // the operation cannot be completed or if nonsensical data is discovered // in the essence descriptor. - Result_t OpenWrite(const char* filename, const WriterInfo&, + Result_t OpenWrite(const std::string& filename, const WriterInfo&, const PictureDescriptor&, ui32_t HeaderSize = 16384); // Writes a pair of frames of essence to the MXF file. If the optional AESEncContext @@ -1215,9 +1353,15 @@ namespace ASDCP { MXFSReader(); virtual ~MXFSReader(); + // Warning: direct manipulation of MXF structures can interfere + // with the normal operation of the wrapper. Caveat emptor! + virtual MXF::OP1aHeader& OP1aHeader(); + virtual MXF::OPAtomIndexFooter& OPAtomIndexFooter(); + virtual MXF::RIP& RIP(); + // Open the file for reading. The file must exist. Returns error if the // operation cannot be completed. - Result_t OpenRead(const char* filename) const; + Result_t OpenRead(const std::string& filename) const; // Returns RESULT_INIT if the file is not open. Result_t Close() const; @@ -1249,6 +1393,12 @@ namespace ASDCP { Result_t ReadFrame(ui32_t frame_number, StereoscopicPhase_t phase, FrameBuffer&, AESDecContext* = 0, HMACContext* = 0) const; + // Using the index table read from the footer partition, lookup the frame number + // and return the offset into the file at which to read that frame of essence. + // Returns RESULT_INIT if the file is not open, and RESULT_FRAME if the frame number is + // out of range. + Result_t LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset, i8_t& temporalOffset, i8_t& keyFrameOffset) const; + // Print debugging information to stream void DumpHeaderMetadata(FILE* = 0) const; void DumpIndex(FILE* = 0) const; @@ -1264,7 +1414,7 @@ namespace ASDCP { struct TimedTextResourceDescriptor { byte_t ResourceID[UUIDlen]; - MIMEType_t Type; + MIMEType_t Type; TimedTextResourceDescriptor() : Type(MT_BIN) {} }; @@ -1273,7 +1423,7 @@ namespace ASDCP { struct TimedTextDescriptor { - Rational EditRate; // + Rational EditRate; // ui32_t ContainerDuration; byte_t AssetID[UUIDlen]; std::string NamespaceName; @@ -1301,7 +1451,7 @@ namespace ASDCP { 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(); } @@ -1311,6 +1461,8 @@ namespace ASDCP { void Dump(FILE* = 0, ui32_t dump_bytes = 0) const; }; + // An abstract base for a lookup service that returns the resource data + // identified by the given ancillary resource id. // class IResourceResolver { @@ -1319,6 +1471,20 @@ namespace ASDCP { virtual Result_t ResolveRID(const byte_t* uuid, FrameBuffer&) const = 0; // return data for RID }; + // Resolves resource references by testing the named directory for file names containing + // the respective UUID. + // + class LocalFilenameResolver : public ASDCP::TimedText::IResourceResolver + { + std::string m_Dirname; + ASDCP_NO_COPY_CONSTRUCT(LocalFilenameResolver); + + public: + LocalFilenameResolver(); + Result_t OpenRead(const std::string& dirname); + Result_t ResolveRID(const byte_t* uuid, FrameBuffer& FrameBuf) const; + }; + // class DCSubtitleParser { @@ -1330,9 +1496,14 @@ namespace ASDCP { DCSubtitleParser(); virtual ~DCSubtitleParser(); - // Opens the XML file for reading, parse data to provide a complete + // 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; + Result_t OpenRead(const std::string& filename) const; + + // Parses an XML document to provide a complete set of stream metadata + // for the MXFWriter below. The optional filename argument is used to + // initialize the default resource resolver (see ReadAncillaryResource). + Result_t OpenRead(const std::string& xml_doc, const std::string& filename) const; // Fill a TimedTextDescriptor struct with the values from the file's contents. // Returns RESULT_INIT if the file is not open. @@ -1363,10 +1534,16 @@ namespace ASDCP { MXFWriter(); virtual ~MXFWriter(); + // Warning: direct manipulation of MXF structures can interfere + // with the normal operation of the wrapper. Caveat emptor! + virtual MXF::OP1aHeader& OP1aHeader(); + virtual MXF::OPAtomIndexFooter& OPAtomIndexFooter(); + virtual MXF::RIP& RIP(); + // Open the file for writing. The file must not exist. Returns error if // the operation cannot be completed or if nonsensical data is discovered // in the essence descriptor. - Result_t OpenWrite(const char* filename, const WriterInfo&, + Result_t OpenWrite(const std::string& filename, const WriterInfo&, const TimedTextDescriptor&, ui32_t HeaderSize = 16384); // Writes the Timed-Text Resource to the MXF file. The file must be UTF-8 @@ -1400,9 +1577,15 @@ namespace ASDCP { MXFReader(); virtual ~MXFReader(); + // Warning: direct manipulation of MXF structures can interfere + // with the normal operation of the wrapper. Caveat emptor! + virtual MXF::OP1aHeader& OP1aHeader(); + virtual MXF::OPAtomIndexFooter& OPAtomIndexFooter(); + virtual MXF::RIP& RIP(); + // Open the file for reading. The file must exist. Returns error if the // operation cannot be completed. - Result_t OpenRead(const char* filename) const; + Result_t OpenRead(const std::string& filename) const; // Returns RESULT_INIT if the file is not open. Result_t Close() const; @@ -1444,6 +1627,294 @@ namespace ASDCP { }; } // namespace TimedText + //--------------------------------------------------------------------------------- + // + namespace DCData + { + struct DCDataDescriptor + { + Rational EditRate; // Sample rate + ui32_t ContainerDuration; // number of frames + byte_t AssetID[UUIDlen]; // The UUID for the DCData track + byte_t DataEssenceCoding[UUIDlen]; // The coding for the data carried + }; + + // Print DCDataDescriptor to std::ostream + std::ostream& operator << (std::ostream& strm, const DCDataDescriptor& ddesc); + // Print debugging information to stream (stderr default) + void DCDataDescriptorDump(const DCDataDescriptor&, FILE* = 0); + + // + class FrameBuffer : public ASDCP::FrameBuffer + { + public: + FrameBuffer() {} + FrameBuffer(ui32_t size) { Capacity(size); } + virtual ~FrameBuffer() {} + + // Print debugging information to stream (stderr default) + void Dump(FILE* = 0, ui32_t dump_bytes = 0) const; + }; + + // An object which opens and reads a DC Data file. The file is expected + // to contain exactly one complete frame of DC data essence as an unwrapped (raw) + // byte stream. + class BytestreamParser + { + class h__BytestreamParser; + mem_ptr m_Parser; + ASDCP_NO_COPY_CONSTRUCT(BytestreamParser); + + public: + BytestreamParser(); + virtual ~BytestreamParser(); + + // Opens a file for reading, parses enough data to provide a complete + // set of stream metadata for the MXFWriter below. + // The frame buffer's PlaintextOffset parameter will be set to the first + // byte of the data segment. Set this value to zero if you want + // encrypted headers. + Result_t OpenReadFrame(const std::string& filename, FrameBuffer&) const; + + // Fill a DCDataDescriptor struct with the values from the file's bytestream. + // Returns RESULT_INIT if the file is not open. + Result_t FillDCDataDescriptor(DCDataDescriptor&) const; + }; + + // An object which reads a sequence of files containing DC Data. + class SequenceParser + { + class h__SequenceParser; + mem_ptr m_Parser; + ASDCP_NO_COPY_CONSTRUCT(SequenceParser); + + public: + SequenceParser(); + virtual ~SequenceParser(); + + // Opens a directory for reading. The directory is expected to contain one or + // more files, each containing the bytestream for exactly one frame. The files + // must be named such that the frames are in temporal order when sorted + // alphabetically by filename. + Result_t OpenRead(const std::string& filename) const; + + // Opens a file sequence for reading. The sequence is expected to contain one or + // more filenames, each naming a file containing the bytestream for exactly one + // frame. + Result_t OpenRead(const std::list& file_list) const; + + // Fill a DCDataDescriptor struct with default values. + // Returns RESULT_INIT if the directory is not open. + Result_t FillDCDataDescriptor(DCDataDescriptor&) const; + + // Rewind the directory to the beginning. + Result_t Reset() const; + + // Reads the next sequential frame in the directory and places it in the + // frame buffer. Fails if the buffer is too small or the direcdtory + // contains no more files. + // The frame buffer's PlaintextOffset parameter will be set to the first + // byte of the data segment. Set this value to zero if you want + // encrypted headers. + Result_t ReadFrame(FrameBuffer&) const; + }; + + // + class MXFWriter + { + class h__Writer; + mem_ptr m_Writer; + ASDCP_NO_COPY_CONSTRUCT(MXFWriter); + + public: + MXFWriter(); + virtual ~MXFWriter(); + + // Warning: direct manipulation of MXF structures can interfere + // with the normal operation of the wrapper. Caveat emptor! + virtual MXF::OP1aHeader& OP1aHeader(); + virtual MXF::OPAtomIndexFooter& OPAtomIndexFooter(); + virtual MXF::RIP& RIP(); + + // Open the file for writing. The file must not exist. Returns error if + // the operation cannot be completed or if nonsensical data is discovered + // in the essence descriptor. + Result_t OpenWrite(const std::string& filename, const WriterInfo&, + const DCDataDescriptor&, ui32_t HeaderSize = 16384); + + // Writes a frame of essence to the MXF file. If the optional AESEncContext + // argument is present, the essence is encrypted prior to writing. + // Fails if the file is not open, is finalized, or an operating system + // error occurs. + Result_t WriteFrame(const FrameBuffer&, AESEncContext* = 0, HMACContext* = 0); + + // Closes the MXF file, writing the index and revised header. + Result_t Finalize(); + }; + + // + class MXFReader + { + class h__Reader; + mem_ptr m_Reader; + ASDCP_NO_COPY_CONSTRUCT(MXFReader); + + public: + MXFReader(); + virtual ~MXFReader(); + + // Warning: direct manipulation of MXF structures can interfere + // with the normal operation of the wrapper. Caveat emptor! + virtual MXF::OP1aHeader& OP1aHeader(); + virtual MXF::OPAtomIndexFooter& OPAtomIndexFooter(); + virtual MXF::RIP& RIP(); + + // Open the file for reading. The file must exist. Returns error if the + // operation cannot be completed. + Result_t OpenRead(const std::string& filename) const; + + // Returns RESULT_INIT if the file is not open. + Result_t Close() const; + + // Fill a DCDataDescriptor struct with the values from the file's header. + // Returns RESULT_INIT if the file is not open. + Result_t FillDCDataDescriptor(DCDataDescriptor&) const; + + // Fill a WriterInfo struct with the values from the file's header. + // Returns RESULT_INIT if the file is not open. + Result_t FillWriterInfo(WriterInfo&) const; + + // Reads a frame of essence from the MXF file. If the optional AESEncContext + // argument is present, the essence is decrypted after reading. If the MXF + // file is encrypted and the AESDecContext argument is NULL, the frame buffer + // will contain the ciphertext frame data. If the HMACContext argument is + // not NULL, the HMAC will be calculated (if the file supports it). + // Returns RESULT_INIT if the file is not open, failure if the frame number is + // out of range, or if optional decrypt or HAMC operations fail. + Result_t ReadFrame(ui32_t frame_number, FrameBuffer&, AESDecContext* = 0, HMACContext* = 0) const; + + // Using the index table read from the footer partition, lookup the frame number + // and return the offset into the file at which to read that frame of essence. + // Returns RESULT_INIT if the file is not open, and RESULT_RANGE if the frame number is + // out of range. + Result_t LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset, i8_t& temporalOffset, i8_t& keyFrameOffset) const; + + // Print debugging information to stream + void DumpHeaderMetadata(FILE* = 0) const; + void DumpIndex(FILE* = 0) const; + }; + + } // namespace DCData + + //--------------------------------------------------------------------------------- + // + namespace ATMOS + { + struct AtmosDescriptor : public DCData::DCDataDescriptor + { + ui32_t FirstFrame; // Frame number of the frame to align with the FFOA of the picture track + ui16_t MaxChannelCount; // Max number of channels in bitstream + ui16_t MaxObjectCount; // Max number of objects in bitstream + byte_t AtmosID[UUIDlen]; // UUID of Atmos Project + ui8_t AtmosVersion; // ATMOS Coder Version used to create bitstream + }; + + // Print AtmosDescriptor to std::ostream + std::ostream& operator << (std::ostream& strm, const AtmosDescriptor& adesc); + // Print debugging information to stream (stderr default) + void AtmosDescriptorDump(const AtmosDescriptor&, FILE* = 0); + // Determine if a file is a raw atmos file + bool IsDolbyAtmos(const std::string& filename); + + // + class MXFWriter + { + + class h__Writer; + mem_ptr m_Writer; + ASDCP_NO_COPY_CONSTRUCT(MXFWriter); + + public: + MXFWriter(); + virtual ~MXFWriter(); + + // Warning: direct manipulation of MXF structures can interfere + // with the normal operation of the wrapper. Caveat emptor! + virtual MXF::OP1aHeader& OP1aHeader(); + virtual MXF::OPAtomIndexFooter& OPAtomIndexFooter(); + virtual MXF::RIP& RIP(); + + // Open the file for writing. The file must not exist. Returns error if + // the operation cannot be completed or if nonsensical data is discovered + // in the essence descriptor. + Result_t OpenWrite(const std::string& filename, const WriterInfo&, + const AtmosDescriptor&, ui32_t HeaderSize = 16384); + + // Writes a frame of essence to the MXF file. If the optional AESEncContext + // argument is present, the essence is encrypted prior to writing. + // Fails if the file is not open, is finalized, or an operating system + // error occurs. + Result_t WriteFrame(const DCData::FrameBuffer&, AESEncContext* = 0, HMACContext* = 0); + + // Closes the MXF file, writing the index and revised header. + Result_t Finalize(); + }; + + // + class MXFReader + { + class h__Reader; + mem_ptr m_Reader; + ASDCP_NO_COPY_CONSTRUCT(MXFReader); + + public: + MXFReader(); + virtual ~MXFReader(); + + // Warning: direct manipulation of MXF structures can interfere + // with the normal operation of the wrapper. Caveat emptor! + virtual MXF::OP1aHeader& OP1aHeader(); + virtual MXF::OPAtomIndexFooter& OPAtomIndexFooter(); + virtual MXF::RIP& RIP(); + + // Open the file for reading. The file must exist. Returns error if the + // operation cannot be completed. + Result_t OpenRead(const std::string& filename) const; + + // Returns RESULT_INIT if the file is not open. + Result_t Close() const; + + // Fill an AtmosDescriptor struct with the values from the file's header. + // Returns RESULT_INIT if the file is not open. + Result_t FillAtmosDescriptor(AtmosDescriptor&) const; + + // Fill a WriterInfo struct with the values from the file's header. + // Returns RESULT_INIT if the file is not open. + Result_t FillWriterInfo(WriterInfo&) const; + + // Reads a frame of essence from the MXF file. If the optional AESEncContext + // argument is present, the essence is decrypted after reading. If the MXF + // file is encrypted and the AESDecContext argument is NULL, the frame buffer + // will contain the ciphertext frame data. If the HMACContext argument is + // not NULL, the HMAC will be calculated (if the file supports it). + // Returns RESULT_INIT if the file is not open, failure if the frame number is + // out of range, or if optional decrypt or HAMC operations fail. + Result_t ReadFrame(ui32_t frame_number, DCData::FrameBuffer&, AESDecContext* = 0, HMACContext* = 0) const; + + // Using the index table read from the footer partition, lookup the frame number + // and return the offset into the file at which to read that frame of essence. + // Returns RESULT_INIT if the file is not open, and RESULT_RANGE if the frame number is + // out of range. + Result_t LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset, i8_t& temporalOffset, i8_t& keyFrameOffset) const; + + // Print debugging information to stream + void DumpHeaderMetadata(FILE* = 0) const; + void DumpIndex(FILE* = 0) const; + }; + + } // namespace ATMOS + + } // namespace ASDCP