1 /*****************************************************************************
2 * Copyright (C) 2013 x265 project
4 * Authors: Deepthi Nandakumar <deepthi@multicorewareinc.com>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
20 * This program is also available under a commercial proprietary license.
21 * For more information, contact us at license @ x265.com.
22 *****************************************************************************/
26 #include "framedata.h"
29 #include "primitives.h"
35 inline pixel
weightBidir(int w0
, int16_t P0
, int w1
, int16_t P1
, int round
, int shift
, int offset
)
37 return Clip((w0
* (P0
+ IF_INTERNAL_OFFS
) + w1
* (P1
+ IF_INTERNAL_OFFS
) + round
+ (offset
<< (shift
- 1))) >> shift
);
54 X265_FREE(m_refAbove
);
55 X265_FREE(m_immedVals
);
56 m_predShortYuv
[0].destroy();
57 m_predShortYuv
[1].destroy();
60 bool Predict::allocBuffers(int csp
)
63 m_hChromaShift
= CHROMA_H_SHIFT(csp
);
64 m_vChromaShift
= CHROMA_V_SHIFT(csp
);
66 int predBufHeight
= ((MAX_CU_SIZE
+ 2) << 4);
67 int predBufStride
= ((MAX_CU_SIZE
+ 8) << 4);
68 CHECKED_MALLOC(m_predBuf
, pixel
, predBufStride
* predBufHeight
);
69 CHECKED_MALLOC(m_immedVals
, int16_t, 64 * (64 + NTAPS_LUMA
- 1));
70 CHECKED_MALLOC(m_refAbove
, pixel
, 12 * MAX_CU_SIZE
);
72 m_refAboveFlt
= m_refAbove
+ 3 * MAX_CU_SIZE
;
73 m_refLeft
= m_refAboveFlt
+ 3 * MAX_CU_SIZE
;
74 m_refLeftFlt
= m_refLeft
+ 3 * MAX_CU_SIZE
;
76 return m_predShortYuv
[0].create(MAX_CU_SIZE
, csp
) && m_predShortYuv
[1].create(MAX_CU_SIZE
, csp
);
82 void Predict::predIntraLumaAng(uint32_t dirMode
, pixel
* dst
, intptr_t stride
, uint32_t log2TrSize
)
84 int tuSize
= 1 << log2TrSize
;
86 pixel
*refLft
, *refAbv
;
88 if (!(g_intraFilterFlags
[dirMode
] & tuSize
))
90 refLft
= m_refLeft
+ tuSize
- 1;
91 refAbv
= m_refAbove
+ tuSize
- 1;
95 refLft
= m_refLeftFlt
+ tuSize
- 1;
96 refAbv
= m_refAboveFlt
+ tuSize
- 1;
99 bool bFilter
= log2TrSize
<= 4;
100 int sizeIdx
= log2TrSize
- 2;
101 X265_CHECK(sizeIdx
>= 0 && sizeIdx
< 4, "intra block size is out of range\n");
102 primitives
.intra_pred
[dirMode
][sizeIdx
](dst
, stride
, refLft
, refAbv
, dirMode
, bFilter
);
105 void Predict::predIntraChromaAng(pixel
* src
, uint32_t dirMode
, pixel
* dst
, intptr_t stride
, uint32_t log2TrSizeC
, int chFmt
)
107 int tuSize
= 1 << log2TrSizeC
;
108 int tuSize2
= tuSize
<< 1;
110 // Create the prediction
111 const int bufOffset
= tuSize
- 1;
112 pixel buf0
[3 * MAX_CU_SIZE
];
113 pixel buf1
[3 * MAX_CU_SIZE
];
115 pixel
* left
= buf0
+ bufOffset
;
117 int limit
= (dirMode
<= 25 && dirMode
>= 11) ? (tuSize
+ 1 + 1) : (tuSize2
+ 1);
118 for (int k
= 0; k
< limit
; k
++)
119 left
[k
] = src
[k
* ADI_BUF_STRIDE
];
121 if (chFmt
== X265_CSP_I444
&& (g_intraFilterFlags
[dirMode
] & tuSize
))
123 // generate filtered intra prediction samples
124 buf0
[bufOffset
- 1] = src
[1];
125 left
= buf1
+ bufOffset
;
126 for (int i
= 0; i
< tuSize2
; i
++)
127 left
[i
] = (buf0
[bufOffset
+ i
- 1] + 2 * buf0
[bufOffset
+ i
] + buf0
[bufOffset
+ i
+ 1] + 2) >> 2;
128 left
[tuSize2
] = buf0
[bufOffset
+ tuSize2
];
130 above
= buf0
+ bufOffset
;
132 for (int i
= 1; i
< tuSize2
; i
++)
133 above
[i
] = (src
[i
- 1] + 2 * src
[i
] + src
[i
+ 1] + 2) >> 2;
134 above
[tuSize2
] = src
[tuSize2
];
138 above
= buf1
+ bufOffset
;
139 memcpy(above
, src
, (tuSize2
+ 1) * sizeof(pixel
));
142 int sizeIdx
= log2TrSizeC
- 2;
143 X265_CHECK(sizeIdx
>= 0 && sizeIdx
< 4, "intra block size is out of range\n");
144 primitives
.intra_pred
[dirMode
][sizeIdx
](dst
, stride
, left
, above
, dirMode
, 0);
147 void Predict::initMotionCompensation(const CUData
& cu
, const CUGeom
& cuGeom
, int partIdx
)
149 m_predSlice
= cu
.m_slice
;
150 cu
.getPartIndexAndSize(partIdx
, m_puAbsPartIdx
, m_puWidth
, m_puHeight
);
151 m_ctuAddr
= cu
.m_cuAddr
;
152 m_cuAbsPartIdx
= cuGeom
.encodeIdx
;
155 void Predict::prepMotionCompensation(const CUData
& cu
, const CUGeom
& cuGeom
, int partIdx
)
157 initMotionCompensation(cu
, cuGeom
, partIdx
);
159 m_refIdx0
= cu
.m_refIdx
[0][m_puAbsPartIdx
];
160 m_clippedMv
[0] = cu
.m_mv
[0][m_puAbsPartIdx
];
161 m_refIdx1
= cu
.m_refIdx
[1][m_puAbsPartIdx
];
162 m_clippedMv
[1] = cu
.m_mv
[1][m_puAbsPartIdx
];
163 cu
.clipMv(m_clippedMv
[0]);
164 cu
.clipMv(m_clippedMv
[1]);
167 void Predict::motionCompensation(Yuv
& predYuv
, bool bLuma
, bool bChroma
)
169 if (m_predSlice
->isInterP())
173 X265_CHECK(m_refIdx0
>= 0, "invalid P refidx\n");
174 X265_CHECK(m_refIdx0
< m_predSlice
->m_numRefIdx
[0], "P refidx out of range\n");
175 const WeightParam
*wp0
= m_predSlice
->m_weightPredTable
[0][m_refIdx0
];
177 if (m_predSlice
->m_pps
->bUseWeightPred
&& wp0
->bPresentFlag
)
179 for (int plane
= 0; plane
< 3; plane
++)
181 wv0
[plane
].w
= wp0
[plane
].inputWeight
;
182 wv0
[plane
].offset
= wp0
[plane
].inputOffset
* (1 << (X265_DEPTH
- 8));
183 wv0
[plane
].shift
= wp0
[plane
].log2WeightDenom
;
184 wv0
[plane
].round
= wp0
[plane
].log2WeightDenom
>= 1 ? 1 << (wp0
[plane
].log2WeightDenom
- 1) : 0;
187 ShortYuv
& shortYuv
= m_predShortYuv
[0];
190 predInterLumaShort(shortYuv
, *m_predSlice
->m_refPicList
[0][m_refIdx0
]->m_reconPicYuv
, m_clippedMv
[0]);
192 predInterChromaShort(shortYuv
, *m_predSlice
->m_refPicList
[0][m_refIdx0
]->m_reconPicYuv
, m_clippedMv
[0]);
194 addWeightUni(predYuv
, shortYuv
, wv0
, bLuma
, bChroma
);
199 predInterLumaPixel(predYuv
, *m_predSlice
->m_refPicList
[0][m_refIdx0
]->m_reconPicYuv
, m_clippedMv
[0]);
201 predInterChromaPixel(predYuv
, *m_predSlice
->m_refPicList
[0][m_refIdx0
]->m_reconPicYuv
, m_clippedMv
[0]);
208 WeightValues wv0
[3], wv1
[3];
209 const WeightParam
*pwp0
, *pwp1
;
211 if (m_predSlice
->m_pps
->bUseWeightedBiPred
)
213 pwp0
= m_refIdx0
>= 0 ? m_predSlice
->m_weightPredTable
[0][m_refIdx0
] : NULL
;
214 pwp1
= m_refIdx1
>= 0 ? m_predSlice
->m_weightPredTable
[1][m_refIdx1
] : NULL
;
216 if (pwp0
&& pwp1
&& (pwp0
->bPresentFlag
|| pwp1
->bPresentFlag
))
218 /* biprediction weighting */
219 for (int plane
= 0; plane
< 3; plane
++)
221 wv0
[plane
].w
= pwp0
[plane
].inputWeight
;
222 wv0
[plane
].o
= pwp0
[plane
].inputOffset
* (1 << (X265_DEPTH
- 8));
223 wv0
[plane
].shift
= pwp0
[plane
].log2WeightDenom
;
224 wv0
[plane
].round
= 1 << pwp0
[plane
].log2WeightDenom
;
226 wv1
[plane
].w
= pwp1
[plane
].inputWeight
;
227 wv1
[plane
].o
= pwp1
[plane
].inputOffset
* (1 << (X265_DEPTH
- 8));
228 wv1
[plane
].shift
= wv0
[plane
].shift
;
229 wv1
[plane
].round
= wv0
[plane
].round
;
234 /* uniprediction weighting, always outputs to wv0 */
235 const WeightParam
* pwp
= (m_refIdx0
>= 0) ? pwp0
: pwp1
;
236 for (int plane
= 0; plane
< 3; plane
++)
238 wv0
[plane
].w
= pwp
[plane
].inputWeight
;
239 wv0
[plane
].offset
= pwp
[plane
].inputOffset
* (1 << (X265_DEPTH
- 8));
240 wv0
[plane
].shift
= pwp
[plane
].log2WeightDenom
;
241 wv0
[plane
].round
= pwp
[plane
].log2WeightDenom
>= 1 ? 1 << (pwp
[plane
].log2WeightDenom
- 1) : 0;
248 if (m_refIdx0
>= 0 && m_refIdx1
>= 0)
251 X265_CHECK(m_refIdx0
< m_predSlice
->m_numRefIdx
[0], "bidir refidx0 out of range\n");
252 X265_CHECK(m_refIdx1
< m_predSlice
->m_numRefIdx
[1], "bidir refidx1 out of range\n");
256 predInterLumaShort(m_predShortYuv
[0], *m_predSlice
->m_refPicList
[0][m_refIdx0
]->m_reconPicYuv
, m_clippedMv
[0]);
257 predInterLumaShort(m_predShortYuv
[1], *m_predSlice
->m_refPicList
[1][m_refIdx1
]->m_reconPicYuv
, m_clippedMv
[1]);
261 predInterChromaShort(m_predShortYuv
[0], *m_predSlice
->m_refPicList
[0][m_refIdx0
]->m_reconPicYuv
, m_clippedMv
[0]);
262 predInterChromaShort(m_predShortYuv
[1], *m_predSlice
->m_refPicList
[1][m_refIdx1
]->m_reconPicYuv
, m_clippedMv
[1]);
265 if (pwp0
&& pwp1
&& (pwp0
->bPresentFlag
|| pwp1
->bPresentFlag
))
266 addWeightBi(predYuv
, m_predShortYuv
[0], m_predShortYuv
[1], wv0
, wv1
, bLuma
, bChroma
);
268 predYuv
.addAvg(m_predShortYuv
[0], m_predShortYuv
[1], m_puAbsPartIdx
, m_puWidth
, m_puHeight
, bLuma
, bChroma
);
270 else if (m_refIdx0
>= 0)
272 /* uniprediction to L0 */
273 X265_CHECK(m_refIdx0
< m_predSlice
->m_numRefIdx
[0], "unidir refidx0 out of range\n");
275 if (pwp0
&& pwp0
->bPresentFlag
)
277 ShortYuv
& shortYuv
= m_predShortYuv
[0];
280 predInterLumaShort(shortYuv
, *m_predSlice
->m_refPicList
[0][m_refIdx0
]->m_reconPicYuv
, m_clippedMv
[0]);
282 predInterChromaShort(shortYuv
, *m_predSlice
->m_refPicList
[0][m_refIdx0
]->m_reconPicYuv
, m_clippedMv
[0]);
284 addWeightUni(predYuv
, shortYuv
, wv0
, bLuma
, bChroma
);
289 predInterLumaPixel(predYuv
, *m_predSlice
->m_refPicList
[0][m_refIdx0
]->m_reconPicYuv
, m_clippedMv
[0]);
291 predInterChromaPixel(predYuv
, *m_predSlice
->m_refPicList
[0][m_refIdx0
]->m_reconPicYuv
, m_clippedMv
[0]);
296 /* uniprediction to L1 */
297 X265_CHECK(m_refIdx1
>= 0, "refidx1 was not positive\n");
298 X265_CHECK(m_refIdx1
< m_predSlice
->m_numRefIdx
[1], "unidir refidx1 out of range\n");
300 if (pwp1
&& pwp1
->bPresentFlag
)
302 ShortYuv
& shortYuv
= m_predShortYuv
[0];
305 predInterLumaShort(shortYuv
, *m_predSlice
->m_refPicList
[1][m_refIdx1
]->m_reconPicYuv
, m_clippedMv
[1]);
307 predInterChromaShort(shortYuv
, *m_predSlice
->m_refPicList
[1][m_refIdx1
]->m_reconPicYuv
, m_clippedMv
[1]);
309 addWeightUni(predYuv
, shortYuv
, wv0
, bLuma
, bChroma
);
314 predInterLumaPixel(predYuv
, *m_predSlice
->m_refPicList
[1][m_refIdx1
]->m_reconPicYuv
, m_clippedMv
[1]);
316 predInterChromaPixel(predYuv
, *m_predSlice
->m_refPicList
[1][m_refIdx1
]->m_reconPicYuv
, m_clippedMv
[1]);
322 void Predict::predInterLumaPixel(Yuv
& dstYuv
, const PicYuv
& refPic
, const MV
& mv
) const
324 pixel
*dst
= dstYuv
.getLumaAddr(m_puAbsPartIdx
);
325 intptr_t dstStride
= dstYuv
.m_size
;
327 intptr_t srcStride
= refPic
.m_stride
;
328 intptr_t srcOffset
= (mv
.x
>> 2) + (mv
.y
>> 2) * srcStride
;
329 int partEnum
= partitionFromSizes(m_puWidth
, m_puHeight
);
330 pixel
* src
= const_cast<PicYuv
&>(refPic
).getLumaAddr(m_ctuAddr
, m_cuAbsPartIdx
+ m_puAbsPartIdx
) + srcOffset
;
332 int xFrac
= mv
.x
& 0x3;
333 int yFrac
= mv
.y
& 0x3;
335 if (!(yFrac
| xFrac
))
336 primitives
.luma_copy_pp
[partEnum
](dst
, dstStride
, src
, srcStride
);
338 primitives
.luma_hpp
[partEnum
](src
, srcStride
, dst
, dstStride
, xFrac
);
340 primitives
.luma_vpp
[partEnum
](src
, srcStride
, dst
, dstStride
, yFrac
);
343 int tmpStride
= m_puWidth
;
344 int filterSize
= NTAPS_LUMA
;
345 int halfFilterSize
= (filterSize
>> 1);
346 primitives
.luma_hps
[partEnum
](src
, srcStride
, m_immedVals
, tmpStride
, xFrac
, 1);
347 primitives
.luma_vsp
[partEnum
](m_immedVals
+ (halfFilterSize
- 1) * tmpStride
, tmpStride
, dst
, dstStride
, yFrac
);
351 void Predict::predInterLumaShort(ShortYuv
& dstSYuv
, const PicYuv
& refPic
, const MV
& mv
) const
353 int16_t *dst
= dstSYuv
.getLumaAddr(m_puAbsPartIdx
);
354 int dstStride
= dstSYuv
.m_size
;
356 intptr_t srcStride
= refPic
.m_stride
;
357 intptr_t srcOffset
= (mv
.x
>> 2) + (mv
.y
>> 2) * srcStride
;
358 pixel
*src
= const_cast<PicYuv
&>(refPic
).getLumaAddr(m_ctuAddr
, m_cuAbsPartIdx
+ m_puAbsPartIdx
) + srcOffset
;
360 int xFrac
= mv
.x
& 0x3;
361 int yFrac
= mv
.y
& 0x3;
363 int partEnum
= partitionFromSizes(m_puWidth
, m_puHeight
);
365 X265_CHECK((m_puWidth
% 4) + (m_puHeight
% 4) == 0, "width or height not divisible by 4\n");
366 X265_CHECK(dstStride
== MAX_CU_SIZE
, "stride expected to be max cu size\n");
368 if (!(yFrac
| xFrac
))
369 primitives
.luma_p2s(src
, srcStride
, dst
, m_puWidth
, m_puHeight
);
371 primitives
.luma_hps
[partEnum
](src
, srcStride
, dst
, dstStride
, xFrac
, 0);
373 primitives
.luma_vps
[partEnum
](src
, srcStride
, dst
, dstStride
, yFrac
);
376 int tmpStride
= m_puWidth
;
377 int filterSize
= NTAPS_LUMA
;
378 int halfFilterSize
= (filterSize
>> 1);
379 primitives
.luma_hps
[partEnum
](src
, srcStride
, m_immedVals
, tmpStride
, xFrac
, 1);
380 primitives
.luma_vss
[partEnum
](m_immedVals
+ (halfFilterSize
- 1) * tmpStride
, tmpStride
, dst
, dstStride
, yFrac
);
384 void Predict::predInterChromaPixel(Yuv
& dstYuv
, const PicYuv
& refPic
, const MV
& mv
) const
386 intptr_t dstStride
= dstYuv
.m_csize
;
387 intptr_t refStride
= refPic
.m_strideC
;
389 int shiftHor
= (2 + m_hChromaShift
);
390 int shiftVer
= (2 + m_vChromaShift
);
392 intptr_t refOffset
= (mv
.x
>> shiftHor
) + (mv
.y
>> shiftVer
) * refStride
;
394 pixel
* refCb
= const_cast<PicYuv
&>(refPic
).getCbAddr(m_ctuAddr
, m_cuAbsPartIdx
+ m_puAbsPartIdx
) + refOffset
;
395 pixel
* refCr
= const_cast<PicYuv
&>(refPic
).getCrAddr(m_ctuAddr
, m_cuAbsPartIdx
+ m_puAbsPartIdx
) + refOffset
;
397 pixel
* dstCb
= dstYuv
.getCbAddr(m_puAbsPartIdx
);
398 pixel
* dstCr
= dstYuv
.getCrAddr(m_puAbsPartIdx
);
400 int xFrac
= mv
.x
& ((1 << shiftHor
) - 1);
401 int yFrac
= mv
.y
& ((1 << shiftVer
) - 1);
403 int partEnum
= partitionFromSizes(m_puWidth
, m_puHeight
);
405 if (!(yFrac
| xFrac
))
407 primitives
.chroma
[m_csp
].copy_pp
[partEnum
](dstCb
, dstStride
, refCb
, refStride
);
408 primitives
.chroma
[m_csp
].copy_pp
[partEnum
](dstCr
, dstStride
, refCr
, refStride
);
412 primitives
.chroma
[m_csp
].filter_hpp
[partEnum
](refCb
, refStride
, dstCb
, dstStride
, xFrac
<< (1 - m_hChromaShift
));
413 primitives
.chroma
[m_csp
].filter_hpp
[partEnum
](refCr
, refStride
, dstCr
, dstStride
, xFrac
<< (1 - m_hChromaShift
));
417 primitives
.chroma
[m_csp
].filter_vpp
[partEnum
](refCb
, refStride
, dstCb
, dstStride
, yFrac
<< (1 - m_vChromaShift
));
418 primitives
.chroma
[m_csp
].filter_vpp
[partEnum
](refCr
, refStride
, dstCr
, dstStride
, yFrac
<< (1 - m_vChromaShift
));
422 int extStride
= m_puWidth
>> m_hChromaShift
;
423 int filterSize
= NTAPS_CHROMA
;
424 int halfFilterSize
= (filterSize
>> 1);
426 primitives
.chroma
[m_csp
].filter_hps
[partEnum
](refCb
, refStride
, m_immedVals
, extStride
, xFrac
<< (1 - m_hChromaShift
), 1);
427 primitives
.chroma
[m_csp
].filter_vsp
[partEnum
](m_immedVals
+ (halfFilterSize
- 1) * extStride
, extStride
, dstCb
, dstStride
, yFrac
<< (1 - m_vChromaShift
));
429 primitives
.chroma
[m_csp
].filter_hps
[partEnum
](refCr
, refStride
, m_immedVals
, extStride
, xFrac
<< (1 - m_hChromaShift
), 1);
430 primitives
.chroma
[m_csp
].filter_vsp
[partEnum
](m_immedVals
+ (halfFilterSize
- 1) * extStride
, extStride
, dstCr
, dstStride
, yFrac
<< (1 - m_vChromaShift
));
434 void Predict::predInterChromaShort(ShortYuv
& dstSYuv
, const PicYuv
& refPic
, const MV
& mv
) const
436 intptr_t refStride
= refPic
.m_strideC
;
437 intptr_t dstStride
= dstSYuv
.m_csize
;
439 int shiftHor
= (2 + m_hChromaShift
);
440 int shiftVer
= (2 + m_vChromaShift
);
442 intptr_t refOffset
= (mv
.x
>> shiftHor
) + (mv
.y
>> shiftVer
) * refStride
;
444 pixel
* refCb
= const_cast<PicYuv
&>(refPic
).getCbAddr(m_ctuAddr
, m_cuAbsPartIdx
+ m_puAbsPartIdx
) + refOffset
;
445 pixel
* refCr
= const_cast<PicYuv
&>(refPic
).getCrAddr(m_ctuAddr
, m_cuAbsPartIdx
+ m_puAbsPartIdx
) + refOffset
;
447 int16_t* dstCb
= dstSYuv
.getCbAddr(m_puAbsPartIdx
);
448 int16_t* dstCr
= dstSYuv
.getCrAddr(m_puAbsPartIdx
);
450 int xFrac
= mv
.x
& ((1 << shiftHor
) - 1);
451 int yFrac
= mv
.y
& ((1 << shiftVer
) - 1);
453 int partEnum
= partitionFromSizes(m_puWidth
, m_puHeight
);
455 uint32_t cxWidth
= m_puWidth
>> m_hChromaShift
;
456 uint32_t cxHeight
= m_puHeight
>> m_vChromaShift
;
458 X265_CHECK(((cxWidth
| cxHeight
) % 2) == 0, "chroma block size expected to be multiple of 2\n");
460 if (!(yFrac
| xFrac
))
462 primitives
.chroma_p2s
[m_csp
](refCb
, refStride
, dstCb
, cxWidth
, cxHeight
);
463 primitives
.chroma_p2s
[m_csp
](refCr
, refStride
, dstCr
, cxWidth
, cxHeight
);
467 primitives
.chroma
[m_csp
].filter_hps
[partEnum
](refCb
, refStride
, dstCb
, dstStride
, xFrac
<< (1 - m_hChromaShift
), 0);
468 primitives
.chroma
[m_csp
].filter_hps
[partEnum
](refCr
, refStride
, dstCr
, dstStride
, xFrac
<< (1 - m_hChromaShift
), 0);
472 primitives
.chroma
[m_csp
].filter_vps
[partEnum
](refCb
, refStride
, dstCb
, dstStride
, yFrac
<< (1 - m_vChromaShift
));
473 primitives
.chroma
[m_csp
].filter_vps
[partEnum
](refCr
, refStride
, dstCr
, dstStride
, yFrac
<< (1 - m_vChromaShift
));
477 int extStride
= cxWidth
;
478 int filterSize
= NTAPS_CHROMA
;
479 int halfFilterSize
= (filterSize
>> 1);
480 primitives
.chroma
[m_csp
].filter_hps
[partEnum
](refCb
, refStride
, m_immedVals
, extStride
, xFrac
<< (1 - m_hChromaShift
), 1);
481 primitives
.chroma
[m_csp
].filter_vss
[partEnum
](m_immedVals
+ (halfFilterSize
- 1) * extStride
, extStride
, dstCb
, dstStride
, yFrac
<< (1 - m_vChromaShift
));
482 primitives
.chroma
[m_csp
].filter_hps
[partEnum
](refCr
, refStride
, m_immedVals
, extStride
, xFrac
<< (1 - m_hChromaShift
), 1);
483 primitives
.chroma
[m_csp
].filter_vss
[partEnum
](m_immedVals
+ (halfFilterSize
- 1) * extStride
, extStride
, dstCr
, dstStride
, yFrac
<< (1 - m_vChromaShift
));
487 /* weighted averaging for bi-pred */
488 void Predict::addWeightBi(Yuv
& predYuv
, const ShortYuv
& srcYuv0
, const ShortYuv
& srcYuv1
, const WeightValues wp0
[3], const WeightValues wp1
[3], bool bLuma
, bool bChroma
) const
492 int w0
, w1
, offset
, shiftNum
, shift
, round
;
493 uint32_t src0Stride
, src1Stride
, dststride
;
495 pixel
* dstY
= predYuv
.getLumaAddr(m_puAbsPartIdx
);
496 pixel
* dstU
= predYuv
.getCbAddr(m_puAbsPartIdx
);
497 pixel
* dstV
= predYuv
.getCrAddr(m_puAbsPartIdx
);
499 const int16_t* srcY0
= srcYuv0
.getLumaAddr(m_puAbsPartIdx
);
500 const int16_t* srcU0
= srcYuv0
.getCbAddr(m_puAbsPartIdx
);
501 const int16_t* srcV0
= srcYuv0
.getCrAddr(m_puAbsPartIdx
);
503 const int16_t* srcY1
= srcYuv1
.getLumaAddr(m_puAbsPartIdx
);
504 const int16_t* srcU1
= srcYuv1
.getCbAddr(m_puAbsPartIdx
);
505 const int16_t* srcV1
= srcYuv1
.getCrAddr(m_puAbsPartIdx
);
511 offset
= wp0
[0].o
+ wp1
[0].o
;
512 shiftNum
= IF_INTERNAL_PREC
- X265_DEPTH
;
513 shift
= wp0
[0].shift
+ shiftNum
+ 1;
514 round
= shift
? (1 << (shift
- 1)) : 0;
517 src0Stride
= srcYuv0
.m_size
;
518 src1Stride
= srcYuv1
.m_size
;
519 dststride
= predYuv
.m_size
;
521 // TODO: can we use weight_sp here?
522 for (y
= m_puHeight
- 1; y
>= 0; y
--)
524 for (x
= m_puWidth
- 1; x
>= 0; )
526 // note: luma min width is 4
527 dstY
[x
] = weightBidir(w0
, srcY0
[x
], w1
, srcY1
[x
], round
, shift
, offset
);
529 dstY
[x
] = weightBidir(w0
, srcY0
[x
], w1
, srcY1
[x
], round
, shift
, offset
);
531 dstY
[x
] = weightBidir(w0
, srcY0
[x
], w1
, srcY1
[x
], round
, shift
, offset
);
533 dstY
[x
] = weightBidir(w0
, srcY0
[x
], w1
, srcY1
[x
], round
, shift
, offset
);
547 offset
= wp0
[1].o
+ wp1
[1].o
;
548 shiftNum
= IF_INTERNAL_PREC
- X265_DEPTH
;
549 shift
= wp0
[1].shift
+ shiftNum
+ 1;
550 round
= shift
? (1 << (shift
- 1)) : 0;
553 src0Stride
= srcYuv0
.m_csize
;
554 src1Stride
= srcYuv1
.m_csize
;
555 dststride
= predYuv
.m_csize
;
557 uint32_t cwidth
= m_puWidth
>> srcYuv0
.m_hChromaShift
;
558 uint32_t cheight
= m_puHeight
>> srcYuv0
.m_vChromaShift
;
560 // TODO: can we use weight_sp here?
561 for (y
= cheight
- 1; y
>= 0; y
--)
563 for (x
= cwidth
- 1; x
>= 0;)
565 // note: chroma min width is 2
566 dstU
[x
] = weightBidir(w0
, srcU0
[x
], w1
, srcU1
[x
], round
, shift
, offset
);
568 dstU
[x
] = weightBidir(w0
, srcU0
[x
], w1
, srcU1
[x
], round
, shift
, offset
);
579 offset
= wp0
[2].o
+ wp1
[2].o
;
580 shift
= wp0
[2].shift
+ shiftNum
+ 1;
581 round
= shift
? (1 << (shift
- 1)) : 0;
584 for (y
= cheight
- 1; y
>= 0; y
--)
586 for (x
= cwidth
- 1; x
>= 0;)
588 // note: chroma min width is 2
589 dstV
[x
] = weightBidir(w0
, srcV0
[x
], w1
, srcV1
[x
], round
, shift
, offset
);
591 dstV
[x
] = weightBidir(w0
, srcV0
[x
], w1
, srcV1
[x
], round
, shift
, offset
);
602 /* weighted averaging for uni-pred */
603 void Predict::addWeightUni(Yuv
& predYuv
, const ShortYuv
& srcYuv
, const WeightValues wp
[3], bool bLuma
, bool bChroma
) const
605 pixel
* dstY
= predYuv
.getLumaAddr(m_puAbsPartIdx
);
606 pixel
* dstU
= predYuv
.getCbAddr(m_puAbsPartIdx
);
607 pixel
* dstV
= predYuv
.getCrAddr(m_puAbsPartIdx
);
609 const int16_t* srcY0
= srcYuv
.getLumaAddr(m_puAbsPartIdx
);
610 const int16_t* srcU0
= srcYuv
.getCbAddr(m_puAbsPartIdx
);
611 const int16_t* srcV0
= srcYuv
.getCrAddr(m_puAbsPartIdx
);
613 int w0
, offset
, shiftNum
, shift
, round
;
614 uint32_t srcStride
, dstStride
;
620 offset
= wp
[0].offset
;
621 shiftNum
= IF_INTERNAL_PREC
- X265_DEPTH
;
622 shift
= wp
[0].shift
+ shiftNum
;
623 round
= shift
? (1 << (shift
- 1)) : 0;
624 srcStride
= srcYuv
.m_size
;
625 dstStride
= predYuv
.m_size
;
627 primitives
.weight_sp(const_cast<int16_t*>(srcY0
), dstY
, srcStride
, dstStride
, m_puWidth
, m_puHeight
, w0
, round
, shift
, offset
);
634 offset
= wp
[1].offset
;
635 shiftNum
= IF_INTERNAL_PREC
- X265_DEPTH
;
636 shift
= wp
[1].shift
+ shiftNum
;
637 round
= shift
? (1 << (shift
- 1)) : 0;
639 srcStride
= srcYuv
.m_csize
;
640 dstStride
= predYuv
.m_csize
;
642 uint32_t cwidth
= m_puWidth
>> srcYuv
.m_hChromaShift
;
643 uint32_t cheight
= m_puHeight
>> srcYuv
.m_vChromaShift
;
645 primitives
.weight_sp(const_cast<int16_t*>(srcU0
), dstU
, srcStride
, dstStride
, cwidth
, cheight
, w0
, round
, shift
, offset
);
649 offset
= wp
[2].offset
;
650 shift
= wp
[2].shift
+ shiftNum
;
651 round
= shift
? (1 << (shift
- 1)) : 0;
653 primitives
.weight_sp(const_cast<int16_t*>(srcV0
), dstV
, srcStride
, dstStride
, cwidth
, cheight
, w0
, round
, shift
, offset
);
657 void Predict::initAdiPattern(const CUData
& cu
, const CUGeom
& cuGeom
, uint32_t absPartIdx
, uint32_t partDepth
, int dirMode
)
659 IntraNeighbors intraNeighbors
;
660 initIntraNeighbors(cu
, absPartIdx
, partDepth
, true, &intraNeighbors
);
662 pixel
* adiBuf
= m_predBuf
;
663 pixel
* refAbove
= m_refAbove
;
664 pixel
* refLeft
= m_refLeft
;
665 pixel
* refAboveFlt
= m_refAboveFlt
;
666 pixel
* refLeftFlt
= m_refLeftFlt
;
668 int tuSize
= intraNeighbors
.tuSize
;
669 int tuSize2
= tuSize
<< 1;
671 pixel
* adiOrigin
= cu
.m_encData
->m_reconPicYuv
->getLumaAddr(cu
.m_cuAddr
, cuGeom
.encodeIdx
+ absPartIdx
);
672 intptr_t picStride
= cu
.m_encData
->m_reconPicYuv
->m_stride
;
674 fillReferenceSamples(adiOrigin
, picStride
, adiBuf
, intraNeighbors
);
676 // initialization of ADI buffers
677 const int bufOffset
= tuSize
- 1;
678 refAbove
+= bufOffset
;
679 refLeft
+= bufOffset
;
681 // ADI_BUF_STRIDE * (2 * tuSize + 1);
682 memcpy(refAbove
, adiBuf
, (tuSize2
+ 1) * sizeof(pixel
));
683 for (int k
= 0; k
< tuSize2
+ 1; k
++)
684 refLeft
[k
] = adiBuf
[k
* ADI_BUF_STRIDE
];
686 if (dirMode
== ALL_IDX
? (8 | 16 | 32) & tuSize
: g_intraFilterFlags
[dirMode
] & tuSize
)
688 // generate filtered intra prediction samples
689 refAboveFlt
+= bufOffset
;
690 refLeftFlt
+= bufOffset
;
692 bool bStrongSmoothing
= (tuSize
== 32 && cu
.m_slice
->m_sps
->bUseStrongIntraSmoothing
);
694 if (bStrongSmoothing
)
696 const int trSize
= 32;
697 const int trSize2
= 32 * 2;
698 const int threshold
= 1 << (X265_DEPTH
- 5);
699 int refBL
= refLeft
[trSize2
];
700 int refTL
= refAbove
[0];
701 int refTR
= refAbove
[trSize2
];
702 bStrongSmoothing
= (abs(refBL
+ refTL
- 2 * refLeft
[trSize
]) < threshold
&&
703 abs(refTL
+ refTR
- 2 * refAbove
[trSize
]) < threshold
);
705 if (bStrongSmoothing
)
707 // bilinear interpolation
708 const int shift
= 5 + 1; // intraNeighbors.log2TrSize + 1;
709 int init
= (refTL
<< shift
) + tuSize
;
712 refLeftFlt
[0] = refAboveFlt
[0] = refAbove
[0];
714 //TODO: Performance Primitive???
715 delta
= refBL
- refTL
;
716 for (int i
= 1; i
< trSize2
; i
++)
717 refLeftFlt
[i
] = (pixel
)((init
+ delta
* i
) >> shift
);
718 refLeftFlt
[trSize2
] = refLeft
[trSize2
];
720 delta
= refTR
- refTL
;
721 for (int i
= 1; i
< trSize2
; i
++)
722 refAboveFlt
[i
] = (pixel
)((init
+ delta
* i
) >> shift
);
723 refAboveFlt
[trSize2
] = refAbove
[trSize2
];
729 refLeft
[-1] = refAbove
[1];
730 for (int i
= 0; i
< tuSize2
; i
++)
731 refLeftFlt
[i
] = (refLeft
[i
- 1] + 2 * refLeft
[i
] + refLeft
[i
+ 1] + 2) >> 2;
732 refLeftFlt
[tuSize2
] = refLeft
[tuSize2
];
734 refAboveFlt
[0] = refLeftFlt
[0];
735 for (int i
= 1; i
< tuSize2
; i
++)
736 refAboveFlt
[i
] = (refAbove
[i
- 1] + 2 * refAbove
[i
] + refAbove
[i
+ 1] + 2) >> 2;
737 refAboveFlt
[tuSize2
] = refAbove
[tuSize2
];
741 void Predict::initAdiPatternChroma(const CUData
& cu
, const CUGeom
& cuGeom
, uint32_t absPartIdx
, uint32_t partDepth
, uint32_t chromaId
)
743 IntraNeighbors intraNeighbors
;
744 initIntraNeighbors(cu
, absPartIdx
, partDepth
, false, &intraNeighbors
);
745 uint32_t tuSize
= intraNeighbors
.tuSize
;
747 const pixel
* adiOrigin
= cu
.m_encData
->m_reconPicYuv
->getChromaAddr(chromaId
, cu
.m_cuAddr
, cuGeom
.encodeIdx
+ absPartIdx
);
748 intptr_t picStride
= cu
.m_encData
->m_reconPicYuv
->m_strideC
;
749 pixel
* adiRef
= getAdiChromaBuf(chromaId
, tuSize
);
751 fillReferenceSamples(adiOrigin
, picStride
, adiRef
, intraNeighbors
);
754 void Predict::initIntraNeighbors(const CUData
& cu
, uint32_t absPartIdx
, uint32_t partDepth
, bool isLuma
, IntraNeighbors
*intraNeighbors
)
756 uint32_t log2TrSize
= cu
.m_log2CUSize
[0] - partDepth
;
757 int log2UnitWidth
= LOG2_UNIT_SIZE
;
758 int log2UnitHeight
= LOG2_UNIT_SIZE
;
762 log2TrSize
-= cu
.m_hChromaShift
;
763 log2UnitWidth
-= cu
.m_hChromaShift
;
764 log2UnitHeight
-= cu
.m_vChromaShift
;
767 int numIntraNeighbor
= 0;
768 bool *bNeighborFlags
= intraNeighbors
->bNeighborFlags
;
770 uint32_t partIdxLT
, partIdxRT
, partIdxLB
;
772 cu
.deriveLeftRightTopIdxAdi(partIdxLT
, partIdxRT
, absPartIdx
, partDepth
);
774 uint32_t tuSize
= 1 << log2TrSize
;
775 int tuWidthInUnits
= tuSize
>> log2UnitWidth
;
776 int tuHeightInUnits
= tuSize
>> log2UnitHeight
;
777 int aboveUnits
= tuWidthInUnits
<< 1;
778 int leftUnits
= tuHeightInUnits
<< 1;
779 int partIdxStride
= cu
.m_slice
->m_sps
->numPartInCUSize
;
780 partIdxLB
= g_rasterToZscan
[g_zscanToRaster
[partIdxLT
] + ((tuHeightInUnits
- 1) * partIdxStride
)];
782 bNeighborFlags
[leftUnits
] = isAboveLeftAvailable(cu
, partIdxLT
);
783 numIntraNeighbor
+= (int)(bNeighborFlags
[leftUnits
]);
784 numIntraNeighbor
+= isAboveAvailable(cu
, partIdxLT
, partIdxRT
, (bNeighborFlags
+ leftUnits
+ 1));
785 numIntraNeighbor
+= isAboveRightAvailable(cu
, partIdxLT
, partIdxRT
, (bNeighborFlags
+ leftUnits
+ 1 + tuWidthInUnits
));
786 numIntraNeighbor
+= isLeftAvailable(cu
, partIdxLT
, partIdxLB
, (bNeighborFlags
+ leftUnits
- 1));
787 numIntraNeighbor
+= isBelowLeftAvailable(cu
, partIdxLT
, partIdxLB
, (bNeighborFlags
+ leftUnits
- 1 - tuHeightInUnits
));
789 intraNeighbors
->numIntraNeighbor
= numIntraNeighbor
;
790 intraNeighbors
->totalUnits
= aboveUnits
+ leftUnits
+ 1;
791 intraNeighbors
->aboveUnits
= aboveUnits
;
792 intraNeighbors
->leftUnits
= leftUnits
;
793 intraNeighbors
->unitWidth
= 1 << log2UnitWidth
;
794 intraNeighbors
->unitHeight
= 1 << log2UnitHeight
;
795 intraNeighbors
->tuSize
= tuSize
;
796 intraNeighbors
->log2TrSize
= log2TrSize
;
799 void Predict::fillReferenceSamples(const pixel
* adiOrigin
, intptr_t picStride
, pixel
* adiRef
, const IntraNeighbors
& intraNeighbors
)
801 const pixel dcValue
= (pixel
)(1 << (X265_DEPTH
- 1));
802 int numIntraNeighbor
= intraNeighbors
.numIntraNeighbor
;
803 int totalUnits
= intraNeighbors
.totalUnits
;
804 uint32_t tuSize
= intraNeighbors
.tuSize
;
805 uint32_t refSize
= tuSize
* 2 + 1;
807 if (numIntraNeighbor
== 0)
809 // Fill border with DC value
810 for (uint32_t i
= 0; i
< refSize
; i
++)
813 for (uint32_t i
= 1; i
< refSize
; i
++)
814 adiRef
[i
* ADI_BUF_STRIDE
] = dcValue
;
816 else if (numIntraNeighbor
== totalUnits
)
818 // Fill top border with rec. samples
819 const pixel
* adiTemp
= adiOrigin
- picStride
- 1;
820 memcpy(adiRef
, adiTemp
, refSize
* sizeof(*adiRef
));
822 // Fill left border with rec. samples
823 adiTemp
= adiOrigin
- 1;
824 for (uint32_t i
= 1; i
< refSize
; i
++)
826 adiRef
[i
* ADI_BUF_STRIDE
] = adiTemp
[0];
827 adiTemp
+= picStride
;
830 else // reference samples are partially available
832 const bool *bNeighborFlags
= intraNeighbors
.bNeighborFlags
;
833 const bool *pNeighborFlags
;
834 int aboveUnits
= intraNeighbors
.aboveUnits
;
835 int leftUnits
= intraNeighbors
.leftUnits
;
836 int unitWidth
= intraNeighbors
.unitWidth
;
837 int unitHeight
= intraNeighbors
.unitHeight
;
838 int totalSamples
= (leftUnits
* unitHeight
) + ((aboveUnits
+ 1) * unitWidth
);
839 pixel adiLineBuffer
[5 * MAX_CU_SIZE
];
843 for (int i
= 0; i
< totalSamples
; i
++)
844 adiLineBuffer
[i
] = dcValue
;
846 // Fill top-left sample
847 const pixel
* adiTemp
= adiOrigin
- picStride
- 1;
848 adi
= adiLineBuffer
+ (leftUnits
* unitHeight
);
849 pNeighborFlags
= bNeighborFlags
+ leftUnits
;
852 pixel topLeftVal
= adiTemp
[0];
853 for (int i
= 0; i
< unitWidth
; i
++)
857 // Fill left & below-left samples
858 adiTemp
+= picStride
;
861 for (int j
= 0; j
< leftUnits
; j
++)
864 for (int i
= 0; i
< unitHeight
; i
++)
865 adi
[-i
] = adiTemp
[i
* picStride
];
867 adiTemp
+= unitHeight
* picStride
;
872 // Fill above & above-right samples
873 adiTemp
= adiOrigin
- picStride
;
874 adi
= adiLineBuffer
+ (leftUnits
* unitHeight
) + unitWidth
;
875 pNeighborFlags
= bNeighborFlags
+ leftUnits
+ 1;
876 for (int j
= 0; j
< aboveUnits
; j
++)
879 memcpy(adi
, adiTemp
, unitWidth
* sizeof(*adiTemp
));
880 adiTemp
+= unitWidth
;
885 // Pad reference samples when necessary
889 int pAdiLineTopRowOffset
= leftUnits
* (unitHeight
- unitWidth
);
890 if (!bNeighborFlags
[0])
892 // very bottom unit of bottom-left; at least one unit will be valid.
893 while (next
< totalUnits
&& !bNeighborFlags
[next
])
896 pixel
*pAdiLineNext
= adiLineBuffer
+ ((next
< leftUnits
) ? (next
* unitHeight
) : (pAdiLineTopRowOffset
+ (next
* unitWidth
)));
897 const pixel refSample
= *pAdiLineNext
;
898 // Pad unavailable samples with new value
899 int nextOrTop
= X265_MIN(next
, leftUnits
);
901 while (curr
< nextOrTop
)
903 for (int i
= 0; i
< unitHeight
; i
++)
913 for (int i
= 0; i
< unitWidth
; i
++)
921 // pad all other reference samples.
922 while (curr
< totalUnits
)
924 if (!bNeighborFlags
[curr
]) // samples not available
926 int numSamplesInCurrUnit
= (curr
>= leftUnits
) ? unitWidth
: unitHeight
;
927 const pixel refSample
= *(adi
- 1);
928 for (int i
= 0; i
< numSamplesInCurrUnit
; i
++)
931 adi
+= numSamplesInCurrUnit
;
936 adi
+= (curr
>= leftUnits
) ? unitWidth
: unitHeight
;
941 // Copy processed samples
942 adi
= adiLineBuffer
+ refSize
+ unitWidth
- 2;
943 memcpy(adiRef
, adi
, refSize
* sizeof(*adiRef
));
945 adi
= adiLineBuffer
+ refSize
- 1;
946 for (int i
= 1; i
< (int)refSize
; i
++)
947 adiRef
[i
* ADI_BUF_STRIDE
] = adi
[-i
];
951 bool Predict::isAboveLeftAvailable(const CUData
& cu
, uint32_t partIdxLT
)
953 uint32_t partAboveLeft
;
954 const CUData
* cuAboveLeft
= cu
.getPUAboveLeft(partAboveLeft
, partIdxLT
);
956 if (!cu
.m_slice
->m_pps
->bConstrainedIntraPred
)
957 return cuAboveLeft
? true : false;
959 return cuAboveLeft
&& cuAboveLeft
->isIntra(partAboveLeft
);
962 int Predict::isAboveAvailable(const CUData
& cu
, uint32_t partIdxLT
, uint32_t partIdxRT
, bool *bValidFlags
)
964 const uint32_t rasterPartBegin
= g_zscanToRaster
[partIdxLT
];
965 const uint32_t rasterPartEnd
= g_zscanToRaster
[partIdxRT
] + 1;
966 const uint32_t idxStep
= 1;
967 bool *validFlagPtr
= bValidFlags
;
970 for (uint32_t rasterPart
= rasterPartBegin
; rasterPart
< rasterPartEnd
; rasterPart
+= idxStep
)
973 const CUData
* cuAbove
= cu
.getPUAbove(partAbove
, g_rasterToZscan
[rasterPart
]);
974 if (cuAbove
&& (!cu
.m_slice
->m_pps
->bConstrainedIntraPred
|| cuAbove
->isIntra(partAbove
)))
977 *validFlagPtr
= true;
980 *validFlagPtr
= false;
988 int Predict::isLeftAvailable(const CUData
& cu
, uint32_t partIdxLT
, uint32_t partIdxLB
, bool *bValidFlags
)
990 const uint32_t rasterPartBegin
= g_zscanToRaster
[partIdxLT
];
991 const uint32_t rasterPartEnd
= g_zscanToRaster
[partIdxLB
] + 1;
992 const uint32_t idxStep
= cu
.m_slice
->m_sps
->numPartInCUSize
;
993 bool *validFlagPtr
= bValidFlags
;
996 for (uint32_t rasterPart
= rasterPartBegin
; rasterPart
< rasterPartEnd
; rasterPart
+= idxStep
)
999 const CUData
* cuLeft
= cu
.getPULeft(partLeft
, g_rasterToZscan
[rasterPart
]);
1000 if (cuLeft
&& (!cu
.m_slice
->m_pps
->bConstrainedIntraPred
|| cuLeft
->isIntra(partLeft
)))
1003 *validFlagPtr
= true;
1006 *validFlagPtr
= false;
1008 validFlagPtr
--; // opposite direction
1014 int Predict::isAboveRightAvailable(const CUData
& cu
, uint32_t partIdxLT
, uint32_t partIdxRT
, bool *bValidFlags
)
1016 const uint32_t numUnitsInPU
= g_zscanToRaster
[partIdxRT
] - g_zscanToRaster
[partIdxLT
] + 1;
1017 bool *validFlagPtr
= bValidFlags
;
1020 for (uint32_t offset
= 1; offset
<= numUnitsInPU
; offset
++)
1022 uint32_t partAboveRight
;
1023 const CUData
* cuAboveRight
= cu
.getPUAboveRightAdi(partAboveRight
, partIdxRT
, offset
);
1024 if (cuAboveRight
&& (!cu
.m_slice
->m_pps
->bConstrainedIntraPred
|| cuAboveRight
->isIntra(partAboveRight
)))
1027 *validFlagPtr
= true;
1030 *validFlagPtr
= false;
1038 int Predict::isBelowLeftAvailable(const CUData
& cu
, uint32_t partIdxLT
, uint32_t partIdxLB
, bool *bValidFlags
)
1040 const uint32_t numUnitsInPU
= (g_zscanToRaster
[partIdxLB
] - g_zscanToRaster
[partIdxLT
]) / cu
.m_slice
->m_sps
->numPartInCUSize
+ 1;
1041 bool *validFlagPtr
= bValidFlags
;
1044 for (uint32_t offset
= 1; offset
<= numUnitsInPU
; offset
++)
1046 uint32_t partBelowLeft
;
1047 const CUData
* cuBelowLeft
= cu
.getPUBelowLeftAdi(partBelowLeft
, partIdxLB
, offset
);
1048 if (cuBelowLeft
&& (!cu
.m_slice
->m_pps
->bConstrainedIntraPred
|| cuBelowLeft
->isIntra(partBelowLeft
)))
1051 *validFlagPtr
= true;
1054 *validFlagPtr
= false;
1056 validFlagPtr
--; // opposite direction