diff --git a/source/common/bitstream.cpp b/source/common/bitstream.cpp index d4a5c2da9..c0f58189c 100644 --- a/source/common/bitstream.cpp +++ b/source/common/bitstream.cpp @@ -56,11 +56,7 @@ void Bitstream::write(uint32_t val, uint32_t numBits) { /* topword aligns m_partialByte with the msb of val */ uint32_t topword = (numBits - nextPartialBits) & ~7; -#if USING_FTRAPV - uint32_t write_bits = (topword < 32 ? m_partialByte << topword : 0) | (val >> nextPartialBits); -#else - uint32_t write_bits = (m_partialByte << topword) | (val >> nextPartialBits); -#endif + uint32_t write_bits = (topword < 32 ? (uint32_t)m_partialByte << topword : 0) | (val >> nextPartialBits); switch (writeBytes) { diff --git a/source/common/cudata.cpp b/source/common/cudata.cpp index 3deafea1c..b07d848c7 100644 --- a/source/common/cudata.cpp +++ b/source/common/cudata.cpp @@ -462,7 +462,8 @@ void CUData::initLosslessCU(const CUData& cu, const CUGeom& cuGeom) m_cuAboveRight = cu.m_cuAboveRight; m_absIdxInCTU = cuGeom.absPartIdx; m_numPartitions = cuGeom.numPartitions; - memcpy(m_qp, cu.m_qp, BytesPerPartition * m_numPartitions); + uint32_t bytesPerPartition = (m_chromaFormat == X265_CSP_I400 ? BytesPerPartition - 4 : BytesPerPartition); + memcpy(m_qp, cu.m_qp, bytesPerPartition * m_numPartitions); memcpy(m_mv[0], cu.m_mv[0], m_numPartitions * sizeof(MV)); memcpy(m_mv[1], cu.m_mv[1], m_numPartitions * sizeof(MV)); memcpy(m_mvd[0], cu.m_mvd[0], m_numPartitions * sizeof(MV)); diff --git a/source/common/cudata.h b/source/common/cudata.h index 38cb96016..54fd30127 100644 --- a/source/common/cudata.h +++ b/source/common/cudata.h @@ -304,8 +304,8 @@ class CUData void getNeighbourMV(uint32_t puIdx, uint32_t absPartIdx, InterNeighbourMV* neighbours) const; void getIntraTUQtDepthRange(uint32_t tuDepthRange[2], uint32_t absPartIdx) const; void getInterTUQtDepthRange(uint32_t tuDepthRange[2], uint32_t absPartIdx) const; - uint32_t getBestRefIdx(uint32_t subPartIdx) const { return ((m_interDir[subPartIdx] & 1) << m_refIdx[0][subPartIdx]) | - (((m_interDir[subPartIdx] >> 1) & 1) << (m_refIdx[1][subPartIdx] + 16)); } + uint32_t getBestRefIdx(uint32_t subPartIdx) const { return ((uint32_t)(m_interDir[subPartIdx] & 1) << (m_refIdx[0][subPartIdx] & 31)) | + ((uint32_t)((m_interDir[subPartIdx] >> 1) & 1) << ((m_refIdx[1][subPartIdx] + 16) & 31)); } uint32_t getPUOffset(uint32_t puIdx, uint32_t absPartIdx) const { return (partAddrTable[(int)m_partSize[absPartIdx]][puIdx] << (m_slice->m_param->unitSizeDepth - m_cuDepth[absPartIdx]) * 2) >> 4; } uint32_t getNumPartInter(uint32_t absPartIdx) const { return nbPartsTable[(int)m_partSize[absPartIdx]]; } diff --git a/source/common/dct.cpp b/source/common/dct.cpp index 932dc7dd5..8c70e53b6 100644 --- a/source/common/dct.cpp +++ b/source/common/dct.cpp @@ -658,7 +658,7 @@ static void dequant_scaling_c(const int16_t* quantCoef, const int32_t* deQuantCo for (int n = 0; n < num; n++) { coeffQ = x265_clip3(-32768, 32767, quantCoef[n] * deQuantCoef[n]); - coef[n] = (int16_t)x265_clip3(-32768, 32767, coeffQ << (per - shift)); + coef[n] = (int16_t)x265_clip3(-32768, 32767, coeffQ * (1 << (per - shift))); } } } diff --git a/source/common/deblock.cpp b/source/common/deblock.cpp index 0f9bc02dd..336d7d47f 100644 --- a/source/common/deblock.cpp +++ b/source/common/deblock.cpp @@ -325,8 +325,8 @@ void Deblock::edgeFilterLuma(const CUData* cuQ, uint32_t absPartIdx, uint32_t de int32_t maskP = -1; int32_t maskQ = -1; - int32_t betaOffset = pps->deblockingFilterBetaOffsetDiv2 << 1; - int32_t tcOffset = pps->deblockingFilterTcOffsetDiv2 << 1; + int32_t betaOffset = pps->deblockingFilterBetaOffsetDiv2 * 2; + int32_t tcOffset = pps->deblockingFilterTcOffsetDiv2 * 2; bool bCheckNoFilter = pps->bTransquantBypassEnabled; if (dir == EDGE_VER) @@ -422,7 +422,7 @@ void Deblock::edgeFilterChroma(const CUData* cuQ, uint32_t absPartIdx, uint32_t int32_t maskP = -1; int32_t maskQ = -1; - int32_t tcOffset = pps->deblockingFilterTcOffsetDiv2 << 1; + int32_t tcOffset = pps->deblockingFilterTcOffsetDiv2 * 2; X265_CHECK(((dir == EDGE_VER) ? ((g_zscanToPelX[absPartIdx] + edge * UNIT_SIZE) >> cuQ->m_hChromaShift) diff --git a/source/common/mv.h b/source/common/mv.h index 5a8872cdd..57933441e 100644 --- a/source/common/mv.h +++ b/source/common/mv.h @@ -56,14 +56,8 @@ struct MV MV& operator >>=(int i) { x >>= i; y >>= i; return *this; } -#if USING_FTRAPV - /* avoid signed left-shifts when -ftrapv is enabled */ - MV& operator <<=(int i) { x *= (1 << i); y *= (1 << i); return *this; } - MV operator <<(int i) const { return MV(x * (1 << i), y * (1 << i)); } -#else - MV& operator <<=(int i) { x <<= i; y <<= i; return *this; } - MV operator <<(int i) const { return MV(x << i, y << i); } -#endif + MV& operator <<=(int i) { x = (int32_t)((uint32_t)x << i); y = (int32_t)((uint32_t)y << i); return *this; } + MV operator <<(int i) const { return MV((int32_t)((uint32_t)x << i), (int32_t)((uint32_t)y << i)); } MV operator >>(int i) const { return MV(x >> i, y >> i); } diff --git a/source/common/picyuv.cpp b/source/common/picyuv.cpp index acffca77d..ee87a8efc 100644 --- a/source/common/picyuv.cpp +++ b/source/common/picyuv.cpp @@ -67,6 +67,10 @@ PicYuv::PicYuv() m_strideC = 0; m_hChromaShift = 0; m_vChromaShift = 0; + m_lumaMarginX = 0; + m_lumaMarginY = 0; + m_chromaMarginX = 0; + m_chromaMarginY = 0; } bool PicYuv::create(x265_param* param, bool picAlloc, pixel *pixelbuf) diff --git a/source/common/pixel.cpp b/source/common/pixel.cpp index e90ef5207..4f7839053 100644 --- a/source/common/pixel.cpp +++ b/source/common/pixel.cpp @@ -400,7 +400,7 @@ void cpy2Dto1D_shl(int16_t* dst, const int16_t* src, intptr_t srcStride, int shi for (int i = 0; i < size; i++) { for (int j = 0; j < size; j++) - dst[j] = src[j] << shift; + dst[j] = (int16_t)((uint32_t)src[j] << shift); src += srcStride; dst += size; @@ -435,7 +435,7 @@ void cpy1Dto2D_shl(int16_t* dst, const int16_t* src, intptr_t dstStride, int shi for (int i = 0; i < size; i++) { for (int j = 0; j < size; j++) - dst[j] = src[j] << shift; + dst[j] = (int16_t)((uint32_t)src[j] << shift); src += size; dst += dstStride; @@ -629,8 +629,8 @@ static void ssim_4x4x2_core(const pixel* pix1, intptr_t stride1, const pixel* pi { for (int x = 0; x < 4; x++) { - int a = pix1[x + y * stride1]; - int b = pix2[x + y * stride2]; + uint32_t a = pix1[x + y * stride1]; + uint32_t b = pix2[x + y * stride2]; s1 += a; s2 += b; ss += a * a; diff --git a/source/common/predict.cpp b/source/common/predict.cpp index 8e9c32d23..8e7a78f0a 100644 --- a/source/common/predict.cpp +++ b/source/common/predict.cpp @@ -342,8 +342,8 @@ void Predict::predInterChromaPixel(const PredictionUnit& pu, Yuv& dstYuv, const intptr_t dstStride = dstYuv.m_csize; intptr_t refStride = refPic.m_strideC; - int mvx = mv.x << (1 - m_hChromaShift); - int mvy = mv.y << (1 - m_vChromaShift); + int mvx = (int32_t)((uint32_t)mv.x << (1 - m_hChromaShift)); + int mvy = (int32_t)((uint32_t)mv.y << (1 - m_vChromaShift)); intptr_t refOffset = (mvx >> 3) + (mvy >> 3) * refStride; @@ -391,8 +391,8 @@ void Predict::predInterChromaShort(const PredictionUnit& pu, ShortYuv& dstSYuv, intptr_t dstStride = dstSYuv.m_csize; intptr_t refStride = refPic.m_strideC; - int mvx = mv.x << (1 - m_hChromaShift); - int mvy = mv.y << (1 - m_vChromaShift); + int mvx = (int32_t)((uint32_t)mv.x << (1 - m_hChromaShift)); + int mvy = (int32_t)((uint32_t)mv.y << (1 - m_vChromaShift)); intptr_t refOffset = (mvx >> 3) + (mvy >> 3) * refStride; diff --git a/source/common/primitives.cpp b/source/common/primitives.cpp index 427fbc1df..1019e1c58 100644 --- a/source/common/primitives.cpp +++ b/source/common/primitives.cpp @@ -86,28 +86,99 @@ void enableLowpassDCTPrimitives(EncoderPrimitives &p) p.cu[BLOCK_32x32].dct = p.cu[BLOCK_32x32].lowpass_dct; } -void setupAliasPrimitives(EncoderPrimitives &p) -{ #if HIGH_BIT_DEPTH - /* at HIGH_BIT_DEPTH, pixel == short so we can alias many primitives */ - for (int i = 0; i < NUM_CU_SIZES; i++) +namespace { +/* At HIGH_BIT_DEPTH pixel and int16_t are the same-size 16-bit type, so the + * short primitives can serve the pixel variants. These trampolines reinterpret + * only the data pointers, avoiding the UB of casting the function pointers + * themselves (flagged by UBSan's -fsanitize=function). */ + +#if !defined(X265_ARCH_ARM64) && !defined(X265_ARCH_RISCV64) +template +sse_t aliasSsePP(const pixel* a, intptr_t strideA, const pixel* b, intptr_t strideB) +{ + return primitives.cu[i].sse_ss(reinterpret_cast(a), strideA, + reinterpret_cast(b), strideB); +} +#endif + +template +void aliasLumaCopyPS(int16_t* dst, intptr_t dstStride, const pixel* src, intptr_t srcStride) +{ primitives.pu[i].copy_pp(reinterpret_cast(dst), dstStride, src, srcStride); } + +template +void aliasLumaCopySP(pixel* dst, intptr_t dstStride, const int16_t* src, intptr_t srcStride) +{ primitives.pu[i].copy_pp(dst, dstStride, reinterpret_cast(src), srcStride); } + +template +void aliasLumaCopySS(int16_t* dst, intptr_t dstStride, const int16_t* src, intptr_t srcStride) +{ primitives.pu[i].copy_pp(reinterpret_cast(dst), dstStride, reinterpret_cast(src), srcStride); } + +template +void aliasChromaCopyPS(int16_t* dst, intptr_t dstStride, const pixel* src, intptr_t srcStride) +{ primitives.chroma[csp].pu[i].copy_pp(reinterpret_cast(dst), dstStride, src, srcStride); } + +template +void aliasChromaCopySP(pixel* dst, intptr_t dstStride, const int16_t* src, intptr_t srcStride) +{ primitives.chroma[csp].pu[i].copy_pp(dst, dstStride, reinterpret_cast(src), srcStride); } + +template +void aliasChromaCopySS(int16_t* dst, intptr_t dstStride, const int16_t* src, intptr_t srcStride) +{ primitives.chroma[csp].pu[i].copy_pp(reinterpret_cast(dst), dstStride, reinterpret_cast(src), srcStride); } + +template +struct AliasFiller +{ + static void fill(EncoderPrimitives& p) { + /* Only install an alias when the underlying short primitive it forwards + * to actually exists. The trampolines dispatch through the base entry, + * so aliasing a missing base would produce a non-NULL pointer that jumps + * through a NULL slot when invoked. Mirroring the base's presence keeps + * the original "NULL base => NULL alias" behaviour that callers (and the + * testbench's "if (opt.foo)" guards) rely on. */ #if !defined(X265_ARCH_ARM64) && !defined(X265_ARCH_RISCV64) - p.cu[i].sse_pp = (pixel_sse_t)p.cu[i].sse_ss; + if (p.cu[i].sse_ss) + p.cu[i].sse_pp = aliasSsePP; #endif + if (p.pu[i].copy_pp) + { + p.cu[i].copy_ps = aliasLumaCopyPS; + p.cu[i].copy_sp = aliasLumaCopySP; + p.cu[i].copy_ss = aliasLumaCopySS; + } - p.cu[i].copy_ps = (copy_ps_t)p.pu[i].copy_pp; - p.cu[i].copy_sp = (copy_sp_t)p.pu[i].copy_pp; - p.cu[i].copy_ss = (copy_ss_t)p.pu[i].copy_pp; + if (p.chroma[X265_CSP_I420].pu[i].copy_pp) + { + p.chroma[X265_CSP_I420].cu[i].copy_ps = aliasChromaCopyPS; + p.chroma[X265_CSP_I420].cu[i].copy_sp = aliasChromaCopySP; + p.chroma[X265_CSP_I420].cu[i].copy_ss = aliasChromaCopySS; + } - p.chroma[X265_CSP_I420].cu[i].copy_ps = (copy_ps_t)p.chroma[X265_CSP_I420].pu[i].copy_pp; - p.chroma[X265_CSP_I420].cu[i].copy_sp = (copy_sp_t)p.chroma[X265_CSP_I420].pu[i].copy_pp; - p.chroma[X265_CSP_I420].cu[i].copy_ss = (copy_ss_t)p.chroma[X265_CSP_I420].pu[i].copy_pp; + if (p.chroma[X265_CSP_I422].pu[i].copy_pp) + { + p.chroma[X265_CSP_I422].cu[i].copy_ps = aliasChromaCopyPS; + p.chroma[X265_CSP_I422].cu[i].copy_sp = aliasChromaCopySP; + p.chroma[X265_CSP_I422].cu[i].copy_ss = aliasChromaCopySS; + } - p.chroma[X265_CSP_I422].cu[i].copy_ps = (copy_ps_t)p.chroma[X265_CSP_I422].pu[i].copy_pp; - p.chroma[X265_CSP_I422].cu[i].copy_sp = (copy_sp_t)p.chroma[X265_CSP_I422].pu[i].copy_pp; - p.chroma[X265_CSP_I422].cu[i].copy_ss = (copy_ss_t)p.chroma[X265_CSP_I422].pu[i].copy_pp; + AliasFiller::fill(p); } +}; + +template<> +struct AliasFiller +{ + static void fill(EncoderPrimitives&) {} +}; +} // namespace +#endif + +void setupAliasPrimitives(EncoderPrimitives &p) +{ +#if HIGH_BIT_DEPTH + /* at HIGH_BIT_DEPTH, pixel == short so we can alias many primitives */ + AliasFiller<0>::fill(p); #endif /* alias chroma 4:4:4 from luma primitives (all but chroma filters) */ diff --git a/source/common/quant.cpp b/source/common/quant.cpp index b6521912b..0b8341527 100644 --- a/source/common/quant.cpp +++ b/source/common/quant.cpp @@ -1341,7 +1341,7 @@ uint32_t Quant::rdoQuant(const CUData& cu, int16_t* dstCoeff, TextType ttype, ui const int64_t origDist = (((int64_t)d * d)); -#define DELTARDCOST(d0, d, deltabits) ((((int64_t)d * d - d0) << scaleBits) + ((lambda2 * (int64_t)(deltabits)) >> 8)) +#define DELTARDCOST(d0, d, deltabits) ((int64_t)((uint64_t)((int64_t)d * d - d0) << scaleBits) + ((lambda2 * (int64_t)(deltabits)) >> 8)) const uint32_t isOne = (absLevel == 1); if (dstCoeff[blkPos]) diff --git a/source/common/quant.h b/source/common/quant.h index 21ec217db..cf6ef74af 100644 --- a/source/common/quant.h +++ b/source/common/quant.h @@ -53,9 +53,10 @@ struct QpParam rem = qpScaled % 6; per = qpScaled / 6; qp = qpScaled; - lambda2 = (int64_t)(x265_lambda2_tab[qp - QP_BD_OFFSET] * 256. + 0.5); - lambda = (int32_t)(x265_lambda_tab[qp - QP_BD_OFFSET] * 256. + 0.5); - X265_CHECK((x265_lambda_tab[qp - QP_BD_OFFSET] * 256. + 0.5) < (double)MAX_INT, "x265_lambda_tab[] value too large\n"); + int lambdaIdx = x265_clip3(QP_MIN, QP_MAX_MAX, qp - QP_BD_OFFSET); + lambda2 = (int64_t)(x265_lambda2_tab[lambdaIdx] * 256. + 0.5); + lambda = (int32_t)(x265_lambda_tab[lambdaIdx] * 256. + 0.5); + X265_CHECK((x265_lambda_tab[lambdaIdx] * 256. + 0.5) < (double)MAX_INT, "x265_lambda_tab[] value too large\n"); } } }; @@ -125,7 +126,7 @@ class Quant // NOTE: cgBlkPos+1 may more than 63, it is invalid for shift, // but in this case, both cgPosX and cgPosY equal to (trSizeCG - 1), // the sigRight and sigLower will clear value to zero, the final result will be correct - const uint32_t sigPos = (uint32_t)(sigCoeffGroupFlag64 >> (cgBlkPos + 1)); // just need lowest 7-bits valid + const uint32_t sigPos = (uint32_t)((sigCoeffGroupFlag64 >> cgBlkPos) >> 1); // just need lowest 7-bits valid // TODO: instruction BT is faster, but _bittest64 still generate instruction 'BT m, r' in VS2012 const uint32_t sigRight = (cgPosX != (trSizeCG - 1)) & sigPos; @@ -138,7 +139,7 @@ class Quant { X265_CHECK(cgBlkPos < 64, "cgBlkPos is too large\n"); // NOTE: unsafe shift operator, see NOTE in calcPatternSigCtx - const uint32_t sigPos = (uint32_t)(cgGroupMask >> (cgBlkPos + 1)); // just need lowest 8-bits valid + const uint32_t sigPos = (uint32_t)((cgGroupMask >> cgBlkPos) >> 1); // just need lowest 8-bits valid const uint32_t sigRight = (cgPosX != (trSizeCG - 1)) & sigPos; const uint32_t sigLower = (cgPosY != (trSizeCG - 1)) & (sigPos >> (trSizeCG - 1)); diff --git a/source/encoder/analysis.cpp b/source/encoder/analysis.cpp index 3f2da42bd..efd665c01 100644 --- a/source/encoder/analysis.cpp +++ b/source/encoder/analysis.cpp @@ -4381,7 +4381,10 @@ int Analysis::calculateQpforCuSize(const CUData& ctu, const CUGeom& cuGeom, int3 cnt++; } } - dQpOffset /= cnt; + if (cnt) + { + dQpOffset /= cnt; + } qp += dQpOffset; if (complexCheck) { diff --git a/source/encoder/encoder.cpp b/source/encoder/encoder.cpp index d6d746903..d8328cecf 100644 --- a/source/encoder/encoder.cpp +++ b/source/encoder/encoder.cpp @@ -2249,9 +2249,9 @@ int Encoder::encode(const x265_picture* pic_in, x265_picture* pic_out) /* pop a single frame from decided list, then provide to frame encoder * curEncoder is guaranteed to be idle at this point */ - if (!pass) + if (!pass && (!m_param->chunkEnd || (m_encodedFrameNum < m_param->chunkEnd))) frameEnc[0] = m_lookahead->getDecidedPicture(); - if (frameEnc[0] && !pass && (!m_param->chunkEnd || (m_encodedFrameNum < m_param->chunkEnd))) + if (frameEnc[0] && !pass) { #if ENABLE_ALPHA || ENABLE_MULTIVIEW diff --git a/source/encoder/framefilter.cpp b/source/encoder/framefilter.cpp index bb5fb7512..3f58beedb 100644 --- a/source/encoder/framefilter.cpp +++ b/source/encoder/framefilter.cpp @@ -385,15 +385,21 @@ void FrameFilter::ParallelFilter::processPostCu(int col) const if ((col == 0) | (col == m_frameFilter->m_numCols - 1)) { copySizeY += lumaMarginX; - copySizeC += chromaMarginX; + if (m_frameFilter->m_param->internalCsp != X265_CSP_I400) + { + copySizeC += chromaMarginX; + } } // First column need extension left padding area and first CU if (col == 0) { pixY -= lumaMarginX; - pixU -= chromaMarginX; - pixV -= chromaMarginX; + if (m_frameFilter->m_param->internalCsp != X265_CSP_I400) + { + pixU -= chromaMarginX; + pixV -= chromaMarginX; + } } // Border extend Top @@ -416,8 +422,11 @@ void FrameFilter::ParallelFilter::processPostCu(int col) const if (m_row == m_frameFilter->m_numRows - 1) { pixY += (realH - 1) * stride; - pixU += ((realH >> vChromaShift) - 1) * strideC; - pixV += ((realH >> vChromaShift) - 1) * strideC; + if (m_frameFilter->m_param->internalCsp != X265_CSP_I400) + { + pixU += ((realH >> vChromaShift) - 1) * strideC; + pixV += ((realH >> vChromaShift) - 1) * strideC; + } for (uint32_t y = 0; y < lumaMarginY; y++) memcpy(pixY + (y + 1) * stride, pixY, copySizeY * sizeof(pixel)); diff --git a/source/encoder/motion.cpp b/source/encoder/motion.cpp index b88351d2d..a1ab3b5e2 100644 --- a/source/encoder/motion.cpp +++ b/source/encoder/motion.cpp @@ -329,9 +329,9 @@ void MotionEstimate::setSourcePU(const Yuv& srcFencYuv, int _ctuAddr, int cuPart fref + (m1x) + (m1y) * stride, \ fref + (m2x) + (m2y) * stride, \ stride, costs); \ - costs[0] += p_cost_mvx[(m0x) << 2]; /* no cost_mvy */\ - costs[1] += p_cost_mvx[(m1x) << 2]; \ - costs[2] += p_cost_mvx[(m2x) << 2]; \ + costs[0] += p_cost_mvx[(m0x) * 4]; /* no cost_mvy */\ + costs[1] += p_cost_mvx[(m1x) * 4]; \ + costs[2] += p_cost_mvx[(m2x) * 4]; \ COPY3_IF_LT(bcost, costs[0], bmv.x, m0x, bmv.y, m0y); \ COPY3_IF_LT(bcost, costs[1], bmv.x, m1x, bmv.y, m1y); \ COPY3_IF_LT(bcost, costs[2], bmv.x, m2x, bmv.y, m2y); \ @@ -1029,8 +1029,8 @@ int MotionEstimate::motionEstimate(ReferencePlanes *ref, COPY1_IF_LT(bcost, (costs[3] << 4) + 12); if (!(bcost & 15)) break; - bmv.x -= (bcost << 28) >> 30; - bmv.y -= (bcost << 30) >> 30; + bmv.x -= (int32_t)((uint32_t)bcost << 28) >> 30; + bmv.y -= (int32_t)((uint32_t)bcost << 30) >> 30; bcost &= ~15; } while (--i && bmv.checkRange(mvmin, mvmax)); @@ -1315,7 +1315,7 @@ int MotionEstimate::motionEstimate(ReferencePlanes *ref, if (dir) { bmv.x = omv.x + i * (dir >> 4); - bmv.y = omv.y + i * ((dir << 28) >> 28); + bmv.y = omv.y + i * ((int32_t)((uint32_t)dir << 28) >> 28); } } } @@ -1807,8 +1807,8 @@ int MotionEstimate::subpelCompare(ReferencePlanes *ref, const MV& qmv, pixelcmp_ int csp = fencPUYuv.m_csp; int hshift = fencPUYuv.m_hChromaShift; int vshift = fencPUYuv.m_vChromaShift; - int mvx = qmv.x << (1 - hshift); - int mvy = qmv.y << (1 - vshift); + int mvx = (int32_t)((uint32_t)qmv.x << (1 - hshift)); + int mvy = (int32_t)((uint32_t)qmv.y << (1 - vshift)); intptr_t fencStrideC = fencPUYuv.m_csize; intptr_t refStrideC = ref->reconPic->m_strideC; diff --git a/source/encoder/nal.cpp b/source/encoder/nal.cpp index fe9bb9086..c2620065f 100644 --- a/source/encoder/nal.cpp +++ b/source/encoder/nal.cpp @@ -72,7 +72,8 @@ void NALList::serialize(NalUnitType nalUnitType, const Bitstream& bs, int layerI uint8_t *temp = X265_MALLOC(uint8_t, nextSize); if (temp) { - memcpy(temp, m_buffer, m_occupancy); + if (m_occupancy) + memcpy(temp, m_buffer, m_occupancy); /* fixup existing payload pointers */ for (uint32_t i = 0; i < m_numNal; i++) diff --git a/source/encoder/ratecontrol.cpp b/source/encoder/ratecontrol.cpp index 9ddaba4b2..21fb9e086 100644 --- a/source/encoder/ratecontrol.cpp +++ b/source/encoder/ratecontrol.cpp @@ -2452,7 +2452,7 @@ void RateControl::rateControlUpdateStats(RateControlEntry* rce) rce->amortizeFrames = m_amortizeFrames; rce->amortizeFraction = m_amortizeFraction; m_partialResidualFrames = X265_MIN((int)rce->amortizeFrames, m_param->keyframeMax); - m_partialResidualCost = (int)((rce->rowTotalBits * rce->amortizeFraction) / m_partialResidualFrames); + m_partialResidualCost = m_partialResidualFrames ? (int)((rce->rowTotalBits * rce->amortizeFraction) / m_partialResidualFrames) : 0; rce->rowTotalBits -= m_partialResidualCost * m_partialResidualFrames; } else if (m_partialResidualFrames) @@ -3204,7 +3204,7 @@ int RateControl::rateControlEnd(Frame* curFrame, int64_t bits, RateControlEntry* if (m_residualFrames) bits += m_residualCost * m_residualFrames; m_residualFrames = X265_MIN((int)rce->amortizeFrames, m_param->keyframeMax); - m_residualCost = (int)((bits * rce->amortizeFraction) / m_residualFrames); + m_residualCost = m_residualFrames ? (int)((bits * rce->amortizeFraction) / m_residualFrames) : 0; bits -= m_residualCost * m_residualFrames; } else if (m_residualFrames) diff --git a/source/encoder/sao.cpp b/source/encoder/sao.cpp index 0dee092d7..63acd48af 100644 --- a/source/encoder/sao.cpp +++ b/source/encoder/sao.cpp @@ -1062,7 +1062,15 @@ void SAO::calcSaoStatsCu_BeforeDblk(Frame* frame, int idxX, int idxY) for (y = firstY; y < endY; y++) { - for (x = (y < startY - 1 ? startX : 0); x < ctuWidth; x++) + x = (y < startY - 1 ? startX : 0); + + // NOTE: upBuff1[x < startX] is not maintained by the loop below, so it is + // uninitialized on the row where x first drops below startX, and stale after + // that. Recompute it here; this matches what the loop would have written. + for (int i = x; i < startX; i++) + upBuff1[i] = x265_signOf(rec[i] - rec[i - stride]); + + for (; x < ctuWidth; x++) { int signDown = x265_signOf(rec[x] - rec[x + stride]); int edgeType = signDown + upBuff1[x] + 2; @@ -1111,6 +1119,13 @@ void SAO::calcSaoStatsCu_BeforeDblk(Frame* frame, int idxX, int idxY) for (y = firstY; y < endY; y++) { x = (y < startY - 1 ? startX : firstX); + + // NOTE: upBuff1[x < startX] is not maintained by the loop below, and the swap + // means it may come from _upBufft, which the fill above never touched. + // Recompute it here; this matches what the loop would have written. + for (int i = x; i < startX; i++) + upBuff1[i] = x265_signOf(rec[i] - rec[i - stride - 1]); + upBufft[x] = x265_signOf(rec[x + stride] - rec[x - 1]); for (; x < endX; x++) { @@ -1162,7 +1177,15 @@ void SAO::calcSaoStatsCu_BeforeDblk(Frame* frame, int idxX, int idxY) for (y = firstY; y < endY; y++) { - for (x = (y < startY - 1 ? startX : firstX); x < endX; x++) + x = (y < startY - 1 ? startX : firstX); + + // NOTE: upBuff1[x < startX - 1] is not maintained by the loop below, so it is + // uninitialized on the row where x first drops below startX, and stale after + // that. Recompute it here; this matches what the loop would have written. + for (int i = x; i < startX; i++) + upBuff1[i] = x265_signOf(rec[i] - rec[i - stride + 1]); + + for (; x < endX; x++) { int signDown = x265_signOf(rec[x] - rec[x + stride - 1]); int edgeType = signDown + upBuff1[x] + 2; @@ -1319,7 +1342,7 @@ void SAO::rdoSaoUnitCu(SAOParam* saoParam, int rowBaseAddr, int idxX, int addr) estDist += estSaoDist(m_count[plane][typeIdx][classIdx + bandPos], mergeOffset, m_offsetOrg[plane][typeIdx][classIdx + bandPos]); } } - mergeDist += (estDist << 8) / lambda[!!plane]; + mergeDist += (int64_t)((uint64_t)estDist << 8) / lambda[!!plane]; } m_entropyCoder.load(m_rdContexts.cur); @@ -1583,7 +1606,7 @@ void SAO::saoLumaComponentParamDist(SAOParam* saoParam, int32_t addr, int64_t& r lclCtuParam->offset[classIdx] = m_offset[0][SAO_BO][classIdx + bestClassBO]; } - rateDist = (bestDist << 8) / lambda[0]; + rateDist = (int64_t)((uint64_t)bestDist << 8) / lambda[0]; m_entropyCoder.load(m_rdContexts.temp); m_entropyCoder.codeSaoOffset(*lclCtuParam, 0); m_entropyCoder.store(m_rdContexts.temp); @@ -1728,7 +1751,7 @@ void SAO::saoChromaComponentParamDist(SAOParam* saoParam, int32_t addr, int64_t& } } - rateDist += (bestDist << 8) / lambda[1]; + rateDist += (int64_t)((uint64_t)bestDist << 8) / lambda[1]; m_entropyCoder.load(m_rdContexts.temp); if (saoParam->bSaoFlag[1]) diff --git a/source/encoder/slicetype.cpp b/source/encoder/slicetype.cpp index 26f62770b..9e2beb0b3 100644 --- a/source/encoder/slicetype.cpp +++ b/source/encoder/slicetype.cpp @@ -821,7 +821,7 @@ uint32_t LookaheadTLD::weightCostLuma(Lowres& fenc, Lowres& ref, WeightParam& wp if (wp.wtPresent) { - int offset = wp.inputOffset << (X265_DEPTH - 8); + int offset = wp.inputOffset * (1 << (X265_DEPTH - 8)); int scale = wp.inputWeight; int denom = wp.log2WeightDenom; int round = denom ? 1 << (denom - 1) : 0; @@ -936,7 +936,7 @@ void LookaheadTLD::weightsAnalyse(Lowres& fenc, Lowres& ref) COPY4_IF_LT(minscore, s, minscale, curScale, minoff, curOffset, found, 1); /* Use a smaller denominator if possible */ - if (mindenom > 0 && !(minscale & 1)) + if (mindenom > 0 && minscale && !(minscale & 1)) { unsigned long idx; BSF(idx, minscale); @@ -954,7 +954,7 @@ void LookaheadTLD::weightsAnalyse(Lowres& fenc, Lowres& ref) // set weighted delta cost fenc.weightedCostDelta[deltaIndex] = minscore / origscore; - int offset = wp.inputOffset << (X265_DEPTH - 8); + int offset = wp.inputOffset * (1 << (X265_DEPTH - 8)); int scale = wp.inputWeight; int denom = wp.log2WeightDenom; int round = denom ? 1 << (denom - 1) : 0; @@ -1068,6 +1068,7 @@ Lookahead::Lookahead(x265_param *param, ThreadPool* pool) m_fadeCount = 0; m_fadeStart = -1; m_origPicBuf = 0; + m_metld = NULL; /* Allow the strength to be adjusted via qcompress, since the two concepts * are very similar. */ @@ -2307,7 +2308,7 @@ void Lookahead::slicetypeDecide() { int leftOver = bframes + 1; int8_t gopId = m_gopId - 1; - int gopLen = x265_gop_ra_length[gopId]; + int gopLen = (gopId >= 0) ? x265_gop_ra_length[gopId] : 0; int listReset = 0; m_outputLock.acquire(); @@ -4201,7 +4202,6 @@ void CostEstimateGroup::processTasks(int workerThreadID) if (workerThreadID < 0) id = pool ? pool->m_numWorkers : 0; LookaheadTLD& tld = m_lookahead.m_tld[id]; - MotionEstimatorTLD& m_metld = m_lookahead.m_metld[id]; m_lock.acquire(); while (m_jobAcquired < m_jobTotal) @@ -4217,6 +4217,7 @@ void CostEstimateGroup::processTasks(int workerThreadID) if (m_lookahead.m_param->bEnableTemporalFilter && curFrame && m_lookahead.isFilterThisframe(curFrame->m_mcstf->m_sliceTypeConfig, curFrame->m_lowres.sliceType)) { ProfileLookaheadTime(tld.mcstfBatchElapsedTime); + MotionEstimatorTLD& m_metld = m_lookahead.m_metld[id]; m_metld.m_bitDepth = curFrame->m_param->internalBitDepth; TemporalFilterRefPicInfo* ref = &curFrame->m_mcstfRefList[e.p0]; diff --git a/source/encoder/weightPrediction.cpp b/source/encoder/weightPrediction.cpp index 15a562e73..dd8339a91 100644 --- a/source/encoder/weightPrediction.cpp +++ b/source/encoder/weightPrediction.cpp @@ -179,7 +179,7 @@ uint32_t weightCost(pixel * fenc, if (w) { /* make a weighted copy of the reference plane */ - int offset = w->inputOffset << (X265_DEPTH - 8); + int offset = w->inputOffset * (1 << (X265_DEPTH - 8)); int weight = w->inputWeight; int denom = w->log2WeightDenom; int round = denom ? 1 << (denom - 1) : 0; @@ -444,7 +444,7 @@ void weightAnalyse(Slice& slice, Frame& frame, x265_param& param) /* Use a smaller luma denominator if possible */ if (!(plane || list)) { - if (mindenom > 0 && !(minscale & 1)) + if (mindenom > 0 && minscale && !(minscale & 1)) { unsigned long idx; BSF(idx, minscale); diff --git a/source/test/pixelharness.cpp b/source/test/pixelharness.cpp index 13a20983b..9c58c672b 100644 --- a/source/test/pixelharness.cpp +++ b/source/test/pixelharness.cpp @@ -28,6 +28,15 @@ using namespace X265_NS; +/* At HIGH_BIT_DEPTH some cu[] slots are aliases: setupAliasPrimitives() installs + * the same trampoline in both tables, so ref == opt and the check can never fail. + * Skip those; the copy_pp / sse_ss they forward to is checked directly below. */ +#if HIGH_BIT_DEPTH +#define TESTABLE(ref, opt) ((opt) && (ref) != (opt)) +#else +#define TESTABLE(ref, opt) (opt) +#endif + PixelHarness::PixelHarness() { /* [0] --- Random values @@ -2458,7 +2467,7 @@ bool PixelHarness::testPU(int part, const EncoderPrimitives& ref, const EncoderP if (part < NUM_CU_SIZES) { - if (opt.cu[part].sse_pp) + if (TESTABLE(ref.cu[part].sse_pp, opt.cu[part].sse_pp)) { if (!check_pixel_sse(ref.cu[part].sse_pp, opt.cu[part].sse_pp)) { @@ -2503,7 +2512,7 @@ bool PixelHarness::testPU(int part, const EncoderPrimitives& ref, const EncoderP } } - if (opt.cu[part].copy_ss) + if (TESTABLE(ref.cu[part].copy_ss, opt.cu[part].copy_ss)) { if (!check_copy_ss(ref.cu[part].copy_ss, opt.cu[part].copy_ss)) { @@ -2512,7 +2521,7 @@ bool PixelHarness::testPU(int part, const EncoderPrimitives& ref, const EncoderP } } - if (opt.cu[part].copy_sp) + if (TESTABLE(ref.cu[part].copy_sp, opt.cu[part].copy_sp)) { if (!check_copy_sp(ref.cu[part].copy_sp, opt.cu[part].copy_sp)) { @@ -2521,7 +2530,7 @@ bool PixelHarness::testPU(int part, const EncoderPrimitives& ref, const EncoderP } } - if (opt.cu[part].copy_ps) + if (TESTABLE(ref.cu[part].copy_ps, opt.cu[part].copy_ps)) { if (!check_copy_ps(ref.cu[part].copy_ps, opt.cu[part].copy_ps)) { @@ -2567,7 +2576,7 @@ bool PixelHarness::testPU(int part, const EncoderPrimitives& ref, const EncoderP } if (part < NUM_CU_SIZES) { - if (opt.chroma[i].cu[part].sse_pp) + if (TESTABLE(ref.chroma[i].cu[part].sse_pp, opt.chroma[i].cu[part].sse_pp)) { if (!check_pixel_sse(ref.chroma[i].cu[part].sse_pp, opt.chroma[i].cu[part].sse_pp)) { @@ -2599,7 +2608,7 @@ bool PixelHarness::testPU(int part, const EncoderPrimitives& ref, const EncoderP return false; } } - if (opt.chroma[i].cu[part].copy_sp) + if (TESTABLE(ref.chroma[i].cu[part].copy_sp, opt.chroma[i].cu[part].copy_sp)) { if (!check_copy_sp(ref.chroma[i].cu[part].copy_sp, opt.chroma[i].cu[part].copy_sp)) { @@ -2607,7 +2616,7 @@ bool PixelHarness::testPU(int part, const EncoderPrimitives& ref, const EncoderP return false; } } - if (opt.chroma[i].cu[part].copy_ps) + if (TESTABLE(ref.chroma[i].cu[part].copy_ps, opt.chroma[i].cu[part].copy_ps)) { if (!check_copy_ps(ref.chroma[i].cu[part].copy_ps, opt.chroma[i].cu[part].copy_ps)) { @@ -2615,7 +2624,7 @@ bool PixelHarness::testPU(int part, const EncoderPrimitives& ref, const EncoderP return false; } } - if (opt.chroma[i].cu[part].copy_ss) + if (TESTABLE(ref.chroma[i].cu[part].copy_ss, opt.chroma[i].cu[part].copy_ss)) { if (!check_copy_ss(ref.chroma[i].cu[part].copy_ss, opt.chroma[i].cu[part].copy_ss)) { diff --git a/source/test/testbench.cpp b/source/test/testbench.cpp index fb12e340d..7a0cd1c4f 100644 --- a/source/test/testbench.cpp +++ b/source/test/testbench.cpp @@ -239,6 +239,11 @@ int main(int argc, char *argv[]) memset(&vecprim, 0, sizeof(vecprim)); setupIntrinsicPrimitives(vecprim, testArch[i].flag); setupAliasPrimitives(vecprim); + /* At HIGH_BIT_DEPTH the aliased primitives (sse_pp, copy_ps/sp/ss, ...) + * are trampolines that dispatch through the global primitive table, so + * it must point at the primitives currently under test before the + * harnesses run - otherwise the aliases jump through NULL slots. */ + memcpy(&primitives, &vecprim, sizeof(EncoderPrimitives)); for (size_t h = 0; h < sizeof(harness) / sizeof(TestHarness*); h++) { if (testname && strncmp(testname, harness[h]->getName(), strlen(testname)))