as-02ooooooooooo!
[asdcplib.git] / src / AS_02_PCM.cpp
1 /*
2   Copyright (c) 2011-2012, Robert Scheler, Heiko Sparenberg Fraunhofer IIS, 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_02_PCM.cpp
28   \version $Id$       
29   \brief   AS-02 library, PCM essence reader and writer implementation
30 */
31
32 #include "AS_02_internal.h"
33
34 #include <map>
35 #include <iostream>
36 #include <iomanip>
37
38 //------------------------------------------------------------------------------------------
39
40 static std::string PCM_PACKAGE_LABEL = "File Package: SMPTE 382M clip wrapping of wave audio";
41 static std::string SOUND_DEF_LABEL = "Sound Track";
42
43 static byte_t SNDFMT_CFG_1_UL[16] = { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0b,
44                                       0x04, 0x02, 0x02, 0x10, 0x03, 0x01, 0x01, 0x00 };
45
46 static byte_t SNDFMT_CFG_2_UL[16] = { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0b,
47                                       0x04, 0x02, 0x02, 0x10, 0x03, 0x01, 0x02, 0x00 };
48
49 static byte_t SNDFMT_CFG_3_UL[16] = { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0b,
50                                       0x04, 0x02, 0x02, 0x10, 0x03, 0x01, 0x03, 0x00 };
51
52 //this must be changed because the CBR_frame_size is only   
53 //
54 static ui32_t
55 calc_CBR_frame_size(ASDCP::WriterInfo& Info, const ASDCP::PCM::AudioDescriptor& ADesc)
56 {
57   ui32_t CBR_frame_size = 0;
58
59   if ( Info.EncryptedEssence )
60     {
61       CBR_frame_size =
62         //TODO: correct?
63         /*SMPTE_UL_LENGTH  
64           + MXF_BER_LENGTH
65           + */klv_cryptinfo_size
66         + calc_esv_length(ASDCP::PCM::CalcFrameBufferSize(ADesc), 0)
67         + ( Info.UsesHMAC ? klv_intpack_size : (MXF_BER_LENGTH * 3) );
68     }
69   else
70     {
71       CBR_frame_size = ASDCP::PCM::CalcFrameBufferSize(ADesc);
72     }
73
74   return CBR_frame_size;
75 }
76
77
78 //------------------------------------------------------------------------------------------
79
80
81 class AS_02::PCM::MXFReader::h__Reader : public AS_02::h__Reader
82 {
83   ASDCP_NO_COPY_CONSTRUCT(h__Reader);
84   h__Reader();
85
86 public:
87   ASDCP::PCM::AudioDescriptor m_ADesc;
88
89   h__Reader(const Dictionary& d) : AS_02::h__Reader(d) {}
90   ~h__Reader() {}
91   ASDCP::Result_t    OpenRead(const char*);
92   ASDCP::Result_t    ReadFrame(ui32_t, ASDCP::PCM::FrameBuffer&, ASDCP::AESDecContext*, ASDCP::HMACContext*);
93
94   
95   Result_t OpenMXFRead(const char* filename);
96   // positions file before reading
97   Result_t ReadEKLVFrame(ui32_t FrameNum, ASDCP::FrameBuffer& FrameBuf,
98                          const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC);
99
100   // reads from current position
101   Result_t ReadEKLVPacket(ui32_t FrameNum, ui32_t SequenceNum, ASDCP::FrameBuffer& FrameBuf,
102                           const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC);
103
104
105 };
106
107
108 //
109 //
110 ASDCP::Result_t
111 AS_02::PCM::MXFReader::h__Reader::OpenRead(const char* filename)
112 {
113   Result_t result = OpenMXFRead(filename);
114
115   if( ASDCP_SUCCESS(result) )
116     {
117       InterchangeObject* Object;
118       if ( ASDCP_SUCCESS(m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(WaveAudioDescriptor), &Object)) )
119         {
120           assert(Object);
121           result = MD_to_PCM_ADesc((ASDCP::MXF::WaveAudioDescriptor*)Object, m_ADesc);
122         }
123     }
124
125   // check for sample/frame rate sanity
126   if ( ASDCP_SUCCESS(result)
127        && m_ADesc.EditRate != EditRate_24
128        && m_ADesc.EditRate != EditRate_25
129        && m_ADesc.EditRate != EditRate_30
130        && m_ADesc.EditRate != EditRate_48
131        && m_ADesc.EditRate != EditRate_50
132        && m_ADesc.EditRate != EditRate_60
133        && m_ADesc.EditRate != EditRate_23_98 )
134     {
135       DefaultLogSink().Error("PCM file EditRate is not a supported value: %d/%d\n", // lu
136                              m_ADesc.EditRate.Numerator, m_ADesc.EditRate.Denominator);
137
138       // oh, they gave us the audio sampling rate instead, assume 24/1
139       if ( m_ADesc.EditRate == SampleRate_48k )
140         {
141           DefaultLogSink().Warn("adjusting EditRate to 24/1\n"); 
142           m_ADesc.EditRate = EditRate_24;
143         }
144       else
145         {
146           // or we just drop the hammer
147           return RESULT_FORMAT;
148         }
149     }
150
151   if( ASDCP_SUCCESS(result) )
152     result = InitMXFIndex();
153
154   if( ASDCP_SUCCESS(result) )
155     result = InitInfo();
156
157   // TODO: test file for sane CBR index BytesPerEditUnit
158
159   return result;
160 }
161
162
163 //
164 //
165 ASDCP::Result_t
166 AS_02::PCM::MXFReader::h__Reader::ReadFrame(ui32_t FrameNum, ASDCP::PCM::FrameBuffer& FrameBuf,
167                                             ASDCP::AESDecContext* Ctx, ASDCP::HMACContext* HMAC)
168 {
169   if ( ! m_File.IsOpen() )
170     return RESULT_INIT;
171
172   assert(m_Dict);
173   return ReadEKLVFrame(FrameNum, FrameBuf, m_Dict->ul(MDD_WAVEssence), Ctx, HMAC);
174 }
175
176
177 AS_02::PCM::MXFReader::MXFReader()
178 {
179   m_Reader = new h__Reader(DefaultCompositeDict());
180 }
181
182
183 AS_02::PCM::MXFReader::~MXFReader()
184 {
185   if ( m_Reader && m_Reader->m_File.IsOpen() )
186     m_Reader->Close();
187 }
188
189 // Warning: direct manipulation of MXF structures can interfere
190 // with the normal operation of the wrapper.  Caveat emptor!
191 //
192 ASDCP::MXF::OPAtomHeader&
193 AS_02::PCM::MXFReader::OPAtomHeader()
194 {
195   if ( m_Reader.empty() )
196     {
197       assert(g_OPAtomHeader);
198       return *g_OPAtomHeader;
199     }
200
201   return m_Reader->m_HeaderPart;
202 }
203
204 // Warning: direct manipulation of MXF structures can interfere
205 // with the normal operation of the wrapper.  Caveat emptor!
206 //
207 /*
208 ASDCP::MXF::OPAtomIndexFooter&
209 AS_02::PCM::MXFReader::OPAtomIndexFooter()
210 {
211   if ( m_Reader.empty() )
212     {
213       assert(g_OPAtomIndexFooter);
214       return *g_OPAtomIndexFooter;
215     }
216
217   return m_Reader->m_FooterPart;
218 }
219 */
220
221 // Open the file for reading. The file must exist. Returns error if the
222 // operation cannot be completed.
223 ASDCP::Result_t
224 AS_02::PCM::MXFReader::OpenRead(const char* filename) const
225 {
226   return m_Reader->OpenRead(filename);
227 }
228
229 // Reads a frame of essence from the MXF file. If the optional AESEncContext
230 // argument is present, the essence is decrypted after reading. If the MXF
231 // file is encrypted and the AESDecContext argument is NULL, the frame buffer
232 // will contain the ciphertext frame data.
233 ASDCP::Result_t
234 AS_02::PCM::MXFReader::ReadFrame(ui32_t FrameNum, ASDCP::PCM::FrameBuffer& FrameBuf,
235                                  ASDCP::AESDecContext* Ctx, ASDCP::HMACContext* HMAC) const
236 {
237   if ( m_Reader && m_Reader->m_File.IsOpen() )
238     return m_Reader->ReadFrame(FrameNum, FrameBuf, Ctx, HMAC);
239
240   return RESULT_INIT;
241 }
242
243
244 // Fill the struct with the values from the file's header.
245 // Returns RESULT_INIT if the file is not open.
246 ASDCP::Result_t
247 AS_02::PCM::MXFReader::FillAudioDescriptor(ASDCP::PCM::AudioDescriptor& ADesc) const
248 {
249   if ( m_Reader && m_Reader->m_File.IsOpen() )
250     {
251       ADesc = m_Reader->m_ADesc;
252       return RESULT_OK;
253     }
254
255   return RESULT_INIT;
256 }
257
258 // Fill the struct with the values from the file's header.
259 // Returns RESULT_INIT if the file is not open.
260 ASDCP::Result_t
261 AS_02::PCM::MXFReader::FillWriterInfo(WriterInfo& Info) const
262 {
263   if ( m_Reader && m_Reader->m_File.IsOpen() )
264     {
265       Info = m_Reader->m_Info;
266       return RESULT_OK;
267     }
268
269   return RESULT_INIT;
270 }
271
272 //
273 void
274 AS_02::PCM::MXFReader::DumpHeaderMetadata(FILE* stream) const
275 {
276   if ( m_Reader && m_Reader->m_File.IsOpen() )
277     m_Reader->m_HeaderPart.Dump(stream);
278 }
279
280
281 //
282 void
283 AS_02::PCM::MXFReader::DumpIndex(FILE* stream) const
284 {
285   if ( m_Reader->m_File.IsOpen() )
286     m_Reader->m_FooterPart.Dump(stream);
287 }
288
289
290 //------------------------------------------------------------------------------------------
291
292 //
293 class AS_02::PCM::MXFWriter::h__Writer : public AS_02::h__Writer
294 {
295   ASDCP_NO_COPY_CONSTRUCT(h__Writer);
296   h__Writer();
297
298 public:
299   ASDCP::PCM::AudioDescriptor m_ADesc;
300   byte_t          m_EssenceUL[SMPTE_UL_LENGTH];
301   ui64_t                        m_KLV_start;
302
303   h__Writer(const Dictionary& d) : AS_02::h__Writer(d), m_KLV_start(0){
304     memset(m_EssenceUL, 0, SMPTE_UL_LENGTH);
305
306   }
307
308   ~h__Writer(){}
309
310   Result_t OpenWrite(const char*, ui32_t HeaderSize);
311   Result_t SetSourceStream(const ASDCP::PCM::AudioDescriptor&);
312   Result_t WriteFrame(const FrameBuffer&, ASDCP::AESEncContext* = 0, ASDCP::HMACContext* = 0);
313
314   Result_t Finalize();
315
316   //void AddSourceClip(const MXF::Rational& EditRate, ui32_t TCFrameRate,
317   // const std::string& TrackName, const UL& EssenceUL,
318   // const UL& DataDefinition, const std::string& PackageLabel);
319   //void AddDMSegment(const MXF::Rational& EditRate, ui32_t TCFrameRate,
320   // const std::string& TrackName, const UL& DataDefinition,
321   // const std::string& PackageLabel);
322   //void AddEssenceDescriptor(const UL& WrappingUL);
323   //Result_t CreateBodyPart(const MXF::Rational& EditRate, ui32_t BytesPerEditUnit = 0);
324
325   ////new method to create BodyPartition for essence and index
326   //Result_t CreateBodyPartPair();
327   ////new method to finalize BodyPartion(index)
328   //Result_t CompleteIndexBodyPart();
329
330   // reimplement these functions in AS_02_PCM to support modifications for AS-02
331   Result_t WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf,
332                            const byte_t* EssenceUL, AESEncContext* Ctx, HMACContext* HMAC);
333   Result_t WriteMXFFooter();
334
335 };
336
337 // Open the file for writing. The file must not exist. Returns error if
338 // the operation cannot be completed.
339 ASDCP::Result_t
340 AS_02::PCM::MXFWriter::h__Writer::OpenWrite(const char* filename, ui32_t HeaderSize)
341 {
342   if ( ! m_State.Test_BEGIN() )
343     return RESULT_STATE;
344
345   Result_t result = m_File.OpenWrite(filename);
346
347   if ( ASDCP_SUCCESS(result) )
348     {
349       m_HeaderSize = HeaderSize;
350       m_EssenceDescriptor = new WaveAudioDescriptor(m_Dict);
351       result = m_State.Goto_INIT();
352     }
353
354   return result;
355 }
356
357
358 // Automatically sets the MXF file's metadata from the WAV parser info.
359 ASDCP::Result_t
360 AS_02::PCM::MXFWriter::h__Writer::SetSourceStream(const ASDCP::PCM::AudioDescriptor& ADesc)
361 {
362   if ( ! m_State.Test_INIT() )
363     return RESULT_STATE;
364
365   if ( ADesc.EditRate != EditRate_24
366        && ADesc.EditRate != EditRate_25
367        && ADesc.EditRate != EditRate_30
368        && ADesc.EditRate != EditRate_48
369        && ADesc.EditRate != EditRate_50
370        && ADesc.EditRate != EditRate_60
371        && ADesc.EditRate != EditRate_23_98 )
372     {
373       DefaultLogSink().Error("AudioDescriptor.EditRate is not a supported value: %d/%d\n",
374                              ADesc.EditRate.Numerator, ADesc.EditRate.Denominator);
375       return RESULT_RAW_FORMAT;
376     }
377
378   if ( ADesc.AudioSamplingRate != SampleRate_48k && ADesc.AudioSamplingRate != SampleRate_96k )
379     {
380       DefaultLogSink().Error("AudioDescriptor.AudioSamplingRate is not 48000/1 or 96000/1: %d/%d\n",
381                              ADesc.AudioSamplingRate.Numerator, ADesc.AudioSamplingRate.Denominator);
382       return RESULT_RAW_FORMAT;
383     }
384
385   assert(m_Dict);
386   m_ADesc = ADesc;
387
388   Result_t result = PCM_ADesc_to_MD(m_ADesc, (WaveAudioDescriptor*)m_EssenceDescriptor);
389
390   if ( ASDCP_SUCCESS(result) )
391     {
392       memcpy(m_EssenceUL, m_Dict->ul(MDD_WAVEssence), SMPTE_UL_LENGTH);
393       //SMPTE 382M-2007: ByteNo. 15 - 02h - Wave Clip-Wrapped Element
394       m_EssenceUL[SMPTE_UL_LENGTH-2] = 2; // 02h - Wave Clip-Wrapped Element
395       m_EssenceUL[SMPTE_UL_LENGTH-1] = 1; // first (and only) essence container
396       result = m_State.Goto_READY();
397     }
398
399   if ( ASDCP_SUCCESS(result) )
400     {
401       ui32_t TCFrameRate = ( m_ADesc.EditRate == EditRate_23_98  ) ? 24 : m_ADesc.EditRate.Numerator;
402
403       result = WriteMXFHeader(PCM_PACKAGE_LABEL, UL(m_Dict->ul(MDD_WAVWrapping)),
404                               SOUND_DEF_LABEL, UL(m_EssenceUL), UL(m_Dict->ul(MDD_SoundDataDef)),
405                               m_ADesc.EditRate, TCFrameRate, calc_CBR_frame_size(m_Info, m_ADesc));
406     }
407
408   return result;
409 }
410
411
412 //
413 //
414 ASDCP::Result_t
415 AS_02::PCM::MXFWriter::h__Writer::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx,
416                                              HMACContext* HMAC)
417 {
418   Result_t result = RESULT_OK;
419
420   if ( m_State.Test_READY() )
421     result = m_State.Goto_RUNNING(); // first time through
422
423   if ( ASDCP_SUCCESS(result) )
424     result = WriteEKLVPacket(FrameBuf, m_EssenceUL, Ctx, HMAC);
425
426   if ( ASDCP_SUCCESS(result) )
427     m_FramesWritten++;
428
429   return result;
430 }
431
432 // Closes the MXF file, writing the index and other closing information.
433 //
434 ASDCP::Result_t
435 AS_02::PCM::MXFWriter::h__Writer::Finalize()
436 {
437   if ( ! m_State.Test_RUNNING() )
438     return RESULT_STATE;
439
440   m_State.Goto_FINAL();
441
442   return WriteMXFFooter();
443 }
444
445
446 //------------------------------------------------------------------------------------------
447 //
448
449
450
451 AS_02::PCM::MXFWriter::MXFWriter()
452 {
453 }
454
455 AS_02::PCM::MXFWriter::~MXFWriter()
456 {
457 }
458
459 // Warning: direct manipulation of MXF structures can interfere
460 // with the normal operation of the wrapper.  Caveat emptor!
461 //
462 ASDCP::MXF::OPAtomHeader&
463 AS_02::PCM::MXFWriter::OPAtomHeader()
464 {
465   if ( m_Writer.empty() )
466     {
467       assert(g_OPAtomHeader);
468       return *g_OPAtomHeader;
469     }
470
471   return m_Writer->m_HeaderPart;
472 }
473
474 // Warning: direct manipulation of MXF structures can interfere
475 // with the normal operation of the wrapper.  Caveat emptor!
476 //
477 /*
478 ASDCP::MXF::OPAtomIndexFooter&
479 AS_02::PCM::MXFWriter::OPAtomIndexFooter()
480 {
481   if ( m_Writer.empty() )
482     {
483       assert(g_OPAtomIndexFooter);
484       return *g_OPAtomIndexFooter;
485     }
486
487   return m_Writer->m_FooterPart;
488 }
489 */
490
491 // Open the file for writing. The file must not exist. Returns error if
492 // the operation cannot be completed.
493 ASDCP::Result_t
494 AS_02::PCM::MXFWriter::OpenWrite(const char* filename, const WriterInfo& Info,
495                                  const ASDCP::PCM::AudioDescriptor& ADesc, ui32_t HeaderSize)
496 {
497   m_Writer = new h__Writer(DefaultSMPTEDict());
498   m_Writer->m_Info = Info;
499
500   Result_t result = m_Writer->OpenWrite(filename, HeaderSize);
501
502   if ( ASDCP_SUCCESS(result) )
503     result = m_Writer->SetSourceStream(ADesc);
504
505   if ( ASDCP_FAILURE(result) )
506     m_Writer.release();
507
508   return result;
509 }
510
511 // Writes a frame of essence to the MXF file. If the optional AESEncContext
512 // argument is present, the essence is encrypted prior to writing.
513 // Fails if the file is not open, is finalized, or an operating system
514 // error occurs.
515 ASDCP::Result_t
516 AS_02::PCM::MXFWriter::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
517 {
518   if ( m_Writer.empty() )
519     return RESULT_INIT;
520
521   return m_Writer->WriteFrame(FrameBuf, Ctx, HMAC);
522 }
523
524 // Closes the MXF file, writing the index and other closing information.
525 ASDCP::Result_t
526 AS_02::PCM::MXFWriter::Finalize()
527 {
528   if ( m_Writer.empty() )
529     return RESULT_INIT;
530
531   return m_Writer->Finalize();
532 }
533
534 // standard method of opening an MXF file for read
535 Result_t
536 AS_02::PCM::MXFReader::h__Reader::OpenMXFRead(const char* filename)
537 {
538   m_LastPosition = 0;
539   AS_02::MXF::OP1aIndexBodyPartion* pCurrentBodyPartIndex = NULL;
540   Partition* pPart = NULL;
541   ui64_t EssenceStart = 0;
542   Result_t result = m_File.OpenRead(filename);
543
544   if ( ASDCP_SUCCESS(result) )
545     result = m_HeaderPart.InitFromFile(m_File);
546
547   if ( ASDCP_SUCCESS(result) )
548     {
549       ui32_t partition_size = m_HeaderPart.m_RIP.PairArray.size();
550
551       if ( partition_size > 3 )
552         {
553           //for all entry except the first and the last(header&footer)
554           Array<RIP::Pair>::iterator r_i = m_HeaderPart.m_RIP.PairArray.begin();
555           r_i++;
556           ui32_t i=2;
557
558           while ( r_i != m_HeaderPart.m_RIP.PairArray.end() && i < partition_size )
559             {
560               m_File.Seek((*r_i).ByteOffset);
561               pPart = new Partition(this->m_Dict);
562               result = pPart->InitFromFile(m_File);
563
564               // TODO:: expect Index partition
565               delete pPart;
566               m_File.Seek((*r_i).ByteOffset);
567               pCurrentBodyPartIndex = new AS_02::MXF::OP1aIndexBodyPartion(this->m_Dict);
568               pCurrentBodyPartIndex->m_Lookup = &m_HeaderPart.m_Primer;
569               result = pCurrentBodyPartIndex->InitFromFile(m_File);
570               
571               if ( ASDCP_FAILURE(result) )
572                 {
573                   break;
574                 }
575
576               r_i++; i++;
577
578               m_File.Seek((*r_i).ByteOffset);
579               pPart = new Partition(this->m_Dict);
580               result = pPart->InitFromFile(m_File);
581               EssenceStart = m_File.Tell();
582
583               if ( ASDCP_FAILURE(result) )
584                 {
585                   break;
586                 }
587
588               if(i==3)
589                 {
590                   m_EssenceStart = EssenceStart;
591                   m_pCurrentBodyPartition = pPart;
592                   m_pCurrentIndexPartition = pCurrentBodyPartIndex;
593                 }
594           
595               m_BodyPartList.push_back(pCurrentBodyPartIndex);
596               m_BodyPartList.push_back(pPart);
597               r_i++; i++;
598             }
599         }
600     }
601
602   return result;
603 }
604
605 // standard method of reading a plaintext or encrypted frame
606 Result_t
607 AS_02::PCM::MXFReader::h__Reader::ReadEKLVFrame(ui32_t FrameNum, ASDCP::FrameBuffer& FrameBuf,
608                                                 const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC)
609 {
610   Result_t result = RESULT_OK;
611   // look up frame index node
612   IndexTableSegment::IndexEntry TmpEntry;
613   ui32_t i = 0;
614
615   if(m_pCurrentIndexPartition == NULL)
616     {
617       m_pCurrentIndexPartition = dynamic_cast<AS_02::MXF::OP1aIndexBodyPartion*> (m_BodyPartList.at(i));
618       m_pCurrentBodyPartition = m_BodyPartList.at(i+1);
619     }           
620   else
621     {
622       return RESULT_FORMAT; //return error
623     }
624                                 
625   if(m_pCurrentIndexPartition == NULL)
626     {
627       return RESULT_FORMAT; //return error\r
628     }
629
630   m_pCurrentIndexPartition->PCMIndexLookup(FrameNum,TmpEntry);
631   // get frame position and go read the frame's key and length
632   Kumu::fpos_t FilePosition = this->m_EssenceStart + TmpEntry.StreamOffset;
633
634   if ( FilePosition != m_LastPosition )
635     {
636       m_LastPosition = FilePosition;
637       result = m_File.Seek(FilePosition);
638     }
639
640   if( ASDCP_SUCCESS(result) )
641     result = ReadEKLVPacket(FrameNum, FrameNum + 1, FrameBuf, EssenceUL, Ctx, HMAC);
642
643   return result;
644 }
645
646 Result_t
647 AS_02::PCM::MXFReader::h__Reader::ReadEKLVPacket(ui32_t FrameNum, ui32_t SequenceNum, ASDCP::FrameBuffer& FrameBuf,
648                                                  const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC)
649 {
650   KLReader Reader;
651
652   //save position to read KLV packet
653   Kumu::fpos_t SaveFilePosition = m_File.Tell();
654   //Seek backward to KLV start
655   m_File.Seek(this->m_EssenceStart);
656   Result_t result = Reader.ReadKLFromFile(m_File);
657   //set old position
658   m_File.Seek(SaveFilePosition);
659
660   if ( ASDCP_FAILURE(result) )
661     return result;
662
663   UL Key(Reader.Key());
664   ui64_t PacketLength = Reader.Length();
665   m_LastPosition = m_LastPosition + PacketLength;
666   if(FrameNum = 0){
667     m_LastPosition+= Reader.KLLength();
668   }
669   assert(m_Dict);
670
671   //TODO: for AS_02 PCM - not in the dictionary
672
673   static const byte_t WaveClipEssenceUL_Data[SMPTE_UL_LENGTH] =\r
674     { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x02, 0x01, 0x01,\r
675       0x0d, 0x01, 0x03, 0x01, 0x16, 0x01, 0x02, 0x01 };
676
677   \r
678     if( memcmp(Key.Value(), WaveClipEssenceUL_Data, SMPTE_UL_LENGTH) == 0 ){
679       byte_t WaveFrameEssenceUL_Data[SMPTE_UL_LENGTH] =\r
680         { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x02, 0x01, 0x01,\r
681           0x0d, 0x01, 0x03, 0x01, 0x16, 0x01, 0x01, 0x01 };
682
683       Key.Set(WaveFrameEssenceUL_Data);
684     }
685
686
687     if ( memcmp(Key.Value(), m_Dict->ul(MDD_CryptEssence), Key.Size() - 1) == 0 )  // ignore the stream numbers
688       {
689         if ( ! m_Info.EncryptedEssence )
690           {
691             DefaultLogSink().Error("EKLV packet found, no Cryptographic Context in header.\n");
692             return RESULT_FORMAT;
693           }
694
695         // read encrypted triplet value into internal buffer
696         assert(PacketLength <= 0xFFFFFFFFL);
697         m_CtFrameBuf.Capacity((ui32_t) PacketLength);
698         ui32_t read_count;
699         result = m_File.Read(m_CtFrameBuf.Data(), (ui32_t) PacketLength,
700                              &read_count);
701
702         if ( ASDCP_FAILURE(result) )
703           return result;
704
705         if ( read_count != PacketLength )
706           {
707             DefaultLogSink().Error("read length is smaller than EKLV packet length.\n");
708             return RESULT_FORMAT;
709           }
710
711         m_CtFrameBuf.Size((ui32_t) PacketLength);
712
713         // should be const but mxflib::ReadBER is not
714         byte_t* ess_p = m_CtFrameBuf.Data();
715
716         // read context ID length
717         if ( ! Kumu::read_test_BER(&ess_p, UUIDlen) )
718           return RESULT_FORMAT;
719
720         // test the context ID
721         if ( memcmp(ess_p, m_Info.ContextID, UUIDlen) != 0 )
722           {
723             DefaultLogSink().Error("Packet's Cryptographic Context ID does not match the header.\n");
724             return RESULT_FORMAT;
725           }
726         ess_p += UUIDlen;
727
728         // read PlaintextOffset length
729         if ( ! Kumu::read_test_BER(&ess_p, sizeof(ui64_t)) )
730           return RESULT_FORMAT;
731
732         ui32_t PlaintextOffset = (ui32_t)KM_i64_BE(Kumu::cp2i<ui64_t>(ess_p));
733         ess_p += sizeof(ui64_t);
734
735         // read essence UL length
736         if ( ! Kumu::read_test_BER(&ess_p, SMPTE_UL_LENGTH) )
737           return RESULT_FORMAT;
738
739         // test essence UL
740         if ( memcmp(ess_p, EssenceUL, SMPTE_UL_LENGTH - 1) != 0 ) // ignore the stream number
741           {
742             char strbuf[IntBufferLen];
743             const MDDEntry* Entry = m_Dict->FindUL(Key.Value());
744             if ( Entry == 0 )
745               DefaultLogSink().Warn("Unexpected Essence UL found: %s.\n", Key.EncodeString(strbuf, IntBufferLen));
746             else
747               DefaultLogSink().Warn("Unexpected Essence UL found: %s.\n", Entry->name);
748             return RESULT_FORMAT;
749           }
750         ess_p += SMPTE_UL_LENGTH;
751
752         // read SourceLength length
753         if ( ! Kumu::read_test_BER(&ess_p, sizeof(ui64_t)) )
754           return RESULT_FORMAT;
755
756         ui32_t SourceLength = (ui32_t)KM_i64_BE(Kumu::cp2i<ui64_t>(ess_p));
757         ess_p += sizeof(ui64_t);
758         assert(SourceLength);
759
760         if ( FrameBuf.Capacity() < SourceLength )
761           {
762             DefaultLogSink().Error("FrameBuf.Capacity: %u SourceLength: %u\n", FrameBuf.Capacity(), SourceLength);
763             return RESULT_SMALLBUF;
764           }
765
766         ui32_t esv_length = calc_esv_length(SourceLength, PlaintextOffset);
767
768         // read ESV length
769         if ( ! Kumu::read_test_BER(&ess_p, esv_length) )
770           {
771             DefaultLogSink().Error("read_test_BER did not return %u\n", esv_length);
772             return RESULT_FORMAT;
773           }
774
775         ui32_t tmp_len = esv_length + (m_Info.UsesHMAC ? klv_intpack_size : 0);
776
777         if ( PacketLength < tmp_len )
778           {
779             DefaultLogSink().Error("Frame length is larger than EKLV packet length.\n");
780             return RESULT_FORMAT;
781           }
782
783         if ( Ctx )
784           {
785             // wrap the pointer and length as a FrameBuffer for use by
786             // DecryptFrameBuffer() and TestValues()
787             FrameBuffer TmpWrapper;
788             TmpWrapper.SetData(ess_p, tmp_len);
789             TmpWrapper.Size(tmp_len);
790             TmpWrapper.SourceLength(SourceLength);
791             TmpWrapper.PlaintextOffset(PlaintextOffset);
792
793             result = DecryptFrameBuffer(TmpWrapper, FrameBuf, Ctx);
794             FrameBuf.FrameNumber(FrameNum);
795
796             // detect and test integrity pack
797             if ( ASDCP_SUCCESS(result) && m_Info.UsesHMAC && HMAC )
798               {
799                 IntegrityPack IntPack;
800                 result = IntPack.TestValues(TmpWrapper, m_Info.AssetUUID, SequenceNum, HMAC);
801               }
802           }
803         else // return ciphertext to caller
804           {
805             if ( FrameBuf.Capacity() < tmp_len )
806               {
807                 char intbuf[IntBufferLen];
808                 DefaultLogSink().Error("FrameBuf.Capacity: %u FrameLength: %s\n",
809                                        FrameBuf.Capacity(), ui64sz(PacketLength, intbuf));
810                 return RESULT_SMALLBUF;
811               }
812
813             memcpy(FrameBuf.Data(), ess_p, tmp_len);
814             FrameBuf.Size(tmp_len);
815             FrameBuf.FrameNumber(FrameNum);
816             FrameBuf.SourceLength(SourceLength);
817             FrameBuf.PlaintextOffset(PlaintextOffset);
818           }
819       }
820     else if ( memcmp(Key.Value(), EssenceUL, Key.Size() - 1) == 0 ) // ignore the stream number
821       { // read plaintext frame
822         if ( FrameBuf.Capacity() < PacketLength )
823           {
824             char intbuf[IntBufferLen];
825             DefaultLogSink().Error("FrameBuf.Capacity: %u FrameLength: %s\n",
826                                    FrameBuf.Capacity(), ui64sz(PacketLength, intbuf));
827             return RESULT_SMALLBUF;
828           }
829
830         // read the data into the supplied buffer
831         ui32_t read_count;
832         assert(PacketLength <= 0xFFFFFFFFL);
833         result = m_File.Read(FrameBuf.Data(), (ui32_t) PacketLength, &read_count);
834
835         if ( ASDCP_FAILURE(result) )
836           return result;
837
838         if ( read_count != PacketLength )
839           {
840             char intbuf1[IntBufferLen];
841             char intbuf2[IntBufferLen];
842             DefaultLogSink().Error("read_count: %s != FrameLength: %s\n",
843                                    ui64sz(read_count, intbuf1),
844                                    ui64sz(PacketLength, intbuf2) );
845
846             return RESULT_READFAIL;
847           }
848
849         FrameBuf.FrameNumber(FrameNum);
850         FrameBuf.Size(read_count);
851       }
852     else
853       {
854         char strbuf[IntBufferLen];
855         const MDDEntry* Entry = m_Dict->FindUL(Key.Value());
856         if ( Entry == 0 )
857           DefaultLogSink().Warn("Unexpected Essence UL found: %s.\n", Key.EncodeString(strbuf, IntBufferLen));
858         else
859           DefaultLogSink().Warn("Unexpected Essence UL found: %s.\n", Entry->name);
860         return RESULT_FORMAT;
861       }
862
863     return result;
864 }
865
866 // standard method of writing the header and footer of a completed MXF file
867 //
868 Result_t
869 AS_02::PCM::MXFWriter::h__Writer::WriteMXFFooter()
870 {
871   // Set top-level file package correctly for OP-Atom
872
873   //  m_MPTCSequence->Duration = m_MPTimecode->Duration = m_MPClSequence->Duration = m_MPClip->Duration = 
874   //    m_FPTCSequence->Duration = m_FPTimecode->Duration = m_FPClSequence->Duration = m_FPClip->Duration = 
875
876   //
877   m_CurrentIndexBodyPartition->m_FramesWritten = m_FramesWritten;
878   m_CurrentIndexBodyPartition->PCMSetIndexParamsCBR(m_CurrentIndexBodyPartition->m_BytesPerEditUnit+24,m_CurrentIndexBodyPartition->m_BytesPerEditUnit);
879   CompleteIndexBodyPart();
880
881   DurationElementList_t::iterator dli = m_DurationUpdateList.begin();
882
883   for (; dli != m_DurationUpdateList.end(); dli++ )
884     **dli = m_FramesWritten;
885
886   m_EssenceDescriptor->ContainerDuration = m_FramesWritten;
887   m_FooterPart.PreviousPartition = m_HeaderPart.m_RIP.PairArray.back().ByteOffset;
888
889   Kumu::fpos_t here = m_File.Tell();
890   m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(0, here)); // Last RIP Entry
891   m_HeaderPart.FooterPartition = here;
892
893   assert(m_Dict);
894   // re-label the partition
895   UL OP1aUL(m_Dict->ul(MDD_OP1a));
896   m_HeaderPart.OperationalPattern = OP1aUL;
897   m_HeaderPart.m_Preface->OperationalPattern = m_HeaderPart.OperationalPattern;
898
899   m_FooterPart.OperationalPattern = m_HeaderPart.OperationalPattern;
900   m_FooterPart.EssenceContainers = m_HeaderPart.EssenceContainers;
901   m_FooterPart.FooterPartition = here;
902   m_FooterPart.ThisPartition = here;
903
904   Result_t result = m_FooterPart.WriteToFile(m_File, m_FramesWritten);
905
906   if ( ASDCP_SUCCESS(result) )
907     result = m_HeaderPart.m_RIP.WriteToFile(m_File);
908
909   if ( ASDCP_SUCCESS(result) )
910     result = m_File.Seek(0);
911
912   if ( ASDCP_SUCCESS(result) )
913     result = m_HeaderPart.WriteToFile(m_File, m_HeaderSize);
914
915   //update the value of FooterPartition in all Partitions
916   std::vector<Partition*>::iterator bl_i = this->m_BodyPartList.begin();
917   for (; bl_i != m_BodyPartList.end(); bl_i++ ){
918     (*bl_i)->FooterPartition =  m_FooterPart.ThisPartition;
919     if ( ASDCP_SUCCESS(result) )
920       result = m_File.Seek((*bl_i)->ThisPartition);
921     if ( ASDCP_SUCCESS(result) ){
922       UL BodyUL(m_Dict->ul(MDD_ClosedCompleteBodyPartition));
923       result = (*bl_i)->WriteToFile(m_File, BodyUL);
924     }
925   } 
926
927   m_File.Close();
928   return result;
929 }
930
931 // standard method of writing a plaintext or encrypted frame
932 Result_t
933 AS_02::PCM::MXFWriter::h__Writer::WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf, const byte_t* EssenceUL,
934                                                   AESEncContext* Ctx, HMACContext* HMAC)
935 {
936   Result_t result = RESULT_OK;
937   IntegrityPack IntPack;
938         
939   const ui32_t AS_02_PCM_MXF_BER_LENGTH = 8;
940   //TODO: AS_02_PCM_MXF_BER_LENGTH - customize for EncryptedEssence 
941
942   byte_t overhead[128];
943   Kumu::MemIOWriter Overhead(overhead, 128);
944   assert(m_Dict);
945
946   if ( FrameBuf.Size() == 0 )
947     {
948       DefaultLogSink().Error("Cannot write empty frame buffer\n");
949       return RESULT_EMPTY_FB;
950     }
951
952   if ( m_Info.EncryptedEssence )
953     {
954       if ( ! Ctx )
955         return RESULT_CRYPT_CTX;
956
957       if ( m_Info.UsesHMAC && ! HMAC )
958         return RESULT_HMAC_CTX;
959
960       if ( FrameBuf.PlaintextOffset() > FrameBuf.Size() )
961         return RESULT_LARGE_PTO;
962
963       // encrypt the essence data (create encrypted source value)
964       result = EncryptFrameBuffer(FrameBuf, m_CtFrameBuf, Ctx);
965
966       // create HMAC
967       if ( ASDCP_SUCCESS(result) && m_Info.UsesHMAC )
968         result = IntPack.CalcValues(m_CtFrameBuf, m_Info.AssetUUID, m_FramesWritten + 1, HMAC);
969
970       if ( ASDCP_SUCCESS(result) )
971         { // write UL
972           Overhead.WriteRaw(m_Dict->ul(MDD_CryptEssence), SMPTE_UL_LENGTH);
973
974           // construct encrypted triplet header
975           ui32_t ETLength = klv_cryptinfo_size + m_CtFrameBuf.Size();
976           ui32_t BER_length = MXF_BER_LENGTH;
977
978           if ( m_Info.UsesHMAC )
979             ETLength += klv_intpack_size;
980           else
981             ETLength += (MXF_BER_LENGTH * 3); // for empty intpack
982
983           if ( ETLength > 0x00ffffff ) // Need BER integer longer than MXF_BER_LENGTH bytes
984             {
985               BER_length = Kumu::get_BER_length_for_value(ETLength);
986
987               // the packet is longer by the difference in expected vs. actual BER length
988               ETLength += BER_length - MXF_BER_LENGTH;
989
990               if ( BER_length == 0 )
991                 result = RESULT_KLV_CODING;
992             }
993
994           if ( ASDCP_SUCCESS(result) )
995             {
996               if ( ! ( Overhead.WriteBER(ETLength, BER_length)                      // write encrypted triplet length
997                        && Overhead.WriteBER(UUIDlen, MXF_BER_LENGTH)                // write ContextID length
998                        && Overhead.WriteRaw(m_Info.ContextID, UUIDlen)              // write ContextID
999                        && Overhead.WriteBER(sizeof(ui64_t), MXF_BER_LENGTH)         // write PlaintextOffset length
1000                        && Overhead.WriteUi64BE(FrameBuf.PlaintextOffset())          // write PlaintextOffset
1001                        && Overhead.WriteBER(SMPTE_UL_LENGTH, MXF_BER_LENGTH)        // write essence UL length
1002                        && Overhead.WriteRaw((byte_t*)EssenceUL, SMPTE_UL_LENGTH)    // write the essence UL
1003                        && Overhead.WriteBER(sizeof(ui64_t), MXF_BER_LENGTH)         // write SourceLength length
1004                        && Overhead.WriteUi64BE(FrameBuf.Size())                     // write SourceLength
1005                        && Overhead.WriteBER(m_CtFrameBuf.Size(), BER_length) ) )    // write ESV length
1006                 {
1007                   result = RESULT_KLV_CODING;
1008                 }
1009             }
1010
1011           if ( ASDCP_SUCCESS(result) )
1012             result = m_File.Writev(Overhead.Data(), Overhead.Length());
1013         }
1014
1015       if ( ASDCP_SUCCESS(result) )
1016         {
1017           m_StreamOffset += Overhead.Length();
1018           // write encrypted source value
1019           result = m_File.Writev((byte_t*)m_CtFrameBuf.RoData(), m_CtFrameBuf.Size());
1020         }
1021
1022       if ( ASDCP_SUCCESS(result) )
1023         {
1024           m_StreamOffset += m_CtFrameBuf.Size();
1025
1026           byte_t hmoverhead[512];
1027           Kumu::MemIOWriter HMACOverhead(hmoverhead, 512);
1028
1029           // write the HMAC
1030           if ( m_Info.UsesHMAC )
1031             {
1032               HMACOverhead.WriteRaw(IntPack.Data, klv_intpack_size);
1033             }
1034           else
1035             { // we still need the var-pack length values if the intpack is empty
1036               for ( ui32_t i = 0; i < 3 ; i++ )
1037                 HMACOverhead.WriteBER(0, MXF_BER_LENGTH);
1038             }
1039
1040           // write HMAC
1041           result = m_File.Writev(HMACOverhead.Data(), HMACOverhead.Length());
1042           m_StreamOffset += HMACOverhead.Length();
1043         }
1044     }
1045   else
1046     {
1047       if(m_FramesWritten == 0){
1048         ui32_t BER_length = AS_02_PCM_MXF_BER_LENGTH; //MXF_BER_LENGTH;
1049
1050         if ( FrameBuf.Size() > 0x00ffffff ) // Need BER integer longer than MXF_BER_LENGTH bytes
1051           {
1052             BER_length = Kumu::get_BER_length_for_value(FrameBuf.Size());
1053
1054             if ( BER_length == 0 )
1055               result = RESULT_KLV_CODING;
1056           }
1057
1058         Overhead.WriteRaw((byte_t*)EssenceUL, SMPTE_UL_LENGTH);
1059         Overhead.WriteBER(FrameBuf.Size(), BER_length);
1060
1061         //position of the KLV start
1062         m_KLV_start = m_File.Tell();
1063
1064         if ( ASDCP_SUCCESS(result) )
1065           result = m_File.Writev(Overhead.Data(), Overhead.Length());
1066
1067         if ( ASDCP_SUCCESS(result) )
1068           result = m_File.Writev((byte_t*)FrameBuf.RoData(), FrameBuf.Size());
1069
1070         if ( ASDCP_SUCCESS(result) )
1071           m_StreamOffset += Overhead.Length() + FrameBuf.Size();
1072       }
1073       else{
1074         //update the KLV - length; new value plus old value from length field
1075         //necessary to know position of length field -> bodyPartition + 8
1076         //update every time when writing new essence or at the end of writing
1077
1078         if ( ASDCP_SUCCESS(result) )
1079           result = m_File.Writev((byte_t*)FrameBuf.RoData(), FrameBuf.Size());
1080
1081         if ( ASDCP_SUCCESS(result) )
1082           m_StreamOffset += FrameBuf.Size();
1083       }
1084     }
1085
1086   if ( ASDCP_SUCCESS(result) )
1087     result = m_File.Writev();
1088
1089   return result;
1090 }
1091
1092 //
1093 // end AS_02_PCM.cpp
1094 //
1095