2 Copyright (c) 2004-2012, John Hurst
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
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.
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.
27 /*! \file AS_DCP_internal.h
29 \brief AS-DCP library, non-public common elements
32 #ifndef _AS_DCP_INTERNAL_H_
33 #define _AS_DCP_INTERNAL_H_
35 #include <KM_platform.h>
40 using Kumu::DefaultLogSink;
41 // using namespace std;
42 using namespace ASDCP;
43 using namespace ASDCP::MXF;
45 #ifdef DEFAULT_MD_DECL
46 ASDCP::MXF::OPAtomHeader *g_OPAtomHeader;
47 ASDCP::MXF::OPAtomIndexFooter *g_OPAtomIndexFooter;
49 extern MXF::OPAtomHeader *g_OPAtomHeader;
50 extern MXF::OPAtomIndexFooter *g_OPAtomIndexFooter;
56 void default_md_object_init();
59 static std::vector<int>
60 version_split(const char* str)
62 std::vector<int> result;
63 const char* pstr = str;
64 const char* r = strchr(pstr, '.');
70 result.push_back(atoi(pstr));
73 r = strchr(pstr, '.');
76 if( strlen(pstr) > 0 )
77 result.push_back(atoi(pstr));
79 assert(result.size() == 3);
83 // constant values used to calculate KLV and EKLV packet sizes
84 static const ui32_t klv_cryptinfo_size =
86 + UUIDlen /* ContextID */
88 + sizeof(ui64_t) /* PlaintextOffset */
90 + SMPTE_UL_LENGTH /* SourceKey */
92 + sizeof(ui64_t) /* SourceLength */
93 + MXF_BER_LENGTH /* ESV length */ ;
95 static const ui32_t klv_intpack_size =
97 + UUIDlen /* TrackFileID */
99 + sizeof(ui64_t) /* SequenceNumber */
101 + 20; /* HMAC length*/
103 // calculate size of encrypted essence with IV, CheckValue, and padding
105 calc_esv_length(ui32_t source_length, ui32_t plaintext_offset)
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);
113 // the check value for EKLV packets
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 };
119 //------------------------------------------------------------------------------------------
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);
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);
137 class KLReader : public ASDCP::KLVPacket
139 ASDCP_NO_COPY_CONSTRUCT(KLReader);
140 byte_t m_KeyBuf[SMPTE_UL_LENGTH*2];
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; }
150 Result_t ReadKLFromFile(Kumu::FileReader& Reader);
155 //---------------------------------------------------------------------------------
158 /// void default_md_object_init();
160 template <class HeaderType, class FooterType>
161 class TrackFileReader
163 KM_NO_COPY_CONSTRUCT(TrackFileReader);
167 const Dictionary* m_Dict;
168 Kumu::FileReader m_File;
169 HeaderType m_HeaderPart;
170 FooterType m_FooterPart;
172 ASDCP::FrameBuffer m_CtFrameBuf;
173 Kumu::fpos_t m_LastPosition;
175 TrackFileReader(const Dictionary& d) :
176 m_HeaderPart(m_Dict), m_FooterPart(m_Dict), m_Dict(&d)
178 default_md_object_init();
181 virtual ~TrackFileReader() {
188 InterchangeObject* Object;
191 Result_t result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(Identification), &Object);
193 // Writer Info and SourcePackage
194 if ( KM_SUCCESS(result) )
196 MD_to_WriterInfo((Identification*)Object, m_Info);
197 result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(SourcePackage), &Object);
200 if ( KM_SUCCESS(result) )
202 SourcePackage* SP = (SourcePackage*)Object;
203 memcpy(m_Info.AssetUUID, SP->PackageUID.Value() + 16, UUIDlen);
206 // optional CryptographicContext
207 if ( KM_SUCCESS(result) )
209 Result_t cr_result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(CryptographicContext), &Object);
211 if ( KM_SUCCESS(cr_result) )
212 MD_to_CryptoInfo((CryptographicContext*)Object, m_Info, *m_Dict);
219 Result_t OpenMXFRead(const char* filename)
222 Result_t result = m_File.OpenRead(filename);
224 if ( KM_SUCCESS(result) )
225 result = m_HeaderPart.InitFromFile(m_File);
230 // positions file before reading
231 Result_t ReadEKLVFrame(const ASDCP::MXF::Partition& CurrentPartition,
232 ui32_t FrameNum, ASDCP::FrameBuffer& FrameBuf,
233 const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC)
235 // look up frame index node
236 IndexTableSegment::IndexEntry TmpEntry;
238 if ( KM_FAILURE(m_FooterPart.Lookup(FrameNum, TmpEntry)) )
240 DefaultLogSink().Error("Frame value out of range: %u\n", FrameNum);
244 // get frame position and go read the frame's key and length
245 Kumu::fpos_t FilePosition = CurrentPartition.BodyOffset + TmpEntry.StreamOffset;
246 Result_t result = RESULT_OK;
248 if ( FilePosition != m_LastPosition )
250 m_LastPosition = FilePosition;
251 result = m_File.Seek(FilePosition);
254 if( KM_SUCCESS(result) )
255 result = ReadEKLVPacket(FrameNum, FrameNum + 1, FrameBuf, EssenceUL, Ctx, HMAC);
260 // reads from current position
261 Result_t ReadEKLVPacket(ui32_t FrameNum, ui32_t SequenceNum, ASDCP::FrameBuffer& FrameBuf,
262 const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC)
265 return Read_EKLV_Packet(m_File, *m_Dict, m_HeaderPart, m_Info, m_LastPosition, m_CtFrameBuf,
266 FrameNum, SequenceNum, FrameBuf, EssenceUL, Ctx, HMAC);
278 class h__ASDCPReader : public MXF::TrackFileReader<OPAtomHeader, OPAtomIndexFooter>
280 ASDCP_NO_COPY_CONSTRUCT(h__ASDCPReader);
284 Partition m_BodyPart;
286 h__ASDCPReader(const Dictionary&);
287 virtual ~h__ASDCPReader();
289 Result_t OpenMXFRead(const char* filename);
291 Result_t InitMXFIndex();
292 Result_t ReadEKLVFrame(ui32_t FrameNum, ASDCP::FrameBuffer& FrameBuf,
293 const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC);
297 // state machine for mxf writer
299 ST_BEGIN, // waiting for Open()
300 ST_INIT, // waiting for SetSourceStream()
301 ST_READY, // ready to write frames
302 ST_RUNNING, // one or more frames written
303 ST_FINAL, // index written, file closed
306 // implementation of h__WriterState class Goto_* methods
307 #define Goto_body(s1,s2) if ( m_State != (s1) ) \
308 return RESULT_STATE; \
314 ASDCP_NO_COPY_CONSTRUCT(h__WriterState);
317 WriterState_t m_State;
318 h__WriterState() : m_State(ST_BEGIN) {}
321 inline bool Test_BEGIN() { return m_State == ST_BEGIN; }
322 inline bool Test_INIT() { return m_State == ST_INIT; }
323 inline bool Test_READY() { return m_State == ST_READY;}
324 inline bool Test_RUNNING() { return m_State == ST_RUNNING; }
325 inline bool Test_FINAL() { return m_State == ST_FINAL; }
326 inline Result_t Goto_INIT() { Goto_body(ST_BEGIN, ST_INIT); }
327 inline Result_t Goto_READY() { Goto_body(ST_INIT, ST_READY); }
328 inline Result_t Goto_RUNNING() { Goto_body(ST_READY, ST_RUNNING); }
329 inline Result_t Goto_FINAL() { Goto_body(ST_RUNNING, ST_FINAL); }
332 typedef std::list<ui64_t*> DurationElementList_t;
337 ASDCP_NO_COPY_CONSTRUCT(h__Writer);
341 const Dictionary* m_Dict;
342 Kumu::FileWriter m_File;
344 OPAtomHeader m_HeaderPart;
345 Partition m_BodyPart;
346 OPAtomIndexFooter m_FooterPart;
347 ui64_t m_EssenceStart;
349 MaterialPackage* m_MaterialPackage;
350 SourcePackage* m_FilePackage;
352 FileDescriptor* m_EssenceDescriptor;
353 std::list<InterchangeObject*> m_EssenceSubDescriptorList;
355 ui32_t m_FramesWritten;
356 ui64_t m_StreamOffset;
357 ASDCP::FrameBuffer m_CtFrameBuf;
358 h__WriterState m_State;
360 DurationElementList_t m_DurationUpdateList;
362 h__Writer(const Dictionary&);
363 virtual ~h__Writer();
366 void AddSourceClip(const MXF::Rational& EditRate, ui32_t TCFrameRate,
367 const std::string& TrackName, const UL& EssenceUL,
368 const UL& DataDefinition, const std::string& PackageLabel);
369 void AddDMSegment(const MXF::Rational& EditRate, ui32_t TCFrameRate,
370 const std::string& TrackName, const UL& DataDefinition,
371 const std::string& PackageLabel);
372 void AddEssenceDescriptor(const UL& WrappingUL);
373 Result_t CreateBodyPart(const MXF::Rational& EditRate, ui32_t BytesPerEditUnit = 0);
375 // all the above for a single source clip
376 Result_t WriteMXFHeader(const std::string& PackageLabel, const UL& WrappingUL,
377 const std::string& TrackName, const UL& EssenceUL,
378 const UL& DataDefinition, const MXF::Rational& EditRate,
379 ui32_t TCFrameRate, ui32_t BytesPerEditUnit = 0);
381 Result_t WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf,
382 const byte_t* EssenceUL, AESEncContext* Ctx, HMACContext* HMAC);
384 Result_t WriteMXFFooter();
389 // helper class for calculating Integrity Packs, used by WriteEKLVPacket() below.
394 byte_t Data[klv_intpack_size];
397 memset(Data, 0, klv_intpack_size);
402 Result_t CalcValues(const ASDCP::FrameBuffer&, const byte_t* AssetID, ui32_t sequence, HMACContext* HMAC);
403 Result_t TestValues(const ASDCP::FrameBuffer&, const byte_t* AssetID, ui32_t sequence, HMACContext* HMAC);
409 #endif // _AS_DCP_INTERNAL_H_
413 // end AS_DCP_internal.h