Added atmos support and new ULs per SMPTE 429-2:2013 - see README for deets.
[asdcplib.git] / src / AS_DCP_internal.h
1 /*
2 Copyright (c) 2004-2012, John Hurst
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8 1. Redistributions of source code must retain the above copyright
9    notice, this list of conditions and the following disclaimer.
10 2. Redistributions in binary form must reproduce the above copyright
11    notice, this list of conditions and the following disclaimer in the
12    documentation and/or other materials provided with the distribution.
13 3. The name of the author may not be used to endorse or promote products
14    derived from this software without specific prior written permission.
15
16 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27 /*! \file    AS_DCP_internal.h
28     \version $Id$
29     \brief   AS-DCP library, non-public common elements
30 */
31
32 #ifndef _AS_DCP_INTERNAL_H_
33 #define _AS_DCP_INTERNAL_H_
34
35 #include <KM_platform.h>
36 #include <KM_util.h>
37 #include <KM_log.h>
38 #include "Metadata.h"
39
40 using Kumu::DefaultLogSink;
41 // using namespace std;
42 using namespace ASDCP;
43 using namespace ASDCP::MXF;
44
45 #ifdef DEFAULT_MD_DECL
46 ASDCP::MXF::OPAtomHeader *g_OPAtomHeader;
47 ASDCP::MXF::OPAtomIndexFooter *g_OPAtomIndexFooter;
48 #else
49 extern MXF::OPAtomHeader *g_OPAtomHeader;
50 extern MXF::OPAtomIndexFooter *g_OPAtomIndexFooter;
51 #endif
52
53
54 namespace ASDCP
55 {
56   void default_md_object_init();
57
58   //
59   static std::vector<int>
60     version_split(const char* str)
61   {
62     std::vector<int> result;
63     const char* pstr = str;
64     const char* r = strchr(pstr, '.');
65
66     while ( r != 0 )
67       {
68         assert(r >= pstr);
69         if ( r > pstr )
70           result.push_back(atoi(pstr));
71
72         pstr = r + 1;
73         r = strchr(pstr, '.');
74       }
75
76     if( strlen(pstr) > 0 )
77       result.push_back(atoi(pstr));
78
79     assert(result.size() == 3);
80     return result;
81   }
82
83   // constant values used to calculate KLV and EKLV packet sizes
84   static const ui32_t klv_cryptinfo_size =
85     MXF_BER_LENGTH
86     + UUIDlen /* ContextID */
87     + MXF_BER_LENGTH
88     + sizeof(ui64_t) /* PlaintextOffset */
89     + MXF_BER_LENGTH
90     + SMPTE_UL_LENGTH /* SourceKey */
91     + MXF_BER_LENGTH
92     + sizeof(ui64_t) /* SourceLength */
93     + MXF_BER_LENGTH /* ESV length */ ;
94
95   static const ui32_t klv_intpack_size =
96     MXF_BER_LENGTH
97     + UUIDlen /* TrackFileID */
98     + MXF_BER_LENGTH
99     + sizeof(ui64_t) /* SequenceNumber */
100     + MXF_BER_LENGTH
101     + 20; /* HMAC length*/
102
103   // calculate size of encrypted essence with IV, CheckValue, and padding
104   inline ui32_t
105     calc_esv_length(ui32_t source_length, ui32_t plaintext_offset)
106     {
107       ui32_t ct_size = source_length - plaintext_offset;
108       ui32_t diff = ct_size % CBC_BLOCK_SIZE;
109       ui32_t block_size = ct_size - diff;
110       return plaintext_offset + block_size + (CBC_BLOCK_SIZE * 3);
111     }
112
113   // the check value for EKLV packets
114   // CHUKCHUKCHUKCHUK
115   static const byte_t ESV_CheckValue[CBC_BLOCK_SIZE] =
116   { 0x43, 0x48, 0x55, 0x4b, 0x43, 0x48, 0x55, 0x4b,
117     0x43, 0x48, 0x55, 0x4b, 0x43, 0x48, 0x55, 0x4b };
118
119   //------------------------------------------------------------------------------------------
120   //
121
122   Result_t MD_to_WriterInfo(MXF::Identification*, WriterInfo&);
123   Result_t MD_to_CryptoInfo(MXF::CryptographicContext*, WriterInfo&, const Dictionary&);
124   Result_t EncryptFrameBuffer(const ASDCP::FrameBuffer&, ASDCP::FrameBuffer&, AESEncContext*);
125   Result_t DecryptFrameBuffer(const ASDCP::FrameBuffer&, ASDCP::FrameBuffer&, AESDecContext*);
126   Result_t PCM_ADesc_to_MD(PCM::AudioDescriptor& ADesc, ASDCP::MXF::WaveAudioDescriptor* ADescObj);
127   Result_t MD_to_PCM_ADesc(ASDCP::MXF::WaveAudioDescriptor* ADescObj, PCM::AudioDescriptor& ADesc);
128   void     AddDMScrypt(Partition& HeaderPart, SourcePackage& Package,
129                        WriterInfo& Descr, const UL& WrappingUL, const Dictionary*& Dict);
130
131   Result_t Read_EKLV_Packet(Kumu::FileReader& File, const ASDCP::Dictionary& Dict, const MXF::OPAtomHeader& HeaderPart,
132                             const ASDCP::WriterInfo& Info, Kumu::fpos_t& LastPosition, ASDCP::FrameBuffer& CtFrameBuf,
133                             ui32_t FrameNum, ui32_t SequenceNum, ASDCP::FrameBuffer& FrameBuf,
134                             const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC);
135
136   //
137  class KLReader : public ASDCP::KLVPacket
138     {
139       ASDCP_NO_COPY_CONSTRUCT(KLReader);
140       byte_t m_KeyBuf[SMPTE_UL_LENGTH*2];
141
142     public:
143       KLReader() {}
144       ~KLReader() {}
145
146       inline const byte_t* Key() { return m_KeyBuf; }
147       inline const ui64_t  Length() { return m_ValueLength; }
148       inline const ui64_t  KLLength() { return m_KLLength; }
149
150       Result_t ReadKLFromFile(Kumu::FileReader& Reader);
151     };
152
153   namespace MXF
154   {
155       //---------------------------------------------------------------------------------
156       //
157
158     ///      void default_md_object_init();
159
160       template <class HeaderType, class FooterType>
161       class TrackFileReader
162       {
163         KM_NO_COPY_CONSTRUCT(TrackFileReader);
164         TrackFileReader();
165
166       public:
167         const Dictionary*  m_Dict;
168         Kumu::FileReader   m_File;
169         HeaderType         m_HeaderPart;
170         FooterType         m_FooterPart;
171         WriterInfo         m_Info;
172         ASDCP::FrameBuffer m_CtFrameBuf;
173         Kumu::fpos_t       m_LastPosition;
174
175       TrackFileReader(const Dictionary& d) :
176         m_HeaderPart(m_Dict), m_FooterPart(m_Dict), m_Dict(&d)
177           {
178             default_md_object_init();
179           }
180
181         virtual ~TrackFileReader() {
182           Close();
183         }
184
185         Result_t InitInfo()
186         {
187           assert(m_Dict);
188           InterchangeObject* Object;
189
190           // Identification
191           Result_t result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(Identification), &Object);
192
193           // Writer Info and SourcePackage
194           if ( KM_SUCCESS(result) )
195             {
196               MD_to_WriterInfo((Identification*)Object, m_Info);
197               result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(SourcePackage), &Object);
198             }
199
200           if ( KM_SUCCESS(result) )
201             {
202               SourcePackage* SP = (SourcePackage*)Object;
203               memcpy(m_Info.AssetUUID, SP->PackageUID.Value() + 16, UUIDlen);
204             }
205
206           // optional CryptographicContext
207           if ( KM_SUCCESS(result) )
208             {
209               Result_t cr_result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(CryptographicContext), &Object);
210
211               if ( KM_SUCCESS(cr_result) )
212                 MD_to_CryptoInfo((CryptographicContext*)Object, m_Info, *m_Dict);
213             }
214
215           return result;
216         }
217
218         //
219         Result_t OpenMXFRead(const char* filename)
220         {
221           m_LastPosition = 0;
222           Result_t result = m_File.OpenRead(filename);
223
224           if ( KM_SUCCESS(result) )
225             result = m_HeaderPart.InitFromFile(m_File);
226       else
227         DefaultLogSink().Error("ASDCP::h__Reader::OpenMXFRead, OpenRead failed\n");
228
229           return result;
230         }
231
232         // positions file before reading
233         Result_t ReadEKLVFrame(const ASDCP::MXF::Partition& CurrentPartition,
234                                ui32_t FrameNum, ASDCP::FrameBuffer& FrameBuf,
235                                const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC)
236         {
237           // look up frame index node
238           IndexTableSegment::IndexEntry TmpEntry;
239
240           if ( KM_FAILURE(m_FooterPart.Lookup(FrameNum, TmpEntry)) )
241             {
242               DefaultLogSink().Error("Frame value out of range: %u\n", FrameNum);
243               return RESULT_RANGE;
244             }
245
246           // get frame position and go read the frame's key and length
247           Kumu::fpos_t FilePosition = CurrentPartition.BodyOffset + TmpEntry.StreamOffset;
248           Result_t result = RESULT_OK;
249
250           if ( FilePosition != m_LastPosition )
251             {
252               m_LastPosition = FilePosition;
253               result = m_File.Seek(FilePosition);
254             }
255
256           if( KM_SUCCESS(result) )
257             result = ReadEKLVPacket(FrameNum, FrameNum + 1, FrameBuf, EssenceUL, Ctx, HMAC);
258
259           return result;
260         }
261
262         // reads from current position
263         Result_t ReadEKLVPacket(ui32_t FrameNum, ui32_t SequenceNum, ASDCP::FrameBuffer& FrameBuf,
264                                 const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC)
265         {
266           assert(m_Dict);
267           return Read_EKLV_Packet(m_File, *m_Dict, m_HeaderPart, m_Info, m_LastPosition, m_CtFrameBuf,
268                                   FrameNum, SequenceNum, FrameBuf, EssenceUL, Ctx, HMAC);
269         }
270
271     // Get the position of a frame from a track file
272     Result_t LocateFrame(const ASDCP::MXF::Partition& CurrentPartition,
273                          ui32_t FrameNum, Kumu::fpos_t& streamOffset,
274                          i8_t& temporalOffset, i8_t& keyFrameOffset)
275     {
276       // look up frame index node
277       IndexTableSegment::IndexEntry TmpEntry;
278
279       if ( KM_FAILURE(m_FooterPart.Lookup(FrameNum, TmpEntry)) )
280       {
281         DefaultLogSink().Error("Frame value out of range: %u\n", FrameNum);
282         return RESULT_RANGE;
283       }
284
285       // get frame position, temporal offset, and key frame ofset
286       streamOffset = CurrentPartition.BodyOffset + TmpEntry.StreamOffset;
287       temporalOffset = TmpEntry.TemporalOffset;
288       keyFrameOffset = TmpEntry.KeyFrameOffset;
289
290       return RESULT_OK;
291     }
292
293         //
294         void     Close() {
295           m_File.Close();
296         }
297       };
298
299   }/// namespace MXF
300
301   //
302   class h__ASDCPReader : public MXF::TrackFileReader<OPAtomHeader, OPAtomIndexFooter>
303     {
304       ASDCP_NO_COPY_CONSTRUCT(h__ASDCPReader);
305       h__ASDCPReader();
306
307     public:
308       Partition m_BodyPart;
309
310       h__ASDCPReader(const Dictionary&);
311       virtual ~h__ASDCPReader();
312
313       Result_t OpenMXFRead(const char* filename);
314       Result_t InitInfo();
315       Result_t InitMXFIndex();
316       Result_t ReadEKLVFrame(ui32_t FrameNum, ASDCP::FrameBuffer& FrameBuf,
317                              const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC);
318       Result_t LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset,
319                            i8_t& temporalOffset, i8_t& keyFrameOffset);
320
321     };
322
323
324   // state machine for mxf writer
325   enum WriterState_t {
326     ST_BEGIN,   // waiting for Open()
327     ST_INIT,    // waiting for SetSourceStream()
328     ST_READY,   // ready to write frames
329     ST_RUNNING, // one or more frames written
330     ST_FINAL,   // index written, file closed
331   };
332
333   // implementation of h__WriterState class Goto_* methods
334 #define Goto_body(s1,s2) if ( m_State != (s1) ) \
335                            return RESULT_STATE; \
336                          m_State = (s2); \
337                          return RESULT_OK
338   //
339   class h__WriterState
340     {
341       ASDCP_NO_COPY_CONSTRUCT(h__WriterState);
342
343     public:
344       WriterState_t m_State;
345       h__WriterState() : m_State(ST_BEGIN) {}
346       ~h__WriterState() {}
347
348       inline bool     Test_BEGIN()   { return m_State == ST_BEGIN; }
349       inline bool     Test_INIT()    { return m_State == ST_INIT; }
350       inline bool     Test_READY()   { return m_State == ST_READY;}
351       inline bool     Test_RUNNING() { return m_State == ST_RUNNING; }
352       inline bool     Test_FINAL()   { return m_State == ST_FINAL; }
353       inline Result_t Goto_INIT()    { Goto_body(ST_BEGIN,   ST_INIT); }
354       inline Result_t Goto_READY()   { Goto_body(ST_INIT,    ST_READY); }
355       inline Result_t Goto_RUNNING() { Goto_body(ST_READY,   ST_RUNNING); }
356       inline Result_t Goto_FINAL()   { Goto_body(ST_RUNNING, ST_FINAL); }
357     };
358
359   typedef std::list<ui64_t*> DurationElementList_t;
360
361   //
362   class h__Writer
363     {
364       ASDCP_NO_COPY_CONSTRUCT(h__Writer);
365       h__Writer();
366
367     public:
368       const Dictionary*  m_Dict;
369       Kumu::FileWriter   m_File;
370       ui32_t             m_HeaderSize;
371       OPAtomHeader       m_HeaderPart;
372       Partition          m_BodyPart;
373       OPAtomIndexFooter  m_FooterPart;
374       ui64_t             m_EssenceStart;
375
376       MaterialPackage*   m_MaterialPackage;
377       SourcePackage*     m_FilePackage;
378
379       FileDescriptor*    m_EssenceDescriptor;
380       std::list<InterchangeObject*> m_EssenceSubDescriptorList;
381
382       ui32_t             m_FramesWritten;
383       ui64_t             m_StreamOffset;
384       ASDCP::FrameBuffer m_CtFrameBuf;
385       h__WriterState     m_State;
386       WriterInfo         m_Info;
387       DurationElementList_t m_DurationUpdateList;
388
389       h__Writer(const Dictionary&);
390       virtual ~h__Writer();
391
392       void InitHeader();
393       void AddSourceClip(const MXF::Rational& EditRate, ui32_t TCFrameRate,
394                          const std::string& TrackName, const UL& EssenceUL,
395                          const UL& DataDefinition, const std::string& PackageLabel);
396       void AddDMSegment(const MXF::Rational& EditRate, ui32_t TCFrameRate,
397                         const std::string& TrackName, const UL& DataDefinition,
398                         const std::string& PackageLabel);
399       void AddEssenceDescriptor(const UL& WrappingUL);
400       Result_t CreateBodyPart(const MXF::Rational& EditRate, ui32_t BytesPerEditUnit = 0);
401
402       // all the above for a single source clip
403       Result_t WriteMXFHeader(const std::string& PackageLabel, const UL& WrappingUL,
404                               const std::string& TrackName, const UL& EssenceUL,
405                               const UL& DataDefinition, const MXF::Rational& EditRate,
406                               ui32_t TCFrameRate, ui32_t BytesPerEditUnit = 0);
407
408       Result_t WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf,
409                                const byte_t* EssenceUL, AESEncContext* Ctx, HMACContext* HMAC);
410
411       Result_t WriteMXFFooter();
412
413    };
414
415
416   // helper class for calculating Integrity Packs, used by WriteEKLVPacket() below.
417   //
418   class IntegrityPack
419     {
420     public:
421       byte_t Data[klv_intpack_size];
422
423       IntegrityPack() {
424         memset(Data, 0, klv_intpack_size);
425       }
426
427       ~IntegrityPack() {}
428
429       Result_t CalcValues(const ASDCP::FrameBuffer&, const byte_t* AssetID, ui32_t sequence, HMACContext* HMAC);
430       Result_t TestValues(const ASDCP::FrameBuffer&, const byte_t* AssetID, ui32_t sequence, HMACContext* HMAC);
431     };
432
433
434 } // namespace ASDCP
435
436 #endif // _AS_DCP_INTERNAL_H_
437
438
439 //
440 // end AS_DCP_internal.h
441 //