Support hashing while writing MXFs.
authorCarl Hetherington <cth@carlh.net>
Thu, 14 Jan 2016 22:05:56 +0000 (22:05 +0000)
committerCarl Hetherington <cth@carlh.net>
Tue, 3 Dec 2019 15:44:40 +0000 (16:44 +0100)
src/AS_DCP.h
src/AS_DCP_JP2K.cpp
src/AS_DCP_internal.h
src/KM_fileio.cpp
src/KM_fileio.h
src/h__Writer.cpp

index 88104e86f899e7bf4a97615345a3402fb626475c..24bd17620488ffe131be77cb22553a0046684227 100755 (executable)
@@ -1225,9 +1225,10 @@ namespace ASDCP {
 
          // Writes a frame of essence to the MXF file. If the optional AESEncContext
          // argument is present, the essence is encrypted prior to writing.
+         // A MD5 hash of the data that we write is written to hash if it is not 0
          // Fails if the file is not open, is finalized, or an operating system
          // error occurs.
-         Result_t WriteFrame(const FrameBuffer&, AESEncContext* = 0, HMACContext* = 0);
+         Result_t WriteFrame(const FrameBuffer&, AESEncContext* = 0, HMACContext* = 0, std::string* hash = 0);
 
          Result_t FakeWriteFrame(int size);
 
@@ -1346,7 +1347,7 @@ namespace ASDCP {
          // RESULT_SPHASE will be returned if phase is reversed. The first frame
          // written must be left eye.
          Result_t WriteFrame(const FrameBuffer&, StereoscopicPhase_t phase,
-                             AESEncContext* = 0, HMACContext* = 0);
+                             AESEncContext* = 0, HMACContext* = 0, std::string* hash = 0);
 
          Result_t FakeWriteFrame(int size, StereoscopicPhase_t phase);
 
index dc7f9846b1e3e093e655519013a9b1089a298bd6..9d6dfc9b2d26a2f9e3ab1826e9516e5f3358d89d 100755 (executable)
@@ -933,7 +933,7 @@ public:
   Result_t OpenWrite(const std::string&, EssenceType_t type, ui32_t HeaderSize, bool);
   Result_t SetSourceStream(const PictureDescriptor&, const std::string& label,
                           ASDCP::Rational LocalEditRate = ASDCP::Rational(0,0));
-  Result_t WriteFrame(const JP2K::FrameBuffer&, bool add_index, AESEncContext*, HMACContext*);
+  Result_t WriteFrame(const JP2K::FrameBuffer&, bool add_index, AESEncContext*, HMACContext*, std::string* hash = 0);
   Result_t FakeWriteFrame(int size, bool add_index);
   Result_t Finalize();
 };
@@ -1039,7 +1039,7 @@ lh__Writer::SetSourceStream(const PictureDescriptor& PDesc, const std::string& l
 //
 ASDCP::Result_t
 lh__Writer::WriteFrame(const JP2K::FrameBuffer& FrameBuf, bool add_index,
-                      AESEncContext* Ctx, HMACContext* HMAC)
+                      AESEncContext* Ctx, HMACContext* HMAC, std::string* hash)
 {
   Result_t result = RESULT_OK;
 
@@ -1049,7 +1049,7 @@ lh__Writer::WriteFrame(const JP2K::FrameBuffer& FrameBuf, bool add_index,
   ui64_t StreamOffset = m_StreamOffset;
 
   if ( ASDCP_SUCCESS(result) )
-    result = WriteEKLVPacket(FrameBuf, m_EssenceUL, Ctx, HMAC);
+    result = WriteEKLVPacket(FrameBuf, m_EssenceUL, Ctx, HMAC, hash);
 
   if ( ASDCP_SUCCESS(result) && add_index )
     {
@@ -1198,12 +1198,12 @@ ASDCP::JP2K::MXFWriter::OpenWrite(const std::string& filename, const WriterInfo&
 // Fails if the file is not open, is finalized, or an operating system
 // error occurs.
 ASDCP::Result_t
-ASDCP::JP2K::MXFWriter::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
+ASDCP::JP2K::MXFWriter::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC, std::string* hash)
 {
   if ( m_Writer.empty() )
     return RESULT_INIT;
 
-  return m_Writer->WriteFrame(FrameBuf, true, Ctx, HMAC);
+  return m_Writer->WriteFrame(FrameBuf, true, Ctx, HMAC, hash);
 }
 
 ASDCP::Result_t
@@ -1246,7 +1246,7 @@ public:
 
   //
   Result_t WriteFrame(const FrameBuffer& FrameBuf, StereoscopicPhase_t phase,
-                     AESEncContext* Ctx, HMACContext* HMAC)
+                     AESEncContext* Ctx, HMACContext* HMAC, std::string* hash)
   {
     if ( m_NextPhase != phase )
       return RESULT_SPHASE;
@@ -1254,11 +1254,11 @@ public:
     if ( phase == SP_LEFT )
       {
        m_NextPhase = SP_RIGHT;
-       return lh__Writer::WriteFrame(FrameBuf, true, Ctx, HMAC);
+       return lh__Writer::WriteFrame(FrameBuf, true, Ctx, HMAC, hash);
       }
 
     m_NextPhase = SP_LEFT;
-    return lh__Writer::WriteFrame(FrameBuf, false, Ctx, HMAC);
+    return lh__Writer::WriteFrame(FrameBuf, false, Ctx, HMAC, hash);
   }
 
   Result_t FakeWriteFrame(int size, StereoscopicPhase_t phase)
@@ -1409,10 +1409,10 @@ ASDCP::JP2K::MXFSWriter::WriteFrame(const SFrameBuffer& FrameBuf, AESEncContext*
   if ( m_Writer.empty() )
     return RESULT_INIT;
 
-  Result_t result = m_Writer->WriteFrame(FrameBuf.Left, SP_LEFT, Ctx, HMAC);
+  Result_t result = m_Writer->WriteFrame(FrameBuf.Left, SP_LEFT, Ctx, HMAC, 0);
 
   if ( ASDCP_SUCCESS(result) )
-    result = m_Writer->WriteFrame(FrameBuf.Right, SP_RIGHT, Ctx, HMAC);
+    result = m_Writer->WriteFrame(FrameBuf.Right, SP_RIGHT, Ctx, HMAC, 0);
 
   return result;
 }
@@ -1423,12 +1423,12 @@ ASDCP::JP2K::MXFSWriter::WriteFrame(const SFrameBuffer& FrameBuf, AESEncContext*
 // error occurs.
 ASDCP::Result_t
 ASDCP::JP2K::MXFSWriter::WriteFrame(const FrameBuffer& FrameBuf, StereoscopicPhase_t phase,
-                                   AESEncContext* Ctx, HMACContext* HMAC)
+                                   AESEncContext* Ctx, HMACContext* HMAC, std::string* hash)
 {
   if ( m_Writer.empty() )
     return RESULT_INIT;
 
-  return m_Writer->WriteFrame(FrameBuf, phase, Ctx, HMAC);
+  return m_Writer->WriteFrame(FrameBuf, phase, Ctx, HMAC, hash);
 }
 
 ASDCP::Result_t
index 369b8fdc95443a031895997b11e469d24da72976..782e5c4e2341c4a65e6b293b3981960406387805 100755 (executable)
@@ -157,7 +157,7 @@ namespace ASDCP
   Result_t Write_EKLV_Packet(Kumu::FileWriter& File, const ASDCP::Dictionary& Dict, const MXF::OP1aHeader& HeaderPart,
                             const ASDCP::WriterInfo& Info, ASDCP::FrameBuffer& CtFrameBuf, ui32_t& FramesWritten,
                             ui64_t & StreamOffset, const ASDCP::FrameBuffer& FrameBuf, const byte_t* EssenceUL,
-                            AESEncContext* Ctx, HMACContext* HMAC);
+                            AESEncContext* Ctx, HMACContext* HMAC, std::string* hash = 0);
 
   //
  class KLReader : public ASDCP::KLVPacket
@@ -860,7 +860,7 @@ namespace ASDCP
 
       Result_t CreateBodyPart(const MXF::Rational& EditRate, ui32_t BytesPerEditUnit = 0);
       Result_t WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf,const byte_t* EssenceUL,
-                              AESEncContext* Ctx, HMACContext* HMAC);
+                              AESEncContext* Ctx, HMACContext* HMAC, std::string* hash = 0);
       Result_t FakeWriteEKLVPacket(int size);
       Result_t WriteASDCPFooter();
     };
index 26996f90144956f99096456233d06cca2e81b253..33e354d2142e1b2bd022fb9fba9c0f70cd06e696 100644 (file)
@@ -32,6 +32,8 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <KM_fileio.h>
 #include <KM_log.h>
 #include <fcntl.h>
+#include <sstream>
+#include <iomanip>
 
 #include <assert.h>
 
@@ -727,7 +729,9 @@ Kumu::FileReader::Size() const
 
 // these are declared here instead of in the header file
 // because we have a mem_ptr that is managing a hidden class
-Kumu::FileWriter::FileWriter() {}
+Kumu::FileWriter::FileWriter()
+  : m_Hashing(false)
+{}
 Kumu::FileWriter::~FileWriter() {}
 
 //
@@ -752,6 +756,41 @@ Kumu::FileWriter::Writev(const byte_t* buf, ui32_t buf_len)
   return RESULT_OK;
 }
 
+void
+Kumu::FileWriter::StartHashing()
+{
+  m_Hashing = true;
+  MD5_Init (&m_MD5Context);
+}
+
+void
+Kumu::FileWriter::MaybeHash(void const * data, int size)
+{
+  if (m_Hashing)
+    {
+      MD5_Update (&m_MD5Context, data, size);
+    }
+}
+
+std::string
+Kumu::FileWriter::StopHashing()
+{
+  m_Hashing = false;
+
+  unsigned char digest[MD5_DIGEST_LENGTH];
+  MD5_Final (digest, &m_MD5Context);
+
+  std::stringstream s;
+  for (int i = 0; i < MD5_DIGEST_LENGTH; ++i)
+    {
+      s << std::hex << std::setfill('0') << std::setw(2) << ((int) digest[i]);
+    }
+
+  return s.str ();
+}
+
+
+
 
 #ifdef KM_WIN32
 //------------------------------------------------------------------------------------------
@@ -998,6 +1037,7 @@ Kumu::FileWriter::Writev(ui32_t* bytes_written)
          break;
        }
 
+      MaybeHash(iov->m_iovec[i].iov_base, iov->m_iovec[i].iov_len);
       *bytes_written += tmp_count;
     }
 
@@ -1028,6 +1068,8 @@ Kumu::FileWriter::Write(const byte_t* buf, ui32_t buf_len, ui32_t* bytes_written
   if ( result == 0 || *bytes_written != buf_len )
     return Kumu::RESULT_WRITEFAIL;
 
+  MaybeHash(buf, buf_len);
+
   return Kumu::RESULT_OK;
 }
 
@@ -1171,6 +1213,11 @@ Kumu::FileWriter::Writev(ui32_t* bytes_written)
   if ( write_size == -1L || write_size != total_size )
     return RESULT_WRITEFAIL;
 
+  for (int i = 0; i < iov->m_Count; ++i)
+    {
+      MaybeHash(iov->m_iovec[i].iov_base, iov->m_iovec[i].iov_len);
+    }
+
   iov->m_Count = 0;
   *bytes_written = write_size;
   return RESULT_OK;
@@ -1190,6 +1237,7 @@ Kumu::FileWriter::Write(const byte_t* buf, ui32_t buf_len, ui32_t* bytes_written
     return RESULT_STATE;
 
   int write_size = write(m_Handle, buf, buf_len);
+  MaybeHash(buf, buf_len);
 
   if ( write_size == -1L || (ui32_t)write_size != buf_len )
     return RESULT_WRITEFAIL;
index 35cac708ef9132e5ace5512d336d29a4a74e4bfd..527373edc378884b8fff5496eb7ca2f5daeeefca 100755 (executable)
@@ -35,6 +35,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <KM_util.h>
 #include <string>
 #include <boost/filesystem.hpp>
+#include <openssl/md5.h>
 
 #ifdef KM_WIN32
 # include <io.h>
@@ -344,6 +345,8 @@ namespace Kumu
       class h__iovec;
       mem_ptr<h__iovec>  m_IOVec;
       KM_NO_COPY_CONSTRUCT(FileWriter);
+      bool m_Hashing;
+      MD5_CTX m_MD5Context;
 
     public:
       FileWriter();
@@ -363,6 +366,10 @@ namespace Kumu
       // the iovec list will be written to disk before the given buffer,as though
       // you had called Writev() first.
       Result_t Write(const byte_t*, ui32_t, ui32_t* = 0);            // write buffer to disk
+
+      void StartHashing();
+      void MaybeHash(void const *, int);
+      std::string StopHashing();
    };
 
   Result_t CreateDirectoriesInPath(const std::string& Path);
index a53093ed0d98dd9b1002d392706b850e54908aa4..bb1a25459d32fca41fa6174d34bdf04da94d9171 100755 (executable)
@@ -168,10 +168,10 @@ ASDCP::h__ASDCPWriter::WriteASDCPHeader(const std::string& PackageLabel, const U
 //
 Result_t
 ASDCP::h__ASDCPWriter::WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf,const byte_t* EssenceUL,
-                                      AESEncContext* Ctx, HMACContext* HMAC)
+                                      AESEncContext* Ctx, HMACContext* HMAC, std::string* hash)
 {
   return Write_EKLV_Packet(m_File, *m_Dict, m_HeaderPart, m_Info, m_CtFrameBuf, m_FramesWritten,
-                          m_StreamOffset, FrameBuf, EssenceUL, Ctx, HMAC);
+                          m_StreamOffset, FrameBuf, EssenceUL, Ctx, HMAC, hash);
 }
 
 Result_t
@@ -239,11 +239,16 @@ Result_t
 ASDCP::Write_EKLV_Packet(Kumu::FileWriter& File, const ASDCP::Dictionary& Dict, const MXF::OP1aHeader&,
                         const ASDCP::WriterInfo& Info, ASDCP::FrameBuffer& CtFrameBuf, ui32_t& FramesWritten,
                         ui64_t & StreamOffset, const ASDCP::FrameBuffer& FrameBuf, const byte_t* EssenceUL,
-                        AESEncContext* Ctx, HMACContext* HMAC)
+                        AESEncContext* Ctx, HMACContext* HMAC, std::string* hash)
 {
   Result_t result = RESULT_OK;
   IntegrityPack IntPack;
 
+  if (hash)
+    {
+      File.StartHashing();
+    }
+
   byte_t overhead[128];
   Kumu::MemIOWriter Overhead(overhead, 128);
 
@@ -374,6 +379,11 @@ ASDCP::Write_EKLV_Packet(Kumu::FileWriter& File, const ASDCP::Dictionary& Dict,
   if ( ASDCP_SUCCESS(result) )
     result = File.Writev();
 
+  if (hash)
+    {
+      *hash = File.StopHashing();
+    }
+
   return result;
 }