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(); }
int cluster_helper_c::render() { std::vector<render_groups_cptr> render_groups; KaxCues cues; cues.SetGlobalTimecodeScale(g_timecode_scale); bool use_simpleblock = !hack_engaged(ENGAGE_NO_SIMPLE_BLOCKS); LacingType lacing_type = hack_engaged(ENGAGE_LACING_XIPH) ? LACING_XIPH : hack_engaged(ENGAGE_LACING_EBML) ? LACING_EBML : LACING_AUTO; int64_t min_cl_timecode = std::numeric_limits<int64_t>::max(); int64_t max_cl_timecode = 0; int elements_in_cluster = 0; bool added_to_cues = false; // Splitpoint stuff if ((-1 == m->header_overhead) && splitting()) m->header_overhead = m->out->getFilePointer() + g_tags_size; // Make sure that we don't have negative/wrapped around timecodes in the output file. // Can happend when we're splitting; so adjust timecode_offset accordingly. m->timecode_offset = boost::accumulate(m->packets, m->timecode_offset, [](int64_t a, const packet_cptr &p) { return std::min(a, p->assigned_timecode); }); int64_t timecode_offset = m->timecode_offset + get_discarded_duration(); for (auto &pack : m->packets) { generic_packetizer_c *source = pack->source; bool has_codec_state = !!pack->codec_state; if (g_video_packetizer == source) m->max_video_timecode_rendered = std::max(pack->assigned_timecode + pack->get_duration(), m->max_video_timecode_rendered); if (discarding()) { if (-1 == m->first_discarded_timecode) m->first_discarded_timecode = pack->assigned_timecode; m->last_discarded_timecode_and_duration = std::max(m->last_discarded_timecode_and_duration, pack->assigned_timecode + pack->get_duration()); continue; } if (source->contains_gap()) m->cluster->SetSilentTrackUsed(); render_groups_c *render_group = nullptr; for (auto &rg : render_groups) if (rg->m_source == source) { render_group = rg.get(); break; } if (!render_group) { render_groups.push_back(render_groups_cptr(new render_groups_c(source))); render_group = render_groups.back().get(); } min_cl_timecode = std::min(pack->assigned_timecode, min_cl_timecode); max_cl_timecode = std::max(pack->assigned_timecode, max_cl_timecode); DataBuffer *data_buffer = new DataBuffer((binary *)pack->data->get_buffer(), pack->data->get_size()); KaxTrackEntry &track_entry = static_cast<KaxTrackEntry &>(*source->get_track_entry()); kax_block_blob_c *previous_block_group = !render_group->m_groups.empty() ? render_group->m_groups.back().get() : nullptr; kax_block_blob_c *new_block_group = previous_block_group; if (!pack->is_key_frame() || has_codec_state || pack->has_discard_padding()) render_group->m_more_data = false; if (!render_group->m_more_data) { set_duration(render_group); render_group->m_durations.clear(); render_group->m_duration_mandatory = false; BlockBlobType this_block_blob_type = !use_simpleblock ? BLOCK_BLOB_NO_SIMPLE : must_duration_be_set(render_group, pack) ? BLOCK_BLOB_NO_SIMPLE : !pack->data_adds.empty() ? BLOCK_BLOB_NO_SIMPLE : has_codec_state ? BLOCK_BLOB_NO_SIMPLE : pack->has_discard_padding() ? BLOCK_BLOB_NO_SIMPLE : BLOCK_BLOB_ALWAYS_SIMPLE; render_group->m_groups.push_back(kax_block_blob_cptr(new kax_block_blob_c(this_block_blob_type))); new_block_group = render_group->m_groups.back().get(); m->cluster->AddBlockBlob(new_block_group); new_block_group->SetParent(*m->cluster); added_to_cues = false; } // Now put the packet into the cluster. render_group->m_more_data = new_block_group->add_frame_auto(track_entry, pack->assigned_timecode - timecode_offset, *data_buffer, lacing_type, pack->has_bref() ? pack->bref - timecode_offset : -1, pack->has_fref() ? pack->fref - timecode_offset : -1); if (has_codec_state) { KaxBlockGroup &bgroup = (KaxBlockGroup &)*new_block_group; KaxCodecState *cstate = new KaxCodecState; bgroup.PushElement(*cstate); cstate->CopyBuffer(pack->codec_state->get_buffer(), pack->codec_state->get_size()); } if (-1 == m->first_timecode_in_file) m->first_timecode_in_file = pack->assigned_timecode; if (-1 == m->first_timecode_in_part) m->first_timecode_in_part = pack->assigned_timecode; m->min_timecode_in_file = std::min(timecode_c::ns(pack->assigned_timecode), m->min_timecode_in_file.value_or_max()); m->max_timecode_in_file = std::max(pack->assigned_timecode, m->max_timecode_in_file); m->max_timecode_and_duration = std::max(pack->assigned_timecode + pack->get_duration(), m->max_timecode_and_duration); if (!pack->is_key_frame() || !track_entry.LacingEnabled()) render_group->m_more_data = false; render_group->m_durations.push_back(pack->get_unmodified_duration()); render_group->m_duration_mandatory |= pack->duration_mandatory; cues_c::get().set_duration_for_id_timecode(source->get_track_num(), pack->assigned_timecode - timecode_offset, pack->get_duration()); if (new_block_group) { // Set the reference priority if it was wanted. if ((0 < pack->ref_priority) && new_block_group->replace_simple_by_group()) GetChild<KaxReferencePriority>(*new_block_group).SetValue(pack->ref_priority); // Handle BlockAdditions if needed if (!pack->data_adds.empty() && new_block_group->ReplaceSimpleByGroup()) { KaxBlockAdditions &additions = AddEmptyChild<KaxBlockAdditions>(*new_block_group); size_t data_add_idx; for (data_add_idx = 0; pack->data_adds.size() > data_add_idx; ++data_add_idx) { auto &block_more = AddEmptyChild<KaxBlockMore>(additions); GetChild<KaxBlockAddID >(block_more).SetValue(data_add_idx + 1); GetChild<KaxBlockAdditional>(block_more).CopyBuffer((binary *)pack->data_adds[data_add_idx]->get_buffer(), pack->data_adds[data_add_idx]->get_size()); } } if (pack->has_discard_padding()) GetChild<KaxDiscardPadding>(*new_block_group).SetValue(pack->discard_padding.to_ns()); } elements_in_cluster++; if (!new_block_group) new_block_group = previous_block_group; else if (g_write_cues && (!added_to_cues || has_codec_state)) { added_to_cues = add_to_cues_maybe(pack); if (added_to_cues) cues.AddBlockBlob(*new_block_group); } pack->group = new_block_group; m->track_statistics[ source->get_uid() ].process(*pack); } if (!discarding()) { if (0 < elements_in_cluster) { for (auto &rg : render_groups) set_duration(rg.get()); m->cluster->SetPreviousTimecode(min_cl_timecode - timecode_offset - 1, (int64_t)g_timecode_scale); m->cluster->set_min_timecode(min_cl_timecode - timecode_offset); m->cluster->set_max_timecode(max_cl_timecode - timecode_offset); m->cluster->Render(*m->out, cues); m->bytes_in_file += m->cluster->ElementSize(); if (g_kax_sh_cues) g_kax_sh_cues->IndexThis(*m->cluster, *g_kax_segment); m->previous_cluster_tc = m->cluster->GlobalTimecode(); cues_c::get().postprocess_cues(cues, *m->cluster); } else m->previous_cluster_tc = -1; } m->min_timecode_in_cluster = -1; m->max_timecode_in_cluster = -1; m->cluster->delete_non_blocks(); return 1; }
static void handle_blockgroup(KaxBlockGroup &blockgroup, KaxCluster &cluster, int64_t tc_scale) { // Only continue if this block group actually contains a block. KaxBlock *block = FINDFIRST(&blockgroup, KaxBlock); if ((NULL == block) || (0 == block->NumberFrames())) return; block->SetParent(cluster); // Do we need this block group? xtr_base_c *extractor = NULL; size_t i; for (i = 0; i < extractors.size(); i++) if (block->TrackNum() == extractors[i]->m_track_num) { extractor = extractors[i]; break; } if (NULL == extractor) return; // Next find the block duration if there is one. KaxBlockDuration *kduration = FINDFIRST(&blockgroup, KaxBlockDuration); int64_t duration = NULL == kduration ? -1 : (int64_t)uint64(*kduration) * tc_scale; // Now find backward and forward references. int64_t bref = 0; int64_t fref = 0; KaxReferenceBlock *kreference = FINDFIRST(&blockgroup, KaxReferenceBlock); for (i = 0; (2 > i) && (NULL != kreference); i++) { if (0 > int64(*kreference)) bref = int64(*kreference); else fref = int64(*kreference); kreference = FINDNEXT(&blockgroup, KaxReferenceBlock, kreference); } // Any block additions present? KaxBlockAdditions *kadditions = FINDFIRST(&blockgroup, KaxBlockAdditions); if (0 > duration) duration = extractor->m_default_duration * block->NumberFrames(); KaxCodecState *kcstate = FINDFIRST(&blockgroup, KaxCodecState); if (NULL != kcstate) { memory_cptr codec_state(new memory_c(kcstate->GetBuffer(), kcstate->GetSize(), false)); extractor->handle_codec_state(codec_state); } for (i = 0; i < block->NumberFrames(); i++) { int64_t this_timecode, this_duration; if (0 > duration) { this_timecode = block->GlobalTimecode(); this_duration = duration; } else { this_timecode = block->GlobalTimecode() + i * duration / block->NumberFrames(); this_duration = duration / block->NumberFrames(); } DataBuffer &data = block->GetBuffer(i); memory_cptr frame(new memory_c(data.Buffer(), data.Size(), false)); extractor->handle_frame(frame, kadditions, this_timecode, this_duration, bref, fref, false, false, true); } }
static int64_t handle_blockgroup(KaxBlockGroup &blockgroup, KaxCluster &cluster, int64_t tc_scale) { // Only continue if this block group actually contains a block. KaxBlock *block = FindChild<KaxBlock>(&blockgroup); if (!block || (0 == block->NumberFrames())) return -1; block->SetParent(cluster); handle_blockgroup_timestamps(blockgroup, tc_scale); // Do we need this block group? auto extractor_itr = track_extractors_by_track_number.find(block->TrackNum()); if (extractor_itr == track_extractors_by_track_number.end()) return -1; // Next find the block duration if there is one. auto &extractor = *extractor_itr->second; KaxBlockDuration *kduration = FindChild<KaxBlockDuration>(&blockgroup); int64_t duration = !kduration ? -1 : static_cast<int64_t>(kduration->GetValue() * tc_scale); int64_t max_timestamp = 0; // Now find backward and forward references. int64_t bref = 0; int64_t fref = 0; auto kreference = FindChild<KaxReferenceBlock>(&blockgroup); for (int i = 0; (2 > i) && kreference; i++) { if (0 > kreference->GetValue()) bref = kreference->GetValue(); else fref = kreference->GetValue(); kreference = FindNextChild(blockgroup, *kreference); } // Any block additions present? KaxBlockAdditions *kadditions = FindChild<KaxBlockAdditions>(&blockgroup); if (0 > duration) duration = extractor.m_default_duration * block->NumberFrames(); KaxCodecState *kcstate = FindChild<KaxCodecState>(&blockgroup); if (kcstate) { memory_cptr codec_state(new memory_c(kcstate->GetBuffer(), kcstate->GetSize(), false)); extractor.handle_codec_state(codec_state); } for (int i = 0, num_frames = block->NumberFrames(); i < num_frames; i++) { int64_t this_timestamp, this_duration; if (0 > duration) { this_timestamp = block->GlobalTimecode(); this_duration = duration; } else { this_timestamp = block->GlobalTimecode() + i * duration / block->NumberFrames(); this_duration = duration / block->NumberFrames(); } auto discard_padding = timestamp_c::ns(0); auto kdiscard_padding = FindChild<KaxDiscardPadding>(blockgroup); if (kdiscard_padding) discard_padding = timestamp_c::ns(kdiscard_padding->GetValue()); auto &data = block->GetBuffer(i); auto frame = std::make_shared<memory_c>(data.Buffer(), data.Size(), false); auto f = xtr_frame_t{frame, kadditions, this_timestamp, this_duration, bref, fref, false, false, true, discard_padding}; extractor.decode_and_handle_frame(f); max_timestamp = std::max(max_timestamp, this_timestamp); } return max_timestamp; }
static int64_t handle_blockgroup(KaxBlockGroup &blockgroup, KaxCluster &cluster, int64_t tc_scale) { // Only continue if this block group actually contains a block. KaxBlock *block = FindChild<KaxBlock>(&blockgroup); if (!block || (0 == block->NumberFrames())) return -1; block->SetParent(cluster); // Do we need this block group? xtr_base_c *extractor = nullptr; size_t i; for (i = 0; i < extractors.size(); i++) if (block->TrackNum() == extractors[i]->m_track_num) { extractor = extractors[i]; break; } if (!extractor) return -1; // Next find the block duration if there is one. KaxBlockDuration *kduration = FindChild<KaxBlockDuration>(&blockgroup); int64_t duration = !kduration ? -1 : static_cast<int64_t>(kduration->GetValue() * tc_scale); int64_t max_timecode = 0; // Now find backward and forward references. int64_t bref = 0; int64_t fref = 0; auto kreference = FindChild<KaxReferenceBlock>(&blockgroup); for (i = 0; (2 > i) && kreference; i++) { if (0 > kreference->GetValue()) bref = kreference->GetValue(); else fref = kreference->GetValue(); kreference = FindNextChild<KaxReferenceBlock>(&blockgroup, kreference); } // Any block additions present? KaxBlockAdditions *kadditions = FindChild<KaxBlockAdditions>(&blockgroup); if (0 > duration) duration = extractor->m_default_duration * block->NumberFrames(); KaxCodecState *kcstate = FindChild<KaxCodecState>(&blockgroup); if (kcstate) { memory_cptr codec_state(new memory_c(kcstate->GetBuffer(), kcstate->GetSize(), false)); extractor->handle_codec_state(codec_state); } for (i = 0; i < block->NumberFrames(); i++) { int64_t this_timecode, this_duration; if (0 > duration) { this_timecode = block->GlobalTimecode(); this_duration = duration; } else { this_timecode = block->GlobalTimecode() + i * duration / block->NumberFrames(); this_duration = duration / block->NumberFrames(); } DataBuffer &data = block->GetBuffer(i); memory_cptr frame(new memory_c(data.Buffer(), data.Size(), false)); extractor->handle_frame(frame, kadditions, this_timecode, this_duration, bref, fref, false, false, true); max_timecode = std::max(max_timecode, this_timecode); } return max_timecode; }