Exemplo n.º 1
0
EbmlElement *
kax_file_c::read_next_level1_element(uint32_t wanted_id,
                                     bool report_cluster_timecode) {
  try {
    auto element = read_next_level1_element_internal(wanted_id);

    if (report_cluster_timecode && (-1 != m_timecode_scale))
      mxinfo(boost::format(Y("The first cluster timecode after the resync is %1%.\n"))
             % format_timecode(FindChildValue<KaxClusterTimecode>(static_cast<KaxCluster *>(element)) * m_timecode_scale));

    return element;

  } catch (mtx::mm_io::exception &e) {
    mxwarn(boost::format("%1% %2% %3%\n")
           % (boost::format(Y("%1%: an exception occurred (message: %2%; type: %3%).")) % "kax_file_c::read_next_level1_element()" % (boost::format("%1% / %2%") % e.what() % e.error()) % typeid(e).name())
           % Y("This usually indicates a damaged file structure.") % Y("The file will not be processed further."));

  } catch (std::exception &e) {
    mxwarn(boost::format("%1% %2% %3%\n")
           % (boost::format(Y("%1%: an exception occurred (message: %2%; type: %3%).")) % "kax_file_c::read_next_level1_element()" % e.what() % typeid(e).name())
           % Y("This usually indicates a damaged file structure.") % Y("The file will not be processed further."));

  } catch (...) {
    mxwarn(boost::format("%1% %2% %3%\n")
           % (boost::format(Y("%1%: an unknown exception occurred.")) % "kax_file_c::read_next_level1_element()")
           % Y("This usually indicates a damaged file structure.") % Y("The file will not be processed further."));
  }
  return nullptr;
}
Exemplo n.º 2
0
void
xtr_srt_c::handle_frame(xtr_frame_t &f) {
  if (-1 == f.duration) {
    mxwarn(boost::format(Y("Track %1%: Subtitle entry number %2% is missing its duration. Assuming a duration of 1s.\n")) % m_tid % (m_num_entries + 1));
    f.duration = 1000000000;
  }

  int64_t start =         f.timecode / 1000000;
  int64_t end   = start + f.duration / 1000000;

  ++m_num_entries;
  char *text = new char[f.frame->get_size() + 1];
  memcpy(text, f.frame->get_buffer(), f.frame->get_size());
  text[f.frame->get_size()] = 0;

  std::string buffer =
    (boost::format("%1%\n"
                   "%|2$02d|:%|3$02d|:%|4$02d|,%|5$03d| --> %|6$02d|:%|7$02d|:%|8$02d|,%|9$03d|\n"
                   "%10%\n\n")
     % m_num_entries
     % (start / 1000 / 60 / 60) % ((start / 1000 / 60) % 60) % ((start / 1000) % 60) % (start % 1000)
     % (end   / 1000 / 60 / 60) % ((end   / 1000 / 60) % 60) % ((end   / 1000) % 60) % (end   % 1000)
     % m_conv->native(text)
     ).str();

  m_out->puts(buffer);
  m_out->flush();
  delete []text;
}
Exemplo n.º 3
0
bool
xtr_avc_c::write_nal(const binary *data,
                     size_t &pos,
                     size_t data_size,
                     size_t write_nal_size_size) {
  size_t i;
  size_t nal_size = 0;

  if (write_nal_size_size > data_size)
    return false;

  for (i = 0; i < write_nal_size_size; ++i)
    nal_size = (nal_size << 8) | data[pos++];

  if ((pos + nal_size) > data_size) {
    mxwarn(boost::format(Y("Track %1%: NAL too big. Size according to header field: %2%, available bytes in packet: %3%. This NAL is defect and will be skipped.\n")) % m_tid % nal_size % (data_size - pos));
    return false;
  }

  m_out->write(s_start_code, 4);
  m_out->write(data + pos, nal_size);

  pos += nal_size;

  return true;
}
Exemplo n.º 4
0
void
options_c::merge_targets() {
  std::map<uint64_t, track_target_c *> targets_by_track_uid;
  std::vector<target_cptr> targets_to_keep;

  for (auto &target : m_targets) {
    auto track_target = dynamic_cast<track_target_c *>(target.get());
    if (!track_target || dynamic_cast<segment_info_target_c *>(target.get())) {
      targets_to_keep.push_back(target);
      continue;
    }

    auto existing_target_it = targets_by_track_uid.find(track_target->get_track_uid());
    auto track_uid          = target->get_track_uid();
    if (targets_by_track_uid.end() == existing_target_it) {
      targets_to_keep.push_back(target);
      targets_by_track_uid[track_uid] = track_target;
      continue;
    }

    existing_target_it->second->merge_changes(*track_target);

    mxwarn(boost::format(Y("The edit specifications '%1%' and '%2%' resolve to the same track with the UID %3%.\n"))
           % existing_target_it->second->get_spec() % track_target->get_spec() % track_uid);
  }

  m_targets.swap(targets_to_keep);
}
Exemplo n.º 5
0
bool
xtr_hevc_c::write_nal(binary const *data,
                      size_t &pos,
                      size_t data_size,
                      size_t write_nal_size_size) {
  if (write_nal_size_size > data_size)
    return false;

  auto nal_size  = get_uint_be(&data[pos], write_nal_size_size);
  pos           += write_nal_size_size;

  if ((pos + nal_size) > data_size) {
    mxwarn(boost::format(Y("Track %1%: NAL too big. Size according to header field: %2%, available bytes in packet: %3%. This NAL is defect and will be skipped.\n")) % m_tid % nal_size % (data_size - pos));
    return false;
  }

  auto nal_unit_type   = (data[pos] >> 1) & 0x3f;
  auto start_code_size = m_first_nalu || (HEVC_NALU_TYPE_VIDEO_PARAM == nal_unit_type) || (HEVC_NALU_TYPE_SEQ_PARAM == nal_unit_type) || (HEVC_NALU_TYPE_PIC_PARAM == nal_unit_type) ? 4 : 3;
  m_first_nalu         = false;

  m_out->write(ms_start_code + (4 - start_code_size), start_code_size);
  m_out->write(data + pos, nal_size);

  pos += nal_size;

  return true;
}
Exemplo n.º 6
0
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);
  }
}
Exemplo n.º 7
0
M2VParser::~M2VParser(){
  DumpQueues();
  if (!probing && !waitQueue.empty()) {
    mxwarn(Y("Video ended with a shortened group of pictures. Some frames have been dropped. You may want to fix the MPEG2 video stream before attempting to multiplex it.\n"));
  }
  FlushWaitQueue();
  delete seqHdrChunk;
  delete gopChunk;
  delete mpgBuf;
}
void
generic_packetizer_c::show_experimental_status_version(std::string const &codec_id) {
  auto idx = get_format_name().get_untranslated();
  if (s_experimental_status_warning_shown[idx])
    return;

  s_experimental_status_warning_shown[idx] = true;
  mxwarn(boost::format(Y("Note that the Matroska specifications regarding the storage of '%1%' have not been finalized yet. "
                         "mkvmerge's support for it is therefore subject to change and uses the CodecID '%2%/EXPERIMENTAL' instead of '%2%'. "
                         "This warning will be removed once the specifications have been finalized and mkvmerge has been updated accordingly.\n"))
         % get_format_name().get_translated() % codec_id);
}
void
generic_packetizer_c::set_as_default_track(int type,
                                           int priority) {
  if (g_default_tracks_priority[type] < priority) {
    g_default_tracks_priority[type] = priority;
    g_default_tracks[type]          = m_hserialno;

  } else if (   (DEFAULT_TRACK_PRIORITY_CMDLINE == priority)
             && (g_default_tracks[type] != m_hserialno)
             && !m_default_track_warning_printed) {
    mxwarn(boost::format(Y("Another default track for %1% tracks has already been set. The 'default' flag for track %2% of '%3%' will not be set.\n"))
           % (DEFTRACK_TYPE_AUDIO == type ? "audio" : DEFTRACK_TYPE_VIDEO == type ? "video" : "subtitle") % m_ti.m_id % m_ti.m_fname);
    m_default_track_warning_printed = true;
  }
}
Exemplo n.º 10
0
iconv_charset_converter_c::iconv_charset_converter_c(const std::string &charset)
  : charset_converter_c(charset)
  , m_is_utf8(false)
  , m_to_utf8_handle(reinterpret_cast<iconv_t>(-1))
  , m_from_utf8_handle(reinterpret_cast<iconv_t>(-1))
{
  if (is_utf8_charset_name(charset)) {
    m_is_utf8 = true;
    return;
  }

  m_to_utf8_handle = iconv_open("UTF-8", charset.c_str());
  if (reinterpret_cast<iconv_t>(-1) == m_to_utf8_handle)
    mxwarn(boost::format(Y("Could not initialize the iconv library for the conversion from %1% to UFT-8. "
                           "Some strings will not be converted to UTF-8 and the resulting Matroska file "
                           "might not comply with the Matroska specs (error: %2%, %3%).\n"))
           % charset % errno % strerror(errno));

  m_from_utf8_handle = iconv_open(charset.c_str(), "UTF-8");
  if (reinterpret_cast<iconv_t>(-1) == m_from_utf8_handle)
    mxwarn(boost::format(Y("Could not initialize the iconv library for the conversion from UFT-8 to %1%. "
                           "Some strings cannot be converted from UTF-8 and might be displayed incorrectly (error: %2%, %3%).\n"))
           % charset % errno % strerror(errno));
}
Exemplo n.º 11
0
void
aac_reader_c::create_packetizer(int64_t) {
  if (!demuxing_requested('a', 0) || (NPTZR() != 0))
    return;

  if (!m_sbr_status_set)
    mxwarn(Y("AAC files may contain HE-AAC / AAC+ / SBR AAC audio. "
             "This can NOT be detected automatically. Therefore you have to "
             "specifiy '--aac-is-sbr 0' manually for this input file if the "
             "file actually contains SBR AAC. The file will be muxed in the "
             "WRONG way otherwise. Also read mkvmerge's documentation.\n"));

  generic_packetizer_c *aacpacketizer = new aac_packetizer_c(this, m_ti, m_aacheader.id, m_aacheader.profile, m_aacheader.sample_rate, m_aacheader.channels, m_emphasis_present);
  add_packetizer(aacpacketizer);

  if (AAC_PROFILE_SBR == m_aacheader.profile)
    aacpacketizer->set_audio_output_sampling_freq(m_aacheader.sample_rate * 2);

  show_packetizer_info(0, aacpacketizer);
}
Exemplo n.º 12
0
void
xtr_usf_c::finish_track() {
  auto subtitles = m_doc->document_element().append_child("subtitles");
  subtitles.append_child("language").append_attribute("code").set_value(m_language.c_str());

  for (auto &entry : m_entries) {
    std::string text = std::string{"<subtitle>"} + entry.m_text + "</subtitle>";
    strip(text, true);

    std::stringstream text_in(text);
    pugi::xml_document subtitle_doc;
    if (!subtitle_doc.load(text_in, pugi::parse_default | pugi::parse_declaration | pugi::parse_doctype | pugi::parse_pi | pugi::parse_comments)) {
      mxwarn(boost::format(Y("Track %1%: An USF subtitle entry starting at timecode %2% is not well-formed XML and will be skipped.\n")) % m_tid % format_timecode(entry.m_start * 1000000, 3));
      continue;
    }

    auto subtitle = subtitles.append_child("subtitle");
    subtitle.append_attribute("start").set_value(format_timecode(entry.m_start * 1000000, 3).c_str());
    subtitle.append_attribute("stop"). set_value(format_timecode(entry.m_end   * 1000000, 3).c_str());

    for (auto child : subtitle_doc.document_element())
      subtitle.append_copy(child);
  }
}
Exemplo n.º 13
0
void
timecode_factory_v3_c::parse(mm_io_c &in) {
  std::string line;
  timecode_duration_c t;
  std::vector<timecode_duration_c>::iterator iit;
  std::vector<timecode_duration_c>::const_iterator pit;

  std::string err_msg_assume = (boost::format(Y("The timecode file '%1%' does not contain a valid 'Assume' line with the default number of frames per second.\n")) % m_file_name).str();

  int line_no = 1;
  do {
    if (!in.getline2(line))
      mxerror(err_msg_assume);
    line_no++;
    strip(line);
    if ((line.length() != 0) && (line[0] != '#'))
      break;
  } while (true);

  if (!ba::istarts_with(line, "assume "))
    mxerror(err_msg_assume);
  line.erase(0, 6);
  strip(line);

  if (!parse_double(line.c_str(), m_default_fps))
    mxerror(err_msg_assume);

  while (in.getline2(line)) {
    line_no++;
    strip(line, true);
    if ((line.length() == 0) || (line[0] == '#'))
      continue;

    double dur;
    if (ba::istarts_with(line, "gap,")) {
      line.erase(0, 4);
      strip(line);

      t.is_gap = true;
      t.fps    = m_default_fps;

      if (!parse_double(line.c_str(), dur))
        mxerror(boost::format(Y("The timecode file '%1%' does not contain a valid 'Gap' line with the duration of the gap.\n")) % m_file_name);
      t.duration = (int64_t)(1000000000.0 * dur);

    } else {
      t.is_gap = false;
      std::vector<std::string> parts = split(line, ",");

      if ((1 == parts.size()) && parse_double(parts[0], dur))
        t.fps = m_default_fps;

      else if ((2 != parts.size()) || !parse_double(parts[1], t.fps)) {
        mxwarn(boost::format(Y("Line %1% of the timecode file '%2%' could not be parsed.\n")) % line_no % m_file_name);
        continue;
      }
      t.duration = (int64_t)(1000000000.0 * dur);
    }

    if ((t.fps < 0) || (t.duration <= 0)) {
      mxwarn(boost::format(Y("Line %1% of the timecode file '%2%' contains inconsistent data (e.g. the duration or the FPS are smaller than zero).\n"))
             % line_no % m_file_name);
      continue;
    }

    m_durations.push_back(t);
  }

  mxverb(3, boost::format("ext_timecodes: Version 3, default fps %1%, %2% entries.\n") % m_default_fps % m_durations.size());

  if (m_durations.size() == 0)
    mxwarn(boost::format(Y("The timecode file '%1%' does not contain any valid entry.\n")) % m_file_name);

  t.duration = 0xfffffffffffffffll;
  t.is_gap   = false;
  t.fps      = m_default_fps;
  m_durations.push_back(t);

  for (iit = m_durations.begin(); iit < m_durations.end(); iit++)
    mxverb(4, boost::format("durations:%1% entry for %2% with %3% FPS\n") % (iit->is_gap ? " gap" : "") % iit->duration % iit->fps);
}
Exemplo n.º 14
0
void
avi_reader_c::add_audio_demuxer(int aid) {
  for (auto &demuxer : m_audio_demuxers)
    if (demuxer.m_aid == aid) // Demuxer already added?
      return;

  AVI_set_audio_track(m_avi, aid);
  if (AVI_read_audio_chunk(m_avi, nullptr) < 0) {
    mxwarn(boost::format(Y("Could not find an index for audio track %1% (avilib error message: %2%). Skipping track.\n")) % (aid + 1) % AVI_strerror());
    return;
  }

  avi_demuxer_t demuxer;
  generic_packetizer_c *packetizer = nullptr;
  alWAVEFORMATEX *wfe              = m_avi->wave_format_ex[aid];
  uint32_t audio_format            = AVI_audio_format(m_avi);

  demuxer.m_aid                    = aid;
  demuxer.m_ptzr                   = -1;
  demuxer.m_samples_per_second     = AVI_audio_rate(m_avi);
  demuxer.m_channels               = AVI_audio_channels(m_avi);
  demuxer.m_bits_per_sample        = AVI_audio_bits(m_avi);

  m_ti.m_id                        = aid + 1;       // ID for this audio track.

  auto stream_header               = &m_avi->stream_headers[aid];
  auto dw_scale                    = static_cast<int64_t>(get_uint32_le(&stream_header->dw_scale));
  auto dw_rate                     = static_cast<int64_t>(get_uint32_le(&stream_header->dw_rate));
  auto dw_sample_size              = static_cast<int64_t>(get_uint32_le(&stream_header->dw_sample_size));
  m_ti.m_avi_audio_data_rate       = dw_scale ? dw_rate * dw_sample_size / dw_scale : 0;

  if ((0xfffe == audio_format) && (get_uint16_le(&wfe->cb_size) >= (sizeof(alWAVEFORMATEXTENSION)))) {
    alWAVEFORMATEXTENSIBLE *ext = reinterpret_cast<alWAVEFORMATEXTENSIBLE *>(wfe);
    audio_format                = get_uint32_le(&ext->extension.guid.data1);

  } else if (get_uint16_le(&wfe->cb_size) > 0)
    m_ti.m_private_data = memory_c::clone(wfe + 1, get_uint16_le(&wfe->cb_size));

  else
    m_ti.m_private_data.reset();

  demuxer.m_codec = codec_c::look_up_audio_format(audio_format);

  if (demuxer.m_codec.is(codec_c::type_e::A_PCM))
    packetizer = new pcm_packetizer_c(this, m_ti, demuxer.m_samples_per_second, demuxer.m_channels, demuxer.m_bits_per_sample, 0x0003 == audio_format ? pcm_packetizer_c::ieee_float : pcm_packetizer_c::little_endian_integer);

  else if (demuxer.m_codec.is(codec_c::type_e::A_MP2) || demuxer.m_codec.is(codec_c::type_e::A_MP3))
    packetizer = new mp3_packetizer_c(this, m_ti, demuxer.m_samples_per_second, demuxer.m_channels, false);

  else if (demuxer.m_codec.is(codec_c::type_e::A_AC3))
    packetizer = new ac3_packetizer_c(this, m_ti, demuxer.m_samples_per_second, demuxer.m_channels, 0);

  else if (demuxer.m_codec.is(codec_c::type_e::A_DTS))
    packetizer = create_dts_packetizer(aid);

  else if (demuxer.m_codec.is(codec_c::type_e::A_AAC))
    packetizer = create_aac_packetizer(aid, demuxer);

  else if (demuxer.m_codec.is(codec_c::type_e::A_VORBIS))
    packetizer = create_vorbis_packetizer(aid);

  else
    mxerror_tid(m_ti.m_fname, aid + 1, boost::format(Y("Unknown/unsupported audio format 0x%|1$04x| for this audio track.\n")) % audio_format);

  packetizer->enable_avi_audio_sync(true);

  show_packetizer_info(aid + 1, packetizer);

  demuxer.m_ptzr = add_packetizer(packetizer);

  m_audio_demuxers.push_back(demuxer);

  int i, maxchunks = AVI_audio_chunks(m_avi);
  for (i = 0; i < maxchunks; i++) {
    auto size = AVI_audio_size(m_avi, i);
    if (size < AVI_MAX_AUDIO_CHUNK_SIZE)
      m_bytes_to_process += size;
  }
}
Exemplo n.º 15
0
void
avi_reader_c::add_audio_demuxer(int aid) {
  for (auto &demuxer : m_audio_demuxers)
    if (demuxer.m_aid == aid) // Demuxer already added?
      return;

  AVI_set_audio_track(m_avi, aid);
  if (AVI_read_audio_chunk(m_avi, nullptr) < 0) {
    mxwarn(boost::format(Y("Could not find an index for audio track %1% (avilib error message: %2%). Skipping track.\n")) % (aid + 1) % AVI_strerror());
    return;
  }

  avi_demuxer_t demuxer;
  generic_packetizer_c *packetizer = nullptr;
  alWAVEFORMATEX *wfe              = m_avi->wave_format_ex[aid];
  uint32_t audio_format            = AVI_audio_format(m_avi);

  demuxer.m_aid                    = aid;
  demuxer.m_ptzr                   = -1;
  demuxer.m_samples_per_second     = AVI_audio_rate(m_avi);
  demuxer.m_channels               = AVI_audio_channels(m_avi);
  demuxer.m_bits_per_sample        = AVI_audio_bits(m_avi);

  m_ti.m_id                        = aid + 1;       // ID for this audio track.
  m_ti.m_avi_block_align           = get_uint16_le(&wfe->n_block_align);
  m_ti.m_avi_avg_bytes_per_sec     = get_uint32_le(&wfe->n_avg_bytes_per_sec);
  m_ti.m_avi_samples_per_chunk     = get_uint32_le(&m_avi->stream_headers[aid].dw_scale);
  m_ti.m_avi_sample_scale          = get_uint32_le(&m_avi->stream_headers[aid].dw_rate);
  m_ti.m_avi_samples_per_sec       = demuxer.m_samples_per_second;

  if ((0xfffe == audio_format) && (get_uint16_le(&wfe->cb_size) >= (sizeof(alWAVEFORMATEXTENSION)))) {
    alWAVEFORMATEXTENSIBLE *ext = reinterpret_cast<alWAVEFORMATEXTENSIBLE *>(wfe);
    audio_format                = get_uint32_le(&ext->extension.guid.data1);

  } else if (get_uint16_le(&wfe->cb_size) > 0)
    m_ti.m_private_data = memory_c::clone(wfe + 1, get_uint16_le(&wfe->cb_size));

  else
    m_ti.m_private_data.reset();

  switch(audio_format) {
    case 0x0001:                // raw PCM audio
    case 0x0003:                // raw PCM audio (float)
      packetizer = new pcm_packetizer_c(this, m_ti, demuxer.m_samples_per_second, demuxer.m_channels, demuxer.m_bits_per_sample, 0x0003 == audio_format ? pcm_packetizer_c::ieee_float : pcm_packetizer_c::little_endian_integer);
      break;

    case 0x0050:                // MP2
    case 0x0055:                // MP3
      packetizer = new mp3_packetizer_c(this, m_ti, demuxer.m_samples_per_second, demuxer.m_channels, false);
      break;

    case 0x2000:                // AC3
      packetizer = new ac3_packetizer_c(this, m_ti, demuxer.m_samples_per_second, demuxer.m_channels, 0);
      break;

    case 0x2001:                // DTS
      packetizer = create_dts_packetizer(aid);
      break;

    case 0x00ff:
    case 0x706d:                // AAC
      packetizer = create_aac_packetizer(aid, demuxer);
      break;

    case 0x566f:                // Vorbis
      packetizer = create_vorbis_packetizer(aid);
      break;

    default:
      mxerror_tid(m_ti.m_fname, aid + 1, boost::format(Y("Unknown/unsupported audio format 0x%|1$04x| for this audio track.\n")) % audio_format);
  }

  show_packetizer_info(aid + 1, packetizer);

  demuxer.m_ptzr = add_packetizer(packetizer);

  m_audio_demuxers.push_back(demuxer);

  int i, maxchunks = AVI_audio_chunks(m_avi);
  for (i = 0; i < maxchunks; i++)
    m_bytes_to_process += AVI_audio_size(m_avi, i);
}
Exemplo n.º 16
0
int64_t
spu_extract_duration(unsigned char *data,
                     size_t buf_size,
                     int64_t timecode) {
    uint32_t date, control_start, next_off, start_off, off;
    unsigned char type;
    int duration;
    bool unknown;

    control_start = get_uint16_be(data + 2);
    next_off = control_start;
    duration = -1;
    start_off = 0;

    while ((start_off != next_off) && (next_off < buf_size)) {
        start_off = next_off;
        date = get_uint16_be(data + start_off) * 1024;
        next_off = get_uint16_be(data + start_off + 2);
        if (next_off < start_off) {
            mxwarn(boost::format(Y("spu_extraction_duration: Encountered broken SPU packet (next_off < start_off) at timecode %1%. "
                                   "This packet might be displayed incorrectly or not at all.\n")) % format_timecode(timecode, 3));
            return -1;
        }
        mxverb(4, boost::format("spu_extraction_duration: date = %1%\n") % date);
        off = start_off + 4;
        for (type = data[off++]; type != 0xff; type = data[off++]) {
            mxverb(4, boost::format("spu_extraction_duration: cmd = %1% ") % type);
            unknown = false;
            switch(type) {
            case 0x00:
                /* Menu ID, 1 byte */
                mxverb(4, "menu ID");
                break;
            case 0x01:
                /* Start display */
                mxverb(4, "start display");
                break;
            case 0x02:
                /* Stop display */
                mxverb(4, boost::format("stop display: %1%") % (date / 90));
                return (int64_t)date * 1000000 / 90;
                break;
            case 0x03:
                /* Palette */
                mxverb(4, "palette");
                off+=2;
                break;
            case 0x04:
                /* Alpha */
                mxverb(4, "alpha");
                off+=2;
                break;
            case 0x05:
                mxverb(4, "coords");
                off+=6;
                break;
            case 0x06:
                mxverb(4, "graphic lines");
                off+=4;
                break;
            case 0xff:
                /* All done, bye-bye */
                mxverb(4, "done");
                return duration;
            default:
                mxverb(4, boost::format("unknown (0x%|1$02x|), skipping %2% bytes.") % type % (next_off - off));
                unknown = true;
            }
            mxverb(4, "\n");
            if (unknown)
                break;
        }
    }
    return duration;
}
Exemplo n.º 17
0
//Maintains the time of the last start of GOP and uses the temporal_reference
//field as an offset.
int32_t M2VParser::FillQueues(){
  if(chunks.empty()){
    return -1;
  }
  bool done = false;
  while(!done){
    MediaTime myTime;
    MPEGChunk* chunk = chunks.front();
    while (chunk->GetType() != MPEG_VIDEO_PICTURE_START_CODE) {
      if (chunk->GetType() == MPEG_VIDEO_GOP_START_CODE) {
        ParseGOPHeader(chunk, m_gopHdr);
        if (frameNum != 0) {
          gopPts = highestPts + 1;
        }
        if (gopChunk)
          delete gopChunk;
        gopChunk = chunk;
        gopNum++;
        /* Perform some sanity checks */
        if(waitSecondField){
          mxerror(Y("Single field frame before GOP header detected. Fix the MPEG2 video stream before attempting to multiplex it.\n"));
        }
        if(!waitQueue.empty()){
          mxwarn(Y("Shortened GOP detected. Some frames have been dropped. You may want to fix the MPEG2 video stream before attempting to multiplex it.\n"));
          FlushWaitQueue();
        }
        if(m_gopHdr.brokenLink){
          mxinfo(Y("Found group of picture with broken link. You may want use smart reencode before attempting to multiplex it.\n"));
        }
        // There are too many broken videos to do the following so ReferenceBlock will be wrong for broken videos.
        /*
        if(m_gopHdr.closedGOP){
          ClearRef();
        }
        */
      } else if (chunk->GetType() == MPEG_VIDEO_SEQUENCE_START_CODE) {
        if (seqHdrChunk)
          delete seqHdrChunk;
        ParseSequenceHeader(chunk, m_seqHdr);
        seqHdrChunk = chunk;

      }

      chunks.erase(chunks.begin());
      if (chunks.empty())
        return -1;
      chunk = chunks.front();
    }
    MPEG2PictureHeader picHdr;
    ParsePictureHeader(chunk, picHdr);

    if (picHdr.pictureStructure == 0x03) {
      usePictureFrames = true;
    }
    myTime = gopPts + picHdr.temporalReference;
    invisible = false;

    if (myTime > highestPts)
      highestPts = myTime;

    switch(picHdr.frameType){
      case MPEG2_I_FRAME:
        PrepareFrame(chunk, myTime, picHdr);
        notReachedFirstGOP = false;
        break;
      case MPEG2_P_FRAME:
        if(firstRef == -1) break;
        PrepareFrame(chunk, myTime, picHdr);
        break;
      default: //B-frames
        if(firstRef == -1 || secondRef == -1){
          if(!m_gopHdr.closedGOP && !m_gopHdr.brokenLink){
            if(gopNum > 0){
              mxerror(Y("Found B frame without second reference in a non closed GOP. Fix the MPEG2 video stream before attempting to multiplex it.\n"));
            } else if (!probing && !bFrameMissingReferenceWarning){
              mxwarn(Y("Found one or more B frames without second reference in the first GOP. You may want to fix the MPEG2 video stream or use smart reencode before attempting to multiplex it.\n"));
              bFrameMissingReferenceWarning = true;
            }
          }
          invisible = true;
        }
        PrepareFrame(chunk, myTime, picHdr);
    }
    frameNum++;
    chunks.erase(chunks.begin());
    delete chunk;
    if (chunks.empty())
      return -1;
  }
  return 0;
}
Exemplo n.º 18
0
bool
content_decoder_c::initialize(KaxTrackEntry &ktentry) {
  encodings.clear();

  KaxContentEncodings *kcencodings = FindChild<KaxContentEncodings>(&ktentry);
  if (!kcencodings)
    return true;

  int tid = kt_get_number(ktentry);

  for (auto kcenc_el : *kcencodings) {
    auto kcenc = dynamic_cast<KaxContentEncoding *>(kcenc_el);
    if (!kcenc)
      continue;

    kax_content_encoding_t enc;

    enc.order    = FindChildValue<KaxContentEncodingOrder>(kcenc);
    enc.type     = FindChildValue<KaxContentEncodingType >(kcenc);
    enc.scope    = FindChildValue<KaxContentEncodingScope>(kcenc, 1u);

    auto ce_comp = FindChild<KaxContentCompression>(kcenc);
    if (ce_comp) {
      enc.comp_algo     = FindChildValue<KaxContentCompAlgo    >(ce_comp);
      enc.comp_settings = FindChildValue<KaxContentCompSettings>(ce_comp);
    }

    auto ce_enc = FindChild<KaxContentEncryption>(kcenc);
    if (ce_enc) {
      enc.enc_algo      = FindChildValue<KaxContentEncAlgo    >(ce_enc);
      enc.enc_keyid     = FindChildValue<KaxContentEncKeyID   >(ce_enc);
      enc.sig_algo      = FindChildValue<KaxContentSigAlgo    >(ce_enc);
      enc.sig_hash_algo = FindChildValue<KaxContentSigHashAlgo>(ce_enc);
      enc.sig_keyid     = FindChildValue<KaxContentSigKeyID   >(ce_enc);
      enc.signature     = FindChildValue<KaxContentSignature  >(ce_enc);
    }

    if (1 == enc.type) {
      mxwarn(boost::format(Y("Track number %1% has been encrypted and decryption has not yet been implemented.\n")) % tid);
      ok = false;
      break;
    }

    if (0 != enc.type) {
      mxerror(boost::format(Y("Unknown content encoding type %1% for track %2%.\n")) % enc.type % tid);
      ok = false;
      break;
    }

    if (0 == enc.comp_algo)
      enc.compressor = std::shared_ptr<compressor_c>(new zlib_compressor_c());

    else if (mtx::included_in(enc.comp_algo, 1u, 2u)) {
      auto algorithm = 1u == enc.comp_algo ? "bzlib" : "lzo1x";
      mxwarn(boost::format(Y("Track %1% was compressed with the algorithm '%2%' which is not supported anymore.\n")) % tid % algorithm);
      ok = false;
      break;

    } else if (3 == enc.comp_algo) {
      enc.compressor = std::shared_ptr<compressor_c>(new header_removal_compressor_c);
      std::static_pointer_cast<header_removal_compressor_c>(enc.compressor)->set_bytes(enc.comp_settings);

    } else {
      mxwarn(boost::format(Y("Track %1% has been compressed with an unknown/unsupported compression algorithm (%2%).\n")) % tid % enc.comp_algo);
      ok = false;
      break;
    }

    encodings.push_back(enc);
  }

  brng::stable_sort(encodings, [](kax_content_encoding_t const &a, kax_content_encoding_t const &b) { return a.order < b.order; });

  return ok;
}
Exemplo n.º 19
0
void
timecode_factory_v1_c::parse(mm_io_c &in) {
  std::string line;
  timecode_range_c t;
  std::vector<timecode_range_c>::iterator iit;
  std::vector<timecode_range_c>::const_iterator pit;

  int line_no = 1;
  do {
    if (!in.getline2(line))
      mxerror(boost::format(Y("The timecode file '%1%' does not contain a valid 'Assume' line with the default number of frames per second.\n")) % m_file_name);
    line_no++;
    strip(line);
    if (!line.empty() && ('#' != line[0]))
      break;
  } while (true);

  if (!ba::istarts_with(line, "assume "))
    mxerror(boost::format(Y("The timecode file '%1%' does not contain a valid 'Assume' line with the default number of frames per second.\n")) % m_file_name);

  line.erase(0, 6);
  strip(line);

  if (!parse_double(line.c_str(), m_default_fps))
    mxerror(boost::format(Y("The timecode file '%1%' does not contain a valid 'Assume' line with the default number of frames per second.\n")) % m_file_name);

  while (in.getline2(line)) {
    line_no++;
    strip(line, true);
    if (line.empty() || ('#' == line[0]))
      continue;

    std::vector<std::string> parts = split(line, ",", 3);
    if (   (parts.size() != 3)
        || !parse_uint(parts[0], t.start_frame)
        || !parse_uint(parts[1], t.end_frame)
        || !parse_double(parts[2], t.fps)) {
      mxwarn(boost::format(Y("Line %1% of the timecode file '%2%' could not be parsed.\n")) % line_no % m_file_name);
      continue;
    }

    if ((t.fps <= 0) || (t.end_frame < t.start_frame)) {
      mxwarn(boost::format(Y("Line %1% of the timecode file '%2%' contains inconsistent data (e.g. the start frame number is bigger than the end frame "
                             "number, or some values are smaller than zero).\n")) % line_no % m_file_name);
      continue;
    }

    m_ranges.push_back(t);
  }

  mxverb(3, boost::format("ext_timecodes: Version 1, default fps %1%, %2% entries.\n") % m_default_fps % m_ranges.size());

  if (m_ranges.size() == 0)
    t.start_frame = 0;
  else {
    std::sort(m_ranges.begin(), m_ranges.end());
    bool done;
    do {
      done = true;
      iit  = m_ranges.begin();
      size_t i;
      for (i = 0; i < (m_ranges.size() - 1); i++) {
        iit++;
        if (m_ranges[i].end_frame < (m_ranges[i + 1].start_frame - 1)) {
          t.start_frame = m_ranges[i].end_frame + 1;
          t.end_frame = m_ranges[i + 1].start_frame - 1;
          t.fps = m_default_fps;
          m_ranges.insert(iit, t);
          done = false;
          break;
        }
      }
    } while (!done);
    if (m_ranges[0].start_frame != 0) {
      t.start_frame = 0;
      t.end_frame = m_ranges[0].start_frame - 1;
      t.fps = m_default_fps;
      m_ranges.insert(m_ranges.begin(), t);
    }
    t.start_frame = m_ranges[m_ranges.size() - 1].end_frame + 1;
  }

  t.end_frame = 0xfffffffffffffffll;
  t.fps       = m_default_fps;
  m_ranges.push_back(t);

  m_ranges[0].base_timecode = 0.0;
  pit = m_ranges.begin();
  for (iit = m_ranges.begin() + 1; iit < m_ranges.end(); iit++, pit++)
    iit->base_timecode = pit->base_timecode + ((double)pit->end_frame - (double)pit->start_frame + 1) * 1000000000.0 / pit->fps;

  for (iit = m_ranges.begin(); iit < m_ranges.end(); iit++)
    mxverb(3, boost::format("ranges: entry %1% -> %2% at %3% with %4%\n") % iit->start_frame % iit->end_frame % iit->fps % iit->base_timecode);
}
Exemplo n.º 20
0
void
mxwarn_fn(const std::string &file_name,
          const std::string &warning) {
  mxwarn(boost::format(Y("'%1%': %2%")) % file_name % warning);
}
Exemplo n.º 21
0
void
kax_file_c::report(std::string const &message) {
  if (m_reporting_enabled)
    mxwarn(message);
}
Exemplo n.º 22
0
void
kax_file_c::report(boost::format const &message) {
  if (m_reporting_enabled)
    mxwarn(message);
}
Exemplo n.º 23
0
void
mxwarn_tid(const std::string &file_name,
           int64_t track_id,
           const std::string &warning) {
  mxwarn(boost::format(Y("'%1%' track %2%: %3%")) % file_name % track_id % warning);
}
Exemplo n.º 24
0
void
xtr_ssa_c::handle_frame(xtr_frame_t &f) {
  if (0 > f.duration) {
    mxwarn(boost::format(Y("Subtitle track %1% is missing some duration elements. "
                           "Please check the resulting SSA/ASS file for entries that have the same start and end time.\n"))
           % m_tid);
    m_warning_printed = true;
  }

  int64_t start =         f.timecode / 1000000;
  int64_t end   = start + f.duration / 1000000;

  char *s       = (char *)safemalloc(f.frame->get_size() + 1);
  memory_c af_s((unsigned char *)s, 0, true);
  memcpy(s, f.frame->get_buffer(), f.frame->get_size());
  s[f.frame->get_size()] = 0;

  // Split the line into the fields.
  // Specs say that the following fields are to put into the block:
  // 0: ReadOrder, 1: Layer, 2: Style, 3: Name, 4: MarginL, 5: MarginR,
  // 6: MarginV, 7: Effect, 8: Text
  std::vector<std::string> fields = split(s, ",", 9);
  if (9 < fields.size()) {
    mxwarn(boost::format(Y("Invalid format for a SSA line ('%1%') at timecode %2%: Too many fields found (%3% instead of 9). This entry will be skipped.\n"))
           % s % format_timecode(f.timecode * 1000000, 3) % fields.size());
    return;
  }

  while (9 != fields.size())
    fields.push_back("");

  // Convert the ReadOrder entry so that we can re-order the entries later.
  int num;
  if (!parse_number(fields[0], num)) {
    mxwarn(boost::format(Y("Invalid format for a SSA line ('%1%') at timecode %2%: The first field is not an integer. This entry will be skipped.\n"))
           % s % format_timecode(f.timecode * 1000000, 3));
    return;
  }

  // Reconstruct the 'original' line. It'll look like this for SSA:
  //   Marked, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
  // and for ASS:
  //   Layer, Start, End, Style, Actor, MarginL, MarginR, MarginV, Effect, Text

  // Problem is that the CodecPrivate may contain a Format: line
  // that defines a different layout. So let's account for that.

  std::string line = "Dialogue: ";
  size_t i;
  for (i = 0; i < m_ssa_format.size(); i++) {
    std::string format = m_ssa_format[i];

    if (balg::iequals(format, "actor"))
      format = "name";

    if (0 < i)
      line += ",";

    if (format == "marked")
      line += "Marked=0";

    else if (format == "start")
      line += (boost::format("%1%:%|2$02d|:%|3$02d|.%|4$02d|")
               % (start / 1000 / 60 / 60) % ((start / 1000 / 60) % 60) % ((start / 1000) % 60) % ((start % 1000) / 10)).str();

    else if (format == "end")
      line += (boost::format("%1%:%|2$02d|:%|3$02d|.%|4$02d|")
               % (end   / 1000 / 60 / 60) % ((end   / 1000 / 60) % 60) % ((end   / 1000) % 60) % ((end   % 1000) / 10)).str();

    else {
      int k;
      for (k = 0; ms_kax_ssa_fields[k]; ++k)
        if (format == ms_kax_ssa_fields[k]) {
          line += fields[k];
          break;
        }
    }
  }

  // Do the charset conversion.
  line  = m_conv->native(line);
  line += "\n";

  // Now store that entry.
  m_lines.push_back(ssa_line_c(line, num));
}