o Fixed Partiton and Preface version numbers in AS-02 files
[asdcplib.git] / src / AS_02_internal.h
1 /*
2 Copyright (c) 2011-2015, 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.OperationalPattern = this->m_HeaderPart.OperationalPattern;
197             body_part.EssenceContainers = this->m_HeaderPart.EssenceContainers;
198             body_part.ThisPartition = this->m_ECStart;
199             result = body_part.WriteToFile(this->m_File, body_ul);
200             this->m_RIP.PairArray.push_back(RIP::PartitionPair(1, body_part.ThisPartition)); // Second RIP Entry
201           }
202
203         return result;
204       }
205
206       // standard method of writing the header and footer of a completed AS-02 file
207       //
208       Result_t WriteAS02Footer()
209       {
210         if ( this->m_IndexWriter.GetDuration() > 0 )
211           {
212             this->m_IndexWriter.ThisPartition = this->m_File.Tell();
213             this->m_IndexWriter.WriteToFile(this->m_File);
214             this->m_RIP.PairArray.push_back(RIP::PartitionPair(0, this->m_IndexWriter.ThisPartition));
215           }
216
217         // update all Duration properties
218         ASDCP::MXF::Partition footer_part(this->m_Dict);
219         DurationElementList_t::iterator dli = this->m_DurationUpdateList.begin();
220
221         for (; dli != this->m_DurationUpdateList.end(); ++dli )
222           {
223             **dli = this->m_FramesWritten;
224           }
225
226         this->m_EssenceDescriptor->ContainerDuration = this->m_FramesWritten;
227         footer_part.PreviousPartition = this->m_RIP.PairArray.back().ByteOffset;
228
229         Kumu::fpos_t here = this->m_File.Tell();
230         this->m_RIP.PairArray.push_back(RIP::PartitionPair(0, here)); // Last RIP Entry
231         this->m_HeaderPart.FooterPartition = here;
232
233         assert(this->m_Dict);
234         footer_part.OperationalPattern = this->m_HeaderPart.OperationalPattern;
235         footer_part.EssenceContainers = this->m_HeaderPart.EssenceContainers;
236         footer_part.FooterPartition = here;
237         footer_part.ThisPartition = here;
238
239         UL footer_ul(this->m_Dict->ul(MDD_CompleteFooter));
240         Result_t result = footer_part.WriteToFile(this->m_File, footer_ul);
241
242         if ( KM_SUCCESS(result) )
243           result = this->m_RIP.WriteToFile(this->m_File);
244
245         if ( KM_SUCCESS(result) )
246           result = this->m_File.Seek(0);
247         
248         if ( KM_SUCCESS(result) )
249           result = m_HeaderPart.WriteToFile(this->m_File, this->m_HeaderSize);
250   
251         if ( KM_SUCCESS(result) )
252           {
253             ASDCP::MXF::RIP::const_pair_iterator i = this->m_RIP.PairArray.begin();
254             ui64_t header_byte_count = this->m_HeaderPart.HeaderByteCount;
255             ui64_t previous_partition = 0;
256
257             for ( i = this->m_RIP.PairArray.begin(); KM_SUCCESS(result) && i != this->m_RIP.PairArray.end(); ++i )
258               {
259                 ASDCP::MXF::Partition plain_part(this->m_Dict);
260                 result = this->m_File.Seek(i->ByteOffset);
261
262                 if ( KM_SUCCESS(result) )
263                   result = plain_part.InitFromFile(this->m_File);
264                 
265                 if ( KM_SUCCESS(result)
266                      && ( plain_part.IndexSID > 0 || plain_part.BodySID > 0 ) )
267                   {
268                     plain_part.PreviousPartition = previous_partition;
269                     plain_part.FooterPartition = footer_part.ThisPartition;
270                     previous_partition = plain_part.ThisPartition;
271                     result = this->m_File.Seek(i->ByteOffset);
272
273                     if ( KM_SUCCESS(result) )
274                       {
275                         UL tmp_ul = plain_part.GetUL();
276                         result = plain_part.WriteToFile(this->m_File, tmp_ul);
277                       }
278                   }
279               }
280           }
281         
282         this->m_File.Close();
283         return result;
284       }
285     };
286
287   //
288   class h__AS02WriterFrame : public h__AS02Writer<AS_02::MXF::AS02IndexWriterVBR>
289     {
290       ASDCP_NO_COPY_CONSTRUCT(h__AS02WriterFrame);
291       h__AS02WriterFrame();
292
293     public:
294       IndexStrategy_t m_IndexStrategy; // per SMPTE ST 2067-5
295
296       h__AS02WriterFrame(const Dictionary&);
297       virtual ~h__AS02WriterFrame();
298
299       Result_t WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf,const byte_t* EssenceUL,
300                                AESEncContext* Ctx, HMACContext* HMAC);
301     };
302
303   //
304   class h__AS02WriterClip : public h__AS02Writer<AS_02::MXF::AS02IndexWriterCBR>
305     {
306       ASDCP_NO_COPY_CONSTRUCT(h__AS02WriterClip);
307       h__AS02WriterClip();
308
309     public:
310       ui64_t  m_ECStart; // offset of the first essence element
311       ui64_t  m_ClipStart;  // state variable for clip-wrap-in-progress
312       IndexStrategy_t m_IndexStrategy; // per SMPTE ST 2067-5
313
314       h__AS02WriterClip(const Dictionary&);
315       virtual ~h__AS02WriterClip();
316
317       bool HasOpenClip() const;
318       Result_t StartClip(const byte_t* EssenceUL, AESEncContext* Ctx, HMACContext* HMAC);
319       Result_t WriteClipBlock(const ASDCP::FrameBuffer& FrameBuf);
320       Result_t FinalizeClip(ui32_t bytes_per_frame);
321     };
322
323 } // namespace AS_02
324
325 #endif // _AS_02_INTERNAL_H_
326
327 //
328 // end AS_02_internal.h
329 //