From bfe0e2c4a81da574a903b57ab43f540688e797d3 Mon Sep 17 00:00:00 2001 From: Moritz Bunkus Date: Wed, 25 Aug 2021 14:19:31 +0200 Subject: [PATCH] AVC/HEVC ES: move more code to common base class --- src/common/avc/es_parser.cpp | 8 ++++ src/common/avc/es_parser.h | 2 +- src/common/avc_hevc/es_parser.cpp | 71 +++++++++++++++++++++++++++++ src/common/avc_hevc/es_parser.h | 10 ++++- src/common/hevc/es_parser.cpp | 75 +++---------------------------- src/common/hevc/es_parser.h | 8 +--- src/extract/xtr_hevc.cpp | 2 +- src/output/p_hevc.cpp | 2 +- src/output/p_hevc_es.cpp | 2 +- 9 files changed, 98 insertions(+), 82 deletions(-) diff --git a/src/common/avc/es_parser.cpp b/src/common/avc/es_parser.cpp index 8140477dc..2d179afc7 100644 --- a/src/common/avc/es_parser.cpp +++ b/src/common/avc/es_parser.cpp @@ -21,6 +21,7 @@ #include "common/endian.h" #include "common/frame_timing.h" #include "common/hacks.h" +#include "common/list_utils.h" #include "common/mpeg.h" #include "common/strings/formatting.h" @@ -77,6 +78,13 @@ es_parser_c::flush_incomplete_frame() { m_have_incomplete_frame = false; } +bool +es_parser_c::does_nalu_get_included_in_extra_data(memory_c const &nalu) + const { + auto nalu_type = (nalu.get_buffer())[0] & 0x1f; + return mtx::included_in(nalu_type, NALU_TYPE_SEQ_PARAM, NALU_TYPE_PIC_PARAM); +} + void es_parser_c::add_sps_and_pps_to_extra_data() { mxdebug_if(m_debug_sps_pps_changes, fmt::format("avc: adding all SPS & PPS before key frame due to changes from AVCC\n")); diff --git a/src/common/avc/es_parser.h b/src/common/avc/es_parser.h index 0431cda6a..ba33cecf4 100644 --- a/src/common/avc/es_parser.h +++ b/src/common/avc/es_parser.h @@ -89,9 +89,9 @@ protected: int64_t duration_for_impl(unsigned int sps, bool field_pic_flag) const; virtual void calculate_frame_order() override; + virtual bool does_nalu_get_included_in_extra_data(memory_c const &nalu) const override; virtual void init_nalu_names() const override; - }; } diff --git a/src/common/avc_hevc/es_parser.cpp b/src/common/avc_hevc/es_parser.cpp index 998b9865e..76e521840 100644 --- a/src/common/avc_hevc/es_parser.cpp +++ b/src/common/avc_hevc/es_parser.cpp @@ -51,6 +51,11 @@ es_parser_c::set_next_i_slice_is_key_frame() { m_recovery_point_valid = true; } +void +es_parser_c::set_normalize_parameter_sets(bool normalize) { + m_normalize_parameter_sets = normalize; +} + void es_parser_c::maybe_dump_raw_data(unsigned char const *buffer, std::size_t size) { @@ -254,6 +259,72 @@ es_parser_c::add_nalu_to_extra_data(memory_cptr const &nalu, container.push_back(nalu); } +void +es_parser_c::add_nalu_to_pending_frame_data(memory_cptr const &nalu) { + nalu->take_ownership(); + m_pending_frame_data.emplace_back(nalu); +} + +void +es_parser_c::add_parameter_sets_to_extra_data() { + std::unordered_map is_in_extra_data; + + for (auto const &data : m_extra_data_pre) { + if (does_nalu_get_included_in_extra_data(*data)) + return; + + is_in_extra_data[mtx::checksum::calculate_as_uint(mtx::checksum::algorithm_e::adler32, *data)] = true; + } + + auto old_extra_data = std::move(m_extra_data_pre); + + m_extra_data_pre.clear(); + m_extra_data_pre.reserve(m_vps_list.size() + m_sps_list.size() + m_pps_list.size() + old_extra_data.size() + m_extra_data_initial.size()); + + auto inserter = std::back_inserter(m_extra_data_pre); + + std::copy(m_vps_list.begin(), m_vps_list.end(), inserter); + std::copy(m_sps_list.begin(), m_sps_list.end(), inserter); + std::copy(m_pps_list.begin(), m_pps_list.end(), inserter); + + for (auto const &data : m_extra_data_initial) + if (!is_in_extra_data[mtx::checksum::calculate_as_uint(mtx::checksum::algorithm_e::adler32, *data)]) + inserter = data; + + std::copy(old_extra_data.begin(), old_extra_data.end(), inserter); + + m_extra_data_initial.clear(); +} + +void +es_parser_c::build_frame_data() { + if (m_incomplete_frame.m_keyframe && m_normalize_parameter_sets) + add_parameter_sets_to_extra_data(); + + auto all_nalus = std::move(m_extra_data_pre); + all_nalus.reserve(all_nalus.size() + m_pending_frame_data.size()); + + std::copy(m_pending_frame_data.begin(), m_pending_frame_data.end(), std::back_inserter(all_nalus)); + + m_extra_data_pre.clear(); + m_pending_frame_data.clear(); + + auto final_size = 0; + + for (auto const &nalu : all_nalus) + final_size += m_nalu_size_length + nalu->get_size(); + + m_incomplete_frame.m_data = memory_c::alloc(final_size); + auto dest = m_incomplete_frame.m_data->get_buffer(); + + for (auto const &nalu : all_nalus) { + mtx::mpeg::write_nalu_size(dest, nalu->get_size(), m_nalu_size_length); + std::memcpy(dest + m_nalu_size_length, nalu->get_buffer(), nalu->get_size()); + + dest += m_nalu_size_length + nalu->get_size(); + } +} + void es_parser_c::flush_unhandled_nalus() { for (auto const &nalu_with_pos : m_unhandled_nalus) diff --git a/src/common/avc_hevc/es_parser.h b/src/common/avc_hevc/es_parser.h index fae851128..b90b92a62 100644 --- a/src/common/avc_hevc/es_parser.h +++ b/src/common/avc_hevc/es_parser.h @@ -56,7 +56,7 @@ protected: std::deque> m_unhandled_nalus; - bool m_first_cleanup{true}, m_simple_picture_order{}, m_discard_actual_frames{}; + bool m_first_cleanup{true}, m_simple_picture_order{}, m_discard_actual_frames{}, m_normalize_parameter_sets{}; std::string const m_debug_type; debugging_option_c m_debug_keyframe_detection, m_debug_nalu_types, m_debug_timestamps, m_debug_sps_info, m_debug_statistics; @@ -96,6 +96,8 @@ public: void set_next_i_slice_is_key_frame(); + void set_normalize_parameter_sets(bool normalize = true); + void set_nalu_size_length(int nalu_size_length); int get_nalu_size_length() const; @@ -149,6 +151,12 @@ public: protected: void add_nalu_to_extra_data(memory_cptr const &nalu, extra_data_position_e position = extra_data_position_e::pre); + void add_nalu_to_pending_frame_data(memory_cptr const &nalu); + void add_parameter_sets_to_extra_data(); + void build_frame_data(); + + virtual bool does_nalu_get_included_in_extra_data(memory_c const &nalu) const = 0; + void debug_dump_statistics() const; public: diff --git a/src/common/hevc/es_parser.cpp b/src/common/hevc/es_parser.cpp index 5f5e0d396..51b1e967d 100644 --- a/src/common/hevc/es_parser.cpp +++ b/src/common/hevc/es_parser.cpp @@ -49,11 +49,6 @@ es_parser_c::headers_parsed() && (m_sps_info_list.front().get_height() > 0); } -void -es_parser_c::normalize_parameter_sets(bool normalize) { - m_normalize_parameter_sets = normalize; -} - void es_parser_c::flush() { if (m_unparsed_buffer && (5 <= m_unparsed_buffer->get_size())) { @@ -93,42 +88,11 @@ es_parser_c::flush_incomplete_frame() { m_incomplete_frame.clear(); } -void -es_parser_c::add_parameter_sets_to_extra_data() { - std::unordered_map is_in_extra_data; - - for (auto const &data : m_extra_data_pre) { - auto nalu_type = (data->get_buffer()[0] >> 1) & 0x3f; - if (mtx::included_in(nalu_type, NALU_TYPE_VIDEO_PARAM, NALU_TYPE_SEQ_PARAM, NALU_TYPE_PIC_PARAM)) - return; - - is_in_extra_data[mtx::checksum::calculate_as_uint(mtx::checksum::algorithm_e::adler32, *data)] = true; - } - - auto old_extra_data = std::move(m_extra_data_pre); - - m_extra_data_pre.clear(); - m_extra_data_pre.reserve(m_vps_list.size() + m_sps_list.size() + m_pps_list.size() + old_extra_data.size() + m_extra_data_initial.size()); - - auto inserter = std::back_inserter(m_extra_data_pre); - - std::copy(m_vps_list.begin(), m_vps_list.end(), inserter); - std::copy(m_sps_list.begin(), m_sps_list.end(), inserter); - std::copy(m_pps_list.begin(), m_pps_list.end(), inserter); - - for (auto const &data : m_extra_data_initial) - if (!is_in_extra_data[mtx::checksum::calculate_as_uint(mtx::checksum::algorithm_e::adler32, *data)]) - inserter = data; - - std::copy(old_extra_data.begin(), old_extra_data.end(), inserter); - - m_extra_data_initial.clear(); -} - -void -es_parser_c::add_nalu_to_pending_frame_data(memory_cptr const &nalu) { - nalu->take_ownership(); - m_pending_frame_data.emplace_back(nalu); +bool +es_parser_c::does_nalu_get_included_in_extra_data(memory_c const &nalu) + const { + auto nalu_type = (nalu.get_buffer()[0] >> 1) & 0x3f; + return mtx::included_in(nalu_type, NALU_TYPE_VIDEO_PARAM, NALU_TYPE_SEQ_PARAM, NALU_TYPE_PIC_PARAM); } void @@ -553,35 +517,6 @@ es_parser_c::parse_slice(memory_cptr const &nalu, } } -void -es_parser_c::build_frame_data() { - if (m_incomplete_frame.m_keyframe && m_normalize_parameter_sets) - add_parameter_sets_to_extra_data(); - - auto all_nalus = std::move(m_extra_data_pre); - all_nalus.reserve(all_nalus.size() + m_pending_frame_data.size()); - - std::copy(m_pending_frame_data.begin(), m_pending_frame_data.end(), std::back_inserter(all_nalus)); - - m_extra_data_pre.clear(); - m_pending_frame_data.clear(); - - auto final_size = 0; - - for (auto const &nalu : all_nalus) - final_size += m_nalu_size_length + nalu->get_size(); - - m_incomplete_frame.m_data = memory_c::alloc(final_size); - auto dest = m_incomplete_frame.m_data->get_buffer(); - - for (auto const &nalu : all_nalus) { - mtx::mpeg::write_nalu_size(dest, nalu->get_size(), m_nalu_size_length); - std::memcpy(dest + m_nalu_size_length, nalu->get_buffer(), nalu->get_size()); - - dest += m_nalu_size_length + nalu->get_size(); - } -} - int64_t es_parser_c::duration_for(mtx::avc_hevc::slice_info_t const &si) const { diff --git a/src/common/hevc/es_parser.h b/src/common/hevc/es_parser.h index 7329ddb31..2accc308d 100644 --- a/src/common/hevc/es_parser.h +++ b/src/common/hevc/es_parser.h @@ -35,8 +35,6 @@ protected: mtx::dovi::dovi_rpu_data_header_t m_dovi_rpu_data_header; - bool m_normalize_parameter_sets{}; - debugging_option_c m_debug_parameter_sets{"hevc_parser|hevc_parameter_sets"}, m_debug_frame_order{"hevc_parser|hevc_frame_order"}; public: @@ -62,8 +60,6 @@ public: bool headers_parsed() const; - void normalize_parameter_sets(bool normalize = true); - virtual int64_t duration_for(mtx::avc_hevc::slice_info_t const &si) const override; bool has_dovi_rpu_header() const { @@ -90,9 +86,7 @@ protected: void handle_slice_nalu(memory_cptr const &nalu, uint64_t nalu_pos); void flush_incomplete_frame(); virtual void calculate_frame_order() override; - void add_parameter_sets_to_extra_data(); - void add_nalu_to_pending_frame_data(memory_cptr const &nalu); - void build_frame_data(); + virtual bool does_nalu_get_included_in_extra_data(memory_c const &nalu) const override; virtual void init_nalu_names() const override; }; diff --git a/src/extract/xtr_hevc.cpp b/src/extract/xtr_hevc.cpp index 2151c8d27..1e0594bb3 100644 --- a/src/extract/xtr_hevc.cpp +++ b/src/extract/xtr_hevc.cpp @@ -38,7 +38,7 @@ xtr_hevc_c::create_file(xtr_base_c *master, if (m_decoded_codec_private->get_size() < 23) mxerror(fmt::format(Y("Track {0} CodecPrivate is too small.\n"), m_tid)); - m_parser.normalize_parameter_sets(m_normalize_parameter_sets); + m_parser.set_normalize_parameter_sets(m_normalize_parameter_sets); m_parser.set_configuration_record(m_decoded_codec_private); m_nal_size_size = 1 + (m_decoded_codec_private->get_buffer()[21] & 3); diff --git a/src/output/p_hevc.cpp b/src/output/p_hevc.cpp index 004b5e1ed..384105dfb 100644 --- a/src/output/p_hevc.cpp +++ b/src/output/p_hevc.cpp @@ -48,7 +48,7 @@ hevc_video_packetizer_c(generic_reader_c *p_reader, set_codec_private(m_ti.m_private_data); - p.parser->normalize_parameter_sets(!mtx::hacks::is_engaged(mtx::hacks::DONT_NORMALIZE_PARAMETER_SETS)); + p.parser->set_normalize_parameter_sets(!mtx::hacks::is_engaged(mtx::hacks::DONT_NORMALIZE_PARAMETER_SETS)); p.parser->set_configuration_record(m_hcodec_private); } diff --git a/src/output/p_hevc_es.cpp b/src/output/p_hevc_es.cpp index bc8fc6ebc..4f7369e07 100644 --- a/src/output/p_hevc_es.cpp +++ b/src/output/p_hevc_es.cpp @@ -25,7 +25,7 @@ hevc_es_video_packetizer_c::hevc_es_video_packetizer_c(generic_reader_c *p_reade { set_codec_id(MKV_V_MPEGH_HEVC); - m_parser.normalize_parameter_sets(!mtx::hacks::is_engaged(mtx::hacks::DONT_NORMALIZE_PARAMETER_SETS)); + m_parser.set_normalize_parameter_sets(!mtx::hacks::is_engaged(mtx::hacks::DONT_NORMALIZE_PARAMETER_SETS)); } connection_result_e