void
mpeg4_p2_video_packetizer_c::extract_aspect_ratio(const unsigned char *buffer,
        int size) {
    if (m_aspect_ratio_extracted)
        return;

    if ((0 != m_connected_to) || display_dimensions_or_aspect_ratio_set()) {
        m_aspect_ratio_extracted = true;
        return;
    }

    uint32_t num, den;
    if (mpeg4::p2::extract_par(buffer, size, num, den)) {
        m_aspect_ratio_extracted = true;
        set_video_aspect_ratio((double)m_hvideo_pixel_width / (double)m_hvideo_pixel_height * (double)num / (double)den, false, OPTION_SOURCE_BITSTREAM);

        generic_packetizer_c::set_headers();
        rerender_track_headers();
        mxinfo_tid(m_ti.m_fname, m_ti.m_id,
                   boost::format(Y("Extracted the aspect ratio information from the MPEG4 layer 2 video data and set the display dimensions to %1%/%2%.\n"))
                   % m_hvideo_display_width % m_hvideo_display_height);

    } else if (50 <= m_frames_output)
        m_aspect_ratio_extracted = true;
}
Exemple #2
0
void
mpeg1_2_video_packetizer_c::create_private_data() {
  MPEGChunk *raw_seq_hdr = m_parser.GetRealSequenceHeader();
  if (NULL != raw_seq_hdr) {
    set_codec_private(raw_seq_hdr->GetPointer(), raw_seq_hdr->GetSize());
    rerender_track_headers();
  }
}
void
mpeg4_p2_video_packetizer_c::extract_config_data(packet_cptr &packet) {
    if (m_ti.m_private_data)
        return;

    m_ti.m_private_data = memory_cptr{mpeg4::p2::parse_config_data(packet->data->get_buffer(), packet->data->get_size(), m_config_data)};
    if (!m_ti.m_private_data)
        mxerror_tid(m_ti.m_fname, m_ti.m_id, Y("Could not find the codec configuration data in the first MPEG-4 part 2 video frame. This track cannot be stored in native mode.\n"));

    fix_codec_string();
    set_codec_private(m_ti.m_private_data);
    rerender_track_headers();
}
Exemple #4
0
void
mpeg1_2_video_packetizer_c::extract_fps(const unsigned char *buffer,
                                        int size) {
  int idx = mpeg1_2::extract_fps_idx(buffer, size);
  if (0 > idx)
    return;

  m_fps = mpeg1_2::get_fps(idx);
  if (0 < m_fps) {
    set_track_default_duration((int64_t)(1000000000.0 / m_fps));
    rerender_track_headers();
  } else
    m_fps = 0.0;
}
Exemple #5
0
bool
mpeg1_2_video_packetizer_c::put_sequence_headers_into_codec_state(packet_cptr packet) {
  unsigned char *buf  = packet->data->get_buffer();
  size_t  pos         = 4;
  size_t  size        = packet->data->get_size();
  unsigned int marker = get_uint32_be(buf);

  while ((pos < size) && (MPEGVIDEO_SEQUENCE_START_CODE != marker)) {
    marker <<= 8;
    marker  |= buf[pos];
    ++pos;
  }

  if ((MPEGVIDEO_SEQUENCE_START_CODE != marker) || ((pos + 4) >= size))
    return false;

  size_t start  = pos - 4;
  marker        = get_uint32_be(&buf[pos]);
  pos          += 4;

  while ((pos < size) && ((MPEGVIDEO_EXT_START_CODE == marker) || (0x00000100 != (marker & 0xffffff00)))) {
    marker <<= 8;
    marker  |= buf[pos];
    ++pos;
  }

  if (pos >= size)
    return false;

  pos            -= 4;
  size_t sh_size  = pos - start;

  if (NULL == m_hcodec_private) {
    set_codec_private(&buf[start], sh_size);
    rerender_track_headers();
  }

  if (!m_seq_hdr.is_set() || (sh_size != m_seq_hdr->get_size()) || memcmp(&buf[start], m_seq_hdr->get_buffer(), sh_size)) {
    m_seq_hdr           = clone_memory(&buf[start], sh_size);
    packet->codec_state = clone_memory(&buf[start], sh_size);
  }

  if (hack_engaged(ENGAGE_USE_CODEC_STATE_ONLY)) {
    memmove(&buf[start], &buf[pos], size - pos);
    packet->data->set_size(size - sh_size);
  }

  return true;
}
Exemple #6
0
void
mpeg1_2_video_packetizer_c::extract_aspect_ratio(const unsigned char *buffer,
                                                 int size) {
  float ar;

  if (display_dimensions_or_aspect_ratio_set())
    return;

  if (!mpeg1_2::extract_ar(buffer, size, ar))
    return;

  set_video_display_dimensions((0 >= ar) || (1 == ar) ? m_width : (int)(m_height * ar), m_height, PARAMETER_SOURCE_BITSTREAM);

  rerender_track_headers();
  m_aspect_ratio_extracted = true;
}
void
mpeg4_p2_video_packetizer_c::extract_size(const unsigned char *buffer,
        int size) {
    if (m_size_extracted)
        return;

    if (0 != m_connected_to) {
        m_size_extracted = true;
        return;
    }

    uint32_t xtr_width, xtr_height;

    if (mpeg4::p2::extract_size(buffer, size, xtr_width, xtr_height)) {
        m_size_extracted = true;

        if (!m_reader->m_appending && ((xtr_width != static_cast<uint32_t>(m_hvideo_pixel_width)) || (xtr_height != static_cast<uint32_t>(m_hvideo_pixel_height)))) {
            set_video_pixel_width(xtr_width);
            set_video_pixel_height(xtr_height);

            if (!m_output_is_native && m_ti.m_private_data && (sizeof(alBITMAPINFOHEADER) <= m_ti.m_private_data->get_size())) {
                auto bih = reinterpret_cast<alBITMAPINFOHEADER *>(m_ti.m_private_data->get_buffer());
                put_uint32_le(&bih->bi_width,  xtr_width);
                put_uint32_le(&bih->bi_height, xtr_height);
                set_codec_private(m_ti.m_private_data);
            }

            m_hvideo_display_width  = -1;
            m_hvideo_display_height = -1;

            generic_packetizer_c::set_headers();
            rerender_track_headers();

            mxinfo_tid(m_ti.m_fname, m_ti.m_id,
                       boost::format(Y("The extracted values for video width and height from the MPEG4 layer 2 video data bitstream differ from what the values "
                                       "in the source container. The ones from the video data bitstream (%1%x%2%) will be used.\n")) % xtr_width % xtr_height);
        }

    } else if (50 <= m_frames_output)
        m_aspect_ratio_extracted = true;
}
void
generic_packetizer_c::add_packet2(packet_cptr pack) {
  if (pack->has_discard_padding())
    set_required_matroska_version(4);

  pack->timecode   = ADJUST_TIMECODE(pack->timecode);
  if (pack->has_bref())
    pack->bref     = ADJUST_TIMECODE(pack->bref);
  if (pack->has_fref())
    pack->fref     = ADJUST_TIMECODE(pack->fref);
  if (pack->has_duration()) {
    pack->duration = static_cast<int64_t>(pack->duration * m_ti.m_tcsync.numerator / m_ti.m_tcsync.denominator);
    if (pack->has_discard_padding())
      pack->duration -= std::min(pack->duration, pack->discard_padding.to_ns());
  }

  if ((2 > m_htrack_min_cache) && pack->has_fref()) {
    set_track_min_cache(2);
    rerender_track_headers();

  } else if ((1 > m_htrack_min_cache) && pack->has_bref()) {
    set_track_min_cache(1);
    rerender_track_headers();
  }

  if (0 > pack->timecode)
    return;

  // 'timecode < safety_last_timecode' may only occur for B frames. In this
  // case we have the coding order, e.g. IPB1B2 and the timecodes
  // I: 0, P: 120, B1: 40, B2: 80.
  if (!m_relaxed_timecode_checking && (pack->timecode < m_safety_last_timecode) && (0 > pack->fref) && hack_engaged(ENGAGE_ENABLE_TIMECODE_WARNING)) {
    if (track_audio == m_htrack_type) {
      int64_t needed_timecode_offset  = m_safety_last_timecode + m_safety_last_duration - pack->timecode;
      m_correction_timecode_offset   += needed_timecode_offset;
      pack->timecode                 += needed_timecode_offset;
      if (pack->has_bref())
        pack->bref += needed_timecode_offset;
      if (pack->has_fref())
        pack->fref += needed_timecode_offset;

      mxwarn_tid(m_ti.m_fname, m_ti.m_id,
                 boost::format(Y("The current packet's timecode is smaller than that of the previous packet. "
                                 "This usually means that the source file is a Matroska file that has not been created 100%% correctly. "
                                 "The timecodes of all packets will be adjusted by %1%ms in order not to lose any data. "
                                 "This may throw audio/video synchronization off, but that can be corrected with mkvmerge's \"--sync\" option. "
                                 "If you already use \"--sync\" and you still get this warning then do NOT worry -- this is normal. "
                                 "If this error happens more than once and you get this message more than once for a particular track "
                                 "then either is the source file badly mastered, or mkvmerge contains a bug. "
                                 "In this case you should contact the author Moritz Bunkus <*****@*****.**>.\n"))
                 % ((needed_timecode_offset + 500000) / 1000000));

    } else
      mxwarn_tid(m_ti.m_fname, m_ti.m_id,
                 boost::format("generic_packetizer_c::add_packet2: timecode < last_timecode (%1% < %2%). %3%\n")
                 % format_timestamp(pack->timecode) % format_timestamp(m_safety_last_timecode) % BUGMSG);
  }

  m_safety_last_timecode        = pack->timecode;
  m_safety_last_duration        = pack->duration;
  pack->timecode_before_factory = pack->timecode;

  m_packet_queue.push_back(pack);
  if (!m_timestamp_factory || (TFA_IMMEDIATE == m_timestamp_factory_application_mode))
    apply_factory_once(pack);
  else
    apply_factory();
}
Exemple #9
0
void
mpeg1_2_video_packetizer_c::remove_stuffing_bytes_and_handle_sequence_headers(packet_cptr packet) {
  mxdebug_if(m_debug_stuffing_removal, boost::format("Starting stuff removal, frame size %1%\n") % packet->data->get_size());

  auto buf              = packet->data->get_buffer();
  auto size             = packet->data->get_size();
  size_t pos            = 4;
  size_t start_code_pos = 0;
  size_t stuffing_start = 0;
  auto marker           = get_uint32_be(buf);
  uint32_t chunk_type   = 0;
  bool seq_hdr_found    = false;

  auto mid_remover      = [this, &stuffing_start, &pos, &size, &buf]() {
    if (!stuffing_start || (stuffing_start >= (pos - 4)))
      return;

    auto num_stuffing_bytes       = pos - 4 - stuffing_start;
    m_num_removed_stuffing_bytes += num_stuffing_bytes;

    ::memmove(&buf[stuffing_start], &buf[pos - 4], size - pos + 4);

    pos  -= num_stuffing_bytes;
    size -= num_stuffing_bytes;

    mxdebug_if(m_debug_stuffing_removal, boost::format("    Stuffing in the middle: %1%\n") % num_stuffing_bytes);
  };

  memory_cptr new_seq_hdr;
  auto seq_hdr_copier = [this, &chunk_type, &seq_hdr_found, &buf, &start_code_pos, &pos, &new_seq_hdr, &size](bool at_end) {
    if ((MPEGVIDEO_SEQUENCE_HEADER_START_CODE != chunk_type) && (MPEGVIDEO_EXT_START_CODE != chunk_type))
      return;

    if (MPEGVIDEO_SEQUENCE_HEADER_START_CODE == chunk_type)
      seq_hdr_found = true;

    else if (!seq_hdr_found)
      return;

    auto bytes_to_copy = at_end ? pos - start_code_pos : pos - 4 - start_code_pos;

    if (!new_seq_hdr)
      new_seq_hdr = memory_c::clone(&buf[start_code_pos], bytes_to_copy);

    else
      new_seq_hdr->add(&buf[start_code_pos], bytes_to_copy);

    if (!hack_engaged(ENGAGE_USE_CODEC_STATE_ONLY))
      return;

    memmove(&buf[start_code_pos], &buf[pos - 4], size - pos + 4);
    pos  -= bytes_to_copy;
    size -= bytes_to_copy;
  };

  while (pos < size) {
    if ((MPEGVIDEO_SLICE_START_CODE_LOWER <= marker) && (MPEGVIDEO_SLICE_START_CODE_UPPER >= marker)) {
      mxdebug_if(m_debug_stuffing_removal, boost::format("  Slice start code at %1%\n") % (pos - 4));

      mid_remover();
      seq_hdr_copier(false);

      chunk_type     = MPEGVIDEO_SLICE_START_CODE_LOWER;
      stuffing_start = 0;
      start_code_pos = pos - 4;

    } else if ((marker & 0xffffff00) == 0x00000100) {
      mxdebug_if(m_debug_stuffing_removal, boost::format("  Non-slice start code at %1%\n") % (pos - 4));

      mid_remover();
      seq_hdr_copier(false);

      chunk_type     = marker;
      stuffing_start = 0;
      start_code_pos = pos - 4;

    } else if ((MPEGVIDEO_SLICE_START_CODE_LOWER == chunk_type) && !stuffing_start && (marker == 0x00000000)) {
      mxdebug_if(m_debug_stuffing_removal, boost::format("    Start at %1%\n") % (pos - 3));

      stuffing_start = pos - 3;
    }

    marker <<= 8;
    marker  |= buf[pos];
    ++pos;
  }

  if ((marker & 0xffffff00) == 0x00000100) {
    seq_hdr_copier(false);
    mid_remover();

  } else if (stuffing_start && (stuffing_start < size)) {
    mxdebug_if(m_debug_stuffing_removal, boost::format("    Stuffing at the end: chunk_type 0x%|1$08x| stuffing_start %2% stuffing_size %3%\n") % chunk_type % stuffing_start % (stuffing_start ? size - stuffing_start : 0));

    m_num_removed_stuffing_bytes += size - stuffing_start;
    size                          = stuffing_start;
  }

  packet->data->set_size(size);

  if (!new_seq_hdr)
    return;

  if (!m_hcodec_private) {
    set_codec_private(new_seq_hdr);
    rerender_track_headers();
  }

  if (!m_seq_hdr || (*new_seq_hdr != *m_seq_hdr)) {
    m_seq_hdr           = new_seq_hdr;
    packet->codec_state = new_seq_hdr->clone();
  }
}