MDD fix
[asdcplib.git] / src / AS_02_internal.h
1 /*
2 Copyright (c) 2011-2016, 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       };
111
112
113    //
114     class AS02IndexWriterCBR : public ASDCP::MXF::Partition
115       {
116         ASDCP::MXF::IndexTableSegment*  m_CurrentSegment;
117         ASDCP::MXF::Rational m_EditRate;
118
119         KM_NO_COPY_CONSTRUCT(AS02IndexWriterCBR);
120         AS02IndexWriterCBR();
121
122       public:
123         const ASDCP::Dictionary*&  m_Dict;
124         ASDCP::IPrimerLookup* m_Lookup;
125         ui32_t m_Duration;
126         ui32_t m_SampleSize;
127       
128         AS02IndexWriterCBR(const ASDCP::Dictionary*&);
129         virtual ~AS02IndexWriterCBR();
130
131         //
132         void SetPrimerLookup(ASDCP::IPrimerLookup* lookup) {
133           assert(lookup);
134           m_Lookup = lookup;
135         }
136
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);
140       };
141   }
142
143   //
144   template <class IndexWriterType>
145   class h__AS02Writer : public ASDCP::MXF::TrackFileWriter<ASDCP::MXF::OP1aHeader>
146     {
147       ASDCP_NO_COPY_CONSTRUCT(h__AS02Writer);
148       h__AS02Writer();
149
150     public:
151       ui32_t  m_PartitionSpace;  // edit units per partition
152       IndexWriterType m_IndexWriter;
153       ui64_t  m_ECStart; // offset of the first essence element
154
155       //
156       h__AS02Writer(const ASDCP::Dictionary& d) :
157           ASDCP::MXF::TrackFileWriter<ASDCP::MXF::OP1aHeader>(d), m_IndexWriter(m_Dict), m_ECStart(0) {}
158
159       ~h__AS02Writer() {}
160
161
162       
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)
168       {
169         if ( EditRate.Numerator == 0 || EditRate.Denominator == 0 )
170           {
171             DefaultLogSink().Error("Non-zero edit-rate reqired.\n");
172             return RESULT_PARAM;
173           }
174
175         InitHeader(MXFVersion_2011);
176
177         AddSourceClip(EditRate, EditRate/*TODO: for a moment*/, TCFrameRate, TrackName, EssenceUL, DataDefinition, PackageLabel);
178         AddEssenceDescriptor(WrappingUL);
179
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;
184
185         Result_t result = this->m_HeaderPart.WriteToFile(this->m_File, this->m_HeaderSize);
186
187         if ( KM_SUCCESS(result) )
188           {
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;
192
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
203           }
204
205         return result;
206       }
207
208       // standard method of writing the header and footer of a completed AS-02 file
209       //
210       Result_t WriteAS02Footer()
211       {
212         if ( this->m_IndexWriter.GetDuration() > 0 )
213           {
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));
217           }
218
219         // update all Duration properties
220         ASDCP::MXF::Partition footer_part(this->m_Dict);
221         DurationElementList_t::iterator dli = this->m_DurationUpdateList.begin();
222
223         for (; dli != this->m_DurationUpdateList.end(); ++dli )
224           {
225             **dli = this->m_FramesWritten;
226           }
227
228         this->m_EssenceDescriptor->ContainerDuration = this->m_FramesWritten;
229         footer_part.PreviousPartition = this->m_RIP.PairArray.back().ByteOffset;
230
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;
234
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;
242
243         UL footer_ul(this->m_Dict->ul(MDD_CompleteFooter));
244         Result_t result = footer_part.WriteToFile(this->m_File, footer_ul);
245
246         if ( KM_SUCCESS(result) )
247           result = this->m_RIP.WriteToFile(this->m_File);
248
249         if ( KM_SUCCESS(result) )
250           result = this->m_File.Seek(0);
251         
252         if ( KM_SUCCESS(result) )
253           result = m_HeaderPart.WriteToFile(this->m_File, this->m_HeaderSize);
254   
255         if ( KM_SUCCESS(result) )
256           {
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;
260
261             for ( i = this->m_RIP.PairArray.begin(); KM_SUCCESS(result) && i != this->m_RIP.PairArray.end(); ++i )
262               {
263                 ASDCP::MXF::Partition plain_part(this->m_Dict);
264                 result = this->m_File.Seek(i->ByteOffset);
265
266                 if ( KM_SUCCESS(result) )
267                   result = plain_part.InitFromFile(this->m_File);
268                 
269                 if ( KM_SUCCESS(result)
270                      && ( plain_part.IndexSID > 0 || plain_part.BodySID > 0 ) )
271                   {
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);
276
277                     if ( KM_SUCCESS(result) )
278                       {
279                         UL tmp_ul = plain_part.GetUL();
280                         result = plain_part.WriteToFile(this->m_File, tmp_ul);
281                       }
282                   }
283               }
284           }
285         
286         this->m_File.Close();
287         return result;
288       }
289     };
290
291   //
292   class h__AS02WriterFrame : public h__AS02Writer<AS_02::MXF::AS02IndexWriterVBR>
293     {
294       ASDCP_NO_COPY_CONSTRUCT(h__AS02WriterFrame);
295       h__AS02WriterFrame();
296
297     public:
298       IndexStrategy_t m_IndexStrategy; // per SMPTE ST 2067-5
299
300       h__AS02WriterFrame(const Dictionary&);
301       virtual ~h__AS02WriterFrame();
302
303       Result_t WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf,const byte_t* EssenceUL,
304                                AESEncContext* Ctx, HMACContext* HMAC);
305     };
306
307   //
308   class h__AS02WriterClip : public h__AS02Writer<AS_02::MXF::AS02IndexWriterCBR>
309     {
310       ASDCP_NO_COPY_CONSTRUCT(h__AS02WriterClip);
311       h__AS02WriterClip();
312
313     public:
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
317
318       h__AS02WriterClip(const Dictionary&);
319       virtual ~h__AS02WriterClip();
320
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);
325     };
326
327 } // namespace AS_02
328
329 #endif // _AS_02_INTERNAL_H_
330
331 //
332 // end AS_02_internal.h
333 //