X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=src%2FAS_02_internal.h;h=4be764d8935a30907a0248ca18d6dcbfb90ca579;hb=13f1b3172139a2f07804d8f9f5d1d987ab78b41f;hp=15f4486ed92fe8af05a7335c89922847e8ed579b;hpb=aac3cfda50b82f7b763b69b9acfcc4d63c81d98b;p=asdcplib.git diff --git a/src/AS_02_internal.h b/src/AS_02_internal.h index 15f4486..4be764d 100644 --- a/src/AS_02_internal.h +++ b/src/AS_02_internal.h @@ -1,28 +1,30 @@ /* - Copyright (c) 2011-2012, Robert Scheler, Heiko Sparenberg Fraunhofer IIS, John Hurst - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - 3. The name of the author may not be used to endorse or promote products - derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +Copyright (c) 2011-2018, Robert Scheler, Heiko Sparenberg Fraunhofer IIS, +John Hurst + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /*! \file AS_02_internal.h \version $Id: AS_02_internal.h *** @@ -32,163 +34,304 @@ #ifndef _AS_02_INTERNAL_H_ #define _AS_02_INTERNAL_H_ -#include -#include -#include -#include "Metadata.h" +#include "KM_log.h" #include "AS_DCP_internal.h" #include "AS_02.h" using Kumu::DefaultLogSink; -using namespace ASDCP; -using namespace ASDCP::MXF; +#ifdef DEFAULT_02_MD_DECL +AS_02::MXF::AS02IndexReader *g_AS02IndexReader; +#else +extern AS_02::MXF::AS02IndexReader *g_AS02IndexReader; +#endif + namespace AS_02 { - static void CalculateIndexPartitionSize(ui32_t& size,ui32_t numberOfIndexEntries) + + void default_md_object_init(); + + + // + class h__AS02Reader : public ASDCP::MXF::TrackFileReader + { + ASDCP_NO_COPY_CONSTRUCT(h__AS02Reader); + h__AS02Reader(); + + public: + h__AS02Reader(const ASDCP::Dictionary&); + virtual ~h__AS02Reader(); + + Result_t OpenMXFRead(const std::string& filename); + + // USE FRAME WRAPPING... + Result_t ReadEKLVFrame(ui32_t FrameNum, ASDCP::FrameBuffer& FrameBuf, + const byte_t* EssenceUL, ASDCP::AESDecContext* Ctx, ASDCP::HMACContext* HMAC); + + // OR CLIP WRAPPING... + // clip wrapping is handled directly by the essence-specific classes + // Result_t ReadyClip(const ui32_t& FrameNum, const byte_t* EssenceUL, ASDCP::AESDecContext* Ctx, ASDCP::HMACContext* HMAC, ui64_t& position); + /// Result_t ReadClipBlock(ASDCP::FrameBuffer& FrameBuf, const ui32_t& read_size); + + // NOT BOTH! + }; + + + namespace MXF { - if(numberOfIndexEntries){ - //Partition::ArchiveSize(); HeaderSize = 124 bytes - //KLV-Item = 20 bytes - //ItemSize IndexEntry = 11 bytes - //number of IndexEntries - parameter - //IndexEntryArray = 12 bytes - //size for other Elements(PosTableCount etc.) = 108 bytes - //see Index.cpp ASDCP::MXF::IndexTableSegment::WriteToTLVSet(TLVWriter& TLVSet) how this is computed - size = 124 + 20 + 11 * numberOfIndexEntries + 12 +108; - size += 20;//because maybe we must fill the last partition, minimum required space for KLV-Item - } - else{ - //Partition HeaderSize = 124 bytes - //KLV-Item = 20 bytes - //244 for 2 IndexTableSegments - size = 124 + 20 + 244; - } + // + class AS02IndexWriterVBR : public ASDCP::MXF::Partition + { + ASDCP::MXF::IndexTableSegment* m_CurrentSegment; + ASDCP::MXF::Rational m_EditRate; + + KM_NO_COPY_CONSTRUCT(AS02IndexWriterVBR); + AS02IndexWriterVBR(); + + public: + const ASDCP::Dictionary*& m_Dict; + ASDCP::IPrimerLookup* m_Lookup; + + AS02IndexWriterVBR(const ASDCP::Dictionary*&); + virtual ~AS02IndexWriterVBR(); + + // + void SetPrimerLookup(ASDCP::IPrimerLookup* lookup) { + assert(lookup); + m_Lookup = lookup; + } + + Result_t WriteToFile(Kumu::FileWriter& Writer); + void Dump(FILE* = 0); + + ui32_t GetDuration() const; + void PushIndexEntry(const ASDCP::MXF::IndexTableSegment::IndexEntry&); + void SetEditRate(const ASDCP::Rational& edit_rate); + }; + + + // + class AS02IndexWriterCBR : public ASDCP::MXF::Partition + { + ASDCP::MXF::IndexTableSegment* m_CurrentSegment; + ASDCP::MXF::Rational m_EditRate; + + KM_NO_COPY_CONSTRUCT(AS02IndexWriterCBR); + AS02IndexWriterCBR(); + + public: + const ASDCP::Dictionary*& m_Dict; + ASDCP::IPrimerLookup* m_Lookup; + ui32_t m_Duration; + ui32_t m_SampleSize; + + AS02IndexWriterCBR(const ASDCP::Dictionary*&); + virtual ~AS02IndexWriterCBR(); + + // + void SetPrimerLookup(ASDCP::IPrimerLookup* lookup) { + assert(lookup); + m_Lookup = lookup; + } + + Result_t WriteToFile(Kumu::FileWriter& Writer); + ui32_t GetDuration() const; + void SetEditRate(const ASDCP::Rational& edit_rate, const ui32_t& sample_size); + }; } // - class h__Reader - { - ASDCP_NO_COPY_CONSTRUCT(h__Reader); - h__Reader(); - - public: - const Dictionary* m_Dict; - Kumu::FileReader m_File; - OPAtomHeader m_HeaderPart; - //more than one Body-Partition use a list - std::vector m_BodyPartList; - OPAtomIndexFooter m_FooterPart; - ui64_t m_EssenceStart; - WriterInfo m_Info; - ASDCP::FrameBuffer m_CtFrameBuf; - Kumu::fpos_t m_LastPosition; - - IndexStrategy_t m_IndexStrategy; //Shim parameter index_strategy_frame/clip - ui32_t m_PartitionSpace; - - ////new elements for AS-02 - Partition* m_pCurrentBodyPartition; - AS_02::MXF::OP1aIndexBodyPartion* m_pCurrentIndexPartition; - ui32_t m_start_pos; - - h__Reader(const Dictionary&); - virtual ~h__Reader(); - - Result_t InitInfo(); - virtual Result_t OpenMXFRead(const char* filename) = 0; - Result_t InitMXFIndex(); - - // positions file before reading - virtual Result_t ReadEKLVFrame(ui32_t FrameNum, ASDCP::FrameBuffer& FrameBuf, - const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC) = 0; - - // reads from current position - virtual Result_t ReadEKLVPacket(ui32_t FrameNum, ui32_t SequenceNum, ASDCP::FrameBuffer& FrameBuf, - const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC) = 0; - void Close(); - }; + template + class h__AS02Writer : public ASDCP::MXF::TrackFileWriter + { + ASDCP_NO_COPY_CONSTRUCT(h__AS02Writer); + h__AS02Writer(); + + public: + ui32_t m_PartitionSpace; // edit units per partition + IndexWriterType m_IndexWriter; + ui64_t m_ECStart; // offset of the first essence element + + // + h__AS02Writer(const ASDCP::Dictionary& d) : + ASDCP::MXF::TrackFileWriter(d), m_IndexWriter(m_Dict), m_ECStart(0) {} + + ~h__AS02Writer() {} + + + + // all the above for a single source clip + Result_t WriteAS02Header(const std::string& PackageLabel, const ASDCP::UL& WrappingUL, + const std::string& TrackName, const ASDCP::UL& EssenceUL, + const ASDCP::UL& DataDefinition, const ASDCP::Rational& EditRate, + const ui32_t& TCFrameRate) + { + if ( EditRate.Numerator == 0 || EditRate.Denominator == 0 ) + { + DefaultLogSink().Error("Non-zero edit-rate reqired.\n"); + return RESULT_PARAM; + } + + InitHeader(MXFVersion_2011); + + AddSourceClip(EditRate, EditRate/*TODO: for a moment*/, TCFrameRate, TrackName, EssenceUL, DataDefinition, PackageLabel); + AddEssenceDescriptor(WrappingUL); + + this->m_IndexWriter.SetPrimerLookup(&this->m_HeaderPart.m_Primer); + this->m_RIP.PairArray.push_back(RIP::PartitionPair(0, 0)); // Header partition RIP entry + this->m_IndexWriter.MajorVersion = m_HeaderPart.MajorVersion; + this->m_IndexWriter.MinorVersion = m_HeaderPart.MinorVersion; + this->m_IndexWriter.OperationalPattern = this->m_HeaderPart.OperationalPattern; + this->m_IndexWriter.EssenceContainers = this->m_HeaderPart.EssenceContainers; + + Result_t result = this->m_HeaderPart.WriteToFile(this->m_File, this->m_HeaderSize); + + if ( KM_SUCCESS(result) ) + { + 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; + + UL body_ul(this->m_Dict->ul(MDD_ClosedCompleteBodyPartition)); + Partition body_part(this->m_Dict); + body_part.BodySID = 1; + body_part.MajorVersion = this->m_HeaderPart.MajorVersion; + body_part.MinorVersion = this->m_HeaderPart.MinorVersion; + body_part.OperationalPattern = this->m_HeaderPart.OperationalPattern; + body_part.EssenceContainers = this->m_HeaderPart.EssenceContainers; + body_part.ThisPartition = this->m_ECStart; + result = body_part.WriteToFile(this->m_File, body_ul); + this->m_RIP.PairArray.push_back(RIP::PartitionPair(1, body_part.ThisPartition)); // Second RIP Entry + } + + return result; + } + + void FlushIndexPartition() + { + if ( this->m_IndexWriter.GetDuration() > 0 ) + { + this->m_IndexWriter.ThisPartition = this->m_File.Tell(); + 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(); + + for (; dli != this->m_DurationUpdateList.end(); ++dli ) + { + **dli = this->m_FramesWritten; + } + + this->m_EssenceDescriptor->ContainerDuration = this->m_FramesWritten; + footer_part.PreviousPartition = this->m_RIP.PairArray.back().ByteOffset; + + Kumu::fpos_t here = this->m_File.Tell(); + this->m_RIP.PairArray.push_back(RIP::PartitionPair(0, here)); // Last RIP Entry + this->m_HeaderPart.FooterPartition = here; + + assert(this->m_Dict); + footer_part.MajorVersion = this->m_HeaderPart.MajorVersion; + footer_part.MinorVersion = this->m_HeaderPart.MinorVersion; + footer_part.OperationalPattern = this->m_HeaderPart.OperationalPattern; + footer_part.EssenceContainers = this->m_HeaderPart.EssenceContainers; + footer_part.FooterPartition = here; + footer_part.ThisPartition = here; + + UL footer_ul(this->m_Dict->ul(MDD_CompleteFooter)); + Result_t result = footer_part.WriteToFile(this->m_File, footer_ul); + + if ( KM_SUCCESS(result) ) + result = this->m_RIP.WriteToFile(this->m_File); + + if ( KM_SUCCESS(result) ) + result = this->m_File.Seek(0); + + if ( KM_SUCCESS(result) ) + result = m_HeaderPart.WriteToFile(this->m_File, this->m_HeaderSize); + + if ( KM_SUCCESS(result) ) + { + ASDCP::MXF::RIP::const_pair_iterator i = this->m_RIP.PairArray.begin(); + ui64_t header_byte_count = this->m_HeaderPart.HeaderByteCount; + ui64_t previous_partition = 0; + + for ( i = this->m_RIP.PairArray.begin(); KM_SUCCESS(result) && i != this->m_RIP.PairArray.end(); ++i ) + { + ASDCP::MXF::Partition plain_part(this->m_Dict); + result = this->m_File.Seek(i->ByteOffset); + + if ( KM_SUCCESS(result) ) + result = plain_part.InitFromFile(this->m_File); + + if ( KM_SUCCESS(result) + && ( plain_part.IndexSID > 0 || plain_part.BodySID > 0 ) ) + { + plain_part.PreviousPartition = previous_partition; + plain_part.FooterPartition = footer_part.ThisPartition; + previous_partition = plain_part.ThisPartition; + result = this->m_File.Seek(i->ByteOffset); + + if ( KM_SUCCESS(result) ) + { + UL tmp_ul = plain_part.GetUL(); + result = plain_part.WriteToFile(this->m_File, tmp_ul); + } + } + } + } + + this->m_File.Close(); + return result; + } + }; // - class h__Writer - { - ASDCP_NO_COPY_CONSTRUCT(h__Writer); - h__Writer(); - - public: - const Dictionary* m_Dict; - Kumu::FileWriter m_File; - ui32_t m_HeaderSize; - OPAtomHeader m_HeaderPart; - //more than one Body-Partition -> use a list of Partitions - std::vector m_BodyPartList; - //we don't use the footer like in the dcps but we need also a footer - AS_02::MXF::OP1aIndexFooter m_FooterPart; - ui64_t m_EssenceStart; - - MaterialPackage* m_MaterialPackage; - SourcePackage* m_FilePackage; - - FileDescriptor* m_EssenceDescriptor; - std::list m_EssenceSubDescriptorList; - - ui32_t m_FramesWritten; - ui64_t m_StreamOffset; - ASDCP::FrameBuffer m_CtFrameBuf; - h__WriterState m_State; - WriterInfo m_Info; - DurationElementList_t m_DurationUpdateList; - - //new elements for AS-02 - ui64_t m_BodyOffset; - //TODO: Currently not used, delete if not necessary - // Counter values for BodySID and IndexSID - ui32_t m_CurrentBodySID; - ui32_t m_CurrentIndexSID; - //TODO: maybe set this to the lf__Writer class because this is only in JP2K creation necessary - //our computed PartitionSpace - ui32_t m_PartitionSpace; - IndexStrategy_t m_IndexStrategy; //Shim parameter index_strategy_frame/clip - - //the EditRate - ASDCP::MXF::Rational m_EditRate; - //the BytesPerEditUnit - ui32_t m_BytesPerEditUnit; - //pointer to the current Body Partition(Index) - AS_02::MXF::OP1aIndexBodyPartion* m_CurrentIndexBodyPartition; - - h__Writer(const Dictionary&); - virtual ~h__Writer(); - - //virtual methods, implementation details for JP2K or PCM are in the MXFWriter::h__Writer classes if they are different - virtual void InitHeader(); - /*virtual*/ void AddSourceClip(const ASDCP::MXF::Rational& EditRate, ui32_t TCFrameRate, - const std::string& TrackName, const UL& EssenceUL, - const UL& DataDefinition, const std::string& PackageLabel); - /*virtual*/ void AddDMSegment(const ASDCP::MXF::Rational& EditRate, ui32_t TCFrameRate, - const std::string& TrackName, const UL& DataDefinition, - const std::string& PackageLabel); - /*virtual*/ void AddEssenceDescriptor(const ASDCP::UL& WrappingUL); - virtual Result_t CreateBodyPart(const ASDCP::MXF::Rational& EditRate, ui32_t BytesPerEditUnit = 0); - - //new method to create BodyPartition for essence and index - virtual Result_t CreateBodyPartPair(); - //new method to finalize BodyPartion(index) - virtual Result_t CompleteIndexBodyPart(); - - // all the above for a single source clip - virtual Result_t WriteMXFHeader(const std::string& PackageLabel, const UL& WrappingUL, - const std::string& TrackName, const UL& EssenceUL, - const UL& DataDefinition, const ASDCP::MXF::Rational& EditRate, - ui32_t TCFrameRate, ui32_t BytesPerEditUnit = 0); - - virtual Result_t WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf, - const byte_t* EssenceUL, AESEncContext* Ctx, HMACContext* HMAC); - - virtual Result_t WriteMXFFooter() = 0; - - }; + class h__AS02WriterFrame : public h__AS02Writer + { + ASDCP_NO_COPY_CONSTRUCT(h__AS02WriterFrame); + h__AS02WriterFrame(); + + public: + IndexStrategy_t m_IndexStrategy; // per SMPTE ST 2067-5 + + h__AS02WriterFrame(const Dictionary&); + virtual ~h__AS02WriterFrame(); + + Result_t WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf,const byte_t* EssenceUL, + const ui32_t& MinEssenceElementBerLength, + AESEncContext* Ctx, HMACContext* HMAC); + }; + + // + class h__AS02WriterClip : public h__AS02Writer + { + ASDCP_NO_COPY_CONSTRUCT(h__AS02WriterClip); + h__AS02WriterClip(); + + public: + ui64_t m_ECStart; // offset of the first essence element + ui64_t m_ClipStart; // state variable for clip-wrap-in-progress + IndexStrategy_t m_IndexStrategy; // per SMPTE ST 2067-5 + + h__AS02WriterClip(const Dictionary&); + virtual ~h__AS02WriterClip(); + + bool HasOpenClip() const; + Result_t StartClip(const byte_t* EssenceUL, AESEncContext* Ctx, HMACContext* HMAC); + Result_t WriteClipBlock(const ASDCP::FrameBuffer& FrameBuf); + Result_t FinalizeClip(ui32_t bytes_per_frame); + }; } // namespace AS_02