X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=src%2FAS_DCP_MXF.cpp;h=82ec81c8445df8cdfe5ee3266be6a5b0cf42feb6;hb=0878e96b455719b4c580c58f6ccefb0d34debb60;hp=9436273e7be18d4f95e4fd4e950ffb3bf4dec2f8;hpb=30d642bd3b8474744dfbdcc2bdc46cdf827102c4;p=asdcplib.git diff --git a/src/AS_DCP_MXF.cpp b/src/AS_DCP_MXF.cpp index 9436273..82ec81c 100755 --- a/src/AS_DCP_MXF.cpp +++ b/src/AS_DCP_MXF.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2004-2005, John Hurst +Copyright (c) 2004-2013, John Hurst All rights reserved. Redistribution and use in source and binary forms, with or without @@ -29,17 +29,46 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \brief AS-DCP library, misc classes and subroutines */ +#include +#include #include "AS_DCP_internal.h" -#include "FileIO.h" -#include "DirScanner.h" #include "JP2K.h" +#include "MPEG.h" #include "Wav.h" +#include +#include //------------------------------------------------------------------------------------------ // misc subroutines +// +std::ostream& +ASDCP::operator << (std::ostream& strm, const WriterInfo& Info) +{ + char str_buf[40]; + + strm << " ProductUUID: " << UUID(Info.ProductUUID).EncodeHex(str_buf, 40) << std::endl; + strm << " ProductVersion: " << Info.ProductVersion << std::endl; + strm << " CompanyName: " << Info.CompanyName << std::endl; + strm << " ProductName: " << Info.ProductName << std::endl; + strm << " EncryptedEssence: " << (Info.EncryptedEssence ? "Yes" : "No") << std::endl; + + if ( Info.EncryptedEssence ) + { + strm << " HMAC: " << (Info.UsesHMAC ? "Yes" : "No") << std::endl; + strm << " ContextID: " << UUID(Info.ContextID).EncodeHex(str_buf, 40) << std::endl; + strm << "CryptographicKeyID: " << UUID(Info.CryptographicKeyID).EncodeHex(str_buf, 40) << std::endl; + } + + strm << " AssetUUID: " << UUID(Info.AssetUUID).EncodeHex(str_buf, 40) << std::endl; + strm << " Label Set Type: " << (Info.LabelSetType == LS_MXF_SMPTE ? "SMPTE" : + (Info.LabelSetType == LS_MXF_INTEROP ? "MXF Interop" : + "Unknown")) << std::endl; + return strm; +} + // void ASDCP::WriterInfoDump(const WriterInfo& Info, FILE* stream) @@ -49,7 +78,7 @@ ASDCP::WriterInfoDump(const WriterInfo& Info, FILE* stream) char str_buf[40]; - fprintf(stream," ProductUUID: %s\n", bin2hex(Info.ProductUUID, 16, str_buf, 40)); + fprintf(stream," ProductUUID: %s\n", UUID(Info.ProductUUID).EncodeHex(str_buf, 40)); fprintf(stream,"\ ProductVersion: %s\n\ CompanyName: %s\n\ @@ -64,11 +93,14 @@ ASDCP::WriterInfoDump(const WriterInfo& Info, FILE* stream) if ( Info.EncryptedEssence ) { fprintf(stream, " HMAC: %s\n", ( Info.UsesHMAC ? "Yes" : "No")); - fprintf(stream, " ContextID: %s\n", bin2hex(Info.ContextID, 16, str_buf, 40)); - fprintf(stream, "CryptographicKeyID: %s\n", bin2hex(Info.CryptographicKeyID, 16, str_buf, 40)); + fprintf(stream, " ContextID: %s\n", UUID(Info.ContextID).EncodeHex(str_buf, 40)); + fprintf(stream, "CryptographicKeyID: %s\n", UUID(Info.CryptographicKeyID).EncodeHex(str_buf, 40)); } - fprintf(stream," AssetUUID: %s\n", bin2hex(Info.AssetUUID, 16, str_buf, 40)); + fprintf(stream," AssetUUID: %s\n", UUID(Info.AssetUUID).EncodeHex(str_buf, 40)); + fprintf(stream," Label Set Type: %s\n", ( Info.LabelSetType == LS_MXF_SMPTE ? "SMPTE" : + ( Info.LabelSetType == LS_MXF_INTEROP ? "MXF Interop" : + "Unknown" ) )); } // @@ -83,13 +115,13 @@ ASDCP::MD_to_WriterInfo(Identification* InfoObj, WriterInfo& Info) Info.CompanyName = "Unknown Company"; memset(Info.ProductUUID, 0, UUIDlen); - InfoObj->ProductName.ToString(tmp_str); + InfoObj->ProductName.EncodeString(tmp_str, IdentBufferLen); if ( *tmp_str ) Info.ProductName = tmp_str; - InfoObj->VersionString.ToString(tmp_str); + InfoObj->VersionString.EncodeString(tmp_str, IdentBufferLen); if ( *tmp_str ) Info.ProductVersion = tmp_str; - InfoObj->CompanyName.ToString(tmp_str); + InfoObj->CompanyName.EncodeString(tmp_str, IdentBufferLen); if ( *tmp_str ) Info.CompanyName = tmp_str; memcpy(Info.ProductUUID, InfoObj->ProductUID.Value(), UUIDlen); @@ -100,7 +132,7 @@ ASDCP::MD_to_WriterInfo(Identification* InfoObj, WriterInfo& Info) // Result_t -ASDCP::MD_to_CryptoInfo(CryptographicContext* InfoObj, WriterInfo& Info) +ASDCP::MD_to_CryptoInfo(CryptographicContext* InfoObj, WriterInfo& Info, const Dictionary& Dict) { ASDCP_TEST_NULL(InfoObj); @@ -108,8 +140,8 @@ ASDCP::MD_to_CryptoInfo(CryptographicContext* InfoObj, WriterInfo& Info) memcpy(Info.ContextID, InfoObj->ContextID.Value(), UUIDlen); memcpy(Info.CryptographicKeyID, InfoObj->CryptographicKeyID.Value(), UUIDlen); - UL MIC_SHA1(Dict::ul(MDD_MICAlgorithm_HMAC_SHA1)); - UL MIC_NONE(Dict::ul(MDD_MICAlgorithm_NONE)); + UL MIC_SHA1(Dict.ul(MDD_MICAlgorithm_HMAC_SHA1)); + UL MIC_NONE(Dict.ul(MDD_MICAlgorithm_NONE)); if ( InfoObj->MICAlgorithm == MIC_SHA1 ) Info.UsesHMAC = true; @@ -129,11 +161,14 @@ ASDCP::MD_to_CryptoInfo(CryptographicContext* InfoObj, WriterInfo& Info) // // ASDCP::Result_t -ASDCP::EssenceType(const char* filename, EssenceType_t& type) +ASDCP::EssenceType(const std::string& filename, EssenceType_t& type) { - ASDCP_TEST_NULL_STR(filename); - FileReader Reader; - OPAtomHeader TestHeader; + const Dictionary* m_Dict = &DefaultCompositeDict(); + InterchangeObject* md_object = 0; + + assert(m_Dict); + Kumu::FileReader Reader; + OP1aHeader TestHeader(m_Dict); Result_t result = Reader.OpenRead(filename); @@ -143,36 +178,103 @@ ASDCP::EssenceType(const char* filename, EssenceType_t& type) if ( ASDCP_SUCCESS(result) ) { type = ESS_UNKNOWN; - if ( ASDCP_SUCCESS(TestHeader.GetMDObjectByType(OBJ_TYPE_ARGS(RGBAEssenceDescriptor))) ) - type = ESS_JPEG_2000; - else + + if ( TestHeader.OperationalPattern == UL(m_Dict->ul(MDD_OPAtom)) + || TestHeader.OperationalPattern == UL(m_Dict->ul(MDD_MXFInterop_OPAtom)) ) { - if ( ASDCP_SUCCESS(TestHeader.GetMDObjectByType(OBJ_TYPE_ARGS(WaveAudioDescriptor))) ) - type = ESS_PCM_24b_48k; - else + if ( ASDCP_SUCCESS(TestHeader.GetMDObjectByType(OBJ_TYPE_ARGS(JPEG2000PictureSubDescriptor))) ) + { + if ( ASDCP_SUCCESS(TestHeader.GetMDObjectByType(OBJ_TYPE_ARGS(StereoscopicPictureSubDescriptor))) ) + { + type = ESS_JPEG_2000_S; + } + else + { + type = ESS_JPEG_2000; + } + } + else if ( ASDCP_SUCCESS(TestHeader.GetMDObjectByType(OBJ_TYPE_ARGS(WaveAudioDescriptor), &md_object)) ) { - if ( ASDCP_SUCCESS(TestHeader.GetMDObjectByType(OBJ_TYPE_ARGS(MPEG2VideoDescriptor))) ) - type = ESS_MPEG2_VES; + assert(md_object); + if ( static_cast(md_object)->AudioSamplingRate == SampleRate_96k ) + { + type = ESS_PCM_24b_96k; + } + else + { + type = ESS_PCM_24b_48k; + } } + else if ( ASDCP_SUCCESS(TestHeader.GetMDObjectByType(OBJ_TYPE_ARGS(MPEG2VideoDescriptor))) ) + { + type = ESS_MPEG2_VES; + } + else if ( ASDCP_SUCCESS(TestHeader.GetMDObjectByType(OBJ_TYPE_ARGS(TimedTextDescriptor))) ) + { + type = ESS_TIMED_TEXT; + } + else if ( ASDCP_SUCCESS(TestHeader.GetMDObjectByType(OBJ_TYPE_ARGS(DCDataDescriptor))) ) + { + if ( ASDCP_SUCCESS(TestHeader.GetMDObjectByType(OBJ_TYPE_ARGS(DolbyAtmosSubDescriptor))) ) + { + type = ESS_DCDATA_DOLBY_ATMOS; + } + else + { + type = ESS_DCDATA_UNKNOWN; + } + } + } + else if ( TestHeader.OperationalPattern == UL(m_Dict->ul(MDD_OP1a)) ) + { + if ( ASDCP_SUCCESS(TestHeader.GetMDObjectByType(OBJ_TYPE_ARGS(JPEG2000PictureSubDescriptor))) ) + { + type = ESS_AS02_JPEG_2000; + } + else if ( ASDCP_SUCCESS(TestHeader.GetMDObjectByType(OBJ_TYPE_ARGS(WaveAudioDescriptor), &md_object)) ) + { + assert(md_object); + if ( static_cast(md_object)->AudioSamplingRate == SampleRate_96k ) + { + type = ESS_AS02_PCM_24b_96k; + } + else + { + type = ESS_AS02_PCM_24b_48k; + } + } + else if ( ASDCP_SUCCESS(TestHeader.GetMDObjectByType(OBJ_TYPE_ARGS(TimedTextDescriptor))) ) + { + type = ESS_AS02_TIMED_TEXT; + } + } + else + { + DefaultLogSink().Error("Unsupported MXF Operational Pattern.\n"); + return RESULT_FORMAT; } } return result; } - // ASDCP::Result_t -ASDCP::RawEssenceType(const char* filename, EssenceType_t& type) +ASDCP::RawEssenceType(const std::string& filename, EssenceType_t& type) { - ASDCP_TEST_NULL_STR(filename); type = ESS_UNKNOWN; ASDCP::FrameBuffer FB; - FileReader Reader; + Kumu::FileReader Reader; + ASDCP::Wav::SimpleWaveHeader WavHeader; + ASDCP::RF64::SimpleRF64Header RF64Header; + ASDCP::AIFF::SimpleAIFFHeader AIFFHeader; + Kumu::XMLElement TmpElement("Tmp"); + + ui32_t data_offset; ui32_t read_count; Result_t result = FB.Capacity(Wav::MaxWavHeader); // using Wav max because everything else is much smaller - if ( ASDCP::PathIsFile(filename) ) + if ( Kumu::PathIsFile(filename) ) { result = Reader.OpenRead(filename); @@ -184,25 +286,58 @@ ASDCP::RawEssenceType(const char* filename, EssenceType_t& type) if ( ASDCP_SUCCESS(result) ) { - ASDCP::Wav::SimpleWaveHeader WavHeader; - ASDCP::AIFF::SimpleAIFFHeader AIFFHeader; - ui32_t data_offset; const byte_t* p = FB.RoData(); + FB.Size(read_count); - if ( p[0] == 0 && p[1] == 0 && p[2] == 1 && (p[3] == 0xb3 || p[3] == 0) ) - type = ESS_MPEG2_VES; - - else if ( ASDCP_SUCCESS(WavHeader.ReadFromBuffer(p, read_count, &data_offset)) ) - type = ESS_PCM_24b_48k; + ui32_t i = 0; + while ( p[i] == 0 ) i++; - else if ( ASDCP_SUCCESS(AIFFHeader.ReadFromBuffer(p, read_count, &data_offset)) ) - type = ESS_PCM_24b_48k; + if ( i > 1 && p[i] == 1 && (p[i+1] == ASDCP::MPEG2::SEQ_START || p[i+1] == ASDCP::MPEG2::PIC_START) ) + { + type = ESS_MPEG2_VES; + } + else if ( memcmp(FB.RoData(), ASDCP::JP2K::Magic, sizeof(ASDCP::JP2K::Magic)) == 0 ) + { + type = ESS_JPEG_2000; + } + else if ( ASDCP_SUCCESS(WavHeader.ReadFromBuffer(FB.RoData(), read_count, &data_offset)) ) + { + switch ( WavHeader.samplespersec ) + { + case 48000: type = ESS_PCM_24b_48k; break; + case 96000: type = ESS_PCM_24b_96k; break; + default: + return RESULT_FORMAT; + } + } + else if ( ASDCP_SUCCESS(RF64Header.ReadFromBuffer(FB.RoData(), read_count, &data_offset)) ) + { + switch ( RF64Header.samplespersec ) + { + case 48000: type = ESS_PCM_24b_48k; break; + case 96000: type = ESS_PCM_24b_96k; break; + default: + return RESULT_FORMAT; + } + } + else if ( ASDCP_SUCCESS(AIFFHeader.ReadFromBuffer(FB.RoData(), read_count, &data_offset)) ) + { + type = ESS_PCM_24b_48k; + } + else if ( Kumu::StringIsXML((const char*)FB.RoData(), FB.Size()) ) + { + type = ESS_TIMED_TEXT; + } + else if ( ASDCP::ATMOS::IsDolbyAtmos(filename) ) + { + type = ESS_DCDATA_DOLBY_ATMOS; + } } } - else if ( ASDCP::PathIsDirectory(filename) ) + else if ( Kumu::PathIsDirectory(filename) ) { - char next_file[ASDCP_MAX_PATH]; - DirScanner Scanner; + char next_file[Kumu::MaxFilePath]; + Kumu::DirScanner Scanner; Result_t result = Scanner.Open(filename); if ( ASDCP_SUCCESS(result) ) @@ -212,10 +347,7 @@ ASDCP::RawEssenceType(const char* filename, EssenceType_t& type) if ( next_file[0] == '.' ) // no hidden files or internal links continue; - std::string Str(filename); - Str += "/"; - Str += next_file; - result = Reader.OpenRead(Str.c_str()); + result = Reader.OpenRead(Kumu::PathJoin(filename, next_file)); if ( ASDCP_SUCCESS(result) ) { @@ -223,10 +355,38 @@ ASDCP::RawEssenceType(const char* filename, EssenceType_t& type) Reader.Close(); } - if ( ASDCP_SUCCESS(result) - && ( memcmp(FB.RoData(), ASDCP::JP2K::Magic, sizeof(ASDCP::JP2K::Magic)) == 0 ) ) - type = ESS_JPEG_2000; - + if ( ASDCP_SUCCESS(result) ) + { + if ( memcmp(FB.RoData(), ASDCP::JP2K::Magic, sizeof(ASDCP::JP2K::Magic)) == 0 ) + { + type = ESS_JPEG_2000; + } + else if ( ASDCP_SUCCESS(WavHeader.ReadFromBuffer(FB.RoData(), read_count, &data_offset)) ) + { + switch ( WavHeader.samplespersec ) + { + case 48000: type = ESS_PCM_24b_48k; break; + case 96000: type = ESS_PCM_24b_96k; break; + default: + return RESULT_FORMAT; + } + } + else if ( ASDCP_SUCCESS(RF64Header.ReadFromBuffer(FB.RoData(), read_count, &data_offset)) ) + { + switch ( RF64Header.samplespersec ) + { + case 48000: type = ESS_PCM_24b_48k; break; + case 96000: type = ESS_PCM_24b_96k; break; + default: + return RESULT_FORMAT; + } + } + else if ( ASDCP::ATMOS::IsDolbyAtmos(Kumu::PathJoin(filename, next_file)) ) + { + type = ESS_DCDATA_DOLBY_ATMOS; + } + } + break; } } @@ -366,7 +526,7 @@ ASDCP::DecryptFrameBuffer(const ASDCP::FrameBuffer& FBin, ASDCP::FrameBuffer& FB // Result_t -ASDCP::IntegrityPack::CalcValues(const ASDCP::FrameBuffer& FB, byte_t* AssetID, +ASDCP::IntegrityPack::CalcValues(const ASDCP::FrameBuffer& FB, const byte_t* AssetID, ui32_t sequence, HMACContext* HMAC) { ASDCP_TEST_NULL(AssetID); @@ -374,7 +534,7 @@ ASDCP::IntegrityPack::CalcValues(const ASDCP::FrameBuffer& FB, byte_t* AssetID, byte_t* p = Data; HMAC->Reset(); - static byte_t ber_4[MXF_BER_LENGTH] = {0x83, 0}; + static byte_t ber_4[MXF_BER_LENGTH] = {0x83, 0, 0, 0}; // update HMAC with essence data HMAC->Update(FB.RoData(), FB.Size()); @@ -394,7 +554,7 @@ ASDCP::IntegrityPack::CalcValues(const ASDCP::FrameBuffer& FB, byte_t* AssetID, p += MXF_BER_LENGTH; // sequence number - i2p(ASDCP_i64_BE(sequence), p); + Kumu::i2p(KM_i64_BE(sequence), p); p += sizeof(ui64_t); // HMAC length @@ -416,7 +576,7 @@ ASDCP::IntegrityPack::CalcValues(const ASDCP::FrameBuffer& FB, byte_t* AssetID, Result_t -ASDCP::IntegrityPack::TestValues(const ASDCP::FrameBuffer& FB, byte_t* AssetID, +ASDCP::IntegrityPack::TestValues(const ASDCP::FrameBuffer& FB, const byte_t* AssetID, ui32_t sequence, HMACContext* HMAC) { ASDCP_TEST_NULL(AssetID); @@ -426,7 +586,7 @@ ASDCP::IntegrityPack::TestValues(const ASDCP::FrameBuffer& FB, byte_t* AssetID, byte_t* p = (byte_t*)FB.RoData() + ( FB.Size() - klv_intpack_size ); // test the AssetID length - if ( ! read_test_BER(&p, UUIDlen) ) + if ( ! Kumu::read_test_BER(&p, UUIDlen) ) return RESULT_HMACFAIL; // test the AssetID @@ -438,22 +598,22 @@ ASDCP::IntegrityPack::TestValues(const ASDCP::FrameBuffer& FB, byte_t* AssetID, p += UUIDlen; // test the sequence length - if ( ! read_test_BER(&p, sizeof(ui64_t)) ) + if ( ! Kumu::read_test_BER(&p, sizeof(ui64_t)) ) return RESULT_HMACFAIL; - ui32_t test_sequence = (ui32_t)ASDCP_i64_BE(cp2i(p)); + ui32_t test_sequence = (ui32_t)KM_i64_BE(Kumu::cp2i(p)); // test the sequence value if ( test_sequence != sequence ) { - DefaultLogSink().Error("IntegrityPack failure: sequence is %lu, expecting %lu.\n", test_sequence, sequence); + DefaultLogSink().Error("IntegrityPack failure: sequence is %u, expecting %u.\n", test_sequence, sequence); return RESULT_HMACFAIL; } p += sizeof(ui64_t); // test the HMAC length - if ( ! read_test_BER(&p, HMAC_SIZE) ) + if ( ! Kumu::read_test_BER(&p, HMAC_SIZE) ) return RESULT_HMACFAIL; // test the HMAC @@ -464,49 +624,6 @@ ASDCP::IntegrityPack::TestValues(const ASDCP::FrameBuffer& FB, byte_t* AssetID, return HMAC->TestHMACValue(p); } -//------------------------------------------------------------------------------------------ -// - - -// -ASDCP::Result_t -ASDCP::KLVReader::ReadKLFromFile(ASDCP::FileReader& Reader) -{ - ui32_t read_count; - m_HeaderLength = SMPTE_UL_LENGTH + MXF_BER_LENGTH; - Result_t result = Reader.Read(m_Key, m_HeaderLength, &read_count); - assert(read_count == m_HeaderLength); - - if ( ASDCP_SUCCESS(result) ) - { - m_BERLength = BER_length(m_Key + SMPTE_UL_LENGTH); - - if ( m_BERLength == 0 ) - { - char intbuf[IntBufferLen]; - ASDCP::DefaultLogSink().Error("KLV format error, zero BER length not allowed at file position %s\n", - i64szx((Reader.Tell() - (fpos_t)SMPTE_UL_LENGTH), 8, intbuf)); - return RESULT_FAIL; - } - - if ( m_BERLength != MXF_BER_LENGTH ) - { - - ASDCP::DefaultLogSink().Error("Found packet with BER length %lu; being less efficient...\n", - m_BERLength); - // TODO: recover the correct BER value - // and reposition the file pointer - ASDCP::DefaultLogSink().Error("please finish me\n"); - assert(0); - } - - if ( ! read_BER(m_Key + SMPTE_UL_LENGTH, &m_Length) ) - return RESULT_FAIL; - } - - return result; -} - // // end AS_DCP_MXF.cpp //