/* Copyright (c) 2005-2019, John Hurst All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /*! \file MXFTypes.h \version $Id$ \brief MXF objects */ #ifndef _MXFTYPES_H_ #define _MXFTYPES_H_ #include "KLV.h" #include "AS_DCP.h" #include #include #include #include #include // used with TLVReader::Read* // // these are used below to manufacture arguments #define OBJ_READ_ARGS(s,l) m_Dict->Type(MDD_##s##_##l), &l #define OBJ_WRITE_ARGS(s,l) m_Dict->Type(MDD_##s##_##l), &l #define OBJ_READ_ARGS_OPT(s,l) m_Dict->Type(MDD_##s##_##l), &l.get() #define OBJ_WRITE_ARGS_OPT(s,l) m_Dict->Type(MDD_##s##_##l), &l.get() #define OBJ_TYPE_ARGS(t) m_Dict->Type(MDD_##t).ul namespace ASDCP { namespace MXF { typedef std::pair ItemInfo; typedef std::map TagMap; // class TLVReader : public Kumu::MemIOReader { TagMap m_ElementMap; IPrimerLookup* m_Lookup; TLVReader(); ASDCP_NO_COPY_CONSTRUCT(TLVReader); public: TLVReader(const byte_t* p, ui32_t c, IPrimerLookup* = 0); bool FindTL(const MDDEntry&); Result_t ReadObject(const MDDEntry&, Kumu::IArchive*); Result_t ReadUi8(const MDDEntry&, ui8_t*); Result_t ReadUi16(const MDDEntry&, ui16_t*); Result_t ReadUi32(const MDDEntry&, ui32_t*); Result_t ReadUi64(const MDDEntry&, ui64_t*); }; // class TLVWriter : public Kumu::MemIOWriter { TagMap m_ElementMap; IPrimerLookup* m_Lookup; TLVWriter(); ASDCP_NO_COPY_CONSTRUCT(TLVWriter); Result_t WriteTag(const MDDEntry&); public: TLVWriter(byte_t* p, ui32_t c, IPrimerLookup* = 0); Result_t WriteObject(const MDDEntry&, Kumu::IArchive*); Result_t WriteUi8(const MDDEntry&, ui8_t*); Result_t WriteUi16(const MDDEntry&, ui16_t*); Result_t WriteUi32(const MDDEntry&, ui32_t*); Result_t WriteUi64(const MDDEntry&, ui64_t*); }; // template class FixedSizeItemCollection : public ContainerType, public Kumu::IArchive { public: FixedSizeItemCollection() {} virtual ~FixedSizeItemCollection() {} ui32_t ItemSize() const { typename ContainerType::value_type tmp_item; return tmp_item.ArchiveLength(); } bool HasValue() const { return ! this->empty(); } ui32_t ArchiveLength() const { return ( sizeof(ui32_t) * 2 ) + ( (ui32_t)this->size() * this->ItemSize() ); } bool Archive(Kumu::MemIOWriter* Writer) const { if ( ! Writer->WriteUi32BE((ui32_t)this->size()) ) return false; if ( ! Writer->WriteUi32BE((ui32_t)this->ItemSize()) ) return false; if ( this->empty() ) return true; typename ContainerType::const_iterator i; bool result = true; for ( i = this->begin(); i != this->end() && result; ++i ) { result = i->Archive(Writer); } return result; } // bool Unarchive(Kumu::MemIOReader* Reader) { ui32_t item_count, item_size; if ( ! Reader->ReadUi32BE(&item_count) ) return false; if ( ! Reader->ReadUi32BE(&item_size) ) return false; if ( item_count > 0 ) { if ( this->ItemSize() != item_size ) return false; } bool result = true; for ( ui32_t i = 0; i < item_count && result; ++i ) { typename ContainerType::value_type tmp_item; result = tmp_item.Unarchive(Reader); if ( result ) { this->push_back(tmp_item); } } return result; } void Dump(FILE* stream = 0, ui32_t depth = 0) { (void) depth; char identbuf[IdentBufferLen]; if ( stream == 0 ) { stream = stderr; } typename ContainerType::const_iterator i; for ( i = this->begin(); i != this->end(); ++i ) { fprintf(stream, " %s\n", (*i).EncodeString(identbuf, IdentBufferLen)); } } }; template class PushSet : public std::set { public: PushSet() {} virtual ~PushSet() {} void push_back(const item_type& item) { this->insert(item); } }; template class Batch : public FixedSizeItemCollection > { public: Batch() {} virtual ~Batch() {} }; template class Array : public FixedSizeItemCollection > { public: Array() {} virtual ~Array() {} }; // template class SimpleArray : public std::list, public Kumu::IArchive { public: SimpleArray() {} virtual ~SimpleArray() {} // bool Unarchive(Kumu::MemIOReader* Reader) { bool result = true; while ( Reader->Remainder() > 0 && result ) { T Tmp; result = Tmp.Unarchive(Reader); if ( result ) { this->push_back(Tmp); } } return result; } inline bool HasValue() const { return ! this->empty(); } ui32_t ArchiveLength() const { ui32_t arch_size = 0; typename std::list::const_iterator l_i = this->begin(); for ( ; l_i != this->end(); l_i++ ) arch_size += l_i->ArchiveLength(); return arch_size; } // bool Archive(Kumu::MemIOWriter* Writer) const { bool result = true; typename std::list::const_iterator l_i = this->begin(); for ( ; l_i != this->end() && result; l_i++ ) result = (*l_i).Archive(Writer); return result; } // void Dump(FILE* stream = 0, ui32_t depth = 0) { (void) depth; char identbuf[IdentBufferLen]; if ( stream == 0 ) stream = stderr; typename std::list::iterator i = this->begin(); for ( ; i != this->end(); i++ ) fprintf(stream, " %s\n", (*i).EncodeString(identbuf, IdentBufferLen)); } }; // class ISO8String : public std::string, public Kumu::IArchive { public: ISO8String() {} ISO8String(const char*); ISO8String(const std::string&); ~ISO8String() {} const ISO8String& operator=(const char*); const ISO8String& operator=(const std::string&); const char* EncodeString(char* str_buf, ui32_t buf_len) const; inline virtual bool HasValue() const { return ! empty(); } inline virtual ui32_t ArchiveLength() const { return (ui32_t)(sizeof(ui32_t) + size()); } virtual bool Unarchive(Kumu::MemIOReader* Reader); virtual bool Archive(Kumu::MemIOWriter* Writer) const; }; // class UTF16String : public std::string, public Kumu::IArchive { public: UTF16String() {} UTF16String(const char*); UTF16String(const std::string&); ~UTF16String() {} const UTF16String& operator=(const char*); const UTF16String& operator=(const std::string&); const char* EncodeString(char* str_buf, ui32_t buf_len) const; inline virtual bool HasValue() const { return ! empty(); } inline virtual ui32_t ArchiveLength() const { return (ui32_t)(sizeof(ui32_t) + size()); } virtual bool Unarchive(Kumu::MemIOReader* Reader); virtual bool Archive(Kumu::MemIOWriter* Writer) const; }; // class Rational : public ASDCP::Rational, public Kumu::IArchive { public: Rational() {} ~Rational() {} Rational(const Rational& rhs) : ASDCP::Rational(), IArchive() { Numerator = rhs.Numerator; Denominator = rhs.Denominator; } const Rational& operator=(const Rational& rhs) { Numerator = rhs.Numerator; Denominator = rhs.Denominator; return *this; } Rational(const ASDCP::Rational& rhs) { Numerator = rhs.Numerator; Denominator = rhs.Denominator; } const Rational& operator=(const ASDCP::Rational& rhs) { Numerator = rhs.Numerator; Denominator = rhs.Denominator; return *this; } // inline const char* EncodeString(char* str_buf, ui32_t buf_len) const { snprintf(str_buf, buf_len, "%d/%d", Numerator, Denominator); return str_buf; } inline virtual bool Unarchive(Kumu::MemIOReader* Reader) { if ( ! Reader->ReadUi32BE((ui32_t*)&Numerator) ) return false; if ( ! Reader->ReadUi32BE((ui32_t*)&Denominator) ) return false; return true; } inline virtual bool HasValue() const { return true; } inline virtual ui32_t ArchiveLength() const { return sizeof(ui32_t)*2; } inline virtual bool Archive(Kumu::MemIOWriter* Writer) const { if ( ! Writer->WriteUi32BE((ui32_t)Numerator) ) return false; if ( ! Writer->WriteUi32BE((ui32_t)Denominator) ) return false; return true; } }; // class LineMapPair : public Kumu::IArchive { public: ui32_t First; ui32_t Second; LineMapPair() : First(0), Second() {} ~LineMapPair() {} LineMapPair(const ui32_t& first, const ui32_t& second) : IArchive() { First = first; Second = second; } LineMapPair(const LineMapPair& rhs) : IArchive() { First = rhs.First; Second = rhs.Second; } const LineMapPair& operator=(const LineMapPair& rhs) { First = rhs.First; Second = rhs.Second; return *this; } // inline const char* EncodeString(char* str_buf, ui32_t buf_len) const { snprintf(str_buf, buf_len, "%d,%d", First, Second); return str_buf; } inline virtual bool Unarchive(Kumu::MemIOReader* Reader) { ui32_t n; if ( ! Reader->ReadUi32BE(&n) ) return false; if ( n != 2 ) return false; if ( ! Reader->ReadUi32BE(&n) ) return false; if ( n != 4 ) return false; if ( ! Reader->ReadUi32BE((ui32_t*)&First) ) return false; if ( ! Reader->ReadUi32BE((ui32_t*)&Second) ) return false; return true; } inline virtual bool HasValue() const { return true; } inline virtual ui32_t ArchiveLength() const { return sizeof(ui32_t)*4; } inline virtual bool Archive(Kumu::MemIOWriter* Writer) const { if ( ! Writer->WriteUi32BE(2UL) ) return false; if ( ! Writer->WriteUi32BE(4UL) ) return false; if ( ! Writer->WriteUi32BE((ui32_t)First) ) return false; if ( ! Writer->WriteUi32BE((ui32_t)Second) ) return false; return true; } }; // class ColorPrimary : public Kumu::IArchive { public: ui16_t X; ui16_t Y; ColorPrimary() : X(0), Y(0) {} ~ColorPrimary() {} ColorPrimary(const ui16_t& x, const ui16_t& y) : X(x), Y(y) {} ColorPrimary(const ColorPrimary& rhs) { Copy(rhs); } const ColorPrimary& operator=(const ColorPrimary& rhs) { Copy(rhs); return *this; } void Copy(const ColorPrimary& rhs) { X = rhs.X; Y = rhs.Y; } // inline const char* EncodeString(char* str_buf, ui32_t buf_len) const { snprintf(str_buf, buf_len, "%d,%d", X, Y); return str_buf; } inline virtual bool Unarchive(Kumu::MemIOReader* Reader) { if ( ! Reader->ReadUi16BE((ui16_t*)&X) ) return false; if ( ! Reader->ReadUi16BE((ui16_t*)&Y) ) return false; return true; } inline virtual bool HasValue() const { return X || Y; } inline virtual ui32_t ArchiveLength() const { return sizeof(ui16_t)*2; } inline virtual bool Archive(Kumu::MemIOWriter* Writer) const { if ( ! Writer->WriteUi16BE((ui16_t)X) ) return false; if ( ! Writer->WriteUi16BE((ui16_t)Y) ) return false; return true; } }; // class ThreeColorPrimaries : public Kumu::IArchive { public: ColorPrimary First; ColorPrimary Second; ColorPrimary Third; ThreeColorPrimaries() {} ~ThreeColorPrimaries() {} ThreeColorPrimaries(const ColorPrimary& first, const ColorPrimary& second, const ColorPrimary& third) : First(first), Second(second), Third(third) {} ThreeColorPrimaries(const ThreeColorPrimaries& rhs) { Copy(rhs); } const ThreeColorPrimaries& operator=(const ThreeColorPrimaries& rhs) { Copy(rhs); return *this; } void Copy(const ThreeColorPrimaries& rhs) { First = rhs.First; Second = rhs.Second; Third = rhs.Third; } // inline const char* EncodeString(char* str_buf, ui32_t buf_len) const { snprintf(str_buf, buf_len, "%d,%d;%d,%d;%d,%d", First.X, First.Y, Second.X, Second.Y, Third.X, Third.Y); return str_buf; } inline virtual bool Unarchive(Kumu::MemIOReader* Reader) { First.Unarchive(Reader); Second.Unarchive(Reader); Third.Unarchive(Reader); return true; } inline virtual bool HasValue() const { return First.HasValue() || Second.HasValue() || Third.HasValue(); } inline virtual ui32_t ArchiveLength() const { return First.ArchiveLength() + Second.ArchiveLength() + Third.ArchiveLength(); } inline virtual bool Archive(Kumu::MemIOWriter* Writer) const { First.Archive(Writer); Second.Archive(Writer); Third.Archive(Writer); return true; } }; // class VersionType : public Kumu::IArchive { public: enum Release_t { RL_UNKNOWN, RL_RELEASE, RL_DEVELOPMENT, RL_PATCHED, RL_BETA, RL_PRIVATE, RL_MAX }; ui16_t Major; ui16_t Minor; ui16_t Patch; ui16_t Build; Release_t Release; VersionType() : Major(0), Minor(0), Patch(0), Build(0), Release(RL_UNKNOWN) {} VersionType(const VersionType& rhs) { Copy(rhs); } virtual ~VersionType() {} const VersionType& operator=(const VersionType& rhs) { Copy(rhs); return *this; } void Copy(const VersionType& rhs) { Major = rhs.Major; Minor = rhs.Minor; Patch = rhs.Patch; Build = rhs.Build; Release = rhs.Release; } void Dump(FILE* = 0); const char* EncodeString(char* str_buf, ui32_t buf_len) const { snprintf(str_buf, buf_len, "%hu.%hu.%hu.%hur%hu", Major, Minor, Patch, Build, ui16_t(Release)); return str_buf; } virtual bool Unarchive(Kumu::MemIOReader* Reader) { if ( ! Reader->ReadUi16BE(&Major) ) return false; if ( ! Reader->ReadUi16BE(&Minor) ) return false; if ( ! Reader->ReadUi16BE(&Patch) ) return false; if ( ! Reader->ReadUi16BE(&Build) ) return false; ui16_t tmp_release; if ( ! Reader->ReadUi16BE(&tmp_release) ) return false; Release = (Release_t)tmp_release; return true; } inline virtual bool HasValue() const { return true; } inline virtual ui32_t ArchiveLength() const { return sizeof(ui16_t)*5; } virtual bool Archive(Kumu::MemIOWriter* Writer) const { if ( ! Writer->WriteUi16BE(Major) ) return false; if ( ! Writer->WriteUi16BE(Minor) ) return false; if ( ! Writer->WriteUi16BE(Patch) ) return false; if ( ! Writer->WriteUi16BE(Build) ) return false; if ( ! Writer->WriteUi16BE((ui16_t)(Release & 0x0000ffffL)) ) return false; return true; } }; /* The RGBALayout type shall be a fixed-size 8 element sequence with a total length of 16 bytes, where each element shall consist of the RGBAComponent type with the following fields: Code (UInt8): Enumerated value specifying component (i.e., component identifier). "0" is the layout terminator. Depth (UInt8): Integer specifying the number of bits occupied (see also G.2.26) 1->32 indicates integer depth 253 = HALF (floating point 16-bit value) 254 = IEEE floating point 32-bit value 255 = IEEE floating point 64-bit value 0 = RGBALayout terminator A Fill component indicates unused bits. After the components have been specified, the remaining Code and Size fields shall be set to zero (0). For each component in the Pixel, one of the following Codes or the terminator shall be specified (explained below): Code ASCII */ struct RGBALayoutTableEntry { byte_t code; char symbol; const char* label; }; struct RGBALayoutTableEntry const RGBALayoutTable[] = { { 0x52, 'R', "Red component" }, { 0x47, 'G', "Green component" }, { 0x42, 'B', "Blue component" }, { 0x41, 'A', "Alpha component" }, { 0x72, 'r', "Red component (LSBs)" }, { 0x67, 'g', "Green component (LSBs)" }, { 0x62, 'b', "Blue component (LSBs)" }, { 0x61, 'a', "Alpha component (LSBs)" }, { 0x46, 'F', "Fill component" }, { 0x50, 'P', "Palette code" }, { 0x55, 'U', "Color Difference Sample (e.g. U, Cb, I etc.)" }, { 0x56, 'V', "Color Difference Sample (e.g. V, Cr, Q etc.)" }, { 0x57, 'W', "Composite Video" }, { 0x58, 'X', "Non co-sited luma component" }, { 0x59, 'Y', "Luma component" }, { 0x5a, 'Z', "Depth component (SMPTE ST 268 compatible)" }, { 0x75, 'u', "Color Difference Sample (e.g. U, Cb, I etc.) (LSBs)" }, { 0x76, 'v', "Color Difference Sample (e.g. V, Cr, Q etc.) (LSBs)" }, { 0x77, 'w', "Composite Video (LSBs)" }, { 0x78, 'x', "Non co-sited luma component (LSBs)" }, { 0x79, 'y', "Luma component (LSBs)" }, { 0x7a, 'z', "Depth component (LSBs) (SMPTE ST 268 compatible)" }, { 0xd8, 'X', "The DCDM X color component (see SMPTE ST 428-1 X')" }, { 0xd9, 'Y', "The DCDM Y color component (see SMPTE ST 428-1 Y')" }, { 0xda, 'Z', "The DCDM Z color component (see SMPTE ST 428-1 Z')" }, { 0x00, '_', "Terminator" } }; size_t const RGBAValueLength = 16; byte_t const RGBAValue_RGB_16[RGBAValueLength] = { 'R', 16, 'G', 16, 'B', 16, 0, 0 }; byte_t const RGBAValue_RGB_12[RGBAValueLength] = { 'R', 12, 'G', 12, 'B', 12, 0, 0 }; byte_t const RGBAValue_RGB_10[RGBAValueLength] = { 'R', 10, 'G', 10, 'B', 10, 0, 0 }; byte_t const RGBAValue_RGB_8[RGBAValueLength] = { 'R', 8, 'G', 8, 'B', 8, 0, 0 }; byte_t const RGBAValue_YUV_16[RGBAValueLength] = { 'Y', 16, 'U', 16, 'V', 16, 0, 0 }; byte_t const RGBAValue_YUV_12[RGBAValueLength] = { 'Y', 12, 'U', 12, 'V', 12, 0, 0 }; byte_t const RGBAValue_YUV_10[RGBAValueLength] = { 'Y', 10, 'U', 10, 'V', 10, 0, 0 }; byte_t const RGBAValue_YUV_8[RGBAValueLength] = { 'Y', 8, 'U', 8, 'V', 8, 0, 0 }; byte_t const RGBAValue_DCDM[RGBAValueLength] = { 0xd8, 10, 0xd9, 10, 0xda, 10, 0, 0 }; class RGBALayout : public Kumu::IArchive { byte_t m_value[RGBAValueLength]; public: RGBALayout(); RGBALayout(const byte_t* value); ~RGBALayout(); RGBALayout(const RGBALayout& rhs) { Set(rhs.m_value); } const RGBALayout& operator=(const RGBALayout& rhs) { Set(rhs.m_value); return *this; } void Set(const byte_t* value) { memcpy(m_value, value, RGBAValueLength); } const char* EncodeString(char* buf, ui32_t buf_len) const; bool HasValue() const { return true; } ui32_t ArchiveLength() const { return RGBAValueLength; } bool Archive(Kumu::MemIOWriter* Writer) const { return Writer->WriteRaw(m_value, RGBAValueLength); } bool Unarchive(Kumu::MemIOReader* Reader) { if ( Reader->Remainder() < RGBAValueLength ) { return false; } memcpy(m_value, Reader->CurrentData(), RGBAValueLength); Reader->SkipOffset(RGBAValueLength); return true; } }; // class Raw : public Kumu::ByteString { public: Raw(); virtual ~Raw(); // virtual bool Unarchive(Kumu::MemIOReader* Reader); virtual bool Archive(Kumu::MemIOWriter* Writer) const; const char* EncodeString(char* str_buf, ui32_t buf_len) const; }; // class J2KExtendedCapabilitiesType : public Kumu::IArchive { public: ui32_t Pcap; Array Ccap; bool HasValue() const { return true; } ui32_t ArchiveLength() const { return 0; } bool Archive(Kumu::MemIOWriter* Writer) const; bool Unarchive(Kumu::MemIOReader* Reader); const char* EncodeString(char* str_buf, ui32_t buf_len) const; }; } // namespace MXF } // namespace ASDCP #endif //_MXFTYPES_H_ // // end MXFTypes.h //