Fix some unused variable warnings.
[asdcplib.git] / src / AS_02_internal.h
1 /*
2 Copyright (c) 2011-2021, 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 #include "AS_02_JXS.h"
41
42 using Kumu::DefaultLogSink;
43
44 namespace AS_02
45 {
46   
47   #ifdef DEFAULT_02_MD_DECL
48   AS_02::MXF::AS02IndexReader *g_AS02IndexReader;
49   #else
50   extern AS_02::MXF::AS02IndexReader *g_AS02IndexReader;
51   #endif
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*, const Kumu::IFileReaderFactory& fileReaderFactory);
64
65       virtual ~h__AS02Reader();
66
67       Result_t OpenMXFRead(const std::string& filename);
68
69       // USE FRAME WRAPPING...
70       Result_t ReadEKLVFrame(ui32_t FrameNum, ASDCP::FrameBuffer& FrameBuf,
71                              const byte_t* EssenceUL, ASDCP::AESDecContext* Ctx, ASDCP::HMACContext* HMAC);
72
73      // OR CLIP WRAPPING...
74       // clip wrapping is handled directly by the essence-specific classes
75       //      Result_t ReadyClip(const ui32_t& FrameNum, const byte_t* EssenceUL, ASDCP::AESDecContext* Ctx, ASDCP::HMACContext* HMAC, ui64_t& position);
76       ///      Result_t ReadClipBlock(ASDCP::FrameBuffer& FrameBuf, const ui32_t& read_size);
77
78       // NOT BOTH!
79     };
80
81
82   namespace MXF
83   {
84     //
85     class AS02IndexWriterVBR : public ASDCP::MXF::Partition
86       {
87         ASDCP::MXF::IndexTableSegment*  m_CurrentSegment;
88         ASDCP::MXF::Rational m_EditRate;
89
90         KM_NO_COPY_CONSTRUCT(AS02IndexWriterVBR);
91         AS02IndexWriterVBR();
92
93       public:
94         const ASDCP::Dictionary*  m_Dict;
95         ASDCP::IPrimerLookup*      m_Lookup;
96       
97         AS02IndexWriterVBR(const ASDCP::Dictionary*);
98         virtual ~AS02IndexWriterVBR();
99
100         //
101         void SetPrimerLookup(ASDCP::IPrimerLookup* lookup) {
102           assert(lookup);
103           m_Lookup = lookup;
104         }
105
106         Result_t WriteToFile(Kumu::FileWriter& Writer);
107         void     Dump(FILE* = 0);
108
109         ui32_t GetDuration() const;
110         void PushIndexEntry(const ASDCP::MXF::IndexTableSegment::IndexEntry&);
111         void SetEditRate(const ASDCP::Rational& edit_rate);
112       };
113
114
115    //
116     class AS02IndexWriterCBR : public ASDCP::MXF::Partition
117       {
118         ASDCP::MXF::IndexTableSegment*  m_CurrentSegment;
119         ASDCP::MXF::Rational m_EditRate;
120
121         KM_NO_COPY_CONSTRUCT(AS02IndexWriterCBR);
122         AS02IndexWriterCBR();
123
124       public:
125         const ASDCP::Dictionary*  m_Dict;
126         ASDCP::IPrimerLookup* m_Lookup;
127         ui32_t m_Duration;
128         ui32_t m_SampleSize;
129       
130         AS02IndexWriterCBR(const ASDCP::Dictionary*);
131         virtual ~AS02IndexWriterCBR();
132
133         //
134         void SetPrimerLookup(ASDCP::IPrimerLookup* lookup) {
135           assert(lookup);
136           m_Lookup = lookup;
137         }
138
139         Result_t WriteToFile(Kumu::FileWriter& Writer);
140         ui32_t GetDuration() const;
141         void SetEditRate(const ASDCP::Rational& edit_rate, const ui32_t& sample_size);
142       };
143   }
144
145   //
146   template <class IndexWriterType>
147   class h__AS02Writer : public ASDCP::MXF::TrackFileWriter<ASDCP::MXF::OP1aHeader>
148     {
149       ASDCP_NO_COPY_CONSTRUCT(h__AS02Writer);
150       h__AS02Writer();
151
152     public:
153       ui32_t  m_PartitionSpace;  // edit units per partition
154       IndexWriterType m_IndexWriter;
155       ui64_t  m_ECStart; // offset of the first essence element
156
157       //
158       h__AS02Writer(const ASDCP::Dictionary *d) :
159           ASDCP::MXF::TrackFileWriter<ASDCP::MXF::OP1aHeader>(d), m_IndexWriter(d), m_ECStart(0) {}
160
161       ~h__AS02Writer() {}
162
163
164       
165       // all the above for a single source clip
166       Result_t WriteAS02Header(const std::string& PackageLabel, const ASDCP::UL& WrappingUL,
167                                const std::string& TrackName, const ASDCP::UL& EssenceUL,
168                                const ASDCP::UL& DataDefinition, const ASDCP::Rational& EditRate,
169                                const std::vector<ASDCP::UL>* conformsToSpecifications = NULL)
170       {
171         if ( EditRate.Numerator == 0 || EditRate.Denominator == 0 )
172           {
173             DefaultLogSink().Error("Non-zero edit-rate reqired.\n");
174             return RESULT_PARAM;
175           }
176
177         InitHeader(MXFVersion_2011, conformsToSpecifications);
178
179         AddSourceClip(EditRate, EditRate/*TODO: for a moment*/, 0 /*no timecode track*/, TrackName, EssenceUL, DataDefinition, PackageLabel);
180         AddEssenceDescriptor(WrappingUL);
181
182         this->m_IndexWriter.SetPrimerLookup(&this->m_HeaderPart.m_Primer);
183         this->m_RIP.PairArray.push_back(RIP::PartitionPair(0, 0)); // Header partition RIP entry
184         this->m_IndexWriter.MajorVersion = m_HeaderPart.MajorVersion;
185         this->m_IndexWriter.MinorVersion = m_HeaderPart.MinorVersion;
186         this->m_IndexWriter.OperationalPattern = this->m_HeaderPart.OperationalPattern;
187         this->m_IndexWriter.EssenceContainers = this->m_HeaderPart.EssenceContainers;
188
189         Result_t result = this->m_HeaderPart.WriteToFile(this->m_File, this->m_HeaderSize);
190
191         if ( KM_SUCCESS(result) )
192           {
193             this->m_PartitionSpace *= (ui32_t)floor( EditRate.Quotient() + 0.5 );  // convert seconds to edit units
194             this->m_ECStart = this->m_File.TellPosition();
195             this->m_IndexWriter.IndexSID = 129;
196
197             UL body_ul(this->m_Dict->ul(MDD_ClosedCompleteBodyPartition));
198             Partition body_part(this->m_Dict);
199             body_part.BodySID = 1;
200             body_part.MajorVersion = this->m_HeaderPart.MajorVersion;
201             body_part.MinorVersion = this->m_HeaderPart.MinorVersion;
202             body_part.OperationalPattern = this->m_HeaderPart.OperationalPattern;
203             body_part.EssenceContainers = this->m_HeaderPart.EssenceContainers;
204             body_part.ThisPartition = this->m_ECStart;
205             result = body_part.WriteToFile(this->m_File, body_ul);
206             this->m_RIP.PairArray.push_back(RIP::PartitionPair(1, body_part.ThisPartition)); // Second RIP Entry
207           }
208
209         return result;
210       }
211
212       Result_t FlushIndexPartition()
213       {
214           Result_t result = RESULT_OK;
215             if ( this->m_IndexWriter.GetDuration() > 0 )
216             {
217             this->m_IndexWriter.ThisPartition = this->m_File.TellPosition();
218             result = this->m_IndexWriter.WriteToFile(this->m_File);
219             this->m_RIP.PairArray.push_back(RIP::PartitionPair(0, this->m_IndexWriter.ThisPartition));
220             }
221           return result;
222       }
223       
224       // standard method of writing the header and footer of a completed AS-02 file
225       //
226       Result_t WriteAS02Footer()
227       {
228           Result_t result = this->FlushIndexPartition();
229           
230         // update all Duration properties
231         ASDCP::MXF::Partition footer_part(this->m_Dict);
232         DurationElementList_t::iterator dli = this->m_DurationUpdateList.begin();
233
234         for (; dli != this->m_DurationUpdateList.end(); ++dli )
235           {
236             **dli = this->m_FramesWritten;
237           }
238
239         this->m_EssenceDescriptor->ContainerDuration = this->m_FramesWritten;
240         footer_part.PreviousPartition = this->m_RIP.PairArray.back().ByteOffset;
241
242         Kumu::fpos_t here = this->m_File.TellPosition();
243         this->m_RIP.PairArray.push_back(RIP::PartitionPair(0, here)); // Last RIP Entry
244         this->m_HeaderPart.FooterPartition = here;
245
246         assert(this->m_Dict);
247         footer_part.MajorVersion = this->m_HeaderPart.MajorVersion;
248         footer_part.MinorVersion = this->m_HeaderPart.MinorVersion;
249         footer_part.OperationalPattern = this->m_HeaderPart.OperationalPattern;
250         footer_part.EssenceContainers = this->m_HeaderPart.EssenceContainers;
251         footer_part.FooterPartition = here;
252         footer_part.ThisPartition = here;
253
254     if (KM_SUCCESS(result))
255     {
256         UL footer_ul(this->m_Dict->ul(MDD_CompleteFooter));
257         result = footer_part.WriteToFile(this->m_File, footer_ul);
258     }
259
260         if ( KM_SUCCESS(result) )
261           result = this->m_RIP.WriteToFile(this->m_File);
262
263         if ( KM_SUCCESS(result) )
264           result = this->m_File.Seek(0);
265         
266         if ( KM_SUCCESS(result) )
267           result = m_HeaderPart.WriteToFile(this->m_File, this->m_HeaderSize);
268   
269         if ( KM_SUCCESS(result) )
270           {
271             ASDCP::MXF::RIP::const_pair_iterator i = this->m_RIP.PairArray.begin();
272             ui64_t previous_partition = 0;
273
274             for ( i = this->m_RIP.PairArray.begin(); KM_SUCCESS(result) && i != this->m_RIP.PairArray.end(); ++i )
275               {
276                 ASDCP::MXF::Partition plain_part(this->m_Dict);
277                 result = this->m_File.Seek(i->ByteOffset);
278
279                 if ( KM_SUCCESS(result) )
280                   result = plain_part.InitFromFile(this->m_File);
281                 
282                 if ( KM_SUCCESS(result)
283                      && ( plain_part.IndexSID > 0 || plain_part.BodySID > 0 ) )
284                   {
285                     plain_part.PreviousPartition = previous_partition;
286                     plain_part.FooterPartition = footer_part.ThisPartition;
287                     previous_partition = plain_part.ThisPartition;
288                     result = this->m_File.Seek(i->ByteOffset);
289
290                     if ( KM_SUCCESS(result) )
291                       {
292                         UL tmp_ul = plain_part.GetUL();
293                         result = plain_part.WriteToFile(this->m_File, tmp_ul);
294                       }
295                   }
296               }
297           }
298         
299         this->m_File.Close();
300         return result;
301       }
302     };
303
304   //
305   class h__AS02WriterFrame : public h__AS02Writer<AS_02::MXF::AS02IndexWriterVBR>
306     {
307       ASDCP_NO_COPY_CONSTRUCT(h__AS02WriterFrame);
308       h__AS02WriterFrame();
309
310     public:
311       IndexStrategy_t m_IndexStrategy; // per SMPTE ST 2067-5
312
313       h__AS02WriterFrame(const Dictionary*);
314       virtual ~h__AS02WriterFrame();
315
316       Result_t WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf,const byte_t* EssenceUL,
317                                const ui32_t& MinEssenceElementBerLength,
318                                AESEncContext* Ctx, HMACContext* HMAC);
319     };
320
321   //
322   template <typename IndexWriterType>
323   class h__AS02WriterClip : public h__AS02Writer<IndexWriterType>
324     {
325       ASDCP_NO_COPY_CONSTRUCT(h__AS02WriterClip);
326       h__AS02WriterClip() {}
327
328     public:
329         ui64_t  m_ECStart; // offset of the first essence element
330         ui64_t  m_ClipStart;  // state variable for clip-wrap-in-progress
331         IndexStrategy_t m_IndexStrategy; // per SMPTE ST 2067-5
332
333         h__AS02WriterClip(const Dictionary* d) :
334             h__AS02Writer<IndexWriterType>(d),
335             m_ECStart(0), m_ClipStart(0), m_IndexStrategy(AS_02::IS_FOLLOW)
336         {}
337         virtual ~h__AS02WriterClip()
338         {}
339
340         bool HasOpenClip() const { return m_ClipStart != 0; }
341         Result_t StartClip(const byte_t* EssenceUL, AESEncContext* Ctx, HMACContext*)
342         {
343             if (Ctx != 0)
344             {
345                 DefaultLogSink().Error("Encryption not yet supported for PCM clip-wrap.\n");
346                 return RESULT_STATE;
347             }
348
349             if (m_ClipStart != 0)
350             {
351                 DefaultLogSink().Error("Cannot open clip, clip already open.\n");
352                 return RESULT_STATE;
353             }
354
355             m_ClipStart = h__AS02Writer<IndexWriterType>::m_File.TellPosition();
356             byte_t clip_buffer[24] = { 0 };
357             memcpy(clip_buffer, EssenceUL, 16);
358             bool check = Kumu::write_BER(clip_buffer + 16, 0, 8);
359             assert(check);
360             return h__AS02Writer<IndexWriterType>::m_File.Write(clip_buffer, 24);
361         }
362         Result_t WriteClipBlock(const ASDCP::FrameBuffer& FrameBuf)
363         {
364             if (m_ClipStart == 0)
365             {
366                 DefaultLogSink().Error("Cannot write clip block, no clip open.\n");
367                 return RESULT_STATE;
368             }
369
370             return h__AS02Writer<IndexWriterType>::m_File.Write(FrameBuf.RoData(), FrameBuf.Size());
371         }
372         Result_t FinalizeClip(ui32_t bytes_per_frame)
373         {
374             if (m_ClipStart == 0)
375             {
376                 DefaultLogSink().Error("Cannot close clip, clip not open.\n");
377                 return RESULT_STATE;
378             }
379
380             ui64_t current_position = h__AS02Writer<IndexWriterType>::m_File.TellPosition();
381             Result_t result = h__AS02Writer<IndexWriterType>::m_File.Seek(m_ClipStart + 16);
382
383             if (KM_SUCCESS(result))
384             {
385                 byte_t clip_buffer[8] = { 0 };
386                 ui64_t size = static_cast<ui64_t>(h__AS02Writer<IndexWriterType>::m_FramesWritten) * bytes_per_frame;
387                 bool check = Kumu::write_BER(clip_buffer, size, 8);
388                 assert(check);
389                 result = h__AS02Writer<IndexWriterType>::m_File.Write(clip_buffer, 8);
390             }
391
392             if (KM_SUCCESS(result))
393             {
394                 result = h__AS02Writer<IndexWriterType>::m_File.Seek(current_position);
395                 m_ClipStart = 0;
396             }
397
398             return result;
399         }
400         Result_t FinalizeClip(ui64_t total_bytes_written)
401         {
402             if (m_ClipStart == 0)
403             {
404                 DefaultLogSink().Error("Cannot close clip, clip not open.\n");
405                 return RESULT_STATE;
406             }
407
408             ui64_t current_position = h__AS02Writer<IndexWriterType>::m_File.TellPosition();
409             Result_t result = h__AS02Writer<IndexWriterType>::m_File.Seek(m_ClipStart + 16);
410
411             if (KM_SUCCESS(result))
412             {
413                 byte_t clip_buffer[8] = { 0 };
414                 bool check = Kumu::write_BER(clip_buffer, total_bytes_written, 8);
415                 assert(check);
416                 result = h__AS02Writer<IndexWriterType>::m_File.Write(clip_buffer, 8);
417             }
418
419             if (KM_SUCCESS(result))
420             {
421                 result = h__AS02Writer<IndexWriterType>::m_File.Seek(current_position);
422                 m_ClipStart = 0;
423             }
424
425             return result;
426
427         }
428     };
429
430 } // namespace AS_02
431
432 #endif // _AS_02_INTERNAL_H_
433
434 //
435 // end AS_02_internal.h
436 //