bool kax_file_c::is_level1_element_id(vint_c id) const { const EbmlSemanticContext &context = EBML_CLASS_CONTEXT(KaxSegment); for (size_t segment_idx = 0; EBML_CTX_SIZE(context) > segment_idx; ++segment_idx) if (EBML_ID_VALUE(EBML_CTX_IDX_ID(context,segment_idx)) == id.m_value) return true; return false; }
bool kax_file_c::is_level1_element_id(vint_c id) const { auto &context = EBML_CLASS_CONTEXT(KaxSegment); for (int segment_idx = 0, end = EBML_CTX_SIZE(context); end > segment_idx; ++segment_idx) if (EBML_ID_VALUE(EBML_CTX_IDX_ID(context,segment_idx)) == id.m_value) return true; return false; }
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); }