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);
227 DefaultLogSink().Error("ASDCP::h__Reader::OpenMXFRead, OpenRead failed\n");
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)
237 // look up frame index node
238 IndexTableSegment::IndexEntry TmpEntry;
240 if ( KM_FAILURE(m_FooterPart.Lookup(FrameNum, TmpEntry)) )
242 DefaultLogSink().Error("Frame value out of range: %u\n", FrameNum);
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;
250 if ( FilePosition != m_LastPosition )
252 m_LastPosition = FilePosition;
253 result = m_File.Seek(FilePosition);
256 if( KM_SUCCESS(result) )
257 result = ReadEKLVPacket(FrameNum, FrameNum + 1, FrameBuf, EssenceUL, Ctx, HMAC);
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)
267 return Read_EKLV_Packet(m_File, *m_Dict, m_HeaderPart, m_Info, m_LastPosition, m_CtFrameBuf,
268 FrameNum, SequenceNum, FrameBuf, EssenceUL, Ctx, HMAC);
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)
276 // look up frame index node
277 IndexTableSegment::IndexEntry TmpEntry;
279 if ( KM_FAILURE(m_FooterPart.Lookup(FrameNum, TmpEntry)) )
281 DefaultLogSink().Error("Frame value out of range: %u\n", FrameNum);
285 // get frame position, temporal offset, and key frame ofset
286 streamOffset = CurrentPartition.BodyOffset + TmpEntry.StreamOffset;
287 temporalOffset = TmpEntry.TemporalOffset;
288 keyFrameOffset = TmpEntry.KeyFrameOffset;
302 class h__ASDCPReader : public MXF::TrackFileReader<OPAtomHeader, OPAtomIndexFooter>
304 ASDCP_NO_COPY_CONSTRUCT(h__ASDCPReader);
308 Partition m_BodyPart;
310 h__ASDCPReader(const Dictionary&);
311 virtual ~h__ASDCPReader();
313 Result_t OpenMXFRead(const char* filename);
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);
324 // state machine for mxf writer
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
333 // implementation of h__WriterState class Goto_* methods
334 #define Goto_body(s1,s2) if ( m_State != (s1) ) \
335 return RESULT_STATE; \
341 ASDCP_NO_COPY_CONSTRUCT(h__WriterState);
344 WriterState_t m_State;
345 h__WriterState() : m_State(ST_BEGIN) {}
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); }
359 typedef std::list<ui64_t*> DurationElementList_t;
364 ASDCP_NO_COPY_CONSTRUCT(h__Writer);
368 const Dictionary* m_Dict;
369 Kumu::FileWriter m_File;
371 OPAtomHeader m_HeaderPart;
372 Partition m_BodyPart;
373 OPAtomIndexFooter m_FooterPart;
374 ui64_t m_EssenceStart;
376 MaterialPackage* m_MaterialPackage;
377 SourcePackage* m_FilePackage;
379 FileDescriptor* m_EssenceDescriptor;
380 std::list<InterchangeObject*> m_EssenceSubDescriptorList;
382 ui32_t m_FramesWritten;
383 ui64_t m_StreamOffset;
384 ASDCP::FrameBuffer m_CtFrameBuf;
385 h__WriterState m_State;
387 DurationElementList_t m_DurationUpdateList;
389 h__Writer(const Dictionary&);
390 virtual ~h__Writer();
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);
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);
408 Result_t WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf,
409 const byte_t* EssenceUL, AESEncContext* Ctx, HMACContext* HMAC);
411 Result_t WriteMXFFooter();
416 // helper class for calculating Integrity Packs, used by WriteEKLVPacket() below.
421 byte_t Data[klv_intpack_size];
424 memset(Data, 0, klv_intpack_size);
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);
436 #endif // _AS_DCP_INTERNAL_H_
440 // end AS_DCP_internal.h