From f4061a21fffad4fdf8dbb2f193f0f0960b25421c Mon Sep 17 00:00:00 2001 From: jhurst Date: Mon, 6 Aug 2018 22:07:03 +0000 Subject: [PATCH] o Added support for SMPTE RDD 47 "ISXD Track File" o Added generic support for SMPTE RP 2057 "Text-Based Metadata Carriage in MXF" o Re-factored AS-02 frame-wrap index write to use a common implementation o Re-factored support for SMPTE ST 410 to use a common implementation (affects o AS-DCP and AS-02 timed-text MXF (SMPTE 429-5) o Patched several ambiguous integer casts. o Added new essence type identifiers ESS_AS02_ISXD and ESS_AS02_ACES o Fixed a bug wherein the Generic Container data tarck clip was instead being o written as a DM track o Fixed UL values DCDataDescriptor and ContainerConstraintSubDescriptor to have o a byte 6 value of 0x53 (Tag Set) instead of 0x07 (coding sentinel) o Added UL values 492 - 511 to the dictionary o Added ApplicationSchemes and ConformsToSpecifications to the Preface set o Added default initializer to MXF::LineMapPair o Added sets DescriptiveFramework, DescriptiveObject, TextBasedDMFramework, o TextBasedObject, GenericStreamTextBasedSet and ISXDDataEssenceDescriptor o Added ISXD support and options '-G', '-u' to as-02-wrap o Added ISXD support and option '-g' to as-02-unwrap --- src/AS_02.h | 98 +++++++- src/AS_02_JP2K.cpp | 2 +- src/AS_02_PHDR.cpp | 17 +- src/AS_02_TimedText.cpp | 69 +----- src/AS_02_internal.h | 17 +- src/AS_DCP.h | 6 +- src/AS_DCP_MXF.cpp | 8 + src/AS_DCP_TimedText.cpp | 67 +----- src/AS_DCP_internal.h | 217 +++++++++-------- src/Dict.cpp | 2 +- src/KLV.cpp | 2 +- src/MDD.cpp | 69 +++++- src/MDD.h | 25 +- src/MXF.cpp | 28 +++ src/MXF.h | 5 +- src/MXFTypes.h | 12 +- src/Makefile.am | 3 +- src/Metadata.cpp | 494 +++++++++++++++++++++++++++++++++++++++ src/Metadata.h | 141 +++++++++++ src/as-02-info.cpp | 9 +- src/as-02-unwrap.cpp | 148 +++++++++++- src/as-02-wrap.cpp | 235 ++++++++++++++++++- src/h__02_Reader.cpp | 5 +- src/h__02_Writer.cpp | 11 +- src/h__Writer.cpp | 127 +++++++++- src/klvwalk.cpp | 4 +- 26 files changed, 1529 insertions(+), 292 deletions(-) diff --git a/src/AS_02.h b/src/AS_02.h index 33163c3..c2c5179 100644 --- a/src/AS_02.h +++ b/src/AS_02.h @@ -1,5 +1,5 @@ /* -Copyright (c) 2011-2016, Robert Scheler, Heiko Sparenberg Fraunhofer IIS, +Copyright (c) 2011-2018, Robert Scheler, Heiko Sparenberg Fraunhofer IIS, John Hurst All rights reserved. @@ -498,7 +498,103 @@ namespace AS_02 }; } // namespace TimedText + namespace ISXD + { + // + class MXFWriter + { + class h__Writer; + ASDCP::mem_ptr m_Writer; + ASDCP_NO_COPY_CONSTRUCT(MXFWriter); + + public: + MXFWriter(); + virtual ~MXFWriter(); + + // Warning: direct manipulation of MXF structures can interfere + // with the normal operation of the wrapper. Caveat emptor! + virtual ASDCP::MXF::OP1aHeader& OP1aHeader(); + virtual ASDCP::MXF::RIP& RIP(); + // Open the file for writing. The file must not exist. Returns error if + // the operation cannot be completed or if nonsensical data is discovered + // in the essence descriptor. + Result_t OpenWrite(const std::string& filename, const ASDCP::WriterInfo&, + const ASDCP::UL& data_essence_coding, + const ASDCP::Rational& edit_rate, const ui32_t& header_size = 16384, + const IndexStrategy_t& strategy = IS_FOLLOW, const ui32_t& partition_space = 10); + + // Writes a frame of essence to the MXF file. If the optional AESEncContext + // argument is present, the essence is encrypted prior to writing. + // Fails if the file is not open, is finalized, or an operating system + // error occurs. + Result_t WriteFrame(const ASDCP::FrameBuffer&, ASDCP::AESEncContext* = 0, ASDCP::HMACContext* = 0); + + // Writes an XML text document to the MXF file as per RP 2067. If the + // optional AESEncContext argument is present, the document is encrypted + // prior to writing. Fails if the file is not open, is finalized, or an + // operating system error occurs. + Result_t AddDmsGenericPartUtf8Text(const ASDCP::FrameBuffer& frame_buffer, ASDCP::AESEncContext* enc = 0, ASDCP::HMACContext* hmac = 0); + + // Closes the MXF file, writing the index and revised header. + Result_t Finalize(); + }; + + // + class MXFReader + { + class h__Reader; + ASDCP::mem_ptr m_Reader; + ASDCP_NO_COPY_CONSTRUCT(MXFReader); + + public: + MXFReader(); + virtual ~MXFReader(); + + // Warning: direct manipulation of MXF structures can interfere + // with the normal operation of the wrapper. Caveat emptor! + virtual ASDCP::MXF::OP1aHeader& OP1aHeader(); + virtual AS_02::MXF::AS02IndexReader& AS02IndexReader(); + virtual ASDCP::MXF::RIP& RIP(); + + // Open the file for reading. The file must exist. Returns error if the + // operation cannot be completed. + Result_t OpenRead(const std::string& filename) const; + + // Open the file for reading. The file must exist. Returns error if the + // operation cannot be completed. If global metadata is available it will + // be placed into the buffer object passed as the second argument. + Result_t OpenRead(const std::string& filename, ASDCP::FrameBuffer& global_metadata) const; + + // Returns RESULT_INIT if the file is not open. + Result_t Close() const; + + // Fill a WriterInfo struct with the values from the file's header. + // Returns RESULT_INIT if the file is not open. + Result_t FillWriterInfo(ASDCP::WriterInfo&) const; + + // Reads a frame of essence from the MXF file. If the optional AESEncContext + // argument is present, the essence is decrypted after reading. If the MXF + // file is encrypted and the AESDecContext argument is NULL, the frame buffer + // will contain the ciphertext frame data. If the HMACContext argument is + // not NULL, the HMAC will be calculated (if the file supports it). + // Returns RESULT_INIT if the file is not open, failure if the frame number is + // out of range, or if optional decrypt or HAMC operations fail. + Result_t ReadFrame(ui32_t frame_number, ASDCP::FrameBuffer&, + ASDCP::AESDecContext* = 0, ASDCP::HMACContext* = 0) const; + + // Reads a Generic Stream Partition payload. Returns RESULT_INIT if the file is + // not open, or RESULT_FORMAT if the SID is not present in the RIP, or if the + // actual partition at ByteOffset does not have a matching BodySID value. + // Encryption is not currently supported. + Result_t ReadGenericStreamPartitionPayload(ui32_t SID, ASDCP::FrameBuffer& FrameBuf); + + // Print debugging information to stream + void DumpHeaderMetadata(FILE* = 0) const; + void DumpIndex(FILE* = 0) const; + }; + + } } // namespace AS_02 diff --git a/src/AS_02_JP2K.cpp b/src/AS_02_JP2K.cpp index ffb40a9..0379a96 100644 --- a/src/AS_02_JP2K.cpp +++ b/src/AS_02_JP2K.cpp @@ -68,7 +68,7 @@ public: Result_t AS_02::JP2K::MXFReader::h__Reader::OpenRead(const std::string& filename) { - Result_t result = OpenMXFRead(filename.c_str()); + Result_t result = OpenMXFRead(filename); if( KM_SUCCESS(result) ) { diff --git a/src/AS_02_PHDR.cpp b/src/AS_02_PHDR.cpp index 94b973d..61795a3 100644 --- a/src/AS_02_PHDR.cpp +++ b/src/AS_02_PHDR.cpp @@ -594,9 +594,8 @@ AS_02::PHDR::MXFWriter::h__Writer::WriteFrame(const AS_02::PHDR::FrameBuffer& Fr if ( m_FramesWritten > 1 && ( ( m_FramesWritten + 1 ) % m_PartitionSpace ) == 0 ) { - m_IndexWriter.ThisPartition = m_File.Tell(); - m_IndexWriter.WriteToFile(m_File); - m_RIP.PairArray.push_back(RIP::PartitionPair(0, m_IndexWriter.ThisPartition)); + assert(m_IndexWriter.GetDuration() > 0); + FlushIndexPartition(); UL body_ul(m_Dict->ul(MDD_ClosedCompleteBodyPartition)); Partition body_part(m_Dict); @@ -627,18 +626,16 @@ Result_t AS_02::PHDR::MXFWriter::h__Writer::Finalize(const std::string& PHDR_master_metadata) { if ( ! m_State.Test_RUNNING() ) - return RESULT_STATE; + { + KM_RESULT_STATE_HERE(); + return RESULT_STATE; + } Result_t result = m_State.Goto_FINAL(); if ( KM_SUCCESS(result) ) { - if ( m_IndexWriter.GetDuration() > 0 ) - { - m_IndexWriter.ThisPartition = this->m_File.Tell(); - m_IndexWriter.WriteToFile(this->m_File); - m_RIP.PairArray.push_back(RIP::PartitionPair(0, this->m_IndexWriter.ThisPartition)); - } + FlushIndexPartition(); if ( ! PHDR_master_metadata.empty() ) { diff --git a/src/AS_02_TimedText.cpp b/src/AS_02_TimedText.cpp index 9e14600..974c811 100644 --- a/src/AS_02_TimedText.cpp +++ b/src/AS_02_TimedText.cpp @@ -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 @@ -186,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); @@ -197,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(tmp_iobj); + TimedTextResourceSubDescriptor* desc_object = dynamic_cast(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); } + if ( KM_SUCCESS(result) ) + { + frame_buf.AssetID(uuid.Value()); + frame_buf.MIMEType(desc_object->MIMEMediaType); + } + return result; } diff --git a/src/AS_02_internal.h b/src/AS_02_internal.h index 560fb6c..e068f8d 100644 --- a/src/AS_02_internal.h +++ b/src/AS_02_internal.h @@ -1,5 +1,5 @@ /* -Copyright (c) 2011-2016, Robert Scheler, Heiko Sparenberg Fraunhofer IIS, +Copyright (c) 2011-2018, Robert Scheler, Heiko Sparenberg Fraunhofer IIS, John Hurst All rights reserved. @@ -188,7 +188,7 @@ namespace AS_02 if ( KM_SUCCESS(result) ) { - this->m_PartitionSpace *= floor( EditRate.Quotient() + 0.5 ); // convert seconds to edit units + this->m_PartitionSpace *= (ui32_t)floor( EditRate.Quotient() + 0.5 ); // convert seconds to edit units this->m_ECStart = this->m_File.Tell(); this->m_IndexWriter.IndexSID = 129; @@ -207,9 +207,7 @@ namespace AS_02 return result; } - // standard method of writing the header and footer of a completed AS-02 file - // - Result_t WriteAS02Footer() + void FlushIndexPartition() { if ( this->m_IndexWriter.GetDuration() > 0 ) { @@ -217,7 +215,14 @@ namespace AS_02 this->m_IndexWriter.WriteToFile(this->m_File); this->m_RIP.PairArray.push_back(RIP::PartitionPair(0, this->m_IndexWriter.ThisPartition)); } - + } + + // standard method of writing the header and footer of a completed AS-02 file + // + Result_t WriteAS02Footer() + { + this->FlushIndexPartition(); + // update all Duration properties ASDCP::MXF::Partition footer_part(this->m_Dict); DurationElementList_t::iterator dli = this->m_DurationUpdateList.begin(); diff --git a/src/AS_DCP.h b/src/AS_DCP.h index b1540aa..96d066c 100755 --- a/src/AS_DCP.h +++ b/src/AS_DCP.h @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2014, John Hurst +Copyright (c) 2003-2018, John Hurst All rights reserved. Redistribution and use in source and binary forms, with or without @@ -221,8 +221,8 @@ namespace ASDCP { ESS_AS02_PCM_24b_48k, // the file contains one or more PCM audio pairs, clip wrapped ESS_AS02_PCM_24b_96k, // the file contains one or more PCM audio pairs, clip wrapped ESS_AS02_TIMED_TEXT, // the file contains a TTML document and zero or more resources - - ESS_ACES, // the file contains one ACES codestream + ESS_AS02_ISXD, // the file contains an ISXD document stream (per SMPTE RDD 47) + ESS_AS02_ACES, // the file contains two or more ACES codestreams (per SMPTE ST 2067-50) ESS_MAX }; diff --git a/src/AS_DCP_MXF.cpp b/src/AS_DCP_MXF.cpp index a7282df..ed1fa7c 100755 --- a/src/AS_DCP_MXF.cpp +++ b/src/AS_DCP_MXF.cpp @@ -252,6 +252,14 @@ ASDCP::EssenceType(const std::string& filename, EssenceType_t& type) { type = ESS_DCDATA_UNKNOWN; } + else if ( ASDCP_SUCCESS(TestHeader.GetMDObjectByType(OBJ_TYPE_ARGS(ISXDDataEssenceDescriptor))) ) + { + type = ESS_AS02_ISXD; + } + else if ( ASDCP_SUCCESS(TestHeader.GetMDObjectByType(OBJ_TYPE_ARGS(ACESPictureSubDescriptor))) ) + { + type = ESS_AS02_ACES; + } } else { diff --git a/src/AS_DCP_TimedText.cpp b/src/AS_DCP_TimedText.cpp index 6e34a5d..1f0930a 100644 --- a/src/AS_DCP_TimedText.cpp +++ b/src/AS_DCP_TimedText.cpp @@ -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 @@ -244,7 +244,7 @@ ASDCP::TimedText::MXFReader::h__Reader::ReadTimedTextResource(FrameBuffer& Frame // ASDCP::Result_t -ASDCP::TimedText::MXFReader::h__Reader::ReadAncillaryResource(const byte_t* uuid, FrameBuffer& FrameBuf, +ASDCP::TimedText::MXFReader::h__Reader::ReadAncillaryResource(const byte_t* uuid, FrameBuffer& frame_buf, AESDecContext* Ctx, HMACContext* HMAC) { KM_TEST_NULL_L(uuid); @@ -258,68 +258,21 @@ ASDCP::TimedText::MXFReader::h__Reader::ReadAncillaryResource(const byte_t* 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(tmp_iobj); + TimedTextResourceSubDescriptor* desc_object = dynamic_cast(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; - } + assert(desc_object); + result = ReadGenericStreamPartitionPayload(desc_object->EssenceStreamID, frame_buf); + } - if ( KM_SUCCESS(result) ) - { - FrameBuf.AssetID(uuid); - 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 - 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", RID.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); - } - } + if ( KM_SUCCESS(result) ) + { + frame_buf.AssetID(uuid); + frame_buf.MIMEType(desc_object->MIMEMediaType); } return result; diff --git a/src/AS_DCP_internal.h b/src/AS_DCP_internal.h index aad500e..73b9e7a 100755 --- a/src/AS_DCP_internal.h +++ b/src/AS_DCP_internal.h @@ -161,9 +161,15 @@ namespace ASDCP Result_t PCM_ADesc_to_MD(PCM::AudioDescriptor& ADesc, ASDCP::MXF::WaveAudioDescriptor* ADescObj); Result_t MD_to_PCM_ADesc(ASDCP::MXF::WaveAudioDescriptor* ADescObj, PCM::AudioDescriptor& ADesc); - void AddDMScrypt(Partition& HeaderPart, SourcePackage& Package, + void AddDmsCrypt(Partition& HeaderPart, SourcePackage& Package, WriterInfo& Descr, const UL& WrappingUL, const Dictionary*& Dict); + Result_t AddDmsTrackGenericPartUtf8Text(Kumu::FileWriter&, ASDCP::MXF::OP1aHeader&, SourcePackage&, + ASDCP::MXF::RIP&, const Dictionary*&); + // + Result_t WriteGenericStreamPartition(Kumu::FileWriter&, ASDCP::MXF::OP1aHeader&, ASDCP::MXF::RIP&, const Dictionary*&, + const ASDCP::FrameBuffer&, ASDCP::AESEncContext* = 0, ASDCP::HMACContext* = 0); + Result_t Read_EKLV_Packet(Kumu::FileReader& File, const ASDCP::Dictionary& Dict, const ASDCP::WriterInfo& Info, Kumu::fpos_t& LastPosition, ASDCP::FrameBuffer& CtFrameBuf, ui32_t FrameNum, ui32_t SequenceNum, ASDCP::FrameBuffer& FrameBuf, @@ -238,7 +244,7 @@ namespace ASDCP if ( ASDCP_SUCCESS(result) ) { result = m_RIP.InitFromFile(m_File); - ui32_t test_s = m_RIP.PairArray.size(); + ui32_t test_s = (ui32_t)m_RIP.PairArray.size(); if ( ASDCP_FAILURE(result) ) { @@ -390,6 +396,69 @@ namespace ASDCP return RESULT_OK; } + // Reads a Generic Stream Partition payload. Returns RESULT_FORMAT if the SID is + // not present in the RIP, or if the actual partition at ByteOffset does not have + // a matching BodySID value. Encryption is not currently supported. + Result_t ReadGenericStreamPartitionPayload(const ui32_t sid, ASDCP::FrameBuffer& frame_buf) + { + Kumu::fpos_t start_offset = 0, end_offset = 0; + ui32_t sequence = 0; + + // locate SID, record the offset + // Count the sequence length in because this is the sequence + // value needed to complete the HMAC. + ASDCP::MXF::RIP::const_pair_iterator i; + for ( i = m_RIP.PairArray.begin(); i != m_RIP.PairArray.end(); ++i, ++sequence ) + { + if ( sid == i->BodySID ) + { + start_offset = i->ByteOffset; + } + else if ( start_offset != 0 ) + { + end_offset = i->ByteOffset; + break; + } + } + + if ( start_offset == 0 || end_offset == 0 ) + { + DefaultLogSink().Error("Body SID not found: %d.\n", sid); + return RESULT_NOT_FOUND; + } + + // Read the Partition header and then read the payload. + Result_t result = m_File.Seek(start_offset); + + if ( KM_SUCCESS(result) ) + { + result = frame_buf.Capacity(end_offset-start_offset); + } + + if ( KM_SUCCESS(result) ) + { + // read the partition header + ASDCP::MXF::Partition GSPart(m_Dict); + result = GSPart.InitFromFile(m_File); + + if ( KM_SUCCESS(result) ) + { + // check the SID + if ( GSPart.BodySID != sid ) + { + DefaultLogSink().Error("Generic stream partition Body SID differs: %s\n", sid); + result = RESULT_FORMAT; + } + else + { + result = ReadEKLVPacket(0, sequence, frame_buf, m_Dict->ul(MDD_GenericStream_DataElement), 0, 0); + } + } + } + + return result; + } + // void Close() { @@ -620,7 +689,7 @@ namespace ASDCP // Material Package // m_MaterialPackage = new MaterialPackage(m_Dict); - m_MaterialPackage->Name = "AS-DCP Material Package"; + m_MaterialPackage->Name = "Material Package"; m_MaterialPackage->PackageUID = MaterialPackageUMID; m_HeaderPart.AddChildObject(m_MaterialPackage); m_ContentStorage->Packages.push_back(m_MaterialPackage->InstanceUID); @@ -698,105 +767,6 @@ namespace ASDCP m_EssenceDescriptor->LinkedTrackID = FPTrack.Track->TrackID; } - // - void AddDMSegment(const MXF::Rational& clip_edit_rate, - const MXF::Rational& tc_edit_rate, ui32_t tc_frame_rate, - const std::string& TrackName, const UL& DataDefinition, - const std::string& PackageLabel) - { - if ( m_ContentStorage == 0 ) - { - m_ContentStorage = new ContentStorage(m_Dict); - m_HeaderPart.AddChildObject(m_ContentStorage); - m_HeaderPart.m_Preface->ContentStorage = m_ContentStorage->InstanceUID; - } - - EssenceContainerData* ECD = new EssenceContainerData(m_Dict); - m_HeaderPart.AddChildObject(ECD); - m_ContentStorage->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); - m_ContentStorage->Packages.push_back(m_MaterialPackage->InstanceUID); - - TrackSet MPTCTrack = - CreateTimecodeTrack(m_HeaderPart, *m_MaterialPackage, - tc_edit_rate, tc_frame_rate, 0, m_Dict); - - MPTCTrack.Sequence->Duration.set_has_value(); - m_DurationUpdateList.push_back(&(MPTCTrack.Sequence->Duration.get())); - MPTCTrack.Clip->Duration.set_has_value(); - m_DurationUpdateList.push_back(&(MPTCTrack.Clip->Duration.get())); - - TrackSet MPTrack = - CreateTrackAndSequence(m_HeaderPart, *m_MaterialPackage, - TrackName, clip_edit_rate, DataDefinition, - 2, m_Dict); - MPTrack.Sequence->Duration.set_has_value(); - m_DurationUpdateList.push_back(&(MPTrack.Sequence->Duration.get())); - - 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); - m_ContentStorage->Packages.push_back(m_FilePackage->InstanceUID); - - TrackSet FPTCTrack = - CreateTimecodeTrack(m_HeaderPart, *m_FilePackage, - clip_edit_rate, tc_frame_rate, - ui64_C(3600) * tc_frame_rate, m_Dict); - - FPTCTrack.Sequence->Duration.set_has_value(); - m_DurationUpdateList.push_back(&(FPTCTrack.Sequence->Duration.get())); - FPTCTrack.Clip->Duration.set_has_value(); - m_DurationUpdateList.push_back(&(FPTCTrack.Clip->Duration.get())); - - TrackSet FPTrack = - CreateTrackAndSequence(m_HeaderPart, *m_FilePackage, - TrackName, clip_edit_rate, DataDefinition, - 2, m_Dict); - - FPTrack.Sequence->Duration.set_has_value(); - m_DurationUpdateList.push_back(&(FPTrack.Sequence->Duration.get())); - - 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 = "ST 429-5 Timed Text"; - - m_DurationUpdateList.push_back(&(FPTrack.Clip->Duration)); - - m_EssenceDescriptor->LinkedTrackID = FPTrack.Track->TrackID; - } - // void AddEssenceDescriptor(const UL& WrappingUL) { @@ -818,7 +788,7 @@ namespace ASDCP 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); + AddDmsCrypt(m_HeaderPart, *m_FilePackage, m_Info, WrappingUL, m_Dict); //// TODO: fix DMSegment Duration value } else @@ -836,6 +806,47 @@ namespace ASDCP m_FilePackage->Descriptor = m_EssenceDescriptor->InstanceUID; } + Result_t AddDmsGenericPartUtf8Text(const ASDCP::FrameBuffer& frame_buffer, + ASDCP::AESEncContext* enc = 0, ASDCP::HMACContext* hmac = 0) + { + Kumu::fpos_t previous_partition_offset = m_RIP.PairArray.back().ByteOffset; + Result_t result = AddDmsTrackGenericPartUtf8Text(m_File, m_HeaderPart, *m_FilePackage, m_RIP, m_Dict); + + if ( KM_SUCCESS(result) ) + { + // m_RIP now contains an entry (at the back) for the new generic stream + // (this entry was created during the call to AddDmsTrackGenericPartUtf8Text()) + if ( m_File.Tell() != m_RIP.PairArray.back().ByteOffset ) + { + DefaultLogSink().Error("File offset has moved since RIP modification. Unrecoverable error.\n"); + return RESULT_FAIL; + } + + // create generic stream partition header + 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 = m_RIP.PairArray.back().ByteOffset; + GSPart.PreviousPartition = previous_partition_offset; + GSPart.OperationalPattern = m_HeaderPart.OperationalPattern; + GSPart.BodySID = m_RIP.PairArray.back().BodySID; + GSPart.EssenceContainers = m_HeaderPart.EssenceContainers; + + static UL gs_part_ul(m_Dict->ul(MDD_GenericStreamPartition)); + Result_t result = GSPart.WriteToFile(m_File, gs_part_ul); + + if ( KM_SUCCESS(result) ) + { + result = Write_EKLV_Packet(m_File, *m_Dict, m_HeaderPart, m_Info, m_CtFrameBuf, m_FramesWritten, + m_StreamOffset, frame_buffer, GenericStream_DataElement.Value(), enc, hmac); + } + } + + return result; + } + // void Close() { diff --git a/src/Dict.cpp b/src/Dict.cpp index a50a05e..fbf76b0 100755 --- a/src/Dict.cpp +++ b/src/Dict.cpp @@ -201,7 +201,7 @@ ASDCP::Dictionary::AddEntry(const MDDEntry& Entry, ui32_t index) std::map::iterator ii = m_md_lookup.find(TmpUL); if ( ii != m_md_lookup.end() ) { - fprintf(stderr, "DUPE! %s (%02x, %02x) %s | (%02x, %02x) %s\n", + Kumu::DefaultLogSink().Warn("Duplicate Dictionary item: %s (%02x, %02x) %s | (%02x, %02x) %s\n", TmpUL.EncodeString(buf, 64), m_MDD_Table[ii->second].tag.a, m_MDD_Table[ii->second].tag.b, m_MDD_Table[ii->second].name, diff --git a/src/KLV.cpp b/src/KLV.cpp index b9a5d63..303a672 100755 --- a/src/KLV.cpp +++ b/src/KLV.cpp @@ -172,7 +172,7 @@ ASDCP::KLVPacket::Dump(FILE* stream, const Dictionary& Dict, bool show_value) fprintf(stream, "%s", TmpUL.EncodeString(buf, 64)); const MDDEntry* Entry = Dict.FindULAnyVersion(m_KeyStart); - fprintf(stream, " len: %7qu (%s)\n", m_ValueLength, (Entry ? Entry->name : "Unknown")); + fprintf(stream, " len: %7llu (%s)\n", m_ValueLength, (Entry ? Entry->name : "Unknown")); if ( show_value && m_ValueLength < 1000 ) Kumu::hexdump(m_ValueStart, Kumu::xmin(m_ValueLength, (ui64_t)128), stream); diff --git a/src/MDD.cpp b/src/MDD.cpp index de71401..bae0f2b 100644 --- a/src/MDD.cpp +++ b/src/MDD.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2006-2016, John Hurst +Copyright (c) 2006-2018, John Hurst All rights reserved. Redistribution and use in source and binary forms, with or without @@ -766,7 +766,7 @@ static const ASDCP::MDDEntry s_MDD_Table[] = { {0}, true, "JPEG2000PictureSubDescriptor_QuantizationDefault" }, { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 243 0x0d, 0x01, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00 }, - {0}, false, "DM_Framework" }, + {0}, false, "DescriptiveFramework" }, { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 244 0x0d, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 }, {0}, false, "DM_Set" }, @@ -923,7 +923,7 @@ static const ASDCP::MDDEntry s_MDD_Table[] = { { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x02, 0x01, 0x0d, // 295 0x0d, 0x01, 0x03, 0x01, 0x17, 0x01, 0x0d, 0x00 }, {0}, false, "DCDataEssence" }, - { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x7f, 0x01, 0x01, // 296 + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 296 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x73, 0x00 }, {0}, false, "DCDataDescriptor" }, { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x05, // 297 @@ -1159,7 +1159,7 @@ static const ASDCP::MDDEntry s_MDD_Table[] = { // ContainerConstraintSubDescriptor to the GenericDescriptor::SubDescriptors // property of the top-most File Descriptor that describes the essence // container. - { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x7f, 0x01, 0x01, // 373 + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 373 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x67, 0x00 }, {0}, false, "ContainerConstraintSubDescriptor" }, @@ -1528,7 +1528,66 @@ static const ASDCP::MDDEntry s_MDD_Table[] = { { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0d, // 491 0x04, 0x10, 0x01, 0x01, 0x01, 0x03, 0x00, 0x00 }, {0}, false, "HDRReferenceViewingEnvironment" }, - + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x02, 0x01, 0x05, // 492 + 0x0e, 0x09, 0x05, 0x02, 0x01, 0x00, 0x01, 0x00 }, + {0}, false, "FrameWrappedISXDData" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x05, // 493 + 0x0e, 0x09, 0x06, 0x07, 0x01, 0x01, 0x01, 0x03 }, + {0}, false, "FrameWrappedISXDContainer" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x05, // 494 + 0x0e, 0x09, 0x05, 0x02, 0x00, 0x00, 0x00, 0x00 }, + {0}, false, "ISXDDataEssenceDescriptor" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x05, // 495 + 0x0e, 0x09, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00 }, + {0}, false, "ISXDDataEssenceDescriptor_NamespaceURI" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x05, // 496 + 0x0e, 0x09, 0x06, 0x06, 0x00, 0x00, 0x00, 0xff }, + {0}, false, "UTF_8_Text_DataEssenceCoding" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 497-chk + 0x0D, 0x01, 0x04, 0x01, 0x04, 0x01, 0x01, 0x00 }, + {0}, false, "TextBasedDMFramework" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0D, // 498-chk + 0x06, 0x01, 0x01, 0x04, 0x05, 0x41, 0x01, 0x00 }, + {0}, true, "TextBasedDMFramework_ObjectRef" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 499 + 0x0d, 0x01, 0x04, 0x01, 0x04, 0x03, 0x01, 0x00 }, + {0}, false, "TextBasedObject" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0d, // 500 + 0x04, 0x06, 0x08, 0x06, 0x00, 0x00, 0x00, 0x00 }, + {0}, false, "TextBasedObject_PayloadSchemeID" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0d, // 501 + 0x04, 0x09, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00 }, + {0}, false, "TextBasedObject_TextMIMEMediaType" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0d, // 502 + 0x03, 0x01, 0x01, 0x02, 0x02, 0x14, 0x00, 0x00 }, + {0}, false, "TextBasedObject_RFC5646TextLanguageCode" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0d, // 503 + 0x03, 0x02, 0x01, 0x06, 0x03, 0x02, 0x00, 0x00 }, + {0}, true, "TextBasedObject_TextDataDescription" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 504 + 0x0d, 0x01, 0x04, 0x01, 0x04, 0x02, 0x01, 0x00 }, + {0}, false, "GenericStreamTextBasedSet" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0d, // 505 + 0x01, 0x03, 0x04, 0x08, 0x00, 0x00, 0x00, 0x00 }, + {0}, false, "GenericStreamTextBasedSet_GenericStreamSID" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x06, 0x01, 0x01, // 506 + 0x0d, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 }, + {0}, false, "DescriptiveObject" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0c, // 507 + 0x05, 0x20, 0x07, 0x01, 0x0c, 0x00, 0x00, 0x00 }, + {0}, false, "DescriptiveFramework_LinkedDescriptiveFrameworkPlugInId" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0c, // 508 + 0x05, 0x20, 0x07, 0x01, 0x11, 0x00, 0x00, 0x00 }, + {0}, false, "DescriptiveObject_LinkedDescriptiveObjectPlugInId" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0c, // 509 + 0x01, 0x02, 0x02, 0x10, 0x02, 0x03, 0x00, 0x00 }, + {0}, false, "Preface_ApplicationSchemes" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0e, // 510 + 0x01, 0x02, 0x02, 0x10, 0x02, 0x04, 0x00, 0x00 }, + {0}, false, "Preface_ConformsToSpecifications" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0c, // 511 + 0x0d, 0x01, 0x04, 0x01, 0x04, 0x01, 0x01, 0x00 }, + {0}, false, "MXFTextBasedFramework" }, { {0}, {0}, false, 0 } }; diff --git a/src/MDD.h b/src/MDD.h index 667cf50..7794336 100755 --- a/src/MDD.h +++ b/src/MDD.h @@ -1,5 +1,5 @@ /* -Copyright (c) 2006-2016, John Hurst +Copyright (c) 2006-2018, John Hurst All rights reserved. Redistribution and use in source and binary forms, with or without @@ -278,7 +278,7 @@ namespace ASDCP { MDD_JPEG2000PictureSubDescriptor_PictureComponentSizing, // 240 MDD_JPEG2000PictureSubDescriptor_CodingStyleDefault, // 241 MDD_JPEG2000PictureSubDescriptor_QuantizationDefault, // 242 - MDD_DM_Framework, // 243 + MDD_DescriptiveFramework, // 243 MDD_DM_Set, // 244 MDD_EncryptedContainerLabel, // 245 MDD_CryptographicFrameworkLabel, // 246 @@ -527,7 +527,26 @@ namespace ASDCP { MDD_TheatricalViewingEnvironment, // 489 MDD_HDTVReferenceViewingEnvironment, // 490 MDD_HDRReferenceViewingEnvironment, // 491 - + MDD_FrameWrappedISXDData, // 492 + MDD_FrameWrappedISXDContainer, // 493 + MDD_ISXDDataEssenceDescriptor, // 494 + MDD_ISXDDataEssenceDescriptor_NamespaceURI, // 495 + MDD_UTF_8_Text_DataEssenceCoding, // 496 + MDD_TextBasedDMFramework, // 497 + MDD_TextBasedDMFramework_ObjectRef, // 498 + MDD_TextBasedObject, // 499 + MDD_TextBasedObject_PayloadSchemeID, // 500 + MDD_TextBasedObject_TextMIMEMediaType, // 501 + MDD_TextBasedObject_RFC5646TextLanguageCode, // 502 + MDD_TextBasedObject_TextDataDescription, // 503 + MDD_GenericStreamTextBasedSet, // 504 + MDD_GenericStreamTextBasedSet_GenericStreamSID, // 505 + MDD_DescriptiveObject, // 506 + MDD_DescriptiveFramework_LinkedDescriptiveFrameworkPlugInId, // 507 + MDD_DescriptiveObject_LinkedDescriptiveObjectPlugInId, // 508 + MDD_Preface_ApplicationSchemes, // 509 + MDD_Preface_ConformsToSpecifications, // 510 + MDD_MXFTextBasedFramework, // 511 MDD_Max }; // enum MDD_t diff --git a/src/MXF.cpp b/src/MXF.cpp index df53b21..1c2ae5c 100755 --- a/src/MXF.cpp +++ b/src/MXF.cpp @@ -608,6 +608,8 @@ ASDCP::MXF::Preface::Copy(const Preface& rhs) OperationalPattern = rhs.OperationalPattern; EssenceContainers = rhs.EssenceContainers; DMSchemes = rhs.DMSchemes; + ApplicationSchemes = rhs.ApplicationSchemes; + ConformsToSpecifications = rhs.ConformsToSpecifications; } // @@ -624,6 +626,16 @@ ASDCP::MXF::Preface::InitFromTLVSet(TLVReader& TLVSet) if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Preface, OperationalPattern)); if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Preface, EssenceContainers)); if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Preface, DMSchemes)); + if ( ASDCP_SUCCESS(result) ) + { + result = TLVSet.ReadObject(OBJ_READ_ARGS_OPT(Preface, ApplicationSchemes)); + ApplicationSchemes.set_has_value( result == RESULT_OK); + } + if ( ASDCP_SUCCESS(result) ) + { + result = TLVSet.ReadObject(OBJ_READ_ARGS_OPT(Preface, ConformsToSpecifications)); + ConformsToSpecifications.set_has_value( result == RESULT_OK); + } return result; } @@ -641,6 +653,14 @@ ASDCP::MXF::Preface::WriteToTLVSet(TLVWriter& TLVSet) if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Preface, OperationalPattern)); if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Preface, EssenceContainers)); if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Preface, DMSchemes)); + if ( ASDCP_SUCCESS(result) && !ApplicationSchemes.empty() ) + { + result = TLVSet.WriteObject(OBJ_WRITE_ARGS_OPT(Preface, ApplicationSchemes)); + } + if ( ASDCP_SUCCESS(result) && !ConformsToSpecifications.empty()) + { + result = TLVSet.WriteObject(OBJ_WRITE_ARGS_OPT(Preface, ConformsToSpecifications)); + } return result; } @@ -682,6 +702,14 @@ ASDCP::MXF::Preface::Dump(FILE* stream) fprintf(stream, " %22s = %s\n", "OperationalPattern", OperationalPattern.EncodeString(identbuf, IdentBufferLen)); fprintf(stream, " %22s:\n", "EssenceContainers"); EssenceContainers.Dump(stream); fprintf(stream, " %22s:\n", "DMSchemes"); DMSchemes.Dump(stream); + if ( ! ApplicationSchemes.empty() ) + { + fprintf(stream, " %22s:\n", "ApplicationSchemes"); ApplicationSchemes.get().Dump(stream); + } + if ( ! ConformsToSpecifications.empty() ) + { + fprintf(stream, " %22s:\n", "ConformsToSpecifications"); ConformsToSpecifications.get().Dump(stream); + } } //------------------------------------------------------------------------------------------ diff --git a/src/MXF.h b/src/MXF.h index 19ff446..b8d1193 100755 --- a/src/MXF.h +++ b/src/MXF.h @@ -1,5 +1,5 @@ /* -Copyright (c) 2005-2015, John Hurst +Copyright (c) 2005-2018, John Hurst All rights reserved. Redistribution and use in source and binary forms, with or without @@ -200,7 +200,7 @@ namespace ASDCP inline const char* EncodeString(char* str_buf, ui32_t buf_len) const { snprintf(str_buf, buf_len, "%02x %02x: ", Tag.a, Tag.b); - UL.EncodeString(str_buf + strlen(str_buf), buf_len - strlen(str_buf)); + UL.EncodeString(str_buf + strlen(str_buf), buf_len - (ui32_t)strlen(str_buf)); return str_buf; } @@ -332,6 +332,7 @@ namespace ASDCP Batch
    EssenceContainers; Batch
      DMSchemes; optional_property > ApplicationSchemes; + optional_property > ConformsToSpecifications; Preface(const Dictionary*& d); virtual ~Preface() {} diff --git a/src/MXFTypes.h b/src/MXFTypes.h index cf3d57c..c49fed9 100755 --- a/src/MXFTypes.h +++ b/src/MXFTypes.h @@ -112,12 +112,12 @@ namespace ASDCP bool HasValue() const { return ! this->empty(); } ui32_t ArchiveLength() const { - return ( sizeof(ui32_t) * 2 ) + ( this->size() * this->ItemSize() ); + return ( sizeof(ui32_t) * 2 ) + ( (ui32_t)this->size() * this->ItemSize() ); } bool Archive(Kumu::MemIOWriter* Writer) const { - if ( ! Writer->WriteUi32BE(this->size()) ) return false; - if ( ! Writer->WriteUi32BE(this->ItemSize()) ) return false; + if ( ! Writer->WriteUi32BE((ui32_t)this->size()) ) return false; + if ( ! Writer->WriteUi32BE((ui32_t)this->ItemSize()) ) return false; if ( this->empty() ) return true; typename ContainerType::const_iterator i; @@ -277,7 +277,7 @@ namespace ASDCP const char* EncodeString(char* str_buf, ui32_t buf_len) const; inline virtual bool HasValue() const { return ! empty(); } - inline virtual ui32_t ArchiveLength() const { return sizeof(ui32_t) + size(); } + inline virtual ui32_t ArchiveLength() const { return (ui32_t)(sizeof(ui32_t) + size()); } virtual bool Unarchive(Kumu::MemIOReader* Reader); virtual bool Archive(Kumu::MemIOWriter* Writer) const; }; @@ -296,7 +296,7 @@ namespace ASDCP const char* EncodeString(char* str_buf, ui32_t buf_len) const; inline virtual bool HasValue() const { return ! empty(); } - inline virtual ui32_t ArchiveLength() const { return sizeof(ui32_t) + size(); } + inline virtual ui32_t ArchiveLength() const { return (ui32_t)(sizeof(ui32_t) + size()); } virtual bool Unarchive(Kumu::MemIOReader* Reader); virtual bool Archive(Kumu::MemIOWriter* Writer) const; }; @@ -359,7 +359,7 @@ namespace ASDCP ui32_t First; ui32_t Second; - LineMapPair() {} + LineMapPair() : First(0), Second() {} ~LineMapPair() {} LineMapPair(const ui32_t& first, const ui32_t& second) : IArchive() { diff --git a/src/Makefile.am b/src/Makefile.am index c7d182b..ccf6bee 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -2,7 +2,7 @@ # # $Id$ # -# Copyright (c) 2007-2016 John Hurst. All rights reserved. +# Copyright (c) 2007-2018 John Hurst. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions @@ -144,6 +144,7 @@ libas02_la_SOURCES = \ h__02_Writer.cpp \ AS_02_JP2K.cpp \ AS_02_PCM.cpp \ + AS_02_ISXD.cpp \ ST2052_TextParser.cpp \ AS_02_TimedText.cpp diff --git a/src/Metadata.cpp b/src/Metadata.cpp index 4a0db5a..a7fdd2e 100755 --- a/src/Metadata.cpp +++ b/src/Metadata.cpp @@ -64,6 +64,8 @@ static InterchangeObject* MPEG2VideoDescriptor_Factory(const Dictionary*& Dict) static InterchangeObject* DMSegment_Factory(const Dictionary*& Dict) { return new DMSegment(Dict); } static InterchangeObject* CryptographicFramework_Factory(const Dictionary*& Dict) { return new CryptographicFramework(Dict); } static InterchangeObject* CryptographicContext_Factory(const Dictionary*& Dict) { return new CryptographicContext(Dict); } +static InterchangeObject* DescriptiveFramework_Factory(const Dictionary*& Dict) { return new DescriptiveFramework(Dict); } +static InterchangeObject* DescriptiveObject_Factory(const Dictionary*& Dict) { return new DescriptiveObject(Dict); } static InterchangeObject* GenericDataEssenceDescriptor_Factory(const Dictionary*& Dict) { return new GenericDataEssenceDescriptor(Dict); } static InterchangeObject* TimedTextDescriptor_Factory(const Dictionary*& Dict) { return new TimedTextDescriptor(Dict); } static InterchangeObject* TimedTextResourceSubDescriptor_Factory(const Dictionary*& Dict) { return new TimedTextResourceSubDescriptor(Dict); } @@ -79,6 +81,10 @@ static InterchangeObject* PrivateDCDataDescriptor_Factory(const Dictionary*& Dic static InterchangeObject* DolbyAtmosSubDescriptor_Factory(const Dictionary*& Dict) { return new DolbyAtmosSubDescriptor(Dict); } static InterchangeObject* ACESPictureSubDescriptor_Factory(const Dictionary*& Dict) { return new ACESPictureSubDescriptor(Dict); } static InterchangeObject* TargetFrameSubDescriptor_Factory(const Dictionary*& Dict) { return new TargetFrameSubDescriptor(Dict); } +static InterchangeObject* TextBasedDMFramework_Factory(const Dictionary*& Dict) { return new TextBasedDMFramework(Dict); } +static InterchangeObject* TextBasedObject_Factory(const Dictionary*& Dict) { return new TextBasedObject(Dict); } +static InterchangeObject* GenericStreamTextBasedSet_Factory(const Dictionary*& Dict) { return new GenericStreamTextBasedSet(Dict); } +static InterchangeObject* ISXDDataEssenceDescriptor_Factory(const Dictionary*& Dict) { return new ISXDDataEssenceDescriptor(Dict); } static InterchangeObject* PHDRMetadataTrackSubDescriptor_Factory(const Dictionary*& Dict) { return new PHDRMetadataTrackSubDescriptor(Dict); } static InterchangeObject* PIMFDynamicMetadataDescriptor_Factory(const Dictionary*& Dict) { return new PIMFDynamicMetadataDescriptor(Dict); } @@ -111,6 +117,8 @@ ASDCP::MXF::Metadata_InitTypes(const Dictionary*& Dict) SetObjectFactory(Dict->ul(MDD_DMSegment), DMSegment_Factory); SetObjectFactory(Dict->ul(MDD_CryptographicFramework), CryptographicFramework_Factory); SetObjectFactory(Dict->ul(MDD_CryptographicContext), CryptographicContext_Factory); + SetObjectFactory(Dict->ul(MDD_DescriptiveFramework), DescriptiveFramework_Factory); + SetObjectFactory(Dict->ul(MDD_DescriptiveObject), DescriptiveObject_Factory); SetObjectFactory(Dict->ul(MDD_GenericDataEssenceDescriptor), GenericDataEssenceDescriptor_Factory); SetObjectFactory(Dict->ul(MDD_TimedTextDescriptor), TimedTextDescriptor_Factory); SetObjectFactory(Dict->ul(MDD_TimedTextResourceSubDescriptor), TimedTextResourceSubDescriptor_Factory); @@ -126,6 +134,10 @@ ASDCP::MXF::Metadata_InitTypes(const Dictionary*& Dict) SetObjectFactory(Dict->ul(MDD_DolbyAtmosSubDescriptor), DolbyAtmosSubDescriptor_Factory); SetObjectFactory(Dict->ul(MDD_ACESPictureSubDescriptor), ACESPictureSubDescriptor_Factory); SetObjectFactory(Dict->ul(MDD_TargetFrameSubDescriptor), TargetFrameSubDescriptor_Factory); + SetObjectFactory(Dict->ul(MDD_TextBasedDMFramework), TextBasedDMFramework_Factory); + SetObjectFactory(Dict->ul(MDD_TextBasedObject), TextBasedObject_Factory); + SetObjectFactory(Dict->ul(MDD_GenericStreamTextBasedSet), GenericStreamTextBasedSet_Factory); + SetObjectFactory(Dict->ul(MDD_ISXDDataEssenceDescriptor), ISXDDataEssenceDescriptor_Factory); SetObjectFactory(Dict->ul(MDD_PHDRMetadataTrackSubDescriptor), PHDRMetadataTrackSubDescriptor_Factory); SetObjectFactory(Dict->ul(MDD_PIMFDynamicMetadataDescriptor), PIMFDynamicMetadataDescriptor_Factory); } @@ -2778,6 +2790,166 @@ CryptographicContext::WriteToBuffer(ASDCP::FrameBuffer& Buffer) return InterchangeObject::WriteToBuffer(Buffer); } +//------------------------------------------------------------------------------------------ +// DescriptiveFramework + +// + +DescriptiveFramework::DescriptiveFramework(const Dictionary*& d) : InterchangeObject(d), m_Dict(d) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_DescriptiveFramework); +} + +DescriptiveFramework::DescriptiveFramework(const DescriptiveFramework& rhs) : InterchangeObject(rhs.m_Dict), m_Dict(rhs.m_Dict) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_DescriptiveFramework); + Copy(rhs); +} + + +// +ASDCP::Result_t +DescriptiveFramework::InitFromTLVSet(TLVReader& TLVSet) +{ + assert(m_Dict); + Result_t result = InterchangeObject::InitFromTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) { + result = TLVSet.ReadObject(OBJ_READ_ARGS_OPT(DescriptiveFramework, LinkedDescriptiveFrameworkPlugInId)); + LinkedDescriptiveFrameworkPlugInId.set_has_value( result == RESULT_OK ); + } + return result; +} + +// +ASDCP::Result_t +DescriptiveFramework::WriteToTLVSet(TLVWriter& TLVSet) +{ + assert(m_Dict); + Result_t result = InterchangeObject::WriteToTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) && ! LinkedDescriptiveFrameworkPlugInId.empty() ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS_OPT(DescriptiveFramework, LinkedDescriptiveFrameworkPlugInId)); + return result; +} + +// +void +DescriptiveFramework::Copy(const DescriptiveFramework& rhs) +{ + InterchangeObject::Copy(rhs); + LinkedDescriptiveFrameworkPlugInId = rhs.LinkedDescriptiveFrameworkPlugInId; +} + +// +void +DescriptiveFramework::Dump(FILE* stream) +{ + char identbuf[IdentBufferLen]; + *identbuf = 0; + + if ( stream == 0 ) + stream = stderr; + + InterchangeObject::Dump(stream); + if ( ! LinkedDescriptiveFrameworkPlugInId.empty() ) { + fprintf(stream, " %22s = %s\n", "LinkedDescriptiveFrameworkPlugInId", LinkedDescriptiveFrameworkPlugInId.get().EncodeString(identbuf, IdentBufferLen)); + } +} + +// +ASDCP::Result_t +DescriptiveFramework::InitFromBuffer(const byte_t* p, ui32_t l) +{ + return InterchangeObject::InitFromBuffer(p, l); +} + +// +ASDCP::Result_t +DescriptiveFramework::WriteToBuffer(ASDCP::FrameBuffer& Buffer) +{ + return InterchangeObject::WriteToBuffer(Buffer); +} + +//------------------------------------------------------------------------------------------ +// DescriptiveObject + +// + +DescriptiveObject::DescriptiveObject(const Dictionary*& d) : InterchangeObject(d), m_Dict(d) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_DescriptiveObject); +} + +DescriptiveObject::DescriptiveObject(const DescriptiveObject& rhs) : InterchangeObject(rhs.m_Dict), m_Dict(rhs.m_Dict) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_DescriptiveObject); + Copy(rhs); +} + + +// +ASDCP::Result_t +DescriptiveObject::InitFromTLVSet(TLVReader& TLVSet) +{ + assert(m_Dict); + Result_t result = InterchangeObject::InitFromTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) { + result = TLVSet.ReadObject(OBJ_READ_ARGS_OPT(DescriptiveObject, LinkedDescriptiveObjectPlugInId)); + LinkedDescriptiveObjectPlugInId.set_has_value( result == RESULT_OK ); + } + return result; +} + +// +ASDCP::Result_t +DescriptiveObject::WriteToTLVSet(TLVWriter& TLVSet) +{ + assert(m_Dict); + Result_t result = InterchangeObject::WriteToTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) && ! LinkedDescriptiveObjectPlugInId.empty() ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS_OPT(DescriptiveObject, LinkedDescriptiveObjectPlugInId)); + return result; +} + +// +void +DescriptiveObject::Copy(const DescriptiveObject& rhs) +{ + InterchangeObject::Copy(rhs); + LinkedDescriptiveObjectPlugInId = rhs.LinkedDescriptiveObjectPlugInId; +} + +// +void +DescriptiveObject::Dump(FILE* stream) +{ + char identbuf[IdentBufferLen]; + *identbuf = 0; + + if ( stream == 0 ) + stream = stderr; + + InterchangeObject::Dump(stream); + if ( ! LinkedDescriptiveObjectPlugInId.empty() ) { + fprintf(stream, " %22s = %s\n", "LinkedDescriptiveObjectPlugInId", LinkedDescriptiveObjectPlugInId.get().EncodeString(identbuf, IdentBufferLen)); + } +} + +// +ASDCP::Result_t +DescriptiveObject::InitFromBuffer(const byte_t* p, ui32_t l) +{ + return InterchangeObject::InitFromBuffer(p, l); +} + +// +ASDCP::Result_t +DescriptiveObject::WriteToBuffer(ASDCP::FrameBuffer& Buffer) +{ + return InterchangeObject::WriteToBuffer(Buffer); +} + //------------------------------------------------------------------------------------------ // GenericDataEssenceDescriptor @@ -4128,6 +4300,328 @@ TargetFrameSubDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer) return InterchangeObject::WriteToBuffer(Buffer); } +//------------------------------------------------------------------------------------------ +// TextBasedDMFramework + +// + +TextBasedDMFramework::TextBasedDMFramework(const Dictionary*& d) : DescriptiveFramework(d), m_Dict(d) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_TextBasedDMFramework); +} + +TextBasedDMFramework::TextBasedDMFramework(const TextBasedDMFramework& rhs) : DescriptiveFramework(rhs.m_Dict), m_Dict(rhs.m_Dict) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_TextBasedDMFramework); + Copy(rhs); +} + + +// +ASDCP::Result_t +TextBasedDMFramework::InitFromTLVSet(TLVReader& TLVSet) +{ + assert(m_Dict); + Result_t result = DescriptiveFramework::InitFromTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) { + result = TLVSet.ReadObject(OBJ_READ_ARGS_OPT(TextBasedDMFramework, ObjectRef)); + ObjectRef.set_has_value( result == RESULT_OK ); + } + return result; +} + +// +ASDCP::Result_t +TextBasedDMFramework::WriteToTLVSet(TLVWriter& TLVSet) +{ + assert(m_Dict); + Result_t result = DescriptiveFramework::WriteToTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) && ! ObjectRef.empty() ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS_OPT(TextBasedDMFramework, ObjectRef)); + return result; +} + +// +void +TextBasedDMFramework::Copy(const TextBasedDMFramework& rhs) +{ + DescriptiveFramework::Copy(rhs); + ObjectRef = rhs.ObjectRef; +} + +// +void +TextBasedDMFramework::Dump(FILE* stream) +{ + char identbuf[IdentBufferLen]; + *identbuf = 0; + + if ( stream == 0 ) + stream = stderr; + + DescriptiveFramework::Dump(stream); + if ( ! ObjectRef.empty() ) { + fprintf(stream, " %22s = %s\n", "ObjectRef", ObjectRef.get().EncodeString(identbuf, IdentBufferLen)); + } +} + +// +ASDCP::Result_t +TextBasedDMFramework::InitFromBuffer(const byte_t* p, ui32_t l) +{ + return InterchangeObject::InitFromBuffer(p, l); +} + +// +ASDCP::Result_t +TextBasedDMFramework::WriteToBuffer(ASDCP::FrameBuffer& Buffer) +{ + return InterchangeObject::WriteToBuffer(Buffer); +} + +//------------------------------------------------------------------------------------------ +// TextBasedObject + +// + +TextBasedObject::TextBasedObject(const Dictionary*& d) : DescriptiveObject(d), m_Dict(d) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_TextBasedObject); +} + +TextBasedObject::TextBasedObject(const TextBasedObject& rhs) : DescriptiveObject(rhs.m_Dict), m_Dict(rhs.m_Dict) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_TextBasedObject); + Copy(rhs); +} + + +// +ASDCP::Result_t +TextBasedObject::InitFromTLVSet(TLVReader& TLVSet) +{ + assert(m_Dict); + Result_t result = DescriptiveObject::InitFromTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(TextBasedObject, PayloadSchemeID)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(TextBasedObject, TextMIMEMediaType)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(TextBasedObject, RFC5646TextLanguageCode)); + if ( ASDCP_SUCCESS(result) ) { + result = TLVSet.ReadObject(OBJ_READ_ARGS_OPT(TextBasedObject, TextDataDescription)); + TextDataDescription.set_has_value( result == RESULT_OK ); + } + return result; +} + +// +ASDCP::Result_t +TextBasedObject::WriteToTLVSet(TLVWriter& TLVSet) +{ + assert(m_Dict); + Result_t result = DescriptiveObject::WriteToTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(TextBasedObject, PayloadSchemeID)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(TextBasedObject, TextMIMEMediaType)); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(TextBasedObject, RFC5646TextLanguageCode)); + if ( ASDCP_SUCCESS(result) && ! TextDataDescription.empty() ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS_OPT(TextBasedObject, TextDataDescription)); + return result; +} + +// +void +TextBasedObject::Copy(const TextBasedObject& rhs) +{ + DescriptiveObject::Copy(rhs); + PayloadSchemeID = rhs.PayloadSchemeID; + TextMIMEMediaType = rhs.TextMIMEMediaType; + RFC5646TextLanguageCode = rhs.RFC5646TextLanguageCode; + TextDataDescription = rhs.TextDataDescription; +} + +// +void +TextBasedObject::Dump(FILE* stream) +{ + char identbuf[IdentBufferLen]; + *identbuf = 0; + + if ( stream == 0 ) + stream = stderr; + + DescriptiveObject::Dump(stream); + fprintf(stream, " %22s = %s\n", "PayloadSchemeID", PayloadSchemeID.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " %22s = %s\n", "TextMIMEMediaType", TextMIMEMediaType.EncodeString(identbuf, IdentBufferLen)); + fprintf(stream, " %22s = %s\n", "RFC5646TextLanguageCode", RFC5646TextLanguageCode.EncodeString(identbuf, IdentBufferLen)); + if ( ! TextDataDescription.empty() ) { + fprintf(stream, " %22s = %s\n", "TextDataDescription", TextDataDescription.get().EncodeString(identbuf, IdentBufferLen)); + } +} + +// +ASDCP::Result_t +TextBasedObject::InitFromBuffer(const byte_t* p, ui32_t l) +{ + return InterchangeObject::InitFromBuffer(p, l); +} + +// +ASDCP::Result_t +TextBasedObject::WriteToBuffer(ASDCP::FrameBuffer& Buffer) +{ + return InterchangeObject::WriteToBuffer(Buffer); +} + +//------------------------------------------------------------------------------------------ +// GenericStreamTextBasedSet + +// + +GenericStreamTextBasedSet::GenericStreamTextBasedSet(const Dictionary*& d) : TextBasedObject(d), m_Dict(d), GenericStreamSID(0) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_GenericStreamTextBasedSet); +} + +GenericStreamTextBasedSet::GenericStreamTextBasedSet(const GenericStreamTextBasedSet& rhs) : TextBasedObject(rhs.m_Dict), m_Dict(rhs.m_Dict) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_GenericStreamTextBasedSet); + Copy(rhs); +} + + +// +ASDCP::Result_t +GenericStreamTextBasedSet::InitFromTLVSet(TLVReader& TLVSet) +{ + assert(m_Dict); + Result_t result = TextBasedObject::InitFromTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(GenericStreamTextBasedSet, GenericStreamSID)); + return result; +} + +// +ASDCP::Result_t +GenericStreamTextBasedSet::WriteToTLVSet(TLVWriter& TLVSet) +{ + assert(m_Dict); + Result_t result = TextBasedObject::WriteToTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(GenericStreamTextBasedSet, GenericStreamSID)); + return result; +} + +// +void +GenericStreamTextBasedSet::Copy(const GenericStreamTextBasedSet& rhs) +{ + TextBasedObject::Copy(rhs); + GenericStreamSID = rhs.GenericStreamSID; +} + +// +void +GenericStreamTextBasedSet::Dump(FILE* stream) +{ + char identbuf[IdentBufferLen]; + *identbuf = 0; + + if ( stream == 0 ) + stream = stderr; + + TextBasedObject::Dump(stream); + fprintf(stream, " %22s = %d\n", "GenericStreamSID", GenericStreamSID); +} + +// +ASDCP::Result_t +GenericStreamTextBasedSet::InitFromBuffer(const byte_t* p, ui32_t l) +{ + return InterchangeObject::InitFromBuffer(p, l); +} + +// +ASDCP::Result_t +GenericStreamTextBasedSet::WriteToBuffer(ASDCP::FrameBuffer& Buffer) +{ + return InterchangeObject::WriteToBuffer(Buffer); +} + +//------------------------------------------------------------------------------------------ +// ISXDDataEssenceDescriptor + +// + +ISXDDataEssenceDescriptor::ISXDDataEssenceDescriptor(const Dictionary*& d) : GenericDataEssenceDescriptor(d), m_Dict(d) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_ISXDDataEssenceDescriptor); +} + +ISXDDataEssenceDescriptor::ISXDDataEssenceDescriptor(const ISXDDataEssenceDescriptor& rhs) : GenericDataEssenceDescriptor(rhs.m_Dict), m_Dict(rhs.m_Dict) +{ + assert(m_Dict); + m_UL = m_Dict->ul(MDD_ISXDDataEssenceDescriptor); + Copy(rhs); +} + + +// +ASDCP::Result_t +ISXDDataEssenceDescriptor::InitFromTLVSet(TLVReader& TLVSet) +{ + assert(m_Dict); + Result_t result = GenericDataEssenceDescriptor::InitFromTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(ISXDDataEssenceDescriptor, NamespaceURI)); + return result; +} + +// +ASDCP::Result_t +ISXDDataEssenceDescriptor::WriteToTLVSet(TLVWriter& TLVSet) +{ + assert(m_Dict); + Result_t result = GenericDataEssenceDescriptor::WriteToTLVSet(TLVSet); + if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(ISXDDataEssenceDescriptor, NamespaceURI)); + return result; +} + +// +void +ISXDDataEssenceDescriptor::Copy(const ISXDDataEssenceDescriptor& rhs) +{ + GenericDataEssenceDescriptor::Copy(rhs); + NamespaceURI = rhs.NamespaceURI; +} + +// +void +ISXDDataEssenceDescriptor::Dump(FILE* stream) +{ + char identbuf[IdentBufferLen]; + *identbuf = 0; + + if ( stream == 0 ) + stream = stderr; + + GenericDataEssenceDescriptor::Dump(stream); + fprintf(stream, " %22s = %s\n", "NamespaceURI", NamespaceURI.EncodeString(identbuf, IdentBufferLen)); +} + +// +ASDCP::Result_t +ISXDDataEssenceDescriptor::InitFromBuffer(const byte_t* p, ui32_t l) +{ + return InterchangeObject::InitFromBuffer(p, l); +} + +// +ASDCP::Result_t +ISXDDataEssenceDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer) +{ + return InterchangeObject::WriteToBuffer(Buffer); +} + //------------------------------------------------------------------------------------------ // PHDRMetadataTrackSubDescriptor diff --git a/src/Metadata.h b/src/Metadata.h index b6cfb62..cc26c70 100755 --- a/src/Metadata.h +++ b/src/Metadata.h @@ -727,6 +727,52 @@ namespace ASDCP virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&); }; + // + class DescriptiveFramework : public InterchangeObject + { + DescriptiveFramework(); + + public: + const Dictionary*& m_Dict; + optional_property LinkedDescriptiveFrameworkPlugInId; + + DescriptiveFramework(const Dictionary*& d); + DescriptiveFramework(const DescriptiveFramework& rhs); + virtual ~DescriptiveFramework() {} + + const DescriptiveFramework& operator=(const DescriptiveFramework& rhs) { Copy(rhs); return *this; } + virtual void Copy(const DescriptiveFramework& rhs); + virtual const char* HasName() { return "DescriptiveFramework"; } + virtual Result_t InitFromTLVSet(TLVReader& TLVSet); + virtual Result_t WriteToTLVSet(TLVWriter& TLVSet); + virtual void Dump(FILE* = 0); + virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l); + virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&); + }; + + // + class DescriptiveObject : public InterchangeObject + { + DescriptiveObject(); + + public: + const Dictionary*& m_Dict; + optional_property LinkedDescriptiveObjectPlugInId; + + DescriptiveObject(const Dictionary*& d); + DescriptiveObject(const DescriptiveObject& rhs); + virtual ~DescriptiveObject() {} + + const DescriptiveObject& operator=(const DescriptiveObject& rhs) { Copy(rhs); return *this; } + virtual void Copy(const DescriptiveObject& rhs); + virtual const char* HasName() { return "DescriptiveObject"; } + virtual Result_t InitFromTLVSet(TLVReader& TLVSet); + virtual Result_t WriteToTLVSet(TLVWriter& TLVSet); + virtual void Dump(FILE* = 0); + virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l); + virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&); + }; + // class GenericDataEssenceDescriptor : public FileDescriptor { @@ -1102,6 +1148,101 @@ namespace ASDCP virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&); }; + // + class TextBasedDMFramework : public DescriptiveFramework + { + TextBasedDMFramework(); + + public: + const Dictionary*& m_Dict; + optional_property ObjectRef; + + TextBasedDMFramework(const Dictionary*& d); + TextBasedDMFramework(const TextBasedDMFramework& rhs); + virtual ~TextBasedDMFramework() {} + + const TextBasedDMFramework& operator=(const TextBasedDMFramework& rhs) { Copy(rhs); return *this; } + virtual void Copy(const TextBasedDMFramework& rhs); + virtual const char* HasName() { return "TextBasedDMFramework"; } + virtual Result_t InitFromTLVSet(TLVReader& TLVSet); + virtual Result_t WriteToTLVSet(TLVWriter& TLVSet); + virtual void Dump(FILE* = 0); + virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l); + virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&); + }; + + // + class TextBasedObject : public DescriptiveObject + { + TextBasedObject(); + + public: + const Dictionary*& m_Dict; + UL PayloadSchemeID; + UTF16String TextMIMEMediaType; + UTF16String RFC5646TextLanguageCode; + optional_property TextDataDescription; + + TextBasedObject(const Dictionary*& d); + TextBasedObject(const TextBasedObject& rhs); + virtual ~TextBasedObject() {} + + const TextBasedObject& operator=(const TextBasedObject& rhs) { Copy(rhs); return *this; } + virtual void Copy(const TextBasedObject& rhs); + virtual const char* HasName() { return "TextBasedObject"; } + virtual Result_t InitFromTLVSet(TLVReader& TLVSet); + virtual Result_t WriteToTLVSet(TLVWriter& TLVSet); + virtual void Dump(FILE* = 0); + virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l); + virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&); + }; + + // + class GenericStreamTextBasedSet : public TextBasedObject + { + GenericStreamTextBasedSet(); + + public: + const Dictionary*& m_Dict; + ui32_t GenericStreamSID; + + GenericStreamTextBasedSet(const Dictionary*& d); + GenericStreamTextBasedSet(const GenericStreamTextBasedSet& rhs); + virtual ~GenericStreamTextBasedSet() {} + + const GenericStreamTextBasedSet& operator=(const GenericStreamTextBasedSet& rhs) { Copy(rhs); return *this; } + virtual void Copy(const GenericStreamTextBasedSet& rhs); + virtual const char* HasName() { return "GenericStreamTextBasedSet"; } + virtual Result_t InitFromTLVSet(TLVReader& TLVSet); + virtual Result_t WriteToTLVSet(TLVWriter& TLVSet); + virtual void Dump(FILE* = 0); + virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l); + virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&); + }; + + // + class ISXDDataEssenceDescriptor : public GenericDataEssenceDescriptor + { + ISXDDataEssenceDescriptor(); + + public: + const Dictionary*& m_Dict; + ISO8String NamespaceURI; + + ISXDDataEssenceDescriptor(const Dictionary*& d); + ISXDDataEssenceDescriptor(const ISXDDataEssenceDescriptor& rhs); + virtual ~ISXDDataEssenceDescriptor() {} + + const ISXDDataEssenceDescriptor& operator=(const ISXDDataEssenceDescriptor& rhs) { Copy(rhs); return *this; } + virtual void Copy(const ISXDDataEssenceDescriptor& rhs); + virtual const char* HasName() { return "ISXDDataEssenceDescriptor"; } + virtual Result_t InitFromTLVSet(TLVReader& TLVSet); + virtual Result_t WriteToTLVSet(TLVWriter& TLVSet); + virtual void Dump(FILE* = 0); + virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l); + virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&); + }; + // class PHDRMetadataTrackSubDescriptor : public InterchangeObject { diff --git a/src/as-02-info.cpp b/src/as-02-info.cpp index 19109e8..df108f6 100644 --- a/src/as-02-info.cpp +++ b/src/as-02-info.cpp @@ -347,7 +347,7 @@ class MyPictureDescriptor : public JP2K::PictureDescriptor fprintf(stream, " Precincts: %u\n", precinct_set_size); fprintf(stream, "precinct dimensions:\n"); - for ( int i = 0; i < precinct_set_size && i < JP2K::MaxPrecincts; i++ ) + for ( unsigned int i = 0; i < precinct_set_size && i < JP2K::MaxPrecincts; i++ ) fprintf(stream, " %d: %d x %d\n", i + 1, s_exp_lookup[coding_style_default.SPcod.PrecinctSize[i]&0x0f], s_exp_lookup[(coding_style_default.SPcod.PrecinctSize[i]>>4)&0x0f] @@ -539,7 +539,7 @@ public: ( m_WriterInfo.LabelSetType == LS_MXF_SMPTE ? "SMPTE 2067-5" : "Unknown" ), type_string, (m_Desc.ContainerDuration != 0 ? m_Desc.ContainerDuration : m_Reader.AS02IndexReader().GetDuration()), - (m_Desc.ContainerDuration == 1 ? "":"s")); + (m_Desc.ContainerDuration == (ui64_t)1 ? "":"s")); if ( Options.showheader_flag ) { @@ -681,7 +681,7 @@ public: total_frame_bytes += this_frame_size; if ( this_frame_size > largest_frame ) - largest_frame = this_frame_size; + largest_frame = (ui32_t)this_frame_size; } last_stream_offset = entry.StreamOffset; @@ -694,7 +694,7 @@ public: static const double mega_const = 1.0 / ( 1000000 / 8.0 ); // we did not accumulate the last, so duration -= 1 - double avg_bytes_frame = total_frame_bytes / ( duration - 1 ); + double avg_bytes_frame = (double)(total_frame_bytes / ( duration - 1 )); m_MaxBitrate = largest_frame * mega_const * m_Desc.EditRate.Quotient(); m_AvgBitrate = avg_bytes_frame * mega_const * m_Desc.EditRate.Quotient(); @@ -811,7 +811,6 @@ int main(int argc, const char** argv) { Result_t result = RESULT_OK; - char str_buf[64]; CommandOptions Options(argc, argv); if ( Options.version_flag ) diff --git a/src/as-02-unwrap.cpp b/src/as-02-unwrap.cpp index 1104be0..5a0ae68 100755 --- a/src/as-02-unwrap.cpp +++ b/src/as-02-unwrap.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2011-2016, Robert Scheler, Heiko Sparenberg Fraunhofer IIS, +Copyright (c) 2011-2018, Robert Scheler, Heiko Sparenberg Fraunhofer IIS, John Hurst All rights reserved. @@ -69,7 +69,7 @@ banner(FILE* stream = stdout) { fprintf(stream, "\n\ %s (asdcplib %s)\n\n\ -Copyright (c) 2011-2015, Robert Scheler, Heiko Sparenberg Fraunhofer IIS, John Hurst\n\n\ +Copyright (c) 2011-2018, Robert Scheler, Heiko Sparenberg Fraunhofer IIS, John Hurst\n\n\ asdcplib may be copied only under the terms of the license found at\n\ the top of every file in the asdcplib distribution kit.\n\n\ Specify the -h (help) option for further information about %s\n\n", @@ -98,6 +98,7 @@ Options:\n\ Defaults to 4,194,304 (4MB)\n\ -d - Number of frames to process, default all\n\ -f - Starting frame number, default 0\n\ + -g - Extract the Generic Stream Partition payload\n\ -h | -help - Show help\n\ -k - Use key for ciphertext operations\n\ -m - verify HMAC values when reading\n\ @@ -142,9 +143,9 @@ public: const char* file_prefix; // filename pre for files written by the extract mode byte_t key_value[KeyLen]; // value of given encryption key (when key_flag is true) byte_t key_id_value[UUIDlen];// value of given key ID (when key_id_flag is true) - PCM::ChannelFormat_t channel_fmt; // audio channel arrangement const char* input_filename; const char* extension; + i32_t g_stream_sid; // Stream ID of a generic stream partition payload to be extracted std::string prefix_buffer; // @@ -154,7 +155,7 @@ public: version_flag(false), help_flag(false), number_width(6), start_frame(0), duration(0xffffffff), duration_flag(false), j2c_pedantic(true), picture_rate(24), fb_size(FRAME_BUFFER_SIZE), file_prefix(0), - input_filename(0) + input_filename(0), extension(0), g_stream_sid(0) { memset(key_value, 0, KeyLen); memset(key_id_value, 0, UUIDlen); @@ -202,6 +203,11 @@ public: start_frame = Kumu::xabs(strtol(argv[i], 0, 10)); break; + case 'g': + TEST_EXTRA_ARG(i, 'g'); + g_stream_sid = strtol(argv[i], 0, 10); + break; + case 'h': help_flag = true; break; case 'm': read_hmac = true; break; @@ -308,7 +314,7 @@ read_JP2K_file(CommandOptions& Options) if ( KM_SUCCESS(result) ) { assert(rgba_descriptor); - frame_count = rgba_descriptor->ContainerDuration; + frame_count = (ui32_t)rgba_descriptor->ContainerDuration; if ( Options.verbose_flag ) { @@ -323,7 +329,7 @@ read_JP2K_file(CommandOptions& Options) if ( KM_SUCCESS(result) ) { assert(cdci_descriptor); - frame_count = cdci_descriptor->ContainerDuration; + frame_count = (ui32_t)cdci_descriptor->ContainerDuration; if ( Options.verbose_flag ) { @@ -474,7 +480,7 @@ read_PCM_file(CommandOptions& Options) } else { - last_frame = wave_descriptor->ContainerDuration; + last_frame = (ui32_t)wave_descriptor->ContainerDuration; } if ( last_frame == 0 ) @@ -486,7 +492,7 @@ read_PCM_file(CommandOptions& Options) ASDCP::MXF::SourceClip *sourceClip = dynamic_cast(tmp_obj); if ( ! sourceClip->Duration.empty() ) { - last_frame = sourceClip->Duration; + last_frame = (ui32_t)sourceClip->Duration; } } } @@ -666,11 +672,122 @@ read_timed_text_file(CommandOptions& Options) return result; } +// +Result_t +read_isxd_file(CommandOptions& Options) +{ + AESDecContext* Context = 0; + HMACContext* HMAC = 0; + AS_02::ISXD::MXFReader Reader; + ASDCP::FrameBuffer FrameBuffer; + ui32_t frame_count = 0; + + Result_t result = Reader.OpenRead(Options.input_filename); + + if ( ASDCP_SUCCESS(result) ) + { + result = FrameBuffer.Capacity(Options.fb_size); + } + + if ( ASDCP_SUCCESS(result) ) + { + std::list object_list; + Reader.OP1aHeader().GetMDObjectsByType(DefaultSMPTEDict().ul(MDD_GenericStreamTextBasedSet), object_list); + + std::list::iterator i; + for ( i = object_list.begin(); i != object_list.end(); ++i ) + { + MXF::GenericStreamTextBasedSet *text_object = dynamic_cast(*i); + assert(text_object); + text_object->Dump(stderr); + } + } + + if ( ASDCP_SUCCESS(result) && Options.key_flag ) + { + Context = new AESDecContext; + result = Context->InitKey(Options.key_value); + + if ( ASDCP_SUCCESS(result) && Options.read_hmac ) + { + WriterInfo Info; + Reader.FillWriterInfo(Info); + + if ( Info.UsesHMAC ) + { + HMAC = new HMACContext; + result = HMAC->InitKey(Options.key_value, Info.LabelSetType); + } + else + { + fputs("File does not contain HMAC values, ignoring -m option.\n", stderr); + } + } + } + + ui32_t last_frame = Options.start_frame + ( Options.duration ? Options.duration : frame_count); + if ( last_frame > frame_count ) + last_frame = frame_count; + + char name_format[64]; + snprintf(name_format, 64, "%%s%%0%du.%s", Options.number_width, Options.extension); + + for ( ui32_t i = Options.start_frame; ASDCP_SUCCESS(result) && i < last_frame; i++ ) + { + result = Reader.ReadFrame(i, FrameBuffer, Context, HMAC); + + if ( ASDCP_SUCCESS(result) ) + { + if ( ! Options.no_write_flag ) + { + Kumu::FileWriter OutFile; + char filename[256]; + ui32_t write_count; + snprintf(filename, 256, name_format, Options.file_prefix, i); + result = OutFile.OpenWrite(filename); + + if ( ASDCP_SUCCESS(result) ) + result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count); + } + } + } + + return result; +} + +Result_t +extract_generic_stream_partition_payload(const std::string& in_filename, const ui32_t sid, const std::string& out_filename) +{ + ASDCP::FrameBuffer payload; + AS_02::ISXD::MXFReader reader; + + Result_t result = reader.OpenRead(in_filename); + + if ( KM_SUCCESS(result) ) + { + result = reader.ReadGenericStreamPartitionPayload(sid, payload); + } + + if ( KM_SUCCESS(result) ) + { + Kumu::FileWriter writer; + ui32_t write_count = 0; + result = writer.OpenWrite(out_filename); + + if ( KM_SUCCESS(result) ) + { + result = writer.Write(payload.RoData(), payload.Size(), &write_count); + } + } + + return result; +} + + // int main(int argc, const char** argv) { - char str_buf[64]; CommandOptions Options(argc, argv); if ( Options.version_flag ) @@ -708,6 +825,19 @@ main(int argc, const char** argv) result = read_timed_text_file(Options); break; + case ESS_AS02_ISXD: + if ( Options.g_stream_sid == 0 ) + { + result = read_isxd_file(Options); + } + else + { + result = extract_generic_stream_partition_payload(Options.input_filename, + Options.g_stream_sid, + Options.file_prefix); + } + break; + default: fprintf(stderr, "%s: Unknown file type (%d), not AS-02 essence.\n", Options.input_filename, EssenceType); return 5; diff --git a/src/as-02-wrap.cpp b/src/as-02-wrap.cpp index 174365b..32a6aec 100755 --- a/src/as-02-wrap.cpp +++ b/src/as-02-wrap.cpp @@ -38,6 +38,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +#include #include #include #include @@ -142,7 +143,10 @@ Options:\n\ -F (0|1) - Set field dominance for interlaced image (default: 0)\n\ -g \n\ - Create MCA labels having the given RFC 5646 language code\n\ - (requires option \"-m\")\n\ + (requires option \"-m\") -- Also used with -G to set the\n\ + value of the TextMIMEMediaType property\n\ + -G - Filename of XML resource to be carried per RP 2057 Generic\n\ + Stream. May be issued multiple times.\n\ -i - Indicates input essence is interlaced fields (forces -Y)\n\ -j - Write key ID instead of creating a random value\n\ -k - Use key for ciphertext operations\n\ @@ -166,6 +170,7 @@ Options:\n\ -t - Set RGB component minimum code value (default: 0)\n\ -T - Set RGB component maximum code value (default: 1023)\n\ -u - Print UL catalog to stdout\n\ + -u
        - ISXD (RDD47) essence coding label\n\ -v - Verbose, prints informative messages to stderr\n\ -W - Read input file only, do not write source file\n\ -x - Horizontal subsampling degree (default: 2)\n\ @@ -252,7 +257,7 @@ public: UL channel_assignment, picture_coding, transfer_characteristic, color_primaries, coding_equations; ASDCP::MXF::AS02_MCAConfigParser mca_config; - std::string mca_language; + std::string language; ui32_t rgba_MaxRef; ui32_t rgba_MinRef; @@ -276,6 +281,10 @@ public: AS_02::IndexStrategy_t index_strategy; //Shim parameter index_strategy_frame/clip ui32_t partition_space; //Shim parameter partition_spacing + // ISXD + UL isxd_essence_coding; + std::list global_isxd_metadata; + // MXF::LineMapPair line_map; std::string out_file, profile_name; // @@ -529,7 +538,12 @@ public: case 'g': TEST_EXTRA_ARG(i, 'g'); - mca_language = argv[i]; + language = argv[i]; + break; + + case 'G': + TEST_EXTRA_ARG(i, 'G'); + global_isxd_metadata.push_back(argv[i]); break; case 'h': help_flag = true; break; @@ -662,6 +676,15 @@ public: case 'u': show_ul_values_flag = true; break; + case 'U': + TEST_EXTRA_ARG(i, 'U'); + if ( ! isxd_essence_coding.DecodeHex(argv[i]) ) + { + fprintf(stderr, "Error decoding UL value: %s\n", argv[i]); + return; + } + break; + case 'V': version_flag = true; break; case 'v': verbose_flag = true; break; case 'W': no_write_flag = true; break; @@ -716,7 +739,7 @@ public: if ( ! mca_config_str.empty() ) { - if ( mca_language.empty() ) + if ( language.empty() ) { if ( ! mca_config.DecodeString(mca_config_str) ) { @@ -725,7 +748,7 @@ public: } else { - if ( ! mca_config.DecodeString(mca_config_str, mca_language) ) + if ( ! mca_config.DecodeString(mca_config_str, language) ) { return; } @@ -1245,6 +1268,195 @@ write_timed_text_file(CommandOptions& Options) return result; } +// +bool +get_current_dms_text_descriptor(AS_02::ISXD::MXFWriter& writer, ASDCP::MXF::GenericStreamTextBasedSet *&text_object) +{ + std::list object_list; + writer.OP1aHeader().GetMDObjectsByType(DefaultSMPTEDict().ul(MDD_GenericStreamTextBasedSet), object_list); + + if ( object_list.empty() ) + { + return false; + } + + text_object = dynamic_cast(object_list.back()); + assert(text_object != 0); + return true; +} + + +// Write one or more plaintext Aux Data bytestreams to a plaintext AS-02 file +// Write one or more plaintext Aux Data bytestreams to a ciphertext AS-02 file +// +Result_t +write_isxd_file(CommandOptions& Options) +{ + AESEncContext* Context = 0; + HMACContext* HMAC = 0; + AS_02::ISXD::MXFWriter Writer; + DCData::FrameBuffer FrameBuffer(Options.fb_size); + DCData::SequenceParser Parser; + byte_t IV_buf[CBC_BLOCK_SIZE]; + Kumu::FortunaRNG RNG; + + // set up essence parser + Result_t result = Parser.OpenRead(Options.filenames.front()); + + // set up MXF writer + if ( ASDCP_SUCCESS(result) ) + { + + if ( Options.verbose_flag ) + { + fprintf(stderr, "Aux Data\n"); + fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size); + } + } + + if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag ) + { + WriterInfo Info = s_MyInfo; // fill in your favorite identifiers here + if ( Options.asset_id_flag ) + memcpy(Info.AssetUUID, Options.asset_id_value, UUIDlen); + else + Kumu::GenRandomUUID(Info.AssetUUID); + + Info.LabelSetType = LS_MXF_SMPTE; + + // configure encryption + if( Options.key_flag ) + { + Kumu::GenRandomUUID(Info.ContextID); + Info.EncryptedEssence = true; + + if ( Options.key_id_flag ) + { + memcpy(Info.CryptographicKeyID, Options.key_id_value, UUIDlen); + } + else + { + create_random_uuid(Info.CryptographicKeyID); + } + + Context = new AESEncContext; + result = Context->InitKey(Options.key_value); + + if ( ASDCP_SUCCESS(result) ) + result = Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE)); + + if ( ASDCP_SUCCESS(result) && Options.write_hmac ) + { + Info.UsesHMAC = true; + HMAC = new HMACContext; + result = HMAC->InitKey(Options.key_value, Info.LabelSetType); + } + } + + if ( ASDCP_SUCCESS(result) ) + { + result = Writer.OpenWrite(Options.out_file, Info, Options.isxd_essence_coding, Options.edit_rate); + } + } + + if ( ASDCP_SUCCESS(result) ) + { + ui32_t duration = 0; + result = Parser.Reset(); + + while ( ASDCP_SUCCESS(result) && duration++ < Options.duration ) + { + result = Parser.ReadFrame(FrameBuffer); + + if ( ASDCP_SUCCESS(result) ) + { + if ( Options.verbose_flag ) + FrameBuffer.Dump(stderr, Options.fb_dump_size); + + if ( Options.encrypt_header_flag ) + FrameBuffer.PlaintextOffset(0); + } + + if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag ) + { + result = Writer.WriteFrame(FrameBuffer, Context, HMAC); + + // The Writer class will forward the last block of ciphertext + // to the encryption context for use as the IV for the next + // frame. If you want to use non-sequitur IV values, un-comment + // the following line of code. + // if ( ASDCP_SUCCESS(result) && Options.key_flag ) + // Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE)); + } + } + + if ( result == RESULT_ENDOFFILE ) + { + result = RESULT_OK; + } + } + + if ( KM_SUCCESS(result) && ! Options.no_write_flag ) + { + ASDCP::FrameBuffer global_metadata; + std::list::iterator i; + + for ( i = Options.global_isxd_metadata.begin(); i != Options.global_isxd_metadata.end(); ++i ) + { + ui32_t file_size = Kumu::FileSize(*i); + result = global_metadata.Capacity(file_size); + + if ( KM_SUCCESS(result) ) + { + ui32_t read_count = 0; + Kumu::FileReader Reader; + std::string namespace_name; + + result = Reader.OpenRead(*i); + + if ( KM_SUCCESS(result) ) + { + result = Reader.Read(global_metadata.Data(), file_size, &read_count); + } + + if ( KM_SUCCESS(result) ) + { + if ( file_size != read_count) + return RESULT_READFAIL; + + global_metadata.Size(read_count); + + std::string ns_prefix, type_name; + Kumu::AttributeList doc_attr_list; + result = GetXMLDocType(global_metadata.RoData(), global_metadata.Size(), ns_prefix, type_name, + namespace_name, doc_attr_list) ? RESULT_OK : RESULT_FAIL; + } + + if ( KM_SUCCESS(result) ) + { + result = Writer.AddDmsGenericPartUtf8Text(global_metadata, Context, HMAC); + } + + if ( KM_SUCCESS(result) ) + { + ASDCP::MXF::GenericStreamTextBasedSet *text_object = 0; + get_current_dms_text_descriptor(Writer, text_object); + assert(text_object); + text_object->TextMIMEMediaType = "text/xml"; + text_object->TextDataDescription = namespace_name; + text_object->RFC5646TextLanguageCode = Options.language; + } + } + } + + if ( KM_SUCCESS(result) ) + { + result = Writer.Finalize(); + } + } + + return result; +} // int @@ -1297,6 +1509,19 @@ main(int argc, const char** argv) result = write_timed_text_file(Options); break; + case ESS_DCDATA_UNKNOWN: + if ( Options.isxd_essence_coding.HasValue() ) + { + result = write_isxd_file(Options); + } + else + { + fprintf(stderr, "%s: Unknown synchronous data file type, not AS-02-compatible essence.\n", + Options.filenames.front().c_str()); + return 5; + } + break; + default: fprintf(stderr, "%s: Unknown file type, not AS-02-compatible essence.\n", Options.filenames.front().c_str()); diff --git a/src/h__02_Reader.cpp b/src/h__02_Reader.cpp index 25a82e0..17e9b0d 100644 --- a/src/h__02_Reader.cpp +++ b/src/h__02_Reader.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2011-2016, Robert Scheler, Heiko Sparenberg Fraunhofer IIS, +Copyright (c) 2011-2018, Robert Scheler, Heiko Sparenberg Fraunhofer IIS, John Hurst All rights reserved. @@ -93,7 +93,7 @@ AS_02::MXF::AS02IndexReader::InitFromFile(const Kumu::FileReader& reader, const } else if ( i->BodySID != first_body_sid ) { - DefaultLogSink().Debug("The index assembler is ignoring BodySID %d.\n", i->BodySID); + // DefaultLogSink().Debug("The index assembler is ignoring BodySID %d.\n", i->BodySID); continue; } @@ -411,7 +411,6 @@ AS_02::h__AS02Reader::OpenMXFRead(const std::string& filename) { // UL OP1a_ul(m_Dict->ul(MDD_OP1a)); - InterchangeObject* Object; m_Info.LabelSetType = LS_MXF_SMPTE; if ( m_HeaderPart.OperationalPattern != OP1a_ul ) diff --git a/src/h__02_Writer.cpp b/src/h__02_Writer.cpp index 62f21f2..37393ca 100644 --- a/src/h__02_Writer.cpp +++ b/src/h__02_Writer.cpp @@ -57,7 +57,7 @@ AS_02::MXF::AS02IndexWriterVBR::WriteToFile(Kumu::FileWriter& Writer) { assert(m_Dict); ASDCP::FrameBuffer index_body_buffer; - ui32_t index_body_size = m_PacketList->m_List.size() * MaxIndexSegmentSize; // segment-count * max-segment-size + ui32_t index_body_size = (ui32_t)m_PacketList->m_List.size() * MaxIndexSegmentSize; // segment-count * max-segment-size Result_t result = index_body_buffer.Capacity(index_body_size); ui64_t start_position = 0; @@ -140,7 +140,7 @@ AS_02::MXF::AS02IndexWriterVBR::GetDuration() const IndexTableSegment* segment = dynamic_cast(*i); if ( segment != 0 ) { - duration += segment->IndexEntryArray.size(); + duration += (ui32_t)segment->IndexEntryArray.size(); } } @@ -193,9 +193,8 @@ AS_02::h__AS02WriterFrame::WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf,co if ( m_FramesWritten > 1 && ( ( m_FramesWritten + 1 ) % m_PartitionSpace ) == 0 ) { - m_IndexWriter.ThisPartition = m_File.Tell(); - m_IndexWriter.WriteToFile(m_File); - m_RIP.PairArray.push_back(RIP::PartitionPair(0, m_IndexWriter.ThisPartition)); + assert(m_IndexWriter.GetDuration() > 0); + FlushIndexPartition(); UL body_ul(m_Dict->ul(MDD_ClosedCompleteBodyPartition)); Partition body_part(m_Dict); @@ -374,8 +373,6 @@ AS_02::h__AS02WriterClip::FinalizeClip(ui32_t bytes_per_frame) return result; } - - // // end h__02_Writer.cpp // diff --git a/src/h__Writer.cpp b/src/h__Writer.cpp index 93388cd..4d11786 100755 --- a/src/h__Writer.cpp +++ b/src/h__Writer.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2004-2015, John Hurst +Copyright (c) 2004-2018, John Hurst All rights reserved. Redistribution and use in source and binary forms, with or without @@ -39,13 +39,13 @@ using namespace ASDCP::MXF; ui32_t ASDCP::derive_timecode_rate_from_edit_rate(const ASDCP::Rational& edit_rate) { - return floor(0.5 + edit_rate.Quotient()); + return (ui32_t)floor(0.5 + edit_rate.Quotient()); } // // add DMS CryptographicFramework entry to source package void -ASDCP::AddDMScrypt(Partition& HeaderPart, SourcePackage& Package, +ASDCP::AddDmsCrypt(Partition& HeaderPart, SourcePackage& Package, WriterInfo& Descr, const UL& WrappingUL, const Dictionary*& Dict) { assert(Dict); @@ -65,6 +65,7 @@ ASDCP::AddDMScrypt(Partition& HeaderPart, SourcePackage& Package, HeaderPart.AddChildObject(Segment); Seq->StructuralComponents.push_back(Segment->InstanceUID); Segment->EventComment = "AS-DCP KLV Encryption"; + Segment->DataDefinition = UL(Dict->ul(MDD_DescriptiveMetaDataDef)); CryptographicFramework* CFW = new CryptographicFramework(Dict); HeaderPart.AddChildObject(CFW); @@ -81,7 +82,127 @@ ASDCP::AddDMScrypt(Partition& HeaderPart, SourcePackage& Package, Context->CryptographicKeyID.Set(Descr.CryptographicKeyID); } +static std::string const rp2057_static_track_label = "SMPTE RP 2057 Generic Stream Text-Based Set"; +// +static bool +id_batch_contains(const Array& batch, const Kumu::UUID& value) +{ + Array::const_iterator i; + for ( i = batch.begin(); i != batch.end(); ++i ) + { + if ( *i == value ) + { + return true; + } + } + return false; +} + +// +Result_t +ASDCP::AddDmsTrackGenericPartUtf8Text(Kumu::FileWriter& file_writer, MXF::OP1aHeader& header_part, + SourcePackage& source_package, MXF::RIP& rip, const Dictionary*& Dict) +{ + Sequence* Sequence_obj = 0; + InterchangeObject* tmp_iobj = 0; + std::list object_list; + + // get the SourcePackage else die + header_part.GetMDObjectByType(Dict->ul(MDD_SourcePackage), &tmp_iobj); + SourcePackage *SourcePackage_obj = dynamic_cast(tmp_iobj); + if ( SourcePackage_obj == 0 ) + { + DefaultLogSink().Error("MXF Metadata contains no SourcePackage Set.\n"); + return RESULT_FORMAT; + } + + // find the first StaticTrack object, having the right label, that is ref'd by the source package + StaticTrack *StaticTrack_obj = 0; + header_part.GetMDObjectsByType(Dict->ul(MDD_StaticTrack), object_list); + std::list::iterator j; + for ( j = object_list.begin(); j != object_list.end(); ++j ) + { + StaticTrack_obj = dynamic_cast(*j); + assert(StaticTrack_obj); + if ( id_batch_contains(SourcePackage_obj->Tracks, StaticTrack_obj->InstanceUID) + && StaticTrack_obj->TrackName.get() == rp2057_static_track_label ) + { + break; + } + StaticTrack_obj = 0; + } + + if ( StaticTrack_obj ) + { + object_list.clear(); + header_part.GetMDObjectsByType(Dict->ul(MDD_Sequence), object_list); + for ( j = object_list.begin(); j != object_list.end(); ++j ) + { + Sequence_obj = dynamic_cast(*j); + assert(Sequence_obj); + if ( Sequence_obj->InstanceUID == StaticTrack_obj->Sequence ) + { + break; + } + Sequence_obj = 0; + } + } + + if ( Sequence_obj == 0 ) + { + assert(Dict); + StaticTrack* static_track = new StaticTrack(Dict); + header_part.AddChildObject(static_track); + source_package.Tracks.push_back(static_track->InstanceUID); + static_track->TrackName = "Descriptive Track"; + static_track->TrackID = 4; + + Sequence_obj = new Sequence(Dict); + header_part.AddChildObject(Sequence_obj); + static_track->Sequence = Sequence_obj->InstanceUID; + Sequence_obj->DataDefinition = UL(Dict->ul(MDD_DescriptiveMetaDataDef)); + header_part.m_Preface->DMSchemes.push_back(UL(Dict->ul(MDD_MXFTextBasedFramework))); + } + + assert(Sequence_obj); + // + DMSegment* Segment = new DMSegment(Dict); + header_part.AddChildObject(Segment); + Sequence_obj->StructuralComponents.push_back(Segment->InstanceUID); + Segment->EventComment = rp2057_static_track_label; + Segment->DataDefinition = UL(Dict->ul(MDD_DescriptiveMetaDataDef)); + + // + TextBasedDMFramework *dmf_obj = new TextBasedDMFramework(Dict); + assert(dmf_obj); + header_part.AddChildObject(dmf_obj); + Segment->DMFramework = dmf_obj->InstanceUID; + GenRandomValue(dmf_obj->ObjectRef); + + + // Create new SID in DMF + ui32_t max_sid = 0; + ASDCP::MXF::RIP::pair_iterator i; + for ( i = rip.PairArray.begin(); i != rip.PairArray.end(); ++i ) + { + if ( max_sid < i->BodySID ) + { + max_sid = i->BodySID; + } + } + + rip.PairArray.push_back(RIP::PartitionPair(max_sid + 1, file_writer.Tell())); + + // Add new GSTBS linked to DMF + GenericStreamTextBasedSet *gst_obj = new GenericStreamTextBasedSet(Dict); + header_part.AddChildObject(gst_obj); + gst_obj->InstanceUID = dmf_obj->ObjectRef; + gst_obj->GenericStreamSID = max_sid + 1; + gst_obj->PayloadSchemeID = UL(Dict->ul(MDD_MXFTextBasedFramework)); + + return RESULT_OK; +} // ASDCP::h__ASDCPWriter::h__ASDCPWriter(const Dictionary& d) : diff --git a/src/klvwalk.cpp b/src/klvwalk.cpp index 801389e..90b719b 100755 --- a/src/klvwalk.cpp +++ b/src/klvwalk.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2005-2016, John Hurst +Copyright (c) 2005-2018, John Hurst All rights reserved. Redistribution and use in source and binary forms, with or without @@ -341,7 +341,7 @@ main(int argc, const char** argv) while ( ASDCP_SUCCESS(result) ) { - fprintf(stdout, "@0x%08qx: ", pos); + fprintf(stdout, "@0x%08llx: ", pos); KP.Dump(stdout, DefaultCompositeDict(), true); pos = Reader.Tell(); result = KP.InitFromFile(Reader); -- 2.30.2