X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;ds=inline;f=src%2FAS_DCP.h;h=1647f1e78c4d373930e8daf5428a523aeda65e71;hb=766b93f3654e6e80623a84774fce0307694340f9;hp=4e10d09a361ba1f31f128eb3d6f5d42e0230ece8;hpb=984de376d405e0b68e77d61558d4f798fa1170a5;p=asdcplib.git diff --git a/src/AS_DCP.h b/src/AS_DCP.h index 4e10d09..1647f1e 100755 --- a/src/AS_DCP.h +++ b/src/AS_DCP.h @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2006, John Hurst +Copyright (c) 2003-2008, John Hurst All rights reserved. Redistribution and use in source and binary forms, with or without @@ -34,16 +34,21 @@ D-Cinema packaging working group DC28.20. The file format, labeled AS-DCP, is described in series of separate documents which include but may not be limited to: - o AS-DCP Track File Specification - o AS-DCP Track File Essence Encryption Specification - o AS-DCP Operational Constraints Specification + o MXF Interop Track File Specification + o MXF Interop Track File Essence Encryption Specification + o MXF Interop Operational Constraints Specification + o SMPTE 429-3-2006 Track File Specification + o SMPTE 429-4-2006 JPEG 2000 for D-Cinema + o SMPTE 429-5-200X Timed Text Track File + o SMPTE 429-6-2006 Essence Encryption Specification + o SMPTE 429-10-200X 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 XXXM - JPEG 2000 picture + o SMPTE 422M - JPEG 2000 picture o SMPTE 382M - WAV/PCM sound o IETF RFC 2104 - HMAC/SHA1 o NIST FIPS 197 - AES (Rijndael) @@ -60,6 +65,11 @@ The following use cases are supported by the library: o Read one or more plaintext JPEG 2000 codestreams from a plaintext ASDCP file o Read one or more plaintext JPEG 2000 codestreams from a ciphertext ASDCP file o Read one or more ciphertext JPEG 2000 codestreams from a ciphertext ASDCP file + o Write one or more plaintext JPEG 2000 stereoscopic codestream pairs to a plaintext ASDCP file + o Write one or more plaintext JPEG 2000 stereoscopic codestream pairs to a ciphertext ASDCP file + o Read one or more plaintext JPEG 2000 stereoscopic codestream pairs from a plaintext ASDCP file + o Read one or more plaintext JPEG 2000 stereoscopic codestream pairs from a ciphertext ASDCP file + o Read one or more ciphertext JPEG 2000 stereoscopic codestream pairs from a ciphertext ASDCP file o Write one or more plaintext PCM audio streams to a plaintext ASDCP file o Write one or more plaintext PCM audio streams to a ciphertext ASDCP file o Read one or more plaintext PCM audio streams from a plaintext ASDCP file @@ -67,8 +77,9 @@ The following use cases are supported by the library: o Read one or more ciphertext PCM audio streams from a ciphertext ASDCP file o Read header metadata from an ASDCP file -This project depends upon the following library: +This project depends upon the following libraries: - OpenSSL http://www.openssl.org/ + - Expat http://expat.sourceforge.net/ (optional) */ @@ -81,6 +92,7 @@ This project depends upon the following library: #include #include #include +#include //-------------------------------------------------------------------------------- // common integer types @@ -143,8 +155,8 @@ namespace ASDCP { // in file format, and if no changes were made to AS_DCP.h, the new version would be // 1.0.1. If changes were also required in AS_DCP.h, the new version would be 1.1.1. const ui32_t VERSION_MAJOR = 1; - const ui32_t VERSION_APIMINOR = 1; - const ui32_t VERSION_IMPMINOR = 13; + const ui32_t VERSION_APIMINOR = 3; + const ui32_t VERSION_IMPMINOR = 18; const char* Version(); // UUIDs are passed around as strings of UUIDlen bytes @@ -190,6 +202,8 @@ namespace ASDCP { 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."); //--------------------------------------------------------------------------------- // file identification @@ -202,6 +216,8 @@ namespace ASDCP { 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 @@ -243,9 +259,10 @@ namespace ASDCP { // common edit rates, use these instead of hard coded constants const Rational EditRate_24(24,1); - const Rational EditRate_23_98(24000,1001); + const Rational EditRate_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); // Non-reference counting container for internal member objects. // Please do not use this class for any other purpose. @@ -890,15 +907,47 @@ namespace ASDCP { namespace JP2K { const ui32_t MaxComponents = 3; - const ui32_t DefaultCodingDataLength = 64; + const ui32_t MaxPrecincts = 32; // ISO 15444-1 Annex A.6.1 + const ui32_t MaxDefaults = 256; // made up - struct ImageComponent +#pragma pack(1) + struct ImageComponent_t // ISO 15444-1 Annex A.5.1 { - byte_t Ssize; - byte_t XRsize; - byte_t YRsize; + ui8_t Ssize; + ui8_t XRsize; + ui8_t YRsize; }; + struct CodingStyleDefault_t // ISO 15444-1 Annex A.6.1 + { + ui8_t Scod; + + struct + { + ui8_t ProgressionOrder; + ui8_t NumberOfLayers[sizeof(ui16_t)]; + ui8_t MultiCompTransform; + } SGcod; + + struct + { + ui8_t DecompositionLevels; + ui8_t CodeblockWidth; + ui8_t CodeblockHeight; + ui8_t CodeblockStyle; + ui8_t Transformation; + ui8_t PrecinctSize[MaxPrecincts]; + } SPcod; + }; + + struct QuantizationDefault_t // ISO 15444-1 Annex A.6.4 + { + ui8_t Sqcd; + ui8_t SPqcd[MaxDefaults]; + ui8_t SPqcdLength; + }; +#pragma pack() + struct PictureDescriptor { Rational EditRate; @@ -917,11 +966,9 @@ namespace ASDCP { ui32_t XTOsize; ui32_t YTOsize; ui16_t Csize; - ImageComponent ImageComponents[MaxComponents]; - byte_t CodingStyle[DefaultCodingDataLength]; - ui32_t CodingStyleLength; - byte_t QuantDefault[DefaultCodingDataLength]; - ui32_t QuantDefaultLength; + ImageComponent_t ImageComponents[MaxComponents]; + CodingStyleDefault_t CodingStyleDefault; + QuantizationDefault_t QuantizationDefault; }; // Print debugging information to stream (stderr default) @@ -965,6 +1012,10 @@ namespace ASDCP { 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 { @@ -1069,7 +1120,302 @@ namespace ASDCP { void DumpHeaderMetadata(FILE* = 0) const; void DumpIndex(FILE* = 0) const; }; + + + // Stereoscopic Image support + // + + enum StereoscopicPhase_t + { + SP_LEFT, + SP_RIGHT + }; + + struct SFrameBuffer + { + JP2K::FrameBuffer Left; + JP2K::FrameBuffer Right; + + SFrameBuffer(ui32_t size) { + Left.Capacity(size); + Right.Capacity(size); + } + }; + + class MXFSWriter + { + class h__SWriter; + mem_ptr m_Writer; + ASDCP_NO_COPY_CONSTRUCT(MXFSWriter); + + public: + MXFSWriter(); + virtual ~MXFSWriter(); + + // Open the file for writing. The file must not exist. Returns error if + // the operation cannot be completed or if nonsensical data is discovered + // in the essence descriptor. + Result_t OpenWrite(const char* filename, const WriterInfo&, + const PictureDescriptor&, ui32_t HeaderSize = 16384); + + // Writes a pair of frames of essence to the MXF file. If the optional AESEncContext + // argument is present, the essence is encrypted prior to writing. + // Fails if the file is not open, is finalized, or an operating system + // error occurs. + Result_t WriteFrame(const SFrameBuffer&, AESEncContext* = 0, HMACContext* = 0); + + // Writes a frame of essence to the MXF file. If the optional AESEncContext + // argument is present, the essence is encrypted prior to writing. + // Fails if the file is not open, is finalized, or an operating system + // error occurs. Frames must be written in the proper phase (L-R-L-R), + // RESULT_SPHASE will be returned if phase is reversed. The first frame + // written must be left eye. + Result_t WriteFrame(const FrameBuffer&, StereoscopicPhase_t phase, + AESEncContext* = 0, HMACContext* = 0); + + // Closes the MXF file, writing the index and revised header. Returns + // RESULT_SPHASE if WriteFrame was called an odd number of times. + Result_t Finalize(); + }; + + // + class MXFSReader + { + class h__SReader; + mem_ptr m_Reader; + ASDCP_NO_COPY_CONSTRUCT(MXFSReader); + + public: + MXFSReader(); + virtual ~MXFSReader(); + + // 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 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 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 m_Parser; + ASDCP_NO_COPY_CONSTRUCT(DCSubtitleParser); + + public: + DCSubtitleParser(); + virtual ~DCSubtitleParser(); + + // Opens the XML file for reading, parse data to provide a complete + // set of stream metadata for the MXFWriter below. + Result_t OpenRead(const char* filename) const; + + // Fill a TimedTextDescriptor struct with the values from the file's contents. + // Returns RESULT_INIT if the file is not open. + Result_t FillDescriptor(TimedTextDescriptor&) const; + + // Reads the complete Timed Text Resource into the given string. + Result_t ReadTimedTextResource(std::string&) const; + + // Reads the Ancillary Resource having the given ID. Fails if the buffer + // is too small or the resource does not exist. The optional Resolver + // argument can be provided which will be used to retrieve the resource + // having a particulat UUID. If a Resolver is not supplied, the default + // internal resolver will return the contents of the file having the UUID + // as the filename. The filename must exist in the same directory as the + // XML file opened with OpenRead(). + Result_t ReadAncillaryResource(const byte_t* uuid, FrameBuffer&, + const IResourceResolver* Resolver = 0) const; + }; + + // + class MXFWriter + { + class h__Writer; + mem_ptr m_Writer; + ASDCP_NO_COPY_CONSTRUCT(MXFWriter); + + public: + MXFWriter(); + virtual ~MXFWriter(); + + // 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 m_Reader; + ASDCP_NO_COPY_CONSTRUCT(MXFReader); + + public: + MXFReader(); + virtual ~MXFReader(); + + // 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 FillDescriptor(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