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