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
;
89 if (!(g_intraFilterFlags
[dirMode
] & tuSize
))
91 refLft
= m_refLeft
+ tuSize
- 1;
92 refAbv
= m_refAbove
+ tuSize
- 1;
96 refLft
= m_refLeftFlt
+ tuSize
- 1;
97 refAbv
= m_refAboveFlt
+ tuSize
- 1;
100 bool bFilter
= log2TrSize
<= 4;
101 int sizeIdx
= log2TrSize
- 2;
102 X265_CHECK(sizeIdx
>= 0 && sizeIdx
< 4, "intra block size is out of range\n");
103 primitives
.intra_pred
[dirMode
][sizeIdx
](dst
, stride
, refLft
, refAbv
, dirMode
, bFilter
);
106 void Predict::predIntraChromaAng(pixel
* src
, uint32_t dirMode
, pixel
* dst
, intptr_t stride
, uint32_t log2TrSizeC
, int chFmt
)
108 int tuSize
= 1 << log2TrSizeC
;
109 int tuSize2
= tuSize
<< 1;
111 // Create the prediction
112 const int bufOffset
= tuSize
- 1;
113 pixel buf0
[3 * MAX_CU_SIZE
];
114 pixel buf1
[3 * MAX_CU_SIZE
];
116 pixel
* left
= buf0
+ bufOffset
;
118 int limit
= (dirMode
<= 25 && dirMode
>= 11) ? (tuSize
+ 1 + 1) : (tuSize2
+ 1);
119 for (int k
= 0; k
< limit
; k
++)
120 left
[k
] = src
[k
* ADI_BUF_STRIDE
];
122 if (chFmt
== X265_CSP_I444
&& (g_intraFilterFlags
[dirMode
] & tuSize
))
124 // generate filtered intra prediction samples
125 buf0
[bufOffset
- 1] = src
[1];
126 left
= buf1
+ bufOffset
;
127 for (int i
= 0; i
< tuSize2
; i
++)
128 left
[i
] = (buf0
[bufOffset
+ i
- 1] + 2 * buf0
[bufOffset
+ i
] + buf0
[bufOffset
+ i
+ 1] + 2) >> 2;
129 left
[tuSize2
] = buf0
[bufOffset
+ tuSize2
];
131 above
= buf0
+ bufOffset
;
133 for (int i
= 1; i
< tuSize2
; i
++)
134 above
[i
] = (src
[i
- 1] + 2 * src
[i
] + src
[i
+ 1] + 2) >> 2;
135 above
[tuSize2
] = src
[tuSize2
];
139 above
= buf1
+ bufOffset
;
140 memcpy(above
, src
, (tuSize2
+ 1) * sizeof(pixel
));
143 int sizeIdx
= log2TrSizeC
- 2;
144 X265_CHECK(sizeIdx
>= 0 && sizeIdx
< 4, "intra block size is out of range\n");
145 primitives
.intra_pred
[dirMode
][sizeIdx
](dst
, stride
, left
, above
, dirMode
, 0);
148 void Predict::initMotionCompensation(const CUData
& cu
, const CUGeom
& cuGeom
, int partIdx
)
150 m_predSlice
= cu
.m_slice
;
151 cu
.getPartIndexAndSize(partIdx
, m_puAbsPartIdx
, m_puWidth
, m_puHeight
);
152 m_ctuAddr
= cu
.m_cuAddr
;
153 m_cuAbsPartIdx
= cuGeom
.encodeIdx
;
156 void Predict::prepMotionCompensation(const CUData
& cu
, const CUGeom
& cuGeom
, int partIdx
)
158 initMotionCompensation(cu
, cuGeom
, partIdx
);
160 m_refIdx0
= cu
.m_refIdx
[0][m_puAbsPartIdx
];
161 m_clippedMv
[0] = cu
.m_mv
[0][m_puAbsPartIdx
];
162 m_refIdx1
= cu
.m_refIdx
[1][m_puAbsPartIdx
];
163 m_clippedMv
[1] = cu
.m_mv
[1][m_puAbsPartIdx
];
164 cu
.clipMv(m_clippedMv
[0]);
165 cu
.clipMv(m_clippedMv
[1]);
168 void Predict::motionCompensation(Yuv
& predYuv
, bool bLuma
, bool bChroma
)
170 if (m_predSlice
->isInterP())
174 X265_CHECK(m_refIdx0
>= 0, "invalid P refidx\n");
175 X265_CHECK(m_refIdx0
< m_predSlice
->m_numRefIdx
[0], "P refidx out of range\n");
176 const WeightParam
*wp0
= m_predSlice
->m_weightPredTable
[0][m_refIdx0
];
178 if (m_predSlice
->m_pps
->bUseWeightPred
&& wp0
->bPresentFlag
)
180 for (int plane
= 0; plane
< 3; plane
++)
182 wv0
[plane
].w
= wp0
[plane
].inputWeight
;
183 wv0
[plane
].offset
= wp0
[plane
].inputOffset
* (1 << (X265_DEPTH
- 8));
184 wv0
[plane
].shift
= wp0
[plane
].log2WeightDenom
;
185 wv0
[plane
].round
= wp0
[plane
].log2WeightDenom
>= 1 ? 1 << (wp0
[plane
].log2WeightDenom
- 1) : 0;
188 ShortYuv
& shortYuv
= m_predShortYuv
[0];
191 predInterLumaShort(shortYuv
, *m_predSlice
->m_refPicList
[0][m_refIdx0
]->m_reconPic
, m_clippedMv
[0]);
193 predInterChromaShort(shortYuv
, *m_predSlice
->m_refPicList
[0][m_refIdx0
]->m_reconPic
, m_clippedMv
[0]);
195 addWeightUni(predYuv
, shortYuv
, wv0
, bLuma
, bChroma
);
200 predInterLumaPixel(predYuv
, *m_predSlice
->m_refPicList
[0][m_refIdx0
]->m_reconPic
, m_clippedMv
[0]);
202 predInterChromaPixel(predYuv
, *m_predSlice
->m_refPicList
[0][m_refIdx0
]->m_reconPic
, m_clippedMv
[0]);
209 WeightValues wv0
[3], wv1
[3];
210 const WeightParam
*pwp0
, *pwp1
;
212 if (m_predSlice
->m_pps
->bUseWeightedBiPred
)
214 pwp0
= m_refIdx0
>= 0 ? m_predSlice
->m_weightPredTable
[0][m_refIdx0
] : NULL
;
215 pwp1
= m_refIdx1
>= 0 ? m_predSlice
->m_weightPredTable
[1][m_refIdx1
] : NULL
;
217 if (pwp0
&& pwp1
&& (pwp0
->bPresentFlag
|| pwp1
->bPresentFlag
))
219 /* biprediction weighting */
220 for (int plane
= 0; plane
< 3; plane
++)
222 wv0
[plane
].w
= pwp0
[plane
].inputWeight
;
223 wv0
[plane
].o
= pwp0
[plane
].inputOffset
* (1 << (X265_DEPTH
- 8));
224 wv0
[plane
].shift
= pwp0
[plane
].log2WeightDenom
;
225 wv0
[plane
].round
= 1 << pwp0
[plane
].log2WeightDenom
;
227 wv1
[plane
].w
= pwp1
[plane
].inputWeight
;
228 wv1
[plane
].o
= pwp1
[plane
].inputOffset
* (1 << (X265_DEPTH
- 8));
229 wv1
[plane
].shift
= wv0
[plane
].shift
;
230 wv1
[plane
].round
= wv0
[plane
].round
;
235 /* uniprediction weighting, always outputs to wv0 */
236 const WeightParam
* pwp
= (m_refIdx0
>= 0) ? pwp0
: pwp1
;
237 for (int plane
= 0; plane
< 3; plane
++)
239 wv0
[plane
].w
= pwp
[plane
].inputWeight
;
240 wv0
[plane
].offset
= pwp
[plane
].inputOffset
* (1 << (X265_DEPTH
- 8));
241 wv0
[plane
].shift
= pwp
[plane
].log2WeightDenom
;
242 wv0
[plane
].round
= pwp
[plane
].log2WeightDenom
>= 1 ? 1 << (pwp
[plane
].log2WeightDenom
- 1) : 0;
249 if (m_refIdx0
>= 0 && m_refIdx1
>= 0)
252 X265_CHECK(m_refIdx0
< m_predSlice
->m_numRefIdx
[0], "bidir refidx0 out of range\n");
253 X265_CHECK(m_refIdx1
< m_predSlice
->m_numRefIdx
[1], "bidir refidx1 out of range\n");
257 predInterLumaShort(m_predShortYuv
[0], *m_predSlice
->m_refPicList
[0][m_refIdx0
]->m_reconPic
, m_clippedMv
[0]);
258 predInterLumaShort(m_predShortYuv
[1], *m_predSlice
->m_refPicList
[1][m_refIdx1
]->m_reconPic
, m_clippedMv
[1]);
262 predInterChromaShort(m_predShortYuv
[0], *m_predSlice
->m_refPicList
[0][m_refIdx0
]->m_reconPic
, m_clippedMv
[0]);
263 predInterChromaShort(m_predShortYuv
[1], *m_predSlice
->m_refPicList
[1][m_refIdx1
]->m_reconPic
, m_clippedMv
[1]);
266 if (pwp0
&& pwp1
&& (pwp0
->bPresentFlag
|| pwp1
->bPresentFlag
))
267 addWeightBi(predYuv
, m_predShortYuv
[0], m_predShortYuv
[1], wv0
, wv1
, bLuma
, bChroma
);
269 predYuv
.addAvg(m_predShortYuv
[0], m_predShortYuv
[1], m_puAbsPartIdx
, m_puWidth
, m_puHeight
, bLuma
, bChroma
);
271 else if (m_refIdx0
>= 0)
273 /* uniprediction to L0 */
274 X265_CHECK(m_refIdx0
< m_predSlice
->m_numRefIdx
[0], "unidir refidx0 out of range\n");
276 if (pwp0
&& pwp0
->bPresentFlag
)
278 ShortYuv
& shortYuv
= m_predShortYuv
[0];
281 predInterLumaShort(shortYuv
, *m_predSlice
->m_refPicList
[0][m_refIdx0
]->m_reconPic
, m_clippedMv
[0]);
283 predInterChromaShort(shortYuv
, *m_predSlice
->m_refPicList
[0][m_refIdx0
]->m_reconPic
, m_clippedMv
[0]);
285 addWeightUni(predYuv
, shortYuv
, wv0
, bLuma
, bChroma
);
290 predInterLumaPixel(predYuv
, *m_predSlice
->m_refPicList
[0][m_refIdx0
]->m_reconPic
, m_clippedMv
[0]);
292 predInterChromaPixel(predYuv
, *m_predSlice
->m_refPicList
[0][m_refIdx0
]->m_reconPic
, m_clippedMv
[0]);
297 /* uniprediction to L1 */
298 X265_CHECK(m_refIdx1
>= 0, "refidx1 was not positive\n");
299 X265_CHECK(m_refIdx1
< m_predSlice
->m_numRefIdx
[1], "unidir refidx1 out of range\n");
301 if (pwp1
&& pwp1
->bPresentFlag
)
303 ShortYuv
& shortYuv
= m_predShortYuv
[0];
306 predInterLumaShort(shortYuv
, *m_predSlice
->m_refPicList
[1][m_refIdx1
]->m_reconPic
, m_clippedMv
[1]);
308 predInterChromaShort(shortYuv
, *m_predSlice
->m_refPicList
[1][m_refIdx1
]->m_reconPic
, m_clippedMv
[1]);
310 addWeightUni(predYuv
, shortYuv
, wv0
, bLuma
, bChroma
);
315 predInterLumaPixel(predYuv
, *m_predSlice
->m_refPicList
[1][m_refIdx1
]->m_reconPic
, m_clippedMv
[1]);
317 predInterChromaPixel(predYuv
, *m_predSlice
->m_refPicList
[1][m_refIdx1
]->m_reconPic
, m_clippedMv
[1]);
323 void Predict::predInterLumaPixel(Yuv
& dstYuv
, const PicYuv
& refPic
, const MV
& mv
) const
325 pixel
* dst
= dstYuv
.getLumaAddr(m_puAbsPartIdx
);
326 intptr_t dstStride
= dstYuv
.m_size
;
328 intptr_t srcStride
= refPic
.m_stride
;
329 intptr_t srcOffset
= (mv
.x
>> 2) + (mv
.y
>> 2) * srcStride
;
330 int partEnum
= partitionFromSizes(m_puWidth
, m_puHeight
);
331 const pixel
* src
= refPic
.getLumaAddr(m_ctuAddr
, m_cuAbsPartIdx
+ m_puAbsPartIdx
) + srcOffset
;
333 int xFrac
= mv
.x
& 0x3;
334 int yFrac
= mv
.y
& 0x3;
336 if (!(yFrac
| xFrac
))
337 primitives
.luma_copy_pp
[partEnum
](dst
, dstStride
, src
, srcStride
);
339 primitives
.luma_hpp
[partEnum
](src
, srcStride
, dst
, dstStride
, xFrac
);
341 primitives
.luma_vpp
[partEnum
](src
, srcStride
, dst
, dstStride
, yFrac
);
344 int tmpStride
= m_puWidth
;
345 int filterSize
= NTAPS_LUMA
;
346 int halfFilterSize
= (filterSize
>> 1);
347 primitives
.luma_hps
[partEnum
](src
, srcStride
, m_immedVals
, tmpStride
, xFrac
, 1);
348 primitives
.luma_vsp
[partEnum
](m_immedVals
+ (halfFilterSize
- 1) * tmpStride
, tmpStride
, dst
, dstStride
, yFrac
);
352 void Predict::predInterLumaShort(ShortYuv
& dstSYuv
, const PicYuv
& refPic
, const MV
& mv
) const
354 int16_t* dst
= dstSYuv
.getLumaAddr(m_puAbsPartIdx
);
355 int dstStride
= dstSYuv
.m_size
;
357 intptr_t srcStride
= refPic
.m_stride
;
358 intptr_t srcOffset
= (mv
.x
>> 2) + (mv
.y
>> 2) * srcStride
;
359 const pixel
* src
= refPic
.getLumaAddr(m_ctuAddr
, m_cuAbsPartIdx
+ m_puAbsPartIdx
) + srcOffset
;
361 int xFrac
= mv
.x
& 0x3;
362 int yFrac
= mv
.y
& 0x3;
364 int partEnum
= partitionFromSizes(m_puWidth
, m_puHeight
);
366 X265_CHECK((m_puWidth
% 4) + (m_puHeight
% 4) == 0, "width or height not divisible by 4\n");
367 X265_CHECK(dstStride
== MAX_CU_SIZE
, "stride expected to be max cu size\n");
369 if (!(yFrac
| xFrac
))
370 primitives
.luma_p2s(src
, srcStride
, dst
, m_puWidth
, m_puHeight
);
372 primitives
.luma_hps
[partEnum
](src
, srcStride
, dst
, dstStride
, xFrac
, 0);
374 primitives
.luma_vps
[partEnum
](src
, srcStride
, dst
, dstStride
, yFrac
);
377 int tmpStride
= m_puWidth
;
378 int filterSize
= NTAPS_LUMA
;
379 int halfFilterSize
= (filterSize
>> 1);
380 primitives
.luma_hps
[partEnum
](src
, srcStride
, m_immedVals
, tmpStride
, xFrac
, 1);
381 primitives
.luma_vss
[partEnum
](m_immedVals
+ (halfFilterSize
- 1) * tmpStride
, tmpStride
, dst
, dstStride
, yFrac
);
385 void Predict::predInterChromaPixel(Yuv
& dstYuv
, const PicYuv
& refPic
, const MV
& mv
) const
387 intptr_t dstStride
= dstYuv
.m_csize
;
388 intptr_t refStride
= refPic
.m_strideC
;
390 int shiftHor
= (2 + m_hChromaShift
);
391 int shiftVer
= (2 + m_vChromaShift
);
393 intptr_t refOffset
= (mv
.x
>> shiftHor
) + (mv
.y
>> shiftVer
) * refStride
;
395 const pixel
* refCb
= refPic
.getCbAddr(m_ctuAddr
, m_cuAbsPartIdx
+ m_puAbsPartIdx
) + refOffset
;
396 const pixel
* refCr
= refPic
.getCrAddr(m_ctuAddr
, m_cuAbsPartIdx
+ m_puAbsPartIdx
) + refOffset
;
398 pixel
* dstCb
= dstYuv
.getCbAddr(m_puAbsPartIdx
);
399 pixel
* dstCr
= dstYuv
.getCrAddr(m_puAbsPartIdx
);
401 int xFrac
= mv
.x
& ((1 << shiftHor
) - 1);
402 int yFrac
= mv
.y
& ((1 << shiftVer
) - 1);
404 int partEnum
= partitionFromSizes(m_puWidth
, m_puHeight
);
406 if (!(yFrac
| xFrac
))
408 primitives
.chroma
[m_csp
].copy_pp
[partEnum
](dstCb
, dstStride
, refCb
, refStride
);
409 primitives
.chroma
[m_csp
].copy_pp
[partEnum
](dstCr
, dstStride
, refCr
, refStride
);
413 primitives
.chroma
[m_csp
].filter_hpp
[partEnum
](refCb
, refStride
, dstCb
, dstStride
, xFrac
<< (1 - m_hChromaShift
));
414 primitives
.chroma
[m_csp
].filter_hpp
[partEnum
](refCr
, refStride
, dstCr
, dstStride
, xFrac
<< (1 - m_hChromaShift
));
418 primitives
.chroma
[m_csp
].filter_vpp
[partEnum
](refCb
, refStride
, dstCb
, dstStride
, yFrac
<< (1 - m_vChromaShift
));
419 primitives
.chroma
[m_csp
].filter_vpp
[partEnum
](refCr
, refStride
, dstCr
, dstStride
, yFrac
<< (1 - m_vChromaShift
));
423 int extStride
= m_puWidth
>> m_hChromaShift
;
424 int filterSize
= NTAPS_CHROMA
;
425 int halfFilterSize
= (filterSize
>> 1);
427 primitives
.chroma
[m_csp
].filter_hps
[partEnum
](refCb
, refStride
, m_immedVals
, extStride
, xFrac
<< (1 - m_hChromaShift
), 1);
428 primitives
.chroma
[m_csp
].filter_vsp
[partEnum
](m_immedVals
+ (halfFilterSize
- 1) * extStride
, extStride
, dstCb
, dstStride
, yFrac
<< (1 - m_vChromaShift
));
430 primitives
.chroma
[m_csp
].filter_hps
[partEnum
](refCr
, refStride
, m_immedVals
, extStride
, xFrac
<< (1 - m_hChromaShift
), 1);
431 primitives
.chroma
[m_csp
].filter_vsp
[partEnum
](m_immedVals
+ (halfFilterSize
- 1) * extStride
, extStride
, dstCr
, dstStride
, yFrac
<< (1 - m_vChromaShift
));
435 void Predict::predInterChromaShort(ShortYuv
& dstSYuv
, const PicYuv
& refPic
, const MV
& mv
) const
437 intptr_t refStride
= refPic
.m_strideC
;
438 intptr_t dstStride
= dstSYuv
.m_csize
;
440 int shiftHor
= (2 + m_hChromaShift
);
441 int shiftVer
= (2 + m_vChromaShift
);
443 intptr_t refOffset
= (mv
.x
>> shiftHor
) + (mv
.y
>> shiftVer
) * refStride
;
445 const pixel
* refCb
= refPic
.getCbAddr(m_ctuAddr
, m_cuAbsPartIdx
+ m_puAbsPartIdx
) + refOffset
;
446 const pixel
* refCr
= refPic
.getCrAddr(m_ctuAddr
, m_cuAbsPartIdx
+ m_puAbsPartIdx
) + refOffset
;
448 int16_t* dstCb
= dstSYuv
.getCbAddr(m_puAbsPartIdx
);
449 int16_t* dstCr
= dstSYuv
.getCrAddr(m_puAbsPartIdx
);
451 int xFrac
= mv
.x
& ((1 << shiftHor
) - 1);
452 int yFrac
= mv
.y
& ((1 << shiftVer
) - 1);
454 int partEnum
= partitionFromSizes(m_puWidth
, m_puHeight
);
456 uint32_t cxWidth
= m_puWidth
>> m_hChromaShift
;
457 uint32_t cxHeight
= m_puHeight
>> m_vChromaShift
;
459 X265_CHECK(((cxWidth
| cxHeight
) % 2) == 0, "chroma block size expected to be multiple of 2\n");
461 if (!(yFrac
| xFrac
))
463 primitives
.chroma
[m_csp
].p2s(refCb
, refStride
, dstCb
, cxWidth
, cxHeight
);
464 primitives
.chroma
[m_csp
].p2s(refCr
, refStride
, dstCr
, cxWidth
, cxHeight
);
468 primitives
.chroma
[m_csp
].filter_hps
[partEnum
](refCb
, refStride
, dstCb
, dstStride
, xFrac
<< (1 - m_hChromaShift
), 0);
469 primitives
.chroma
[m_csp
].filter_hps
[partEnum
](refCr
, refStride
, dstCr
, dstStride
, xFrac
<< (1 - m_hChromaShift
), 0);
473 primitives
.chroma
[m_csp
].filter_vps
[partEnum
](refCb
, refStride
, dstCb
, dstStride
, yFrac
<< (1 - m_vChromaShift
));
474 primitives
.chroma
[m_csp
].filter_vps
[partEnum
](refCr
, refStride
, dstCr
, dstStride
, yFrac
<< (1 - m_vChromaShift
));
478 int extStride
= cxWidth
;
479 int filterSize
= NTAPS_CHROMA
;
480 int halfFilterSize
= (filterSize
>> 1);
481 primitives
.chroma
[m_csp
].filter_hps
[partEnum
](refCb
, refStride
, m_immedVals
, extStride
, xFrac
<< (1 - m_hChromaShift
), 1);
482 primitives
.chroma
[m_csp
].filter_vss
[partEnum
](m_immedVals
+ (halfFilterSize
- 1) * extStride
, extStride
, dstCb
, dstStride
, yFrac
<< (1 - m_vChromaShift
));
483 primitives
.chroma
[m_csp
].filter_hps
[partEnum
](refCr
, refStride
, m_immedVals
, extStride
, xFrac
<< (1 - m_hChromaShift
), 1);
484 primitives
.chroma
[m_csp
].filter_vss
[partEnum
](m_immedVals
+ (halfFilterSize
- 1) * extStride
, extStride
, dstCr
, dstStride
, yFrac
<< (1 - m_vChromaShift
));
488 /* weighted averaging for bi-pred */
489 void Predict::addWeightBi(Yuv
& predYuv
, const ShortYuv
& srcYuv0
, const ShortYuv
& srcYuv1
, const WeightValues wp0
[3], const WeightValues wp1
[3], bool bLuma
, bool bChroma
) const
493 int w0
, w1
, offset
, shiftNum
, shift
, round
;
494 uint32_t src0Stride
, src1Stride
, dststride
;
498 pixel
* dstY
= predYuv
.getLumaAddr(m_puAbsPartIdx
);
499 const int16_t* srcY0
= srcYuv0
.getLumaAddr(m_puAbsPartIdx
);
500 const int16_t* srcY1
= srcYuv1
.getLumaAddr(m_puAbsPartIdx
);
504 offset
= wp0
[0].o
+ wp1
[0].o
;
505 shiftNum
= IF_INTERNAL_PREC
- X265_DEPTH
;
506 shift
= wp0
[0].shift
+ shiftNum
+ 1;
507 round
= shift
? (1 << (shift
- 1)) : 0;
510 src0Stride
= srcYuv0
.m_size
;
511 src1Stride
= srcYuv1
.m_size
;
512 dststride
= predYuv
.m_size
;
514 // TODO: can we use weight_sp here?
515 for (y
= m_puHeight
- 1; y
>= 0; y
--)
517 for (x
= m_puWidth
- 1; x
>= 0; )
519 // note: luma min width is 4
520 dstY
[x
] = weightBidir(w0
, srcY0
[x
], w1
, srcY1
[x
], round
, shift
, offset
);
522 dstY
[x
] = weightBidir(w0
, srcY0
[x
], w1
, srcY1
[x
], round
, shift
, offset
);
524 dstY
[x
] = weightBidir(w0
, srcY0
[x
], w1
, srcY1
[x
], round
, shift
, offset
);
526 dstY
[x
] = weightBidir(w0
, srcY0
[x
], w1
, srcY1
[x
], round
, shift
, offset
);
538 pixel
* dstU
= predYuv
.getCbAddr(m_puAbsPartIdx
);
539 pixel
* dstV
= predYuv
.getCrAddr(m_puAbsPartIdx
);
540 const int16_t* srcU0
= srcYuv0
.getCbAddr(m_puAbsPartIdx
);
541 const int16_t* srcV0
= srcYuv0
.getCrAddr(m_puAbsPartIdx
);
542 const int16_t* srcU1
= srcYuv1
.getCbAddr(m_puAbsPartIdx
);
543 const int16_t* srcV1
= srcYuv1
.getCrAddr(m_puAbsPartIdx
);
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 int w0
, offset
, shiftNum
, shift
, round
;
606 uint32_t srcStride
, dstStride
;
610 pixel
* dstY
= predYuv
.getLumaAddr(m_puAbsPartIdx
);
611 const int16_t* srcY0
= srcYuv
.getLumaAddr(m_puAbsPartIdx
);
615 offset
= wp
[0].offset
;
616 shiftNum
= IF_INTERNAL_PREC
- X265_DEPTH
;
617 shift
= wp
[0].shift
+ shiftNum
;
618 round
= shift
? (1 << (shift
- 1)) : 0;
619 srcStride
= srcYuv
.m_size
;
620 dstStride
= predYuv
.m_size
;
622 primitives
.weight_sp(srcY0
, dstY
, srcStride
, dstStride
, m_puWidth
, m_puHeight
, w0
, round
, shift
, offset
);
627 pixel
* dstU
= predYuv
.getCbAddr(m_puAbsPartIdx
);
628 pixel
* dstV
= predYuv
.getCrAddr(m_puAbsPartIdx
);
629 const int16_t* srcU0
= srcYuv
.getCbAddr(m_puAbsPartIdx
);
630 const int16_t* srcV0
= srcYuv
.getCrAddr(m_puAbsPartIdx
);
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(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(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_reconPic
->getLumaAddr(cu
.m_cuAddr
, cuGeom
.encodeIdx
+ absPartIdx
);
672 intptr_t picStride
= cu
.m_encData
->m_reconPic
->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_reconPic
->getChromaAddr(chromaId
, cu
.m_cuAddr
, cuGeom
.encodeIdx
+ absPartIdx
);
748 intptr_t picStride
= cu
.m_encData
->m_reconPic
->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