Added library names
[asdcplib.git] / src / AS_02_ACES.h
1 /*
2 Copyright (c) 2018, Bjoern Stresing, Patrick Bichiou, Wolfgang Ruppel,
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 /*
30 This module implements MXF AS-02 IMF App #1 ACES. It's a set of file access objects that
31 offer simplified access to files conforming to the draft IMF App #1 ACES. The file
32 format, labeled IMF Essence Component (AKA "AS-02" for historical
33 reasons), is described in the following document:
34
35 o SMPTE 2067-5:2013 IMF Essence Component
36
37 The following use cases are supported by the module:
38
39 o Write essence to a plaintext or ciphertext AS-02 file:
40 ACES codestreams
41
42 o Read essence from a plaintext or ciphertext AS-02 file:
43 ACES codestreams
44
45 o Read header metadata from an AS-02 file
46 */
47
48 #ifndef AS_02_ACES_h__
49 #define AS_02_ACES_h__
50
51 #include "AS_DCP.h"
52 #include "AS_02.h"
53 #include "Metadata.h"
54 #include <vector>
55
56
57 typedef ui16_t      real16_t;
58 typedef float       real32_t;
59 typedef double      real64_t;
60
61 namespace AS_02
62 {
63
64 using Kumu::Result_t;
65 using Kumu::RESULT_FALSE;
66 using Kumu::RESULT_OK;
67 using Kumu::RESULT_FAIL;
68 using Kumu::RESULT_PTR;
69 using Kumu::RESULT_NULL_STR;
70 using Kumu::RESULT_ALLOC;
71 using Kumu::RESULT_PARAM;
72 using Kumu::RESULT_NOTIMPL;
73 using Kumu::RESULT_SMALLBUF;
74 using Kumu::RESULT_INIT;
75 using Kumu::RESULT_NOT_FOUND;
76 using Kumu::RESULT_NO_PERM;
77 using Kumu::RESULT_FILEOPEN;
78 using Kumu::RESULT_BADSEEK;
79 using Kumu::RESULT_READFAIL;
80 using Kumu::RESULT_WRITEFAIL;
81 using Kumu::RESULT_STATE;
82 using Kumu::RESULT_ENDOFFILE;
83 using Kumu::RESULT_CONFIG;
84
85 ASDCP::Rational ConvertToRational(double in);
86
87 namespace ACES
88 {
89
90 static const byte_t ACESPixelLayoutMonoscopicWOAlpha[ASDCP::MXF::RGBAValueLength] = {0x42, 0xfd, 0x47, 0xfd, 0x52, 0xfd, 0x00};
91 static const byte_t ACESPixelLayoutMonoscopicWAlpha[ASDCP::MXF::RGBAValueLength] = {0x41, 0xfd, 0x42, 0xfd, 0x47, 0xfd, 0x52, 0xfd, 0x00};
92
93 enum eAttributes
94 {
95
96   Invalid = 0,
97   AcesImageContainerFlag,
98   Channels,
99   Chromaticities,
100   Compression,
101   DataWindow,
102   DisplayWindow,
103   LineOrder,
104   PixelAspectRatio,
105   ScreenWindowCenter,
106   SreenWindowWidth,
107   Other
108 };
109
110 enum eTypes
111 {
112
113   Unknown_t = 0,
114   UnsignedChar_t,
115   Short_t,
116   UnsignedShort_t,
117   Int_t,
118   UnsignedInt_t,
119   UnsignedLong_t,
120   Half_t,
121   Float_t,
122   Double_t,
123   Box2i_t,
124   Chlist_t,
125   Chromaticities_t,
126   Compression_t,
127   LineOrder_t,
128   Keycode_t,
129   Rational_t,
130   String_t,
131   StringVector_t,
132   Timecode_t,
133   V2f_t,
134   V3f_t
135 };
136
137 struct channel
138 {
139   std::string  name; // Shall be one of R, G, B, Left.R, Left.G, Left.B
140   i32_t  pixelType;
141   ui32_t  pLinear;
142   i32_t  xSampling;
143   i32_t  ySampling;
144   bool operator==(const channel &Other) const;
145   bool operator!=(const channel &Other) const { return !(*this == Other); }
146 };
147
148 struct box2i
149 {
150   i32_t xMin;
151   i32_t yMin;
152   i32_t xMax;
153   i32_t yMax;
154   bool operator==(const box2i &Other) const;
155   bool operator!=(const box2i &Other) const { return !(*this == Other); }
156 };
157
158 struct keycode
159 {
160   i32_t filmMfcCode; //  0 .. 99
161   i32_t filmType; //  0 .. 99
162   i32_t prefix; //  0 .. 999999
163   i32_t count; //  0 .. 9999
164   i32_t perfOffset; //  1 .. 119
165   i32_t perfsPerFrame; //  1 .. 15
166   i32_t perfsPerCount; //  20 .. 120
167   bool operator==(const keycode &Other) const;
168   bool operator!=(const keycode &Other) const { return !(*this == Other); }
169 };
170
171 struct v2f
172 {
173   real32_t x;
174   real32_t y;
175   bool operator==(const v2f &Other) const;
176   bool operator!=(const v2f &Other) const { return !(*this == Other); }
177 };
178
179 struct v3f
180 {
181   real32_t x;
182   real32_t y;
183   real32_t z;
184   bool operator==(const v3f &Other) const;
185   bool operator!=(const v3f &Other) const { return !(*this == Other); }
186 };
187
188 struct chromaticities
189 {
190   v2f red;
191   v2f green;
192   v2f blue;
193   v2f white;
194   bool operator==(const chromaticities &Other) const;
195   bool operator!=(const chromaticities &Other) const { return !(*this == Other); }
196 };
197
198 struct timecode
199 {
200   ui32_t timeAndFlags;
201   ui32_t userData;
202   bool operator==(const timecode &Other) const;
203   bool operator!=(const timecode &Other) const { return !(*this == Other); }
204 };
205
206 // Extract optional metadata with ACESDataAccessor functions.
207 struct generic
208 {
209   generic() : type(Unknown_t), size(0) {}
210   std::string attributeName;
211   eTypes type;
212   ui16_t size;
213   byte_t data[1024];
214 };
215
216 typedef std::vector<channel> chlist;
217 typedef std::vector<std::string> stringVector;
218 typedef std::vector<generic> other;
219
220 enum MIMEType_t { MT_PNG, MT_TIFF, MT_UNDEF };
221
222 const char*
223 MIME2str(AS_02::ACES::MIMEType_t m);
224
225 struct AncillaryResourceDescriptor
226 {
227   byte_t      ResourceID[16];
228   MIMEType_t  Type;
229   std::string  filePath;
230
231   AncillaryResourceDescriptor() : Type(MT_UNDEF) {}
232 };
233
234 typedef std::list<AncillaryResourceDescriptor> ResourceList_t;
235
236
237 struct PictureDescriptor
238 {
239   ASDCP::Rational  EditRate;
240   ui32_t      ContainerDuration;
241   ASDCP::Rational SampleRate;
242
243   i32_t      AcesImageContainerFlag;
244   chromaticities  Chromaticities;
245   ui8_t      Compression; // shall be 0
246   ui8_t      LineOrder; // 0 increasing Y line order, 1 decreasing Y line order. Should be 0
247   box2i      DataWindow;
248   box2i      DisplayWindow;
249   real32_t    PixelAspectRatio;
250   v2f                                  ScreenWindowCenter;
251   real32_t    ScreenWindowWidth;
252   chlist      Channels; // vector
253   other      Other; // vector
254   //ResourceList_t   ResourceList;
255
256   // Doesn't compare Other.
257   bool operator==(const PictureDescriptor &Other) const;
258   // Doesn't compare Other.
259   bool operator!=(const PictureDescriptor &Other) const { return !(*this == Other); }
260 };
261
262 // Print debugging information to std::ostream
263 std::ostream& operator << (std::ostream &strm, const PictureDescriptor &PDesc);
264 // Print debugging information to stream (stderr default)
265 void PictureDescriptorDump(const PictureDescriptor &PDesc, FILE *stream = NULL);
266 // Convert a PictureDescriptor to MXF RGBA Picture Essence Descriptor.
267 // ACESVersion defaults to 0.0.0 Unknown
268 // OdtId defaults to 0 == None
269 // You may want to change ACESVersion and/or OdtId afterwards
270 Result_t ACES_PDesc_to_MD(const PictureDescriptor &PDesc,
271                           const ASDCP::Dictionary &dict,
272                           ASDCP::MXF::RGBAEssenceDescriptor &EssenceDescriptor);
273
274 const byte_t PNGMagic[8] = { 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a };
275 const byte_t TIFFMagicLE[4] = { 0x49, 0x49, 0x2a, 0x00 };
276 const byte_t TIFFMagicBE[4] = { 0x4d, 0x4d, 0x00, 0x2a };
277
278 //
279 int const NS_ID_LENGTH = 16;
280 //
281 static byte_t s_ns_id_target_frame_prefix[NS_ID_LENGTH] =
282 {
283   // RFC 4122 type 5
284   // 2067-50 8.2.5.4 / RFC4122 Appendix C
285   //urn:uuid:bba41561-c505-4c9c-ab5a-71c68c2d70ea
286   0xbb, 0xa4, 0x15, 0x61, 0xc5, 0x05, 0x4c, 0x9c,
287   0xab, 0x5a, 0x71, 0xc6, 0x8c, 0x2d, 0x70, 0xea
288 };
289 static byte_t  s_asset_id_prefix[NS_ID_LENGTH] =
290 {
291   // RFC 4122 type 5
292   // 2067-2:2016 7.3.1
293     0xaf, 0x86, 0xb7, 0xec, 0x4c, 0xdf, 0x4f, 0x9f,
294     0x82, 0x0f, 0x6f, 0xd8, 0xd3, 0x00, 0x30, 0x23
295 };
296 // Generate UUID asset ID values from target frame file contents
297 AS_02::Result_t CreateTargetFrameAssetId(Kumu::UUID& rID, const std::string& target_frame_file);
298 static Kumu::UUID create_4122_type5_id(const byte_t* subject_name, Kumu::fsize_t size, const byte_t* ns_id);
299
300 class FrameBuffer : public ASDCP::FrameBuffer
301 {
302 public:
303   FrameBuffer() {}
304   FrameBuffer(ui32_t size) { Capacity(size); }
305   virtual ~FrameBuffer() {}
306
307   // Print debugging information to stream (stderr default)
308   void Dump(FILE *stream = NULL, ui32_t dump_bytes = 0) const;
309 };
310
311 // Parses the data in the frame buffer to fill in the picture descriptor. Copies
312 // the offset of the image data into start_of_data. Returns error if the parser fails.
313 Result_t ParseMetadataIntoDesc(const FrameBuffer &FB, PictureDescriptor &PDesc, byte_t *start_of_data = NULL);
314
315
316 // An object which opens and reads a ACES codestream file. The file is expected
317 // to contain exactly one complete frame of picture essence as an unwrapped codestream.
318 class CodestreamParser
319 {
320   class h__CodestreamParser;
321   ASDCP::mem_ptr<h__CodestreamParser> m_Parser;
322   ASDCP_NO_COPY_CONSTRUCT(CodestreamParser);
323
324 public:
325   CodestreamParser();
326   virtual ~CodestreamParser();
327
328   // Opens a file for reading, parses enough data to provide a complete
329   // set of stream metadata for the MXFWriter below.
330   // The frame buffer's PlaintextOffset parameter will be set to the first
331   // byte of the data segment. Set this value to zero if you want
332   // encrypted headers.
333   Result_t OpenReadFrame(const std::string &filename, FrameBuffer &FB) const;
334
335   // Fill a PictureDescriptor struct with the values from the file's codestream.
336   // Returns RESULT_INIT if the file is not open.
337   Result_t FillPictureDescriptor(PictureDescriptor &PDesc) const;
338 };
339
340
341 class SequenceParser
342 {
343   class h__SequenceParser;
344   ASDCP::mem_ptr<h__SequenceParser> m_Parser;
345   ASDCP_NO_COPY_CONSTRUCT(SequenceParser);
346
347 public:
348   SequenceParser();
349   virtual ~SequenceParser();
350
351   // Opens a directory for reading.  The directory is expected to contain one or
352   // more files, each containing the codestream for exactly one picture. The
353   // files must be named such that the frames are in temporal order when sorted
354   // alphabetically by filename. The parser will automatically parse enough data
355   // from the first file to provide a complete set of stream metadata for the
356   // MXFWriter below.  If the "pedantic" parameter is given and is true, the
357   // parser will check the metadata for each codestream and fail if a
358   // mismatch is detected.
359   Result_t OpenRead(const std::string &directory, bool pedantic = false, const std::list<std::string> &target_frame_file_list = std::list<std::string>()) const;
360
361   // Opens a file sequence for reading.  The sequence is expected to contain one or
362   // more filenames, each naming a file containing the codestream for exactly one
363   // picture. The parser will automatically parse enough data
364   // from the first file to provide a complete set of stream metadata for the
365   // MXFWriter below.  If the "pedantic" parameter is given and is true, the
366   // parser will check the metadata for each codestream and fail if a
367   // mismatch is detected.
368   Result_t OpenRead(const std::list<std::string> &file_list, bool pedantic = false, const std::list<std::string> &target_frame_file_list = std::list<std::string>()) const;
369
370   // Fill a PictureDescriptor struct with the values from the first file's codestream.
371   // Returns RESULT_INIT if the directory is not open.
372   Result_t FillPictureDescriptor(PictureDescriptor &PDesc) const;
373
374   // Fill a ResourceList_t struct with the value from the sequence parser.
375   // Returns RESULT_INIT if empty.
376   Result_t FillResourceList(ResourceList_t &rResourceList_t) const;
377
378   // Rewind the directory to the beginning.
379   Result_t Reset() const;
380
381   // Reads the next sequential frame in the directory and places it in the
382   // frame buffer. Fails if the buffer is too small or the directory
383   // contains no more files.
384   // The frame buffer's PlaintextOffset parameter will be set to the first
385   // byte of the data segment. Set this value to zero if you want
386   // encrypted headers.
387   Result_t ReadFrame(FrameBuffer &FB) const;
388
389   Result_t ReadAncillaryResource(const std::string &filename, FrameBuffer &FB) const;
390 };
391
392
393 class MXFWriter
394 {
395   class h__Writer;
396   ASDCP::mem_ptr<h__Writer> m_Writer;
397   ASDCP_NO_COPY_CONSTRUCT(MXFWriter);
398
399 public:
400   MXFWriter();
401   virtual ~MXFWriter();
402
403   // Warning: direct manipulation of MXF structures can interfere
404   // with the normal operation of the wrapper.  Caveat emptor!
405   virtual ASDCP::MXF::OP1aHeader& OP1aHeader();
406   virtual ASDCP::MXF::RIP& RIP();
407
408   // Open the file for writing. The file must not exist. Returns error if
409   // the operation cannot be completed or if nonsensical data is discovered
410   // in the essence descriptor.
411   Result_t OpenWrite(const std::string &filename, const ASDCP::WriterInfo &Info,
412                                  ASDCP::MXF::FileDescriptor *essence_descriptor,
413                                  ASDCP::MXF::InterchangeObject_list_t& essence_sub_descriptor_list,
414                                  const ASDCP::Rational &edit_rate,
415                                  const ResourceList_t &ancillary_resources = ResourceList_t(),
416                                  const ui32_t &header_size = 16384,
417                                  const AS_02::IndexStrategy_t &strategy = AS_02::IS_FOLLOW,
418                                  const ui32_t &partition_space = 10);
419
420   // Writes a frame of essence to the MXF file. If the optional AESEncContext
421   // argument is present, the essence is encrypted prior to writing.
422   // Fails if the file is not open, is finalized, or an operating system
423   // error occurs.
424   Result_t WriteFrame(const FrameBuffer &FrameBuf, ASDCP::AESEncContext *Ctx = NULL, ASDCP::HMACContext *HMAC = NULL);
425
426   // Writes an Ancillary Resource to the MXF file. If the optional AESEncContext
427   // argument is present, the essence is encrypted prior to writing.
428   // Fails if the file is not open, is finalized, or an operating system
429   // error occurs. RESULT_STATE will be returned if the method is called before
430   // WriteFrame()
431   Result_t WriteAncillaryResource(const AS_02::ACES::FrameBuffer &rBuf, ASDCP::AESEncContext* = 0, ASDCP::HMACContext* = 0);
432
433   // Closes the MXF file, writing the index and revised header.
434   Result_t Finalize();
435 };
436
437
438 class MXFReader
439 {
440   class h__Reader;
441   ASDCP::mem_ptr<h__Reader> m_Reader;
442   ASDCP_NO_COPY_CONSTRUCT(MXFReader);
443
444 public:
445   MXFReader();
446   virtual ~MXFReader();
447
448   // Warning: direct manipulation of MXF structures can interfere
449   // with the normal operation of the wrapper.  Caveat emptor!
450   virtual ASDCP::MXF::OP1aHeader& OP1aHeader();
451   virtual AS_02::MXF::AS02IndexReader& AS02IndexReader();
452   virtual ASDCP::MXF::RIP& RIP();
453
454   // Open the file for reading. The file must exist. Returns error if the
455   // operation cannot be completed.
456   Result_t OpenRead(const std::string &filename) const;
457
458   // Fill a ResourceList_t struct with the ancillary resources that are present in the file.
459   // Returns RESULT_INIT if the file is not open.
460   Result_t FillAncillaryResourceList(AS_02::ACES::ResourceList_t &ancillary_resources) const;
461
462   // Returns RESULT_INIT if the file is not open.
463   Result_t Close() const;
464
465   // Fill a WriterInfo struct with the values from the file's header.
466   // Returns RESULT_INIT if the file is not open.
467   Result_t FillWriterInfo(ASDCP::WriterInfo &Info) const;
468
469   // Reads a frame of essence from the MXF file. If the optional AESEncContext
470   // argument is present, the essence is decrypted after reading. If the MXF
471   // file is encrypted and the AESDecContext argument is NULL, the frame buffer
472   // will contain the ciphertext frame data. If the HMACContext argument is
473   // not NULL, the HMAC will be calculated (if the file supports it).
474   // Returns RESULT_INIT if the file is not open, failure if the frame number is
475   // out of range, or if optional decrypt or HAMC operations fail.
476   Result_t ReadFrame(ui32_t FrameNum, AS_02::ACES::FrameBuffer &FrameBuf, ASDCP::AESDecContext *Ctx = 0, ASDCP::HMACContext *HMAC = 0) const;
477
478   // Reads the ancillary resource having the given UUID from the MXF file. If the
479   // optional AESEncContext argument is present, the resource is decrypted after
480   // reading. If the MXF file is encrypted and the AESDecContext argument is NULL,
481   // the frame buffer will contain the ciphertext frame data. If the HMACContext
482   // argument is not NULL, the HMAC will be calculated (if the file supports it).
483   // Returns RESULT_INIT if the file is not open, failure if the frame number is
484   // out of range, or if optional decrypt or HAMC operations fail.
485   Result_t ReadAncillaryResource(const Kumu::UUID&, AS_02::ACES::FrameBuffer&, ASDCP::AESDecContext* = 0, ASDCP::HMACContext* = 0) const;
486
487   // Print debugging information to stream
488          void     DumpHeaderMetadata(FILE* = 0) const;
489          void     DumpIndex(FILE* = 0) const;
490
491 };
492 } // namespace ACES
493
494 } // namespace AS_02
495
496 #endif // AS_02_ACES_h__