2 Copyright (c) 2011-2018, Robert Scheler, Heiko Sparenberg Fraunhofer IIS,
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
10 1. Redistributions of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in the
14 documentation and/or other materials provided with the distribution.
15 3. The name of the author may not be used to endorse or promote products
16 derived from this software without specific prior written permission.
18 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 \brief AS-02 library, public interface
33 This module implements MXF AS-02 is a set of file access objects that
34 offer simplified access to files conforming to the standards published
35 by the SMPTE Media and Packaging Technology Committee 35PM. The file
36 format, labeled IMF Essence Component (AKA "AS-02" for historical
37 reasons), is described in the following document:
39 o SMPTE 2067-5:2013 IMF Essence Component
41 The following use cases are supported by the module:
43 o Write essence to a plaintext or ciphertext AS-02 file:
47 o Read essence from a plaintext or ciphertext AS-02 file:
51 o Read header metadata from an AS-02 file
53 NOTE: ciphertext support for clip-wrapped PCM is not yet complete.
66 KM_DECLARE_RESULT(AS02_FORMAT, -116, "The file format is not proper OP-1a/AS-02.");
70 // reads distributed index tables and provides a uniform lookup with
71 // translated StreamOffest values (that is, StreamOffest is adjusted
72 // to the actual file position
73 class AS02IndexReader : public ASDCP::MXF::Partition
75 Kumu::ByteString m_IndexSegmentData;
77 ui32_t m_BytesPerEditUnit;
79 Result_t InitFromBuffer(const byte_t* p, ui32_t l, const ui64_t& body_offset, const ui64_t& essence_container_offset);
81 ASDCP_NO_COPY_CONSTRUCT(AS02IndexReader);
85 ASDCP::IPrimerLookup *m_Lookup;
87 AS02IndexReader(const ASDCP::Dictionary*);
88 virtual ~AS02IndexReader();
90 Result_t InitFromFile(const Kumu::IFileReader& reader, const ASDCP::MXF::RIP& rip, const bool has_header_essence);
91 ui64_t GetDuration() const;
93 Result_t GetMDObjectByID(const Kumu::UUID&, ASDCP::MXF::InterchangeObject** = 0);
94 Result_t GetMDObjectByType(const byte_t*, ASDCP::MXF::InterchangeObject** = 0);
95 Result_t GetMDObjectsByType(const byte_t* ObjectID, std::list<ASDCP::MXF::InterchangeObject*>& ObjectList);
96 Result_t Lookup(ui32_t frame_num, ASDCP::MXF::IndexTableSegment::IndexEntry&) const;
100 // Returns size in bytes of a single sample of data described by ADesc
101 inline ui32_t CalcSampleSize(const ASDCP::MXF::WaveAudioDescriptor& d)
103 return (d.QuantizationBits / 8) * d.ChannelCount;
106 // Returns number of samples per frame of data described by ADesc
107 inline ui32_t CalcSamplesPerFrame(const ASDCP::MXF::WaveAudioDescriptor& d, const ASDCP::Rational& edit_rate)
109 double tmpd = d.AudioSamplingRate.Quotient() / edit_rate.Quotient();
110 return (ui32_t)ceil(tmpd);
113 // Returns the size in bytes of a frame of data described by ADesc
114 inline ui32_t CalcFrameBufferSize(const ASDCP::MXF::WaveAudioDescriptor& d, const ASDCP::Rational& edit_rate)
116 return CalcSampleSize(d) * CalcSamplesPerFrame(d, edit_rate);
119 // Returns number of frames for data described by ADesc, given a duration in samples and an edit rate
120 inline ui32_t CalcFramesFromDurationInSamples(const ui32_t duration_samples, const ASDCP::MXF::WaveAudioDescriptor& d,
121 const ASDCP::Rational& edit_rate)
123 ui32_t spf = CalcSamplesPerFrame(d, edit_rate);
124 ui32_t frames = duration_samples / spf;
126 if ( duration_samples % spf != 0 )
137 // IMF App 2 edit rates not already exposed in namespace ASDCP
138 const ASDCP::Rational EditRate_29_97 = ASDCP::Rational(30000, 1001);
139 const ASDCP::Rational EditRate_59_94 = ASDCP::Rational(60000, 1001);
141 //---------------------------------------------------------------------------------
142 // Accessors in the MXFReader and MXFWriter classes below return these types to
143 // provide direct access to MXF metadata structures declared in MXF.h and Metadata.h
145 // See ST 2067-5 Sec. x.y.z
160 ASDCP::mem_ptr<h__Writer> m_Writer;
161 ASDCP_NO_COPY_CONSTRUCT(MXFWriter);
165 virtual ~MXFWriter();
167 // Warning: direct manipulation of MXF structures can interfere
168 // with the normal operation of the wrapper. Caveat emptor!
169 virtual ASDCP::MXF::OP1aHeader& OP1aHeader();
170 virtual ASDCP::MXF::RIP& RIP();
172 // Open the file for writing. The file must not exist. Returns error if
173 // the operation cannot be completed or if nonsensical data is discovered
174 // in the essence descriptor.
175 Result_t OpenWrite(const std::string& filename, const ASDCP::WriterInfo&,
176 ASDCP::MXF::FileDescriptor* essence_descriptor,
177 ASDCP::MXF::InterchangeObject_list_t& essence_sub_descriptor_list,
178 const ASDCP::Rational& edit_rate, const ui32_t& header_size = 16384,
179 const IndexStrategy_t& strategy = IS_FOLLOW, const ui32_t& partition_space = 10);
181 // Writes a frame of essence to the MXF file. If the optional AESEncContext
182 // argument is present, the essence is encrypted prior to writing.
183 // Fails if the file is not open, is finalized, or an operating system
185 Result_t WriteFrame(const ASDCP::JP2K::FrameBuffer&, ASDCP::AESEncContext* = 0, ASDCP::HMACContext* = 0);
187 // Closes the MXF file, writing the index and revised header.
195 ASDCP::mem_ptr<h__Reader> m_Reader;
196 ASDCP_NO_COPY_CONSTRUCT(MXFReader);
199 MXFReader(const Kumu::IFileReaderFactory& fileReaderFactory);
200 virtual ~MXFReader();
202 // Warning: direct manipulation of MXF structures can interfere
203 // with the normal operation of the wrapper. Caveat emptor!
204 virtual ASDCP::MXF::OP1aHeader& OP1aHeader();
205 virtual AS_02::MXF::AS02IndexReader& AS02IndexReader();
206 virtual ASDCP::MXF::RIP& RIP();
208 // Open the file for reading. The file must exist. Returns error if the
209 // operation cannot be completed.
210 Result_t OpenRead(const std::string& filename) const;
212 // Returns RESULT_INIT if the file is not open.
213 Result_t Close() const;
215 // Fill a WriterInfo struct with the values from the file's header.
216 // Returns RESULT_INIT if the file is not open.
217 Result_t FillWriterInfo(ASDCP::WriterInfo&) const;
219 // Reads a frame of essence from the MXF file. If the optional AESEncContext
220 // argument is present, the essence is decrypted after reading. If the MXF
221 // file is encrypted and the AESDecContext argument is NULL, the frame buffer
222 // will contain the ciphertext frame data. If the HMACContext argument is
223 // not NULL, the HMAC will be calculated (if the file supports it).
224 // Returns RESULT_INIT if the file is not open, failure if the frame number is
225 // out of range, or if optional decrypt or HAMC operations fail.
226 Result_t ReadFrame(ui32_t frame_number, ASDCP::JP2K::FrameBuffer&, ASDCP::AESDecContext* = 0, ASDCP::HMACContext* = 0) const;
228 // Print debugging information to stream
229 void DumpHeaderMetadata(FILE* = 0) const;
230 void DumpIndex(FILE* = 0) const;
236 //---------------------------------------------------------------------------------
240 // see AS_DCP.h for related data types
242 // An AS-02 PCM file is clip-wrapped, but the interface defined below mimics that used
243 // for frame-wrapped essence elsewhere in this library. The concept of frame rate
244 // therefore is only relevant to these classes and is not reflected in or affected by
245 // the contents of the MXF file. The frame rate that is set on the writer is only
246 // for compatibility with the existing parsers, samples are packed contiguously into
247 // the same clip-wrapped packet. Similarly, the edit rate must be set when initializing
248 // the reader to signal the number of samples to be read by each call to ReadFrame();
254 ASDCP::mem_ptr<h__Writer> m_Writer;
255 ASDCP_NO_COPY_CONSTRUCT(MXFWriter);
259 virtual ~MXFWriter();
261 // Warning: direct manipulation of MXF structures can interfere
262 // with the normal operation of the wrapper. Caveat emptor!
263 virtual ASDCP::MXF::OP1aHeader& OP1aHeader();
264 virtual ASDCP::MXF::RIP& RIP();
266 // Open the file for writing. The file must not exist. Returns error if
267 // the operation cannot be completed or if nonsensical data is discovered
268 // in the essence descriptor.
269 Result_t OpenWrite(const std::string& filename, const ASDCP::WriterInfo&,
270 ASDCP::MXF::FileDescriptor* essence_descriptor,
271 ASDCP::MXF::InterchangeObject_list_t& essence_sub_descriptor_list,
272 const ASDCP::Rational& edit_rate, ui32_t HeaderSize = 16384);
274 // Writes a frame of essence to the MXF file. If the optional AESEncContext
275 // argument is present, the essence is encrypted prior to writing.
276 // Fails if the file is not open, is finalized, or an operating system
278 Result_t WriteFrame(const ASDCP::FrameBuffer&, ASDCP::AESEncContext* = 0, ASDCP::HMACContext* = 0);
280 // Closes the MXF file, writing the index and revised header.
288 ASDCP::mem_ptr<h__Reader> m_Reader;
289 ASDCP_NO_COPY_CONSTRUCT(MXFReader);
292 MXFReader(const Kumu::IFileReaderFactory& fileReaderFactory);
293 virtual ~MXFReader();
295 // Warning: direct manipulation of MXF structures can interfere
296 // with the normal operation of the wrapper. Caveat emptor!
297 virtual ASDCP::MXF::OP1aHeader& OP1aHeader();
298 virtual AS_02::MXF::AS02IndexReader& AS02IndexReader();
299 virtual ASDCP::MXF::RIP& RIP();
301 // Open the file for reading. The file must exist. Returns error if the
302 // operation cannot be completed.
303 Result_t OpenRead(const std::string& filename, const ASDCP::Rational& EditRate) const;
305 // Returns RESULT_INIT if the file is not open.
306 Result_t Close() const;
308 // Fill a WriterInfo struct with the values from the file's header.
309 // Returns RESULT_INIT if the file is not open.
310 Result_t FillWriterInfo(ASDCP::WriterInfo&) const;
312 // Reads a frame of essence from the MXF file. If the optional AESEncContext
313 // argument is present, the essence is decrypted after reading. If the MXF
314 // file is encrypted and the AESDecContext argument is NULL, the frame buffer
315 // will contain the ciphertext frame data. If the HMACContext argument is
316 // not NULL, the HMAC will be calculated (if the file supports it).
317 // Returns RESULT_INIT if the file is not open, failure if the frame number is
318 // out of range, or if optional decrypt or HAMC operations fail.
319 Result_t ReadFrame(ui32_t frame_number, ASDCP::PCM::FrameBuffer&, ASDCP::AESDecContext* = 0, ASDCP::HMACContext* = 0) const;
321 // Print debugging information to stream
322 void DumpHeaderMetadata(FILE* = 0) const;
323 void DumpIndex(FILE* = 0) const;
327 //---------------------------------------------------------------------------------
331 using ASDCP::TimedText::TimedTextDescriptor;
332 using ASDCP::TimedText::TimedTextResourceDescriptor;
333 using ASDCP::TimedText::ResourceList_t;
336 class Type5UUIDFilenameResolver : public ASDCP::TimedText::IResourceResolver
338 typedef std::map<Kumu::UUID, std::string> ResourceMap;
340 ResourceMap m_ResourceMap;
341 std::string m_Dirname;
342 KM_NO_COPY_CONSTRUCT(Type5UUIDFilenameResolver);
345 Type5UUIDFilenameResolver();
346 virtual ~Type5UUIDFilenameResolver();
347 Result_t OpenRead(const std::string& dirname);
348 Result_t ResolveRID(const byte_t* uuid, ASDCP::TimedText::FrameBuffer& FrameBuf) const;
352 // Generate UUID asset ID values from file contents
353 Kumu::UUID CreatePNGNameId(const std::string& image_name);
354 Kumu::UUID CreateFontNameId(const std::string& font_name);
357 class ST2052_TextParser
360 ASDCP::mem_ptr<h__TextParser> m_Parser;
361 ASDCP_NO_COPY_CONSTRUCT(ST2052_TextParser);
365 virtual ~ST2052_TextParser();
367 // Opens an XML file for reading, parses data to provide a complete
368 // set of stream metadata for the MXFWriter below.
369 Result_t OpenRead(const std::string& filename) const;
371 // Parse an XML string
372 Result_t OpenRead(const std::string& xml_doc, const std::string& filename) const;
374 // The "profile_name" parameter was removed from OpenRead() because it made the API
375 // awkward WRT lexical compatibility with TimedText_Parser. The value can still be
376 // modified by changing the descriptor's NamespaceName property after the call to
377 // FillTimedTextDescriptor() has set it.
379 // Fill a TimedTextDescriptor struct with the values from the file's contents.
380 // Returns RESULT_INIT if the file is not open.
381 Result_t FillTimedTextDescriptor(ASDCP::TimedText::TimedTextDescriptor&) const;
383 // Reads the complete Timed Text Resource into the given string.
384 Result_t ReadTimedTextResource(std::string&) const;
386 // Reads the Ancillary Resource having the given ID. Fails if the buffer
387 // is too small or the resource does not exist. The optional Resolver
388 // argument can be provided which will be used to retrieve the resource
389 // having a particulat UUID. If a Resolver is not supplied, the default
390 // internal resolver will return the contents of the file having the UUID
391 // as the filename. The filename must exist in the same directory as the
392 // XML file opened with OpenRead().
393 Result_t ReadAncillaryResource(const Kumu::UUID&, ASDCP::TimedText::FrameBuffer&,
394 const ASDCP::TimedText::IResourceResolver* Resolver = 0) const;
401 ASDCP::mem_ptr<h__Writer> m_Writer;
402 ASDCP_NO_COPY_CONSTRUCT(MXFWriter);
406 virtual ~MXFWriter();
408 // Warning: direct manipulation of MXF structures can interfere
409 // with the normal operation of the wrapper. Caveat emptor!
410 virtual ASDCP::MXF::OP1aHeader& OP1aHeader();
411 virtual ASDCP::MXF::RIP& RIP();
413 // Open the file for writing. The file must not exist. Returns error if
414 // the operation cannot be completed or if nonsensical data is discovered
415 // in the essence descriptor.
416 Result_t OpenWrite(const std::string& filename, const ASDCP::WriterInfo&,
417 const ASDCP::TimedText::TimedTextDescriptor&, ui32_t HeaderSize = 16384);
419 // Writes the Timed-Text Resource to the MXF file. The file must be UTF-8
420 // encoded. If the optional AESEncContext argument is present, the essence
421 // is encrypted prior to writing. Fails if the file is not open, is finalized,
422 // or an operating system error occurs.
423 // This method may only be called once, and it must be called before any
424 // call to WriteAncillaryResource(). RESULT_STATE will be returned if these
425 // conditions are not met.
426 Result_t WriteTimedTextResource(const std::string& XMLDoc, ASDCP::AESEncContext* = 0, ASDCP::HMACContext* = 0);
428 // Writes an Ancillary Resource to the MXF file. If the optional AESEncContext
429 // argument is present, the essence is encrypted prior to writing.
430 // Fails if the file is not open, is finalized, or an operating system
431 // error occurs. RESULT_STATE will be returned if the method is called before
432 // WriteTimedTextResource()
433 Result_t WriteAncillaryResource(const ASDCP::TimedText::FrameBuffer&, ASDCP::AESEncContext* = 0, ASDCP::HMACContext* = 0);
435 // Closes the MXF file, writing the index and revised header.
443 ASDCP::mem_ptr<h__Reader> m_Reader;
444 ASDCP_NO_COPY_CONSTRUCT(MXFReader);
447 MXFReader(const Kumu::IFileReaderFactory& fileReaderFactory);
448 virtual ~MXFReader();
450 // Warning: direct manipulation of MXF structures can interfere
451 // with the normal operation of the wrapper. Caveat emptor!
452 virtual ASDCP::MXF::OP1aHeader& OP1aHeader();
453 virtual AS_02::MXF::AS02IndexReader& AS02IndexReader();
454 virtual ASDCP::MXF::RIP& RIP();
456 // Open the file for reading. The file must exist. Returns error if the
457 // operation cannot be completed.
458 Result_t OpenRead(const std::string& filename) const;
460 // Returns RESULT_INIT if the file is not open.
461 Result_t Close() const;
463 // Fill a TimedTextDescriptor struct with the values from the file's header.
464 // Returns RESULT_INIT if the file is not open.
465 Result_t FillTimedTextDescriptor(ASDCP::TimedText::TimedTextDescriptor&) const;
467 // Fill a WriterInfo struct with the values from the file's header.
468 // Returns RESULT_INIT if the file is not open.
469 Result_t FillWriterInfo(ASDCP::WriterInfo&) const;
471 // Reads the complete Timed Text Resource into the given string. Fails if the resource
472 // is encrypted and AESDecContext is NULL (use the following method to retrieve the
473 // raw ciphertet block).
474 Result_t ReadTimedTextResource(std::string&, ASDCP::AESDecContext* = 0, ASDCP::HMACContext* = 0) const;
476 // Reads the complete Timed Text Resource from the MXF file. If the optional AESEncContext
477 // argument is present, the resource is decrypted after reading. If the MXF
478 // file is encrypted and the AESDecContext argument is NULL, the frame buffer
479 // will contain the ciphertext frame data. If the HMACContext argument is
480 // not NULL, the HMAC will be calculated (if the file supports it).
481 // Returns RESULT_INIT if the file is not open, failure if the frame number is
482 // out of range, or if optional decrypt or HAMC operations fail.
483 Result_t ReadTimedTextResource(ASDCP::TimedText::FrameBuffer&, ASDCP::AESDecContext* = 0, ASDCP::HMACContext* = 0) const;
485 // Reads the timed-text resource having the given UUID from the MXF file. If the
486 // optional AESEncContext argument is present, the resource is decrypted after
487 // reading. If the MXF file is encrypted and the AESDecContext argument is NULL,
488 // the frame buffer will contain the ciphertext frame data. If the HMACContext
489 // argument is not NULL, the HMAC will be calculated (if the file supports it).
490 // Returns RESULT_INIT if the file is not open, failure if the frame number is
491 // out of range, or if optional decrypt or HAMC operations fail.
492 Result_t ReadAncillaryResource(const Kumu::UUID&, ASDCP::TimedText::FrameBuffer&, ASDCP::AESDecContext* = 0, ASDCP::HMACContext* = 0) const;
494 // Print debugging information to stream
495 void DumpHeaderMetadata(FILE* = 0) const;
496 void DumpIndex(FILE* = 0) const;
498 } // namespace TimedText
506 ASDCP::mem_ptr<h__Writer> m_Writer;
507 ASDCP_NO_COPY_CONSTRUCT(MXFWriter);
511 virtual ~MXFWriter();
513 // Warning: direct manipulation of MXF structures can interfere
514 // with the normal operation of the wrapper. Caveat emptor!
515 virtual ASDCP::MXF::OP1aHeader& OP1aHeader();
516 virtual ASDCP::MXF::RIP& RIP();
518 // Open the file for writing. The file must not exist. Returns error if
519 // the operation cannot be completed or if nonsensical data is discovered
520 // in the essence descriptor.
521 Result_t OpenWrite(const std::string& filename, const ASDCP::WriterInfo&,
522 const std::string& isxd_document_namespace,
523 const ASDCP::Rational& edit_rate, const ui32_t& header_size = 16384,
524 const IndexStrategy_t& strategy = IS_FOLLOW, const ui32_t& partition_space = 10);
526 // Writes a frame of essence to the MXF file. If the optional AESEncContext
527 // argument is present, the essence is encrypted prior to writing.
528 // Fails if the file is not open, is finalized, or an operating system
530 Result_t WriteFrame(const ASDCP::FrameBuffer&, ASDCP::AESEncContext* = 0, ASDCP::HMACContext* = 0);
532 // Writes an XML text document to the MXF file as per RP 2057. If the
533 // optional AESEncContext argument is present, the document is encrypted
534 // prior to writing. Fails if the file is not open, is finalized, or an
535 // operating system error occurs.
536 Result_t AddDmsGenericPartUtf8Text(const ASDCP::FrameBuffer& frame_buffer, ASDCP::AESEncContext* enc = 0, ASDCP::HMACContext* hmac = 0);
538 // Closes the MXF file, writing the index and revised header.
546 ASDCP::mem_ptr<h__Reader> m_Reader;
547 ASDCP_NO_COPY_CONSTRUCT(MXFReader);
550 MXFReader(const Kumu::IFileReaderFactory& fileReaderFactory);
551 virtual ~MXFReader();
553 // Warning: direct manipulation of MXF structures can interfere
554 // with the normal operation of the wrapper. Caveat emptor!
555 virtual ASDCP::MXF::OP1aHeader& OP1aHeader();
556 virtual AS_02::MXF::AS02IndexReader& AS02IndexReader();
557 virtual ASDCP::MXF::RIP& RIP();
559 // Open the file for reading. The file must exist. Returns error if the
560 // operation cannot be completed.
561 Result_t OpenRead(const std::string& filename) const;
563 // Returns RESULT_INIT if the file is not open.
564 Result_t Close() const;
566 // Fill a WriterInfo struct with the values from the file's header.
567 // Returns RESULT_INIT if the file is not open.
568 Result_t FillWriterInfo(ASDCP::WriterInfo&) const;
570 // Reads a frame of essence from the MXF file. If the optional AESEncContext
571 // argument is present, the essence is decrypted after reading. If the MXF
572 // file is encrypted and the AESDecContext argument is NULL, the frame buffer
573 // will contain the ciphertext frame data. If the HMACContext argument is
574 // not NULL, the HMAC will be calculated (if the file supports it).
575 // Returns RESULT_INIT if the file is not open, failure if the frame number is
576 // out of range, or if optional decrypt or HAMC operations fail.
577 Result_t ReadFrame(ui32_t frame_number, ASDCP::FrameBuffer&,
578 ASDCP::AESDecContext* = 0, ASDCP::HMACContext* = 0) const;
580 // Reads a Generic Stream Partition payload. Returns RESULT_INIT if the file is
581 // not open, or RESULT_FORMAT if the SID is not present in the RIP, or if the
582 // actual partition at ByteOffset does not have a matching BodySID value.
583 // Encryption is not currently supported.
584 Result_t ReadGenericStreamPartitionPayload(ui32_t SID, ASDCP::FrameBuffer& FrameBuf);
586 // Print debugging information to stream
587 void DumpHeaderMetadata(FILE* = 0) const;
588 void DumpIndex(FILE* = 0) const;