2 Copyright (c) 2011-2018, Robert Scheler, Heiko Sparenberg Fraunhofer IIS,
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
10 1. Redistributions of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in the
14 documentation and/or other materials provided with the distribution.
15 3. The name of the author may not be used to endorse or promote products
16 derived from this software without specific prior written permission.
18 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 /*! \file AS_02_internal.h
30 \version $Id: AS_02_internal.h ***
31 \brief AS-02 library, non-public common elements
34 #ifndef _AS_02_INTERNAL_H_
35 #define _AS_02_INTERNAL_H_
38 #include "AS_DCP_internal.h"
41 using Kumu::DefaultLogSink;
43 #ifdef DEFAULT_02_MD_DECL
44 AS_02::MXF::AS02IndexReader *g_AS02IndexReader;
46 extern AS_02::MXF::AS02IndexReader *g_AS02IndexReader;
53 void default_md_object_init();
57 class h__AS02Reader : public ASDCP::MXF::TrackFileReader<ASDCP::MXF::OP1aHeader, AS_02::MXF::AS02IndexReader>
59 ASDCP_NO_COPY_CONSTRUCT(h__AS02Reader);
63 h__AS02Reader(const ASDCP::Dictionary&);
64 virtual ~h__AS02Reader();
66 Result_t OpenMXFRead(const std::string& filename);
68 // USE FRAME WRAPPING...
69 Result_t ReadEKLVFrame(ui32_t FrameNum, ASDCP::FrameBuffer& FrameBuf,
70 const byte_t* EssenceUL, ASDCP::AESDecContext* Ctx, ASDCP::HMACContext* HMAC);
72 // OR CLIP WRAPPING...
73 // clip wrapping is handled directly by the essence-specific classes
74 // Result_t ReadyClip(const ui32_t& FrameNum, const byte_t* EssenceUL, ASDCP::AESDecContext* Ctx, ASDCP::HMACContext* HMAC, ui64_t& position);
75 /// Result_t ReadClipBlock(ASDCP::FrameBuffer& FrameBuf, const ui32_t& read_size);
84 class AS02IndexWriterVBR : public ASDCP::MXF::Partition
86 ASDCP::MXF::IndexTableSegment* m_CurrentSegment;
87 ASDCP::MXF::Rational m_EditRate;
89 KM_NO_COPY_CONSTRUCT(AS02IndexWriterVBR);
93 const ASDCP::Dictionary*& m_Dict;
94 ASDCP::IPrimerLookup* m_Lookup;
96 AS02IndexWriterVBR(const ASDCP::Dictionary*&);
97 virtual ~AS02IndexWriterVBR();
100 void SetPrimerLookup(ASDCP::IPrimerLookup* lookup) {
105 Result_t WriteToFile(Kumu::FileWriter& Writer);
106 void Dump(FILE* = 0);
108 ui32_t GetDuration() const;
109 void PushIndexEntry(const ASDCP::MXF::IndexTableSegment::IndexEntry&);
114 class AS02IndexWriterCBR : public ASDCP::MXF::Partition
116 ASDCP::MXF::IndexTableSegment* m_CurrentSegment;
117 ASDCP::MXF::Rational m_EditRate;
119 KM_NO_COPY_CONSTRUCT(AS02IndexWriterCBR);
120 AS02IndexWriterCBR();
123 const ASDCP::Dictionary*& m_Dict;
124 ASDCP::IPrimerLookup* m_Lookup;
128 AS02IndexWriterCBR(const ASDCP::Dictionary*&);
129 virtual ~AS02IndexWriterCBR();
132 void SetPrimerLookup(ASDCP::IPrimerLookup* lookup) {
137 Result_t WriteToFile(Kumu::FileWriter& Writer);
138 ui32_t GetDuration() const;
139 void SetEditRate(const ASDCP::Rational& edit_rate, const ui32_t& sample_size);
144 template <class IndexWriterType>
145 class h__AS02Writer : public ASDCP::MXF::TrackFileWriter<ASDCP::MXF::OP1aHeader>
147 ASDCP_NO_COPY_CONSTRUCT(h__AS02Writer);
151 ui32_t m_PartitionSpace; // edit units per partition
152 IndexWriterType m_IndexWriter;
153 ui64_t m_ECStart; // offset of the first essence element
156 h__AS02Writer(const ASDCP::Dictionary& d) :
157 ASDCP::MXF::TrackFileWriter<ASDCP::MXF::OP1aHeader>(d), m_IndexWriter(m_Dict), m_ECStart(0) {}
163 // all the above for a single source clip
164 Result_t WriteAS02Header(const std::string& PackageLabel, const ASDCP::UL& WrappingUL,
165 const std::string& TrackName, const ASDCP::UL& EssenceUL,
166 const ASDCP::UL& DataDefinition, const ASDCP::Rational& EditRate,
167 const ui32_t& TCFrameRate)
169 if ( EditRate.Numerator == 0 || EditRate.Denominator == 0 )
171 DefaultLogSink().Error("Non-zero edit-rate reqired.\n");
175 InitHeader(MXFVersion_2011);
177 AddSourceClip(EditRate, EditRate/*TODO: for a moment*/, TCFrameRate, TrackName, EssenceUL, DataDefinition, PackageLabel);
178 AddEssenceDescriptor(WrappingUL);
180 this->m_IndexWriter.SetPrimerLookup(&this->m_HeaderPart.m_Primer);
181 this->m_RIP.PairArray.push_back(RIP::PartitionPair(0, 0)); // Header partition RIP entry
182 this->m_IndexWriter.MajorVersion = m_HeaderPart.MajorVersion;
183 this->m_IndexWriter.MinorVersion = m_HeaderPart.MinorVersion;
184 this->m_IndexWriter.OperationalPattern = this->m_HeaderPart.OperationalPattern;
185 this->m_IndexWriter.EssenceContainers = this->m_HeaderPart.EssenceContainers;
187 Result_t result = this->m_HeaderPart.WriteToFile(this->m_File, this->m_HeaderSize);
189 if ( KM_SUCCESS(result) )
191 this->m_PartitionSpace *= (ui32_t)floor( EditRate.Quotient() + 0.5 ); // convert seconds to edit units
192 this->m_ECStart = this->m_File.Tell();
193 this->m_IndexWriter.IndexSID = 129;
195 UL body_ul(this->m_Dict->ul(MDD_ClosedCompleteBodyPartition));
196 Partition body_part(this->m_Dict);
197 body_part.BodySID = 1;
198 body_part.MajorVersion = this->m_HeaderPart.MajorVersion;
199 body_part.MinorVersion = this->m_HeaderPart.MinorVersion;
200 body_part.OperationalPattern = this->m_HeaderPart.OperationalPattern;
201 body_part.EssenceContainers = this->m_HeaderPart.EssenceContainers;
202 body_part.ThisPartition = this->m_ECStart;
203 result = body_part.WriteToFile(this->m_File, body_ul);
204 this->m_RIP.PairArray.push_back(RIP::PartitionPair(1, body_part.ThisPartition)); // Second RIP Entry
210 void FlushIndexPartition()
212 if ( this->m_IndexWriter.GetDuration() > 0 )
214 this->m_IndexWriter.ThisPartition = this->m_File.Tell();
215 this->m_IndexWriter.WriteToFile(this->m_File);
216 this->m_RIP.PairArray.push_back(RIP::PartitionPair(0, this->m_IndexWriter.ThisPartition));
220 // standard method of writing the header and footer of a completed AS-02 file
222 Result_t WriteAS02Footer()
224 this->FlushIndexPartition();
226 // update all Duration properties
227 ASDCP::MXF::Partition footer_part(this->m_Dict);
228 DurationElementList_t::iterator dli = this->m_DurationUpdateList.begin();
230 for (; dli != this->m_DurationUpdateList.end(); ++dli )
232 **dli = this->m_FramesWritten;
235 this->m_EssenceDescriptor->ContainerDuration = this->m_FramesWritten;
236 footer_part.PreviousPartition = this->m_RIP.PairArray.back().ByteOffset;
238 Kumu::fpos_t here = this->m_File.Tell();
239 this->m_RIP.PairArray.push_back(RIP::PartitionPair(0, here)); // Last RIP Entry
240 this->m_HeaderPart.FooterPartition = here;
242 assert(this->m_Dict);
243 footer_part.MajorVersion = this->m_HeaderPart.MajorVersion;
244 footer_part.MinorVersion = this->m_HeaderPart.MinorVersion;
245 footer_part.OperationalPattern = this->m_HeaderPart.OperationalPattern;
246 footer_part.EssenceContainers = this->m_HeaderPart.EssenceContainers;
247 footer_part.FooterPartition = here;
248 footer_part.ThisPartition = here;
250 UL footer_ul(this->m_Dict->ul(MDD_CompleteFooter));
251 Result_t result = footer_part.WriteToFile(this->m_File, footer_ul);
253 if ( KM_SUCCESS(result) )
254 result = this->m_RIP.WriteToFile(this->m_File);
256 if ( KM_SUCCESS(result) )
257 result = this->m_File.Seek(0);
259 if ( KM_SUCCESS(result) )
260 result = m_HeaderPart.WriteToFile(this->m_File, this->m_HeaderSize);
262 if ( KM_SUCCESS(result) )
264 ASDCP::MXF::RIP::const_pair_iterator i = this->m_RIP.PairArray.begin();
265 ui64_t header_byte_count = this->m_HeaderPart.HeaderByteCount;
266 ui64_t previous_partition = 0;
268 for ( i = this->m_RIP.PairArray.begin(); KM_SUCCESS(result) && i != this->m_RIP.PairArray.end(); ++i )
270 ASDCP::MXF::Partition plain_part(this->m_Dict);
271 result = this->m_File.Seek(i->ByteOffset);
273 if ( KM_SUCCESS(result) )
274 result = plain_part.InitFromFile(this->m_File);
276 if ( KM_SUCCESS(result)
277 && ( plain_part.IndexSID > 0 || plain_part.BodySID > 0 ) )
279 plain_part.PreviousPartition = previous_partition;
280 plain_part.FooterPartition = footer_part.ThisPartition;
281 previous_partition = plain_part.ThisPartition;
282 result = this->m_File.Seek(i->ByteOffset);
284 if ( KM_SUCCESS(result) )
286 UL tmp_ul = plain_part.GetUL();
287 result = plain_part.WriteToFile(this->m_File, tmp_ul);
293 this->m_File.Close();
299 class h__AS02WriterFrame : public h__AS02Writer<AS_02::MXF::AS02IndexWriterVBR>
301 ASDCP_NO_COPY_CONSTRUCT(h__AS02WriterFrame);
302 h__AS02WriterFrame();
305 IndexStrategy_t m_IndexStrategy; // per SMPTE ST 2067-5
307 h__AS02WriterFrame(const Dictionary&);
308 virtual ~h__AS02WriterFrame();
310 Result_t WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf,const byte_t* EssenceUL,
311 AESEncContext* Ctx, HMACContext* HMAC);
315 class h__AS02WriterClip : public h__AS02Writer<AS_02::MXF::AS02IndexWriterCBR>
317 ASDCP_NO_COPY_CONSTRUCT(h__AS02WriterClip);
321 ui64_t m_ECStart; // offset of the first essence element
322 ui64_t m_ClipStart; // state variable for clip-wrap-in-progress
323 IndexStrategy_t m_IndexStrategy; // per SMPTE ST 2067-5
325 h__AS02WriterClip(const Dictionary&);
326 virtual ~h__AS02WriterClip();
328 bool HasOpenClip() const;
329 Result_t StartClip(const byte_t* EssenceUL, AESEncContext* Ctx, HMACContext* HMAC);
330 Result_t WriteClipBlock(const ASDCP::FrameBuffer& FrameBuf);
331 Result_t FinalizeClip(ui32_t bytes_per_frame);
336 #endif // _AS_02_INTERNAL_H_
339 // end AS_02_internal.h