From: John Hurst Date: Mon, 30 Dec 2019 22:03:53 +0000 (-0800) Subject: Merge pull request #20 from cinecert/htj2c X-Git-Tag: rel_2_10_35~7 X-Git-Url: https://main.carlh.net/gitweb/?a=commitdiff_plain;h=9e269bd45830f54551722a65b0d7aa8f327e17dc;hp=a67f55782d4758355190fe3f14ac6159b9d79e1e;p=asdcplib.git Merge pull request #20 from cinecert/htj2c WIP: add support for ST 422:2019 --- diff --git a/.gitignore b/.gitignore index 8aed0cc..ba1f60f 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,13 @@ # src/.deps src/.libs +/build + +### +# some tool dirs +# + +/.vscode ### # autotools output diff --git a/src/AS_DCP.h b/src/AS_DCP.h index 96d066c..74991f6 100755 --- a/src/AS_DCP.h +++ b/src/AS_DCP.h @@ -1048,6 +1048,12 @@ namespace ASDCP { const ui32_t MaxComponents = 3; const ui32_t MaxPrecincts = 32; // ISO 15444-1 Annex A.6.1 const ui32_t MaxDefaults = 256; // made up + const ui8_t MaxCapabilities = 32; + const ui16_t MaxPRFN = 4; + const ui16_t MaxCPFN = 4; + const i8_t NoExtendedCapabilitiesSignaled = -1; + const ui16_t NoPRFSignaled = 0; + const ui16_t NoCPFSignaled = 0; #pragma pack(1) struct ImageComponent_t // ISO 15444-1 Annex A.5.1 @@ -1085,6 +1091,26 @@ namespace ASDCP { ui8_t SPqcd[MaxDefaults]; ui8_t SPqcdLength; }; + + struct ExtendedCapabilities_t // ISO 15444-1 Annex A.5.2 + { + ui32_t Pcap; // Pcap = 0 means that no extended capabilities are required + i8_t N; // Number of Ccap elements, or NoExtendedCapabilitiesSignaled if no Extended Capabilities are signaled + ui16_t Ccap[MaxCapabilities]; + }; + + struct Profile_t // ISO 15444-1 + { + ui16_t N; // N = NoPRFSignaled means that Profile is signaled through Rsiz exclusively + ui16_t Pprf[MaxPRFN]; // Pprf^i in ISO/IEC 15444-1 corresponds to Pprf[i -1] + }; + + struct CorrespondingProfile_t // ISO 15444-1 + { + ui16_t N; // N = NoCPFSignaled means that no corresponding profile is signaled + ui16_t Pcpf[MaxCPFN]; // Pcpf^i in ISO/IEC 15444-1 corresponds to Pcpf[i -1] + }; + #pragma pack() struct PictureDescriptor @@ -1108,6 +1134,9 @@ namespace ASDCP { ImageComponent_t ImageComponents[MaxComponents]; CodingStyleDefault_t CodingStyleDefault; QuantizationDefault_t QuantizationDefault; + ExtendedCapabilities_t ExtendedCapabilities; + Profile_t Profile; + CorrespondingProfile_t CorrespondingProfile; }; // Print debugging information to std::ostream diff --git a/src/AS_DCP_JP2K.cpp b/src/AS_DCP_JP2K.cpp index a4bffc6..129f53d 100755 --- a/src/AS_DCP_JP2K.cpp +++ b/src/AS_DCP_JP2K.cpp @@ -32,6 +32,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "AS_DCP_internal.h" #include #include +#include using namespace ASDCP::JP2K; using Kumu::GenRandomValue; @@ -106,6 +107,46 @@ ASDCP::JP2K::operator << (std::ostream& strm, const PictureDescriptor& PDesc) strm << " SPqcd: " << Kumu::bin2hex(PDesc.QuantizationDefault.SPqcd, PDesc.QuantizationDefault.SPqcdLength, tmp_buf, MaxDefaults*2) << std::endl; + if (PDesc.Profile.N != 0) { + strm << "Profile:" << std::endl; + + for (ui16_t i = 0; i < PDesc.Profile.N; i++) { + strm << " Pprf(" << (i + 1) << "): " + << std::hex << std::showbase << PDesc.Profile.Pprf[i] << std::dec << std::noshowbase + << std::endl; + } + } + + if (PDesc.CorrespondingProfile.N != 0) { + strm << "Corresponding Profile:" << std::endl; + + for (ui16_t i = 0; i < PDesc.CorrespondingProfile.N; i++) { + + strm << " Pcpf(" << (i + 1) << "): " + << std::hex << std::showbase << PDesc.CorrespondingProfile.Pcpf[i] << std::dec << std::noshowbase + << std::endl; + } + } + + if (PDesc.ExtendedCapabilities.N != JP2K::NoExtendedCapabilitiesSignaled && PDesc.ExtendedCapabilities.Pcap != 0) { + + strm << "Extended Capabilities:" << std::endl; + + + strm << " Pcap:" << PDesc.ExtendedCapabilities.Pcap << std::endl; + + for (i32_t b = 0, i = 0; b < JP2K::MaxCapabilities; b++) { + + if ((PDesc.ExtendedCapabilities.Pcap >> b) & 0x1) { + + strm << " Ccap(" << (JP2K::MaxCapabilities - b) << "): " << + std::hex << std::showbase << PDesc.ExtendedCapabilities.Ccap[i++] << std::dec << std::noshowbase + << std::endl; + + } + } + } + return strm; } @@ -197,6 +238,42 @@ ASDCP::JP2K::PictureDescriptorDump(const PictureDescriptor& PDesc, FILE* stream) Kumu::bin2hex(PDesc.QuantizationDefault.SPqcd, PDesc.QuantizationDefault.SPqcdLength, tmp_buf, MaxDefaults*2) ); + + + if (PDesc.Profile.N != 0) { + fprintf(stream, " Profile:\n"); + + for (ui16_t i = 0; i < PDesc.Profile.N; i++) { + + fprintf(stream, " Pprf(%d): %hx\n", i + 1, PDesc.Profile.Pprf[i]); + + } + } + + if (PDesc.CorrespondingProfile.N != 0) { + fprintf(stream, "Corresponding Profile:\n"); + + for (ui16_t i = 0; i < PDesc.CorrespondingProfile.N; i++) { + fprintf(stream, " Pcpf(%d): %hx\n", i + 1, PDesc.CorrespondingProfile.Pcpf[i]); + + } + } + + if (PDesc.ExtendedCapabilities.N != JP2K::NoExtendedCapabilitiesSignaled) { + + fprintf(stream, "Extended Capabilities: %x\n", PDesc.ExtendedCapabilities.Pcap); + + for (i32_t b = 0, i = 0; b < JP2K::MaxCapabilities && i < PDesc.ExtendedCapabilities.N; b++) { + + if ((PDesc.ExtendedCapabilities.Pcap >> (JP2K::MaxCapabilities - b - 1)) & 0x1) { + + fprintf(stream, " Ccap(%d): %hx\n", b + 1, PDesc.ExtendedCapabilities.Ccap[i++]); + + } + } + + } + } @@ -255,6 +332,58 @@ ASDCP::JP2K_PDesc_to_MD(const JP2K::PictureDescriptor& PDesc, EssenceSubDescriptor.QuantizationDefault.get().Length(qdflt_size); EssenceSubDescriptor.QuantizationDefault.set_has_value(); + // Profile + + if (PDesc.Profile.N == 0) { + EssenceSubDescriptor.J2KProfile.set_has_value(false); + } else { + EssenceSubDescriptor.J2KProfile.get().resize(PDesc.Profile.N); + + std::copy(PDesc.Profile.Pprf, + PDesc.Profile.Pprf + PDesc.Profile.N, + EssenceSubDescriptor.J2KProfile.get().begin()); + + EssenceSubDescriptor.J2KProfile.set_has_value(); + } + + // Corresponding profile + + if (PDesc.CorrespondingProfile.N == 0) { + + EssenceSubDescriptor.J2KCorrespondingProfile.set_has_value(false); + + } else { + EssenceSubDescriptor.J2KCorrespondingProfile.get().resize(PDesc.CorrespondingProfile.N); + + std::copy(PDesc.CorrespondingProfile.Pcpf, + PDesc.CorrespondingProfile.Pcpf + PDesc.CorrespondingProfile.N, + EssenceSubDescriptor.J2KCorrespondingProfile.get().begin()); + + EssenceSubDescriptor.J2KCorrespondingProfile.set_has_value(); + } + + // Extended capabilities + + if (PDesc.ExtendedCapabilities.N == JP2K::NoExtendedCapabilitiesSignaled) { + + /* No extended capabilities are signaled */ + + EssenceSubDescriptor.J2KExtendedCapabilities.set_has_value(false); + + } else { + + EssenceSubDescriptor.J2KExtendedCapabilities.get().Pcap = PDesc.ExtendedCapabilities.Pcap; + + EssenceSubDescriptor.J2KExtendedCapabilities.get().Ccap.resize(PDesc.ExtendedCapabilities.N); + + std::copy(PDesc.ExtendedCapabilities.Ccap, + PDesc.ExtendedCapabilities.Ccap + PDesc.ExtendedCapabilities.N, + EssenceSubDescriptor.J2KExtendedCapabilities.get().Ccap.begin()); + + EssenceSubDescriptor.J2KExtendedCapabilities.set_has_value(true); + + } + return RESULT_OK; } @@ -312,6 +441,67 @@ ASDCP::MD_to_JP2K_PDesc(const ASDCP::MXF::GenericPictureEssenceDescriptor& Esse EssenceSubDescriptor.QuantizationDefault.const_get().Length()); PDesc.QuantizationDefault.SPqcdLength = EssenceSubDescriptor.QuantizationDefault.const_get().Length() - 1; + + // Profile + + std::fill(PDesc.Profile.Pprf, PDesc.Profile.Pprf + JP2K::MaxPRFN, 0); + + if (EssenceSubDescriptor.J2KProfile.empty() || + EssenceSubDescriptor.J2KProfile.const_get().size() == 0) { + + PDesc.Profile.N = 0; + + } else { + + PDesc.Profile.N = EssenceSubDescriptor.J2KProfile.const_get().size(); + + std::copy(EssenceSubDescriptor.J2KProfile.const_get().begin(), + EssenceSubDescriptor.J2KProfile.const_get().end(), + PDesc.Profile.Pprf); + + } + + // Corresponding profile + + std::fill(PDesc.CorrespondingProfile.Pcpf, PDesc.CorrespondingProfile.Pcpf + JP2K::MaxCPFN, 0); + + if (EssenceSubDescriptor.J2KCorrespondingProfile.empty() || + EssenceSubDescriptor.J2KCorrespondingProfile.const_get().size() == 0) { + + PDesc.CorrespondingProfile.N = 0; + + } + else { + + PDesc.CorrespondingProfile.N = EssenceSubDescriptor.J2KCorrespondingProfile.const_get().size(); + + std::copy(EssenceSubDescriptor.J2KCorrespondingProfile.const_get().begin(), + EssenceSubDescriptor.J2KCorrespondingProfile.const_get().end(), + PDesc.CorrespondingProfile.Pcpf); + + } + + // Extended capabilities + + std::fill(PDesc.ExtendedCapabilities.Ccap, PDesc.ExtendedCapabilities.Ccap + JP2K::MaxCapabilities, 0); + + if (EssenceSubDescriptor.J2KExtendedCapabilities.empty()) { + + PDesc.ExtendedCapabilities.Pcap = 0; + PDesc.ExtendedCapabilities.N = JP2K::NoExtendedCapabilitiesSignaled; + + } + else { + + PDesc.ExtendedCapabilities.Pcap = EssenceSubDescriptor.J2KExtendedCapabilities.const_get().Pcap; + PDesc.ExtendedCapabilities.N = EssenceSubDescriptor.J2KExtendedCapabilities.const_get().Ccap.size(); + + std::copy(EssenceSubDescriptor.J2KExtendedCapabilities.const_get().Ccap.begin(), + EssenceSubDescriptor.J2KExtendedCapabilities.const_get().Ccap.end(), + PDesc.ExtendedCapabilities.Ccap); + + } + return RESULT_OK; } diff --git a/src/JP2K.cpp b/src/JP2K.cpp index a0f2a8a..4d2c130 100755 --- a/src/JP2K.cpp +++ b/src/JP2K.cpp @@ -37,45 +37,17 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. using Kumu::DefaultLogSink; -// when indexed with the second byte of a marker code, this table will procuce one of -// two values: -// 0 - the marker is a standalone marker -// 1 - the marker designates a marker segment -// -const byte_t MarkerSegmentMap[] = - { - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ - /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 - /* 1 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1 - /* 2 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2 - /* 3 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3 - /* 4 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4 - /* 5 */ 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, // 5 - /* 6 */ 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6 - /* 7 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 7 - /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 - /* 9 */ 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9 - /* a */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // a - /* b */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // b - /* c */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // c - /* d */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // d - /* e */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // e - /* f */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // f - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ - }; - - // ASDCP::Result_t ASDCP::JP2K::GetNextMarker(const byte_t** buf, JP2K::Marker& Marker) { assert((buf != 0) && (*buf != 0 )); - if ( **buf != 0xff ) + if (*(*buf)++ != 0xff ) return ASDCP::RESULT_FAIL; - Marker.m_IsSegment = (MarkerSegmentMap[*(++(*buf))] == 1); Marker.m_Type = (Marker_t)(0xff00 | *(*buf)++); + Marker.m_IsSegment = Marker.m_Type != MRK_SOC && Marker.m_Type != MRK_SOD && Marker.m_Type != MRK_EOC; if ( Marker.m_IsSegment ) { @@ -86,13 +58,13 @@ ASDCP::JP2K::GetNextMarker(const byte_t** buf, JP2K::Marker& Marker) *buf += Marker.m_DataSize; } - + /* TODO: why is this here? if ( Marker.m_DataSize != 0 && Marker.m_DataSize < 3 ) { DefaultLogSink().Error("Illegal data size: %u\n", Marker.m_DataSize); return ASDCP::RESULT_FAIL; } - + */ return ASDCP::RESULT_OK; } @@ -227,6 +199,78 @@ ASDCP::JP2K::Accessor::COM::Dump(FILE* stream) const } } +// +void +ASDCP::JP2K::Accessor::PRF::Dump(FILE* stream) const +{ + if ( stream == 0 ) + stream = stderr; + + fprintf(stream, "PRF: \n"); + + if (N() == 0) { + + fprintf(stream, " N/A"); + + } else { + + for (ui16_t i = 1; i <= N(); i++) { + fprintf(stream, "pprf(%d): %d\n", i, pprf(i)); + } + + } +} + +// +void +ASDCP::JP2K::Accessor::CPF::Dump(FILE* stream) const +{ + if ( stream == 0 ) + stream = stderr; + + fprintf(stream, "CPF: \n"); + + if (N() == 0) { + + fprintf(stream, " N/A"); + + } else { + + for (ui16_t i = 1; i <= N(); i++) { + fprintf(stream, "pcpf(%d): %d\n", i, pcpf(i)); + } + + } +} + + +// +void +ASDCP::JP2K::Accessor::CAP::Dump(FILE* stream) const +{ + if ( stream == 0 ) + stream = stderr; + + fprintf(stream, "CAP: \n"); + + ui32_t pcap = this->pcap(); + + if (pcap == 0) { + + fprintf(stream, " None"); + + } else { + + for (i32_t b = 32, i = 1; b > 0; b--) { + + if ((pcap >> (32 - b)) & 0x1) { + + fprintf(stream, " ccap(%d): %d\n", b, this->ccap(i++)); + + } + } + } +} //------------------------------------------------------------------------------------------------------- // @@ -274,6 +318,9 @@ ASDCP::JP2K::GetMarkerString(Marker_t m) case MRK_EPH: return "EPH: End of packet header"; break; case MRK_CRG: return "CRG: Component registration"; break; case MRK_COM: return "COM: Comment"; break; + case MRK_CPF: return "CPF: Corresponding profile"; break; + case MRK_CAP: return "CAP: Capabilities"; break; + case MRK_PRF: return "PRF: Profile"; break; } return "Unknown marker code"; diff --git a/src/JP2K.h b/src/JP2K.h index b043dfc..8128de5 100755 --- a/src/JP2K.h +++ b/src/JP2K.h @@ -54,9 +54,12 @@ namespace JP2K MRK_SOT = 0xff90, // Start of tile-part MRK_SOD = 0xff93, // Start of data MRK_EOC = 0xffd9, // End of codestream + MRK_CAP = 0xff50, // Extended capabilities MRK_SIZ = 0xff51, // Image and tile size MRK_COD = 0xff52, // Coding style default MRK_COC = 0xff53, // Coding style component + MRK_PRF = 0xff56, // Profile + MRK_CPF = 0xff59, // Corresponding profile MRK_RGN = 0xff5e, // Region of interest MRK_QCD = 0xff5c, // Quantization default MRK_QCC = 0xff5d, // Quantization component @@ -219,6 +222,90 @@ namespace JP2K inline ui32_t CommentSize() const { return m_DataSize; } void Dump(FILE* stream = 0) const; }; + + // Corresponding Profile + class CPF { + + const ui16_t* m_Data; + ui16_t m_N; + + KM_NO_COPY_CONSTRUCT(CPF); + CPF(); + + public: + CPF(const Marker& M) { + assert(M.m_Type == MRK_CPF); + + m_Data = (ui16_t*) M.m_Data; + m_N = M.m_DataSize >> 1; + } + + ~CPF() {} + + inline ui16_t N() const { return m_N; } + + inline ui16_t pcpf(ui16_t i) const { return KM_i16_BE(m_Data[2 * (i - 1)]); } + + void Dump(FILE* stream = 0) const; + }; + + // Profile + class PRF { + + const ui16_t* m_Data; + ui16_t m_N; + + KM_NO_COPY_CONSTRUCT(PRF); + PRF(); + + public: + PRF(const Marker& M) { + assert(M.m_Type == MRK_PRF); + + m_Data = (ui16_t*) M.m_Data; + m_N = M.m_DataSize >> 1; + } + + ~PRF() {} + + inline ui16_t N() const { return m_N; } + + inline ui16_t pprf(ui16_t i) const { return KM_i16_BE(m_Data[2 * (i - 1)]); } + + void Dump(FILE* stream = 0) const; + }; + + // Extended capabilities + class CAP { + + const ui16_t* m_Data; + + ui32_t m_Pcap; + + i8_t m_N; + + KM_NO_COPY_CONSTRUCT(CAP); + CAP(); + + public: + CAP(const Marker& M) { + assert(M.m_Type == MRK_CAP); + + m_Data = (ui16_t *) (M.m_Data + 4); + m_Pcap = KM_i32_BE(*(ui32_t*)(M.m_Data)); + m_N = (M.m_DataSize - 4) >> 1; + } + + ~CAP() {} + + inline ui32_t pcap() const { return m_Pcap; } + + inline i8_t N() const { return m_N; } + + inline ui16_t ccap(ui16_t i) const { return KM_i16_BE(m_Data[2 * (i - 1)]); } + + void Dump(FILE* stream = 0) const; + }; } // namespace Accessor } // namespace JP2K } // namespace ASDCP diff --git a/src/JP2K_Codestream_Parser.cpp b/src/JP2K_Codestream_Parser.cpp index 0ed2649..9d55409 100755 --- a/src/JP2K_Codestream_Parser.cpp +++ b/src/JP2K_Codestream_Parser.cpp @@ -101,6 +101,12 @@ ASDCP::JP2K::ParseMetadataIntoDesc(const FrameBuffer& FB, PictureDescriptor& PDe const byte_t* p = FB.RoData(); const byte_t* end_p = p + FB.Size(); + /* initialize optional items */ + + PDesc.ExtendedCapabilities.N = JP2K::NoExtendedCapabilitiesSignaled; + PDesc.Profile.N = 0; + PDesc.CorrespondingProfile.N = 0; + while ( p < end_p && ASDCP_SUCCESS(result) ) { result = GetNextMarker(&p, NextMarker); @@ -178,6 +184,66 @@ ASDCP::JP2K::ParseMetadataIntoDesc(const FrameBuffer& FB, PictureDescriptor& PDe memcpy(&PDesc.QuantizationDefault, NextMarker.m_Data, NextMarker.m_DataSize); PDesc.QuantizationDefault.SPqcdLength = NextMarker.m_DataSize - 1; break; + + case MRK_CAP: + { + Accessor::CAP CAP_(NextMarker); + + PDesc.ExtendedCapabilities.Pcap = CAP_.pcap(); + + PDesc.ExtendedCapabilities.N = CAP_.N(); + + for (i32_t i = 0; i < CAP_.N(); i++) { + + PDesc.ExtendedCapabilities.Ccap[i] = CAP_.ccap(i); + + } + + } + break; + + case MRK_PRF: + { + Accessor::PRF PRF_(NextMarker); + + ui16_t n = PRF_.N(); + + if ( n > MaxPRFN ) + { + DefaultLogSink().Error("Number (%d) of Pprf^i exceeds maximum supported\n", n); + return RESULT_RAW_FORMAT; + } + + PDesc.Profile.N = n; + + for(i32_t i = 0; i < n ; i++) { + + PDesc.Profile.Pprf[i] = PRF_.pprf(i+1); + } + } + break; + + case MRK_CPF: + { + Accessor::CPF CPF_(NextMarker); + + ui16_t n = CPF_.N(); + + if ( n > MaxCPFN ) + { + DefaultLogSink().Error("Number (%d) of Pcpf^i exceeds maximum supported\n", n); + return RESULT_RAW_FORMAT; + } + + PDesc.CorrespondingProfile.N = n; + + for(i32_t i = 0; i < n; i++) { + + PDesc.CorrespondingProfile.Pcpf[i] = CPF_.pcpf(i+1); + } + } + break; + } } diff --git a/src/JP2K_Sequence_Parser.cpp b/src/JP2K_Sequence_Parser.cpp index a080440..c561033 100755 --- a/src/JP2K_Sequence_Parser.cpp +++ b/src/JP2K_Sequence_Parser.cpp @@ -249,6 +249,57 @@ operator==(const ASDCP::JP2K::CodingStyleDefault_t& lhs, const ASDCP::JP2K::Codi return true; } +// +bool +operator==(const ASDCP::JP2K::ExtendedCapabilities_t& lhs, const ASDCP::JP2K::ExtendedCapabilities_t& rhs) +{ + if (lhs.N != rhs.N) return false; + + if (lhs.N != JP2K::NoExtendedCapabilitiesSignaled) { + + if (lhs.Pcap != rhs.Pcap) return false; + + for (ui32_t i = 0; i < lhs.N; i++) + { + if (lhs.Ccap[i] != rhs.Ccap[i]) + return false; + } + + } + + return true; +} + +// +bool +operator==(const ASDCP::JP2K::CorrespondingProfile_t& lhs, const ASDCP::JP2K::CorrespondingProfile_t& rhs) +{ + if (lhs.N != rhs.N) return false; + + for (ui32_t i = 0; i < lhs.N; i++) + { + if (lhs.Pcpf[i] != rhs.Pcpf[i]) + return false; + } + + return true; +} + +// +bool +operator==(const ASDCP::JP2K::Profile_t& lhs, const ASDCP::JP2K::Profile_t& rhs) +{ + if (lhs.N != rhs.N) return false; + + for (ui32_t i = 0; i < lhs.N; i++) + { + if (lhs.Pprf[i] != rhs.Pprf[i]) + return false; + } + + return true; +} + // bool operator==(const ASDCP::JP2K::PictureDescriptor& lhs, const ASDCP::JP2K::PictureDescriptor& rhs) @@ -271,6 +322,9 @@ operator==(const ASDCP::JP2K::PictureDescriptor& lhs, const ASDCP::JP2K::Picture if ( lhs.Csize != rhs.Csize ) return false; if ( ! ( lhs.CodingStyleDefault == rhs.CodingStyleDefault ) ) return false; if ( ! ( lhs.QuantizationDefault == rhs.QuantizationDefault ) ) return false; + if (!(lhs.Profile == rhs.Profile)) return false; + if (!(lhs.CorrespondingProfile == rhs.CorrespondingProfile)) return false; + if (!(lhs.ExtendedCapabilities == rhs.ExtendedCapabilities)) return false; for ( ui32_t i = 0; i < JP2K::MaxComponents; i++ ) { diff --git a/src/KM_util.h b/src/KM_util.h index f3f60f1..f6a8935 100755 --- a/src/KM_util.h +++ b/src/KM_util.h @@ -256,6 +256,37 @@ namespace Kumu } }; + // + class ArchivableUi16 : public Kumu::IArchive + { + public: + ui16_t value; + + ArchivableUi16() : value(0) {} + ArchivableUi16(const ui16_t& val) : value(val) {} + virtual ~ArchivableUi16() {} + + bool HasValue() const { return true; } + ui32_t ArchiveLength() const { return sizeof(ui16_t); } + + operator ui16_t() const { return value; } + + bool Archive(MemIOWriter* Writer) const { + if ( Writer == 0 ) return false; + return Writer->WriteUi16BE(value); + } + + bool Unarchive(MemIOReader* Reader) { + if ( Reader == 0 ) return false; + return Reader->ReadUi16BE(&value); + } + + const char* EncodeString(char* str_buf, ui32_t buf_len) const { + snprintf(str_buf, buf_len, "%hu", value); + return str_buf; + } + }; + // typedef Kumu::ArchivableList StringList; diff --git a/src/MDD.cpp b/src/MDD.cpp index a2c691f..06d0fde 100644 --- a/src/MDD.cpp +++ b/src/MDD.cpp @@ -1608,8 +1608,26 @@ static const ASDCP::MDDEntry s_MDD_Table[] = { {0}, false, "ACESFrameWrappedEssence" }, { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0d, // 518 0x03, 0x02, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00 }, - {0}, false, "DCAudioChannel_FSKSyncSignalChannel" }, - { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0d, // 519 + {0}, false, "DCAudioChannel_FSKSyncSignalChannel" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0e, + 0x04, 0x01, 0x06, 0x03, 0x0f, 0x00, 0x00, 0x00 }, + {0}, false, "JPEG2000PictureSubDescriptor_J2KExtendedCapabilities" }, // 519 + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0e, + 0x04, 0x01, 0x06, 0x03, 0x10, 0x00, 0x00, 0x00 }, + {0}, false, "JPEG2000PictureSubDescriptor_J2KProfile" }, // 520 + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0e, + 0x04, 0x01, 0x06, 0x03, 0x11, 0x00, 0x00, 0x00 }, + {0}, false, "JPEG2000PictureSubDescriptor_J2KCorrespondingProfile" }, // 521 + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x04, 0x01, 0x01, + 0x03, 0x01, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00 }, + {0}, false, "J2KExtendedCapabilities" }, // 522 + { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0D, + 0x04, 0x01, 0x02, 0x02, 0x03, 0x01, 0x08, 0x00 }, + {0}, false, "HTJ2KPictureCodingScheme" }, // 523 + { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0D, + 0x04, 0x01, 0x02, 0x02, 0x03, 0x01, 0x08, 0x01 }, + {0}, false, "HTJ2KPictureCodingSchemeGeneric" }, // 524 + { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0d, // 525 0x0d, 0x0f, 0x03, 0x02, 0x01, 0x01, 0x00, 0x00 }, {0}, false, "AudioChannelSLVS" }, { {0}, {0}, false, 0 }, diff --git a/src/MDD.h b/src/MDD.h index 6d7b702..d704217 100755 --- a/src/MDD.h +++ b/src/MDD.h @@ -554,7 +554,13 @@ namespace ASDCP { MDD_ACESUncompressedMonoscopicWithAlpha, // 516 MDD_ACESFrameWrappedEssence, // 517 MDD_DCAudioChannel_FSKSyncSignalChannel, // 518 - MDD_AudioChannelSLVS, // 519 + MDD_JPEG2000PictureSubDescriptor_J2KExtendedCapabilities, // 519 + MDD_JPEG2000PictureSubDescriptor_J2KProfile, // 520 + MDD_JPEG2000PictureSubDescriptor_J2KCorrespondingProfile, // 521 + MDD_J2KExtendedCapabilities, // 522 + MDD_HTJ2KPictureCodingScheme, // 523 + MDD_HTJ2KPictureCodingSchemeGeneric, // 524 + MDD_AudioChannelSLVS, // 525 MDD_Max }; // enum MDD_t diff --git a/src/MXFTypes.cpp b/src/MXFTypes.cpp index a98a4d2..39d928b 100755 --- a/src/MXFTypes.cpp +++ b/src/MXFTypes.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2005-2016, John Hurst +Copyright (c) 2005-2019, John Hurst All rights reserved. Redistribution and use in source and binary forms, with or without @@ -774,6 +774,63 @@ ASDCP::MXF::Raw::EncodeString(char* str_buf, ui32_t buf_len) const return str_buf; } + +// +bool +ASDCP::MXF::J2KExtendedCapabilities::Archive(Kumu::MemIOWriter* Writer) const { + if ( ! Writer->WriteUi32BE(Pcap) ) + { + return false; + } + + if ( ! Ccap.Archive(Writer) ) + { + return false; + } + + return true; +} + +// +bool +ASDCP::MXF::J2KExtendedCapabilities::Unarchive(Kumu::MemIOReader* Reader) { + if ( ! Reader->ReadUi32BE(&Pcap) ) + { + return false; + } + + if ( ! Ccap.Unarchive(Reader) ) + { + return false; + } + + return true; +} + +// +const char* +ASDCP::MXF::J2KExtendedCapabilities::EncodeString(char* str_buf, ui32_t buf_len) const +{ + const int str_len = ( sizeof(ui16_t) + 1 ) * JP2K::MaxCapabilities; + + if ( Pcap != 0 && buf_len > str_len ) + { + for ( int i = 0; i < Ccap.size(); ++i ) + { + snprintf(str_buf+(i*3), 4, "%02hx.", Ccap[i]); + } + + str_buf[str_len-1] = 0; + } + else + { + str_buf[0] = 0; + } + + return str_buf; +} + + // // end MXFTypes.cpp // diff --git a/src/MXFTypes.h b/src/MXFTypes.h index c49fed9..eb8b3df 100755 --- a/src/MXFTypes.h +++ b/src/MXFTypes.h @@ -1,5 +1,5 @@ /* -Copyright (c) 2005-2016, John Hurst +Copyright (c) 2005-2019, John Hurst All rights reserved. Redistribution and use in source and binary forms, with or without @@ -33,6 +33,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define _MXFTYPES_H_ #include "KLV.h" +#include "AS_DCP.h" #include #include #include @@ -688,6 +689,21 @@ namespace ASDCP const char* EncodeString(char* str_buf, ui32_t buf_len) const; }; + // + class J2KExtendedCapabilities : 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 diff --git a/src/Metadata.cpp b/src/Metadata.cpp index 2a1e1f2..9b7f95e 100755 --- a/src/Metadata.cpp +++ b/src/Metadata.cpp @@ -2125,6 +2125,18 @@ JPEG2000PictureSubDescriptor::InitFromTLVSet(TLVReader& TLVSet) result = TLVSet.ReadObject(OBJ_READ_ARGS_OPT(JPEG2000PictureSubDescriptor, J2CLayout)); J2CLayout.set_has_value( result == RESULT_OK ); } + if ( ASDCP_SUCCESS(result) ) { + result = TLVSet.ReadObject(OBJ_READ_ARGS_OPT(JPEG2000PictureSubDescriptor, J2KExtendedCapabilities)); + J2KExtendedCapabilities.set_has_value( result == RESULT_OK ); + } + if ( ASDCP_SUCCESS(result) ) { + result = TLVSet.ReadObject(OBJ_READ_ARGS_OPT(JPEG2000PictureSubDescriptor, J2KProfile)); + J2KProfile.set_has_value( result == RESULT_OK ); + } + if ( ASDCP_SUCCESS(result) ) { + result = TLVSet.ReadObject(OBJ_READ_ARGS_OPT(JPEG2000PictureSubDescriptor, J2KCorrespondingProfile)); + J2KCorrespondingProfile.set_has_value( result == RESULT_OK ); + } return result; } @@ -2148,6 +2160,9 @@ JPEG2000PictureSubDescriptor::WriteToTLVSet(TLVWriter& TLVSet) if ( ASDCP_SUCCESS(result) && ! CodingStyleDefault.empty() ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS_OPT(JPEG2000PictureSubDescriptor, CodingStyleDefault)); if ( ASDCP_SUCCESS(result) && ! QuantizationDefault.empty() ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS_OPT(JPEG2000PictureSubDescriptor, QuantizationDefault)); if ( ASDCP_SUCCESS(result) && ! J2CLayout.empty() ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS_OPT(JPEG2000PictureSubDescriptor, J2CLayout)); + if ( ASDCP_SUCCESS(result) && ! J2KExtendedCapabilities.empty() ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS_OPT(JPEG2000PictureSubDescriptor, J2KExtendedCapabilities)); + if ( ASDCP_SUCCESS(result) && ! J2KProfile.empty() ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS_OPT(JPEG2000PictureSubDescriptor, J2KProfile)); + if ( ASDCP_SUCCESS(result) && ! J2KCorrespondingProfile.empty() ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS_OPT(JPEG2000PictureSubDescriptor, J2KCorrespondingProfile)); return result; } @@ -2170,6 +2185,9 @@ JPEG2000PictureSubDescriptor::Copy(const JPEG2000PictureSubDescriptor& rhs) CodingStyleDefault = rhs.CodingStyleDefault; QuantizationDefault = rhs.QuantizationDefault; J2CLayout = rhs.J2CLayout; + J2KExtendedCapabilities = rhs.J2KExtendedCapabilities; + J2KProfile = rhs.J2KProfile; + J2KCorrespondingProfile = rhs.J2KCorrespondingProfile; } // @@ -2205,6 +2223,17 @@ JPEG2000PictureSubDescriptor::Dump(FILE* stream) if ( ! J2CLayout.empty() ) { fprintf(stream, " %22s = %s\n", "J2CLayout", J2CLayout.get().EncodeString(identbuf, IdentBufferLen)); } + if ( ! J2KExtendedCapabilities.empty() ) { + fprintf(stream, " %22s = %s\n", "J2KExtendedCapabilities", J2KExtendedCapabilities.get().EncodeString(identbuf, IdentBufferLen)); + } + if ( ! J2KProfile.empty() ) { + fprintf(stream, " %22s:\n", "J2KProfile"); + J2KProfile.get().Dump(stream); + } + if ( ! J2KCorrespondingProfile.empty() ) { + fprintf(stream, " %22s:\n", "J2KCorrespondingProfile"); + J2KCorrespondingProfile.get().Dump(stream); + } } // diff --git a/src/Metadata.h b/src/Metadata.h index 6601d64..03b3169 100755 --- a/src/Metadata.h +++ b/src/Metadata.h @@ -571,6 +571,9 @@ namespace ASDCP optional_property CodingStyleDefault; optional_property QuantizationDefault; optional_property J2CLayout; + optional_property J2KExtendedCapabilities; + optional_property > J2KProfile; + optional_property > J2KCorrespondingProfile; JPEG2000PictureSubDescriptor(const Dictionary*& d); JPEG2000PictureSubDescriptor(const JPEG2000PictureSubDescriptor& rhs); diff --git a/src/j2c-test.cpp b/src/j2c-test.cpp index 9184982..bcf95d0 100755 --- a/src/j2c-test.cpp +++ b/src/j2c-test.cpp @@ -246,6 +246,21 @@ main(int argc, const char** argv) { has_tlm = true; } + else if ( current_marker.m_Type == MRK_CAP ) + { + Accessor::CAP CAP_(current_marker); + CAP_.Dump(stdout); + } + else if ( current_marker.m_Type == MRK_PRF ) + { + Accessor::PRF PRF_(current_marker); + PRF_.Dump(stdout); + } + else if ( current_marker.m_Type == MRK_CPF ) + { + Accessor::CPF CPF_(current_marker); + CPF_.Dump(stdout); + } else { fprintf(stderr, "Unprocessed marker - %s\n", GetMarkerString(current_marker.m_Type));