EbmlElement * kax_file_c::read_one_element() { if (m_segment_end && (m_in.getFilePointer() >= m_segment_end)) return nullptr; auto upper_lvl_el = 0; auto l1 = m_es->FindNextElement(EBML_CLASS_CONTEXT(KaxSegment), upper_lvl_el, 0xFFFFFFFFL, true); if (!l1) return nullptr; auto callbacks = find_ebml_callbacks(EBML_INFO(KaxSegment), EbmlId(*l1)); if (!callbacks) callbacks = &EBML_CLASS_CALLBACK(KaxSegment); auto l2 = static_cast<EbmlElement *>(nullptr); try { l1->Read(*m_es.get(), EBML_INFO_CONTEXT(*callbacks), upper_lvl_el, l2, true); } catch (std::runtime_error &e) { mxdebug_if(m_debug_resync, boost::format("exception reading element data: %1%\n") % e.what()); m_in.setFilePointer(l1->GetElementPosition() + 1); delete l1; return nullptr; } auto 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; }
std::map<id_timecode_t, uint64_t> cues_c::calculate_block_positions(KaxCluster &cluster) const { std::map<id_timecode_t, uint64_t> positions; for (auto child : cluster) { auto simple_block = dynamic_cast<KaxSimpleBlock *>(child); if (simple_block) { simple_block->SetParent(cluster); positions[ id_timecode_t{ simple_block->TrackNum(), simple_block->GlobalTimecode() } ] = simple_block->GetElementPosition(); continue; } auto block_group = dynamic_cast<KaxBlockGroup *>(child); if (!block_group) continue; auto block = FindChild<KaxBlock>(block_group); if (!block) continue; block->SetParent(cluster); positions[ id_timecode_t{ block->TrackNum(), block->GlobalTimecode() } ] = block->GetElementPosition(); } return positions; }
uint64 EbmlVoid::ReplaceWith(EbmlElement & EltToReplaceWith, IOCallback & output, bool ComeBackAfterward, bool bWithDefault) { EltToReplaceWith.UpdateSize(bWithDefault); if (HeadSize() + GetSize() < EltToReplaceWith.GetSize() + EltToReplaceWith.HeadSize()) { // the element can't be written here ! return INVALID_FILEPOS_T; } if (HeadSize() + GetSize() - EltToReplaceWith.GetSize() - EltToReplaceWith.HeadSize() == 1) { // there is not enough space to put a filling element return INVALID_FILEPOS_T; } uint64 CurrentPosition = output.getFilePointer(); output.setFilePointer(GetElementPosition()); EltToReplaceWith.Render(output, bWithDefault); if (HeadSize() + GetSize() - EltToReplaceWith.GetSize() - EltToReplaceWith.HeadSize() > 1) { // fill the rest with another void element EbmlVoid aTmp; aTmp.SetSize_(HeadSize() + GetSize() - EltToReplaceWith.GetSize() - EltToReplaceWith.HeadSize() - 1); // 1 is the length of the Void ID int HeadBefore = aTmp.HeadSize(); aTmp.SetSize_(aTmp.GetSize() - CodedSizeLength(aTmp.GetSize(), aTmp.GetSizeLength(), aTmp.IsFiniteSize())); int HeadAfter = aTmp.HeadSize(); if (HeadBefore != HeadAfter) { aTmp.SetSizeLength(CodedSizeLength(aTmp.GetSize(), aTmp.GetSizeLength(), aTmp.IsFiniteSize()) - (HeadAfter - HeadBefore)); } aTmp.RenderHead(output, false, bWithDefault); // the rest of the data is not rewritten } if (ComeBackAfterward) { output.setFilePointer(CurrentPosition); } return GetSize() + HeadSize(); }
uint64 KaxSegment::GetGlobalPosition(uint64 aRelativePosition) const { return aRelativePosition + GetElementPosition() + HeadSize(); }
uint64 KaxSegment::GetRelativePosition(uint64 aGlobalPosition) const { return aGlobalPosition - GetElementPosition() - HeadSize(); }
EbmlElement * kax_file_c::read_next_level1_element_internal(uint32_t wanted_id) { if (m_segment_end && (m_in.getFilePointer() >= m_segment_end)) return nullptr; m_resynced = false; m_resync_start_pos = 0; // Read the next ID. auto search_start_pos = m_in.getFilePointer(); auto actual_id = vint_c::read_ebml_id(m_in); m_in.setFilePointer(search_start_pos, seek_beginning); if (m_debug_read_next) mxinfo(boost::format("kax_file::read_next_level1_element(): search at %1% for %|4$x| act id %|2$x| is_valid %3%\n") % search_start_pos % actual_id.m_value % actual_id.is_valid() % wanted_id); // If no valid ID was read then re-sync right away. No other tests // can be run. if (!actual_id.is_valid()) return resync_to_level1_element(wanted_id); // Easiest case: next level 1 element following the previous one // without any element inbetween. if ( (wanted_id == actual_id.m_value) || ( (0 == wanted_id) && ( is_level1_element_id(actual_id) || is_global_element_id(actual_id)))) { auto l1 = read_one_element(); if (l1) return l1; } // If a specific level 1 is wanted then look for next ID by skipping // other level 1 or special elements. If that files fallback to a // byte-for-byte search for the ID. if ((0 != wanted_id) && (is_level1_element_id(actual_id) || is_global_element_id(actual_id))) { m_in.setFilePointer(search_start_pos, seek_beginning); auto l1 = read_one_element(); if (l1) { auto element_size = get_element_size(l1); auto ok = (0 != element_size) && m_in.setFilePointer2(l1->GetElementPosition() + element_size, seek_beginning); if (m_debug_read_next) mxinfo(boost::format("kax_file::read_next_level1_element(): other level 1 element %1% new pos %2% fsize %3% epos %4% esize %5%\n") % EBML_NAME(l1) % (l1->GetElementPosition() + element_size) % m_file_size % l1->GetElementPosition() % element_size); delete l1; return ok ? read_next_level1_element(wanted_id) : nullptr; } } // Last case: no valid ID found. Try a byte-for-byte search for the // next wanted/level 1 ID. Also try to locate at least three valid // ID/sizes, not just one ID. m_in.setFilePointer(search_start_pos, seek_beginning); return resync_to_level1_element(wanted_id); }