IMF MCA labels
[asdcplib.git] / src / AS_DCP_MXF.cpp
index 1c8b6e9d5c95513ad1f1191e4f9e4e5780e75f03..f3ad310ed2bde3effb793e13f11a7b62213ee12b 100755 (executable)
@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2004-2006, John Hurst
+Copyright (c) 2004-2013, John Hurst
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -30,15 +30,45 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #include <KM_fileio.h>
+#include <KM_xml.h>
 #include "AS_DCP_internal.h"
 #include "JP2K.h"
+#include "MPEG.h"
 #include "Wav.h"
+#include <iostream>
+#include <iomanip>
 
 
 //------------------------------------------------------------------------------------------
 // misc subroutines
 
 
+//
+std::ostream&
+ASDCP::operator << (std::ostream& strm, const WriterInfo& Info)
+{
+  char str_buf[40];
+
+  strm << "       ProductUUID: " << UUID(Info.ProductUUID).EncodeHex(str_buf, 40) << std::endl;
+  strm << "    ProductVersion: " << Info.ProductVersion << std::endl;
+  strm << "       CompanyName: " << Info.CompanyName << std::endl;
+  strm << "       ProductName: " << Info.ProductName << std::endl;
+  strm << "  EncryptedEssence: " << (Info.EncryptedEssence ? "Yes" : "No") << std::endl;
+
+  if ( Info.EncryptedEssence )
+    {
+      strm << "              HMAC: " << (Info.UsesHMAC ? "Yes" : "No") << std::endl;
+      strm << "         ContextID: " << UUID(Info.ContextID).EncodeHex(str_buf, 40) << std::endl;
+      strm << "CryptographicKeyID: " << UUID(Info.CryptographicKeyID).EncodeHex(str_buf, 40) << std::endl;
+    }
+
+  strm << "         AssetUUID: " << UUID(Info.AssetUUID).EncodeHex(str_buf, 40) << std::endl;
+  strm << "    Label Set Type: " << (Info.LabelSetType == LS_MXF_SMPTE ? "SMPTE" :
+                                    (Info.LabelSetType == LS_MXF_INTEROP ? "MXF Interop" :
+                                     "Unknown")) << std::endl;
+  return strm;
+}
+
 //
 void
 ASDCP::WriterInfoDump(const WriterInfo& Info, FILE* stream)
@@ -102,7 +132,7 @@ ASDCP::MD_to_WriterInfo(Identification* InfoObj, WriterInfo& Info)
 
 //
 Result_t
-ASDCP::MD_to_CryptoInfo(CryptographicContext* InfoObj, WriterInfo& Info)
+ASDCP::MD_to_CryptoInfo(CryptographicContext* InfoObj, WriterInfo& Info, const Dictionary& Dict)
 {
   ASDCP_TEST_NULL(InfoObj);
 
@@ -110,8 +140,8 @@ ASDCP::MD_to_CryptoInfo(CryptographicContext* InfoObj, WriterInfo& Info)
   memcpy(Info.ContextID, InfoObj->ContextID.Value(), UUIDlen);
   memcpy(Info.CryptographicKeyID, InfoObj->CryptographicKeyID.Value(), UUIDlen);
 
-  UL MIC_SHA1(Dict::ul(MDD_MICAlgorithm_HMAC_SHA1));
-  UL MIC_NONE(Dict::ul(MDD_MICAlgorithm_NONE));
+  UL MIC_SHA1(Dict.ul(MDD_MICAlgorithm_HMAC_SHA1));
+  UL MIC_NONE(Dict.ul(MDD_MICAlgorithm_NONE));
 
   if ( InfoObj->MICAlgorithm == MIC_SHA1 )
     Info.UsesHMAC = true;
@@ -133,9 +163,14 @@ ASDCP::MD_to_CryptoInfo(CryptographicContext* InfoObj, WriterInfo& Info)
 ASDCP::Result_t
 ASDCP::EssenceType(const char* filename, EssenceType_t& type)
 {
+  const Dictionary* m_Dict = &DefaultCompositeDict();
+  InterchangeObject* md_object = 0;
+
+  assert(m_Dict);
+
   ASDCP_TEST_NULL_STR(filename);
   Kumu::FileReader   Reader;
-  OPAtomHeader TestHeader;
+  OP1aHeader TestHeader(m_Dict);
 
   Result_t result = Reader.OpenRead(filename);
 
@@ -145,16 +180,46 @@ ASDCP::EssenceType(const char* filename, EssenceType_t& type)
   if ( ASDCP_SUCCESS(result) )
     {
       type = ESS_UNKNOWN;
-      if ( ASDCP_SUCCESS(TestHeader.GetMDObjectByType(OBJ_TYPE_ARGS(RGBAEssenceDescriptor))) )
-       type = ESS_JPEG_2000;
-      else
+      if ( ASDCP_SUCCESS(TestHeader.GetMDObjectByType(OBJ_TYPE_ARGS(JPEG2000PictureSubDescriptor))) )
        {
-         if ( ASDCP_SUCCESS(TestHeader.GetMDObjectByType(OBJ_TYPE_ARGS(WaveAudioDescriptor))) )
-           type = ESS_PCM_24b_48k;
+         if ( ASDCP_SUCCESS(TestHeader.GetMDObjectByType(OBJ_TYPE_ARGS(StereoscopicPictureSubDescriptor))) )
+           {
+             type = ESS_JPEG_2000_S;
+           }
          else
            {
-             if ( ASDCP_SUCCESS(TestHeader.GetMDObjectByType(OBJ_TYPE_ARGS(MPEG2VideoDescriptor))) )
-               type = ESS_MPEG2_VES;
+             type = ESS_JPEG_2000;
+           }
+       }
+      else if ( ASDCP_SUCCESS(TestHeader.GetMDObjectByType(OBJ_TYPE_ARGS(WaveAudioDescriptor), &md_object)) )
+       {
+         assert(md_object);
+         if ( static_cast<ASDCP::MXF::WaveAudioDescriptor*>(md_object)->AudioSamplingRate == SampleRate_96k )
+           {
+             type = ESS_PCM_24b_96k;
+           }
+         else
+           {
+             type = ESS_PCM_24b_48k;
+           }
+       }
+      else if ( ASDCP_SUCCESS(TestHeader.GetMDObjectByType(OBJ_TYPE_ARGS(MPEG2VideoDescriptor))) )
+       {
+       type = ESS_MPEG2_VES;
+       }
+      else if ( ASDCP_SUCCESS(TestHeader.GetMDObjectByType(OBJ_TYPE_ARGS(TimedTextDescriptor))) )
+       {
+       type = ESS_TIMED_TEXT;
+       }
+      else if ( ASDCP_SUCCESS(TestHeader.GetMDObjectByType(OBJ_TYPE_ARGS(DCDataDescriptor))) )
+       {
+         if ( ASDCP_SUCCESS(TestHeader.GetMDObjectByType(OBJ_TYPE_ARGS(DolbyAtmosSubDescriptor))) )
+           {
+             type = ESS_DCDATA_DOLBY_ATMOS;
+           }
+         else
+           {
+             type = ESS_DCDATA_UNKNOWN;
            }
        }
     }
@@ -170,6 +235,12 @@ ASDCP::RawEssenceType(const char* filename, EssenceType_t& type)
   type = ESS_UNKNOWN;
   ASDCP::FrameBuffer FB;
   Kumu::FileReader Reader;
+  ASDCP::Wav::SimpleWaveHeader WavHeader;
+  ASDCP::RF64::SimpleRF64Header RF64Header;
+  ASDCP::AIFF::SimpleAIFFHeader AIFFHeader;
+  Kumu::XMLElement TmpElement("Tmp");
+
+  ui32_t data_offset;
   ui32_t read_count;
   Result_t result = FB.Capacity(Wav::MaxWavHeader); // using Wav max because everything else is much smaller
 
@@ -185,19 +256,52 @@ ASDCP::RawEssenceType(const char* filename, EssenceType_t& type)
 
       if ( ASDCP_SUCCESS(result) )
        {
-         ASDCP::Wav::SimpleWaveHeader WavHeader;
-         ASDCP::AIFF::SimpleAIFFHeader AIFFHeader;
-         ui32_t data_offset;
          const byte_t* p = FB.RoData();
+         FB.Size(read_count);
 
-         if ( p[0] == 0 &&  p[1] == 0 &&  p[2] == 1 &&  (p[3] == 0xb3 || p[3] == 0) )
-           type = ESS_MPEG2_VES;
-
-         else if ( ASDCP_SUCCESS(WavHeader.ReadFromBuffer(p, read_count, &data_offset)) )
-           type = ESS_PCM_24b_48k;
+         ui32_t i = 0;
+         while ( p[i] == 0 ) i++;
 
-         else if ( ASDCP_SUCCESS(AIFFHeader.ReadFromBuffer(p, read_count, &data_offset)) )
-           type = ESS_PCM_24b_48k;
+         if ( i > 1 && p[i] == 1 &&  (p[i+1] == ASDCP::MPEG2::SEQ_START || p[i+1] == ASDCP::MPEG2::PIC_START) )
+           {
+             type = ESS_MPEG2_VES;
+           }
+         else if ( memcmp(FB.RoData(), ASDCP::JP2K::Magic, sizeof(ASDCP::JP2K::Magic)) == 0 )
+           {
+             type = ESS_JPEG_2000;
+           }
+         else if ( ASDCP_SUCCESS(WavHeader.ReadFromBuffer(FB.RoData(), read_count, &data_offset)) )
+           {
+             switch ( WavHeader.samplespersec )
+               {
+               case 48000: type = ESS_PCM_24b_48k; break;
+               case 96000: type = ESS_PCM_24b_96k; break;
+               default:
+                 return RESULT_FORMAT;
+               }
+           }
+         else if ( ASDCP_SUCCESS(RF64Header.ReadFromBuffer(FB.RoData(), read_count, &data_offset)) )
+           {
+             switch ( RF64Header.samplespersec )
+               {
+               case 48000: type = ESS_PCM_24b_48k; break;
+               case 96000: type = ESS_PCM_24b_96k; break;
+               default:
+                 return RESULT_FORMAT;
+               }
+           }
+         else if ( ASDCP_SUCCESS(AIFFHeader.ReadFromBuffer(FB.RoData(), read_count, &data_offset)) )
+           {
+             type = ESS_PCM_24b_48k;
+           }
+         else if ( Kumu::StringIsXML((const char*)FB.RoData(), FB.Size()) )
+           {
+             type = ESS_TIMED_TEXT;
+           }
+         else if ( ASDCP::ATMOS::IsDolbyAtmos(filename) )
+           {
+             type = ESS_DCDATA_DOLBY_ATMOS;
+           }
        }
     }
   else if ( Kumu::PathIsDirectory(filename) )
@@ -224,10 +328,38 @@ ASDCP::RawEssenceType(const char* filename, EssenceType_t& type)
                  Reader.Close();
                }
 
-             if ( ASDCP_SUCCESS(result)
-                  && ( memcmp(FB.RoData(), ASDCP::JP2K::Magic, sizeof(ASDCP::JP2K::Magic)) == 0 ) )
-               type = ESS_JPEG_2000;
-
+             if ( ASDCP_SUCCESS(result) )
+               {
+                 if ( memcmp(FB.RoData(), ASDCP::JP2K::Magic, sizeof(ASDCP::JP2K::Magic)) == 0 )
+                   {
+                     type = ESS_JPEG_2000;
+                   }
+                 else if ( ASDCP_SUCCESS(WavHeader.ReadFromBuffer(FB.RoData(), read_count, &data_offset)) )
+                   {
+                     switch ( WavHeader.samplespersec )
+                       {
+                       case 48000: type = ESS_PCM_24b_48k; break;
+                       case 96000: type = ESS_PCM_24b_96k; break;
+                       default:
+                         return RESULT_FORMAT;
+                       }
+                   }
+                 else if ( ASDCP_SUCCESS(RF64Header.ReadFromBuffer(FB.RoData(), read_count, &data_offset)) )
+                   {
+                     switch ( RF64Header.samplespersec )
+                       {
+                       case 48000: type = ESS_PCM_24b_48k; break;
+                       case 96000: type = ESS_PCM_24b_96k; break;
+                       default:
+                         return RESULT_FORMAT;
+                       }
+                   }
+                 else if ( ASDCP::ATMOS::IsDolbyAtmos(Str.c_str()) )
+                   {
+                     type = ESS_DCDATA_DOLBY_ATMOS;
+                   }
+               }
+             
              break;
            }
        }
@@ -367,7 +499,7 @@ ASDCP::DecryptFrameBuffer(const ASDCP::FrameBuffer& FBin, ASDCP::FrameBuffer& FB
 
 //
 Result_t
-ASDCP::IntegrityPack::CalcValues(const ASDCP::FrameBuffer& FB, byte_t* AssetID,
+ASDCP::IntegrityPack::CalcValues(const ASDCP::FrameBuffer& FB, const byte_t* AssetID,
                                 ui32_t sequence, HMACContext* HMAC)
 {
   ASDCP_TEST_NULL(AssetID);
@@ -375,7 +507,7 @@ ASDCP::IntegrityPack::CalcValues(const ASDCP::FrameBuffer& FB, byte_t* AssetID,
   byte_t* p = Data;
   HMAC->Reset();
 
-  static byte_t ber_4[MXF_BER_LENGTH] = {0x83, 0};
+  static byte_t ber_4[MXF_BER_LENGTH] = {0x83, 0, 0, 0};
 
   // update HMAC with essence data
   HMAC->Update(FB.RoData(), FB.Size());
@@ -417,7 +549,7 @@ ASDCP::IntegrityPack::CalcValues(const ASDCP::FrameBuffer& FB, byte_t* AssetID,
 
 
 Result_t
-ASDCP::IntegrityPack::TestValues(const ASDCP::FrameBuffer& FB, byte_t* AssetID,
+ASDCP::IntegrityPack::TestValues(const ASDCP::FrameBuffer& FB, const byte_t* AssetID,
                                 ui32_t sequence, HMACContext* HMAC)
 {
   ASDCP_TEST_NULL(AssetID);
@@ -447,7 +579,7 @@ ASDCP::IntegrityPack::TestValues(const ASDCP::FrameBuffer& FB, byte_t* AssetID,
   // test the sequence value
   if ( test_sequence != sequence )
     {
-      DefaultLogSink().Error("IntegrityPack failure: sequence is %lu, expecting %lu.\n", test_sequence, sequence);
+      DefaultLogSink().Error("IntegrityPack failure: sequence is %u, expecting %u.\n", test_sequence, sequence);
       return RESULT_HMACFAIL;
     }