2 Copyright (c) 2011-2016, 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.OperationalPattern = this->m_HeaderPart.OperationalPattern;
183 this->m_IndexWriter.EssenceContainers = this->m_HeaderPart.EssenceContainers;
185 Result_t result = this->m_HeaderPart.WriteToFile(this->m_File, this->m_HeaderSize);
187 if ( KM_SUCCESS(result) )
189 this->m_PartitionSpace *= floor( EditRate.Quotient() + 0.5 ); // convert seconds to edit units
190 this->m_ECStart = this->m_File.Tell();
191 this->m_IndexWriter.IndexSID = 129;
193 UL body_ul(this->m_Dict->ul(MDD_ClosedCompleteBodyPartition));
194 Partition body_part(this->m_Dict);
195 body_part.BodySID = 1;
196 body_part.MajorVersion = this->m_HeaderPart.MajorVersion;
197 body_part.MinorVersion = this->m_HeaderPart.MinorVersion;
198 body_part.OperationalPattern = this->m_HeaderPart.OperationalPattern;
199 body_part.EssenceContainers = this->m_HeaderPart.EssenceContainers;
200 body_part.ThisPartition = this->m_ECStart;
201 result = body_part.WriteToFile(this->m_File, body_ul);
202 this->m_RIP.PairArray.push_back(RIP::PartitionPair(1, body_part.ThisPartition)); // Second RIP Entry
208 // standard method of writing the header and footer of a completed AS-02 file
210 Result_t WriteAS02Footer()
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));
219 // update all Duration properties
220 ASDCP::MXF::Partition footer_part(this->m_Dict);
221 DurationElementList_t::iterator dli = this->m_DurationUpdateList.begin();
223 for (; dli != this->m_DurationUpdateList.end(); ++dli )
225 **dli = this->m_FramesWritten;
228 this->m_EssenceDescriptor->ContainerDuration = this->m_FramesWritten;
229 footer_part.PreviousPartition = this->m_RIP.PairArray.back().ByteOffset;
231 Kumu::fpos_t here = this->m_File.Tell();
232 this->m_RIP.PairArray.push_back(RIP::PartitionPair(0, here)); // Last RIP Entry
233 this->m_HeaderPart.FooterPartition = here;
235 assert(this->m_Dict);
236 footer_part.MajorVersion = this->m_HeaderPart.MajorVersion;
237 footer_part.MinorVersion = this->m_HeaderPart.MinorVersion;
238 footer_part.OperationalPattern = this->m_HeaderPart.OperationalPattern;
239 footer_part.EssenceContainers = this->m_HeaderPart.EssenceContainers;
240 footer_part.FooterPartition = here;
241 footer_part.ThisPartition = here;
243 UL footer_ul(this->m_Dict->ul(MDD_CompleteFooter));
244 Result_t result = footer_part.WriteToFile(this->m_File, footer_ul);
246 if ( KM_SUCCESS(result) )
247 result = this->m_RIP.WriteToFile(this->m_File);
249 if ( KM_SUCCESS(result) )
250 result = this->m_File.Seek(0);
252 if ( KM_SUCCESS(result) )
253 result = m_HeaderPart.WriteToFile(this->m_File, this->m_HeaderSize);
255 if ( KM_SUCCESS(result) )
257 ASDCP::MXF::RIP::const_pair_iterator i = this->m_RIP.PairArray.begin();
258 ui64_t header_byte_count = this->m_HeaderPart.HeaderByteCount;
259 ui64_t previous_partition = 0;
261 for ( i = this->m_RIP.PairArray.begin(); KM_SUCCESS(result) && i != this->m_RIP.PairArray.end(); ++i )
263 ASDCP::MXF::Partition plain_part(this->m_Dict);
264 result = this->m_File.Seek(i->ByteOffset);
266 if ( KM_SUCCESS(result) )
267 result = plain_part.InitFromFile(this->m_File);
269 if ( KM_SUCCESS(result)
270 && ( plain_part.IndexSID > 0 || plain_part.BodySID > 0 ) )
272 plain_part.PreviousPartition = previous_partition;
273 plain_part.FooterPartition = footer_part.ThisPartition;
274 previous_partition = plain_part.ThisPartition;
275 result = this->m_File.Seek(i->ByteOffset);
277 if ( KM_SUCCESS(result) )
279 UL tmp_ul = plain_part.GetUL();
280 result = plain_part.WriteToFile(this->m_File, tmp_ul);
286 this->m_File.Close();
292 class h__AS02WriterFrame : public h__AS02Writer<AS_02::MXF::AS02IndexWriterVBR>
294 ASDCP_NO_COPY_CONSTRUCT(h__AS02WriterFrame);
295 h__AS02WriterFrame();
298 IndexStrategy_t m_IndexStrategy; // per SMPTE ST 2067-5
300 h__AS02WriterFrame(const Dictionary&);
301 virtual ~h__AS02WriterFrame();
303 Result_t WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf,const byte_t* EssenceUL,
304 AESEncContext* Ctx, HMACContext* HMAC);
308 class h__AS02WriterClip : public h__AS02Writer<AS_02::MXF::AS02IndexWriterCBR>
310 ASDCP_NO_COPY_CONSTRUCT(h__AS02WriterClip);
314 ui64_t m_ECStart; // offset of the first essence element
315 ui64_t m_ClipStart; // state variable for clip-wrap-in-progress
316 IndexStrategy_t m_IndexStrategy; // per SMPTE ST 2067-5
318 h__AS02WriterClip(const Dictionary&);
319 virtual ~h__AS02WriterClip();
321 bool HasOpenClip() const;
322 Result_t StartClip(const byte_t* EssenceUL, AESEncContext* Ctx, HMACContext* HMAC);
323 Result_t WriteClipBlock(const ASDCP::FrameBuffer& FrameBuf);
324 Result_t FinalizeClip(ui32_t bytes_per_frame);
329 #endif // _AS_02_INTERNAL_H_
332 // end AS_02_internal.h