void AvidClip::SetPhysicalSourceStartTimecode() { // set start position in file source package source clips that reference a physical source package size_t i; for (i = 0; i < mTracks.size(); i++) { SourcePackage *ref_source_package = mTracks[i]->GetRefSourcePackage(); if (!ref_source_package || !ref_source_package->haveDescriptor() || !mTracks[i]->GetDataModel()->isSubclassOf(ref_source_package->getDescriptor(), &MXF_SET_K(PhysicalDescriptor))) { continue; } // get physical package start timecode Timecode phys_start_timecode; if (!GetStartTimecode(ref_source_package, &phys_start_timecode)) continue; // convert to a offset at clip frame rate uint16_t rounded_clip_tc_base = get_rounded_tc_base(mClipFrameRate); int64_t phys_tc_start_offset = convert_position(phys_start_timecode.GetOffset(), rounded_clip_tc_base, phys_start_timecode.GetRoundedTCBase(), ROUND_AUTO); int64_t clip_tc_start_offset = convert_position(mStartTimecode.GetOffset(), rounded_clip_tc_base, mStartTimecode.GetRoundedTCBase(), ROUND_AUTO); int64_t start_position = clip_tc_start_offset - phys_tc_start_offset; if (start_position < 0) { // physical source's start timecode was > start timecode log_warn("Not setting start timecode in file source package because start position was negative\n"); continue; } // set the start position vector<GenericTrack*> tracks = mTracks[i]->GetFileSourcePackage()->getTracks(); size_t j; for (j = 0; j < tracks.size(); j++) { Track *track = dynamic_cast<Track*>(tracks[j]); if (!track) continue; StructuralComponent *track_sequence = track->getSequence(); mxfUL data_def = track_sequence->getDataDefinition(); if (!mxf_is_picture(&data_def) && !mxf_is_sound(&data_def)) continue; Sequence *sequence = dynamic_cast<Sequence*>(track_sequence); BMX_ASSERT(sequence); vector<StructuralComponent*> components = sequence->getStructuralComponents(); BMX_ASSERT(components.size() == 1); SourceClip *source_clip = dynamic_cast<SourceClip*>(components[0]); BMX_ASSERT(source_clip); source_clip->setStartPosition(convert_position(mClipFrameRate, start_position, track->getEditRate(), ROUND_AUTO)); break; } } }
void OP1AFile::UpdateTrackMetadata(GenericPackage *package, int64_t origin, int64_t duration) { vector<GenericTrack*> tracks = package->getTracks(); size_t i; for (i = 0; i < tracks.size(); i++) { Track *track = dynamic_cast<Track*>(tracks[i]); if (!track) continue; track->setOrigin(origin); Sequence *sequence = dynamic_cast<Sequence*>(track->getSequence()); BMX_ASSERT(sequence); vector<StructuralComponent*> components = sequence->getStructuralComponents(); if (sequence->getDuration() < 0) { sequence->setDuration(duration); BMX_ASSERT(components.size() == 1); components[0]->setDuration(duration); } if (components.size() == 1) { TimecodeComponent *timecode_component = dynamic_cast<TimecodeComponent*>(components[0]); if (timecode_component) { Timecode start_timecode = mStartTimecode; start_timecode.AddOffset(- origin, mFrameRate); timecode_component->setRoundedTimecodeBase(start_timecode.GetRoundedTCBase()); timecode_component->setDropFrame(start_timecode.IsDropFrame()); timecode_component->setStartTimecode(start_timecode.GetOffset()); } } } }
TextBasedDMFramework *FindTextBasedDMFramework(mxfpp::HeaderMetadata *header_metadata, mxfUL xml_metadata_scheme_id, mxfpp::StaticTrack **static_track) { MaterialPackage *mp = header_metadata->getPreface()->findMaterialPackage(); if (!mp) return NULL; // expect to find Static DM Track -> Sequence -> DM Segment -> DM Framework (a TextBasedDMFramework) std::vector<GenericTrack*> tracks = mp->getTracks(); size_t i; for (i = 0; i < tracks.size(); i++) { StaticTrack *st = dynamic_cast<StaticTrack*>(tracks[i]); if (!st) continue; StructuralComponent *sc = st->getSequence(); if (!sc || sc->getDataDefinition() != MXF_DDEF_L(DescriptiveMetadata)) continue; Sequence *seq = dynamic_cast<Sequence*>(sc); DMSegment *seg = dynamic_cast<DMSegment*>(sc); if (!seq && !seg) continue; if (seq) { std::vector<StructuralComponent*> scs = seq->getStructuralComponents(); if (scs.size() != 1) continue; seg = dynamic_cast<DMSegment*>(scs[0]); if (!seg) continue; } if (!seg->haveDMFramework()) continue; DMFramework *framework = seg->getDMFrameworkLight(); if (framework) { TextBasedDMFramework *fw = dynamic_cast<TextBasedDMFramework*>(framework); if (!fw) continue; TextBasedObject *t = dynamic_cast<TextBasedObject*>(fw->getTextBasedObject()); if (!t) continue; mxfUL ul = t->getTextBasedMetadataPayloadSchemaID(); if (mxf_equals_ul(&ul, &xml_metadata_scheme_id)) { // this is a match! if (static_track != NULL) *static_track = st; return fw; } } } return NULL; }
void AS02Track::UpdatePackageMetadata(GenericPackage *package) { SourcePackage *source_package = dynamic_cast<SourcePackage*>(package); FileDescriptor *file_descriptor = 0; if (source_package && source_package->haveDescriptor()) file_descriptor = dynamic_cast<FileDescriptor*>(source_package->getDescriptor()); vector<GenericTrack*> tracks = package->getTracks(); // update track origin in file source package tracks and // duration in sequences, timecode components and source clips size_t i; for (i = 0; i < tracks.size(); i++) { Track *track = dynamic_cast<Track*>(tracks[i]); BMX_ASSERT(track); if (source_package) track->setOrigin(mOutputStartOffset); Sequence *sequence = dynamic_cast<Sequence*>(track->getSequence()); BMX_ASSERT(sequence); vector<StructuralComponent*> components = sequence->getStructuralComponents(); if (sequence->getDuration() < 0) { if (source_package) sequence->setDuration(GetDuration()); else sequence->setDuration(GetOutputDuration(false)); BMX_ASSERT(components.size() == 1); if (source_package) components[0]->setDuration(GetDuration()); else components[0]->setDuration(GetOutputDuration(false)); } if (source_package && components.size() == 1) { TimecodeComponent *timecode_component = dynamic_cast<TimecodeComponent*>(components[0]); if (timecode_component) { Timecode sp_start_timecode = mClip->mStartTimecode; sp_start_timecode.AddOffset(- mOutputStartOffset, GetSampleRate()); timecode_component->setRoundedTimecodeBase(sp_start_timecode.GetRoundedTCBase()); timecode_component->setDropFrame(sp_start_timecode.IsDropFrame()); timecode_component->setStartTimecode(sp_start_timecode.GetOffset()); } } } // update the container duration in the file descriptor if (file_descriptor) file_descriptor->setContainerDuration(mContainerDuration); }
void AvidInfo::GetLocators(MaterialPackage *mp) { // expect to find (DM) Event Track - (DM) Sequence - DMSegment vector<GenericTrack*> tracks = mp->getTracks(); size_t i; for (i = 0; i < tracks.size(); i++) { EventTrack *et = dynamic_cast<EventTrack*>(tracks[i]); if (!et) continue; StructuralComponent *sc = et->getSequence(); if (!sc || sc->getDataDefinition() != MXF_DDEF_L(DescriptiveMetadata)) continue; Sequence *seq = dynamic_cast<Sequence*>(sc); if (!seq) continue; vector<StructuralComponent*> dm_segs = seq->getStructuralComponents(); if (dm_segs.empty()) continue; size_t j; for (j = 0; j < dm_segs.size(); j++) { DMSegment *seg = dynamic_cast<DMSegment*>(dm_segs[j]); if (!seg) break; AvidLocator locator; locator.position = seg->getEventStartPosition(); if (seg->haveEventComment()) locator.comment = seg->getEventComment(); if (seg->haveItem(&MXF_ITEM_K(DMSegment, CommentMarkerColor))) { RGBColor rgb_color; BMX_CHECK(mxf_avid_get_rgb_color_item(seg->getCMetadataSet(), &MXF_ITEM_K(DMSegment, CommentMarkerColor), &rgb_color)); locator.color = convert_rgb_color(&rgb_color); } else { locator.color = COLOR_BLACK; } locators.push_back(locator); } if (j < dm_segs.size()) locators.clear(); locators_edit_rate = et->getEventEditRate(); break; } }
std::vector<DMFramework*> GetStaticFrameworks(MaterialPackage *mp) { std::vector<DMFramework*> frameworks; // expect to find Static DM Track -> Sequence -> DM Segment -> DM Framework std::vector<GenericTrack*> tracks = mp->getTracks(); size_t i; for (i = 0; i < tracks.size(); i++) { StaticTrack *st = dynamic_cast<StaticTrack*>(tracks[i]); if (!st) continue; StructuralComponent *sc = st->getSequence(); if (!sc || sc->getDataDefinition() != MXF_DDEF_L(DescriptiveMetadata)) continue; Sequence *seq = dynamic_cast<Sequence*>(sc); DMSegment *seg = dynamic_cast<DMSegment*>(sc); if (!seq && !seg) continue; if (seq) { std::vector<StructuralComponent*> scs = seq->getStructuralComponents(); if (scs.size() != 1) continue; seg = dynamic_cast<DMSegment*>(scs[0]); if (!seg) continue; } if (!seg->haveDMFramework()) continue; DMFramework *framework = seg->getDMFrameworkLight(); if (framework) frameworks.push_back(framework); } return frameworks; }
bool AvidClip::GetStartTimecode(GenericPackage *package, Timecode *timecode) { // find the timecode component in this package TimecodeComponent *tc_component = 0; vector<GenericTrack*> tracks = package->getTracks(); size_t i; for (i = 0; i < tracks.size(); i++) { Track *track = dynamic_cast<Track*>(tracks[i]); if (!track) continue; StructuralComponent *track_sequence = track->getSequence(); mxfUL data_def = track_sequence->getDataDefinition(); if (!mxf_is_timecode(&data_def)) continue; Sequence *sequence = dynamic_cast<Sequence*>(track_sequence); tc_component = dynamic_cast<TimecodeComponent*>(track_sequence); if (sequence) { vector<StructuralComponent*> components = sequence->getStructuralComponents(); size_t j; for (j = 0; j < components.size(); j++) { tc_component = dynamic_cast<TimecodeComponent*>(components[j]); if (tc_component) break; } } if (tc_component) break; } if (!tc_component) return false; timecode->Init(tc_component->getRoundedTimecodeBase(), tc_component->getDropFrame(), tc_component->getStartTimecode()); return true; }
void AvidClip::UpdateTrackDurations(AvidTrack *avid_track, Track *track, mxfRational edit_rate, int64_t duration) { int64_t track_duration = convert_duration(edit_rate, duration, track->getEditRate(), ROUND_AUTO); Sequence *sequence = dynamic_cast<Sequence*>(track->getSequence()); BMX_ASSERT(sequence); if (sequence->getDuration() >= 0) { if (sequence->getDuration() < track_duration) log_warn("Existing track duration is less than the essence duration\n"); return; } sequence->setDuration(track_duration); Preface *preface = avid_track->GetHeaderMetadata()->getPreface(); vector<StructuralComponent*> components = sequence->getStructuralComponents(); BMX_CHECK(components.size() == 1); components[0]->setDuration(track_duration); // update duration further down the reference chain SourceClip *source_clip = dynamic_cast<SourceClip*>(components[0]); if (source_clip) { mxfUMID source_package_id = source_clip->getSourcePackageID(); if (source_package_id != g_Null_UMID) { GenericPackage *ref_package = preface->findPackage(source_package_id); if (ref_package) { GenericTrack *ref_gen_track = ref_package->findTrack(source_clip->getSourceTrackID()); if (ref_gen_track) { Track *ref_track = dynamic_cast<Track*>(ref_gen_track); BMX_CHECK(ref_track); UpdateTrackDurations(avid_track, ref_track, track->getEditRate(), source_clip->getStartPosition() + track_duration); } } } } }
OPAtomTrackReader::OPAtomTrackReader(string filename, File *file, Partition *header_partition) { mFilename = filename; mTrackId = 0; mDurationInMetadata = -1; mIsPicture = true; DataModel *data_model = 0; AvidHeaderMetadata *header_metadata = 0; FrameOffsetIndexTableSegment *index_table = 0; try { int64_t essence_length = 0; mxfUL essence_label = g_Null_UL; mxfRational edit_rate = (mxfRational){0, 1}; FileDescriptor *file_descriptor = 0; uint32_t frame_size = 0; mxfKey key; uint8_t llen; uint64_t len; // get essence container label vector<mxfUL> container_labels = header_partition->getEssenceContainers(); MXFPP_CHECK(container_labels.size() == 1); essence_label = container_labels[0]; // read the header metadata data_model = new DataModel(); header_metadata = new AvidHeaderMetadata(data_model); TaggedValue::registerObjectFactory(header_metadata); file->readNextNonFillerKL(&key, &llen, &len); if (!mxf_is_header_metadata(&key)) throw OP_ATOM_FAIL; header_metadata->read(file, header_partition, &key, llen, len); Preface *preface = header_metadata->getPreface(); ContentStorage *content = preface->getContentStorage(); vector<GenericPackage*> packages = content->getPackages(); // get the file source package and descriptor SourcePackage *fsp; size_t i; for (i = 0; i < packages.size(); i++) { fsp = dynamic_cast<SourcePackage*>(packages[i]); if (!fsp || !fsp->haveDescriptor()) continue; file_descriptor = dynamic_cast<FileDescriptor*>(fsp->getDescriptor()); if (file_descriptor) break; } if (!file_descriptor) throw OP_ATOM_NO_FILE_PACKAGE; // get the material track info Track *mp_track = 0; for (i = 0; i < packages.size(); i++) { MaterialPackage *mp = dynamic_cast<MaterialPackage*>(packages[i]); if (!mp) continue; vector<GenericTrack*> tracks = mp->getTracks(); size_t j; for (j = 0; j < tracks.size(); j++) { Track *track = dynamic_cast<Track*>(tracks[j]); if (!track) continue; StructuralComponent *track_sequence = track->getSequence(); Sequence *sequence = dynamic_cast<Sequence*>(track_sequence); SourceClip *source_clip = dynamic_cast<SourceClip*>(track_sequence); if (sequence) { vector<StructuralComponent*> components = sequence->getStructuralComponents(); if (components.size() != 1) continue; source_clip = dynamic_cast<SourceClip*>(components[0]); } if (!source_clip) continue; mxfUMID fsp_umid = fsp->getPackageUID(); mxfUMID sc_umid = source_clip->getSourcePackageID(); if (memcmp(&fsp_umid, &sc_umid, sizeof(fsp_umid)) == 0) { mp_track = track; edit_rate = mp_track->getEditRate(); mTrackId = mp_track->getTrackID(); mDurationInMetadata = source_clip->getDuration(); break; } } if (mp_track) break; } if (!mp_track) throw OP_ATOM_HEADER_ERROR; // read the index table if present and complete int64_t file_pos = file->tell(); try { file->readNextNonFillerKL(&key, &llen, &len); while (!IndexTableSegment::isIndexTableSegment(&key)) { file->skip(len); file->readNextNonFillerKL(&key, &llen, &len); } if (IndexTableSegment::isIndexTableSegment(&key)) { index_table = FrameOffsetIndexTableSegment::read(file, len); mxfRational index_edit_rate = index_table->getIndexEditRate(); if (memcmp(&index_edit_rate, &edit_rate, sizeof(index_edit_rate)) == 0) frame_size = index_table->getEditUnitByteCount(); } } catch (...) { mxf_log_warn("Ignore errors - failed to find or read the index table segment\n"); // do nothing } file->seek(file_pos, SEEK_SET); // position the file at the start of the essence data try { file->readNextNonFillerKL(&key, &llen, &len); while (!mxf_is_gc_essence_element(&key) && !mxf_avid_is_essence_element(&key)) { file->skip(len); file->readNextNonFillerKL(&key, &llen, &len); } } catch (...) { throw OP_ATOM_ESSENCE_DATA_NOT_FOUND; } essence_length = len; mEssenceParser = RawEssenceParser::Create(file, essence_length, essence_label, file_descriptor, edit_rate, frame_size, index_table); if (!mEssenceParser) throw MXFException("Failed to create essence parser"); mDataModel = data_model; mHeaderMetadata = header_metadata; mIndexTable = index_table; } catch (...) { delete data_model; delete header_metadata; delete index_table; throw; } }