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; }
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; } }