// Open the file for writing. The file must not exist. Returns error if // the operation cannot be completed. Result_t AS_02::JP2K::MXFWriter::h__Writer::OpenWrite(const std::string& filename, ASDCP::MXF::FileDescriptor* essence_descriptor, ASDCP::MXF::InterchangeObject_list_t& essence_sub_descriptor_list, const AS_02::IndexStrategy_t& IndexStrategy, const ui32_t& PartitionSpace_sec, const ui32_t& HeaderSize) { if ( ! m_State.Test_BEGIN() ) { KM_RESULT_STATE_HERE(); return RESULT_STATE; } if ( m_IndexStrategy != AS_02::IS_FOLLOW ) { DefaultLogSink().Error("Only strategy IS_FOLLOW is supported at this time.\n"); return Kumu::RESULT_NOTIMPL; } Result_t result = m_File.OpenWrite(filename.c_str()); if ( KM_SUCCESS(result) ) { m_IndexStrategy = IndexStrategy; m_PartitionSpace = PartitionSpace_sec; // later converted to edit units by SetSourceStream() m_HeaderSize = HeaderSize; if ( essence_descriptor->GetUL() != UL(m_Dict->ul(MDD_RGBAEssenceDescriptor)) && essence_descriptor->GetUL() != UL(m_Dict->ul(MDD_CDCIEssenceDescriptor)) ) { DefaultLogSink().Error("Essence descriptor is not a RGBAEssenceDescriptor or CDCIEssenceDescriptor.\n"); essence_descriptor->Dump(); return RESULT_AS02_FORMAT; } m_EssenceDescriptor = essence_descriptor; ASDCP::MXF::InterchangeObject_list_t::iterator i; for ( i = essence_sub_descriptor_list.begin(); i != essence_sub_descriptor_list.end(); ++i ) { if ( (*i)->GetUL() != UL(m_Dict->ul(MDD_JPEG2000PictureSubDescriptor)) ) { DefaultLogSink().Error("Essence sub-descriptor is not a JPEG2000PictureSubDescriptor.\n"); (*i)->Dump(); } m_EssenceSubDescriptorList.push_back(*i); GenRandomValue((*i)->InstanceUID); m_EssenceDescriptor->SubDescriptors.push_back((*i)->InstanceUID); *i = 0; // parent will only free the ones we don't keep } result = m_State.Goto_INIT(); } return result; }
ASDCP::Result_t AS_02::TimedText::MXFWriter::h__Writer::SetSourceStream(ASDCP::TimedText::TimedTextDescriptor const& TDesc) { if ( ! m_State.Test_INIT() ) { KM_RESULT_STATE_HERE(); return RESULT_STATE; } assert(m_Dict); m_TDesc = TDesc; Result_t result = TimedText_TDesc_to_MD(m_TDesc); if ( KM_SUCCESS(result) ) { ResourceList_t::const_iterator i; for ( i = m_TDesc.ResourceList.begin() ; i != m_TDesc.ResourceList.end(); ++i ) { TimedTextResourceSubDescriptor* resourceSubdescriptor = new TimedTextResourceSubDescriptor(m_Dict); GenRandomValue(resourceSubdescriptor->InstanceUID); resourceSubdescriptor->AncillaryResourceID.Set((*i).ResourceID); resourceSubdescriptor->MIMEMediaType = MIME2str((*i).Type); resourceSubdescriptor->EssenceStreamID = m_EssenceStreamID++; m_EssenceSubDescriptorList.push_back((FileDescriptor*)resourceSubdescriptor); m_EssenceDescriptor->SubDescriptors.push_back(resourceSubdescriptor->InstanceUID); // 72 == sizeof K, L, instanceuid, uuid + sizeof int32 + tag/len * 4 m_HeaderSize += ( resourceSubdescriptor->MIMEMediaType.ArchiveLength() * 2 /*ArchiveLength is broken*/ ) + 72; } } if ( KM_SUCCESS(result) ) { result = WriteAS02Header(TIMED_TEXT_PACKAGE_LABEL, UL(m_Dict->ul(MDD_TimedTextWrappingClip)), "Data Track", UL(m_EssenceUL), UL(m_Dict->ul(MDD_TimedTextEssence)), TDesc.EditRate, derive_timecode_rate_from_edit_rate(TDesc.EditRate)); } if ( KM_SUCCESS(result) ) { this->m_IndexWriter.SetPrimerLookup(&this->m_HeaderPart.m_Primer); } if ( KM_SUCCESS(result) ) { memcpy(m_EssenceUL, m_Dict->ul(MDD_TimedTextEssence), SMPTE_UL_LENGTH); m_EssenceUL[SMPTE_UL_LENGTH-1] = 1; // first (and only) essence container result = m_State.Goto_READY(); } return result; }
ASDCP::Result_t ASDCP::TimedText::MXFWriter::h__Writer::SetSourceStream(ASDCP::TimedText::TimedTextDescriptor const& TDesc) { if ( ! m_State.Test_INIT() ) return RESULT_STATE; m_TDesc = TDesc; ResourceList_t::const_iterator ri; Result_t result = TimedText_TDesc_to_MD(m_TDesc); for ( ri = m_TDesc.ResourceList.begin() ; ri != m_TDesc.ResourceList.end() && ASDCP_SUCCESS(result); ri++ ) { TimedTextResourceSubDescriptor* resourceSubdescriptor = new TimedTextResourceSubDescriptor(m_Dict); GenRandomValue(resourceSubdescriptor->InstanceUID); resourceSubdescriptor->AncillaryResourceID.Set((*ri).ResourceID); resourceSubdescriptor->MIMEMediaType = MIME2str((*ri).Type); resourceSubdescriptor->EssenceStreamID = m_EssenceStreamID++; m_EssenceSubDescriptorList.push_back((FileDescriptor*)resourceSubdescriptor); m_EssenceDescriptor->SubDescriptors.push_back(resourceSubdescriptor->InstanceUID); // 72 == sizeof K, L, instanceuid, uuid + sizeof int32 + tag/len * 4 m_HeaderSize += ( resourceSubdescriptor->MIMEMediaType.ArchiveLength() * 2 /*ArchiveLength is broken*/ ) + 72; } m_EssenceStreamID = 10; assert(m_Dict); if ( ASDCP_SUCCESS(result) ) { InitHeader(); AddDMSegment(m_TDesc.EditRate, 24, TIMED_TEXT_DEF_LABEL, UL(m_Dict->ul(MDD_DataDataDef)), TIMED_TEXT_PACKAGE_LABEL); AddEssenceDescriptor(UL(m_Dict->ul(MDD_TimedTextWrapping))); result = m_HeaderPart.WriteToFile(m_File, m_HeaderSize); if ( KM_SUCCESS(result) ) result = CreateBodyPart(m_TDesc.EditRate); } if ( ASDCP_SUCCESS(result) ) { memcpy(m_EssenceUL, m_Dict->ul(MDD_TimedTextEssence), SMPTE_UL_LENGTH); m_EssenceUL[SMPTE_UL_LENGTH-1] = 1; // first (and only) essence container result = m_State.Goto_READY(); } return result; }
ASDCP::Result_t ASDCP::TimedText::MXFWriter::h__Writer::SetSourceStream(ASDCP::TimedText::TimedTextDescriptor const& TDesc) { if ( ! m_State.Test_INIT() ) return RESULT_STATE; m_TDesc = TDesc; ResourceList_t::const_iterator ri; Result_t result = TimedText_TDesc_to_MD(m_TDesc); for ( ri = m_TDesc.ResourceList.begin() ; ri != m_TDesc.ResourceList.end() && ASDCP_SUCCESS(result); ri++ ) { TimedTextResourceSubDescriptor* resourceSubdescriptor = new TimedTextResourceSubDescriptor(m_Dict); GenRandomValue(resourceSubdescriptor->InstanceUID); resourceSubdescriptor->AncillaryResourceID.Set((*ri).ResourceID); resourceSubdescriptor->MIMEMediaType = MIME2str((*ri).Type); resourceSubdescriptor->EssenceStreamID = m_EssenceStreamID++; m_EssenceSubDescriptorList.push_back((FileDescriptor*)resourceSubdescriptor); m_EssenceDescriptor->SubDescriptors.push_back(resourceSubdescriptor->InstanceUID); // 72 == sizeof K, L, instanceuid, uuid + sizeof int32 + tag/len * 4 m_HeaderSize += ( resourceSubdescriptor->MIMEMediaType.ArchiveLength() * 2 /*ArchiveLength is broken*/ ) + 72; } m_EssenceStreamID = 10; assert(m_Dict); if ( ASDCP_SUCCESS(result) ) { InitHeader(MXFVersion_2004); // First RIP Entry if ( m_Info.LabelSetType == LS_MXF_SMPTE ) // ERK { m_RIP.PairArray.push_back(RIP::PartitionPair(0, 0)); // 3-part, no essence in header } else { DefaultLogSink().Error("Unable to write Interop timed-text MXF file. Use SMPTE DCP options instead.\n"); return RESULT_FORMAT; } // timecode rate and essence rate are the same AddSourceClip(m_TDesc.EditRate, m_TDesc.EditRate, derive_timecode_rate_from_edit_rate(m_TDesc.EditRate), TIMED_TEXT_DEF_LABEL, m_EssenceUL, UL(m_Dict->ul(MDD_DataDataDef)), TIMED_TEXT_PACKAGE_LABEL); AddEssenceDescriptor(UL(m_Dict->ul(MDD_TimedTextWrappingClip))); result = m_HeaderPart.WriteToFile(m_File, m_HeaderSize); if ( KM_SUCCESS(result) ) result = CreateBodyPart(m_TDesc.EditRate); } if ( ASDCP_SUCCESS(result) ) { memcpy(m_EssenceUL, m_Dict->ul(MDD_TimedTextEssence), SMPTE_UL_LENGTH); m_EssenceUL[SMPTE_UL_LENGTH-1] = 1; // first (and only) essence container result = m_State.Goto_READY(); } return result; }
// all the above for a single source clip Result_t AS_02::PHDR::MXFWriter::h__Writer::WritePHDRHeader(const std::string& PackageLabel, const ASDCP::UL& WrappingUL, const std::string& TrackName, const ASDCP::UL& EssenceUL, const ASDCP::UL& DataDefinition, const ASDCP::Rational& EditRate, const ui32_t& TCFrameRate) { if ( EditRate.Numerator == 0 || EditRate.Denominator == 0 ) { DefaultLogSink().Error("Non-zero edit-rate reqired.\n"); return RESULT_PARAM; } InitHeader(); AddSourceClip(EditRate, EditRate/*TODO: for a moment*/, TCFrameRate, TrackName, EssenceUL, DataDefinition, PackageLabel); // add metadata track TrackSet<SourceClip> metdata_track = CreateTrackAndSequence<SourcePackage, SourceClip>(m_HeaderPart, *m_FilePackage, MD_DEF_LABEL, EditRate, UL(m_Dict->ul(MDD_PHDRImageMetadataItem)), 3 /* track id */, m_Dict); metdata_track.Sequence->Duration.set_has_value(); m_DurationUpdateList.push_back(&(metdata_track.Sequence->Duration.get())); // Consult ST 379:2004 Sec. 6.3, "Element to track relationship" to see where "12" comes from. metdata_track.Track->TrackNumber = KM_i32_BE(Kumu::cp2i<ui32_t>((UL(m_MetadataUL).Value() + 12))); metdata_track.Clip = new SourceClip(m_Dict); m_HeaderPart.AddChildObject(metdata_track.Clip); metdata_track.Sequence->StructuralComponents.push_back(metdata_track.Clip->InstanceUID); metdata_track.Clip->DataDefinition = UL(m_Dict->ul(MDD_PHDRImageMetadataWrappingFrame)); // for now we do not allow setting this value, so all files will be 'original' metdata_track.Clip->SourceTrackID = 0; metdata_track.Clip->SourcePackageID = NilUMID; metdata_track.Clip->Duration.set_has_value(); m_DurationUpdateList.push_back(&(metdata_track.Clip->Duration.get())); // add PHDR subdescriptor m_MetadataTrackSubDescriptor = new PHDRMetadataTrackSubDescriptor(m_Dict); m_EssenceSubDescriptorList.push_back(m_MetadataTrackSubDescriptor); GenRandomValue(m_MetadataTrackSubDescriptor->InstanceUID); m_EssenceDescriptor->SubDescriptors.push_back(m_MetadataTrackSubDescriptor->InstanceUID); m_MetadataTrackSubDescriptor->DataDefinition = UL(m_Dict->ul(MDD_PHDRImageMetadataWrappingFrame)); m_MetadataTrackSubDescriptor->SourceTrackID = 3; m_MetadataTrackSubDescriptor->SimplePayloadSID = 0; AddEssenceDescriptor(WrappingUL); m_IndexWriter.SetPrimerLookup(&m_HeaderPart.m_Primer); m_RIP.PairArray.push_back(RIP::Pair(0, 0)); // Header partition RIP entry m_IndexWriter.OperationalPattern = m_HeaderPart.OperationalPattern; m_IndexWriter.EssenceContainers = m_HeaderPart.EssenceContainers; Result_t result = m_HeaderPart.WriteToFile(m_File, m_HeaderSize); if ( KM_SUCCESS(result) ) { m_PartitionSpace *= floor( EditRate.Quotient() + 0.5 ); // convert seconds to edit units m_ECStart = m_File.Tell(); m_IndexWriter.IndexSID = 129; UL body_ul(m_Dict->ul(MDD_ClosedCompleteBodyPartition)); Partition body_part(m_Dict); body_part.BodySID = 1; body_part.OperationalPattern = m_HeaderPart.OperationalPattern; body_part.EssenceContainers = m_HeaderPart.EssenceContainers; body_part.ThisPartition = m_ECStart; result = body_part.WriteToFile(m_File, body_ul); m_RIP.PairArray.push_back(RIP::Pair(1, body_part.ThisPartition)); // Second RIP Entry } return result; }