Example #1
0
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();
}
Example #2
0
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;
}
Example #3
0
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);
  }
}
Example #4
0
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;
}
Example #5
0
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;
}