1 // Copyright (c) 2018-2019 Intel Corporation
2 //
3 // Permission is hereby granted, free of charge, to any person obtaining a copy
4 // of this software and associated documentation files (the "Software"), to deal
5 // in the Software without restriction, including without limitation the rights
6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 // copies of the Software, and to permit persons to whom the Software is
8 // furnished to do so, subject to the following conditions:
9 //
10 // The above copyright notice and this permission notice shall be included in all
11 // copies or substantial portions of the Software.
12 //
13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 // SOFTWARE.
20
21 #include "mfxvideo.h"
22
23 #if MFX_VERSION >= MFX_VERSION_NEXT
24
25 #include "block_structures.h"
26
GetChildBlock(std::vector<BaseBlock> & childrenBlocks) const27 void BaseBlock::GetChildBlock(std::vector<BaseBlock>& childrenBlocks) const
28 {
29 childrenBlocks.clear();
30 childrenBlocks.reserve(4);
31
32 //sizes and positions
33 mfxU32 childHeight = m_BHeight / 2;
34 mfxU32 childWidth = m_BWidth / 2;
35 for (mfxU32 i = 0; i < 4; i++)
36 {
37 childrenBlocks.emplace_back(m_AdrX + childWidth * (i % 2), m_AdrY + childHeight * (i / 2), childHeight, childWidth);
38 }
39 }
40
GetChildRefSampleInfo(const RefSampleAvail & currAvail,const BaseBlock & ctu,std::vector<RefSampleAvail> & childrenRefSampleAvail) const41 void BaseBlock::GetChildRefSampleInfo(const RefSampleAvail & currAvail, const BaseBlock & ctu, std::vector<RefSampleAvail>& childrenRefSampleAvail) const
42 {
43 childrenRefSampleAvail.clear();
44 childrenRefSampleAvail.resize(4);
45
46 //is left down block available for children
47 childrenRefSampleAvail[0].LeftDown = true;
48 childrenRefSampleAvail[1].LeftDown = false;
49
50 if (m_AdrY + m_BHeight == ctu.m_AdrY + ctu.m_BHeight)
51 {
52 childrenRefSampleAvail[2].LeftDown = true;
53 childrenRefSampleAvail[3].LeftDown = true;
54 }
55 else
56 {
57 childrenRefSampleAvail[2].LeftDown = currAvail.LeftDown;
58 childrenRefSampleAvail[3].LeftDown = false;
59 }
60
61 //is up right block available for children
62 childrenRefSampleAvail[0].UpRight = true;
63 childrenRefSampleAvail[2].UpRight = true;
64
65 if (m_AdrX + m_BWidth == ctu.m_AdrX + ctu.m_BWidth)
66 {
67 childrenRefSampleAvail[1].UpRight = true;
68 childrenRefSampleAvail[3].UpRight = true;
69 }
70 else
71 {
72 childrenRefSampleAvail[1].UpRight = currAvail.UpRight;
73 childrenRefSampleAvail[3].UpRight = false;
74 }
75 }
76
77 //This recursive function fills outVec with BaseBlocks, coordinates and sizes of which correspond to
78 //the quad-tree structure specified by the quad-tree root node and the base size and coordinates of
79 //the "root node "
GetQuadTreeBlocksRecur(QuadTreeNode & node,mfxU32 baseAdrX,mfxU32 baseAdrY,mfxU32 baseSize,std::vector<BaseBlock> & outVec)80 void QuadTree::GetQuadTreeBlocksRecur(QuadTreeNode & node, mfxU32 baseAdrX, mfxU32 baseAdrY, mfxU32 baseSize, std::vector<BaseBlock>& outVec)
81 {
82 if (!node.m_Children.empty())
83 {
84 for (mfxU32 i_y = 0; i_y < 2; i_y++)
85 {
86 for (mfxU32 i_x = 0; i_x < 2; i_x++)
87 {
88 QuadTreeNode& child = node.m_Children[2 * i_y + i_x];
89 mfxU32 childSize = baseSize / 2;
90 mfxU32 childAdrX = baseAdrX + i_x * childSize;
91 mfxU32 childAdrY = baseAdrY + i_y * childSize;
92 GetQuadTreeBlocksRecur(child, childAdrX, childAdrY, childSize, outVec);
93 }
94 }
95 }
96 else
97 {
98 outVec.emplace_back(baseAdrX, baseAdrY, baseSize, baseSize);
99 return;
100 }
101 }
102
GetQuadTreeRefSampleAvailVector(QuadTreeNode & node,BaseBlock & currBlock,const BaseBlock & ctu,std::vector<RefSampleAvail> & outVec)103 void QuadTree::GetQuadTreeRefSampleAvailVector(QuadTreeNode & node, BaseBlock & currBlock, const BaseBlock & ctu, std::vector<RefSampleAvail>& outVec)
104 {
105 RefSampleAvail helper(true, true);
106 GetQuadTreeRefSampleAvailVectorRecur(node, currBlock, helper, ctu, outVec);
107 }
108
GetQuadTreeRefSampleAvailVectorRecur(QuadTreeNode & node,BaseBlock & currBlock,const RefSampleAvail & currAvail,const BaseBlock & ctu,std::vector<RefSampleAvail> & outVec)109 void QuadTree::GetQuadTreeRefSampleAvailVectorRecur(QuadTreeNode & node, BaseBlock & currBlock, const RefSampleAvail& currAvail, const BaseBlock & ctu, std::vector<RefSampleAvail>& outVec)
110 {
111 if (!node.m_Children.empty())
112 {
113 //children blocks, refSamples availability for children is counted here
114 std::vector<BaseBlock> childrenBlocks;
115 currBlock.GetChildBlock(childrenBlocks);
116 std::vector<RefSampleAvail> childrenRefSamplesInfo;
117 currBlock.GetChildRefSampleInfo(currAvail, ctu, childrenRefSamplesInfo);
118
119 //recursive call for children
120 for (mfxU32 i = 0; i < 4; i++)
121 {
122 GetQuadTreeRefSampleAvailVectorRecur(node.m_Children[i], childrenBlocks[i], childrenRefSamplesInfo[i], ctu, outVec);
123 }
124 }
125 else
126 {
127
128 //put leaves into outVec in depth-first order
129 outVec.emplace_back(currAvail);
130 }
131 return;
132 }
133
PatchBlock(const PatchBlock & rhs)134 PatchBlock::PatchBlock(const PatchBlock & rhs) : PatchBlock(static_cast<BaseBlock>(rhs))
135 {
136 memcpy(PatchData.get(), rhs.PatchData.get(), sizeof(mfxU8) * m_BWidth * m_BHeight * 3 / 2);
137 }
138
operator =(const PatchBlock & rhs)139 PatchBlock & PatchBlock::operator=(const PatchBlock & rhs)
140 {
141 BaseBlock::operator=(rhs);
142
143 mfxU32 sq = m_BWidth * m_BHeight;
144 PatchData.reset(new mfxU8[sq * 3 / 2]);
145
146 memcpy(PatchData.get(), rhs.PatchData.get(), sizeof(mfxU8) * sq * 3 / 2);
147
148 m_YPlane = PatchData.get();
149 m_UPlane = m_YPlane + sq;
150 m_VPlane = m_UPlane + (sq / 4);
151
152 return *this;
153 }
154
PatchBlock(const BaseBlock & BB)155 PatchBlock::PatchBlock(const BaseBlock& BB) : BaseBlock(BB)
156 {
157 mfxU32 sq = m_BWidth * m_BHeight;
158 PatchData.reset(new mfxU8[sq * 3 / 2]);
159 m_YPlane = PatchData.get();
160 m_UPlane = m_YPlane + sq;
161 m_VPlane = m_UPlane + (sq / 4);
162
163 memset(m_YPlane, LUMA_DEFAULT, sq);
164 memset(m_UPlane, CHROMA_DEFAULT, sq / 4);
165 memset(m_VPlane, CHROMA_DEFAULT, sq / 4);
166 }
167
168 //constructor that memsets PatchBlock with the particurlar sample
PatchBlock(const BaseBlock & BB,mfxU8 y_comp,mfxU8 u_comp,mfxU8 v_comp)169 PatchBlock::PatchBlock(const BaseBlock& BB, mfxU8 y_comp, mfxU8 u_comp, mfxU8 v_comp) : BaseBlock(BB)
170 {
171 mfxU32 sq = m_BWidth * m_BHeight;
172 PatchData.reset(new mfxU8[sq * 3 / 2]);
173 m_YPlane = PatchData.get();
174 m_UPlane = m_YPlane + sq;
175 m_VPlane = m_UPlane + (sq / 4);
176
177 memset(m_YPlane, y_comp, sq);
178 memset(m_UPlane, u_comp, sq / 4);
179 memset(m_VPlane, v_comp, sq / 4);
180 }
181
182 //constructor that fills PatchBlock with coresponding data from the srcPatch
PatchBlock(const BaseBlock & dstBlock,const PatchBlock & srcBlock)183 PatchBlock::PatchBlock(const BaseBlock& dstBlock, const PatchBlock& srcBlock) : PatchBlock(dstBlock)
184 {
185 if (!dstBlock.IsInBlock(srcBlock))
186 {
187 throw std::string("ERROR: PatchBlock: new PatchBlock should be located inside the old one in frame coords");
188 }
189
190 //Calculating the coords of dstBlock relative to srcBlock
191 mfxU32 offsetX = dstBlock.m_AdrX - srcBlock.m_AdrX;
192 mfxU32 offsetY = dstBlock.m_AdrY - srcBlock.m_AdrY;
193
194 for (mfxU32 i = 0; i < m_BHeight; i++)
195 {
196 memcpy(m_YPlane + i * m_BWidth, srcBlock.m_YPlane + (offsetY + i) * srcBlock.m_BWidth + offsetX, m_BWidth);
197 }
198 for (mfxU32 i = 0; i < m_BHeight / 2; i++)
199 {
200 memcpy(m_UPlane + i * (m_BWidth / 2), srcBlock.m_UPlane + (offsetY / 2 + i) * (srcBlock.m_BWidth / 2) + offsetX / 2, m_BWidth / 2);
201 memcpy(m_VPlane + i * (m_BWidth / 2), srcBlock.m_VPlane + (offsetY / 2 + i) * (srcBlock.m_BWidth / 2) + offsetX / 2, m_BWidth / 2);
202 }
203 }
204
205 //constructor that filles PatchBlock with coresponding data from the surface
PatchBlock(const BaseBlock & BB,const ExtendedSurface & surf)206 PatchBlock::PatchBlock(const BaseBlock & BB, const ExtendedSurface & surf) : PatchBlock(BB)
207 {
208 if (!BB.IsInBlock(BaseBlock(0, 0, surf.Info.CropW, surf.Info.CropH)))
209 {
210 throw std::string("ERROR: PatchBlock: new patchBlock should be located inside the surface");
211 }
212
213 for (mfxU32 i = 0; i < m_BHeight; i++)
214 {
215 memcpy(m_YPlane + i * m_BWidth, surf.Data.Y + (m_AdrY + i) * surf.Data.Pitch + m_AdrX, m_BWidth);
216 }
217 for (mfxU32 i = 0; i < m_BHeight / 2; i++)
218 {
219 memcpy(m_UPlane + i * (m_BWidth / 2), surf.Data.U + (m_AdrY / 2 + i) * (surf.Data.Pitch / 2) + m_AdrX / 2, m_BWidth / 2);
220 memcpy(m_VPlane + i * (m_BWidth / 2), surf.Data.V + (m_AdrY / 2 + i) * (surf.Data.Pitch / 2) + m_AdrX / 2, m_BWidth / 2);
221 }
222 }
223
224 //distance between current PatchBlock and other_patch counted as a sum of abs differences between luma components over all samples
CalcYSAD(const PatchBlock & otherPatch) const225 mfxU32 PatchBlock::CalcYSAD(const PatchBlock & otherPatch) const
226 {
227 mfxU32 curDiff = 0;
228 if (m_BHeight == otherPatch.m_BHeight && m_BWidth == otherPatch.m_BWidth)
229 {
230 for (mfxU32 i = 0; i < m_BHeight*m_BWidth; i++)
231 {
232 curDiff += abs(m_YPlane[i] - otherPatch.m_YPlane[i]);
233 }
234 }
235 else
236 {
237 throw std::string("ERROR: CalcYSAD: block size mismatch");
238 }
239 return curDiff;
240 }
241
242 //compAdrX and compAdrY are given in the comp color space
GetSampleI420(COLOR_COMPONENT comp,mfxU32 compAdrX,mfxU32 compAdrY) const243 mfxU8 PatchBlock::GetSampleI420(COLOR_COMPONENT comp, mfxU32 compAdrX, mfxU32 compAdrY) const
244 {
245 switch (comp)
246 {
247 case LUMA_Y:
248 return m_YPlane[compAdrY * m_BWidth + compAdrX];
249 case CHROMA_U:
250 return m_UPlane[compAdrY * (m_BWidth / 2) + compAdrX];
251 case CHROMA_V:
252 return m_VPlane[compAdrY * (m_BWidth / 2) + compAdrX];
253 default:
254 throw std::string("ERROR: Trying to get unspecified component");
255 }
256 }
257
258 //Inserts refPatch into this PatchBlock, if refPatch is located inside this PatchBlock
InsertAnotherPatch(const PatchBlock & refPatch)259 void PatchBlock::InsertAnotherPatch(const PatchBlock & refPatch)
260 {
261 if (!refPatch.IsInBlock(*this))
262 {
263 throw std::string("ERROR: InsertAnotherPatch: refPatch should be inside targetPatch\n");
264 }
265
266 //Calculating coordinate offset of refPatch relative to this PatchBlock
267 mfxU32 offsetX = refPatch.m_AdrX - m_AdrX;
268 mfxU32 offsetY = refPatch.m_AdrY - m_AdrY;
269
270 //luma
271 for (mfxU32 i = 0; i < refPatch.m_BHeight; i++)
272 {
273 memcpy(m_YPlane + (offsetY + i) * m_BWidth + offsetX, refPatch.m_YPlane + i * refPatch.m_BWidth, refPatch.m_BWidth);
274 }
275 //chroma U, V
276 for (mfxU32 i = 0; i < refPatch.m_BHeight / 2; ++i)
277 {
278 memcpy(m_UPlane + (offsetY / 2 + i) * m_BWidth / 2 + offsetX / 2, refPatch.m_UPlane + i * (refPatch.m_BWidth / 2), refPatch.m_BWidth / 2);
279 memcpy(m_VPlane + (offsetY / 2 + i) * m_BWidth / 2 + offsetX / 2, refPatch.m_VPlane + i * (refPatch.m_BWidth / 2), refPatch.m_BWidth / 2);
280 }
281 return;
282 }
283
284 //Returns a BaseBlock with coordinates that are shifted by the m_MV motion vector
285 //from the corresponding list relative to the current PU position
GetShiftedBaseBlock(REF_LIST_INDEX list) const286 BaseBlock PUBlock::GetShiftedBaseBlock(REF_LIST_INDEX list) const
287 {
288 mfxI64 posX = (mfxI64) m_AdrX + (m_MV.MV[list].x >> 2);
289 mfxI64 posY = (mfxI64) m_AdrY + (m_MV.MV[list].y >> 2);
290
291 if (posX < 0 && posY < 0)
292 {
293 throw std::string("ERROR: GetShiftedBaseBlock: negative resulting block coords");
294 }
295
296 return BaseBlock((mfxU32) posX, (mfxU32) posY, m_BWidth, m_BHeight);
297 }
298
BuildPUsVector(INTER_PART_MODE mode)299 void CUBlock::BuildPUsVector(INTER_PART_MODE mode)
300 {
301 switch (mode)
302 {
303 case INTER_2NxN:
304 // UP PU
305 m_PUVec.emplace_back(PUBlock(m_AdrX, m_AdrY, m_BWidth, m_BHeight / 2));
306 // DOWN PU
307 m_PUVec.emplace_back(PUBlock(m_AdrX, m_AdrY + m_BHeight / 2, m_BWidth, m_BHeight / 2));
308 break;
309
310 case INTER_Nx2N:
311 // LEFT PU
312 m_PUVec.emplace_back(PUBlock(m_AdrX, m_AdrY, m_BWidth / 2, m_BHeight));
313 // RIGHT PU
314 m_PUVec.emplace_back(PUBlock(m_AdrX + m_BWidth / 2, m_AdrY, m_BWidth / 2, m_BHeight));
315 break;
316
317 case INTER_NxN:
318 // TOP LEFT PU
319 m_PUVec.emplace_back(PUBlock(m_AdrX, m_AdrY, m_BWidth / 2, m_BHeight / 2));
320 // TOP RIGHT PU
321 m_PUVec.emplace_back(PUBlock(m_AdrX + m_BWidth / 2, m_AdrY, m_BWidth / 2, m_BHeight / 2));
322 // BOT LEFT PU
323 m_PUVec.emplace_back(PUBlock(m_AdrX, m_AdrY + m_BHeight / 2, m_BWidth / 2, m_BHeight / 2));
324 // BOT RIGHT PU
325 m_PUVec.emplace_back(PUBlock(m_AdrX + m_BWidth / 2, m_AdrY + m_BHeight / 2, m_BWidth / 2, m_BHeight / 2));
326 break;
327
328 case INTER_2NxnU:
329 // UP SMALL PU
330 m_PUVec.emplace_back(PUBlock(m_AdrX, m_AdrY, m_BWidth, m_BHeight / 4));
331 // DOWN LARGE PU
332 m_PUVec.emplace_back(PUBlock(m_AdrX, m_AdrY + m_BHeight / 4, m_BWidth, (m_BHeight * 3) / 4));
333 break;
334
335 case INTER_2NxnD:
336 // UP LARGE PU
337 m_PUVec.emplace_back(PUBlock(m_AdrX, m_AdrY, m_BWidth, (m_BHeight * 3) / 4));
338 // DOWN SMALL PU
339 m_PUVec.emplace_back(PUBlock(m_AdrX, m_AdrY + (m_BHeight * 3) / 4, m_BWidth, m_BHeight / 4));
340 break;
341
342 case INTER_nLx2N:
343 // LEFT SMALL PU
344 m_PUVec.emplace_back(PUBlock(m_AdrX, m_AdrY, m_BWidth / 4, m_BHeight));
345 // RIGHT LARGE PU
346 m_PUVec.emplace_back(PUBlock(m_AdrX + m_BWidth / 4, m_AdrY, (m_BWidth * 3) / 4, m_BHeight));
347 break;
348
349 case INTER_nRx2N:
350 // LEFT LARGE PU
351 m_PUVec.emplace_back(PUBlock(m_AdrX, m_AdrY, (m_BWidth * 3) / 4, m_BHeight));
352 // RIGHT SMALL PU
353 m_PUVec.emplace_back(PUBlock(m_AdrX + (m_BWidth * 3) / 4, m_AdrY, m_BWidth / 4, m_BHeight));
354 break;
355
356 case INTER_2Nx2N:
357 default:
358 m_PUVec.emplace_back(PUBlock(m_AdrX, m_AdrY, m_BWidth, m_BHeight));
359 break;
360 }
361 return;
362 }
363
364 #endif // MFX_VERSION
365