/*! \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; }
void KaxCluster::ReleaseFrames() { EBML_MASTER_ITERATOR Itr; for (Itr = begin(); Itr != end(); ++Itr) { if (EbmlId(*(*Itr)) == EBML_ID(KaxBlockGroup)) { static_cast<KaxBlockGroup*>(*Itr)->ReleaseFrames(); } } }
void cues_c::write(mm_io_c &out, KaxSeekHead &seek_head) { if (!m_points.size() || !g_cue_writing_requested) return; // auto start = get_current_time_millis(); sort(); // auto end_sort = get_current_time_millis(); // Need to write the (empty) cues element so that its position will // be set for indexing in g_kax_sh_main. Necessary because there's // no API function to force the position to a certain value; nor is // there a different API function in KaxSeekHead for adding anything // by ID and position manually. out.save_pos(); kax_cues_position_dummy_c cues_dummy; cues_dummy.Render(out); out.restore_pos(); // Write meta seek information if it is not disabled. seek_head.IndexThis(cues_dummy, *g_kax_segment); // Forcefully write the correct head and copy its content from the // temporary storage location. auto total_size = calculate_total_size(); write_ebml_element_head(out, EBML_ID(KaxCues), total_size); for (auto &point : m_points) { KaxCuePoint kc_point; GetChild<KaxCueTime>(kc_point).SetValue(point.timecode / g_timecode_scale); auto &positions = GetChild<KaxCueTrackPositions>(kc_point); GetChild<KaxCueTrack>(positions).SetValue(point.track_num); GetChild<KaxCueClusterPosition>(positions).SetValue(point.cluster_position); auto codec_state_position = m_codec_state_position_map.find({ point.track_num, point.timecode }); if (codec_state_position != m_codec_state_position_map.end()) GetChild<KaxCueCodecState>(positions).SetValue(codec_state_position->second); if (point.relative_position) GetChild<KaxCueRelativePosition>(positions).SetValue(point.relative_position); if (point.duration) GetChild<KaxCueDuration>(positions).SetValue(RND_TIMECODE_SCALE(point.duration) / g_timecode_scale); kc_point.Render(out); } m_points.clear(); m_codec_state_position_map.clear(); m_num_cue_points_postprocessed = 0; // auto end_all = get_current_time_millis(); // mxinfo(boost::format("dur sort %1% write %2% total %3%\n") % (end_sort - start) % (end_all - end_sort) % (end_all - start)); }
KaxCluster::KaxCluster(const KaxCluster & ElementToClone) :EbmlMaster(ElementToClone) ,bSilentTracksUsed(ElementToClone.bSilentTracksUsed) { // update the parent of each children EBML_MASTER_ITERATOR Itr = begin(); while (Itr != end()) { if (EbmlId(**Itr) == EBML_ID(KaxBlockGroup)) { static_cast<KaxBlockGroup *>(*Itr)->SetParent(*this); } else if (EbmlId(**Itr) == EBML_ID(KaxBlock)) { static_cast<KaxBlock *>(*Itr)->SetParent(*this); #if MATROSKA_VERSION >= 2 } else if (EbmlId(**Itr) == EBML_ID(KaxBlockVirtual)) { static_cast<KaxBlockVirtual *>(*Itr)->SetParent(*this); #endif // MATROSKA_VERSION } ++Itr; } }
KaxSegment::KaxSegment(const KaxSegment & ElementToClone) :EbmlMaster(ElementToClone) { // update the parent of each children EBML_MASTER_ITERATOR Itr = begin(); while (Itr != end()) { if (EbmlId(**Itr) == EBML_ID(KaxCluster)) { static_cast<KaxCluster *>(*Itr)->SetParent(*this); } ++Itr; } }
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; }
uint64_t cues_c::calculate_point_size(cue_point_t const &point) const { uint64_t point_size = EBML_ID_LENGTH(EBML_ID(KaxCuePoint)) + 1 + EBML_ID_LENGTH(EBML_ID(KaxCuePoint)) + 1 + calculate_bytes_for_uint(point.timecode / g_timecode_scale) + EBML_ID_LENGTH(EBML_ID(KaxCueTrackPositions)) + 1 + EBML_ID_LENGTH(EBML_ID(KaxCueTrack)) + 1 + calculate_bytes_for_uint(point.track_num) + EBML_ID_LENGTH(EBML_ID(KaxCueClusterPosition)) + 1 + calculate_bytes_for_uint(point.cluster_position); auto codec_state_position = m_codec_state_position_map.find({ point.track_num, point.timecode }); if (codec_state_position != m_codec_state_position_map.end()) point_size += EBML_ID_LENGTH(EBML_ID(KaxCueCodecState)) + 1 + calculate_bytes_for_uint(codec_state_position->second); if (point.relative_position) point_size += EBML_ID_LENGTH(EBML_ID(KaxCueRelativePosition)) + 1 + calculate_bytes_for_uint(point.relative_position); if (point.duration) point_size += EBML_ID_LENGTH(EBML_ID(KaxCueDuration)) + 1 + calculate_bytes_for_uint(RND_TIMECODE_SCALE(point.duration) / g_timecode_scale); return point_size; }
/*! \todo better zero copy handling */ filepos_t KaxInternalBlock::ReadData(IOCallback & input, ScopeMode ReadFully) { filepos_t Result; FirstFrameLocation = input.getFilePointer(); // will be updated accordingly below if (ReadFully == SCOPE_ALL_DATA) { Result = EbmlBinary::ReadData(input, ReadFully); binary *cursor = EbmlBinary::GetBuffer(); uint8 BlockHeadSize = 4; // update internal values TrackNumber = *cursor++; if ((TrackNumber & 0x80) == 0) { // there is extra data if ((TrackNumber & 0x40) == 0) { // We don't support track numbers that large ! return Result; } TrackNumber = (TrackNumber & 0x3F) << 8; TrackNumber += *cursor++; BlockHeadSize++; } else { TrackNumber &= 0x7F; } big_int16 b16; b16.Eval(cursor); LocalTimecode = int16(b16); bLocalTimecodeUsed = true; cursor += 2; if (EbmlId(*this) == EBML_ID(KaxSimpleBlock)) { bIsKeyframe = (*cursor & 0x80) != 0; bIsDiscardable = (*cursor & 0x01) != 0; } mInvisible = (*cursor & 0x08) >> 3; mLacing = LacingType((*cursor++ & 0x06) >> 1); // put all Frames in the list if (mLacing == LACING_NONE) { FirstFrameLocation += cursor - EbmlBinary::GetBuffer(); DataBuffer * soloFrame = new DataBuffer(cursor, GetSize() - BlockHeadSize); myBuffers.push_back(soloFrame); SizeList.resize(1); SizeList[0] = GetSize() - BlockHeadSize; } else { // read the number of frames in the lace uint32 LastBufferSize = GetSize() - BlockHeadSize - 1; // 1 for number of frame uint8 FrameNum = *cursor++; // number of frames in the lace - 1 // read the list of frame sizes uint8 Index; int32 FrameSize; uint32 SizeRead; uint64 SizeUnknown; SizeList.resize(FrameNum + 1); switch (mLacing) { case LACING_XIPH: for (Index=0; Index<FrameNum; Index++) { // get the size of the frame FrameSize = 0; do { FrameSize += uint8(*cursor); LastBufferSize--; } while (*cursor++ == 0xFF); SizeList[Index] = FrameSize; LastBufferSize -= FrameSize; } SizeList[Index] = LastBufferSize; break; case LACING_EBML: SizeRead = LastBufferSize; FrameSize = ReadCodedSizeValue(cursor, SizeRead, SizeUnknown); SizeList[0] = FrameSize; cursor += SizeRead; LastBufferSize -= FrameSize + SizeRead; for (Index=1; Index<FrameNum; Index++) { // get the size of the frame SizeRead = LastBufferSize; FrameSize += ReadCodedSizeSignedValue(cursor, SizeRead, SizeUnknown); SizeList[Index] = FrameSize; cursor += SizeRead; LastBufferSize -= FrameSize + SizeRead; } SizeList[Index] = LastBufferSize; break; case LACING_FIXED: for (Index=0; Index<=FrameNum; Index++) { // get the size of the frame SizeList[Index] = LastBufferSize / (FrameNum + 1); } break; default: // other lacing not supported assert(0); } FirstFrameLocation += cursor - EbmlBinary::GetBuffer(); for (Index=0; Index<=FrameNum; Index++) { DataBuffer * lacedFrame = new DataBuffer(cursor, SizeList[Index]); myBuffers.push_back(lacedFrame); cursor += SizeList[Index]; } } SetValueIsSet(); }
/*! \todo better zero copy handling */ filepos_t KaxInternalBlock::ReadData(IOCallback & input, ScopeMode ReadFully) { filepos_t Result; FirstFrameLocation = input.getFilePointer(); // will be updated accordingly below SetValueIsSet(false); try { if (ReadFully == SCOPE_ALL_DATA) { Result = EbmlBinary::ReadData(input, ReadFully); if (Result != GetSize()) throw SafeReadIOCallback::EndOfStreamX(GetSize() - Result); binary *BufferStart = EbmlBinary::GetBuffer(); SafeReadIOCallback Mem(*this); uint8 BlockHeadSize = 4; // update internal values TrackNumber = Mem.GetUInt8(); if ((TrackNumber & 0x80) == 0) { // there is extra data if ((TrackNumber & 0x40) == 0) { // We don't support track numbers that large ! throw SafeReadIOCallback::EndOfStreamX(0); } TrackNumber = (TrackNumber & 0x3F) << 8; TrackNumber += Mem.GetUInt8(); BlockHeadSize++; } else { TrackNumber &= 0x7F; } LocalTimecode = int16(Mem.GetUInt16BE()); bLocalTimecodeUsed = true; uint8 Flags = Mem.GetUInt8(); if (EbmlId(*this) == EBML_ID(KaxSimpleBlock)) { bIsKeyframe = (Flags & 0x80) != 0; bIsDiscardable = (Flags & 0x01) != 0; } mInvisible = (Flags & 0x08) >> 3; mLacing = LacingType((Flags & 0x06) >> 1); // put all Frames in the list if (mLacing == LACING_NONE) { FirstFrameLocation += Mem.GetPosition(); DataBuffer * soloFrame = new DataBuffer(BufferStart + Mem.GetPosition(), GetSize() - BlockHeadSize); myBuffers.push_back(soloFrame); SizeList.resize(1); SizeList[0] = GetSize() - BlockHeadSize; } else { // read the number of frames in the lace uint32 LastBufferSize = GetSize() - BlockHeadSize - 1; // 1 for number of frame uint8 FrameNum = Mem.GetUInt8(); // number of frames in the lace - 1 // read the list of frame sizes uint8 Index; int32 FrameSize; uint32 SizeRead; uint64 SizeUnknown; SizeList.resize(FrameNum + 1); switch (mLacing) { case LACING_XIPH: for (Index=0; Index<FrameNum; Index++) { // get the size of the frame FrameSize = 0; uint8 Value; do { Value = Mem.GetUInt8(); FrameSize += Value; LastBufferSize--; } while (Value == 0xFF); SizeList[Index] = FrameSize; LastBufferSize -= FrameSize; } SizeList[Index] = LastBufferSize; break; case LACING_EBML: SizeRead = LastBufferSize; FrameSize = ReadCodedSizeValue(BufferStart + Mem.GetPosition(), SizeRead, SizeUnknown); SizeList[0] = FrameSize; Mem.Skip(SizeRead); LastBufferSize -= FrameSize + SizeRead; for (Index=1; Index<FrameNum; Index++) { // get the size of the frame SizeRead = LastBufferSize; FrameSize += ReadCodedSizeSignedValue(BufferStart + Mem.GetPosition(), SizeRead, SizeUnknown); SizeList[Index] = FrameSize; Mem.Skip(SizeRead); LastBufferSize -= FrameSize + SizeRead; } if (Index <= FrameNum) // Safety check if FrameNum == 0 SizeList[Index] = LastBufferSize; break; case LACING_FIXED: for (Index=0; Index<=FrameNum; Index++) { // get the size of the frame SizeList[Index] = LastBufferSize / (FrameNum + 1); } break; default: // other lacing not supported assert(0); } FirstFrameLocation += Mem.GetPosition(); for (Index=0; Index<=FrameNum; Index++) { DataBuffer * lacedFrame = new DataBuffer(BufferStart + Mem.GetPosition(), SizeList[Index]); myBuffers.push_back(lacedFrame); Mem.Skip(SizeList[Index]); } } binary *BufferEnd = BufferStart + GetSize(); size_t NumFrames = myBuffers.size(); // Sanity checks for frame pointers and boundaries. for (size_t Index = 0; Index < NumFrames; ++Index) { binary *FrameStart = myBuffers[Index]->Buffer(); binary *FrameEnd = FrameStart + myBuffers[Index]->Size(); binary *ExpectedEnd = (Index + 1) < NumFrames ? myBuffers[Index + 1]->Buffer() : BufferEnd; if ((FrameStart < BufferStart) || (FrameEnd > BufferEnd) || (FrameEnd != ExpectedEnd)) throw SafeReadIOCallback::EndOfStreamX(0); } SetValueIsSet(); } else if (ReadFully == SCOPE_PARTIAL_DATA) { binary _TempHead[5]; Result = input.read(_TempHead, 5); if (Result != 5) throw SafeReadIOCallback::EndOfStreamX(0); binary *cursor = _TempHead; binary *_tmpBuf; uint8 BlockHeadSize = 4; // update internal values TrackNumber = *cursor++; if ((TrackNumber & 0x80) == 0) { // there is extra data if ((TrackNumber & 0x40) == 0) { // We don't support track numbers that large ! return Result; } TrackNumber = (TrackNumber & 0x3F) << 8; TrackNumber += *cursor++; BlockHeadSize++; } else { TrackNumber &= 0x7F; } big_int16 b16; b16.Eval(cursor); LocalTimecode = int16(b16); bLocalTimecodeUsed = true; cursor += 2; if (EbmlId(*this) == EBML_ID(KaxSimpleBlock)) { bIsKeyframe = (*cursor & 0x80) != 0; bIsDiscardable = (*cursor & 0x01) != 0; } mInvisible = (*cursor & 0x08) >> 3; mLacing = LacingType((*cursor++ & 0x06) >> 1); if (cursor == &_TempHead[4]) { _TempHead[0] = _TempHead[4]; } else { Result += input.read(_TempHead, 1); } FirstFrameLocation += cursor - _TempHead; // put all Frames in the list if (mLacing != LACING_NONE) { // read the number of frames in the lace uint32 LastBufferSize = GetSize() - BlockHeadSize - 1; // 1 for number of frame uint8 FrameNum = _TempHead[0]; // number of frames in the lace - 1 // read the list of frame sizes uint8 Index; int32 FrameSize; uint32 SizeRead; uint64 SizeUnknown; SizeList.resize(FrameNum + 1); switch (mLacing) { case LACING_XIPH: for (Index=0; Index<FrameNum; Index++) { // get the size of the frame FrameSize = 0; do { Result += input.read(_TempHead, 1); FrameSize += uint8(_TempHead[0]); LastBufferSize--; FirstFrameLocation++; } while (_TempHead[0] == 0xFF); FirstFrameLocation++; SizeList[Index] = FrameSize; LastBufferSize -= FrameSize; } SizeList[Index] = LastBufferSize; break; case LACING_EBML: SizeRead = LastBufferSize; cursor = _tmpBuf = new binary[FrameNum*4]; /// \warning assume the mean size will be coded in less than 4 bytes Result += input.read(cursor, FrameNum*4); FrameSize = ReadCodedSizeValue(cursor, SizeRead, SizeUnknown); SizeList[0] = FrameSize; cursor += SizeRead; LastBufferSize -= FrameSize + SizeRead; for (Index=1; Index<FrameNum; Index++) { // get the size of the frame SizeRead = LastBufferSize; FrameSize += ReadCodedSizeSignedValue(cursor, SizeRead, SizeUnknown); SizeList[Index] = FrameSize; cursor += SizeRead; LastBufferSize -= FrameSize + SizeRead; } FirstFrameLocation += cursor - _tmpBuf; SizeList[Index] = LastBufferSize; delete [] _tmpBuf; break; case LACING_FIXED: for (Index=0; Index<=FrameNum; Index++) { // get the size of the frame SizeList[Index] = LastBufferSize / (FrameNum + 1); } break; default: // other lacing not supported assert(0); } } else { SizeList.resize(1); SizeList[0] = GetSize() - BlockHeadSize; } SetValueIsSet(false); Result = GetSize(); } else {
KaxCluster * kax_file_c::read_next_cluster() { return static_cast<KaxCluster *>(read_next_level1_element(EBML_ID_VALUE(EBML_ID(KaxCluster)))); }
EbmlElement * kax_file_c::resync_to_level1_element_internal(uint32_t wanted_id) { if (m_segment_end && (m_in->getFilePointer() >= m_segment_end)) return nullptr; m_resynced = true; m_resync_start_pos = m_in->getFilePointer(); uint32_t actual_id = m_in->read_uint32_be(); int64_t start_time = mtx::sys::get_current_time_millis(); bool is_cluster_id = !wanted_id || (EBML_ID_VALUE(EBML_ID(KaxCluster)) == wanted_id); // 0 means: any level 1 element will do mxinfo(boost::format(Y("%1%: Error in the Matroska file structure at position %2%. Resyncing to the next level 1 element.\n")) % m_in->get_file_name() % m_resync_start_pos); if (is_cluster_id && (-1 != m_last_timecode)) { mxinfo(boost::format(Y("The last timecode processed before the error was encountered was %1%.\n")) % format_timecode(m_last_timecode)); m_last_timecode = -1; } if (m_debug_resync) mxinfo(boost::format("kax_file::resync_to_level1_element(): starting at %1% potential ID %|2$08x|\n") % m_resync_start_pos % actual_id); while (m_in->getFilePointer() < m_file_size) { int64_t now = mtx::sys::get_current_time_millis(); if ((now - start_time) >= 10000) { mxinfo(boost::format("Still resyncing at position %1%.\n") % m_in->getFilePointer()); start_time = now; } actual_id = (actual_id << 8) | m_in->read_uint8(); if ( ((0 != wanted_id) && (wanted_id != actual_id)) || ((0 == wanted_id) && !is_level1_element_id(vint_c(actual_id, 4)))) continue; uint64_t current_start_pos = m_in->getFilePointer() - 4; uint64_t element_pos = current_start_pos; unsigned int num_headers = 1; bool valid_unknown_size = false; if (m_debug_resync) mxinfo(boost::format("kax_file::resync_to_level1_element(): byte-for-byte search, found level 1 ID %|2$x| at %1%\n") % current_start_pos % actual_id); try { unsigned int idx; for (idx = 0; 3 > idx; ++idx) { vint_c length = vint_c::read(m_in); if (m_debug_resync) mxinfo(boost::format("kax_file::resync_to_level1_element(): read ebml length %1%/%2% valid? %3% unknown? %4%\n") % length.m_value % length.m_coded_size % length.is_valid() % length.is_unknown()); if (length.is_unknown()) { valid_unknown_size = true; break; } if ( !length.is_valid() || ((element_pos + length.m_value + length.m_coded_size + 2 * 4) >= m_file_size) || !m_in->setFilePointer2(element_pos + 4 + length.m_value + length.m_coded_size, seek_beginning)) break; element_pos = m_in->getFilePointer(); uint32_t next_id = m_in->read_uint32_be(); if (m_debug_resync) mxinfo(boost::format("kax_file::resync_to_level1_element(): next ID is %|1$x| at %2%\n") % next_id % element_pos); if ( ((0 != wanted_id) && (wanted_id != next_id)) || ((0 == wanted_id) && !is_level1_element_id(vint_c(next_id, 4)))) break; ++num_headers; } } catch (...) { } if ((4 == num_headers) || valid_unknown_size) { mxinfo(boost::format(Y("Resyncing successful at position %1%.\n")) % current_start_pos); m_in->setFilePointer(current_start_pos, seek_beginning); return read_next_level1_element(wanted_id, is_cluster_id); } m_in->setFilePointer(current_start_pos + 4, seek_beginning); } mxinfo(Y("Resync failed: no valid Matroska level 1 element found.\n")); return nullptr; }
bool kax_file_c::is_global_element_id(vint_c id) const { return (EBML_ID_VALUE(EBML_ID(EbmlVoid)) == id.m_value) || (EBML_ID_VALUE(EBML_ID(EbmlCrc32)) == id.m_value); }
/*! \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; }
/*! \brief Method to help reading a Master element and all subsequent children quickly \todo add an option to discard even unknown elements \todo handle when a mandatory element is not found */ void EbmlMaster::Read(EbmlStream & inDataStream, const EbmlSemanticContext & sContext, int & UpperEltFound, EbmlElement * & FoundElt, bool AllowDummyElt, ScopeMode ReadFully) { if (ReadFully != SCOPE_NO_DATA) { EbmlElement * ElementLevelA; // remove all existing elements, including the mandatory ones... size_t Index; for (Index=0; Index<ElementList.size(); Index++) { if (!(*ElementList[Index]).IsLocked()) { delete ElementList[Index]; } } ElementList.clear(); uint64 MaxSizeToRead; if (IsFiniteSize()) MaxSizeToRead = GetSize(); else MaxSizeToRead = 0x7FFFFFFF; // read blocks and discard the ones we don't care about if (MaxSizeToRead > 0) { inDataStream.I_O().setFilePointer(GetSizePosition() + GetSizeLength(), seek_beginning); ElementLevelA = inDataStream.FindNextElement(sContext, UpperEltFound, MaxSizeToRead, AllowDummyElt); while (ElementLevelA != NULL && UpperEltFound <= 0 && MaxSizeToRead > 0) { if (IsFiniteSize()) MaxSizeToRead = GetEndPosition() - ElementLevelA->GetEndPosition(); // even if it's the default value if (!AllowDummyElt && ElementLevelA->IsDummy()) { ElementLevelA->SkipData(inDataStream, sContext); delete ElementLevelA; // forget this unknown element } else { // more logical to do it afterward ElementList.push_back(ElementLevelA); ElementLevelA->Read(inDataStream, EBML_CONTEXT(ElementLevelA), UpperEltFound, FoundElt, AllowDummyElt, ReadFully); // just in case ElementLevelA->SkipData(inDataStream, EBML_CONTEXT(ElementLevelA)); } if (UpperEltFound > 0) { UpperEltFound--; if (UpperEltFound > 0 || MaxSizeToRead <= 0) goto processCrc; ElementLevelA = FoundElt; continue; } if (UpperEltFound < 0) { UpperEltFound++; if (UpperEltFound < 0) goto processCrc; } if (MaxSizeToRead <= 0) goto processCrc;// this level is finished ElementLevelA = inDataStream.FindNextElement(sContext, UpperEltFound, MaxSizeToRead, AllowDummyElt); } if (UpperEltFound > 0) { FoundElt = ElementLevelA; } } processCrc: EBML_MASTER_ITERATOR Itr, CrcItr; for (Itr = ElementList.begin(); Itr != ElementList.end();) { if ((EbmlId)(*(*Itr)) == EBML_ID(EbmlCrc32)) { bChecksumUsed = true; // remove the element Checksum = *(static_cast<EbmlCrc32*>(*Itr)); CrcItr = Itr; break; } ++Itr; } if (bChecksumUsed) { delete *CrcItr; Remove(CrcItr); } SetValueIsSet(); } }