Bump patch version post tag.
[asdcplib.git] / src / AS_02_internal.h
1 /*
2 Copyright (c) 2011-2018, Robert Scheler, Heiko Sparenberg Fraunhofer IIS,
3 John Hurst
4
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
9 are met:
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.
17
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.
28 */ 
29 /*! \file    AS_02_internal.h
30   \version $Id: AS_02_internal.h ***       
31   \brief   AS-02 library, non-public common elements
32 */
33
34 #ifndef _AS_02_INTERNAL_H_
35 #define _AS_02_INTERNAL_H_
36
37 #include "KM_log.h"
38 #include "AS_DCP_internal.h"
39 #include "AS_02.h"
40
41 using Kumu::DefaultLogSink;
42
43 #ifdef DEFAULT_02_MD_DECL
44 AS_02::MXF::AS02IndexReader *g_AS02IndexReader;
45 #else
46 extern AS_02::MXF::AS02IndexReader *g_AS02IndexReader;
47 #endif
48
49
50 namespace AS_02
51 {
52
53   void default_md_object_init();
54
55
56   //
57   class h__AS02Reader : public ASDCP::MXF::TrackFileReader<ASDCP::MXF::OP1aHeader, AS_02::MXF::AS02IndexReader>
58     {
59       ASDCP_NO_COPY_CONSTRUCT(h__AS02Reader);
60       h__AS02Reader();
61
62     public:
63       h__AS02Reader(const ASDCP::Dictionary&);
64       virtual ~h__AS02Reader();
65
66       Result_t OpenMXFRead(const std::string& filename);
67
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);
71
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);
76
77       // NOT BOTH!
78     };
79
80
81   namespace MXF
82   {
83     //
84     class AS02IndexWriterVBR : public ASDCP::MXF::Partition
85       {
86         ASDCP::MXF::IndexTableSegment*  m_CurrentSegment;
87         ASDCP::MXF::Rational m_EditRate;
88
89         KM_NO_COPY_CONSTRUCT(AS02IndexWriterVBR);
90         AS02IndexWriterVBR();
91
92       public:
93         const ASDCP::Dictionary*&  m_Dict;
94         ASDCP::IPrimerLookup*      m_Lookup;
95       
96         AS02IndexWriterVBR(const ASDCP::Dictionary*&);
97         virtual ~AS02IndexWriterVBR();
98
99         //
100         void SetPrimerLookup(ASDCP::IPrimerLookup* lookup) {
101           assert(lookup);
102           m_Lookup = lookup;
103         }
104
105         Result_t WriteToFile(Kumu::FileWriter& Writer);
106         void     Dump(FILE* = 0);
107
108         ui32_t GetDuration() const;
109         void PushIndexEntry(const ASDCP::MXF::IndexTableSegment::IndexEntry&);
110         void SetEditRate(const ASDCP::Rational& edit_rate);
111       };
112
113
114    //
115     class AS02IndexWriterCBR : public ASDCP::MXF::Partition
116       {
117         ASDCP::MXF::IndexTableSegment*  m_CurrentSegment;
118         ASDCP::MXF::Rational m_EditRate;
119
120         KM_NO_COPY_CONSTRUCT(AS02IndexWriterCBR);
121         AS02IndexWriterCBR();
122
123       public:
124         const ASDCP::Dictionary*&  m_Dict;
125         ASDCP::IPrimerLookup* m_Lookup;
126         ui32_t m_Duration;
127         ui32_t m_SampleSize;
128       
129         AS02IndexWriterCBR(const ASDCP::Dictionary*&);
130         virtual ~AS02IndexWriterCBR();
131
132         //
133         void SetPrimerLookup(ASDCP::IPrimerLookup* lookup) {
134           assert(lookup);
135           m_Lookup = lookup;
136         }
137
138         Result_t WriteToFile(Kumu::FileWriter& Writer);
139         ui32_t GetDuration() const;
140         void SetEditRate(const ASDCP::Rational& edit_rate, const ui32_t& sample_size);
141       };
142   }
143
144   //
145   template <class IndexWriterType>
146   class h__AS02Writer : public ASDCP::MXF::TrackFileWriter<ASDCP::MXF::OP1aHeader>
147     {
148       ASDCP_NO_COPY_CONSTRUCT(h__AS02Writer);
149       h__AS02Writer();
150
151     public:
152       ui32_t  m_PartitionSpace;  // edit units per partition
153       IndexWriterType m_IndexWriter;
154       ui64_t  m_ECStart; // offset of the first essence element
155
156       //
157       h__AS02Writer(const ASDCP::Dictionary& d) :
158           ASDCP::MXF::TrackFileWriter<ASDCP::MXF::OP1aHeader>(d), m_IndexWriter(m_Dict), m_ECStart(0) {}
159
160       ~h__AS02Writer() {}
161
162
163       
164       // all the above for a single source clip
165       Result_t WriteAS02Header(const std::string& PackageLabel, const ASDCP::UL& WrappingUL,
166                                const std::string& TrackName, const ASDCP::UL& EssenceUL,
167                                const ASDCP::UL& DataDefinition, const ASDCP::Rational& EditRate,
168                                const ui32_t& TCFrameRate)
169       {
170         if ( EditRate.Numerator == 0 || EditRate.Denominator == 0 )
171           {
172             DefaultLogSink().Error("Non-zero edit-rate reqired.\n");
173             return RESULT_PARAM;
174           }
175
176         InitHeader(MXFVersion_2011);
177
178         AddSourceClip(EditRate, EditRate/*TODO: for a moment*/, TCFrameRate, TrackName, EssenceUL, DataDefinition, PackageLabel);
179         AddEssenceDescriptor(WrappingUL);
180
181         this->m_IndexWriter.SetPrimerLookup(&this->m_HeaderPart.m_Primer);
182         this->m_RIP.PairArray.push_back(RIP::PartitionPair(0, 0)); // Header partition RIP entry
183         this->m_IndexWriter.MajorVersion = m_HeaderPart.MajorVersion;
184         this->m_IndexWriter.MinorVersion = m_HeaderPart.MinorVersion;
185         this->m_IndexWriter.OperationalPattern = this->m_HeaderPart.OperationalPattern;
186         this->m_IndexWriter.EssenceContainers = this->m_HeaderPart.EssenceContainers;
187
188         Result_t result = this->m_HeaderPart.WriteToFile(this->m_File, this->m_HeaderSize);
189
190         if ( KM_SUCCESS(result) )
191           {
192             this->m_PartitionSpace *= (ui32_t)floor( EditRate.Quotient() + 0.5 );  // convert seconds to edit units
193             this->m_ECStart = this->m_File.Tell();
194             this->m_IndexWriter.IndexSID = 129;
195
196             UL body_ul(this->m_Dict->ul(MDD_ClosedCompleteBodyPartition));
197             Partition body_part(this->m_Dict);
198             body_part.BodySID = 1;
199             body_part.MajorVersion = this->m_HeaderPart.MajorVersion;
200             body_part.MinorVersion = this->m_HeaderPart.MinorVersion;
201             body_part.OperationalPattern = this->m_HeaderPart.OperationalPattern;
202             body_part.EssenceContainers = this->m_HeaderPart.EssenceContainers;
203             body_part.ThisPartition = this->m_ECStart;
204             result = body_part.WriteToFile(this->m_File, body_ul);
205             this->m_RIP.PairArray.push_back(RIP::PartitionPair(1, body_part.ThisPartition)); // Second RIP Entry
206           }
207
208         return result;
209       }
210
211       void FlushIndexPartition()
212       {
213         if ( this->m_IndexWriter.GetDuration() > 0 )
214           {
215             this->m_IndexWriter.ThisPartition = this->m_File.Tell();
216             this->m_IndexWriter.WriteToFile(this->m_File);
217             this->m_RIP.PairArray.push_back(RIP::PartitionPair(0, this->m_IndexWriter.ThisPartition));
218           }
219       }
220       
221       // standard method of writing the header and footer of a completed AS-02 file
222       //
223       Result_t WriteAS02Footer()
224       {
225         this->FlushIndexPartition();
226           
227         // update all Duration properties
228         ASDCP::MXF::Partition footer_part(this->m_Dict);
229         DurationElementList_t::iterator dli = this->m_DurationUpdateList.begin();
230
231         for (; dli != this->m_DurationUpdateList.end(); ++dli )
232           {
233             **dli = this->m_FramesWritten;
234           }
235
236         this->m_EssenceDescriptor->ContainerDuration = this->m_FramesWritten;
237         footer_part.PreviousPartition = this->m_RIP.PairArray.back().ByteOffset;
238
239         Kumu::fpos_t here = this->m_File.Tell();
240         this->m_RIP.PairArray.push_back(RIP::PartitionPair(0, here)); // Last RIP Entry
241         this->m_HeaderPart.FooterPartition = here;
242
243         assert(this->m_Dict);
244         footer_part.MajorVersion = this->m_HeaderPart.MajorVersion;
245         footer_part.MinorVersion = this->m_HeaderPart.MinorVersion;
246         footer_part.OperationalPattern = this->m_HeaderPart.OperationalPattern;
247         footer_part.EssenceContainers = this->m_HeaderPart.EssenceContainers;
248         footer_part.FooterPartition = here;
249         footer_part.ThisPartition = here;
250
251         UL footer_ul(this->m_Dict->ul(MDD_CompleteFooter));
252         Result_t result = footer_part.WriteToFile(this->m_File, footer_ul);
253
254         if ( KM_SUCCESS(result) )
255           result = this->m_RIP.WriteToFile(this->m_File);
256
257         if ( KM_SUCCESS(result) )
258           result = this->m_File.Seek(0);
259         
260         if ( KM_SUCCESS(result) )
261           result = m_HeaderPart.WriteToFile(this->m_File, this->m_HeaderSize);
262   
263         if ( KM_SUCCESS(result) )
264           {
265             ASDCP::MXF::RIP::const_pair_iterator i = this->m_RIP.PairArray.begin();
266             ui64_t header_byte_count = this->m_HeaderPart.HeaderByteCount;
267             ui64_t previous_partition = 0;
268
269             for ( i = this->m_RIP.PairArray.begin(); KM_SUCCESS(result) && i != this->m_RIP.PairArray.end(); ++i )
270               {
271                 ASDCP::MXF::Partition plain_part(this->m_Dict);
272                 result = this->m_File.Seek(i->ByteOffset);
273
274                 if ( KM_SUCCESS(result) )
275                   result = plain_part.InitFromFile(this->m_File);
276                 
277                 if ( KM_SUCCESS(result)
278                      && ( plain_part.IndexSID > 0 || plain_part.BodySID > 0 ) )
279                   {
280                     plain_part.PreviousPartition = previous_partition;
281                     plain_part.FooterPartition = footer_part.ThisPartition;
282                     previous_partition = plain_part.ThisPartition;
283                     result = this->m_File.Seek(i->ByteOffset);
284
285                     if ( KM_SUCCESS(result) )
286                       {
287                         UL tmp_ul = plain_part.GetUL();
288                         result = plain_part.WriteToFile(this->m_File, tmp_ul);
289                       }
290                   }
291               }
292           }
293         
294         this->m_File.Close();
295         return result;
296       }
297     };
298
299   //
300   class h__AS02WriterFrame : public h__AS02Writer<AS_02::MXF::AS02IndexWriterVBR>
301     {
302       ASDCP_NO_COPY_CONSTRUCT(h__AS02WriterFrame);
303       h__AS02WriterFrame();
304
305     public:
306       IndexStrategy_t m_IndexStrategy; // per SMPTE ST 2067-5
307
308       h__AS02WriterFrame(const Dictionary&);
309       virtual ~h__AS02WriterFrame();
310
311       Result_t WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf,const byte_t* EssenceUL,
312                                const ui32_t& MinEssenceElementBerLength,
313                                AESEncContext* Ctx, HMACContext* HMAC);
314     };
315
316   //
317   class h__AS02WriterClip : public h__AS02Writer<AS_02::MXF::AS02IndexWriterCBR>
318     {
319       ASDCP_NO_COPY_CONSTRUCT(h__AS02WriterClip);
320       h__AS02WriterClip();
321
322     public:
323       ui64_t  m_ECStart; // offset of the first essence element
324       ui64_t  m_ClipStart;  // state variable for clip-wrap-in-progress
325       IndexStrategy_t m_IndexStrategy; // per SMPTE ST 2067-5
326
327       h__AS02WriterClip(const Dictionary&);
328       virtual ~h__AS02WriterClip();
329
330       bool HasOpenClip() const;
331       Result_t StartClip(const byte_t* EssenceUL, AESEncContext* Ctx, HMACContext* HMAC);
332       Result_t WriteClipBlock(const ASDCP::FrameBuffer& FrameBuf);
333       Result_t FinalizeClip(ui32_t bytes_per_frame);
334     };
335
336 } // namespace AS_02
337
338 #endif // _AS_02_INTERNAL_H_
339
340 //
341 // end AS_02_internal.h
342 //