Fix typo.
[asdcplib.git] / src / AS_02.h
index 355f93a82c3c9e2f3787f239042c592d099fe5c3..61a2c1e0ba6b83c0e1fd715086c01c5361643d52 100644 (file)
@@ -1,5 +1,7 @@
 /*
-Copyright (c) 2011-2012, Robert Scheler, Heiko Sparenberg Fraunhofer IIS, John Hurst
+Copyright (c) 2011-2018, Robert Scheler, Heiko Sparenberg Fraunhofer IIS,
+John Hurst
+
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -34,7 +36,7 @@ by the SMPTE Media and Packaging Technology Committee 35PM. The file
 format, labeled IMF Essence Component (AKA "AS-02" for historical
 reasons), is described in the following document:
 
- o SMPTE 2067-5:201X (draft at this time) IMF Essence Component
+ o SMPTE 2067-5:2013 IMF Essence Component
 
 The following use cases are supported by the module:
 
@@ -47,101 +49,96 @@ The following use cases are supported by the module:
      PCM audio streams
 
  o Read header metadata from an AS-02 file
+
+NOTE: ciphertext support for clip-wrapped PCM is not yet complete.
 */
 
 #ifndef _AS_02_H_
 #define _AS_02_H_
 
-#include "AS_DCP.h"
-#include "MXF.h"
+#include "Metadata.h"
 
 
-namespace ASDCP {
-  namespace MXF {
-    // #include<Metadata.h> to use these
-    class OPAtomHeader;
-    class OPAtomIndexFooter;
-  };
-};
-
 namespace AS_02
 {
   using Kumu::Result_t;
 
-  namespace MXF {
+  KM_DECLARE_RESULT(AS02_FORMAT,        -116, "The file format is not proper OP-1a/AS-02.");
 
+  namespace MXF {
     //
-    class OP1aIndexBodyPartion : public ASDCP::MXF::Partition
+    // reads distributed index tables and provides a uniform lookup with
+    // translated StreamOffest values (that is, StreamOffest is adjusted
+    // to the actual file position
+    class AS02IndexReader : public ASDCP::MXF::Partition
     {
-      ASDCP::MXF::IndexTableSegment*  m_CurrentSegment;
-      ASDCP::FrameBuffer  m_Buffer;
-      ASDCP::MXF::Rational m_EditRate;
-      ui32_t                           klv_fill_size;
+      Kumu::ByteString m_IndexSegmentData;
+      ui32_t m_Duration;
+      ui32_t m_BytesPerEditUnit;
 
-      ASDCP_NO_COPY_CONSTRUCT(OP1aIndexBodyPartion);
+      Result_t InitFromBuffer(const byte_t* p, ui32_t l, const ui64_t& body_offset, const ui64_t& essence_container_offset);
 
+      ASDCP_NO_COPY_CONSTRUCT(AS02IndexReader);
+      AS02IndexReader();
+         
     public:
-      const ASDCP::Dictionary*&  m_Dict;
-      Kumu::fpos_t        m_ECOffset;
-      ASDCP::IPrimerLookup*      m_Lookup;
-
-      ui32_t             m_BytesPerEditUnit;
-      ui32_t             m_FramesWritten;
-      
-      OP1aIndexBodyPartion(const ASDCP::Dictionary*&);
-      virtual ~OP1aIndexBodyPartion();
-      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, ASDCP::UL& PartitionLabel);
-      virtual void     Dump(FILE* = 0);
-
-      virtual bool Lookup(ui32_t frame_num, ASDCP::MXF::IndexTableSegment::IndexEntry&,ui32_t&) const;
-      virtual void PushIndexEntry(const ASDCP::MXF::IndexTableSegment::IndexEntry&);
-      virtual void SetIndexParamsCBR(ASDCP::IPrimerLookup* lookup, ui32_t size, const ASDCP::MXF::Rational& Rate);
-      virtual void SetIndexParamsVBR(ASDCP::IPrimerLookup* lookup, const ASDCP::MXF::Rational& Rate, Kumu::fpos_t offset);
-
-      //new
-      virtual ui64_t Duration();
-      virtual Result_t FillWriteToFile(Kumu::FileWriter& Writer, ui32_t numberOfIndexEntries);
-
-      //new for PCM
-      virtual void PCMSetIndexParamsCBR(ui32_t sizeFirst, ui32_t sizeOthers);
-      virtual void PCMIndexLookup(ui32_t frame_num, ASDCP::MXF::IndexTableSegment::IndexEntry& Entry) const;
-      
+      const ASDCP::Dictionary*&   m_Dict;
+      ASDCP::IPrimerLookup *m_Lookup;
+    
+      AS02IndexReader(const ASDCP::Dictionary*&);
+      virtual ~AS02IndexReader();
+    
+      Result_t InitFromFile(const Kumu::FileReader& reader, const ASDCP::MXF::RIP& rip, const bool has_header_essence);
+      ui32_t GetDuration() const;
+      void     Dump(FILE* = 0);
+      Result_t GetMDObjectByID(const Kumu::UUID&, ASDCP::MXF::InterchangeObject** = 0);
+      Result_t GetMDObjectByType(const byte_t*, ASDCP::MXF::InterchangeObject** = 0);
+      Result_t GetMDObjectsByType(const byte_t* ObjectID, std::list<ASDCP::MXF::InterchangeObject*>& ObjectList);
+      Result_t Lookup(ui32_t frame_num, ASDCP::MXF::IndexTableSegment::IndexEntry&) const;
     };
 
-    //
-    class OP1aIndexFooter : public ASDCP::MXF::Partition
+    
+    // Returns size in bytes of a single sample of data described by ADesc
+    inline ui32_t CalcSampleSize(const ASDCP::MXF::WaveAudioDescriptor& d)
     {
-      ASDCP::MXF::IndexTableSegment*  m_CurrentSegment;
-      ASDCP::FrameBuffer  m_Buffer;
-      ui32_t              m_BytesPerEditUnit;
-      ASDCP::MXF::Rational m_EditRate;
-      ui32_t              m_BodySID;
-      ASDCP_NO_COPY_CONSTRUCT(OP1aIndexFooter);
+      return (d.QuantizationBits / 8) * d.ChannelCount;
+    }
 
-    public:
-      const ASDCP::Dictionary*&   m_Dict;
-      Kumu::fpos_t        m_ECOffset;
-      ASDCP::IPrimerLookup*      m_Lookup;
-
-      OP1aIndexFooter(const ASDCP::Dictionary*&);
-      virtual ~OP1aIndexFooter();
-      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 Lookup(ui32_t frame_num, ASDCP::MXF::IndexTableSegment::IndexEntry&) const;
-      virtual void     PushIndexEntry(const ASDCP::MXF::IndexTableSegment::IndexEntry&);
-      virtual void     SetIndexParamsCBR(ASDCP::IPrimerLookup* lookup, ui32_t size, const ASDCP::MXF::Rational& Rate);
-      virtual void     SetIndexParamsVBR(ASDCP::IPrimerLookup* lookup, const ASDCP::MXF::Rational& Rate, Kumu::fpos_t offset);
-    };
+      // Returns number of samples per frame of data described by ADesc
+    inline ui32_t CalcSamplesPerFrame(const ASDCP::MXF::WaveAudioDescriptor& d, const ASDCP::Rational& edit_rate)
+    {
+      double tmpd = d.AudioSamplingRate.Quotient() / edit_rate.Quotient();
+      return (ui32_t)ceil(tmpd);
+    }
+
+    // Returns the size in bytes of a frame of data described by ADesc
+    inline ui32_t CalcFrameBufferSize(const ASDCP::MXF::WaveAudioDescriptor& d, const ASDCP::Rational& edit_rate)
+    {
+      return CalcSampleSize(d) * CalcSamplesPerFrame(d, edit_rate);
+    }
+
+    // Returns number of frames for data described by ADesc, given a duration in samples and an edit rate
+    inline ui32_t CalcFramesFromDurationInSamples(const ui32_t duration_samples, const ASDCP::MXF::WaveAudioDescriptor& d,
+                                                 const ASDCP::Rational& edit_rate)
+    {
+      ui32_t spf = CalcSamplesPerFrame(d, edit_rate);
+      ui32_t frames = duration_samples / spf;
+      
+      if ( duration_samples % spf != 0 )
+       {
+         ++frames;
+       }
+
+      return frames;
+    }
 
   } // namespace MXF
 
 
+  // IMF App 2 edit rates not already exposed in namespace ASDCP
+  const ASDCP::Rational EditRate_29_97 = ASDCP::Rational(30000, 1001);
+  const ASDCP::Rational EditRate_59_94 = ASDCP::Rational(60000, 1001);
+
   //---------------------------------------------------------------------------------
   // 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
@@ -152,10 +149,11 @@ namespace AS_02
     IS_LEAD,
     IS_FOLLOW,
     IS_FILE_SPECIFIC,
+    IS_MAX
   };
  
   namespace JP2K
-  {
+  { 
     //
     class MXFWriter
     {
@@ -169,17 +167,18 @@ namespace AS_02
 
       // Warning: direct manipulation of MXF structures can interfere
       // with the normal operation of the wrapper.  Caveat emptor!
-      virtual ASDCP::MXF::OPAtomHeader& OPAtomHeader();
+      virtual ASDCP::MXF::OP1aHeader& OP1aHeader();
+      virtual ASDCP::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 ASDCP::WriterInfo&,
-                        const ASDCP::JP2K::PictureDescriptor&,
-                        const IndexStrategy_t& Strategy = IS_FOLLOW,
-                        const ui32_t& PartitionSpace = 60, /* seconds per partition */
-                        const ui32_t& HeaderSize = 16384);
-      
+      Result_t OpenWrite(const std::string& filename, const ASDCP::WriterInfo&,
+                        ASDCP::MXF::FileDescriptor* essence_descriptor,
+                        ASDCP::MXF::InterchangeObject_list_t& essence_sub_descriptor_list,
+                        const ASDCP::Rational& edit_rate, const ui32_t& header_size = 16384,
+                        const IndexStrategy_t& strategy = IS_FOLLOW, const ui32_t& partition_space = 10);
+
       // 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
@@ -203,19 +202,17 @@ namespace AS_02
 
       // Warning: direct manipulation of MXF structures can interfere
       // with the normal operation of the wrapper.  Caveat emptor!
-      virtual ASDCP::MXF::OPAtomHeader& OPAtomHeader();
+      virtual ASDCP::MXF::OP1aHeader& OP1aHeader();
+      virtual AS_02::MXF::AS02IndexReader& AS02IndexReader();
+      virtual ASDCP::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;
 
-      // Fill an AudioDescriptor struct with the values from the file's header.
-      // Returns RESULT_INIT if the file is not open.
-      Result_t FillPictureDescriptor(ASDCP::JP2K::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(ASDCP::WriterInfo&) const;
@@ -243,8 +240,16 @@ namespace AS_02
   {
     // see AS_DCP.h for related data types
 
+    // An AS-02 PCM file is clip-wrapped, but the interface defined below mimics that used
+    // for frame-wrapped essence elsewhere in this library.  The concept of frame rate
+    // therefore is only relevant to these classes and is not reflected in or affected by
+    // the contents of the MXF file.  The frame rate that is set on the writer is only
+    // for compatibility with the existing parsers, samples are packed contiguously into
+    // the same clip-wrapped packet.  Similarly, the edit rate must be set when initializing
+    // the reader to signal the number of samples to be read by each call to ReadFrame();
+
     //
-    class MXFWriter
+      class MXFWriter
     {
       class h__Writer;
       ASDCP::mem_ptr<h__Writer> m_Writer;
@@ -256,13 +261,16 @@ namespace AS_02
 
       // Warning: direct manipulation of MXF structures can interfere
       // with the normal operation of the wrapper.  Caveat emptor!
-      virtual ASDCP::MXF::OPAtomHeader& OPAtomHeader();
+      virtual ASDCP::MXF::OP1aHeader& OP1aHeader();
+      virtual ASDCP::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 ASDCP::WriterInfo&,
-                               const ASDCP::PCM::AudioDescriptor&, ui32_t HeaderSize = 16384);
+      Result_t OpenWrite(const std::string& filename, const ASDCP::WriterInfo&,
+                        ASDCP::MXF::FileDescriptor* essence_descriptor,
+                        ASDCP::MXF::InterchangeObject_list_t& essence_sub_descriptor_list,
+                        const ASDCP::Rational& edit_rate, 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.
@@ -287,19 +295,17 @@ namespace AS_02
 
       // Warning: direct manipulation of MXF structures can interfere
       // with the normal operation of the wrapper.  Caveat emptor!
-      virtual ASDCP::MXF::OPAtomHeader& OPAtomHeader();
+      virtual ASDCP::MXF::OP1aHeader& OP1aHeader();
+      virtual AS_02::MXF::AS02IndexReader& AS02IndexReader();
+      virtual ASDCP::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 ASDCP::Rational& EditRate) 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(ASDCP::PCM::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(ASDCP::WriterInfo&) const;
@@ -319,7 +325,271 @@ namespace AS_02
     };
   } // namespace PCM
 
+  //---------------------------------------------------------------------------------
+  //
+  namespace TimedText
+    {
+      using ASDCP::TimedText::TimedTextDescriptor;
+      using ASDCP::TimedText::TimedTextResourceDescriptor;
+      using ASDCP::TimedText::ResourceList_t;
+
+      //
+      class Type5UUIDFilenameResolver : public ASDCP::TimedText::IResourceResolver
+       {
+         typedef std::map<Kumu::UUID, std::string> ResourceMap;
+           
+         ResourceMap m_ResourceMap;
+         std::string m_Dirname;
+         KM_NO_COPY_CONSTRUCT(Type5UUIDFilenameResolver);
+
+       public:
+         Type5UUIDFilenameResolver();
+         virtual ~Type5UUIDFilenameResolver();
+         Result_t OpenRead(const std::string& dirname);
+         Result_t ResolveRID(const byte_t* uuid, ASDCP::TimedText::FrameBuffer& FrameBuf) const;
+       };
+      
+
+      // Generate UUID asset ID values from file contents
+      Kumu::UUID CreatePNGNameId(const std::string& image_name);
+      Kumu::UUID CreateFontNameId(const std::string& font_name);
+
+      //
+      class ST2052_TextParser
+       {
+         class h__TextParser;
+         ASDCP::mem_ptr<h__TextParser> m_Parser;
+         ASDCP_NO_COPY_CONSTRUCT(ST2052_TextParser);
+
+       public:
+         ST2052_TextParser();
+         virtual ~ST2052_TextParser();
+
+         // Opens an XML file for reading, parses data to provide a complete
+         // set of stream metadata for the MXFWriter below.
+         Result_t OpenRead(const std::string& filename) const;
+
+         // Parse an XML string 
+         Result_t OpenRead(const std::string& xml_doc, const std::string& filename) const;
+
+         // The "profile_name" parameter was removed from OpenRead() because it made the API
+         // awkward WRT lexical compatibility with TimedText_Parser. The value can still be
+         // modified by changing the descriptor's NamespaceName property after the call to
+         // FillTimedTextDescriptor() has set it.
+                             
+         // Fill a TimedTextDescriptor struct with the values from the file's contents.
+         // Returns RESULT_INIT if the file is not open.
+         Result_t FillTimedTextDescriptor(ASDCP::TimedText::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 Kumu::UUID&, ASDCP::TimedText::FrameBuffer&,
+                                        const ASDCP::TimedText::IResourceResolver* Resolver = 0) const;
+       };
+
+      //
+      class MXFWriter
+       {
+         class h__Writer;
+         ASDCP::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 ASDCP::MXF::OP1aHeader& OP1aHeader();
+         virtual ASDCP::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 ASDCP::WriterInfo&,
+                            const ASDCP::TimedText::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, ASDCP::AESEncContext* = 0, ASDCP::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 ASDCP::TimedText::FrameBuffer&, ASDCP::AESEncContext* = 0, ASDCP::HMACContext* = 0);
+
+         // Closes the MXF file, writing the index and revised header.
+         Result_t Finalize();
+       };
+
+      //
+      class MXFReader
+       {
+         class h__Reader;
+         ASDCP::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 ASDCP::MXF::OP1aHeader& OP1aHeader();
+         virtual AS_02::MXF::AS02IndexReader& AS02IndexReader();
+         virtual ASDCP::MXF::RIP& RIP();
+
+         // Open the file for reading. The file must exist. Returns error if the
+         // operation cannot be completed.
+         Result_t OpenRead(const std::string& filename) const;
+
+         // Returns RESULT_INIT if the file is not open.
+         Result_t Close() const;
+
+         // Fill a TimedTextDescriptor struct with the values from the file's header.
+         // Returns RESULT_INIT if the file is not open.
+         Result_t FillTimedTextDescriptor(ASDCP::TimedText::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(ASDCP::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&, ASDCP::AESDecContext* = 0, ASDCP::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(ASDCP::TimedText::FrameBuffer&, ASDCP::AESDecContext* = 0, ASDCP::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 Kumu::UUID&, ASDCP::TimedText::FrameBuffer&, ASDCP::AESDecContext* = 0, ASDCP::HMACContext* = 0) const;
+
+         // Print debugging information to stream
+         void     DumpHeaderMetadata(FILE* = 0) const;
+         void     DumpIndex(FILE* = 0) const;
+       };
+    } // namespace TimedText
+
+  namespace ISXD
+  { 
+    //
+    class MXFWriter
+    {
+      class h__Writer;
+      ASDCP::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 ASDCP::MXF::OP1aHeader& OP1aHeader();
+      virtual ASDCP::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 ASDCP::WriterInfo&,
+                        const std::string& isxd_document_namespace,
+                        const ASDCP::Rational& edit_rate, const ui32_t& header_size = 16384,
+                        const IndexStrategy_t& strategy = IS_FOLLOW, const ui32_t& partition_space = 10);
+
+      // 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 ASDCP::FrameBuffer&, ASDCP::AESEncContext* = 0, ASDCP::HMACContext* = 0);
+
+      // Writes an XML text document to the MXF file as per RP 2057. If the
+      // optional AESEncContext argument is present, the document is encrypted
+      // prior to writing. Fails if the file is not open, is finalized, or an
+      // operating system error occurs.
+      Result_t AddDmsGenericPartUtf8Text(const ASDCP::FrameBuffer& frame_buffer, ASDCP::AESEncContext* enc = 0, ASDCP::HMACContext* hmac = 0);
+
+      // Closes the MXF file, writing the index and revised header.
+      Result_t Finalize();
+    };
+
+    //
+    class MXFReader
+    {
+      class h__Reader;
+      ASDCP::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 ASDCP::MXF::OP1aHeader& OP1aHeader();
+      virtual AS_02::MXF::AS02IndexReader& AS02IndexReader();
+      virtual ASDCP::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 WriterInfo struct with the values from the file's header.
+      // Returns RESULT_INIT if the file is not open.
+      Result_t FillWriterInfo(ASDCP::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, ASDCP::FrameBuffer&,
+                        ASDCP::AESDecContext* = 0, ASDCP::HMACContext* = 0) const;
+
+      // Reads a Generic Stream Partition payload. Returns RESULT_INIT if the file is
+      // not open, or RESULT_FORMAT if the SID is not present in the  RIP, or if the
+      // actual partition at ByteOffset does not have a matching BodySID value.
+      // Encryption is not currently supported.
+      Result_t ReadGenericStreamPartitionPayload(ui32_t SID, ASDCP::FrameBuffer& FrameBuf);
+  
+      // Print debugging information to stream
+      void     DumpHeaderMetadata(FILE* = 0) const;
+      void     DumpIndex(FILE* = 0) const;
+    };
+    
+  }
 
 } // namespace AS_02