o Added support for SMPTE RDD 47 "ISXD Track File"
authorjhurst <jhurst@cinecert.com>
Mon, 6 Aug 2018 22:07:03 +0000 (22:07 +0000)
committerjhurst <>
Mon, 6 Aug 2018 22:07:03 +0000 (22:07 +0000)
o Added generic support for SMPTE RP 2057 "Text-Based Metadata Carriage in MXF"
o Re-factored AS-02 frame-wrap index write to use a common implementation
o Re-factored support for SMPTE ST 410 to use a common implementation (affects
o   AS-DCP and AS-02 timed-text MXF (SMPTE 429-5)
o Patched several ambiguous integer casts.
o Added new essence type identifiers ESS_AS02_ISXD and ESS_AS02_ACES
o Fixed a bug wherein the Generic Container data tarck clip was instead being
o   written as a DM track
o Fixed UL values DCDataDescriptor and ContainerConstraintSubDescriptor to have
o   a byte 6 value of 0x53 (Tag Set) instead of 0x07 (coding sentinel)
o Added UL values 492 - 511 to the dictionary
o Added ApplicationSchemes and ConformsToSpecifications to the Preface set
o Added default initializer to MXF::LineMapPair
o Added sets DescriptiveFramework, DescriptiveObject, TextBasedDMFramework,
o   TextBasedObject, GenericStreamTextBasedSet and ISXDDataEssenceDescriptor
o Added ISXD support and options '-G', '-u' to as-02-wrap
o Added ISXD support and option '-g' to as-02-unwrap

26 files changed:
src/AS_02.h
src/AS_02_JP2K.cpp
src/AS_02_PHDR.cpp
src/AS_02_TimedText.cpp
src/AS_02_internal.h
src/AS_DCP.h
src/AS_DCP_MXF.cpp
src/AS_DCP_TimedText.cpp
src/AS_DCP_internal.h
src/Dict.cpp
src/KLV.cpp
src/MDD.cpp
src/MDD.h
src/MXF.cpp
src/MXF.h
src/MXFTypes.h
src/Makefile.am
src/Metadata.cpp
src/Metadata.h
src/as-02-info.cpp
src/as-02-unwrap.cpp
src/as-02-wrap.cpp
src/h__02_Reader.cpp
src/h__02_Writer.cpp
src/h__Writer.cpp
src/klvwalk.cpp

index 33163c3a6462c483bc314c22f45a86beacdbd29f..c2c51799b86b2e434973a1d41012641241d1f425 100644 (file)
@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2011-2016, Robert Scheler, Heiko Sparenberg Fraunhofer IIS,
+Copyright (c) 2011-2018, Robert Scheler, Heiko Sparenberg Fraunhofer IIS,
 John Hurst
 
 All rights reserved.
@@ -498,7 +498,103 @@ namespace AS_02
        };
     } // 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 ASDCP::UL& data_essence_coding,
+                        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 2067. 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;
+
+      // Open the file for reading. The file must exist. Returns error if the
+      // operation cannot be completed. If global metadata is available it will
+      // be placed into the buffer object passed as the second argument.
+      Result_t OpenRead(const std::string& filename, ASDCP::FrameBuffer& global_metadata) 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
 
index ffb40a93054865decaa2de87397c97502226d1d1..0379a96efb38bee83e333d3f6280aaf92591fa50 100644 (file)
@@ -68,7 +68,7 @@ public:
 Result_t
 AS_02::JP2K::MXFReader::h__Reader::OpenRead(const std::string& filename)
 {
-  Result_t result = OpenMXFRead(filename.c_str());
+  Result_t result = OpenMXFRead(filename);
 
   if( KM_SUCCESS(result) )
     {
index 94b973d270fef5d7fa793c39696caa4459d8f062..61795a34f33dc595f473c9e2a66aa745cd1fd58b 100644 (file)
@@ -594,9 +594,8 @@ AS_02::PHDR::MXFWriter::h__Writer::WriteFrame(const AS_02::PHDR::FrameBuffer& Fr
 
       if ( m_FramesWritten > 1 && ( ( m_FramesWritten + 1 ) % m_PartitionSpace ) == 0 )
        {
-         m_IndexWriter.ThisPartition = m_File.Tell();
-         m_IndexWriter.WriteToFile(m_File);
-         m_RIP.PairArray.push_back(RIP::PartitionPair(0, m_IndexWriter.ThisPartition));
+         assert(m_IndexWriter.GetDuration() > 0);
+         FlushIndexPartition();
 
          UL body_ul(m_Dict->ul(MDD_ClosedCompleteBodyPartition));
          Partition body_part(m_Dict);
@@ -627,18 +626,16 @@ Result_t
 AS_02::PHDR::MXFWriter::h__Writer::Finalize(const std::string& PHDR_master_metadata)
 {
   if ( ! m_State.Test_RUNNING() )
-    return RESULT_STATE;
+    {
+      KM_RESULT_STATE_HERE();
+      return RESULT_STATE;
+    }
 
   Result_t result = m_State.Goto_FINAL();
 
   if ( KM_SUCCESS(result) )
     {
-      if ( m_IndexWriter.GetDuration() > 0 )
-       {
-         m_IndexWriter.ThisPartition = this->m_File.Tell();
-         m_IndexWriter.WriteToFile(this->m_File);
-         m_RIP.PairArray.push_back(RIP::PartitionPair(0, this->m_IndexWriter.ThisPartition));
-       }
+      FlushIndexPartition();
 
       if ( ! PHDR_master_metadata.empty() )
        {
index 9e14600b98a697925b829677a7602266f34549c3..974c811e2e7fa8b50fb789a1e0616b075e319a93 100644 (file)
@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2008-2016, John Hurst
+Copyright (c) 2008-2018, John Hurst
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -186,7 +186,7 @@ AS_02::TimedText::MXFReader::h__Reader::ReadTimedTextResource(ASDCP::TimedText::
 //
 ASDCP::Result_t
 AS_02::TimedText::MXFReader::h__Reader::ReadAncillaryResource(const Kumu::UUID& uuid,
-                                                             ASDCP::TimedText::FrameBuffer& FrameBuf,
+                                                             ASDCP::TimedText::FrameBuffer& frame_buf,
                                                              AESDecContext* Ctx, HMACContext* HMAC)
 {
   ResourceMap_t::const_iterator ri = m_ResourceMap.find(uuid);
@@ -197,70 +197,23 @@ AS_02::TimedText::MXFReader::h__Reader::ReadAncillaryResource(const Kumu::UUID&
       return RESULT_RANGE;
     }
 
-  TimedTextResourceSubDescriptor* DescObject = 0;
   // get the subdescriptor
   InterchangeObject* tmp_iobj = 0;
   Result_t result = m_HeaderPart.GetMDObjectByID((*ri).second, &tmp_iobj);
-  DescObject = static_cast<TimedTextResourceSubDescriptor*>(tmp_iobj);
+  TimedTextResourceSubDescriptor* desc_object = dynamic_cast<TimedTextResourceSubDescriptor*>(tmp_iobj);
 
   if ( KM_SUCCESS(result) )
     {
-      RIP::const_pair_iterator pi;
-      RIP::PartitionPair TmpPair;
-      ui32_t sequence = 0;
-
-      // Look up the partition start in the RIP using the SID.
-      // Count the sequence length in because this is the sequence
-      // value needed to  complete the HMAC.
-      for ( pi = m_RIP.PairArray.begin(); pi != m_RIP.PairArray.end(); ++pi, ++sequence )
-       {
-         if ( (*pi).BodySID == DescObject->EssenceStreamID )
-           {
-             TmpPair = *pi;
-             break;
-           }
-       }
-
-      if ( TmpPair.ByteOffset == 0 )
-       {
-         DefaultLogSink().Error("Body SID not found in RIP set: %d\n", DescObject->EssenceStreamID);
-         return RESULT_FORMAT;
-       }
-
-      if ( KM_SUCCESS(result) )
-       {
-         FrameBuf.AssetID(uuid.Value());
-         FrameBuf.MIMEType(DescObject->MIMEMediaType);
-
-         // seek tp the start of the partition
-         if ( (Kumu::fpos_t)TmpPair.ByteOffset != m_LastPosition )
-           {
-             m_LastPosition = TmpPair.ByteOffset;
-             result = m_File.Seek(TmpPair.ByteOffset);
-           }
-
-         // read the partition header
-         ASDCP::MXF::Partition GSPart(m_Dict);
-         result = GSPart.InitFromFile(m_File);
-
-         if( ASDCP_SUCCESS(result) )
-           {
-             // check the SID
-             if ( DescObject->EssenceStreamID != GSPart.BodySID )
-               {
-                 char buf[64];
-                 DefaultLogSink().Error("Generic stream partition body differs: %s\n", uuid.EncodeHex(buf, 64));
-                 return RESULT_FORMAT;
-               }
-
-             // read the essence packet
-             assert(m_Dict);
-             if( ASDCP_SUCCESS(result) )
-               result = ReadEKLVPacket(0, sequence, FrameBuf, m_Dict->ul(MDD_GenericStream_DataElement), Ctx, HMAC);
-           }
-       }
+      assert(desc_object);
+      result = ReadGenericStreamPartitionPayload(desc_object->EssenceStreamID, frame_buf);
     }
 
+  if ( KM_SUCCESS(result) )
+    {
+      frame_buf.AssetID(uuid.Value());
+      frame_buf.MIMEType(desc_object->MIMEMediaType);
+    }
+  
   return result;
 }
 
index 560fb6c0107ebaf7390b520d0b22feb32885ddf8..e068f8de2dd945e471a6933d5a2f0f86d70a7e5f 100644 (file)
@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2011-2016, Robert Scheler, Heiko Sparenberg Fraunhofer IIS,
+Copyright (c) 2011-2018, Robert Scheler, Heiko Sparenberg Fraunhofer IIS,
 John Hurst
 
 All rights reserved.
@@ -188,7 +188,7 @@ namespace AS_02
 
        if ( KM_SUCCESS(result) )
          {
-           this->m_PartitionSpace *= floor( EditRate.Quotient() + 0.5 );  // convert seconds to edit units
+           this->m_PartitionSpace *= (ui32_t)floor( EditRate.Quotient() + 0.5 );  // convert seconds to edit units
            this->m_ECStart = this->m_File.Tell();
            this->m_IndexWriter.IndexSID = 129;
 
@@ -207,9 +207,7 @@ namespace AS_02
        return result;
       }
 
-      // standard method of writing the header and footer of a completed AS-02 file
-      //
-      Result_t WriteAS02Footer()
+      void FlushIndexPartition()
       {
        if ( this->m_IndexWriter.GetDuration() > 0 )
          {
@@ -217,7 +215,14 @@ namespace AS_02
            this->m_IndexWriter.WriteToFile(this->m_File);
            this->m_RIP.PairArray.push_back(RIP::PartitionPair(0, this->m_IndexWriter.ThisPartition));
          }
-
+      }
+      
+      // standard method of writing the header and footer of a completed AS-02 file
+      //
+      Result_t WriteAS02Footer()
+      {
+       this->FlushIndexPartition();
+         
        // update all Duration properties
        ASDCP::MXF::Partition footer_part(this->m_Dict);
        DurationElementList_t::iterator dli = this->m_DurationUpdateList.begin();
index b1540aabcdec14401a2ca69c037b4700e7d51372..96d066cac98acbb8485ba92b443d510a7010d2a6 100755 (executable)
@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2003-2014, John Hurst
+Copyright (c) 2003-2018, John Hurst
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -221,8 +221,8 @@ namespace ASDCP {
     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_ACES,                 // the file contains one ACES codestream
+    ESS_AS02_ISXD,            // the file contains an ISXD document stream (per SMPTE RDD 47)
+    ESS_AS02_ACES,            // the file contains two or more ACES codestreams (per SMPTE ST 2067-50)
     ESS_MAX
   };
 
index a7282df04c4db7c3f59dac4384651efc4061ebff..ed1fa7cc3a44f066d248a846013f012a03c817c5 100755 (executable)
@@ -252,6 +252,14 @@ ASDCP::EssenceType(const std::string& filename, EssenceType_t& type)
            {
              type = ESS_DCDATA_UNKNOWN;
            }
+         else if ( ASDCP_SUCCESS(TestHeader.GetMDObjectByType(OBJ_TYPE_ARGS(ISXDDataEssenceDescriptor))) )
+           {
+             type = ESS_AS02_ISXD;
+           }
+         else if ( ASDCP_SUCCESS(TestHeader.GetMDObjectByType(OBJ_TYPE_ARGS(ACESPictureSubDescriptor))) )
+           {
+             type = ESS_AS02_ACES;
+           }
        }
       else
        {
index 6e34a5d8bcae2c884c0563cc9ea7966967b26f5b..1f0930a53c2fdd231643dc0fcd4919edb19fd6e4 100644 (file)
@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2008-2016, John Hurst
+Copyright (c) 2008-2018, John Hurst
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -244,7 +244,7 @@ ASDCP::TimedText::MXFReader::h__Reader::ReadTimedTextResource(FrameBuffer& Frame
 
 //
 ASDCP::Result_t
-ASDCP::TimedText::MXFReader::h__Reader::ReadAncillaryResource(const byte_t* uuid, FrameBuffer& FrameBuf,
+ASDCP::TimedText::MXFReader::h__Reader::ReadAncillaryResource(const byte_t* uuid, FrameBuffer& frame_buf,
                                                              AESDecContext* Ctx, HMACContext* HMAC)
 {
   KM_TEST_NULL_L(uuid);
@@ -258,68 +258,21 @@ ASDCP::TimedText::MXFReader::h__Reader::ReadAncillaryResource(const byte_t* uuid
       return RESULT_RANGE;
     }
 
-  TimedTextResourceSubDescriptor* DescObject = 0;
   // get the subdescriptor
   InterchangeObject* tmp_iobj = 0;
   Result_t result = m_HeaderPart.GetMDObjectByID((*ri).second, &tmp_iobj);
-  DescObject = static_cast<TimedTextResourceSubDescriptor*>(tmp_iobj);
+  TimedTextResourceSubDescriptor* desc_object = dynamic_cast<TimedTextResourceSubDescriptor*>(tmp_iobj);
 
   if ( KM_SUCCESS(result) )
     {
-      RIP::const_pair_iterator pi;
-      RIP::PartitionPair TmpPair;
-      ui32_t sequence = 0;
-
-      // Look up the partition start in the RIP using the SID.
-      // Count the sequence length in because this is the sequence
-      // value needed to  complete the HMAC.
-      for ( pi = m_RIP.PairArray.begin(); pi != m_RIP.PairArray.end(); ++pi, ++sequence )
-       {
-         if ( (*pi).BodySID == DescObject->EssenceStreamID )
-           {
-             TmpPair = *pi;
-             break;
-           }
-       }
-
-      if ( TmpPair.ByteOffset == 0 )
-       {
-         DefaultLogSink().Error("Body SID not found in RIP set: %d\n", DescObject->EssenceStreamID);
-         return RESULT_FORMAT;
-       }
+      assert(desc_object);
+      result = ReadGenericStreamPartitionPayload(desc_object->EssenceStreamID, frame_buf);
+    }
 
-      if ( KM_SUCCESS(result) )
-       {
-         FrameBuf.AssetID(uuid);
-         FrameBuf.MIMEType(DescObject->MIMEMediaType);
-
-         // seek tp the start of the partition
-         if ( (Kumu::fpos_t)TmpPair.ByteOffset != m_LastPosition )
-           {
-             m_LastPosition = TmpPair.ByteOffset;
-             result = m_File.Seek(TmpPair.ByteOffset);
-           }
-
-         // read the partition header
-         MXF::Partition GSPart(m_Dict);
-         result = GSPart.InitFromFile(m_File);
-
-         if( ASDCP_SUCCESS(result) )
-           {
-             // check the SID
-             if ( DescObject->EssenceStreamID != GSPart.BodySID )
-               {
-                 char buf[64];
-                 DefaultLogSink().Error("Generic stream partition body differs: %s\n", RID.EncodeHex(buf, 64));
-                 return RESULT_FORMAT;
-               }
-
-             // read the essence packet
-             assert(m_Dict);
-             if( ASDCP_SUCCESS(result) )
-               result = ReadEKLVPacket(0, sequence, FrameBuf, m_Dict->ul(MDD_GenericStream_DataElement), Ctx, HMAC);
-           }
-       }
+  if ( KM_SUCCESS(result) )
+    {
+      frame_buf.AssetID(uuid);
+      frame_buf.MIMEType(desc_object->MIMEMediaType);
     }
 
   return result;
index aad500eef3106890abca8b3b663e8af777a6d021..73b9e7a45fd89a8e93262d207a18c2d4031ad44c 100755 (executable)
@@ -161,9 +161,15 @@ namespace ASDCP
   Result_t PCM_ADesc_to_MD(PCM::AudioDescriptor& ADesc, ASDCP::MXF::WaveAudioDescriptor* ADescObj);
   Result_t MD_to_PCM_ADesc(ASDCP::MXF::WaveAudioDescriptor* ADescObj, PCM::AudioDescriptor& ADesc);
 
-  void     AddDMScrypt(Partition& HeaderPart, SourcePackage& Package,
+  void     AddDmsCrypt(Partition& HeaderPart, SourcePackage& Package,
                       WriterInfo& Descr, const UL& WrappingUL, const Dictionary*& Dict);
 
+  Result_t AddDmsTrackGenericPartUtf8Text(Kumu::FileWriter&, ASDCP::MXF::OP1aHeader&, SourcePackage&,
+                                         ASDCP::MXF::RIP&, const Dictionary*&);
+  //
+  Result_t WriteGenericStreamPartition(Kumu::FileWriter&, ASDCP::MXF::OP1aHeader&, ASDCP::MXF::RIP&, const Dictionary*&,
+                                      const ASDCP::FrameBuffer&, ASDCP::AESEncContext* = 0, ASDCP::HMACContext* = 0);
+  
   Result_t Read_EKLV_Packet(Kumu::FileReader& File, const ASDCP::Dictionary& Dict,
                            const ASDCP::WriterInfo& Info, Kumu::fpos_t& LastPosition, ASDCP::FrameBuffer& CtFrameBuf,
                            ui32_t FrameNum, ui32_t SequenceNum, ASDCP::FrameBuffer& FrameBuf,
@@ -238,7 +244,7 @@ namespace ASDCP
          if ( ASDCP_SUCCESS(result) )
            {
              result = m_RIP.InitFromFile(m_File);
-             ui32_t test_s = m_RIP.PairArray.size();
+             ui32_t test_s = (ui32_t)m_RIP.PairArray.size();
 
              if ( ASDCP_FAILURE(result) )
                {
@@ -390,6 +396,69 @@ namespace ASDCP
          return RESULT_OK;
        }
 
+       // Reads a Generic Stream Partition payload. Returns 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(const ui32_t sid, ASDCP::FrameBuffer& frame_buf)
+       {
+         Kumu::fpos_t start_offset = 0, end_offset = 0;
+         ui32_t sequence = 0;
+
+         // locate SID, record the offset
+         // Count the sequence length in because this is the sequence
+         // value needed to  complete the HMAC.
+         ASDCP::MXF::RIP::const_pair_iterator i;
+         for ( i = m_RIP.PairArray.begin(); i != m_RIP.PairArray.end(); ++i, ++sequence )
+           {
+             if ( sid == i->BodySID )
+               {
+                 start_offset = i->ByteOffset;
+               }
+             else if ( start_offset != 0 )
+               {
+                 end_offset = i->ByteOffset;
+                 break;
+               }
+           }
+
+         if ( start_offset == 0 || end_offset == 0 )
+           {
+             DefaultLogSink().Error("Body SID not found: %d.\n", sid);
+             return RESULT_NOT_FOUND;
+           }
+
+         // Read the Partition header and then read the payload.
+         Result_t result = m_File.Seek(start_offset);
+
+         if ( KM_SUCCESS(result) )
+           {
+             result = frame_buf.Capacity(end_offset-start_offset);
+           }
+    
+         if ( KM_SUCCESS(result) )
+           {
+             // read the partition header
+             ASDCP::MXF::Partition GSPart(m_Dict);
+             result = GSPart.InitFromFile(m_File);
+
+             if ( KM_SUCCESS(result) )
+               {
+                 // check the SID
+                 if ( GSPart.BodySID != sid )
+                   {
+                     DefaultLogSink().Error("Generic stream partition Body SID differs: %s\n", sid);
+                     result = RESULT_FORMAT;
+                   }
+                 else
+                   {
+                     result = ReadEKLVPacket(0, sequence, frame_buf, m_Dict->ul(MDD_GenericStream_DataElement), 0, 0);
+                   }
+               }
+           }
+  
+         return result;
+       }
+
        //
        void Close()
        {
@@ -620,7 +689,7 @@ namespace ASDCP
          // Material Package
          //
          m_MaterialPackage = new MaterialPackage(m_Dict);
-         m_MaterialPackage->Name = "AS-DCP Material Package";
+         m_MaterialPackage->Name = "Material Package";
          m_MaterialPackage->PackageUID = MaterialPackageUMID;
          m_HeaderPart.AddChildObject(m_MaterialPackage);
          m_ContentStorage->Packages.push_back(m_MaterialPackage->InstanceUID);
@@ -698,105 +767,6 @@ namespace ASDCP
          m_EssenceDescriptor->LinkedTrackID = FPTrack.Track->TrackID;
        }
 
-       //
-       void AddDMSegment(const MXF::Rational& clip_edit_rate,
-                         const MXF::Rational& tc_edit_rate, ui32_t tc_frame_rate,
-                         const std::string& TrackName, const UL& DataDefinition,
-                         const std::string& PackageLabel)
-       {
-         if ( m_ContentStorage == 0 )
-           {
-             m_ContentStorage = new ContentStorage(m_Dict);
-             m_HeaderPart.AddChildObject(m_ContentStorage);
-             m_HeaderPart.m_Preface->ContentStorage = m_ContentStorage->InstanceUID;
-           }
-
-         EssenceContainerData* ECD = new EssenceContainerData(m_Dict);
-         m_HeaderPart.AddChildObject(ECD);
-         m_ContentStorage->EssenceContainerData.push_back(ECD->InstanceUID);
-         ECD->IndexSID = 129;
-         ECD->BodySID = 1;
-
-         UUID assetUUID(m_Info.AssetUUID);
-         UMID SourcePackageUMID, MaterialPackageUMID;
-         SourcePackageUMID.MakeUMID(0x0f, assetUUID);
-         MaterialPackageUMID.MakeUMID(0x0f); // unidentified essence
-
-         //
-         // Material Package
-         //
-         m_MaterialPackage = new MaterialPackage(m_Dict);
-         m_MaterialPackage->Name = "AS-DCP Material Package";
-         m_MaterialPackage->PackageUID = MaterialPackageUMID;
-         m_HeaderPart.AddChildObject(m_MaterialPackage);
-         m_ContentStorage->Packages.push_back(m_MaterialPackage->InstanceUID);
-
-         TrackSet<TimecodeComponent> MPTCTrack =
-           CreateTimecodeTrack<MaterialPackage>(m_HeaderPart, *m_MaterialPackage,
-                                                tc_edit_rate, tc_frame_rate, 0, m_Dict);
-
-         MPTCTrack.Sequence->Duration.set_has_value();
-         m_DurationUpdateList.push_back(&(MPTCTrack.Sequence->Duration.get()));
-         MPTCTrack.Clip->Duration.set_has_value();
-         m_DurationUpdateList.push_back(&(MPTCTrack.Clip->Duration.get()));
-
-         TrackSet<DMSegment> MPTrack =
-           CreateTrackAndSequence<MaterialPackage, DMSegment>(m_HeaderPart, *m_MaterialPackage,
-                                                              TrackName, clip_edit_rate, DataDefinition,
-                                                              2, m_Dict);
-         MPTrack.Sequence->Duration.set_has_value();
-         m_DurationUpdateList.push_back(&(MPTrack.Sequence->Duration.get()));
-
-         MPTrack.Clip = new DMSegment(m_Dict);
-         m_HeaderPart.AddChildObject(MPTrack.Clip);
-         MPTrack.Sequence->StructuralComponents.push_back(MPTrack.Clip->InstanceUID);
-         MPTrack.Clip->DataDefinition = DataDefinition;
-         //  MPTrack.Clip->SourcePackageID = SourcePackageUMID;
-         //  MPTrack.Clip->SourceTrackID = 2;
-
-         m_DurationUpdateList.push_back(&(MPTrack.Clip->Duration));
-
-  
-         //
-         // File (Source) Package
-         //
-         m_FilePackage = new SourcePackage(m_Dict);
-         m_FilePackage->Name = PackageLabel.c_str();
-         m_FilePackage->PackageUID = SourcePackageUMID;
-         ECD->LinkedPackageUID = SourcePackageUMID;
-
-         m_HeaderPart.AddChildObject(m_FilePackage);
-         m_ContentStorage->Packages.push_back(m_FilePackage->InstanceUID);
-
-         TrackSet<TimecodeComponent> FPTCTrack =
-           CreateTimecodeTrack<SourcePackage>(m_HeaderPart, *m_FilePackage,
-                                              clip_edit_rate, tc_frame_rate,
-                                              ui64_C(3600) * tc_frame_rate, m_Dict);
-
-         FPTCTrack.Sequence->Duration.set_has_value();
-         m_DurationUpdateList.push_back(&(FPTCTrack.Sequence->Duration.get()));
-         FPTCTrack.Clip->Duration.set_has_value();
-         m_DurationUpdateList.push_back(&(FPTCTrack.Clip->Duration.get()));
-
-         TrackSet<DMSegment> FPTrack =
-           CreateTrackAndSequence<SourcePackage, DMSegment>(m_HeaderPart, *m_FilePackage,
-                                                            TrackName, clip_edit_rate, DataDefinition,
-                                                            2, m_Dict);
-
-         FPTrack.Sequence->Duration.set_has_value();
-         m_DurationUpdateList.push_back(&(FPTrack.Sequence->Duration.get()));
-
-         FPTrack.Clip = new DMSegment(m_Dict);
-         m_HeaderPart.AddChildObject(FPTrack.Clip);
-         FPTrack.Sequence->StructuralComponents.push_back(FPTrack.Clip->InstanceUID);
-         FPTrack.Clip->DataDefinition = DataDefinition;
-         FPTrack.Clip->EventComment = "ST 429-5 Timed Text";
-
-         m_DurationUpdateList.push_back(&(FPTrack.Clip->Duration));
-
-         m_EssenceDescriptor->LinkedTrackID = FPTrack.Track->TrackID;
-       }
-
        //
        void AddEssenceDescriptor(const UL& WrappingUL)
        {
@@ -818,7 +788,7 @@ namespace ASDCP
              UL CryptEssenceUL(m_Dict->ul(MDD_EncryptedContainerLabel));
              m_HeaderPart.EssenceContainers.push_back(CryptEssenceUL);
              m_HeaderPart.m_Preface->DMSchemes.push_back(UL(m_Dict->ul(MDD_CryptographicFrameworkLabel)));
-             AddDMScrypt(m_HeaderPart, *m_FilePackage, m_Info, WrappingUL, m_Dict);
+             AddDmsCrypt(m_HeaderPart, *m_FilePackage, m_Info, WrappingUL, m_Dict);
              //// TODO: fix DMSegment Duration value
            }
          else
@@ -836,6 +806,47 @@ namespace ASDCP
          m_FilePackage->Descriptor = m_EssenceDescriptor->InstanceUID;
        }
 
+       Result_t AddDmsGenericPartUtf8Text(const ASDCP::FrameBuffer& frame_buffer,
+                                          ASDCP::AESEncContext* enc = 0, ASDCP::HMACContext* hmac = 0)
+       {
+         Kumu::fpos_t previous_partition_offset = m_RIP.PairArray.back().ByteOffset;
+         Result_t result = AddDmsTrackGenericPartUtf8Text(m_File, m_HeaderPart, *m_FilePackage, m_RIP, m_Dict);
+
+         if ( KM_SUCCESS(result) )
+           {
+             // m_RIP now contains an entry (at the back) for the new generic stream
+             // (this entry was created during the call to AddDmsTrackGenericPartUtf8Text())
+             if ( m_File.Tell() != m_RIP.PairArray.back().ByteOffset )
+               {
+                 DefaultLogSink().Error("File offset has moved since RIP modification. Unrecoverable error.\n");
+                 return RESULT_FAIL;
+               }
+         
+             // create generic stream partition header
+             static UL GenericStream_DataElement(m_Dict->ul(MDD_GenericStream_DataElement));
+             ASDCP::MXF::Partition GSPart(m_Dict);
+
+             GSPart.MajorVersion = m_HeaderPart.MajorVersion;
+             GSPart.MinorVersion = m_HeaderPart.MinorVersion;
+             GSPart.ThisPartition = m_RIP.PairArray.back().ByteOffset;
+             GSPart.PreviousPartition = previous_partition_offset;
+             GSPart.OperationalPattern = m_HeaderPart.OperationalPattern;
+             GSPart.BodySID = m_RIP.PairArray.back().BodySID;
+             GSPart.EssenceContainers = m_HeaderPart.EssenceContainers;
+
+             static UL gs_part_ul(m_Dict->ul(MDD_GenericStreamPartition));
+             Result_t result = GSPart.WriteToFile(m_File, gs_part_ul);
+         
+             if ( KM_SUCCESS(result) )
+               {
+                 result = Write_EKLV_Packet(m_File, *m_Dict, m_HeaderPart, m_Info, m_CtFrameBuf, m_FramesWritten,
+                                            m_StreamOffset, frame_buffer, GenericStream_DataElement.Value(), enc, hmac);
+               }
+           }
+
+         return result;
+       }
+
        //
        void Close()
        {
index a50a05eb3c9efa92b8db249cf9d50061aa2410be..fbf76b021bee40ad81629ebea5d319b5794a192c 100755 (executable)
@@ -201,7 +201,7 @@ ASDCP::Dictionary::AddEntry(const MDDEntry& Entry, ui32_t index)
   std::map<ASDCP::UL, ui32_t>::iterator ii = m_md_lookup.find(TmpUL);
   if ( ii != m_md_lookup.end() )
     {
-      fprintf(stderr, "DUPE! %s (%02x, %02x) %s | (%02x, %02x) %s\n",
+      Kumu::DefaultLogSink().Warn("Duplicate Dictionary item: %s (%02x, %02x) %s | (%02x, %02x) %s\n",
              TmpUL.EncodeString(buf, 64),
              m_MDD_Table[ii->second].tag.a, m_MDD_Table[ii->second].tag.b,
              m_MDD_Table[ii->second].name,
index b9a5d63433263289a875815ae7313c7cc9d81a48..303a6725372d1e95b073800563b87132be30e9be 100755 (executable)
@@ -172,7 +172,7 @@ ASDCP::KLVPacket::Dump(FILE* stream, const Dictionary& Dict, bool show_value)
       fprintf(stream, "%s", TmpUL.EncodeString(buf, 64));
 
       const MDDEntry* Entry = Dict.FindULAnyVersion(m_KeyStart);
-      fprintf(stream, "  len: %7qu (%s)\n", m_ValueLength, (Entry ? Entry->name : "Unknown"));
+      fprintf(stream, "  len: %7llu (%s)\n", m_ValueLength, (Entry ? Entry->name : "Unknown"));
 
       if ( show_value && m_ValueLength < 1000 )
        Kumu::hexdump(m_ValueStart, Kumu::xmin(m_ValueLength, (ui64_t)128), stream);
index de7140173c6bf88eb08d5660391bb5ed114183cd..bae0f2b5e25074d59676dde062d1a0315160460d 100644 (file)
@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2006-2016, John Hurst
+Copyright (c) 2006-2018, John Hurst
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -766,7 +766,7 @@ static const ASDCP::MDDEntry s_MDD_Table[] = {
      {0}, true, "JPEG2000PictureSubDescriptor_QuantizationDefault" },
    { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 243
        0x0d, 0x01, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00 },
-     {0}, false, "DM_Framework" },
+     {0}, false, "DescriptiveFramework" },
    { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 244
        0x0d, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 },
      {0}, false, "DM_Set" },
@@ -923,7 +923,7 @@ static const ASDCP::MDDEntry s_MDD_Table[] = {
    { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x02, 0x01, 0x0d, // 295
        0x0d, 0x01, 0x03, 0x01, 0x17, 0x01, 0x0d, 0x00 },
      {0}, false, "DCDataEssence" },
-   { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x7f, 0x01, 0x01, // 296
+   { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 296
        0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x73, 0x00 },
      {0}, false, "DCDataDescriptor" },
    { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x05, // 297
@@ -1159,7 +1159,7 @@ static const ASDCP::MDDEntry s_MDD_Table[] = {
    // ContainerConstraintSubDescriptor to the GenericDescriptor::SubDescriptors
    // property of the top-most File Descriptor that describes the essence
    // container.
-   { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x7f, 0x01, 0x01, // 373
+   { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 373
        0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x67, 0x00 },
      {0}, false, "ContainerConstraintSubDescriptor" },
 
@@ -1528,7 +1528,66 @@ static const ASDCP::MDDEntry s_MDD_Table[] = {
    { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0d, // 491
        0x04, 0x10, 0x01, 0x01, 0x01, 0x03, 0x00, 0x00 },
      {0}, false, "HDRReferenceViewingEnvironment" },
-   
+   { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x02, 0x01, 0x05, // 492
+       0x0e, 0x09, 0x05, 0x02, 0x01, 0x00, 0x01, 0x00 },
+     {0}, false, "FrameWrappedISXDData" },
+   { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x05, // 493
+       0x0e, 0x09, 0x06, 0x07, 0x01, 0x01, 0x01, 0x03 },
+     {0}, false, "FrameWrappedISXDContainer" },
+   { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x05, // 494
+       0x0e, 0x09, 0x05, 0x02, 0x00, 0x00, 0x00, 0x00 },
+     {0}, false, "ISXDDataEssenceDescriptor" },
+   { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x05, // 495
+       0x0e, 0x09, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00 },
+     {0}, false, "ISXDDataEssenceDescriptor_NamespaceURI" },
+   { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x05, // 496
+       0x0e, 0x09, 0x06, 0x06, 0x00, 0x00, 0x00, 0xff },
+     {0}, false, "UTF_8_Text_DataEssenceCoding" },
+   { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 497-chk
+       0x0D, 0x01, 0x04, 0x01, 0x04, 0x01, 0x01, 0x00 },
+     {0}, false, "TextBasedDMFramework" },
+   { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0D, // 498-chk
+       0x06, 0x01, 0x01, 0x04, 0x05, 0x41, 0x01, 0x00 },
+     {0}, true, "TextBasedDMFramework_ObjectRef" },
+   { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 499
+       0x0d, 0x01, 0x04, 0x01, 0x04, 0x03, 0x01, 0x00 },
+     {0}, false, "TextBasedObject" },
+   { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0d, // 500
+       0x04, 0x06, 0x08, 0x06, 0x00, 0x00, 0x00, 0x00 },
+     {0}, false, "TextBasedObject_PayloadSchemeID" },
+   { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0d, // 501
+       0x04, 0x09, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00 },
+     {0}, false, "TextBasedObject_TextMIMEMediaType" },
+   { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0d, // 502
+       0x03, 0x01, 0x01, 0x02, 0x02, 0x14, 0x00, 0x00 },
+     {0}, false, "TextBasedObject_RFC5646TextLanguageCode" },
+   { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0d, // 503
+       0x03, 0x02, 0x01, 0x06, 0x03, 0x02, 0x00, 0x00 },
+     {0}, true, "TextBasedObject_TextDataDescription" },
+   { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 504
+       0x0d, 0x01, 0x04, 0x01, 0x04, 0x02, 0x01, 0x00 },
+     {0}, false, "GenericStreamTextBasedSet" },
+   { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0d, // 505
+       0x01, 0x03, 0x04, 0x08, 0x00, 0x00, 0x00, 0x00 },
+     {0}, false, "GenericStreamTextBasedSet_GenericStreamSID" },
+   { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x06, 0x01, 0x01, // 506
+       0x0d, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 },
+     {0}, false, "DescriptiveObject" },
+   { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0c, // 507
+       0x05, 0x20, 0x07, 0x01, 0x0c, 0x00, 0x00, 0x00 },
+     {0}, false, "DescriptiveFramework_LinkedDescriptiveFrameworkPlugInId" },
+   { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0c, // 508
+       0x05, 0x20, 0x07, 0x01, 0x11, 0x00, 0x00, 0x00 },
+     {0}, false, "DescriptiveObject_LinkedDescriptiveObjectPlugInId" },
+   { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0c, // 509
+       0x01, 0x02, 0x02, 0x10, 0x02, 0x03, 0x00, 0x00 },
+     {0}, false, "Preface_ApplicationSchemes" },
+   { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0e, // 510
+       0x01, 0x02, 0x02, 0x10, 0x02, 0x04, 0x00, 0x00 },
+     {0}, false, "Preface_ConformsToSpecifications" },
+   { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0c, // 511
+       0x0d, 0x01, 0x04, 0x01, 0x04, 0x01, 0x01, 0x00 },
+     {0}, false, "MXFTextBasedFramework" },
    { {0}, {0}, false, 0 }
  };
 
index 667cf50a6eb425c158b61a90851aa8f64a576268..779433693fff47a29321ae7e4f9a2adf7eb26033 100755 (executable)
--- a/src/MDD.h
+++ b/src/MDD.h
@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2006-2016, John Hurst
+Copyright (c) 2006-2018, John Hurst
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -278,7 +278,7 @@ namespace ASDCP {
         MDD_JPEG2000PictureSubDescriptor_PictureComponentSizing,  // 240
         MDD_JPEG2000PictureSubDescriptor_CodingStyleDefault,  // 241
         MDD_JPEG2000PictureSubDescriptor_QuantizationDefault,  // 242
-        MDD_DM_Framework,  // 243
+        MDD_DescriptiveFramework,  // 243
         MDD_DM_Set,  // 244
         MDD_EncryptedContainerLabel,  // 245
         MDD_CryptographicFrameworkLabel,  // 246
@@ -527,7 +527,26 @@ namespace ASDCP {
        MDD_TheatricalViewingEnvironment, // 489
        MDD_HDTVReferenceViewingEnvironment, // 490
        MDD_HDRReferenceViewingEnvironment, // 491
-
+       MDD_FrameWrappedISXDData, // 492
+       MDD_FrameWrappedISXDContainer, // 493
+       MDD_ISXDDataEssenceDescriptor, // 494
+       MDD_ISXDDataEssenceDescriptor_NamespaceURI, // 495
+       MDD_UTF_8_Text_DataEssenceCoding, // 496
+       MDD_TextBasedDMFramework, // 497
+       MDD_TextBasedDMFramework_ObjectRef, // 498
+       MDD_TextBasedObject, // 499
+       MDD_TextBasedObject_PayloadSchemeID, // 500
+       MDD_TextBasedObject_TextMIMEMediaType, // 501
+       MDD_TextBasedObject_RFC5646TextLanguageCode, // 502
+       MDD_TextBasedObject_TextDataDescription, // 503
+       MDD_GenericStreamTextBasedSet, // 504
+       MDD_GenericStreamTextBasedSet_GenericStreamSID, // 505
+       MDD_DescriptiveObject,   // 506
+       MDD_DescriptiveFramework_LinkedDescriptiveFrameworkPlugInId, // 507
+       MDD_DescriptiveObject_LinkedDescriptiveObjectPlugInId, // 508
+       MDD_Preface_ApplicationSchemes,  // 509
+       MDD_Preface_ConformsToSpecifications, // 510
+       MDD_MXFTextBasedFramework,  // 511
         MDD_Max
     }; // enum MDD_t
 
index df53b2183e7faa45ff4590ac7aaf9ee006a9680a..1c2ae5cbcd58a019dc2177e77a2acc8dec904200 100755 (executable)
@@ -608,6 +608,8 @@ ASDCP::MXF::Preface::Copy(const Preface& rhs)
   OperationalPattern = rhs.OperationalPattern;
   EssenceContainers = rhs.EssenceContainers;
   DMSchemes = rhs.DMSchemes;
+  ApplicationSchemes = rhs.ApplicationSchemes;
+  ConformsToSpecifications = rhs.ConformsToSpecifications;
 }
 
 //
@@ -624,6 +626,16 @@ ASDCP::MXF::Preface::InitFromTLVSet(TLVReader& TLVSet)
   if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Preface, OperationalPattern));
   if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Preface, EssenceContainers));
   if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Preface, DMSchemes));
+  if ( ASDCP_SUCCESS(result) ) 
+    {
+      result = TLVSet.ReadObject(OBJ_READ_ARGS_OPT(Preface, ApplicationSchemes));
+      ApplicationSchemes.set_has_value( result == RESULT_OK);
+    }
+  if ( ASDCP_SUCCESS(result) )
+    {
+      result = TLVSet.ReadObject(OBJ_READ_ARGS_OPT(Preface, ConformsToSpecifications));
+      ConformsToSpecifications.set_has_value( result == RESULT_OK);
+    }
   return result;
 }
 
@@ -641,6 +653,14 @@ ASDCP::MXF::Preface::WriteToTLVSet(TLVWriter& TLVSet)
   if ( ASDCP_SUCCESS(result) )  result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Preface, OperationalPattern));
   if ( ASDCP_SUCCESS(result) )  result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Preface, EssenceContainers));
   if ( ASDCP_SUCCESS(result) )  result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Preface, DMSchemes));
+  if ( ASDCP_SUCCESS(result) && !ApplicationSchemes.empty() )
+    {
+      result = TLVSet.WriteObject(OBJ_WRITE_ARGS_OPT(Preface, ApplicationSchemes));
+    }
+  if ( ASDCP_SUCCESS(result) && !ConformsToSpecifications.empty())
+    {
+      result = TLVSet.WriteObject(OBJ_WRITE_ARGS_OPT(Preface, ConformsToSpecifications));
+    }
   return result;
 }
 
@@ -682,6 +702,14 @@ ASDCP::MXF::Preface::Dump(FILE* stream)
   fprintf(stream, "  %22s = %s\n",  "OperationalPattern", OperationalPattern.EncodeString(identbuf, IdentBufferLen));
   fprintf(stream, "  %22s:\n", "EssenceContainers");  EssenceContainers.Dump(stream);
   fprintf(stream, "  %22s:\n", "DMSchemes");  DMSchemes.Dump(stream);
+  if ( ! ApplicationSchemes.empty() )
+    {
+      fprintf(stream, "  %22s:\n", "ApplicationSchemes");  ApplicationSchemes.get().Dump(stream);
+    }
+  if ( ! ConformsToSpecifications.empty() )
+    {
+      fprintf(stream, "  %22s:\n", "ConformsToSpecifications");  ConformsToSpecifications.get().Dump(stream);
+    }
 }
 
 //------------------------------------------------------------------------------------------
index 19ff4462bcc2f5ef727bf3aac970f139f7248ade..b8d11939a4e0674a03b70474fa61b35f3801efed 100755 (executable)
--- a/src/MXF.h
+++ b/src/MXF.h
@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2005-2015, John Hurst
+Copyright (c) 2005-2018, John Hurst
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -200,7 +200,7 @@ namespace ASDCP
 
              inline const char* EncodeString(char* str_buf, ui32_t buf_len) const {
                snprintf(str_buf, buf_len, "%02x %02x: ", Tag.a, Tag.b);
-               UL.EncodeString(str_buf + strlen(str_buf), buf_len - strlen(str_buf));
+               UL.EncodeString(str_buf + strlen(str_buf), buf_len - (ui32_t)strlen(str_buf));
                return str_buf;
              }
 
@@ -332,6 +332,7 @@ namespace ASDCP
          Batch<UL>    EssenceContainers;
          Batch<UL>    DMSchemes;
          optional_property<Batch<UL> > ApplicationSchemes;
+         optional_property<Batch<UL> > ConformsToSpecifications;
 
          Preface(const Dictionary*& d);
          virtual ~Preface() {}
index cf3d57c891fdf947d7d4ff3aef0aed9a9e3909ed..c49fed9b6f07b267e1f5de0621865dc7c65a4db2 100755 (executable)
@@ -112,12 +112,12 @@ namespace ASDCP
          bool HasValue() const { return ! this->empty(); }
 
          ui32_t ArchiveLength() const {
-           return ( sizeof(ui32_t) * 2 ) +  ( this->size() * this->ItemSize() );
+           return ( sizeof(ui32_t) * 2 ) +  ( (ui32_t)this->size() * this->ItemSize() );
          }
 
          bool Archive(Kumu::MemIOWriter* Writer) const {
-           if ( ! Writer->WriteUi32BE(this->size()) ) return false;
-           if ( ! Writer->WriteUi32BE(this->ItemSize()) ) return false;
+           if ( ! Writer->WriteUi32BE((ui32_t)this->size()) ) return false;
+           if ( ! Writer->WriteUi32BE((ui32_t)this->ItemSize()) ) return false;
            if ( this->empty() ) return true;
            
            typename ContainerType::const_iterator i;
@@ -277,7 +277,7 @@ namespace ASDCP
 
          const char* EncodeString(char* str_buf, ui32_t buf_len) const;
          inline virtual bool HasValue() const { return ! empty(); }
-         inline virtual ui32_t ArchiveLength() const { return sizeof(ui32_t) + size(); }
+         inline virtual ui32_t ArchiveLength() const { return (ui32_t)(sizeof(ui32_t) + size()); }
          virtual bool Unarchive(Kumu::MemIOReader* Reader);
          virtual bool Archive(Kumu::MemIOWriter* Writer) const;
        };
@@ -296,7 +296,7 @@ namespace ASDCP
 
          const char* EncodeString(char* str_buf, ui32_t buf_len) const;
          inline virtual bool HasValue() const { return ! empty(); }
-         inline virtual ui32_t ArchiveLength() const { return sizeof(ui32_t) + size(); }
+         inline virtual ui32_t ArchiveLength() const { return (ui32_t)(sizeof(ui32_t) + size()); }
          virtual bool Unarchive(Kumu::MemIOReader* Reader);
          virtual bool Archive(Kumu::MemIOWriter* Writer) const;
        };
@@ -359,7 +359,7 @@ namespace ASDCP
          ui32_t First;
          ui32_t Second;
 
-         LineMapPair() {}
+       LineMapPair() : First(0), Second() {}
          ~LineMapPair() {}
 
        LineMapPair(const ui32_t& first, const ui32_t& second) : IArchive() {
index c7d182bf770100183157ccfee0ee0b6dd6f9c58f..ccf6bee7f9b6387d6329e712d3058251d618d5a0 100644 (file)
@@ -2,7 +2,7 @@
 #
 # $Id$
 #
-# Copyright (c) 2007-2016 John Hurst. All rights reserved.
+# Copyright (c) 2007-2018 John Hurst. All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
 # modification, are permitted provided that the following conditions
@@ -144,6 +144,7 @@ libas02_la_SOURCES  = \
        h__02_Writer.cpp \
        AS_02_JP2K.cpp \
        AS_02_PCM.cpp \
+       AS_02_ISXD.cpp \
        ST2052_TextParser.cpp \
        AS_02_TimedText.cpp
 
index 4a0db5ae44f13abdba1efbb4eebd0d61b29173b3..a7fdd2e4ca3dcd50d6162cea9a016e7eee5ab552 100755 (executable)
@@ -64,6 +64,8 @@ static InterchangeObject* MPEG2VideoDescriptor_Factory(const Dictionary*& Dict)
 static InterchangeObject* DMSegment_Factory(const Dictionary*& Dict) { return new DMSegment(Dict); }
 static InterchangeObject* CryptographicFramework_Factory(const Dictionary*& Dict) { return new CryptographicFramework(Dict); }
 static InterchangeObject* CryptographicContext_Factory(const Dictionary*& Dict) { return new CryptographicContext(Dict); }
+static InterchangeObject* DescriptiveFramework_Factory(const Dictionary*& Dict) { return new DescriptiveFramework(Dict); }
+static InterchangeObject* DescriptiveObject_Factory(const Dictionary*& Dict) { return new DescriptiveObject(Dict); }
 static InterchangeObject* GenericDataEssenceDescriptor_Factory(const Dictionary*& Dict) { return new GenericDataEssenceDescriptor(Dict); }
 static InterchangeObject* TimedTextDescriptor_Factory(const Dictionary*& Dict) { return new TimedTextDescriptor(Dict); }
 static InterchangeObject* TimedTextResourceSubDescriptor_Factory(const Dictionary*& Dict) { return new TimedTextResourceSubDescriptor(Dict); }
@@ -79,6 +81,10 @@ static InterchangeObject* PrivateDCDataDescriptor_Factory(const Dictionary*& Dic
 static InterchangeObject* DolbyAtmosSubDescriptor_Factory(const Dictionary*& Dict) { return new DolbyAtmosSubDescriptor(Dict); }
 static InterchangeObject* ACESPictureSubDescriptor_Factory(const Dictionary*& Dict) { return new ACESPictureSubDescriptor(Dict); }
 static InterchangeObject* TargetFrameSubDescriptor_Factory(const Dictionary*& Dict) { return new TargetFrameSubDescriptor(Dict); }
+static InterchangeObject* TextBasedDMFramework_Factory(const Dictionary*& Dict) { return new TextBasedDMFramework(Dict); }
+static InterchangeObject* TextBasedObject_Factory(const Dictionary*& Dict) { return new TextBasedObject(Dict); }
+static InterchangeObject* GenericStreamTextBasedSet_Factory(const Dictionary*& Dict) { return new GenericStreamTextBasedSet(Dict); }
+static InterchangeObject* ISXDDataEssenceDescriptor_Factory(const Dictionary*& Dict) { return new ISXDDataEssenceDescriptor(Dict); }
 static InterchangeObject* PHDRMetadataTrackSubDescriptor_Factory(const Dictionary*& Dict) { return new PHDRMetadataTrackSubDescriptor(Dict); }
 static InterchangeObject* PIMFDynamicMetadataDescriptor_Factory(const Dictionary*& Dict) { return new PIMFDynamicMetadataDescriptor(Dict); }
 
@@ -111,6 +117,8 @@ ASDCP::MXF::Metadata_InitTypes(const Dictionary*& Dict)
   SetObjectFactory(Dict->ul(MDD_DMSegment), DMSegment_Factory);
   SetObjectFactory(Dict->ul(MDD_CryptographicFramework), CryptographicFramework_Factory);
   SetObjectFactory(Dict->ul(MDD_CryptographicContext), CryptographicContext_Factory);
+  SetObjectFactory(Dict->ul(MDD_DescriptiveFramework), DescriptiveFramework_Factory);
+  SetObjectFactory(Dict->ul(MDD_DescriptiveObject), DescriptiveObject_Factory);
   SetObjectFactory(Dict->ul(MDD_GenericDataEssenceDescriptor), GenericDataEssenceDescriptor_Factory);
   SetObjectFactory(Dict->ul(MDD_TimedTextDescriptor), TimedTextDescriptor_Factory);
   SetObjectFactory(Dict->ul(MDD_TimedTextResourceSubDescriptor), TimedTextResourceSubDescriptor_Factory);
@@ -126,6 +134,10 @@ ASDCP::MXF::Metadata_InitTypes(const Dictionary*& Dict)
   SetObjectFactory(Dict->ul(MDD_DolbyAtmosSubDescriptor), DolbyAtmosSubDescriptor_Factory);
   SetObjectFactory(Dict->ul(MDD_ACESPictureSubDescriptor), ACESPictureSubDescriptor_Factory);
   SetObjectFactory(Dict->ul(MDD_TargetFrameSubDescriptor), TargetFrameSubDescriptor_Factory);
+  SetObjectFactory(Dict->ul(MDD_TextBasedDMFramework), TextBasedDMFramework_Factory);
+  SetObjectFactory(Dict->ul(MDD_TextBasedObject), TextBasedObject_Factory);
+  SetObjectFactory(Dict->ul(MDD_GenericStreamTextBasedSet), GenericStreamTextBasedSet_Factory);
+  SetObjectFactory(Dict->ul(MDD_ISXDDataEssenceDescriptor), ISXDDataEssenceDescriptor_Factory);
   SetObjectFactory(Dict->ul(MDD_PHDRMetadataTrackSubDescriptor), PHDRMetadataTrackSubDescriptor_Factory);
   SetObjectFactory(Dict->ul(MDD_PIMFDynamicMetadataDescriptor), PIMFDynamicMetadataDescriptor_Factory);
 }
@@ -2778,6 +2790,166 @@ CryptographicContext::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
   return InterchangeObject::WriteToBuffer(Buffer);
 }
 
+//------------------------------------------------------------------------------------------
+// DescriptiveFramework
+
+//
+
+DescriptiveFramework::DescriptiveFramework(const Dictionary*& d) : InterchangeObject(d), m_Dict(d)
+{
+  assert(m_Dict);
+  m_UL = m_Dict->ul(MDD_DescriptiveFramework);
+}
+
+DescriptiveFramework::DescriptiveFramework(const DescriptiveFramework& rhs) : InterchangeObject(rhs.m_Dict), m_Dict(rhs.m_Dict)
+{
+  assert(m_Dict);
+  m_UL = m_Dict->ul(MDD_DescriptiveFramework);
+  Copy(rhs);
+}
+
+
+//
+ASDCP::Result_t
+DescriptiveFramework::InitFromTLVSet(TLVReader& TLVSet)
+{
+  assert(m_Dict);
+  Result_t result = InterchangeObject::InitFromTLVSet(TLVSet);
+  if ( ASDCP_SUCCESS(result) ) {
+    result = TLVSet.ReadObject(OBJ_READ_ARGS_OPT(DescriptiveFramework, LinkedDescriptiveFrameworkPlugInId));
+    LinkedDescriptiveFrameworkPlugInId.set_has_value( result == RESULT_OK );
+  }
+  return result;
+}
+
+//
+ASDCP::Result_t
+DescriptiveFramework::WriteToTLVSet(TLVWriter& TLVSet)
+{
+  assert(m_Dict);
+  Result_t result = InterchangeObject::WriteToTLVSet(TLVSet);
+  if ( ASDCP_SUCCESS(result)  && ! LinkedDescriptiveFrameworkPlugInId.empty() ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS_OPT(DescriptiveFramework, LinkedDescriptiveFrameworkPlugInId));
+  return result;
+}
+
+//
+void
+DescriptiveFramework::Copy(const DescriptiveFramework& rhs)
+{
+  InterchangeObject::Copy(rhs);
+  LinkedDescriptiveFrameworkPlugInId = rhs.LinkedDescriptiveFrameworkPlugInId;
+}
+
+//
+void
+DescriptiveFramework::Dump(FILE* stream)
+{
+  char identbuf[IdentBufferLen];
+  *identbuf = 0;
+
+  if ( stream == 0 )
+    stream = stderr;
+
+  InterchangeObject::Dump(stream);
+  if ( ! LinkedDescriptiveFrameworkPlugInId.empty() ) {
+    fprintf(stream, "  %22s = %s\n",  "LinkedDescriptiveFrameworkPlugInId", LinkedDescriptiveFrameworkPlugInId.get().EncodeString(identbuf, IdentBufferLen));
+  }
+}
+
+//
+ASDCP::Result_t
+DescriptiveFramework::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+  return InterchangeObject::InitFromBuffer(p, l);
+}
+
+//
+ASDCP::Result_t
+DescriptiveFramework::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+  return InterchangeObject::WriteToBuffer(Buffer);
+}
+
+//------------------------------------------------------------------------------------------
+// DescriptiveObject
+
+//
+
+DescriptiveObject::DescriptiveObject(const Dictionary*& d) : InterchangeObject(d), m_Dict(d)
+{
+  assert(m_Dict);
+  m_UL = m_Dict->ul(MDD_DescriptiveObject);
+}
+
+DescriptiveObject::DescriptiveObject(const DescriptiveObject& rhs) : InterchangeObject(rhs.m_Dict), m_Dict(rhs.m_Dict)
+{
+  assert(m_Dict);
+  m_UL = m_Dict->ul(MDD_DescriptiveObject);
+  Copy(rhs);
+}
+
+
+//
+ASDCP::Result_t
+DescriptiveObject::InitFromTLVSet(TLVReader& TLVSet)
+{
+  assert(m_Dict);
+  Result_t result = InterchangeObject::InitFromTLVSet(TLVSet);
+  if ( ASDCP_SUCCESS(result) ) {
+    result = TLVSet.ReadObject(OBJ_READ_ARGS_OPT(DescriptiveObject, LinkedDescriptiveObjectPlugInId));
+    LinkedDescriptiveObjectPlugInId.set_has_value( result == RESULT_OK );
+  }
+  return result;
+}
+
+//
+ASDCP::Result_t
+DescriptiveObject::WriteToTLVSet(TLVWriter& TLVSet)
+{
+  assert(m_Dict);
+  Result_t result = InterchangeObject::WriteToTLVSet(TLVSet);
+  if ( ASDCP_SUCCESS(result)  && ! LinkedDescriptiveObjectPlugInId.empty() ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS_OPT(DescriptiveObject, LinkedDescriptiveObjectPlugInId));
+  return result;
+}
+
+//
+void
+DescriptiveObject::Copy(const DescriptiveObject& rhs)
+{
+  InterchangeObject::Copy(rhs);
+  LinkedDescriptiveObjectPlugInId = rhs.LinkedDescriptiveObjectPlugInId;
+}
+
+//
+void
+DescriptiveObject::Dump(FILE* stream)
+{
+  char identbuf[IdentBufferLen];
+  *identbuf = 0;
+
+  if ( stream == 0 )
+    stream = stderr;
+
+  InterchangeObject::Dump(stream);
+  if ( ! LinkedDescriptiveObjectPlugInId.empty() ) {
+    fprintf(stream, "  %22s = %s\n",  "LinkedDescriptiveObjectPlugInId", LinkedDescriptiveObjectPlugInId.get().EncodeString(identbuf, IdentBufferLen));
+  }
+}
+
+//
+ASDCP::Result_t
+DescriptiveObject::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+  return InterchangeObject::InitFromBuffer(p, l);
+}
+
+//
+ASDCP::Result_t
+DescriptiveObject::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+  return InterchangeObject::WriteToBuffer(Buffer);
+}
+
 //------------------------------------------------------------------------------------------
 // GenericDataEssenceDescriptor
 
@@ -4128,6 +4300,328 @@ TargetFrameSubDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
   return InterchangeObject::WriteToBuffer(Buffer);
 }
 
+//------------------------------------------------------------------------------------------
+// TextBasedDMFramework
+
+//
+
+TextBasedDMFramework::TextBasedDMFramework(const Dictionary*& d) : DescriptiveFramework(d), m_Dict(d)
+{
+  assert(m_Dict);
+  m_UL = m_Dict->ul(MDD_TextBasedDMFramework);
+}
+
+TextBasedDMFramework::TextBasedDMFramework(const TextBasedDMFramework& rhs) : DescriptiveFramework(rhs.m_Dict), m_Dict(rhs.m_Dict)
+{
+  assert(m_Dict);
+  m_UL = m_Dict->ul(MDD_TextBasedDMFramework);
+  Copy(rhs);
+}
+
+
+//
+ASDCP::Result_t
+TextBasedDMFramework::InitFromTLVSet(TLVReader& TLVSet)
+{
+  assert(m_Dict);
+  Result_t result = DescriptiveFramework::InitFromTLVSet(TLVSet);
+  if ( ASDCP_SUCCESS(result) ) {
+    result = TLVSet.ReadObject(OBJ_READ_ARGS_OPT(TextBasedDMFramework, ObjectRef));
+    ObjectRef.set_has_value( result == RESULT_OK );
+  }
+  return result;
+}
+
+//
+ASDCP::Result_t
+TextBasedDMFramework::WriteToTLVSet(TLVWriter& TLVSet)
+{
+  assert(m_Dict);
+  Result_t result = DescriptiveFramework::WriteToTLVSet(TLVSet);
+  if ( ASDCP_SUCCESS(result)  && ! ObjectRef.empty() ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS_OPT(TextBasedDMFramework, ObjectRef));
+  return result;
+}
+
+//
+void
+TextBasedDMFramework::Copy(const TextBasedDMFramework& rhs)
+{
+  DescriptiveFramework::Copy(rhs);
+  ObjectRef = rhs.ObjectRef;
+}
+
+//
+void
+TextBasedDMFramework::Dump(FILE* stream)
+{
+  char identbuf[IdentBufferLen];
+  *identbuf = 0;
+
+  if ( stream == 0 )
+    stream = stderr;
+
+  DescriptiveFramework::Dump(stream);
+  if ( ! ObjectRef.empty() ) {
+    fprintf(stream, "  %22s = %s\n",  "ObjectRef", ObjectRef.get().EncodeString(identbuf, IdentBufferLen));
+  }
+}
+
+//
+ASDCP::Result_t
+TextBasedDMFramework::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+  return InterchangeObject::InitFromBuffer(p, l);
+}
+
+//
+ASDCP::Result_t
+TextBasedDMFramework::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+  return InterchangeObject::WriteToBuffer(Buffer);
+}
+
+//------------------------------------------------------------------------------------------
+// TextBasedObject
+
+//
+
+TextBasedObject::TextBasedObject(const Dictionary*& d) : DescriptiveObject(d), m_Dict(d)
+{
+  assert(m_Dict);
+  m_UL = m_Dict->ul(MDD_TextBasedObject);
+}
+
+TextBasedObject::TextBasedObject(const TextBasedObject& rhs) : DescriptiveObject(rhs.m_Dict), m_Dict(rhs.m_Dict)
+{
+  assert(m_Dict);
+  m_UL = m_Dict->ul(MDD_TextBasedObject);
+  Copy(rhs);
+}
+
+
+//
+ASDCP::Result_t
+TextBasedObject::InitFromTLVSet(TLVReader& TLVSet)
+{
+  assert(m_Dict);
+  Result_t result = DescriptiveObject::InitFromTLVSet(TLVSet);
+  if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(TextBasedObject, PayloadSchemeID));
+  if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(TextBasedObject, TextMIMEMediaType));
+  if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(TextBasedObject, RFC5646TextLanguageCode));
+  if ( ASDCP_SUCCESS(result) ) {
+    result = TLVSet.ReadObject(OBJ_READ_ARGS_OPT(TextBasedObject, TextDataDescription));
+    TextDataDescription.set_has_value( result == RESULT_OK );
+  }
+  return result;
+}
+
+//
+ASDCP::Result_t
+TextBasedObject::WriteToTLVSet(TLVWriter& TLVSet)
+{
+  assert(m_Dict);
+  Result_t result = DescriptiveObject::WriteToTLVSet(TLVSet);
+  if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(TextBasedObject, PayloadSchemeID));
+  if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(TextBasedObject, TextMIMEMediaType));
+  if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(TextBasedObject, RFC5646TextLanguageCode));
+  if ( ASDCP_SUCCESS(result)  && ! TextDataDescription.empty() ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS_OPT(TextBasedObject, TextDataDescription));
+  return result;
+}
+
+//
+void
+TextBasedObject::Copy(const TextBasedObject& rhs)
+{
+  DescriptiveObject::Copy(rhs);
+  PayloadSchemeID = rhs.PayloadSchemeID;
+  TextMIMEMediaType = rhs.TextMIMEMediaType;
+  RFC5646TextLanguageCode = rhs.RFC5646TextLanguageCode;
+  TextDataDescription = rhs.TextDataDescription;
+}
+
+//
+void
+TextBasedObject::Dump(FILE* stream)
+{
+  char identbuf[IdentBufferLen];
+  *identbuf = 0;
+
+  if ( stream == 0 )
+    stream = stderr;
+
+  DescriptiveObject::Dump(stream);
+  fprintf(stream, "  %22s = %s\n",  "PayloadSchemeID", PayloadSchemeID.EncodeString(identbuf, IdentBufferLen));
+  fprintf(stream, "  %22s = %s\n",  "TextMIMEMediaType", TextMIMEMediaType.EncodeString(identbuf, IdentBufferLen));
+  fprintf(stream, "  %22s = %s\n",  "RFC5646TextLanguageCode", RFC5646TextLanguageCode.EncodeString(identbuf, IdentBufferLen));
+  if ( ! TextDataDescription.empty() ) {
+    fprintf(stream, "  %22s = %s\n",  "TextDataDescription", TextDataDescription.get().EncodeString(identbuf, IdentBufferLen));
+  }
+}
+
+//
+ASDCP::Result_t
+TextBasedObject::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+  return InterchangeObject::InitFromBuffer(p, l);
+}
+
+//
+ASDCP::Result_t
+TextBasedObject::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+  return InterchangeObject::WriteToBuffer(Buffer);
+}
+
+//------------------------------------------------------------------------------------------
+// GenericStreamTextBasedSet
+
+//
+
+GenericStreamTextBasedSet::GenericStreamTextBasedSet(const Dictionary*& d) : TextBasedObject(d), m_Dict(d), GenericStreamSID(0)
+{
+  assert(m_Dict);
+  m_UL = m_Dict->ul(MDD_GenericStreamTextBasedSet);
+}
+
+GenericStreamTextBasedSet::GenericStreamTextBasedSet(const GenericStreamTextBasedSet& rhs) : TextBasedObject(rhs.m_Dict), m_Dict(rhs.m_Dict)
+{
+  assert(m_Dict);
+  m_UL = m_Dict->ul(MDD_GenericStreamTextBasedSet);
+  Copy(rhs);
+}
+
+
+//
+ASDCP::Result_t
+GenericStreamTextBasedSet::InitFromTLVSet(TLVReader& TLVSet)
+{
+  assert(m_Dict);
+  Result_t result = TextBasedObject::InitFromTLVSet(TLVSet);
+  if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(GenericStreamTextBasedSet, GenericStreamSID));
+  return result;
+}
+
+//
+ASDCP::Result_t
+GenericStreamTextBasedSet::WriteToTLVSet(TLVWriter& TLVSet)
+{
+  assert(m_Dict);
+  Result_t result = TextBasedObject::WriteToTLVSet(TLVSet);
+  if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(GenericStreamTextBasedSet, GenericStreamSID));
+  return result;
+}
+
+//
+void
+GenericStreamTextBasedSet::Copy(const GenericStreamTextBasedSet& rhs)
+{
+  TextBasedObject::Copy(rhs);
+  GenericStreamSID = rhs.GenericStreamSID;
+}
+
+//
+void
+GenericStreamTextBasedSet::Dump(FILE* stream)
+{
+  char identbuf[IdentBufferLen];
+  *identbuf = 0;
+
+  if ( stream == 0 )
+    stream = stderr;
+
+  TextBasedObject::Dump(stream);
+  fprintf(stream, "  %22s = %d\n",  "GenericStreamSID", GenericStreamSID);
+}
+
+//
+ASDCP::Result_t
+GenericStreamTextBasedSet::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+  return InterchangeObject::InitFromBuffer(p, l);
+}
+
+//
+ASDCP::Result_t
+GenericStreamTextBasedSet::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+  return InterchangeObject::WriteToBuffer(Buffer);
+}
+
+//------------------------------------------------------------------------------------------
+// ISXDDataEssenceDescriptor
+
+//
+
+ISXDDataEssenceDescriptor::ISXDDataEssenceDescriptor(const Dictionary*& d) : GenericDataEssenceDescriptor(d), m_Dict(d)
+{
+  assert(m_Dict);
+  m_UL = m_Dict->ul(MDD_ISXDDataEssenceDescriptor);
+}
+
+ISXDDataEssenceDescriptor::ISXDDataEssenceDescriptor(const ISXDDataEssenceDescriptor& rhs) : GenericDataEssenceDescriptor(rhs.m_Dict), m_Dict(rhs.m_Dict)
+{
+  assert(m_Dict);
+  m_UL = m_Dict->ul(MDD_ISXDDataEssenceDescriptor);
+  Copy(rhs);
+}
+
+
+//
+ASDCP::Result_t
+ISXDDataEssenceDescriptor::InitFromTLVSet(TLVReader& TLVSet)
+{
+  assert(m_Dict);
+  Result_t result = GenericDataEssenceDescriptor::InitFromTLVSet(TLVSet);
+  if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(ISXDDataEssenceDescriptor, NamespaceURI));
+  return result;
+}
+
+//
+ASDCP::Result_t
+ISXDDataEssenceDescriptor::WriteToTLVSet(TLVWriter& TLVSet)
+{
+  assert(m_Dict);
+  Result_t result = GenericDataEssenceDescriptor::WriteToTLVSet(TLVSet);
+  if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(ISXDDataEssenceDescriptor, NamespaceURI));
+  return result;
+}
+
+//
+void
+ISXDDataEssenceDescriptor::Copy(const ISXDDataEssenceDescriptor& rhs)
+{
+  GenericDataEssenceDescriptor::Copy(rhs);
+  NamespaceURI = rhs.NamespaceURI;
+}
+
+//
+void
+ISXDDataEssenceDescriptor::Dump(FILE* stream)
+{
+  char identbuf[IdentBufferLen];
+  *identbuf = 0;
+
+  if ( stream == 0 )
+    stream = stderr;
+
+  GenericDataEssenceDescriptor::Dump(stream);
+  fprintf(stream, "  %22s = %s\n",  "NamespaceURI", NamespaceURI.EncodeString(identbuf, IdentBufferLen));
+}
+
+//
+ASDCP::Result_t
+ISXDDataEssenceDescriptor::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+  return InterchangeObject::InitFromBuffer(p, l);
+}
+
+//
+ASDCP::Result_t
+ISXDDataEssenceDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+  return InterchangeObject::WriteToBuffer(Buffer);
+}
+
 //------------------------------------------------------------------------------------------
 // PHDRMetadataTrackSubDescriptor
 
index b6cfb62f3729457ea504ff40d7540744af561c5c..cc26c70967d8648b3afb0afd36d28521f12db0b3 100755 (executable)
@@ -727,6 +727,52 @@ namespace ASDCP
       virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
        };
 
+      //
+      class DescriptiveFramework : public InterchangeObject
+       {
+         DescriptiveFramework();
+
+       public:
+         const Dictionary*& m_Dict;
+          optional_property<UUID > LinkedDescriptiveFrameworkPlugInId;
+
+      DescriptiveFramework(const Dictionary*& d);
+      DescriptiveFramework(const DescriptiveFramework& rhs);
+      virtual ~DescriptiveFramework() {}
+
+      const DescriptiveFramework& operator=(const DescriptiveFramework& rhs) { Copy(rhs); return *this; }
+      virtual void Copy(const DescriptiveFramework& rhs);
+      virtual const char* HasName() { return "DescriptiveFramework"; }
+      virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
+      virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
+      virtual void     Dump(FILE* = 0);
+      virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+      virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+       };
+
+      //
+      class DescriptiveObject : public InterchangeObject
+       {
+         DescriptiveObject();
+
+       public:
+         const Dictionary*& m_Dict;
+          optional_property<UUID > LinkedDescriptiveObjectPlugInId;
+
+      DescriptiveObject(const Dictionary*& d);
+      DescriptiveObject(const DescriptiveObject& rhs);
+      virtual ~DescriptiveObject() {}
+
+      const DescriptiveObject& operator=(const DescriptiveObject& rhs) { Copy(rhs); return *this; }
+      virtual void Copy(const DescriptiveObject& rhs);
+      virtual const char* HasName() { return "DescriptiveObject"; }
+      virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
+      virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
+      virtual void     Dump(FILE* = 0);
+      virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+      virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+       };
+
       //
       class GenericDataEssenceDescriptor : public FileDescriptor
        {
@@ -1102,6 +1148,101 @@ namespace ASDCP
       virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
        };
 
+      //
+      class TextBasedDMFramework : public DescriptiveFramework
+       {
+         TextBasedDMFramework();
+
+       public:
+         const Dictionary*& m_Dict;
+          optional_property<UUID > ObjectRef;
+
+      TextBasedDMFramework(const Dictionary*& d);
+      TextBasedDMFramework(const TextBasedDMFramework& rhs);
+      virtual ~TextBasedDMFramework() {}
+
+      const TextBasedDMFramework& operator=(const TextBasedDMFramework& rhs) { Copy(rhs); return *this; }
+      virtual void Copy(const TextBasedDMFramework& rhs);
+      virtual const char* HasName() { return "TextBasedDMFramework"; }
+      virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
+      virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
+      virtual void     Dump(FILE* = 0);
+      virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+      virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+       };
+
+      //
+      class TextBasedObject : public DescriptiveObject
+       {
+         TextBasedObject();
+
+       public:
+         const Dictionary*& m_Dict;
+          UL PayloadSchemeID;
+          UTF16String TextMIMEMediaType;
+          UTF16String RFC5646TextLanguageCode;
+          optional_property<UTF16String > TextDataDescription;
+
+      TextBasedObject(const Dictionary*& d);
+      TextBasedObject(const TextBasedObject& rhs);
+      virtual ~TextBasedObject() {}
+
+      const TextBasedObject& operator=(const TextBasedObject& rhs) { Copy(rhs); return *this; }
+      virtual void Copy(const TextBasedObject& rhs);
+      virtual const char* HasName() { return "TextBasedObject"; }
+      virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
+      virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
+      virtual void     Dump(FILE* = 0);
+      virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+      virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+       };
+
+      //
+      class GenericStreamTextBasedSet : public TextBasedObject
+       {
+         GenericStreamTextBasedSet();
+
+       public:
+         const Dictionary*& m_Dict;
+          ui32_t GenericStreamSID;
+
+      GenericStreamTextBasedSet(const Dictionary*& d);
+      GenericStreamTextBasedSet(const GenericStreamTextBasedSet& rhs);
+      virtual ~GenericStreamTextBasedSet() {}
+
+      const GenericStreamTextBasedSet& operator=(const GenericStreamTextBasedSet& rhs) { Copy(rhs); return *this; }
+      virtual void Copy(const GenericStreamTextBasedSet& rhs);
+      virtual const char* HasName() { return "GenericStreamTextBasedSet"; }
+      virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
+      virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
+      virtual void     Dump(FILE* = 0);
+      virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+      virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+       };
+
+      //
+      class ISXDDataEssenceDescriptor : public GenericDataEssenceDescriptor
+       {
+         ISXDDataEssenceDescriptor();
+
+       public:
+         const Dictionary*& m_Dict;
+          ISO8String NamespaceURI;
+
+      ISXDDataEssenceDescriptor(const Dictionary*& d);
+      ISXDDataEssenceDescriptor(const ISXDDataEssenceDescriptor& rhs);
+      virtual ~ISXDDataEssenceDescriptor() {}
+
+      const ISXDDataEssenceDescriptor& operator=(const ISXDDataEssenceDescriptor& rhs) { Copy(rhs); return *this; }
+      virtual void Copy(const ISXDDataEssenceDescriptor& rhs);
+      virtual const char* HasName() { return "ISXDDataEssenceDescriptor"; }
+      virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
+      virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
+      virtual void     Dump(FILE* = 0);
+      virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+      virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+       };
+
       //
       class PHDRMetadataTrackSubDescriptor : public InterchangeObject
        {
index 19109e87d2d686f0b096170312892c8776065b12..df108f6ca73cd171bd999f1841d4d95d30d4bc69 100644 (file)
@@ -347,7 +347,7 @@ class MyPictureDescriptor : public JP2K::PictureDescriptor
        fprintf(stream, "          Precincts: %u\n", precinct_set_size);
        fprintf(stream, "precinct dimensions:\n");
 
-       for ( int i = 0; i < precinct_set_size && i < JP2K::MaxPrecincts; i++ )
+       for ( unsigned int i = 0; i < precinct_set_size && i < JP2K::MaxPrecincts; i++ )
          fprintf(stream, "    %d: %d x %d\n", i + 1,
                  s_exp_lookup[coding_style_default.SPcod.PrecinctSize[i]&0x0f],
                  s_exp_lookup[(coding_style_default.SPcod.PrecinctSize[i]>>4)&0x0f]
@@ -539,7 +539,7 @@ public:
                ( m_WriterInfo.LabelSetType == LS_MXF_SMPTE ? "SMPTE 2067-5" : "Unknown" ),
                type_string,
                (m_Desc.ContainerDuration != 0 ? m_Desc.ContainerDuration : m_Reader.AS02IndexReader().GetDuration()),
-               (m_Desc.ContainerDuration == 1 ? "":"s"));
+               (m_Desc.ContainerDuration == (ui64_t)1 ? "":"s"));
 
        if ( Options.showheader_flag )
          {
@@ -681,7 +681,7 @@ public:
                total_frame_bytes += this_frame_size;
 
                if ( this_frame_size > largest_frame )
-                 largest_frame = this_frame_size;
+                 largest_frame = (ui32_t)this_frame_size;
              }
 
            last_stream_offset = entry.StreamOffset;
@@ -694,7 +694,7 @@ public:
        static const double mega_const = 1.0 / ( 1000000 / 8.0 );
 
        // we did not accumulate the last, so duration -= 1
-       double avg_bytes_frame = total_frame_bytes / ( duration - 1 );
+       double avg_bytes_frame = (double)(total_frame_bytes / ( duration - 1 ));
 
        m_MaxBitrate = largest_frame * mega_const * m_Desc.EditRate.Quotient();
        m_AvgBitrate = avg_bytes_frame * mega_const * m_Desc.EditRate.Quotient();
@@ -811,7 +811,6 @@ int
 main(int argc, const char** argv)
 {
   Result_t result = RESULT_OK;
-  char     str_buf[64];
   CommandOptions Options(argc, argv);
 
   if ( Options.version_flag )
index 1104be06ad8fbf879d7a57d8b937c840cf3d4fde..5a0ae685e5f3797573e15ac4f4dc13c3b0c54b24 100755 (executable)
@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2011-2016, Robert Scheler, Heiko Sparenberg Fraunhofer IIS,
+Copyright (c) 2011-2018, Robert Scheler, Heiko Sparenberg Fraunhofer IIS,
 John Hurst
 
 All rights reserved.
@@ -69,7 +69,7 @@ banner(FILE* stream = stdout)
 {
   fprintf(stream, "\n\
 %s (asdcplib %s)\n\n\
-Copyright (c) 2011-2015, Robert Scheler, Heiko Sparenberg Fraunhofer IIS, John Hurst\n\n\
+Copyright (c) 2011-2018, Robert Scheler, Heiko Sparenberg Fraunhofer IIS, John Hurst\n\n\
 asdcplib may be copied only under the terms of the license found at\n\
 the top of every file in the asdcplib distribution kit.\n\n\
 Specify the -h (help) option for further information about %s\n\n",
@@ -98,6 +98,7 @@ Options:\n\
                       Defaults to 4,194,304 (4MB)\n\
   -d <duration>     - Number of frames to process, default all\n\
   -f <start-frame>  - Starting frame number, default 0\n\
+  -g <SID>          - Extract the Generic Stream Partition payload\n\
   -h | -help        - Show help\n\
   -k <key-string>   - Use key for ciphertext operations\n\
   -m                - verify HMAC values when reading\n\
@@ -142,9 +143,9 @@ public:
   const char* file_prefix; // filename pre for files written by the extract mode
   byte_t key_value[KeyLen];  // value of given encryption key (when key_flag is true)
   byte_t key_id_value[UUIDlen];// value of given key ID (when key_id_flag is true)
-  PCM::ChannelFormat_t channel_fmt; // audio channel arrangement
   const char* input_filename;
   const char* extension;
+  i32_t g_stream_sid;     // Stream ID of a generic stream partition payload to be extracted
   std::string prefix_buffer;
 
   //
@@ -154,7 +155,7 @@ public:
     version_flag(false), help_flag(false), number_width(6),
     start_frame(0), duration(0xffffffff), duration_flag(false), j2c_pedantic(true),
     picture_rate(24), fb_size(FRAME_BUFFER_SIZE), file_prefix(0),
-    input_filename(0)
+    input_filename(0), extension(0), g_stream_sid(0)
   {
     memset(key_value, 0, KeyLen);
     memset(key_id_value, 0, UUIDlen);
@@ -202,6 +203,11 @@ public:
                start_frame = Kumu::xabs(strtol(argv[i], 0, 10));
                break;
 
+             case 'g':
+               TEST_EXTRA_ARG(i, 'g');
+               g_stream_sid = strtol(argv[i], 0, 10);
+               break;
+                 
              case 'h': help_flag = true; break;
              case 'm': read_hmac = true; break;
 
@@ -308,7 +314,7 @@ read_JP2K_file(CommandOptions& Options)
       if ( KM_SUCCESS(result) )
        {
          assert(rgba_descriptor);
-         frame_count = rgba_descriptor->ContainerDuration;
+         frame_count = (ui32_t)rgba_descriptor->ContainerDuration;
 
          if ( Options.verbose_flag )
            {
@@ -323,7 +329,7 @@ read_JP2K_file(CommandOptions& Options)
          if ( KM_SUCCESS(result) )
            {
              assert(cdci_descriptor);
-             frame_count = cdci_descriptor->ContainerDuration;
+             frame_count = (ui32_t)cdci_descriptor->ContainerDuration;
 
              if ( Options.verbose_flag )
                {
@@ -474,7 +480,7 @@ read_PCM_file(CommandOptions& Options)
            }
          else
            {
-             last_frame = wave_descriptor->ContainerDuration;
+             last_frame = (ui32_t)wave_descriptor->ContainerDuration;
            }
 
          if ( last_frame == 0 )
@@ -486,7 +492,7 @@ read_PCM_file(CommandOptions& Options)
                  ASDCP::MXF::SourceClip *sourceClip = dynamic_cast<ASDCP::MXF::SourceClip*>(tmp_obj);
                  if ( ! sourceClip->Duration.empty() )
                    {
-                     last_frame = sourceClip->Duration;
+                     last_frame = (ui32_t)sourceClip->Duration;
                    }
                }
            }
@@ -666,11 +672,122 @@ read_timed_text_file(CommandOptions& Options)
   return result;
 }
 
+//
+Result_t
+read_isxd_file(CommandOptions& Options)
+{
+  AESDecContext*     Context = 0;
+  HMACContext*       HMAC = 0;
+  AS_02::ISXD::MXFReader    Reader;
+  ASDCP::FrameBuffer  FrameBuffer;
+  ui32_t             frame_count = 0;
+
+  Result_t result = Reader.OpenRead(Options.input_filename);
+
+  if ( ASDCP_SUCCESS(result) )
+    {
+      result = FrameBuffer.Capacity(Options.fb_size);
+    }
+
+  if ( ASDCP_SUCCESS(result) )
+    {
+      std::list<MXF::InterchangeObject*> object_list;
+      Reader.OP1aHeader().GetMDObjectsByType(DefaultSMPTEDict().ul(MDD_GenericStreamTextBasedSet), object_list);
+
+      std::list<MXF::InterchangeObject*>::iterator i;
+      for ( i = object_list.begin(); i != object_list.end(); ++i )
+       {
+         MXF::GenericStreamTextBasedSet *text_object = dynamic_cast<MXF::GenericStreamTextBasedSet*>(*i);
+         assert(text_object);
+         text_object->Dump(stderr);
+       }
+    }
+
+  if ( ASDCP_SUCCESS(result) && Options.key_flag )
+    {
+      Context = new AESDecContext;
+      result = Context->InitKey(Options.key_value);
+
+      if ( ASDCP_SUCCESS(result) && Options.read_hmac )
+       {
+         WriterInfo Info;
+         Reader.FillWriterInfo(Info);
+
+         if ( Info.UsesHMAC )
+           {
+             HMAC = new HMACContext;
+             result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
+           }
+         else
+           {
+             fputs("File does not contain HMAC values, ignoring -m option.\n", stderr);
+           }
+       }
+    }
+
+  ui32_t last_frame = Options.start_frame + ( Options.duration ? Options.duration : frame_count);
+  if ( last_frame > frame_count )
+    last_frame = frame_count;
+
+  char name_format[64];
+  snprintf(name_format,  64, "%%s%%0%du.%s", Options.number_width, Options.extension);
+
+  for ( ui32_t i = Options.start_frame; ASDCP_SUCCESS(result) && i < last_frame; i++ )
+    {
+      result = Reader.ReadFrame(i, FrameBuffer, Context, HMAC);
+
+      if ( ASDCP_SUCCESS(result) )
+       {
+         if ( ! Options.no_write_flag )
+           {
+             Kumu::FileWriter OutFile;
+             char filename[256];
+             ui32_t write_count;
+             snprintf(filename, 256, name_format, Options.file_prefix, i);
+             result = OutFile.OpenWrite(filename);
+
+             if ( ASDCP_SUCCESS(result) )
+               result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count);
+           }
+       }
+    }
+
+  return result;
+}
+
+Result_t
+extract_generic_stream_partition_payload(const std::string& in_filename, const ui32_t sid, const std::string& out_filename)
+{
+  ASDCP::FrameBuffer payload;
+  AS_02::ISXD::MXFReader reader;
+
+  Result_t result = reader.OpenRead(in_filename);
+          
+  if ( KM_SUCCESS(result) )
+    {
+      result = reader.ReadGenericStreamPartitionPayload(sid, payload);
+    }
+  
+  if ( KM_SUCCESS(result) )
+    {
+      Kumu::FileWriter writer;
+      ui32_t write_count = 0;
+      result = writer.OpenWrite(out_filename);
+      
+      if ( KM_SUCCESS(result) )
+       {
+         result = writer.Write(payload.RoData(), payload.Size(), &write_count);
+       }
+    }
+
+  return result;
+}
+
+
 //
 int
 main(int argc, const char** argv)
 {
-  char     str_buf[64];
   CommandOptions Options(argc, argv);
 
   if ( Options.version_flag )
@@ -708,6 +825,19 @@ main(int argc, const char** argv)
          result = read_timed_text_file(Options);
          break;
 
+       case ESS_AS02_ISXD:
+         if ( Options.g_stream_sid == 0 )
+           {
+             result = read_isxd_file(Options);
+           }
+         else
+           {
+             result = extract_generic_stream_partition_payload(Options.input_filename,
+                                                               Options.g_stream_sid,
+                                                               Options.file_prefix);
+           }
+         break;
+
        default:
          fprintf(stderr, "%s: Unknown file type (%d), not AS-02 essence.\n", Options.input_filename, EssenceType);
          return 5;
index 174365b8c67a71f7d68c26040ed361c700b21144..32a6aec7e75d56679e92e825d6567cc17465ba7d 100755 (executable)
@@ -38,6 +38,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include <KM_fileio.h>
 #include <KM_prng.h>
+#include <KM_xml.h>
 #include <AS_02.h>
 #include <PCMParserList.h>
 #include <Metadata.h>
@@ -142,7 +143,10 @@ Options:\n\
   -F (0|1)          - Set field dominance for interlaced image (default: 0)\n\
   -g <rfc-5646-code>\n\
                     - Create MCA labels having the given RFC 5646 language code\n\
-                      (requires option \"-m\")\n\
+                      (requires option \"-m\") -- Also used with -G to set the\n\
+                      value of the TextMIMEMediaType property\n\
+  -G <filename>     - Filename of XML resource to be carried per RP 2057 Generic\n\
+                      Stream. May be issued multiple times.\n\
   -i                - Indicates input essence is interlaced fields (forces -Y)\n\
   -j <key-id-str>   - Write key ID instead of creating a random value\n\
   -k <key-string>   - Use key for ciphertext operations\n\
@@ -166,6 +170,7 @@ Options:\n\
   -t <min>          - Set RGB component minimum code value (default: 0)\n\
   -T <max>          - Set RGB component maximum code value (default: 1023)\n\
   -u                - Print UL catalog to stdout\n\
+  -u <UL>           - ISXD (RDD47) essence coding label\n\
   -v                - Verbose, prints informative messages to stderr\n\
   -W                - Read input file only, do not write source file\n\
   -x <int>          - Horizontal subsampling degree (default: 2)\n\
@@ -252,7 +257,7 @@ public:
 
   UL channel_assignment, picture_coding, transfer_characteristic, color_primaries, coding_equations;
   ASDCP::MXF::AS02_MCAConfigParser mca_config;
-  std::string mca_language;
+  std::string language;
 
   ui32_t rgba_MaxRef;
   ui32_t rgba_MinRef;
@@ -276,6 +281,10 @@ public:
   AS_02::IndexStrategy_t index_strategy; //Shim parameter index_strategy_frame/clip
   ui32_t partition_space; //Shim parameter partition_spacing
 
+  // ISXD
+  UL isxd_essence_coding;
+  std::list<std::string> global_isxd_metadata;
+
   //
   MXF::LineMapPair line_map;
   std::string out_file, profile_name; //
@@ -529,7 +538,12 @@ public:
 
              case 'g':
                TEST_EXTRA_ARG(i, 'g');
-               mca_language = argv[i];
+               language = argv[i];
+               break;
+
+             case 'G':
+               TEST_EXTRA_ARG(i, 'G');
+               global_isxd_metadata.push_back(argv[i]);
                break;
 
              case 'h': help_flag = true; break;
@@ -662,6 +676,15 @@ public:
 
              case 'u': show_ul_values_flag = true; break;
 
+             case 'U':
+               TEST_EXTRA_ARG(i, 'U');
+               if ( ! isxd_essence_coding.DecodeHex(argv[i]) )
+                 {
+                   fprintf(stderr, "Error decoding UL value: %s\n", argv[i]);
+                   return;
+                 }
+               break;
+
              case 'V': version_flag = true; break;
              case 'v': verbose_flag = true; break;
              case 'W': no_write_flag = true; break;
@@ -716,7 +739,7 @@ public:
 
     if ( ! mca_config_str.empty() )
       {
-       if ( mca_language.empty() )
+       if ( language.empty() )
          {
            if ( ! mca_config.DecodeString(mca_config_str) )
              {
@@ -725,7 +748,7 @@ public:
          }
        else
          {
-           if ( ! mca_config.DecodeString(mca_config_str, mca_language) )
+           if ( ! mca_config.DecodeString(mca_config_str, language) )
              {
                return;
              }
@@ -1245,6 +1268,195 @@ write_timed_text_file(CommandOptions& Options)
   return result;
 }
 
+//
+bool
+get_current_dms_text_descriptor(AS_02::ISXD::MXFWriter& writer, ASDCP::MXF::GenericStreamTextBasedSet *&text_object)
+{
+  std::list<MXF::InterchangeObject*> object_list;
+  writer.OP1aHeader().GetMDObjectsByType(DefaultSMPTEDict().ul(MDD_GenericStreamTextBasedSet), object_list);
+
+  if ( object_list.empty() )
+    {
+      return false;
+    }
+
+  text_object = dynamic_cast<MXF::GenericStreamTextBasedSet*>(object_list.back());
+  assert(text_object != 0);
+  return true;
+}
+                     
+
+// Write one or more plaintext Aux Data bytestreams to a plaintext AS-02 file
+// Write one or more plaintext Aux Data bytestreams to a ciphertext AS-02 file
+//
+Result_t
+write_isxd_file(CommandOptions& Options)
+{
+  AESEncContext*          Context = 0;
+  HMACContext*            HMAC = 0;
+  AS_02::ISXD::MXFWriter Writer;
+  DCData::FrameBuffer     FrameBuffer(Options.fb_size);
+  DCData::SequenceParser  Parser;
+  byte_t                  IV_buf[CBC_BLOCK_SIZE];
+  Kumu::FortunaRNG        RNG;
+
+  // set up essence parser
+  Result_t result = Parser.OpenRead(Options.filenames.front());
+
+  // set up MXF writer
+  if ( ASDCP_SUCCESS(result) )
+  {
+
+    if ( Options.verbose_flag )
+       {
+         fprintf(stderr, "Aux Data\n");
+         fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size);
+       }
+  }
+
+  if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
+  {
+    WriterInfo Info = s_MyInfo;  // fill in your favorite identifiers here
+    if ( Options.asset_id_flag )
+      memcpy(Info.AssetUUID, Options.asset_id_value, UUIDlen);
+    else
+      Kumu::GenRandomUUID(Info.AssetUUID);
+
+    Info.LabelSetType = LS_MXF_SMPTE;
+
+      // configure encryption
+    if( Options.key_flag )
+       {
+         Kumu::GenRandomUUID(Info.ContextID);
+         Info.EncryptedEssence = true;
+
+         if ( Options.key_id_flag )
+           {
+             memcpy(Info.CryptographicKeyID, Options.key_id_value, UUIDlen);
+           }
+         else
+           {
+             create_random_uuid(Info.CryptographicKeyID);
+           }
+
+         Context = new AESEncContext;
+         result = Context->InitKey(Options.key_value);
+
+         if ( ASDCP_SUCCESS(result) )
+           result = Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
+
+         if ( ASDCP_SUCCESS(result) && Options.write_hmac )
+      {
+        Info.UsesHMAC = true;
+        HMAC = new HMACContext;
+        result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
+      }
+       }
+
+    if ( ASDCP_SUCCESS(result) )
+      {
+       result = Writer.OpenWrite(Options.out_file, Info, Options.isxd_essence_coding, Options.edit_rate);
+      }
+  }
+
+  if ( ASDCP_SUCCESS(result) )
+  {
+    ui32_t duration = 0;
+    result = Parser.Reset();
+
+    while ( ASDCP_SUCCESS(result) && duration++ < Options.duration )
+      {
+       result = Parser.ReadFrame(FrameBuffer);
+
+       if ( ASDCP_SUCCESS(result) )
+         {
+           if ( Options.verbose_flag )
+             FrameBuffer.Dump(stderr, Options.fb_dump_size);
+
+           if ( Options.encrypt_header_flag )
+             FrameBuffer.PlaintextOffset(0);
+         }
+
+       if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
+         {
+           result = Writer.WriteFrame(FrameBuffer, Context, HMAC);
+
+           // The Writer class will forward the last block of ciphertext
+           // to the encryption context for use as the IV for the next
+           // frame. If you want to use non-sequitur IV values, un-comment
+           // the following  line of code.
+           // if ( ASDCP_SUCCESS(result) && Options.key_flag )
+           //   Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
+         }
+      }
+
+    if ( result == RESULT_ENDOFFILE )
+      {
+       result = RESULT_OK;
+      }
+  }
+
+  if ( KM_SUCCESS(result) && ! Options.no_write_flag )
+    {
+      ASDCP::FrameBuffer global_metadata;
+      std::list<std::string>::iterator i;
+      
+      for ( i = Options.global_isxd_metadata.begin(); i != Options.global_isxd_metadata.end(); ++i )
+       {
+         ui32_t file_size = Kumu::FileSize(*i);
+         result = global_metadata.Capacity(file_size);
+
+         if ( KM_SUCCESS(result) )
+           {
+             ui32_t read_count = 0;
+             Kumu::FileReader Reader;
+             std::string namespace_name;
+
+             result = Reader.OpenRead(*i);
+
+             if ( KM_SUCCESS(result) )
+               {
+                 result = Reader.Read(global_metadata.Data(), file_size, &read_count);
+               }
+
+             if ( KM_SUCCESS(result) )
+               {
+                 if ( file_size != read_count) 
+                   return RESULT_READFAIL;
+
+                 global_metadata.Size(read_count);
+
+                 std::string ns_prefix, type_name;
+                 Kumu::AttributeList doc_attr_list;
+                 result = GetXMLDocType(global_metadata.RoData(), global_metadata.Size(), ns_prefix, type_name,
+                                        namespace_name, doc_attr_list) ? RESULT_OK : RESULT_FAIL;
+               }
+
+             if ( KM_SUCCESS(result) )
+               {
+                 result = Writer.AddDmsGenericPartUtf8Text(global_metadata, Context, HMAC);
+               }
+
+             if ( KM_SUCCESS(result) )
+               {
+                 ASDCP::MXF::GenericStreamTextBasedSet *text_object = 0;
+                 get_current_dms_text_descriptor(Writer, text_object);
+                 assert(text_object);
+                 text_object->TextMIMEMediaType = "text/xml";
+                 text_object->TextDataDescription = namespace_name;
+                 text_object->RFC5646TextLanguageCode = Options.language;
+               }
+           }
+       }
+
+      if ( KM_SUCCESS(result) )
+       {
+         result = Writer.Finalize();
+       }
+    }
+
+  return result;
+}
 
 //
 int
@@ -1297,6 +1509,19 @@ main(int argc, const char** argv)
          result = write_timed_text_file(Options);
          break;
 
+       case ESS_DCDATA_UNKNOWN:
+         if ( Options.isxd_essence_coding.HasValue() )
+           {
+             result = write_isxd_file(Options);      
+           }
+         else
+           {
+             fprintf(stderr, "%s: Unknown synchronous data file type, not AS-02-compatible essence.\n",
+                     Options.filenames.front().c_str());
+             return 5;
+           }
+         break;
+
        default:
          fprintf(stderr, "%s: Unknown file type, not AS-02-compatible essence.\n",
                  Options.filenames.front().c_str());
index 25a82e0e1c7c7c6708c5be760acb5098750f3a75..17e9b0d78385ce9b93c3d95db490ac5befc3a2b7 100644 (file)
@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2011-2016, Robert Scheler, Heiko Sparenberg Fraunhofer IIS,
+Copyright (c) 2011-2018, Robert Scheler, Heiko Sparenberg Fraunhofer IIS,
 John Hurst
 
 All rights reserved.
@@ -93,7 +93,7 @@ AS_02::MXF::AS02IndexReader::InitFromFile(const Kumu::FileReader& reader, const
        }
       else if ( i->BodySID != first_body_sid )
        {
-         DefaultLogSink().Debug("The index assembler is ignoring BodySID %d.\n", i->BodySID);
+         //      DefaultLogSink().Debug("The index assembler is ignoring BodySID %d.\n", i->BodySID);
          continue;
        }
 
@@ -411,7 +411,6 @@ AS_02::h__AS02Reader::OpenMXFRead(const std::string& filename)
     {
       //
       UL OP1a_ul(m_Dict->ul(MDD_OP1a));
-      InterchangeObject* Object;
       m_Info.LabelSetType = LS_MXF_SMPTE;
 
       if ( m_HeaderPart.OperationalPattern != OP1a_ul )
index 62f21f2051280c7f6c509d60e691a15056632f7e..37393caf91903f18b5712c6ced5b7bca839dd941 100644 (file)
@@ -57,7 +57,7 @@ AS_02::MXF::AS02IndexWriterVBR::WriteToFile(Kumu::FileWriter& Writer)
 {
   assert(m_Dict);
   ASDCP::FrameBuffer index_body_buffer;
-  ui32_t   index_body_size = m_PacketList->m_List.size() * MaxIndexSegmentSize; // segment-count * max-segment-size
+  ui32_t index_body_size = (ui32_t)m_PacketList->m_List.size() * MaxIndexSegmentSize; // segment-count * max-segment-size
   Result_t result = index_body_buffer.Capacity(index_body_size); 
   ui64_t start_position = 0;
 
@@ -140,7 +140,7 @@ AS_02::MXF::AS02IndexWriterVBR::GetDuration() const
       IndexTableSegment* segment = dynamic_cast<IndexTableSegment*>(*i);
       if ( segment != 0 )
        {
-         duration += segment->IndexEntryArray.size();
+         duration += (ui32_t)segment->IndexEntryArray.size();
        }
     }
 
@@ -193,9 +193,8 @@ AS_02::h__AS02WriterFrame::WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf,co
 
   if ( m_FramesWritten > 1 && ( ( m_FramesWritten + 1 ) % m_PartitionSpace ) == 0 )
     {
-      m_IndexWriter.ThisPartition = m_File.Tell();
-      m_IndexWriter.WriteToFile(m_File);
-      m_RIP.PairArray.push_back(RIP::PartitionPair(0, m_IndexWriter.ThisPartition));
+      assert(m_IndexWriter.GetDuration() > 0);
+      FlushIndexPartition();
 
       UL body_ul(m_Dict->ul(MDD_ClosedCompleteBodyPartition));
       Partition body_part(m_Dict);
@@ -374,8 +373,6 @@ AS_02::h__AS02WriterClip::FinalizeClip(ui32_t bytes_per_frame)
   return result;
 }
 
-
-
 //
 // end h__02_Writer.cpp
 //
index 93388cd7dcf388a4be0311dfca0297d28b5b2467..4d11786145a49bf92459de942317117e8df8998e 100755 (executable)
@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2004-2015, John Hurst
+Copyright (c) 2004-2018, John Hurst
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -39,13 +39,13 @@ using namespace ASDCP::MXF;
 ui32_t
 ASDCP::derive_timecode_rate_from_edit_rate(const ASDCP::Rational& edit_rate)
 {
-  return floor(0.5 + edit_rate.Quotient());
+  return (ui32_t)floor(0.5 + edit_rate.Quotient());
 }
 
 //
 // add DMS CryptographicFramework entry to source package
 void
-ASDCP::AddDMScrypt(Partition& HeaderPart, SourcePackage& Package,
+ASDCP::AddDmsCrypt(Partition& HeaderPart, SourcePackage& Package,
                   WriterInfo& Descr, const UL& WrappingUL, const Dictionary*& Dict)
 {
   assert(Dict);
@@ -65,6 +65,7 @@ ASDCP::AddDMScrypt(Partition& HeaderPart, SourcePackage& Package,
   HeaderPart.AddChildObject(Segment);
   Seq->StructuralComponents.push_back(Segment->InstanceUID);
   Segment->EventComment = "AS-DCP KLV Encryption";
+  Segment->DataDefinition = UL(Dict->ul(MDD_DescriptiveMetaDataDef));
 
   CryptographicFramework* CFW = new CryptographicFramework(Dict);
   HeaderPart.AddChildObject(CFW);
@@ -81,7 +82,127 @@ ASDCP::AddDMScrypt(Partition& HeaderPart, SourcePackage& Package,
   Context->CryptographicKeyID.Set(Descr.CryptographicKeyID);
 }
 
+static std::string const rp2057_static_track_label = "SMPTE RP 2057 Generic Stream Text-Based Set";
 
+//
+static bool
+id_batch_contains(const Array<Kumu::UUID>& batch, const Kumu::UUID& value)
+{
+  Array<Kumu::UUID>::const_iterator i;
+  for ( i = batch.begin(); i != batch.end(); ++i )
+    {
+      if ( *i == value )
+       {
+         return true;
+       }
+    }
+  return false;
+}
+
+//
+Result_t
+ASDCP::AddDmsTrackGenericPartUtf8Text(Kumu::FileWriter& file_writer, MXF::OP1aHeader& header_part,
+                                     SourcePackage& source_package, MXF::RIP& rip, const Dictionary*& Dict)
+{
+  Sequence* Sequence_obj = 0;
+  InterchangeObject* tmp_iobj = 0;
+  std::list<InterchangeObject*> object_list;
+
+  // get the SourcePackage else die
+  header_part.GetMDObjectByType(Dict->ul(MDD_SourcePackage), &tmp_iobj);
+  SourcePackage *SourcePackage_obj = dynamic_cast<SourcePackage*>(tmp_iobj);
+  if ( SourcePackage_obj == 0 )
+    {
+      DefaultLogSink().Error("MXF Metadata contains no SourcePackage Set.\n");
+      return RESULT_FORMAT;
+    }
+
+  // find the first StaticTrack object, having the right label, that is ref'd by the source package
+  StaticTrack *StaticTrack_obj = 0;
+  header_part.GetMDObjectsByType(Dict->ul(MDD_StaticTrack), object_list);
+  std::list<InterchangeObject*>::iterator j;
+  for ( j = object_list.begin(); j != object_list.end(); ++j )
+    {
+      StaticTrack_obj = dynamic_cast<StaticTrack*>(*j);
+      assert(StaticTrack_obj);
+      if ( id_batch_contains(SourcePackage_obj->Tracks, StaticTrack_obj->InstanceUID)
+          && StaticTrack_obj->TrackName.get() == rp2057_static_track_label )
+       {
+         break;
+       }
+      StaticTrack_obj = 0;
+    }
+
+  if ( StaticTrack_obj )
+    {
+      object_list.clear();
+      header_part.GetMDObjectsByType(Dict->ul(MDD_Sequence), object_list);
+      for ( j = object_list.begin(); j != object_list.end(); ++j )
+       {
+         Sequence_obj = dynamic_cast<Sequence*>(*j);
+         assert(Sequence_obj);
+         if ( Sequence_obj->InstanceUID == StaticTrack_obj->Sequence )
+           {
+             break;
+           }
+         Sequence_obj = 0;
+       }
+    }
+
+  if ( Sequence_obj == 0 )
+    {
+      assert(Dict);
+      StaticTrack* static_track = new StaticTrack(Dict);
+      header_part.AddChildObject(static_track);
+      source_package.Tracks.push_back(static_track->InstanceUID);
+      static_track->TrackName = "Descriptive Track";
+      static_track->TrackID = 4;
+
+      Sequence_obj = new Sequence(Dict);
+      header_part.AddChildObject(Sequence_obj);
+      static_track->Sequence = Sequence_obj->InstanceUID;
+      Sequence_obj->DataDefinition = UL(Dict->ul(MDD_DescriptiveMetaDataDef));
+      header_part.m_Preface->DMSchemes.push_back(UL(Dict->ul(MDD_MXFTextBasedFramework)));
+    }
+
+  assert(Sequence_obj);
+  // 
+  DMSegment* Segment = new DMSegment(Dict);
+  header_part.AddChildObject(Segment);
+  Sequence_obj->StructuralComponents.push_back(Segment->InstanceUID);
+  Segment->EventComment = rp2057_static_track_label;
+  Segment->DataDefinition = UL(Dict->ul(MDD_DescriptiveMetaDataDef));
+
+  //
+  TextBasedDMFramework *dmf_obj = new TextBasedDMFramework(Dict);
+  assert(dmf_obj);
+  header_part.AddChildObject(dmf_obj);
+  Segment->DMFramework = dmf_obj->InstanceUID;
+  GenRandomValue(dmf_obj->ObjectRef);
+
+
+  // Create new SID in DMF
+  ui32_t max_sid = 0;
+  ASDCP::MXF::RIP::pair_iterator i;
+  for ( i = rip.PairArray.begin(); i != rip.PairArray.end(); ++i )
+    {
+      if ( max_sid < i->BodySID )
+       {
+         max_sid = i->BodySID;
+       }
+    }
+
+  rip.PairArray.push_back(RIP::PartitionPair(max_sid + 1, file_writer.Tell()));
+
+  // Add new GSTBS linked to DMF
+  GenericStreamTextBasedSet *gst_obj = new GenericStreamTextBasedSet(Dict);
+  header_part.AddChildObject(gst_obj);
+  gst_obj->InstanceUID = dmf_obj->ObjectRef;
+  gst_obj->GenericStreamSID = max_sid + 1;
+  gst_obj->PayloadSchemeID = UL(Dict->ul(MDD_MXFTextBasedFramework));
+  
+  return RESULT_OK;
+}
 
 //
 ASDCP::h__ASDCPWriter::h__ASDCPWriter(const Dictionary& d) :
index 801389eaa5f731bb422a284ba84137186245cdc0..90b719b87544c4f791b7e18a60311a2111ac629b 100755 (executable)
@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2005-2016, John Hurst
+Copyright (c) 2005-2018, John Hurst
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -341,7 +341,7 @@ main(int argc, const char** argv)
          
          while ( ASDCP_SUCCESS(result) )
            {
-             fprintf(stdout, "@0x%08qx: ", pos);
+             fprintf(stdout, "@0x%08llx: ", pos);
              KP.Dump(stdout, DefaultCompositeDict(), true);
              pos = Reader.Tell();
              result = KP.InitFromFile(Reader);