X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Fh__Writer.cpp;h=93388cd7dcf388a4be0311dfca0297d28b5b2467;hb=6a98c7ff80a4ec278dfcf8d1639cdc42fbb67ae7;hp=9f1d3fe24093eb9c2cc11ca3f10b085a09649ab2;hpb=fe443bd90d915478994953b56836577a96ea4a28;p=asdcplib.git diff --git a/src/h__Writer.cpp b/src/h__Writer.cpp index 9f1d3fe..93388cd 100755 --- a/src/h__Writer.cpp +++ b/src/h__Writer.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2004-2006, John Hurst +Copyright (c) 2004-2015, John Hurst All rights reserved. Redistribution and use in source and binary forms, with or without @@ -35,358 +35,66 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. using namespace ASDCP; using namespace ASDCP::MXF; -// a magic number identifying asdcplib -#ifndef ASDCP_BUILD_NUMBER -#define ASDCP_BUILD_NUMBER 0x6A68 -#endif - - - // -ASDCP::h__Writer::h__Writer() : - m_HeaderSize(0), m_EssenceStart(0), - m_EssenceDescriptor(0), m_FramesWritten(0), m_StreamOffset(0) -{ -} - -ASDCP::h__Writer::~h__Writer() +ui32_t +ASDCP::derive_timecode_rate_from_edit_rate(const ASDCP::Rational& edit_rate) { + return floor(0.5 + edit_rate.Quotient()); } // // add DMS CryptographicFramework entry to source package void -AddDMScrypt(Partition& HeaderPart, SourcePackage& Package, WriterInfo& Descr, const UL& WrappingUL) +ASDCP::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); } -// -void -ASDCP::h__Writer::InitHeader() -{ - assert(m_EssenceDescriptor); - - m_HeaderPart.m_Primer.ClearTagList(); - m_HeaderPart.m_Preface = new Preface; - 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.OperationalPattern = m_HeaderPart.m_Preface->OperationalPattern; - - // 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; - 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; - Ident->ToolkitVersion.Major = VERSION_MAJOR; - Ident->ToolkitVersion.Minor = VERSION_APIMINOR; - Ident->ToolkitVersion.Patch = VERSION_IMPMINOR; - Ident->ToolkitVersion.Build = ASDCP_BUILD_NUMBER; - Ident->ToolkitVersion.Release = VersionType::RL_RELEASE; -} - -// -template -struct TrackSet -{ - MXF::Track* Track; - MXF::Sequence* Sequence; - ClipT* Clip; - - TrackSet() : Track(0), Sequence(0), Clip(0) {} -}; - -// -template -TrackSet -CreateTrackAndSequence(OPAtomHeader& Header, PackageT& Package, const std::string TrackName, - const MXF::Rational& EditRate, const UL& Definition, ui32_t TrackID) -{ - TrackSet NewTrack; - - NewTrack.Track = new Track; - 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; - Header.AddChildObject(NewTrack.Sequence); - NewTrack.Track->Sequence = NewTrack.Sequence->InstanceUID; - NewTrack.Sequence->DataDefinition = Definition; - - return NewTrack; -} - -// -template -TrackSet -CreateTimecodeTrack(OPAtomHeader& Header, PackageT& Package, - const MXF::Rational& EditRate, ui32_t TCFrameRate, ui64_t TCStart) -{ - UL TCUL(Dict::ul(MDD_TimecodeDataDef)); - - TrackSet NewTrack = CreateTrackAndSequence(Header, Package, "Timecode Track", EditRate, TCUL, 1); - - NewTrack.Clip = new TimecodeComponent; - 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; - m_HeaderPart.AddChildObject(Storage); - m_HeaderPart.m_Preface->ContentStorage = Storage->InstanceUID; - - EssenceContainerData* ECD = new EssenceContainerData; - 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_MaterialPackage->Name = "AS-DCP 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_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_DurationUpdateList.push_back(&(MPTrack.Sequence->Duration)); - - MPTrack.Clip = new SourceClip; - 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_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_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_DurationUpdateList.push_back(&(FPTrack.Sequence->Duration)); - - FPTrack.Clip = new SourceClip; - 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_HeaderPart.AddChildObject(Storage); - m_HeaderPart.m_Preface->ContentStorage = Storage->InstanceUID; - - EssenceContainerData* ECD = new EssenceContainerData; - 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_MaterialPackage->Name = "AS-DCP 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_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_DurationUpdateList.push_back(&(MPTrack.Sequence->Duration)); - - MPTrack.Clip = new DMSegment; - 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_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_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_DurationUpdateList.push_back(&(FPTrack.Sequence->Duration)); - - FPTrack.Clip = new DMSegment; - 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_HeaderPart.m_Preface->PrimaryPackage = m_FilePackage->InstanceUID; - - // - // Encryption Descriptor - // - if ( m_Info.EncryptedEssence ) - { - UL CryptEssenceUL(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); - } - else - { - m_HeaderPart.EssenceContainers.push_back(UL(Dict::ul(MDD_GCMulti))); - m_HeaderPart.EssenceContainers.push_back(WrappingUL); - } +ASDCP::h__ASDCPWriter::h__ASDCPWriter(const Dictionary& d) : + MXF::TrackFileWriter(d), m_BodyPart(m_Dict), m_FooterPart(m_Dict) {} - m_HeaderPart.m_Preface->EssenceContainers = m_HeaderPart.EssenceContainers; - m_HeaderPart.AddChildObject(m_EssenceDescriptor); +ASDCP::h__ASDCPWriter::~h__ASDCPWriter() {} - std::list::iterator sdli = m_EssenceSubDescriptorList.begin(); - for ( ; sdli != m_EssenceSubDescriptorList.end(); sdli++ ) - m_HeaderPart.AddChildObject(*sdli); - - m_FilePackage->Descriptor = m_EssenceDescriptor->InstanceUID; -} // Result_t -ASDCP::h__Writer::CreateBodyPart(const MXF::Rational& EditRate, ui32_t BytesPerEditUnit) +ASDCP::h__ASDCPWriter::CreateBodyPart(const MXF::Rational& EditRate, ui32_t BytesPerEditUnit) { + assert(m_Dict); Result_t result = RESULT_OK; // create a body partition if we're writing proper 429-3/OP-Atom @@ -396,11 +104,11 @@ ASDCP::h__Writer::CreateBodyPart(const MXF::Rational& EditRate, ui32_t BytesPerE m_BodyPart.EssenceContainers = m_HeaderPart.EssenceContainers; m_BodyPart.ThisPartition = m_File.Tell(); m_BodyPart.BodySID = 1; - UL OPAtomUL(Dict::ul(MDD_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 + m_RIP.PairArray.push_back(RIP::PartitionPair(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 @@ -415,9 +123,13 @@ ASDCP::h__Writer::CreateBodyPart(const MXF::Rational& EditRate, ui32_t BytesPerE m_FooterPart.IndexSID = 129; if ( BytesPerEditUnit == 0 ) - m_FooterPart.SetIndexParamsVBR(&m_HeaderPart.m_Primer, EditRate, ECoffset); + { + m_FooterPart.SetIndexParamsVBR(&m_HeaderPart.m_Primer, EditRate, ECoffset); + } else - m_FooterPart.SetIndexParamsCBR(&m_HeaderPart.m_Primer, BytesPerEditUnit, EditRate); + { + m_FooterPart.SetIndexParamsCBR(&m_HeaderPart.m_Primer, BytesPerEditUnit, EditRate); + } } return result; @@ -425,12 +137,24 @@ ASDCP::h__Writer::CreateBodyPart(const MXF::Rational& EditRate, ui32_t BytesPerE // 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) +ASDCP::h__ASDCPWriter::WriteASDCPHeader(const std::string& PackageLabel, const UL& WrappingUL, + const std::string& TrackName, const UL& EssenceUL, const UL& DataDefinition, + const MXF::Rational& EditRate, ui32_t TCFrameRate, ui32_t BytesPerEditUnit) { - InitHeader(); - AddSourceClip(EditRate, TCFrameRate, TrackName, DataDefinition, PackageLabel); + InitHeader(MXFVersion_2004); + + // First RIP Entry + if ( m_Info.LabelSetType == LS_MXF_SMPTE ) // ERK + { + m_RIP.PairArray.push_back(RIP::PartitionPair(0, 0)); // 3-part, no essence in header + } + else + { + m_RIP.PairArray.push_back(RIP::PartitionPair(1, 0)); // 2-part, essence in header + } + + // timecode rate and essence rate are the same + AddSourceClip(EditRate, EditRate, TCFrameRate, TrackName, EssenceUL, DataDefinition, PackageLabel); AddEssenceDescriptor(WrappingUL); Result_t result = m_HeaderPart.WriteToFile(m_File, m_HeaderSize); @@ -441,11 +165,72 @@ ASDCP::h__Writer::WriteMXFHeader(const std::string& PackageLabel, const UL& Wrap return result; } +// +Result_t +ASDCP::h__ASDCPWriter::WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf,const byte_t* EssenceUL, + AESEncContext* Ctx, HMACContext* HMAC) +{ + return Write_EKLV_Packet(m_File, *m_Dict, m_HeaderPart, m_Info, m_CtFrameBuf, m_FramesWritten, + m_StreamOffset, FrameBuf, EssenceUL, Ctx, HMAC); +} + +// standard method of writing the header and footer of a completed MXF file +// +Result_t +ASDCP::h__ASDCPWriter::WriteASDCPFooter() +{ + // update all Duration properties + 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_RIP.PairArray.back().ByteOffset; + + Kumu::fpos_t here = m_File.Tell(); + m_RIP.PairArray.push_back(RIP::PartitionPair(0, here)); // Last RIP Entry + m_HeaderPart.FooterPartition = here; + + assert(m_Dict); + // re-label the header partition, set the footer + UL OPAtomUL(m_Dict->ul(MDD_OPAtom)); + m_HeaderPart.OperationalPattern = OPAtomUL; + m_HeaderPart.m_Preface->OperationalPattern = OPAtomUL; + m_FooterPart.OperationalPattern = OPAtomUL; + + m_FooterPart.EssenceContainers = m_HeaderPart.EssenceContainers; + m_FooterPart.FooterPartition = here; + m_FooterPart.ThisPartition = here; + + Result_t result = m_FooterPart.WriteToFile(m_File, m_FramesWritten); + + if ( ASDCP_SUCCESS(result) ) + result = m_RIP.WriteToFile(m_File); + + if ( ASDCP_SUCCESS(result) ) + result = m_File.Seek(0); + + if ( ASDCP_SUCCESS(result) ) + result = m_HeaderPart.WriteToFile(m_File, m_HeaderSize); + + m_File.Close(); + return result; +} + + +//------------------------------------------------------------------------------------------ +// + // standard method of writing a plaintext or encrypted frame Result_t -ASDCP::h__Writer::WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf, const byte_t* EssenceUL, - AESEncContext* Ctx, HMACContext* HMAC) +ASDCP::Write_EKLV_Packet(Kumu::FileWriter& File, const ASDCP::Dictionary& Dict, const MXF::OP1aHeader& HeaderPart, + const ASDCP::WriterInfo& Info, ASDCP::FrameBuffer& CtFrameBuf, ui32_t& FramesWritten, + ui64_t & StreamOffset, const ASDCP::FrameBuffer& FrameBuf, const byte_t* EssenceUL, + AESEncContext* Ctx, HMACContext* HMAC) { Result_t result = RESULT_OK; IntegrityPack IntPack; @@ -459,69 +244,85 @@ ASDCP::h__Writer::WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf, const byte return RESULT_EMPTY_FB; } - if ( m_Info.EncryptedEssence ) + if ( Info.EncryptedEssence ) { if ( ! Ctx ) return RESULT_CRYPT_CTX; - if ( m_Info.UsesHMAC && ! HMAC ) + if ( 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); + result = EncryptFrameBuffer(FrameBuf, 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) && Info.UsesHMAC ) + result = IntPack.CalcValues(CtFrameBuf, Info.AssetUUID, FramesWritten + 1, HMAC); 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(Dict.ul(MDD_CryptEssence), SMPTE_UL_LENGTH); // construct encrypted triplet header - ui32_t ETLength = klv_cryptinfo_size + m_CtFrameBuf.Size(); + ui32_t ETLength = klv_cryptinfo_size + CtFrameBuf.Size(); + ui32_t BER_length = MXF_BER_LENGTH; - if ( m_Info.UsesHMAC ) + if ( Info.UsesHMAC ) ETLength += klv_intpack_size; else ETLength += (MXF_BER_LENGTH * 3); // for empty intpack - Overhead.WriteBER(ETLength, MXF_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(), MXF_BER_LENGTH); // write ESV length - - result = m_File.Writev(Overhead.Data(), Overhead.Length()); + 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(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(CtFrameBuf.Size(), BER_length) ) ) // write ESV length + { + result = RESULT_KLV_CODING; + } + } + + if ( ASDCP_SUCCESS(result) ) + result = File.Writev(Overhead.Data(), Overhead.Length()); } if ( ASDCP_SUCCESS(result) ) { - m_StreamOffset += Overhead.Length(); + StreamOffset += Overhead.Length(); // write encrypted source value - result = m_File.Writev((byte_t*)m_CtFrameBuf.RoData(), m_CtFrameBuf.Size()); + result = File.Writev((byte_t*)CtFrameBuf.RoData(), CtFrameBuf.Size()); } if ( ASDCP_SUCCESS(result) ) { - m_StreamOffset += m_CtFrameBuf.Size(); + StreamOffset += CtFrameBuf.Size(); byte_t hmoverhead[512]; Kumu::MemIOWriter HMACOverhead(hmoverhead, 512); // write the HMAC - if ( m_Info.UsesHMAC ) + if ( Info.UsesHMAC ) { HMACOverhead.WriteRaw(IntPack.Data, klv_intpack_size); } @@ -532,78 +333,38 @@ ASDCP::h__Writer::WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf, const byte } // write HMAC - result = m_File.Writev(HMACOverhead.Data(), HMACOverhead.Length()); - m_StreamOffset += HMACOverhead.Length(); + result = File.Writev(HMACOverhead.Data(), HMACOverhead.Length()); + StreamOffset += HMACOverhead.Length(); } } 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(), MXF_BER_LENGTH); - result = m_File.Writev(Overhead.Data(), Overhead.Length()); + Overhead.WriteBER(FrameBuf.Size(), BER_length); + + if ( ASDCP_SUCCESS(result) ) + result = File.Writev(Overhead.Data(), Overhead.Length()); if ( ASDCP_SUCCESS(result) ) - result = m_File.Writev((byte_t*)FrameBuf.RoData(), FrameBuf.Size()); + result = File.Writev((byte_t*)FrameBuf.RoData(), FrameBuf.Size()); if ( ASDCP_SUCCESS(result) ) - m_StreamOffset += Overhead.Length() + FrameBuf.Size(); + StreamOffset += Overhead.Length() + FrameBuf.Size(); } if ( ASDCP_SUCCESS(result) ) - result = m_File.Writev(); - - return result; -} - - -// standard method of writing the header and footer of a completed MXF file -// -Result_t -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 = - - 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)); // Last RIP Entry - m_HeaderPart.FooterPartition = here; - - // re-label the partition - UL OPAtomUL(Dict::ul(MDD_OPAtom)); - - if ( m_Info.LabelSetType == LS_MXF_INTEROP ) - OPAtomUL.Set(Dict::ul(MDD_MXFInterop_OPAtom)); - - m_HeaderPart.OperationalPattern = OPAtomUL; - m_HeaderPart.m_Preface->OperationalPattern = m_HeaderPart.OperationalPattern; - - m_FooterPart.OperationalPattern = m_HeaderPart.OperationalPattern; - m_FooterPart.EssenceContainers = m_HeaderPart.EssenceContainers; - m_FooterPart.FooterPartition = here; - m_FooterPart.ThisPartition = here; - - Result_t result = m_FooterPart.WriteToFile(m_File, m_FramesWritten); - - if ( ASDCP_SUCCESS(result) ) - result = m_HeaderPart.m_RIP.WriteToFile(m_File); - - if ( ASDCP_SUCCESS(result) ) - result = m_File.Seek(0); + result = File.Writev(); - if ( ASDCP_SUCCESS(result) ) - result = m_HeaderPart.WriteToFile(m_File, m_HeaderSize); - - m_File.Close(); return result; }