Denis' bug fixes
authorjhurst <jhurst@cinecert.com>
Thu, 19 Oct 2006 02:59:54 +0000 (02:59 +0000)
committerjhurst <>
Thu, 19 Oct 2006 02:59:54 +0000 (02:59 +0000)
README
src/AS_DCP.h
src/KM_util.cpp
src/KM_util.h
src/MDD.cpp
src/MXF.cpp
src/MXF.h
src/MXFTypes.cpp
src/asdcp-test.cpp
src/blackwave.cpp
src/h__Writer.cpp

diff --git a/README b/README
index 71becabbd5d4eaabd5c9b18fec83b858833b447b..4e4bb1f755e9218b458aeaa64125564faaca030c 100755 (executable)
--- a/README
+++ b/README
@@ -113,6 +113,14 @@ utilities all respond to -h and there are manual pages in man/.
 
 
 Change History
+2006.10.18 - Bug fixes v1.1.11
+ o Increased index table entry list size to 5000.
+ o Added length checking to TLV writer (returns error if TLV
+   payload exceeds 64kB).
+ o Fixed partition header and RIP errors related to 2-partition
+   files (MXF Interop mode).
+ o Added -t option, SHA-1 digest with Base64 output on stdout.
+
 2006.10.05 - Bug fixes v1.1.10
  o Changed RM_RELEASE to RL_RELEASE in MXFTypes.h.
  o Changed the MXF writer to use RL_RELEASE (was RL_DEVELOPMENT).
index 75056660096ebcb6416957d192b2e053edccca8a..961dae37e536dfdee60f1836673ae3d8117dfa8c 100755 (executable)
@@ -144,7 +144,7 @@ namespace ASDCP {
   // 1.0.1. If changes were also required in AS_DCP.h, the new version would be 1.1.1.
   const ui32_t VERSION_MAJOR = 1;
   const ui32_t VERSION_APIMINOR = 1;
-  const ui32_t VERSION_IMPMINOR = 10;
+  const ui32_t VERSION_IMPMINOR = 11;
   const char* Version();
 
   // UUIDs are passed around as strings of UUIDlen bytes
index 7dd6719ba28d0083c19d6d48fadfe6a2fc7ebb56..339f78bd1003be77fa7f655851ce9b7277515a11 100755 (executable)
@@ -600,6 +600,20 @@ Kumu::Timestamp::operator<(const Timestamp& rhs) const
   return ( CompareFileTime(&lft, &rft) == -1 );
 }
 
+//
+bool
+Kumu::Timestamp::operator>(const Timestamp& rhs) const
+{
+  SYSTEMTIME lhst, rhst;
+  FILETIME lft, rft;
+
+  TIMESTAMP_TO_SYSTIME(*this, &lhst);
+  TIMESTAMP_TO_SYSTIME(rhs, &rhst);
+  SystemTimeToFileTime(&lhst, &lft);
+  SystemTimeToFileTime(&rhst, &rft);
+  return ( CompareFileTime(&lft, &rft) == 1 );
+}
+
 inline ui64_t
 seconds_to_ns100(ui32_t seconds)
 {
@@ -685,6 +699,16 @@ Kumu::Timestamp::operator<(const Timestamp& rhs) const
   return ( timegm(&lhtm) < timegm(&rhtm) );
 }
 
+//
+bool
+Kumu::Timestamp::operator>(const Timestamp& rhs) const
+{
+  struct tm lhtm, rhtm;
+  TIMESTAMP_TO_TM(*this, &lhtm);
+  TIMESTAMP_TO_TM(rhs, &rhtm);
+  return ( timegm(&lhtm) > timegm(&rhtm) );
+}
+
 //
 void
 Kumu::Timestamp::AddDays(i32_t days)
index d210bb91560dd3cc4ae9c9e1135a878858159098..e01cd2bbdda1393930cc0dcfd2f6c3d60eede04e 100755 (executable)
@@ -276,6 +276,10 @@ namespace Kumu
       UUID(const UUID& rhs) : Identifier<UUID_Length>(rhs) {}
       virtual ~UUID() {}
 
+      inline const char* EncodeString(char* buf, ui32_t buf_len) const {
+       return bin2UUIDhex(m_Value, Size(), buf, buf_len);
+      }
+
       inline const char* EncodeHex(char* buf, ui32_t buf_len) const {
        return bin2UUIDhex(m_Value, Size(), buf, buf_len);
       }
@@ -325,6 +329,7 @@ namespace Kumu
 
       const Timestamp& operator=(const Timestamp& rhs);
       bool operator<(const Timestamp& rhs) const;
+      bool operator>(const Timestamp& rhs) const;
       bool operator==(const Timestamp& rhs) const;
       bool operator!=(const Timestamp& rhs) const;
 
index 29be17760d841e0538a8a36d72a2a85caa083086..21282575d3d584fdc6bf5d3624d3082b85c11017 100644 (file)
@@ -84,8 +84,10 @@ static const ASDCP::MDDEntry s_MDD_Table[] = {
   { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x02, 0x01, 0x01, // 16
       0x0d, 0x01, 0x03, 0x01, 0x16, 0x01, 0x01, 0x00 },
       {0}, false, "WAVEssence" },
-  { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x09, // 17
-      0x04, 0x01, 0x02, 0x02, 0x03, 0x01, 0x01, 0x01 },
+  { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x07,
+      0x04, 0x01, 0x02, 0x02, 0x03, 0x01, 0x01, 0x03 },
+      // 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x09, // 17
+      //      0x04, 0x01, 0x02, 0x02, 0x03, 0x01, 0x01, 0x01 },
       {0}, false, "JP2KEssenceCompression" },
   { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x07, // 18
       0x02, 0x09, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00 },
index 0913f1bb84688a384bef1fa05e7408dca7f09856..28b156c650e11709a3e3c58d8771f997453aab39 100755 (executable)
@@ -33,6 +33,10 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <KM_log.h>
 using Kumu::DefaultLogSink;
 
+// index segments must be < 64K
+// NOTE: this value may too high if advanced index entry elements are used.
+const ui32_t CBRIndexEntriesPerSegment = 5000;
+
 //------------------------------------------------------------------------------------------
 //
 
@@ -1093,7 +1097,7 @@ ASDCP::MXF::OPAtomIndexFooter::PushIndexEntry(const IndexTableSegment::IndexEntr
       m_CurrentSegment->IndexEditRate = m_EditRate;
       m_CurrentSegment->IndexStartPosition = 0;
     }
-  else if ( m_CurrentSegment->IndexEntryArray.size() >= 1486 ) // 1486 gets us 16K packets
+  else if ( m_CurrentSegment->IndexEntryArray.size() >= CBRIndexEntriesPerSegment )
     { // no, this one is full, start another
       m_CurrentSegment->IndexDuration = m_CurrentSegment->IndexEntryArray.size();
       ui64_t StartPosition = m_CurrentSegment->IndexStartPosition + m_CurrentSegment->IndexDuration;
index a38b6dbcdd05b332f13e9b45e2324fe1a0d6e379..ed7fb0dc4fa8a39e791978c7af1c3f8cc13c133e 100755 (executable)
--- a/src/MXF.h
+++ b/src/MXF.h
@@ -259,6 +259,9 @@ namespace ASDCP
              i8_t               KeyFrameOffset;
              ui8_t              Flags;
              ui64_t             StreamOffset;
+
+             // if you use these, you will need to change CBRIndexEntriesPerSegment in MXF.cpp
+             // to a more suitable value
              //              std::list<ui32_t>  SliceOffset;
              //              Array<Rational>    PosTable;
 
index 90d68c1fbee963f4601e2e65dfe9d63baac315d0..625a2e2c05b78cda8545939a61c94ca5c0f5cc51 100755 (executable)
@@ -616,7 +616,8 @@ ASDCP::MXF::TLVWriter::WriteObject(const MDDEntry& Entry, Kumu::IArchive* Object
 
       ui32_t before = Length();
       if ( ! Object->Archive(this) ) return RESULT_KLV_CODING;
-      Kumu::i2p<ui16_t>(KM_i16_BE( Length() - before), l_p);
+      if ( (Length() - before) > 0xffffL ) return RESULT_KLV_CODING;
+      Kumu::i2p<ui16_t>(KM_i16_BE(Length() - before), l_p);
     }
 
   return result;
index e43569efa41179f230c016422442bd7c2fc8864c..cf7a91f0e45c98fbffdfe9537ee22c7ce7fb9381 100755 (executable)
@@ -56,6 +56,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <WavFileWriter.h>
 #include <MXF.h>
 #include <Metadata.h>
+#include <openssl/sha.h>
 
 using namespace ASDCP;
 
@@ -90,19 +91,6 @@ public:
 } s_MyInfo;
 
 
-// Macros used to test command option data state.
-
-// True if a major mode has already been selected.
-#define TEST_MAJOR_MODE()     ( info_flag||create_flag||extract_flag||genkey_flag||genid_flag||gop_start_flag )
-
-// Causes the caller to return if a major mode has already been selected,
-// otherwise sets the given flag.
-#define TEST_SET_MAJOR_MODE(f) if ( TEST_MAJOR_MODE() ) \
-                                 { \
-                                   fputs("Conflicting major mode, choose one of -(gcixG)).\n", stderr); \
-                                   return; \
-                                 } \
-                                 (f) = true;
 
 // Increment the iterator, test for an additional non-option command line argument.
 // Causes the caller to return if there are no remaining arguments or if the next
@@ -142,11 +130,13 @@ USAGE: %s -c <output-file> [-b <buffer-size>] [-d <duration>] [-e|-E]\n\
        %s -g | -u\n\
 \n\
        %s -G [-v] <input-file>\n\
+\n\
+       %s -t <input-file>\n\
 \n\
        %s -x <file-prefix> [-b <buffer-size>] [-d <duration>]\n\
        [-f <starting-frame>] [-m] [-p <frame-rate>] [-R] [-s <num>] [-S]\n\
        [-v] [-W] <input-file>\n\
-\n", PACKAGE, PACKAGE, PACKAGE, PACKAGE, PACKAGE, PACKAGE);
+\n", PACKAGE, PACKAGE, PACKAGE, PACKAGE, PACKAGE, PACKAGE, PACKAGE);
 
   fprintf(stream, "\
 Major modes:\n\
@@ -155,6 +145,7 @@ Major modes:\n\
   -G                - Perform GOP start lookup test on MXF+Interop MPEG file\n\
   -h | -help        - Show help\n\
   -i                - Show file info\n\
+  -t                - Calculate message digest of input file\n\
   -u                - Generate a random UUID value to stdout\n\
   -V                - Show version information\n\
   -x <root-name>    - Extract essence from AS-DCP file to named file(s)\n\
@@ -203,6 +194,20 @@ Other Options:\n\
 \n");
 }
 
+//
+enum MajorMode_t
+{
+  MMT_NONE,
+  MMT_INFO,
+  MMT_CREATE,
+  MMT_EXTRACT,
+  MMT_GEN_ID,
+  MMT_GEN_KEY,
+  MMT_GOP_START,
+  MMT_DIGEST
+};
+
+
 //
 //
 class CommandOptions
@@ -210,13 +215,8 @@ class CommandOptions
   CommandOptions();
 
 public:
+  MajorMode_t mode;
   bool   error_flag;     // true if the given options are in error or not complete
-  bool   info_flag;      // true if the file info mode was selected
-  bool   create_flag;    // true if the file create mode was selected
-  bool   extract_flag;   // true if the file extract mode was selected
-  bool   genkey_flag;    // true if we are to generate a new key value
-  bool   genid_flag;     // true if we are to generate a new UUID value
-  bool   gop_start_flag; // true if we are to perform a GOP start lookup test
   bool   key_flag;       // true if an encryption key was given
   bool   key_id_flag;    // true if a key ID was given
   bool   encrypt_header_flag; // true if mpeg headers are to be encrypted
@@ -262,9 +262,7 @@ public:
 
   //
   CommandOptions(int argc, const char** argv) :
-    error_flag(true), info_flag(false), create_flag(false),
-    extract_flag(false), genkey_flag(false), genid_flag(false), gop_start_flag(false),
-    key_flag(false), key_id_flag(false), encrypt_header_flag(true),
+    mode(MMT_NONE), error_flag(true), key_flag(false), key_id_flag(false), encrypt_header_flag(true),
     write_hmac(true), read_hmac(false), split_wav(false),
     verbose_flag(false), fb_dump_size(0), showindex_flag(false), showheader_flag(false),
     no_write_flag(false), version_flag(false), help_flag(false), start_frame(0),
@@ -287,8 +285,8 @@ public:
          {
            switch ( argv[i][1] )
              {
-             case 'i': TEST_SET_MAJOR_MODE(info_flag); break;
-             case 'G': TEST_SET_MAJOR_MODE(gop_start_flag); break;
+             case 'i': mode = MMT_INFO;        break;
+             case 'G': mode = MMT_GOP_START; break;
              case 'W': no_write_flag = true; break;
              case 'n': showindex_flag = true; break;
              case 'H': showheader_flag = true; break;
@@ -297,8 +295,8 @@ public:
              case 'V': version_flag = true; break;
              case 'h': help_flag = true; break;
              case 'v': verbose_flag = true; break;
-             case 'g': genkey_flag = true; break;
-             case 'u': genid_flag = true; break;
+             case 'g': mode = MMT_GEN_KEY; break;
+             case 'u': mode = MMT_GEN_ID; break;
              case 'e': encrypt_header_flag = true; break;
              case 'E': encrypt_header_flag = false; break;
              case 'M': write_hmac = false; break;
@@ -306,14 +304,14 @@ public:
              case 'L': use_smpte_labels = true; break;
 
              case 'c':
-               TEST_SET_MAJOR_MODE(create_flag);
                TEST_EXTRA_ARG(i, 'c');
+               mode = MMT_CREATE;
                out_file = argv[i];
                break;
 
              case 'x':
-               TEST_SET_MAJOR_MODE(extract_flag);
                TEST_EXTRA_ARG(i, 'x');
+               mode = MMT_EXTRACT;
                file_root = argv[i];
                break;
 
@@ -366,6 +364,8 @@ public:
                fb_dump_size = atoi(argv[i]);
                break;
 
+             case 't': mode = MMT_DIGEST; break;
+
              case 'b':
                TEST_EXTRA_ARG(i, 'b');
                fb_size = atoi(argv[i]);
@@ -404,18 +404,19 @@ public:
     if ( help_flag || version_flag )
       return;
     
-    if ( TEST_MAJOR_MODE() )
+    if ( ( mode == MMT_INFO
+          || mode == MMT_CREATE
+          || mode == MMT_EXTRACT
+          || mode == MMT_GOP_START
+          || mode == MMT_DIGEST ) && file_count == 0 )
       {
-       if ( ! genkey_flag && ! genid_flag && file_count == 0 )
-         {
-           fputs("Option requires at least one filename argument.\n", stderr);
-           return;
-         }
+       fputs("Option requires at least one filename argument.\n", stderr);
+       return;
       }
 
-    if ( ! TEST_MAJOR_MODE() && ! help_flag && ! version_flag )
+    if ( mode == MMT_NONE && ! help_flag && ! version_flag )
       {
-       fputs("No operation selected (use one of -(gcixG) or -h for help).\n", stderr);
+       fputs("No operation selected (use one of -[gGcitux] or -h for help).\n", stderr);
        return;
       }
 
@@ -1234,6 +1235,48 @@ show_file_info(CommandOptions& Options)
 }
 
 
+//
+Result_t
+digest_file(const char* filename)
+{
+  using namespace Kumu;
+
+  ASDCP_TEST_NULL_STR(filename);
+  FileReader Reader;
+  SHA_CTX Ctx;
+  SHA1_Init(&Ctx);
+  ByteString Buf(8192);
+
+  Result_t result = Reader.OpenRead(filename);
+
+  while ( ASDCP_SUCCESS(result) )
+    {
+      ui32_t read_count = 0;
+      result = Reader.Read(Buf.Data(), Buf.Capacity(), &read_count);
+
+      if ( result == RESULT_ENDOFFILE )
+       {
+         result = RESULT_OK;
+         break;
+       }
+
+      if ( ASDCP_SUCCESS(result) )
+       SHA1_Update(&Ctx, Buf.Data(), read_count);
+    }
+
+  if ( ASDCP_SUCCESS(result) )
+    {
+      const ui32_t sha_len = 20;
+      byte_t bin_buf[sha_len];
+      char sha_buf[64];
+      SHA1_Final(bin_buf, &Ctx);
+
+      fprintf(stdout, "%s %s\n", base64encode(bin_buf, sha_len, sha_buf, 64), filename);
+    }
+
+  return result;
+}
+
 //
 int
 main(int argc, const char** argv)
@@ -1256,15 +1299,15 @@ main(int argc, const char** argv)
       return 3;
     }
 
-  if ( Options.info_flag )
+  if ( Options.mode == MMT_INFO )
     {
       result = show_file_info(Options);
     }
-  else if ( Options.gop_start_flag )
+  else if ( Options.mode == MMT_GOP_START )
     {
       result = gop_start_test(Options);
     }
-  else if ( Options.genkey_flag )
+  else if ( Options.mode == MMT_GEN_KEY )
     {
       Kumu::FortunaRNG RNG;
       byte_t bin_buf[KeyLen];
@@ -1273,14 +1316,19 @@ main(int argc, const char** argv)
       RNG.FillRandom(bin_buf, KeyLen);
       printf("%s\n", Kumu::bin2hex(bin_buf, KeyLen, str_buf, 40));
     }
-  else if ( Options.genid_flag )
+  else if ( Options.mode == MMT_GEN_ID )
     {
       UUID TmpID;
       Kumu::GenRandomValue(TmpID);
       char   str_buf[40];
       printf("%s\n", TmpID.EncodeHex(str_buf, 40));
     }
-  else if ( Options.extract_flag )
+  else if ( Options.mode == MMT_DIGEST )
+    {
+      for ( ui32_t i = 0; i < Options.file_count && ASDCP_SUCCESS(result); i++ )
+       result = digest_file(Options.filenames[i]);
+    }
+  else if ( Options.mode == MMT_EXTRACT )
     {
       EssenceType_t EssenceType;
       result = ASDCP::EssenceType(Options.filenames[0], EssenceType);
@@ -1307,7 +1355,7 @@ main(int argc, const char** argv)
            }
        }
     }
-  else if ( Options.create_flag )
+  else if ( Options.mode == MMT_CREATE )
     {
       if ( Options.do_repeat && ! Options.duration_flag )
        {
index b704b47d515dbebf4ceba0771664438cb9ce4c7e..311a0dbc4c5f6112b45ae98462b8f335bef26c19 100644 (file)
@@ -157,8 +157,8 @@ make_black_wav_file(CommandOptions& Options)
   ADesc.Locked = 0;
   ADesc.ChannelCount = 1;
   ADesc.QuantizationBits = 24;
-  ADesc.BlockAlign = 18;
-  ADesc.AvgBps = 86400;
+  ADesc.BlockAlign = 3;
+  ADesc.AvgBps = 14400;
   ADesc.LinkedTrackID = 1;
   ADesc.ContainerDuration = Options.duration;
 
index 32568c43ea95e4f730c70fced794a43660011dbc..1105e039de873964c7c937bb25b5efe035829f4d 100755 (executable)
@@ -109,7 +109,12 @@ ASDCP::h__Writer::WriteMXFHeader(const std::string& PackageLabel, const UL& Wrap
   // so we tell the world by using OP1a
   m_HeaderPart.m_Preface->OperationalPattern = UL(Dict::ul(MDD_OP1a));
   m_HeaderPart.OperationalPattern = m_HeaderPart.m_Preface->OperationalPattern;
-  m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(0, 0)); // First RIP Entry
+
+  // First RIP Entry
+  if ( m_Info.LabelSetType == LS_MXF_SMPTE )
+    m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(0, 0)); // 3-part, no essence in header
+  else
+    m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(1, 0)); // 2-part, essence in header
 
   //
   // Identification
@@ -298,11 +303,16 @@ ASDCP::h__Writer::WriteMXFHeader(const std::string& PackageLabel, const UL& Wrap
       UL BodyUL(Dict::ul(MDD_ClosedCompleteBodyPartition));
       result = m_BodyPart.WriteToFile(m_File, BodyUL);
     }
+  else
+    {
+      m_HeaderPart.BodySID = 1;
+    }
 
   if ( ASDCP_SUCCESS(result) )
     {
       // Index setup
       Kumu::fpos_t ECoffset = m_File.Tell();
+      m_FooterPart.IndexSID = 129;
 
       if ( BytesPerEditUnit == 0 )
        m_FooterPart.SetIndexParamsVBR(&m_HeaderPart.m_Primer, EditRate, ECoffset);
@@ -441,7 +451,7 @@ ASDCP::h__Writer::WriteMXFFooter()
     m_EssenceDescriptor->ContainerDuration = m_FramesWritten;
 
   Kumu::fpos_t here = m_File.Tell();
-  m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(0, here)); // Third RIP Entry
+  m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(0, here)); // Last RIP Entry
   m_HeaderPart.FooterPartition = here;
 
   // re-label the partition
@@ -453,7 +463,11 @@ ASDCP::h__Writer::WriteMXFFooter()
   m_HeaderPart.OperationalPattern = OPAtomUL;
   m_HeaderPart.m_Preface->OperationalPattern = m_HeaderPart.OperationalPattern;
 
-  m_FooterPart.PreviousPartition = m_BodyPart.ThisPartition;
+  if ( m_Info.LabelSetType == LS_MXF_SMPTE )
+    m_FooterPart.PreviousPartition = m_BodyPart.ThisPartition;
+  else
+    m_FooterPart.PreviousPartition = m_HeaderPart.ThisPartition;
+
   m_FooterPart.OperationalPattern = m_HeaderPart.OperationalPattern;
   m_FooterPart.EssenceContainers = m_HeaderPart.EssenceContainers;
   m_FooterPart.FooterPartition = here;