Beispiel #1
0
bool
extract_cuesheet(kax_analyzer_c &analyzer,
                 options_c::mode_options_c &options) {
  KaxChapters all_chapters;
  auto chapters_m       = analyzer.read_all(EBML_INFO(KaxChapters));
  auto tags_m           = analyzer.read_all(EBML_INFO(KaxTags));
  KaxChapters *chapters = dynamic_cast<KaxChapters *>(chapters_m.get());
  KaxTags *all_tags     = dynamic_cast<KaxTags *>(    tags_m.get());

  if (!chapters || !all_tags)
    return true;

  for (auto chapter_entry : *chapters) {
    if (!dynamic_cast<KaxEditionEntry *>(chapter_entry))
      continue;

    auto eentry = static_cast<KaxEditionEntry *>(chapter_entry);
    for (auto edition_entry : *eentry)
      if (dynamic_cast<KaxChapterAtom *>(edition_entry))
        all_chapters.PushElement(*edition_entry);
  }

  write_cuesheet(analyzer.get_file().get_file_name(), all_chapters, *all_tags, -1, *open_output_file(options.m_output_file_name));

  while (all_chapters.ListSize() > 0)
    all_chapters.Remove(0);

  return true;
}
Beispiel #2
0
static uint64_t
find_timecode_scale(kax_analyzer_c &analyzer) {
  auto info_m = analyzer.read_all(EBML_INFO(KaxInfo));
  auto info   = dynamic_cast<KaxInfo *>(info_m.get());

  return info ? FindChildValue<KaxTimecodeScale>(info, 1000000ull) : 1000000ull;
}
Beispiel #3
0
bool
extract_tags(kax_analyzer_c &analyzer,
             options_c::mode_options_c &options) {
  auto tags = analyzer.read_all(EBML_INFO(KaxTags));

  if (!dynamic_cast<KaxTags *>(tags.get()))
    return true;

  mtx::xml::ebml_tags_converter_c::write_xml(static_cast<KaxTags &>(*tags), *open_output_file(options.m_output_file_name));

  return true;
}
Beispiel #4
0
static std::unordered_map<int64_t, std::vector<cue_point_t> >
parse_cue_points(kax_analyzer_c &analyzer) {
  auto cues_m = analyzer.read_all(EBML_INFO(KaxCues));
  auto cues   = dynamic_cast<KaxCues *>(cues_m.get());

  if (!cues)
    mxerror(Y("No cues were found.\n"));

  auto cue_points = std::unordered_map<int64_t, std::vector<cue_point_t> >{};

  for (auto const &elt : *cues) {
    auto kcue_point = dynamic_cast<KaxCuePoint *>(elt);
    if (!kcue_point)
      continue;

    auto ktime = FindChild<KaxCueTime>(*kcue_point);
    if (!ktime)
      continue;

    auto p = cue_point_t{ktime->GetValue()};
    auto ktrack_pos = FindChild<KaxCueTrackPositions>(*kcue_point);
    if (!ktrack_pos)
      continue;

    for (auto const &pos_elt : *ktrack_pos) {
      if (Is<KaxCueClusterPosition>(pos_elt))
        p.cluster_position.reset(static_cast<KaxCueClusterPosition *>(pos_elt)->GetValue());

      else if (Is<KaxCueRelativePosition>(pos_elt))
        p.relative_position.reset(static_cast<KaxCueRelativePosition *>(pos_elt)->GetValue());

      else if (Is<KaxCueDuration>(pos_elt))
        p.duration.reset(static_cast<KaxCueDuration *>(pos_elt)->GetValue());
    }

    for (auto const &pos_elt : *ktrack_pos)
      if (Is<KaxCueTrack>(pos_elt))
        cue_points[ static_cast<KaxCueTrack *>(pos_elt)->GetValue() ].push_back(p);
  }

  return cue_points;
}
Beispiel #5
0
static std::map<int64_t, int64_t>
generate_track_number_map(kax_analyzer_c &analyzer) {
  auto track_number_map = std::map<int64_t, int64_t>{};
  auto tracks_m         = analyzer.read_all(EBML_INFO(KaxTracks));
  auto tracks           = dynamic_cast<KaxTracks *>(tracks_m.get());

  if (!tracks)
    return track_number_map;

  auto tid = 0;

  for (auto const &elt : *tracks) {
    auto ktrack_entry = dynamic_cast<KaxTrackEntry *>(elt);
    if (!ktrack_entry)
      continue;

    auto ktrack_number = FindChild<KaxTrackNumber>(ktrack_entry);
    if (ktrack_number)
      track_number_map[tid++] = ktrack_number->GetValue();
  }

  return track_number_map;
}
Beispiel #6
0
bool
extract_tracks(kax_analyzer_c &analyzer,
               options_c::mode_options_c &options) {
  auto &tspecs = options.m_tracks;

  if (tspecs.empty())
    return false;

  // open input file
  auto &in          = analyzer.get_file();
  auto file         = std::make_shared<kax_file_c>(in);
  int64_t file_size = in.get_size();

  // open input file
  auto af_segment_info = ebml_master_cptr{ analyzer.read_all(EBML_INFO(KaxInfo)) };
  auto segment_info    = dynamic_cast<KaxInfo *>(af_segment_info.get());
  auto af_tracks       = ebml_master_cptr{ analyzer.read_all(EBML_INFO(KaxTracks)) };
  auto tracks          = dynamic_cast<KaxTracks *>(af_tracks.get());

  if (!segment_info || !tracks)
    return false;

  find_and_verify_track_uids(*tracks, tspecs);
  create_extractors(*tracks, tspecs);
  create_timestamp_files(*tracks, tspecs);

  try {
    in.setFilePointer(0);
    auto es = std::make_shared<EbmlStream>(in);

    // Find the EbmlHead element. Must be the first one.
    EbmlElement *l0 = es->FindNextID(EBML_INFO(EbmlHead), 0xFFFFFFFFL);
    if (!l0) {
      show_error(Y("Error: No EBML head found."));
      return false;
    }

    // Don't verify its data for now.
    l0->SkipData(*es, EBML_CONTEXT(l0));
    delete l0;

    while (1) {
      // Next element must be a segment
      l0 = es->FindNextID(EBML_INFO(KaxSegment), 0xFFFFFFFFFFFFFFFFLL);

      if (!l0) {
        show_error(Y("No segment/level 0 element found."));
        return false;
      }

      if (Is<KaxSegment>(l0))
        break;

      l0->SkipData(*es, EBML_CONTEXT(l0));
      delete l0;
    }

    auto previous_percentage = -1;
    auto tc_scale            = FindChildValue<KaxTimecodeScale, uint64_t>(segment_info, 1000000);

    file->set_timestamp_scale(tc_scale);
    file->set_segment_end(*l0);

    while (true) {
      auto cluster = std::unique_ptr<KaxCluster>{file->read_next_cluster()};
      if (!cluster)
        break;

      auto ctc = static_cast<KaxClusterTimecode *> (cluster->FindFirstElt(EBML_INFO(KaxClusterTimecode), false));
      cluster->InitTimecode(ctc ? ctc->GetValue() : 0, tc_scale);

      if (0 == verbose) {
        auto current_percentage = in.getFilePointer() * 100 / file_size;

        if (previous_percentage != static_cast<int>(current_percentage)) {
          if (mtx::cli::g_gui_mode)
            mxinfo(boost::format("#GUI#progress %1%%%\n") % current_percentage);
          else
            mxinfo(boost::format(Y("Progress: %1%%%%2%")) % current_percentage % "\r");

          previous_percentage = current_percentage;
        }
      }

      size_t i;
      int64_t max_timestamp = -1;

      for (i = 0; cluster->ListSize() > i; ++i) {
        int64_t max_bg_timestamp = -1;
        EbmlElement *el          = (*cluster)[i];

        if (Is<KaxBlockGroup>(el))
          max_bg_timestamp = handle_blockgroup(*static_cast<KaxBlockGroup *>(el), *cluster, tc_scale);

        else if (Is<KaxSimpleBlock>(el))
          max_bg_timestamp = handle_simpleblock(*static_cast<KaxSimpleBlock *>(el), *cluster);

        max_timestamp = std::max(max_timestamp, max_bg_timestamp);
      }

      if (-1 != max_timestamp)
        file->set_last_timestamp(max_timestamp);
    }

    delete l0;

    auto af_chapters = ebml_element_cptr{ analyzer.read_all(EBML_INFO(KaxChapters)) };
    auto chapters    = dynamic_cast<KaxChapters *>(af_chapters.get());

    auto af_tags     = ebml_element_cptr{ analyzer.read_all(EBML_INFO(KaxTags)) };
    auto tags        = dynamic_cast<KaxTags *>(af_tags.get());

    if (chapters && tags)
      write_all_cuesheets(*chapters, *tags, tspecs);

    // Now just close the files and go to sleep. Mummy will sing you a
    // lullaby. Just close your eyes, listen to her sweet voice, singing,
    // singing, fading... fad... ing...
    close_extractors();
    close_timestamp_files();

    if (0 == verbose) {
      if (mtx::cli::g_gui_mode)
        mxinfo(boost::format("#GUI#progress %1%%%\n") % 100);
      else
        mxinfo(boost::format(Y("Progress: %1%%%%2%")) % 100 % "\n");
    }

    return true;
  } catch (...) {
    show_error(Y("Caught exception"));

    return false;
  }
}