X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=src%2FAS_DCP.h;h=b49746b9c9fc589b46537d9dbe01f8c9bfd8358d;hb=8fad4cc485b8791abb93ec97fe6bff7b7aa3834b;hp=5dafdaa5fbef63e0623340893b817731c9d22909;hpb=72e5392ca11c06a1ac0732c71f86df0d9a712ce3;p=asdcplib.git diff --git a/src/AS_DCP.h b/src/AS_DCP.h index 5dafdaa..b49746b 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) */ @@ -78,8 +89,10 @@ This project depends upon the following library: #include #include #include -#include #include +#include +#include +#include //-------------------------------------------------------------------------------- // common integer types @@ -133,17 +146,8 @@ typedef unsigned int ui32_t; // All library components are defined in the namespace ASDCP // namespace ASDCP { - // The version number consists of three segments: major, API minor, and - // implementation minor. Whenever a change is made to AS_DCP.h, the API minor - // version will increment. Changes made to the internal implementation will - // result in the incrementing of the implementation minor version. - - // For example, if asdcplib version 1.0.0 were modified to accomodate changes - // in file format, and if no changes were made to AS_DCP.h, the new version would be - // 1.0.1. If changes were also required in AS_DCP.h, the new version would be 1.1.1. - const ui32_t VERSION_MAJOR = 1; - const ui32_t VERSION_APIMINOR = 1; - const ui32_t VERSION_IMPMINOR = 9; + // + // The version number declaration and explanation have moved to ../configure.ac const char* Version(); // UUIDs are passed around as strings of UUIDlen bytes @@ -189,6 +193,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 @@ -201,6 +207,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 @@ -242,9 +250,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. @@ -329,6 +338,8 @@ namespace ASDCP { } }; + // 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); @@ -407,7 +418,7 @@ namespace ASDCP { // Initializes HMAC context. The key argument must point to a binary // key that is CBC_KEY_SIZE bytes in length. Returns error if the key // argument is NULL. - Result_t InitKey(const byte_t* key, LabelSet_t = LS_MXF_INTEROP); + Result_t InitKey(const byte_t* key, LabelSet_t); // Reset internal state, allows repeated cycles of Update -> Finalize void Reset(); @@ -559,6 +570,8 @@ namespace ASDCP { 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); @@ -751,6 +764,8 @@ namespace ASDCP { ui32_t ContainerDuration; // number of frames }; + // 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); @@ -889,14 +904,46 @@ 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 + +#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 ImageComponent + 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 { - byte_t Ssize; - byte_t XRsize; - byte_t YRsize; + ui8_t Sqcd; + ui8_t SPqcd[MaxDefaults]; + ui8_t SPqcdLength; }; +#pragma pack() struct PictureDescriptor { @@ -916,13 +963,13 @@ namespace ASDCP { ui32_t XTOsize; ui32_t YTOsize; ui16_t Csize; - ImageComponent ImageComponents[MaxComponents]; - byte_t CodingStyle[DefaultCodingDataLength]; - ui32_t CodingStyleLength; - byte_t QuantDefault[DefaultCodingDataLength]; - ui32_t QuantDefaultLength; + ImageComponent_t ImageComponents[MaxComponents]; + CodingStyleDefault_t CodingStyleDefault; + QuantizationDefault_t QuantizationDefault; }; + // Print debugging information to std::ostream + std::ostream& operator << (std::ostream& strm, const PictureDescriptor& pdesc); // Print debugging information to stream (stderr default) void PictureDescriptorDump(const PictureDescriptor&, FILE* = 0); @@ -964,6 +1011,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 { @@ -1068,7 +1119,304 @@ 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 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 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