e068f8de2dd945e471a6933d5a2f0f86d70a7e5f
[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       };
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.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;
186
187         Result_t result = this->m_HeaderPart.WriteToFile(this->m_File, this->m_HeaderSize);
188
189         if ( KM_SUCCESS(result) )
190           {
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;
194
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
205           }
206
207         return result;
208       }
209
210       void FlushIndexPartition()
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       
220       // standard method of writing the header and footer of a completed AS-02 file
221       //
222       Result_t WriteAS02Footer()
223       {
224         this->FlushIndexPartition();
225           
226         // update all Duration properties
227         ASDCP::MXF::Partition footer_part(this->m_Dict);
228         DurationElementList_t::iterator dli = this->m_DurationUpdateList.begin();
229
230         for (; dli != this->m_DurationUpdateList.end(); ++dli )
231           {
232             **dli = this->m_FramesWritten;
233           }
234
235         this->m_EssenceDescriptor->ContainerDuration = this->m_FramesWritten;
236         footer_part.PreviousPartition = this->m_RIP.PairArray.back().ByteOffset;
237
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;
241
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;
249
250         UL footer_ul(this->m_Dict->ul(MDD_CompleteFooter));
251         Result_t result = footer_part.WriteToFile(this->m_File, footer_ul);
252
253         if ( KM_SUCCESS(result) )
254           result = this->m_RIP.WriteToFile(this->m_File);
255
256         if ( KM_SUCCESS(result) )
257           result = this->m_File.Seek(0);
258         
259         if ( KM_SUCCESS(result) )
260           result = m_HeaderPart.WriteToFile(this->m_File, this->m_HeaderSize);
261   
262         if ( KM_SUCCESS(result) )
263           {
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;
267
268             for ( i = this->m_RIP.PairArray.begin(); KM_SUCCESS(result) && i != this->m_RIP.PairArray.end(); ++i )
269               {
270                 ASDCP::MXF::Partition plain_part(this->m_Dict);
271                 result = this->m_File.Seek(i->ByteOffset);
272
273                 if ( KM_SUCCESS(result) )
274                   result = plain_part.InitFromFile(this->m_File);
275                 
276                 if ( KM_SUCCESS(result)
277                      && ( plain_part.IndexSID > 0 || plain_part.BodySID > 0 ) )
278                   {
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);
283
284                     if ( KM_SUCCESS(result) )
285                       {
286                         UL tmp_ul = plain_part.GetUL();
287                         result = plain_part.WriteToFile(this->m_File, tmp_ul);
288                       }
289                   }
290               }
291           }
292         
293         this->m_File.Close();
294         return result;
295       }
296     };
297
298   //
299   class h__AS02WriterFrame : public h__AS02Writer<AS_02::MXF::AS02IndexWriterVBR>
300     {
301       ASDCP_NO_COPY_CONSTRUCT(h__AS02WriterFrame);
302       h__AS02WriterFrame();
303
304     public:
305       IndexStrategy_t m_IndexStrategy; // per SMPTE ST 2067-5
306
307       h__AS02WriterFrame(const Dictionary&);
308       virtual ~h__AS02WriterFrame();
309
310       Result_t WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf,const byte_t* EssenceUL,
311                                AESEncContext* Ctx, HMACContext* HMAC);
312     };
313
314   //
315   class h__AS02WriterClip : public h__AS02Writer<AS_02::MXF::AS02IndexWriterCBR>
316     {
317       ASDCP_NO_COPY_CONSTRUCT(h__AS02WriterClip);
318       h__AS02WriterClip();
319
320     public:
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
324
325       h__AS02WriterClip(const Dictionary&);
326       virtual ~h__AS02WriterClip();
327
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);
332     };
333
334 } // namespace AS_02
335
336 #endif // _AS_02_INTERNAL_H_
337
338 //
339 // end AS_02_internal.h
340 //