/*! \warning Assume that the list has been sorted (Sort()) */ const KaxCuePoint * KaxCues::GetTimecodePoint(uint64 aTimecode) const { uint64 TimecodeToLocate = aTimecode / GlobalTimecodeScale(); const KaxCuePoint * aPointPrev = NULL; uint64 aPrevTime = 0; uint64 aNextTime = EBML_PRETTYLONGINT(0xFFFFFFFFFFFF); EBML_MASTER_CONST_ITERATOR Itr; for (Itr = begin(); Itr != end(); ++Itr) { if (EbmlId(*(*Itr)) == EBML_ID(KaxCuePoint)) { const KaxCuePoint *tmp = static_cast<const KaxCuePoint *>(*Itr); // check the tile const KaxCueTime *aTime = static_cast<const KaxCueTime *>(tmp->FindFirstElt(EBML_INFO(KaxCueTime))); if (aTime != NULL) { uint64 _Time = uint64(*aTime); if (_Time > aPrevTime && _Time < TimecodeToLocate) { aPrevTime = _Time; aPointPrev = tmp; } if (_Time < aNextTime && _Time > TimecodeToLocate) { aNextTime= _Time; } } } } return aPointPrev; }
EbmlElement * kax_file_c::read_one_element() { if (m_segment_end && (m_in->getFilePointer() >= m_segment_end)) return nullptr; int upper_lvl_el = 0; EbmlElement *l1 = m_es->FindNextElement(EBML_CLASS_CONTEXT(KaxSegment), upper_lvl_el, 0xFFFFFFFFL, true); if (!l1) return nullptr; const EbmlCallbacks *callbacks = find_ebml_callbacks(EBML_INFO(KaxSegment), EbmlId(*l1)); if (!callbacks) callbacks = &EBML_CLASS_CALLBACK(KaxSegment); EbmlElement *l2 = nullptr; try { l1->Read(*m_es.get(), EBML_INFO_CONTEXT(*callbacks), upper_lvl_el, l2, true); } catch (libebml::CRTError &e) { mxdebug_if(m_debug_resync, boost::format("exception reading element data: %1% (%2%)\n") % e.what() % e.getError()); m_in->setFilePointer(l1->GetElementPosition() + 1); delete l1; return nullptr; } unsigned long element_size = get_element_size(l1); if (m_debug_resync) mxinfo(boost::format("kax_file::read_one_element(): read element at %1% calculated size %2% stored size %3%\n") % l1->GetElementPosition() % element_size % (l1->IsFiniteSize() ? (boost::format("%1%") % l1->ElementSize()).str() : std::string("unknown"))); m_in->setFilePointer(l1->GetElementPosition() + element_size, seek_beginning); return l1; }
uint16 KaxCueTrackPositions::TrackNumber() const { const KaxCueTrack *aTrack = static_cast<const KaxCueTrack *>(FindFirstElt(EBML_INFO(KaxCueTrack))); if (aTrack == NULL) return 0; return uint16(*aTrack); }
bool KaxCuePoint::Timecode(uint64 & aTimecode, uint64 GlobalTimecodeScale) const { const KaxCueTime *aTime = static_cast<const KaxCueTime *>(FindFirstElt(EBML_INFO(KaxCueTime))); if (aTime == NULL) return false; aTimecode = uint64(*aTime) * GlobalTimecodeScale; return true; }
uint64 KaxCluster::GetBlockGlobalTimecode(int16 GlobalSavedTimecode) { if (!bFirstFrameInside) { KaxClusterTimecode * Timecode = static_cast<KaxClusterTimecode *>(this->FindElt(EBML_INFO(KaxClusterTimecode))); assert (bFirstFrameInside); // use the InitTimecode() hack for now MinTimecode = MaxTimecode = PreviousTimecode = *static_cast<EbmlUInteger *>(Timecode); bFirstFrameInside = true; bPreviousTimecodeIsSet = true; } return int64(GlobalSavedTimecode * GlobalTimecodeScale()) + GlobalTimecode(); }
bool KaxCuePoint::IsSmallerThan(const EbmlElement * EltB) const { assert(EbmlId(*this) == EBML_ID(KaxCuePoint)); assert(EbmlId(*EltB) == EBML_ID(KaxCuePoint)); const KaxCuePoint & theEltB = *static_cast<const KaxCuePoint *>(EltB); // compare timecode const KaxCueTime * TimeCodeA = static_cast<const KaxCueTime *>(FindElt(EBML_INFO(KaxCueTime))); if (TimeCodeA == NULL) return false; const KaxCueTime * TimeCodeB = static_cast<const KaxCueTime *>(theEltB.FindElt(EBML_INFO(KaxCueTime))); if (TimeCodeB == NULL) return false; if (TimeCodeA->IsSmallerThan(TimeCodeB)) return true; if (TimeCodeB->IsSmallerThan(TimeCodeA)) return false; // compare tracks (timecodes are equal) const KaxCueTrack * TrackA = static_cast<const KaxCueTrack *>(FindElt(EBML_INFO(KaxCueTrack))); if (TrackA == NULL) return false; const KaxCueTrack * TrackB = static_cast<const KaxCueTrack *>(theEltB.FindElt(EBML_INFO(KaxCueTrack))); if (TrackB == NULL) return false; if (TrackA->IsSmallerThan(TrackB)) return true; if (TrackB->IsSmallerThan(TrackA)) return false; return false; }
void KaxCuePoint::PositionSet(const KaxBlockBlob & BlobReference, uint64 GlobalTimecodeScale) { const KaxInternalBlock &BlockReference = BlobReference; // fill me KaxCueTime & NewTime = GetChild<KaxCueTime>(*this); *static_cast<EbmlUInteger*>(&NewTime) = BlockReference.GlobalTimecode() / GlobalTimecodeScale; KaxCueTrackPositions & NewPositions = AddNewChild<KaxCueTrackPositions>(*this); KaxCueTrack & TheTrack = GetChild<KaxCueTrack>(NewPositions); *static_cast<EbmlUInteger*>(&TheTrack) = BlockReference.TrackNum(); KaxCueClusterPosition & TheClustPos = GetChild<KaxCueClusterPosition>(NewPositions); *static_cast<EbmlUInteger*>(&TheClustPos) = BlockReference.ClusterPosition(); #if 0 // MATROSKA_VERSION >= 2 // handle reference use if (BlockReference.ReferenceCount() != 0) { unsigned int i; for (i=0; i<BlockReference.ReferenceCount(); i++) { KaxCueReference & NewRefs = AddNewChild<KaxCueReference>(NewPositions); NewRefs.AddReference(BlockReference.Reference(i).RefBlock(), GlobalTimecodeScale); } } #endif // MATROSKA_VERSION #if MATROSKA_VERSION >= 2 if (!BlobReference.IsSimpleBlock()) { const KaxBlockGroup &BlockGroup = BlobReference; const KaxCodecState *CodecState = static_cast<KaxCodecState *>(BlockGroup.FindFirstElt(EBML_INFO(KaxCodecState))); if (CodecState != NULL) { KaxCueCodecState &CueCodecState = AddNewChild<KaxCueCodecState>(NewPositions); *static_cast<EbmlUInteger*>(&CueCodecState) = BlockGroup.GetParentCluster()->GetParentSegment()->GetRelativePosition(CodecState->GetElementPosition()); } } #endif // MATROSKA_VERSION SetValueIsSet(); }
START_LIBMATROSKA_NAMESPACE /*! \todo handle codec state checking \todo remove duplicate references (reference to 2 frames that each reference the same frame) */ void KaxCuePoint::PositionSet(const KaxBlockGroup & BlockReference, uint64 GlobalTimecodeScale) { // fill me KaxCueTime & NewTime = GetChild<KaxCueTime>(*this); *static_cast<EbmlUInteger*>(&NewTime) = BlockReference.GlobalTimecode() / GlobalTimecodeScale; KaxCueTrackPositions & NewPositions = AddNewChild<KaxCueTrackPositions>(*this); KaxCueTrack & TheTrack = GetChild<KaxCueTrack>(NewPositions); *static_cast<EbmlUInteger*>(&TheTrack) = BlockReference.TrackNumber(); KaxCueClusterPosition & TheClustPos = GetChild<KaxCueClusterPosition>(NewPositions); *static_cast<EbmlUInteger*>(&TheClustPos) = BlockReference.ClusterPosition(); #if MATROSKA_VERSION >= 2 // handle reference use if (BlockReference.ReferenceCount() != 0) { unsigned int i; for (i=0; i<BlockReference.ReferenceCount(); i++) { KaxCueReference & NewRefs = AddNewChild<KaxCueReference>(NewPositions); NewRefs.AddReference(BlockReference.Reference(i).RefBlock(), GlobalTimecodeScale); } } KaxCodecState *CodecState = static_cast<KaxCodecState *>(BlockReference.FindFirstElt(EBML_INFO(KaxCodecState))); if (CodecState != NULL) { KaxCueCodecState &CueCodecState = AddNewChild<KaxCueCodecState>(NewPositions); *static_cast<EbmlUInteger*>(&CueCodecState) = BlockReference.GetParentCluster()->GetParentSegment()->GetRelativePosition(CodecState->GetElementPosition()); } #endif // MATROSKA_VERSION SetValueIsSet(); }
uint64 KaxCueTrackPositions::ClusterPosition() const { const KaxCueClusterPosition *aPos = static_cast<const KaxCueClusterPosition *>(FindFirstElt(EBML_INFO(KaxCueClusterPosition))); if (aPos == NULL) return 0; return uint64(*aPos); }
/*! \brief return the position of the Cluster to load */ const KaxCueTrackPositions * KaxCuePoint::GetSeekPosition() const { const KaxCueTrackPositions * result = NULL; uint64 aPosition = EBML_PRETTYLONGINT(0xFFFFFFFFFFFFFFF); // find the position of the "earlier" Cluster const KaxCueTrackPositions *aPoss = static_cast<const KaxCueTrackPositions *>(FindFirstElt(EBML_INFO(KaxCueTrackPositions))); while (aPoss != NULL) { const KaxCueClusterPosition *aPos = static_cast<const KaxCueClusterPosition *>(aPoss->FindFirstElt(EBML_INFO(KaxCueClusterPosition))); if (aPos != NULL && uint64(*aPos) < aPosition) { aPosition = uint64(*aPos); result = aPoss; } aPoss = static_cast<const KaxCueTrackPositions *>(FindNextElt(*aPoss)); } return result; }
/*! \todo only put the Blocks written in the cue entries */ filepos_t KaxCluster::Render(IOCallback & output, KaxCues & CueToUpdate, bool bSaveDefault) { filepos_t Result = 0; size_t Index; EBML_MASTER_ITERATOR TrkItr, Itr; // update the Timecode of the Cluster before writing KaxClusterTimecode * Timecode = static_cast<KaxClusterTimecode *>(this->FindElt(EBML_INFO(KaxClusterTimecode))); *static_cast<EbmlUInteger *>(Timecode) = GlobalTimecode() / GlobalTimecodeScale(); if (Blobs.size() == 0) { // old-school direct KaxBlockGroup // SilentTracks handling // check the parent cluster for existing tracks and see if they are contained in this cluster or not if (bSilentTracksUsed) { KaxTracks & MyTracks = *static_cast<KaxTracks *>(ParentSegment->FindElt(EBML_INFO(KaxTracks))); for (TrkItr = MyTracks.begin(); TrkItr != MyTracks.end(); ++TrkItr) { if (EbmlId(*(*TrkItr)) == EBML_ID(KaxTrackEntry)) { KaxTrackEntry & entry = *static_cast<KaxTrackEntry *>(*TrkItr); uint32 tracknum = entry.TrackNumber(); for (Itr = begin(); Itr != end(); ++Itr) { if (EbmlId(*(*Itr)) == EBML_ID(KaxBlockGroup)) { KaxBlockGroup & group = *static_cast<KaxBlockGroup *>(*Itr); if (group.TrackNumber() == tracknum) break; // this track is used } } // the track wasn't found in this cluster if (Itr == end()) { KaxClusterSilentTracks * SilentTracks = static_cast<KaxClusterSilentTracks *>(this->FindFirstElt(EBML_INFO(KaxClusterSilentTracks))); assert(SilentTracks != NULL); // the flag bSilentTracksUsed should be set when creating the Cluster KaxClusterSilentTrackNumber * trackelt = static_cast<KaxClusterSilentTrackNumber *>(SilentTracks->AddNewElt(EBML_INFO(KaxClusterSilentTrackNumber))); *static_cast<EbmlUInteger *>(trackelt) = tracknum; } } } } Result = EbmlMaster::Render(output, bSaveDefault); // For all Blocks add their position on the CueEntry for (Itr = begin(); Itr != end(); ++Itr) { if (EbmlId(*(*Itr)) == EBML_ID(KaxBlockGroup)) { CueToUpdate.PositionSet(*static_cast<const KaxBlockGroup *>(*Itr)); } } } else { // new school, using KaxBlockBlob for (Index = 0; Index<Blobs.size(); Index++) { #if MATROSKA_VERSION >= 2 if (Blobs[Index]->IsSimpleBlock()) PushElement( (KaxSimpleBlock&) *Blobs[Index] ); else #endif PushElement( (KaxBlockGroup&) *Blobs[Index] ); } // SilentTracks handling // check the parent cluster for existing tracks and see if they are contained in this cluster or not if (bSilentTracksUsed) { KaxTracks & MyTracks = *static_cast<KaxTracks *>(ParentSegment->FindElt(EBML_INFO(KaxTracks))); for (TrkItr = MyTracks.begin(); TrkItr != MyTracks.end(); ++TrkItr) { if (EbmlId(*(*TrkItr)) == EBML_ID(KaxTrackEntry)) { KaxTrackEntry & entry = *static_cast<KaxTrackEntry *>(*TrkItr); uint32 tracknum = entry.TrackNumber(); for (Index = 0; Index<Blobs.size(); Index++) { if (((KaxInternalBlock&)*Blobs[Index]).TrackNum() == tracknum) break; // this track is used } // the track wasn't found in this cluster if (Index == ListSize()) { KaxClusterSilentTracks * SilentTracks = static_cast<KaxClusterSilentTracks *>(this->FindFirstElt(EBML_INFO(KaxClusterSilentTracks))); assert(SilentTracks != NULL); // the flag bSilentTracksUsed should be set when creating the Cluster KaxClusterSilentTrackNumber * trackelt = static_cast<KaxClusterSilentTrackNumber *>(SilentTracks->AddNewElt(EBML_INFO(KaxClusterSilentTrackNumber))); *static_cast<EbmlUInteger *>(trackelt) = tracknum; } } } } Result = EbmlMaster::Render(output, bSaveDefault); // For all Blocks add their position on the CueEntry for (Index = 0; Index<Blobs.size(); Index++) { CueToUpdate.PositionSet(*Blobs[Index]); } Blobs.clear(); } return Result; }
** **********************************************************************/ /*! \file \version \$Id: 51041ecb39a4fd1d3ef7982c26f4ebed686b2637 $ \author Steve Lhomme <robux4 @ users.sf.net> */ #include "ebml/EbmlContexts.h" #include "ebml/EbmlCrc32.h" #include "ebml/EbmlVoid.h" START_LIBEBML_NAMESPACE static const EbmlSemantic EbmlGlobal_ContextList[2] = { EbmlSemantic(false, false, EBML_INFO(EbmlCrc32)), ///< EbmlCrc32 EbmlSemantic(false, false, EBML_INFO(EbmlVoid)), ///< EbmlVoid }; const EbmlSemanticContext Context_EbmlGlobal = EbmlSemanticContext(0, NULL, NULL, *GetEbmlGlobal_Context, NULL); static const EbmlSemanticContext EbmlGlobal_Context = EbmlSemanticContext(countof(EbmlGlobal_ContextList), EbmlGlobal_ContextList, NULL, *GetEbmlGlobal_Context, NULL); const EbmlSemanticContext & GetEbmlGlobal_Context() { return EbmlGlobal_Context; } END_LIBEBML_NAMESPACE