ASDCP::Result_t ASDCP::ATMOS::MXFReader::h__Reader::OpenRead(const std::string& filename) { Result_t result = DCData::h__Reader::OpenRead(filename); if( ASDCP_SUCCESS(result) ) { if (NULL == m_EssenceSubDescriptor) { InterchangeObject* iObj = NULL; result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(DolbyAtmosSubDescriptor), &iObj); m_EssenceSubDescriptor = static_cast<MXF::DolbyAtmosSubDescriptor*>(iObj); if ( iObj == 0 ) { DefaultLogSink().Error("DolbyAtmosSubDescriptor object not found.\n"); return RESULT_FORMAT; } } if ( ASDCP_SUCCESS(result) ) { result = MD_to_Atmos_ADesc(m_ADesc); } } return result; }
// Automatically sets the MXF file's metadata from the WAV parser info. ASDCP::Result_t ASDCP::PCM::MXFWriter::h__Writer::SetSourceStream(const AudioDescriptor& ADesc) { if ( ! m_State.Test_INIT() ) return RESULT_STATE; if ( ADesc.EditRate != EditRate_24 && ADesc.EditRate != EditRate_25 && ADesc.EditRate != EditRate_30 && ADesc.EditRate != EditRate_48 && ADesc.EditRate != EditRate_50 && ADesc.EditRate != EditRate_60 && ADesc.EditRate != EditRate_96 && ADesc.EditRate != EditRate_100 && ADesc.EditRate != EditRate_120 && ADesc.EditRate != EditRate_16 && ADesc.EditRate != EditRate_18 && ADesc.EditRate != EditRate_20 && ADesc.EditRate != EditRate_22 && ADesc.EditRate != EditRate_23_98 ) { DefaultLogSink().Error("AudioDescriptor.EditRate is not a supported value: %d/%d\n", ADesc.EditRate.Numerator, ADesc.EditRate.Denominator); return RESULT_RAW_FORMAT; } if ( ADesc.AudioSamplingRate != SampleRate_48k && ADesc.AudioSamplingRate != SampleRate_96k ) { DefaultLogSink().Error("AudioDescriptor.AudioSamplingRate is not 48000/1 or 96000/1: %d/%d\n", ADesc.AudioSamplingRate.Numerator, ADesc.AudioSamplingRate.Denominator); return RESULT_RAW_FORMAT; } assert(m_Dict); m_ADesc = ADesc; Result_t result = PCM_ADesc_to_MD(m_ADesc, (WaveAudioDescriptor*)m_EssenceDescriptor); if ( ASDCP_SUCCESS(result) ) { memcpy(m_EssenceUL, m_Dict->ul(MDD_WAVEssence), SMPTE_UL_LENGTH); m_EssenceUL[SMPTE_UL_LENGTH-1] = 1; // first (and only) essence container result = m_State.Goto_READY(); } if ( ASDCP_SUCCESS(result) ) { result = WriteASDCPHeader(PCM_PACKAGE_LABEL, UL(m_Dict->ul(MDD_WAVWrappingFrame)), SOUND_DEF_LABEL, UL(m_EssenceUL), UL(m_Dict->ul(MDD_SoundDataDef)), m_ADesc.EditRate, derive_timecode_rate_from_edit_rate(m_ADesc.EditRate), calc_CBR_frame_size(m_Info, m_ADesc)); } return result; }
ASDCP::Result_t ASDCP::MXF::IndexTableSegment::InitFromTLVSet(TLVReader& TLVSet) { Result_t result = InterchangeObject::InitFromTLVSet(TLVSet); if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(IndexTableSegmentBase, IndexEditRate)); if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi64(OBJ_READ_ARGS(IndexTableSegmentBase, IndexStartPosition)); if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi64(OBJ_READ_ARGS(IndexTableSegmentBase, IndexDuration)); if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(IndexTableSegmentBase, EditUnitByteCount)); if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(IndexTableSegmentBase, IndexSID)); if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(EssenceContainerData, BodySID)); if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi8(OBJ_READ_ARGS(IndexTableSegmentBase, SliceCount)); if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi8(OBJ_READ_ARGS(IndexTableSegmentBase, PosTableCount)); if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(IndexTableSegment, DeltaEntryArray)); if ( ASDCP_SUCCESS(result) ) { bool rc = TLVSet.FindTL(m_Dict->Type(MDD_IndexTableSegment_IndexEntryArray)); if ( rc ) { ui32_t item_count, item_size; ui32_t const decoder_item_size = IndexEntryArray.ItemSize(); if ( TLVSet.ReadUi32BE(&item_count) ) { if ( TLVSet.ReadUi32BE(&item_size) ) { for ( ui32_t i = 0; i < item_count && rc; ++i ) { IndexEntry tmp_item; rc = tmp_item.Unarchive(&TLVSet); if ( rc ) { IndexEntryArray.push_back(tmp_item); if ( decoder_item_size < item_size ) { TLVSet.SkipOffset(item_size - decoder_item_size); } } } } } } result = rc ? RESULT_OK : RESULT_FALSE; } return result; }
ASDCP::Result_t ASDCP::MXF::IndexTableSegment::WriteToTLVSet(TLVWriter& TLVSet) { Result_t result = InterchangeObject::WriteToTLVSet(TLVSet); if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(IndexTableSegmentBase, IndexEditRate)); if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi64(OBJ_WRITE_ARGS(IndexTableSegmentBase, IndexStartPosition)); if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi64(OBJ_WRITE_ARGS(IndexTableSegmentBase, IndexDuration)); if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(IndexTableSegmentBase, EditUnitByteCount)); if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(IndexTableSegmentBase, IndexSID)); if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(EssenceContainerData, BodySID)); if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi8(OBJ_WRITE_ARGS(IndexTableSegmentBase, SliceCount)); if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi8(OBJ_WRITE_ARGS(IndexTableSegmentBase, PosTableCount)); if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(IndexTableSegment, DeltaEntryArray)); if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(IndexTableSegment, IndexEntryArray)); return result; }
ASDCP::Result_t ASDCP::PCM::MXFWriter::h__Writer::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC) { Result_t result = RESULT_OK; if ( m_State.Test_READY() ) result = m_State.Goto_RUNNING(); // first time through if ( ASDCP_SUCCESS(result) ) result = WriteEKLVPacket(FrameBuf, m_EssenceUL, Ctx, HMAC); if ( ASDCP_SUCCESS(result) ) m_FramesWritten++; return result; }
ASDCP::Result_t ASDCP::EssenceType(const char* filename, EssenceType_t& type) { const Dictionary* m_Dict = &DefaultCompositeDict(); assert(m_Dict); ASDCP_TEST_NULL_STR(filename); Kumu::FileReader Reader; OPAtomHeader TestHeader(m_Dict); Result_t result = Reader.OpenRead(filename); if ( ASDCP_SUCCESS(result) ) result = TestHeader.InitFromFile(Reader); // test UL and OP if ( ASDCP_SUCCESS(result) ) { type = ESS_UNKNOWN; if ( ASDCP_SUCCESS(TestHeader.GetMDObjectByType(OBJ_TYPE_ARGS(RGBAEssenceDescriptor))) ) { 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))) ) 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; } } return result; }
ASDCP::Result_t ASDCP::ATMOS::MXFReader::h__Reader::MD_to_Atmos_ADesc(ATMOS::AtmosDescriptor& ADesc) { ASDCP_TEST_NULL(m_EssenceSubDescriptor); Result_t result = MD_to_DCData_DDesc(ADesc); if( ASDCP_SUCCESS(result) ) { MXF::DolbyAtmosSubDescriptor* ADescObj = m_EssenceSubDescriptor; ADesc.MaxChannelCount = ADescObj->MaxChannelCount; ADesc.MaxObjectCount = ADescObj->MaxObjectCount; ::memcpy(ADesc.AtmosID, ADescObj->AtmosID.Value(), UUIDlen); ADesc.AtmosVersion = ADescObj->AtmosVersion; ADesc.FirstFrame = ADescObj->FirstFrame; } return result; }
// Open the file for writing. The file must not exist. Returns error if // the operation cannot be completed. ASDCP::Result_t ASDCP::PCM::MXFWriter::h__Writer::OpenWrite(const std::string& filename, ui32_t HeaderSize) { if ( ! m_State.Test_BEGIN() ) return RESULT_STATE; Result_t result = m_File.OpenWrite(filename); if ( ASDCP_SUCCESS(result) ) { m_HeaderSize = HeaderSize; m_EssenceDescriptor = new WaveAudioDescriptor(m_Dict); result = m_State.Goto_INIT(); } return result; }
ASDCP::Result_t ASDCP::ATMOS::MXFWriter::h__Writer::OpenWrite(const std::string& filename, ui32_t HeaderSize, const AtmosDescriptor& ADesc) { m_EssenceSubDescriptor = new DolbyAtmosSubDescriptor(m_Dict); DCData::SubDescriptorList_t subDescriptors; subDescriptors.push_back(m_EssenceSubDescriptor); Result_t result = DCData::h__Writer::OpenWrite(filename, HeaderSize, subDescriptors); if ( ASDCP_FAILURE(result) ) delete m_EssenceSubDescriptor; if ( ASDCP_SUCCESS(result) ) { m_ADesc = ADesc; memcpy(m_ADesc.DataEssenceCoding, ATMOS_ESSENCE_CODING, SMPTE_UL_LENGTH); result = Atmos_ADesc_to_MD(m_ADesc); } return result; }
// Open the file for writing. The file must not exist. Returns error if // the operation cannot be completed. ASDCP::Result_t ASDCP::PCM::MXFWriter::OpenWrite(const std::string& filename, const WriterInfo& Info, const AudioDescriptor& ADesc, ui32_t HeaderSize) { if ( Info.LabelSetType == LS_MXF_SMPTE ) m_Writer = new h__Writer(DefaultSMPTEDict()); else m_Writer = new h__Writer(DefaultInteropDict()); m_Writer->m_Info = Info; Result_t result = m_Writer->OpenWrite(filename, HeaderSize); if ( ASDCP_SUCCESS(result) ) result = m_Writer->SetSourceStream(ADesc); if ( ASDCP_FAILURE(result) ) m_Writer.release(); return result; }
// Open the file for writing. The file must not exist. Returns error if // the operation cannot be completed. ASDCP::Result_t ASDCP::ATMOS::MXFWriter::OpenWrite(const std::string& filename, const WriterInfo& Info, const AtmosDescriptor& ADesc, ui32_t HeaderSize) { if ( Info.LabelSetType != LS_MXF_SMPTE ) { DefaultLogSink().Error("Atmos support requires LS_MXF_SMPTE\n"); return RESULT_FORMAT; } m_Writer = new h__Writer(DefaultSMPTEDict()); m_Writer->m_Info = Info; Result_t result = m_Writer->OpenWrite(filename, HeaderSize, ADesc); if ( ASDCP_SUCCESS(result) ) result = m_Writer->SetSourceStream(ADesc, ATMOS_ESSENCE_CODING, ATMOS_PACKAGE_LABEL, ATMOS_DEF_LABEL); if ( ASDCP_FAILURE(result) ) m_Writer.release(); return result; }
Result_t ASDCP::DecryptFrameBuffer(const ASDCP::FrameBuffer& FBin, ASDCP::FrameBuffer& FBout, AESDecContext* Ctx) { ASDCP_TEST_NULL(Ctx); assert(FBout.Capacity() >= FBin.SourceLength()); ui32_t ct_size = FBin.SourceLength() - FBin.PlaintextOffset(); ui32_t diff = ct_size % CBC_BLOCK_SIZE; ui32_t block_size = ct_size - diff; assert(block_size); assert((block_size % CBC_BLOCK_SIZE) == 0); const byte_t* buf = FBin.RoData(); // get ivec Ctx->SetIVec(buf); buf += CBC_BLOCK_SIZE; // decrypt and test check value byte_t CheckValue[CBC_BLOCK_SIZE]; Result_t result = Ctx->DecryptBlock(buf, CheckValue, CBC_BLOCK_SIZE); buf += CBC_BLOCK_SIZE; if ( memcmp(CheckValue, ESV_CheckValue, CBC_BLOCK_SIZE) != 0 ) return RESULT_CHECKFAIL; // copy plaintext region if ( FBin.PlaintextOffset() > 0 ) { memcpy(FBout.Data(), buf, FBin.PlaintextOffset()); buf += FBin.PlaintextOffset(); } // decrypt all but last block if ( ASDCP_SUCCESS(result) ) { result = Ctx->DecryptBlock(buf, FBout.Data() + FBin.PlaintextOffset(), block_size); buf += block_size; } // decrypt last block if ( ASDCP_SUCCESS(result) ) { byte_t the_last_block[CBC_BLOCK_SIZE]; result = Ctx->DecryptBlock(buf, the_last_block, CBC_BLOCK_SIZE); if ( the_last_block[diff] != 0 ) { DefaultLogSink().Error("Unexpected non-zero padding value.\n"); return RESULT_FORMAT; } if ( diff > 0 ) memcpy(FBout.Data() + FBin.PlaintextOffset() + block_size, the_last_block, diff); } if ( ASDCP_SUCCESS(result) ) FBout.Size(FBin.SourceLength()); return result; }
Result_t ASDCP::EncryptFrameBuffer(const ASDCP::FrameBuffer& FBin, ASDCP::FrameBuffer& FBout, AESEncContext* Ctx) { ASDCP_TEST_NULL(Ctx); FBout.Size(0); // size the buffer Result_t result = FBout.Capacity(calc_esv_length(FBin.Size(), FBin.PlaintextOffset())); // write the IV byte_t* p = FBout.Data(); // write the IV to the frame buffer Ctx->GetIVec(p); p += CBC_BLOCK_SIZE; // encrypt the check value to the frame buffer if ( ASDCP_SUCCESS(result) ) { result = Ctx->EncryptBlock(ESV_CheckValue, p, CBC_BLOCK_SIZE); p += CBC_BLOCK_SIZE; } // write optional plaintext region if ( FBin.PlaintextOffset() > 0 ) { assert(FBin.PlaintextOffset() <= FBin.Size()); memcpy(p, FBin.RoData(), FBin.PlaintextOffset()); p += FBin.PlaintextOffset(); } ui32_t ct_size = FBin.Size() - FBin.PlaintextOffset(); ui32_t diff = ct_size % CBC_BLOCK_SIZE; ui32_t block_size = ct_size - diff; assert((block_size % CBC_BLOCK_SIZE) == 0); // encrypt the ciphertext region essence data if ( ASDCP_SUCCESS(result) ) { result = Ctx->EncryptBlock(FBin.RoData() + FBin.PlaintextOffset(), p, block_size); p += block_size; } // construct and encrypt the padding if ( ASDCP_SUCCESS(result) ) { byte_t the_last_block[CBC_BLOCK_SIZE]; if ( diff > 0 ) memcpy(the_last_block, FBin.RoData() + FBin.PlaintextOffset() + block_size, diff); for (ui32_t i = 0; diff < CBC_BLOCK_SIZE; diff++, i++ ) the_last_block[diff] = i; result = Ctx->EncryptBlock(the_last_block, p, CBC_BLOCK_SIZE); } if ( ASDCP_SUCCESS(result) ) FBout.Size(calc_esv_length(FBin.Size(), FBin.PlaintextOffset())); return result; }
ASDCP::Result_t ASDCP::RawEssenceType(const std::string& filename, EssenceType_t& type) { type = ESS_UNKNOWN; ASDCP::FrameBuffer FB; 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 ( Kumu::PathIsFile(filename) ) { result = Reader.OpenRead(filename); if ( ASDCP_SUCCESS(result) ) { result = Reader.Read(FB.Data(), FB.Capacity(), &read_count); Reader.Close(); } if ( ASDCP_SUCCESS(result) ) { const byte_t* p = FB.RoData(); FB.Size(read_count); ui32_t i = 0; while ( p[i] == 0 ) i++; 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 ( string_is_xml(FB) ) { type = ESS_TIMED_TEXT; } else if ( ASDCP::ATMOS::IsDolbyAtmos(filename) ) { type = ESS_DCDATA_DOLBY_ATMOS; } } } else if ( Kumu::PathIsDirectory(filename) ) { char next_file[Kumu::MaxFilePath]; Kumu::DirScanner Scanner; Result_t result = Scanner.Open(filename); if ( ASDCP_SUCCESS(result) ) { while ( ASDCP_SUCCESS(Scanner.GetNext(next_file)) ) { if ( next_file[0] == '.' ) // no hidden files or internal links continue; result = Reader.OpenRead(Kumu::PathJoin(filename, next_file)); if ( ASDCP_SUCCESS(result) ) { result = Reader.Read(FB.Data(), FB.Capacity(), &read_count); Reader.Close(); } 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; } else { type = ESS_DCDATA_UNKNOWN; } } break; } } } return result; }
ASDCP::Result_t ASDCP::EssenceType(const std::string& filename, EssenceType_t& type) { 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); if ( ASDCP_SUCCESS(result) ) result = TestHeader.InitFromFile(Reader); // test UL and OP if ( ASDCP_SUCCESS(result) ) { type = ESS_UNKNOWN; 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(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)) ) { assert(md_object); if ( static_cast<ASDCP::MXF::WaveAudioDescriptor*>(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<ASDCP::MXF::WaveAudioDescriptor*>(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::PCM::MXFReader::h__Reader::OpenRead(const std::string& filename) { Result_t result = OpenMXFRead(filename); if( ASDCP_SUCCESS(result) ) { InterchangeObject* Object = 0 ; if ( ASDCP_SUCCESS(m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(WaveAudioDescriptor), &Object)) ) { if ( Object == 0 ) { DefaultLogSink().Error("WaveAudioDescriptor object not found.\n"); return RESULT_FORMAT; } result = MD_to_PCM_ADesc((MXF::WaveAudioDescriptor*)Object, m_ADesc); } } if ( m_ADesc.ContainerDuration == 0 ) { DefaultLogSink().Error("ContainerDuration unset.\n"); return RESULT_FORMAT; } // check for sample/frame rate sanity if ( ASDCP_SUCCESS(result) && m_ADesc.EditRate != EditRate_24 && m_ADesc.EditRate != EditRate_25 && m_ADesc.EditRate != EditRate_30 && m_ADesc.EditRate != EditRate_48 && m_ADesc.EditRate != EditRate_50 && m_ADesc.EditRate != EditRate_60 && m_ADesc.EditRate != EditRate_96 && m_ADesc.EditRate != EditRate_100 && m_ADesc.EditRate != EditRate_120 && m_ADesc.EditRate != EditRate_16 && m_ADesc.EditRate != EditRate_18 && m_ADesc.EditRate != EditRate_20 && m_ADesc.EditRate != EditRate_22 && m_ADesc.EditRate != EditRate_23_98 ) { DefaultLogSink().Error("PCM file EditRate is not a supported value: %d/%d\n", // lu m_ADesc.EditRate.Numerator, m_ADesc.EditRate.Denominator); // oh, they gave us the audio sampling rate instead, assume 24/1 if ( m_ADesc.EditRate == SampleRate_48k || m_ADesc.EditRate == SampleRate_96k ) { DefaultLogSink().Warn("adjusting EditRate to 24/1\n"); m_ADesc.EditRate = EditRate_24; } else { DefaultLogSink().Error("PCM EditRate not in expected value range.\n"); // or we just drop the hammer return RESULT_FORMAT; } } // TODO: test file for sane CBR index BytesPerEditUnit return result; }