/work/vvdec/source/Lib/CommonLib/ParameterSetManager.h
Line | Count | Source |
1 | | /* ----------------------------------------------------------------------------- |
2 | | The copyright in this software is being made available under the Clear BSD |
3 | | License, included below. No patent rights, trademark rights and/or |
4 | | other Intellectual Property Rights other than the copyrights concerning |
5 | | the Software are granted under this license. |
6 | | |
7 | | The Clear BSD License |
8 | | |
9 | | Copyright (c) 2018-2026, Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. & The VVdeC Authors. |
10 | | All rights reserved. |
11 | | |
12 | | Redistribution and use in source and binary forms, with or without modification, |
13 | | are permitted (subject to the limitations in the disclaimer below) provided that |
14 | | the following conditions are met: |
15 | | |
16 | | * Redistributions of source code must retain the above copyright notice, |
17 | | this list of conditions and the following disclaimer. |
18 | | |
19 | | * Redistributions in binary form must reproduce the above copyright |
20 | | notice, this list of conditions and the following disclaimer in the |
21 | | documentation and/or other materials provided with the distribution. |
22 | | |
23 | | * Neither the name of the copyright holder nor the names of its |
24 | | contributors may be used to endorse or promote products derived from this |
25 | | software without specific prior written permission. |
26 | | |
27 | | NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY |
28 | | THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND |
29 | | CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
30 | | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A |
31 | | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR |
32 | | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
33 | | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
34 | | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
35 | | BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER |
36 | | IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
37 | | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
38 | | POSSIBILITY OF SUCH DAMAGE. |
39 | | |
40 | | |
41 | | ------------------------------------------------------------------------------------------- */ |
42 | | |
43 | | #pragma once |
44 | | |
45 | | #include "CommonDef.h" |
46 | | #include "Slice.h" |
47 | | |
48 | | #include <algorithm> |
49 | | #include <map> |
50 | | #include <vector> |
51 | | #include <array> |
52 | | |
53 | | namespace vvdec |
54 | | { |
55 | | |
56 | | template<class T, int MAX_ID> |
57 | | class ParameterSetMap |
58 | | { |
59 | | public: |
60 | | struct MapData |
61 | | { |
62 | | AlignedByteVec cNaluData; // Can be empty |
63 | | std::shared_ptr<T> parameterSet; |
64 | | bool bChanged = false; |
65 | | }; |
66 | | |
67 | | ~ParameterSetMap() |
68 | 3.82k | { |
69 | 3.82k | m_paramsetMap.clear(); |
70 | 3.82k | m_lastActiveParameterSet.reset(); |
71 | 3.82k | } vvdec::ParameterSetMap<vvdec::VPS, 16>::~ParameterSetMap() Line | Count | Source | 68 | 956 | { | 69 | 956 | m_paramsetMap.clear(); | 70 | 956 | m_lastActiveParameterSet.reset(); | 71 | 956 | } |
vvdec::ParameterSetMap<vvdec::APS, 64>::~ParameterSetMap() Line | Count | Source | 68 | 956 | { | 69 | 956 | m_paramsetMap.clear(); | 70 | 956 | m_lastActiveParameterSet.reset(); | 71 | 956 | } |
vvdec::ParameterSetMap<vvdec::PPS, 64>::~ParameterSetMap() Line | Count | Source | 68 | 956 | { | 69 | 956 | m_paramsetMap.clear(); | 70 | 956 | m_lastActiveParameterSet.reset(); | 71 | 956 | } |
vvdec::ParameterSetMap<vvdec::SPS, 16>::~ParameterSetMap() Line | Count | Source | 68 | 956 | { | 69 | 956 | m_paramsetMap.clear(); | 70 | 956 | m_lastActiveParameterSet.reset(); | 71 | 956 | } |
|
72 | | |
73 | | void storePS( int psId, T* ps, AlignedByteVec&& cNaluData ) |
74 | 29 | { |
75 | 29 | CHECK( psId >= MAX_ID, "Invalid PS id" ); |
76 | 29 | if( m_paramsetMap.find( psId ) != m_paramsetMap.end() ) |
77 | 0 | { |
78 | 0 | MapData& mapData = m_paramsetMap[psId]; |
79 | | |
80 | | // work out changed flag, also on the replaced one: a picture being parsed still uses it |
81 | 0 | mapData.parameterSet->m_changedFlag |= ( mapData.cNaluData != cNaluData ); |
82 | 0 | const bool changed = mapData.parameterSet->m_changedFlag; |
83 | | |
84 | | // Don't throw away identical parameter sets as VTM does: |
85 | | // The PPS can be identical to a previous one, but the SPS changed, so it needs to be interpreted differently. |
86 | | // |
87 | | // if( !mapData.parameterSet->m_changedFlag ) |
88 | | // { |
89 | | // // just keep the old one |
90 | | // delete ps; |
91 | | // return; |
92 | | // } |
93 | |
|
94 | 0 | if( find( m_activePsId.begin(), m_activePsId.end(), psId ) != m_activePsId.end() ) |
95 | 0 | { |
96 | 0 | std::swap( m_paramsetMap[psId].parameterSet, m_lastActiveParameterSet ); |
97 | 0 | } |
98 | 0 | m_paramsetMap[psId].cNaluData.clear(); |
99 | 0 | m_paramsetMap[psId].parameterSet.reset(ps); |
100 | 0 | ps->m_changedFlag = changed; |
101 | 0 | } |
102 | 29 | else |
103 | 29 | { |
104 | 29 | m_paramsetMap[psId].parameterSet.reset(ps); |
105 | 29 | ps->m_changedFlag = false; |
106 | 29 | } |
107 | | |
108 | 29 | if( !cNaluData.empty() ) |
109 | 29 | { |
110 | 29 | m_paramsetMap[psId].cNaluData = std::move( cNaluData ); |
111 | 29 | } |
112 | 0 | else |
113 | 0 | { |
114 | 0 | m_paramsetMap[psId].cNaluData.clear(); |
115 | 0 | } |
116 | 29 | } Unexecuted instantiation: vvdec::ParameterSetMap<vvdec::VPS, 16>::storePS(int, vvdec::VPS*, std::__1::vector<unsigned char, vvdec::AlignedAllocator<unsigned char> >&&) vvdec::ParameterSetMap<vvdec::SPS, 16>::storePS(int, vvdec::SPS*, std::__1::vector<unsigned char, vvdec::AlignedAllocator<unsigned char> >&&) Line | Count | Source | 74 | 13 | { | 75 | 13 | CHECK( psId >= MAX_ID, "Invalid PS id" ); | 76 | 13 | if( m_paramsetMap.find( psId ) != m_paramsetMap.end() ) | 77 | 0 | { | 78 | 0 | MapData& mapData = m_paramsetMap[psId]; | 79 | | | 80 | | // work out changed flag, also on the replaced one: a picture being parsed still uses it | 81 | 0 | mapData.parameterSet->m_changedFlag |= ( mapData.cNaluData != cNaluData ); | 82 | 0 | const bool changed = mapData.parameterSet->m_changedFlag; | 83 | | | 84 | | // Don't throw away identical parameter sets as VTM does: | 85 | | // The PPS can be identical to a previous one, but the SPS changed, so it needs to be interpreted differently. | 86 | | // | 87 | | // if( !mapData.parameterSet->m_changedFlag ) | 88 | | // { | 89 | | // // just keep the old one | 90 | | // delete ps; | 91 | | // return; | 92 | | // } | 93 | |
| 94 | 0 | if( find( m_activePsId.begin(), m_activePsId.end(), psId ) != m_activePsId.end() ) | 95 | 0 | { | 96 | 0 | std::swap( m_paramsetMap[psId].parameterSet, m_lastActiveParameterSet ); | 97 | 0 | } | 98 | 0 | m_paramsetMap[psId].cNaluData.clear(); | 99 | 0 | m_paramsetMap[psId].parameterSet.reset(ps); | 100 | 0 | ps->m_changedFlag = changed; | 101 | 0 | } | 102 | 13 | else | 103 | 13 | { | 104 | 13 | m_paramsetMap[psId].parameterSet.reset(ps); | 105 | 13 | ps->m_changedFlag = false; | 106 | 13 | } | 107 | | | 108 | 13 | if( !cNaluData.empty() ) | 109 | 13 | { | 110 | 13 | m_paramsetMap[psId].cNaluData = std::move( cNaluData ); | 111 | 13 | } | 112 | 0 | else | 113 | 0 | { | 114 | 0 | m_paramsetMap[psId].cNaluData.clear(); | 115 | 0 | } | 116 | 13 | } |
Unexecuted instantiation: vvdec::ParameterSetMap<vvdec::PPS, 64>::storePS(int, vvdec::PPS*, std::__1::vector<unsigned char, vvdec::AlignedAllocator<unsigned char> >&&) vvdec::ParameterSetMap<vvdec::APS, 64>::storePS(int, vvdec::APS*, std::__1::vector<unsigned char, vvdec::AlignedAllocator<unsigned char> >&&) Line | Count | Source | 74 | 16 | { | 75 | 16 | CHECK( psId >= MAX_ID, "Invalid PS id" ); | 76 | 16 | if( m_paramsetMap.find( psId ) != m_paramsetMap.end() ) | 77 | 0 | { | 78 | 0 | MapData& mapData = m_paramsetMap[psId]; | 79 | | | 80 | | // work out changed flag, also on the replaced one: a picture being parsed still uses it | 81 | 0 | mapData.parameterSet->m_changedFlag |= ( mapData.cNaluData != cNaluData ); | 82 | 0 | const bool changed = mapData.parameterSet->m_changedFlag; | 83 | | | 84 | | // Don't throw away identical parameter sets as VTM does: | 85 | | // The PPS can be identical to a previous one, but the SPS changed, so it needs to be interpreted differently. | 86 | | // | 87 | | // if( !mapData.parameterSet->m_changedFlag ) | 88 | | // { | 89 | | // // just keep the old one | 90 | | // delete ps; | 91 | | // return; | 92 | | // } | 93 | |
| 94 | 0 | if( find( m_activePsId.begin(), m_activePsId.end(), psId ) != m_activePsId.end() ) | 95 | 0 | { | 96 | 0 | std::swap( m_paramsetMap[psId].parameterSet, m_lastActiveParameterSet ); | 97 | 0 | } | 98 | 0 | m_paramsetMap[psId].cNaluData.clear(); | 99 | 0 | m_paramsetMap[psId].parameterSet.reset(ps); | 100 | 0 | ps->m_changedFlag = changed; | 101 | 0 | } | 102 | 16 | else | 103 | 16 | { | 104 | 16 | m_paramsetMap[psId].parameterSet.reset(ps); | 105 | 16 | ps->m_changedFlag = false; | 106 | 16 | } | 107 | | | 108 | 16 | if( !cNaluData.empty() ) | 109 | 16 | { | 110 | 16 | m_paramsetMap[psId].cNaluData = std::move( cNaluData ); | 111 | 16 | } | 112 | 0 | else | 113 | 0 | { | 114 | 0 | m_paramsetMap[psId].cNaluData.clear(); | 115 | 0 | } | 116 | 16 | } |
|
117 | | |
118 | | T* getPS_nothrow( int psId ) |
119 | 0 | { |
120 | 0 | auto it = m_paramsetMap.find( psId ); |
121 | 0 | return it == m_paramsetMap.end() ? nullptr : it->second.parameterSet.get(); |
122 | 0 | } Unexecuted instantiation: vvdec::ParameterSetMap<vvdec::SPS, 16>::getPS_nothrow(int) Unexecuted instantiation: vvdec::ParameterSetMap<vvdec::PPS, 64>::getPS_nothrow(int) Unexecuted instantiation: vvdec::ParameterSetMap<vvdec::APS, 64>::getPS_nothrow(int) Unexecuted instantiation: vvdec::ParameterSetMap<vvdec::VPS, 16>::getPS_nothrow(int) |
123 | | |
124 | | const T* getPS_nothrow( int psId ) const |
125 | 6 | { |
126 | 6 | auto it = m_paramsetMap.find( psId ); |
127 | 6 | return it == m_paramsetMap.end() ? nullptr : it->second.parameterSet.get(); |
128 | 6 | } Unexecuted instantiation: vvdec::ParameterSetMap<vvdec::VPS, 16>::getPS_nothrow(int) const vvdec::ParameterSetMap<vvdec::SPS, 16>::getPS_nothrow(int) const Line | Count | Source | 125 | 1 | { | 126 | 1 | auto it = m_paramsetMap.find( psId ); | 127 | 1 | return it == m_paramsetMap.end() ? nullptr : it->second.parameterSet.get(); | 128 | 1 | } |
vvdec::ParameterSetMap<vvdec::PPS, 64>::getPS_nothrow(int) const Line | Count | Source | 125 | 5 | { | 126 | 5 | auto it = m_paramsetMap.find( psId ); | 127 | 5 | return it == m_paramsetMap.end() ? nullptr : it->second.parameterSet.get(); | 128 | 5 | } |
Unexecuted instantiation: vvdec::ParameterSetMap<vvdec::APS, 64>::getPS_nothrow(int) const |
129 | | |
130 | | T* getPS( int psId ) |
131 | 0 | { |
132 | 0 | T* ps = getPS_nothrow( psId ); |
133 | 0 | constexpr static int apsIdShift = std::is_same<T, APS>::value ? NUM_APS_TYPE_LEN : 0; |
134 | 0 | CHECK( !ps, "Missing Parameter Set (id:" << ( psId >> apsIdShift ) << ')' ); |
135 | 0 | return ps; |
136 | 0 | } Unexecuted instantiation: vvdec::ParameterSetMap<vvdec::SPS, 16>::getPS(int) Unexecuted instantiation: vvdec::ParameterSetMap<vvdec::PPS, 64>::getPS(int) Unexecuted instantiation: vvdec::ParameterSetMap<vvdec::APS, 64>::getPS(int) Unexecuted instantiation: vvdec::ParameterSetMap<vvdec::VPS, 16>::getPS(int) |
137 | | |
138 | | const T* getPS( int psId ) const |
139 | 6 | { |
140 | 6 | const T* ps = getPS_nothrow( psId ); |
141 | 6 | constexpr static int apsIdShift = std::is_same<T, APS>::value ? NUM_APS_TYPE_LEN : 0; |
142 | 6 | CHECK( !ps, "Missing Parameter Set (id:" << ( psId >> apsIdShift ) << ')' ); |
143 | 0 | return ps; |
144 | 6 | } Unexecuted instantiation: vvdec::ParameterSetMap<vvdec::VPS, 16>::getPS(int) const vvdec::ParameterSetMap<vvdec::SPS, 16>::getPS(int) const Line | Count | Source | 139 | 1 | { | 140 | 1 | const T* ps = getPS_nothrow( psId ); | 141 | 1 | constexpr static int apsIdShift = std::is_same<T, APS>::value ? NUM_APS_TYPE_LEN : 0; | 142 | 1 | CHECK( !ps, "Missing Parameter Set (id:" << ( psId >> apsIdShift ) << ')' ); | 143 | 0 | return ps; | 144 | 1 | } |
vvdec::ParameterSetMap<vvdec::PPS, 64>::getPS(int) const Line | Count | Source | 139 | 5 | { | 140 | 5 | const T* ps = getPS_nothrow( psId ); | 141 | 5 | constexpr static int apsIdShift = std::is_same<T, APS>::value ? NUM_APS_TYPE_LEN : 0; | 142 | 5 | CHECK( !ps, "Missing Parameter Set (id:" << ( psId >> apsIdShift ) << ')' ); | 143 | 0 | return ps; | 144 | 5 | } |
Unexecuted instantiation: vvdec::ParameterSetMap<vvdec::APS, 64>::getPS(int) const |
145 | | |
146 | | T* getFirstPS() const |
147 | 0 | { |
148 | 0 | return ( m_paramsetMap.begin() == m_paramsetMap.end() ) ? NULL : m_paramsetMap.begin()->second.parameterSet.get(); |
149 | 0 | } Unexecuted instantiation: vvdec::ParameterSetMap<vvdec::SPS, 16>::getFirstPS() const Unexecuted instantiation: vvdec::ParameterSetMap<vvdec::APS, 64>::getFirstPS() const |
150 | | |
151 | 0 | void setActive( int psId ) { m_activePsId.push_back( psId ); }Unexecuted instantiation: vvdec::ParameterSetMap<vvdec::VPS, 16>::setActive(int) Unexecuted instantiation: vvdec::ParameterSetMap<vvdec::SPS, 16>::setActive(int) Unexecuted instantiation: vvdec::ParameterSetMap<vvdec::PPS, 64>::setActive(int) Unexecuted instantiation: vvdec::ParameterSetMap<vvdec::APS, 64>::setActive(int) |
152 | 0 | void clearActive() { m_activePsId.clear(); }Unexecuted instantiation: vvdec::ParameterSetMap<vvdec::APS, 64>::clearActive() Unexecuted instantiation: vvdec::ParameterSetMap<vvdec::VPS, 16>::clearActive() Unexecuted instantiation: vvdec::ParameterSetMap<vvdec::SPS, 16>::clearActive() Unexecuted instantiation: vvdec::ParameterSetMap<vvdec::PPS, 64>::clearActive() |
153 | | |
154 | | void clearChangedFlags() |
155 | 0 | { |
156 | 0 | for( auto& entry: m_paramsetMap ) entry.second.parameterSet->clearChangedFlag(); |
157 | 0 | } |
158 | | |
159 | | bool getAnyChangedFlag() const |
160 | 0 | { |
161 | 0 | return std::any_of( m_paramsetMap.begin(), m_paramsetMap.end(), []( const auto& entry ) { return entry.second.parameterSet->getChangedFlag(); } ); |
162 | 0 | } |
163 | | |
164 | | void clearMap() { m_paramsetMap.clear(); } |
165 | | |
166 | | private: |
167 | | std::map<int, MapData> m_paramsetMap; |
168 | | std::shared_ptr<T> m_lastActiveParameterSet; |
169 | | std::vector<int> m_activePsId; |
170 | | }; |
171 | | |
172 | | |
173 | | class ParameterSetManager |
174 | | { |
175 | | public: |
176 | 956 | ParameterSetManager() = default; |
177 | 956 | ~ParameterSetManager() = default; |
178 | | |
179 | | using APSArray = std::array<const APS*, ALF_CTB_MAX_NUM_APS>; |
180 | | |
181 | | struct ActivePSs |
182 | | { |
183 | | const SPS* sps; |
184 | | const PPS* pps; |
185 | | APSArray* alfAPSs; |
186 | | const APS* lmcsAps; |
187 | | const APS* scalingListAps; |
188 | | }; |
189 | | |
190 | | ActivePSs xActivateParameterSets( const bool isFirstSlice, const Slice* pPilot, const PicHeader* picHeader, const bool rejectSpsChangeInClvs = false ); |
191 | | |
192 | | //! store sequence parameter set and take ownership of it |
193 | | //! store picture parameter set and take ownership of it |
194 | 0 | void storeVPS( VPS* vps, AlignedByteVec& naluData ) { m_vpsMap.storePS( vps->getVPSId(), vps, std::move( naluData ) ); } |
195 | 13 | void storeSPS( SPS* sps, AlignedByteVec& naluData ) { m_spsMap.storePS( sps->getSPSId(), sps, std::move( naluData ) ); } |
196 | 0 | void storePPS( PPS* pps, AlignedByteVec& naluData ) { m_ppsMap.storePS( pps->getPPSId(), pps, std::move( naluData ) ); } |
197 | 16 | void storeAPS( APS* aps, AlignedByteVec& naluData ) { m_apsMap.storePS( ( aps->getAPSId() << NUM_APS_TYPE_LEN ) + aps->getAPSType(), aps, std::move( naluData ) ); } |
198 | | |
199 | | //! get pointer to existing sequence parameter set |
200 | 0 | const VPS* getVPS ( int vpsId ) const { if( !vpsId ) return nullptr; return m_vpsMap.getPS( vpsId ); } |
201 | 1 | const SPS* getSPS ( int spsId ) const { return m_spsMap.getPS ( spsId ); } |
202 | 5 | const PPS* getPPS ( int ppsId ) const { return m_ppsMap.getPS ( ppsId ); } |
203 | 0 | const APS* getAPS ( int apsId, int apsType ) const { return m_apsMap.getPS ( ( apsId << NUM_APS_TYPE_LEN ) + apsType ); } |
204 | 0 | const APS* getAPS_nothrow( int apsId, int apsType ) const { return m_apsMap.getPS_nothrow( ( apsId << NUM_APS_TYPE_LEN ) + apsType ); } |
205 | | // getter only used by DecLibParser::prepareLostPicture(). Is it really needed? |
206 | 0 | const APSArray& getAlfAPSs() const { return m_alfAPSs; } |
207 | | |
208 | 0 | const SPS* getFirstSPS() const { return m_spsMap.getFirstPS(); } |
209 | 0 | const APS* getFirstAPS() const { return m_apsMap.getFirstPS(); } |
210 | 0 | bool getAPSChangedFlag() const { return m_apsMap.getAnyChangedFlag(); } |
211 | | |
212 | | //! activate a PPS and, depending on isIDR parameter, also SPS. returns true, if activation is successful |
213 | | bool activatePPS( int ppsId, bool isIRAP ); |
214 | | bool activateAPS( int apsId, int apsType ); |
215 | | |
216 | 0 | const SPS* getActiveSPS() const { return m_spsMap.getPS( m_activeSPSId ); } |
217 | | |
218 | | private: |
219 | 0 | SPS* getSPS( int spsId ) { return m_spsMap.getPS( spsId ); } |
220 | 0 | PPS* getPPS( int ppsId ) { return m_ppsMap.getPS( ppsId ); } |
221 | 0 | APS* getAPS( int apsId, int apsType ) { return m_apsMap.getPS( ( apsId << NUM_APS_TYPE_LEN ) + apsType ); } |
222 | | |
223 | | ParameterSetMap<SPS, MAX_NUM_SPS> m_spsMap; |
224 | | ParameterSetMap<PPS, MAX_NUM_PPS> m_ppsMap; |
225 | | ParameterSetMap<APS, ALF_CTB_MAX_NUM_APS * MAX_NUM_APS_TYPE> m_apsMap; |
226 | | ParameterSetMap<VPS, MAX_NUM_VPS> m_vpsMap; |
227 | | |
228 | | APSArray m_alfAPSs; |
229 | | |
230 | | int m_activeSPSId = -1; // -1 for nothing active |
231 | | int m_activeVPSId = -1; // -1 for nothing active |
232 | | }; |
233 | | |
234 | | } |