UL dict final
[asdcplib.git] / src / h__Writer.cpp
index 297c74184b284db2401b49dd3059547e59e24da0..69873b65fb59611eff9b62c702e4be0bc20b0044 100755 (executable)
@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2004-2006, John Hurst
+Copyright (c) 2004-2009, John Hurst
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -41,12 +41,36 @@ using namespace ASDCP::MXF;
 #endif
 
 
+static std::vector<int>
+version_split(const char* str)
+{
+  std::vector<int> result;
+
+  const char* pstr = str;
+  const char* r = strchr(pstr, '.');
+
+  while ( r != 0 )
+    {
+      assert(r >= pstr);
+      if ( r > pstr )
+       result.push_back(atoi(pstr));
+
+      pstr = r + 1;
+      r = strchr(pstr, '.');
+    }
+
+  if( strlen(pstr) > 0 )
+    result.push_back(atoi(pstr));
+
+  assert(result.size() == 3);
+  return result;
+}
+
 
 //
-ASDCP::h__Writer::h__Writer() :
+ASDCP::h__Writer::h__Writer(const Dictionary& d) :
+  m_HeaderPart(m_Dict), m_BodyPart(m_Dict), m_FooterPart(m_Dict), m_Dict(&d),
   m_HeaderSize(0), m_EssenceStart(0),
-  m_MaterialPackage(0), m_MPTCSequence(0), m_MPTimecode(0), m_MPClSequence(0), m_MPClip(0),
-  m_FilePackage(0), m_FPTCSequence(0), m_FPTimecode(0), m_FPClSequence(0), m_FPClip(0),
   m_EssenceDescriptor(0), m_FramesWritten(0), m_StreamOffset(0)
 {
 }
@@ -55,67 +79,71 @@ ASDCP::h__Writer::~h__Writer()
 {
 }
 
-
 //
 // add DMS CryptographicFramework entry to source package
 void
-AddDMScrypt(Partition& HeaderPart, SourcePackage& Package, WriterInfo& Descr, const UL& WrappingUL)
+AddDMScrypt(Partition& HeaderPart, SourcePackage& Package,
+           WriterInfo& Descr, const UL& WrappingUL, const Dictionary*& Dict)
 {
+  assert(Dict);
   // Essence Track
-  StaticTrack* NewTrack = new StaticTrack;
+  StaticTrack* NewTrack = new StaticTrack(Dict);
   HeaderPart.AddChildObject(NewTrack);
   Package.Tracks.push_back(NewTrack->InstanceUID);
   NewTrack->TrackName = "Descriptive Track";
   NewTrack->TrackID = 3;
 
-  Sequence* Seq = new Sequence;
+  Sequence* Seq = new Sequence(Dict);
   HeaderPart.AddChildObject(Seq);
   NewTrack->Sequence = Seq->InstanceUID;
-  Seq->DataDefinition = UL(Dict::ul(MDD_DescriptiveMetaDataDef));
+  Seq->DataDefinition = UL(Dict->ul(MDD_DescriptiveMetaDataDef));
 
-  DMSegment* Segment = new DMSegment;
+  DMSegment* Segment = new DMSegment(Dict);
   HeaderPart.AddChildObject(Segment);
   Seq->StructuralComponents.push_back(Segment->InstanceUID);
   Segment->EventComment = "AS-DCP KLV Encryption";
   
-  CryptographicFramework* CFW = new CryptographicFramework;
+  CryptographicFramework* CFW = new CryptographicFramework(Dict);
   HeaderPart.AddChildObject(CFW);
   Segment->DMFramework = CFW->InstanceUID;
 
-  CryptographicContext* Context = new CryptographicContext;
+  CryptographicContext* Context = new CryptographicContext(Dict);
   HeaderPart.AddChildObject(Context);
   CFW->ContextSR = Context->InstanceUID;
 
   Context->ContextID.Set(Descr.ContextID);
   Context->SourceEssenceContainer = WrappingUL; // ??????
-  Context->CipherAlgorithm.Set(Dict::ul(MDD_CipherAlgorithm_AES));
-  Context->MICAlgorithm.Set( Descr.UsesHMAC ? Dict::ul(MDD_MICAlgorithm_HMAC_SHA1) : Dict::ul(MDD_MICAlgorithm_NONE) );
+  Context->CipherAlgorithm.Set(Dict->ul(MDD_CipherAlgorithm_AES));
+  Context->MICAlgorithm.Set( Descr.UsesHMAC ? Dict->ul(MDD_MICAlgorithm_HMAC_SHA1) : Dict->ul(MDD_MICAlgorithm_NONE) );
   Context->CryptographicKeyID.Set(Descr.CryptographicKeyID);
 }
 
 //
-Result_t
-ASDCP::h__Writer::WriteMXFHeader(const std::string& PackageLabel, const UL& WrappingUL,
-                                const std::string& TrackName, const UL& DataDefinition,
-                                const MXF::Rational& EditRate,
-                                ui32_t TCFrameRate, ui32_t BytesPerEditUnit)
+void
+ASDCP::h__Writer::InitHeader()
 {
-  ASDCP_TEST_NULL(m_EssenceDescriptor);
+  assert(m_Dict);
+  assert(m_EssenceDescriptor);
 
   m_HeaderPart.m_Primer.ClearTagList();
-  m_HeaderPart.m_Preface = new Preface;
+  m_HeaderPart.m_Preface = new Preface(m_Dict);
   m_HeaderPart.AddChildObject(m_HeaderPart.m_Preface);
 
   // Set the Operational Pattern label -- we're just starting and have no RIP or index,
   // so we tell the world by using OP1a
-  m_HeaderPart.m_Preface->OperationalPattern = UL(Dict::ul(MDD_OP1a));
+  m_HeaderPart.m_Preface->OperationalPattern = UL(m_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
   //
-  Identification* Ident = new Identification;
+  Identification* Ident = new Identification(m_Dict);
   m_HeaderPart.AddChildObject(Ident);
   m_HeaderPart.m_Preface->Identifications.push_back(Ident->InstanceUID);
 
@@ -125,178 +153,309 @@ ASDCP::h__Writer::WriteMXFHeader(const std::string& PackageLabel, const UL& Wrap
   Ident->VersionString = m_Info.ProductVersion.c_str();
   Ident->ProductUID.Set(m_Info.ProductUUID);
   Ident->Platform = ASDCP_PLATFORM;
-  Ident->ToolkitVersion.Major = VERSION_MAJOR;
-  Ident->ToolkitVersion.Minor = VERSION_APIMINOR;
-  Ident->ToolkitVersion.Patch = VERSION_IMPMINOR;
+
+  std::vector<int> version = version_split(Version());
+
+  Ident->ToolkitVersion.Major = version[0];
+  Ident->ToolkitVersion.Minor = version[1];
+  Ident->ToolkitVersion.Patch = version[2];
   Ident->ToolkitVersion.Build = ASDCP_BUILD_NUMBER;
-  Ident->ToolkitVersion.Release = VersionType::RL_DEVELOPMENT;
+  Ident->ToolkitVersion.Release = VersionType::RL_RELEASE;
+}
+
+//
+template <class ClipT>
+struct TrackSet
+{
+  MXF::Track*    Track;
+  MXF::Sequence* Sequence;
+  ClipT*         Clip;
+
+  TrackSet() : Track(0), Sequence(0), Clip(0) {}
+};
+
+//
+template <class PackageT, class ClipT>
+TrackSet<ClipT>
+CreateTrackAndSequence(OPAtomHeader& Header, PackageT& Package, const std::string TrackName,
+                      const MXF::Rational& EditRate, const UL& Definition, ui32_t TrackID, const Dictionary*& Dict)
+{
+  TrackSet<ClipT> NewTrack;
+
+  NewTrack.Track = new Track(Dict);
+  Header.AddChildObject(NewTrack.Track);
+  NewTrack.Track->EditRate = EditRate;
+  Package.Tracks.push_back(NewTrack.Track->InstanceUID);
+  NewTrack.Track->TrackID = TrackID;
+  NewTrack.Track->TrackName = TrackName.c_str();
+
+  NewTrack.Sequence = new Sequence(Dict);
+  Header.AddChildObject(NewTrack.Sequence);
+  NewTrack.Track->Sequence = NewTrack.Sequence->InstanceUID;
+  NewTrack.Sequence->DataDefinition = Definition;
+
+  return NewTrack;
+}
+
+//
+template <class PackageT>
+TrackSet<TimecodeComponent>
+CreateTimecodeTrack(OPAtomHeader& Header, PackageT& Package,
+                   const MXF::Rational& EditRate, ui32_t TCFrameRate, ui64_t TCStart, const Dictionary*& Dict)
+{
+  assert(Dict);
+  UL TCUL(Dict->ul(MDD_TimecodeDataDef));
+
+  TrackSet<TimecodeComponent> NewTrack = CreateTrackAndSequence<PackageT, TimecodeComponent>(Header, Package, "Timecode Track", EditRate, TCUL, 1, Dict);
+
+  NewTrack.Clip = new TimecodeComponent(Dict);
+  Header.AddChildObject(NewTrack.Clip);
+  NewTrack.Sequence->StructuralComponents.push_back(NewTrack.Clip->InstanceUID);
+  NewTrack.Clip->RoundedTimecodeBase = TCFrameRate;
+  NewTrack.Clip->StartTimecode = TCStart;
+  NewTrack.Clip->DataDefinition = TCUL;
+
+  return NewTrack;
+}
 
+
+//
+void
+ASDCP::h__Writer::AddSourceClip(const MXF::Rational& EditRate, ui32_t TCFrameRate,
+                               const std::string& TrackName, const UL& DataDefinition,
+                               const std::string& PackageLabel)
+{
   //
-  ContentStorage* Storage = new ContentStorage;
+  ContentStorage* Storage = new ContentStorage(m_Dict);
   m_HeaderPart.AddChildObject(Storage);
   m_HeaderPart.m_Preface->ContentStorage = Storage->InstanceUID;
 
-  EssenceContainerData* ECD = new EssenceContainerData;
+  EssenceContainerData* ECD = new EssenceContainerData(m_Dict);
   m_HeaderPart.AddChildObject(ECD);
   Storage->EssenceContainerData.push_back(ECD->InstanceUID);
   ECD->IndexSID = 129;
   ECD->BodySID = 1;
 
+  UUID assetUUID(m_Info.AssetUUID);
+  UMID SourcePackageUMID, MaterialPackageUMID;
+  SourcePackageUMID.MakeUMID(0x0f, assetUUID);
+  MaterialPackageUMID.MakeUMID(0x0f); // unidentified essence
+
   //
   // Material Package
   //
-  UMID PackageUMID;
-  PackageUMID.MakeUMID(0x0f); // unidentified essence
-  m_MaterialPackage = new MaterialPackage;
+  m_MaterialPackage = new MaterialPackage(m_Dict);
   m_MaterialPackage->Name = "AS-DCP Material Package";
-  m_MaterialPackage->PackageUID = PackageUMID;
+  m_MaterialPackage->PackageUID = MaterialPackageUMID;
   m_HeaderPart.AddChildObject(m_MaterialPackage);
   Storage->Packages.push_back(m_MaterialPackage->InstanceUID);
 
-  // Timecode Track
-  Track* NewTrack = new Track;
-  m_HeaderPart.AddChildObject(NewTrack);
-  NewTrack->EditRate = EditRate;
-  m_MaterialPackage->Tracks.push_back(NewTrack->InstanceUID);
-  NewTrack->TrackID = 1;
-  NewTrack->TrackName = "Timecode Track";
-
-  m_MPTCSequence = new Sequence;
-  m_HeaderPart.AddChildObject(m_MPTCSequence);
-  NewTrack->Sequence = m_MPTCSequence->InstanceUID;
-  m_MPTCSequence->DataDefinition = UL(Dict::ul(MDD_TimecodeDataDef));
-
-  m_MPTimecode = new TimecodeComponent;
-  m_HeaderPart.AddChildObject(m_MPTimecode);
-  m_MPTCSequence->StructuralComponents.push_back(m_MPTimecode->InstanceUID);
-  m_MPTimecode->RoundedTimecodeBase = TCFrameRate;
-  m_MPTimecode->StartTimecode = ui64_C(0);
-  m_MPTimecode->DataDefinition = UL(Dict::ul(MDD_TimecodeDataDef));
+  TrackSet<TimecodeComponent> MPTCTrack = CreateTimecodeTrack<MaterialPackage>(m_HeaderPart, *m_MaterialPackage,
+                                                                              EditRate, TCFrameRate, 0, m_Dict);
+  m_DurationUpdateList.push_back(&(MPTCTrack.Sequence->Duration));
+  m_DurationUpdateList.push_back(&(MPTCTrack.Clip->Duration));
 
-  // Essence Track
-  NewTrack = new Track;
-  m_HeaderPart.AddChildObject(NewTrack);
-  NewTrack->EditRate = EditRate;
-  m_MaterialPackage->Tracks.push_back(NewTrack->InstanceUID);
-  NewTrack->TrackID = 2;
-  NewTrack->TrackName = TrackName.c_str();
-
-  m_MPClSequence = new Sequence;
-  m_HeaderPart.AddChildObject(m_MPClSequence);
-  NewTrack->Sequence = m_MPClSequence->InstanceUID;
-  m_MPClSequence->DataDefinition = DataDefinition;
-
-  m_MPClip = new SourceClip;
-  m_HeaderPart.AddChildObject(m_MPClip);
-  m_MPClSequence->StructuralComponents.push_back(m_MPClip->InstanceUID);
-  m_MPClip->DataDefinition = DataDefinition;
+  TrackSet<SourceClip> MPTrack = CreateTrackAndSequence<MaterialPackage, SourceClip>(m_HeaderPart, *m_MaterialPackage,
+                                                                                    TrackName, EditRate, DataDefinition,
+                                                                                    2, m_Dict);
+  m_DurationUpdateList.push_back(&(MPTrack.Sequence->Duration));
+
+  MPTrack.Clip = new SourceClip(m_Dict);
+  m_HeaderPart.AddChildObject(MPTrack.Clip);
+  MPTrack.Sequence->StructuralComponents.push_back(MPTrack.Clip->InstanceUID);
+  MPTrack.Clip->DataDefinition = DataDefinition;
+  MPTrack.Clip->SourcePackageID = SourcePackageUMID;
+  MPTrack.Clip->SourceTrackID = 2;
+  m_DurationUpdateList.push_back(&(MPTrack.Clip->Duration));
 
+  
   //
   // File (Source) Package
   //
+  m_FilePackage = new SourcePackage(m_Dict);
+  m_FilePackage->Name = PackageLabel.c_str();
+  m_FilePackage->PackageUID = SourcePackageUMID;
+  ECD->LinkedPackageUID = SourcePackageUMID;
+
+  m_HeaderPart.AddChildObject(m_FilePackage);
+  Storage->Packages.push_back(m_FilePackage->InstanceUID);
+
+  TrackSet<TimecodeComponent> FPTCTrack = CreateTimecodeTrack<SourcePackage>(m_HeaderPart, *m_FilePackage,
+                                                                            EditRate, TCFrameRate,
+                                                                            ui64_C(3600) * TCFrameRate, m_Dict);
+  m_DurationUpdateList.push_back(&(FPTCTrack.Sequence->Duration));
+  m_DurationUpdateList.push_back(&(FPTCTrack.Clip->Duration));
+
+  TrackSet<SourceClip> FPTrack = CreateTrackAndSequence<SourcePackage, SourceClip>(m_HeaderPart, *m_FilePackage,
+                                                                                  TrackName, EditRate, DataDefinition,
+                                                                                  2, m_Dict);
+  m_DurationUpdateList.push_back(&(FPTrack.Sequence->Duration));
+
+  FPTrack.Clip = new SourceClip(m_Dict);
+  m_HeaderPart.AddChildObject(FPTrack.Clip);
+  FPTrack.Sequence->StructuralComponents.push_back(FPTrack.Clip->InstanceUID);
+  FPTrack.Clip->DataDefinition = DataDefinition;
+
+  // for now we do not allow setting this value, so all files will be 'original'
+  FPTrack.Clip->SourceTrackID = 0;
+  FPTrack.Clip->SourcePackageID = NilUMID;
+  m_DurationUpdateList.push_back(&(FPTrack.Clip->Duration));
+
+  m_EssenceDescriptor->LinkedTrackID = FPTrack.Track->TrackID;
+}
+
+//
+void
+ASDCP::h__Writer::AddDMSegment(const MXF::Rational& EditRate, ui32_t TCFrameRate,
+                               const std::string& TrackName, const UL& DataDefinition,
+                              const std::string& PackageLabel)
+{
+  //
+  ContentStorage* Storage = new ContentStorage(m_Dict);
+  m_HeaderPart.AddChildObject(Storage);
+  m_HeaderPart.m_Preface->ContentStorage = Storage->InstanceUID;
+
+  EssenceContainerData* ECD = new EssenceContainerData(m_Dict);
+  m_HeaderPart.AddChildObject(ECD);
+  Storage->EssenceContainerData.push_back(ECD->InstanceUID);
+  ECD->IndexSID = 129;
+  ECD->BodySID = 1;
+
   UUID assetUUID(m_Info.AssetUUID);
-  PackageUMID.MakeUMID(0x0f, assetUUID);
+  UMID SourcePackageUMID, MaterialPackageUMID;
+  SourcePackageUMID.MakeUMID(0x0f, assetUUID);
+  MaterialPackageUMID.MakeUMID(0x0f); // unidentified essence
+
+  //
+  // Material Package
+  //
+  m_MaterialPackage = new MaterialPackage(m_Dict);
+  m_MaterialPackage->Name = "AS-DCP Material Package";
+  m_MaterialPackage->PackageUID = MaterialPackageUMID;
+  m_HeaderPart.AddChildObject(m_MaterialPackage);
+  Storage->Packages.push_back(m_MaterialPackage->InstanceUID);
 
-  m_FilePackage = new SourcePackage;
+  TrackSet<TimecodeComponent> MPTCTrack = CreateTimecodeTrack<MaterialPackage>(m_HeaderPart, *m_MaterialPackage,
+                                                                              EditRate, TCFrameRate, 0, m_Dict);
+  m_DurationUpdateList.push_back(&(MPTCTrack.Sequence->Duration));
+  m_DurationUpdateList.push_back(&(MPTCTrack.Clip->Duration));
+
+  TrackSet<DMSegment> MPTrack = CreateTrackAndSequence<MaterialPackage, DMSegment>(m_HeaderPart, *m_MaterialPackage,
+                                                                                  TrackName, EditRate, DataDefinition,
+                                                                                  2, m_Dict);
+  m_DurationUpdateList.push_back(&(MPTrack.Sequence->Duration));
+
+  MPTrack.Clip = new DMSegment(m_Dict);
+  m_HeaderPart.AddChildObject(MPTrack.Clip);
+  MPTrack.Sequence->StructuralComponents.push_back(MPTrack.Clip->InstanceUID);
+  MPTrack.Clip->DataDefinition = DataDefinition;
+  //  MPTrack.Clip->SourcePackageID = SourcePackageUMID;
+  //  MPTrack.Clip->SourceTrackID = 2;
+  m_DurationUpdateList.push_back(&(MPTrack.Clip->Duration));
+
+  
+  //
+  // File (Source) Package
+  //
+  m_FilePackage = new SourcePackage(m_Dict);
   m_FilePackage->Name = PackageLabel.c_str();
-  m_FilePackage->PackageUID = PackageUMID;
-  ECD->LinkedPackageUID = PackageUMID;
-  m_MPClip->SourcePackageID = PackageUMID;
-  m_MPClip->SourceTrackID = 1;
+  m_FilePackage->PackageUID = SourcePackageUMID;
+  ECD->LinkedPackageUID = SourcePackageUMID;
 
   m_HeaderPart.AddChildObject(m_FilePackage);
   Storage->Packages.push_back(m_FilePackage->InstanceUID);
 
-  // Timecode Track
-  NewTrack = new Track;
-  m_HeaderPart.AddChildObject(NewTrack);
-  NewTrack->EditRate = EditRate;
-  m_FilePackage->Tracks.push_back(NewTrack->InstanceUID);
-  NewTrack->TrackID = 1;
-  NewTrack->TrackName = "Timecode Track";
-
-  m_FPTCSequence = new Sequence;
-  m_HeaderPart.AddChildObject(m_FPTCSequence);
-  NewTrack->Sequence = m_FPTCSequence->InstanceUID;
-  m_FPTCSequence->DataDefinition = UL(Dict::ul(MDD_TimecodeDataDef));
-
-  m_FPTimecode = new TimecodeComponent;
-  m_HeaderPart.AddChildObject(m_FPTimecode);
-  m_FPTCSequence->StructuralComponents.push_back(m_FPTimecode->InstanceUID);
-  m_FPTimecode->RoundedTimecodeBase = TCFrameRate;
-  m_FPTimecode->StartTimecode = ui64_C(86400); // 01:00:00:00
-  m_FPTimecode->DataDefinition = UL(Dict::ul(MDD_TimecodeDataDef));
-
-  // Essence Track
-  NewTrack = new Track;
-  m_HeaderPart.AddChildObject(NewTrack);
-  NewTrack->EditRate = EditRate;
-  m_FilePackage->Tracks.push_back(NewTrack->InstanceUID);
-  NewTrack->TrackID = 2;
-  NewTrack->TrackName = TrackName.c_str();
-
-  m_FPClSequence = new Sequence;
-  m_HeaderPart.AddChildObject(m_FPClSequence);
-  NewTrack->Sequence = m_FPClSequence->InstanceUID;
-  m_FPClSequence->DataDefinition = DataDefinition;
-
-  m_FPClip = new SourceClip;
-  m_HeaderPart.AddChildObject(m_FPClip);
-  m_FPClSequence->StructuralComponents.push_back(m_FPClip->InstanceUID);
-  m_FPClip->DataDefinition = DataDefinition;
+  TrackSet<TimecodeComponent> FPTCTrack = CreateTimecodeTrack<SourcePackage>(m_HeaderPart, *m_FilePackage,
+                                                                            EditRate, TCFrameRate,
+                                                                            ui64_C(3600) * TCFrameRate, m_Dict);
+  m_DurationUpdateList.push_back(&(FPTCTrack.Sequence->Duration));
+  m_DurationUpdateList.push_back(&(FPTCTrack.Clip->Duration));
+
+  TrackSet<DMSegment> FPTrack = CreateTrackAndSequence<SourcePackage, DMSegment>(m_HeaderPart, *m_FilePackage,
+                                                                                TrackName, EditRate, DataDefinition,
+                                                                                2, m_Dict);
+  m_DurationUpdateList.push_back(&(FPTrack.Sequence->Duration));
+
+  FPTrack.Clip = new DMSegment(m_Dict);
+  m_HeaderPart.AddChildObject(FPTrack.Clip);
+  FPTrack.Sequence->StructuralComponents.push_back(FPTrack.Clip->InstanceUID);
+  FPTrack.Clip->DataDefinition = DataDefinition;
+  FPTrack.Clip->EventComment = "D-Cinema Timed Text";
+
+  m_DurationUpdateList.push_back(&(FPTrack.Clip->Duration));
+  m_EssenceDescriptor->LinkedTrackID = FPTrack.Track->TrackID;
+}
 
+//
+void
+ASDCP::h__Writer::AddEssenceDescriptor(const UL& WrappingUL)
+{
   //
   // Essence Descriptor
   //
   m_EssenceDescriptor->EssenceContainer = WrappingUL;
-  m_EssenceDescriptor->LinkedTrackID = NewTrack->TrackID;
   m_HeaderPart.m_Preface->PrimaryPackage = m_FilePackage->InstanceUID;
 
   //
-  // Encryption Descriptor
+  // Essence Descriptors
   //
+  assert(m_Dict);
+  UL GenericContainerUL(m_Dict->ul(MDD_GCMulti));
+  m_HeaderPart.EssenceContainers.push_back(GenericContainerUL);
+
   if ( m_Info.EncryptedEssence )
     {
-      UL CryptEssenceUL(Dict::ul(MDD_EncryptedContainerLabel));
+      UL CryptEssenceUL(m_Dict->ul(MDD_EncryptedContainerLabel));
       m_HeaderPart.EssenceContainers.push_back(CryptEssenceUL);
-      m_HeaderPart.m_Preface->DMSchemes.push_back(UL(Dict::ul(MDD_CryptographicFrameworkLabel)));
-      AddDMScrypt(m_HeaderPart, *m_FilePackage, m_Info, WrappingUL);
+      m_HeaderPart.m_Preface->DMSchemes.push_back(UL(m_Dict->ul(MDD_CryptographicFrameworkLabel)));
+      AddDMScrypt(m_HeaderPart, *m_FilePackage, m_Info, WrappingUL, m_Dict);
     }
   else
     {
-      m_HeaderPart.EssenceContainers.push_back(UL(Dict::ul(MDD_GCMulti)));
       m_HeaderPart.EssenceContainers.push_back(WrappingUL);
     }
 
   m_HeaderPart.m_Preface->EssenceContainers = m_HeaderPart.EssenceContainers;
   m_HeaderPart.AddChildObject(m_EssenceDescriptor);
+
+  std::list<InterchangeObject*>::iterator sdli = m_EssenceSubDescriptorList.begin();
+  for ( ; sdli != m_EssenceSubDescriptorList.end(); sdli++ )
+      m_HeaderPart.AddChildObject(*sdli);
+
   m_FilePackage->Descriptor = m_EssenceDescriptor->InstanceUID;
+}
 
-  // Write the header partition
-  Result_t result = m_HeaderPart.WriteToFile(m_File, m_HeaderSize);
+//
+Result_t
+ASDCP::h__Writer::CreateBodyPart(const MXF::Rational& EditRate, ui32_t BytesPerEditUnit)
+{
+  assert(m_Dict);
+  Result_t result = RESULT_OK;
 
-  if ( ASDCP_SUCCESS(result) )
+  // create a body partition if we're writing proper 429-3/OP-Atom
+  if ( m_Info.LabelSetType == LS_MXF_SMPTE )
     {
       // Body Partition
       m_BodyPart.EssenceContainers = m_HeaderPart.EssenceContainers;
       m_BodyPart.ThisPartition = m_File.Tell();
       m_BodyPart.BodySID = 1;
-      UL OPAtomUL(Dict::ul(MDD_OPAtom));
-
-      if ( m_Info.LabelSetType == LS_MXF_INTEROP )
-       OPAtomUL.Set(Dict::ul(MDD_MXFInterop_OPAtom));
-
+      UL OPAtomUL(m_Dict->ul(MDD_OPAtom));
       m_BodyPart.OperationalPattern = OPAtomUL;
       m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(1, m_BodyPart.ThisPartition)); // Second RIP Entry
       
-      UL BodyUL(Dict::ul(MDD_ClosedCompleteBodyPartition));
+      UL BodyUL(m_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);
@@ -307,6 +466,23 @@ ASDCP::h__Writer::WriteMXFHeader(const std::string& PackageLabel, const UL& Wrap
   return result;
 }
 
+//
+Result_t
+ASDCP::h__Writer::WriteMXFHeader(const std::string& PackageLabel, const UL& WrappingUL,
+                                const std::string& TrackName, const UL& DataDefinition,
+                                const MXF::Rational& EditRate, ui32_t TCFrameRate, ui32_t BytesPerEditUnit)
+{
+  InitHeader();
+  AddSourceClip(EditRate, TCFrameRate, TrackName, DataDefinition, PackageLabel);
+  AddEssenceDescriptor(WrappingUL);
+
+  Result_t result = m_HeaderPart.WriteToFile(m_File, m_HeaderSize);
+
+  if ( KM_SUCCESS(result) )
+    result = CreateBodyPart(EditRate, BytesPerEditUnit);
+
+  return result;
+}
 
 
 // standard method of writing a plaintext or encrypted frame
@@ -319,6 +495,7 @@ ASDCP::h__Writer::WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf, const byte
 
   byte_t overhead[128];
   Kumu::MemIOWriter Overhead(overhead, 128);
+  assert(m_Dict);
 
   if ( FrameBuf.Size() == 0 )
     {
@@ -346,10 +523,7 @@ ASDCP::h__Writer::WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf, const byte
 
       if ( ASDCP_SUCCESS(result) )
        { // write UL
-         if ( m_Info.LabelSetType == LS_MXF_INTEROP )
-           Overhead.WriteRaw(Dict::ul(MDD_MXFInterop_CryptEssence), SMPTE_UL_LENGTH);
-         else
-           Overhead.WriteRaw(Dict::ul(MDD_CryptEssence), SMPTE_UL_LENGTH);
+         Overhead.WriteRaw(m_Dict->ul(MDD_CryptEssence), SMPTE_UL_LENGTH);
 
          // construct encrypted triplet header
          ui32_t ETLength = klv_cryptinfo_size + m_CtFrameBuf.Size();
@@ -430,24 +604,27 @@ ASDCP::h__Writer::WriteMXFFooter()
 {
   // Set top-level file package correctly for OP-Atom
 
-  m_MPTCSequence->Duration = m_MPTimecode->Duration = m_MPClSequence->Duration = m_MPClip->Duration = 
-    m_FPTCSequence->Duration = m_FPTimecode->Duration = m_FPClSequence->Duration = m_FPClip->Duration = 
-    m_EssenceDescriptor->ContainerDuration = m_FramesWritten;
+  //  m_MPTCSequence->Duration = m_MPTimecode->Duration = m_MPClSequence->Duration = m_MPClip->Duration = 
+  //    m_FPTCSequence->Duration = m_FPTimecode->Duration = m_FPClSequence->Duration = m_FPClip->Duration = 
+
+  DurationElementList_t::iterator dli = m_DurationUpdateList.begin();
+
+  for (; dli != m_DurationUpdateList.end(); dli++ )
+    **dli = m_FramesWritten;
+
+  m_EssenceDescriptor->ContainerDuration = m_FramesWritten;
+  m_FooterPart.PreviousPartition = m_HeaderPart.m_RIP.PairArray.back().ByteOffset;
 
   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;
 
+  assert(m_Dict);
   // re-label the partition
-  UL OPAtomUL(Dict::ul(MDD_OPAtom));
-
-  if ( m_Info.LabelSetType == LS_MXF_INTEROP )
-    OPAtomUL.Set(Dict::ul(MDD_MXFInterop_OPAtom));
-  
+  UL OPAtomUL(m_Dict->ul(MDD_OPAtom));
   m_HeaderPart.OperationalPattern = OPAtomUL;
   m_HeaderPart.m_Preface->OperationalPattern = m_HeaderPart.OperationalPattern;
 
-  m_FooterPart.PreviousPartition = m_BodyPart.ThisPartition;
   m_FooterPart.OperationalPattern = m_HeaderPart.OperationalPattern;
   m_FooterPart.EssenceContainers = m_HeaderPart.EssenceContainers;
   m_FooterPart.FooterPartition = here;