Exemple #1
0
/** \brief Find a chapter atom with a specific UID.

   Its parameters don't have to be checked for validity.

   \param chapters The chapters in which to look for the atom.
   \param uid The requested unique atom ID. The special value \c 0 results in
     the first atom in the first edition being returned.

   \return A pointer to the atom or \c nullptr if none has been found.
*/
KaxChapterAtom *
find_chapter_with_uid(KaxChapters &chapters,
                      uint64_t uid) {
  if (0 == uid) {
    KaxEditionEntry *eentry = FindChild<KaxEditionEntry>(&chapters);
    if (!eentry)
      return nullptr;
    return FindChild<KaxChapterAtom>(eentry);
  }

  size_t eentry_idx;
  for (eentry_idx = 0; chapters.ListSize() > eentry_idx; eentry_idx++) {
    KaxEditionEntry *eentry = dynamic_cast<KaxEditionEntry *>(chapters[eentry_idx]);
    if (!eentry)
      continue;

    size_t atom_idx;
    for (atom_idx = 0; eentry->ListSize() > atom_idx; atom_idx++) {
      KaxChapterAtom *atom = dynamic_cast<KaxChapterAtom *>((*eentry)[atom_idx]);
      if (!atom)
        continue;

      KaxChapterUID *cuid = FindChild<KaxChapterUID>(atom);
      if ((cuid) && (uint64(*cuid) == uid))
        return atom;
    }
  }

  return nullptr;
}
Exemple #2
0
void
write_chapters_simple(int &chapter_num,
                      KaxChapters *chapters,
                      mm_io_c *out) {
  s_chapter_start_times.clear();
  s_chapter_names.clear();
  s_chapter_entries.clear();

  size_t chapter_idx;
  for (chapter_idx = 0; chapters->ListSize() > chapter_idx; chapter_idx++) {
    if (Is<KaxEditionEntry>((*chapters)[chapter_idx])) {
      KaxEditionEntry *edition = static_cast<KaxEditionEntry *>((*chapters)[chapter_idx]);

      size_t edition_idx;
      for (edition_idx = 0; edition->ListSize() > edition_idx; edition_idx++)
        if (Is<KaxChapterAtom>((*edition)[edition_idx]))
          write_chapter_atom_simple(static_cast<KaxChapterAtom *>((*edition)[edition_idx]), 2);
    }
  }

  for (chapter_idx = 0; s_chapter_entries.size() > chapter_idx; chapter_idx++) {
    int64_t v = s_chapter_entries[chapter_idx].m_start;
    out->puts(g_cc_stdio->native((boost::format("CHAPTER%|1$02d|=%|2$02d|:%|3$02d|:%|4$02d|.%|5$03d|\n")
                                  % chapter_num % (v / 1000 / 60 / 60) % ((v / 1000 / 60) % 60) % ((v / 1000) % 60) % (v % 1000)).str()));
    out->puts(g_cc_stdio->native((boost::format("CHAPTER%|1$02d|NAME=%2%\n") % chapter_num % s_chapter_entries[chapter_idx].m_name).str()));
    chapter_num++;
  }

  s_chapter_start_times.clear();
  s_chapter_names.clear();
  s_chapter_entries.clear();
}
void
ebml_chapters_converter_c::fix_edition_entry(KaxEditionEntry &eentry)
  const {
  bool atom_found = false;

  KaxEditionUID *euid = nullptr;
  for (auto element : eentry)
    if (dynamic_cast<KaxEditionUID *>(element)) {
      euid = static_cast<KaxEditionUID *>(element);
      if (!is_unique_number(uint64(*euid), UNIQUE_EDITION_IDS)) {
        mxwarn(boost::format(Y("Chapter parser: The EditionUID %1% is not unique and could not be reused. A new one will be created.\n")) % uint64(*euid));
        *static_cast<EbmlUInteger *>(euid) = create_unique_number(UNIQUE_EDITION_IDS);
      }

    } else if (dynamic_cast<KaxChapterAtom *>(element)) {
      atom_found = true;
      fix_atom(static_cast<KaxChapterAtom &>(*element));
    }

  if (!atom_found)
    throw conversion_x{Y("At least one <ChapterAtom> element is needed.")};

  if (!euid) {
    euid                               = new KaxEditionUID;
    *static_cast<EbmlUInteger *>(euid) = create_unique_number(UNIQUE_EDITION_IDS);
    eentry.PushElement(*euid);
  }
}
Exemple #4
0
/** \brief Remove all chapter atoms that are outside of a time range

   All chapter atoms that lie completely outside the timecode range
   given with <tt>[min_tc..max_tc]</tt> are deleted.

   Chapters which start before the window but end inside or after the window
   are kept as well, and their start timecode is adjusted.

   If two or more chapters with the same UID are encountered on the same
   level then those are merged into a single chapter. The start timecode
   is the minimum start timecode of all the chapters, and the end timecode
   is the maximum end timecode of all the chapters.

   The parameters are checked for validity.

   \param chapters The chapters to check.
   \param min_tc The minimum timecode to accept.
   \param max_tc The maximum timecode to accept.
   \param offset This value is subtracted from both the start and end timecode
     for each chapter after the decision whether or not to keep it has been
     made.

   \return \c false if all chapters were discarded, \c true otherwise
*/
bool
select_chapters_in_timeframe(KaxChapters *chapters,
                             int64_t min_tc,
                             int64_t max_tc,
                             int64_t offset) {
  // Check the parameters.
  if (!chapters)
    return false;

  // Remove the atoms that are outside of the requested range.
  size_t master_idx;
  for (master_idx = 0; chapters->ListSize() > master_idx; master_idx++) {
    EbmlMaster *work_master = dynamic_cast<KaxEditionEntry *>((*chapters)[master_idx]);
    if (work_master)
      remove_entries(min_tc, max_tc, offset, *work_master);
  }

  // Count the number of atoms in each edition. Delete editions without
  // any atom in them.
  master_idx = 0;
  while (chapters->ListSize() > master_idx) {
    KaxEditionEntry *eentry = dynamic_cast<KaxEditionEntry *>((*chapters)[master_idx]);
    if (!eentry) {
      master_idx++;
      continue;
    }

    size_t num_atoms = 0, eentry_idx;
    for (eentry_idx = 0; eentry->ListSize() > eentry_idx; eentry_idx++)
      if (dynamic_cast<KaxChapterAtom *>((*eentry)[eentry_idx]))
        num_atoms++;

    if (0 == num_atoms) {
      chapters->Remove(master_idx);
      delete eentry;

    } else
      master_idx++;
  }

  return chapters->ListSize() > 0;
}
Exemple #5
0
void
extract_cuesheet(const std::string &file_name,
                 kax_analyzer_c::parse_mode_e parse_mode) {
  kax_analyzer_cptr analyzer;

  // open input file
  try {
    analyzer = kax_analyzer_cptr(new kax_analyzer_c(file_name));
    if (!analyzer->process(parse_mode, MODE_READ))
      throw false;
  } catch (...) {
    show_error(boost::format(Y("The file '%1%' could not be opened for reading (%2%).")) % file_name % strerror(errno));
    return;
  }

  KaxChapters all_chapters;
  KaxChapters *chapters = dynamic_cast<KaxChapters *>(analyzer->read_all(EBML_INFO(KaxChapters)));
  KaxTags *all_tags     = dynamic_cast<KaxTags *>(analyzer->read_all(EBML_INFO(KaxTags)));

  if ((NULL != chapters) && (NULL != all_tags)) {
    size_t i;
    for (i = 0; i < chapters->ListSize(); i++) {
      if (dynamic_cast<KaxEditionEntry *>((*chapters)[i]) == NULL)
        continue;

      KaxEditionEntry *eentry = dynamic_cast<KaxEditionEntry *>((*chapters)[i]);
      size_t k;
      for (k = 0; k < eentry->ListSize(); k++)
        if (dynamic_cast<KaxChapterAtom *>((*eentry)[k]) != NULL)
          all_chapters.PushElement(*(*eentry)[k]);
    }

    write_cuesheet(file_name, all_chapters, *all_tags, -1, *g_mm_stdio);

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

  delete all_tags;
  delete chapters;
}