o Added preliminary support for timed-text wrapping for AS-02. This
[asdcplib.git] / src / AS_02.h
1 /*
2 Copyright (c) 2011-2013, Robert Scheler, Heiko Sparenberg Fraunhofer IIS,
3 John Hurst
4
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
9 are met:
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.
17
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.
28 */ 
29 /*! \file    AS_02.h
30     \version $Id$       
31     \brief   AS-02 library, public interface
32
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:
38
39  o SMPTE 2067-5:2013 IMF Essence Component
40
41 The following use cases are supported by the module:
42
43  o Write essence to a plaintext or ciphertext AS-02 file:
44      JPEG 2000 codestreams
45      PCM audio streams
46
47  o Read essence from a plaintext or ciphertext AS-02 file:
48      JPEG 2000 codestreams
49      PCM audio streams
50
51  o Read header metadata from an AS-02 file
52
53 NOTE: ciphertext support for clip-wrapped PCM is not yet complete.
54 */
55
56 #ifndef _AS_02_H_
57 #define _AS_02_H_
58
59 #include "Metadata.h"
60
61
62 namespace AS_02
63 {
64   using Kumu::Result_t;
65
66   KM_DECLARE_RESULT(AS02_FORMAT,        -116, "The file format is not proper OP-1a/AS-02.");
67
68   namespace MXF {
69     //
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
74     {
75       Kumu::ByteString m_IndexSegmentData;
76       ui32_t m_Duration;
77       ui32_t m_BytesPerEditUnit;
78
79       Result_t InitFromBuffer(const byte_t* p, ui32_t l, const ui64_t& body_offset, const ui64_t& essence_container_offset);
80
81       ASDCP_NO_COPY_CONSTRUCT(AS02IndexReader);
82       AS02IndexReader();
83           
84     public:
85       const ASDCP::Dictionary*&   m_Dict;
86       ASDCP::IPrimerLookup *m_Lookup;
87     
88       AS02IndexReader(const ASDCP::Dictionary*&);
89       virtual ~AS02IndexReader();
90     
91       Result_t InitFromFile(const Kumu::FileReader& reader, const ASDCP::MXF::RIP& rip, const bool has_header_essence);
92       ui32_t GetDuration() const;
93       void     Dump(FILE* = 0);
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;
98     };
99
100
101     
102     // Returns size in bytes of a single sample of data described by ADesc
103     inline ui32_t CalcSampleSize(const ASDCP::MXF::WaveAudioDescriptor& d)
104     {
105       return (d.QuantizationBits / 8) * d.ChannelCount;
106     }
107
108       // Returns number of samples per frame of data described by ADesc
109     inline ui32_t CalcSamplesPerFrame(const ASDCP::MXF::WaveAudioDescriptor& d, const ASDCP::Rational& edit_rate)
110     {
111       double tmpd = d.AudioSamplingRate.Quotient() / edit_rate.Quotient();
112       return (ui32_t)ceil(tmpd);
113     }
114
115     // Returns the size in bytes of a frame of data described by ADesc
116     inline ui32_t CalcFrameBufferSize(const ASDCP::MXF::WaveAudioDescriptor& d, const ASDCP::Rational& edit_rate)
117     {
118       return CalcSampleSize(d) * CalcSamplesPerFrame(d, edit_rate);
119     }
120
121     // Returns number of frames for data described by ADesc, given a duration in samples and an edit rate
122     inline ui32_t CalcFramesFromDurationInSamples(const ui32_t durationInSamples, const ASDCP::MXF::WaveAudioDescriptor& d, const ASDCP::Rational& edit_rate)
123     {
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));
127     }
128
129   } // namespace MXF
130
131   //---------------------------------------------------------------------------------
132   // Accessors in the MXFReader and MXFWriter classes below return these types to
133   // provide direct access to MXF metadata structures declared in MXF.h and Metadata.h
134
135   // See ST 2067-5 Sec. x.y.z
136   enum IndexStrategy_t
137   {
138     IS_LEAD,
139     IS_FOLLOW,
140     IS_FILE_SPECIFIC,
141     IS_MAX
142   };
143  
144   namespace JP2K
145   {
146     //
147     class MXFWriter
148     {
149       class h__Writer;
150       ASDCP::mem_ptr<h__Writer> m_Writer;
151       ASDCP_NO_COPY_CONSTRUCT(MXFWriter);
152       
153     public:
154       MXFWriter();
155       virtual ~MXFWriter();
156
157       // Warning: direct manipulation of MXF structures can interfere
158       // with the normal operation of the wrapper.  Caveat emptor!
159       virtual ASDCP::MXF::OP1aHeader& OP1aHeader();
160       virtual ASDCP::MXF::RIP& RIP();
161
162       // Open the file for writing. The file must not exist. Returns error if
163       // the operation cannot be completed or if nonsensical data is discovered
164       // in the essence descriptor.
165       Result_t OpenWrite(const std::string& filename, const ASDCP::WriterInfo&,
166                          ASDCP::MXF::FileDescriptor* essence_descriptor,
167                          ASDCP::MXF::InterchangeObject_list_t& essence_sub_descriptor_list,
168                          const ASDCP::Rational& edit_rate, const ui32_t& header_size = 16384,
169                          const IndexStrategy_t& strategy = IS_FOLLOW, const ui32_t& partition_space = 10);
170       
171       // Writes a frame of essence to the MXF file. If the optional AESEncContext
172       // argument is present, the essence is encrypted prior to writing.
173       // Fails if the file is not open, is finalized, or an operating system
174       // error occurs.
175       Result_t WriteFrame(const ASDCP::JP2K::FrameBuffer&, ASDCP::AESEncContext* = 0, ASDCP::HMACContext* = 0);
176
177       // Closes the MXF file, writing the index and revised header.
178       Result_t Finalize();
179     };
180
181     //
182     class MXFReader
183     {
184       class h__Reader;
185       ASDCP::mem_ptr<h__Reader> m_Reader;
186       ASDCP_NO_COPY_CONSTRUCT(MXFReader);
187
188     public:
189       MXFReader();
190       virtual ~MXFReader();
191
192       // Warning: direct manipulation of MXF structures can interfere
193       // with the normal operation of the wrapper.  Caveat emptor!
194       virtual ASDCP::MXF::OP1aHeader& OP1aHeader();
195       virtual AS_02::MXF::AS02IndexReader& AS02IndexReader();
196       virtual ASDCP::MXF::RIP& RIP();
197
198       // Open the file for reading. The file must exist. Returns error if the
199       // operation cannot be completed.
200       Result_t OpenRead(const std::string& filename) const;
201
202       // Returns RESULT_INIT if the file is not open.
203       Result_t Close() const;
204
205       // Fill a WriterInfo struct with the values from the file's header.
206       // Returns RESULT_INIT if the file is not open.
207       Result_t FillWriterInfo(ASDCP::WriterInfo&) const;
208
209       // Reads a frame of essence from the MXF file. If the optional AESEncContext
210       // argument is present, the essence is decrypted after reading. If the MXF
211       // file is encrypted and the AESDecContext argument is NULL, the frame buffer
212       // will contain the ciphertext frame data. If the HMACContext argument is
213       // not NULL, the HMAC will be calculated (if the file supports it).
214       // Returns RESULT_INIT if the file is not open, failure if the frame number is
215       // out of range, or if optional decrypt or HAMC operations fail.
216       Result_t ReadFrame(ui32_t frame_number, ASDCP::JP2K::FrameBuffer&, ASDCP::AESDecContext* = 0, ASDCP::HMACContext* = 0) const;
217
218       // Print debugging information to stream
219       void     DumpHeaderMetadata(FILE* = 0) const;
220       void     DumpIndex(FILE* = 0) const;
221     };
222     
223   } //namespace JP2K
224   
225
226   //---------------------------------------------------------------------------------
227   //
228   namespace PCM
229   {
230     // see AS_DCP.h for related data types
231
232     // An AS-02 PCM file is clip-wrapped, but the interface defined below mimics that used
233     // for frame-wrapped essence elsewhere in this library.  The concept of frame rate
234     // therefore is only relevant to these classes and is not reflected in or affected by
235     // the contents of the MXF file.  The frame rate that is set on the writer is only
236     // for compatibility with the existing parsers, samples are packed contiguously into
237     // the same clip-wrapped packet.  Similarly, the edit rate must be set when initializing
238     // the reader to signal the number of samples to be read by each call to ReadFrame();
239
240     //
241     class MXFWriter
242     {
243       class h__Writer;
244       ASDCP::mem_ptr<h__Writer> m_Writer;
245       ASDCP_NO_COPY_CONSTRUCT(MXFWriter);
246
247     public:
248       MXFWriter();
249       virtual ~MXFWriter();
250
251       // Warning: direct manipulation of MXF structures can interfere
252       // with the normal operation of the wrapper.  Caveat emptor!
253       virtual ASDCP::MXF::OP1aHeader& OP1aHeader();
254       virtual ASDCP::MXF::RIP& RIP();
255
256       // Open the file for writing. The file must not exist. Returns error if
257       // the operation cannot be completed or if nonsensical data is discovered
258       // in the essence descriptor.
259       Result_t OpenWrite(const std::string& filename, const ASDCP::WriterInfo&,
260                          ASDCP::MXF::FileDescriptor* essence_descriptor,
261                          ASDCP::MXF::InterchangeObject_list_t& essence_sub_descriptor_list,
262                          const ASDCP::Rational& edit_rate, ui32_t HeaderSize = 16384);
263
264       // Writes a frame of essence to the MXF file. If the optional AESEncContext
265       // argument is present, the essence is encrypted prior to writing.
266       // Fails if the file is not open, is finalized, or an operating system
267       // error occurs.
268       Result_t WriteFrame(const ASDCP::FrameBuffer&, ASDCP::AESEncContext* = 0, ASDCP::HMACContext* = 0);
269       
270       // Closes the MXF file, writing the index and revised header.
271       Result_t Finalize();
272     };
273
274     //
275     class MXFReader
276     {
277       class h__Reader;
278       ASDCP::mem_ptr<h__Reader> m_Reader;
279       ASDCP_NO_COPY_CONSTRUCT(MXFReader);
280
281     public:
282       MXFReader();
283       virtual ~MXFReader();
284
285       // Warning: direct manipulation of MXF structures can interfere
286       // with the normal operation of the wrapper.  Caveat emptor!
287       virtual ASDCP::MXF::OP1aHeader& OP1aHeader();
288       virtual AS_02::MXF::AS02IndexReader& AS02IndexReader();
289       virtual ASDCP::MXF::RIP& RIP();
290
291       // Open the file for reading. The file must exist. Returns error if the
292       // operation cannot be completed.
293       Result_t OpenRead(const std::string& filename, const ASDCP::Rational& EditRate);
294
295       // Returns RESULT_INIT if the file is not open.
296       Result_t Close() const;
297
298       // Fill a WriterInfo struct with the values from the file's header.
299       // Returns RESULT_INIT if the file is not open.
300       Result_t FillWriterInfo(ASDCP::WriterInfo&) const;
301
302       // Reads a frame of essence from the MXF file. If the optional AESEncContext
303       // argument is present, the essence is decrypted after reading. If the MXF
304       // file is encrypted and the AESDecContext argument is NULL, the frame buffer
305       // will contain the ciphertext frame data. If the HMACContext argument is
306       // not NULL, the HMAC will be calculated (if the file supports it).
307       // Returns RESULT_INIT if the file is not open, failure if the frame number is
308       // out of range, or if optional decrypt or HAMC operations fail.
309       Result_t ReadFrame(ui32_t frame_number, ASDCP::PCM::FrameBuffer&, ASDCP::AESDecContext* = 0, ASDCP::HMACContext* = 0) const;
310       
311       // Print debugging information to stream
312       void     DumpHeaderMetadata(FILE* = 0) const;
313       void     DumpIndex(FILE* = 0) const;
314     };
315   } // namespace PCM
316
317   //---------------------------------------------------------------------------------
318   //
319   namespace TimedText
320     {
321       using ASDCP::TimedText::TimedTextDescriptor;
322       using ASDCP::TimedText::TimedTextResourceDescriptor;
323       using ASDCP::TimedText::ResourceList_t;
324
325       //
326       class ST2052_TextParser
327         {
328           class h__TextParser;
329           ASDCP::mem_ptr<h__TextParser> m_Parser;
330           ASDCP_NO_COPY_CONSTRUCT(ST2052_TextParser);
331
332         public:
333           ST2052_TextParser();
334           virtual ~ST2052_TextParser();
335
336           // Opens an XML file for reading, parses data to provide a complete
337           // set of stream metadata for the MXFWriter below.
338           Result_t OpenRead(const std::string& filename) const;
339
340           // Parse an XML string 
341           Result_t OpenRead(const std::string& xml_doc, const std::string& filename) const;
342
343           // Fill a TimedTextDescriptor struct with the values from the file's contents.
344           // Returns RESULT_INIT if the file is not open.
345           Result_t FillTimedTextDescriptor(ASDCP::TimedText::TimedTextDescriptor&) const;
346
347           // Reads the complete Timed Text Resource into the given string.
348           Result_t ReadTimedTextResource(std::string&) const;
349
350           // Reads the Ancillary Resource having the given ID. Fails if the buffer
351           // is too small or the resource does not exist. The optional Resolver
352           // argument can be provided which will be used to retrieve the resource
353           // having a particulat UUID. If a Resolver is not supplied, the default
354           // internal resolver will return the contents of the file having the UUID
355           // as the filename. The filename must exist in the same directory as the
356           // XML file opened with OpenRead().
357           Result_t ReadAncillaryResource(const Kumu::UUID&, ASDCP::TimedText::FrameBuffer&,
358                                          const ASDCP::TimedText::IResourceResolver* Resolver = 0) const;
359         };
360
361       //
362       class MXFWriter
363         {
364           class h__Writer;
365           ASDCP::mem_ptr<h__Writer> m_Writer;
366           ASDCP_NO_COPY_CONSTRUCT(MXFWriter);
367
368         public:
369           MXFWriter();
370           virtual ~MXFWriter();
371
372           // Warning: direct manipulation of MXF structures can interfere
373           // with the normal operation of the wrapper.  Caveat emptor!
374           virtual ASDCP::MXF::OP1aHeader& OP1aHeader();
375           virtual ASDCP::MXF::RIP& RIP();
376
377           // Open the file for writing. The file must not exist. Returns error if
378           // the operation cannot be completed or if nonsensical data is discovered
379           // in the essence descriptor.
380           Result_t OpenWrite(const std::string& filename, const ASDCP::WriterInfo&,
381                              const ASDCP::TimedText::TimedTextDescriptor&, ui32_t HeaderSize = 16384);
382
383           // Writes the Timed-Text Resource to the MXF file. The file must be UTF-8
384           // encoded. If the optional AESEncContext argument is present, the essence
385           // is encrypted prior to writing. Fails if the file is not open, is finalized,
386           // or an operating system error occurs.
387           // This method may only be called once, and it must be called before any
388           // call to WriteAncillaryResource(). RESULT_STATE will be returned if these
389           // conditions are not met.
390           Result_t WriteTimedTextResource(const std::string& XMLDoc, ASDCP::AESEncContext* = 0, ASDCP::HMACContext* = 0);
391
392           // Writes an Ancillary Resource to the MXF file. If the optional AESEncContext
393           // argument is present, the essence is encrypted prior to writing.
394           // Fails if the file is not open, is finalized, or an operating system
395           // error occurs. RESULT_STATE will be returned if the method is called before
396           // WriteTimedTextResource()
397           Result_t WriteAncillaryResource(const ASDCP::TimedText::FrameBuffer&, ASDCP::AESEncContext* = 0, ASDCP::HMACContext* = 0);
398
399           // Closes the MXF file, writing the index and revised header.
400           Result_t Finalize();
401         };
402
403       //
404       class MXFReader
405         {
406           class h__Reader;
407           ASDCP::mem_ptr<h__Reader> m_Reader;
408           ASDCP_NO_COPY_CONSTRUCT(MXFReader);
409
410         public:
411           MXFReader();
412           virtual ~MXFReader();
413
414           // Warning: direct manipulation of MXF structures can interfere
415           // with the normal operation of the wrapper.  Caveat emptor!
416           virtual ASDCP::MXF::OP1aHeader& OP1aHeader();
417           virtual AS_02::MXF::AS02IndexReader& AS02IndexReader();
418           virtual ASDCP::MXF::RIP& RIP();
419
420           // Open the file for reading. The file must exist. Returns error if the
421           // operation cannot be completed.
422           Result_t OpenRead(const std::string& filename) const;
423
424           // Returns RESULT_INIT if the file is not open.
425           Result_t Close() const;
426
427           // Fill a TimedTextDescriptor struct with the values from the file's header.
428           // Returns RESULT_INIT if the file is not open.
429           Result_t FillTimedTextDescriptor(ASDCP::TimedText::TimedTextDescriptor&) const;
430
431           // Fill a WriterInfo struct with the values from the file's header.
432           // Returns RESULT_INIT if the file is not open.
433           Result_t FillWriterInfo(ASDCP::WriterInfo&) const;
434
435           // Reads the complete Timed Text Resource into the given string. Fails if the resource
436           // is encrypted and AESDecContext is NULL (use the following method to retrieve the
437           // raw ciphertet block).
438           Result_t ReadTimedTextResource(std::string&, ASDCP::AESDecContext* = 0, ASDCP::HMACContext* = 0) const;
439
440           // Reads the complete Timed Text Resource from the MXF file. If the optional AESEncContext
441           // argument is present, the resource is decrypted after reading. If the MXF
442           // file is encrypted and the AESDecContext argument is NULL, the frame buffer
443           // will contain the ciphertext frame data. If the HMACContext argument is
444           // not NULL, the HMAC will be calculated (if the file supports it).
445           // Returns RESULT_INIT if the file is not open, failure if the frame number is
446           // out of range, or if optional decrypt or HAMC operations fail.
447           Result_t ReadTimedTextResource(ASDCP::TimedText::FrameBuffer&, ASDCP::AESDecContext* = 0, ASDCP::HMACContext* = 0) const;
448
449           // Reads the timed-text resource having the given UUID from the MXF file. If the
450           // optional AESEncContext argument is present, the resource is decrypted after
451           // reading. If the MXF file is encrypted and the AESDecContext argument is NULL,
452           // the frame buffer will contain the ciphertext frame data. If the HMACContext
453           // argument is not NULL, the HMAC will be calculated (if the file supports it).
454           // Returns RESULT_INIT if the file is not open, failure if the frame number is
455           // out of range, or if optional decrypt or HAMC operations fail.
456           Result_t ReadAncillaryResource(const Kumu::UUID&, ASDCP::TimedText::FrameBuffer&, ASDCP::AESDecContext* = 0, ASDCP::HMACContext* = 0) const;
457
458           // Print debugging information to stream
459           void     DumpHeaderMetadata(FILE* = 0) const;
460           void     DumpIndex(FILE* = 0) const;
461         };
462     } // namespace TimedText
463
464
465 } // namespace AS_02
466
467 #endif // _AS_02_H_
468
469 //
470 // end AS_02.h
471 //