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