o Added optional Generic Partition to IMF Aux Data prototype, used to carry global...
authorjhurst <jhurst@cinecert.com>
Tue, 22 Nov 2016 17:58:19 +0000 (17:58 +0000)
committerjhurst <>
Tue, 22 Nov 2016 17:58:19 +0000 (17:58 +0000)
 o Added support for 192, 200 and 240 fps images, includes 96, 100 and 120 fpe stereo
 o Fixed raw essence detector for IMF Aux Data files
 o Added missing MCA properties to MCALabelSubDescriptor (contributed by Ruppel)
 o New MXF data type: LineMapPair
 o Added default 0,0 VideoLineMap value when wrapping CDCI with as-02-wrap
 o Added VideoLineMap property to GenericPictureEssenceDescriptor
 o Added timed text unwrap support to as-02-unwrap (contributed by Ruppel)

20 files changed:
src/AS_02.h
src/AS_02_internal.h
src/AS_DCP.h
src/AS_DCP_ATMOS.cpp
src/AS_DCP_DCData.cpp
src/AS_DCP_JP2K.cpp
src/AS_DCP_MXF.cpp
src/AS_DCP_PCM.cpp
src/MDD.cpp
src/MDD.h
src/MXFTypes.h
src/Metadata.cpp
src/Metadata.h
src/TimedText_Parser.cpp
src/as-02-unwrap.cpp
src/as-02-wrap.cpp
src/asdcp-test.cpp
src/asdcp-unwrap.cpp
src/asdcp-wrap.cpp
src/h__02_Reader.cpp

index 69f159b7c51720a8eadeaaa0e98dfcdc3ecf8637..5d621a78d4bf3005d61bee832baa471026329add 100644 (file)
@@ -511,8 +511,7 @@ namespace AS_02
       // 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&,
-                        ASDCP::MXF::FileDescriptor* essence_descriptor,
-                        ASDCP::MXF::InterchangeObject_list_t& essence_sub_descriptor_list,
+                        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);
 
@@ -522,8 +521,11 @@ namespace AS_02
       // error occurs.
       Result_t WriteFrame(const ASDCP::FrameBuffer&, ASDCP::AESEncContext* = 0, ASDCP::HMACContext* = 0);
 
-      // Closes the MXF file, writing the index and revised header.
+      // Closes the MXF file, writing the index and revised header. No global metadata block is written.
       Result_t Finalize();
+
+      // Closes the MXF file, writing the global metadata block and then final index and revised header.
+      Result_t Finalize(const ASDCP::FrameBuffer& global_metadata);
     };
 
     //
@@ -547,6 +549,11 @@ namespace AS_02
       // 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;
 
index bcee7a7b088c15423ae5d8f51391042fd873298c..2f96c25b5e576aa2dd22f79cc0b212f78757c6b6 100644 (file)
@@ -63,7 +63,7 @@ namespace AS_02
       h__AS02Reader(const ASDCP::Dictionary&);
       virtual ~h__AS02Reader();
 
-      Result_t OpenMXFRead(const char* filename);
+      Result_t OpenMXFRead(const std::string& filename);
 
       // USE FRAME WRAPPING...
       Result_t ReadEKLVFrame(ui32_t FrameNum, ASDCP::FrameBuffer& FrameBuf,
index 75ca97f76edafcc2da37d93b3e4c86049aaef577..b1540aabcdec14401a2ca69c037b4700e7d51372 100755 (executable)
@@ -302,6 +302,9 @@ namespace ASDCP {
   const Rational EditRate_96 = Rational(96,1);
   const Rational EditRate_100 = Rational(100,1);
   const Rational EditRate_120 = Rational(120,1);
+  const Rational EditRate_192 = Rational(192,1);
+  const Rational EditRate_200 = Rational(200,1);
+  const Rational EditRate_240 = Rational(240,1);
 
   // Archival frame rates, see ST 428-21
   // These rates are new and not supported by all systems. Do not assume that
index f53ae714a2b4ccdce03fcffb05a095f096b45df8..a016f2789afdefd1aebbb0733ba773c1b4711f6a 100644 (file)
@@ -187,15 +187,18 @@ ASDCP::ATMOS::MXFReader::h__Reader::OpenRead(const std::string& filename)
 
   // check for sample/frame rate sanity
   if ( ASDCP_SUCCESS(result)
-                && m_DDesc.EditRate != EditRate_24
-                && m_DDesc.EditRate != EditRate_25
-                && m_DDesc.EditRate != EditRate_30
-                && m_DDesc.EditRate != EditRate_48
-                && m_DDesc.EditRate != EditRate_50
-                && m_DDesc.EditRate != EditRate_60
-                && m_DDesc.EditRate != EditRate_96
-                && m_DDesc.EditRate != EditRate_100
-       && m_DDesc.EditRate != EditRate_120 )
+       && m_DDesc.EditRate != EditRate_24
+       && m_DDesc.EditRate != EditRate_25
+       && m_DDesc.EditRate != EditRate_30
+       && m_DDesc.EditRate != EditRate_48
+       && m_DDesc.EditRate != EditRate_50
+       && m_DDesc.EditRate != EditRate_60
+       && m_DDesc.EditRate != EditRate_96
+       && m_DDesc.EditRate != EditRate_100
+       && m_DDesc.EditRate != EditRate_120
+       && m_DDesc.EditRate != EditRate_192
+       && m_DDesc.EditRate != EditRate_200
+       && m_DDesc.EditRate != EditRate_240 )
   {
     DefaultLogSink().Error("DC Data file EditRate is not a supported value: %d/%d\n", // lu
                            m_DDesc.EditRate.Numerator, m_DDesc.EditRate.Denominator);
@@ -503,7 +506,10 @@ ASDCP::ATMOS::MXFWriter::h__Writer::SetSourceStream(ASDCP::DCData::DCDataDescrip
        && DDesc.EditRate != EditRate_60
        && DDesc.EditRate != EditRate_96
        && DDesc.EditRate != EditRate_100
-       && DDesc.EditRate != EditRate_120 )
+       && DDesc.EditRate != EditRate_120
+       && DDesc.EditRate != EditRate_192
+       && DDesc.EditRate != EditRate_200
+       && DDesc.EditRate != EditRate_240 )
   {
     DefaultLogSink().Error("DCDataDescriptor.EditRate is not a supported value: %d/%d\n",
                            DDesc.EditRate.Numerator, DDesc.EditRate.Denominator);
index 208e8520a12ce6c397d8abbb607e381e94aa0294..818af2c630e97da32484e975ca910554213944f6 100644 (file)
@@ -157,15 +157,18 @@ ASDCP::DCData::MXFReader::h__Reader::OpenRead(const std::string& filename)
 
   // check for sample/frame rate sanity
   if ( ASDCP_SUCCESS(result)
-                && m_DDesc.EditRate != EditRate_24
-                && m_DDesc.EditRate != EditRate_25
-                && m_DDesc.EditRate != EditRate_30
-                && m_DDesc.EditRate != EditRate_48
-                && m_DDesc.EditRate != EditRate_50
-                && m_DDesc.EditRate != EditRate_60
-                && m_DDesc.EditRate != EditRate_96
-                && m_DDesc.EditRate != EditRate_100
-       && m_DDesc.EditRate != EditRate_120 )
+       && m_DDesc.EditRate != EditRate_24
+       && m_DDesc.EditRate != EditRate_25
+       && m_DDesc.EditRate != EditRate_30
+       && m_DDesc.EditRate != EditRate_48
+       && m_DDesc.EditRate != EditRate_50
+       && m_DDesc.EditRate != EditRate_60
+       && m_DDesc.EditRate != EditRate_96
+       && m_DDesc.EditRate != EditRate_100
+       && m_DDesc.EditRate != EditRate_120
+       && m_DDesc.EditRate != EditRate_192
+       && m_DDesc.EditRate != EditRate_200
+       && m_DDesc.EditRate != EditRate_240 )
   {
     DefaultLogSink().Error("DC Data file EditRate is not a supported value: %d/%d\n", // lu
                            m_DDesc.EditRate.Numerator, m_DDesc.EditRate.Denominator);
@@ -444,7 +447,10 @@ ASDCP::DCData::MXFWriter::h__Writer::SetSourceStream(DCDataDescriptor const& DDe
        && DDesc.EditRate != EditRate_60
        && DDesc.EditRate != EditRate_96
        && DDesc.EditRate != EditRate_100
-       && DDesc.EditRate != EditRate_120 )
+       && DDesc.EditRate != EditRate_120
+       && DDesc.EditRate != EditRate_192
+       && DDesc.EditRate != EditRate_200
+       && DDesc.EditRate != EditRate_240 )
   {
     DefaultLogSink().Error("DCDataDescriptor.EditRate is not a supported value: %d/%d\n",
                            DDesc.EditRate.Numerator, DDesc.EditRate.Denominator);
index acb8f4eb3b77e230573d33ec5f4975954a84501e..937231fdd677b248467a4e5bcdb24ccda6471847 100755 (executable)
@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2004-2014, John Hurst
+Copyright (c) 2004-2016, John Hurst
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -397,7 +397,10 @@ lh__Reader::OpenRead(const std::string& filename, EssenceType_t type)
                   || ( m_EditRate == EditRate_30 && m_SampleRate == EditRate_60 )
                   || ( m_EditRate == EditRate_48 && m_SampleRate == EditRate_96 )
                   || ( m_EditRate == EditRate_50 && m_SampleRate == EditRate_100 )
-                  || ( m_EditRate == EditRate_60 && m_SampleRate == EditRate_120 ) )
+                  || ( m_EditRate == EditRate_60 && m_SampleRate == EditRate_120 )
+                  || ( m_EditRate == EditRate_96 && m_SampleRate == EditRate_192 )
+                  || ( m_EditRate == EditRate_100 && m_SampleRate == EditRate_200 )
+                  || ( m_EditRate == EditRate_120 && m_SampleRate == EditRate_240 ) )
                {
                  DefaultLogSink().Debug("File may contain JPEG Interop stereoscopic images.\n");
                  return RESULT_SFORMAT;
@@ -456,6 +459,30 @@ lh__Reader::OpenRead(const std::string& filename, EssenceType_t type)
                  return RESULT_FORMAT;
                }
            }
+         else if ( m_EditRate == EditRate_96 )
+           {
+             if ( m_SampleRate != EditRate_192 )
+               {
+                 DefaultLogSink().Error("EditRate and SampleRate not correct for 96/192 stereoscopic essence.\n");
+                 return RESULT_FORMAT;
+               }
+           }
+         else if ( m_EditRate == EditRate_100 )
+           {
+             if ( m_SampleRate != EditRate_200 )
+               {
+                 DefaultLogSink().Error("EditRate and SampleRate not correct for 100/200 stereoscopic essence.\n");
+                 return RESULT_FORMAT;
+               }
+           }
+         else if ( m_EditRate == EditRate_120 )
+           {
+             if ( m_SampleRate != EditRate_240 )
+               {
+                 DefaultLogSink().Error("EditRate and SampleRate not correct for 120/240 stereoscopic essence.\n");
+                 return RESULT_FORMAT;
+               }
+           }
          else
            {
              DefaultLogSink().Error("EditRate not correct for stereoscopic essence: %d/%d.\n",
@@ -1330,6 +1357,15 @@ ASDCP::JP2K::MXFSWriter::OpenWrite(const std::string& filename, const WriterInfo
       else if ( PDesc.EditRate == ASDCP::EditRate_60 )
        TmpPDesc.EditRate = ASDCP::EditRate_120;
 
+      else if ( PDesc.EditRate == ASDCP::EditRate_96 )
+       TmpPDesc.EditRate = ASDCP::EditRate_192;
+
+      else if ( PDesc.EditRate == ASDCP::EditRate_100 )
+       TmpPDesc.EditRate = ASDCP::EditRate_200;
+
+      else if ( PDesc.EditRate == ASDCP::EditRate_120 )
+       TmpPDesc.EditRate = ASDCP::EditRate_240;
+
       result = m_Writer->SetSourceStream(TmpPDesc, JP2K_S_PACKAGE_LABEL, PDesc.EditRate);
     }
 
index ab400fbcb7cf28f9a05fdb783d4c9a6f3836f93d..f7f9db391a15c125e32282ecbc7246bce56eb126 100755 (executable)
@@ -248,7 +248,7 @@ ASDCP::EssenceType(const std::string& filename, EssenceType_t& type)
            {
              type = ESS_AS02_TIMED_TEXT;
            }
-         else if ( ASDCP_SUCCESS(TestHeader.GetMDObjectByType(OBJ_TYPE_ARGS(DCDataDescriptor))) )
+         else if ( ASDCP_SUCCESS(TestHeader.GetMDObjectByType(OBJ_TYPE_ARGS(IMFDynamicMetadataDescriptor))) )
            {
              type = ESS_DCDATA_UNKNOWN;
            }
index d90581440474498fe2fdf7ee15f375b573e88f98..6cf1d42baa5d7266110f6d81cf35495769d81e73 100755 (executable)
@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2004-2013, John Hurst
+Copyright (c) 2004-2016, John Hurst
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -293,6 +293,9 @@ ASDCP::PCM::MXFReader::h__Reader::OpenRead(const std::string& filename)
        && m_ADesc.EditRate != EditRate_96
        && m_ADesc.EditRate != EditRate_100
        && m_ADesc.EditRate != EditRate_120
+       && m_ADesc.EditRate != EditRate_192
+       && m_ADesc.EditRate != EditRate_200
+       && m_ADesc.EditRate != EditRate_240
        && m_ADesc.EditRate != EditRate_16
        && m_ADesc.EditRate != EditRate_18
        && m_ADesc.EditRate != EditRate_20
@@ -567,6 +570,9 @@ ASDCP::PCM::MXFWriter::h__Writer::SetSourceStream(const AudioDescriptor& ADesc)
        && ADesc.EditRate != EditRate_96
        && ADesc.EditRate != EditRate_100
        && ADesc.EditRate != EditRate_120
+       && ADesc.EditRate != EditRate_192
+       && ADesc.EditRate != EditRate_200
+       && ADesc.EditRate != EditRate_240
        && ADesc.EditRate != EditRate_16
        && ADesc.EditRate != EditRate_18
        && ADesc.EditRate != EditRate_20
index 2d6d0d2d2356b1cbcc1058fd14d4f3839412afdc..d8f3be7af3868268a646e6f7e0cea17a4e2fd999 100644 (file)
@@ -1198,6 +1198,45 @@ static const ASDCP::MDDEntry s_MDD_Table[] = {
       0x0e, 0x09, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00 },
     {0}, false, "PrivateDCDataDescriptor" },
 
+  { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0e, // 384
+      0x01, 0x05, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00 },
+    {0}, false, "MCALabelSubDescriptor_MCATitle" },
+  { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0e, // 385
+      0x01, 0x05, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00 },
+    {0}, false, "MCALabelSubDescriptor_MCATitleVersion" },
+  { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0e, // 386
+      0x01, 0x05, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00 },
+    {0}, false, "MCALabelSubDescriptor_MCATitleSubVersion" },
+  { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0e, // 387
+      0x01, 0x05, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00 },
+    {0}, false, "MCALabelSubDescriptor_MCAEpisode" },
+  { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0e, // 388
+      0x01, 0x04, 0x01, 0x05, 0x00, 0x00, 0x00, 0x00 },
+    {0}, false, "MCALabelSubDescriptor_MCAPartitionKind" },
+  { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0e, // 389
+      0x01, 0x04, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00 },
+    {0}, false, "MCALabelSubDescriptor_MCAPartitionNumber" },
+  { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0e, // 390
+      0x03, 0x02, 0x01, 0x02, 0x20, 0x00, 0x00, 0x00 },
+    {0}, false, "MCALabelSubDescriptor_MCAAudioContentKind" },
+  { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0e, // 391
+      0x03, 0x02, 0x01, 0x02, 0x21, 0x00, 0x00, 0x00 },
+    {0}, false, "MCALabelSubDescriptor_MCAAudioElementKind" },
+  
+  // protype for generic aux data (IMF)
+  { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x05, // 392
+      0x0e, 0x09, 0x06, 0x07, 0x01, 0x01, 0x10, 0x00 },
+    {0}, false, "IMFDynamicMetadataWrappingFrame" },
+  { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x02, 0x01, 0x05, // 393
+      0x0e, 0x09, 0x06, 0x07, 0x01, 0x01, 0x11, 0x00 },
+    {0}, false, "IMFDynamicMetadataEssence" },
+  { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x05, // 394
+      0x0e, 0x09, 0x06, 0x07, 0x01, 0x01, 0x12, 0x00 },
+    {0}, false, "IMFDynamicMetadataDescriptor" },
+  { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 395
+      0x0e, 0x09, 0x06, 0x07, 0x01, 0x01, 0x13, 0x00 },
+    {0}, false, "IMFDynamicMetadataDescriptor_GlobalPayloadSID" },
+
   { {0}, {0}, false, 0 }
 };
 
index cef2db32681a392d5cfa9cb9858d83148aa1a33e..7240ba29fdbfc5d6ec625cf9fbef4de9e6bdbcab 100755 (executable)
--- a/src/MDD.h
+++ b/src/MDD.h
@@ -419,6 +419,20 @@ namespace ASDCP {
        MDD_PrivateDCDataWrappingFrame, // 381
        MDD_PrivateDCDataEssence,  // 382
        MDD_PrivateDCDataDescriptor, // 383
+
+       MDD_MCALabelSubDescriptor_MCATitle, // 384
+       MDD_MCALabelSubDescriptor_MCATitleVersion, // 385
+       MDD_MCALabelSubDescriptor_MCATitleSubVersion, // 386
+       MDD_MCALabelSubDescriptor_MCAEpisode, // 387
+       MDD_MCALabelSubDescriptor_MCAPartitionKind, // 388
+       MDD_MCALabelSubDescriptor_MCAPartitionNumber, // 389
+       MDD_MCALabelSubDescriptor_MCAAudioContentKind, // 390
+       MDD_MCALabelSubDescriptor_MCAAudioElementKind, // 391
+
+       MDD_IMFDynamicMetadataWrappingFrame, // 392
+       MDD_IMFDynamicMetadataEssence, // 393
+       MDD_IMFDynamicMetadataDescriptor, // 394
+       MDD_IMFDynamicMetadataDescriptor_GlobalPayloadSID, // 395
         MDD_Max
     }; // enum MDD_t
 
index 3bfa03d067dcc202514ee48f113d057c5217e5e1..48dbf3f928bec243b01917a29963d218a8977abc 100755 (executable)
@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2005-2015, John Hurst
+Copyright (c) 2005-2016, John Hurst
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -352,6 +352,61 @@ namespace ASDCP
          }
        };
 
+      //
+      class LineMapPair : public Kumu::IArchive
+       {
+       public:
+         ui32_t First;
+         ui32_t Second;
+
+         LineMapPair() {}
+         ~LineMapPair() {}
+
+       LineMapPair(const ui32_t& first, const ui32_t& second) : IArchive() {
+           First = first;
+           Second = second;
+         }
+
+         LineMapPair(const LineMapPair& rhs) : IArchive() {
+           First = rhs.First;
+           Second = rhs.Second;
+         }
+
+         const LineMapPair& operator=(const LineMapPair& rhs) {
+           First = rhs.First;
+           Second = rhs.Second;
+           return *this;
+         }
+
+         //
+         inline const char* EncodeString(char* str_buf, ui32_t buf_len) const {
+           snprintf(str_buf, buf_len, "%d,%d", First, Second);
+           return str_buf;
+         }
+
+         inline virtual bool Unarchive(Kumu::MemIOReader* Reader) {
+           ui32_t n;
+           if ( ! Reader->ReadUi32BE(&n) ) return false;
+           if ( n != 4 ) return false;
+           if ( ! Reader->ReadUi32BE(&n) ) return false;
+           if ( n != 2 ) return false;
+           if ( ! Reader->ReadUi32BE((ui32_t*)&First) ) return false;
+           if ( ! Reader->ReadUi32BE((ui32_t*)&Second) ) return false;
+           return true;
+         }
+
+         inline virtual bool HasValue() const { return true; }
+         inline virtual ui32_t ArchiveLength() const { return sizeof(ui32_t)*4; }
+
+         inline virtual bool Archive(Kumu::MemIOWriter* Writer) const {
+           if ( ! Writer->WriteUi32BE(4UL) ) return false;
+           if ( ! Writer->WriteUi32BE(2UL) ) return false;
+           if ( ! Writer->WriteUi32BE((ui32_t)First) ) return false;
+           if ( ! Writer->WriteUi32BE((ui32_t)Second) ) return false;
+           return true;
+         }
+       };
+
       //
       class VersionType : public Kumu::IArchive
        {
index 72136d7a5175b56a66641a9d0a6bc21eee425b7f..8662cfd8d5c5a91dcfd67270620525f5979f1e62 100755 (executable)
@@ -78,6 +78,7 @@ static InterchangeObject* DCDataDescriptor_Factory(const Dictionary*& Dict) { re
 static InterchangeObject* PrivateDCDataDescriptor_Factory(const Dictionary*& Dict) { return new PrivateDCDataDescriptor(Dict); }
 static InterchangeObject* DolbyAtmosSubDescriptor_Factory(const Dictionary*& Dict) { return new DolbyAtmosSubDescriptor(Dict); }
 static InterchangeObject* PHDRMetadataTrackSubDescriptor_Factory(const Dictionary*& Dict) { return new PHDRMetadataTrackSubDescriptor(Dict); }
+static InterchangeObject* IMFDynamicMetadataDescriptor_Factory(const Dictionary*& Dict) { return new IMFDynamicMetadataDescriptor(Dict); }
 
 
 void
@@ -122,6 +123,7 @@ ASDCP::MXF::Metadata_InitTypes(const Dictionary*& Dict)
   SetObjectFactory(Dict->ul(MDD_PrivateDCDataDescriptor), PrivateDCDataDescriptor_Factory);
   SetObjectFactory(Dict->ul(MDD_DolbyAtmosSubDescriptor), DolbyAtmosSubDescriptor_Factory);
   SetObjectFactory(Dict->ul(MDD_PHDRMetadataTrackSubDescriptor), PHDRMetadataTrackSubDescriptor_Factory);
+  SetObjectFactory(Dict->ul(MDD_IMFDynamicMetadataDescriptor), IMFDynamicMetadataDescriptor_Factory);
 }
 
 //------------------------------------------------------------------------------------------
@@ -1704,6 +1706,10 @@ GenericPictureEssenceDescriptor::InitFromTLVSet(TLVReader& TLVSet)
     result = TLVSet.ReadUi32(OBJ_READ_ARGS_OPT(GenericPictureEssenceDescriptor, ActiveYOffset));
     ActiveYOffset.set_has_value( result == RESULT_OK );
   }
+  if ( ASDCP_SUCCESS(result) ) {
+    result = TLVSet.ReadObject(OBJ_READ_ARGS_OPT(GenericPictureEssenceDescriptor, VideoLineMap));
+    VideoLineMap.set_has_value( result == RESULT_OK );
+  }
   return result;
 }
 
@@ -1743,6 +1749,7 @@ GenericPictureEssenceDescriptor::WriteToTLVSet(TLVWriter& TLVSet)
   if ( ASDCP_SUCCESS(result)  && ! ActiveHeight.empty() ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS_OPT(GenericPictureEssenceDescriptor, ActiveHeight));
   if ( ASDCP_SUCCESS(result)  && ! ActiveXOffset.empty() ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS_OPT(GenericPictureEssenceDescriptor, ActiveXOffset));
   if ( ASDCP_SUCCESS(result)  && ! ActiveYOffset.empty() ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS_OPT(GenericPictureEssenceDescriptor, ActiveYOffset));
+  if ( ASDCP_SUCCESS(result)  && ! VideoLineMap.empty() ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS_OPT(GenericPictureEssenceDescriptor, VideoLineMap));
   return result;
 }
 
@@ -1781,6 +1788,7 @@ GenericPictureEssenceDescriptor::Copy(const GenericPictureEssenceDescriptor& rhs
   ActiveHeight = rhs.ActiveHeight;
   ActiveXOffset = rhs.ActiveXOffset;
   ActiveYOffset = rhs.ActiveYOffset;
+  VideoLineMap = rhs.VideoLineMap;
 }
 
 //
@@ -1875,6 +1883,9 @@ GenericPictureEssenceDescriptor::Dump(FILE* stream)
   if ( ! ActiveYOffset.empty() ) {
     fprintf(stream, "  %22s = %d\n",  "ActiveYOffset", ActiveYOffset.get());
   }
+  if ( ! VideoLineMap.empty() ) {
+    fprintf(stream, "  %22s = %s\n",  "VideoLineMap", VideoLineMap.get().EncodeString(identbuf, IdentBufferLen));
+  }
 }
 
 //
@@ -3230,6 +3241,38 @@ MCALabelSubDescriptor::InitFromTLVSet(TLVReader& TLVSet)
     result = TLVSet.ReadObject(OBJ_READ_ARGS_OPT(MCALabelSubDescriptor, RFC5646SpokenLanguage));
     RFC5646SpokenLanguage.set_has_value( result == RESULT_OK );
   }
+  if ( ASDCP_SUCCESS(result) ) {
+    result = TLVSet.ReadObject(OBJ_READ_ARGS_OPT(MCALabelSubDescriptor, MCATitle));
+    MCATitle.set_has_value( result == RESULT_OK );
+  }
+  if ( ASDCP_SUCCESS(result) ) {
+    result = TLVSet.ReadObject(OBJ_READ_ARGS_OPT(MCALabelSubDescriptor, MCATitleVersion));
+    MCATitleVersion.set_has_value( result == RESULT_OK );
+  }
+  if ( ASDCP_SUCCESS(result) ) {
+    result = TLVSet.ReadObject(OBJ_READ_ARGS_OPT(MCALabelSubDescriptor, MCATitleSubVersion));
+    MCATitleSubVersion.set_has_value( result == RESULT_OK );
+  }
+  if ( ASDCP_SUCCESS(result) ) {
+    result = TLVSet.ReadObject(OBJ_READ_ARGS_OPT(MCALabelSubDescriptor, MCAEpisode));
+    MCAEpisode.set_has_value( result == RESULT_OK );
+  }
+  if ( ASDCP_SUCCESS(result) ) {
+    result = TLVSet.ReadObject(OBJ_READ_ARGS_OPT(MCALabelSubDescriptor, MCAPartitionKind));
+    MCAPartitionKind.set_has_value( result == RESULT_OK );
+  }
+  if ( ASDCP_SUCCESS(result) ) {
+    result = TLVSet.ReadObject(OBJ_READ_ARGS_OPT(MCALabelSubDescriptor, MCAPartitionNumber));
+    MCAPartitionNumber.set_has_value( result == RESULT_OK );
+  }
+  if ( ASDCP_SUCCESS(result) ) {
+    result = TLVSet.ReadObject(OBJ_READ_ARGS_OPT(MCALabelSubDescriptor, MCAAudioContentKind));
+    MCAAudioContentKind.set_has_value( result == RESULT_OK );
+  }
+  if ( ASDCP_SUCCESS(result) ) {
+    result = TLVSet.ReadObject(OBJ_READ_ARGS_OPT(MCALabelSubDescriptor, MCAAudioElementKind));
+    MCAAudioElementKind.set_has_value( result == RESULT_OK );
+  }
   return result;
 }
 
@@ -3245,6 +3288,14 @@ MCALabelSubDescriptor::WriteToTLVSet(TLVWriter& TLVSet)
   if ( ASDCP_SUCCESS(result)  && ! MCATagName.empty() ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS_OPT(MCALabelSubDescriptor, MCATagName));
   if ( ASDCP_SUCCESS(result)  && ! MCAChannelID.empty() ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS_OPT(MCALabelSubDescriptor, MCAChannelID));
   if ( ASDCP_SUCCESS(result)  && ! RFC5646SpokenLanguage.empty() ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS_OPT(MCALabelSubDescriptor, RFC5646SpokenLanguage));
+  if ( ASDCP_SUCCESS(result)  && ! MCATitle.empty() ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS_OPT(MCALabelSubDescriptor, MCATitle));
+  if ( ASDCP_SUCCESS(result)  && ! MCATitleVersion.empty() ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS_OPT(MCALabelSubDescriptor, MCATitleVersion));
+  if ( ASDCP_SUCCESS(result)  && ! MCATitleSubVersion.empty() ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS_OPT(MCALabelSubDescriptor, MCATitleSubVersion));
+  if ( ASDCP_SUCCESS(result)  && ! MCAEpisode.empty() ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS_OPT(MCALabelSubDescriptor, MCAEpisode));
+  if ( ASDCP_SUCCESS(result)  && ! MCAPartitionKind.empty() ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS_OPT(MCALabelSubDescriptor, MCAPartitionKind));
+  if ( ASDCP_SUCCESS(result)  && ! MCAPartitionNumber.empty() ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS_OPT(MCALabelSubDescriptor, MCAPartitionNumber));
+  if ( ASDCP_SUCCESS(result)  && ! MCAAudioContentKind.empty() ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS_OPT(MCALabelSubDescriptor, MCAAudioContentKind));
+  if ( ASDCP_SUCCESS(result)  && ! MCAAudioElementKind.empty() ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS_OPT(MCALabelSubDescriptor, MCAAudioElementKind));
   return result;
 }
 
@@ -3259,6 +3310,14 @@ MCALabelSubDescriptor::Copy(const MCALabelSubDescriptor& rhs)
   MCATagName = rhs.MCATagName;
   MCAChannelID = rhs.MCAChannelID;
   RFC5646SpokenLanguage = rhs.RFC5646SpokenLanguage;
+  MCATitle = rhs.MCATitle;
+  MCATitleVersion = rhs.MCATitleVersion;
+  MCATitleSubVersion = rhs.MCATitleSubVersion;
+  MCAEpisode = rhs.MCAEpisode;
+  MCAPartitionKind = rhs.MCAPartitionKind;
+  MCAPartitionNumber = rhs.MCAPartitionNumber;
+  MCAAudioContentKind = rhs.MCAAudioContentKind;
+  MCAAudioElementKind = rhs.MCAAudioElementKind;
 }
 
 //
@@ -3284,6 +3343,30 @@ MCALabelSubDescriptor::Dump(FILE* stream)
   if ( ! RFC5646SpokenLanguage.empty() ) {
     fprintf(stream, "  %22s = %s\n",  "RFC5646SpokenLanguage", RFC5646SpokenLanguage.get().EncodeString(identbuf, IdentBufferLen));
   }
+  if ( ! MCATitle.empty() ) {
+    fprintf(stream, "  %22s = %s\n",  "MCATitle", MCATitle.get().EncodeString(identbuf, IdentBufferLen));
+  }
+  if ( ! MCATitleVersion.empty() ) {
+    fprintf(stream, "  %22s = %s\n",  "MCATitleVersion", MCATitleVersion.get().EncodeString(identbuf, IdentBufferLen));
+  }
+  if ( ! MCATitleSubVersion.empty() ) {
+    fprintf(stream, "  %22s = %s\n",  "MCATitleSubVersion", MCATitleSubVersion.get().EncodeString(identbuf, IdentBufferLen));
+  }
+  if ( ! MCAEpisode.empty() ) {
+    fprintf(stream, "  %22s = %s\n",  "MCAEpisode", MCAEpisode.get().EncodeString(identbuf, IdentBufferLen));
+  }
+  if ( ! MCAPartitionKind.empty() ) {
+    fprintf(stream, "  %22s = %s\n",  "MCAPartitionKind", MCAPartitionKind.get().EncodeString(identbuf, IdentBufferLen));
+  }
+  if ( ! MCAPartitionNumber.empty() ) {
+    fprintf(stream, "  %22s = %s\n",  "MCAPartitionNumber", MCAPartitionNumber.get().EncodeString(identbuf, IdentBufferLen));
+  }
+  if ( ! MCAAudioContentKind.empty() ) {
+    fprintf(stream, "  %22s = %s\n",  "MCAAudioContentKind", MCAAudioContentKind.get().EncodeString(identbuf, IdentBufferLen));
+  }
+  if ( ! MCAAudioElementKind.empty() ) {
+    fprintf(stream, "  %22s = %s\n",  "MCAAudioElementKind", MCAAudioElementKind.get().EncodeString(identbuf, IdentBufferLen));
+  }
 }
 
 //
@@ -3847,6 +3930,81 @@ PHDRMetadataTrackSubDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
   return InterchangeObject::WriteToBuffer(Buffer);
 }
 
+//------------------------------------------------------------------------------------------
+// IMFDynamicMetadataDescriptor
+
+//
+
+IMFDynamicMetadataDescriptor::IMFDynamicMetadataDescriptor(const Dictionary*& d) : GenericDataEssenceDescriptor(d), m_Dict(d), GlobalPayloadSID(0)
+{
+  assert(m_Dict);
+  m_UL = m_Dict->ul(MDD_IMFDynamicMetadataDescriptor);
+}
+
+IMFDynamicMetadataDescriptor::IMFDynamicMetadataDescriptor(const IMFDynamicMetadataDescriptor& rhs) : GenericDataEssenceDescriptor(rhs.m_Dict), m_Dict(rhs.m_Dict)
+{
+  assert(m_Dict);
+  m_UL = m_Dict->ul(MDD_IMFDynamicMetadataDescriptor);
+  Copy(rhs);
+}
+
+
+//
+ASDCP::Result_t
+IMFDynamicMetadataDescriptor::InitFromTLVSet(TLVReader& TLVSet)
+{
+  assert(m_Dict);
+  Result_t result = GenericDataEssenceDescriptor::InitFromTLVSet(TLVSet);
+  if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(IMFDynamicMetadataDescriptor, GlobalPayloadSID));
+  return result;
+}
+
+//
+ASDCP::Result_t
+IMFDynamicMetadataDescriptor::WriteToTLVSet(TLVWriter& TLVSet)
+{
+  assert(m_Dict);
+  Result_t result = GenericDataEssenceDescriptor::WriteToTLVSet(TLVSet);
+  if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(IMFDynamicMetadataDescriptor, GlobalPayloadSID));
+  return result;
+}
+
+//
+void
+IMFDynamicMetadataDescriptor::Copy(const IMFDynamicMetadataDescriptor& rhs)
+{
+  GenericDataEssenceDescriptor::Copy(rhs);
+  GlobalPayloadSID = rhs.GlobalPayloadSID;
+}
+
+//
+void
+IMFDynamicMetadataDescriptor::Dump(FILE* stream)
+{
+  char identbuf[IdentBufferLen];
+  *identbuf = 0;
+
+  if ( stream == 0 )
+    stream = stderr;
+
+  GenericDataEssenceDescriptor::Dump(stream);
+  fprintf(stream, "  %22s = %d\n",  "GlobalPayloadSID", GlobalPayloadSID);
+}
+
+//
+ASDCP::Result_t
+IMFDynamicMetadataDescriptor::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+  return InterchangeObject::InitFromBuffer(p, l);
+}
+
+//
+ASDCP::Result_t
+IMFDynamicMetadataDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+  return InterchangeObject::WriteToBuffer(Buffer);
+}
+
 //
 // end Metadata.cpp
 //
index e71ddf24e656e3bbc5541ae296ebb6110e1df7c4..e5133e8f8dec9fe26e80e1db45e9b084b5c5d081 100755 (executable)
@@ -502,6 +502,7 @@ namespace ASDCP
           optional_property<ui32_t > ActiveHeight;
           optional_property<ui32_t > ActiveXOffset;
           optional_property<ui32_t > ActiveYOffset;
+          optional_property<LineMapPair > VideoLineMap;
 
       GenericPictureEssenceDescriptor(const Dictionary*& d);
       GenericPictureEssenceDescriptor(const GenericPictureEssenceDescriptor& rhs);
@@ -875,6 +876,14 @@ namespace ASDCP
           optional_property<UTF16String > MCATagName;
           optional_property<ui32_t > MCAChannelID;
           optional_property<ISO8String > RFC5646SpokenLanguage;
+          optional_property<UTF16String > MCATitle;
+          optional_property<UTF16String > MCATitleVersion;
+          optional_property<UTF16String > MCATitleSubVersion;
+          optional_property<UTF16String > MCAEpisode;
+          optional_property<UTF16String > MCAPartitionKind;
+          optional_property<UTF16String > MCAPartitionNumber;
+          optional_property<UTF16String > MCAAudioContentKind;
+          optional_property<UTF16String > MCAAudioElementKind;
 
       MCALabelSubDescriptor(const Dictionary*& d);
       MCALabelSubDescriptor(const MCALabelSubDescriptor& rhs);
@@ -1054,6 +1063,29 @@ namespace ASDCP
       virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
        };
 
+      //
+      class IMFDynamicMetadataDescriptor : public GenericDataEssenceDescriptor
+       {
+         IMFDynamicMetadataDescriptor();
+
+       public:
+         const Dictionary*& m_Dict;
+          ui32_t GlobalPayloadSID;
+
+      IMFDynamicMetadataDescriptor(const Dictionary*& d);
+      IMFDynamicMetadataDescriptor(const IMFDynamicMetadataDescriptor& rhs);
+      virtual ~IMFDynamicMetadataDescriptor() {}
+
+      const IMFDynamicMetadataDescriptor& operator=(const IMFDynamicMetadataDescriptor& rhs) { Copy(rhs); return *this; }
+      virtual void Copy(const IMFDynamicMetadataDescriptor& rhs);
+      virtual const char* HasName() { return "IMFDynamicMetadataDescriptor"; }
+      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&);
+       };
+
     } // namespace MXF
 } // namespace ASDCP
 
index 5aeacf17139253a685d0ac56b1702c6e6b8b14b5..22d37bb507d6cab0669f3b0488733071fdc87c38 100644 (file)
@@ -249,7 +249,10 @@ ASDCP::TimedText::DCSubtitleParser::h__SubtitleParser::OpenRead()
        && m_TDesc.EditRate != EditRate_60
        && m_TDesc.EditRate != EditRate_96
        && m_TDesc.EditRate != EditRate_100
-       && m_TDesc.EditRate != EditRate_120 )
+       && m_TDesc.EditRate != EditRate_120
+       && m_TDesc.EditRate != EditRate_192
+       && m_TDesc.EditRate != EditRate_200
+       && m_TDesc.EditRate != EditRate_240 )
     {
       DefaultLogSink(). Error("Unexpected EditRate: %d/%d\n",
                              m_TDesc.EditRate.Numerator, m_TDesc.EditRate.Denominator);
index 1f400508194bf9b210411a3def20de1a9f4a890f..3c100b9a1e4abceaba47f24304ca15d4bb9979a1 100755 (executable)
@@ -99,6 +99,7 @@ Options:\n\
   -d <duration>     - Number of frames to process, default all\n\
   -e <extension>    - Extension to use for aux data files. default \"bin\"\n\
   -f <start-frame>  - Starting frame number, default 0\n\
+  -g <filename>     - Extract global metadata to the named file.\n\
   -h | -help        - Show help\n\
   -k <key-string>   - Use key for ciphertext operations\n\
   -m                - verify HMAC values when reading\n\
@@ -146,7 +147,7 @@ public:
   PCM::ChannelFormat_t channel_fmt; // audio channel arrangement
   const char* input_filename;
   const char* extension;
-  std::string prefix_buffer;
+  std::string global_metadata_filename, prefix_buffer;
 
   //
   CommandOptions(int argc, const char** argv) :
@@ -203,6 +204,11 @@ public:
                start_frame = Kumu::xabs(strtol(argv[i], 0, 10));
                break;
 
+             case 'g':
+               TEST_EXTRA_ARG(i, 'g');
+               global_metadata_filename = argv[i];
+               break;
+
              case 'h': help_flag = true; break;
              case 'm': read_hmac = true; break;
 
@@ -586,6 +592,87 @@ read_PCM_file(CommandOptions& Options)
 }
 
 
+//------------------------------------------------------------------------------------------
+// TimedText essence
+
+// Read one or more timed text streams from a plaintext AS-02 file
+//
+Result_t
+read_timed_text_file(CommandOptions& Options)
+{
+  AESDecContext*     Context = 0;
+  HMACContext*       HMAC = 0;
+  AS_02::TimedText::MXFReader     Reader;
+  TimedText::FrameBuffer   FrameBuffer(Options.fb_size);
+  //ASDCP::TimedText::FrameBuffer   FrameBuffer(Options.fb_size);
+  AS_02::TimedText::TimedTextDescriptor TDesc;
+  ASDCP::MXF::TimedTextDescriptor *tt_descriptor = 0;
+
+  Result_t result = Reader.OpenRead(Options.input_filename);
+
+  if ( ASDCP_SUCCESS(result) )
+    {
+      result = Reader.OP1aHeader().GetMDObjectByType(DefaultCompositeDict().ul(MDD_TimedTextDescriptor),
+                                                    reinterpret_cast<MXF::InterchangeObject**>(&tt_descriptor));
+    if ( Options.verbose_flag ) {
+       tt_descriptor->Dump();
+    }
+
+
+  if ( ASDCP_FAILURE(result) )
+    return result;
+
+  std::string XMLDoc;
+  std::string out_path = Kumu::PathDirname(Options.file_prefix);
+  ui32_t write_count;
+  char buf[64];
+  TimedText::ResourceList_t::const_iterator ri;
+
+  result = Reader.ReadTimedTextResource(XMLDoc);
+
+  if ( ASDCP_SUCCESS(result) )
+    {
+      Reader.FillTimedTextDescriptor(TDesc);
+      FrameBuffer.Capacity(Options.fb_size);
+
+      if ( Options.verbose_flag )
+       TimedText::DescriptorDump(TDesc);
+    }
+
+  if ( ASDCP_SUCCESS(result) && ( ! Options.no_write_flag ) )
+    {
+      Kumu::FileWriter Writer;
+      result = Writer.OpenWrite(Options.file_prefix);
+
+      if ( ASDCP_SUCCESS(result) )
+       result = Writer.Write(reinterpret_cast<const byte_t*>(XMLDoc.c_str()), XMLDoc.size(), &write_count);
+    }
+
+  for ( ri = TDesc.ResourceList.begin() ; ri != TDesc.ResourceList.end() && ASDCP_SUCCESS(result); ri++ )
+    {
+      result = Reader.ReadAncillaryResource(ri->ResourceID, FrameBuffer, Context, HMAC);
+
+      if ( ASDCP_SUCCESS(result) && ( ! Options.no_write_flag ) )
+       {
+         Kumu::FileWriter Writer;
+         if (out_path != "") {
+                 result = Writer.OpenWrite(Kumu::PathJoin(out_path, Kumu::UUID(ri->ResourceID).EncodeHex(buf, 64)).c_str());
+         } else {
+                 // Workaround for a bug in Kumu::PathJoin
+                 result = Writer.OpenWrite(Kumu::UUID(ri->ResourceID).EncodeHex(buf, 64));
+         }
+
+         if ( ASDCP_SUCCESS(result) )
+           result = Writer.Write(FrameBuffer.RoData(), FrameBuffer.Size(), &write_count);
+
+             if ( Options.verbose_flag )
+               FrameBuffer.Dump(stderr, Options.fb_dump_size);
+       }
+    }
+    }
+  return result;
+}
+
 // Read one or more plaintext DCData bytestreams from a plaintext ASDCP file
 // Read one or more plaintext DCData bytestreams from a ciphertext ASDCP file
 // Read one or more ciphertext DCData byestreams from a ciphertext ASDCP file
@@ -599,7 +686,28 @@ read_aux_data_file(CommandOptions& Options)
   DCData::FrameBuffer FrameBuffer(Options.fb_size);
   ui32_t             frame_count = 0;
 
-  Result_t result = Reader.OpenRead(Options.input_filename);
+  ASDCP::FrameBuffer global_metadata;
+  Result_t result = Reader.OpenRead(Options.input_filename, global_metadata);
+
+  if ( ASDCP_SUCCESS(result)
+       && global_metadata.Size()
+       && ! Options.global_metadata_filename.empty() )
+    {
+      ui32_t write_count = 0;
+      Kumu::FileWriter Writer;
+
+      result = Writer.OpenWrite(Options.global_metadata_filename);
+
+      if ( ASDCP_SUCCESS(result) )
+       {
+         result = Writer.Write(global_metadata.RoData(), global_metadata.Size(), &write_count);
+       }
+
+      if ( ASDCP_SUCCESS(result) && global_metadata.Size() != write_count) 
+       {
+         return RESULT_WRITEFAIL;
+       }
+    }
 
   if ( ASDCP_SUCCESS(result) )
     {
@@ -705,6 +813,10 @@ main(int argc, const char** argv)
          result = read_PCM_file(Options);
          break;
 
+       case ESS_AS02_TIMED_TEXT:
+         result = read_timed_text_file(Options);
+         break;
+
         case ESS_DCDATA_UNKNOWN:
           result = read_aux_data_file(Options);
           break;
index 2e33a990fc5abc211e7552a9694305f0989066da..794f2be893e7cd9a91eac45f523f295536450cdf 100755 (executable)
@@ -141,9 +141,13 @@ Options:\n\
   -e                - Encrypt JP2K headers (default)\n\
   -E                - Do not encrypt JP2K headers\n\
   -F (0|1)          - Set field dominance for interlaced image (default: 0)\n\
+  -g <filename>     - Write global metadata from the named file.\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\
+  -l <first>,<second>\n\
+                    - Integer values that set the VideoLineMap when creating\n\
+                      interlaced YCbCr files\n\
   -M                - Do not create HMAC values when writing\n\
   -m <expr>         - Write MCA labels using <expr>.  Example:\n\
                         51(L,R,C,LFE,Ls,Rs,),HI,VIN\n\
@@ -199,7 +203,7 @@ public:
   bool   key_id_flag;    // true if a key ID was given
   byte_t key_id_value[UUIDlen];// value of given key ID (when key_id_flag is true)
   byte_t asset_id_value[UUIDlen];// value of asset ID (when asset_id_flag is true)
-  std::string out_file; //
+  std::string global_metadata_filename, out_file; //
   bool show_ul_values_flag;    /// if true, dump the UL table before going tp work.
   Kumu::PathList_t filenames;  // list of filenames to be processed
 
@@ -227,6 +231,23 @@ public:
 
   //
   UL aux_data_coding;
+  MXF::LineMapPair line_map;
+
+  //
+  bool set_video_line_map(const std::string& arg)
+  {
+    const char* sep_str = strrchr(arg.c_str(), ',');
+
+    if ( sep_str == 0 )
+      {
+       fprintf(stderr, "Expecting <first>,<second>\n");
+       return false;
+      }
+
+    line_map.First = Kumu::xabs(strtol(arg.c_str(), 0, 10));
+    line_map.Second = Kumu::xabs(strtol(sep_str+1, 0, 10));
+    return true;
+  }
 
   //
   bool set_video_ref(const std::string& arg)
@@ -269,7 +290,8 @@ public:
     mca_config(g_dict), rgba_MaxRef(1023), rgba_MinRef(0),
     horizontal_subsampling(2), vertical_subsampling(2), component_depth(10),
     frame_layout(0), aspect_ratio(ASDCP::Rational(4,3)), field_dominance(0),
-    mxf_header_size(16384), cdci_WhiteRefLevel(940), cdci_BlackRefLevel(64), cdci_ColorRange(897)
+    mxf_header_size(16384), cdci_WhiteRefLevel(940), cdci_BlackRefLevel(64), cdci_ColorRange(897),
+    line_map(0,0)
   {
     memset(key_value, 0, KeyLen);
     memset(key_id_value, 0, UUIDlen);
@@ -353,6 +375,11 @@ public:
                  }
                break;
 
+             case 'g':
+               TEST_EXTRA_ARG(i, 'g');
+               global_metadata_filename = argv[i];
+               break;
+
              case 'h': help_flag = true; break;
 
              case 'i':
@@ -389,6 +416,14 @@ public:
                }
                break;
 
+             case 'l':
+               TEST_EXTRA_ARG(i, 'y');
+               if ( ! set_video_line_map(argv[i]) )
+                 {
+                   return;
+                 }
+               break;
+
              case 'M': write_hmac = false; break;
 
              case 'm':
@@ -589,6 +624,7 @@ write_JP2K_file(CommandOptions& Options)
              tmp_dscr->WhiteReflevel = Options.cdci_WhiteRefLevel;
              tmp_dscr->BlackRefLevel = Options.cdci_BlackRefLevel;
              tmp_dscr->ColorRange = Options.cdci_ColorRange;
+             tmp_dscr->VideoLineMap = Options.line_map;
              essence_descriptor = static_cast<ASDCP::MXF::FileDescriptor*>(tmp_dscr);
            }
        }
@@ -987,6 +1023,15 @@ write_aux_data_file(CommandOptions& Options)
   byte_t                  IV_buf[CBC_BLOCK_SIZE];
   Kumu::FortunaRNG        RNG;
 
+  if ( ! Options.global_metadata_filename.empty() )
+    {
+      if ( ! Kumu::PathIsFile(Options.global_metadata_filename) )
+       {
+         fprintf(stderr, "No such file or filename: \"%s\".\n", Options.global_metadata_filename.c_str());
+         return RESULT_PARAM;
+       }
+    }
+
   // set up essence parser
   Result_t result = Parser.OpenRead(Options.filenames.front());
 
@@ -1042,14 +1087,7 @@ write_aux_data_file(CommandOptions& Options)
 
     if ( ASDCP_SUCCESS(result) )
       {
-       ASDCP::MXF::InterchangeObject_list_t essence_sub_descriptor_list; // empty for now
-       ASDCP::MXF::DCDataDescriptor *essence_descriptor = new ASDCP::MXF::DCDataDescriptor(g_dict);
-       essence_descriptor->SampleRate = Options.edit_rate;
-       essence_descriptor->ContainerDuration = 0;
-       essence_descriptor->DataEssenceCoding = Options.aux_data_coding;
-       
-       result = Writer.OpenWrite(Options.out_file, Info, essence_descriptor,
-                                 essence_sub_descriptor_list, Options.edit_rate);
+       result = Writer.OpenWrite(Options.out_file, Info, Options.aux_data_coding, Options.edit_rate);
       }
   }
 
@@ -1089,7 +1127,39 @@ write_aux_data_file(CommandOptions& Options)
   }
 
   if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
-    result = Writer.Finalize();
+    {
+      if ( Options.global_metadata_filename.empty() )
+       {
+         result = Writer.Finalize();
+       }
+      else
+       {
+         ASDCP::FrameBuffer global_metadata;
+         ui32_t file_size = Kumu::FileSize(Options.global_metadata_filename);
+         result = global_metadata.Capacity(file_size);
+
+         if ( ASDCP_SUCCESS(result) )
+           {
+             ui32_t read_count = 0;
+             Kumu::FileReader Reader;
+
+             result = Reader.OpenRead(Options.global_metadata_filename);
+
+             if ( ASDCP_SUCCESS(result) )
+               result = Reader.Read(global_metadata.Data(), file_size, &read_count);
+    
+             if ( ASDCP_SUCCESS(result) )
+               {
+                 if ( file_size != read_count) 
+                   return RESULT_READFAIL;
+
+                 global_metadata.Size(read_count);
+               }
+           }
+  
+         result = Writer.Finalize(global_metadata);
+       }
+    }
 
   return result;
 }
index 1b491b05a96327c8c5a542b10dcbf8afa6958281..df108c3974ce221cec0fe107ad7ee9102749d251 100755 (executable)
@@ -306,6 +306,9 @@ public:
     if ( picture_rate == 96 ) return EditRate_96;
     if ( picture_rate == 100 ) return EditRate_100;
     if ( picture_rate == 120 ) return EditRate_120;
+    if ( picture_rate == 192 ) return EditRate_192;
+    if ( picture_rate == 200 ) return EditRate_200;
+    if ( picture_rate == 240 ) return EditRate_240;
     return EditRate_24;
   }
 
@@ -326,6 +329,9 @@ public:
     if ( picture_rate == 96 ) return "96";
     if ( picture_rate == 100 ) return "100";
     if ( picture_rate == 120 ) return "120";
+    if ( picture_rate == 192 ) return "192";
+    if ( picture_rate == 200 ) return "200";
+    if ( picture_rate == 240 ) return "240";
     return "24";
   }
 
index 3a8bdd0d680093e7ec2ab9a6636bc1cb2a092b6f..a24219f0d7fb50119003e964d13766b8a0eaca53 100755 (executable)
@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2003-2014, John Hurst
+Copyright (c) 2003-2016, John Hurst
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -98,7 +98,7 @@ Options:\n\
   -h | -help        - Show help\n\
   -k <key-string>   - Use key for ciphertext operations\n\
   -m                - verify HMAC values when reading\n\
-  -p <rate>         - fps of picture when wrapping PCM or JP2K:\n\
+  -p <rate>         - Alternative picture rate when unwrapping PCM:\n\
                       Use one of [23|24|25|30|48|50|60], 24 is default\n\
   -s <size>         - Number of bytes to dump to output when -v is given\n\
   -V                - Show version information\n\
@@ -173,6 +173,9 @@ public:
     if ( picture_rate == 96 ) return EditRate_96;
     if ( picture_rate == 100 ) return EditRate_100;
     if ( picture_rate == 120 ) return EditRate_120;
+    if ( picture_rate == 192 ) return EditRate_192;
+    if ( picture_rate == 200 ) return EditRate_200;
+    if ( picture_rate == 240 ) return EditRate_240;
     return EditRate_24;
   }
 
index e8bf2f1960db5b5e888099c1f532e7e3ab5c889e..4312cc785fc482423845ccd17320165d80bfac55 100755 (executable)
@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2003-2015, John Hurst
+Copyright (c) 2003-2016, John Hurst
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -266,6 +266,9 @@ public:
     if ( picture_rate == 96 ) return EditRate_96;
     if ( picture_rate == 100 ) return EditRate_100;
     if ( picture_rate == 120 ) return EditRate_120;
+    if ( picture_rate == 192 ) return EditRate_192;
+    if ( picture_rate == 200 ) return EditRate_200;
+    if ( picture_rate == 240 ) return EditRate_240;
     return EditRate_24;
   }
 
@@ -286,6 +289,9 @@ public:
     if ( picture_rate == 96 ) return "96";
     if ( picture_rate == 100 ) return "100";
     if ( picture_rate == 120 ) return "120";
+    if ( picture_rate == 192 ) return "192";
+    if ( picture_rate == 200 ) return "200";
+    if ( picture_rate == 240 ) return "240";
     return "24";
   }
 
@@ -617,7 +623,8 @@ bool
 check_phfr_params(CommandOptions& Options, JP2K::PictureDescriptor& PDesc)
 {
   Rational rate = Options.PictureRate();
-  if ( rate != EditRate_96 && rate != EditRate_100 && rate != EditRate_120 )
+  if ( rate != EditRate_96 && rate != EditRate_100 && rate != EditRate_120
+       && rate != EditRate_192 && rate != EditRate_200 && rate != EditRate_240 )
     return true;
 
   if ( PDesc.StoredWidth > 2048 )
index 9e07f72c75adf6fee2f9010563a68fd33aa19881..25a82e0e1c7c7c6708c5be760acb5098750f3a75 100644 (file)
@@ -399,7 +399,7 @@ AS_02::h__AS02Reader::~h__AS02Reader() {}
 
 // AS-DCP method of opening an MXF file for read
 Result_t
-AS_02::h__AS02Reader::OpenMXFRead(const char* filename)
+AS_02::h__AS02Reader::OpenMXFRead(const std::string& filename)
 {
   bool has_header_essence = false;
   Result_t result = ASDCP::MXF::TrackFileReader<OP1aHeader, AS_02::MXF::AS02IndexReader>::OpenMXFRead(filename);