added
[asdcplib.git] / src / AS_DCP_PCM.cpp
1 /*
2 Copyright (c) 2004-2011, 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_PCM.cpp
28     \version $Id$       
29     \brief   AS-DCP library, PCM essence reader and writer implementation
30 */
31
32 #include "AS_DCP_internal.h"
33 #include <map>
34 #include <iostream>
35 #include <iomanip>
36
37 //------------------------------------------------------------------------------------------
38
39 static std::string PCM_PACKAGE_LABEL = "File Package: SMPTE 382M frame wrapping of wave audio";
40 static std::string SOUND_DEF_LABEL = "Sound Track";
41
42 //
43 Result_t
44 PCM_ADesc_to_MD(PCM::AudioDescriptor& ADesc, MXF::WaveAudioDescriptor* ADescObj)
45 {
46   ASDCP_TEST_NULL(ADescObj);
47   ADescObj->SampleRate = ADesc.EditRate;
48   ADescObj->AudioSamplingRate = ADesc.AudioSamplingRate;
49   ADescObj->Locked = ADesc.Locked;
50   ADescObj->ChannelCount = ADesc.ChannelCount;
51   ADescObj->QuantizationBits = ADesc.QuantizationBits;
52   ADescObj->BlockAlign = ADesc.BlockAlign;
53   ADescObj->AvgBps = ADesc.AvgBps;
54   ADescObj->LinkedTrackID = ADesc.LinkedTrackID;
55   ADescObj->ContainerDuration = ADesc.ContainerDuration;
56
57   ADescObj->ChannelAssignment.Reset();
58
59   switch ( ADesc.ChannelFormat )
60     {
61       case PCM::CF_CFG_1:
62         ADescObj->ChannelAssignment = DefaultSMPTEDict().Type(MDD_DCAudioChannelCfg_1_5p1).ul;
63         break;
64
65       case PCM::CF_CFG_2:
66         ADescObj->ChannelAssignment = DefaultSMPTEDict().Type(MDD_DCAudioChannelCfg_2_6p1).ul;
67         break;
68
69       case PCM::CF_CFG_3:
70         ADescObj->ChannelAssignment = DefaultSMPTEDict().Type(MDD_DCAudioChannelCfg_3_7p1).ul;
71         break;
72
73       case PCM::CF_CFG_4:
74         ADescObj->ChannelAssignment = DefaultSMPTEDict().Type(MDD_DCAudioChannelCfg_4_WTF).ul;
75         break;
76
77       case PCM::CF_CFG_5:
78         ADescObj->ChannelAssignment = DefaultSMPTEDict().Type(MDD_DCAudioChannelCfg_5_7p1_DS).ul;
79         break;
80     }
81
82   return RESULT_OK;
83 }
84
85 //
86 ASDCP::Result_t
87 MD_to_PCM_ADesc(MXF::WaveAudioDescriptor* ADescObj, PCM::AudioDescriptor& ADesc)
88 {
89   ASDCP_TEST_NULL(ADescObj);
90   ADesc.EditRate = ADescObj->SampleRate;
91   ADesc.AudioSamplingRate = ADescObj->AudioSamplingRate;
92   ADesc.Locked = ADescObj->Locked;
93   ADesc.ChannelCount = ADescObj->ChannelCount;
94   ADesc.QuantizationBits = ADescObj->QuantizationBits;
95   ADesc.BlockAlign = ADescObj->BlockAlign;
96   ADesc.AvgBps = ADescObj->AvgBps;
97   ADesc.LinkedTrackID = ADescObj->LinkedTrackID;
98   assert(ADescObj->ContainerDuration <= 0xFFFFFFFFL);
99   ADesc.ContainerDuration = (ui32_t) ADescObj->ContainerDuration;
100
101   ADesc.ChannelFormat = PCM::CF_NONE;
102
103   if ( ADescObj->ChannelAssignment.HasValue() )
104     {
105       if ( ADescObj->ChannelAssignment == DefaultSMPTEDict().Type(MDD_DCAudioChannelCfg_1_5p1).ul )
106         ADesc.ChannelFormat = PCM::CF_CFG_1;
107
108       else if ( ADescObj->ChannelAssignment == DefaultSMPTEDict().Type(MDD_DCAudioChannelCfg_2_6p1).ul )
109         ADesc.ChannelFormat = PCM::CF_CFG_2;
110
111       else if ( ADescObj->ChannelAssignment == DefaultSMPTEDict().Type(MDD_DCAudioChannelCfg_3_7p1).ul )
112         ADesc.ChannelFormat = PCM::CF_CFG_3;
113
114       else if ( ADescObj->ChannelAssignment == DefaultSMPTEDict().Type(MDD_DCAudioChannelCfg_4_WTF).ul )
115         ADesc.ChannelFormat = PCM::CF_CFG_4;
116
117       else if ( ADescObj->ChannelAssignment == DefaultSMPTEDict().Type(MDD_DCAudioChannelCfg_5_7p1_DS).ul )
118         ADesc.ChannelFormat = PCM::CF_CFG_5;
119     }
120
121   return RESULT_OK;
122 }
123
124 //
125 std::ostream&
126 ASDCP::PCM::operator << (std::ostream& strm, const AudioDescriptor& ADesc)
127 {
128   strm << "        SampleRate: " << ADesc.EditRate.Numerator << "/" << ADesc.EditRate.Denominator << std::endl;
129   strm << " AudioSamplingRate: " << ADesc.AudioSamplingRate.Numerator << "/" << ADesc.AudioSamplingRate.Denominator << std::endl;
130   strm << "            Locked: " << (unsigned) ADesc.Locked << std::endl;
131   strm << "      ChannelCount: " << (unsigned) ADesc.ChannelCount << std::endl;
132   strm << "  QuantizationBits: " << (unsigned) ADesc.QuantizationBits << std::endl;
133   strm << "        BlockAlign: " << (unsigned) ADesc.BlockAlign << std::endl;
134   strm << "            AvgBps: " << (unsigned) ADesc.AvgBps << std::endl;
135   strm << "     LinkedTrackID: " << (unsigned) ADesc.LinkedTrackID << std::endl;
136   strm << " ContainerDuration: " << (unsigned) ADesc.ContainerDuration << std::endl;
137
138   return strm;
139 }
140
141 //
142 void
143 ASDCP::PCM::AudioDescriptorDump(const AudioDescriptor& ADesc, FILE* stream)
144 {
145   if ( stream == 0 )
146     stream = stderr;
147
148   fprintf(stream, "\
149         EditRate: %d/%d\n\
150  AudioSamplingRate: %d/%d\n\
151             Locked: %u\n\
152       ChannelCount: %u\n\
153   QuantizationBits: %u\n\
154         BlockAlign: %u\n\
155             AvgBps: %u\n\
156      LinkedTrackID: %u\n\
157  ContainerDuration: %u\n",
158           ADesc.EditRate.Numerator, ADesc.EditRate.Denominator,
159           ADesc.AudioSamplingRate.Numerator, ADesc.AudioSamplingRate.Denominator,
160           ADesc.Locked,
161           ADesc.ChannelCount,
162           ADesc.QuantizationBits,
163           ADesc.BlockAlign,
164           ADesc.AvgBps,
165           ADesc.LinkedTrackID,
166           ADesc.ContainerDuration
167           );
168 }
169
170
171 //
172 //
173 static ui32_t
174 calc_CBR_frame_size(ASDCP::WriterInfo& Info, const ASDCP::PCM::AudioDescriptor& ADesc)
175 {
176   ui32_t CBR_frame_size = 0;
177
178   if ( Info.EncryptedEssence )
179     {
180       CBR_frame_size =
181         SMPTE_UL_LENGTH
182         + MXF_BER_LENGTH
183         + klv_cryptinfo_size
184         + calc_esv_length(ASDCP::PCM::CalcFrameBufferSize(ADesc), 0)
185         + ( Info.UsesHMAC ? klv_intpack_size : (MXF_BER_LENGTH * 3) );
186     }
187   else
188     {
189       CBR_frame_size = ASDCP::PCM::CalcFrameBufferSize(ADesc) + SMPTE_UL_LENGTH + MXF_BER_LENGTH;
190     }
191
192   return CBR_frame_size;
193 }
194
195
196 //------------------------------------------------------------------------------------------
197
198
199 class ASDCP::PCM::MXFReader::h__Reader : public ASDCP::h__Reader
200 {
201   ASDCP_NO_COPY_CONSTRUCT(h__Reader);
202   h__Reader();
203
204 public:
205   AudioDescriptor m_ADesc;
206
207   h__Reader(const Dictionary& d) : ASDCP::h__Reader(d) {}
208   ~h__Reader() {}
209   Result_t    OpenRead(const char*);
210   Result_t    ReadFrame(ui32_t, FrameBuffer&, AESDecContext*, HMACContext*);
211 };
212
213
214 //
215 //
216 ASDCP::Result_t
217 ASDCP::PCM::MXFReader::h__Reader::OpenRead(const char* filename)
218 {
219   Result_t result = OpenMXFRead(filename);
220
221   if( ASDCP_SUCCESS(result) )
222     {
223       InterchangeObject* Object;
224       if ( ASDCP_SUCCESS(m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(WaveAudioDescriptor), &Object)) )
225         {
226           assert(Object);
227           result = MD_to_PCM_ADesc((MXF::WaveAudioDescriptor*)Object, m_ADesc);
228         }
229     }
230
231   // check for sample/frame rate sanity
232   if ( ASDCP_SUCCESS(result)
233        && m_ADesc.EditRate != EditRate_24
234        && m_ADesc.EditRate != EditRate_25
235        && m_ADesc.EditRate != EditRate_30
236        && m_ADesc.EditRate != EditRate_48
237        && m_ADesc.EditRate != EditRate_50
238        && m_ADesc.EditRate != EditRate_60
239        && m_ADesc.EditRate != EditRate_23_98 )
240     {
241       DefaultLogSink().Error("PCM file EditRate is not a supported value: %d/%d\n", // lu
242                              m_ADesc.EditRate.Numerator, m_ADesc.EditRate.Denominator);
243
244       // oh, they gave us the audio sampling rate instead, assume 24/1
245       if ( m_ADesc.EditRate == SampleRate_48k )
246         {
247           DefaultLogSink().Warn("adjusting EditRate to 24/1\n"); 
248           m_ADesc.EditRate = EditRate_24;
249         }
250       else
251         {
252           // or we just drop the hammer
253           return RESULT_FORMAT;
254         }
255     }
256
257   if( ASDCP_SUCCESS(result) )
258     result = InitMXFIndex();
259
260   if( ASDCP_SUCCESS(result) )
261     result = InitInfo();
262
263   // TODO: test file for sane CBR index BytesPerEditUnit
264
265   return result;
266 }
267
268
269 //
270 //
271 ASDCP::Result_t
272 ASDCP::PCM::MXFReader::h__Reader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
273                                             AESDecContext* Ctx, HMACContext* HMAC)
274 {
275   if ( ! m_File.IsOpen() )
276     return RESULT_INIT;
277
278   assert(m_Dict);
279   return ReadEKLVFrame(FrameNum, FrameBuf, m_Dict->ul(MDD_WAVEssence), Ctx, HMAC);
280 }
281
282 //------------------------------------------------------------------------------------------
283
284
285 //
286 void
287 ASDCP::PCM::FrameBuffer::Dump(FILE* stream, ui32_t dump_len) const
288 {
289   if ( stream == 0 )
290     stream = stderr;
291
292   fprintf(stream, "Frame: %06u, %7u bytes\n",
293           m_FrameNumber, m_Size);
294
295   if ( dump_len )
296     Kumu::hexdump(m_Data, dump_len, stream);
297 }
298
299 //------------------------------------------------------------------------------------------
300
301 ASDCP::PCM::MXFReader::MXFReader()
302 {
303   m_Reader = new h__Reader(DefaultCompositeDict());
304 }
305
306
307 ASDCP::PCM::MXFReader::~MXFReader()
308 {
309   if ( m_Reader && m_Reader->m_File.IsOpen() )
310     m_Reader->Close();
311 }
312
313 // Open the file for reading. The file must exist. Returns error if the
314 // operation cannot be completed.
315 ASDCP::Result_t
316 ASDCP::PCM::MXFReader::OpenRead(const char* filename) const
317 {
318   return m_Reader->OpenRead(filename);
319 }
320
321 // Reads a frame of essence from the MXF file. If the optional AESEncContext
322 // argument is present, the essence is decrypted after reading. If the MXF
323 // file is encrypted and the AESDecContext argument is NULL, the frame buffer
324 // will contain the ciphertext frame data.
325 ASDCP::Result_t
326 ASDCP::PCM::MXFReader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
327                                  AESDecContext* Ctx, HMACContext* HMAC) const
328 {
329   if ( m_Reader && m_Reader->m_File.IsOpen() )
330     return m_Reader->ReadFrame(FrameNum, FrameBuf, Ctx, HMAC);
331
332   return RESULT_INIT;
333 }
334
335
336 // Fill the struct with the values from the file's header.
337 // Returns RESULT_INIT if the file is not open.
338 ASDCP::Result_t
339 ASDCP::PCM::MXFReader::FillAudioDescriptor(AudioDescriptor& ADesc) const
340 {
341   if ( m_Reader && m_Reader->m_File.IsOpen() )
342     {
343       ADesc = m_Reader->m_ADesc;
344       return RESULT_OK;
345     }
346
347   return RESULT_INIT;
348 }
349
350 // Fill the struct with the values from the file's header.
351 // Returns RESULT_INIT if the file is not open.
352 ASDCP::Result_t
353 ASDCP::PCM::MXFReader::FillWriterInfo(WriterInfo& Info) const
354 {
355   if ( m_Reader && m_Reader->m_File.IsOpen() )
356     {
357       Info = m_Reader->m_Info;
358       return RESULT_OK;
359     }
360
361   return RESULT_INIT;
362 }
363
364 //
365 void
366 ASDCP::PCM::MXFReader::DumpHeaderMetadata(FILE* stream) const
367 {
368   if ( m_Reader && m_Reader->m_File.IsOpen() )
369     m_Reader->m_HeaderPart.Dump(stream);
370 }
371
372
373 //
374 void
375 ASDCP::PCM::MXFReader::DumpIndex(FILE* stream) const
376 {
377   if ( m_Reader->m_File.IsOpen() )
378     m_Reader->m_FooterPart.Dump(stream);
379 }
380
381 //
382 ASDCP::Result_t
383 ASDCP::PCM::MXFReader::Close() const
384 {
385   if ( m_Reader && m_Reader->m_File.IsOpen() )
386     {
387       m_Reader->Close();
388       return RESULT_OK;
389     }
390
391   return RESULT_INIT;
392 }
393
394
395 //------------------------------------------------------------------------------------------
396
397 //
398 class ASDCP::PCM::MXFWriter::h__Writer : public ASDCP::h__Writer
399 {
400   ASDCP_NO_COPY_CONSTRUCT(h__Writer);
401   h__Writer();
402
403 public:
404   AudioDescriptor m_ADesc;
405   byte_t          m_EssenceUL[SMPTE_UL_LENGTH];
406   
407   h__Writer(const Dictionary& d) : ASDCP::h__Writer(d) {
408     memset(m_EssenceUL, 0, SMPTE_UL_LENGTH);
409   }
410
411   ~h__Writer(){}
412
413   Result_t OpenWrite(const char*, ui32_t HeaderSize);
414   Result_t SetSourceStream(const AudioDescriptor&);
415   Result_t WriteFrame(const FrameBuffer&, AESEncContext* = 0, HMACContext* = 0);
416   Result_t Finalize();
417 };
418
419
420
421 // Open the file for writing. The file must not exist. Returns error if
422 // the operation cannot be completed.
423 ASDCP::Result_t
424 ASDCP::PCM::MXFWriter::h__Writer::OpenWrite(const char* filename, ui32_t HeaderSize)
425 {
426   if ( ! m_State.Test_BEGIN() )
427     return RESULT_STATE;
428
429   Result_t result = m_File.OpenWrite(filename);
430
431   if ( ASDCP_SUCCESS(result) )
432     {
433       m_HeaderSize = HeaderSize;
434       m_EssenceDescriptor = new WaveAudioDescriptor(m_Dict);
435       result = m_State.Goto_INIT();
436     }
437
438   return result;
439 }
440
441
442 // Automatically sets the MXF file's metadata from the WAV parser info.
443 ASDCP::Result_t
444 ASDCP::PCM::MXFWriter::h__Writer::SetSourceStream(const AudioDescriptor& ADesc)
445 {
446   if ( ! m_State.Test_INIT() )
447     return RESULT_STATE;
448
449   if ( ADesc.EditRate != EditRate_24
450        && ADesc.EditRate != EditRate_25
451        && ADesc.EditRate != EditRate_30
452        && ADesc.EditRate != EditRate_48
453        && ADesc.EditRate != EditRate_50
454        && ADesc.EditRate != EditRate_60
455        && ADesc.EditRate != EditRate_23_98 )
456     {
457       DefaultLogSink().Error("AudioDescriptor.EditRate is not a supported value: %d/%d\n",
458                              ADesc.EditRate.Numerator, ADesc.EditRate.Denominator);
459       return RESULT_RAW_FORMAT;
460     }
461
462   if ( ADesc.AudioSamplingRate != SampleRate_48k && ADesc.AudioSamplingRate != SampleRate_96k )
463     {
464       DefaultLogSink().Error("AudioDescriptor.AudioSamplingRate is not 48000/1 or 96000/1: %d/%d\n",
465                              ADesc.AudioSamplingRate.Numerator, ADesc.AudioSamplingRate.Denominator);
466       return RESULT_RAW_FORMAT;
467     }
468
469   assert(m_Dict);
470   m_ADesc = ADesc;
471
472   Result_t result = PCM_ADesc_to_MD(m_ADesc, (WaveAudioDescriptor*)m_EssenceDescriptor);
473   
474   if ( ASDCP_SUCCESS(result) )
475     {
476       memcpy(m_EssenceUL, m_Dict->ul(MDD_WAVEssence), SMPTE_UL_LENGTH);
477       m_EssenceUL[SMPTE_UL_LENGTH-1] = 1; // first (and only) essence container
478       result = m_State.Goto_READY();
479     }
480
481   if ( ASDCP_SUCCESS(result) )
482     {
483       ui32_t TCFrameRate = ( m_ADesc.EditRate == EditRate_23_98  ) ? 24 : m_ADesc.EditRate.Numerator;
484       
485       result = WriteMXFHeader(PCM_PACKAGE_LABEL, UL(m_Dict->ul(MDD_WAVWrapping)),
486                               SOUND_DEF_LABEL, UL(m_EssenceUL), UL(m_Dict->ul(MDD_SoundDataDef)),
487                               m_ADesc.EditRate, TCFrameRate, calc_CBR_frame_size(m_Info, m_ADesc));
488     }
489
490   return result;
491 }
492
493
494 //
495 //
496 ASDCP::Result_t
497 ASDCP::PCM::MXFWriter::h__Writer::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx,
498                                              HMACContext* HMAC)
499 {
500   Result_t result = RESULT_OK;
501
502   if ( m_State.Test_READY() )
503     result = m_State.Goto_RUNNING(); // first time through
504
505   if ( ASDCP_SUCCESS(result) )
506     result = WriteEKLVPacket(FrameBuf, m_EssenceUL, Ctx, HMAC);
507
508   if ( ASDCP_SUCCESS(result) )
509     m_FramesWritten++;
510
511   return result;
512 }
513
514 // Closes the MXF file, writing the index and other closing information.
515 //
516 ASDCP::Result_t
517 ASDCP::PCM::MXFWriter::h__Writer::Finalize()
518 {
519   if ( ! m_State.Test_RUNNING() )
520     return RESULT_STATE;
521
522   m_State.Goto_FINAL();
523
524   return WriteMXFFooter();
525 }
526
527
528 //------------------------------------------------------------------------------------------
529 //
530
531
532
533 ASDCP::PCM::MXFWriter::MXFWriter()
534 {
535 }
536
537 ASDCP::PCM::MXFWriter::~MXFWriter()
538 {
539 }
540
541
542 // Open the file for writing. The file must not exist. Returns error if
543 // the operation cannot be completed.
544 ASDCP::Result_t
545 ASDCP::PCM::MXFWriter::OpenWrite(const char* filename, const WriterInfo& Info,
546                                  const AudioDescriptor& ADesc, ui32_t HeaderSize)
547 {
548   if ( Info.LabelSetType == LS_MXF_SMPTE )
549     m_Writer = new h__Writer(DefaultSMPTEDict());
550   else
551     m_Writer = new h__Writer(DefaultInteropDict());
552
553   m_Writer->m_Info = Info;
554   
555   Result_t result = m_Writer->OpenWrite(filename, HeaderSize);
556
557   if ( ASDCP_SUCCESS(result) )
558     result = m_Writer->SetSourceStream(ADesc);
559
560   if ( ASDCP_FAILURE(result) )
561     m_Writer.release();
562
563   return result;
564 }
565
566 // Writes a frame of essence to the MXF file. If the optional AESEncContext
567 // argument is present, the essence is encrypted prior to writing.
568 // Fails if the file is not open, is finalized, or an operating system
569 // error occurs.
570 ASDCP::Result_t
571 ASDCP::PCM::MXFWriter::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
572 {
573   if ( m_Writer.empty() )
574     return RESULT_INIT;
575
576   return m_Writer->WriteFrame(FrameBuf, Ctx, HMAC);
577 }
578
579 // Closes the MXF file, writing the index and other closing information.
580 ASDCP::Result_t
581 ASDCP::PCM::MXFWriter::Finalize()
582 {
583   if ( m_Writer.empty() )
584     return RESULT_INIT;
585
586   return m_Writer->Finalize();
587 }
588
589 //
590 // end AS_DCP_PCM.cpp
591 //
592