X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Fh__02_Writer.cpp;h=1de439214f363b48cf015cda61dc926855173278;hb=620722efa3a2df7857074e36abd751826a61d0e0;hp=919e89a687ef21f5925bca8e4163023bdfc38445;hpb=02576f10e9fbda710a7db35757950786a776a71d;p=asdcplib.git diff --git a/src/h__02_Writer.cpp b/src/h__02_Writer.cpp index 919e89a..1de4392 100644 --- a/src/h__02_Writer.cpp +++ b/src/h__02_Writer.cpp @@ -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-2013, 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$ @@ -34,640 +36,340 @@ 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; } +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 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 = 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 -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::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 -TrackSet -CreateTrackAndSequence(OPAtomHeader& Header, PackageT& Package, const std::string TrackName, - const MXF::Rational& EditRate, const UL& Definition, ui32_t TrackID, const Dictionary*& Dict) -{ - TrackSet 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 -TrackSet -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 NewTrack = CreateTrackAndSequence(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::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 MPTCTrack = - CreateTimecodeTrack(m_HeaderPart, *m_MaterialPackage, - EditRate, TCFrameRate, 0, m_Dict); - m_DurationUpdateList.push_back(&(MPTCTrack.Sequence->Duration)); - m_DurationUpdateList.push_back(&(MPTCTrack.Clip->Duration)); - - TrackSet MPTrack = - CreateTrackAndSequence(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 FPTCTrack = - CreateTimecodeTrack(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 FPTrack = - CreateTrackAndSequence(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((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::const_iterator i; + + for ( i = m_PacketList->m_List.begin(); i != m_PacketList->m_List.end(); ++i ) + { + IndexTableSegment* segment = dynamic_cast(*i); + if ( segment != 0 ) + { + duration += 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 MPTCTrack = - CreateTimecodeTrack(m_HeaderPart, *m_MaterialPackage, - EditRate, TCFrameRate, 0, m_Dict); - m_DurationUpdateList.push_back(&(MPTCTrack.Sequence->Duration)); - m_DurationUpdateList.push_back(&(MPTCTrack.Clip->Duration)); - - TrackSet MPTrack = - CreateTrackAndSequence(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 FPTCTrack = - CreateTimecodeTrack(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 FPTrack = - CreateTrackAndSequence(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::h__AS02WriterFrame::h__AS02WriterFrame(const ASDCP::Dictionary& d) : + h__AS02Writer(d), m_IndexStrategy(AS_02::IS_FOLLOW) {} + +AS_02::h__AS02WriterFrame::~h__AS02WriterFrame() {} + +// +Result_t +AS_02::h__AS02WriterFrame::WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf,const byte_t* EssenceUL, AESEncContext* Ctx, HMACContext* HMAC) { - // - // 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); + ui64_t this_stream_offset = m_StreamOffset; // m_StreamOffset will be changed by the call to Write_EKLV_Packet - 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); + Result_t result = Write_EKLV_Packet(m_File, *m_Dict, m_HeaderPart, m_Info, m_CtFrameBuf, m_FramesWritten, + m_StreamOffset, FrameBuf, EssenceUL, Ctx, HMAC); + + if ( KM_SUCCESS(result) ) + { + IndexTableSegment::IndexEntry Entry; + Entry.StreamOffset = this_stream_offset; + m_IndexWriter.PushIndexEntry(Entry); } - else + + if ( m_FramesWritten > 0 && ( m_FramesWritten % m_PartitionSpace ) == 0 ) { - m_HeaderPart.EssenceContainers.push_back(WrappingUL); + m_IndexWriter.ThisPartition = m_File.Tell(); + m_IndexWriter.WriteToFile(m_File); + m_RIP.PairArray.push_back(RIP::Pair(0, m_IndexWriter.ThisPartition)); + + UL body_ul(m_Dict->ul(MDD_ClosedCompleteBodyPartition)); + Partition body_part(m_Dict); + 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::Pair(1, body_part.ThisPartition)); } - m_HeaderPart.m_Preface->EssenceContainers = m_HeaderPart.EssenceContainers; - m_HeaderPart.AddChildObject(m_EssenceDescriptor); + return result; +} - std::list::iterator sdli = m_EssenceSubDescriptorList.begin(); - for ( ; sdli != m_EssenceSubDescriptorList.end(); sdli++ ) - m_HeaderPart.AddChildObject(*sdli); - m_FilePackage->Descriptor = m_EssenceDescriptor->InstanceUID; +//------------------------------------------------------------------------------------------ +// + + +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; } +AS_02::MXF::AS02IndexWriterCBR::~AS02IndexWriterCBR() {} + // Result_t -AS_02::h__Writer::CreateBodyPart(const ASDCP::MXF::Rational& EditRate, ui32_t BytesPerEditUnit) +AS_02::MXF::AS02IndexWriterCBR::WriteToFile(Kumu::FileWriter& Writer) { assert(m_Dict); - Result_t result = RESULT_OK; - m_EditRate = EditRate; - m_BytesPerEditUnit = BytesPerEditUnit; + 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(); - result = CreateBodyPartPair(); - - //TODO: no IndexTables in the footer -> The spec is silent on that topic - m_FooterPart.IndexSID = 0;//129; - - 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; - 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 ) + if ( KM_SUCCESS(result) ) { - /* 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; - 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); + IndexByteCount = index_body_buffer.Size(); + UL body_ul(m_Dict->ul(MDD_ClosedCompleteBodyPartition)); + result = Partition::WriteToFile(Writer, body_ul); } - /* similar to both index strategies */ - - 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); - - if ( ASDCP_SUCCESS(result) ) + if ( KM_SUCCESS(result) ) { - //TODO: Is this necessary?What means ECoffset?Never used in the code? If necessary check if it is set correctly. - - // Index setup - Kumu::fpos_t ECoffset = m_File.Tell(); - - 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); - } + 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 ) - { - m_CurrentIndexBodyPartition->ThisPartition = m_File.Tell(); - m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(m_CurrentIndexBodyPartition->BodySID, m_CurrentIndexBodyPartition->ThisPartition)); - } - - UL BodyUL(m_Dict->ul(MDD_ClosedCompleteBodyPartition)); - ui64_t cur_pos = m_File.Tell(); - m_File.Seek(m_CurrentIndexBodyPartition->ThisPartition); - 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(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()); - if ( BER_length == 0 ) - result = RESULT_KLV_CODING; - } - - Overhead.WriteRaw((byte_t*)EssenceUL, SMPTE_UL_LENGTH); - Overhead.WriteBER(FrameBuf.Size(), BER_length); + 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 ( ASDCP_SUCCESS(result) ) - result = m_File.Writev(Overhead.Data(), Overhead.Length()); +// +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; + } - if ( ASDCP_SUCCESS(result) ) - result = m_File.Writev((byte_t*)FrameBuf.RoData(), FrameBuf.Size()); + return m_File.Write(FrameBuf.RoData(), FrameBuf.Size()); +} - if ( ASDCP_SUCCESS(result) ) - m_StreamOffset += Overhead.Length() + FrameBuf.Size(); +// +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; } + ui64_t current_position = m_File.Tell(); + Result_t result = m_File.Seek(m_ClipStart+16); + if ( ASDCP_SUCCESS(result) ) - result = m_File.Writev(); + { + byte_t clip_buffer[8] = {0}; + bool check = Kumu::write_BER(clip_buffer, m_FramesWritten * bytes_per_frame, 8); + assert(check); + result = m_File.Write(clip_buffer, 8); + } + m_File.Seek(current_position); + m_ClipStart = 0; return result; } + + + // // end h__02_Writer.cpp //