X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;ds=sidebyside;f=src%2Fh__Writer.cpp;h=69873b65fb59611eff9b62c702e4be0bc20b0044;hb=19bd80c074e1dec35404fd85607a2a68c791b2d9;hp=411f63e9f35f66d9c55cf69ebf311c04ce51913e;hpb=8095eaa320551b6795d0368c0ad0c227a3167caa;p=asdcplib.git diff --git a/src/h__Writer.cpp b/src/h__Writer.cpp index 411f63e..69873b6 100755 --- a/src/h__Writer.cpp +++ b/src/h__Writer.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2004-2005, John Hurst +Copyright (c) 2004-2009, John Hurst All rights reserved. Redistribution and use in source and binary forms, with or without @@ -30,234 +30,472 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "AS_DCP_internal.h" -#include "MemIO.h" -#include "Timecode.h" -#include +#include "KLV.h" -using namespace mxflib; using namespace ASDCP; +using namespace ASDCP::MXF; +// a magic number identifying asdcplib +#ifndef ASDCP_BUILD_NUMBER +#define ASDCP_BUILD_NUMBER 0x6A68 +#endif + + +static std::vector +version_split(const char* str) +{ + std::vector result; + + const char* pstr = str; + const char* r = strchr(pstr, '.'); + + while ( r != 0 ) + { + assert(r >= pstr); + if ( r > pstr ) + result.push_back(atoi(pstr)); + + pstr = r + 1; + r = strchr(pstr, '.'); + } -ASDCP::h__Writer::h__Writer() : m_FramesWritten(0), m_StreamOffset(0) + if( strlen(pstr) > 0 ) + result.push_back(atoi(pstr)); + + assert(result.size() == 3); + return result; +} + + +// +ASDCP::h__Writer::h__Writer(const Dictionary& d) : + m_HeaderPart(m_Dict), m_BodyPart(m_Dict), m_FooterPart(m_Dict), m_Dict(&d), + m_HeaderSize(0), m_EssenceStart(0), + m_EssenceDescriptor(0), m_FramesWritten(0), m_StreamOffset(0) { - init_mxf_types(); } ASDCP::h__Writer::~h__Writer() { } -// standard method of writing the header of a new MXF file -Result_t -ASDCP::h__Writer::WriteMXFHeader(EssenceType_t EssenceType, ASDCP::Rational& EditRate, - ui32_t TCFrameRate, ui32_t BytesPerEditUnit) +// +// add DMS CryptographicFramework entry to source package +void +AddDMScrypt(Partition& HeaderPart, SourcePackage& Package, + WriterInfo& Descr, const UL& WrappingUL, const Dictionary*& Dict) { - // write the stream metadata - m_Metadata = new Metadata(); - assert(m_Metadata); - assert(m_Metadata->m_Object); + assert(Dict); + // Essence Track + 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(Dict); + HeaderPart.AddChildObject(Seq); + NewTrack->Sequence = Seq->InstanceUID; + Seq->DataDefinition = UL(Dict->ul(MDD_DescriptiveMetaDataDef)); + + DMSegment* Segment = new DMSegment(Dict); + HeaderPart.AddChildObject(Segment); + Seq->StructuralComponents.push_back(Segment->InstanceUID); + Segment->EventComment = "AS-DCP KLV Encryption"; + + CryptographicFramework* CFW = new CryptographicFramework(Dict); + HeaderPart.AddChildObject(CFW); + Segment->DMFramework = CFW->InstanceUID; + + 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->CryptographicKeyID.Set(Descr.CryptographicKeyID); +} - if ( m_Info.EncryptedEssence ) - { - UL DMSUL(CryptoFrameworkUL_Data); - m_Metadata->AddDMScheme(DMSUL); - } +// +void +ASDCP::h__Writer::InitHeader() +{ + assert(m_Dict); + assert(m_EssenceDescriptor); - // Set the OP label - // If we are writing OP-Atom we write the header as OP1a initially as another process - // may try to read the file before it is complete and then it will NOT be a valid OP-Atom file - m_Metadata->SetOP(OP1aUL); - - // Build the Material Package - // DRAGONS: We should really try and determine the UMID type rather than cop-out! - UMID PackageUMID; - PackageUMID.MakeUMID(0x0d); // mixed type - -#if ASDCP_USE_MXFLIB - mxflib::Rational EditRate_; - EditRate_.Numerator = EditRate.Numerator; - EditRate_.Denominator = EditRate.Denominator; -#else -#define EditRate_ EditRate -#endif + m_HeaderPart.m_Primer.ClearTagList(); + m_HeaderPart.m_Preface = new Preface(m_Dict); + m_HeaderPart.AddChildObject(m_HeaderPart.m_Preface); - m_MaterialPackage = m_Metadata->AddMaterialPackage("AS-DCP Material Package", PackageUMID); - m_Metadata->SetPrimaryPackage(m_MaterialPackage); // This will be overwritten for OP-Atom - - TrackPtr MPTimecodeTrack = m_MaterialPackage->AddTimecodeTrack(EditRate_); - m_MPTimecode = MPTimecodeTrack->AddTimecodeComponent(TCFrameRate, 0, 0); + // 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; - TrackPtr FPTimecodeTrack = 0; - mxflib::UUID assetUUID(m_Info.AssetUUID); + // 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 - UMID EssenceUMID; - - switch ( EssenceType ) - { - case ESS_MPEG2_VES: - PackageUMID.MakeUMID(0x0f, assetUUID); - m_FilePackage = m_Metadata->AddFilePackage(1, MPEG_PACKAGE_LABEL, PackageUMID); - m_MPTrack = m_MaterialPackage->AddPictureTrack(EditRate_); - m_FPTrack = m_FilePackage->AddPictureTrack(0, EditRate_); - break; - - case ESS_JPEG_2000: - PackageUMID.MakeUMID(0x0f, assetUUID); - m_FilePackage = m_Metadata->AddFilePackage(1, JP2K_PACKAGE_LABEL, PackageUMID); - m_MPTrack = m_MaterialPackage->AddPictureTrack(EditRate_); - m_FPTrack = m_FilePackage->AddPictureTrack(0, EditRate_); - break; - - case ESS_PCM_24b_48k: - PackageUMID.MakeUMID(0x0f, assetUUID); - m_FilePackage = m_Metadata->AddFilePackage(1, PCM_PACKAGE_LABEL, PackageUMID); - m_MPTrack = m_MaterialPackage->AddSoundTrack(EditRate_); - m_FPTrack = m_FilePackage->AddSoundTrack(0, EditRate_); - break; - - default: return RESULT_RAW_ESS; - } + // + // 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; +} + +// +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, const Dictionary*& Dict) +{ + TrackSet NewTrack; + + NewTrack.Track = new Track(Dict); + Header.AddChildObject(NewTrack.Track); + NewTrack.Track->EditRate = EditRate; + Package.Tracks.push_back(NewTrack.Track->InstanceUID); + NewTrack.Track->TrackID = TrackID; + NewTrack.Track->TrackName = TrackName.c_str(); + + NewTrack.Sequence = new Sequence(Dict); + Header.AddChildObject(NewTrack.Sequence); + NewTrack.Track->Sequence = NewTrack.Sequence->InstanceUID; + NewTrack.Sequence->DataDefinition = Definition; + + return NewTrack; +} + +// +template +TrackSet +CreateTimecodeTrack(OPAtomHeader& Header, PackageT& Package, + const MXF::Rational& EditRate, ui32_t TCFrameRate, ui64_t TCStart, const Dictionary*& Dict) +{ + assert(Dict); + UL TCUL(Dict->ul(MDD_TimecodeDataDef)); + + TrackSet NewTrack = CreateTrackAndSequence(Header, Package, "Timecode Track", EditRate, TCUL, 1, Dict); + + NewTrack.Clip = new TimecodeComponent(Dict); + Header.AddChildObject(NewTrack.Clip); + NewTrack.Sequence->StructuralComponents.push_back(NewTrack.Clip->InstanceUID); + NewTrack.Clip->RoundedTimecodeBase = TCFrameRate; + NewTrack.Clip->StartTimecode = TCStart; + NewTrack.Clip->DataDefinition = TCUL; + + return NewTrack; +} + + +// +void +ASDCP::h__Writer::AddSourceClip(const MXF::Rational& EditRate, ui32_t TCFrameRate, + const std::string& TrackName, const UL& DataDefinition, + const std::string& PackageLabel) +{ + // + ContentStorage* Storage = new ContentStorage(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-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_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)); - // Add an essence element - FPTimecodeTrack = m_FilePackage->AddTimecodeTrack(EditRate_); - m_FPTimecode = FPTimecodeTrack->AddTimecodeComponent(TCFrameRate, 0/* NDF */, - tc_to_frames(TCFrameRate, 1, 0, 0, 0) ); - - // Add a single Component to this Track of the Material Package - m_MPClip = m_MPTrack->AddSourceClip(); - // Add a single Component to this Track of the File Package - m_FPClip = m_FPTrack->AddSourceClip(); - const byte_t* SourceEssenceContainerLabel = 0; + // + // 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 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; +} - // Frame wrapping - if ( m_Info.EncryptedEssence ) - { - switch ( EssenceType ) - { - case ESS_MPEG2_VES: - SourceEssenceContainerLabel = WrappingUL_Data_MPEG2_VES; - break; - - case ESS_JPEG_2000: - SourceEssenceContainerLabel = WrappingUL_Data_JPEG_2000; - break; - - case ESS_PCM_24b_48k: - SourceEssenceContainerLabel = WrappingUL_Data_PCM_24b_48k; - break; - - default: - return RESULT_RAW_ESS; - } - } +// +void +ASDCP::h__Writer::AddDMSegment(const MXF::Rational& EditRate, ui32_t TCFrameRate, + const std::string& TrackName, const UL& DataDefinition, + const std::string& PackageLabel) +{ + // + ContentStorage* Storage = new ContentStorage(m_Dict); + m_HeaderPart.AddChildObject(Storage); + m_HeaderPart.m_Preface->ContentStorage = Storage->InstanceUID; + + EssenceContainerData* ECD = new EssenceContainerData(m_Dict); + m_HeaderPart.AddChildObject(ECD); + Storage->EssenceContainerData.push_back(ECD->InstanceUID); + ECD->IndexSID = 129; + ECD->BodySID = 1; + + UUID assetUUID(m_Info.AssetUUID); + UMID SourcePackageUMID, MaterialPackageUMID; + SourcePackageUMID.MakeUMID(0x0f, assetUUID); + MaterialPackageUMID.MakeUMID(0x0f); // unidentified essence + + // + // Material Package + // + m_MaterialPackage = new MaterialPackage(m_Dict); + m_MaterialPackage->Name = "AS-DCP Material Package"; + m_MaterialPackage->PackageUID = MaterialPackageUMID; + m_HeaderPart.AddChildObject(m_MaterialPackage); + Storage->Packages.push_back(m_MaterialPackage->InstanceUID); + + 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)); - mem_ptr
    WrappingUL; - switch ( EssenceType ) - { - case ESS_MPEG2_VES: - WrappingUL = new UL(WrappingUL_Data_MPEG2_VES); // memchk TESTED - break; - - case ESS_JPEG_2000: - WrappingUL = new UL(WrappingUL_Data_JPEG_2000); // memchk TESTED - break; - - case ESS_PCM_24b_48k: - WrappingUL = new UL(WrappingUL_Data_PCM_24b_48k); // memchk TESTED - break; - - default: - return RESULT_RAW_ESS; - } - assert(!WrappingUL.empty()); - m_EssenceDescriptor->SetValue("EssenceContainer", DataChunk(klv_key_size, WrappingUL->GetValue())); - // Write a File Descriptor only on the internally ref'ed Track - m_EssenceDescriptor->SetUint("LinkedTrackID", m_FPTrack->GetUint("TrackID")); - m_FilePackage->AddChild("Descriptor")->MakeLink(*m_EssenceDescriptor); + // + // 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; +} - UL CryptEssenceUL(WrappingUL_Data_Crypt); +// +void +ASDCP::h__Writer::AddEssenceDescriptor(const UL& WrappingUL) +{ + // + // Essence Descriptor + // + m_EssenceDescriptor->EssenceContainer = WrappingUL; + m_HeaderPart.m_Preface->PrimaryPackage = m_FilePackage->InstanceUID; + + // + // Essence Descriptors + // + assert(m_Dict); + UL GenericContainerUL(m_Dict->ul(MDD_GCMulti)); + m_HeaderPart.EssenceContainers.push_back(GenericContainerUL); if ( m_Info.EncryptedEssence ) { - m_Metadata->AddEssenceType(CryptEssenceUL); + 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 { - UL GCUL(GCMulti_Data); - m_Metadata->AddEssenceType(GCUL); - m_Metadata->AddEssenceType(*WrappingUL); + m_HeaderPart.EssenceContainers.push_back(WrappingUL); } - // Link the MP to the FP - m_MPClip->MakeLink(m_FPTrack, 0); + m_HeaderPart.m_Preface->EssenceContainers = m_HeaderPart.EssenceContainers; + m_HeaderPart.AddChildObject(m_EssenceDescriptor); - // - // ** Write out the header ** - // + std::list::iterator sdli = m_EssenceSubDescriptorList.begin(); + for ( ; sdli != m_EssenceSubDescriptorList.end(); sdli++ ) + m_HeaderPart.AddChildObject(*sdli); - m_HeaderPart = new Partition("OpenHeader"); - assert(m_HeaderPart); - m_HeaderPart->SetKAG(1); // Everything else can stay at default - m_HeaderPart->SetUint("BodySID", 1); - - m_HeaderPart->AddMetadata(m_Metadata); - - // Build an Ident set describing us and link into the metadata - MDObject* Ident = new MDObject("Identification"); - assert(Ident); - Ident->SetString("CompanyName", m_Info.CompanyName); - Ident->SetString("ProductName", m_Info.ProductName); - Ident->SetString("VersionString", m_Info.ProductVersion); - UUID ProductUID(m_Info.ProductUUID); - Ident->SetValue("ProductUID", DataChunk(UUIDlen, ProductUID.GetValue())); - - // TODO: get Oliver to show me how this works - // Ident->SetString("ToolkitVersion", ?); - - m_Metadata->UpdateGenerations(*Ident); + m_FilePackage->Descriptor = m_EssenceDescriptor->InstanceUID; +} - if ( m_Info.EncryptedEssence ) - AddDMScrypt(m_FilePackage, m_Info, SourceEssenceContainerLabel); +// +Result_t +ASDCP::h__Writer::CreateBodyPart(const MXF::Rational& EditRate, ui32_t BytesPerEditUnit) +{ + assert(m_Dict); + Result_t result = RESULT_OK; - // Write the header partition - m_File->WritePartition(*m_HeaderPart, HeaderPadding); + // create a body partition if we're writing proper 429-3/OP-Atom + if ( m_Info.LabelSetType == LS_MXF_SMPTE ) + { + // Body Partition + m_BodyPart.EssenceContainers = m_HeaderPart.EssenceContainers; + m_BodyPart.ThisPartition = m_File.Tell(); + m_BodyPart.BodySID = 1; + UL OPAtomUL(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 - // set up the index - switch ( EssenceType ) + UL BodyUL(m_Dict->ul(MDD_ClosedCompleteBodyPartition)); + result = m_BodyPart.WriteToFile(m_File, BodyUL); + } + else + { + m_HeaderPart.BodySID = 1; + } + + if ( ASDCP_SUCCESS(result) ) { - case ESS_MPEG2_VES: - case ESS_JPEG_2000: - m_IndexMan = new IndexManager(0, 0); - m_IndexMan->SetPosTableIndex(0, -1); - break; - - case ESS_PCM_24b_48k: - m_IndexMan = new IndexManager(0, BytesPerEditUnit); - break; - - case ESS_UNKNOWN: - return RESULT_INIT; + // Index setup + Kumu::fpos_t ECoffset = m_File.Tell(); + m_FooterPart.IndexSID = 129; + + if ( BytesPerEditUnit == 0 ) + m_FooterPart.SetIndexParamsVBR(&m_HeaderPart.m_Primer, EditRate, ECoffset); + else + m_FooterPart.SetIndexParamsCBR(&m_HeaderPart.m_Primer, BytesPerEditUnit, EditRate); } - m_IndexMan->SetBodySID(1); - m_IndexMan->SetIndexSID(129); - m_IndexMan->SetEditRate(EditRate_); + return result; +} + +// +Result_t +ASDCP::h__Writer::WriteMXFHeader(const std::string& PackageLabel, const UL& WrappingUL, + const std::string& TrackName, const UL& DataDefinition, + const MXF::Rational& EditRate, ui32_t TCFrameRate, ui32_t BytesPerEditUnit) +{ + InitHeader(); + AddSourceClip(EditRate, TCFrameRate, TrackName, DataDefinition, PackageLabel); + AddEssenceDescriptor(WrappingUL); + + Result_t result = m_HeaderPart.WriteToFile(m_File, m_HeaderSize); + + if ( KM_SUCCESS(result) ) + result = CreateBodyPart(EditRate, BytesPerEditUnit); - return RESULT_OK; + 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) { - Result_t result; + Result_t result = RESULT_OK; IntegrityPack IntPack; byte_t overhead[128]; - MemIOWriter Overhead(overhead, 128); + Kumu::MemIOWriter Overhead(overhead, 128); + assert(m_Dict); if ( FrameBuf.Size() == 0 ) { @@ -285,7 +523,7 @@ ASDCP::h__Writer::WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf, const byte if ( ASDCP_SUCCESS(result) ) { // write UL - Overhead.WriteRaw((byte_t*)CryptEssenceUL_Data, klv_key_size); + Overhead.WriteRaw(m_Dict->ul(MDD_CryptEssence), SMPTE_UL_LENGTH); // construct encrypted triplet header ui32_t ETLength = klv_cryptinfo_size + m_CtFrameBuf.Size(); @@ -293,27 +531,27 @@ ASDCP::h__Writer::WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf, const byte if ( m_Info.UsesHMAC ) ETLength += klv_intpack_size; else - ETLength += (klv_length_size * 3); // for empty intpack + ETLength += (MXF_BER_LENGTH * 3); // for empty intpack - Overhead.WriteBER(ETLength, klv_length_size); // write encrypted triplet length - Overhead.WriteBER(UUIDlen, klv_length_size); // write ContextID length + 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), klv_length_size); // write PlaintextOffset length + Overhead.WriteBER(sizeof(ui64_t), MXF_BER_LENGTH); // write PlaintextOffset length Overhead.WriteUi64BE(FrameBuf.PlaintextOffset()); // write PlaintextOffset - Overhead.WriteBER(klv_key_size, klv_length_size); // write essence UL length - Overhead.WriteRaw((byte_t*)EssenceUL, klv_key_size); // write the essence UL - Overhead.WriteBER(sizeof(ui64_t), klv_length_size); // write SourceLength length + 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(), klv_length_size); // write ESV length + Overhead.WriteBER(m_CtFrameBuf.Size(), MXF_BER_LENGTH); // write ESV length - result = m_File->Writev(Overhead.Data(), Overhead.Size()); + result = m_File.Writev(Overhead.Data(), Overhead.Length()); } if ( ASDCP_SUCCESS(result) ) { - m_StreamOffset += Overhead.Size(); + m_StreamOffset += Overhead.Length(); // write encrypted source value - result = m_File->Writev((byte_t*)m_CtFrameBuf.RoData(), m_CtFrameBuf.Size()); + result = m_File.Writev((byte_t*)m_CtFrameBuf.RoData(), m_CtFrameBuf.Size()); } if ( ASDCP_SUCCESS(result) ) @@ -321,7 +559,7 @@ ASDCP::h__Writer::WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf, const byte m_StreamOffset += m_CtFrameBuf.Size(); byte_t hmoverhead[512]; - MemIOWriter HMACOverhead(hmoverhead, 512); + Kumu::MemIOWriter HMACOverhead(hmoverhead, 512); // write the HMAC if ( m_Info.UsesHMAC ) @@ -331,29 +569,29 @@ ASDCP::h__Writer::WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf, const byte 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, klv_length_size); + HMACOverhead.WriteBER(0, MXF_BER_LENGTH); } // write HMAC - result = m_File->Writev(HMACOverhead.Data(), HMACOverhead.Size()); - m_StreamOffset += HMACOverhead.Size(); + result = m_File.Writev(HMACOverhead.Data(), HMACOverhead.Length()); + m_StreamOffset += HMACOverhead.Length(); } } else { - Overhead.WriteRaw((byte_t*)EssenceUL, klv_key_size); - Overhead.WriteBER(FrameBuf.Size(), klv_length_size); - result = m_File->Writev(Overhead.Data(), Overhead.Size()); + Overhead.WriteRaw((byte_t*)EssenceUL, SMPTE_UL_LENGTH); + Overhead.WriteBER(FrameBuf.Size(), MXF_BER_LENGTH); + result = m_File.Writev(Overhead.Data(), Overhead.Length()); if ( ASDCP_SUCCESS(result) ) - result = m_File->Writev((byte_t*)FrameBuf.RoData(), FrameBuf.Size()); + result = m_File.Writev((byte_t*)FrameBuf.RoData(), FrameBuf.Size()); if ( ASDCP_SUCCESS(result) ) - m_StreamOffset += Overhead.Size() + FrameBuf.Size(); + m_StreamOffset += Overhead.Length() + FrameBuf.Size(); } if ( ASDCP_SUCCESS(result) ) - result = m_File->Writev(); + result = m_File.Writev(); return result; } @@ -362,95 +600,49 @@ ASDCP::h__Writer::WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf, const byte // standard method of writing the header and footer of a completed MXF file // Result_t -ASDCP::h__Writer::WriteMXFFooter(EssenceType_t EssenceType) +ASDCP::h__Writer::WriteMXFFooter() { - // write the index - DataChunk IndexChunk; - ui32_t IndexSID = 0; - - // Find all essence container data sets so we can update "IndexSID" - MDObjectListPtr ECDataSets = 0; - MDObject* Ptr = (*m_Metadata)["ContentStorage"]; - if ( Ptr ) - Ptr = Ptr->GetLink(); - if ( Ptr ) - Ptr = (*Ptr)["EssenceContainerData"]; - if ( Ptr ) - ECDataSets = Ptr->ChildList("EssenceContainer"); - - // ** Handle full index tables next ** - // *********************************** - - // Make an index table containing all available entries - IndexTablePtr Index = m_IndexMan->MakeIndex(); - m_IndexMan->AddEntriesToIndex(Index); - - // Write the index table - Index->WriteIndex(IndexChunk); - - // Record the IndexSID for when the index is written - IndexSID = Index->IndexSID; - - // Update IndexSID in essence container data set - MDObjectList::iterator ECD_it = ECDataSets->begin(); - while(ECD_it != ECDataSets->end()) - { - if((*ECD_it)->GetLink()) - { - if((*ECD_it)->GetLink()->GetUint("BodySID") == m_IndexMan->GetBodySID()) - { - (*ECD_it)->GetLink()->SetUint("IndexSID", m_IndexMan->GetIndexSID()); - break; - } - } + // Set top-level file package correctly for OP-Atom - ECD_it++; - } + // m_MPTCSequence->Duration = m_MPTimecode->Duration = m_MPClSequence->Duration = m_MPClip->Duration = + // m_FPTCSequence->Duration = m_FPTimecode->Duration = m_FPClSequence->Duration = m_FPClip->Duration = - // If we are writing OP-Atom this is the first place we can claim it - m_Metadata->SetOP(OPAtomUL); - - // Set top-level file package correctly for OP-Atom - m_Metadata->SetPrimaryPackage(m_FilePackage); - - m_Metadata->SetTime(); - m_MPTimecode->SetDuration(m_FramesWritten); + DurationElementList_t::iterator dli = m_DurationUpdateList.begin(); - m_MPClip->SetDuration(m_FramesWritten); - m_FPTimecode->SetDuration(m_FramesWritten); - m_FPClip->SetDuration(m_FramesWritten); - m_EssenceDescriptor->SetInt64("ContainerDuration", m_FramesWritten); + for (; dli != m_DurationUpdateList.end(); dli++ ) + **dli = m_FramesWritten; - // Turn the header or body partition into a footer - m_HeaderPart->ChangeType("CompleteFooter"); - m_HeaderPart->SetUint("IndexSID", IndexSID); + m_EssenceDescriptor->ContainerDuration = m_FramesWritten; + m_FooterPart.PreviousPartition = m_HeaderPart.m_RIP.PairArray.back().ByteOffset; - // Make sure any new sets are linked in - m_HeaderPart->UpdateMetadata(m_Metadata); + 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; - // Actually write the footer - m_File->WritePartitionWithIndex(*m_HeaderPart, &IndexChunk, false); + assert(m_Dict); + // re-label the partition + UL OPAtomUL(m_Dict->ul(MDD_OPAtom)); + m_HeaderPart.OperationalPattern = OPAtomUL; + m_HeaderPart.m_Preface->OperationalPattern = m_HeaderPart.OperationalPattern; - // Add a RIP - m_File->WriteRIP(); + m_FooterPart.OperationalPattern = m_HeaderPart.OperationalPattern; + m_FooterPart.EssenceContainers = m_HeaderPart.EssenceContainers; + m_FooterPart.FooterPartition = here; + m_FooterPart.ThisPartition = here; - // - // ** Update the header ** - // - // For generalized OPs update the value of "FooterPartition" in the header pack - // For OP-Atom re-write the entire header - // - ASDCP::fpos_t FooterPos = m_HeaderPart->GetUint64("FooterPartition"); - m_File->Seek(0); + Result_t result = m_FooterPart.WriteToFile(m_File, m_FramesWritten); - m_HeaderPart->ChangeType("ClosedCompleteHeader"); - m_HeaderPart->SetUint64("FooterPartition", FooterPos); - m_HeaderPart->SetUint64("BodySID", 1); + if ( ASDCP_SUCCESS(result) ) + result = m_HeaderPart.m_RIP.WriteToFile(m_File); - m_File->ReWritePartition(*m_HeaderPart); - m_File->Close(); - - return RESULT_OK; + 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; } //