2 Copyright (c) 2011-2014, 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 const ASDCP::Dictionary*& m_Dict;
86 ASDCP::IPrimerLookup *m_Lookup;
88 AS02IndexReader(const ASDCP::Dictionary*&);
89 virtual ~AS02IndexReader();
91 Result_t InitFromFile(const Kumu::FileReader& reader, const ASDCP::MXF::RIP& rip, const bool has_header_essence);
92 ui32_t GetDuration() const;
94 Result_t GetMDObjectByID(const Kumu::UUID&, ASDCP::MXF::InterchangeObject** = 0);
95 Result_t GetMDObjectByType(const byte_t*, ASDCP::MXF::InterchangeObject** = 0);
96 Result_t GetMDObjectsByType(const byte_t* ObjectID, std::list<ASDCP::MXF::InterchangeObject*>& ObjectList);
97 Result_t Lookup(ui32_t frame_num, ASDCP::MXF::IndexTableSegment::IndexEntry&) const;
101 // Returns size in bytes of a single sample of data described by ADesc
102 inline ui32_t CalcSampleSize(const ASDCP::MXF::WaveAudioDescriptor& d)
104 return (d.QuantizationBits / 8) * d.ChannelCount;
107 // Returns number of samples per frame of data described by ADesc
108 inline ui32_t CalcSamplesPerFrame(const ASDCP::MXF::WaveAudioDescriptor& d, const ASDCP::Rational& edit_rate)
110 double tmpd = d.AudioSamplingRate.Quotient() / edit_rate.Quotient();
111 return (ui32_t)ceil(tmpd);
114 // Returns the size in bytes of a frame of data described by ADesc
115 inline ui32_t CalcFrameBufferSize(const ASDCP::MXF::WaveAudioDescriptor& d, const ASDCP::Rational& edit_rate)
117 return CalcSampleSize(d) * CalcSamplesPerFrame(d, edit_rate);
120 // Returns number of frames for data described by ADesc, given a duration in samples and an edit rate
121 inline ui32_t CalcFramesFromDurationInSamples(const ui32_t durationInSamples, const ASDCP::MXF::WaveAudioDescriptor& d,
122 const ASDCP::Rational& edit_rate)
124 return static_cast<ui32_t>(static_cast<ui64_t>(durationInSamples) *
125 static_cast<ui64_t>(d.AudioSamplingRate.Denominator * edit_rate.Numerator) /
126 static_cast<ui64_t>(d.AudioSamplingRate.Numerator * edit_rate.Denominator));
132 // IMF App 2 edit rates not already exposed in namespace ASDCP
133 const ASDCP::Rational EditRate_29_97 = ASDCP::Rational(30000, 1001);
134 const ASDCP::Rational EditRate_59_94 = ASDCP::Rational(60000, 1001);
136 //---------------------------------------------------------------------------------
137 // Accessors in the MXFReader and MXFWriter classes below return these types to
138 // provide direct access to MXF metadata structures declared in MXF.h and Metadata.h
140 // See ST 2067-5 Sec. x.y.z
155 ASDCP::mem_ptr<h__Writer> m_Writer;
156 ASDCP_NO_COPY_CONSTRUCT(MXFWriter);
160 virtual ~MXFWriter();
162 // Warning: direct manipulation of MXF structures can interfere
163 // with the normal operation of the wrapper. Caveat emptor!
164 virtual ASDCP::MXF::OP1aHeader& OP1aHeader();
165 virtual ASDCP::MXF::RIP& RIP();
167 // Open the file for writing. The file must not exist. Returns error if
168 // the operation cannot be completed or if nonsensical data is discovered
169 // in the essence descriptor.
170 Result_t OpenWrite(const std::string& filename, const ASDCP::WriterInfo&,
171 ASDCP::MXF::FileDescriptor* essence_descriptor,
172 ASDCP::MXF::InterchangeObject_list_t& essence_sub_descriptor_list,
173 const ASDCP::Rational& edit_rate, const ui32_t& header_size = 16384,
174 const IndexStrategy_t& strategy = IS_FOLLOW, const ui32_t& partition_space = 10);
176 // Writes a frame of essence to the MXF file. If the optional AESEncContext
177 // argument is present, the essence is encrypted prior to writing.
178 // Fails if the file is not open, is finalized, or an operating system
180 Result_t WriteFrame(const ASDCP::JP2K::FrameBuffer&, ASDCP::AESEncContext* = 0, ASDCP::HMACContext* = 0);
182 // Closes the MXF file, writing the index and revised header.
190 ASDCP::mem_ptr<h__Reader> m_Reader;
191 ASDCP_NO_COPY_CONSTRUCT(MXFReader);
195 virtual ~MXFReader();
197 // Warning: direct manipulation of MXF structures can interfere
198 // with the normal operation of the wrapper. Caveat emptor!
199 virtual ASDCP::MXF::OP1aHeader& OP1aHeader();
200 virtual AS_02::MXF::AS02IndexReader& AS02IndexReader();
201 virtual ASDCP::MXF::RIP& RIP();
203 // Open the file for reading. The file must exist. Returns error if the
204 // operation cannot be completed.
205 Result_t OpenRead(const std::string& filename) const;
207 // Returns RESULT_INIT if the file is not open.
208 Result_t Close() const;
210 // Fill a WriterInfo struct with the values from the file's header.
211 // Returns RESULT_INIT if the file is not open.
212 Result_t FillWriterInfo(ASDCP::WriterInfo&) const;
214 // Reads a frame of essence from the MXF file. If the optional AESEncContext
215 // argument is present, the essence is decrypted after reading. If the MXF
216 // file is encrypted and the AESDecContext argument is NULL, the frame buffer
217 // will contain the ciphertext frame data. If the HMACContext argument is
218 // not NULL, the HMAC will be calculated (if the file supports it).
219 // Returns RESULT_INIT if the file is not open, failure if the frame number is
220 // out of range, or if optional decrypt or HAMC operations fail.
221 Result_t ReadFrame(ui32_t frame_number, ASDCP::JP2K::FrameBuffer&, ASDCP::AESDecContext* = 0, ASDCP::HMACContext* = 0) const;
223 // Print debugging information to stream
224 void DumpHeaderMetadata(FILE* = 0) const;
225 void DumpIndex(FILE* = 0) const;
231 //---------------------------------------------------------------------------------
235 // see AS_DCP.h for related data types
237 // An AS-02 PCM file is clip-wrapped, but the interface defined below mimics that used
238 // for frame-wrapped essence elsewhere in this library. The concept of frame rate
239 // therefore is only relevant to these classes and is not reflected in or affected by
240 // the contents of the MXF file. The frame rate that is set on the writer is only
241 // for compatibility with the existing parsers, samples are packed contiguously into
242 // the same clip-wrapped packet. Similarly, the edit rate must be set when initializing
243 // the reader to signal the number of samples to be read by each call to ReadFrame();
249 ASDCP::mem_ptr<h__Writer> m_Writer;
250 ASDCP_NO_COPY_CONSTRUCT(MXFWriter);
254 virtual ~MXFWriter();
256 // Warning: direct manipulation of MXF structures can interfere
257 // with the normal operation of the wrapper. Caveat emptor!
258 virtual ASDCP::MXF::OP1aHeader& OP1aHeader();
259 virtual ASDCP::MXF::RIP& RIP();
261 // Open the file for writing. The file must not exist. Returns error if
262 // the operation cannot be completed or if nonsensical data is discovered
263 // in the essence descriptor.
264 Result_t OpenWrite(const std::string& filename, const ASDCP::WriterInfo&,
265 ASDCP::MXF::FileDescriptor* essence_descriptor,
266 ASDCP::MXF::InterchangeObject_list_t& essence_sub_descriptor_list,
267 const ASDCP::Rational& edit_rate, ui32_t HeaderSize = 16384);
269 // Writes a frame of essence to the MXF file. If the optional AESEncContext
270 // argument is present, the essence is encrypted prior to writing.
271 // Fails if the file is not open, is finalized, or an operating system
273 Result_t WriteFrame(const ASDCP::FrameBuffer&, ASDCP::AESEncContext* = 0, ASDCP::HMACContext* = 0);
275 // Closes the MXF file, writing the index and revised header.
283 ASDCP::mem_ptr<h__Reader> m_Reader;
284 ASDCP_NO_COPY_CONSTRUCT(MXFReader);
288 virtual ~MXFReader();
290 // Warning: direct manipulation of MXF structures can interfere
291 // with the normal operation of the wrapper. Caveat emptor!
292 virtual ASDCP::MXF::OP1aHeader& OP1aHeader();
293 virtual AS_02::MXF::AS02IndexReader& AS02IndexReader();
294 virtual ASDCP::MXF::RIP& RIP();
296 // Open the file for reading. The file must exist. Returns error if the
297 // operation cannot be completed.
298 Result_t OpenRead(const std::string& filename, const ASDCP::Rational& EditRate);
300 // Returns RESULT_INIT if the file is not open.
301 Result_t Close() const;
303 // Fill a WriterInfo struct with the values from the file's header.
304 // Returns RESULT_INIT if the file is not open.
305 Result_t FillWriterInfo(ASDCP::WriterInfo&) const;
307 // Reads a frame of essence from the MXF file. If the optional AESEncContext
308 // argument is present, the essence is decrypted after reading. If the MXF
309 // file is encrypted and the AESDecContext argument is NULL, the frame buffer
310 // will contain the ciphertext frame data. If the HMACContext argument is
311 // not NULL, the HMAC will be calculated (if the file supports it).
312 // Returns RESULT_INIT if the file is not open, failure if the frame number is
313 // out of range, or if optional decrypt or HAMC operations fail.
314 Result_t ReadFrame(ui32_t frame_number, ASDCP::PCM::FrameBuffer&, ASDCP::AESDecContext* = 0, ASDCP::HMACContext* = 0) const;
316 // Print debugging information to stream
317 void DumpHeaderMetadata(FILE* = 0) const;
318 void DumpIndex(FILE* = 0) const;
322 //---------------------------------------------------------------------------------
326 using ASDCP::TimedText::TimedTextDescriptor;
327 using ASDCP::TimedText::TimedTextResourceDescriptor;
328 using ASDCP::TimedText::ResourceList_t;
331 class ST2052_TextParser
334 ASDCP::mem_ptr<h__TextParser> m_Parser;
335 ASDCP_NO_COPY_CONSTRUCT(ST2052_TextParser);
339 virtual ~ST2052_TextParser();
341 // Opens an XML file for reading, parses data to provide a complete
342 // set of stream metadata for the MXFWriter below.
343 Result_t OpenRead(const std::string& filename) const;
345 // Parse an XML string
346 Result_t OpenRead(const std::string& xml_doc, const std::string& filename) const;
348 // Fill a TimedTextDescriptor struct with the values from the file's contents.
349 // Returns RESULT_INIT if the file is not open.
350 Result_t FillTimedTextDescriptor(ASDCP::TimedText::TimedTextDescriptor&) const;
352 // Reads the complete Timed Text Resource into the given string.
353 Result_t ReadTimedTextResource(std::string&) const;
355 // Reads the Ancillary Resource having the given ID. Fails if the buffer
356 // is too small or the resource does not exist. The optional Resolver
357 // argument can be provided which will be used to retrieve the resource
358 // having a particulat UUID. If a Resolver is not supplied, the default
359 // internal resolver will return the contents of the file having the UUID
360 // as the filename. The filename must exist in the same directory as the
361 // XML file opened with OpenRead().
362 Result_t ReadAncillaryResource(const Kumu::UUID&, ASDCP::TimedText::FrameBuffer&,
363 const ASDCP::TimedText::IResourceResolver* Resolver = 0) const;
370 ASDCP::mem_ptr<h__Writer> m_Writer;
371 ASDCP_NO_COPY_CONSTRUCT(MXFWriter);
375 virtual ~MXFWriter();
377 // Warning: direct manipulation of MXF structures can interfere
378 // with the normal operation of the wrapper. Caveat emptor!
379 virtual ASDCP::MXF::OP1aHeader& OP1aHeader();
380 virtual ASDCP::MXF::RIP& RIP();
382 // Open the file for writing. The file must not exist. Returns error if
383 // the operation cannot be completed or if nonsensical data is discovered
384 // in the essence descriptor.
385 Result_t OpenWrite(const std::string& filename, const ASDCP::WriterInfo&,
386 const ASDCP::TimedText::TimedTextDescriptor&, ui32_t HeaderSize = 16384);
388 // Writes the Timed-Text Resource to the MXF file. The file must be UTF-8
389 // encoded. If the optional AESEncContext argument is present, the essence
390 // is encrypted prior to writing. Fails if the file is not open, is finalized,
391 // or an operating system error occurs.
392 // This method may only be called once, and it must be called before any
393 // call to WriteAncillaryResource(). RESULT_STATE will be returned if these
394 // conditions are not met.
395 Result_t WriteTimedTextResource(const std::string& XMLDoc, ASDCP::AESEncContext* = 0, ASDCP::HMACContext* = 0);
397 // Writes an Ancillary Resource to the MXF file. If the optional AESEncContext
398 // argument is present, the essence is encrypted prior to writing.
399 // Fails if the file is not open, is finalized, or an operating system
400 // error occurs. RESULT_STATE will be returned if the method is called before
401 // WriteTimedTextResource()
402 Result_t WriteAncillaryResource(const ASDCP::TimedText::FrameBuffer&, ASDCP::AESEncContext* = 0, ASDCP::HMACContext* = 0);
404 // Closes the MXF file, writing the index and revised header.
412 ASDCP::mem_ptr<h__Reader> m_Reader;
413 ASDCP_NO_COPY_CONSTRUCT(MXFReader);
417 virtual ~MXFReader();
419 // Warning: direct manipulation of MXF structures can interfere
420 // with the normal operation of the wrapper. Caveat emptor!
421 virtual ASDCP::MXF::OP1aHeader& OP1aHeader();
422 virtual AS_02::MXF::AS02IndexReader& AS02IndexReader();
423 virtual ASDCP::MXF::RIP& RIP();
425 // Open the file for reading. The file must exist. Returns error if the
426 // operation cannot be completed.
427 Result_t OpenRead(const std::string& filename) const;
429 // Returns RESULT_INIT if the file is not open.
430 Result_t Close() const;
432 // Fill a TimedTextDescriptor struct with the values from the file's header.
433 // Returns RESULT_INIT if the file is not open.
434 Result_t FillTimedTextDescriptor(ASDCP::TimedText::TimedTextDescriptor&) const;
436 // Fill a WriterInfo struct with the values from the file's header.
437 // Returns RESULT_INIT if the file is not open.
438 Result_t FillWriterInfo(ASDCP::WriterInfo&) const;
440 // Reads the complete Timed Text Resource into the given string. Fails if the resource
441 // is encrypted and AESDecContext is NULL (use the following method to retrieve the
442 // raw ciphertet block).
443 Result_t ReadTimedTextResource(std::string&, ASDCP::AESDecContext* = 0, ASDCP::HMACContext* = 0) const;
445 // Reads the complete Timed Text Resource from the MXF file. If the optional AESEncContext
446 // argument is present, the resource is decrypted after reading. If the MXF
447 // file is encrypted and the AESDecContext argument is NULL, the frame buffer
448 // will contain the ciphertext frame data. If the HMACContext argument is
449 // not NULL, the HMAC will be calculated (if the file supports it).
450 // Returns RESULT_INIT if the file is not open, failure if the frame number is
451 // out of range, or if optional decrypt or HAMC operations fail.
452 Result_t ReadTimedTextResource(ASDCP::TimedText::FrameBuffer&, ASDCP::AESDecContext* = 0, ASDCP::HMACContext* = 0) const;
454 // Reads the timed-text resource having the given UUID from the MXF file. If the
455 // optional AESEncContext argument is present, the resource is decrypted after
456 // reading. If the MXF file is encrypted and the AESDecContext argument is NULL,
457 // the frame buffer will contain the ciphertext frame data. If the HMACContext
458 // argument is not NULL, the HMAC will be calculated (if the file supports it).
459 // Returns RESULT_INIT if the file is not open, failure if the frame number is
460 // out of range, or if optional decrypt or HAMC operations fail.
461 Result_t ReadAncillaryResource(const Kumu::UUID&, ASDCP::TimedText::FrameBuffer&, ASDCP::AESDecContext* = 0, ASDCP::HMACContext* = 0) const;
463 // Print debugging information to stream
464 void DumpHeaderMetadata(FILE* = 0) const;
465 void DumpIndex(FILE* = 0) const;
467 } // namespace TimedText