change_cptr change_c::parse_spec(change_c::change_type_e type, const std::string &spec) { std::string name, value; if (ct_delete == type) name = spec; else { auto parts = split(spec, "=", 2); if (2 != parts.size()) throw std::runtime_error(Y("missing value")); name = parts[0]; value = parts[1]; } if (name.empty()) throw std::runtime_error(Y("missing property name")); if ( mtx::included_in(type, ct_add, ct_set) && (name == "language")) { auto idx = map_to_iso639_2_code(value); if (-1 == idx) throw std::runtime_error{(boost::format(("invalid ISO 639-2 language code '%1%'")) % value).str()}; value = g_iso639_languages[idx].iso639_2_code; } return std::make_shared<change_c>(type, name, value); }
void Track::setDefaults() { auto &settings = Settings::get(); if (isAudio() && settings.m_setAudioDelayFromFileName) m_delay = extractAudioDelayFromFileName(); if (settings.m_disableAVCompression && (isVideo() || isAudio())) m_compression = CompNone; m_forcedTrackFlag = m_properties[Q("forced_track")] == "1"; m_defaultTrackFlagWasSet = m_properties[Q("default_track")] == "1"; m_name = m_properties[Q("track_name")]; m_cropping = m_properties[Q("cropping")]; if (!m_properties[Q("stereo_mode")].isEmpty()) m_stereoscopy = m_properties[Q("stereo_mode")].toUInt() + 1; auto idx = map_to_iso639_2_code(to_utf8(m_properties[Q("language")]), true); if (0 <= idx) m_language = to_qs(iso639_languages[idx].iso639_2_code); QRegExp re_displayDimensions{"^(\\d+)x(\\d+)$"}; if (-1 != re_displayDimensions.indexIn(m_properties[Q("display_dimensions")])) { m_displayWidth = re_displayDimensions.cap(1); m_displayHeight = re_displayDimensions.cap(2); } }
bool mmg_app::OnInit() { #ifdef __WXMAC__ ProcessSerialNumber PSN; GetCurrentProcess(&PSN); TransformProcessType(&PSN, kProcessTransformToForegroundApplication); #endif wxImage::AddHandler(new wxPNGHandler); mtx_common_init("mmg"); wxConfigBase *cfg; uint32_t i; wxString k, v; int index; prepare_mmg_data_folder(); #if defined(SYS_WINDOWS) cfg = new wxConfig(wxT("mkvmergeGUI")); #else cfg = new wxFileConfig(wxT("mkvmergeGUI"), wxEmptyString, get_config_file_name()); #endif cfg->SetExpandEnvVars(false); wxConfigBase::Set(cfg); init_ui_locale(); cfg->SetPath(wxT("/GUI")); cfg->Read(wxT("last_directory"), &last_open_dir, wxEmptyString); for (i = 0; i < 4; i++) { k.Printf(wxT("last_settings %u"), i); if (cfg->Read(k, &v) && wxFile::Exists(v)) last_settings.push_back(v); k.Printf(wxT("last_chapters %u"), i); if (cfg->Read(k, &v) && wxFile::Exists(v)) last_chapters.push_back(v); } cfg->SetPath(wxT("/chapter_editor")); cfg->Read(wxT("default_language"), &k, wxT("und")); g_default_chapter_language = wxMB(k); index = map_to_iso639_2_code(g_default_chapter_language.c_str()); if (-1 == index) g_default_chapter_language = "und"; else g_default_chapter_language = iso639_languages[index].iso639_2_code; if (cfg->Read(wxT("default_country"), &k) && (0 < k.length())) g_default_chapter_country = wxMB(k); if (!is_valid_cctld(g_default_chapter_country.c_str())) g_default_chapter_country = ""; app = this; mdlg = new mmg_dialog(); mdlg->Show(true); handle_command_line_arguments(); return true; }
void usf_reader_c::parse_metadata(mtx::xml::document_cptr &doc) { auto attribute = doc->document_element().child("metadata").child("language").attribute("code"); if (attribute && !std::string{attribute.value()}.empty()) { int index = map_to_iso639_2_code(attribute.value()); if (-1 != index) m_default_language = iso639_languages[index].iso639_2_code; else if (!g_identifying) mxwarn_fn(m_ti.m_fname, boost::format(Y("The default language code '%1%' is not a valid ISO639-2 language code and will be ignored.\n")) % attribute.value()); } }
void usf_reader_c::parse_subtitles(mtx::xml::document_cptr &doc) { for (auto subtitles = doc->document_element().child("subtitles"); subtitles; subtitles = subtitles.next_sibling("subtitles")) { auto track = std::make_shared<usf_track_t>(); m_tracks.push_back(track); auto attribute = subtitles.child("language").attribute("code"); if (attribute && !std::string{attribute.value()}.empty()) { int index = map_to_iso639_2_code(attribute.value()); if (-1 != index) track->m_language = iso639_languages[index].iso639_2_code; else if (!g_identifying) mxwarn_tid(m_ti.m_fname, m_tracks.size() - 1, boost::format(Y("The language code '%1%' is not a valid ISO639-2 language code and will be ignored.\n")) % attribute.value()); } for (auto subtitle = subtitles.child("subtitle"); subtitle; subtitle = subtitle.next_sibling("subtitle")) { usf_entry_t entry; int64_t duration = -1; attribute = subtitle.attribute("start"); if (attribute) entry.m_start = try_to_parse_timecode(attribute.value()); attribute = subtitle.attribute("stop"); if (attribute) entry.m_end = try_to_parse_timecode(attribute.value()); attribute = subtitle.attribute("duration"); if (attribute) duration = try_to_parse_timecode(attribute.value()); if ((-1 == entry.m_end) && (-1 != entry.m_start) && (-1 != duration)) entry.m_end = entry.m_start + duration; std::stringstream out; for (auto node : subtitle) node.print(out, "", pugi::format_default | pugi::format_raw); entry.m_text = out.str(); track->m_entries.push_back(entry); } } }
void ebml_chapters_converter_c::fix_display(KaxChapterDisplay &display) const { if (!FindChild<KaxChapterString>(display)) throw conversion_x{Y("<ChapterDisplay> is missing the <ChapterString> child.")}; KaxChapterLanguage *clanguage = FindChild<KaxChapterLanguage>(display); if (!clanguage) { clanguage = new KaxChapterLanguage; *static_cast<EbmlString *>(clanguage) = "und"; display.PushElement(*clanguage); } else { int index = map_to_iso639_2_code(std::string(*clanguage)); if (-1 == index) throw conversion_x{boost::format(Y("'%1%' is not a valid ISO639-2 language code.")) % std::string(*clanguage)}; } KaxChapterCountry *ccountry = FindChild<KaxChapterCountry>(display); if (ccountry && !is_valid_cctld(std::string(*ccountry))) throw conversion_x{boost::format(Y("'%1%' is not a valid ccTLD country code.")) % std::string(*ccountry)}; }
void ogm_reader_c::handle_stream_comments() { std::shared_ptr<std::vector<std::string> > comments; std::string title; bool charset_warning_printed = false; charset_converter_cptr cch = charset_converter_c::init(m_ti.m_chapter_charset); size_t i; for (i = 0; i < sdemuxers.size(); i++) { ogm_demuxer_cptr &dmx = sdemuxers[i]; if ((OGM_STREAM_TYPE_A_FLAC == dmx->stype) || (2 > dmx->packet_data.size())) continue; comments = extract_vorbis_comments(dmx->packet_data[1]); if (comments->empty()) continue; std::vector<std::string> chapter_strings; size_t j; for (j = 0; comments->size() > j; j++) { mxverb(2, boost::format("ogm_reader: commment for #%1% for %2%: %3%\n") % j % i % (*comments)[j]); std::vector<std::string> comment = split((*comments)[j], "=", 2); if (comment.size() != 2) continue; if (comment[0] == "LANGUAGE") { int index; index = map_to_iso639_2_code(comment[1].c_str()); if (-1 != index) dmx->language = iso639_languages[index].iso639_2_code; else { std::string lang = comment[1]; int pos1 = lang.find("["); while (0 <= pos1) { int pos2 = lang.find("]", pos1); if (-1 == pos2) pos2 = lang.length() - 1; lang.erase(pos1, pos2 - pos1 + 1); pos1 = lang.find("["); } pos1 = lang.find("("); while (0 <= pos1) { int pos2 = lang.find(")", pos1); if (-1 == pos2) pos2 = lang.length() - 1; lang.erase(pos1, pos2 - pos1 + 1); pos1 = lang.find("("); } index = map_to_iso639_2_code(lang.c_str()); if (-1 != index) dmx->language = iso639_languages[index].iso639_2_code; } } else if (comment[0] == "TITLE") title = comment[1]; else if (balg::starts_with(comment[0], "CHAPTER")) chapter_strings.push_back((*comments)[j]); } bool segment_title_set = false; if (title != "") { title = cch->utf8(title); if (!g_segment_title_set && g_segment_title.empty() && (OGM_STREAM_TYPE_V_MSCOMP == dmx->stype)) { g_segment_title = title; g_segment_title_set = true; segment_title_set = true; } dmx->title = title.c_str(); title = ""; } bool chapters_set = false; if (!chapter_strings.empty() && !m_ti.m_no_chapters) { try { std::shared_ptr<mm_mem_io_c> out(new mm_mem_io_c(nullptr, 0, 1000)); out->write_bom("UTF-8"); for (j = 0; j < chapter_strings.size(); j++) out->puts(cch->utf8(chapter_strings[j]) + std::string("\n")); out->set_file_name(m_ti.m_fname); std::shared_ptr<mm_text_io_c> text_out(new mm_text_io_c(out.get(), false)); m_chapters = parse_chapters(text_out.get(), 0, -1, 0, m_ti.m_chapter_language); chapters_set = true; align_chapter_edition_uids(m_chapters.get()); } catch (...) { } } if ( (segment_title_set || chapters_set) && !charset_warning_printed && (m_ti.m_chapter_charset.empty())) { mxwarn_fn(m_ti.m_fname, Y("This Ogg/OGM file contains chapter or title information. Unfortunately the charset used to store this information in " "the file cannot be identified unambiguously. The program assumes that your system's current charset is appropriate. This can " "be overridden with the '--chapter-charset <charset>' switch.\n")); charset_warning_printed = true; } } }
int mpeg_ts_reader_c::parse_pmt(unsigned char *pmt) { if (!pmt) { mxdebug_if(m_debug_pat_pmt, "mpeg_ts:parse_pmt: Invalid parameters!\n"); return -1; } mpeg_ts_pmt_t *pmt_header = (mpeg_ts_pmt_t *)pmt; if (pmt_header->table_id != 0x02) { mxdebug_if(m_debug_pat_pmt, "mpeg_ts:parse_pmt: Invalid PMT table_id!\n"); return -1; } if (pmt_header->get_section_syntax_indicator() != 1 || pmt_header->get_current_next_indicator() == 0) { mxdebug_if(m_debug_pat_pmt, "mpeg_ts:parse_pmt: Invalid PMT section_syntax_indicator/current_next_indicator!\n"); return -1; } if (pmt_header->section_number != 0 || pmt_header->last_section_number != 0) { mxdebug_if(m_debug_pat_pmt, "mpeg_ts:parse_pmt: Unsupported multiple section PMT!\n"); return -1; } unsigned short pmt_section_length = pmt_header->get_section_length(); uint32_t elapsed_CRC = crc_calc_mpeg2(pmt, 3 + pmt_section_length - 4/*CRC32*/); uint32_t read_CRC = get_uint32_be(pmt + 3 + pmt_section_length - 4); if (elapsed_CRC != read_CRC) { mxdebug_if(m_debug_pat_pmt, boost::format("mpeg_ts:parse_pmt: Wrong PMT CRC !!! Elapsed = 0x%|1$08x|, read 0x%|2$08x|\n") % elapsed_CRC % read_CRC); return -1; } if (pmt_section_length < 13 || pmt_section_length > 1021) { mxdebug_if(m_debug_pat_pmt, boost::format("mpeg_ts:parse_pmt: Wrong PMT section_length (=%1%)\n") % pmt_section_length); return -1; } mpeg_ts_pmt_descriptor_t *pmt_descriptor = (mpeg_ts_pmt_descriptor_t *)(pmt + sizeof(mpeg_ts_pmt_t)); unsigned short program_info_length = pmt_header->get_program_info_length(); while (pmt_descriptor < (mpeg_ts_pmt_descriptor_t *)(pmt + sizeof(mpeg_ts_pmt_t) + program_info_length)) pmt_descriptor = (mpeg_ts_pmt_descriptor_t *)((unsigned char *)pmt_descriptor + sizeof(mpeg_ts_pmt_descriptor_t) + pmt_descriptor->length); mpeg_ts_pmt_pid_info_t *pmt_pid_info = (mpeg_ts_pmt_pid_info_t *)pmt_descriptor; // Calculate pids_count size_t pids_found = 0; while (pmt_pid_info < (mpeg_ts_pmt_pid_info_t *)(pmt + 3 + pmt_section_length - 4/*CRC32*/)) { pids_found++; pmt_pid_info = (mpeg_ts_pmt_pid_info_t *)((unsigned char *)pmt_pid_info + sizeof(mpeg_ts_pmt_pid_info_t) + pmt_pid_info->get_es_info_length()); } mxdebug_if(m_debug_pat_pmt, boost::format("mpeg_ts:parse_pmt: program number (%1%)\n") % pmt_header->get_program_number()); mxdebug_if(m_debug_pat_pmt, boost::format("mpeg_ts:parse_pmt: pcr pid (%1%)\n") % pmt_header->get_pcr_pid()); if (pids_found == 0) { mxdebug_if(m_debug_pat_pmt, "mpeg_ts:parse_pmt: There's no information about elementary PIDs\n"); return 0; } pmt_pid_info = (mpeg_ts_pmt_pid_info_t *)pmt_descriptor; // Extract pid_info while (pmt_pid_info < (mpeg_ts_pmt_pid_info_t *)(pmt + 3 + pmt_section_length - 4/*CRC32*/)) { mpeg_ts_track_ptr track(new mpeg_ts_track_c(*this)); unsigned short es_info_length = pmt_pid_info->get_es_info_length(); track->type = ES_UNKNOWN; track->set_pid(pmt_pid_info->get_pid()); switch(pmt_pid_info->stream_type) { case ISO_11172_VIDEO: track->type = ES_VIDEO_TYPE; track->fourcc = FOURCC('M', 'P', 'G', '1'); break; case ISO_13818_VIDEO: track->type = ES_VIDEO_TYPE; track->fourcc = FOURCC('M', 'P', 'G', '2'); break; case ISO_14496_PART2_VIDEO: track->type = ES_VIDEO_TYPE; track->fourcc = FOURCC('M', 'P', 'G', '4'); break; case ISO_14496_PART10_VIDEO: track->type = ES_VIDEO_TYPE; track->fourcc = FOURCC('A', 'V', 'C', '1'); break; case STREAM_VIDEO_VC1: track->type = ES_VIDEO_TYPE; track->fourcc = FOURCC('W', 'V', 'C', '1'); break; case ISO_11172_AUDIO: case ISO_13818_AUDIO: track->type = ES_AUDIO_TYPE; track->fourcc = FOURCC('M', 'P', '2', ' '); break; case ISO_13818_PART7_AUDIO: track->type = ES_AUDIO_TYPE; track->fourcc = FOURCC('A', 'A', 'C', ' '); break; case ISO_14496_PART3_AUDIO: track->type = ES_AUDIO_TYPE; track->fourcc = FOURCC('A', 'A', 'C', ' '); break; case STREAM_AUDIO_AC3: case STREAM_AUDIO_AC3_PLUS: // EAC3 track->type = ES_AUDIO_TYPE; track->fourcc = FOURCC('A', 'C', '3', ' '); break; case STREAM_AUDIO_AC3_LOSSLESS: track->type = ES_AUDIO_TYPE; track->fourcc = FOURCC('T', 'R', 'H', 'D'); break; case STREAM_AUDIO_DTS: case STREAM_AUDIO_DTS_HD: case STREAM_AUDIO_DTS_HD_MA: track->type = ES_AUDIO_TYPE; track->fourcc = FOURCC('D', 'T', 'S', ' '); break; case STREAM_SUBTITLES_HDMV_PGS: track->type = ES_SUBT_TYPE; track->fourcc = FOURCC('P', 'G', 'S', ' '); track->probed_ok = true; break; case ISO_13818_PES_PRIVATE: break; default: mxdebug_if(m_debug_pat_pmt, boost::format("mpeg_ts:parse_pmt: Unknown stream type: %1%\n") % (int)pmt_pid_info->stream_type); track->type = ES_UNKNOWN; break; } pmt_descriptor = (mpeg_ts_pmt_descriptor_t *)((unsigned char *)pmt_pid_info + sizeof(mpeg_ts_pmt_pid_info_t)); bool type_known = false; while (pmt_descriptor < (mpeg_ts_pmt_descriptor_t *)((unsigned char *)pmt_pid_info + sizeof(mpeg_ts_pmt_pid_info_t) + es_info_length)) { mxdebug_if(m_debug_pat_pmt, boost::format("mpeg_ts:parse_pmt: PMT descriptor tag 0x%|1$02x| length %2%\n") % static_cast<unsigned int>(pmt_descriptor->tag) % static_cast<unsigned int>(pmt_descriptor->length)); switch(pmt_descriptor->tag) { case 0x56: // Teletext descriptor if (pmt_pid_info->stream_type == ISO_13818_PES_PRIVATE) { // PES containig private data track->type = ES_UNKNOWN; type_known = true; mxdebug_if(m_debug_pat_pmt, "mpeg_ts:parse_pmt: Teletext found but not handled !!\n"); } break; case 0x59: // Subtitles descriptor if (pmt_pid_info->stream_type == ISO_13818_PES_PRIVATE) { // PES containig private data track->type = ES_SUBT_TYPE; track->fourcc = FOURCC('V', 'S', 'U', 'B'); type_known = true; } break; case 0x6A: // AC3 descriptor case 0x7A: // EAC3 descriptor if (pmt_pid_info->stream_type == ISO_13818_PES_PRIVATE) { // PES containig private data track->type = ES_AUDIO_TYPE; track->fourcc = FOURCC('A', 'C', '3', ' '); type_known = true; } break; case 0x7b: // DTS descriptor if (pmt_pid_info->stream_type == ISO_13818_PES_PRIVATE) { // PES containig private data track->type = ES_AUDIO_TYPE; track->fourcc = FOURCC('D', 'T', 'S', ' '); type_known = true; } break; case 0x0a: // ISO 639 language descriptor if (3 <= pmt_descriptor->length) { int language_idx = map_to_iso639_2_code(std::string(reinterpret_cast<char *>(pmt_descriptor + 1), 3).c_str()); if (-1 != language_idx) track->language = iso639_languages[language_idx].iso639_2_code; } break; } pmt_descriptor = (mpeg_ts_pmt_descriptor_t *)((unsigned char *)pmt_descriptor + sizeof(mpeg_ts_pmt_descriptor_t) + pmt_descriptor->length); } // Default to AC3 if it's a PES private stream type that's missing // a known/more concrete descriptor tag. if ((pmt_pid_info->stream_type == ISO_13818_PES_PRIVATE) && !type_known) { track->type = ES_AUDIO_TYPE; track->fourcc = FOURCC('A', 'C', '3', ' '); } pmt_pid_info = (mpeg_ts_pmt_pid_info_t *)((unsigned char *)pmt_pid_info + sizeof(mpeg_ts_pmt_pid_info_t) + es_info_length); if (track->type != ES_UNKNOWN) { PMT_found = true; track->pid = track->pid; track->processed = false; track->data_ready = false; tracks.push_back(track); es_to_process++; uint32_t fourcc = get_uint32_be(&track->fourcc); mxdebug_if(m_debug_pat_pmt, boost::format("mpeg_ts:parse_pmt: PID %1% has type: 0x%|2$08x| (%3%)\n") % track->pid % fourcc % std::string(reinterpret_cast<char *>(&fourcc), 4)); } } return 0; }