Merge pull request #9 from dcbullock/master
[asdcplib.git] / src / AS_02_TimedText.cpp
index c404d9be5e533c1ee8bdd6a1f3e270cc83395eed..68683954959b463dfd5139588409eff2a752a8a2 100644 (file)
@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2008-2016, John Hurst
+Copyright (c) 2008-2018, John Hurst
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -167,7 +167,9 @@ AS_02::TimedText::MXFReader::h__Reader::ReadTimedTextResource(ASDCP::TimedText::
                                                              AESDecContext* Ctx, HMACContext* HMAC)
 {
   if ( ! m_File.IsOpen() )
-    return RESULT_INIT;
+    {
+      return RESULT_INIT;
+    }
 
   assert(m_Dict);
   Result_t result = ReadEKLVFrame(0, FrameBuf, m_Dict->ul(MDD_TimedTextEssence), Ctx, HMAC);
@@ -184,7 +186,7 @@ AS_02::TimedText::MXFReader::h__Reader::ReadTimedTextResource(ASDCP::TimedText::
 //
 ASDCP::Result_t
 AS_02::TimedText::MXFReader::h__Reader::ReadAncillaryResource(const Kumu::UUID& uuid,
-                                                             ASDCP::TimedText::FrameBuffer& FrameBuf,
+                                                             ASDCP::TimedText::FrameBuffer& frame_buf,
                                                              AESDecContext* Ctx, HMACContext* HMAC)
 {
   ResourceMap_t::const_iterator ri = m_ResourceMap.find(uuid);
@@ -195,70 +197,23 @@ AS_02::TimedText::MXFReader::h__Reader::ReadAncillaryResource(const Kumu::UUID&
       return RESULT_RANGE;
     }
 
-  TimedTextResourceSubDescriptor* DescObject = 0;
   // get the subdescriptor
   InterchangeObject* tmp_iobj = 0;
   Result_t result = m_HeaderPart.GetMDObjectByID((*ri).second, &tmp_iobj);
-  DescObject = static_cast<TimedTextResourceSubDescriptor*>(tmp_iobj);
+  TimedTextResourceSubDescriptor* desc_object = dynamic_cast<TimedTextResourceSubDescriptor*>(tmp_iobj);
 
   if ( KM_SUCCESS(result) )
     {
-      RIP::const_pair_iterator pi;
-      RIP::PartitionPair TmpPair;
-      ui32_t sequence = 0;
-
-      // Look up the partition start in the RIP using the SID.
-      // Count the sequence length in because this is the sequence
-      // value needed to  complete the HMAC.
-      for ( pi = m_RIP.PairArray.begin(); pi != m_RIP.PairArray.end(); ++pi, ++sequence )
-       {
-         if ( (*pi).BodySID == DescObject->EssenceStreamID )
-           {
-             TmpPair = *pi;
-             break;
-           }
-       }
-
-      if ( TmpPair.ByteOffset == 0 )
-       {
-         DefaultLogSink().Error("Body SID not found in RIP set: %d\n", DescObject->EssenceStreamID);
-         return RESULT_FORMAT;
-       }
-
-      if ( KM_SUCCESS(result) )
-       {
-         FrameBuf.AssetID(uuid.Value());
-         FrameBuf.MIMEType(DescObject->MIMEMediaType);
-
-         // seek tp the start of the partition
-         if ( (Kumu::fpos_t)TmpPair.ByteOffset != m_LastPosition )
-           {
-             m_LastPosition = TmpPair.ByteOffset;
-             result = m_File.Seek(TmpPair.ByteOffset);
-           }
-
-         // read the partition header
-         ASDCP::MXF::Partition GSPart(m_Dict);
-         result = GSPart.InitFromFile(m_File);
-
-         if( ASDCP_SUCCESS(result) )
-           {
-             // check the SID
-             if ( DescObject->EssenceStreamID != GSPart.BodySID )
-               {
-                 char buf[64];
-                 DefaultLogSink().Error("Generic stream partition body differs: %s\n", uuid.EncodeHex(buf, 64));
-                 return RESULT_FORMAT;
-               }
-
-             // read the essence packet
-             assert(m_Dict);
-             if( ASDCP_SUCCESS(result) )
-               result = ReadEKLVPacket(0, sequence, FrameBuf, m_Dict->ul(MDD_GenericStream_DataElement), Ctx, HMAC);
-           }
-       }
+      assert(desc_object);
+      result = ReadGenericStreamPartitionPayload(desc_object->EssenceStreamID, frame_buf, Ctx, HMAC);
     }
 
+  if ( KM_SUCCESS(result) )
+    {
+      frame_buf.AssetID(uuid.Value());
+      frame_buf.MIMEType(desc_object->MIMEMediaType);
+    }
+  
   return result;
 }
 
@@ -437,6 +392,7 @@ public:
   TimedTextDescriptor m_TDesc;
   byte_t m_EssenceUL[SMPTE_UL_LENGTH];
   ui32_t m_EssenceStreamID;
+  ASDCP::Rational m_EditRate;
 
   h__Writer(const Dictionary& d) : AS_02::h__AS02WriterClip(d), m_EssenceStreamID(10)
   {
@@ -522,19 +478,11 @@ AS_02::TimedText::MXFWriter::h__Writer::SetSourceStream(ASDCP::TimedText::TimedT
          // 72 == sizeof K, L, instanceuid, uuid + sizeof int32 + tag/len * 4
          m_HeaderSize += ( resourceSubdescriptor->MIMEMediaType.ArchiveLength() * 2 /*ArchiveLength is broken*/ ) + 72;
        }
-    }
-  
-  if ( KM_SUCCESS(result) )
-    {
-      result = WriteAS02Header(TIMED_TEXT_PACKAGE_LABEL, UL(m_Dict->ul(MDD_TimedTextWrappingClip)),
-                              "Data Track", UL(m_EssenceUL), UL(m_Dict->ul(MDD_TimedTextEssence)),
-                              TDesc.EditRate, derive_timecode_rate_from_edit_rate(TDesc.EditRate));
-    }
-  if ( KM_SUCCESS(result) )
-    {
-      this->m_IndexWriter.SetPrimerLookup(&this->m_HeaderPart.m_Primer);
-    }
+    }  
+
+  //Reset m_EssenceStreamID to 10 for later usage in WriteAncillaryResource
+  m_EssenceStreamID = 10;
+  assert(m_Dict);
 
   if ( KM_SUCCESS(result) )
     {
@@ -543,6 +491,14 @@ AS_02::TimedText::MXFWriter::h__Writer::SetSourceStream(ASDCP::TimedText::TimedT
       result = m_State.Goto_READY();
     }
 
+  if ( KM_SUCCESS(result) )
+    {
+      m_EditRate = TDesc.EditRate;
+      result = WriteAS02Header(TIMED_TEXT_PACKAGE_LABEL, UL(m_Dict->ul(MDD_TimedTextWrappingClip)),
+                              "Data Track", UL(m_EssenceUL), UL(m_Dict->ul(MDD_DataDataDef)),
+                              TDesc.EditRate, derive_timecode_rate_from_edit_rate(TDesc.EditRate));
+    }
+
   return result;
 }
 
@@ -551,6 +507,8 @@ ASDCP::Result_t
 AS_02::TimedText::MXFWriter::h__Writer::WriteTimedTextResource(const std::string& XMLDoc,
                                                               ASDCP::AESEncContext* Ctx, ASDCP::HMACContext* HMAC)
 {
+  ASDCP::FrameBuffer segment_buffer;
+  IndexTableSegment::IndexEntry index_entry;
   Result_t result = m_State.Goto_RUNNING();
 
   if ( KM_SUCCESS(result) )
@@ -562,19 +520,69 @@ AS_02::TimedText::MXFWriter::h__Writer::WriteTimedTextResource(const std::string
       
       memcpy(FrameBuf.Data(), XMLDoc.c_str(), str_size);
       FrameBuf.Size(str_size);
-
-      IndexTableSegment::IndexEntry Entry;
-      Entry.StreamOffset = m_StreamOffset;
+      index_entry.StreamOffset = m_StreamOffset;
       
+      result = Write_EKLV_Packet(m_File, *m_Dict, m_HeaderPart, m_Info, m_CtFrameBuf, m_FramesWritten,
+                                m_StreamOffset, FrameBuf, m_EssenceUL, MXF_BER_LENGTH, Ctx, HMAC);
+    }
+
+  if ( KM_SUCCESS(result) )
+    {
+      // encode the index table
+      IndexTableSegment::DeltaEntry nil_delta_entry;
+      IndexTableSegment segment(m_Dict);
+      segment.m_Lookup = &m_HeaderPart.m_Primer;
+      GenRandomValue(segment.InstanceUID);
+
+      segment.DeltaEntryArray.push_back(nil_delta_entry);
+      segment.IndexEditRate = m_EditRate;
+      segment.IndexStartPosition = 0;
+      segment.IndexDuration = -1;
+      segment.IndexEntryArray.push_back(index_entry);
+
+      result = segment_buffer.Capacity(MaxIndexSegmentSize); // segment-count * max-segment-size
+
       if ( KM_SUCCESS(result) )
        {
-         ui64_t this_stream_offset = m_StreamOffset; // m_StreamOffset will be changed by the call to Write_EKLV_Packet
-
-         result = Write_EKLV_Packet(m_File, *m_Dict, m_HeaderPart, m_Info, m_CtFrameBuf, m_FramesWritten,
-                                    m_StreamOffset, FrameBuf, m_EssenceUL, Ctx, HMAC);
+         result = segment.WriteToBuffer(segment_buffer);
        }
     }
 
+  if ( KM_SUCCESS(result) )
+    {
+      // create an index partition header
+      Kumu::fpos_t here = m_File.Tell();
+      assert(m_Dict);
+
+      ASDCP::MXF::Partition partition(m_Dict);
+      partition.MajorVersion = m_HeaderPart.MajorVersion;
+      partition.MinorVersion = m_HeaderPart.MinorVersion;
+      partition.ThisPartition = here;
+      partition.BodySID = 0;
+      partition.IndexSID = 129;
+      partition.IndexByteCount = segment_buffer.Size();
+      partition.PreviousPartition = m_RIP.PairArray.back().ByteOffset;
+      partition.OperationalPattern = m_HeaderPart.OperationalPattern;
+
+      m_RIP.PairArray.push_back(RIP::PartitionPair(0, here));
+      partition.EssenceContainers = m_HeaderPart.EssenceContainers;
+      UL TmpUL(m_Dict->ul(MDD_ClosedCompleteBodyPartition));
+      result = partition.WriteToFile(m_File, TmpUL);
+    }
+  
+  if ( KM_SUCCESS(result) )
+    {
+      // write the encoded index table
+      ui32_t write_count = 0;
+      result = m_File.Write(segment_buffer.RoData(), segment_buffer.Size(), &write_count);
+      assert(write_count == segment_buffer.Size());
+    }
+
+  if ( KM_SUCCESS(result) )
+    {
+      m_FramesWritten++;
+    }
+
   return result;
 }
 
@@ -597,22 +605,23 @@ AS_02::TimedText::MXFWriter::h__Writer::WriteAncillaryResource(const ASDCP::Time
   static UL GenericStream_DataElement(m_Dict->ul(MDD_GenericStream_DataElement));
   ASDCP::MXF::Partition GSPart(m_Dict);
 
+  GSPart.MajorVersion = m_HeaderPart.MajorVersion;
+  GSPart.MinorVersion = m_HeaderPart.MinorVersion;
   GSPart.ThisPartition = here;
   GSPart.PreviousPartition = m_RIP.PairArray.back().ByteOffset;
   GSPart.BodySID = m_EssenceStreamID;
   GSPart.OperationalPattern = m_HeaderPart.OperationalPattern;
 
   m_RIP.PairArray.push_back(RIP::PartitionPair(m_EssenceStreamID++, here));
-  GSPart.EssenceContainers.push_back(UL(m_Dict->ul(MDD_TimedTextEssence)));
+  GSPart.EssenceContainers = m_HeaderPart.EssenceContainers;
   UL TmpUL(m_Dict->ul(MDD_GenericStreamPartition));
   Result_t result = GSPart.WriteToFile(m_File, TmpUL);
 
   if ( KM_SUCCESS(result) )
     {
-      ui64_t this_stream_offset = m_StreamOffset; // m_StreamOffset will be changed by the call to Write_EKLV_Packet
-      
       result = Write_EKLV_Packet(m_File, *m_Dict, m_HeaderPart, m_Info, m_CtFrameBuf, m_FramesWritten,
-                                m_StreamOffset, FrameBuf, GenericStream_DataElement.Value(), Ctx, HMAC);
+                                m_StreamOffset, FrameBuf, GenericStream_DataElement.Value(),
+                                MXF_BER_LENGTH, Ctx, HMAC);
     }
 
   m_FramesWritten++;
@@ -629,7 +638,7 @@ AS_02::TimedText::MXFWriter::h__Writer::Finalize()
       return RESULT_STATE;
     }
 
-  m_IndexWriter.m_Duration = m_FramesWritten = m_TDesc.ContainerDuration;
+  m_FramesWritten = m_TDesc.ContainerDuration;
 
   Result_t result = m_State.Goto_FINAL();