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