void mpeg4_p10_video_packetizer_c::set_headers() { static auto s_debug_fix_bistream_timing_info = debugging_option_c{"fix_bitstream_timing_info"}; if (m_ti.m_private_data && m_ti.m_private_data->get_size()) extract_aspect_ratio(); if (m_ti.m_private_data && m_ti.m_private_data->get_size() && m_ti.m_fix_bitstream_frame_rate) { int64_t l_track_default_duration = -1; if (m_timestamp_factory) l_track_default_duration = m_timestamp_factory->get_default_duration(-1); if ((-1 == l_track_default_duration) && m_default_duration_forced) l_track_default_duration = m_htrack_default_duration; if ((-1 == l_track_default_duration) && (0.0 < m_fps)) l_track_default_duration = static_cast<int64_t>(1000000000.0 / m_fps); if (-1 != l_track_default_duration) l_track_default_duration /= 2; mxdebug_if(s_debug_fix_bistream_timing_info, boost::format("fix_bitstream_timing_info: factory default_duration %1% default_duration_forced? %2% htrack_default_duration %3% fps %4% l_track_default_duration %5%\n") % (m_timestamp_factory ? m_timestamp_factory->get_default_duration(-1) : -2) % m_default_duration_forced % m_htrack_default_duration % m_fps % l_track_default_duration); set_codec_private(mpeg4::p10::fix_sps_fps(m_ti.m_private_data, l_track_default_duration)); } generic_video_packetizer_c::set_headers(); }
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(); }
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; }
mpeg4_p10_video_packetizer_c:: mpeg4_p10_video_packetizer_c(generic_reader_c *p_reader, track_info_c &p_ti, double fps, int width, int height) : generic_video_packetizer_c{p_reader, p_ti, MKV_V_MPEG4_AVC, fps, width, height} , m_nalu_size_len_src{} , m_nalu_size_len_dst{} , m_max_nalu_size{} { m_relaxed_timecode_checking = true; setup_nalu_size_len_change(); set_codec_private(m_ti.m_private_data); }
void mpeg4_p10_video_packetizer_c::extract_aspect_ratio() { auto result = mpeg4::p10::extract_par(m_ti.m_private_data); set_codec_private(result.new_avcc); if (!result.is_valid() || display_dimensions_or_aspect_ratio_set()) return; auto par = static_cast<double>(result.numerator) / static_cast<double>(result.denominator); set_video_display_dimensions(1 <= par ? std::llround(m_width * par) : m_width, 1 <= par ? m_height : std::llround(m_height / par), OPTION_SOURCE_BITSTREAM); mxinfo_tid(m_ti.m_fname, m_ti.m_id, boost::format(Y("Extracted the aspect ratio information from the MPEG-4 layer 10 (AVC) video data and set the display dimensions to %1%/%2%.\n")) % m_ti.m_display_width % m_ti.m_display_height); }
void mpeg4_p10_video_packetizer_c::setup_nalu_size_len_change() { if (!m_ti.m_private_data || (5 > m_ti.m_private_data->get_size())) return; auto private_data = m_ti.m_private_data->get_buffer(); m_nalu_size_len_src = (private_data[4] & 0x03) + 1; m_nalu_size_len_dst = m_nalu_size_len_src; if (!m_ti.m_nalu_size_length || (m_ti.m_nalu_size_length == m_nalu_size_len_src)) return; m_nalu_size_len_dst = m_ti.m_nalu_size_length; private_data[4] = (private_data[4] & 0xfc) | (m_nalu_size_len_dst - 1); m_max_nalu_size = 1ll << (8 * m_nalu_size_len_dst); set_codec_private(m_ti.m_private_data); mxverb(2, boost::format("mpeg4_p10: Adjusting NALU size length from %1% to %2%\n") % m_nalu_size_len_src % m_nalu_size_len_dst); }
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 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(); } }