Implemented J2K desc to/from MD
[asdcplib.git] / src / Dict.cpp
index 384843e45e936073b814b6025eb086fe0abe0e54..752b81a9fee32f297d422d98bb0b230e0309a46a 100755 (executable)
@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2006, John Hurst
+Copyright (c) 2006-2018, John Hurst
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -30,73 +30,368 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 
+#include "KM_mutex.h"
+#include "KM_log.h"
 #include "KLV.h"
 #include "MDD.cpp"
 
 //------------------------------------------------------------------------------------------
-// singleton wrapper
 
-const byte_t mdd_key[] = { 0x06, 0x0e, 0x2b, 0x34 };
+// The composite dict is the union of the SMPTE and Interop dicts
+//
+static ASDCP::Dictionary s_CompositeDict;
+static Kumu::Mutex s_CompositeDictLock;
+static bool s_CompositeDictInit = false;
+
+//
+const ASDCP::Dictionary&
+ASDCP::DefaultCompositeDict()
+{
+  if ( ! s_CompositeDictInit )
+    {
+      Kumu::AutoMutex AL(s_CompositeDictLock);
+
+      if ( ! s_CompositeDictInit )
+       {
+         s_CompositeDict.Init();
+         s_CompositeDictInit = true;
+       }
+    }
+
+  return s_CompositeDict;
+}
+
+//
+//
+static ASDCP::Dictionary s_InteropDict;
+static Kumu::Mutex s_InteropDictLock;
+static bool s_InteropDictInit = false;
+
+//
+const ASDCP::Dictionary&
+ASDCP::DefaultInteropDict()
+{
+  if ( ! s_InteropDictInit )
+    {
+      Kumu::AutoMutex AL(s_InteropDictLock);
+
+      if ( ! s_InteropDictInit )
+       {
+         s_InteropDict.Init();
+
+         s_InteropDict.DeleteEntry(MDD_MXFInterop_OPAtom);
+         s_InteropDict.DeleteEntry(MDD_MXFInterop_CryptEssence);
+         s_InteropDict.DeleteEntry(MDD_MXFInterop_GenericDescriptor_SubDescriptors);
+
+         s_InteropDict.AddEntry(s_MDD_Table[MDD_MXFInterop_OPAtom], MDD_OPAtom);
+         s_InteropDict.AddEntry(s_MDD_Table[MDD_MXFInterop_CryptEssence], MDD_CryptEssence);
+         s_InteropDict.AddEntry(s_MDD_Table[MDD_MXFInterop_GenericDescriptor_SubDescriptors],
+                                    MDD_GenericDescriptor_SubDescriptors);
+
+         s_InteropDictInit = true;
+       }
+    }
+
+  return s_InteropDict;
+}
+
+//
+//
+static ASDCP::Dictionary s_SMPTEDict;
+static Kumu::Mutex s_SMPTEDictLock;
+static bool s_SMPTEDictInit = false;
+
+//
+const ASDCP::Dictionary&
+ASDCP::DefaultSMPTEDict()
+{
+  if ( ! s_SMPTEDictInit )
+    {
+      Kumu::AutoMutex AL(s_SMPTEDictLock);
+
+      if ( ! s_SMPTEDictInit )
+       {
+         s_SMPTEDict.Init();
+
+         s_SMPTEDict.DeleteEntry(MDD_MXFInterop_OPAtom);
+         s_SMPTEDict.DeleteEntry(MDD_MXFInterop_CryptEssence);
+         s_SMPTEDict.DeleteEntry(MDD_MXFInterop_GenericDescriptor_SubDescriptors);
+
+         s_SMPTEDictInit = true;
+       }
+    }
+
+  return s_SMPTEDict;
+}
+
+//
+const ASDCP::MDDEntry&
+ASDCP::MXFInterop_OPAtom_Entry() {
+  return s_MDD_Table[MDD_MXFInterop_OPAtom];
+}
 
 //
 const ASDCP::MDDEntry&
-ASDCP::Dict::Type(MDD_t type_id)
+ASDCP::SMPTE_390_OPAtom_Entry() {
+  return s_MDD_Table[MDD_OPAtom];
+}
+
+//
+//
+static ASDCP::Dictionary s_AtmosSMPTEDict;
+static Kumu::Mutex s_AtmosSMPTEDictLock;
+static bool s_AtmosSMPTEDictInit = false;
+
+//
+const ASDCP::Dictionary&
+ASDCP::AtmosSMPTEDict()
 {
-  return s_MDD_Table[type_id];
+  if ( ! s_AtmosSMPTEDictInit )
+    {
+      Kumu::AutoMutex AL(s_AtmosSMPTEDictLock);
+
+      if ( ! s_AtmosSMPTEDictInit )
+       {
+         s_AtmosSMPTEDict.Init();
+
+         s_AtmosSMPTEDict.DeleteEntry(MDD_MXFInterop_OPAtom);
+         s_AtmosSMPTEDict.DeleteEntry(MDD_MXFInterop_CryptEssence);
+         s_AtmosSMPTEDict.DeleteEntry(MDD_MXFInterop_GenericDescriptor_SubDescriptors);
+
+         // legacy Atmos files have the wrong version byte
+         assert(s_AtmosSMPTEDict.Type(MDD_GenericDataEssenceDescriptor_DataEssenceCoding).ul[7] == 0x03);
+         s_AtmosSMPTEDict.MutableType(MDD_GenericDataEssenceDescriptor_DataEssenceCoding).ul[7] = 0x05;
+         
+         s_AtmosSMPTEDictInit = true;
+       }
+    }
+
+  return s_AtmosSMPTEDict;
+}
+
+//------------------------------------------------------------------------------------------
+//
+
+ASDCP::Dictionary::Dictionary() {}
+ASDCP::Dictionary::~Dictionary() {}
+
+//
+void
+ASDCP::Dictionary::Init()
+{
+  m_md_lookup.clear();
+  memset(m_MDD_Table, 0, sizeof(m_MDD_Table));
+
+  for ( ui32_t x = 0; x < (ui32_t)ASDCP::MDD_Max; ++x )
+    {
+      if ( x == MDD_PartitionMetadata_IndexSID_DEPRECATED  // 30
+          || x == MDD_PartitionMetadata_BodySID_DEPRECATED  // 32
+          || x == MDD_PartitionMetadata_OperationalPattern_DEPRECATED  // 33
+          || x == MDD_PartitionMetadata_EssenceContainers_DEPRECATED  // 34
+          || x == MDD_IndexTableSegmentBase_IndexSID_DEPRECATED  // 56
+          || x == MDD_IndexTableSegmentBase_BodySID_DEPRECATED  // 57
+          || x == MDD_PartitionArray_RandomIndexMetadata_BodySID_DEPRECATED  // 73
+          || x == MDD_Preface_OperationalPattern_DEPRECATED  // 84
+          || x == MDD_Preface_EssenceContainers_DEPRECATED  // 85
+          || x == MDD_EssenceContainerData_IndexSID_DEPRECATED  // 103
+          || x == MDD_EssenceContainerData_BodySID_DEPRECATED  // 104
+          || x == MDD_TimedTextResourceSubDescriptor_EssenceStreamID_DEPRECATED // 264
+          || x == MDD_DMSegment_DataDefinition_DEPRECATED // 266
+          || x == MDD_DMSegment_Duration_DEPRECATED // 267
+          )
+       continue;
+
+      AddEntry(s_MDD_Table[x], x);
+    }
+}
+
+//
+bool
+ASDCP::Dictionary::AddEntry(const MDDEntry& Entry, ui32_t index)
+{
+  if ( index >= (ui32_t)MDD_Max )
+    {
+      Kumu::DefaultLogSink().Warn("UL Dictionary: index exceeds maximum: %d\n", index);
+      return false;
+    }
+
+  bool result = true;
+  // is this index already there?
+  std::map<ui32_t, ASDCP::UL>::iterator rii = m_md_rev_lookup.find(index);
+
+  if ( rii != m_md_rev_lookup.end() )
+    {
+      DeleteEntry(index);
+      result = false;
+    }
+
+  UL TmpUL(Entry.ul);
+
+#define MDD_AUTHORING_MODE
+#ifdef MDD_AUTHORING_MODE
+  char buf[64];
+  std::map<ASDCP::UL, ui32_t>::iterator ii = m_md_lookup.find(TmpUL);
+  if ( ii != m_md_lookup.end() )
+    {
+      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,
+             Entry.tag.a, Entry.tag.b, Entry.name);
+    }
+#endif
+
+  m_md_lookup.insert(std::map<UL, ui32_t>::value_type(TmpUL, index));
+  m_md_rev_lookup.insert(std::map<ui32_t, UL>::value_type(index, TmpUL));
+  m_md_sym_lookup.insert(std::map<std::string, ui32_t>::value_type(Entry.name, index));
+  m_MDD_Table[index] = Entry;
+
+  return result;
+}
+
+//
+bool
+ASDCP::Dictionary::DeleteEntry(ui32_t index)
+{
+  std::map<ui32_t, ASDCP::UL>::iterator rii = m_md_rev_lookup.find(index);
+  if ( rii != m_md_rev_lookup.end() )
+    {
+      std::map<ASDCP::UL, ui32_t>::iterator ii = m_md_lookup.find(rii->second);
+      assert(ii != m_md_lookup.end());
+
+      MDDEntry NilEntry;
+      memset(&NilEntry, 0, sizeof(NilEntry));
+
+      m_md_lookup.erase(ii);
+      m_md_rev_lookup.erase(rii);
+      m_MDD_Table[index] = NilEntry;
+      return true;
+    }
+
+  return false;
+}
+
+//
+const ASDCP::MDDEntry&
+ASDCP::Dictionary::Type(MDD_t type_id) const
+{
+  assert(m_MDD_Table[0].name[0]);
+  std::map<ui32_t, ASDCP::UL>::const_iterator rii = m_md_rev_lookup.find(type_id);
+
+  if ( rii == m_md_rev_lookup.end() )
+    Kumu::DefaultLogSink().Warn("UL Dictionary: unknown UL type_id: %d\n", type_id);
+
+  return m_MDD_Table[type_id];
+}
+
+//
+ASDCP::MDDEntry&
+ASDCP::Dictionary::MutableType(MDD_t type_id)
+{
+  assert(m_MDD_Table[0].name[0]);
+  std::map<ui32_t, ASDCP::UL>::iterator rii = m_md_rev_lookup.find(type_id);
+
+  if ( rii == m_md_rev_lookup.end() )
+    Kumu::DefaultLogSink().Warn("UL Dictionary: unknown UL type_id: %d\n", type_id);
+
+  return m_MDD_Table[type_id];
 }
 
 //
 const ASDCP::MDDEntry*
-ASDCP::Dict::FindUL(const byte_t* ul_buf)
+ASDCP::Dictionary::FindULAnyVersion(const byte_t* ul_buf) const
 {
-  ui32_t t_idx = 0;
-  ui32_t k_idx = 8;
-
-  // must be a pointer to a SMPTE UL
-  if ( ul_buf == 0 || memcmp(mdd_key, ul_buf, 4) != 0 )
-    return 0;
-
-  // advance to first matching element
-  // TODO: optimize using binary search
-  while ( s_MDD_Table[t_idx].ul != 0
-         && s_MDD_Table[t_idx].ul[k_idx] != ul_buf[k_idx] )
-    t_idx++;
-
-  if ( s_MDD_Table[t_idx].ul == 0 )
-    return 0;
-
-  // match successive elements
-  while ( s_MDD_Table[t_idx].ul != 0
-         && k_idx < SMPTE_UL_LENGTH - 1
-         && s_MDD_Table[t_idx].ul[k_idx] == ul_buf[k_idx] )
+  assert(m_MDD_Table[0].name[0]);
+  byte_t search_ul[SMPTE_UL_LENGTH];
+  memcpy(search_ul, ul_buf, SMPTE_UL_LENGTH);
+  memset(search_ul+7, 0, SMPTE_UL_LENGTH-7);
+
+  UL target(ul_buf);
+  const ASDCP::MDDEntry *found_entry = 0;
+
+  std::map<UL, ui32_t>::const_iterator lower = m_md_lookup.lower_bound(UL(search_ul));
+
+  for ( ; lower != m_md_lookup.end(); ++lower )
     {
-      if ( s_MDD_Table[t_idx].ul[k_idx+1] == ul_buf[k_idx+1] )
+      if ( lower->first.MatchExact(target) )
        {
-         k_idx++;
+         found_entry = &m_MDD_Table[lower->second];
+         break;
        }
-      else
+      else if ( found_entry == 0 && lower->first.MatchIgnoreStream(target) )
        {
-         while ( s_MDD_Table[t_idx].ul != 0
-                 && s_MDD_Table[t_idx].ul[k_idx] == ul_buf[k_idx]
-                 && s_MDD_Table[t_idx].ul[k_idx+1] != ul_buf[k_idx+1] )
-           t_idx++;
-             
-         while ( s_MDD_Table[t_idx].ul[k_idx] != ul_buf[k_idx] )
-           k_idx--;
+         found_entry = &m_MDD_Table[lower->second];
        }
+      else if ( found_entry != 0 && ! lower->first.MatchIgnoreStream(target) )
+       {
+         break;
+       }
+    }
+
+  if ( found_entry == 0 )
+    {
+      char buf[64];
+      Kumu::DefaultLogSink().Warn("UL Dictionary: unknown UL: %s\n", target.EncodeString(buf, 64));
+    }
+
+  return found_entry;
+}
+
+//
+const ASDCP::MDDEntry*
+ASDCP::Dictionary::FindULExact(const byte_t* ul_buf) const
+{
+  assert(m_MDD_Table[0].name[0]);
+  std::map<UL, ui32_t>::const_iterator i = m_md_lookup.find(UL(ul_buf));
+  
+  if ( i == m_md_lookup.end() )
+    {
+      char buf[64];
+      UL tmp_ul(ul_buf);
+      Kumu::DefaultLogSink().Warn("UL Dictionary: unknown UL: %s\n", tmp_ul.EncodeString(buf, 64));
+      return 0;
     }
 
-  return (s_MDD_Table[t_idx].ul == 0 ? 0 : &s_MDD_Table[t_idx]);
+  return &m_MDD_Table[i->second];
 }
 
+//
+const ASDCP::MDDEntry*
+ASDCP::Dictionary::FindSymbol(const std::string& str) const
+{
+  assert(m_MDD_Table[0].name[0]);
+  std::map<std::string, ui32_t>::const_iterator i = m_md_sym_lookup.find(str);
+  
+  if ( i == m_md_sym_lookup.end() )
+    {
+      Kumu::DefaultLogSink().Warn("UL Dictionary: unknown symbol: %s\n", str.c_str());
+      return 0;
+    }
+
+  return &m_MDD_Table[i->second];
+}
 
 //
-// implementation
+void
+ASDCP::Dictionary::Dump(FILE* stream) const
+{
+  if ( stream == 0 )
+    stream = stderr;
 
-ASDCP::Dict::Dict() { DefaultLogSink().Warn("new Dict\n"); }
-ASDCP::Dict::~Dict() {}
+  MDD_t di = (MDD_t)0;
+  char     str_buf[64];
 
+  while ( di < MDD_Max )
+    {
+      if ( m_MDD_Table[di].name != 0 )
+       {
+         UL TmpUL(m_MDD_Table[di].ul);
+         fprintf(stream, "%s: %s\n", TmpUL.EncodeString(str_buf, 64), m_MDD_Table[di].name);
+       }
 
+      di = (MDD_t)(di + 1);
+    }
+}
 
 //
 // end Dict.cpp