ISXDDataEssenceDescriptor_NamespaceURI UL fixed
[asdcplib.git] / src / h__02_Writer.cpp
index 0ff06606be840eb38f3339aa720893c115885e2e..9b1c6c6d27625db4d94b3e77825ae455b62d6038 100644 (file)
@@ -1,28 +1,30 @@
 /*
-  Copyright (c) 2011-2012, Robert Scheler, Heiko Sparenberg Fraunhofer IIS, John Hurst
-  All rights reserved.
-
-  Redistribution and use in source and binary forms, with or without
-  modification, are permitted provided that the following conditions
-  are met:
-  1. Redistributions of source code must retain the above copyright
-  notice, this list of conditions and the following disclaimer.
-  2. Redistributions in binary form must reproduce the above copyright
-  notice, this list of conditions and the following disclaimer in the
-  documentation and/or other materials provided with the distribution.
-  3. The name of the author may not be used to endorse or promote products
-  derived from this software without specific prior written permission.
-
-  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
-  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
-  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+Copyright (c) 2011-2018, Robert Scheler, Heiko Sparenberg Fraunhofer IIS,
+John Hurst
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+   derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */ 
 /*! \file    h__02_Writer.cpp
   \version $Id$
 using namespace ASDCP;
 using namespace ASDCP::MXF;
 
-// a magic number identifying asdcplib
-#ifndef ASDCP_BUILD_NUMBER
-#define ASDCP_BUILD_NUMBER 0x6A68
-#endif
+static const ui32_t CBRIndexEntriesPerSegment = 5000;
 
+
+//------------------------------------------------------------------------------------------
 //
-AS_02::h__Writer::h__Writer(const Dictionary& d) :
-  m_HeaderPart(m_Dict), m_FooterPart(m_Dict), m_Dict(&d),
-  m_HeaderSize(0), m_EssenceStart(0),
-  m_EssenceDescriptor(0), m_FramesWritten(0),
-  m_StreamOffset(0), m_BodyOffset(0),
-  m_CurrentBodySID(0), m_CurrentIndexSID(0),
-  m_PartitionSpace(60), m_IndexStrategy(AS_02::IS_FOLLOW)
-{
-}
 
-AS_02::h__Writer::~h__Writer()
+AS_02::MXF::AS02IndexWriterVBR::AS02IndexWriterVBR(const ASDCP::Dictionary*& d) :
+  Partition(d), m_CurrentSegment(0), m_Dict(d), m_Lookup(0)
 {
-  while (! m_BodyPartList.empty() )
-    {
-      delete m_BodyPartList.back();
-      m_BodyPartList.pop_back();
-    }
+  BodySID = 0;
+  IndexSID = 129;
+  MinorVersion = 3;
 }
 
+AS_02::MXF::AS02IndexWriterVBR::~AS02IndexWriterVBR() {}
+
 //
-void
-AS_02::h__Writer::InitHeader()
+Result_t
+AS_02::MXF::AS02IndexWriterVBR::WriteToFile(Kumu::FileWriter& Writer)
 {
   assert(m_Dict);
-  assert(m_EssenceDescriptor);
-
-  m_HeaderPart.m_Primer.ClearTagList();
-  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(m_Dict->ul(MDD_OP1a));
-  m_HeaderPart.OperationalPattern = m_HeaderPart.m_Preface->OperationalPattern;
-
-  //always more than 3 partition in AS-02; essence is not permitted to be existent in the header
-  m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(0, 0)); // no essence in header
-
-  //
-  // Identification
-  //
-  Identification* Ident = new Identification(m_Dict);
-  m_HeaderPart.AddChildObject(Ident);
-  m_HeaderPart.m_Preface->Identifications.push_back(Ident->InstanceUID);
-
-  Kumu::GenRandomValue(Ident->ThisGenerationUID);
-  Ident->CompanyName = m_Info.CompanyName.c_str();
-  Ident->ProductName = m_Info.ProductName.c_str();
-  Ident->VersionString = m_Info.ProductVersion.c_str();
-  Ident->ProductUID.Set(m_Info.ProductUUID);
-  Ident->Platform = ASDCP_PLATFORM;
-
-  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_RELEASE;
-}
+  ASDCP::FrameBuffer index_body_buffer;
+  ui32_t index_body_size = (ui32_t)m_PacketList->m_List.size() * MaxIndexSegmentSize; // segment-count * max-segment-size
+  Result_t result = index_body_buffer.Capacity(index_body_size); 
+  ui64_t start_position = 0;
 
-template <class ClipT>
-struct TrackSet
-{
-  MXF::Track*    Track;
-  MXF::Sequence* Sequence;
-  ClipT*         Clip;
+  if ( m_CurrentSegment != 0 )
+    {
+      m_CurrentSegment->IndexDuration = m_CurrentSegment->IndexEntryArray.size();
+      start_position = m_CurrentSegment->IndexStartPosition + m_CurrentSegment->IndexDuration;
+      m_CurrentSegment = 0;
+    }
 
-  TrackSet() : Track(0), Sequence(0), Clip(0) {}
-};
+  std::list<InterchangeObject*>::iterator pl_i = m_PacketList->m_List.begin();
+  for ( ; pl_i != m_PacketList->m_List.end() && KM_SUCCESS(result); pl_i++ )
+    {
+      InterchangeObject* object = *pl_i;
+      object->m_Lookup = m_Lookup;
+
+      ASDCP::FrameBuffer WriteWrapper;
+      WriteWrapper.SetData(index_body_buffer.Data() + index_body_buffer.Size(),
+                          index_body_buffer.Capacity() - index_body_buffer.Size());
+      result = object->WriteToBuffer(WriteWrapper);
+      index_body_buffer.Size(index_body_buffer.Size() + WriteWrapper.Size());
+      delete *pl_i;
+      *pl_i = 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;
+  m_PacketList->m_List.clear();
 
-  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();
+  if ( KM_SUCCESS(result) )
+    {
+      IndexByteCount = index_body_buffer.Size();
+      UL body_ul(m_Dict->ul(MDD_ClosedCompleteBodyPartition));
+      result = Partition::WriteToFile(Writer, body_ul);
+    }
 
-  NewTrack.Sequence = new Sequence(Dict);
-  Header.AddChildObject(NewTrack.Sequence);
-  NewTrack.Track->Sequence = NewTrack.Sequence->InstanceUID;
-  NewTrack.Sequence->DataDefinition = Definition;
+  if ( KM_SUCCESS(result) )
+    {
+      ui32_t write_count = 0;
+      result = Writer.Write(index_body_buffer.RoData(), index_body_buffer.Size(), &write_count);
+      assert(write_count == index_body_buffer.Size());
+    }
 
-  return NewTrack;
+  if ( KM_SUCCESS(result) )
+    {
+      m_CurrentSegment = new IndexTableSegment(m_Dict);
+      assert(m_CurrentSegment);
+      AddChildObject(m_CurrentSegment);
+      m_CurrentSegment->DeltaEntryArray.push_back(IndexTableSegment::DeltaEntry());
+      m_CurrentSegment->IndexEditRate = m_EditRate;
+      m_CurrentSegment->IndexStartPosition = start_position;
+    }
+
+  return result;
 }
 
 //
-template <class PackageT>
-TrackSet<TimecodeComponent>
-CreateTimecodeTrack(OPAtomHeader& Header, PackageT& Package,
-                   const MXF::Rational& EditRate, ui32_t TCFrameRate, ui64_t TCStart, const Dictionary*& Dict)
+void
+AS_02::MXF::AS02IndexWriterVBR::Dump(FILE* stream)
 {
-  assert(Dict);
-  UL TCUL(Dict->ul(MDD_TimecodeDataDef));
+  if ( stream == 0 )
+    stream = stderr;
 
-  TrackSet<TimecodeComponent> NewTrack = CreateTrackAndSequence<PackageT, TimecodeComponent>(Header, Package, "Timecode Track", EditRate, TCUL, 1, Dict);
+  Partition::Dump(stream);
 
-  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;
+  std::list<InterchangeObject*>::iterator i = m_PacketList->m_List.begin();
+  for ( ; i != m_PacketList->m_List.end(); ++i )
+    {
+      (*i)->Dump(stream);
+    }
 }
 
-
 //
-void
-AS_02::h__Writer::AddSourceClip(const ASDCP::MXF::Rational& EditRate, ui32_t TCFrameRate,
-                               const std::string& TrackName, const UL& EssenceUL,
-                               const UL& DataDefinition, const std::string& PackageLabel)
+ui32_t
+AS_02::MXF::AS02IndexWriterVBR::GetDuration() const
 {
-  //
-  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);
-  UMID SourcePackageUMID, MaterialPackageUMID;
-  SourcePackageUMID.MakeUMID(0x0f, assetUUID);
-  MaterialPackageUMID.MakeUMID(0x0f); // unidentified essence
-
-  //
-  // Material Package
-  //
-  m_MaterialPackage = new MaterialPackage(m_Dict);
-  m_MaterialPackage->Name = "AS_02 Material Package";
-  m_MaterialPackage->PackageUID = MaterialPackageUMID;
-  m_HeaderPart.AddChildObject(m_MaterialPackage);
-  Storage->Packages.push_back(m_MaterialPackage->InstanceUID);
-
-  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<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));
-
-  // Consult ST 379:2004 Sec. 6.3, "Element to track relationship" to see where "12" comes from.
-  FPTrack.Track->TrackNumber = KM_i32_BE(Kumu::cp2i<ui32_t>((EssenceUL.Value() + 12)));
-
-  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;
+  ui32_t duration = 0;
+  std::list<InterchangeObject*>::const_iterator i;
+
+  for ( i = m_PacketList->m_List.begin(); i != m_PacketList->m_List.end(); ++i )
+    {
+      IndexTableSegment* segment = dynamic_cast<IndexTableSegment*>(*i);
+      if ( segment != 0 )
+       {
+         duration += (ui32_t)segment->IndexEntryArray.size();
+       }
+    }
+
+  return duration;
 }
 
 //
 void
-AS_02::h__Writer::AddDMSegment(const ASDCP::MXF::Rational& EditRate, ui32_t TCFrameRate,
-                              const std::string& TrackName, const UL& DataDefinition,
-                              const std::string& PackageLabel)
+AS_02::MXF::AS02IndexWriterVBR::PushIndexEntry(const IndexTableSegment::IndexEntry& Entry)
 {
-  //
-  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);
-  UMID SourcePackageUMID, MaterialPackageUMID;
-  SourcePackageUMID.MakeUMID(0x0f, assetUUID);
-  MaterialPackageUMID.MakeUMID(0x0f); // unidentified essence
-
-  //
-  // Material Package
-  //
-  m_MaterialPackage = new MaterialPackage(m_Dict);
-  m_MaterialPackage->Name = "AS_02 Material Package";
-  m_MaterialPackage->PackageUID = MaterialPackageUMID;
-  m_HeaderPart.AddChildObject(m_MaterialPackage);
-  Storage->Packages.push_back(m_MaterialPackage->InstanceUID);
-
-  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 = 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<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;
+  // do we have an available segment?
+  if ( m_CurrentSegment == 0 )
+    { // no, set up a new segment
+      m_CurrentSegment = new IndexTableSegment(m_Dict);
+      assert(m_CurrentSegment);
+      AddChildObject(m_CurrentSegment);
+      m_CurrentSegment->DeltaEntryArray.push_back(IndexTableSegment::DeltaEntry());
+      m_CurrentSegment->IndexEditRate = m_EditRate;
+      m_CurrentSegment->IndexStartPosition = 0;
+    }
+
+  m_CurrentSegment->IndexEntryArray.push_back(Entry);
 }
 
-//
 void
-AS_02::h__Writer::AddEssenceDescriptor(const UL& WrappingUL)
+AS_02::MXF::AS02IndexWriterVBR::SetEditRate(const ASDCP::Rational& edit_rate)
 {
-  //
-  // Essence Descriptor
-  //
-  m_EssenceDescriptor->EssenceContainer = WrappingUL;
-  m_HeaderPart.m_Preface->PrimaryPackage = m_FilePackage->InstanceUID;
-
-  //
-  // Essence Descriptors
-  //
-  assert(m_Dict);
-  //TODO: Mono Essence, only one GenericContainer ? 
-  //UL GenericContainerUL(m_Dict->ul(MDD_GCMulti));
-  //m_HeaderPart.EssenceContainers.push_back(GenericContainerUL);
-
-  if ( m_Info.EncryptedEssence )
-    {
-      UL CryptEssenceUL(m_Dict->ul(MDD_EncryptedContainerLabel));
-      m_HeaderPart.EssenceContainers.push_back(CryptEssenceUL);
-      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(WrappingUL);
-    }
+  m_EditRate = edit_rate;
+}
 
-  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);
+//
+AS_02::h__AS02WriterFrame::h__AS02WriterFrame(const ASDCP::Dictionary& d) :
+  h__AS02Writer<AS_02::MXF::AS02IndexWriterVBR>(d), m_IndexStrategy(AS_02::IS_FOLLOW) {}
 
-  m_FilePackage->Descriptor = m_EssenceDescriptor->InstanceUID;
-}
+AS_02::h__AS02WriterFrame::~h__AS02WriterFrame() {}
 
 //
 Result_t
-AS_02::h__Writer::CreateBodyPart(const ASDCP::MXF::Rational& EditRate, ui32_t BytesPerEditUnit)
+AS_02::h__AS02WriterFrame::WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf,const byte_t* EssenceUL,
+                                          const ui32_t& MinEssenceElementBerLength,
+                                          AESEncContext* Ctx, HMACContext* HMAC)
 {
-  assert(m_Dict);
-  Result_t result = RESULT_OK;
-  m_EditRate = EditRate;
-  m_BytesPerEditUnit = BytesPerEditUnit;
+  ui64_t this_stream_offset = m_StreamOffset; // m_StreamOffset will be changed by the call to Write_EKLV_Packet
 
-  result = CreateBodyPartPair();
+  Result_t result = Write_EKLV_Packet(m_File, *m_Dict, m_HeaderPart, m_Info, m_CtFrameBuf, m_FramesWritten,
+                                     m_StreamOffset, FrameBuf, EssenceUL, MinEssenceElementBerLength, Ctx, HMAC);
 
-  //TODO: no IndexTables in the footer -> The spec is silent on that topic
-  m_FooterPart.IndexSID = 0;//129;
+  if ( KM_SUCCESS(result) )
+    {  
+      IndexTableSegment::IndexEntry Entry;
+      Entry.StreamOffset = this_stream_offset;
+      m_IndexWriter.PushIndexEntry(Entry);
+    }
+
+  if ( m_FramesWritten > 1 && ( ( m_FramesWritten + 1 ) % m_PartitionSpace ) == 0 )
+    {
+      assert(m_IndexWriter.GetDuration() > 0);
+      FlushIndexPartition();
+
+      UL body_ul(m_Dict->ul(MDD_ClosedCompleteBodyPartition));
+      Partition body_part(m_Dict);
+      body_part.MajorVersion = m_HeaderPart.MajorVersion;
+      body_part.MinorVersion = m_HeaderPart.MinorVersion;
+      body_part.BodySID = 1;
+      body_part.OperationalPattern = m_HeaderPart.OperationalPattern;
+      body_part.EssenceContainers = m_HeaderPart.EssenceContainers;
+      body_part.ThisPartition = m_File.Tell();
+
+      body_part.BodyOffset = m_StreamOffset;
+      result = body_part.WriteToFile(m_File, body_ul);
+      m_RIP.PairArray.push_back(RIP::PartitionPair(1, body_part.ThisPartition));
+    }
 
   return result;
 }
 
-// standard method of creating a new BodyPartition Pair for Essence and IndexTables
-Result_t AS_02::h__Writer::CreateBodyPartPair()
-{
-  Result_t result = RESULT_OK;
-
-  if ( m_IndexStrategy == AS_02::IS_FILE_SPECIFIC ){
-    result = RESULT_FAIL;
-  }
-
-  //similar to both index strategies  
-
-  Partition *m_BodyPartEssence = new ASDCP::MXF::Partition(m_Dict);       
-  m_BodyPartEssence->EssenceContainers = m_HeaderPart.EssenceContainers;
-  //necessary? - here we must increment the BodySID, when a new BodyPartion is created
-  m_BodyPartEssence->BodySID = 1;//++m_CurrentBodySID;
-  UL OperationalPattern(m_Dict->ul(MDD_OP1a));
-  m_BodyPartEssence->OperationalPattern = OperationalPattern;
-
-  m_BodyPartEssence->FooterPartition = 0;
-  m_BodyPartEssence->IndexSID = 0;
-  m_BodyPartEssence->BodyOffset = m_BodyOffset;
-
-  m_CurrentIndexBodyPartition = new AS_02::MXF::OP1aIndexBodyPartion(this->m_Dict);    
-  m_CurrentIndexBodyPartition->EssenceContainers = m_HeaderPart.EssenceContainers;
-  m_CurrentIndexBodyPartition->BodySID = 0;
-  m_CurrentIndexBodyPartition->OperationalPattern = OperationalPattern;
-  m_CurrentIndexBodyPartition->FooterPartition = 0;
-  m_CurrentIndexBodyPartition->IndexSID = 129;//++m_CurrentIndexSID;
-
-  //we must differentiate between index_strategy "lead" and "follow"
-  if ( m_IndexStrategy == AS_02::IS_FOLLOW )
-    {
-      if(m_BodyPartList.size()>0){
-       m_BodyPartEssence->PreviousPartition = m_BodyPartList.back()->ThisPartition;
-      }
-      else{
-       m_BodyPartEssence->PreviousPartition = m_HeaderPart.ThisPartition;
-      }
-      /* Write partition header for the body partition and create IndexBodyPartition.
-        When "all" essence packets are written, write out index table. */
-      m_CurrentIndexBodyPartition->ThisPartition = 0;
-      m_BodyPartEssence->ThisPartition = m_File.Tell();
-      m_CurrentIndexBodyPartition->PreviousPartition = m_BodyPartEssence->ThisPartition;\r
-       m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(m_CurrentIndexBodyPartition->BodySID, m_CurrentIndexBodyPartition->ThisPartition));
-
-       this->m_BodyPartList.push_back(m_CurrentIndexBodyPartition);
-       this->m_BodyPartList.push_back(m_BodyPartEssence);
-    }
-  else if ( m_IndexStrategy == AS_02::IS_LEAD )
-    {
-      /* Write KLVFill packet large enough to hold the completed index data */
-      m_CurrentIndexBodyPartition->ThisPartition = m_File.Tell();
-      m_CurrentIndexBodyPartition->FillWriteToFile(m_File,m_PartitionSpace);
-      m_BodyPartEssence->ThisPartition = m_File.Tell();
-      m_BodyPartEssence->PreviousPartition = m_CurrentIndexBodyPartition->ThisPartition;\r
-       m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(m_CurrentIndexBodyPartition->BodySID, m_CurrentIndexBodyPartition->ThisPartition));
-
-       if(m_BodyPartList.size()>0){
-         m_CurrentIndexBodyPartition->PreviousPartition = m_BodyPartList.back()->ThisPartition;
-       }
-       else{
-         m_CurrentIndexBodyPartition->PreviousPartition = m_HeaderPart.ThisPartition;
-       }
 
-       //necessary to traverse across all of the body partition packs and update the FooterPartition entries at the end of writing                     
-       this->m_BodyPartList.push_back(m_CurrentIndexBodyPartition);
-       this->m_BodyPartList.push_back(m_BodyPartEssence);
+//------------------------------------------------------------------------------------------
+//
 
-    }
 
-  /* similar to both index strategies */
+AS_02::MXF::AS02IndexWriterCBR::AS02IndexWriterCBR(const ASDCP::Dictionary*& d) :
+  Partition(d), m_CurrentSegment(0), m_Dict(d), m_Lookup(0), m_Duration(0), m_SampleSize(0)
+{
+  BodySID = 0;
+  IndexSID = 129;
+  MinorVersion = 3;
+}
 
-  m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(m_BodyPartEssence->BodySID, m_BodyPartEssence->ThisPartition));
-  UL BodyUL(m_Dict->ul(MDD_ClosedCompleteBodyPartition));
-  result = m_BodyPartEssence->WriteToFile(m_File, BodyUL);
+AS_02::MXF::AS02IndexWriterCBR::~AS02IndexWriterCBR() {}
 
-  if ( ASDCP_SUCCESS(result) )
-    {
-      //TODO: Is this necessary?What means ECoffset?Never used in the code? If necessary check if it is set correctly.
+//
+Result_t
+AS_02::MXF::AS02IndexWriterCBR::WriteToFile(Kumu::FileWriter& Writer)
+{
+  assert(m_Dict);
+  ASDCP::FrameBuffer index_body_buffer;
+  ui32_t   index_body_size = MaxIndexSegmentSize; // segment-count * max-segment-size
+  Result_t result = index_body_buffer.Capacity(index_body_size); 
+
+  m_CurrentSegment = new IndexTableSegment(m_Dict);
+  assert(m_CurrentSegment);
+  m_CurrentSegment->m_Lookup = m_Lookup;
+  m_CurrentSegment->IndexEditRate = m_EditRate;
+  m_CurrentSegment->IndexStartPosition = 0;
+  m_CurrentSegment->IndexDuration = m_Duration;
+  m_CurrentSegment->EditUnitByteCount = m_SampleSize;
+  AddChildObject(m_CurrentSegment);
+
+  ASDCP::FrameBuffer WriteWrapper;
+  WriteWrapper.SetData(index_body_buffer.Data() + index_body_buffer.Size(),
+                      index_body_buffer.Capacity() - index_body_buffer.Size());
+
+  result = m_CurrentSegment->WriteToBuffer(WriteWrapper);
+  index_body_buffer.Size(index_body_buffer.Size() + WriteWrapper.Size());
+  delete m_CurrentSegment;
+  m_CurrentSegment = 0;
+  m_PacketList->m_List.clear();
 
-      // Index setup
-      Kumu::fpos_t ECoffset = m_File.Tell();
+  if ( KM_SUCCESS(result) )
+    {
+      IndexByteCount = index_body_buffer.Size();
+      UL body_ul(m_Dict->ul(MDD_ClosedCompleteBodyPartition));
+      result = Partition::WriteToFile(Writer, body_ul);
+    }
 
-      if(m_BytesPerEditUnit == 0){
-       m_CurrentIndexBodyPartition->SetIndexParamsVBR(&m_HeaderPart.m_Primer, m_EditRate, ECoffset);
-      }
-      else{
-       m_CurrentIndexBodyPartition->SetIndexParamsCBR(&m_HeaderPart.m_Primer, m_BytesPerEditUnit, m_EditRate);
-      }
+  if ( KM_SUCCESS(result) )
+    {
+      ui32_t write_count = 0;
+      result = Writer.Write(index_body_buffer.RoData(), index_body_buffer.Size(), &write_count);
+      assert(write_count == index_body_buffer.Size());
     }
 
   return result;
 }
 
-Result_t AS_02::h__Writer::CompleteIndexBodyPart()
+//
+ui32_t
+AS_02::MXF::AS02IndexWriterCBR::GetDuration() const
 {
-  Result_t result = RESULT_OK;
-  if ( m_IndexStrategy == AS_02::IS_FOLLOW )
-    {\r
-      m_CurrentIndexBodyPartition->ThisPartition = m_File.Tell();\r
-       m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(m_CurrentIndexBodyPartition->BodySID, m_CurrentIndexBodyPartition->ThisPartition));\r
-         }
-
-  UL BodyUL(m_Dict->ul(MDD_ClosedCompleteBodyPartition));\r
-    ui64_t cur_pos = m_File.Tell();\r
-      m_File.Seek(m_CurrentIndexBodyPartition->ThisPartition);\r
-       result = m_CurrentIndexBodyPartition->WriteToFile(m_File, BodyUL);
-       m_File.Seek(cur_pos);
-       return result;
+  return m_Duration;
 }
 
 //
-Result_t
-AS_02::h__Writer::WriteMXFHeader(const std::string& PackageLabel, const UL& WrappingUL,
-                                const std::string& TrackName, const UL& EssenceUL, const UL& DataDefinition,
-                                const ASDCP::MXF::Rational& EditRate, ui32_t TCFrameRate, ui32_t BytesPerEditUnit)
+void
+AS_02::MXF::AS02IndexWriterCBR::SetEditRate(const ASDCP::Rational& edit_rate, const ui32_t& sample_size)
 {
-  InitHeader();
-  AddSourceClip(EditRate, TCFrameRate, TrackName, EssenceUL, DataDefinition, PackageLabel);
-  AddEssenceDescriptor(WrappingUL);
+  m_EditRate = edit_rate;
+  m_SampleSize = sample_size;
+}
 
-  Result_t result = m_HeaderPart.WriteToFile(m_File, m_HeaderSize);
 
-  //use the FrameRate for the indexing; initialize the SID counters
-  m_CurrentBodySID = 0;
-  m_CurrentIndexSID = 0;
-  m_PartitionSpace = m_PartitionSpace * TCFrameRate; ///// TODO ????
+//------------------------------------------------------------------------------------------
+//
 
-  if ( KM_SUCCESS(result) )
-    result = CreateBodyPart(EditRate, BytesPerEditUnit);
+//
+AS_02::h__AS02WriterClip::h__AS02WriterClip(const ASDCP::Dictionary& d) :
+  h__AS02Writer<AS_02::MXF::AS02IndexWriterCBR>(d),
+  m_ECStart(0), m_ClipStart(0), m_IndexStrategy(AS_02::IS_FOLLOW) {}
 
-  return result;
-}
+AS_02::h__AS02WriterClip::~h__AS02WriterClip() {}
 
+//
+bool
+AS_02::h__AS02WriterClip::HasOpenClip() const
+{
+  return m_ClipStart != 0;
+}
 
-// standard method of writing a plaintext or encrypted frame
+//
 Result_t
-AS_02::h__Writer::WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf, const byte_t* EssenceUL,
-                                 AESEncContext* Ctx, HMACContext* HMAC)
+AS_02::h__AS02WriterClip::StartClip(const byte_t* EssenceUL, AESEncContext* Ctx, HMACContext* HMAC)
 {
-  Result_t result = RESULT_OK;
-  IntegrityPack IntPack;
-
-  byte_t overhead[128];
-  Kumu::MemIOWriter Overhead(overhead, 128);
-  assert(m_Dict);
-
-  if ( FrameBuf.Size() == 0 )
+  if ( Ctx != 0 )
     {
-      DefaultLogSink().Error("Cannot write empty frame buffer\n");
-      return RESULT_EMPTY_FB;
+      DefaultLogSink().Error("Encryption not yet supported for PCM clip-wrap.\n");
+      return RESULT_STATE;
     }
 
-  if ( m_Info.EncryptedEssence )
+  if ( m_ClipStart != 0 )
     {
-      if ( ! Ctx )
-       return RESULT_CRYPT_CTX;
-
-      if ( m_Info.UsesHMAC && ! HMAC )
-       return RESULT_HMAC_CTX;
-
-      if ( FrameBuf.PlaintextOffset() > FrameBuf.Size() )
-       return RESULT_LARGE_PTO;
-
-      // encrypt the essence data (create encrypted source value)
-      result = EncryptFrameBuffer(FrameBuf, m_CtFrameBuf, Ctx);
-
-      // create HMAC
-      if ( ASDCP_SUCCESS(result) && m_Info.UsesHMAC )
-       result = IntPack.CalcValues(m_CtFrameBuf, m_Info.AssetUUID, m_FramesWritten + 1, HMAC);
-
-      if ( ASDCP_SUCCESS(result) )
-       { // write UL
-         Overhead.WriteRaw(m_Dict->ul(MDD_CryptEssence), SMPTE_UL_LENGTH);
-
-         // construct encrypted triplet header
-         ui32_t ETLength = klv_cryptinfo_size + m_CtFrameBuf.Size();
-         ui32_t BER_length = MXF_BER_LENGTH;
-
-         if ( m_Info.UsesHMAC )
-           ETLength += klv_intpack_size;
-         else
-           ETLength += (MXF_BER_LENGTH * 3); // for empty intpack
-
-         if ( ETLength > 0x00ffffff ) // Need BER integer longer than MXF_BER_LENGTH bytes
-           {
-             BER_length = Kumu::get_BER_length_for_value(ETLength);
-
-             // the packet is longer by the difference in expected vs. actual BER length
-             ETLength += BER_length - MXF_BER_LENGTH;
-
-             if ( BER_length == 0 )
-               result = RESULT_KLV_CODING;
-           }
-
-         if ( ASDCP_SUCCESS(result) )
-           {
-             if ( ! ( Overhead.WriteBER(ETLength, BER_length)                 // write encrypted triplet length
-                      && Overhead.WriteBER(UUIDlen, MXF_BER_LENGTH)                // write ContextID length
-                      && Overhead.WriteRaw(m_Info.ContextID, UUIDlen)              // write ContextID
-                      && Overhead.WriteBER(sizeof(ui64_t), MXF_BER_LENGTH)         // write PlaintextOffset length
-                      && Overhead.WriteUi64BE(FrameBuf.PlaintextOffset())          // write PlaintextOffset
-                      && Overhead.WriteBER(SMPTE_UL_LENGTH, MXF_BER_LENGTH)        // write essence UL length
-                      && Overhead.WriteRaw((byte_t*)EssenceUL, SMPTE_UL_LENGTH)    // write the essence UL
-                      && Overhead.WriteBER(sizeof(ui64_t), MXF_BER_LENGTH)         // write SourceLength length
-                      && Overhead.WriteUi64BE(FrameBuf.Size())                     // write SourceLength
-                      && Overhead.WriteBER(m_CtFrameBuf.Size(), BER_length) ) )    // write ESV length
-               {
-                 result = RESULT_KLV_CODING;
-               }
-           }
-
-         if ( ASDCP_SUCCESS(result) )
-           result = m_File.Writev(Overhead.Data(), Overhead.Length());
-       }
-
-      if ( ASDCP_SUCCESS(result) )
-       {
-         m_StreamOffset += Overhead.Length();
-         // write encrypted source value
-         result = m_File.Writev((byte_t*)m_CtFrameBuf.RoData(), m_CtFrameBuf.Size());
-       }
-
-      if ( ASDCP_SUCCESS(result) )
-       {
-         m_StreamOffset += m_CtFrameBuf.Size();
-
-         byte_t hmoverhead[512];
-         Kumu::MemIOWriter HMACOverhead(hmoverhead, 512);
-
-         // write the HMAC
-         if ( m_Info.UsesHMAC )
-           {
-             HMACOverhead.WriteRaw(IntPack.Data, klv_intpack_size);
-           }
-         else
-           { // we still need the var-pack length values if the intpack is empty
-             for ( ui32_t i = 0; i < 3 ; i++ )
-               HMACOverhead.WriteBER(0, MXF_BER_LENGTH);
-           }
-
-         // write HMAC
-         result = m_File.Writev(HMACOverhead.Data(), HMACOverhead.Length());
-         m_StreamOffset += HMACOverhead.Length();
-       }
+      DefaultLogSink().Error("Cannot open clip, clip already open.\n");
+      return RESULT_STATE;
     }
-  else
-    {
-      ui32_t BER_length = MXF_BER_LENGTH;
 
-      if ( FrameBuf.Size() > 0x00ffffff ) // Need BER integer longer than MXF_BER_LENGTH bytes
-       {
-         BER_length = Kumu::get_BER_length_for_value(FrameBuf.Size());
+  m_ClipStart = m_File.Tell();
+  byte_t clip_buffer[24] = {0};
+  memcpy(clip_buffer, EssenceUL, 16);
+  bool check = Kumu::write_BER(clip_buffer+16, 0, 8);
+  assert(check);
+  return m_File.Write(clip_buffer, 24);
+}
 
-         if ( BER_length == 0 )
-           result = RESULT_KLV_CODING;
-       }
+//
+Result_t
+AS_02::h__AS02WriterClip::WriteClipBlock(const ASDCP::FrameBuffer& FrameBuf)
+{
+  if ( m_ClipStart == 0 )
+    {
+      DefaultLogSink().Error("Cannot write clip block, no clip open.\n");
+      return RESULT_STATE;
+    }
 
-      Overhead.WriteRaw((byte_t*)EssenceUL, SMPTE_UL_LENGTH);
-      Overhead.WriteBER(FrameBuf.Size(), BER_length);
+  return m_File.Write(FrameBuf.RoData(), FrameBuf.Size());
+}
 
-      if ( ASDCP_SUCCESS(result) )
-       result = m_File.Writev(Overhead.Data(), Overhead.Length());
+//
+Result_t
+AS_02::h__AS02WriterClip::FinalizeClip(ui32_t bytes_per_frame)
+{
+  if ( m_ClipStart == 0 )
+    {
+      DefaultLogSink().Error("Cannot close clip, clip not open.\n");
+      return RESULT_STATE;
+    }
 
-      if ( ASDCP_SUCCESS(result) )
-       result = m_File.Writev((byte_t*)FrameBuf.RoData(), FrameBuf.Size());
+  ui64_t current_position = m_File.Tell();
+  Result_t result = m_File.Seek(m_ClipStart+16);
 
-      if ( ASDCP_SUCCESS(result) )
-       m_StreamOffset += Overhead.Length() + FrameBuf.Size();
+  if ( KM_SUCCESS(result) )
+    {
+      byte_t clip_buffer[8] = {0};
+      ui64_t size = static_cast<ui64_t>(m_FramesWritten) * bytes_per_frame;
+      bool check = Kumu::write_BER(clip_buffer, size, 8);
+      assert(check);
+      result = m_File.Write(clip_buffer, 8);
     }
 
-  if ( ASDCP_SUCCESS(result) )
-    result = m_File.Writev();
-
+  if ( KM_SUCCESS(result) )
+    {
+      result = m_File.Seek(current_position);
+      m_ClipStart = 0;
+    }
+  
   return result;
 }